mirror of
https://github.com/eliasstepanik/core.git
synced 2026-01-27 20:38:31 +00:00
Feat: sdk for integrations
This commit is contained in:
parent
54e535d57d
commit
2396c0ea57
2
.gitignore
vendored
2
.gitignore
vendored
@ -45,3 +45,5 @@ registry/
|
|||||||
|
|
||||||
.cursor
|
.cursor
|
||||||
CLAUDE.md
|
CLAUDE.md
|
||||||
|
|
||||||
|
.claude
|
||||||
@ -1,14 +1,10 @@
|
|||||||
import { EditorContent, useEditor } from "@tiptap/react";
|
import { EditorContent, useEditor } from "@tiptap/react";
|
||||||
|
|
||||||
import React, { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { Document } from "@tiptap/extension-document";
|
|
||||||
import HardBreak from "@tiptap/extension-hard-break";
|
|
||||||
import { History } from "@tiptap/extension-history";
|
|
||||||
import { Paragraph } from "@tiptap/extension-paragraph";
|
|
||||||
import { Text } from "@tiptap/extension-text";
|
|
||||||
import { UserTypeEnum } from "@core/types";
|
import { UserTypeEnum } from "@core/types";
|
||||||
import { type ConversationHistory } from "@core/database";
|
import { type ConversationHistory } from "@core/database";
|
||||||
import { cn } from "~/lib/utils";
|
import { cn } from "~/lib/utils";
|
||||||
|
import { extensionsForConversation } from "./editor-extensions";
|
||||||
|
|
||||||
interface AIConversationItemProps {
|
interface AIConversationItemProps {
|
||||||
conversationHistory: ConversationHistory;
|
conversationHistory: ConversationHistory;
|
||||||
@ -24,14 +20,7 @@ export const ConversationItem = ({
|
|||||||
const id = `a${conversationHistory.id.replace(/-/g, "")}`;
|
const id = `a${conversationHistory.id.replace(/-/g, "")}`;
|
||||||
|
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
extensions: [
|
extensions: [...extensionsForConversation],
|
||||||
Document,
|
|
||||||
Paragraph,
|
|
||||||
Text,
|
|
||||||
HardBreak.configure({
|
|
||||||
keepMarks: true,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
editable: false,
|
editable: false,
|
||||||
content: conversationHistory.message,
|
content: conversationHistory.message,
|
||||||
});
|
});
|
||||||
@ -54,7 +43,7 @@ export const ConversationItem = ({
|
|||||||
isUser && "bg-primary/20 max-w-[500px] rounded-md p-3",
|
isUser && "bg-primary/20 max-w-[500px] rounded-md p-3",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<EditorContent editor={editor} />
|
<EditorContent editor={editor} className="editor-container" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useFetcher } from "@remix-run/react";
|
import { useFetcher, useNavigate } from "@remix-run/react";
|
||||||
import { useEffect, useState, useCallback, useRef } from "react";
|
import { useEffect, useState, useCallback, useRef } from "react";
|
||||||
import {
|
import {
|
||||||
List,
|
List,
|
||||||
@ -7,7 +7,7 @@ import {
|
|||||||
type ListRowRenderer,
|
type ListRowRenderer,
|
||||||
} from "react-virtualized";
|
} from "react-virtualized";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { MessageSquare, Clock } from "lucide-react";
|
import { MessageSquare, Clock, Plus } from "lucide-react";
|
||||||
import { cn } from "~/lib/utils";
|
import { cn } from "~/lib/utils";
|
||||||
import { Button } from "../ui";
|
import { Button } from "../ui";
|
||||||
|
|
||||||
@ -40,10 +40,13 @@ type ConversationListResponse = {
|
|||||||
|
|
||||||
export const ConversationList = ({
|
export const ConversationList = ({
|
||||||
currentConversationId,
|
currentConversationId,
|
||||||
|
showNewConversationCTA,
|
||||||
}: {
|
}: {
|
||||||
currentConversationId?: string;
|
currentConversationId?: string;
|
||||||
|
showNewConversationCTA?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const fetcher = useFetcher<ConversationListResponse>();
|
const fetcher = useFetcher<ConversationListResponse>();
|
||||||
|
const navigate = useNavigate();
|
||||||
const [conversations, setConversations] = useState<ConversationItem[]>([]);
|
const [conversations, setConversations] = useState<ConversationItem[]>([]);
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const [hasNextPage, setHasNextPage] = useState(true);
|
const [hasNextPage, setHasNextPage] = useState(true);
|
||||||
@ -155,7 +158,7 @@ export const ConversationList = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={key} style={style}>
|
<div key={key} style={style}>
|
||||||
<div className="p-2">
|
<div className="p-1">
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
className={cn(
|
className={cn(
|
||||||
@ -194,6 +197,19 @@ export const ConversationList = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full flex-col">
|
||||||
|
{showNewConversationCTA && (
|
||||||
|
<div className="flex items-center justify-start p-1 pb-0">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
className="w-full justify-start gap-2 py-4"
|
||||||
|
onClick={() => {
|
||||||
|
navigate("/home/conversation");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Plus size={14} /> New conversation
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{/* <div className="border-b">
|
{/* <div className="border-b">
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
@ -43,9 +43,7 @@ export function ConversationTextarea({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = isLoading
|
const data = isLoading ? {} : { message: text, conversationId };
|
||||||
? {}
|
|
||||||
: { message: text, title: text, conversationId };
|
|
||||||
|
|
||||||
submit(data as any, {
|
submit(data as any, {
|
||||||
action: isLoading
|
action: isLoading
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { EditorRoot, EditorContent, Placeholder } from "novel";
|
import { EditorRoot, EditorContent, Placeholder } from "novel";
|
||||||
import { useState, useRef, useCallback } from "react";
|
import { useState, useRef, useCallback } from "react";
|
||||||
import { Form, useNavigate, useSubmit } from "@remix-run/react";
|
import { Form, useSubmit } from "@remix-run/react";
|
||||||
import { cn } from "~/lib/utils";
|
import { cn } from "~/lib/utils";
|
||||||
import { Document } from "@tiptap/extension-document";
|
import { Document } from "@tiptap/extension-document";
|
||||||
import HardBreak from "@tiptap/extension-hard-break";
|
import HardBreak from "@tiptap/extension-hard-break";
|
||||||
@ -21,6 +21,7 @@ export const ConversationNew = ({
|
|||||||
user: { name: string | null };
|
user: { name: string | null };
|
||||||
}) => {
|
}) => {
|
||||||
const [content, setContent] = useState("");
|
const [content, setContent] = useState("");
|
||||||
|
const [title, setTitle] = useState("");
|
||||||
const editorRef = useRef<any>(null);
|
const editorRef = useRef<any>(null);
|
||||||
|
|
||||||
const submit = useSubmit();
|
const submit = useSubmit();
|
||||||
@ -31,13 +32,15 @@ export const ConversationNew = ({
|
|||||||
if (!content.trim()) return;
|
if (!content.trim()) return;
|
||||||
|
|
||||||
submit(
|
submit(
|
||||||
{ message: content, title: content },
|
{ message: content, title },
|
||||||
{
|
{
|
||||||
action: "/home/conversation",
|
action: "/home/conversation",
|
||||||
method: "post",
|
method: "post",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
setContent("");
|
||||||
|
setTitle("");
|
||||||
},
|
},
|
||||||
[content],
|
[content],
|
||||||
);
|
);
|
||||||
@ -71,9 +74,13 @@ export const ConversationNew = ({
|
|||||||
<div className="flex h-full w-full flex-col items-start justify-start overflow-y-auto p-4">
|
<div className="flex h-full w-full flex-col items-start justify-start overflow-y-auto p-4">
|
||||||
<div className="flex w-full flex-col items-center">
|
<div className="flex w-full flex-col items-center">
|
||||||
<div className="w-full max-w-[90ch]">
|
<div className="w-full max-w-[90ch]">
|
||||||
<h1 className="mx-1 mb-4 text-left text-[32px] font-medium">
|
<h1 className="mx-1 text-left text-[32px] font-medium">
|
||||||
Hello <span className="text-primary">{user.name}</span>
|
Hello <span className="text-primary">{user.name}</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
<p className="text-muted-foreground mx-1 mb-4">
|
||||||
|
Demo UI: basic conversation to showcase memory integration.
|
||||||
|
</p>
|
||||||
<div className="bg-background-3 border-border rounded-lg border-1 py-2">
|
<div className="bg-background-3 border-border rounded-lg border-1 py-2">
|
||||||
<EditorRoot>
|
<EditorRoot>
|
||||||
<EditorContent
|
<EditorContent
|
||||||
@ -82,7 +89,7 @@ export const ConversationNew = ({
|
|||||||
extensions={[
|
extensions={[
|
||||||
Placeholder.configure({
|
Placeholder.configure({
|
||||||
placeholder: () => {
|
placeholder: () => {
|
||||||
return "Ask sol...";
|
return "Ask CORE...";
|
||||||
},
|
},
|
||||||
includeChildren: true,
|
includeChildren: true,
|
||||||
}),
|
}),
|
||||||
@ -113,6 +120,7 @@ export const ConversationNew = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
setContent("");
|
setContent("");
|
||||||
|
setTitle("");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -125,7 +133,9 @@ export const ConversationNew = ({
|
|||||||
)}
|
)}
|
||||||
onUpdate={({ editor }: { editor: any }) => {
|
onUpdate={({ editor }: { editor: any }) => {
|
||||||
const html = editor.getHTML();
|
const html = editor.getHTML();
|
||||||
|
const text = editor.getText();
|
||||||
setContent(html);
|
setContent(html);
|
||||||
|
setTitle(text);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</EditorRoot>
|
</EditorRoot>
|
||||||
|
|||||||
148
apps/webapp/app/components/conversation/editor-extensions.tsx
Normal file
148
apps/webapp/app/components/conversation/editor-extensions.tsx
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import { cx } from "class-variance-authority";
|
||||||
|
import {
|
||||||
|
StarterKit,
|
||||||
|
TiptapLink,
|
||||||
|
HorizontalRule,
|
||||||
|
Placeholder,
|
||||||
|
HighlightExtension,
|
||||||
|
AIHighlight,
|
||||||
|
} from "novel";
|
||||||
|
|
||||||
|
import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
|
||||||
|
import Heading from "@tiptap/extension-heading";
|
||||||
|
import Table from "@tiptap/extension-table";
|
||||||
|
import TableCell from "@tiptap/extension-table-cell";
|
||||||
|
import TableHeader from "@tiptap/extension-table-header";
|
||||||
|
import TableRow from "@tiptap/extension-table-row";
|
||||||
|
import { all, createLowlight } from "lowlight";
|
||||||
|
import { mergeAttributes, type Extension } from "@tiptap/react";
|
||||||
|
|
||||||
|
// create a lowlight instance with all languages loaded
|
||||||
|
export const lowlight = createLowlight(all);
|
||||||
|
|
||||||
|
const tiptapLink = TiptapLink.configure({
|
||||||
|
HTMLAttributes: {
|
||||||
|
class: cx("text-primary cursor-pointer"),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const horizontalRule = HorizontalRule.configure({
|
||||||
|
HTMLAttributes: {
|
||||||
|
class: cx("my-2 border-t border-muted-foreground"),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const heading = Heading.extend({
|
||||||
|
renderHTML({ node, HTMLAttributes }) {
|
||||||
|
const hasLevel = this.options.levels.includes(node.attrs.level);
|
||||||
|
const level: 1 | 2 | 3 = hasLevel
|
||||||
|
? node.attrs.level
|
||||||
|
: this.options.levels[0];
|
||||||
|
const levelMap = { 1: "text-2xl", 2: "text-xl", 3: "text-lg" };
|
||||||
|
|
||||||
|
return [
|
||||||
|
`h${level}`,
|
||||||
|
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
|
||||||
|
class: `heading-node h${node.attrs.level}-style ${levelMap[level]} my-[1rem] font-medium`,
|
||||||
|
}),
|
||||||
|
0,
|
||||||
|
];
|
||||||
|
},
|
||||||
|
}).configure({ levels: [1, 2, 3] });
|
||||||
|
|
||||||
|
const defaultPlaceholder = Placeholder.configure({
|
||||||
|
placeholder: ({ node }) => {
|
||||||
|
if (node.type.name === "heading") {
|
||||||
|
return `Heading ${node.attrs.level}`;
|
||||||
|
}
|
||||||
|
if (node.type.name === "image" || node.type.name === "table") {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (node.type.name === "codeBlock") {
|
||||||
|
return "Type in your code here...";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
includeChildren: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getPlaceholder = (placeholder: string | Extension) => {
|
||||||
|
if (!placeholder) {
|
||||||
|
return defaultPlaceholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof placeholder === "string") {
|
||||||
|
return Placeholder.configure({
|
||||||
|
placeholder: () => {
|
||||||
|
return placeholder;
|
||||||
|
},
|
||||||
|
includeChildren: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return placeholder;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const starterKit = StarterKit.configure({
|
||||||
|
heading: false,
|
||||||
|
history: false,
|
||||||
|
bulletList: {
|
||||||
|
HTMLAttributes: {
|
||||||
|
class: cx("list-disc list-outside pl-4 leading-1 my-1 mb-1.5"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
orderedList: {
|
||||||
|
HTMLAttributes: {
|
||||||
|
class: cx("list-decimal list-outside pl-4 leading-1 my-1"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
listItem: {
|
||||||
|
HTMLAttributes: {
|
||||||
|
class: cx("mt-1.5"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
blockquote: {
|
||||||
|
HTMLAttributes: {
|
||||||
|
class: cx("border-l-4 border-gray-400 dark:border-gray-500"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
paragraph: {
|
||||||
|
HTMLAttributes: {
|
||||||
|
class: cx("leading-[24px] mt-[1rem] paragraph-node"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
codeBlock: false,
|
||||||
|
code: {
|
||||||
|
HTMLAttributes: {
|
||||||
|
class: cx(
|
||||||
|
"rounded bg-grayAlpha-100 text-[#BF4594] px-1.5 py-1 font-mono font-medium border-none",
|
||||||
|
),
|
||||||
|
spellcheck: "false",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
horizontalRule: false,
|
||||||
|
dropcursor: {
|
||||||
|
color: "#DBEAFE",
|
||||||
|
width: 4,
|
||||||
|
},
|
||||||
|
gapcursor: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const extensionsForConversation = [
|
||||||
|
starterKit,
|
||||||
|
tiptapLink,
|
||||||
|
horizontalRule,
|
||||||
|
heading,
|
||||||
|
AIHighlight,
|
||||||
|
HighlightExtension,
|
||||||
|
Table.configure({
|
||||||
|
resizable: true,
|
||||||
|
}),
|
||||||
|
TableRow,
|
||||||
|
TableHeader,
|
||||||
|
TableCell,
|
||||||
|
CodeBlockLowlight.configure({
|
||||||
|
lowlight,
|
||||||
|
}),
|
||||||
|
];
|
||||||
@ -1,13 +1,8 @@
|
|||||||
import { EditorContent, useEditor } from "@tiptap/react";
|
import { EditorContent, useEditor } from "@tiptap/react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Document } from "@tiptap/extension-document";
|
|
||||||
import HardBreak from "@tiptap/extension-hard-break";
|
|
||||||
import { History } from "@tiptap/extension-history";
|
|
||||||
import { Paragraph } from "@tiptap/extension-paragraph";
|
|
||||||
import { Text } from "@tiptap/extension-text";
|
|
||||||
|
|
||||||
import { useTriggerStream } from "./use-trigger-stream";
|
import { useTriggerStream } from "./use-trigger-stream";
|
||||||
import { Placeholder } from "novel";
|
import { extensionsForConversation } from "./editor-extensions";
|
||||||
|
|
||||||
interface StreamingConversationProps {
|
interface StreamingConversationProps {
|
||||||
runId: string;
|
runId: string;
|
||||||
@ -41,15 +36,7 @@ export const StreamingConversation = ({
|
|||||||
];
|
];
|
||||||
|
|
||||||
const messagesEditor = useEditor({
|
const messagesEditor = useEditor({
|
||||||
extensions: [
|
extensions: [...extensionsForConversation],
|
||||||
Placeholder,
|
|
||||||
Document,
|
|
||||||
Paragraph,
|
|
||||||
Text,
|
|
||||||
HardBreak.configure({
|
|
||||||
keepMarks: true,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
editable: false,
|
editable: false,
|
||||||
content: "",
|
content: "",
|
||||||
});
|
});
|
||||||
@ -94,7 +81,7 @@ export const StreamingConversation = ({
|
|||||||
{message ? (
|
{message ? (
|
||||||
<EditorContent
|
<EditorContent
|
||||||
editor={messagesEditor}
|
editor={messagesEditor}
|
||||||
className="text-foreground"
|
className="text-foreground editor-container"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="text-foreground italic">{loadingText}</div>
|
<div className="text-foreground italic">{loadingText}</div>
|
||||||
|
|||||||
@ -179,7 +179,8 @@ export const Graph = forwardRef<GraphRef, GraphProps>(
|
|||||||
relations: [],
|
relations: [],
|
||||||
relationData: [],
|
relationData: [],
|
||||||
label: "",
|
label: "",
|
||||||
color: theme.link.stroke,
|
color: "#0000001A",
|
||||||
|
labelColor: "#0000001A",
|
||||||
size: 1,
|
size: 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { LLMMappings, LLMModelEnum } from "@core/types";
|
|||||||
import {
|
import {
|
||||||
type CoreMessage,
|
type CoreMessage,
|
||||||
type LanguageModelV1,
|
type LanguageModelV1,
|
||||||
|
embed,
|
||||||
generateText,
|
generateText,
|
||||||
streamText,
|
streamText,
|
||||||
} from "ai";
|
} from "ai";
|
||||||
@ -77,3 +78,29 @@ export async function makeModelCall(
|
|||||||
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getEmbedding(text: string) {
|
||||||
|
const ollamaUrl = env.OLLAMA_URL;
|
||||||
|
|
||||||
|
if (!ollamaUrl) {
|
||||||
|
// Use OpenAI embedding model when explicitly requested
|
||||||
|
const { embedding } = await embed({
|
||||||
|
model: openai.embedding("text-embedding-3-small"),
|
||||||
|
value: text,
|
||||||
|
});
|
||||||
|
return embedding;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to using Ollama
|
||||||
|
const model = env.EMBEDDING_MODEL;
|
||||||
|
|
||||||
|
const ollama = createOllama({
|
||||||
|
baseURL: ollamaUrl,
|
||||||
|
});
|
||||||
|
const { embedding } = await embed({
|
||||||
|
model: ollama.embedding(model),
|
||||||
|
value: text,
|
||||||
|
});
|
||||||
|
|
||||||
|
return embedding;
|
||||||
|
}
|
||||||
|
|||||||
@ -138,7 +138,10 @@ export default function SingleConversation() {
|
|||||||
collapsedSize={16}
|
collapsedSize={16}
|
||||||
className="border-border h-[calc(100vh_-_60px)] min-w-[200px] border-r-1"
|
className="border-border h-[calc(100vh_-_60px)] min-w-[200px] border-r-1"
|
||||||
>
|
>
|
||||||
<ConversationList currentConversationId={conversationId} />
|
<ConversationList
|
||||||
|
currentConversationId={conversationId}
|
||||||
|
showNewConversationCTA
|
||||||
|
/>
|
||||||
</ResizablePanel>
|
</ResizablePanel>
|
||||||
<ResizableHandle className="w-1" />
|
<ResizableHandle className="w-1" />
|
||||||
|
|
||||||
|
|||||||
@ -41,8 +41,8 @@ export default function Home() {
|
|||||||
<SidebarInset className="bg-background h-[100vh] py-2 pr-2">
|
<SidebarInset className="bg-background h-[100vh] py-2 pr-2">
|
||||||
<div className="bg-background-2 h-full rounded-md">
|
<div className="bg-background-2 h-full rounded-md">
|
||||||
<SiteHeader />
|
<SiteHeader />
|
||||||
<div className="flex flex-1 flex-col">
|
<div className="flex h-[calc(100vh_-_60px)] flex-col">
|
||||||
<div className="@container/main flex flex-1 flex-col gap-2">
|
<div className="@container/main flex h-full flex-col gap-2">
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full flex-col">
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { openai } from "@ai-sdk/openai";
|
import { type CoreMessage } from "ai";
|
||||||
import { type CoreMessage, embed } from "ai";
|
|
||||||
import {
|
import {
|
||||||
type AddEpisodeParams,
|
type AddEpisodeParams,
|
||||||
type EntityNode,
|
type EntityNode,
|
||||||
@ -35,39 +34,16 @@ import {
|
|||||||
saveTriple,
|
saveTriple,
|
||||||
searchStatementsByEmbedding,
|
searchStatementsByEmbedding,
|
||||||
} from "./graphModels/statement";
|
} from "./graphModels/statement";
|
||||||
import { makeModelCall } from "~/lib/model.server";
|
import { getEmbedding, makeModelCall } from "~/lib/model.server";
|
||||||
import { Apps, getNodeTypes, getNodeTypesString } from "~/utils/presets/nodes";
|
import { Apps, getNodeTypes, getNodeTypesString } from "~/utils/presets/nodes";
|
||||||
import { normalizePrompt } from "./prompts";
|
import { normalizePrompt } from "./prompts";
|
||||||
import { env } from "~/env.server";
|
|
||||||
import { createOllama } from "ollama-ai-provider";
|
|
||||||
|
|
||||||
// Default number of previous episodes to retrieve for context
|
// Default number of previous episodes to retrieve for context
|
||||||
const DEFAULT_EPISODE_WINDOW = 5;
|
const DEFAULT_EPISODE_WINDOW = 5;
|
||||||
|
|
||||||
export class KnowledgeGraphService {
|
export class KnowledgeGraphService {
|
||||||
async getEmbedding(text: string, useOpenAI = false) {
|
async getEmbedding(text: string) {
|
||||||
if (useOpenAI) {
|
return getEmbedding(text);
|
||||||
// Use OpenAI embedding model when explicitly requested
|
|
||||||
const { embedding } = await embed({
|
|
||||||
model: openai.embedding("text-embedding-3-small"),
|
|
||||||
value: text,
|
|
||||||
});
|
|
||||||
return embedding;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default to using Ollama
|
|
||||||
const ollamaUrl = env.OLLAMA_URL;
|
|
||||||
const model = env.EMBEDDING_MODEL;
|
|
||||||
|
|
||||||
const ollama = createOllama({
|
|
||||||
baseURL: ollamaUrl,
|
|
||||||
});
|
|
||||||
const { embedding } = await embed({
|
|
||||||
model: ollama.embedding(model),
|
|
||||||
value: text,
|
|
||||||
});
|
|
||||||
|
|
||||||
return embedding;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
import { openai } from "@ai-sdk/openai";
|
|
||||||
import type { StatementNode } from "@core/types";
|
import type { StatementNode } from "@core/types";
|
||||||
import { embed } from "ai";
|
|
||||||
import { logger } from "./logger.service";
|
import { logger } from "./logger.service";
|
||||||
import { applyCrossEncoderReranking, applyWeightedRRF } from "./search/rerank";
|
import { applyCrossEncoderReranking, applyWeightedRRF } from "./search/rerank";
|
||||||
import {
|
import {
|
||||||
@ -9,6 +7,7 @@ import {
|
|||||||
performBM25Search,
|
performBM25Search,
|
||||||
performVectorSearch,
|
performVectorSearch,
|
||||||
} from "./search/utils";
|
} from "./search/utils";
|
||||||
|
import { getEmbedding } from "~/lib/model.server";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SearchService provides methods to search the reified + temporal knowledge graph
|
* SearchService provides methods to search the reified + temporal knowledge graph
|
||||||
@ -16,12 +15,7 @@ import {
|
|||||||
*/
|
*/
|
||||||
export class SearchService {
|
export class SearchService {
|
||||||
async getEmbedding(text: string) {
|
async getEmbedding(text: string) {
|
||||||
const { embedding } = await embed({
|
return getEmbedding(text);
|
||||||
model: openai.embedding("text-embedding-3-small"),
|
|
||||||
value: text,
|
|
||||||
});
|
|
||||||
|
|
||||||
return embedding;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -363,8 +363,107 @@
|
|||||||
@apply text-base;
|
@apply text-base;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.is-editor-empty {
|
p.is-editor-empty:before {
|
||||||
|
@apply text-muted-foreground;
|
||||||
|
|
||||||
font-size: 14px !important;
|
font-size: 14px !important;
|
||||||
|
content: attr(data-placeholder);
|
||||||
|
float: left;
|
||||||
|
height: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.title-bar-sigma {
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-webkit-app-region: drag;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick .header {
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-webkit-app-region: drag;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container p {
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container .heading-node:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container .paragraph-node:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item--task {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tasks-component ul {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ProseMirror:not(.dragging) .ProseMirror-selectednode {
|
||||||
|
@apply bg-grayAlpha-100;
|
||||||
|
|
||||||
|
outline: none !important;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ProseMirror:not(.dragging) .ProseMirror-selectednode.node-skill {
|
||||||
|
@apply !bg-transparent !pt-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prosemirror-dropcursor-block {
|
||||||
|
@apply !bg-primary/50;
|
||||||
|
height: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-handle {
|
||||||
|
position: fixed;
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity ease-in 0.2s;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' style='fill: rgba(0, 0, 0, 0.5)'%3E%3Cpath d='M3,2 C2.44771525,2 2,1.55228475 2,1 C2,0.44771525 2.44771525,0 3,0 C3.55228475,0 4,0.44771525 4,1 C4,1.55228475 3.55228475,2 3,2 Z M3,6 C2.44771525,6 2,5.55228475 2,5 C2,4.44771525 2.44771525,4 3,4 C3.55228475,4 4,4.44771525 4,5 C4,5.55228475 3.55228475,6 3,6 Z M3,10 C2.44771525,10 2,9.55228475 2,9 C2,8.44771525 2.44771525,8 3,8 C3.55228475,8 4,8.44771525 4,9 C4,9.55228475 3.55228475,10 3,10 Z M7,2 C6.44771525,2 6,1.55228475 6,1 C6,0.44771525 6.44771525,0 7,0 C7.55228475,0 8,0.44771525 8,1 C8,1.55228475 7.55228475,2 7,2 Z M7,6 C6.44771525,6 6,5.55228475 6,5 C6,4.44771525 6.44771525,4 7,4 C7.55228475,4 8,4.44771525 8,5 C8,5.55228475 7.55228475,6 7,6 Z M7,10 C6.44771525,10 6,9.55228475 6,9 C6,8.44771525 6.44771525,8 7,8 C7.55228475,8 8,8.44771525 8,9 C8,9.55228475 7.55228475,10 7,10 Z'%3E%3C/path%3E%3C/svg%3E");
|
||||||
|
background-size: calc(0.5em + 0.375rem) calc(0.5em + 0.375rem);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
width: 1.2rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
z-index: 50;
|
||||||
|
cursor: grab;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--novel-stone-100);
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: var(--novel-stone-200);
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.hide {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
display: none;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .drag-handle {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' style='fill: rgba(255,255,255, 0.5)'%3E%3Cpath d='M3,2 C2.44771525,2 2,1.55228475 2,1 C2,0.44771525 2.44771525,0 3,0 C3.55228475,0 4,0.44771525 4,1 C4,1.55228475 3.55228475,2 3,2 Z M3,6 C2.44771525,6 2,5.55228475 2,5 C2,4.44771525 2.44771525,4 3,4 C3.55228475,4 4,4.44771525 4,5 C4,5.55228475 3.55228475,6 3,6 Z M3,10 C2.44771525,10 2,9.55228475 2,9 C2,8.44771525 2.44771525,8 3,8 C3.55228475,8 4,8.44771525 4,9 C4,9.55228475 3.55228475,10 3,10 Z M7,2 C6.44771525,2 6,1.55228475 6,1 C6,0.44771525 6.44771525,0 7,0 C7.55228475,0 8,0.44771525 8,1 C8,1.55228475 7.55228475,2 7,2 Z M7,6 C6.44771525,6 6,5.55228475 6,5 C6,4.44771525 6.44771525,4 7,4 C7.55228475,4 8,4.44771525 8,5 C8,5.55228475 7.55228475,6 7,6 Z M7,10 C6.44771525,10 6,9.55228475 6,9 C6,8.44771525 6.44771525,8 7,8 C7.55228475,8 8,8.44771525 8,9 C8,9.55228475 7.55228475,10 7,10 Z'%3E%3C/path%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ export const createConversationTitle = task({
|
|||||||
() => {},
|
() => {},
|
||||||
undefined,
|
undefined,
|
||||||
"",
|
"",
|
||||||
LLMMappings.CLAUDESONNET,
|
LLMMappings.GPT41,
|
||||||
);
|
);
|
||||||
|
|
||||||
for await (const chunk of gen) {
|
for await (const chunk of gen) {
|
||||||
|
|||||||
@ -59,6 +59,13 @@
|
|||||||
"@tiptap/extension-history": "^2.11.9",
|
"@tiptap/extension-history": "^2.11.9",
|
||||||
"@tiptap/extension-paragraph": "^2.11.9",
|
"@tiptap/extension-paragraph": "^2.11.9",
|
||||||
"@tiptap/extension-text": "^2.11.9",
|
"@tiptap/extension-text": "^2.11.9",
|
||||||
|
"@tiptap/extension-table": "2.11.9",
|
||||||
|
"@tiptap/extension-table-cell": "2.11.9",
|
||||||
|
"@tiptap/extension-heading": "2.11.9",
|
||||||
|
"@tiptap/extension-table-header": "2.11.9",
|
||||||
|
"@tiptap/extension-table-row": "2.11.9",
|
||||||
|
"@tiptap/extension-code-block": "2.11.9",
|
||||||
|
"@tiptap/extension-code-block-lowlight": "^2.11.9",
|
||||||
"@tiptap/starter-kit": "2.11.9",
|
"@tiptap/starter-kit": "2.11.9",
|
||||||
"@tiptap/react": "^2.11.9",
|
"@tiptap/react": "^2.11.9",
|
||||||
"@tiptap/pm": "^2.11.9",
|
"@tiptap/pm": "^2.11.9",
|
||||||
@ -89,6 +96,7 @@
|
|||||||
"isbot": "^4.1.0",
|
"isbot": "^4.1.0",
|
||||||
"jose": "^5.2.3",
|
"jose": "^5.2.3",
|
||||||
"lucide-react": "^0.511.0",
|
"lucide-react": "^0.511.0",
|
||||||
|
"lowlight": "^3.3.0",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"nanoid": "3.3.8",
|
"nanoid": "3.3.8",
|
||||||
"neo4j-driver": "^5.28.1",
|
"neo4j-driver": "^5.28.1",
|
||||||
|
|||||||
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@echo/core-types",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "Core types for Echo integrations",
|
|
||||||
"main": "dist/index.js",
|
|
||||||
"types": "dist/index.d.ts",
|
|
||||||
"scripts": {
|
|
||||||
"build": "tsc",
|
|
||||||
"dev": "tsc --watch"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"typescript": "^5.0.0"
|
|
||||||
},
|
|
||||||
"exports": {
|
|
||||||
".": {
|
|
||||||
"import": "./dist/index.js",
|
|
||||||
"require": "./dist/index.js",
|
|
||||||
"types": "./dist/index.d.ts"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export * from './integration';
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
export enum IntegrationEventType {
|
|
||||||
/**
|
|
||||||
* Setting up or creating an integration account
|
|
||||||
*/
|
|
||||||
SETUP = "setup",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processing incoming data from the integration
|
|
||||||
*/
|
|
||||||
PROCESS = "process",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Identifying which account a webhook belongs to
|
|
||||||
*/
|
|
||||||
IDENTIFY = "identify",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scheduled synchronization of data
|
|
||||||
*/
|
|
||||||
SYNC = "sync",
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IntegrationEventPayload {
|
|
||||||
event: IntegrationEventType;
|
|
||||||
[x: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Spec {
|
|
||||||
name: string;
|
|
||||||
key: string;
|
|
||||||
description: string;
|
|
||||||
icon: string;
|
|
||||||
mcp?: {
|
|
||||||
command: string;
|
|
||||||
args: string[];
|
|
||||||
env: Record<string, string>;
|
|
||||||
};
|
|
||||||
auth?: {
|
|
||||||
OAuth2?: {
|
|
||||||
token_url: string;
|
|
||||||
authorization_url: string;
|
|
||||||
scopes: string[];
|
|
||||||
scope_identifier?: string;
|
|
||||||
scope_separator?: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Config {
|
|
||||||
access_token: string;
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Identifier {
|
|
||||||
id: string;
|
|
||||||
type?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MessageType = 'spec' | 'data' | 'identifier';
|
|
||||||
|
|
||||||
export interface Message {
|
|
||||||
type: MessageType;
|
|
||||||
data: any;
|
|
||||||
}
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "ES2020",
|
|
||||||
"module": "ESNext",
|
|
||||||
"lib": ["ES2020"],
|
|
||||||
"declaration": true,
|
|
||||||
"outDir": "./dist",
|
|
||||||
"rootDir": "./src",
|
|
||||||
"strict": true,
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"resolveJsonModule": true
|
|
||||||
},
|
|
||||||
"include": ["src/**/*", "*.ts"],
|
|
||||||
"exclude": ["node_modules", "dist"]
|
|
||||||
}
|
|
||||||
1
integrations/slack/.gitignore
vendored
1
integrations/slack/.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
bin
|
bin
|
||||||
node_modules
|
node_modules
|
||||||
|
|
||||||
|
|||||||
@ -66,6 +66,6 @@
|
|||||||
"commander": "^12.0.0",
|
"commander": "^12.0.0",
|
||||||
"openai": "^4.0.0",
|
"openai": "^4.0.0",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"@echo/core-types": "workspace:*"
|
"@redplanethq/sdk": "0.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
17
integrations/slack/pnpm-lock.yaml
generated
17
integrations/slack/pnpm-lock.yaml
generated
@ -8,6 +8,9 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@redplanethq/sdk':
|
||||||
|
specifier: 0.1.0
|
||||||
|
version: 0.1.0
|
||||||
axios:
|
axios:
|
||||||
specifier: ^1.7.9
|
specifier: ^1.7.9
|
||||||
version: 1.9.0
|
version: 1.9.0
|
||||||
@ -489,6 +492,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==}
|
resolution: {integrity: sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==}
|
||||||
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
|
||||||
|
|
||||||
|
'@redplanethq/sdk@0.1.0':
|
||||||
|
resolution: {integrity: sha512-RmPfT9XESjTSMLlAMkolZEF28PvGo5hlwrG75JQy1tAZkvaTHzC7A2mEAMbsBvOMrJuUztL3NtCmVF//C/C/+A==}
|
||||||
|
engines: {node: '>=18.0.0'}
|
||||||
|
|
||||||
'@rollup/plugin-commonjs@28.0.3':
|
'@rollup/plugin-commonjs@28.0.3':
|
||||||
resolution: {integrity: sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ==}
|
resolution: {integrity: sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ==}
|
||||||
engines: {node: '>=16.0.0 || 14 >= 14.17'}
|
engines: {node: '>=16.0.0 || 14 >= 14.17'}
|
||||||
@ -901,6 +908,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
|
resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
commander@14.0.0:
|
||||||
|
resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==}
|
||||||
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
commander@2.20.3:
|
commander@2.20.3:
|
||||||
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
||||||
|
|
||||||
@ -2894,6 +2905,10 @@ snapshots:
|
|||||||
|
|
||||||
'@pkgr/core@0.2.4': {}
|
'@pkgr/core@0.2.4': {}
|
||||||
|
|
||||||
|
'@redplanethq/sdk@0.1.0':
|
||||||
|
dependencies:
|
||||||
|
commander: 14.0.0
|
||||||
|
|
||||||
'@rollup/plugin-commonjs@28.0.3(rollup@4.40.2)':
|
'@rollup/plugin-commonjs@28.0.3(rollup@4.40.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rollup/pluginutils': 5.1.4(rollup@4.40.2)
|
'@rollup/pluginutils': 5.1.4(rollup@4.40.2)
|
||||||
@ -3320,6 +3335,8 @@ snapshots:
|
|||||||
|
|
||||||
commander@12.1.0: {}
|
commander@12.1.0: {}
|
||||||
|
|
||||||
|
commander@14.0.0: {}
|
||||||
|
|
||||||
commander@2.20.3: {}
|
commander@2.20.3: {}
|
||||||
|
|
||||||
commander@4.1.1: {}
|
commander@4.1.1: {}
|
||||||
|
|||||||
@ -1,65 +0,0 @@
|
|||||||
# IntegrationCLI Base Class
|
|
||||||
|
|
||||||
This is a common CLI base class that can be moved to the SDK and used by all integrations.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### 1. Create your integration-specific CLI class:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { IntegrationCLI, IntegrationEventPayload } from './common/IntegrationCLI';
|
|
||||||
|
|
||||||
export class MyIntegrationCLI extends IntegrationCLI {
|
|
||||||
constructor() {
|
|
||||||
super('my-integration', '1.0.0');
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async handleEvent(eventPayload: IntegrationEventPayload): Promise<any> {
|
|
||||||
// Your integration-specific logic here
|
|
||||||
return await processMyIntegrationEvent(eventPayload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Create your CLI entry point:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
import { MyIntegrationCLI } from './MyIntegrationCLI';
|
|
||||||
|
|
||||||
const cli = new MyIntegrationCLI();
|
|
||||||
cli.parse();
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Update your package.json:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"bin": {
|
|
||||||
"my-integration": "./dist/cli.js"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"commander": "^12.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Available Commands
|
|
||||||
|
|
||||||
The base class provides these commands automatically:
|
|
||||||
|
|
||||||
- `account create --oauth-response <json> --integration-definition <json>`
|
|
||||||
- `account delete --account-id <id>`
|
|
||||||
- `process --event-data <json> --integration-account <json>`
|
|
||||||
- `identify --webhook-data <json>`
|
|
||||||
- `sync --integration-account <json>`
|
|
||||||
|
|
||||||
## Moving to SDK
|
|
||||||
|
|
||||||
To move this to the SDK:
|
|
||||||
|
|
||||||
1. Move `IntegrationCLI.ts` to `@redplanethq/sol-sdk/src/cli/`
|
|
||||||
2. Export it from the SDK's index
|
|
||||||
3. Update imports in integrations to use the SDK version
|
|
||||||
4. Add commander as a dependency to the SDK
|
|
||||||
@ -2,23 +2,24 @@
|
|||||||
|
|
||||||
import { integrationCreate } from './account-create';
|
import { integrationCreate } from './account-create';
|
||||||
import { createActivityEvent } from './create-activity';
|
import { createActivityEvent } from './create-activity';
|
||||||
import { IntegrationCLI } from './common/IntegrationCLI';
|
import {
|
||||||
import { IntegrationEventPayload, Spec } from '@echo/core-types';
|
IntegrationCLI,
|
||||||
|
IntegrationEventPayload,
|
||||||
|
IntegrationEventType,
|
||||||
|
Spec,
|
||||||
|
} from '@redplanethq/sdk';
|
||||||
|
|
||||||
export async function run(eventPayload: IntegrationEventPayload) {
|
export async function run(eventPayload: IntegrationEventPayload) {
|
||||||
switch (eventPayload.event) {
|
switch (eventPayload.event) {
|
||||||
case 'SETUP':
|
case IntegrationEventType.SETUP:
|
||||||
return await integrationCreate(eventPayload.eventBody, eventPayload.integrationDefinition);
|
return await integrationCreate(eventPayload.eventBody, eventPayload.integrationDefinition);
|
||||||
|
|
||||||
case 'IDENTIFY':
|
case IntegrationEventType.IDENTIFY:
|
||||||
return eventPayload.eventBody.event.user;
|
return eventPayload.eventBody.event.user;
|
||||||
|
|
||||||
case 'PROCESS':
|
case IntegrationEventType.PROCESS:
|
||||||
return createActivityEvent(eventPayload.eventBody, eventPayload.config);
|
return createActivityEvent(eventPayload.eventBody, eventPayload.config);
|
||||||
|
|
||||||
case 'SYNC':
|
|
||||||
return { message: 'Scheduled sync completed successfully' };
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
message: `The event payload type is ${eventPayload.event}`,
|
message: `The event payload type is ${eventPayload.event}`,
|
||||||
@ -38,45 +39,45 @@ class SlackCLI extends IntegrationCLI {
|
|||||||
|
|
||||||
protected async getSpec(): Promise<Spec> {
|
protected async getSpec(): Promise<Spec> {
|
||||||
return {
|
return {
|
||||||
name: "Slack extension",
|
name: 'Slack extension',
|
||||||
key: "slack",
|
key: 'slack',
|
||||||
description: "Connect your workspace to Slack. Run your workflows from slack bookmarks",
|
description: 'Connect your workspace to Slack. Run your workflows from slack bookmarks',
|
||||||
icon: "slack",
|
icon: 'slack',
|
||||||
mcp: {
|
mcp: {
|
||||||
command: "npx",
|
command: 'npx',
|
||||||
args: ["-y", "@modelcontextprotocol/server-slack"],
|
args: ['-y', '@modelcontextprotocol/server-slack'],
|
||||||
env: {
|
env: {
|
||||||
"SLACK_BOT_TOKEN": "${config:access_token}",
|
SLACK_BOT_TOKEN: '${config:access_token}',
|
||||||
"SLACK_TEAM_ID": "${config:team_id}",
|
SLACK_TEAM_ID: '${config:team_id}',
|
||||||
"SLACK_CHANNEL_IDS": "${config:channel_ids}"
|
SLACK_CHANNEL_IDS: '${config:channel_ids}',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
auth: {
|
auth: {
|
||||||
OAuth2: {
|
OAuth2: {
|
||||||
token_url: "https://slack.com/api/oauth.v2.access",
|
token_url: 'https://slack.com/api/oauth.v2.access',
|
||||||
authorization_url: "https://slack.com/oauth/v2/authorize",
|
authorization_url: 'https://slack.com/oauth/v2/authorize',
|
||||||
scopes: [
|
scopes: [
|
||||||
"stars:read",
|
'stars:read',
|
||||||
"team:read",
|
'team:read',
|
||||||
"stars:write",
|
'stars:write',
|
||||||
"users:read",
|
'users:read',
|
||||||
"channels:read",
|
'channels:read',
|
||||||
"groups:read",
|
'groups:read',
|
||||||
"im:read",
|
'im:read',
|
||||||
"im:history",
|
'im:history',
|
||||||
"mpim:read",
|
'mpim:read',
|
||||||
"mpim:write",
|
'mpim:write',
|
||||||
"mpim:history",
|
'mpim:history',
|
||||||
"channels:history",
|
'channels:history',
|
||||||
"chat:write",
|
'chat:write',
|
||||||
"reactions:read",
|
'reactions:read',
|
||||||
"reactions:write",
|
'reactions:write',
|
||||||
"users.profile:read"
|
'users.profile:read',
|
||||||
],
|
],
|
||||||
scope_identifier: "user_scope",
|
scope_identifier: 'user_scope',
|
||||||
scope_separator: ","
|
scope_separator: ',',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
203
packages/sdk/README.md
Normal file
203
packages/sdk/README.md
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
# Echo SDK
|
||||||
|
|
||||||
|
The Echo SDK provides tools and utilities for building integrations with the Echo platform.
|
||||||
|
|
||||||
|
## Integration System
|
||||||
|
|
||||||
|
The Echo integration system uses a CLI-based approach where each integration is a command-line tool that responds to specific events. This makes integrations portable, testable, and easy to debug.
|
||||||
|
|
||||||
|
### Integration Event Types
|
||||||
|
|
||||||
|
Each integration CLI handles 5 core event types:
|
||||||
|
|
||||||
|
#### 1. `spec`
|
||||||
|
Returns the integration's metadata and configuration.
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
```bash
|
||||||
|
my-integration spec
|
||||||
|
```
|
||||||
|
|
||||||
|
**Returns:** Integration specification including name, description, auth config, etc.
|
||||||
|
|
||||||
|
#### 2. `setup`
|
||||||
|
Processes authentication data and returns tokens/credentials to be saved.
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
```bash
|
||||||
|
my-integration setup --event-body '{"code":"oauth_code","state":"state"}' --integration-definition '{}'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Returns:** Configuration data (tokens, credentials) to be stored for the account.
|
||||||
|
|
||||||
|
#### 3. `identify`
|
||||||
|
Extracts accountId from webhook data to route webhooks to the correct account.
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
```bash
|
||||||
|
my-integration identify --webhook-data '{"team_id":"T123","event":{}}'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Returns:** Account identifier for webhook routing.
|
||||||
|
|
||||||
|
#### 4. `process`
|
||||||
|
Handles webhook events and returns activity data.
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
```bash
|
||||||
|
my-integration process --event-data '{"type":"reaction_added","reaction":"=M"}' --config '{"access_token":"token"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Returns:** Activity messages representing user actions.
|
||||||
|
|
||||||
|
#### 5. `sync`
|
||||||
|
Performs scheduled data synchronization for integrations that don't support webhooks.
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
```bash
|
||||||
|
my-integration sync --config '{"access_token":"token","last_sync":"2023-01-01T00:00:00Z"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Returns:** Activity messages and updated state for next sync.
|
||||||
|
|
||||||
|
### Message Types
|
||||||
|
|
||||||
|
All integration responses are wrapped in a `Message` object with a `type` field:
|
||||||
|
|
||||||
|
- **`spec`** - Integration metadata and configuration
|
||||||
|
- **`activity`** - User actions/events from the integration
|
||||||
|
- **`state`** - Sync state for polling integrations
|
||||||
|
- **`identifier`** - Account identification for webhook routing
|
||||||
|
|
||||||
|
### Building an Integration
|
||||||
|
|
||||||
|
1. **Install the SDK:**
|
||||||
|
```bash
|
||||||
|
npm install @echo/core-sdk
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Create your integration class:**
|
||||||
|
```typescript
|
||||||
|
import { IntegrationCLI } from '@echo/core-sdk';
|
||||||
|
|
||||||
|
class MyIntegration extends IntegrationCLI {
|
||||||
|
constructor() {
|
||||||
|
super('my-integration', '1.0.0');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async handleEvent(eventPayload: IntegrationEventPayload): Promise<any> {
|
||||||
|
switch (eventPayload.event) {
|
||||||
|
case 'SETUP':
|
||||||
|
return this.handleSetup(eventPayload);
|
||||||
|
case 'PROCESS':
|
||||||
|
return this.handleProcess(eventPayload);
|
||||||
|
case 'IDENTIFY':
|
||||||
|
return this.handleIdentify(eventPayload);
|
||||||
|
case 'SYNC':
|
||||||
|
return this.handleSync(eventPayload);
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown event type: ${eventPayload.event}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async getSpec(): Promise<Spec> {
|
||||||
|
return {
|
||||||
|
name: 'My Integration',
|
||||||
|
key: 'my-integration',
|
||||||
|
description: 'Integration with My Service',
|
||||||
|
icon: 'https://example.com/icon.png',
|
||||||
|
auth: {
|
||||||
|
OAuth2: {
|
||||||
|
token_url: 'https://api.example.com/oauth/token',
|
||||||
|
authorization_url: 'https://api.example.com/oauth/authorize',
|
||||||
|
scopes: ['read', 'write']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleSetup(eventPayload: IntegrationEventPayload): Promise<any> {
|
||||||
|
// Process OAuth response and return tokens to save
|
||||||
|
const { code } = eventPayload.eventBody;
|
||||||
|
// Exchange code for tokens...
|
||||||
|
return {
|
||||||
|
access_token: 'token',
|
||||||
|
refresh_token: 'refresh_token',
|
||||||
|
expires_at: Date.now() + 3600000
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleProcess(eventPayload: IntegrationEventPayload): Promise<any> {
|
||||||
|
// Handle webhook events
|
||||||
|
const { eventData } = eventPayload.eventBody;
|
||||||
|
// Process event and return activity...
|
||||||
|
return {
|
||||||
|
type: 'message',
|
||||||
|
user: 'user123',
|
||||||
|
content: 'Hello world',
|
||||||
|
timestamp: new Date()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleIdentify(eventPayload: IntegrationEventPayload): Promise<any> {
|
||||||
|
// Extract account ID from webhook
|
||||||
|
const { team_id } = eventPayload.eventBody;
|
||||||
|
return { id: team_id };
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleSync(eventPayload: IntegrationEventPayload): Promise<any> {
|
||||||
|
// Perform scheduled sync
|
||||||
|
const { config } = eventPayload;
|
||||||
|
// Fetch data since last sync...
|
||||||
|
return {
|
||||||
|
activities: [/* activity data */],
|
||||||
|
state: { last_sync: new Date().toISOString() }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CLI entry point
|
||||||
|
const integration = new MyIntegration();
|
||||||
|
integration.parse();
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Build and package your integration:**
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
npm pack
|
||||||
|
```
|
||||||
|
|
||||||
|
### Integration Development
|
||||||
|
|
||||||
|
The `IntegrationCLI` base class provides:
|
||||||
|
|
||||||
|
- **Automatic CLI setup** with all required commands
|
||||||
|
- **JSON input/output handling** for all event types
|
||||||
|
- **Error handling** with proper exit codes
|
||||||
|
- **Consistent message formatting** for all responses
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
Test your integration by running commands directly:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test spec
|
||||||
|
node dist/index.js spec
|
||||||
|
|
||||||
|
# Test setup
|
||||||
|
node dist/index.js setup --event-body '{"code":"test"}' --integration-definition '{}'
|
||||||
|
|
||||||
|
# Test webhook processing
|
||||||
|
node dist/index.js process --event-data '{"type":"test"}' --config '{"token":"test"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Best Practices
|
||||||
|
|
||||||
|
1. **Always validate input data** before processing
|
||||||
|
2. **Handle errors gracefully** with meaningful error messages
|
||||||
|
3. **Use consistent data structures** for activities
|
||||||
|
4. **Include proper timestamps** in all activity data
|
||||||
|
5. **Store minimal state** for sync operations
|
||||||
|
6. **Test all event types** thoroughly
|
||||||
|
|
||||||
|
For more examples, see the integrations in the `integrations/` directory.
|
||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@redplanethq/sol-sdk",
|
"name": "@redplanethq/sdk",
|
||||||
"version": "0.2.18",
|
"version": "0.1.0",
|
||||||
"description": "Sol Node.JS SDK",
|
"description": "CORE Node.JS SDK",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"module": "./dist/index.mjs",
|
"module": "./dist/index.mjs",
|
||||||
@ -29,6 +29,7 @@
|
|||||||
"typecheck": "tsc --noEmit"
|
"typecheck": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"commander": "14.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@core/types": "workspace:*",
|
"@core/types": "workspace:*",
|
||||||
@ -44,6 +45,5 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
},
|
}
|
||||||
"packageManager": "pnpm@10.3.0"
|
|
||||||
}
|
}
|
||||||
@ -1 +1,2 @@
|
|||||||
export * from '@core/types';
|
export * from '@core/types';
|
||||||
|
export * from './integrations';
|
||||||
|
|||||||
1
packages/sdk/src/integrations/index.ts
Normal file
1
packages/sdk/src/integrations/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { IntegrationCLI } from './integration_cli';
|
||||||
@ -2,10 +2,9 @@ import { Command } from 'commander';
|
|||||||
import {
|
import {
|
||||||
IntegrationEventPayload,
|
IntegrationEventPayload,
|
||||||
Spec,
|
Spec,
|
||||||
Config,
|
Message,
|
||||||
Identifier,
|
IntegrationEventType,
|
||||||
Message
|
} from '@core/types';
|
||||||
} from '@echo/core-types';
|
|
||||||
|
|
||||||
export abstract class IntegrationCLI {
|
export abstract class IntegrationCLI {
|
||||||
protected program: Command;
|
protected program: Command;
|
||||||
@ -32,28 +31,35 @@ export abstract class IntegrationCLI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setupAccountCommands(): void {
|
private setupAccountCommands(): void {
|
||||||
const accountCmd = this.program
|
this.program
|
||||||
.command('account')
|
.command('setup')
|
||||||
.description(`Manage ${this.integrationName} integration accounts`);
|
.description(`Set up a new ${this.integrationName} integration account`)
|
||||||
|
.requiredOption(
|
||||||
accountCmd
|
'--event-body <body>',
|
||||||
.command('create')
|
'Event body JSON (e.g. OAuth response or setup data)',
|
||||||
.description(`Create a new ${this.integrationName} integration account`)
|
)
|
||||||
.requiredOption('--oauth-response <response>', 'OAuth response JSON')
|
.requiredOption(
|
||||||
|
'--integration-definition <definition>',
|
||||||
|
'Integration definition JSON',
|
||||||
|
)
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
try {
|
try {
|
||||||
const oauthResponse = JSON.parse(options.oauthResponse);
|
const eventBody = JSON.parse(options.eventBody);
|
||||||
const integrationDefinition = JSON.parse(options.integrationDefinition);
|
const integrationDefinition = JSON.parse(
|
||||||
|
options.integrationDefinition,
|
||||||
|
);
|
||||||
|
|
||||||
const result = await this.handleEvent({
|
const messages: Message[] = await this.handleEvent({
|
||||||
event: 'INTEGRATION_ACCOUNT_CREATED',
|
event: IntegrationEventType.SETUP,
|
||||||
eventBody: { oauthResponse },
|
eventBody,
|
||||||
integrationDefinition,
|
integrationDefinition,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('Account created successfully:', JSON.stringify(result, null, 2));
|
for (const message of messages) {
|
||||||
|
console.log(JSON.stringify(message, null, 2));
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error creating account:', error);
|
console.error('Error during setup:', error);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -70,17 +76,15 @@ export abstract class IntegrationCLI {
|
|||||||
const eventData = JSON.parse(options.eventData);
|
const eventData = JSON.parse(options.eventData);
|
||||||
const config = JSON.parse(options.config);
|
const config = JSON.parse(options.config);
|
||||||
|
|
||||||
const result = await this.handleEvent({
|
const messages: Message[] = await this.handleEvent({
|
||||||
event: 'PROCESS',
|
event: IntegrationEventType.PROCESS,
|
||||||
eventBody: { eventData },
|
eventBody: { eventData },
|
||||||
config,
|
config,
|
||||||
});
|
});
|
||||||
|
|
||||||
const message: Message = {
|
for (const message of messages) {
|
||||||
type: 'data',
|
console.log(JSON.stringify(message, null, 2));
|
||||||
data: result
|
}
|
||||||
};
|
|
||||||
console.log(JSON.stringify(message, null, 2));
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error processing data:', error);
|
console.error('Error processing data:', error);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
@ -95,16 +99,14 @@ export abstract class IntegrationCLI {
|
|||||||
try {
|
try {
|
||||||
const webhookData = JSON.parse(options.webhookData);
|
const webhookData = JSON.parse(options.webhookData);
|
||||||
|
|
||||||
const result = await this.handleEvent({
|
const messages: Message[] = await this.handleEvent({
|
||||||
event: 'IDENTIFY',
|
event: IntegrationEventType.IDENTIFY,
|
||||||
eventBody: webhookData,
|
eventBody: webhookData,
|
||||||
});
|
});
|
||||||
|
|
||||||
const message: Message = {
|
for (const message of messages) {
|
||||||
type: 'identifier',
|
console.log(JSON.stringify(message, null, 2));
|
||||||
data: result
|
}
|
||||||
};
|
|
||||||
console.log(JSON.stringify(message, null, 2));
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error identifying account:', error);
|
console.error('Error identifying account:', error);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
@ -121,8 +123,9 @@ export abstract class IntegrationCLI {
|
|||||||
const spec = await this.getSpec();
|
const spec = await this.getSpec();
|
||||||
const message: Message = {
|
const message: Message = {
|
||||||
type: 'spec',
|
type: 'spec',
|
||||||
data: spec
|
data: spec,
|
||||||
};
|
};
|
||||||
|
// For spec, we keep the single message output for compatibility
|
||||||
console.log(JSON.stringify(message, null, 2));
|
console.log(JSON.stringify(message, null, 2));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error getting spec:', error);
|
console.error('Error getting spec:', error);
|
||||||
@ -136,21 +139,22 @@ export abstract class IntegrationCLI {
|
|||||||
.command('sync')
|
.command('sync')
|
||||||
.description('Perform scheduled sync')
|
.description('Perform scheduled sync')
|
||||||
.requiredOption('--config <config>', 'Integration configuration JSON')
|
.requiredOption('--config <config>', 'Integration configuration JSON')
|
||||||
|
.option('--state <state>', 'Integration state JSON', '{}')
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
try {
|
try {
|
||||||
const config = JSON.parse(options.config);
|
const config = JSON.parse(options.config);
|
||||||
|
const state = options.state ? JSON.parse(options.state) : {};
|
||||||
|
|
||||||
const result = await this.handleEvent({
|
const messages: Message[] = await this.handleEvent({
|
||||||
event: 'SYNC',
|
event: IntegrationEventType.SYNC,
|
||||||
eventBody: {},
|
eventBody: {},
|
||||||
config,
|
config,
|
||||||
|
state,
|
||||||
});
|
});
|
||||||
|
|
||||||
const message: Message = {
|
for (const message of messages) {
|
||||||
type: 'data',
|
console.log(JSON.stringify(message, null, 2));
|
||||||
data: result
|
}
|
||||||
};
|
|
||||||
console.log(JSON.stringify(message, null, 2));
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error during sync:', error);
|
console.error('Error during sync:', error);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
@ -161,8 +165,11 @@ export abstract class IntegrationCLI {
|
|||||||
/**
|
/**
|
||||||
* Abstract method that must be implemented by each integration
|
* Abstract method that must be implemented by each integration
|
||||||
* This method should handle the integration-specific logic for each event type
|
* This method should handle the integration-specific logic for each event type
|
||||||
|
* and return an array of Message objects.
|
||||||
*/
|
*/
|
||||||
protected abstract handleEvent(eventPayload: IntegrationEventPayload): Promise<any>;
|
protected abstract handleEvent(
|
||||||
|
eventPayload: IntegrationEventPayload,
|
||||||
|
): Promise<Message[]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract method that must be implemented by each integration
|
* Abstract method that must be implemented by each integration
|
||||||
@ -1,70 +1,63 @@
|
|||||||
import { Spec } from "./oauth";
|
import { APIKeyParams, OAuth2Params } from "./oauth";
|
||||||
|
|
||||||
export enum IntegrationPayloadEventType {
|
export enum IntegrationEventType {
|
||||||
/**
|
/**
|
||||||
* When a webhook is received, this event is triggered to identify which integration
|
* Processes authentication data and returns tokens/credentials to be saved
|
||||||
* account the webhook belongs to
|
|
||||||
*/
|
*/
|
||||||
IDENTIFY_WEBHOOK_ACCOUNT = "identify_webhook_account",
|
SETUP = "setup",
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lifecycle events for integration accounts
|
* Processing incoming data from the integration
|
||||||
*/
|
*/
|
||||||
INTEGRATION_ACCOUNT_CREATED = "integration_account_created",
|
PROCESS = "process",
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When data is received from the integration source (e.g. new Slack message)
|
* Identifying which account a webhook belongs to
|
||||||
*/
|
*/
|
||||||
INTEGRATION_DATA_RECEIVED = "integration_data_received",
|
IDENTIFY = "identify",
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For integrations without webhook support, this event is triggered at the
|
* Scheduled synchronization of data
|
||||||
* configured frequency to sync data
|
|
||||||
*/
|
*/
|
||||||
SCHEDULED_SYNC = "scheduled_sync",
|
SYNC = "sync",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For returning integration metadata/config
|
||||||
|
*/
|
||||||
|
SPEC = "spec",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IntegrationEventPayload {
|
export interface IntegrationEventPayload {
|
||||||
event: IntegrationPayloadEventType;
|
event: IntegrationEventType;
|
||||||
[x: string]: any;
|
[x: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Activity {
|
export class Spec {
|
||||||
id: string;
|
name: string;
|
||||||
type: string;
|
key: string;
|
||||||
timestamp: string;
|
description: string;
|
||||||
data: any;
|
icon: string;
|
||||||
|
mcp?: {
|
||||||
|
command: string;
|
||||||
|
args: string[];
|
||||||
|
env: Record<string, string>;
|
||||||
|
};
|
||||||
|
auth?: Record<string, OAuth2Params | APIKeyParams>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IntegrationAccountConfig {
|
export interface Config {
|
||||||
access_token: string;
|
access_token: string;
|
||||||
team_id?: string;
|
|
||||||
channel_ids?: string;
|
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IntegrationAccountIdentifier {
|
export interface Identifier {
|
||||||
identifier: string;
|
id: string;
|
||||||
type: string;
|
type?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IntegrationAccountSettings {
|
export type MessageType = "spec" | "activity" | "state" | "identifier";
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MessageType =
|
|
||||||
| "Spec"
|
|
||||||
| "Activity"
|
|
||||||
| "IntegrationAccountConfig"
|
|
||||||
| "IntegrationAccountIdentifier"
|
|
||||||
| "IntegrationAccountSettings";
|
|
||||||
|
|
||||||
export interface Message {
|
export interface Message {
|
||||||
type: MessageType;
|
type: MessageType;
|
||||||
data:
|
data: any;
|
||||||
| Spec
|
|
||||||
| Activity
|
|
||||||
| IntegrationAccountConfig
|
|
||||||
| IntegrationAccountIdentifier
|
|
||||||
| IntegrationAccountSettings;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,8 +18,3 @@ export class APIKeyParams {
|
|||||||
"header_name": string;
|
"header_name": string;
|
||||||
"format": string;
|
"format": string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Spec {
|
|
||||||
auth: Record<string, OAuth2Params | APIKeyParams>;
|
|
||||||
other_data?: any;
|
|
||||||
}
|
|
||||||
|
|||||||
106
pnpm-lock.yaml
generated
106
pnpm-lock.yaml
generated
@ -156,18 +156,39 @@ importers:
|
|||||||
'@tanstack/react-table':
|
'@tanstack/react-table':
|
||||||
specifier: ^8.13.2
|
specifier: ^8.13.2
|
||||||
version: 8.21.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 8.21.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
'@tiptap/extension-code-block':
|
||||||
|
specifier: 2.11.9
|
||||||
|
version: 2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
||||||
|
'@tiptap/extension-code-block-lowlight':
|
||||||
|
specifier: ^2.11.9
|
||||||
|
version: 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/extension-code-block@2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)(highlight.js@11.11.1)(lowlight@3.3.0)
|
||||||
'@tiptap/extension-document':
|
'@tiptap/extension-document':
|
||||||
specifier: ^2.11.9
|
specifier: ^2.11.9
|
||||||
version: 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
version: 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
'@tiptap/extension-hard-break':
|
'@tiptap/extension-hard-break':
|
||||||
specifier: ^2.11.9
|
specifier: ^2.11.9
|
||||||
version: 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
version: 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
|
'@tiptap/extension-heading':
|
||||||
|
specifier: 2.11.9
|
||||||
|
version: 2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
'@tiptap/extension-history':
|
'@tiptap/extension-history':
|
||||||
specifier: ^2.11.9
|
specifier: ^2.11.9
|
||||||
version: 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
version: 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
||||||
'@tiptap/extension-paragraph':
|
'@tiptap/extension-paragraph':
|
||||||
specifier: ^2.11.9
|
specifier: ^2.11.9
|
||||||
version: 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
version: 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
|
'@tiptap/extension-table':
|
||||||
|
specifier: 2.11.9
|
||||||
|
version: 2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
||||||
|
'@tiptap/extension-table-cell':
|
||||||
|
specifier: 2.11.9
|
||||||
|
version: 2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
|
'@tiptap/extension-table-header':
|
||||||
|
specifier: 2.11.9
|
||||||
|
version: 2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
|
'@tiptap/extension-table-row':
|
||||||
|
specifier: 2.11.9
|
||||||
|
version: 2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
'@tiptap/extension-text':
|
'@tiptap/extension-text':
|
||||||
specifier: ^2.11.9
|
specifier: ^2.11.9
|
||||||
version: 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
version: 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
@ -258,6 +279,9 @@ importers:
|
|||||||
jose:
|
jose:
|
||||||
specifier: ^5.2.3
|
specifier: ^5.2.3
|
||||||
version: 5.10.0
|
version: 5.10.0
|
||||||
|
lowlight:
|
||||||
|
specifier: ^3.3.0
|
||||||
|
version: 3.3.0
|
||||||
lucide-react:
|
lucide-react:
|
||||||
specifier: ^0.511.0
|
specifier: ^0.511.0
|
||||||
version: 0.511.0(react@18.3.1)
|
version: 0.511.0(react@18.3.1)
|
||||||
@ -275,7 +299,7 @@ importers:
|
|||||||
version: 1.0.4
|
version: 1.0.4
|
||||||
novel:
|
novel:
|
||||||
specifier: ^1.0.2
|
specifier: ^1.0.2
|
||||||
version: 1.0.2(@tiptap/extension-code-block@2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0))(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(highlight.js@11.11.1)(lowlight@3.3.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 1.0.2(@tiptap/extension-code-block@2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0))(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(highlight.js@11.11.1)(lowlight@3.3.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
ollama-ai-provider:
|
ollama-ai-provider:
|
||||||
specifier: 1.2.0
|
specifier: 1.2.0
|
||||||
version: 1.2.0(zod@3.23.8)
|
version: 1.2.0(zod@3.23.8)
|
||||||
@ -461,12 +485,6 @@ importers:
|
|||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.3.2(typescript@5.8.3)(vite@6.3.5(@types/node@18.19.115)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0))
|
version: 4.3.2(typescript@5.8.3)(vite@6.3.5(@types/node@18.19.115)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0))
|
||||||
|
|
||||||
core/types:
|
|
||||||
devDependencies:
|
|
||||||
typescript:
|
|
||||||
specifier: ^5.0.0
|
|
||||||
version: 5.8.3
|
|
||||||
|
|
||||||
packages/database:
|
packages/database:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@prisma/client':
|
'@prisma/client':
|
||||||
@ -521,6 +539,10 @@ importers:
|
|||||||
version: 18.2.69
|
version: 18.2.69
|
||||||
|
|
||||||
packages/sdk:
|
packages/sdk:
|
||||||
|
dependencies:
|
||||||
|
commander:
|
||||||
|
specifier: 14.0.0
|
||||||
|
version: 14.0.0
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@core/types':
|
'@core/types':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
@ -3769,8 +3791,8 @@ packages:
|
|||||||
highlight.js: ^11
|
highlight.js: ^11
|
||||||
lowlight: ^2 || ^3
|
lowlight: ^2 || ^3
|
||||||
|
|
||||||
'@tiptap/extension-code-block@2.25.0':
|
'@tiptap/extension-code-block@2.11.9':
|
||||||
resolution: {integrity: sha512-T4kXbZNZ/NyklzQ/FWmUnjD4hgmJPrIBazzCZ/E/rF/Ag2IvUsztBT0PN3vTa+DAZ+IbM61TjlIpyJs1R7OdbQ==}
|
resolution: {integrity: sha512-brwvt/SdP65DpchPv5rkhjEjjIIgE1+9ySw8kCTiyXWUrmZA0kK/iwp5zPpHfsoWT8Sa9+fh2uraVZGOF9Dcqw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
'@tiptap/pm': ^2.7.0
|
'@tiptap/pm': ^2.7.0
|
||||||
@ -3814,8 +3836,8 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
|
|
||||||
'@tiptap/extension-heading@2.25.0':
|
'@tiptap/extension-heading@2.11.9':
|
||||||
resolution: {integrity: sha512-IrRKRRr7Bhpnq5aue1v5/e5N/eNdVV/THsgqqpLZO48pgN8Wv+TweOZe1Ntg/v8L4QSBC8iGMxxhiJZT8AzSkA==}
|
resolution: {integrity: sha512-Z84Vbw26bnMyIyZ7hc8/xXDD5uAcr4GA1zs0HPs4Er9wROOqkZnlgE54LaObXn2YbMKuDZ24cmCU8LFy0etN+w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
|
|
||||||
@ -3878,6 +3900,27 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@tiptap/core': ^2.7.0
|
'@tiptap/core': ^2.7.0
|
||||||
|
|
||||||
|
'@tiptap/extension-table-cell@2.11.9':
|
||||||
|
resolution: {integrity: sha512-YlM7y4UlAcHZuW8p6gkAi1DJa4Vc/8F5BiL2fiW/lot2awE05mI14jjpCZLqJ2wrO9aLguOJbN2VRXEFcTQO7Q==}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': ^2.7.0
|
||||||
|
|
||||||
|
'@tiptap/extension-table-header@2.11.9':
|
||||||
|
resolution: {integrity: sha512-6bLZDywhLaBlgy4Zp26yB28256F2lyjgoUO90w1doU4c19qlS1pkAwt3clYNlqQgMVVVjIZObbt8gZYma/8svA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': ^2.7.0
|
||||||
|
|
||||||
|
'@tiptap/extension-table-row@2.11.9':
|
||||||
|
resolution: {integrity: sha512-so/rP4KTabeoQtvnPFYrVFqMi/QJAihBa5InZPDEjT4pue0yPQbOnTcGRgKiMNYLIEwAC9nw6i1zWlkY5Eic+w==}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': ^2.7.0
|
||||||
|
|
||||||
|
'@tiptap/extension-table@2.11.9':
|
||||||
|
resolution: {integrity: sha512-4VWflJs7B9hgt1uG0SUdFtXJHlHbggIUtjX0tqd1BU9AsYspPXREALicG8Rz9Dm0eOX6dR30+I3LvL3K15XhTA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': ^2.7.0
|
||||||
|
'@tiptap/pm': ^2.7.0
|
||||||
|
|
||||||
'@tiptap/extension-task-item@2.25.0':
|
'@tiptap/extension-task-item@2.25.0':
|
||||||
resolution: {integrity: sha512-8F7Z7jbsyGrPLHQCn+n39zdqIgxwR1kJ1nL5ZwhEW3ZhJgkFF0WMJSv36mwIJwL08p8um/c6g72AYB/e8CD7eA==}
|
resolution: {integrity: sha512-8F7Z7jbsyGrPLHQCn+n39zdqIgxwR1kJ1nL5ZwhEW3ZhJgkFF0WMJSv36mwIJwL08p8um/c6g72AYB/e8CD7eA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -5036,6 +5079,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
|
resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
|
|
||||||
|
commander@14.0.0:
|
||||||
|
resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==}
|
||||||
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
commander@2.20.3:
|
commander@2.20.3:
|
||||||
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
||||||
|
|
||||||
@ -13534,15 +13581,15 @@ snapshots:
|
|||||||
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
||||||
'@tiptap/pm': 2.25.0
|
'@tiptap/pm': 2.25.0
|
||||||
|
|
||||||
'@tiptap/extension-code-block-lowlight@2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/extension-code-block@2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)(highlight.js@11.11.1)(lowlight@3.3.0)':
|
'@tiptap/extension-code-block-lowlight@2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/extension-code-block@2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)(highlight.js@11.11.1)(lowlight@3.3.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
||||||
'@tiptap/extension-code-block': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
'@tiptap/extension-code-block': 2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
||||||
'@tiptap/pm': 2.25.0
|
'@tiptap/pm': 2.25.0
|
||||||
highlight.js: 11.11.1
|
highlight.js: 11.11.1
|
||||||
lowlight: 3.3.0
|
lowlight: 3.3.0
|
||||||
|
|
||||||
'@tiptap/extension-code-block@2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)':
|
'@tiptap/extension-code-block@2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
||||||
'@tiptap/pm': 2.25.0
|
'@tiptap/pm': 2.25.0
|
||||||
@ -13580,7 +13627,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
||||||
|
|
||||||
'@tiptap/extension-heading@2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))':
|
'@tiptap/extension-heading@2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
||||||
|
|
||||||
@ -13633,6 +13680,23 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
||||||
|
|
||||||
|
'@tiptap/extension-table-cell@2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
||||||
|
|
||||||
|
'@tiptap/extension-table-header@2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
||||||
|
|
||||||
|
'@tiptap/extension-table-row@2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
||||||
|
|
||||||
|
'@tiptap/extension-table@2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
||||||
|
'@tiptap/pm': 2.25.0
|
||||||
|
|
||||||
'@tiptap/extension-task-item@2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)':
|
'@tiptap/extension-task-item@2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
||||||
@ -13698,12 +13762,12 @@ snapshots:
|
|||||||
'@tiptap/extension-bold': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
'@tiptap/extension-bold': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
'@tiptap/extension-bullet-list': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
'@tiptap/extension-bullet-list': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
'@tiptap/extension-code': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
'@tiptap/extension-code': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
'@tiptap/extension-code-block': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
'@tiptap/extension-code-block': 2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
||||||
'@tiptap/extension-document': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
'@tiptap/extension-document': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
'@tiptap/extension-dropcursor': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
'@tiptap/extension-dropcursor': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
||||||
'@tiptap/extension-gapcursor': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
'@tiptap/extension-gapcursor': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
||||||
'@tiptap/extension-hard-break': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
'@tiptap/extension-hard-break': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
'@tiptap/extension-heading': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
'@tiptap/extension-heading': 2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
'@tiptap/extension-history': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
'@tiptap/extension-history': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
||||||
'@tiptap/extension-horizontal-rule': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
'@tiptap/extension-horizontal-rule': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
||||||
'@tiptap/extension-italic': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
'@tiptap/extension-italic': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
@ -14003,7 +14067,7 @@ snapshots:
|
|||||||
|
|
||||||
'@types/hast@3.0.4':
|
'@types/hast@3.0.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/unist': 2.0.11
|
'@types/unist': 3.0.3
|
||||||
|
|
||||||
'@types/http-errors@2.0.5': {}
|
'@types/http-errors@2.0.5': {}
|
||||||
|
|
||||||
@ -15084,6 +15148,8 @@ snapshots:
|
|||||||
|
|
||||||
commander@11.1.0: {}
|
commander@11.1.0: {}
|
||||||
|
|
||||||
|
commander@14.0.0: {}
|
||||||
|
|
||||||
commander@2.20.3: {}
|
commander@2.20.3: {}
|
||||||
|
|
||||||
commander@4.1.1: {}
|
commander@4.1.1: {}
|
||||||
@ -18311,12 +18377,12 @@ snapshots:
|
|||||||
|
|
||||||
normalize.css@8.0.1: {}
|
normalize.css@8.0.1: {}
|
||||||
|
|
||||||
novel@1.0.2(@tiptap/extension-code-block@2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0))(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(highlight.js@11.11.1)(lowlight@3.3.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
novel@1.0.2(@tiptap/extension-code-block@2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0))(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(highlight.js@11.11.1)(lowlight@3.3.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@radix-ui/react-slot': 1.2.3(@types/react@18.2.69)(react@18.3.1)
|
'@radix-ui/react-slot': 1.2.3(@types/react@18.2.69)(react@18.3.1)
|
||||||
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
||||||
'@tiptap/extension-character-count': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
'@tiptap/extension-character-count': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
||||||
'@tiptap/extension-code-block-lowlight': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/extension-code-block@2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)(highlight.js@11.11.1)(lowlight@3.3.0)
|
'@tiptap/extension-code-block-lowlight': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/extension-code-block@2.11.9(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)(highlight.js@11.11.1)(lowlight@3.3.0)
|
||||||
'@tiptap/extension-color': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/extension-text-style@2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0)))
|
'@tiptap/extension-color': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/extension-text-style@2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0)))
|
||||||
'@tiptap/extension-highlight': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
'@tiptap/extension-highlight': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
|
||||||
'@tiptap/extension-horizontal-rule': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
'@tiptap/extension-horizontal-rule': 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user