diff --git a/apps/webapp/app/services/knowledgeGraph.server.ts b/apps/webapp/app/services/knowledgeGraph.server.ts
index efe2da1..1b2aeda 100644
--- a/apps/webapp/app/services/knowledgeGraph.server.ts
+++ b/apps/webapp/app/services/knowledgeGraph.server.ts
@@ -1,5 +1,4 @@
-import { openai } from "@ai-sdk/openai";
-import { type CoreMessage, embed } from "ai";
+import { type CoreMessage } from "ai";
import {
type AddEpisodeParams,
type EntityNode,
@@ -35,39 +34,16 @@ import {
saveTriple,
searchStatementsByEmbedding,
} 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 { normalizePrompt } from "./prompts";
-import { env } from "~/env.server";
-import { createOllama } from "ollama-ai-provider";
// Default number of previous episodes to retrieve for context
const DEFAULT_EPISODE_WINDOW = 5;
export class KnowledgeGraphService {
- async getEmbedding(text: string, useOpenAI = false) {
- if (useOpenAI) {
- // 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;
+ async getEmbedding(text: string) {
+ return getEmbedding(text);
}
/**
diff --git a/apps/webapp/app/services/search.server.ts b/apps/webapp/app/services/search.server.ts
index 335762c..eded062 100644
--- a/apps/webapp/app/services/search.server.ts
+++ b/apps/webapp/app/services/search.server.ts
@@ -1,6 +1,4 @@
-import { openai } from "@ai-sdk/openai";
import type { StatementNode } from "@core/types";
-import { embed } from "ai";
import { logger } from "./logger.service";
import { applyCrossEncoderReranking, applyWeightedRRF } from "./search/rerank";
import {
@@ -9,6 +7,7 @@ import {
performBM25Search,
performVectorSearch,
} from "./search/utils";
+import { getEmbedding } from "~/lib/model.server";
/**
* SearchService provides methods to search the reified + temporal knowledge graph
@@ -16,12 +15,7 @@ import {
*/
export class SearchService {
async getEmbedding(text: string) {
- const { embedding } = await embed({
- model: openai.embedding("text-embedding-3-small"),
- value: text,
- });
-
- return embedding;
+ return getEmbedding(text);
}
/**
diff --git a/apps/webapp/app/tailwind.css b/apps/webapp/app/tailwind.css
index 2a093b3..88743f9 100644
--- a/apps/webapp/app/tailwind.css
+++ b/apps/webapp/app/tailwind.css
@@ -363,8 +363,107 @@
@apply text-base;
}
- p.is-editor-empty {
+ p.is-editor-empty:before {
+ @apply text-muted-foreground;
+
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");
+}
+
diff --git a/apps/webapp/app/trigger/conversation/create-conversation-title.ts b/apps/webapp/app/trigger/conversation/create-conversation-title.ts
index ed66966..93ab7ec 100644
--- a/apps/webapp/app/trigger/conversation/create-conversation-title.ts
+++ b/apps/webapp/app/trigger/conversation/create-conversation-title.ts
@@ -23,7 +23,7 @@ export const createConversationTitle = task({
() => {},
undefined,
"",
- LLMMappings.CLAUDESONNET,
+ LLMMappings.GPT41,
);
for await (const chunk of gen) {
diff --git a/apps/webapp/package.json b/apps/webapp/package.json
index 093076f..765eb37 100644
--- a/apps/webapp/package.json
+++ b/apps/webapp/package.json
@@ -59,6 +59,13 @@
"@tiptap/extension-history": "^2.11.9",
"@tiptap/extension-paragraph": "^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/react": "^2.11.9",
"@tiptap/pm": "^2.11.9",
@@ -89,6 +96,7 @@
"isbot": "^4.1.0",
"jose": "^5.2.3",
"lucide-react": "^0.511.0",
+ "lowlight": "^3.3.0",
"morgan": "^1.10.0",
"nanoid": "3.3.8",
"neo4j-driver": "^5.28.1",
diff --git a/core/types/package.json b/core/types/package.json
deleted file mode 100644
index 8b9198c..0000000
--- a/core/types/package.json
+++ /dev/null
@@ -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"
- }
- }
-}
\ No newline at end of file
diff --git a/core/types/src/index.ts b/core/types/src/index.ts
deleted file mode 100644
index 1081f03..0000000
--- a/core/types/src/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './integration';
\ No newline at end of file
diff --git a/core/types/src/integration.ts b/core/types/src/integration.ts
deleted file mode 100644
index 3089e22..0000000
--- a/core/types/src/integration.ts
+++ /dev/null
@@ -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
;
- };
- 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;
-}
\ No newline at end of file
diff --git a/core/types/tsconfig.json b/core/types/tsconfig.json
deleted file mode 100644
index b5482c0..0000000
--- a/core/types/tsconfig.json
+++ /dev/null
@@ -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"]
-}
\ No newline at end of file
diff --git a/integrations/slack/.gitignore b/integrations/slack/.gitignore
index 9b60c0a..611892f 100644
--- a/integrations/slack/.gitignore
+++ b/integrations/slack/.gitignore
@@ -1,2 +1,3 @@
bin
-node_modules
\ No newline at end of file
+node_modules
+
diff --git a/integrations/slack/package.json b/integrations/slack/package.json
index dba603f..d291834 100644
--- a/integrations/slack/package.json
+++ b/integrations/slack/package.json
@@ -66,6 +66,6 @@
"commander": "^12.0.0",
"openai": "^4.0.0",
"react-query": "^3.39.3",
- "@echo/core-types": "workspace:*"
+ "@redplanethq/sdk": "0.1.0"
}
}
\ No newline at end of file
diff --git a/integrations/slack/pnpm-lock.yaml b/integrations/slack/pnpm-lock.yaml
index 657304d..e0bca70 100644
--- a/integrations/slack/pnpm-lock.yaml
+++ b/integrations/slack/pnpm-lock.yaml
@@ -8,6 +8,9 @@ importers:
.:
dependencies:
+ '@redplanethq/sdk':
+ specifier: 0.1.0
+ version: 0.1.0
axios:
specifier: ^1.7.9
version: 1.9.0
@@ -489,6 +492,10 @@ packages:
resolution: {integrity: sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==}
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':
resolution: {integrity: sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ==}
engines: {node: '>=16.0.0 || 14 >= 14.17'}
@@ -901,6 +908,10 @@ packages:
resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
engines: {node: '>=18'}
+ commander@14.0.0:
+ resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==}
+ engines: {node: '>=20'}
+
commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
@@ -2894,6 +2905,10 @@ snapshots:
'@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)':
dependencies:
'@rollup/pluginutils': 5.1.4(rollup@4.40.2)
@@ -3320,6 +3335,8 @@ snapshots:
commander@12.1.0: {}
+ commander@14.0.0: {}
+
commander@2.20.3: {}
commander@4.1.1: {}
diff --git a/integrations/slack/src/common/README.md b/integrations/slack/src/common/README.md
deleted file mode 100644
index efd21bc..0000000
--- a/integrations/slack/src/common/README.md
+++ /dev/null
@@ -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 {
- // 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 --integration-definition `
-- `account delete --account-id `
-- `process --event-data --integration-account `
-- `identify --webhook-data `
-- `sync --integration-account `
-
-## 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
\ No newline at end of file
diff --git a/integrations/slack/src/index.ts b/integrations/slack/src/index.ts
index d66ee50..8e5f84d 100644
--- a/integrations/slack/src/index.ts
+++ b/integrations/slack/src/index.ts
@@ -2,23 +2,24 @@
import { integrationCreate } from './account-create';
import { createActivityEvent } from './create-activity';
-import { IntegrationCLI } from './common/IntegrationCLI';
-import { IntegrationEventPayload, Spec } from '@echo/core-types';
+import {
+ IntegrationCLI,
+ IntegrationEventPayload,
+ IntegrationEventType,
+ Spec,
+} from '@redplanethq/sdk';
export async function run(eventPayload: IntegrationEventPayload) {
switch (eventPayload.event) {
- case 'SETUP':
+ case IntegrationEventType.SETUP:
return await integrationCreate(eventPayload.eventBody, eventPayload.integrationDefinition);
- case 'IDENTIFY':
+ case IntegrationEventType.IDENTIFY:
return eventPayload.eventBody.event.user;
- case 'PROCESS':
+ case IntegrationEventType.PROCESS:
return createActivityEvent(eventPayload.eventBody, eventPayload.config);
- case 'SYNC':
- return { message: 'Scheduled sync completed successfully' };
-
default:
return {
message: `The event payload type is ${eventPayload.event}`,
@@ -38,45 +39,45 @@ class SlackCLI extends IntegrationCLI {
protected async getSpec(): Promise {
return {
- name: "Slack extension",
- key: "slack",
- description: "Connect your workspace to Slack. Run your workflows from slack bookmarks",
- icon: "slack",
+ name: 'Slack extension',
+ key: 'slack',
+ description: 'Connect your workspace to Slack. Run your workflows from slack bookmarks',
+ icon: 'slack',
mcp: {
- command: "npx",
- args: ["-y", "@modelcontextprotocol/server-slack"],
+ command: 'npx',
+ args: ['-y', '@modelcontextprotocol/server-slack'],
env: {
- "SLACK_BOT_TOKEN": "${config:access_token}",
- "SLACK_TEAM_ID": "${config:team_id}",
- "SLACK_CHANNEL_IDS": "${config:channel_ids}"
- }
+ SLACK_BOT_TOKEN: '${config:access_token}',
+ SLACK_TEAM_ID: '${config:team_id}',
+ SLACK_CHANNEL_IDS: '${config:channel_ids}',
+ },
},
auth: {
OAuth2: {
- token_url: "https://slack.com/api/oauth.v2.access",
- authorization_url: "https://slack.com/oauth/v2/authorize",
+ token_url: 'https://slack.com/api/oauth.v2.access',
+ authorization_url: 'https://slack.com/oauth/v2/authorize',
scopes: [
- "stars:read",
- "team:read",
- "stars:write",
- "users:read",
- "channels:read",
- "groups:read",
- "im:read",
- "im:history",
- "mpim:read",
- "mpim:write",
- "mpim:history",
- "channels:history",
- "chat:write",
- "reactions:read",
- "reactions:write",
- "users.profile:read"
+ 'stars:read',
+ 'team:read',
+ 'stars:write',
+ 'users:read',
+ 'channels:read',
+ 'groups:read',
+ 'im:read',
+ 'im:history',
+ 'mpim:read',
+ 'mpim:write',
+ 'mpim:history',
+ 'channels:history',
+ 'chat:write',
+ 'reactions:read',
+ 'reactions:write',
+ 'users.profile:read',
],
- scope_identifier: "user_scope",
- scope_separator: ","
- }
- }
+ scope_identifier: 'user_scope',
+ scope_separator: ',',
+ },
+ },
};
}
}
diff --git a/packages/sdk/README.md b/packages/sdk/README.md
new file mode 100644
index 0000000..5d8867c
--- /dev/null
+++ b/packages/sdk/README.md
@@ -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 {
+ 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 {
+ 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 {
+ // 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 {
+ // 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 {
+ // Extract account ID from webhook
+ const { team_id } = eventPayload.eventBody;
+ return { id: team_id };
+ }
+
+ private async handleSync(eventPayload: IntegrationEventPayload): Promise {
+ // 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.
\ No newline at end of file
diff --git a/packages/sdk/package.json b/packages/sdk/package.json
index fed7b69..5ab5b14 100644
--- a/packages/sdk/package.json
+++ b/packages/sdk/package.json
@@ -1,7 +1,7 @@
{
- "name": "@redplanethq/sol-sdk",
- "version": "0.2.18",
- "description": "Sol Node.JS SDK",
+ "name": "@redplanethq/sdk",
+ "version": "0.1.0",
+ "description": "CORE Node.JS SDK",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"module": "./dist/index.mjs",
@@ -29,6 +29,7 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
+ "commander": "14.0.0"
},
"devDependencies": {
"@core/types": "workspace:*",
@@ -44,6 +45,5 @@
},
"engines": {
"node": ">=18.0.0"
- },
- "packageManager": "pnpm@10.3.0"
+ }
}
\ No newline at end of file
diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts
index d33aaa0..7e22831 100644
--- a/packages/sdk/src/index.ts
+++ b/packages/sdk/src/index.ts
@@ -1 +1,2 @@
export * from '@core/types';
+export * from './integrations';
diff --git a/packages/sdk/src/integrations/index.ts b/packages/sdk/src/integrations/index.ts
new file mode 100644
index 0000000..bdaf855
--- /dev/null
+++ b/packages/sdk/src/integrations/index.ts
@@ -0,0 +1 @@
+export { IntegrationCLI } from './integration_cli';
\ No newline at end of file
diff --git a/integrations/slack/src/common/IntegrationCLI.ts b/packages/sdk/src/integrations/integration_cli.ts
similarity index 64%
rename from integrations/slack/src/common/IntegrationCLI.ts
rename to packages/sdk/src/integrations/integration_cli.ts
index 093438d..462271c 100644
--- a/integrations/slack/src/common/IntegrationCLI.ts
+++ b/packages/sdk/src/integrations/integration_cli.ts
@@ -1,11 +1,10 @@
import { Command } from 'commander';
-import {
- IntegrationEventPayload,
- Spec,
- Config,
- Identifier,
- Message
-} from '@echo/core-types';
+import {
+ IntegrationEventPayload,
+ Spec,
+ Message,
+ IntegrationEventType,
+} from '@core/types';
export abstract class IntegrationCLI {
protected program: Command;
@@ -32,28 +31,35 @@ export abstract class IntegrationCLI {
}
private setupAccountCommands(): void {
- const accountCmd = this.program
- .command('account')
- .description(`Manage ${this.integrationName} integration accounts`);
-
- accountCmd
- .command('create')
- .description(`Create a new ${this.integrationName} integration account`)
- .requiredOption('--oauth-response ', 'OAuth response JSON')
+ this.program
+ .command('setup')
+ .description(`Set up a new ${this.integrationName} integration account`)
+ .requiredOption(
+ '--event-body ',
+ 'Event body JSON (e.g. OAuth response or setup data)',
+ )
+ .requiredOption(
+ '--integration-definition ',
+ 'Integration definition JSON',
+ )
.action(async (options) => {
try {
- const oauthResponse = JSON.parse(options.oauthResponse);
- const integrationDefinition = JSON.parse(options.integrationDefinition);
+ const eventBody = JSON.parse(options.eventBody);
+ const integrationDefinition = JSON.parse(
+ options.integrationDefinition,
+ );
- const result = await this.handleEvent({
- event: 'INTEGRATION_ACCOUNT_CREATED',
- eventBody: { oauthResponse },
+ const messages: Message[] = await this.handleEvent({
+ event: IntegrationEventType.SETUP,
+ eventBody,
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) {
- console.error('Error creating account:', error);
+ console.error('Error during setup:', error);
process.exit(1);
}
});
@@ -70,17 +76,15 @@ export abstract class IntegrationCLI {
const eventData = JSON.parse(options.eventData);
const config = JSON.parse(options.config);
- const result = await this.handleEvent({
- event: 'PROCESS',
+ const messages: Message[] = await this.handleEvent({
+ event: IntegrationEventType.PROCESS,
eventBody: { eventData },
config,
});
- const message: Message = {
- type: 'data',
- data: result
- };
- console.log(JSON.stringify(message, null, 2));
+ for (const message of messages) {
+ console.log(JSON.stringify(message, null, 2));
+ }
} catch (error) {
console.error('Error processing data:', error);
process.exit(1);
@@ -95,16 +99,14 @@ export abstract class IntegrationCLI {
try {
const webhookData = JSON.parse(options.webhookData);
- const result = await this.handleEvent({
- event: 'IDENTIFY',
+ const messages: Message[] = await this.handleEvent({
+ event: IntegrationEventType.IDENTIFY,
eventBody: webhookData,
});
- const message: Message = {
- type: 'identifier',
- data: result
- };
- console.log(JSON.stringify(message, null, 2));
+ for (const message of messages) {
+ console.log(JSON.stringify(message, null, 2));
+ }
} catch (error) {
console.error('Error identifying account:', error);
process.exit(1);
@@ -121,8 +123,9 @@ export abstract class IntegrationCLI {
const spec = await this.getSpec();
const message: Message = {
type: 'spec',
- data: spec
+ data: spec,
};
+ // For spec, we keep the single message output for compatibility
console.log(JSON.stringify(message, null, 2));
} catch (error) {
console.error('Error getting spec:', error);
@@ -136,21 +139,22 @@ export abstract class IntegrationCLI {
.command('sync')
.description('Perform scheduled sync')
.requiredOption('--config ', 'Integration configuration JSON')
+ .option('--state ', 'Integration state JSON', '{}')
.action(async (options) => {
try {
const config = JSON.parse(options.config);
+ const state = options.state ? JSON.parse(options.state) : {};
- const result = await this.handleEvent({
- event: 'SYNC',
+ const messages: Message[] = await this.handleEvent({
+ event: IntegrationEventType.SYNC,
eventBody: {},
config,
+ state,
});
- const message: Message = {
- type: 'data',
- data: result
- };
- console.log(JSON.stringify(message, null, 2));
+ for (const message of messages) {
+ console.log(JSON.stringify(message, null, 2));
+ }
} catch (error) {
console.error('Error during sync:', error);
process.exit(1);
@@ -161,8 +165,11 @@ export abstract class IntegrationCLI {
/**
* Abstract method that must be implemented by each integration
* 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;
+ protected abstract handleEvent(
+ eventPayload: IntegrationEventPayload,
+ ): Promise;
/**
* Abstract method that must be implemented by each integration
diff --git a/packages/types/src/integration.ts b/packages/types/src/integration.ts
index e9036d8..2848217 100644
--- a/packages/types/src/integration.ts
+++ b/packages/types/src/integration.ts
@@ -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
- * account the webhook belongs to
+ * Processes authentication data and returns tokens/credentials to be saved
*/
- 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
- * configured frequency to sync data
+ * Scheduled synchronization of data
*/
- SCHEDULED_SYNC = "scheduled_sync",
+ SYNC = "sync",
+
+ /**
+ * For returning integration metadata/config
+ */
+ SPEC = "spec",
}
export interface IntegrationEventPayload {
- event: IntegrationPayloadEventType;
+ event: IntegrationEventType;
[x: string]: any;
}
-export interface Activity {
- id: string;
- type: string;
- timestamp: string;
- data: any;
+export class Spec {
+ name: string;
+ key: string;
+ description: string;
+ icon: string;
+ mcp?: {
+ command: string;
+ args: string[];
+ env: Record;
+ };
+ auth?: Record;
}
-export interface IntegrationAccountConfig {
+export interface Config {
access_token: string;
- team_id?: string;
- channel_ids?: string;
[key: string]: any;
}
-export interface IntegrationAccountIdentifier {
- identifier: string;
- type: string;
+export interface Identifier {
+ id: string;
+ type?: string;
}
-export interface IntegrationAccountSettings {
- [key: string]: any;
-}
-
-export type MessageType =
- | "Spec"
- | "Activity"
- | "IntegrationAccountConfig"
- | "IntegrationAccountIdentifier"
- | "IntegrationAccountSettings";
+export type MessageType = "spec" | "activity" | "state" | "identifier";
export interface Message {
type: MessageType;
- data:
- | Spec
- | Activity
- | IntegrationAccountConfig
- | IntegrationAccountIdentifier
- | IntegrationAccountSettings;
+ data: any;
}
diff --git a/packages/types/src/oauth/params.ts b/packages/types/src/oauth/params.ts
index f2c423c..026dc07 100644
--- a/packages/types/src/oauth/params.ts
+++ b/packages/types/src/oauth/params.ts
@@ -18,8 +18,3 @@ export class APIKeyParams {
"header_name": string;
"format": string;
}
-
-export class Spec {
- auth: Record;
- other_data?: any;
-}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7aa64c5..8355be4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -156,18 +156,39 @@ importers:
'@tanstack/react-table':
specifier: ^8.13.2
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':
specifier: ^2.11.9
version: 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
'@tiptap/extension-hard-break':
specifier: ^2.11.9
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':
specifier: ^2.11.9
version: 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))(@tiptap/pm@2.25.0)
'@tiptap/extension-paragraph':
specifier: ^2.11.9
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':
specifier: ^2.11.9
version: 2.25.0(@tiptap/core@2.25.0(@tiptap/pm@2.25.0))
@@ -258,6 +279,9 @@ importers:
jose:
specifier: ^5.2.3
version: 5.10.0
+ lowlight:
+ specifier: ^3.3.0
+ version: 3.3.0
lucide-react:
specifier: ^0.511.0
version: 0.511.0(react@18.3.1)
@@ -275,7 +299,7 @@ importers:
version: 1.0.4
novel:
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:
specifier: 1.2.0
version: 1.2.0(zod@3.23.8)
@@ -461,12 +485,6 @@ importers:
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))
- core/types:
- devDependencies:
- typescript:
- specifier: ^5.0.0
- version: 5.8.3
-
packages/database:
dependencies:
'@prisma/client':
@@ -521,6 +539,10 @@ importers:
version: 18.2.69
packages/sdk:
+ dependencies:
+ commander:
+ specifier: 14.0.0
+ version: 14.0.0
devDependencies:
'@core/types':
specifier: workspace:*
@@ -3769,8 +3791,8 @@ packages:
highlight.js: ^11
lowlight: ^2 || ^3
- '@tiptap/extension-code-block@2.25.0':
- resolution: {integrity: sha512-T4kXbZNZ/NyklzQ/FWmUnjD4hgmJPrIBazzCZ/E/rF/Ag2IvUsztBT0PN3vTa+DAZ+IbM61TjlIpyJs1R7OdbQ==}
+ '@tiptap/extension-code-block@2.11.9':
+ resolution: {integrity: sha512-brwvt/SdP65DpchPv5rkhjEjjIIgE1+9ySw8kCTiyXWUrmZA0kK/iwp5zPpHfsoWT8Sa9+fh2uraVZGOF9Dcqw==}
peerDependencies:
'@tiptap/core': ^2.7.0
'@tiptap/pm': ^2.7.0
@@ -3814,8 +3836,8 @@ packages:
peerDependencies:
'@tiptap/core': ^2.7.0
- '@tiptap/extension-heading@2.25.0':
- resolution: {integrity: sha512-IrRKRRr7Bhpnq5aue1v5/e5N/eNdVV/THsgqqpLZO48pgN8Wv+TweOZe1Ntg/v8L4QSBC8iGMxxhiJZT8AzSkA==}
+ '@tiptap/extension-heading@2.11.9':
+ resolution: {integrity: sha512-Z84Vbw26bnMyIyZ7hc8/xXDD5uAcr4GA1zs0HPs4Er9wROOqkZnlgE54LaObXn2YbMKuDZ24cmCU8LFy0etN+w==}
peerDependencies:
'@tiptap/core': ^2.7.0
@@ -3878,6 +3900,27 @@ packages:
peerDependencies:
'@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':
resolution: {integrity: sha512-8F7Z7jbsyGrPLHQCn+n39zdqIgxwR1kJ1nL5ZwhEW3ZhJgkFF0WMJSv36mwIJwL08p8um/c6g72AYB/e8CD7eA==}
peerDependencies:
@@ -5036,6 +5079,10 @@ packages:
resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
engines: {node: '>=16'}
+ commander@14.0.0:
+ resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==}
+ engines: {node: '>=20'}
+
commander@2.20.3:
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/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:
'@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
highlight.js: 11.11.1
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:
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
'@tiptap/pm': 2.25.0
@@ -13580,7 +13627,7 @@ snapshots:
dependencies:
'@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:
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
@@ -13633,6 +13680,23 @@ snapshots:
dependencies:
'@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)':
dependencies:
'@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-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-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-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-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-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))
@@ -14003,7 +14067,7 @@ snapshots:
'@types/hast@3.0.4':
dependencies:
- '@types/unist': 2.0.11
+ '@types/unist': 3.0.3
'@types/http-errors@2.0.5': {}
@@ -15084,6 +15148,8 @@ snapshots:
commander@11.1.0: {}
+ commander@14.0.0: {}
+
commander@2.20.3: {}
commander@4.1.1: {}
@@ -18311,12 +18377,12 @@ snapshots:
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:
'@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/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-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)