From 6b4e4b112cf3d0dc8b35af192b9bb25bf7713cff Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Sat, 21 Mar 2026 08:32:40 -0300 Subject: [PATCH 01/32] feat(document-api): return ref handle from superdoc_create MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The create response now includes a ref handle that can be passed directly to superdoc_format or superdoc_edit without a search step. Before: create → search → format (3 calls) After: create → format using ref from response (2 calls) The ref is minted from the created block's nodeId + text range + document revision. It's a V4 block-scoped ref that resolves to the full text range of the created content. --- .../src/contract/operation-definitions.ts | 2 +- packages/document-api/src/contract/schemas.ts | 10 ++++++ .../document-api/src/types/create.types.ts | 4 +++ .../plan-engine/create-wrappers.ts | 32 +++++++++++++++++-- 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/packages/document-api/src/contract/operation-definitions.ts b/packages/document-api/src/contract/operation-definitions.ts index a9e78b18ee..2297b383c4 100644 --- a/packages/document-api/src/contract/operation-definitions.ts +++ b/packages/document-api/src/contract/operation-definitions.ts @@ -101,7 +101,7 @@ export const INTENT_GROUP_META: Record = { create: { toolName: 'superdoc_create', description: - 'Create one paragraph or heading per call. After creating, search for it and apply formatting (fontFamily, fontSize) from neighboring blocks. For multiple paragraphs, use superdoc_mutations with text.insert steps instead of calling create repeatedly.', + 'Create one paragraph or heading per call. Returns a ref handle in the response — pass it directly to superdoc_format ref param to apply formatting (fontFamily, color) from neighboring blocks. No search step needed after create.', }, format: { toolName: 'superdoc_format', diff --git a/packages/document-api/src/contract/schemas.ts b/packages/document-api/src/contract/schemas.ts index 8bd1603b11..09a8b49ebd 100644 --- a/packages/document-api/src/contract/schemas.ts +++ b/packages/document-api/src/contract/schemas.ts @@ -767,6 +767,11 @@ const createParagraphSuccessSchema = objectSchema( paragraph: paragraphAddressSchema, insertionPoint: textAddressSchema, trackedChangeRefs: arraySchema(trackChangeRefSchema), + ref: { + type: 'string', + description: + 'Ref handle for the created block. Pass directly to superdoc_format or superdoc_edit ref param without searching.', + }, }, ['success', 'paragraph', 'insertionPoint'], ); @@ -793,6 +798,11 @@ const createHeadingSuccessSchema = objectSchema( heading: headingAddressSchema, insertionPoint: textAddressSchema, trackedChangeRefs: arraySchema(trackChangeRefSchema), + ref: { + type: 'string', + description: + 'Ref handle for the created block. Pass directly to superdoc_format or superdoc_edit ref param without searching.', + }, }, ['success', 'heading', 'insertionPoint'], ); diff --git a/packages/document-api/src/types/create.types.ts b/packages/document-api/src/types/create.types.ts index 16fe4c22bd..f80cf54651 100644 --- a/packages/document-api/src/types/create.types.ts +++ b/packages/document-api/src/types/create.types.ts @@ -21,6 +21,8 @@ export interface CreateParagraphSuccessResult { paragraph: BlockNodeAddress; insertionPoint: TextAddress; trackedChangeRefs?: ReceiptInsert[]; + /** Stable ref handle for the created block. Pass directly to superdoc_format or superdoc_edit without searching. */ + ref?: string; } export interface CreateParagraphFailureResult { @@ -47,6 +49,8 @@ export interface CreateHeadingSuccessResult { heading: BlockNodeAddress; insertionPoint: TextAddress; trackedChangeRefs?: ReceiptInsert[]; + /** Stable ref handle for the created block. Pass directly to superdoc_format or superdoc_edit without searching. */ + ref?: string; } export interface CreateHeadingFailureResult { diff --git a/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts b/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts index 02d6abdc75..528c0f69bd 100644 --- a/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts +++ b/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts @@ -25,6 +25,26 @@ import { collectTrackInsertRefsInRange } from '../helpers/tracked-change-refs.js import { DocumentApiAdapterError } from '../errors.js'; import { requireEditorCommand, ensureTrackedCapability } from '../helpers/mutation-helpers.js'; import { executeDomainCommand, resolveWriteStoryRuntime, disposeEphemeralWriteRuntime } from './plan-wrappers.js'; +import { getRevision } from './revision-tracker.js'; +import { encodeV4Ref } from '../story-runtime/story-ref-codec.js'; + +// --------------------------------------------------------------------------- +// Ref minting — create a text-scoped ref for the created block so the +// caller can immediately use it with superdoc_format without searching. +// --------------------------------------------------------------------------- + +function mintBlockRef(editor: Editor, storyKey: string, nodeId: string, textLength: number): string { + const rev = getRevision(editor); + return encodeV4Ref({ + v: 4, + rev, + storyKey, + scope: 'block', + matchId: `create:${nodeId}`, + segments: [{ blockId: nodeId, start: 0, end: textLength }], + blockIndex: 0, + }); +} // --------------------------------------------------------------------------- // Command types (internal to the wrapper) @@ -101,6 +121,7 @@ function buildParagraphCreateSuccess( paragraphNodeId: string, trackedChangeRefs?: CreateParagraphSuccessResult['trackedChangeRefs'], story?: StoryLocator, + ref?: string, ): CreateParagraphSuccessResult { return { success: true, @@ -117,6 +138,7 @@ function buildParagraphCreateSuccess( ...(story && { story }), }, trackedChangeRefs, + ...(ref ? { ref } : {}), }; } @@ -124,6 +146,7 @@ function buildHeadingCreateSuccess( headingNodeId: string, trackedChangeRefs?: CreateHeadingSuccessResult['trackedChangeRefs'], story?: StoryLocator, + ref?: string, ): CreateHeadingSuccessResult { return { success: true, @@ -140,6 +163,7 @@ function buildHeadingCreateSuccess( ...(story && { story }), }, trackedChangeRefs, + ...(ref ? { ref } : {}), }; } @@ -245,7 +269,9 @@ export function createParagraphWrapper( if (runtime.commit) runtime.commit(editor); const nonBodyStory = runtime.kind !== 'body' ? runtime.locator : undefined; - return buildParagraphCreateSuccess(canonicalId, trackedChangeRefs, nonBodyStory); + const textLen = input.text?.length ?? 0; + const ref = textLen > 0 ? mintBlockRef(storyEditor, runtime.storyKey, canonicalId, textLen) : undefined; + return buildParagraphCreateSuccess(canonicalId, trackedChangeRefs, nonBodyStory, ref); } finally { disposeEphemeralWriteRuntime(runtime); } @@ -352,7 +378,9 @@ export function createHeadingWrapper( if (runtime.commit) runtime.commit(editor); const nonBodyStory = runtime.kind !== 'body' ? runtime.locator : undefined; - return buildHeadingCreateSuccess(canonicalId, trackedChangeRefs, nonBodyStory); + const textLen = input.text?.length ?? 0; + const ref = textLen > 0 ? mintBlockRef(storyEditor, runtime.storyKey, canonicalId, textLen) : undefined; + return buildHeadingCreateSuccess(canonicalId, trackedChangeRefs, nonBodyStory, ref); } finally { disposeEphemeralWriteRuntime(runtime); } From abfb545cb9b3df4c6de2165be072967a1379202c Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Sat, 21 Mar 2026 08:36:23 -0300 Subject: [PATCH 02/32] =?UTF-8?q?fix(sdk):=20stronger=20create=20descripti?= =?UTF-8?q?on=20=E2=80=94=20use=20ref,=20dont=20search,=20dont=20resize=20?= =?UTF-8?q?headings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/document-api/src/contract/operation-definitions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/document-api/src/contract/operation-definitions.ts b/packages/document-api/src/contract/operation-definitions.ts index 2297b383c4..b97096fbaf 100644 --- a/packages/document-api/src/contract/operation-definitions.ts +++ b/packages/document-api/src/contract/operation-definitions.ts @@ -101,7 +101,7 @@ export const INTENT_GROUP_META: Record = { create: { toolName: 'superdoc_create', description: - 'Create one paragraph or heading per call. Returns a ref handle in the response — pass it directly to superdoc_format ref param to apply formatting (fontFamily, color) from neighboring blocks. No search step needed after create.', + 'Create one paragraph or heading. Response includes a ref — use it directly with superdoc_format (DO NOT search again). Apply only fontFamily from neighbors. For headings, do NOT change fontSize or color — the default heading style is correct.', }, format: { toolName: 'superdoc_format', From fd5172a7aaa1f014f66537e22bd435eb79f36c5a Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Sat, 21 Mar 2026 08:38:22 -0300 Subject: [PATCH 03/32] fix(sdk): apply fontFamily AND color from neighbors, skip fontSize on headings --- packages/document-api/src/contract/operation-definitions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/document-api/src/contract/operation-definitions.ts b/packages/document-api/src/contract/operation-definitions.ts index b97096fbaf..3d7062c10d 100644 --- a/packages/document-api/src/contract/operation-definitions.ts +++ b/packages/document-api/src/contract/operation-definitions.ts @@ -101,7 +101,7 @@ export const INTENT_GROUP_META: Record = { create: { toolName: 'superdoc_create', description: - 'Create one paragraph or heading. Response includes a ref — use it directly with superdoc_format (DO NOT search again). Apply only fontFamily from neighbors. For headings, do NOT change fontSize or color — the default heading style is correct.', + 'Create one paragraph or heading. Response includes a ref — use it with superdoc_format (DO NOT search). Apply fontFamily and color from neighboring blocks. Do NOT change fontSize on headings.', }, format: { toolName: 'superdoc_format', From 33ecda17eaeba0575dded8e5018209ea07598f49 Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Sat, 21 Mar 2026 08:40:13 -0300 Subject: [PATCH 04/32] fix(sdk): resolve system prompt conflicts with tool descriptions - Removed "optional styleId" reference (styleId was removed) - Changed "search after create" to "use ref from response" - Separated heading vs paragraph formatting rules - Added create ref to targeting section - Removed contradictory "search before editing" for create flow --- packages/sdk/tools/system-prompt.md | 89 +++++++++-------------------- 1 file changed, 26 insertions(+), 63 deletions(-) diff --git a/packages/sdk/tools/system-prompt.md b/packages/sdk/tools/system-prompt.md index 380e272b66..0fd5cbf06b 100644 --- a/packages/sdk/tools/system-prompt.md +++ b/packages/sdk/tools/system-prompt.md @@ -7,9 +7,9 @@ You are a document editing assistant. You have a DOCX document open and a set of | Tool | Purpose | |------|---------| | superdoc_search | Find text or nodes in the document | -| superdoc_get_content | Read document content (text, markdown, html, info) | +| superdoc_get_content | Read document content (text, markdown, html, info, blocks) | | superdoc_edit | Insert, replace, delete text, undo/redo | -| superdoc_create | Create paragraphs or headings (with optional styleId) | +| superdoc_create | Create paragraphs or headings (returns a ref for immediate formatting) | | superdoc_format | Apply inline and paragraph formatting, set named styles | | superdoc_list | Create and manipulate bullet/numbered lists | | superdoc_comment | Create, update, delete, and list comments | @@ -22,57 +22,30 @@ Every editing tool needs a **target** — an address telling the API *where* to ### Getting targets -Use `superdoc_search` to find content. Each match item returns: - -- **`handle.ref`** — a ref string for text-level operations. Pass the ref string as: - - `ref` parameter on `superdoc_format` (for inline styles like bold, italic) - - `ref` parameter on `superdoc_edit` (for text replacement, deletion) - - Example: `superdoc_format({action: "inline", ref: "text:eyJ...", inline: {bold: true}})` -- **`address`** — a block-level address like `{ "kind": "block", "nodeType": "paragraph", "nodeId": "abc123" }`. Pass it as `target` to `superdoc_format` (for paragraph-level properties like alignment, spacing), `superdoc_list`, and `superdoc_create`. - -### Text search results - -When searching for text (`type: "text"`), each match includes: -- `snippet` — the matched text with surrounding context -- `highlightRange` — `{ start, end }` character offsets of the match -- `blocks` — array of `{ blockId, range }` entries showing which blocks contain the match - -### Node search results - -When searching for nodes (`type: "node"`), each match includes: -- `address` — the block address of the matched node - -## Multi-action tools - -Most tools support multiple actions via an `action` parameter. For example: -- `superdoc_get_content` with `action: "text"` returns plain text; `action: "info"` returns document metadata and styles. -- `superdoc_edit` with `action: "insert"` inserts content; `action: "delete"` deletes content. -- `superdoc_format` with `action: "inline"` applies inline formatting; `action: "set_style"` applies a named paragraph style. - -Single-action tools like `superdoc_search` do not require an `action` parameter. +- **From `superdoc_search`**: Returns `handle.ref` — pass as `ref` param to `superdoc_format` or `superdoc_edit`. +- **From `superdoc_create`**: Returns `ref` in the response — pass directly to `superdoc_format`. No search needed. +- **From blocks data**: Each block has a `nodeId` — use it to build block addresses for `superdoc_create` `at` positioning. ## Workflow -**ALWAYS start by calling `superdoc_get_content({action: "blocks"})` before any other tool.** This returns every block in the document with its nodeId, type, text preview, styleId, fontFamily, fontSize, bold, and alignment. You need this to: -- Know the document's structure and block IDs for targeting -- See what fonts, sizes, and styles are used so new content matches -- Find blocks by their text preview without a separate search +**ALWAYS start by calling `superdoc_get_content({action: "blocks"})` before any other tool.** This returns every block with its nodeId, type, text, fontFamily, fontSize, bold, color, and alignment. After getting blocks: -1. **Search before editing**: Use `superdoc_search` to get valid targets (handles/refs). -2. **Edit with targets**: Pass handles/addresses from search results to editing tools. +1. **Edit existing content**: Use `superdoc_search` to get refs, then `superdoc_edit` or `superdoc_format`. +2. **Create new content**: Use `superdoc_create`, then use the `ref` from the response to apply formatting. DO NOT search after create. 3. **Re-search after each mutation**: Refs expire after any edit. Always search again before the next operation. 4. **Batch when possible**: For multi-step edits, prefer `superdoc_mutations`. -### Style-aware content creation +### Formatting after create -After creating any content (paragraph, heading), you MUST match the document's formatting: +After `superdoc_create`, use the `ref` from the response directly: -1. **Create** the content with `superdoc_create` -2. **Search** for the new text with `superdoc_search` to get a ref handle -3. **Apply formatting** with `superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", fontSize: ...}})` using the fontFamily and fontSize values from the neighboring blocks in the blocks data +``` +superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", color: "..."}}) +``` -Example: if blocks show `fontFamily: "Times New Roman, serif"` and `fontSize: 9.5`, apply those same values to your new content. +- **For paragraphs**: Apply `fontFamily`, `fontSize`, and `color` from neighboring blocks. +- **For headings**: Apply `fontFamily` and `color` from neighboring blocks. Do NOT change `fontSize` — the heading default size is correct. ### Placing content near specific text @@ -82,8 +55,6 @@ To add content near a heading or specific text (e.g., "add a paragraph after the 2. **Get the blockId** from `result.items[0].blocks[0].blockId` 3. **Create content after it**: `superdoc_create({action: "paragraph", text: "...", at: {kind: "after", target: {kind: "block", nodeType: "heading", nodeId: ""}}})` -**Do NOT search by node type and then try to match by position** — this is unreliable in large documents. Always search for the actual text content to find the exact location. - ## Using superdoc_mutations The mutations tool executes a plan of steps atomically. Use `action: "apply"` to execute, or `action: "preview"` to dry-run. @@ -96,22 +67,18 @@ Each step has: ### Workflow: split mutations by logical phase -**Always use `superdoc_search` first** to obtain stable refs, then reference those refs in your mutation steps. - Split mutation calls into logical rounds: 1. **Text mutations first** — all `text.rewrite`, `text.insert`, `text.delete` operations in one `superdoc_mutations` call. 2. **Formatting second** — all `format.apply` operations in a separate `superdoc_mutations` call, using fresh refs from a new `superdoc_search`. -**Why**: Text edits change content and invalidate addresses. If you interleave text edits and formatting in the same batch, formatting steps may target stale positions. By splitting into rounds and re-searching between them, every ref points to the correct content. - ## Using superdoc_comment The comment tool manages comment threads in the document. - **`create`** — Create a new comment thread anchored to a target range. -- **`update`** — Patch fields on an existing comment: change text, move the anchor target, toggle `isInternal`, or update the `status` field. +- **`update`** — Patch fields on an existing comment. - **`delete`** — Remove a comment or reply by ID. -- **`get`** — Retrieve a single comment thread by ID, including replies. +- **`get`** — Retrieve a single comment thread by ID. - **`list`** — List all comment threads in the document. ### Creating comments @@ -127,23 +94,19 @@ To add a comment on specific text: }) ``` -**Only pass `action`, `text`, and `target` for creating a new comment.** Do not pass other params — they belong to different comment actions. +**Only pass `action`, `text`, and `target` for creating a new comment.** ### Resolving comments -To resolve a comment, use `action: "update"` with `{ commentId: "", status: "resolved" }`. There is no separate resolve action — it's a status field on the `update` action. +To resolve a comment, use `action: "update"` with `{ commentId: "", status: "resolved" }`. ## Important rules -- **Refs expire after any mutation.** Always re-search after each edit to get fresh refs. When applying the same change to multiple matches (e.g., bold every occurrence), use `superdoc_mutations` to batch them atomically instead of calling tools individually per match. -- **Replace all occurrences** of the same text with a single mutation step using `require: "all"`, not multiple steps targeting the same pattern (which causes overlap conflicts). -- **Search patterns are plain text**, not markdown. Don't include `#`, `**`, or formatting markers in search patterns. -- **`within` scopes to a single block**, not a section. To find text in a section, search the full document for the text directly. -- **Table cells are separate blocks.** Search for individual cell values (e.g., `"28"`), not patterns spanning multiple cells. +- **Refs expire after any mutation.** Always re-search after each edit to get fresh refs. Exception: refs from `superdoc_create` are valid immediately after creation. +- **Replace all occurrences** of the same text with a single mutation step using `require: "all"`, not multiple steps targeting the same pattern. +- **Search patterns are plain text**, not markdown. Don't include `#`, `**`, or formatting markers. +- **`within` scopes to a single block**, not a section. To find text in a section, search the full document. +- **Table cells are separate blocks.** Search for individual cell values, not patterns spanning multiple cells. - **superdoc_search `select.type`** must be `"text"` or `"node"`. To find headings, use `{type: "node", nodeType: "heading"}`, NOT `{type: "heading"}`. -- **Do NOT combine `limit`/`offset` with `require: "first"` or `require: "exactlyOne"`** in superdoc_search. Use `require: "any"` with `limit` for paginated results. -- For `superdoc_format` inline properties, use `null` inside the `inline` object to clear a property (e.g., `"inline": { "bold": null }` removes bold). -- **Creating lists** requires two modes: - - `mode: "fromParagraphs"` — converts existing paragraphs into list items. Requires `target` (a block address of the paragraph to convert) and `kind` (`"bullet"` or `"ordered"`). - - `mode: "empty"` — creates a new empty list at a paragraph position. Requires `at` (a block address: `{kind:"block", nodeType:"paragraph", nodeId:""}`) and `kind`. - - **Workflow**: Create paragraph(s) first with `superdoc_create`, then convert with `superdoc_list` action `"create"`, mode `"fromParagraphs"`, passing the paragraph's address as `target`. +- **Do NOT combine `limit`/`offset` with `require: "first"` or `require: "exactlyOne"`**. Use `require: "any"` with `limit` for paginated results. +- **Creating lists**: Create one paragraph per item first, then call `superdoc_list` action `"create"` with `mode: "fromParagraphs"` for each paragraph. From c7b364ac4062f70e0aef6c46851a5ca64c8b3c07 Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Sat, 21 Mar 2026 09:10:37 -0300 Subject: [PATCH 05/32] feat(document-api): add color field to blocks.list with #000000 default --- packages/document-api/src/contract/schemas.ts | 1 + packages/document-api/src/types/blocks.types.ts | 2 ++ .../document-api-adapters/plan-engine/blocks-wrappers.ts | 7 +++++++ 3 files changed, 10 insertions(+) diff --git a/packages/document-api/src/contract/schemas.ts b/packages/document-api/src/contract/schemas.ts index 09a8b49ebd..82aa151db6 100644 --- a/packages/document-api/src/contract/schemas.ts +++ b/packages/document-api/src/contract/schemas.ts @@ -3041,6 +3041,7 @@ const operationSchemas: Record = { fontFamily: { type: 'string', description: 'Font family from first text run.' }, fontSize: { type: 'number', description: 'Font size from first text run.' }, bold: { type: 'boolean', description: 'True if text is bold.' }, + color: { type: 'string', description: "Text color (e.g. '#000000'). Defaults to black when not set." }, alignment: { type: 'string', description: 'Paragraph alignment.' }, headingLevel: { type: 'number', description: 'Heading level (1-6).' }, }, diff --git a/packages/document-api/src/types/blocks.types.ts b/packages/document-api/src/types/blocks.types.ts index 88c84d37ba..a4ad1905a4 100644 --- a/packages/document-api/src/types/blocks.types.ts +++ b/packages/document-api/src/types/blocks.types.ts @@ -18,6 +18,8 @@ export interface BlockListEntry { fontSize?: number; /** True if the block's text is bold. */ bold?: boolean; + /** Text color (defaults to '#000000' when not explicitly set). */ + color?: string; /** Paragraph alignment. */ alignment?: string; /** Heading level (1-6). Only for headings. */ diff --git a/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts b/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts index f16c8e85cf..64d9f6fdc8 100644 --- a/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts +++ b/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts @@ -72,6 +72,7 @@ function extractBlockFormatting(node: ProseMirrorNode): { fontFamily?: string; fontSize?: number; bold?: boolean; + color?: string; alignment?: string; headingLevel?: number; } { @@ -83,6 +84,7 @@ function extractBlockFormatting(node: ProseMirrorNode): { let fontFamily: string | undefined; let fontSize: number | undefined; let bold: boolean | undefined; + let color: string | undefined; node.descendants((child) => { if (fontFamily !== undefined) return false; @@ -96,10 +98,14 @@ function extractBlockFormatting(node: ProseMirrorNode): { if (typeof raw === 'number' && Number.isFinite(raw)) fontSize = raw; } if (attrs.bold === true) bold = true; + if (typeof attrs.color === 'string' && attrs.color) color = attrs.color; } return false; }); + // Default to black when no explicit color is set + if (!color) color = '#000000'; + let headingLevel: number | undefined; if (typeof styleId === 'string') { const m = HEADING_PATTERN.exec(styleId); @@ -111,6 +117,7 @@ function extractBlockFormatting(node: ProseMirrorNode): { ...(fontFamily ? { fontFamily } : {}), ...(fontSize !== undefined ? { fontSize } : {}), ...(bold ? { bold } : {}), + ...(color ? { color } : {}), ...(pProps?.justification ? { alignment: pProps.justification } : {}), ...(headingLevel ? { headingLevel } : {}), }; From de3cf2f02970056bcb453c4c6a90937dd6403051 Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Sat, 21 Mar 2026 10:19:52 -0300 Subject: [PATCH 06/32] feat(sdk): introduce browser SDK with initial tools and validation --- .../reference/_generated-manifest.json | 2 +- .../document-api/reference/blocks/list.mdx | 4 + .../document-api/reference/create/heading.mdx | 10 +++ .../reference/create/paragraph.mdx | 10 +++ packages/sdk/langs/browser/package.json | 15 ++++ packages/sdk/langs/browser/src/assets.ts | 25 ++++++ packages/sdk/langs/browser/src/dispatch.ts | 47 ++++++++++ packages/sdk/langs/browser/src/index.ts | 6 ++ .../sdk/langs/browser/src/system-prompt.ts | 89 ++++++------------- packages/sdk/langs/browser/src/validate.ts | 81 +++++++++++++++++ packages/sdk/langs/browser/tsconfig.json | 16 ++++ .../src/core/commands/insertHeadingAt.js | 13 ++- .../src/core/commands/insertParagraphAt.js | 12 ++- 13 files changed, 262 insertions(+), 68 deletions(-) create mode 100644 packages/sdk/langs/browser/package.json create mode 100644 packages/sdk/langs/browser/src/assets.ts create mode 100644 packages/sdk/langs/browser/src/dispatch.ts create mode 100644 packages/sdk/langs/browser/src/index.ts create mode 100644 packages/sdk/langs/browser/src/validate.ts create mode 100644 packages/sdk/langs/browser/tsconfig.json diff --git a/apps/docs/document-api/reference/_generated-manifest.json b/apps/docs/document-api/reference/_generated-manifest.json index 18b133472c..b9c617bb0d 100644 --- a/apps/docs/document-api/reference/_generated-manifest.json +++ b/apps/docs/document-api/reference/_generated-manifest.json @@ -986,5 +986,5 @@ } ], "marker": "{/* GENERATED FILE: DO NOT EDIT. Regenerate via `pnpm run docapi:sync`. */}", - "sourceHash": "d4231e3456244bc979f6e72db4da7ca682ec851ea2fefebb48689c299fbad039" + "sourceHash": "9182a83139a4a500218c753103fa6da6c4f440a28c1ed00ca4a64996318c6bfe" } diff --git a/apps/docs/document-api/reference/blocks/list.mdx b/apps/docs/document-api/reference/blocks/list.mdx index 37189468ea..8c8e5e8b90 100644 --- a/apps/docs/document-api/reference/blocks/list.mdx +++ b/apps/docs/document-api/reference/blocks/list.mdx @@ -130,6 +130,10 @@ Returns a BlocksListResult with total block count, an ordered array of block ent "description": "True if text is bold.", "type": "boolean" }, + "color": { + "description": "Text color (e.g. '#000000'). Defaults to black when not set.", + "type": "string" + }, "fontFamily": { "description": "Font family from first text run.", "type": "string" diff --git a/apps/docs/document-api/reference/create/heading.mdx b/apps/docs/document-api/reference/create/heading.mdx index ec2050b751..1d7f43d48c 100644 --- a/apps/docs/document-api/reference/create/heading.mdx +++ b/apps/docs/document-api/reference/create/heading.mdx @@ -62,6 +62,7 @@ Returns a CreateHeadingResult with the new heading block ID and address. | `insertionPoint.range` | Range | yes | Range | | `insertionPoint.range.end` | integer | yes | | | `insertionPoint.range.start` | integer | yes | | +| `ref` | string | no | | | `success` | `true` | yes | Constant: `true` | | `trackedChangeRefs` | TrackedChangeAddress[] | no | | @@ -92,6 +93,7 @@ Returns a CreateHeadingResult with the new heading block ID and address. "start": 0 } }, + "ref": "handle:abc123", "success": true, "trackedChangeRefs": [ { @@ -222,6 +224,10 @@ Returns a CreateHeadingResult with the new heading block ID and address. "insertionPoint": { "$ref": "#/$defs/TextAddress" }, + "ref": { + "description": "Ref handle for the created block. Pass directly to superdoc_format or superdoc_edit ref param without searching.", + "type": "string" + }, "success": { "const": true }, @@ -287,6 +293,10 @@ Returns a CreateHeadingResult with the new heading block ID and address. "insertionPoint": { "$ref": "#/$defs/TextAddress" }, + "ref": { + "description": "Ref handle for the created block. Pass directly to superdoc_format or superdoc_edit ref param without searching.", + "type": "string" + }, "success": { "const": true }, diff --git a/apps/docs/document-api/reference/create/paragraph.mdx b/apps/docs/document-api/reference/create/paragraph.mdx index 142e1562aa..e2d1c4a43a 100644 --- a/apps/docs/document-api/reference/create/paragraph.mdx +++ b/apps/docs/document-api/reference/create/paragraph.mdx @@ -60,6 +60,7 @@ Returns a CreateParagraphResult with the new paragraph block ID and address. | `paragraph.kind` | `"block"` | yes | Constant: `"block"` | | `paragraph.nodeId` | string | yes | | | `paragraph.nodeType` | `"paragraph"` | yes | Constant: `"paragraph"` | +| `ref` | string | no | | | `success` | `true` | yes | Constant: `true` | | `trackedChangeRefs` | TrackedChangeAddress[] | no | | @@ -90,6 +91,7 @@ Returns a CreateParagraphResult with the new paragraph block ID and address. "nodeId": "node-def456", "nodeType": "paragraph" }, + "ref": "handle:abc123", "success": true, "trackedChangeRefs": [ { @@ -211,6 +213,10 @@ Returns a CreateParagraphResult with the new paragraph block ID and address. "paragraph": { "$ref": "#/$defs/ParagraphAddress" }, + "ref": { + "description": "Ref handle for the created block. Pass directly to superdoc_format or superdoc_edit ref param without searching.", + "type": "string" + }, "success": { "const": true }, @@ -276,6 +282,10 @@ Returns a CreateParagraphResult with the new paragraph block ID and address. "paragraph": { "$ref": "#/$defs/ParagraphAddress" }, + "ref": { + "description": "Ref handle for the created block. Pass directly to superdoc_format or superdoc_edit ref param without searching.", + "type": "string" + }, "success": { "const": true }, diff --git a/packages/sdk/langs/browser/package.json b/packages/sdk/langs/browser/package.json new file mode 100644 index 0000000000..557a824873 --- /dev/null +++ b/packages/sdk/langs/browser/package.json @@ -0,0 +1,15 @@ +{ + "name": "@superdoc-dev/sdk-browser", + "version": "1.0.0-alpha.1", + "private": true, + "type": "module", + "main": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": "./src/index.ts" + }, + "sideEffects": false, + "dependencies": { + "@superdoc/document-api": "workspace:*" + } +} diff --git a/packages/sdk/langs/browser/src/assets.ts b/packages/sdk/langs/browser/src/assets.ts new file mode 100644 index 0000000000..e481cb195d --- /dev/null +++ b/packages/sdk/langs/browser/src/assets.ts @@ -0,0 +1,25 @@ +// Tool artifacts re-exported from the workspace tools directory. +// JSON imports are resolved at build time by the consumer's bundler. +// The system prompt is embedded as a TS string constant (generated from system-prompt.md). + +// @ts-ignore — JSON import resolved by bundler +import catalog from '../tools/catalog.json'; +// @ts-ignore — JSON import resolved by bundler +import toolsOpenai from '../tools/tools.openai.json'; +import { SYSTEM_PROMPT } from './system-prompt'; +import type { ToolCatalog } from './validate'; + +/** Get the tool catalog (used internally for validation). */ +export function getCatalogJson(): ToolCatalog { + return catalog as ToolCatalog; +} + +/** Get the OpenAI-formatted tool definitions for chat completions. */ +export function getOpenAITools(): any[] { + return (toolsOpenai as { tools: any[] }).tools; +} + +/** Get the system prompt for the agent. */ +export function getSystemPrompt(): string { + return SYSTEM_PROMPT; +} diff --git a/packages/sdk/langs/browser/src/dispatch.ts b/packages/sdk/langs/browser/src/dispatch.ts new file mode 100644 index 0000000000..b943cfe63a --- /dev/null +++ b/packages/sdk/langs/browser/src/dispatch.ts @@ -0,0 +1,47 @@ +import { dispatchIntentTool } from './intent-dispatch'; +import { validateToolArgs } from './validate'; +import { getCatalogJson } from './assets'; +import type { ToolCatalogEntry } from './validate'; + +/** + * A minimal interface matching DocumentApi.invoke(). + * Avoids a hard compile-time dependency on @superdoc/document-api + * while still being type-safe for consumers that pass a real DocumentApi. + */ +export interface InvokableDocumentApi { + invoke(request: { operationId: string; input: unknown; options?: unknown }): unknown; +} + +/** + * Dispatch an LLM tool call against an in-browser DocumentApi. + * + * Drop-in replacement for the Node SDK's dispatchSuperDocTool. + * Instead of routing through a CLI process, this calls documentApi.invoke() directly. + * + * The catalog is loaded automatically from the bundled JSON — no setup needed. + */ +export function dispatchSuperDocTool( + documentApi: InvokableDocumentApi, + toolName: string, + args: Record = {}, +): unknown { + const catalog = getCatalogJson(); + const tool = catalog.tools.find((t: ToolCatalogEntry) => t.toolName === toolName); + if (!tool) { + throw new Error( + `Unknown tool: "${toolName}". Available: ${catalog.tools.map((t: ToolCatalogEntry) => t.toolName).join(', ')}`, + ); + } + + validateToolArgs(toolName, args, tool); + + // Strip doc/sessionId — not relevant in browser context + const { doc: _doc, sessionId: _sid, ...cleanArgs } = args; + + return dispatchIntentTool(toolName, cleanArgs, (operationId, input) => { + // Intent dispatch produces "doc.insert", "doc.format.apply", etc. + // DocumentApi.invoke() expects the id without "doc." prefix: "insert", "format.apply" + const stripped = operationId.startsWith('doc.') ? operationId.slice(4) : operationId; + return documentApi.invoke({ operationId: stripped, input }); + }); +} diff --git a/packages/sdk/langs/browser/src/index.ts b/packages/sdk/langs/browser/src/index.ts new file mode 100644 index 0000000000..4d3d67c8c1 --- /dev/null +++ b/packages/sdk/langs/browser/src/index.ts @@ -0,0 +1,6 @@ +export { dispatchSuperDocTool } from './dispatch'; +export type { InvokableDocumentApi } from './dispatch'; +export { dispatchIntentTool } from './intent-dispatch'; +export { validateToolArgs } from './validate'; +export type { ToolCatalog, ToolCatalogEntry, OperationEntry } from './validate'; +export { getSystemPrompt, getOpenAITools, getCatalogJson } from './assets'; diff --git a/packages/sdk/langs/browser/src/system-prompt.ts b/packages/sdk/langs/browser/src/system-prompt.ts index 7eafbd7a7b..172e213e2b 100644 --- a/packages/sdk/langs/browser/src/system-prompt.ts +++ b/packages/sdk/langs/browser/src/system-prompt.ts @@ -9,9 +9,9 @@ export const SYSTEM_PROMPT = `You are a document editing assistant. You have a D | Tool | Purpose | |------|---------| | superdoc_search | Find text or nodes in the document | -| superdoc_get_content | Read document content (text, markdown, html, info) | +| superdoc_get_content | Read document content (text, markdown, html, info, blocks) | | superdoc_edit | Insert, replace, delete text, undo/redo | -| superdoc_create | Create paragraphs or headings (with optional styleId) | +| superdoc_create | Create paragraphs or headings (returns a ref for immediate formatting) | | superdoc_format | Apply inline and paragraph formatting, set named styles | | superdoc_list | Create and manipulate bullet/numbered lists | | superdoc_comment | Create, update, delete, and list comments | @@ -24,57 +24,30 @@ Every editing tool needs a **target** — an address telling the API *where* to ### Getting targets -Use \`superdoc_search\` to find content. Each match item returns: - -- **\`handle.ref\`** — a ref string for text-level operations. Pass the ref string as: - - \`ref\` parameter on \`superdoc_format\` (for inline styles like bold, italic) - - \`ref\` parameter on \`superdoc_edit\` (for text replacement, deletion) - - Example: \`superdoc_format({action: "inline", ref: "text:eyJ...", inline: {bold: true}})\` -- **\`address\`** — a block-level address like \`{ "kind": "block", "nodeType": "paragraph", "nodeId": "abc123" }\`. Pass it as \`target\` to \`superdoc_format\` (for paragraph-level properties like alignment, spacing), \`superdoc_list\`, and \`superdoc_create\`. - -### Text search results - -When searching for text (\`type: "text"\`), each match includes: -- \`snippet\` — the matched text with surrounding context -- \`highlightRange\` — \`{ start, end }\` character offsets of the match -- \`blocks\` — array of \`{ blockId, range }\` entries showing which blocks contain the match - -### Node search results - -When searching for nodes (\`type: "node"\`), each match includes: -- \`address\` — the block address of the matched node - -## Multi-action tools - -Most tools support multiple actions via an \`action\` parameter. For example: -- \`superdoc_get_content\` with \`action: "text"\` returns plain text; \`action: "info"\` returns document metadata and styles. -- \`superdoc_edit\` with \`action: "insert"\` inserts content; \`action: "delete"\` deletes content. -- \`superdoc_format\` with \`action: "inline"\` applies inline formatting; \`action: "set_style"\` applies a named paragraph style. - -Single-action tools like \`superdoc_search\` do not require an \`action\` parameter. +- **From \`superdoc_search\`**: Returns \`handle.ref\` — pass as \`ref\` param to \`superdoc_format\` or \`superdoc_edit\`. +- **From \`superdoc_create\`**: Returns \`ref\` in the response — pass directly to \`superdoc_format\`. No search needed. +- **From blocks data**: Each block has a \`nodeId\` — use it to build block addresses for \`superdoc_create\` \`at\` positioning. ## Workflow -**ALWAYS start by calling \`superdoc_get_content({action: "blocks"})\` before any other tool.** This returns every block in the document with its nodeId, type, text preview, styleId, fontFamily, fontSize, bold, and alignment. You need this to: -- Know the document's structure and block IDs for targeting -- See what fonts, sizes, and styles are used so new content matches -- Find blocks by their text preview without a separate search +**ALWAYS start by calling \`superdoc_get_content({action: "blocks"})\` before any other tool.** This returns every block with its nodeId, type, text, fontFamily, fontSize, bold, color, and alignment. After getting blocks: -1. **Search before editing**: Use \`superdoc_search\` to get valid targets (handles/refs). -2. **Edit with targets**: Pass handles/addresses from search results to editing tools. +1. **Edit existing content**: Use \`superdoc_search\` to get refs, then \`superdoc_edit\` or \`superdoc_format\`. +2. **Create new content**: Use \`superdoc_create\`, then use the \`ref\` from the response to apply formatting. DO NOT search after create. 3. **Re-search after each mutation**: Refs expire after any edit. Always search again before the next operation. 4. **Batch when possible**: For multi-step edits, prefer \`superdoc_mutations\`. -### Style-aware content creation +### Formatting after create -After creating any content (paragraph, heading), you MUST match the document's formatting: +After \`superdoc_create\`, use the \`ref\` from the response directly: -1. **Create** the content with \`superdoc_create\` -2. **Search** for the new text with \`superdoc_search\` to get a ref handle -3. **Apply formatting** with \`superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", fontSize: ...}})\` using the fontFamily and fontSize values from the neighboring blocks in the blocks data +\`\`\` +superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", color: "..."}}) +\`\`\` -Example: if blocks show \`fontFamily: "Times New Roman, serif"\` and \`fontSize: 9.5\`, apply those same values to your new content. +- **For paragraphs**: Apply \`fontFamily\`, \`fontSize\`, and \`color\` from neighboring blocks. +- **For headings**: Apply \`fontFamily\` and \`color\` from neighboring blocks. Do NOT change \`fontSize\` — the heading default size is correct. ### Placing content near specific text @@ -84,8 +57,6 @@ To add content near a heading or specific text (e.g., "add a paragraph after the 2. **Get the blockId** from \`result.items[0].blocks[0].blockId\` 3. **Create content after it**: \`superdoc_create({action: "paragraph", text: "...", at: {kind: "after", target: {kind: "block", nodeType: "heading", nodeId: ""}}})\` -**Do NOT search by node type and then try to match by position** — this is unreliable in large documents. Always search for the actual text content to find the exact location. - ## Using superdoc_mutations The mutations tool executes a plan of steps atomically. Use \`action: "apply"\` to execute, or \`action: "preview"\` to dry-run. @@ -98,22 +69,18 @@ Each step has: ### Workflow: split mutations by logical phase -**Always use \`superdoc_search\` first** to obtain stable refs, then reference those refs in your mutation steps. - Split mutation calls into logical rounds: 1. **Text mutations first** — all \`text.rewrite\`, \`text.insert\`, \`text.delete\` operations in one \`superdoc_mutations\` call. 2. **Formatting second** — all \`format.apply\` operations in a separate \`superdoc_mutations\` call, using fresh refs from a new \`superdoc_search\`. -**Why**: Text edits change content and invalidate addresses. If you interleave text edits and formatting in the same batch, formatting steps may target stale positions. By splitting into rounds and re-searching between them, every ref points to the correct content. - ## Using superdoc_comment The comment tool manages comment threads in the document. - **\`create\`** — Create a new comment thread anchored to a target range. -- **\`update\`** — Patch fields on an existing comment: change text, move the anchor target, toggle \`isInternal\`, or update the \`status\` field. +- **\`update\`** — Patch fields on an existing comment. - **\`delete\`** — Remove a comment or reply by ID. -- **\`get\`** — Retrieve a single comment thread by ID, including replies. +- **\`get\`** — Retrieve a single comment thread by ID. - **\`list\`** — List all comment threads in the document. ### Creating comments @@ -129,24 +96,20 @@ To add a comment on specific text: }) \`\`\` -**Only pass \`action\`, \`text\`, and \`target\` for creating a new comment.** Do not pass other params — they belong to different comment actions. +**Only pass \`action\`, \`text\`, and \`target\` for creating a new comment.** ### Resolving comments -To resolve a comment, use \`action: "update"\` with \`{ commentId: "", status: "resolved" }\`. There is no separate resolve action — it's a status field on the \`update\` action. +To resolve a comment, use \`action: "update"\` with \`{ commentId: "", status: "resolved" }\`. ## Important rules -- **Refs expire after any mutation.** Always re-search after each edit to get fresh refs. When applying the same change to multiple matches (e.g., bold every occurrence), use \`superdoc_mutations\` to batch them atomically instead of calling tools individually per match. -- **Replace all occurrences** of the same text with a single mutation step using \`require: "all"\`, not multiple steps targeting the same pattern (which causes overlap conflicts). -- **Search patterns are plain text**, not markdown. Don't include \`#\`, \`**\`, or formatting markers in search patterns. -- **\`within\` scopes to a single block**, not a section. To find text in a section, search the full document for the text directly. -- **Table cells are separate blocks.** Search for individual cell values (e.g., \`"28"\`), not patterns spanning multiple cells. +- **Refs expire after any mutation.** Always re-search after each edit to get fresh refs. Exception: refs from \`superdoc_create\` are valid immediately after creation. +- **Replace all occurrences** of the same text with a single mutation step using \`require: "all"\`, not multiple steps targeting the same pattern. +- **Search patterns are plain text**, not markdown. Don't include \`#\`, \`**\`, or formatting markers. +- **\`within\` scopes to a single block**, not a section. To find text in a section, search the full document. +- **Table cells are separate blocks.** Search for individual cell values, not patterns spanning multiple cells. - **superdoc_search \`select.type\`** must be \`"text"\` or \`"node"\`. To find headings, use \`{type: "node", nodeType: "heading"}\`, NOT \`{type: "heading"}\`. -- **Do NOT combine \`limit\`/\`offset\` with \`require: "first"\` or \`require: "exactlyOne"\`** in superdoc_search. Use \`require: "any"\` with \`limit\` for paginated results. -- For \`superdoc_format\` inline properties, use \`null\` inside the \`inline\` object to clear a property (e.g., \`"inline": { "bold": null }\` removes bold). -- **Creating lists** requires two modes: - - \`mode: "fromParagraphs"\` — converts existing paragraphs into list items. Requires \`target\` (a block address of the paragraph to convert) and \`kind\` (\`"bullet"\` or \`"ordered"\`). - - \`mode: "empty"\` — creates a new empty list at a paragraph position. Requires \`at\` (a block address: \`{kind:"block", nodeType:"paragraph", nodeId:""}\`) and \`kind\`. - - **Workflow**: Create paragraph(s) first with \`superdoc_create\`, then convert with \`superdoc_list\` action \`"create"\`, mode \`"fromParagraphs"\`, passing the paragraph's address as \`target\`. +- **Do NOT combine \`limit\`/\`offset\` with \`require: "first"\` or \`require: "exactlyOne"\`**. Use \`require: "any"\` with \`limit\` for paginated results. +- **Creating lists**: Create one paragraph per item first, then call \`superdoc_list\` action \`"create"\` with \`mode: "fromParagraphs"\` for each paragraph. `; diff --git a/packages/sdk/langs/browser/src/validate.ts b/packages/sdk/langs/browser/src/validate.ts new file mode 100644 index 0000000000..fd34b655b7 --- /dev/null +++ b/packages/sdk/langs/browser/src/validate.ts @@ -0,0 +1,81 @@ +// Extracted from packages/sdk/langs/node/src/tools.ts — pure logic, no Node.js deps. + +export type ToolCatalog = { + contractVersion: string; + generatedAt: string | null; + toolCount: number; + tools: ToolCatalogEntry[]; +}; + +export type ToolCatalogEntry = { + toolName: string; + description: string; + inputSchema: Record; + mutates: boolean; + operations: OperationEntry[]; +}; + +export type OperationEntry = { + operationId: string; + intentAction: string; + required?: string[]; + requiredOneOf?: string[][]; +}; + +function isRecord(value: unknown): value is Record { + return typeof value === 'object' && value != null && !Array.isArray(value); +} + +export function validateToolArgs(toolName: string, args: Record, tool: ToolCatalogEntry): void { + const schema = tool.inputSchema; + const properties = isRecord(schema.properties) ? schema.properties : {}; + const required: string[] = Array.isArray(schema.required) ? (schema.required as string[]) : []; + + // 1. Reject unknown keys + const knownKeys = new Set(Object.keys(properties)); + const unknownKeys = Object.keys(args).filter((k) => !knownKeys.has(k)); + if (unknownKeys.length > 0) { + throw new Error(`Unknown argument(s) for ${toolName}: ${unknownKeys.join(', ')}`); + } + + // 2. Reject missing universally-required keys + const missingKeys = required.filter((k) => args[k] == null); + if (missingKeys.length > 0) { + throw new Error(`Missing required argument(s) for ${toolName}: ${missingKeys.join(', ')}`); + } + + // 3. Per-operation required constraints + const action = args.action; + let op: OperationEntry | undefined; + if (typeof action === 'string' && tool.operations.length > 1) { + op = tool.operations.find((o) => o.intentAction === action); + } else if (tool.operations.length === 1) { + op = tool.operations[0]; + } + + if (op) { + validateOperationRequired(toolName, action, args, op); + } +} + +function validateOperationRequired( + toolName: string, + action: unknown, + args: Record, + op: OperationEntry, +): void { + const actionLabel = typeof action === 'string' ? ` action "${action}"` : ''; + + if (op.requiredOneOf && op.requiredOneOf.length > 0) { + const satisfied = op.requiredOneOf.some((branch) => branch.every((k) => args[k] != null)); + if (!satisfied) { + const options = op.requiredOneOf.map((b) => b.join(' + ')).join(' | '); + throw new Error(`Missing required argument(s) for ${toolName}${actionLabel}: must provide one of: ${options}`); + } + } else if (op.required && op.required.length > 0) { + const missingActionKeys = op.required.filter((k) => args[k] == null); + if (missingActionKeys.length > 0) { + throw new Error(`Missing required argument(s) for ${toolName}${actionLabel}: ${missingActionKeys.join(', ')}`); + } + } +} diff --git a/packages/sdk/langs/browser/tsconfig.json b/packages/sdk/langs/browser/tsconfig.json new file mode 100644 index 0000000000..e0b87bdf8d --- /dev/null +++ b/packages/sdk/langs/browser/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "bundler", + "lib": ["ES2020", "DOM"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "noEmit": true, + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve" + }, + "include": ["src/**/*.ts"] +} diff --git a/packages/super-editor/src/core/commands/insertHeadingAt.js b/packages/super-editor/src/core/commands/insertHeadingAt.js index 102710d477..dd166a659f 100644 --- a/packages/super-editor/src/core/commands/insertHeadingAt.js +++ b/packages/super-editor/src/core/commands/insertHeadingAt.js @@ -1,8 +1,10 @@ +import { findNearbyMarks } from '../helpers/findNearbyMarks.js'; + /** * Insert a heading node at an absolute document position. * - * Internally, headings are paragraph nodes with a heading styleId - * (`Heading1` through `Heading6`) set on `paragraphProperties`. + * Copies text marks (fontFamily, color) from the nearest heading + * or body paragraph so new headings match the document's font. * * @param {{ pos: number; level: number; text?: string; sdBlockId?: string; paraId?: string; tracked?: boolean }} options * @returns {import('./types/index.js').Command} @@ -21,7 +23,12 @@ export const insertHeadingAt = paragraphProperties: { styleId: `Heading${level}` }, }; const normalizedText = typeof text === 'string' ? text : ''; - const textNode = normalizedText.length > 0 ? state.schema.text(normalizedText) : null; + + let textNode = null; + if (normalizedText.length > 0) { + const marks = findNearbyMarks(state.doc, pos, { prefer: 'heading' }); + textNode = marks.length > 0 ? state.schema.text(normalizedText, marks) : state.schema.text(normalizedText); + } let paragraphNode; try { diff --git a/packages/super-editor/src/core/commands/insertParagraphAt.js b/packages/super-editor/src/core/commands/insertParagraphAt.js index 2d89b53f87..e6c834a4d9 100644 --- a/packages/super-editor/src/core/commands/insertParagraphAt.js +++ b/packages/super-editor/src/core/commands/insertParagraphAt.js @@ -1,6 +1,11 @@ +import { findNearbyMarks } from '../helpers/findNearbyMarks.js'; + /** * Insert a paragraph node at an absolute document position. * + * Copies text marks (fontFamily, fontSize, color) from the nearest + * body paragraph so new content matches the document's formatting. + * * @param {{ pos: number; text?: string; sdBlockId?: string; paraId?: string; tracked?: boolean }} options * @returns {import('./types/index.js').Command} */ @@ -16,7 +21,12 @@ export const insertParagraphAt = ...(paraId ? { paraId } : undefined), }; const normalizedText = typeof text === 'string' ? text : ''; - const textNode = normalizedText.length > 0 ? state.schema.text(normalizedText) : null; + + let textNode = null; + if (normalizedText.length > 0) { + const marks = findNearbyMarks(state.doc, pos, { prefer: 'body' }); + textNode = marks.length > 0 ? state.schema.text(normalizedText, marks) : state.schema.text(normalizedText); + } let paragraphNode; try { From cd67aebcffc1dde693934593c67b2e84aa3ae74d Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Sat, 21 Mar 2026 12:54:45 -0300 Subject: [PATCH 07/32] refactor(document-api): update operation parameters and documentation for insert and replace operations --- apps/cli/src/cli/operation-params.ts | 7 +- .../reference/_generated-manifest.json | 2 +- .../document-api/reference/blocks/list.mdx | 4 + apps/docs/document-api/reference/index.mdx | 2 +- apps/docs/document-api/reference/insert.mdx | 2 +- apps/docs/document-api/reference/replace.mdx | 4 +- apps/docs/document-engine/sdks.mdx | 4 +- .../src/contract/operation-definitions.ts | 16 ++- packages/document-api/src/contract/schemas.ts | 8 +- .../document-api/src/types/blocks.types.ts | 2 + .../sdk/codegen/src/generate-intent-tools.mjs | 2 +- packages/sdk/langs/browser/src/dispatch.ts | 14 +- .../sdk/langs/browser/src/system-prompt.ts | 10 +- packages/sdk/tools/system-prompt.md | 12 +- .../src/core/commands/insertHeadingAt.js | 16 ++- .../src/core/helpers/findNearbyMarks.js | 1 + .../__conformance__/schema-validator.ts | 3 + .../plan-engine/blocks-wrappers.ts | 38 ++++-- .../plan-engine/create-wrappers.ts | 124 ++++++++++++++++++ 19 files changed, 230 insertions(+), 41 deletions(-) diff --git a/apps/cli/src/cli/operation-params.ts b/apps/cli/src/cli/operation-params.ts index 3e6bf42288..f73d986338 100644 --- a/apps/cli/src/cli/operation-params.ts +++ b/apps/cli/src/cli/operation-params.ts @@ -539,16 +539,17 @@ const EXTRA_CLI_PARAMS: Partial> = { ], // Text-range operations: flat flags (--block-id, --start, --end) as shortcuts for --target-json 'doc.insert': [ - ...TEXT_TARGET_FLAT_PARAMS, + ...TEXT_TARGET_FLAT_PARAMS_AGENT_HIDDEN, { name: 'offset', kind: 'flag', type: 'number', description: 'Character offset for insertion (alias for --start/--end with same value).', + agentVisible: false as const, }, ], - 'doc.replace': [...TEXT_TARGET_FLAT_PARAMS], - 'doc.delete': [...TEXT_TARGET_FLAT_PARAMS], + 'doc.replace': [...TEXT_TARGET_FLAT_PARAMS_AGENT_HIDDEN], + 'doc.delete': [...TEXT_TARGET_FLAT_PARAMS_AGENT_HIDDEN], 'doc.styles.apply': [ { name: 'target', diff --git a/apps/docs/document-api/reference/_generated-manifest.json b/apps/docs/document-api/reference/_generated-manifest.json index b9c617bb0d..dd2229ac09 100644 --- a/apps/docs/document-api/reference/_generated-manifest.json +++ b/apps/docs/document-api/reference/_generated-manifest.json @@ -986,5 +986,5 @@ } ], "marker": "{/* GENERATED FILE: DO NOT EDIT. Regenerate via `pnpm run docapi:sync`. */}", - "sourceHash": "9182a83139a4a500218c753103fa6da6c4f440a28c1ed00ca4a64996318c6bfe" + "sourceHash": "cd730056677977f863b9e7bf54f9e372f7ea9aefb18246cc99bb3d04eda405e5" } diff --git a/apps/docs/document-api/reference/blocks/list.mdx b/apps/docs/document-api/reference/blocks/list.mdx index 8c8e5e8b90..69ba1a7fad 100644 --- a/apps/docs/document-api/reference/blocks/list.mdx +++ b/apps/docs/document-api/reference/blocks/list.mdx @@ -169,6 +169,10 @@ Returns a BlocksListResult with total block count, an ordered array of block ent "ordinal": { "type": "number" }, + "ref": { + "description": "Ref handle for this block. Pass directly to superdoc_format or superdoc_edit ref param. Only present for non-empty blocks.", + "type": "string" + }, "styleId": { "description": "Named paragraph style.", "oneOf": [ diff --git a/apps/docs/document-api/reference/index.mdx b/apps/docs/document-api/reference/index.mdx index f8d6fee0bb..75cdcf8a52 100644 --- a/apps/docs/document-api/reference/index.mdx +++ b/apps/docs/document-api/reference/index.mdx @@ -70,7 +70,7 @@ The tables below are grouped by namespace. | info | editor.doc.info(...) | Return document summary info including word, character, paragraph, heading, table, image, comment, tracked-change, SDT-field, list, and page counts, plus outline and capabilities. | | clearContent | editor.doc.clearContent(...) | Clear all document body content, leaving a single empty paragraph. | | insert | editor.doc.insert(...) | Insert content into the document. Two input shapes: text-based (value + type) inserts inline content at a SelectionTarget or ref position within an existing block; structural SDFragment (content) inserts one or more blocks as siblings relative to a BlockNodeAddress target. When target/ref is omitted, content appends at the end of the document. Text mode supports text (default), markdown, and html content types via the `type` field. Structural mode uses `placement` (before/after/insideStart/insideEnd) to position relative to the target block. | -| replace | editor.doc.replace(...) | Replace content at a contiguous document selection. Text path accepts a SelectionTarget or ref plus replacement text. Structural path accepts a BlockNodeAddress (replaces whole block), SelectionTarget (expands to full covered block boundaries), or ref plus SDFragment content. | +| replace | editor.doc.replace(...) | Replace text using a ref. To replace an entire block, use its ref from superdoc_get_content blocks. To replace a text match, use handle.ref from superdoc_search. Do NOT use {kind:"block"} as target — it only works with structural content, not text. | | delete | editor.doc.delete(...) | Delete content at a contiguous document selection. Accepts a SelectionTarget or mutation-ready ref. Supports cross-block deletion and optional block-edge expansion via behavior mode. | #### Blocks diff --git a/apps/docs/document-api/reference/insert.mdx b/apps/docs/document-api/reference/insert.mdx index 30e608e9f4..3f0d0fc77e 100644 --- a/apps/docs/document-api/reference/insert.mdx +++ b/apps/docs/document-api/reference/insert.mdx @@ -233,7 +233,7 @@ Returns an SDMutationReceipt with applied status; resolution reports the inserte "$ref": "#/$defs/StoryLocator" }, "ref": { - "description": "Handle ref string returned by a prior search/query result.", + "description": "Handle ref from superdoc_search result (pass handle.ref value directly). Preferred over building a target object.", "type": "string" }, "type": { diff --git a/apps/docs/document-api/reference/replace.mdx b/apps/docs/document-api/reference/replace.mdx index de53ace0bb..7b3ebf43ee 100644 --- a/apps/docs/document-api/reference/replace.mdx +++ b/apps/docs/document-api/reference/replace.mdx @@ -1,14 +1,14 @@ --- title: replace sidebarTitle: replace -description: Replace content at a contiguous document selection. Text path accepts a SelectionTarget or ref plus replacement text. Structural path accepts a BlockNodeAddress (replaces whole block), SelectionTarget (expands to full covered block boundaries), or ref plus SDFragment content. +description: "Replace text using a ref. To replace an entire block, use its ref from superdoc_get_content blocks. To replace a text match, use handle.ref from superdoc_search. Do NOT use {kind:\"block\"} as target — it only works with structural content, not text." --- {/* GENERATED FILE: DO NOT EDIT. Regenerate via `pnpm run docapi:sync`. */} ## Summary -Replace content at a contiguous document selection. Text path accepts a SelectionTarget or ref plus replacement text. Structural path accepts a BlockNodeAddress (replaces whole block), SelectionTarget (expands to full covered block boundaries), or ref plus SDFragment content. +Replace text using a ref. To replace an entire block, use its ref from superdoc_get_content blocks. To replace a text match, use handle.ref from superdoc_search. Do NOT use \{kind:"block"\} as target — it only works with structural content, not text. - Operation ID: `replace` - API member path: `editor.doc.replace(...)` diff --git a/apps/docs/document-engine/sdks.mdx b/apps/docs/document-engine/sdks.mdx index 6258e0cf81..b046c31031 100644 --- a/apps/docs/document-engine/sdks.mdx +++ b/apps/docs/document-engine/sdks.mdx @@ -383,7 +383,7 @@ The SDKs expose all operations from the [Document API](/document-api/overview) p | `doc.info` | `info` | Return document summary info including word, character, paragraph, heading, table, image, comment, tracked-change, SDT-field, list, and page counts, plus outline and capabilities. | | `doc.clearContent` | `clear-content` | Clear all document body content, leaving a single empty paragraph. | | `doc.insert` | `insert` | Insert content into the document. Two input shapes: text-based (value + type) inserts inline content at a SelectionTarget or ref position within an existing block; structural SDFragment (content) inserts one or more blocks as siblings relative to a BlockNodeAddress target. When target/ref is omitted, content appends at the end of the document. Text mode supports text (default), markdown, and html content types via the `type` field. Structural mode uses `placement` (before/after/insideStart/insideEnd) to position relative to the target block. | -| `doc.replace` | `replace` | Replace content at a contiguous document selection. Text path accepts a SelectionTarget or ref plus replacement text. Structural path accepts a BlockNodeAddress (replaces whole block), SelectionTarget (expands to full covered block boundaries), or ref plus SDFragment content. | +| `doc.replace` | `replace` | Replace text using a ref. To replace an entire block, use its ref from superdoc_get_content blocks. To replace a text match, use handle.ref from superdoc_search. Do NOT use {kind:"block"} as target — it only works with structural content, not text. | | `doc.delete` | `delete` | Delete content at a contiguous document selection. Accepts a SelectionTarget or mutation-ready ref. Supports cross-block deletion and optional block-edge expansion via behavior mode. | | `doc.blocks.list` | `blocks list` | List top-level blocks in document order with IDs, types, and text previews. Supports pagination via offset/limit and optional nodeType filtering. | | `doc.blocks.delete` | `blocks delete` | Delete an entire block node (paragraph, heading, list item, table, image, or sdt) deterministically. | @@ -833,7 +833,7 @@ The SDKs expose all operations from the [Document API](/document-api/overview) p | `doc.info` | `info` | Return document summary info including word, character, paragraph, heading, table, image, comment, tracked-change, SDT-field, list, and page counts, plus outline and capabilities. | | `doc.clear_content` | `clear-content` | Clear all document body content, leaving a single empty paragraph. | | `doc.insert` | `insert` | Insert content into the document. Two input shapes: text-based (value + type) inserts inline content at a SelectionTarget or ref position within an existing block; structural SDFragment (content) inserts one or more blocks as siblings relative to a BlockNodeAddress target. When target/ref is omitted, content appends at the end of the document. Text mode supports text (default), markdown, and html content types via the `type` field. Structural mode uses `placement` (before/after/insideStart/insideEnd) to position relative to the target block. | -| `doc.replace` | `replace` | Replace content at a contiguous document selection. Text path accepts a SelectionTarget or ref plus replacement text. Structural path accepts a BlockNodeAddress (replaces whole block), SelectionTarget (expands to full covered block boundaries), or ref plus SDFragment content. | +| `doc.replace` | `replace` | Replace text using a ref. To replace an entire block, use its ref from superdoc_get_content blocks. To replace a text match, use handle.ref from superdoc_search. Do NOT use {kind:"block"} as target — it only works with structural content, not text. | | `doc.delete` | `delete` | Delete content at a contiguous document selection. Accepts a SelectionTarget or mutation-ready ref. Supports cross-block deletion and optional block-edge expansion via behavior mode. | | `doc.blocks.list` | `blocks list` | List top-level blocks in document order with IDs, types, and text previews. Supports pagination via offset/limit and optional nodeType filtering. | | `doc.blocks.delete` | `blocks delete` | Delete an entire block node (paragraph, heading, list item, table, image, or sdt) deterministically. | diff --git a/packages/document-api/src/contract/operation-definitions.ts b/packages/document-api/src/contract/operation-definitions.ts index 3d7062c10d..8ecb47b9cf 100644 --- a/packages/document-api/src/contract/operation-definitions.ts +++ b/packages/document-api/src/contract/operation-definitions.ts @@ -95,13 +95,17 @@ export const INTENT_GROUP_META: Record = { get_content: { toolName: 'superdoc_get_content', description: - 'Read document content. Use action "info" for structure and styles, "blocks" for all block IDs and types, "text" or "markdown" for content. Call info or blocks before editing.', + 'Read document content. Use action "blocks" to get all blocks with nodeId, formatting, and ref handles for immediate use with superdoc_format or superdoc_edit. Use "text" or "markdown" for full content. Use "info" for document metadata.', + }, + edit: { + toolName: 'superdoc_edit', + description: + 'Insert, replace, delete text, or undo/redo. For replace/delete: use ref param. A search handle.ref only covers the matched text. To replace an entire block (rewrite/shorten), use the block ref from superdoc_get_content blocks instead — it covers the full text.', }, - edit: { toolName: 'superdoc_edit', description: 'Insert, replace, delete text, or undo/redo' }, create: { toolName: 'superdoc_create', description: - 'Create one paragraph or heading. Response includes a ref — use it with superdoc_format (DO NOT search). Apply fontFamily and color from neighboring blocks. Do NOT change fontSize on headings.', + 'Create one paragraph or heading. Response includes a ref and nodeId. After creating, call superdoc_format with the ref to match the document style: copy fontFamily and color from nearby blocks. For headings: only set fontFamily and color (NOT fontSize). For paragraphs: set fontFamily, fontSize, and color. Use superdoc_get_content blocks to read existing formatting. When creating multiple items, use the previous nodeId as the next at target.', }, format: { toolName: 'superdoc_format', @@ -494,9 +498,9 @@ export const OPERATION_DEFINITIONS = { replace: { memberPath: 'replace', description: - 'Replace content at a contiguous document selection. ' + - 'Text path accepts a SelectionTarget or ref plus replacement text. ' + - 'Structural path accepts a BlockNodeAddress (replaces whole block), SelectionTarget (expands to full covered block boundaries), or ref plus SDFragment content.', + 'Replace text using a ref. To replace an entire block, use its ref from superdoc_get_content blocks. ' + + 'To replace a text match, use handle.ref from superdoc_search. ' + + 'Do NOT use {kind:"block"} as target — it only works with structural content, not text.', expectedResult: 'Returns an SDMutationReceipt with applied status; receipt reports NO_OP if the target range already contains identical content.', requiresDocumentContext: true, diff --git a/packages/document-api/src/contract/schemas.ts b/packages/document-api/src/contract/schemas.ts index 82aa151db6..21bc634166 100644 --- a/packages/document-api/src/contract/schemas.ts +++ b/packages/document-api/src/contract/schemas.ts @@ -127,7 +127,8 @@ function optionalTargetLocatorWithPayload( { ref: { type: 'string', - description: 'Handle ref string returned by a prior search/query result.', + description: + 'Handle ref from superdoc_search result (pass handle.ref value directly). Preferred over building a target object.', }, ...payloadProperties, }, @@ -3044,6 +3045,11 @@ const operationSchemas: Record = { color: { type: 'string', description: "Text color (e.g. '#000000'). Defaults to black when not set." }, alignment: { type: 'string', description: 'Paragraph alignment.' }, headingLevel: { type: 'number', description: 'Heading level (1-6).' }, + ref: { + type: 'string', + description: + 'Ref handle for this block. Pass directly to superdoc_format or superdoc_edit ref param. Only present for non-empty blocks.', + }, }, ['ordinal', 'nodeId', 'nodeType'], ), diff --git a/packages/document-api/src/types/blocks.types.ts b/packages/document-api/src/types/blocks.types.ts index a4ad1905a4..4503b6226e 100644 --- a/packages/document-api/src/types/blocks.types.ts +++ b/packages/document-api/src/types/blocks.types.ts @@ -24,6 +24,8 @@ export interface BlockListEntry { alignment?: string; /** Heading level (1-6). Only for headings. */ headingLevel?: number; + /** Ref handle targeting the block's full text. Pass to superdoc_format or superdoc_edit. */ + ref?: string; } export interface BlocksListInput { diff --git a/packages/sdk/codegen/src/generate-intent-tools.mjs b/packages/sdk/codegen/src/generate-intent-tools.mjs index f83ba97334..908a31d3cd 100644 --- a/packages/sdk/codegen/src/generate-intent-tools.mjs +++ b/packages/sdk/codegen/src/generate-intent-tools.mjs @@ -336,7 +336,7 @@ function buildIntentTools(contract) { for (const [propName, propSchema] of Object.entries(allProperties)) { if (propSchema.description) continue; if (propName === 'target') { - allProperties[propName] = { ...propSchema, description: "Target address object. Use 'ref' instead if you have a search handle. Format: {kind:'text', blockId, range:{start,end}} or {kind:'block', nodeType, nodeId}." }; + allProperties[propName] = { ...propSchema, description: "Target address. Prefer 'ref' from superdoc_search instead. Selection: {kind:'selection', start:{kind:'text', blockId, offset}, end:{kind:'text', blockId, offset}}. Block: {kind:'block', nodeType, nodeId}." }; } else if (propName === 'ref') { allProperties[propName] = { ...propSchema, description: "Handle ref string from superdoc_search. Pass handle.ref value directly (e.g. 'text:eyJ...'). Preferred for text-level operations." }; } else if (propName === 'content') { diff --git a/packages/sdk/langs/browser/src/dispatch.ts b/packages/sdk/langs/browser/src/dispatch.ts index b943cfe63a..a3cc0ce090 100644 --- a/packages/sdk/langs/browser/src/dispatch.ts +++ b/packages/sdk/langs/browser/src/dispatch.ts @@ -42,6 +42,18 @@ export function dispatchSuperDocTool( // Intent dispatch produces "doc.insert", "doc.format.apply", etc. // DocumentApi.invoke() expects the id without "doc." prefix: "insert", "format.apply" const stripped = operationId.startsWith('doc.') ? operationId.slice(4) : operationId; - return documentApi.invoke({ operationId: stripped, input }); + + // Extract envelope params — these go into options, not input + const { changeMode, dryRun, force, ...operationInput } = input; + const options: Record = {}; + if (changeMode !== undefined) options.changeMode = changeMode; + if (dryRun !== undefined) options.dryRun = dryRun; + if (force !== undefined) options.force = force; + + return documentApi.invoke({ + operationId: stripped, + input: operationInput, + ...(Object.keys(options).length > 0 ? { options } : {}), + }); }); } diff --git a/packages/sdk/langs/browser/src/system-prompt.ts b/packages/sdk/langs/browser/src/system-prompt.ts index 172e213e2b..da8897c30f 100644 --- a/packages/sdk/langs/browser/src/system-prompt.ts +++ b/packages/sdk/langs/browser/src/system-prompt.ts @@ -24,19 +24,19 @@ Every editing tool needs a **target** — an address telling the API *where* to ### Getting targets -- **From \`superdoc_search\`**: Returns \`handle.ref\` — pass as \`ref\` param to \`superdoc_format\` or \`superdoc_edit\`. +- **From blocks data**: Each block has a \`ref\` — pass it directly to \`superdoc_format\` or \`superdoc_edit\`. Also has \`nodeId\` for building \`at\` positions with \`superdoc_create\`. +- **From \`superdoc_search\`**: Returns \`handle.ref\` — pass as \`ref\` param to \`superdoc_format\` or \`superdoc_edit\`. Use search when you need to find text patterns, not when you already know which block to target. - **From \`superdoc_create\`**: Returns \`ref\` in the response — pass directly to \`superdoc_format\`. No search needed. -- **From blocks data**: Each block has a \`nodeId\` — use it to build block addresses for \`superdoc_create\` \`at\` positioning. ## Workflow -**ALWAYS start by calling \`superdoc_get_content({action: "blocks"})\` before any other tool.** This returns every block with its nodeId, type, text, fontFamily, fontSize, bold, color, and alignment. +For complex edits that need document context (formatting, positioning relative to blocks), call \`superdoc_get_content({action: "blocks"})\` first. This returns every block with its nodeId, type, text, fontFamily, fontSize, bold, color, alignment, and a **ref** handle. Use the ref directly with \`superdoc_format\` or \`superdoc_edit\` — no search needed. For simple tasks (search, create at document end, get plain text, undo), call the appropriate tool directly. -After getting blocks: -1. **Edit existing content**: Use \`superdoc_search\` to get refs, then \`superdoc_edit\` or \`superdoc_format\`. +1. **Edit existing content**: Use \`superdoc_search\` to get a ref, then pass \`ref\` to \`superdoc_edit\` or \`superdoc_format\`. Do not build \`target\` objects manually. 2. **Create new content**: Use \`superdoc_create\`, then use the \`ref\` from the response to apply formatting. DO NOT search after create. 3. **Re-search after each mutation**: Refs expire after any edit. Always search again before the next operation. 4. **Batch when possible**: For multi-step edits, prefer \`superdoc_mutations\`. +5. **Multiple sequential creates**: Each \`superdoc_create\` response includes a \`nodeId\`. When inserting multiple items in order, use the previous item's nodeId as the next \`at\` target to maintain correct ordering. ### Formatting after create diff --git a/packages/sdk/tools/system-prompt.md b/packages/sdk/tools/system-prompt.md index 0fd5cbf06b..afe47166f4 100644 --- a/packages/sdk/tools/system-prompt.md +++ b/packages/sdk/tools/system-prompt.md @@ -22,19 +22,19 @@ Every editing tool needs a **target** — an address telling the API *where* to ### Getting targets -- **From `superdoc_search`**: Returns `handle.ref` — pass as `ref` param to `superdoc_format` or `superdoc_edit`. +- **From blocks data**: Each block has a `ref` — pass it directly to `superdoc_format` or `superdoc_edit`. Also has `nodeId` for building `at` positions with `superdoc_create`. +- **From `superdoc_search`**: Returns `handle.ref` — pass as `ref` param to `superdoc_format` or `superdoc_edit`. Use search when you need to find text patterns, not when you already know which block to target. - **From `superdoc_create`**: Returns `ref` in the response — pass directly to `superdoc_format`. No search needed. -- **From blocks data**: Each block has a `nodeId` — use it to build block addresses for `superdoc_create` `at` positioning. ## Workflow -**ALWAYS start by calling `superdoc_get_content({action: "blocks"})` before any other tool.** This returns every block with its nodeId, type, text, fontFamily, fontSize, bold, color, and alignment. +For complex edits that need document context (formatting, positioning relative to blocks), call `superdoc_get_content({action: "blocks"})` first. This returns every block with its nodeId, type, text, fontFamily, fontSize, bold, color, alignment, and a **ref** handle. Use the ref directly with `superdoc_format` or `superdoc_edit` — no search needed. For simple tasks (search, create at document end, get plain text, undo), call the appropriate tool directly. -After getting blocks: -1. **Edit existing content**: Use `superdoc_search` to get refs, then `superdoc_edit` or `superdoc_format`. +1. **Edit existing content**: Use `superdoc_search` to get a ref, then pass `ref` to `superdoc_edit` or `superdoc_format`. Do not build `target` objects manually. 2. **Create new content**: Use `superdoc_create`, then use the `ref` from the response to apply formatting. DO NOT search after create. 3. **Re-search after each mutation**: Refs expire after any edit. Always search again before the next operation. 4. **Batch when possible**: For multi-step edits, prefer `superdoc_mutations`. +5. **Multiple sequential creates**: Each `superdoc_create` response includes a `nodeId`. When inserting multiple items in order, use the previous item's nodeId as the next `at` target to maintain correct ordering. ### Formatting after create @@ -109,4 +109,4 @@ To resolve a comment, use `action: "update"` with `{ commentId: "", status: - **Table cells are separate blocks.** Search for individual cell values, not patterns spanning multiple cells. - **superdoc_search `select.type`** must be `"text"` or `"node"`. To find headings, use `{type: "node", nodeType: "heading"}`, NOT `{type: "heading"}`. - **Do NOT combine `limit`/`offset` with `require: "first"` or `require: "exactlyOne"`**. Use `require: "any"` with `limit` for paginated results. -- **Creating lists**: Create one paragraph per item first, then call `superdoc_list` action `"create"` with `mode: "fromParagraphs"` for each paragraph. +- **Creating lists**: Create one paragraph per item first, then call `superdoc_list` action `"create"` with `mode: "fromParagraphs"` and `preset: "disc"` (bullet) or `preset: "decimal"` (numbered) for each paragraph. diff --git a/packages/super-editor/src/core/commands/insertHeadingAt.js b/packages/super-editor/src/core/commands/insertHeadingAt.js index dd166a659f..29c49d4667 100644 --- a/packages/super-editor/src/core/commands/insertHeadingAt.js +++ b/packages/super-editor/src/core/commands/insertHeadingAt.js @@ -26,8 +26,20 @@ export const insertHeadingAt = let textNode = null; if (normalizedText.length > 0) { - const marks = findNearbyMarks(state.doc, pos, { prefer: 'heading' }); - textNode = marks.length > 0 ? state.schema.text(normalizedText, marks) : state.schema.text(normalizedText); + const rawMarks = findNearbyMarks(state.doc, pos, { prefer: 'heading' }); + // Strip fontSize from copied marks — headings should keep their style-level size. + const marks = rawMarks.map((mark) => { + if (mark.type.name === 'textStyle' && mark.attrs.fontSize != null) { + const { fontSize: _, ...rest } = mark.attrs; + return mark.type.create(rest); + } + return mark; + }); + const meaningful = marks.filter( + (m) => m.type.name !== 'textStyle' || Object.values(m.attrs).some((v) => v != null), + ); + textNode = + meaningful.length > 0 ? state.schema.text(normalizedText, meaningful) : state.schema.text(normalizedText); } let paragraphNode; diff --git a/packages/super-editor/src/core/helpers/findNearbyMarks.js b/packages/super-editor/src/core/helpers/findNearbyMarks.js index 3a0b148b2e..425f8ad650 100644 --- a/packages/super-editor/src/core/helpers/findNearbyMarks.js +++ b/packages/super-editor/src/core/helpers/findNearbyMarks.js @@ -52,6 +52,7 @@ function extractMeaningfulMarks(paragraphNode) { * @returns {readonly import('prosemirror-model').Mark[]} */ export function findNearbyMarks(doc, pos, { prefer } = {}) { + if (typeof doc.resolve !== 'function') return []; const resolvedPos = doc.resolve(Math.min(pos, doc.content.size)); let fallback = /** @type {readonly import('prosemirror-model').Mark[]} */ ([]); diff --git a/packages/super-editor/src/document-api-adapters/__conformance__/schema-validator.ts b/packages/super-editor/src/document-api-adapters/__conformance__/schema-validator.ts index 03cd9a6631..5a65558888 100644 --- a/packages/super-editor/src/document-api-adapters/__conformance__/schema-validator.ts +++ b/packages/super-editor/src/document-api-adapters/__conformance__/schema-validator.ts @@ -24,6 +24,9 @@ const SUPPORTED_SCHEMA_KEYWORDS = new Set([ 'anyOf', '$ref', '$defs', + 'description', + 'minimum', + 'maximum', ]); export interface SchemaValidationResult { diff --git a/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts b/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts index 64d9f6fdc8..6c191e5551 100644 --- a/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts +++ b/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts @@ -33,6 +33,7 @@ import { DocumentApiAdapterError } from '../errors.js'; import { requireEditorCommand, rejectTrackedMode } from '../helpers/mutation-helpers.js'; import { executeDomainCommand } from './plan-wrappers.js'; import { getRevision } from './revision-tracker.js'; +import { encodeV4Ref } from '../story-runtime/story-ref-codec.js'; // --------------------------------------------------------------------------- // Constants @@ -226,16 +227,35 @@ export function blocksListWrapper(editor: Editor, input?: BlocksListInput): Bloc const limit = input?.limit ?? total; const paged = filtered.slice(offset, offset + limit); - const blocks: BlockListEntry[] = paged.map((candidate, i) => ({ - ordinal: offset + i, - nodeId: candidate.nodeId, - nodeType: candidate.nodeType, - textPreview: extractTextPreview(candidate.node), - isEmpty: candidate.node.textContent.length === 0, - ...extractBlockFormatting(candidate.node), - })); + const rev = getRevision(editor); + + const blocks: BlockListEntry[] = paged.map((candidate, i) => { + const textLength = candidate.node.textContent.length; + const ref = + textLength > 0 + ? encodeV4Ref({ + v: 4, + rev, + storyKey: 'body', + scope: 'block', + matchId: candidate.nodeId, + segments: [{ blockId: candidate.nodeId, start: 0, end: textLength }], + blockIndex: offset + i, + }) + : undefined; + + return { + ordinal: offset + i, + nodeId: candidate.nodeId, + nodeType: candidate.nodeType, + textPreview: extractTextPreview(candidate.node), + isEmpty: textLength === 0, + ...extractBlockFormatting(candidate.node), + ...(ref ? { ref } : {}), + }; + }); - return { total, blocks, revision: getRevision(editor) }; + return { total, blocks, revision: rev }; } // --------------------------------------------------------------------------- diff --git a/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts b/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts index 528c0f69bd..186727e5ed 100644 --- a/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts +++ b/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts @@ -46,6 +46,100 @@ function mintBlockRef(editor: Editor, storyKey: string, nodeId: string, textLeng }); } +// --------------------------------------------------------------------------- +// Auto-formatting: apply fontFamily + color from nearby blocks so new +// headings/paragraphs match the document's visual style without extra LLM steps. +// --------------------------------------------------------------------------- + +function findNearbyFormatting( + editor: Editor, + _pos: number, + skipHeadings: boolean, +): { fontFamily?: string; fontSize?: number; color?: string } | null { + const doc = editor.state.doc; + const result: { fontFamily?: string; fontSize?: number; color?: string } = {}; + + // Walk top-level children near the insertion point + let offset = 0; + for (let i = 0; i < doc.childCount; i++) { + const child = doc.child(i); + const childEnd = offset + child.nodeSize; + + if (child.type.name === 'paragraph') { + const pProps = (child.attrs as Record).paragraphProperties as { styleId?: string } | undefined; + const isHeading = pProps?.styleId && /^Heading\d$/.test(pProps.styleId); + + if (skipHeadings && isHeading) { + offset = childEnd; + continue; + } + + // Read formatting from text marks + child.descendants((textNode) => { + if (result.fontFamily) return false; + const marks = textNode.marks ?? []; + if (!textNode.isText || marks.length === 0) return; + for (const mark of marks) { + const attrs = mark.attrs as Record; + if (typeof attrs.fontFamily === 'string' && attrs.fontFamily) { + result.fontFamily = attrs.fontFamily; + } + if (typeof attrs.color === 'string' && attrs.color) { + result.color = attrs.color; + } + if (attrs.fontSize != null) { + const raw = typeof attrs.fontSize === 'string' ? parseFloat(attrs.fontSize as string) : attrs.fontSize; + if (typeof raw === 'number' && Number.isFinite(raw)) result.fontSize = raw as number; + } + } + return false; + }); + + if (result.fontFamily) return result; + } + + offset = childEnd; + } + + return result.fontFamily ? result : null; +} + +function applyFormattingToCreatedBlock( + editor: Editor, + nodeId: string, + formatting: { fontFamily?: string; fontSize?: number; color?: string }, +): void { + const textStyleType = editor.state.schema.marks.textStyle; + if (!textStyleType) return; + + // Find the created block by walking the document + const doc = editor.state.doc; + let blockPos = -1; + let blockEnd = -1; + + doc.descendants((node, pos) => { + if (blockPos >= 0) return false; + const attrs = node.attrs as Record; + if (node.type.name === 'paragraph' && (attrs.sdBlockId === nodeId || attrs.paraId === nodeId)) { + blockPos = pos + 1; // inside the paragraph + blockEnd = pos + node.nodeSize - 1; + return false; + } + }); + + if (blockPos < 0 || blockEnd <= blockPos) return; + + const mark = textStyleType.create({ + fontFamily: formatting.fontFamily ?? null, + fontSize: formatting.fontSize ?? null, + color: formatting.color ?? null, + }); + + const tr = editor.state.tr.addMark(blockPos, blockEnd, mark); + tr.setMeta('inputType', 'programmatic'); + editor.view?.dispatch(tr); +} + // --------------------------------------------------------------------------- // Command types (internal to the wrapper) // --------------------------------------------------------------------------- @@ -268,6 +362,20 @@ export function createParagraphWrapper( } if (runtime.commit) runtime.commit(editor); + + // Auto-apply fontFamily + fontSize + color from nearby blocks so the + // paragraph matches the document's visual style without extra LLM steps. + try { + if (input.text) { + const formatting = findNearbyFormatting(storyEditor, insertAt, false); + if (formatting) { + applyFormattingToCreatedBlock(storyEditor, paragraphId, formatting); + } + } + } catch { + /* best-effort — formatting failure should not break creation */ + } + const nonBodyStory = runtime.kind !== 'body' ? runtime.locator : undefined; const textLen = input.text?.length ?? 0; const ref = textLen > 0 ? mintBlockRef(storyEditor, runtime.storyKey, canonicalId, textLen) : undefined; @@ -377,6 +485,22 @@ export function createHeadingWrapper( } if (runtime.commit) runtime.commit(editor); + + // Auto-apply fontFamily + color from nearby blocks so the heading + // matches the document's visual style without extra LLM format steps. + // Skip fontSize — headings should keep their style-level size. + try { + if (input.text) { + const formatting = findNearbyFormatting(storyEditor, insertAt, true); + if (formatting) { + const { fontSize: _skipSize, ...headingFormatting } = formatting; + applyFormattingToCreatedBlock(storyEditor, headingId, headingFormatting); + } + } + } catch { + /* best-effort — formatting failure should not break creation */ + } + const nonBodyStory = runtime.kind !== 'body' ? runtime.locator : undefined; const textLen = input.text?.length ?? 0; const ref = textLen > 0 ? mintBlockRef(storyEditor, runtime.storyKey, canonicalId, textLen) : undefined; From f9a1b9eaecb9c92cc621deab09477ec78c5e1266 Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Tue, 24 Mar 2026 08:45:44 -0300 Subject: [PATCH 08/32] fix(super-editor): auto-format created blocks and suppress heading numbering - Apply fontFamily/fontSize/color/bold from nearby body text blocks via runProperties + textStyle marks + sdPreserveRunPropertiesKeys meta so the style engine cascade respects inline overrides on heading-styled paragraphs. - Set numberingProperties {numId:'0'} on created headings to suppress outline numbering inherited from template heading styles. - Update superdoc_create tool description: LLM MUST call superdoc_format after create with bold:false and body-text formatting values. - Use editor.dispatch() instead of editor.view?.dispatch() for consistency with the plan engine executor dispatch path. --- .../src/contract/operation-definitions.ts | 2 +- .../sdk/langs/browser/src/system-prompt.ts | 14 ++-- packages/sdk/tools/system-prompt.md | 12 +-- .../src/core/commands/insertHeadingAt.js | 8 +- .../src/core/commands/insertHeadingAt.test.js | 5 +- .../plan-engine/create-wrappers.ts | 75 ++++++++++++++----- 6 files changed, 81 insertions(+), 35 deletions(-) diff --git a/packages/document-api/src/contract/operation-definitions.ts b/packages/document-api/src/contract/operation-definitions.ts index 8ecb47b9cf..ffdabc58b1 100644 --- a/packages/document-api/src/contract/operation-definitions.ts +++ b/packages/document-api/src/contract/operation-definitions.ts @@ -105,7 +105,7 @@ export const INTENT_GROUP_META: Record = { create: { toolName: 'superdoc_create', description: - 'Create one paragraph or heading. Response includes a ref and nodeId. After creating, call superdoc_format with the ref to match the document style: copy fontFamily and color from nearby blocks. For headings: only set fontFamily and color (NOT fontSize). For paragraphs: set fontFamily, fontSize, and color. Use superdoc_get_content blocks to read existing formatting. When creating multiple items, use the previous nodeId as the next at target.', + 'Create one paragraph or heading. Response includes ref and nodeId. You MUST call superdoc_format after this tool to apply styling from BODY TEXT blocks (not titles/headings). Call superdoc_get_content blocks first, then after creating use the ref with superdoc_format action "inline". Always include bold:false unless body text is bold. For headings: set fontFamily, color, bold (NOT fontSize). For paragraphs: set fontFamily, fontSize, color, bold. When creating multiple items, use the previous nodeId as the next at target.', }, format: { toolName: 'superdoc_format', diff --git a/packages/sdk/langs/browser/src/system-prompt.ts b/packages/sdk/langs/browser/src/system-prompt.ts index da8897c30f..a6330a2cd9 100644 --- a/packages/sdk/langs/browser/src/system-prompt.ts +++ b/packages/sdk/langs/browser/src/system-prompt.ts @@ -38,16 +38,18 @@ For complex edits that need document context (formatting, positioning relative t 4. **Batch when possible**: For multi-step edits, prefer \`superdoc_mutations\`. 5. **Multiple sequential creates**: Each \`superdoc_create\` response includes a \`nodeId\`. When inserting multiple items in order, use the previous item's nodeId as the next \`at\` target to maintain correct ordering. -### Formatting after create +### Formatting after create (REQUIRED) -After \`superdoc_create\`, use the \`ref\` from the response directly: +Every \`superdoc_create\` call MUST be followed by \`superdoc_format\` to match the document's style. Use the \`ref\` from the create response: \`\`\` -superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", color: "..."}}) +superdoc_format({action: "inline", ref: "", inline: {fontFamily: "Calibri", fontSize: 9, color: "#000000", bold: false}}) \`\`\` -- **For paragraphs**: Apply \`fontFamily\`, \`fontSize\`, and \`color\` from neighboring blocks. -- **For headings**: Apply \`fontFamily\` and \`color\` from neighboring blocks. Do NOT change \`fontSize\` — the heading default size is correct. +Get \`fontFamily\`, \`fontSize\`, \`color\`, and \`bold\` values from the blocks data. Use the BODY TEXT blocks (not titles or headings) as the reference for formatting. Always include \`bold: false\` unless the surrounding body text is bold. + +- **For paragraphs**: Apply \`fontFamily\`, \`fontSize\`, \`color\`, and \`bold\`. +- **For headings**: Apply \`fontFamily\`, \`color\`, and \`bold\` only. Do NOT set \`fontSize\` on headings. ### Placing content near specific text @@ -111,5 +113,5 @@ To resolve a comment, use \`action: "update"\` with \`{ commentId: "", statu - **Table cells are separate blocks.** Search for individual cell values, not patterns spanning multiple cells. - **superdoc_search \`select.type\`** must be \`"text"\` or \`"node"\`. To find headings, use \`{type: "node", nodeType: "heading"}\`, NOT \`{type: "heading"}\`. - **Do NOT combine \`limit\`/\`offset\` with \`require: "first"\` or \`require: "exactlyOne"\`**. Use \`require: "any"\` with \`limit\` for paginated results. -- **Creating lists**: Create one paragraph per item first, then call \`superdoc_list\` action \`"create"\` with \`mode: "fromParagraphs"\` for each paragraph. +- **Creating lists**: Create one paragraph per item first, then call \`superdoc_list\` action \`"create"\` with \`mode: "fromParagraphs"\` and \`preset: "disc"\` (bullet) or \`preset: "decimal"\` (numbered) for each paragraph. `; diff --git a/packages/sdk/tools/system-prompt.md b/packages/sdk/tools/system-prompt.md index afe47166f4..870a9fdd37 100644 --- a/packages/sdk/tools/system-prompt.md +++ b/packages/sdk/tools/system-prompt.md @@ -36,16 +36,18 @@ For complex edits that need document context (formatting, positioning relative t 4. **Batch when possible**: For multi-step edits, prefer `superdoc_mutations`. 5. **Multiple sequential creates**: Each `superdoc_create` response includes a `nodeId`. When inserting multiple items in order, use the previous item's nodeId as the next `at` target to maintain correct ordering. -### Formatting after create +### Formatting after create (REQUIRED) -After `superdoc_create`, use the `ref` from the response directly: +Every `superdoc_create` call MUST be followed by `superdoc_format` to match the document's style. Use the `ref` from the create response: ``` -superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", color: "..."}}) +superdoc_format({action: "inline", ref: "", inline: {fontFamily: "Calibri", fontSize: 9, color: "#000000", bold: false}}) ``` -- **For paragraphs**: Apply `fontFamily`, `fontSize`, and `color` from neighboring blocks. -- **For headings**: Apply `fontFamily` and `color` from neighboring blocks. Do NOT change `fontSize` — the heading default size is correct. +Get `fontFamily`, `fontSize`, `color`, and `bold` values from the blocks data. Use the BODY TEXT blocks (not titles or headings) as the reference for formatting. Always include `bold: false` unless the surrounding body text is bold. + +- **For paragraphs**: Apply `fontFamily`, `fontSize`, `color`, and `bold`. +- **For headings**: Apply `fontFamily`, `color`, and `bold` only. Do NOT set `fontSize` on headings. ### Placing content near specific text diff --git a/packages/super-editor/src/core/commands/insertHeadingAt.js b/packages/super-editor/src/core/commands/insertHeadingAt.js index 29c49d4667..dcb7cbcffc 100644 --- a/packages/super-editor/src/core/commands/insertHeadingAt.js +++ b/packages/super-editor/src/core/commands/insertHeadingAt.js @@ -20,7 +20,11 @@ export const insertHeadingAt = const attrs = { ...(sdBlockId ? { sdBlockId } : undefined), ...(paraId ? { paraId } : undefined), - paragraphProperties: { styleId: `Heading${level}` }, + paragraphProperties: { + styleId: `Heading${level}`, + // Explicitly suppress outline numbering that some templates link to heading styles + numberingProperties: { numId: '0', ilvl: '0' }, + }, }; const normalizedText = typeof text === 'string' ? text : ''; @@ -30,7 +34,7 @@ export const insertHeadingAt = // Strip fontSize from copied marks — headings should keep their style-level size. const marks = rawMarks.map((mark) => { if (mark.type.name === 'textStyle' && mark.attrs.fontSize != null) { - const { fontSize: _, ...rest } = mark.attrs; + const rest = Object.fromEntries(Object.entries(mark.attrs).filter(([k]) => k !== 'fontSize')); return mark.type.create(rest); } return mark; diff --git a/packages/super-editor/src/core/commands/insertHeadingAt.test.js b/packages/super-editor/src/core/commands/insertHeadingAt.test.js index 958285aed4..512403e27e 100644 --- a/packages/super-editor/src/core/commands/insertHeadingAt.test.js +++ b/packages/super-editor/src/core/commands/insertHeadingAt.test.js @@ -121,7 +121,8 @@ describe('insertHeadingAt', () => { insertHeadingAt({ pos: 0, level })({ state, dispatch }); const attrs = paragraphType.createAndFill.mock.calls[0]?.[0]; - expect(attrs.paragraphProperties).toEqual({ styleId: `Heading${level}` }); + expect(attrs.paragraphProperties.styleId).toBe(`Heading${level}`); + expect(attrs.paragraphProperties.numberingProperties).toEqual({ numId: '0', ilvl: '0' }); } }); @@ -134,7 +135,7 @@ describe('insertHeadingAt', () => { const attrs = paragraphType.createAndFill.mock.calls[0]?.[0]; expect(attrs.sdBlockId).toBe('block-1'); - expect(attrs.paragraphProperties).toEqual({ styleId: 'Heading1' }); + expect(attrs.paragraphProperties.styleId).toBe('Heading1'); }); it('creates a text node when text is provided', () => { diff --git a/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts b/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts index 186727e5ed..d380d4d3a4 100644 --- a/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts +++ b/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts @@ -55,9 +55,9 @@ function findNearbyFormatting( editor: Editor, _pos: number, skipHeadings: boolean, -): { fontFamily?: string; fontSize?: number; color?: string } | null { +): { fontFamily?: string; fontSize?: number; bold?: boolean; color?: string } | null { const doc = editor.state.doc; - const result: { fontFamily?: string; fontSize?: number; color?: string } = {}; + const result: { fontFamily?: string; fontSize?: number; bold?: boolean; color?: string } = {}; // Walk top-level children near the insertion point let offset = 0; @@ -91,37 +91,42 @@ function findNearbyFormatting( const raw = typeof attrs.fontSize === 'string' ? parseFloat(attrs.fontSize as string) : attrs.fontSize; if (typeof raw === 'number' && Number.isFinite(raw)) result.fontSize = raw as number; } + if (attrs.bold === true) result.bold = true; + else if (result.bold === undefined) result.bold = false; } return false; }); - if (result.fontFamily) return result; + if (result.fontFamily) { + // Default to black when no explicit color is set (matches extractBlockFormatting behavior) + if (!result.color) result.color = '#000000'; + return result; + } } offset = childEnd; } + if (result.fontFamily && !result.color) result.color = '#000000'; return result.fontFamily ? result : null; } function applyFormattingToCreatedBlock( editor: Editor, nodeId: string, - formatting: { fontFamily?: string; fontSize?: number; color?: string }, + formatting: { fontFamily?: string; fontSize?: number; bold?: boolean; color?: string }, ): void { - const textStyleType = editor.state.schema.marks.textStyle; - if (!textStyleType) return; - - // Find the created block by walking the document const doc = editor.state.doc; + const textStyleType = editor.state.schema.marks.textStyle; let blockPos = -1; let blockEnd = -1; + // Find the created paragraph doc.descendants((node, pos) => { if (blockPos >= 0) return false; const attrs = node.attrs as Record; if (node.type.name === 'paragraph' && (attrs.sdBlockId === nodeId || attrs.paraId === nodeId)) { - blockPos = pos + 1; // inside the paragraph + blockPos = pos + 1; blockEnd = pos + node.nodeSize - 1; return false; } @@ -129,15 +134,45 @@ function applyFormattingToCreatedBlock( if (blockPos < 0 || blockEnd <= blockPos) return; - const mark = textStyleType.create({ - fontFamily: formatting.fontFamily ?? null, - fontSize: formatting.fontSize ?? null, - color: formatting.color ?? null, + const tr = editor.state.tr; + + // 1. Add textStyle marks on text nodes (so marks are the source of truth) + if (textStyleType) { + const mark = textStyleType.create({ + fontFamily: formatting.fontFamily ?? null, + fontSize: formatting.fontSize ?? null, + bold: formatting.bold ?? null, + color: formatting.color ?? null, + }); + tr.addMark(blockPos, blockEnd, mark); + } + + // 2. Also set runProperties directly on run nodes (so the style engine + // cascade sees them as inlineRpr, the highest-priority layer) + doc.nodesBetween(blockPos, blockEnd, (node, pos) => { + if (node.type.name === 'run') { + const existingRp = (node.attrs as Record).runProperties as Record | undefined; + const merged: Record = { ...(existingRp ?? {}) }; + if (formatting.fontFamily) merged.fontFamily = formatting.fontFamily; + if (formatting.fontSize != null) merged.fontSize = formatting.fontSize; + if (formatting.bold != null) merged.bold = formatting.bold; + if (formatting.color) merged.color = formatting.color; + tr.setNodeMarkup(pos, null, { ...node.attrs, runProperties: merged }); + } }); - const tr = editor.state.tr.addMark(blockPos, blockEnd, mark); + // 3. Tell calculateInlineRunPropertiesPlugin to PRESERVE our values + // instead of re-deriving them from the style cascade. + const preserveKeys = Object.keys(formatting).filter((k) => (formatting as Record)[k] != null); + if (preserveKeys.length > 0) { + tr.setMeta( + 'sdPreserveRunPropertiesKeys', + preserveKeys.map((k) => ({ key: k, preferExisting: true })), + ); + } + tr.setMeta('inputType', 'programmatic'); - editor.view?.dispatch(tr); + editor.dispatch(tr); } // --------------------------------------------------------------------------- @@ -372,8 +407,9 @@ export function createParagraphWrapper( applyFormattingToCreatedBlock(storyEditor, paragraphId, formatting); } } - } catch { - /* best-effort — formatting failure should not break creation */ + } catch (e) { + // Best-effort — formatting failure should not break creation + console.warn('[create-wrapper] auto-formatting failed:', e); } const nonBodyStory = runtime.kind !== 'body' ? runtime.locator : undefined; @@ -497,8 +533,9 @@ export function createHeadingWrapper( applyFormattingToCreatedBlock(storyEditor, headingId, headingFormatting); } } - } catch { - /* best-effort — formatting failure should not break creation */ + } catch (e) { + // Best-effort — formatting failure should not break creation + console.warn('[create-wrapper] auto-formatting failed:', e); } const nonBodyStory = runtime.kind !== 'body' ? runtime.locator : undefined; From 2ff4aa35fb346dd72ee72be379dbb7d159e4c911 Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Tue, 24 Mar 2026 08:46:25 -0300 Subject: [PATCH 09/32] chore: update lockfile for browser SDK dependency --- pnpm-lock.yaml | 1814 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 1622 insertions(+), 192 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 654955535a..1c46da3af0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -352,7 +352,7 @@ importers: version: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitest/coverage-v8': specifier: 'catalog:' - version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) concurrently: specifier: 'catalog:' version: 9.2.1 @@ -415,7 +415,7 @@ importers: version: 0.25.0(rollup@4.59.0)(vite@7.3.1(@types/node@22.19.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) optionalDependencies: canvas: specifier: 3.2.1 @@ -494,7 +494,7 @@ importers: version: 14.0.3 mintlify: specifier: 4.2.442 - version: 4.2.442(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.8)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) + version: 4.2.442(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) remark-mdx: specifier: ^3.1.1 version: 3.1.1 @@ -811,7 +811,7 @@ importers: version: 10.4.27(postcss@8.5.6) axios: specifier: ^1.9.0 - version: 1.13.2(debug@4.4.3) + version: 1.13.2 class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -877,7 +877,7 @@ importers: version: 0.9.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) y-prosemirror: specifier: latest - version: 1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) + version: 1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.7)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) yjs: specifier: latest version: 13.6.30 @@ -950,7 +950,7 @@ importers: dependencies: next: specifier: 15.3.3 - version: 15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3) + version: 15.3.3(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3) react: specifier: ^19.0.0 version: 19.2.4 @@ -1487,6 +1487,155 @@ importers: specifier: npm:rolldown-vite@7.3.1 version: rolldown-vite@7.3.1(@types/node@22.19.8)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + examples/eval-demo: + dependencies: + '@ai-sdk/openai': + specifier: ^1.3.0 + version: 1.3.24(zod@3.25.76) + '@base-ui/react': + specifier: ^1.2.0 + version: 1.3.0(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@superdoc-dev/react': + specifier: workspace:* + version: link:../../packages/react + '@superdoc-dev/sdk': + specifier: workspace:* + version: link:../../packages/sdk/langs/node + '@tailwindcss/postcss': + specifier: ^4.2.1 + version: 4.2.2 + ai: + specifier: ^4.3.0 + version: 4.3.19(react@19.2.4)(zod@3.25.76) + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + lucide-react: + specifier: ^0.577.0 + version: 0.577.0(react@19.2.4) + next: + specifier: ^15.3.0 + version: 15.3.3(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3) + openai: + specifier: ^4.80.0 + version: 4.104.0(ws@8.19.0)(zod@3.25.76) + postcss: + specifier: ^8.5.8 + version: 8.5.8 + react: + specifier: ^19.0.0 + version: 19.2.4 + react-dom: + specifier: ^19.0.0 + version: 19.2.4(react@19.2.4) + shadcn: + specifier: ^4.0.2 + version: 4.1.0(@types/node@22.19.8)(typescript@5.9.3) + superdoc: + specifier: workspace:* + version: link:../../packages/superdoc + tailwind-merge: + specifier: ^3.5.0 + version: 3.5.0 + tailwindcss: + specifier: ^4.2.1 + version: 4.2.2 + tw-animate-css: + specifier: ^1.4.0 + version: 1.4.0 + ws: + specifier: ^8.18.0 + version: 8.19.0 + y-websocket: + specifier: ^2.1.0 + version: 2.1.0(yjs@13.6.30) + yjs: + specifier: ^13.6.0 + version: 13.6.30 + zod: + specifier: ^3.24.0 + version: 3.25.76 + devDependencies: + '@types/node': + specifier: ^22.0.0 + version: 22.19.8 + '@types/react': + specifier: ^19.0.0 + version: 19.2.11 + '@types/react-dom': + specifier: ^19.0.0 + version: 19.2.3(@types/react@19.2.11) + '@types/ws': + specifier: ^8.5.0 + version: 8.18.1 + typescript: + specifier: ^5.7.0 + version: 5.9.3 + + examples/eval-demo-browser: + dependencies: + '@base-ui/react': + specifier: ^1.2.0 + version: 1.3.0(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@openai/agents': + specifier: ^0.1.0 + version: 0.1.11(ws@8.19.0)(zod@4.3.6) + '@superdoc-dev/sdk-browser': + specifier: workspace:* + version: link:../../packages/sdk/langs/browser + '@tailwindcss/postcss': + specifier: ^4.2.1 + version: 4.2.2 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + next: + specifier: ^15.3.0 + version: 15.3.3(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3) + openai: + specifier: ^5.0.0 + version: 5.23.2(ws@8.19.0)(zod@4.3.6) + postcss: + specifier: ^8.5.8 + version: 8.5.8 + react: + specifier: ^19.0.0 + version: 19.2.4 + react-dom: + specifier: ^19.0.0 + version: 19.2.4(react@19.2.4) + superdoc: + specifier: workspace:* + version: link:../../packages/superdoc + tailwind-merge: + specifier: ^3.5.0 + version: 3.5.0 + tailwindcss: + specifier: ^4.2.1 + version: 4.2.2 + tw-animate-css: + specifier: ^1.4.0 + version: 1.4.0 + devDependencies: + '@types/node': + specifier: ^22.0.0 + version: 22.19.8 + '@types/react': + specifier: ^19.0.0 + version: 19.2.11 + '@types/react-dom': + specifier: ^19.0.0 + version: 19.2.3(@types/react@19.2.11) + typescript: + specifier: ^5.7.0 + version: 5.9.3 + examples/features/ai-redlining: dependencies: react: @@ -1678,7 +1827,7 @@ importers: devDependencies: '@angular-devkit/build-angular': specifier: ^21.1.4 - version: 21.2.3(@angular/compiler-cli@21.2.5(@angular/compiler@21.2.5)(typescript@5.9.3))(@angular/compiler@21.2.5)(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.2.5(@angular/common@21.2.5(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1)))(@types/node@22.19.8)(chokidar@5.0.0)(html-webpack-plugin@5.6.6(webpack@5.105.2(esbuild@0.27.3)))(jiti@2.6.1)(tailwindcss@4.2.2)(tsx@4.21.0)(typescript@5.9.3)(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2) + version: 21.2.3(@angular/compiler-cli@21.2.5(@angular/compiler@21.2.5)(typescript@5.9.3))(@angular/compiler@21.2.5)(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.2.5(@angular/common@21.2.5(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1)))(@types/node@22.19.8)(chokidar@5.0.0)(html-webpack-plugin@5.6.6(webpack@5.105.2(esbuild@0.27.3)))(jiti@2.6.1)(tailwindcss@4.2.2)(tsx@4.21.0)(typescript@5.9.3)(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2) '@angular/cli': specifier: ^21.1.4 version: 21.2.3(@types/node@22.19.8)(chokidar@5.0.0) @@ -1829,6 +1978,37 @@ importers: specifier: ^5.9.3 version: 5.9.3 + examples/scroll-repro: + dependencies: + '@superdoc-dev/react': + specifier: workspace:* + version: link:../../packages/react + react: + specifier: 'catalog:' + version: 19.2.4 + react-dom: + specifier: 'catalog:' + version: 19.2.4(react@19.2.4) + superdoc: + specifier: workspace:* + version: link:../../packages/superdoc + devDependencies: + '@types/react': + specifier: 'catalog:' + version: 19.2.11 + '@types/react-dom': + specifier: 'catalog:' + version: 19.2.3(@types/react@19.2.11) + '@vitejs/plugin-react': + specifier: 'catalog:' + version: 5.1.3(rolldown-vite@7.3.1(@types/node@22.19.8)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) + typescript: + specifier: 'catalog:' + version: 5.9.3 + vite: + specifier: npm:rolldown-vite@7.3.1 + version: rolldown-vite@7.3.1(@types/node@22.19.8)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + packages/ai: devDependencies: '@types/node': @@ -1866,7 +2046,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.2)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) vue: specifier: 3.5.25 version: 3.5.25(typescript@5.9.3) @@ -1891,7 +2071,7 @@ importers: version: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitest/coverage-v8': specifier: 'catalog:' - version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.2)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) concurrently: specifier: 'catalog:' version: 9.2.1 @@ -1915,7 +2095,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.2)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) packages/document-api: {} @@ -1968,7 +2148,7 @@ importers: version: 4.5.4(@types/node@22.19.8)(rolldown-vite@7.3.1(@types/node@22.19.8)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))(rollup@4.59.0)(typescript@5.9.3) vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.8)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) packages/esign/demo: dependencies: @@ -2030,7 +2210,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.8)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) packages/layout-engine/layout-bridge: dependencies: @@ -2067,7 +2247,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) packages/layout-engine/layout-engine: dependencies: @@ -2128,7 +2308,7 @@ importers: devDependencies: vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.8)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) packages/layout-engine/pm-adapter: dependencies: @@ -2168,7 +2348,7 @@ importers: version: link:../painters/dom vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.8)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) packages/layout-engine/style-engine: dependencies: @@ -2184,7 +2364,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.8)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) packages/layout-engine/tests: dependencies: @@ -2269,12 +2449,18 @@ importers: version: 4.5.4(@types/node@22.19.2)(rolldown-vite@7.3.1(@types/node@22.19.2)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))(rollup@4.59.0)(typescript@5.9.3) vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) packages/sdk: {} packages/sdk/codegen: {} + packages/sdk/langs/browser: + dependencies: + '@superdoc/document-api': + specifier: workspace:* + version: link:../../../document-api + packages/sdk/langs/node: devDependencies: '@types/bun': @@ -2486,7 +2672,7 @@ importers: version: 0.25.0(rolldown-vite@7.3.1(@types/node@22.19.8)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))(rollup@4.59.0) vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.8)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) y-protocols: specifier: 'catalog:' version: 1.0.7(yjs@13.6.19) @@ -2508,6 +2694,9 @@ importers: pinia: specifier: 'catalog:' version: 2.3.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)) + prosemirror-view: + specifier: ^1.41.7 + version: 1.41.7 rollup-plugin-copy: specifier: 'catalog:' version: 3.5.0 @@ -2522,17 +2711,17 @@ importers: version: 1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.19))(yjs@13.6.19) y-websocket: specifier: 'catalog:' - version: 3.0.0(yjs@13.6.19) + version: 3.0.0(yjs@13.6.30) yjs: specifier: 'catalog:' - version: 13.6.19 + version: 13.6.30 devDependencies: '@hocuspocus/provider': specifier: 'catalog:' - version: 2.15.3(y-protocols@1.0.7(yjs@13.6.19))(yjs@13.6.19) + version: 2.15.3(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) '@hocuspocus/server': specifier: 'catalog:' - version: 2.15.3(y-protocols@1.0.7(yjs@13.6.19))(yjs@13.6.19) + version: 2.15.3(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) '@superdoc-dev/superdoc-yjs-collaboration': specifier: workspace:* version: link:../collaboration-yjs @@ -2592,7 +2781,7 @@ importers: version: 0.25.0(rolldown-vite@7.3.1(@types/node@22.19.8)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))(rollup@4.59.0) vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.8)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) ws: specifier: ^8.18.3 version: 8.19.0 @@ -2658,7 +2847,7 @@ importers: version: 4.5.4(@types/node@22.19.8)(rolldown-vite@7.3.1(@types/node@22.19.8)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))(rollup@4.59.0)(typescript@5.9.3) vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.8)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) packages/template-builder/demo: dependencies: @@ -2695,7 +2884,7 @@ importers: devDependencies: vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.8)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) shared/common: devDependencies: @@ -2710,7 +2899,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) vue: specifier: 3.5.25 version: 3.5.25(typescript@5.9.3) @@ -2745,7 +2934,7 @@ importers: devDependencies: vitest: specifier: 'catalog:' - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.8)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) tests/visual: dependencies: @@ -2786,16 +2975,48 @@ packages: peerDependencies: zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/openai@1.3.24': + resolution: {integrity: sha512-GYXnGJTHRTZc4gJMSmFRgEQudjqd4PUN0ZjQhPwOAYH1yOAvQoG/Ikqs+HyISRbLPCrhbZnPKCNHuRU4OfpW0Q==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.0.0 + + '@ai-sdk/provider-utils@2.2.8': + resolution: {integrity: sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.23.8 + '@ai-sdk/provider-utils@4.0.21': resolution: {integrity: sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/provider@1.1.3': + resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==} + engines: {node: '>=18'} + '@ai-sdk/provider@3.0.8': resolution: {integrity: sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==} engines: {node: '>=18'} + '@ai-sdk/react@1.2.12': + resolution: {integrity: sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g==} + engines: {node: '>=18'} + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + zod: ^3.23.8 + peerDependenciesMeta: + zod: + optional: true + + '@ai-sdk/ui-utils@1.2.11': + resolution: {integrity: sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.23.8 + '@ai-zen/node-fetch-event-source@2.1.4': resolution: {integrity: sha512-OHFwPJecr+qwlyX5CGmTvKAKPZAdZaxvx/XDqS1lx4I2ZAk9riU0XnEaRGOOAEFrdcLZ98O5yWqubwjaQc0umg==} @@ -4114,6 +4335,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + '@babel/preset-typescript@7.28.5': + resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/runtime@7.28.6': resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} engines: {node: '>=6.9.0'} @@ -4130,6 +4357,27 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@base-ui/react@1.3.0': + resolution: {integrity: sha512-FwpKqZbPz14AITp1CVgf4AjhKPe1OeeVKSBMdgD10zbFlj3QSWelmtCMLi2+/PFZZcIm3l87G7rwtCZJwHyXWA==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + + '@base-ui/utils@0.2.6': + resolution: {integrity: sha512-yQ+qeuqohwhsNpoYDqqXaLllYAkPCP4vYdDrVo8FQXaAPfHWm1pG/Vm+jmGTA5JFS0BAIjookyapuJFY8F9PIw==} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + '@bcoe/v8-coverage@1.0.2': resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} @@ -4301,6 +4549,10 @@ packages: resolution: {integrity: sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==} engines: {node: '>=14.17.0'} + '@dotenvx/dotenvx@1.57.0': + resolution: {integrity: sha512-WsTEcqfHzKmLFZh3jLGd7o4iCkrIupp+qFH2FJUJtQXUh2GcOnLXD00DcrhlO4H8QSmaKnW9lugOEbrdpu25kA==} + hasBin: true + '@dxup/nuxt@0.4.0': resolution: {integrity: sha512-28LDotpr9G2knUse3cQYsOo6NJq5yhABv4ByRVRYJUmzf9Q31DI7rpRek4POlKy1aAcYyKgu5J2616pyqLohYg==} peerDependencies: @@ -4309,6 +4561,12 @@ packages: '@dxup/unimport@0.1.2': resolution: {integrity: sha512-/B8YJGPzaYq1NbsQmwgP8EZqg40NpTw4ZB3suuI0TplbxKHeK94jeaawLmVhCv+YwUnOpiWEz9U6SeThku/8JQ==} + '@ecies/ciphers@0.2.5': + resolution: {integrity: sha512-GalEZH4JgOMHYYcYmVqnFirFsjZHeoGMDt9IxEnM9F7GRUUyUksJ7Ou53L83WHJq3RWKD3AcBpo0iQh0oMpf8A==} + engines: {bun: '>=1', deno: '>=2', node: '>=16'} + peerDependencies: + '@noble/ciphers': ^1.0.0 + '@emnapi/core@1.8.1': resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} @@ -5027,18 +5285,33 @@ packages: '@floating-ui/core@1.7.4': resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==} + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + '@floating-ui/dom@1.7.5': resolution: {integrity: sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==} + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + '@floating-ui/react-dom@2.1.7': resolution: {integrity: sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' + '@floating-ui/react-dom@2.1.8': + resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + '@fortawesome/fontawesome-common-types@6.7.2': resolution: {integrity: sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==} engines: {node: '>=6'} @@ -6114,6 +6387,10 @@ packages: cpu: [x64] os: [win32] + '@mswjs/interceptors@0.41.3': + resolution: {integrity: sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA==} + engines: {node: '>=18'} + '@napi-rs/canvas-android-arm64@0.1.80': resolution: {integrity: sha512-sk7xhN/MoXeuExlggf91pNziBxLPVUqF2CAVnB57KLG/pz7+U5TKG8eXdc3pm0d7Od0WreB6ZKLj37sX9muGOQ==} engines: {node: '>= 10'} @@ -6594,6 +6871,14 @@ packages: typescript: '>=5.9 <6.0' webpack: ^5.54.0 + '@noble/ciphers@1.3.0': + resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.7': + resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} + engines: {node: ^14.21.3 || >=16} + '@noble/hashes@1.4.0': resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} engines: {node: '>= 16'} @@ -6792,6 +7077,23 @@ packages: '@one-ini/wasm@0.1.1': resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + '@open-draft/deferred-promise@2.2.0': + resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} + + '@open-draft/logger@0.3.0': + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} + + '@open-draft/until@2.1.0': + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + + '@openai/agents-core@0.1.11': + resolution: {integrity: sha512-ye8VIAO2wPIg1zClldIj8We/1R55VmdgnMyn0g4YGbp6RD5Wpv9yfH5kPNWxmHvw8ji+XehyggGoklY4FGQoBQ==} + peerDependencies: + zod: ^3.25.40 + peerDependenciesMeta: + zod: + optional: true + '@openai/agents-core@0.5.4': resolution: {integrity: sha512-qAT9zGIIM7GT5/WGkLpp8Fuar7NL5qu30b5+o2jP3mE6aMfx9OZjdj0za/iYLeV5kzQ5pOcbvRXenfzHrhvd/A==} peerDependencies: @@ -6800,16 +7102,31 @@ packages: zod: optional: true + '@openai/agents-openai@0.1.11': + resolution: {integrity: sha512-TYYbY7o1cNxtOIO4F1a20qkqDT1Iwr9ZEi0MO2sEaeioK8rGB/Ux54iFvsA3IblUYyK+5fD25vr4vXFasvg2Kg==} + peerDependencies: + zod: ^3.25.40 + '@openai/agents-openai@0.5.4': resolution: {integrity: sha512-1uDEu9iwM7oB3oWNxvT/yzkcr7WtjHe1ekbQOAsasEv9S0MKTT8uP2kknRVgxzgw+awTZBrhO2vfGhD1iKinuQ==} peerDependencies: zod: ^4.0.0 + '@openai/agents-realtime@0.1.11': + resolution: {integrity: sha512-8jaNuYU1acra28i7bYrZIPubI6s2ziY2ZudqAVK2ad+giopXcrNSiJTuZ2S3z+ESnIejwMiYLfnY2Le8W0SJ7A==} + peerDependencies: + zod: ^3.25.40 + '@openai/agents-realtime@0.5.4': resolution: {integrity: sha512-qlrhMWD3Xpzfrxplt/jvc1nlGtjNnRmyzgRAj6J5HX/bcnP0W4UdYHEJOreiIC8inj27kcVjQslyu0DAjVuXsA==} peerDependencies: zod: ^4.0.0 + '@openai/agents@0.1.11': + resolution: {integrity: sha512-jnaFt54iP71vYDXvpG3EGX2kVRYIU2xBdCT3uFqdXm4KqFAP9JQFNGiKKBEeE5rbXARpqAQpKH+5HfoANndpcQ==} + peerDependencies: + zod: ^3.25.40 + '@openai/agents@0.5.4': resolution: {integrity: sha512-INstpf2vZ0rV6Zq9jcSzqq/oL2/D84YGGKCXnU2otAcQ0ji/VZm+zplDow/+oENnvKiXKdVtOrGMsXqNFL7W+Q==} peerDependencies: @@ -9771,6 +10088,9 @@ packages: '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@ts-morph/common@0.27.0': + resolution: {integrity: sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==} + '@tsconfig/node10@1.0.12': resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} @@ -9878,6 +10198,9 @@ packages: '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/diff-match-patch@1.0.36': + resolution: {integrity: sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==} + '@types/es-aggregate-error@1.0.6': resolution: {integrity: sha512-qJ7LIFp06h1QE1aVxbVd+zJP2wdaugYXYfd6JxsyRMrYHaxb6itXPogW2tz+ylUJ1n1b+JF1PHyYCfYHm0dvUg==} @@ -10057,6 +10380,9 @@ packages: '@types/sockjs@0.3.36': resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==} + '@types/statuses@2.0.6': + resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} + '@types/strip-bom@4.0.1': resolution: {integrity: sha512-d3RZcMmYRuL5f+jG5YM5ISs9z/HCwI2xjqXxhLon54dlpBWfVLVStOFTalO7UcX7RXaIJ6oylqOTg3Cbu6zU1Q==} deprecated: This is a stub types definition. strip-bom provides its own type definitions, so you do not need this installed. @@ -10079,6 +10405,9 @@ packages: '@types/urijs@1.19.26': resolution: {integrity: sha512-wkXrVzX5yoqLnndOwFsieJA7oKM8cNkOKJtf/3vVGSUFkWDKZvFHpIl9Pvqb/T9UsawBBFMTTD8xu7sK5MWuvg==} + '@types/validate-npm-package-name@4.0.2': + resolution: {integrity: sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==} + '@types/vscode@1.108.1': resolution: {integrity: sha512-DerV0BbSzt87TbrqmZ7lRDIYaMiqvP8tmJTzW2p49ZBVtGUnGAu2RGQd1Wv4XMzEVUpaHbsemVM5nfuQJj7H6w==} @@ -10834,6 +11163,16 @@ packages: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} + abstract-leveldown@6.2.3: + resolution: {integrity: sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ==} + engines: {node: '>=6'} + deprecated: Superseded by abstract-level (https://github.com/Level/community#faq) + + abstract-leveldown@6.3.0: + resolution: {integrity: sha512-TU5nlYgta8YrBMNpc9FwQzRbiXsj49gsALsXadbGHt9CROPzX5fB0rWDR5mtdpOOKa5XqRFpbj1QroPAoPzVjQ==} + engines: {node: '>=6'} + deprecated: Superseded by abstract-level (https://github.com/Level/community#faq) + abstract-logging@2.0.1: resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} @@ -10910,6 +11249,10 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} @@ -10922,6 +11265,16 @@ packages: resolution: {integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==} engines: {node: '>=18'} + ai@4.3.19: + resolution: {integrity: sha512-dIE2bfNpqHN3r6IINp9znguYdhIOheKW2LDigAMrgt/upT3B8eBGPSCblENvaZGoq+hxaN9fSMzjWpbqloP+7Q==} + engines: {node: '>=18'} + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + zod: ^3.23.8 + peerDependenciesMeta: + react: + optional: true + ai@6.0.133: resolution: {integrity: sha512-8YBTQdRtIpa7gLKWLvUHLnKxI5lEyV1z9o20+8uDjMs4EOGuv62fQivHD/Yi7SBidzEhAORjCBcQrQ5Lu2V0Vw==} engines: {node: '>=18'} @@ -11205,6 +11558,10 @@ packages: resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} engines: {node: '>=4'} + ast-types@0.16.1: + resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + engines: {node: '>=4'} + ast-v8-to-istanbul@0.3.11: resolution: {integrity: sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==} @@ -11224,6 +11581,9 @@ packages: resolution: {integrity: sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==} engines: {node: ^4.7 || >=6.9 || >=7.3} + async-limiter@1.0.1: + resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} + async-listener@0.6.10: resolution: {integrity: sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==} engines: {node: <=0.11.8 || >0.11.10} @@ -11971,6 +12331,9 @@ packages: resolution: {integrity: sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==} engines: {node: '>=16'} + code-block-writer@13.0.3: + resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} + code-excerpt@4.0.0: resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -12681,6 +13044,11 @@ packages: resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} engines: {node: '>=10'} + deferred-leveldown@5.3.0: + resolution: {integrity: sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw==} + engines: {node: '>=6'} + deprecated: Superseded by abstract-level (https://github.com/Level/community#faq) + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -12783,6 +13151,9 @@ packages: didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + diff-match-patch@1.0.5: + resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} + diff@4.0.4: resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} engines: {node: '>=0.3.1'} @@ -13013,6 +13384,10 @@ packages: ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + eciesjs@0.4.18: + resolution: {integrity: sha512-wG99Zcfcys9fZux7Cft8BAX/YrOJLJSZ3jyYPfhZHqN2E+Ffx+QXBDsv3gubEgPtV6dTzJMSQUwk1H98/t/0wQ==} + engines: {bun: '>=1', deno: '>=2', node: '>=16'} + editions@6.22.0: resolution: {integrity: sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==} engines: {ecmascript: '>= es5', node: '>=4'} @@ -13074,6 +13449,11 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} + encoding-down@6.3.0: + resolution: {integrity: sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw==} + engines: {node: '>=6'} + deprecated: Superseded by abstract-level (https://github.com/Level/community#faq) + encoding-sniffer@0.2.1: resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} @@ -13908,6 +14288,10 @@ packages: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} + formdata-node@4.4.1: + resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} + engines: {node: '>= 12.20'} + formdata-polyfill@4.0.10: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} @@ -14011,6 +14395,9 @@ packages: resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==} engines: {node: '>=10'} + fuzzysort@3.1.0: + resolution: {integrity: sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==} + fzf@0.5.2: resolution: {integrity: sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==} @@ -14064,6 +14451,10 @@ packages: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} + get-own-enumerable-keys@1.0.0: + resolution: {integrity: sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==} + engines: {node: '>=14.16'} + get-port-please@3.2.0: resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} @@ -14263,6 +14654,10 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + graphql@16.13.1: + resolution: {integrity: sha512-gGgrVCoDKlIZ8fIqXBBb0pPKqDgki0Z/FSKNiQzSGj2uEYHr1tq5wmBegGwJx6QB5S5cM0khSBpi/JFHMCvsmQ==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + gtoken@7.1.0: resolution: {integrity: sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==} engines: {node: '>=14.0.0'} @@ -14430,6 +14825,9 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + headers-polyfill@4.0.3: + resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} + hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} @@ -14646,6 +15044,9 @@ packages: resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} engines: {node: '>=18.18.0'} + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + hyperdyperid@1.2.0: resolution: {integrity: sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==} engines: {node: '>=10.18'} @@ -14707,6 +15108,9 @@ packages: immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + immediate@3.3.0: + resolution: {integrity: sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==} + immer@9.0.21: resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} @@ -15041,6 +15445,9 @@ packages: resolution: {integrity: sha512-6QCxa49rQbmUWLfk0nuGqzql9U8uaV2H6279bRErPBHe/109hCzsLUBUHfbEtvLIHBd6hyXbgedBSHevm43Edw==} engines: {node: '>=16'} + is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} + is-number-object@1.1.1: resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} engines: {node: '>= 0.4'} @@ -15053,6 +15460,10 @@ packages: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} engines: {node: '>=8'} + is-obj@3.0.0: + resolution: {integrity: sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==} + engines: {node: '>=12'} + is-online@10.0.0: resolution: {integrity: sha512-WCPdKwNDjXJJmUubf2VHLMDBkUZEtuOvpXUfUnUFbEnM6In9ByiScL4f4jKACz/fsb2qDkesFerW3snf/AYz3A==} engines: {node: '>=14.16'} @@ -15109,6 +15520,10 @@ packages: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} + is-regexp@3.1.0: + resolution: {integrity: sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==} + engines: {node: '>=12'} + is-relative@1.0.0: resolution: {integrity: sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==} engines: {node: '>=0.10.0'} @@ -15163,6 +15578,10 @@ packages: resolution: {integrity: sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==} engines: {node: '>=0.10.0'} + is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + is-unicode-supported@2.1.0: resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} engines: {node: '>=18'} @@ -15215,6 +15634,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isexe@3.1.5: + resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} + engines: {node: '>=18'} + isexe@4.0.0: resolution: {integrity: sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==} engines: {node: '>=20'} @@ -15427,6 +15850,11 @@ packages: jsonc-parser@3.3.1: resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + jsondiffpatch@0.6.0: + resolution: {integrity: sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -15512,6 +15940,10 @@ packages: klaw@3.0.0: resolution: {integrity: sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==} + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + kleur@4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} @@ -15647,6 +16079,52 @@ packages: engines: {node: '>=14'} hasBin: true + level-codec@9.0.2: + resolution: {integrity: sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ==} + engines: {node: '>=6'} + deprecated: Superseded by level-transcoder (https://github.com/Level/community#faq) + + level-concat-iterator@2.0.1: + resolution: {integrity: sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw==} + engines: {node: '>=6'} + deprecated: Superseded by abstract-level (https://github.com/Level/community#faq) + + level-errors@2.0.1: + resolution: {integrity: sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw==} + engines: {node: '>=6'} + deprecated: Superseded by abstract-level (https://github.com/Level/community#faq) + + level-iterator-stream@4.0.2: + resolution: {integrity: sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q==} + engines: {node: '>=6'} + + level-js@5.0.2: + resolution: {integrity: sha512-SnBIDo2pdO5VXh02ZmtAyPP6/+6YTJg2ibLtl9C34pWvmtMEmRTWpra+qO/hifkUtBTOtfx6S9vLDjBsBK4gRg==} + deprecated: Superseded by browser-level (https://github.com/Level/community#faq) + + level-packager@5.1.1: + resolution: {integrity: sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ==} + engines: {node: '>=6'} + deprecated: Superseded by abstract-level (https://github.com/Level/community#faq) + + level-supports@1.0.1: + resolution: {integrity: sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg==} + engines: {node: '>=6'} + + level@6.0.1: + resolution: {integrity: sha512-psRSqJZCsC/irNhfHzrVZbmPYXDcEYhA5TVNwr+V92jF44rbf86hqGp8fiT702FyiArScYIlPSBTDUASCVNSpw==} + engines: {node: '>=8.6.0'} + + leveldown@5.6.0: + resolution: {integrity: sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ==} + engines: {node: '>=8.6.0'} + deprecated: Superseded by classic-level (https://github.com/Level/community#faq) + + levelup@4.4.0: + resolution: {integrity: sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ==} + engines: {node: '>=6'} + deprecated: Superseded by abstract-level (https://github.com/Level/community#faq) + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -15969,6 +16447,10 @@ packages: lodash@4.17.23: resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} + log-symbols@6.0.0: + resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} + engines: {node: '>=18'} + log-symbols@7.0.1: resolution: {integrity: sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==} engines: {node: '>=18'} @@ -16034,11 +16516,19 @@ packages: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} + ltgt@2.2.1: + resolution: {integrity: sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==} + lucide-react@0.454.0: resolution: {integrity: sha512-hw7zMDwykCLnEzgncEEjHeA6+45aeEzRYuKHuyRSOPkhko+J3ySGjGIzu+mmMfDFG1vazHepMaYFYHbTFAZAAQ==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc + lucide-react@0.577.0: + resolution: {integrity: sha512-4LjoFv2eEPwYDPg/CUdBJQSDfPyzXCRrVW1X7jrx/trgxnxkHFjnVZINbzvzxjN70dxychOfg+FTYwBiS3pQ5A==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -16756,6 +17246,16 @@ packages: msgpackr@1.11.9: resolution: {integrity: sha512-FkoAAyyA6HM8wL882EcEyFZ9s7hVADSwG9xrVx3dxxNQAtgADTrJoEWivID82Iv1zWDsv/OtbrrcZAzGzOMdNw==} + msw@2.12.14: + resolution: {integrity: sha512-4KXa4nVBIBjbDbd7vfQNuQ25eFxug0aropCQFoI0JdOBuJWamkT1yLVIWReFI8SiTRc+H1hKzaNk+cLk2N9rtQ==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + typescript: '>= 4.8.x' + peerDependenciesMeta: + typescript: + optional: true + muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} @@ -16805,6 +17305,9 @@ packages: napi-build-utils@2.0.0: resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + napi-macros@2.0.0: + resolution: {integrity: sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==} + napi-postinstall@0.3.4: resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -17008,6 +17511,10 @@ packages: resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} hasBin: true + node-gyp-build@4.1.1: + resolution: {integrity: sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ==} + hasBin: true + node-gyp-build@4.8.4: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true @@ -17352,6 +17859,10 @@ packages: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} + object-treeify@1.1.33: + resolution: {integrity: sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==} + engines: {node: '>= 10'} + object.assign@4.1.7: resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} @@ -17501,6 +18012,30 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} + openai@4.104.0: + resolution: {integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.23.8 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + + openai@5.23.2: + resolution: {integrity: sha512-MQBzmTulj+MM5O8SKEk/gL8a7s5mktS9zUtAkU257WjvobGc9nKcBuVwjyEEcb9SI8a8Y2G/mzn3vm9n1Jlleg==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.23.8 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + openai@6.32.0: resolution: {integrity: sha512-j3k+BjydAf8yQlcOI7WUQMQTbbF5GEIMAE2iZYCOzwwB3S2pCheaWYp+XZRNAch4jWVc52PMDGRRjutao3lLCg==} hasBin: true @@ -17533,6 +18068,10 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + ora@8.2.0: + resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} + engines: {node: '>=18'} + ora@9.3.0: resolution: {integrity: sha512-lBX72MWFduWEf7v7uWf5DHp9Jn5BI8bNPGuFgtXMmr2uDz2Gz2749y3am3agSDdkhHPHYmmxEGSKH85ZLGzgXw==} engines: {node: '>=20'} @@ -17550,6 +18089,9 @@ packages: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} + outvariant@1.4.3: + resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} + own-keys@1.0.1: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} @@ -17876,6 +18418,9 @@ packages: path-to-regexp@3.3.0: resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} @@ -18504,6 +19049,10 @@ packages: engines: {node: ^20.20.0 || >=22.22.0} hasBin: true + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -18558,6 +19107,9 @@ packages: prosemirror-view@1.41.5: resolution: {integrity: sha512-UDQbIPnDrjE8tqUBbPmCOZgtd75htE6W3r0JCmY9bL6W1iemDM37MZEKC49d+tdQ0v/CKx4gjxLoLsfkD2NiZA==} + prosemirror-view@1.41.7: + resolution: {integrity: sha512-jUwKNCEIGiqdvhlS91/2QAg21e4dfU5bH2iwmSDQeosXJgKF7smG0YSplOWK0cjSNgIqXe7VXqo7EIfUFJdt3w==} + proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} @@ -18939,6 +19491,10 @@ packages: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} + recast@0.23.11: + resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} + engines: {node: '>= 4'} + recharts-scale@0.4.5: resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==} @@ -19155,6 +19711,9 @@ packages: requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + reselect@5.1.1: + resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} + resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} @@ -19239,6 +19798,9 @@ packages: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} + rettime@0.10.1: + resolution: {integrity: sha512-uyDrIlUEH37cinabq0AX4QbgV4HbFZ/gqoiunWQ1UqBtRvTTytwhNYjE++pO/MjPTZL5KQCf2bEoJ/BJNVQ5Kw==} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -19481,6 +20043,9 @@ packages: secure-compare@3.0.1: resolution: {integrity: sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==} + secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + secure-json-parse@4.1.0: resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} @@ -19642,6 +20207,10 @@ packages: engines: {node: '>= 0.10'} hasBin: true + shadcn@4.1.0: + resolution: {integrity: sha512-3zETJ+0Ezj69FS6RL0HOkLKKAR5yXisXx1iISJdfLQfrUqj/VIQlanQi1Ukk+9OE+XHZVj4FQNTBSfbr2CyCYg==} + hasBin: true + shallow-clone@0.1.2: resolution: {integrity: sha512-J1zdXCky5GmNnuauESROVu31MQSnLoYvlyEn6j2Ztk6Q5EHFIhxkMhYcv6vuDzl2XEzoRr856QwzMgWM/TmZgw==} engines: {node: '>=0.10.0'} @@ -19962,6 +20531,10 @@ packages: std-env@4.0.0: resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} + stdin-discarder@0.2.2: + resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} + engines: {node: '>=18'} + stdin-discarder@0.3.1: resolution: {integrity: sha512-reExS1kSGoElkextOcPkel4NE99S0BWxjUHQeDFnR8S993JxpPX7KU4MNmO19NXhlJp+8dmdCbKQVNgLJh2teA==} engines: {node: '>=18'} @@ -20003,6 +20576,9 @@ packages: streamx@2.23.0: resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} + strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} + string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -20055,6 +20631,10 @@ packages: stringify-entities@4.0.4: resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + stringify-object@5.0.0: + resolution: {integrity: sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==} + engines: {node: '>=14.16'} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -20214,6 +20794,11 @@ packages: resolution: {integrity: sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==} hasBin: true + swr@2.4.1: + resolution: {integrity: sha512-2CC6CiKQtEwaEeNiqWTAw9PGykW8SR5zZX8MZk6TeAvEAnVS7Visz8WzphqgtQ8v2xz/4Q5K+j+SeMaKXeeQIA==} + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + sylvester@0.0.21: resolution: {integrity: sha512-yUT0ukFkFEt4nb+NY+n2ag51aS/u9UHXoZw+A4jgD77/jzZsBoSDHuqysrVCBC4CYR4TYvUJq54ONpXgDBH8tA==} engines: {node: '>=0.2.6'} @@ -20229,6 +20814,9 @@ packages: resolution: {integrity: sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==} engines: {node: '>=18'} + tabbable@6.4.0: + resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} + tagged-tag@1.0.0: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} @@ -20236,6 +20824,9 @@ packages: tailwind-merge@2.6.1: resolution: {integrity: sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==} + tailwind-merge@3.5.0: + resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} + tailwindcss-animate@1.0.7: resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} peerDependencies: @@ -20371,6 +20962,10 @@ packages: thread-stream@3.1.0: resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + throttleit@2.1.0: + resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} + engines: {node: '>=18'} + through2@2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} @@ -20548,6 +21143,9 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-morph@26.0.0: + resolution: {integrity: sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==} + ts-node@10.9.2: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true @@ -20565,6 +21163,10 @@ packages: tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + tsconfig-paths@4.2.0: + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} + tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -20613,6 +21215,9 @@ packages: resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + tw-animate-css@1.4.0: + resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} + tweetnacl@0.14.5: resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} @@ -21041,6 +21646,9 @@ packages: uploadthing: optional: true + until-async@3.0.2: + resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==} + untun@0.1.3: resolution: {integrity: sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==} hasBin: true @@ -21508,6 +22116,10 @@ packages: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} + web-streams-polyfill@4.0.0-beta.3: + resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} + engines: {node: '>= 14'} + web-worker@1.2.0: resolution: {integrity: sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==} @@ -21695,6 +22307,11 @@ packages: engines: {node: '>= 8'} hasBin: true + which@4.0.0: + resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} + engines: {node: ^16.13.0 || >=18.0.0} + hasBin: true + which@6.0.1: resolution: {integrity: sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==} engines: {node: ^20.17.0 || >=22.9.0} @@ -21764,6 +22381,17 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@6.2.3: + resolution: {integrity: sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@7.5.10: resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} engines: {node: '>=8.3.0'} @@ -21862,6 +22490,11 @@ packages: peerDependencies: yjs: ^13.0.0 + y-leveldb@0.1.2: + resolution: {integrity: sha512-6ulEn5AXfXJYi89rXPEg2mMHAyyw8+ZfeMMdOtBbV8FJpQ1NOrcgi6DTAcXof0dap84NjHPT2+9d0rb6cFsjEg==} + peerDependencies: + yjs: ^13.0.0 + y-prosemirror@1.3.7: resolution: {integrity: sha512-NpM99WSdD4Fx4if5xOMDpPtU3oAmTSjlzh5U4353ABbRHl1HtAFUx6HlebLZfyFxXN9jzKMDkVbcRjqOZVkYQg==} engines: {node: '>=16.0.0', npm: '>=8.0.0'} @@ -21878,6 +22511,13 @@ packages: peerDependencies: yjs: ^13.0.0 + y-websocket@2.1.0: + resolution: {integrity: sha512-WHYDRqomaGkkaujtowCDwL8KYk+t1zQCGIgKyvxvchhjTQlMgWXRHJK+FDEcWmHA7I7o/4fy0eniOrtmz0e4mA==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + hasBin: true + peerDependencies: + yjs: ^13.5.6 + y-websocket@3.0.0: resolution: {integrity: sha512-mUHy7AzkOZ834T/7piqtlA8Yk6AchqKqcrCXjKW8J1w2lPtRDjz8W5/CvXz9higKAHgKRKqpI3T33YkRFLkPtg==} engines: {node: '>=16.0.0', npm: '>=8.0.0'} @@ -22032,6 +22672,19 @@ snapshots: '@vercel/oidc': 3.1.0 zod: 4.3.6 + '@ai-sdk/openai@1.3.24(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 1.1.3 + '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) + zod: 3.25.76 + + '@ai-sdk/provider-utils@2.2.8(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 1.1.3 + nanoid: 3.3.11 + secure-json-parse: 2.7.0 + zod: 3.25.76 + '@ai-sdk/provider-utils@4.0.21(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 @@ -22039,10 +22692,31 @@ snapshots: eventsource-parser: 3.0.6 zod: 4.3.6 + '@ai-sdk/provider@1.1.3': + dependencies: + json-schema: 0.4.0 + '@ai-sdk/provider@3.0.8': dependencies: json-schema: 0.4.0 + '@ai-sdk/react@1.2.12(react@19.2.4)(zod@3.25.76)': + dependencies: + '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) + '@ai-sdk/ui-utils': 1.2.11(zod@3.25.76) + react: 19.2.4 + swr: 2.4.1(react@19.2.4) + throttleit: 2.1.0 + optionalDependencies: + zod: 3.25.76 + + '@ai-sdk/ui-utils@1.2.11(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 1.1.3 + '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) + zod: 3.25.76 + zod-to-json-schema: 3.25.1(zod@3.25.76) + '@ai-zen/node-fetch-event-source@2.1.4': dependencies: cross-fetch: 4.1.0 @@ -22153,13 +22827,13 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular-devkit/build-angular@21.2.3(@angular/compiler-cli@21.2.5(@angular/compiler@21.2.5)(typescript@5.9.3))(@angular/compiler@21.2.5)(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.2.5(@angular/common@21.2.5(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1)))(@types/node@22.19.8)(chokidar@5.0.0)(html-webpack-plugin@5.6.6(webpack@5.105.2(esbuild@0.27.3)))(jiti@2.6.1)(tailwindcss@4.2.2)(tsx@4.21.0)(typescript@5.9.3)(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)': + '@angular-devkit/build-angular@21.2.3(@angular/compiler-cli@21.2.5(@angular/compiler@21.2.5)(typescript@5.9.3))(@angular/compiler@21.2.5)(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.2.5(@angular/common@21.2.5(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1)))(@types/node@22.19.8)(chokidar@5.0.0)(html-webpack-plugin@5.6.6(webpack@5.105.2(esbuild@0.27.3)))(jiti@2.6.1)(tailwindcss@4.2.2)(tsx@4.21.0)(typescript@5.9.3)(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2102.3(chokidar@5.0.0) '@angular-devkit/build-webpack': 0.2102.3(chokidar@5.0.0)(webpack-dev-server@5.2.3(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.3)))(webpack@5.105.2(esbuild@0.27.3)) '@angular-devkit/core': 21.2.3(chokidar@5.0.0) - '@angular/build': 21.2.3(@angular/compiler-cli@21.2.5(@angular/compiler@21.2.5)(typescript@5.9.3))(@angular/compiler@21.2.5)(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.2.5(@angular/common@21.2.5(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1)))(@types/node@22.19.8)(chokidar@5.0.0)(jiti@2.6.1)(less@4.4.2)(postcss@8.5.6)(tailwindcss@4.2.2)(terser@5.46.0)(tslib@2.8.1)(tsx@4.21.0)(typescript@5.9.3)(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2) + '@angular/build': 21.2.3(@angular/compiler-cli@21.2.5(@angular/compiler@21.2.5)(typescript@5.9.3))(@angular/compiler@21.2.5)(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.2.5(@angular/common@21.2.5(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1)))(@types/node@22.19.8)(chokidar@5.0.0)(jiti@2.6.1)(less@4.4.2)(postcss@8.5.6)(tailwindcss@4.2.2)(terser@5.46.0)(tslib@2.8.1)(tsx@4.21.0)(typescript@5.9.3)(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2) '@angular/compiler-cli': 21.2.5(@angular/compiler@21.2.5)(typescript@5.9.3) '@babel/core': 7.29.0 '@babel/generator': 7.29.1 @@ -22268,7 +22942,7 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular/build@21.2.3(@angular/compiler-cli@21.2.5(@angular/compiler@21.2.5)(typescript@5.9.3))(@angular/compiler@21.2.5)(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.2.5(@angular/common@21.2.5(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1)))(@types/node@22.19.8)(chokidar@5.0.0)(jiti@2.6.1)(less@4.4.2)(postcss@8.5.6)(tailwindcss@4.2.2)(terser@5.46.0)(tslib@2.8.1)(tsx@4.21.0)(typescript@5.9.3)(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)': + '@angular/build@21.2.3(@angular/compiler-cli@21.2.5(@angular/compiler@21.2.5)(typescript@5.9.3))(@angular/compiler@21.2.5)(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.2.5(@angular/common@21.2.5(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.5(@angular/compiler@21.2.5)(rxjs@7.8.2)(zone.js@0.16.1)))(@types/node@22.19.8)(chokidar@5.0.0)(jiti@2.6.1)(less@4.4.2)(postcss@8.5.6)(tailwindcss@4.2.2)(terser@5.46.0)(tslib@2.8.1)(tsx@4.21.0)(typescript@5.9.3)(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2102.3(chokidar@5.0.0) @@ -22308,7 +22982,7 @@ snapshots: lmdb: 3.5.1 postcss: 8.5.6 tailwindcss: 4.2.2 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - '@types/node' - chokidar @@ -22438,8 +23112,8 @@ snapshots: '@apidevtools/openapi-schemas': 2.1.0 '@apidevtools/swagger-methods': 3.0.2 '@jsdevtools/ono': 7.1.3 - ajv: 8.17.1 - ajv-draft-04: 1.0.0(ajv@8.17.1) + ajv: 8.18.0 + ajv-draft-04: 1.0.0(ajv@8.18.0) call-me-maybe: 1.0.2 openapi-types: 7.2.3 @@ -22487,9 +23161,9 @@ snapshots: '@stoplight/types': 13.20.0 '@types/json-schema': 7.0.15 '@types/urijs': 1.19.26 - ajv: 8.17.1 - ajv-errors: 3.0.0(ajv@8.17.1) - ajv-formats: 2.1.1(ajv@8.17.1) + ajv: 8.18.0 + ajv-errors: 3.0.0(ajv@8.18.0) + ajv-formats: 2.1.1(ajv@8.18.0) avsc: 5.7.9 js-yaml: 4.1.1 jsonpath-plus: 10.3.0 @@ -24649,6 +25323,17 @@ snapshots: '@babel/types': 7.29.0 esutils: 2.0.3 + '@babel/preset-typescript@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + '@babel/runtime@7.28.6': {} '@babel/template@7.28.6': @@ -24674,6 +25359,30 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@base-ui/react@1.3.0(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@base-ui/utils': 0.2.6(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@floating-ui/utils': 0.2.11 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + tabbable: 6.4.0 + use-sync-external-store: 1.6.0(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.11 + + '@base-ui/utils@0.2.6(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@floating-ui/utils': 0.2.11 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + reselect: 5.1.1 + use-sync-external-store: 1.6.0(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.11 + '@bcoe/v8-coverage@1.0.2': {} '@bomb.sh/tab@0.0.14(cac@6.7.14)(citty@0.2.1)': @@ -24886,6 +25595,18 @@ snapshots: '@discoveryjs/json-ext@0.6.3': {} + '@dotenvx/dotenvx@1.57.0': + dependencies: + commander: 11.1.0 + dotenv: 17.3.1 + eciesjs: 0.4.18 + execa: 5.1.1 + fdir: 6.5.0(picomatch@4.0.3) + ignore: 5.3.2 + object-treeify: 1.1.33 + picomatch: 4.0.3 + which: 4.0.0 + '@dxup/nuxt@0.4.0(magicast@0.5.2)(typescript@5.9.3)': dependencies: '@dxup/unimport': 0.1.2 @@ -24899,6 +25620,10 @@ snapshots: '@dxup/unimport@0.1.2': {} + '@ecies/ciphers@0.2.5(@noble/ciphers@1.3.0)': + dependencies: + '@noble/ciphers': 1.3.0 + '@emnapi/core@1.8.1': dependencies: '@emnapi/wasi-threads': 1.1.0 @@ -25349,25 +26074,42 @@ snapshots: dependencies: '@floating-ui/utils': 0.2.10 + '@floating-ui/core@1.7.5': + dependencies: + '@floating-ui/utils': 0.2.11 + '@floating-ui/dom@1.7.5': dependencies: '@floating-ui/core': 1.7.4 '@floating-ui/utils': 0.2.10 + '@floating-ui/dom@1.7.6': + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 + '@floating-ui/react-dom@2.1.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@floating-ui/dom': 1.7.5 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@floating-ui/react-dom@2.1.7(react-dom@19.2.4(react@19.2.3))(react@19.2.3)': + '@floating-ui/react-dom@2.1.8(react-dom@19.2.4(react@19.2.3))(react@19.2.3)': dependencies: - '@floating-ui/dom': 1.7.5 + '@floating-ui/dom': 1.7.6 react: 19.2.3 react-dom: 19.2.4(react@19.2.3) + '@floating-ui/react-dom@2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@floating-ui/dom': 1.7.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + '@floating-ui/utils@0.2.10': {} + '@floating-ui/utils@0.2.11': {} + '@fortawesome/fontawesome-common-types@6.7.2': {} '@fortawesome/fontawesome-svg-core@6.7.2': @@ -25452,6 +26194,18 @@ snapshots: - bufferutil - utf-8-validate + '@hocuspocus/provider@2.15.3(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30)': + dependencies: + '@hocuspocus/common': 2.15.3 + '@lifeomic/attempt': 3.1.0 + lib0: 0.2.117 + ws: 8.19.0 + y-protocols: 1.0.7(yjs@13.6.30) + yjs: 13.6.30 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@hocuspocus/provider@3.4.4(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30)': dependencies: '@hocuspocus/common': 3.4.4 @@ -25478,6 +26232,20 @@ snapshots: - bufferutil - utf-8-validate + '@hocuspocus/server@2.15.3(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30)': + dependencies: + '@hocuspocus/common': 2.15.3 + async-lock: 1.4.1 + kleur: 4.1.5 + lib0: 0.2.117 + uuid: 11.1.0 + ws: 8.19.0 + y-protocols: 1.0.7(yjs@13.6.30) + yjs: 13.6.30 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@hono/node-server@1.19.9(hono@4.12.1)': dependencies: hono: 4.12.1 @@ -25731,6 +26499,16 @@ snapshots: chalk: 4.1.2 figures: 3.2.0 + '@inquirer/checkbox@4.3.2(@types/node@22.19.2)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@22.19.2) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/checkbox@4.3.2(@types/node@22.19.8)': dependencies: '@inquirer/ansi': 1.0.2 @@ -25756,6 +26534,13 @@ snapshots: '@inquirer/type': 1.5.5 chalk: 4.1.2 + '@inquirer/confirm@5.1.21(@types/node@22.19.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/confirm@5.1.21(@types/node@22.19.8)': dependencies: '@inquirer/core': 10.3.2(@types/node@22.19.8) @@ -25770,6 +26555,19 @@ snapshots: optionalDependencies: '@types/node': 18.19.130 + '@inquirer/core@10.3.2(@types/node@22.19.2)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@22.19.2) + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/core@10.3.2(@types/node@22.19.8)': dependencies: '@inquirer/ansi': 1.0.2 @@ -25836,6 +26634,14 @@ snapshots: chalk: 4.1.2 external-editor: 3.1.0 + '@inquirer/editor@4.2.23(@types/node@22.19.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/external-editor': 1.0.3(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/editor@4.2.23(@types/node@22.19.8)': dependencies: '@inquirer/core': 10.3.2(@types/node@22.19.8) @@ -25859,6 +26665,14 @@ snapshots: chalk: 4.1.2 figures: 3.2.0 + '@inquirer/expand@4.0.23(@types/node@22.19.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/expand@4.0.23(@types/node@22.19.8)': dependencies: '@inquirer/core': 10.3.2(@types/node@22.19.8) @@ -25867,6 +26681,13 @@ snapshots: optionalDependencies: '@types/node': 22.19.8 + '@inquirer/external-editor@1.0.3(@types/node@22.19.2)': + dependencies: + chardet: 2.1.1 + iconv-lite: 0.7.2 + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/external-editor@1.0.3(@types/node@22.19.8)': dependencies: chardet: 2.1.1 @@ -25891,6 +26712,13 @@ snapshots: '@inquirer/type': 1.5.5 chalk: 4.1.2 + '@inquirer/input@4.3.1(@types/node@22.19.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/input@4.3.1(@types/node@22.19.8)': dependencies: '@inquirer/core': 10.3.2(@types/node@22.19.8) @@ -25905,6 +26733,13 @@ snapshots: optionalDependencies: '@types/node': 18.19.130 + '@inquirer/number@3.0.23(@types/node@22.19.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/number@3.0.23(@types/node@22.19.8)': dependencies: '@inquirer/core': 10.3.2(@types/node@22.19.8) @@ -25919,6 +26754,14 @@ snapshots: ansi-escapes: 4.3.2 chalk: 4.1.2 + '@inquirer/password@4.0.23(@types/node@22.19.2)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/password@4.0.23(@types/node@22.19.8)': dependencies: '@inquirer/ansi': 1.0.2 @@ -25954,20 +26797,20 @@ snapshots: optionalDependencies: '@types/node': 22.19.8 - '@inquirer/prompts@7.9.0(@types/node@22.19.8)': + '@inquirer/prompts@7.9.0(@types/node@22.19.2)': dependencies: - '@inquirer/checkbox': 4.3.2(@types/node@22.19.8) - '@inquirer/confirm': 5.1.21(@types/node@22.19.8) - '@inquirer/editor': 4.2.23(@types/node@22.19.8) - '@inquirer/expand': 4.0.23(@types/node@22.19.8) - '@inquirer/input': 4.3.1(@types/node@22.19.8) - '@inquirer/number': 3.0.23(@types/node@22.19.8) - '@inquirer/password': 4.0.23(@types/node@22.19.8) - '@inquirer/rawlist': 4.1.11(@types/node@22.19.8) - '@inquirer/search': 3.2.2(@types/node@22.19.8) - '@inquirer/select': 4.4.2(@types/node@22.19.8) + '@inquirer/checkbox': 4.3.2(@types/node@22.19.2) + '@inquirer/confirm': 5.1.21(@types/node@22.19.2) + '@inquirer/editor': 4.2.23(@types/node@22.19.2) + '@inquirer/expand': 4.0.23(@types/node@22.19.2) + '@inquirer/input': 4.3.1(@types/node@22.19.2) + '@inquirer/number': 3.0.23(@types/node@22.19.2) + '@inquirer/password': 4.0.23(@types/node@22.19.2) + '@inquirer/rawlist': 4.1.11(@types/node@22.19.2) + '@inquirer/search': 3.2.2(@types/node@22.19.2) + '@inquirer/select': 4.4.2(@types/node@22.19.2) optionalDependencies: - '@types/node': 22.19.8 + '@types/node': 22.19.2 '@inquirer/rawlist@1.2.16': dependencies: @@ -25975,6 +26818,14 @@ snapshots: '@inquirer/type': 1.5.5 chalk: 4.1.2 + '@inquirer/rawlist@4.1.11(@types/node@22.19.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/rawlist@4.1.11(@types/node@22.19.8)': dependencies: '@inquirer/core': 10.3.2(@types/node@22.19.8) @@ -25983,6 +26834,15 @@ snapshots: optionalDependencies: '@types/node': 22.19.8 + '@inquirer/search@3.2.2(@types/node@22.19.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@22.19.2) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/search@3.2.2(@types/node@22.19.8)': dependencies: '@inquirer/core': 10.3.2(@types/node@22.19.8) @@ -26000,6 +26860,16 @@ snapshots: chalk: 4.1.2 figures: 3.2.0 + '@inquirer/select@4.4.2(@types/node@22.19.2)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@22.19.2) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/select@4.4.2(@types/node@22.19.8)': dependencies: '@inquirer/ansi': 1.0.2 @@ -26023,6 +26893,10 @@ snapshots: dependencies: mute-stream: 1.0.0 + '@inquirer/type@3.0.10(@types/node@22.19.2)': + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/type@3.0.10(@types/node@22.19.8)': optionalDependencies: '@types/node': 22.19.8 @@ -26407,9 +27281,9 @@ snapshots: '@types/fs-extra': 11.0.4 '@types/node-fetch': 2.6.13 '@types/strip-bom': 4.0.1 - ajv: 8.17.1 - ajv-draft-04: 1.0.0(ajv@8.17.1) - ajv-formats: 3.0.1(ajv@8.17.1) + ajv: 8.18.0 + ajv-draft-04: 1.0.0(ajv@8.18.0) + ajv-formats: 3.0.1(ajv@8.18.0) node-fetch: 2.7.0 strip-bom: 5.0.0 transitivePeerDependencies: @@ -26426,7 +27300,7 @@ snapshots: '@microsoft/dev-tunnels-management@1.1.9': dependencies: '@microsoft/dev-tunnels-contracts': 1.1.9 - axios: 1.13.2(debug@4.4.3) + axios: 1.13.6(debug@4.4.3) buffer: 5.7.1 debug: 4.4.3(supports-color@5.5.0) vscode-jsonrpc: 4.0.0 @@ -26448,9 +27322,9 @@ snapshots: dependencies: '@types/fs-extra': 11.0.4 '@types/node-fetch': 2.6.13 - ajv: 8.17.1 - ajv-draft-04: 1.0.0(ajv@8.17.1) - ajv-formats: 3.0.1(ajv@8.17.1) + ajv: 8.18.0 + ajv-draft-04: 1.0.0(ajv@8.18.0) + ajv-formats: 3.0.1(ajv@8.18.0) fs-extra: 9.1.0 node-fetch: 2.7.0 transitivePeerDependencies: @@ -26492,7 +27366,7 @@ snapshots: lodash: 4.17.23 node-machine-id: 1.1.12 open: 8.4.2 - semver: 7.7.3 + semver: 7.7.4 tree-kill: 1.2.2 underscore: 1.13.7 optionalDependencies: @@ -26506,7 +27380,7 @@ snapshots: dependencies: '@azure/core-auth': 1.10.1 '@microsoft/teams-manifest': 0.1.5 - axios: 1.13.2(debug@4.4.3) + axios: 1.13.6(debug@4.4.3) chai: 4.5.0 jsonschema: 1.5.0 neverthrow: 3.2.0 @@ -26533,8 +27407,8 @@ snapshots: '@microsoft/m365-spec-parser': 0.2.11 '@microsoft/teamsfx-api': 0.23.1 adm-zip: 0.5.16 - ajv: 8.17.1 - axios: 1.13.2(debug@4.4.3) + ajv: 8.18.0 + axios: 1.13.6(debug@4.4.3) axios-retry: 3.9.1 comment-json: 4.6.2 cryptr: 6.4.0 @@ -26561,7 +27435,7 @@ snapshots: proper-lockfile: 4.1.2 read-package-json-fast: 2.0.3 reflect-metadata: 0.1.14 - semver: 7.7.3 + semver: 7.7.4 strip-bom: 4.0.0 swagger2openapi: 7.0.8 typedi: 0.10.0 @@ -26583,11 +27457,11 @@ snapshots: '@microsoft/tsdoc@0.16.0': {} - '@mintlify/cli@4.0.1045(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.8)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)': + '@mintlify/cli@4.0.1045(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)': dependencies: - '@inquirer/prompts': 7.9.0(@types/node@22.19.8) + '@inquirer/prompts': 7.9.0(@types/node@22.19.2) '@mintlify/common': 1.0.810(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) - '@mintlify/link-rot': 3.0.979(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) + '@mintlify/link-rot': 3.0.979(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) '@mintlify/models': 0.0.286 '@mintlify/prebuild': 1.0.950(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) '@mintlify/previewing': 4.0.1008(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) @@ -26600,7 +27474,7 @@ snapshots: front-matter: 4.0.2 fs-extra: 11.2.0 ink: 6.3.0(@types/react@19.2.11)(react@19.2.3) - inquirer: 12.3.0(@types/node@22.19.8) + inquirer: 12.3.0(@types/node@22.19.2) js-yaml: 4.1.0 mdast-util-mdx-jsx: 3.2.0 react: 19.2.3 @@ -26626,7 +27500,7 @@ snapshots: - utf-8-validate - yaml - '@mintlify/common@1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3))(typescript@5.9.3)': + '@mintlify/common@1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3)': dependencies: '@asyncapi/parser': 3.4.0 '@mintlify/mdx': 3.0.4(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) @@ -26666,7 +27540,7 @@ snapshots: remark-parse: 11.0.0 remark-rehype: 11.1.1 remark-stringify: 11.0.0 - tailwindcss: 3.4.4(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3)) + tailwindcss: 3.4.4(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3)) unified: 11.0.5 unist-builder: 4.0.0 unist-util-map: 4.0.0 @@ -26750,12 +27624,12 @@ snapshots: - typescript - yaml - '@mintlify/link-rot@3.0.979(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)': + '@mintlify/link-rot@3.0.979(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)': dependencies: '@mintlify/common': 1.0.810(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) '@mintlify/prebuild': 1.0.950(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) '@mintlify/previewing': 4.0.1008(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) - '@mintlify/scraping': 4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3))(typescript@5.9.3) + '@mintlify/scraping': 4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3) '@mintlify/validation': 0.1.639(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) fs-extra: 11.1.0 unist-util-visit: 4.1.2 @@ -26813,16 +27687,16 @@ snapshots: '@mintlify/models@0.0.286': dependencies: - axios: 1.13.2(debug@4.4.3) + axios: 1.13.2 openapi-types: 12.1.3 transitivePeerDependencies: - debug '@mintlify/openapi-parser@0.0.8': dependencies: - ajv: 8.17.1 - ajv-draft-04: 1.0.0(ajv@8.17.1) - ajv-formats: 3.0.1(ajv@8.17.1) + ajv: 8.18.0 + ajv-draft-04: 1.0.0(ajv@8.18.0) + ajv-formats: 3.0.1(ajv@8.18.0) jsonpointer: 5.0.1 leven: 4.1.0 yaml: 2.8.2 @@ -26899,9 +27773,9 @@ snapshots: - utf-8-validate - yaml - '@mintlify/scraping@4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3))(typescript@5.9.3)': + '@mintlify/scraping@4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3)': dependencies: - '@mintlify/common': 1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3))(typescript@5.9.3) + '@mintlify/common': 1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3) '@mintlify/openapi-parser': 0.0.8 fs-extra: 11.1.1 hast-util-to-mdast: 10.1.0 @@ -27037,6 +27911,28 @@ snapshots: transitivePeerDependencies: - supports-color + '@modelcontextprotocol/sdk@1.27.1(zod@3.25.76)': + dependencies: + '@hono/node-server': 1.19.9(hono@4.12.8) + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 8.2.1(express@5.2.1) + hono: 4.12.8 + jose: 6.1.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.1(zod@3.25.76) + transitivePeerDependencies: + - supports-color + '@modelcontextprotocol/sdk@1.27.1(zod@4.3.6)': dependencies: '@hono/node-server': 1.19.9(hono@4.12.8) @@ -27085,6 +27981,15 @@ snapshots: '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': optional: true + '@mswjs/interceptors@0.41.3': + dependencies: + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 + '@napi-rs/canvas-android-arm64@0.1.80': optional: true @@ -27399,6 +28304,12 @@ snapshots: typescript: 5.9.3 webpack: 5.105.2(esbuild@0.27.3) + '@noble/ciphers@1.3.0': {} + + '@noble/curves@1.9.7': + dependencies: + '@noble/hashes': 1.8.0 + '@noble/hashes@1.4.0': {} '@noble/hashes@1.8.0': {} @@ -27816,6 +28727,27 @@ snapshots: '@one-ini/wasm@0.1.1': {} + '@open-draft/deferred-promise@2.2.0': {} + + '@open-draft/logger@0.3.0': + dependencies: + is-node-process: 1.2.0 + outvariant: 1.4.3 + + '@open-draft/until@2.1.0': {} + + '@openai/agents-core@0.1.11(ws@8.19.0)(zod@4.3.6)': + dependencies: + debug: 4.4.3(supports-color@5.5.0) + openai: 5.23.2(ws@8.19.0)(zod@4.3.6) + optionalDependencies: + '@modelcontextprotocol/sdk': 1.27.1(zod@4.3.6) + zod: 4.3.6 + transitivePeerDependencies: + - '@cfworker/json-schema' + - supports-color + - ws + '@openai/agents-core@0.5.4(ws@8.19.0)(zod@4.3.6)': dependencies: debug: 4.4.3(supports-color@5.5.0) @@ -27828,6 +28760,17 @@ snapshots: - supports-color - ws + '@openai/agents-openai@0.1.11(ws@8.19.0)(zod@4.3.6)': + dependencies: + '@openai/agents-core': 0.1.11(ws@8.19.0)(zod@4.3.6) + debug: 4.4.3(supports-color@5.5.0) + openai: 5.23.2(ws@8.19.0)(zod@4.3.6) + zod: 4.3.6 + transitivePeerDependencies: + - '@cfworker/json-schema' + - supports-color + - ws + '@openai/agents-openai@0.5.4(ws@8.19.0)(zod@4.3.6)': dependencies: '@openai/agents-core': 0.5.4(ws@8.19.0)(zod@4.3.6) @@ -27839,6 +28782,19 @@ snapshots: - supports-color - ws + '@openai/agents-realtime@0.1.11(zod@4.3.6)': + dependencies: + '@openai/agents-core': 0.1.11(ws@8.19.0)(zod@4.3.6) + '@types/ws': 8.18.1 + debug: 4.4.3(supports-color@5.5.0) + ws: 8.19.0 + zod: 4.3.6 + transitivePeerDependencies: + - '@cfworker/json-schema' + - bufferutil + - supports-color + - utf-8-validate + '@openai/agents-realtime@0.5.4(zod@4.3.6)': dependencies: '@openai/agents-core': 0.5.4(ws@8.19.0)(zod@4.3.6) @@ -27852,6 +28808,21 @@ snapshots: - supports-color - utf-8-validate + '@openai/agents@0.1.11(ws@8.19.0)(zod@4.3.6)': + dependencies: + '@openai/agents-core': 0.1.11(ws@8.19.0)(zod@4.3.6) + '@openai/agents-openai': 0.1.11(ws@8.19.0)(zod@4.3.6) + '@openai/agents-realtime': 0.1.11(zod@4.3.6) + debug: 4.4.3(supports-color@5.5.0) + openai: 5.23.2(ws@8.19.0)(zod@4.3.6) + zod: 4.3.6 + transitivePeerDependencies: + - '@cfworker/json-schema' + - bufferutil + - supports-color + - utf-8-validate + - ws + '@openai/agents@0.5.4(ws@8.19.0)(zod@4.3.6)': dependencies: '@openai/agents-core': 0.5.4(ws@8.19.0)(zod@4.3.6) @@ -28869,7 +29840,7 @@ snapshots: '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)': dependencies: - '@floating-ui/react-dom': 2.1.7(react-dom@19.2.4(react@19.2.3))(react@19.2.3) + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.3))(react@19.2.3) '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.11)(react@19.2.3) '@radix-ui/react-context': 1.1.2(@types/react@19.2.11)(react@19.2.3) @@ -30630,9 +31601,9 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@stoplight/better-ajv-errors@1.0.3(ajv@8.17.1)': + '@stoplight/better-ajv-errors@1.0.3(ajv@8.18.0)': dependencies: - ajv: 8.17.1 + ajv: 8.18.0 jsonpointer: 5.0.1 leven: 3.1.0 @@ -30671,7 +31642,7 @@ snapshots: '@stoplight/spectral-core@1.21.0': dependencies: - '@stoplight/better-ajv-errors': 1.0.3(ajv@8.17.1) + '@stoplight/better-ajv-errors': 1.0.3(ajv@8.18.0) '@stoplight/json': 3.21.0 '@stoplight/path': 1.3.2 '@stoplight/spectral-parsers': 1.0.5 @@ -30680,9 +31651,9 @@ snapshots: '@stoplight/types': 13.6.0 '@types/es-aggregate-error': 1.0.6 '@types/json-schema': 7.0.15 - ajv: 8.17.1 - ajv-errors: 3.0.0(ajv@8.17.1) - ajv-formats: 2.1.1(ajv@8.17.1) + ajv: 8.18.0 + ajv-errors: 3.0.0(ajv@8.18.0) + ajv-formats: 2.1.1(ajv@8.18.0) es-aggregate-error: 1.0.14 jsonpath-plus: 10.3.0 lodash: 4.17.23 @@ -30706,15 +31677,15 @@ snapshots: '@stoplight/spectral-functions@1.10.1': dependencies: - '@stoplight/better-ajv-errors': 1.0.3(ajv@8.17.1) + '@stoplight/better-ajv-errors': 1.0.3(ajv@8.18.0) '@stoplight/json': 3.21.0 '@stoplight/spectral-core': 1.21.0 '@stoplight/spectral-formats': 1.8.2 '@stoplight/spectral-runtime': 1.1.4 - ajv: 8.17.1 - ajv-draft-04: 1.0.0(ajv@8.17.1) - ajv-errors: 3.0.0(ajv@8.17.1) - ajv-formats: 2.1.1(ajv@8.17.1) + ajv: 8.18.0 + ajv-draft-04: 1.0.0(ajv@8.18.0) + ajv-errors: 3.0.0(ajv@8.18.0) + ajv-formats: 2.1.1(ajv@8.18.0) lodash: 4.17.23 tslib: 2.8.1 transitivePeerDependencies: @@ -30905,7 +31876,7 @@ snapshots: '@alloc/quick-lru': 5.2.0 '@tailwindcss/node': 4.2.2 '@tailwindcss/oxide': 4.2.2 - postcss: 8.5.6 + postcss: 8.5.8 tailwindcss: 4.2.2 '@testing-library/dom@10.4.1': @@ -30957,6 +31928,12 @@ snapshots: '@tootallnate/quickjs-emscripten@0.23.0': {} + '@ts-morph/common@0.27.0': + dependencies: + fast-glob: 3.3.3 + minimatch: 10.2.4 + path-browserify: 1.0.1 + '@tsconfig/node10@1.0.12': optional: true @@ -30974,7 +31951,7 @@ snapshots: '@tufjs/models@4.1.0': dependencies: '@tufjs/canonical-json': 2.0.0 - minimatch: 10.1.2 + minimatch: 10.2.4 '@tybys/wasm-util@0.10.1': dependencies: @@ -31079,6 +32056,8 @@ snapshots: '@types/deep-eql@4.0.2': {} + '@types/diff-match-patch@1.0.36': {} + '@types/es-aggregate-error@1.0.6': dependencies: '@types/node': 22.19.8 @@ -31202,7 +32181,6 @@ snapshots: '@types/node@18.19.130': dependencies: undici-types: 5.26.5 - optional: true '@types/node@20.19.37': dependencies: @@ -31291,6 +32269,8 @@ snapshots: dependencies: '@types/node': 22.19.8 + '@types/statuses@2.0.6': {} + '@types/strip-bom@4.0.1': dependencies: strip-bom: 5.0.0 @@ -31307,6 +32287,8 @@ snapshots: '@types/urijs@1.19.26': {} + '@types/validate-npm-package-name@4.0.2': {} + '@types/vscode@1.108.1': {} '@types/webidl-conversions@7.0.3': @@ -32003,7 +32985,7 @@ snapshots: vite: rolldown-vite@7.3.1(@types/node@22.19.8)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) vue: 3.5.25(typescript@5.9.3) - '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.2)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 @@ -32018,7 +33000,26 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.2)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) + transitivePeerDependencies: + - supports-color + + '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 1.0.2 + ast-v8-to-istanbul: 0.3.11 + debug: 4.4.3(supports-color@5.5.0) + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + magic-string: 0.30.21 + magicast: 0.3.5 + std-env: 3.10.0 + test-exclude: 7.0.1 + tinyrainbow: 2.0.0 + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color @@ -32030,28 +33031,31 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(rolldown-vite@7.3.1(@types/node@22.19.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@3.2.4(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(rolldown-vite@7.3.1(@types/node@22.19.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: + msw: 2.12.14(@types/node@22.19.2)(typescript@5.9.3) vite: rolldown-vite@7.3.1(@types/node@22.19.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/mocker@3.2.4(rolldown-vite@7.3.1(@types/node@22.19.2)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@3.2.4(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(rolldown-vite@7.3.1(@types/node@22.19.2)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: + msw: 2.12.14(@types/node@22.19.2)(typescript@5.9.3) vite: rolldown-vite@7.3.1(@types/node@22.19.2)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/mocker@3.2.4(rolldown-vite@7.3.1(@types/node@22.19.8)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@3.2.4(msw@2.12.14(@types/node@22.19.8)(typescript@5.9.3))(rolldown-vite@7.3.1(@types/node@22.19.8)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: + msw: 2.12.14(@types/node@22.19.8)(typescript@5.9.3) vite: rolldown-vite@7.3.1(@types/node@22.19.8)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2) '@vitest/pretty-format@3.2.4': @@ -32252,7 +33256,7 @@ snapshots: '@vue/shared': 3.5.25 estree-walker: 2.0.2 magic-string: 0.30.21 - postcss: 8.5.6 + postcss: 8.5.8 source-map-js: 1.2.1 '@vue/compiler-ssr@3.5.25': @@ -32491,6 +33495,24 @@ snapshots: dependencies: event-target-shim: 5.0.1 + abstract-leveldown@6.2.3: + dependencies: + buffer: 5.7.1 + immediate: 3.3.0 + level-concat-iterator: 2.0.1 + level-supports: 1.0.1 + xtend: 4.0.2 + optional: true + + abstract-leveldown@6.3.0: + dependencies: + buffer: 5.7.1 + immediate: 3.3.0 + level-concat-iterator: 2.0.1 + level-supports: 1.0.1 + xtend: 4.0.2 + optional: true + abstract-logging@2.0.1: {} accepts@1.3.8: @@ -32559,6 +33581,10 @@ snapshots: agent-base@7.1.4: {} + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 @@ -32574,6 +33600,18 @@ snapshots: clean-stack: 5.3.0 indent-string: 5.0.0 + ai@4.3.19(react@19.2.4)(zod@3.25.76): + dependencies: + '@ai-sdk/provider': 1.1.3 + '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) + '@ai-sdk/react': 1.2.12(react@19.2.4)(zod@3.25.76) + '@ai-sdk/ui-utils': 1.2.11(zod@3.25.76) + '@opentelemetry/api': 1.9.0 + jsondiffpatch: 0.6.0 + zod: 3.25.76 + optionalDependencies: + react: 19.2.4 + ai@6.0.133(zod@4.3.6): dependencies: '@ai-sdk/gateway': 3.0.77(zod@4.3.6) @@ -32590,14 +33628,22 @@ snapshots: optionalDependencies: ajv: 8.17.1 - ajv-errors@3.0.0(ajv@8.17.1): + ajv-draft-04@1.0.0(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv-errors@3.0.0(ajv@8.18.0): dependencies: - ajv: 8.17.1 + ajv: 8.18.0 ajv-formats@2.1.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 + ajv-formats@2.1.1(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + ajv-formats@3.0.1(ajv@8.13.0): optionalDependencies: ajv: 8.13.0 @@ -32925,6 +33971,10 @@ snapshots: dependencies: tslib: 2.8.1 + ast-types@0.16.1: + dependencies: + tslib: 2.8.1 + ast-v8-to-istanbul@0.3.11: dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -32944,6 +33994,9 @@ snapshots: dependencies: stack-chain: 1.3.7 + async-limiter@1.0.1: + optional: true + async-listener@0.6.10: dependencies: semver: 5.7.2 @@ -33032,7 +34085,7 @@ snapshots: transitivePeerDependencies: - debug - axios@1.13.2(debug@4.4.3): + axios@1.13.2: dependencies: follow-redirects: 1.15.11(debug@4.4.3) form-data: 4.0.5 @@ -33047,7 +34100,6 @@ snapshots: proxy-from-env: 1.1.0 transitivePeerDependencies: - debug - optional: true axobject-query@4.1.0: {} @@ -33174,9 +34226,9 @@ snapshots: domhandler: 5.0.3 htmlparser2: 10.1.0 picocolors: 1.1.1 - postcss: 8.5.6 + postcss: 8.5.8 postcss-media-query-parser: 0.2.3 - postcss-safe-parser: 7.0.1(postcss@8.5.6) + postcss-safe-parser: 7.0.1(postcss@8.5.8) before-after-hook@4.0.0: {} @@ -33376,7 +34428,7 @@ snapshots: browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.9.19 - caniuse-lite: 1.0.30001767 + caniuse-lite: 1.0.30001780 electron-to-chromium: 1.5.286 node-releases: 2.0.27 update-browserslist-db: 1.2.3(browserslist@4.28.1) @@ -33530,7 +34582,7 @@ snapshots: caniuse-api@3.0.0: dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001767 + caniuse-lite: 1.0.30001780 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 @@ -33840,6 +34892,8 @@ snapshots: cockatiel@3.2.1: {} + code-block-writer@13.0.3: {} + code-excerpt@4.0.0: dependencies: convert-to-spaces: 2.0.1 @@ -34229,12 +35283,12 @@ snapshots: css-loader@7.1.3(webpack@5.105.2(esbuild@0.27.3)): dependencies: - icss-utils: 5.1.0(postcss@8.5.6) - postcss: 8.5.6 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.6) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.6) - postcss-modules-scope: 3.2.1(postcss@8.5.6) - postcss-modules-values: 4.0.0(postcss@8.5.6) + icss-utils: 5.1.0(postcss@8.5.8) + postcss: 8.5.8 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.8) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.8) + postcss-modules-scope: 3.2.1(postcss@8.5.8) + postcss-modules-values: 4.0.0(postcss@8.5.8) postcss-value-parser: 4.2.0 semver: 7.7.4 optionalDependencies: @@ -34499,6 +35553,12 @@ snapshots: defer-to-connect@2.0.1: {} + deferred-leveldown@5.3.0: + dependencies: + abstract-leveldown: 6.2.3 + inherits: 2.0.4 + optional: true + define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 @@ -34595,6 +35655,8 @@ snapshots: didyoumean@1.2.2: {} + diff-match-patch@1.0.5: {} + diff@4.0.4: optional: true @@ -34795,6 +35857,13 @@ snapshots: dependencies: safe-buffer: 5.2.1 + eciesjs@0.4.18: + dependencies: + '@ecies/ciphers': 0.2.5(@noble/ciphers@1.3.0) + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + editions@6.22.0: dependencies: version-range: 4.15.0 @@ -34852,6 +35921,14 @@ snapshots: encodeurl@2.0.0: {} + encoding-down@6.3.0: + dependencies: + abstract-leveldown: 6.3.0 + inherits: 2.0.4 + level-codec: 9.0.2 + level-errors: 2.0.1 + optional: true + encoding-sniffer@0.2.1: dependencies: iconv-lite: 0.6.3 @@ -35479,8 +36556,8 @@ snapshots: '@babel/parser': 7.29.0 eslint: 9.39.2(jiti@2.6.1) hermes-parser: 0.25.1 - zod: 4.3.6 - zod-validation-error: 4.0.2(zod@4.3.6) + zod: 3.25.76 + zod-validation-error: 4.0.2(zod@3.25.76) transitivePeerDependencies: - supports-color @@ -36253,6 +37330,11 @@ snapshots: format@0.2.2: {} + formdata-node@4.4.1: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 4.0.0-beta.3 + formdata-polyfill@4.0.10: dependencies: fetch-blob: 3.2.0 @@ -36364,6 +37446,8 @@ snapshots: fuse.js@7.1.0: {} + fuzzysort@3.1.0: {} + fzf@0.5.2: {} gaxios@6.7.1: @@ -36431,6 +37515,8 @@ snapshots: get-nonce@1.0.1: {} + get-own-enumerable-keys@1.0.0: {} + get-port-please@3.2.0: {} get-proto@1.0.1: @@ -36719,6 +37805,8 @@ snapshots: graphemer@1.4.0: {} + graphql@16.13.1: {} + gtoken@7.1.0: dependencies: gaxios: 6.7.1 @@ -37086,6 +38174,8 @@ snapshots: he@1.2.0: {} + headers-polyfill@4.0.3: {} + hermes-estree@0.25.1: {} hermes-parser@0.25.1: @@ -37356,6 +38446,10 @@ snapshots: human-signals@8.0.1: {} + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + hyperdyperid@1.2.0: {} ibm-cloud-sdk-core@5.4.9: @@ -37394,9 +38488,9 @@ snapshots: dependencies: safer-buffer: 2.1.2 - icss-utils@5.1.0(postcss@8.5.6): + icss-utils@5.1.0(postcss@8.5.8): dependencies: - postcss: 8.5.6 + postcss: 8.5.8 idtoken-verifier@2.2.4: dependencies: @@ -37426,6 +38520,9 @@ snapshots: immediate@3.0.6: {} + immediate@3.3.0: + optional: true + immer@9.0.21: {} immutable@5.1.5: {} @@ -37563,12 +38660,12 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - inquirer@12.3.0(@types/node@22.19.8): + inquirer@12.3.0(@types/node@22.19.2): dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.8) - '@inquirer/prompts': 7.9.0(@types/node@22.19.8) - '@inquirer/type': 3.0.10(@types/node@22.19.8) - '@types/node': 22.19.8 + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/prompts': 7.9.0(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + '@types/node': 22.19.2 ansi-escapes: 4.3.2 mute-stream: 2.0.0 run-async: 3.0.0 @@ -37780,6 +38877,8 @@ snapshots: is-network-error@1.3.1: {} + is-node-process@1.2.0: {} + is-number-object@1.1.1: dependencies: call-bound: 1.0.4 @@ -37789,6 +38888,8 @@ snapshots: is-obj@2.0.0: {} + is-obj@3.0.0: {} + is-online@10.0.0: dependencies: got: 12.6.1 @@ -37833,6 +38934,8 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 + is-regexp@3.1.0: {} + is-relative@1.0.0: dependencies: is-unc-path: 1.0.0 @@ -37880,6 +38983,8 @@ snapshots: dependencies: unc-path-regex: 0.1.2 + is-unicode-supported@1.3.0: {} + is-unicode-supported@2.1.0: {} is-weakmap@2.0.2: {} @@ -37919,6 +39024,8 @@ snapshots: isexe@2.0.0: {} + isexe@3.1.5: {} + isexe@4.0.0: {} isobject@3.0.1: {} @@ -38134,6 +39241,12 @@ snapshots: jsonc-parser@3.3.1: {} + jsondiffpatch@0.6.0: + dependencies: + '@types/diff-match-patch': 1.0.36 + chalk: 5.6.2 + diff-match-patch: 1.0.5 + jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 @@ -38249,6 +39362,8 @@ snapshots: dependencies: graceful-fs: 4.2.11 + kleur@3.0.3: {} + kleur@4.1.5: {} klona@2.0.6: {} @@ -38372,6 +39487,68 @@ snapshots: needle: 3.5.0 source-map: 0.6.1 + level-codec@9.0.2: + dependencies: + buffer: 5.7.1 + optional: true + + level-concat-iterator@2.0.1: + optional: true + + level-errors@2.0.1: + dependencies: + errno: 0.1.8 + optional: true + + level-iterator-stream@4.0.2: + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2(patch_hash=e4aadcbd3e7fffdf34e27d9a810232cda21beee31c3b1f1fda75b4877dfe5e61) + xtend: 4.0.2 + optional: true + + level-js@5.0.2: + dependencies: + abstract-leveldown: 6.2.3 + buffer: 5.7.1 + inherits: 2.0.4 + ltgt: 2.2.1 + optional: true + + level-packager@5.1.1: + dependencies: + encoding-down: 6.3.0 + levelup: 4.4.0 + optional: true + + level-supports@1.0.1: + dependencies: + xtend: 4.0.2 + optional: true + + level@6.0.1: + dependencies: + level-js: 5.0.2 + level-packager: 5.1.1 + leveldown: 5.6.0 + optional: true + + leveldown@5.6.0: + dependencies: + abstract-leveldown: 6.2.3 + napi-macros: 2.0.0 + node-gyp-build: 4.1.1 + optional: true + + levelup@4.4.0: + dependencies: + deferred-leveldown: 5.3.0 + level-errors: 2.0.1 + level-iterator-stream: 4.0.2 + level-supports: 1.0.1 + xtend: 4.0.2 + optional: true + leven@3.1.0: {} leven@4.1.0: {} @@ -38658,6 +39835,11 @@ snapshots: lodash@4.17.23: {} + log-symbols@6.0.0: + dependencies: + chalk: 5.6.2 + is-unicode-supported: 1.3.0 + log-symbols@7.0.1: dependencies: is-unicode-supported: 2.1.0 @@ -38726,10 +39908,17 @@ snapshots: lru-cache@7.18.3: {} + ltgt@2.2.1: + optional: true + lucide-react@0.454.0(react@18.2.0): dependencies: react: 18.2.0 + lucide-react@0.577.0(react@19.2.4): + dependencies: + react: 19.2.4 + lz-string@1.5.0: {} magic-regexp@0.10.0: @@ -39858,9 +41047,9 @@ snapshots: dependencies: minipass: 7.1.2 - mintlify@4.2.442(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.8)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2): + mintlify@4.2.442(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2): dependencies: - '@mintlify/cli': 4.0.1045(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.8)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) + '@mintlify/cli': 4.0.1045(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) transitivePeerDependencies: - '@radix-ui/react-popover' - '@types/node' @@ -39978,6 +41167,57 @@ snapshots: msgpackr-extract: 3.0.3 optional: true + msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3): + dependencies: + '@inquirer/confirm': 5.1.21(@types/node@22.19.2) + '@mswjs/interceptors': 0.41.3 + '@open-draft/deferred-promise': 2.2.0 + '@types/statuses': 2.0.6 + cookie: 1.1.1 + graphql: 16.13.1 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + rettime: 0.10.1 + statuses: 2.0.2 + strict-event-emitter: 0.5.1 + tough-cookie: 6.0.0 + type-fest: 5.5.0 + until-async: 3.0.2 + yargs: 17.7.2 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/node' + optional: true + + msw@2.12.14(@types/node@22.19.8)(typescript@5.9.3): + dependencies: + '@inquirer/confirm': 5.1.21(@types/node@22.19.8) + '@mswjs/interceptors': 0.41.3 + '@open-draft/deferred-promise': 2.2.0 + '@types/statuses': 2.0.6 + cookie: 1.1.1 + graphql: 16.13.1 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + rettime: 0.10.1 + statuses: 2.0.2 + strict-event-emitter: 0.5.1 + tough-cookie: 6.0.0 + type-fest: 5.5.0 + until-async: 3.0.2 + yargs: 17.7.2 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/node' + muggle-string@0.4.1: {} multer@2.1.1: @@ -40016,6 +41256,9 @@ snapshots: napi-build-utils@2.0.0: {} + napi-macros@2.0.0: + optional: true + napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} @@ -40119,7 +41362,7 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3): + next@15.3.3(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3): dependencies: '@next/env': 15.3.3 '@swc/counter': 0.1.3 @@ -40129,7 +41372,7 @@ snapshots: postcss: 8.4.31 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - styled-jsx: 5.1.6(react@19.2.4) + styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.4) optionalDependencies: '@next/swc-darwin-arm64': 15.3.3 '@next/swc-darwin-x64': 15.3.3 @@ -40156,7 +41399,7 @@ snapshots: postcss: 8.4.31 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - styled-jsx: 5.1.6(react@19.2.4) + styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.4) optionalDependencies: '@next/swc-darwin-arm64': 16.1.6 '@next/swc-darwin-x64': 16.1.6 @@ -40345,6 +41588,9 @@ snapshots: detect-libc: 2.1.2 optional: true + node-gyp-build@4.1.1: + optional: true + node-gyp-build@4.8.4: {} node-gyp@12.2.0: @@ -40720,6 +41966,8 @@ snapshots: object-keys@1.1.1: {} + object-treeify@1.1.33: {} + object.assign@4.1.7: dependencies: call-bind: 1.0.8 @@ -40980,6 +42228,26 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 + openai@4.104.0(ws@8.19.0)(zod@3.25.76): + dependencies: + '@types/node': 18.19.130 + '@types/node-fetch': 2.6.13 + abort-controller: 3.0.0 + agentkeepalive: 4.6.0 + form-data-encoder: 1.7.2 + formdata-node: 4.4.1 + node-fetch: 2.7.0 + optionalDependencies: + ws: 8.19.0 + zod: 3.25.76 + transitivePeerDependencies: + - encoding + + openai@5.23.2(ws@8.19.0)(zod@4.3.6): + optionalDependencies: + ws: 8.19.0 + zod: 4.3.6 + openai@6.32.0(ws@8.19.0)(zod@4.3.6): optionalDependencies: ws: 8.19.0 @@ -41008,6 +42276,18 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + ora@8.2.0: + dependencies: + chalk: 5.6.2 + cli-cursor: 5.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 2.1.0 + log-symbols: 6.0.0 + stdin-discarder: 0.2.2 + string-width: 7.2.0 + strip-ansi: 7.1.2 + ora@9.3.0: dependencies: chalk: 5.6.2 @@ -41028,6 +42308,8 @@ snapshots: os-tmpdir@1.0.2: {} + outvariant@1.4.3: {} + own-keys@1.0.1: dependencies: get-intrinsic: 1.3.0 @@ -41437,6 +42719,8 @@ snapshots: path-to-regexp@3.3.0: {} + path-to-regexp@6.3.0: {} + path-to-regexp@8.3.0: {} path-type@4.0.0: {} @@ -41728,32 +43012,32 @@ snapshots: dependencies: postcss: 8.5.8 - postcss-import@15.1.0(postcss@8.5.6): + postcss-import@15.1.0(postcss@8.5.8): dependencies: - postcss: 8.5.6 + postcss: 8.5.8 postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.11 - postcss-js@4.1.0(postcss@8.5.6): + postcss-js@4.1.0(postcss@8.5.8): dependencies: camelcase-css: 2.0.1 - postcss: 8.5.6 + postcss: 8.5.8 - postcss-load-config@4.0.2(postcss@8.5.6)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3)): + postcss-load-config@4.0.2(postcss@8.5.8)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3)): dependencies: lilconfig: 3.1.3 yaml: 2.8.2 optionalDependencies: - postcss: 8.5.6 - ts-node: 10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3) + postcss: 8.5.8 + ts-node: 10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3) - postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2): + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.2): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 1.21.7 - postcss: 8.5.6 + postcss: 8.5.8 tsx: 4.21.0 yaml: 2.8.2 @@ -41818,37 +43102,32 @@ snapshots: postcss: 8.5.8 postcss-selector-parser: 7.1.1 - postcss-modules-extract-imports@3.1.0(postcss@8.5.6): + postcss-modules-extract-imports@3.1.0(postcss@8.5.8): dependencies: - postcss: 8.5.6 + postcss: 8.5.8 - postcss-modules-local-by-default@4.2.0(postcss@8.5.6): + postcss-modules-local-by-default@4.2.0(postcss@8.5.8): dependencies: - icss-utils: 5.1.0(postcss@8.5.6) - postcss: 8.5.6 + icss-utils: 5.1.0(postcss@8.5.8) + postcss: 8.5.8 postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 - postcss-modules-scope@3.2.1(postcss@8.5.6): + postcss-modules-scope@3.2.1(postcss@8.5.8): dependencies: - postcss: 8.5.6 + postcss: 8.5.8 postcss-selector-parser: 7.1.1 - postcss-modules-values@4.0.0(postcss@8.5.6): + postcss-modules-values@4.0.0(postcss@8.5.8): dependencies: - icss-utils: 5.1.0(postcss@8.5.6) - postcss: 8.5.6 + icss-utils: 5.1.0(postcss@8.5.8) + postcss: 8.5.8 postcss-nested-import@1.3.0(postcss@8.5.8): dependencies: postcss: 8.5.8 resolve: 1.22.11 - postcss-nested@6.2.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-selector-parser: 6.1.2 - postcss-nested@6.2.0(postcss@8.5.8): dependencies: postcss: 8.5.8 @@ -41920,9 +43199,9 @@ snapshots: postcss: 8.5.8 postcss-value-parser: 4.2.0 - postcss-safe-parser@7.0.1(postcss@8.5.6): + postcss-safe-parser@7.0.1(postcss@8.5.8): dependencies: - postcss: 8.5.6 + postcss: 8.5.8 postcss-selector-parser@6.1.2: dependencies: @@ -42229,6 +43508,11 @@ snapshots: - typescript - utf-8-validate + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -42299,7 +43583,7 @@ snapshots: dependencies: prosemirror-model: 1.25.4 prosemirror-transform: 1.11.0 - prosemirror-view: 1.41.5 + prosemirror-view: 1.41.7 prosemirror-tables@1.8.5: dependencies: @@ -42325,6 +43609,12 @@ snapshots: prosemirror-state: 1.4.4 prosemirror-transform: 1.11.0 + prosemirror-view@1.41.7: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + proto-list@1.2.4: {} protobufjs@7.5.4: @@ -42811,6 +44101,14 @@ snapshots: real-require@0.2.0: {} + recast@0.23.11: + dependencies: + ast-types: 0.16.1 + esprima: 4.0.1 + source-map: 0.6.1 + tiny-invariant: 1.3.3 + tslib: 2.8.1 + recharts-scale@0.4.5: dependencies: decimal.js-light: 2.5.1 @@ -43185,6 +44483,8 @@ snapshots: requires-port@1.0.0: {} + reselect@5.1.1: {} + resolve-alpn@1.2.1: {} resolve-cwd@3.0.0: @@ -43202,7 +44502,7 @@ snapshots: adjust-sourcemap-loader: 4.0.0 convert-source-map: 1.9.0 loader-utils: 2.0.4 - postcss: 8.5.6 + postcss: 8.5.8 source-map: 0.6.1 resolve@1.22.11: @@ -43285,6 +44585,8 @@ snapshots: retry@0.13.1: {} + rettime@0.10.1: {} + reusify@1.1.0: {} rfdc@1.4.1: {} @@ -43317,7 +44619,7 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) lightningcss: 1.31.1 picomatch: 4.0.3 - postcss: 8.5.6 + postcss: 8.5.8 rolldown: 1.0.0-beta.53 tinyglobby: 0.2.15 optionalDependencies: @@ -43337,7 +44639,7 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) lightningcss: 1.31.1 picomatch: 4.0.3 - postcss: 8.5.6 + postcss: 8.5.8 rolldown: 1.0.0-beta.53 tinyglobby: 0.2.15 optionalDependencies: @@ -43357,7 +44659,7 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) lightningcss: 1.31.1 picomatch: 4.0.3 - postcss: 8.5.6 + postcss: 8.5.8 rolldown: 1.0.0-beta.53 tinyglobby: 0.2.15 optionalDependencies: @@ -43377,7 +44679,7 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) lightningcss: 1.31.1 picomatch: 4.0.3 - postcss: 8.5.6 + postcss: 8.5.8 rolldown: 1.0.0-beta.53 tinyglobby: 0.2.15 optionalDependencies: @@ -43635,6 +44937,8 @@ snapshots: secure-compare@3.0.1: {} + secure-json-parse@2.7.0: {} + secure-json-parse@4.1.0: {} seedrandom@3.0.5: {} @@ -43906,6 +45210,49 @@ snapshots: safe-buffer: 5.2.1 to-buffer: 1.2.2 + shadcn@4.1.0(@types/node@22.19.8)(typescript@5.9.3): + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) + '@dotenvx/dotenvx': 1.57.0 + '@modelcontextprotocol/sdk': 1.27.1(zod@3.25.76) + '@types/validate-npm-package-name': 4.0.2 + browserslist: 4.28.1 + commander: 14.0.3 + cosmiconfig: 9.0.0(typescript@5.9.3) + dedent: 1.7.2 + deepmerge: 4.3.1 + diff: 8.0.3 + execa: 9.6.1 + fast-glob: 3.3.3 + fs-extra: 11.3.3 + fuzzysort: 3.1.0 + https-proxy-agent: 7.0.6 + kleur: 4.1.5 + msw: 2.12.14(@types/node@22.19.8)(typescript@5.9.3) + node-fetch: 3.3.2 + open: 11.0.0 + ora: 8.2.0 + postcss: 8.5.8 + postcss-selector-parser: 7.1.1 + prompts: 2.4.2 + recast: 0.23.11 + stringify-object: 5.0.0 + tailwind-merge: 3.5.0 + ts-morph: 26.0.0 + tsconfig-paths: 4.2.0 + validate-npm-package-name: 7.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.1(zod@3.25.76) + transitivePeerDependencies: + - '@cfworker/json-schema' + - '@types/node' + - babel-plugin-macros + - supports-color + - typescript + shallow-clone@0.1.2: dependencies: is-extendable: 0.1.1 @@ -44363,6 +45710,8 @@ snapshots: std-env@4.0.0: {} + stdin-discarder@0.2.2: {} + stdin-discarder@0.3.1: {} steno@0.4.4: @@ -44413,6 +45762,8 @@ snapshots: - bare-abort-controller - react-native-b4a + strict-event-emitter@0.5.1: {} + string-argv@0.3.2: {} string-width@4.2.3: @@ -44501,6 +45852,12 @@ snapshots: character-entities-html4: 2.1.0 character-entities-legacy: 3.0.0 + stringify-object@5.0.0: + dependencies: + get-own-enumerable-keys: 1.0.0 + is-obj: 3.0.0 + is-regexp: 3.1.0 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -44556,15 +45913,17 @@ snapshots: dependencies: inline-style-parser: 0.2.7 - styled-jsx@5.1.6(react@18.2.0): + styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.2.4): dependencies: client-only: 0.0.1 - react: 18.2.0 + react: 19.2.4 + optionalDependencies: + '@babel/core': 7.29.0 - styled-jsx@5.1.6(react@19.2.4): + styled-jsx@5.1.6(react@18.2.0): dependencies: client-only: 0.0.1 - react: 19.2.4 + react: 18.2.0 styled-jsx@5.1.7(@babel/core@7.29.0)(react@19.2.4): dependencies: @@ -44662,6 +46021,12 @@ snapshots: transitivePeerDependencies: - encoding + swr@2.4.1(react@19.2.4): + dependencies: + dequal: 2.0.3 + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) + sylvester@0.0.21: optional: true @@ -44673,10 +46038,14 @@ snapshots: system-architecture@0.1.0: {} + tabbable@6.4.0: {} + tagged-tag@1.0.0: {} tailwind-merge@2.6.1: {} + tailwind-merge@3.5.0: {} + tailwindcss-animate@1.0.7(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2)): dependencies: tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.2) @@ -44697,11 +46066,11 @@ snapshots: normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.1.1 - postcss: 8.5.6 - postcss-import: 15.1.0(postcss@8.5.6) - postcss-js: 4.1.0(postcss@8.5.6) - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2) - postcss-nested: 6.2.0(postcss@8.5.6) + postcss: 8.5.8 + postcss-import: 15.1.0(postcss@8.5.8) + postcss-js: 4.1.0(postcss@8.5.8) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.2) + postcss-nested: 6.2.0(postcss@8.5.8) postcss-selector-parser: 6.1.2 resolve: 1.22.11 sucrase: 3.35.1 @@ -44709,7 +46078,7 @@ snapshots: - tsx - yaml - tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3)): + tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -44725,11 +46094,11 @@ snapshots: normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.1.1 - postcss: 8.5.6 - postcss-import: 15.1.0(postcss@8.5.6) - postcss-js: 4.1.0(postcss@8.5.6) - postcss-load-config: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3)) - postcss-nested: 6.2.0(postcss@8.5.6) + postcss: 8.5.8 + postcss-import: 15.1.0(postcss@8.5.8) + postcss-js: 4.1.0(postcss@8.5.8) + postcss-load-config: 4.0.2(postcss@8.5.8)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3)) + postcss-nested: 6.2.0(postcss@8.5.8) postcss-selector-parser: 6.1.2 resolve: 1.22.11 sucrase: 3.35.1 @@ -44899,6 +46268,8 @@ snapshots: dependencies: real-require: 0.2.0 + throttleit@2.1.0: {} + through2@2.0.5: dependencies: readable-stream: 2.3.8 @@ -45046,6 +46417,11 @@ snapshots: ts-interface-checker@0.1.13: {} + ts-morph@26.0.0: + dependencies: + '@ts-morph/common': 0.27.0 + code-block-writer: 13.0.3 + ts-node@10.9.2(@swc/core@1.15.18)(@types/node@18.19.130)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -45067,14 +46443,14 @@ snapshots: '@swc/core': 1.15.18 optional: true - ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.8)(typescript@5.9.3): + ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.19.8 + '@types/node': 22.19.2 acorn: 8.15.0 acorn-walk: 8.3.5 arg: 4.1.3 @@ -45095,6 +46471,12 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 + tsconfig-paths@4.2.0: + dependencies: + json5: 2.2.3 + minimist: 1.2.8 + strip-bom: 3.0.0 + tslib@1.14.1: {} tslib@2.8.1: {} @@ -45156,6 +46538,8 @@ snapshots: tunnel@0.0.6: {} + tw-animate-css@1.4.0: {} + tweetnacl@0.14.5: {} twoslash-protocol@0.3.6: {} @@ -45348,8 +46732,7 @@ snapshots: underscore@1.13.7: {} - undici-types@5.26.5: - optional: true + undici-types@5.26.5: {} undici-types@6.21.0: {} @@ -45613,6 +46996,8 @@ snapshots: db0: 0.3.4(better-sqlite3@12.8.0)(drizzle-orm@0.45.1(@opentelemetry/api@1.9.0)(better-sqlite3@12.8.0)(bun-types@1.3.8)(pg@8.20.0)) ioredis: 5.10.1 + until-async@3.0.2: {} + untun@0.1.3: dependencies: citty: 0.1.6 @@ -45717,6 +47102,10 @@ snapshots: dependencies: react: 18.2.0 + use-sync-external-store@1.6.0(react@19.2.4): + dependencies: + react: 19.2.4 + utif2@4.1.0: dependencies: pako: 1.0.11 @@ -46174,11 +47563,11 @@ snapshots: vite@7.3.1(@types/node@22.19.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: - esbuild: 0.27.2 + esbuild: 0.27.4 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.57.1 + postcss: 8.5.8 + rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 22.19.2 @@ -46193,11 +47582,11 @@ snapshots: vite@7.3.1(@types/node@22.19.8)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: - esbuild: 0.27.2 + esbuild: 0.27.4 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.57.1 + postcss: 8.5.8 + rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 22.19.8 @@ -46210,11 +47599,11 @@ snapshots: tsx: 4.21.0 yaml: 2.8.2 - vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.2)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2): + vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.2)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(rolldown-vite@7.3.1(@types/node@22.19.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 3.2.4(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(rolldown-vite@7.3.1(@types/node@22.19.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -46254,11 +47643,11 @@ snapshots: - tsx - yaml - vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2): + vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(rolldown-vite@7.3.1(@types/node@22.19.2)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 3.2.4(msw@2.12.14(@types/node@22.19.2)(typescript@5.9.3))(rolldown-vite@7.3.1(@types/node@22.19.2)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -46298,11 +47687,11 @@ snapshots: - tsx - yaml - vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2): + vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.8)(esbuild@0.27.4)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.1))(less@4.4.2)(msw@2.12.14(@types/node@22.19.8)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(rolldown-vite@7.3.1(@types/node@22.19.8)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 3.2.4(msw@2.12.14(@types/node@22.19.8)(typescript@5.9.3))(rolldown-vite@7.3.1(@types/node@22.19.8)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -46429,6 +47818,8 @@ snapshots: web-streams-polyfill@3.3.3: {} + web-streams-polyfill@4.0.0-beta.3: {} + web-worker@1.2.0: {} webidl-conversions@3.0.1: {} @@ -46783,6 +48174,10 @@ snapshots: dependencies: isexe: 2.0.0 + which@4.0.0: + dependencies: + isexe: 3.1.5 + which@6.0.1: dependencies: isexe: 4.0.0 @@ -46863,6 +48258,11 @@ snapshots: wrappy@1.0.2: {} + ws@6.2.3: + dependencies: + async-limiter: 1.0.1 + optional: true + ws@7.5.10: {} ws@8.17.1: {} @@ -46914,6 +48314,13 @@ snapshots: lib0: 0.2.117 yjs: 13.6.19 + y-leveldb@0.1.2(yjs@13.6.30): + dependencies: + level: 6.0.1 + lib0: 0.2.117 + yjs: 13.6.30 + optional: true + y-prosemirror@1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.19))(yjs@13.6.19): dependencies: lib0: 0.2.117 @@ -46923,12 +48330,12 @@ snapshots: y-protocols: 1.0.7(yjs@13.6.19) yjs: 13.6.19 - y-prosemirror@1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30): + y-prosemirror@1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.7)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30): dependencies: lib0: 0.2.117 prosemirror-model: 1.25.4 prosemirror-state: 1.4.4 - prosemirror-view: 1.41.5 + prosemirror-view: 1.41.7 y-protocols: 1.0.7(yjs@13.6.30) yjs: 13.6.30 @@ -46942,12 +48349,31 @@ snapshots: lib0: 0.2.117 yjs: 13.6.30 + y-websocket@2.1.0(yjs@13.6.30): + dependencies: + lib0: 0.2.117 + lodash.debounce: 4.0.8 + y-protocols: 1.0.7(yjs@13.6.30) + yjs: 13.6.30 + optionalDependencies: + ws: 6.2.3 + y-leveldb: 0.1.2(yjs@13.6.30) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + y-websocket@3.0.0(yjs@13.6.19): dependencies: lib0: 0.2.117 y-protocols: 1.0.7(yjs@13.6.19) yjs: 13.6.19 + y-websocket@3.0.0(yjs@13.6.30): + dependencies: + lib0: 0.2.117 + y-protocols: 1.0.7(yjs@13.6.30) + yjs: 13.6.30 + y18n@5.0.8: {} yallist@3.1.1: {} @@ -47062,13 +48488,17 @@ snapshots: dependencies: zod: 3.24.0 + zod-to-json-schema@3.25.1(zod@3.25.76): + dependencies: + zod: 3.25.76 + zod-to-json-schema@3.25.1(zod@4.3.6): dependencies: zod: 4.3.6 - zod-validation-error@4.0.2(zod@4.3.6): + zod-validation-error@4.0.2(zod@3.25.76): dependencies: - zod: 4.3.6 + zod: 3.25.76 zod@3.21.4: {} From 28523f81e489651a489b5b10e5573db77e937ead Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Tue, 24 Mar 2026 09:01:22 -0300 Subject: [PATCH 10/32] refactor(super-editor): remove server-side auto-formatting, keep ref minting Remove findNearbyFormatting, applyFormattingToCreatedBlock, and mark-copying from insertHeadingAt/insertParagraphAt. These added ~200 lines of complexity but didn't work: the style engine cascade overrides inline marks for headings, and the code incorrectly copied bold from title paragraphs. The LLM handles formatting correctly via superdoc_format after create, guided by tool descriptions. Server-side auto-formatting was a wrong turn. Keep: numberingProperties suppression, mintBlockRef, block refs in blocks.list. --- .../src/core/commands/insertHeadingAt.js | 25 +-- .../src/core/commands/insertParagraphAt.js | 12 +- .../plan-engine/create-wrappers.ts | 161 ------------------ 3 files changed, 4 insertions(+), 194 deletions(-) diff --git a/packages/super-editor/src/core/commands/insertHeadingAt.js b/packages/super-editor/src/core/commands/insertHeadingAt.js index dcb7cbcffc..29d191d969 100644 --- a/packages/super-editor/src/core/commands/insertHeadingAt.js +++ b/packages/super-editor/src/core/commands/insertHeadingAt.js @@ -1,10 +1,8 @@ -import { findNearbyMarks } from '../helpers/findNearbyMarks.js'; - /** * Insert a heading node at an absolute document position. * - * Copies text marks (fontFamily, color) from the nearest heading - * or body paragraph so new headings match the document's font. + * Internally, headings are paragraph nodes with a heading styleId + * (`Heading1` through `Heading6`) set on `paragraphProperties`. * * @param {{ pos: number; level: number; text?: string; sdBlockId?: string; paraId?: string; tracked?: boolean }} options * @returns {import('./types/index.js').Command} @@ -27,24 +25,7 @@ export const insertHeadingAt = }, }; const normalizedText = typeof text === 'string' ? text : ''; - - let textNode = null; - if (normalizedText.length > 0) { - const rawMarks = findNearbyMarks(state.doc, pos, { prefer: 'heading' }); - // Strip fontSize from copied marks — headings should keep their style-level size. - const marks = rawMarks.map((mark) => { - if (mark.type.name === 'textStyle' && mark.attrs.fontSize != null) { - const rest = Object.fromEntries(Object.entries(mark.attrs).filter(([k]) => k !== 'fontSize')); - return mark.type.create(rest); - } - return mark; - }); - const meaningful = marks.filter( - (m) => m.type.name !== 'textStyle' || Object.values(m.attrs).some((v) => v != null), - ); - textNode = - meaningful.length > 0 ? state.schema.text(normalizedText, meaningful) : state.schema.text(normalizedText); - } + const textNode = normalizedText.length > 0 ? state.schema.text(normalizedText) : null; let paragraphNode; try { diff --git a/packages/super-editor/src/core/commands/insertParagraphAt.js b/packages/super-editor/src/core/commands/insertParagraphAt.js index e6c834a4d9..2d89b53f87 100644 --- a/packages/super-editor/src/core/commands/insertParagraphAt.js +++ b/packages/super-editor/src/core/commands/insertParagraphAt.js @@ -1,11 +1,6 @@ -import { findNearbyMarks } from '../helpers/findNearbyMarks.js'; - /** * Insert a paragraph node at an absolute document position. * - * Copies text marks (fontFamily, fontSize, color) from the nearest - * body paragraph so new content matches the document's formatting. - * * @param {{ pos: number; text?: string; sdBlockId?: string; paraId?: string; tracked?: boolean }} options * @returns {import('./types/index.js').Command} */ @@ -21,12 +16,7 @@ export const insertParagraphAt = ...(paraId ? { paraId } : undefined), }; const normalizedText = typeof text === 'string' ? text : ''; - - let textNode = null; - if (normalizedText.length > 0) { - const marks = findNearbyMarks(state.doc, pos, { prefer: 'body' }); - textNode = marks.length > 0 ? state.schema.text(normalizedText, marks) : state.schema.text(normalizedText); - } + const textNode = normalizedText.length > 0 ? state.schema.text(normalizedText) : null; let paragraphNode; try { diff --git a/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts b/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts index d380d4d3a4..528c0f69bd 100644 --- a/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts +++ b/packages/super-editor/src/document-api-adapters/plan-engine/create-wrappers.ts @@ -46,135 +46,6 @@ function mintBlockRef(editor: Editor, storyKey: string, nodeId: string, textLeng }); } -// --------------------------------------------------------------------------- -// Auto-formatting: apply fontFamily + color from nearby blocks so new -// headings/paragraphs match the document's visual style without extra LLM steps. -// --------------------------------------------------------------------------- - -function findNearbyFormatting( - editor: Editor, - _pos: number, - skipHeadings: boolean, -): { fontFamily?: string; fontSize?: number; bold?: boolean; color?: string } | null { - const doc = editor.state.doc; - const result: { fontFamily?: string; fontSize?: number; bold?: boolean; color?: string } = {}; - - // Walk top-level children near the insertion point - let offset = 0; - for (let i = 0; i < doc.childCount; i++) { - const child = doc.child(i); - const childEnd = offset + child.nodeSize; - - if (child.type.name === 'paragraph') { - const pProps = (child.attrs as Record).paragraphProperties as { styleId?: string } | undefined; - const isHeading = pProps?.styleId && /^Heading\d$/.test(pProps.styleId); - - if (skipHeadings && isHeading) { - offset = childEnd; - continue; - } - - // Read formatting from text marks - child.descendants((textNode) => { - if (result.fontFamily) return false; - const marks = textNode.marks ?? []; - if (!textNode.isText || marks.length === 0) return; - for (const mark of marks) { - const attrs = mark.attrs as Record; - if (typeof attrs.fontFamily === 'string' && attrs.fontFamily) { - result.fontFamily = attrs.fontFamily; - } - if (typeof attrs.color === 'string' && attrs.color) { - result.color = attrs.color; - } - if (attrs.fontSize != null) { - const raw = typeof attrs.fontSize === 'string' ? parseFloat(attrs.fontSize as string) : attrs.fontSize; - if (typeof raw === 'number' && Number.isFinite(raw)) result.fontSize = raw as number; - } - if (attrs.bold === true) result.bold = true; - else if (result.bold === undefined) result.bold = false; - } - return false; - }); - - if (result.fontFamily) { - // Default to black when no explicit color is set (matches extractBlockFormatting behavior) - if (!result.color) result.color = '#000000'; - return result; - } - } - - offset = childEnd; - } - - if (result.fontFamily && !result.color) result.color = '#000000'; - return result.fontFamily ? result : null; -} - -function applyFormattingToCreatedBlock( - editor: Editor, - nodeId: string, - formatting: { fontFamily?: string; fontSize?: number; bold?: boolean; color?: string }, -): void { - const doc = editor.state.doc; - const textStyleType = editor.state.schema.marks.textStyle; - let blockPos = -1; - let blockEnd = -1; - - // Find the created paragraph - doc.descendants((node, pos) => { - if (blockPos >= 0) return false; - const attrs = node.attrs as Record; - if (node.type.name === 'paragraph' && (attrs.sdBlockId === nodeId || attrs.paraId === nodeId)) { - blockPos = pos + 1; - blockEnd = pos + node.nodeSize - 1; - return false; - } - }); - - if (blockPos < 0 || blockEnd <= blockPos) return; - - const tr = editor.state.tr; - - // 1. Add textStyle marks on text nodes (so marks are the source of truth) - if (textStyleType) { - const mark = textStyleType.create({ - fontFamily: formatting.fontFamily ?? null, - fontSize: formatting.fontSize ?? null, - bold: formatting.bold ?? null, - color: formatting.color ?? null, - }); - tr.addMark(blockPos, blockEnd, mark); - } - - // 2. Also set runProperties directly on run nodes (so the style engine - // cascade sees them as inlineRpr, the highest-priority layer) - doc.nodesBetween(blockPos, blockEnd, (node, pos) => { - if (node.type.name === 'run') { - const existingRp = (node.attrs as Record).runProperties as Record | undefined; - const merged: Record = { ...(existingRp ?? {}) }; - if (formatting.fontFamily) merged.fontFamily = formatting.fontFamily; - if (formatting.fontSize != null) merged.fontSize = formatting.fontSize; - if (formatting.bold != null) merged.bold = formatting.bold; - if (formatting.color) merged.color = formatting.color; - tr.setNodeMarkup(pos, null, { ...node.attrs, runProperties: merged }); - } - }); - - // 3. Tell calculateInlineRunPropertiesPlugin to PRESERVE our values - // instead of re-deriving them from the style cascade. - const preserveKeys = Object.keys(formatting).filter((k) => (formatting as Record)[k] != null); - if (preserveKeys.length > 0) { - tr.setMeta( - 'sdPreserveRunPropertiesKeys', - preserveKeys.map((k) => ({ key: k, preferExisting: true })), - ); - } - - tr.setMeta('inputType', 'programmatic'); - editor.dispatch(tr); -} - // --------------------------------------------------------------------------- // Command types (internal to the wrapper) // --------------------------------------------------------------------------- @@ -397,21 +268,6 @@ export function createParagraphWrapper( } if (runtime.commit) runtime.commit(editor); - - // Auto-apply fontFamily + fontSize + color from nearby blocks so the - // paragraph matches the document's visual style without extra LLM steps. - try { - if (input.text) { - const formatting = findNearbyFormatting(storyEditor, insertAt, false); - if (formatting) { - applyFormattingToCreatedBlock(storyEditor, paragraphId, formatting); - } - } - } catch (e) { - // Best-effort — formatting failure should not break creation - console.warn('[create-wrapper] auto-formatting failed:', e); - } - const nonBodyStory = runtime.kind !== 'body' ? runtime.locator : undefined; const textLen = input.text?.length ?? 0; const ref = textLen > 0 ? mintBlockRef(storyEditor, runtime.storyKey, canonicalId, textLen) : undefined; @@ -521,23 +377,6 @@ export function createHeadingWrapper( } if (runtime.commit) runtime.commit(editor); - - // Auto-apply fontFamily + color from nearby blocks so the heading - // matches the document's visual style without extra LLM format steps. - // Skip fontSize — headings should keep their style-level size. - try { - if (input.text) { - const formatting = findNearbyFormatting(storyEditor, insertAt, true); - if (formatting) { - const { fontSize: _skipSize, ...headingFormatting } = formatting; - applyFormattingToCreatedBlock(storyEditor, headingId, headingFormatting); - } - } - } catch (e) { - // Best-effort — formatting failure should not break creation - console.warn('[create-wrapper] auto-formatting failed:', e); - } - const nonBodyStory = runtime.kind !== 'body' ? runtime.locator : undefined; const textLen = input.text?.length ?? 0; const ref = textLen > 0 ? mintBlockRef(storyEditor, runtime.storyKey, canonicalId, textLen) : undefined; From 7587196b68ddfcd00e83d8ded756e2f354412167 Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Tue, 24 Mar 2026 10:27:11 -0300 Subject: [PATCH 11/32] fix(sdk): improve tool descriptions for heading/paragraph formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Headings: set fontFamily, fontSize (scaled up from body), color, bold:true - Paragraphs: set fontFamily, fontSize, color, bold:false - Always use color #000000 (never copy from blocks — some have white text) - Call blocks without limit/filters to get full document context - Get fontFamily/fontSize from body text blocks, not info defaults --- .../src/contract/operation-definitions.ts | 2 +- packages/sdk/langs/browser/src/system-prompt.ts | 15 ++++++++------- packages/sdk/tools/system-prompt.md | 15 ++++++++------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/document-api/src/contract/operation-definitions.ts b/packages/document-api/src/contract/operation-definitions.ts index ffdabc58b1..db1f5adc1d 100644 --- a/packages/document-api/src/contract/operation-definitions.ts +++ b/packages/document-api/src/contract/operation-definitions.ts @@ -105,7 +105,7 @@ export const INTENT_GROUP_META: Record = { create: { toolName: 'superdoc_create', description: - 'Create one paragraph or heading. Response includes ref and nodeId. You MUST call superdoc_format after this tool to apply styling from BODY TEXT blocks (not titles/headings). Call superdoc_get_content blocks first, then after creating use the ref with superdoc_format action "inline". Always include bold:false unless body text is bold. For headings: set fontFamily, color, bold (NOT fontSize). For paragraphs: set fontFamily, fontSize, color, bold. When creating multiple items, use the previous nodeId as the next at target.', + 'Create one paragraph or heading. Response includes ref and nodeId. You MUST call superdoc_format after this tool. Call superdoc_get_content blocks first to get fontFamily/fontSize from body text blocks. Always use color "#000000". For paragraphs: set fontFamily, fontSize, color, bold:false. For headings: set fontFamily, fontSize (scaled up from body), color, bold:true. When creating multiple items, use the previous nodeId as the next at target.', }, format: { toolName: 'superdoc_format', diff --git a/packages/sdk/langs/browser/src/system-prompt.ts b/packages/sdk/langs/browser/src/system-prompt.ts index a6330a2cd9..abab4c6c78 100644 --- a/packages/sdk/langs/browser/src/system-prompt.ts +++ b/packages/sdk/langs/browser/src/system-prompt.ts @@ -30,7 +30,7 @@ Every editing tool needs a **target** — an address telling the API *where* to ## Workflow -For complex edits that need document context (formatting, positioning relative to blocks), call \`superdoc_get_content({action: "blocks"})\` first. This returns every block with its nodeId, type, text, fontFamily, fontSize, bold, color, alignment, and a **ref** handle. Use the ref directly with \`superdoc_format\` or \`superdoc_edit\` — no search needed. For simple tasks (search, create at document end, get plain text, undo), call the appropriate tool directly. +Call \`superdoc_get_content({action: "blocks"})\` first — no limit, no filters, get the full document. This returns every block with nodeId, type, text, fontFamily, fontSize, color, and a **ref** handle. One call gives you everything: formatting values, positioning targets, and refs for editing. Do NOT add \`limit\`, \`offset\`, or \`nodeTypes\` filters. 1. **Edit existing content**: Use \`superdoc_search\` to get a ref, then pass \`ref\` to \`superdoc_edit\` or \`superdoc_format\`. Do not build \`target\` objects manually. 2. **Create new content**: Use \`superdoc_create\`, then use the \`ref\` from the response to apply formatting. DO NOT search after create. @@ -40,16 +40,17 @@ For complex edits that need document context (formatting, positioning relative t ### Formatting after create (REQUIRED) -Every \`superdoc_create\` call MUST be followed by \`superdoc_format\` to match the document's style. Use the \`ref\` from the create response: +Every \`superdoc_create\` call MUST be followed by \`superdoc_format\` to match the document's style. Use the \`ref\` from the create response. Get \`fontFamily\` and \`fontSize\` from body text blocks (\`superdoc_get_content blocks\`). **Always use \`color: "#000000"\`** — never copy color from blocks. +**For paragraphs:** \`\`\` -superdoc_format({action: "inline", ref: "", inline: {fontFamily: "Calibri", fontSize: 9, color: "#000000", bold: false}}) +superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", fontSize: 12, color: "#000000", bold: false}}) \`\`\` -Get \`fontFamily\`, \`fontSize\`, \`color\`, and \`bold\` values from the blocks data. Use the BODY TEXT blocks (not titles or headings) as the reference for formatting. Always include \`bold: false\` unless the surrounding body text is bold. - -- **For paragraphs**: Apply \`fontFamily\`, \`fontSize\`, \`color\`, and \`bold\`. -- **For headings**: Apply \`fontFamily\`, \`color\`, and \`bold\` only. Do NOT set \`fontSize\` on headings. +**For headings** (scale fontSize up from body size — e.g. body 12pt → heading 16pt): +\`\`\` +superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", fontSize: 16, color: "#000000", bold: true}}) +\`\`\` ### Placing content near specific text diff --git a/packages/sdk/tools/system-prompt.md b/packages/sdk/tools/system-prompt.md index 870a9fdd37..e55a1367fe 100644 --- a/packages/sdk/tools/system-prompt.md +++ b/packages/sdk/tools/system-prompt.md @@ -28,7 +28,7 @@ Every editing tool needs a **target** — an address telling the API *where* to ## Workflow -For complex edits that need document context (formatting, positioning relative to blocks), call `superdoc_get_content({action: "blocks"})` first. This returns every block with its nodeId, type, text, fontFamily, fontSize, bold, color, alignment, and a **ref** handle. Use the ref directly with `superdoc_format` or `superdoc_edit` — no search needed. For simple tasks (search, create at document end, get plain text, undo), call the appropriate tool directly. +Call `superdoc_get_content({action: "blocks"})` first — no limit, no filters, get the full document. This returns every block with nodeId, type, text, fontFamily, fontSize, color, and a **ref** handle. One call gives you everything: formatting values, positioning targets, and refs for editing. Do NOT add `limit`, `offset`, or `nodeTypes` filters. 1. **Edit existing content**: Use `superdoc_search` to get a ref, then pass `ref` to `superdoc_edit` or `superdoc_format`. Do not build `target` objects manually. 2. **Create new content**: Use `superdoc_create`, then use the `ref` from the response to apply formatting. DO NOT search after create. @@ -38,16 +38,17 @@ For complex edits that need document context (formatting, positioning relative t ### Formatting after create (REQUIRED) -Every `superdoc_create` call MUST be followed by `superdoc_format` to match the document's style. Use the `ref` from the create response: +Every `superdoc_create` call MUST be followed by `superdoc_format` to match the document's style. Use the `ref` from the create response. Get `fontFamily` and `fontSize` from body text blocks (`superdoc_get_content blocks`). **Always use `color: "#000000"`** — never copy color from blocks. +**For paragraphs:** ``` -superdoc_format({action: "inline", ref: "", inline: {fontFamily: "Calibri", fontSize: 9, color: "#000000", bold: false}}) +superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", fontSize: 12, color: "#000000", bold: false}}) ``` -Get `fontFamily`, `fontSize`, `color`, and `bold` values from the blocks data. Use the BODY TEXT blocks (not titles or headings) as the reference for formatting. Always include `bold: false` unless the surrounding body text is bold. - -- **For paragraphs**: Apply `fontFamily`, `fontSize`, `color`, and `bold`. -- **For headings**: Apply `fontFamily`, `color`, and `bold` only. Do NOT set `fontSize` on headings. +**For headings** (scale fontSize up from body size — e.g. body 12pt → heading 16pt): +``` +superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", fontSize: 16, color: "#000000", bold: true}}) +``` ### Placing content near specific text From 82d09c59a87d053054657bb0bd6ff5a845c58187 Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Tue, 24 Mar 2026 16:15:09 -0300 Subject: [PATCH 12/32] chore: remove browser SDK additions from PR scope Restore pre-existing generated files to main versions. New browser SDK files (package.json, dispatch.ts, validate.ts, etc.) moved to local-only for a separate PR. --- packages/sdk/langs/browser/package.json | 15 - packages/sdk/langs/browser/src/assets.ts | 25 -- packages/sdk/langs/browser/src/dispatch.ts | 59 --- packages/sdk/langs/browser/src/index.ts | 6 - .../sdk/langs/browser/src/system-prompt.ts | 94 +++-- packages/sdk/langs/browser/src/validate.ts | 81 ---- packages/sdk/langs/browser/tsconfig.json | 16 - pnpm-lock.yaml | 380 +++++++++++++++--- 8 files changed, 377 insertions(+), 299 deletions(-) delete mode 100644 packages/sdk/langs/browser/package.json delete mode 100644 packages/sdk/langs/browser/src/assets.ts delete mode 100644 packages/sdk/langs/browser/src/dispatch.ts delete mode 100644 packages/sdk/langs/browser/src/index.ts delete mode 100644 packages/sdk/langs/browser/src/validate.ts delete mode 100644 packages/sdk/langs/browser/tsconfig.json diff --git a/packages/sdk/langs/browser/package.json b/packages/sdk/langs/browser/package.json deleted file mode 100644 index 557a824873..0000000000 --- a/packages/sdk/langs/browser/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "@superdoc-dev/sdk-browser", - "version": "1.0.0-alpha.1", - "private": true, - "type": "module", - "main": "./src/index.ts", - "types": "./src/index.ts", - "exports": { - ".": "./src/index.ts" - }, - "sideEffects": false, - "dependencies": { - "@superdoc/document-api": "workspace:*" - } -} diff --git a/packages/sdk/langs/browser/src/assets.ts b/packages/sdk/langs/browser/src/assets.ts deleted file mode 100644 index e481cb195d..0000000000 --- a/packages/sdk/langs/browser/src/assets.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Tool artifacts re-exported from the workspace tools directory. -// JSON imports are resolved at build time by the consumer's bundler. -// The system prompt is embedded as a TS string constant (generated from system-prompt.md). - -// @ts-ignore — JSON import resolved by bundler -import catalog from '../tools/catalog.json'; -// @ts-ignore — JSON import resolved by bundler -import toolsOpenai from '../tools/tools.openai.json'; -import { SYSTEM_PROMPT } from './system-prompt'; -import type { ToolCatalog } from './validate'; - -/** Get the tool catalog (used internally for validation). */ -export function getCatalogJson(): ToolCatalog { - return catalog as ToolCatalog; -} - -/** Get the OpenAI-formatted tool definitions for chat completions. */ -export function getOpenAITools(): any[] { - return (toolsOpenai as { tools: any[] }).tools; -} - -/** Get the system prompt for the agent. */ -export function getSystemPrompt(): string { - return SYSTEM_PROMPT; -} diff --git a/packages/sdk/langs/browser/src/dispatch.ts b/packages/sdk/langs/browser/src/dispatch.ts deleted file mode 100644 index a3cc0ce090..0000000000 --- a/packages/sdk/langs/browser/src/dispatch.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { dispatchIntentTool } from './intent-dispatch'; -import { validateToolArgs } from './validate'; -import { getCatalogJson } from './assets'; -import type { ToolCatalogEntry } from './validate'; - -/** - * A minimal interface matching DocumentApi.invoke(). - * Avoids a hard compile-time dependency on @superdoc/document-api - * while still being type-safe for consumers that pass a real DocumentApi. - */ -export interface InvokableDocumentApi { - invoke(request: { operationId: string; input: unknown; options?: unknown }): unknown; -} - -/** - * Dispatch an LLM tool call against an in-browser DocumentApi. - * - * Drop-in replacement for the Node SDK's dispatchSuperDocTool. - * Instead of routing through a CLI process, this calls documentApi.invoke() directly. - * - * The catalog is loaded automatically from the bundled JSON — no setup needed. - */ -export function dispatchSuperDocTool( - documentApi: InvokableDocumentApi, - toolName: string, - args: Record = {}, -): unknown { - const catalog = getCatalogJson(); - const tool = catalog.tools.find((t: ToolCatalogEntry) => t.toolName === toolName); - if (!tool) { - throw new Error( - `Unknown tool: "${toolName}". Available: ${catalog.tools.map((t: ToolCatalogEntry) => t.toolName).join(', ')}`, - ); - } - - validateToolArgs(toolName, args, tool); - - // Strip doc/sessionId — not relevant in browser context - const { doc: _doc, sessionId: _sid, ...cleanArgs } = args; - - return dispatchIntentTool(toolName, cleanArgs, (operationId, input) => { - // Intent dispatch produces "doc.insert", "doc.format.apply", etc. - // DocumentApi.invoke() expects the id without "doc." prefix: "insert", "format.apply" - const stripped = operationId.startsWith('doc.') ? operationId.slice(4) : operationId; - - // Extract envelope params — these go into options, not input - const { changeMode, dryRun, force, ...operationInput } = input; - const options: Record = {}; - if (changeMode !== undefined) options.changeMode = changeMode; - if (dryRun !== undefined) options.dryRun = dryRun; - if (force !== undefined) options.force = force; - - return documentApi.invoke({ - operationId: stripped, - input: operationInput, - ...(Object.keys(options).length > 0 ? { options } : {}), - }); - }); -} diff --git a/packages/sdk/langs/browser/src/index.ts b/packages/sdk/langs/browser/src/index.ts deleted file mode 100644 index 4d3d67c8c1..0000000000 --- a/packages/sdk/langs/browser/src/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { dispatchSuperDocTool } from './dispatch'; -export type { InvokableDocumentApi } from './dispatch'; -export { dispatchIntentTool } from './intent-dispatch'; -export { validateToolArgs } from './validate'; -export type { ToolCatalog, ToolCatalogEntry, OperationEntry } from './validate'; -export { getSystemPrompt, getOpenAITools, getCatalogJson } from './assets'; diff --git a/packages/sdk/langs/browser/src/system-prompt.ts b/packages/sdk/langs/browser/src/system-prompt.ts index abab4c6c78..7eafbd7a7b 100644 --- a/packages/sdk/langs/browser/src/system-prompt.ts +++ b/packages/sdk/langs/browser/src/system-prompt.ts @@ -9,9 +9,9 @@ export const SYSTEM_PROMPT = `You are a document editing assistant. You have a D | Tool | Purpose | |------|---------| | superdoc_search | Find text or nodes in the document | -| superdoc_get_content | Read document content (text, markdown, html, info, blocks) | +| superdoc_get_content | Read document content (text, markdown, html, info) | | superdoc_edit | Insert, replace, delete text, undo/redo | -| superdoc_create | Create paragraphs or headings (returns a ref for immediate formatting) | +| superdoc_create | Create paragraphs or headings (with optional styleId) | | superdoc_format | Apply inline and paragraph formatting, set named styles | | superdoc_list | Create and manipulate bullet/numbered lists | | superdoc_comment | Create, update, delete, and list comments | @@ -24,33 +24,57 @@ Every editing tool needs a **target** — an address telling the API *where* to ### Getting targets -- **From blocks data**: Each block has a \`ref\` — pass it directly to \`superdoc_format\` or \`superdoc_edit\`. Also has \`nodeId\` for building \`at\` positions with \`superdoc_create\`. -- **From \`superdoc_search\`**: Returns \`handle.ref\` — pass as \`ref\` param to \`superdoc_format\` or \`superdoc_edit\`. Use search when you need to find text patterns, not when you already know which block to target. -- **From \`superdoc_create\`**: Returns \`ref\` in the response — pass directly to \`superdoc_format\`. No search needed. +Use \`superdoc_search\` to find content. Each match item returns: + +- **\`handle.ref\`** — a ref string for text-level operations. Pass the ref string as: + - \`ref\` parameter on \`superdoc_format\` (for inline styles like bold, italic) + - \`ref\` parameter on \`superdoc_edit\` (for text replacement, deletion) + - Example: \`superdoc_format({action: "inline", ref: "text:eyJ...", inline: {bold: true}})\` +- **\`address\`** — a block-level address like \`{ "kind": "block", "nodeType": "paragraph", "nodeId": "abc123" }\`. Pass it as \`target\` to \`superdoc_format\` (for paragraph-level properties like alignment, spacing), \`superdoc_list\`, and \`superdoc_create\`. + +### Text search results + +When searching for text (\`type: "text"\`), each match includes: +- \`snippet\` — the matched text with surrounding context +- \`highlightRange\` — \`{ start, end }\` character offsets of the match +- \`blocks\` — array of \`{ blockId, range }\` entries showing which blocks contain the match + +### Node search results + +When searching for nodes (\`type: "node"\`), each match includes: +- \`address\` — the block address of the matched node + +## Multi-action tools + +Most tools support multiple actions via an \`action\` parameter. For example: +- \`superdoc_get_content\` with \`action: "text"\` returns plain text; \`action: "info"\` returns document metadata and styles. +- \`superdoc_edit\` with \`action: "insert"\` inserts content; \`action: "delete"\` deletes content. +- \`superdoc_format\` with \`action: "inline"\` applies inline formatting; \`action: "set_style"\` applies a named paragraph style. + +Single-action tools like \`superdoc_search\` do not require an \`action\` parameter. ## Workflow -Call \`superdoc_get_content({action: "blocks"})\` first — no limit, no filters, get the full document. This returns every block with nodeId, type, text, fontFamily, fontSize, color, and a **ref** handle. One call gives you everything: formatting values, positioning targets, and refs for editing. Do NOT add \`limit\`, \`offset\`, or \`nodeTypes\` filters. +**ALWAYS start by calling \`superdoc_get_content({action: "blocks"})\` before any other tool.** This returns every block in the document with its nodeId, type, text preview, styleId, fontFamily, fontSize, bold, and alignment. You need this to: +- Know the document's structure and block IDs for targeting +- See what fonts, sizes, and styles are used so new content matches +- Find blocks by their text preview without a separate search -1. **Edit existing content**: Use \`superdoc_search\` to get a ref, then pass \`ref\` to \`superdoc_edit\` or \`superdoc_format\`. Do not build \`target\` objects manually. -2. **Create new content**: Use \`superdoc_create\`, then use the \`ref\` from the response to apply formatting. DO NOT search after create. +After getting blocks: +1. **Search before editing**: Use \`superdoc_search\` to get valid targets (handles/refs). +2. **Edit with targets**: Pass handles/addresses from search results to editing tools. 3. **Re-search after each mutation**: Refs expire after any edit. Always search again before the next operation. 4. **Batch when possible**: For multi-step edits, prefer \`superdoc_mutations\`. -5. **Multiple sequential creates**: Each \`superdoc_create\` response includes a \`nodeId\`. When inserting multiple items in order, use the previous item's nodeId as the next \`at\` target to maintain correct ordering. -### Formatting after create (REQUIRED) +### Style-aware content creation -Every \`superdoc_create\` call MUST be followed by \`superdoc_format\` to match the document's style. Use the \`ref\` from the create response. Get \`fontFamily\` and \`fontSize\` from body text blocks (\`superdoc_get_content blocks\`). **Always use \`color: "#000000"\`** — never copy color from blocks. +After creating any content (paragraph, heading), you MUST match the document's formatting: -**For paragraphs:** -\`\`\` -superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", fontSize: 12, color: "#000000", bold: false}}) -\`\`\` +1. **Create** the content with \`superdoc_create\` +2. **Search** for the new text with \`superdoc_search\` to get a ref handle +3. **Apply formatting** with \`superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", fontSize: ...}})\` using the fontFamily and fontSize values from the neighboring blocks in the blocks data -**For headings** (scale fontSize up from body size — e.g. body 12pt → heading 16pt): -\`\`\` -superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", fontSize: 16, color: "#000000", bold: true}}) -\`\`\` +Example: if blocks show \`fontFamily: "Times New Roman, serif"\` and \`fontSize: 9.5\`, apply those same values to your new content. ### Placing content near specific text @@ -60,6 +84,8 @@ To add content near a heading or specific text (e.g., "add a paragraph after the 2. **Get the blockId** from \`result.items[0].blocks[0].blockId\` 3. **Create content after it**: \`superdoc_create({action: "paragraph", text: "...", at: {kind: "after", target: {kind: "block", nodeType: "heading", nodeId: ""}}})\` +**Do NOT search by node type and then try to match by position** — this is unreliable in large documents. Always search for the actual text content to find the exact location. + ## Using superdoc_mutations The mutations tool executes a plan of steps atomically. Use \`action: "apply"\` to execute, or \`action: "preview"\` to dry-run. @@ -72,18 +98,22 @@ Each step has: ### Workflow: split mutations by logical phase +**Always use \`superdoc_search\` first** to obtain stable refs, then reference those refs in your mutation steps. + Split mutation calls into logical rounds: 1. **Text mutations first** — all \`text.rewrite\`, \`text.insert\`, \`text.delete\` operations in one \`superdoc_mutations\` call. 2. **Formatting second** — all \`format.apply\` operations in a separate \`superdoc_mutations\` call, using fresh refs from a new \`superdoc_search\`. +**Why**: Text edits change content and invalidate addresses. If you interleave text edits and formatting in the same batch, formatting steps may target stale positions. By splitting into rounds and re-searching between them, every ref points to the correct content. + ## Using superdoc_comment The comment tool manages comment threads in the document. - **\`create\`** — Create a new comment thread anchored to a target range. -- **\`update\`** — Patch fields on an existing comment. +- **\`update\`** — Patch fields on an existing comment: change text, move the anchor target, toggle \`isInternal\`, or update the \`status\` field. - **\`delete\`** — Remove a comment or reply by ID. -- **\`get\`** — Retrieve a single comment thread by ID. +- **\`get\`** — Retrieve a single comment thread by ID, including replies. - **\`list\`** — List all comment threads in the document. ### Creating comments @@ -99,20 +129,24 @@ To add a comment on specific text: }) \`\`\` -**Only pass \`action\`, \`text\`, and \`target\` for creating a new comment.** +**Only pass \`action\`, \`text\`, and \`target\` for creating a new comment.** Do not pass other params — they belong to different comment actions. ### Resolving comments -To resolve a comment, use \`action: "update"\` with \`{ commentId: "", status: "resolved" }\`. +To resolve a comment, use \`action: "update"\` with \`{ commentId: "", status: "resolved" }\`. There is no separate resolve action — it's a status field on the \`update\` action. ## Important rules -- **Refs expire after any mutation.** Always re-search after each edit to get fresh refs. Exception: refs from \`superdoc_create\` are valid immediately after creation. -- **Replace all occurrences** of the same text with a single mutation step using \`require: "all"\`, not multiple steps targeting the same pattern. -- **Search patterns are plain text**, not markdown. Don't include \`#\`, \`**\`, or formatting markers. -- **\`within\` scopes to a single block**, not a section. To find text in a section, search the full document. -- **Table cells are separate blocks.** Search for individual cell values, not patterns spanning multiple cells. +- **Refs expire after any mutation.** Always re-search after each edit to get fresh refs. When applying the same change to multiple matches (e.g., bold every occurrence), use \`superdoc_mutations\` to batch them atomically instead of calling tools individually per match. +- **Replace all occurrences** of the same text with a single mutation step using \`require: "all"\`, not multiple steps targeting the same pattern (which causes overlap conflicts). +- **Search patterns are plain text**, not markdown. Don't include \`#\`, \`**\`, or formatting markers in search patterns. +- **\`within\` scopes to a single block**, not a section. To find text in a section, search the full document for the text directly. +- **Table cells are separate blocks.** Search for individual cell values (e.g., \`"28"\`), not patterns spanning multiple cells. - **superdoc_search \`select.type\`** must be \`"text"\` or \`"node"\`. To find headings, use \`{type: "node", nodeType: "heading"}\`, NOT \`{type: "heading"}\`. -- **Do NOT combine \`limit\`/\`offset\` with \`require: "first"\` or \`require: "exactlyOne"\`**. Use \`require: "any"\` with \`limit\` for paginated results. -- **Creating lists**: Create one paragraph per item first, then call \`superdoc_list\` action \`"create"\` with \`mode: "fromParagraphs"\` and \`preset: "disc"\` (bullet) or \`preset: "decimal"\` (numbered) for each paragraph. +- **Do NOT combine \`limit\`/\`offset\` with \`require: "first"\` or \`require: "exactlyOne"\`** in superdoc_search. Use \`require: "any"\` with \`limit\` for paginated results. +- For \`superdoc_format\` inline properties, use \`null\` inside the \`inline\` object to clear a property (e.g., \`"inline": { "bold": null }\` removes bold). +- **Creating lists** requires two modes: + - \`mode: "fromParagraphs"\` — converts existing paragraphs into list items. Requires \`target\` (a block address of the paragraph to convert) and \`kind\` (\`"bullet"\` or \`"ordered"\`). + - \`mode: "empty"\` — creates a new empty list at a paragraph position. Requires \`at\` (a block address: \`{kind:"block", nodeType:"paragraph", nodeId:""}\`) and \`kind\`. + - **Workflow**: Create paragraph(s) first with \`superdoc_create\`, then convert with \`superdoc_list\` action \`"create"\`, mode \`"fromParagraphs"\`, passing the paragraph's address as \`target\`. `; diff --git a/packages/sdk/langs/browser/src/validate.ts b/packages/sdk/langs/browser/src/validate.ts deleted file mode 100644 index fd34b655b7..0000000000 --- a/packages/sdk/langs/browser/src/validate.ts +++ /dev/null @@ -1,81 +0,0 @@ -// Extracted from packages/sdk/langs/node/src/tools.ts — pure logic, no Node.js deps. - -export type ToolCatalog = { - contractVersion: string; - generatedAt: string | null; - toolCount: number; - tools: ToolCatalogEntry[]; -}; - -export type ToolCatalogEntry = { - toolName: string; - description: string; - inputSchema: Record; - mutates: boolean; - operations: OperationEntry[]; -}; - -export type OperationEntry = { - operationId: string; - intentAction: string; - required?: string[]; - requiredOneOf?: string[][]; -}; - -function isRecord(value: unknown): value is Record { - return typeof value === 'object' && value != null && !Array.isArray(value); -} - -export function validateToolArgs(toolName: string, args: Record, tool: ToolCatalogEntry): void { - const schema = tool.inputSchema; - const properties = isRecord(schema.properties) ? schema.properties : {}; - const required: string[] = Array.isArray(schema.required) ? (schema.required as string[]) : []; - - // 1. Reject unknown keys - const knownKeys = new Set(Object.keys(properties)); - const unknownKeys = Object.keys(args).filter((k) => !knownKeys.has(k)); - if (unknownKeys.length > 0) { - throw new Error(`Unknown argument(s) for ${toolName}: ${unknownKeys.join(', ')}`); - } - - // 2. Reject missing universally-required keys - const missingKeys = required.filter((k) => args[k] == null); - if (missingKeys.length > 0) { - throw new Error(`Missing required argument(s) for ${toolName}: ${missingKeys.join(', ')}`); - } - - // 3. Per-operation required constraints - const action = args.action; - let op: OperationEntry | undefined; - if (typeof action === 'string' && tool.operations.length > 1) { - op = tool.operations.find((o) => o.intentAction === action); - } else if (tool.operations.length === 1) { - op = tool.operations[0]; - } - - if (op) { - validateOperationRequired(toolName, action, args, op); - } -} - -function validateOperationRequired( - toolName: string, - action: unknown, - args: Record, - op: OperationEntry, -): void { - const actionLabel = typeof action === 'string' ? ` action "${action}"` : ''; - - if (op.requiredOneOf && op.requiredOneOf.length > 0) { - const satisfied = op.requiredOneOf.some((branch) => branch.every((k) => args[k] != null)); - if (!satisfied) { - const options = op.requiredOneOf.map((b) => b.join(' + ')).join(' | '); - throw new Error(`Missing required argument(s) for ${toolName}${actionLabel}: must provide one of: ${options}`); - } - } else if (op.required && op.required.length > 0) { - const missingActionKeys = op.required.filter((k) => args[k] == null); - if (missingActionKeys.length > 0) { - throw new Error(`Missing required argument(s) for ${toolName}${actionLabel}: ${missingActionKeys.join(', ')}`); - } - } -} diff --git a/packages/sdk/langs/browser/tsconfig.json b/packages/sdk/langs/browser/tsconfig.json deleted file mode 100644 index e0b87bdf8d..0000000000 --- a/packages/sdk/langs/browser/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ESNext", - "moduleResolution": "bundler", - "lib": ["ES2020", "DOM"], - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "noEmit": true, - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve" - }, - "include": ["src/**/*.ts"] -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 55cb252b1f..bf7f9a3452 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -528,7 +528,7 @@ importers: version: 14.0.3 mintlify: specifier: 4.2.446 - version: 4.2.446(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@25.5.0)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + version: 4.2.446(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) remark-mdx: specifier: ^3.1.1 version: 3.1.1 @@ -911,7 +911,7 @@ importers: version: 0.9.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) y-prosemirror: specifier: latest - version: 1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) + version: 1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.7)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) yjs: specifier: latest version: 13.6.30 @@ -1395,6 +1395,79 @@ importers: specifier: ^4.21.0 version: 4.21.0 + examples/collaboration/ai-with-nodesdk: + dependencies: + '@base-ui/react': + specifier: ^1.2.0 + version: 1.3.0(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@openai/agents': + specifier: ^0.1.0 + version: 0.1.11(ws@8.19.0)(zod@4.3.6) + '@superdoc-dev/sdk': + specifier: workspace:* + version: link:../../../packages/sdk/langs/node + '@tailwindcss/postcss': + specifier: ^4.2.1 + version: 4.2.2 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + next: + specifier: ^15.3.0 + version: 15.3.3(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3) + openai: + specifier: ^5.0.0 + version: 5.23.2(ws@8.19.0)(zod@4.3.6) + postcss: + specifier: ^8.5.8 + version: 8.5.8 + react: + specifier: ^19.0.0 + version: 19.2.4 + react-dom: + specifier: ^19.0.0 + version: 19.2.4(react@19.2.4) + superdoc: + specifier: workspace:* + version: link:../../../packages/superdoc + tailwind-merge: + specifier: ^3.5.0 + version: 3.5.0 + tailwindcss: + specifier: ^4.2.1 + version: 4.2.2 + tw-animate-css: + specifier: ^1.4.0 + version: 1.4.0 + ws: + specifier: ^8.18.0 + version: 8.19.0 + y-websocket: + specifier: ^2.1.0 + version: 2.1.0(yjs@13.6.30) + yjs: + specifier: ^13.6.0 + version: 13.6.30 + devDependencies: + '@types/node': + specifier: ^22.0.0 + version: 22.19.8 + '@types/react': + specifier: ^19.0.0 + version: 19.2.11 + '@types/react-dom': + specifier: ^19.0.0 + version: 19.2.3(@types/react@19.2.11) + '@types/ws': + specifier: ^8.5.0 + version: 8.18.1 + typescript: + specifier: ^5.7.0 + version: 5.9.3 + examples/collaboration/hocuspocus: dependencies: '@hocuspocus/provider': @@ -1670,6 +1743,79 @@ importers: specifier: ^5.7.0 version: 5.9.3 + examples/eval-demo-server: + dependencies: + '@base-ui/react': + specifier: ^1.2.0 + version: 1.3.0(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@openai/agents': + specifier: ^0.1.0 + version: 0.1.11(ws@8.19.0)(zod@4.3.6) + '@superdoc-dev/sdk': + specifier: workspace:* + version: link:../../packages/sdk/langs/node + '@tailwindcss/postcss': + specifier: ^4.2.1 + version: 4.2.2 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + next: + specifier: ^15.3.0 + version: 15.3.3(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3) + openai: + specifier: ^5.0.0 + version: 5.23.2(ws@8.19.0)(zod@4.3.6) + postcss: + specifier: ^8.5.8 + version: 8.5.8 + react: + specifier: ^19.0.0 + version: 19.2.4 + react-dom: + specifier: ^19.0.0 + version: 19.2.4(react@19.2.4) + superdoc: + specifier: workspace:* + version: link:../../packages/superdoc + tailwind-merge: + specifier: ^3.5.0 + version: 3.5.0 + tailwindcss: + specifier: ^4.2.1 + version: 4.2.2 + tw-animate-css: + specifier: ^1.4.0 + version: 1.4.0 + ws: + specifier: ^8.18.0 + version: 8.19.0 + y-websocket: + specifier: ^2.1.0 + version: 2.1.0(yjs@13.6.30) + yjs: + specifier: ^13.6.0 + version: 13.6.30 + devDependencies: + '@types/node': + specifier: ^22.0.0 + version: 22.19.8 + '@types/react': + specifier: ^19.0.0 + version: 19.2.11 + '@types/react-dom': + specifier: ^19.0.0 + version: 19.2.3(@types/react@19.2.11) + '@types/ws': + specifier: ^8.5.0 + version: 8.18.1 + typescript: + specifier: ^5.7.0 + version: 5.9.3 + examples/features/ai-redlining: dependencies: react: @@ -2728,6 +2874,9 @@ importers: pinia: specifier: 'catalog:' version: 2.3.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)) + prosemirror-view: + specifier: ^1.41.7 + version: 1.41.7 rollup-plugin-copy: specifier: 'catalog:' version: 3.5.0 @@ -2739,7 +2888,7 @@ importers: version: 3.5.25(typescript@5.9.3) y-prosemirror: specifier: 'catalog:' - version: 1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) + version: 1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.7)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) y-websocket: specifier: 'catalog:' version: 3.0.0(yjs@13.6.30) @@ -18934,6 +19083,9 @@ packages: prosemirror-view@1.41.5: resolution: {integrity: sha512-UDQbIPnDrjE8tqUBbPmCOZgtd75htE6W3r0JCmY9bL6W1iemDM37MZEKC49d+tdQ0v/CKx4gjxLoLsfkD2NiZA==} + prosemirror-view@1.41.7: + resolution: {integrity: sha512-jUwKNCEIGiqdvhlS91/2QAg21e4dfU5bH2iwmSDQeosXJgKF7smG0YSplOWK0cjSNgIqXe7VXqo7EIfUFJdt3w==} + proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} @@ -26297,6 +26449,16 @@ snapshots: chalk: 4.1.2 figures: 3.2.0 + '@inquirer/checkbox@4.3.2(@types/node@22.19.2)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@22.19.2) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/checkbox@4.3.2(@types/node@25.5.0)': dependencies: '@inquirer/ansi': 1.0.2 @@ -26328,7 +26490,6 @@ snapshots: '@inquirer/type': 3.0.10(@types/node@22.19.2) optionalDependencies: '@types/node': 22.19.2 - optional: true '@inquirer/confirm@5.1.21(@types/node@22.19.8)': dependencies: @@ -26363,7 +26524,6 @@ snapshots: yoctocolors-cjs: 2.1.3 optionalDependencies: '@types/node': 22.19.2 - optional: true '@inquirer/core@10.3.2(@types/node@22.19.8)': dependencies: @@ -26444,6 +26604,14 @@ snapshots: chalk: 4.1.2 external-editor: 3.1.0 + '@inquirer/editor@4.2.23(@types/node@22.19.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/external-editor': 1.0.3(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/editor@4.2.23(@types/node@25.5.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.5.0) @@ -26467,6 +26635,14 @@ snapshots: chalk: 4.1.2 figures: 3.2.0 + '@inquirer/expand@4.0.23(@types/node@22.19.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/expand@4.0.23(@types/node@25.5.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.5.0) @@ -26475,6 +26651,13 @@ snapshots: optionalDependencies: '@types/node': 25.5.0 + '@inquirer/external-editor@1.0.3(@types/node@22.19.2)': + dependencies: + chardet: 2.1.1 + iconv-lite: 0.7.2 + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/external-editor@1.0.3(@types/node@25.5.0)': dependencies: chardet: 2.1.1 @@ -26499,6 +26682,13 @@ snapshots: '@inquirer/type': 1.5.5 chalk: 4.1.2 + '@inquirer/input@4.3.1(@types/node@22.19.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/input@4.3.1(@types/node@25.5.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.5.0) @@ -26513,6 +26703,13 @@ snapshots: optionalDependencies: '@types/node': 18.19.130 + '@inquirer/number@3.0.23(@types/node@22.19.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/number@3.0.23(@types/node@25.5.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.5.0) @@ -26527,6 +26724,14 @@ snapshots: ansi-escapes: 4.3.2 chalk: 4.1.2 + '@inquirer/password@4.0.23(@types/node@22.19.2)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/password@4.0.23(@types/node@25.5.0)': dependencies: '@inquirer/ansi': 1.0.2 @@ -26547,6 +26752,21 @@ snapshots: '@inquirer/rawlist': 1.2.16 '@inquirer/select': 1.3.3 + '@inquirer/prompts@7.10.1(@types/node@22.19.2)': + dependencies: + '@inquirer/checkbox': 4.3.2(@types/node@22.19.2) + '@inquirer/confirm': 5.1.21(@types/node@22.19.2) + '@inquirer/editor': 4.2.23(@types/node@22.19.2) + '@inquirer/expand': 4.0.23(@types/node@22.19.2) + '@inquirer/input': 4.3.1(@types/node@22.19.2) + '@inquirer/number': 3.0.23(@types/node@22.19.2) + '@inquirer/password': 4.0.23(@types/node@22.19.2) + '@inquirer/rawlist': 4.1.11(@types/node@22.19.2) + '@inquirer/search': 3.2.2(@types/node@22.19.2) + '@inquirer/select': 4.4.2(@types/node@22.19.2) + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/prompts@7.10.1(@types/node@25.5.0)': dependencies: '@inquirer/checkbox': 4.3.2(@types/node@25.5.0) @@ -26562,20 +26782,20 @@ snapshots: optionalDependencies: '@types/node': 25.5.0 - '@inquirer/prompts@7.9.0(@types/node@25.5.0)': + '@inquirer/prompts@7.9.0(@types/node@22.19.2)': dependencies: - '@inquirer/checkbox': 4.3.2(@types/node@25.5.0) - '@inquirer/confirm': 5.1.21(@types/node@25.5.0) - '@inquirer/editor': 4.2.23(@types/node@25.5.0) - '@inquirer/expand': 4.0.23(@types/node@25.5.0) - '@inquirer/input': 4.3.1(@types/node@25.5.0) - '@inquirer/number': 3.0.23(@types/node@25.5.0) - '@inquirer/password': 4.0.23(@types/node@25.5.0) - '@inquirer/rawlist': 4.1.11(@types/node@25.5.0) - '@inquirer/search': 3.2.2(@types/node@25.5.0) - '@inquirer/select': 4.4.2(@types/node@25.5.0) + '@inquirer/checkbox': 4.3.2(@types/node@22.19.2) + '@inquirer/confirm': 5.1.21(@types/node@22.19.2) + '@inquirer/editor': 4.2.23(@types/node@22.19.2) + '@inquirer/expand': 4.0.23(@types/node@22.19.2) + '@inquirer/input': 4.3.1(@types/node@22.19.2) + '@inquirer/number': 3.0.23(@types/node@22.19.2) + '@inquirer/password': 4.0.23(@types/node@22.19.2) + '@inquirer/rawlist': 4.1.11(@types/node@22.19.2) + '@inquirer/search': 3.2.2(@types/node@22.19.2) + '@inquirer/select': 4.4.2(@types/node@22.19.2) optionalDependencies: - '@types/node': 25.5.0 + '@types/node': 22.19.2 '@inquirer/rawlist@1.2.16': dependencies: @@ -26583,6 +26803,14 @@ snapshots: '@inquirer/type': 1.5.5 chalk: 4.1.2 + '@inquirer/rawlist@4.1.11(@types/node@22.19.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/rawlist@4.1.11(@types/node@25.5.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.5.0) @@ -26591,6 +26819,15 @@ snapshots: optionalDependencies: '@types/node': 25.5.0 + '@inquirer/search@3.2.2(@types/node@22.19.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@22.19.2) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/search@3.2.2(@types/node@25.5.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.5.0) @@ -26608,6 +26845,16 @@ snapshots: chalk: 4.1.2 figures: 3.2.0 + '@inquirer/select@4.4.2(@types/node@22.19.2)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@22.19.2) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.19.2 + '@inquirer/select@4.4.2(@types/node@25.5.0)': dependencies: '@inquirer/ansi': 1.0.2 @@ -26634,7 +26881,6 @@ snapshots: '@inquirer/type@3.0.10(@types/node@22.19.2)': optionalDependencies: '@types/node': 22.19.2 - optional: true '@inquirer/type@3.0.10(@types/node@22.19.8)': optionalDependencies: @@ -27200,11 +27446,11 @@ snapshots: '@microsoft/tsdoc@0.16.0': {} - '@mintlify/cli@4.0.1049(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@25.5.0)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': + '@mintlify/cli@4.0.1049(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': dependencies: - '@inquirer/prompts': 7.9.0(@types/node@25.5.0) + '@inquirer/prompts': 7.9.0(@types/node@22.19.2) '@mintlify/common': 1.0.813(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) - '@mintlify/link-rot': 3.0.983(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@mintlify/link-rot': 3.0.983(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) '@mintlify/models': 0.0.286 '@mintlify/prebuild': 1.0.954(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) '@mintlify/previewing': 4.0.1012(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) @@ -27217,7 +27463,7 @@ snapshots: front-matter: 4.0.2 fs-extra: 11.2.0 ink: 6.3.0(@types/react@19.2.11)(react@19.2.3) - inquirer: 12.3.0(@types/node@25.5.0) + inquirer: 12.3.0(@types/node@22.19.2) js-yaml: 4.1.0 mdast-util-mdx-jsx: 3.2.0 react: 19.2.3 @@ -27243,7 +27489,7 @@ snapshots: - utf-8-validate - yaml - '@mintlify/common@1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(typescript@5.9.3)': + '@mintlify/common@1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3)': dependencies: '@asyncapi/parser': 3.4.0 '@mintlify/mdx': 3.0.4(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) @@ -27283,7 +27529,7 @@ snapshots: remark-parse: 11.0.0 remark-rehype: 11.1.1 remark-stringify: 11.0.0 - tailwindcss: 3.4.4(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3)) + tailwindcss: 3.4.4(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3)) unified: 11.0.5 unist-builder: 4.0.0 unist-util-map: 4.0.0 @@ -27367,12 +27613,12 @@ snapshots: - typescript - yaml - '@mintlify/link-rot@3.0.983(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': + '@mintlify/link-rot@3.0.983(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': dependencies: '@mintlify/common': 1.0.813(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) '@mintlify/prebuild': 1.0.954(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) '@mintlify/previewing': 4.0.1012(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) - '@mintlify/scraping': 4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(typescript@5.9.3) + '@mintlify/scraping': 4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3) '@mintlify/validation': 0.1.640(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) fs-extra: 11.1.0 unist-util-visit: 4.1.2 @@ -27516,9 +27762,9 @@ snapshots: - utf-8-validate - yaml - '@mintlify/scraping@4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(typescript@5.9.3)': + '@mintlify/scraping@4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3)': dependencies: - '@mintlify/common': 1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(typescript@5.9.3) + '@mintlify/common': 1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3) '@mintlify/openapi-parser': 0.0.8 fs-extra: 11.1.1 hast-util-to-mdast: 10.1.0 @@ -31959,6 +32205,7 @@ snapshots: '@types/node@25.5.0': dependencies: undici-types: 7.18.2 + optional: true '@types/normalize-package-data@2.4.4': {} @@ -38394,12 +38641,12 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - inquirer@12.3.0(@types/node@25.5.0): + inquirer@12.3.0(@types/node@22.19.2): dependencies: - '@inquirer/core': 10.3.2(@types/node@25.5.0) - '@inquirer/prompts': 7.10.1(@types/node@25.5.0) - '@inquirer/type': 3.0.10(@types/node@25.5.0) - '@types/node': 25.5.0 + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/prompts': 7.10.1(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + '@types/node': 22.19.2 ansi-escapes: 4.3.2 mute-stream: 2.0.0 run-async: 3.0.0 @@ -39708,7 +39955,7 @@ snapshots: mathjs@15.1.1: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 complex.js: 2.4.3 decimal.js: 10.6.0 escape-latex: 1.2.0 @@ -40728,9 +40975,9 @@ snapshots: dependencies: minipass: 7.1.2 - mintlify@4.2.446(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@25.5.0)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3): + mintlify@4.2.446(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3): dependencies: - '@mintlify/cli': 4.0.1049(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@25.5.0)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@mintlify/cli': 4.0.1049(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) transitivePeerDependencies: - '@radix-ui/react-popover' - '@types/node' @@ -42712,13 +42959,6 @@ snapshots: dependencies: postcss: 8.5.8 - postcss-import@15.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.11 - postcss-import@15.1.0(postcss@8.5.8): dependencies: postcss: 8.5.8 @@ -42726,30 +42966,25 @@ snapshots: read-cache: 1.0.0 resolve: 1.22.11 - postcss-js@4.1.0(postcss@8.5.6): - dependencies: - camelcase-css: 2.0.1 - postcss: 8.5.6 - postcss-js@4.1.0(postcss@8.5.8): dependencies: camelcase-css: 2.0.1 postcss: 8.5.8 - postcss-load-config@4.0.2(postcss@8.5.8)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3)): + postcss-load-config@4.0.2(postcss@8.5.8)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3)): dependencies: lilconfig: 3.1.3 yaml: 2.8.3 optionalDependencies: postcss: 8.5.8 - ts-node: 10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3) + ts-node: 10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3) - postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.3): + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.3): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 1.21.7 - postcss: 8.5.6 + postcss: 8.5.8 tsx: 4.21.0 yaml: 2.8.3 @@ -42840,11 +43075,6 @@ snapshots: postcss: 8.5.8 resolve: 1.22.11 - postcss-nested@6.2.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-selector-parser: 6.1.2 - postcss-nested@6.2.0(postcss@8.5.8): dependencies: postcss: 8.5.8 @@ -43326,6 +43556,12 @@ snapshots: prosemirror-state: 1.4.4 prosemirror-transform: 1.11.0 + prosemirror-view@1.41.7: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.11.0 + proto-list@1.2.4: {} protobufjs@7.5.4: @@ -45765,11 +46001,11 @@ snapshots: normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.1.1 - postcss: 8.5.6 - postcss-import: 15.1.0(postcss@8.5.6) - postcss-js: 4.1.0(postcss@8.5.6) - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.3) - postcss-nested: 6.2.0(postcss@8.5.6) + postcss: 8.5.8 + postcss-import: 15.1.0(postcss@8.5.8) + postcss-js: 4.1.0(postcss@8.5.8) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.3) + postcss-nested: 6.2.0(postcss@8.5.8) postcss-selector-parser: 6.1.2 resolve: 1.22.11 sucrase: 3.35.1 @@ -45777,7 +46013,7 @@ snapshots: - tsx - yaml - tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3)): + tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -45796,7 +46032,7 @@ snapshots: postcss: 8.5.8 postcss-import: 15.1.0(postcss@8.5.8) postcss-js: 4.1.0(postcss@8.5.8) - postcss-load-config: 4.0.2(postcss@8.5.8)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3)) + postcss-load-config: 4.0.2(postcss@8.5.8)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3)) postcss-nested: 6.2.0(postcss@8.5.8) postcss-selector-parser: 6.1.2 resolve: 1.22.11 @@ -46142,14 +46378,14 @@ snapshots: '@swc/core': 1.15.18 optional: true - ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3): + ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 25.5.0 + '@types/node': 22.19.2 acorn: 8.16.0 acorn-walk: 8.3.5 arg: 4.1.3 @@ -46437,7 +46673,8 @@ snapshots: undici-types@6.21.0: {} - undici-types@7.18.2: {} + undici-types@7.18.2: + optional: true undici@7.20.0: {} @@ -47968,6 +48205,15 @@ snapshots: y-protocols: 1.0.7(yjs@13.6.30) yjs: 13.6.30 + y-prosemirror@1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.7)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30): + dependencies: + lib0: 0.2.117 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-view: 1.41.7 + y-protocols: 1.0.7(yjs@13.6.30) + yjs: 13.6.30 + y-protocols@1.0.7(yjs@13.6.19): dependencies: lib0: 0.2.117 From b483c3d1f8ad26953e53d301ddf6059bac344992 Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Tue, 24 Mar 2026 16:37:20 -0300 Subject: [PATCH 13/32] fix(document-api): fix extractBlockFormatting color and clean up PR - Only read fontFamily/fontSize/color from textStyle marks and bold from bold marks. Prevents highlight mark background colors from being reported as text color in blocks.list. - Remove "always use color #000000" restriction from create tool description and system prompt since blocks data now reports correct text colors. - Revert unrelated formatting change in apps/create/src/index.ts. - Revert orphaned findNearbyMarks defensive guard (was added for removed auto-formatting code). --- apps/create/src/index.ts | 7 ++++++- .../src/contract/operation-definitions.ts | 2 +- packages/sdk/tools/system-prompt.md | 2 +- .../src/core/helpers/findNearbyMarks.js | 1 - .../plan-engine/blocks-wrappers.ts | 17 +++++++++++------ 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/create/src/index.ts b/apps/create/src/index.ts index 32b1c5449b..e6c8f6c688 100644 --- a/apps/create/src/index.ts +++ b/apps/create/src/index.ts @@ -56,7 +56,12 @@ async function main() { let agentTool = 'claude-code'; if (!nonInteractive) { - const agentIdx = await select('Which agent tool do you use?', ['Claude Code', 'Cursor', 'Windsurf', 'None / Skip']); + const agentIdx = await select('Which agent tool do you use?', [ + 'Claude Code', + 'Cursor', + 'Windsurf', + 'None / Skip', + ]); agentTool = ['claude-code', 'cursor', 'windsurf', 'none'][agentIdx]; setupMcp = agentTool !== 'none'; } diff --git a/packages/document-api/src/contract/operation-definitions.ts b/packages/document-api/src/contract/operation-definitions.ts index db1f5adc1d..dd58e12e4e 100644 --- a/packages/document-api/src/contract/operation-definitions.ts +++ b/packages/document-api/src/contract/operation-definitions.ts @@ -105,7 +105,7 @@ export const INTENT_GROUP_META: Record = { create: { toolName: 'superdoc_create', description: - 'Create one paragraph or heading. Response includes ref and nodeId. You MUST call superdoc_format after this tool. Call superdoc_get_content blocks first to get fontFamily/fontSize from body text blocks. Always use color "#000000". For paragraphs: set fontFamily, fontSize, color, bold:false. For headings: set fontFamily, fontSize (scaled up from body), color, bold:true. When creating multiple items, use the previous nodeId as the next at target.', + 'Create one paragraph or heading. Response includes ref and nodeId. You MUST call superdoc_format after this tool. Call superdoc_get_content blocks first to get fontFamily, fontSize, color from body text blocks. For paragraphs: set fontFamily, fontSize, color, bold:false. For headings: set fontFamily, fontSize (scaled up from body), color, bold:true. When creating multiple items, use the previous nodeId as the next at target.', }, format: { toolName: 'superdoc_format', diff --git a/packages/sdk/tools/system-prompt.md b/packages/sdk/tools/system-prompt.md index e55a1367fe..00af9dac19 100644 --- a/packages/sdk/tools/system-prompt.md +++ b/packages/sdk/tools/system-prompt.md @@ -38,7 +38,7 @@ Call `superdoc_get_content({action: "blocks"})` first — no limit, no filters, ### Formatting after create (REQUIRED) -Every `superdoc_create` call MUST be followed by `superdoc_format` to match the document's style. Use the `ref` from the create response. Get `fontFamily` and `fontSize` from body text blocks (`superdoc_get_content blocks`). **Always use `color: "#000000"`** — never copy color from blocks. +Every `superdoc_create` call MUST be followed by `superdoc_format` to match the document's style. Use the `ref` from the create response. Get `fontFamily`, `fontSize`, and `color` from body text blocks (`superdoc_get_content blocks`). **For paragraphs:** ``` diff --git a/packages/super-editor/src/core/helpers/findNearbyMarks.js b/packages/super-editor/src/core/helpers/findNearbyMarks.js index 425f8ad650..3a0b148b2e 100644 --- a/packages/super-editor/src/core/helpers/findNearbyMarks.js +++ b/packages/super-editor/src/core/helpers/findNearbyMarks.js @@ -52,7 +52,6 @@ function extractMeaningfulMarks(paragraphNode) { * @returns {readonly import('prosemirror-model').Mark[]} */ export function findNearbyMarks(doc, pos, { prefer } = {}) { - if (typeof doc.resolve !== 'function') return []; const resolvedPos = doc.resolve(Math.min(pos, doc.content.size)); let fallback = /** @type {readonly import('prosemirror-model').Mark[]} */ ([]); diff --git a/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts b/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts index 6c191e5551..c706136343 100644 --- a/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts +++ b/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts @@ -92,14 +92,19 @@ function extractBlockFormatting(node: ProseMirrorNode): { const marks = child.marks ?? []; if (!child.isText || marks.length === 0) return; for (const mark of marks) { + const markName = (mark.type as { name?: string }).name; const attrs = mark.attrs as Record; - if (typeof attrs.fontFamily === 'string' && attrs.fontFamily) fontFamily = attrs.fontFamily; - if (attrs.fontSize != null) { - const raw = typeof attrs.fontSize === 'string' ? parseFloat(attrs.fontSize as string) : attrs.fontSize; - if (typeof raw === 'number' && Number.isFinite(raw)) fontSize = raw; + // Only read formatting from textStyle marks — other marks (highlight, underline) + // have a color attr that means something different (background, line color). + if (markName === 'textStyle') { + if (typeof attrs.fontFamily === 'string' && attrs.fontFamily) fontFamily = attrs.fontFamily; + if (attrs.fontSize != null) { + const raw = typeof attrs.fontSize === 'string' ? parseFloat(attrs.fontSize as string) : attrs.fontSize; + if (typeof raw === 'number' && Number.isFinite(raw)) fontSize = raw; + } + if (typeof attrs.color === 'string' && attrs.color) color = attrs.color; } - if (attrs.bold === true) bold = true; - if (typeof attrs.color === 'string' && attrs.color) color = attrs.color; + if (markName === 'bold' && attrs.value === true) bold = true; } return false; }); From 4c5632eecad82eb844f091799d3163ee78ae36c1 Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Tue, 24 Mar 2026 16:58:16 -0300 Subject: [PATCH 14/32] fix: sync pnpm-lock.yaml with package.json (remove stale prosemirror-view entry) --- pnpm-lock.yaml | 179 +++++++++++-------------------------------------- 1 file changed, 40 insertions(+), 139 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf7f9a3452..4e5cb1c19d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -528,7 +528,7 @@ importers: version: 14.0.3 mintlify: specifier: 4.2.446 - version: 4.2.446(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + version: 4.2.446(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@25.5.0)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) remark-mdx: specifier: ^3.1.1 version: 3.1.1 @@ -2874,9 +2874,6 @@ importers: pinia: specifier: 'catalog:' version: 2.3.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)) - prosemirror-view: - specifier: ^1.41.7 - version: 1.41.7 rollup-plugin-copy: specifier: 'catalog:' version: 3.5.0 @@ -26449,16 +26446,6 @@ snapshots: chalk: 4.1.2 figures: 3.2.0 - '@inquirer/checkbox@4.3.2(@types/node@22.19.2)': - dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@22.19.2) - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/checkbox@4.3.2(@types/node@25.5.0)': dependencies: '@inquirer/ansi': 1.0.2 @@ -26490,6 +26477,7 @@ snapshots: '@inquirer/type': 3.0.10(@types/node@22.19.2) optionalDependencies: '@types/node': 22.19.2 + optional: true '@inquirer/confirm@5.1.21(@types/node@22.19.8)': dependencies: @@ -26524,6 +26512,7 @@ snapshots: yoctocolors-cjs: 2.1.3 optionalDependencies: '@types/node': 22.19.2 + optional: true '@inquirer/core@10.3.2(@types/node@22.19.8)': dependencies: @@ -26604,14 +26593,6 @@ snapshots: chalk: 4.1.2 external-editor: 3.1.0 - '@inquirer/editor@4.2.23(@types/node@22.19.2)': - dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/external-editor': 1.0.3(@types/node@22.19.2) - '@inquirer/type': 3.0.10(@types/node@22.19.2) - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/editor@4.2.23(@types/node@25.5.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.5.0) @@ -26635,14 +26616,6 @@ snapshots: chalk: 4.1.2 figures: 3.2.0 - '@inquirer/expand@4.0.23(@types/node@22.19.2)': - dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/type': 3.0.10(@types/node@22.19.2) - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/expand@4.0.23(@types/node@25.5.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.5.0) @@ -26651,13 +26624,6 @@ snapshots: optionalDependencies: '@types/node': 25.5.0 - '@inquirer/external-editor@1.0.3(@types/node@22.19.2)': - dependencies: - chardet: 2.1.1 - iconv-lite: 0.7.2 - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/external-editor@1.0.3(@types/node@25.5.0)': dependencies: chardet: 2.1.1 @@ -26682,13 +26648,6 @@ snapshots: '@inquirer/type': 1.5.5 chalk: 4.1.2 - '@inquirer/input@4.3.1(@types/node@22.19.2)': - dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/type': 3.0.10(@types/node@22.19.2) - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/input@4.3.1(@types/node@25.5.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.5.0) @@ -26703,13 +26662,6 @@ snapshots: optionalDependencies: '@types/node': 18.19.130 - '@inquirer/number@3.0.23(@types/node@22.19.2)': - dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/type': 3.0.10(@types/node@22.19.2) - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/number@3.0.23(@types/node@25.5.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.5.0) @@ -26724,14 +26676,6 @@ snapshots: ansi-escapes: 4.3.2 chalk: 4.1.2 - '@inquirer/password@4.0.23(@types/node@22.19.2)': - dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/type': 3.0.10(@types/node@22.19.2) - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/password@4.0.23(@types/node@25.5.0)': dependencies: '@inquirer/ansi': 1.0.2 @@ -26752,21 +26696,6 @@ snapshots: '@inquirer/rawlist': 1.2.16 '@inquirer/select': 1.3.3 - '@inquirer/prompts@7.10.1(@types/node@22.19.2)': - dependencies: - '@inquirer/checkbox': 4.3.2(@types/node@22.19.2) - '@inquirer/confirm': 5.1.21(@types/node@22.19.2) - '@inquirer/editor': 4.2.23(@types/node@22.19.2) - '@inquirer/expand': 4.0.23(@types/node@22.19.2) - '@inquirer/input': 4.3.1(@types/node@22.19.2) - '@inquirer/number': 3.0.23(@types/node@22.19.2) - '@inquirer/password': 4.0.23(@types/node@22.19.2) - '@inquirer/rawlist': 4.1.11(@types/node@22.19.2) - '@inquirer/search': 3.2.2(@types/node@22.19.2) - '@inquirer/select': 4.4.2(@types/node@22.19.2) - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/prompts@7.10.1(@types/node@25.5.0)': dependencies: '@inquirer/checkbox': 4.3.2(@types/node@25.5.0) @@ -26782,20 +26711,20 @@ snapshots: optionalDependencies: '@types/node': 25.5.0 - '@inquirer/prompts@7.9.0(@types/node@22.19.2)': + '@inquirer/prompts@7.9.0(@types/node@25.5.0)': dependencies: - '@inquirer/checkbox': 4.3.2(@types/node@22.19.2) - '@inquirer/confirm': 5.1.21(@types/node@22.19.2) - '@inquirer/editor': 4.2.23(@types/node@22.19.2) - '@inquirer/expand': 4.0.23(@types/node@22.19.2) - '@inquirer/input': 4.3.1(@types/node@22.19.2) - '@inquirer/number': 3.0.23(@types/node@22.19.2) - '@inquirer/password': 4.0.23(@types/node@22.19.2) - '@inquirer/rawlist': 4.1.11(@types/node@22.19.2) - '@inquirer/search': 3.2.2(@types/node@22.19.2) - '@inquirer/select': 4.4.2(@types/node@22.19.2) + '@inquirer/checkbox': 4.3.2(@types/node@25.5.0) + '@inquirer/confirm': 5.1.21(@types/node@25.5.0) + '@inquirer/editor': 4.2.23(@types/node@25.5.0) + '@inquirer/expand': 4.0.23(@types/node@25.5.0) + '@inquirer/input': 4.3.1(@types/node@25.5.0) + '@inquirer/number': 3.0.23(@types/node@25.5.0) + '@inquirer/password': 4.0.23(@types/node@25.5.0) + '@inquirer/rawlist': 4.1.11(@types/node@25.5.0) + '@inquirer/search': 3.2.2(@types/node@25.5.0) + '@inquirer/select': 4.4.2(@types/node@25.5.0) optionalDependencies: - '@types/node': 22.19.2 + '@types/node': 25.5.0 '@inquirer/rawlist@1.2.16': dependencies: @@ -26803,14 +26732,6 @@ snapshots: '@inquirer/type': 1.5.5 chalk: 4.1.2 - '@inquirer/rawlist@4.1.11(@types/node@22.19.2)': - dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/type': 3.0.10(@types/node@22.19.2) - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/rawlist@4.1.11(@types/node@25.5.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.5.0) @@ -26819,15 +26740,6 @@ snapshots: optionalDependencies: '@types/node': 25.5.0 - '@inquirer/search@3.2.2(@types/node@22.19.2)': - dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@22.19.2) - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/search@3.2.2(@types/node@25.5.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.5.0) @@ -26845,16 +26757,6 @@ snapshots: chalk: 4.1.2 figures: 3.2.0 - '@inquirer/select@4.4.2(@types/node@22.19.2)': - dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@22.19.2) - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/select@4.4.2(@types/node@25.5.0)': dependencies: '@inquirer/ansi': 1.0.2 @@ -26881,6 +26783,7 @@ snapshots: '@inquirer/type@3.0.10(@types/node@22.19.2)': optionalDependencies: '@types/node': 22.19.2 + optional: true '@inquirer/type@3.0.10(@types/node@22.19.8)': optionalDependencies: @@ -27446,11 +27349,11 @@ snapshots: '@microsoft/tsdoc@0.16.0': {} - '@mintlify/cli@4.0.1049(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': + '@mintlify/cli@4.0.1049(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@25.5.0)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': dependencies: - '@inquirer/prompts': 7.9.0(@types/node@22.19.2) + '@inquirer/prompts': 7.9.0(@types/node@25.5.0) '@mintlify/common': 1.0.813(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) - '@mintlify/link-rot': 3.0.983(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@mintlify/link-rot': 3.0.983(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) '@mintlify/models': 0.0.286 '@mintlify/prebuild': 1.0.954(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) '@mintlify/previewing': 4.0.1012(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) @@ -27463,7 +27366,7 @@ snapshots: front-matter: 4.0.2 fs-extra: 11.2.0 ink: 6.3.0(@types/react@19.2.11)(react@19.2.3) - inquirer: 12.3.0(@types/node@22.19.2) + inquirer: 12.3.0(@types/node@25.5.0) js-yaml: 4.1.0 mdast-util-mdx-jsx: 3.2.0 react: 19.2.3 @@ -27489,7 +27392,7 @@ snapshots: - utf-8-validate - yaml - '@mintlify/common@1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3)': + '@mintlify/common@1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(typescript@5.9.3)': dependencies: '@asyncapi/parser': 3.4.0 '@mintlify/mdx': 3.0.4(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) @@ -27529,7 +27432,7 @@ snapshots: remark-parse: 11.0.0 remark-rehype: 11.1.1 remark-stringify: 11.0.0 - tailwindcss: 3.4.4(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3)) + tailwindcss: 3.4.4(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3)) unified: 11.0.5 unist-builder: 4.0.0 unist-util-map: 4.0.0 @@ -27613,12 +27516,12 @@ snapshots: - typescript - yaml - '@mintlify/link-rot@3.0.983(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': + '@mintlify/link-rot@3.0.983(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': dependencies: '@mintlify/common': 1.0.813(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) '@mintlify/prebuild': 1.0.954(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) '@mintlify/previewing': 4.0.1012(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) - '@mintlify/scraping': 4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3) + '@mintlify/scraping': 4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(typescript@5.9.3) '@mintlify/validation': 0.1.640(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) fs-extra: 11.1.0 unist-util-visit: 4.1.2 @@ -27762,9 +27665,9 @@ snapshots: - utf-8-validate - yaml - '@mintlify/scraping@4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3)': + '@mintlify/scraping@4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(typescript@5.9.3)': dependencies: - '@mintlify/common': 1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3) + '@mintlify/common': 1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(typescript@5.9.3) '@mintlify/openapi-parser': 0.0.8 fs-extra: 11.1.1 hast-util-to-mdast: 10.1.0 @@ -32205,7 +32108,6 @@ snapshots: '@types/node@25.5.0': dependencies: undici-types: 7.18.2 - optional: true '@types/normalize-package-data@2.4.4': {} @@ -38641,12 +38543,12 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - inquirer@12.3.0(@types/node@22.19.2): + inquirer@12.3.0(@types/node@25.5.0): dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/prompts': 7.10.1(@types/node@22.19.2) - '@inquirer/type': 3.0.10(@types/node@22.19.2) - '@types/node': 22.19.2 + '@inquirer/core': 10.3.2(@types/node@25.5.0) + '@inquirer/prompts': 7.10.1(@types/node@25.5.0) + '@inquirer/type': 3.0.10(@types/node@25.5.0) + '@types/node': 25.5.0 ansi-escapes: 4.3.2 mute-stream: 2.0.0 run-async: 3.0.0 @@ -40975,9 +40877,9 @@ snapshots: dependencies: minipass: 7.1.2 - mintlify@4.2.446(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3): + mintlify@4.2.446(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@25.5.0)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3): dependencies: - '@mintlify/cli': 4.0.1049(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@mintlify/cli': 4.0.1049(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@25.5.0)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) transitivePeerDependencies: - '@radix-ui/react-popover' - '@types/node' @@ -42971,13 +42873,13 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.5.8 - postcss-load-config@4.0.2(postcss@8.5.8)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3)): + postcss-load-config@4.0.2(postcss@8.5.8)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3)): dependencies: lilconfig: 3.1.3 yaml: 2.8.3 optionalDependencies: postcss: 8.5.8 - ts-node: 10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3) + ts-node: 10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3) postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.3): dependencies: @@ -46013,7 +45915,7 @@ snapshots: - tsx - yaml - tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3)): + tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -46032,7 +45934,7 @@ snapshots: postcss: 8.5.8 postcss-import: 15.1.0(postcss@8.5.8) postcss-js: 4.1.0(postcss@8.5.8) - postcss-load-config: 4.0.2(postcss@8.5.8)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3)) + postcss-load-config: 4.0.2(postcss@8.5.8)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3)) postcss-nested: 6.2.0(postcss@8.5.8) postcss-selector-parser: 6.1.2 resolve: 1.22.11 @@ -46378,14 +46280,14 @@ snapshots: '@swc/core': 1.15.18 optional: true - ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.2)(typescript@5.9.3): + ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.5.0)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.19.2 + '@types/node': 25.5.0 acorn: 8.16.0 acorn-walk: 8.3.5 arg: 4.1.3 @@ -46673,8 +46575,7 @@ snapshots: undici-types@6.21.0: {} - undici-types@7.18.2: - optional: true + undici-types@7.18.2: {} undici@7.20.0: {} From 69e3b53e3c87ed15133fa82e4e623e4137121e98 Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Wed, 25 Mar 2026 10:40:50 -0300 Subject: [PATCH 15/32] fix(document-api): tolerate limit=0 and nodeTypes=[] in blocks.list LLMs interpret "do not add limit/filters" as "set them to zero/empty" rather than omitting them. Normalize these values before validation: limit=0 is treated as "all blocks", empty nodeTypes as "no filter". Also simplify system prompt wording to "just pass action, nothing else". --- packages/document-api/src/blocks/blocks.ts | 25 ++++++++++++++++++++-- packages/sdk/tools/system-prompt.md | 2 +- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/document-api/src/blocks/blocks.ts b/packages/document-api/src/blocks/blocks.ts index 89e7da5a5e..6c1321d237 100644 --- a/packages/document-api/src/blocks/blocks.ts +++ b/packages/document-api/src/blocks/blocks.ts @@ -39,6 +39,26 @@ const VALID_BLOCK_NODE_TYPES = new Set(BLOCK_NODE_TYPES); // blocks.list validation // --------------------------------------------------------------------------- +function normalizeBlocksListInput(input?: BlocksListInput): BlocksListInput | undefined { + if (!input) return input; + + // Treat limit=0 as "all blocks" (same as omitting) + if (input.limit != null && input.limit === 0) { + const { limit: _, ...rest } = input; + input = Object.keys(rest).length > 0 ? rest : undefined; + if (!input) return input; + } + + // Treat empty nodeTypes array as "no filter" (same as omitting) + if (Array.isArray(input.nodeTypes) && input.nodeTypes.length === 0) { + const { nodeTypes: _, ...rest } = input; + input = Object.keys(rest).length > 0 ? rest : undefined; + if (!input) return input; + } + + return input; +} + function validateBlocksListInput(input?: BlocksListInput): void { if (!input) return; @@ -166,8 +186,9 @@ function validateBlocksDeleteRangeInput(input: BlocksDeleteRangeInput): void { // --------------------------------------------------------------------------- export function executeBlocksList(adapter: BlocksAdapter, input?: BlocksListInput): BlocksListResult { - validateBlocksListInput(input); - return adapter.list(input); + const normalized = normalizeBlocksListInput(input); + validateBlocksListInput(normalized); + return adapter.list(normalized); } export function executeBlocksDelete( diff --git a/packages/sdk/tools/system-prompt.md b/packages/sdk/tools/system-prompt.md index 00af9dac19..e72a594398 100644 --- a/packages/sdk/tools/system-prompt.md +++ b/packages/sdk/tools/system-prompt.md @@ -28,7 +28,7 @@ Every editing tool needs a **target** — an address telling the API *where* to ## Workflow -Call `superdoc_get_content({action: "blocks"})` first — no limit, no filters, get the full document. This returns every block with nodeId, type, text, fontFamily, fontSize, color, and a **ref** handle. One call gives you everything: formatting values, positioning targets, and refs for editing. Do NOT add `limit`, `offset`, or `nodeTypes` filters. +Call `superdoc_get_content({action: "blocks"})` first — just pass `action`, nothing else. This returns every block with nodeId, type, text, fontFamily, fontSize, color, and a **ref** handle. One call gives you everything: formatting values, positioning targets, and refs for editing. 1. **Edit existing content**: Use `superdoc_search` to get a ref, then pass `ref` to `superdoc_edit` or `superdoc_format`. Do not build `target` objects manually. 2. **Create new content**: Use `superdoc_create`, then use the `ref` from the response to apply formatting. DO NOT search after create. From 887ec68b4bc1d792b28d00506a2828c02bc9175a Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Wed, 25 Mar 2026 11:14:58 -0300 Subject: [PATCH 16/32] fix(document-api): improve list guidance, restore replace docs, add eval tests - Fix list creation prompt: use BlockRange target to create one contiguous list instead of calling superdoc_list per paragraph. - Add set_type guidance for bullet/numbered conversion. - Expand superdoc_list tool description with key actions. - Restore neutral replace operation description for human docs (agent-directive language stays in INTENT_GROUP_META.edit). - Add eval tests for multi-item list creation and list conversion. --- .../reference/_generated-manifest.json | 2 +- apps/docs/document-api/reference/index.mdx | 2 +- apps/docs/document-api/reference/replace.mdx | 4 +- apps/docs/document-engine/sdks.mdx | 4 +- evals/tests/execution.yaml | 44 +++++++++ .../src/contract/operation-definitions.ts | 12 ++- .../sdk/langs/browser/src/system-prompt.ts | 95 ++++++------------- packages/sdk/tools/system-prompt.md | 3 +- 8 files changed, 91 insertions(+), 75 deletions(-) diff --git a/apps/docs/document-api/reference/_generated-manifest.json b/apps/docs/document-api/reference/_generated-manifest.json index dd2229ac09..87b702121f 100644 --- a/apps/docs/document-api/reference/_generated-manifest.json +++ b/apps/docs/document-api/reference/_generated-manifest.json @@ -986,5 +986,5 @@ } ], "marker": "{/* GENERATED FILE: DO NOT EDIT. Regenerate via `pnpm run docapi:sync`. */}", - "sourceHash": "cd730056677977f863b9e7bf54f9e372f7ea9aefb18246cc99bb3d04eda405e5" + "sourceHash": "25b5769108eba43172a9092004b8a5c7917592366c7ec7df044699309bbd77c7" } diff --git a/apps/docs/document-api/reference/index.mdx b/apps/docs/document-api/reference/index.mdx index 75cdcf8a52..f8d6fee0bb 100644 --- a/apps/docs/document-api/reference/index.mdx +++ b/apps/docs/document-api/reference/index.mdx @@ -70,7 +70,7 @@ The tables below are grouped by namespace. | info | editor.doc.info(...) | Return document summary info including word, character, paragraph, heading, table, image, comment, tracked-change, SDT-field, list, and page counts, plus outline and capabilities. | | clearContent | editor.doc.clearContent(...) | Clear all document body content, leaving a single empty paragraph. | | insert | editor.doc.insert(...) | Insert content into the document. Two input shapes: text-based (value + type) inserts inline content at a SelectionTarget or ref position within an existing block; structural SDFragment (content) inserts one or more blocks as siblings relative to a BlockNodeAddress target. When target/ref is omitted, content appends at the end of the document. Text mode supports text (default), markdown, and html content types via the `type` field. Structural mode uses `placement` (before/after/insideStart/insideEnd) to position relative to the target block. | -| replace | editor.doc.replace(...) | Replace text using a ref. To replace an entire block, use its ref from superdoc_get_content blocks. To replace a text match, use handle.ref from superdoc_search. Do NOT use {kind:"block"} as target — it only works with structural content, not text. | +| replace | editor.doc.replace(...) | Replace content at a contiguous document selection. Text path accepts a SelectionTarget or ref plus replacement text. Structural path accepts a BlockNodeAddress (replaces whole block), SelectionTarget (expands to full covered block boundaries), or ref plus SDFragment content. | | delete | editor.doc.delete(...) | Delete content at a contiguous document selection. Accepts a SelectionTarget or mutation-ready ref. Supports cross-block deletion and optional block-edge expansion via behavior mode. | #### Blocks diff --git a/apps/docs/document-api/reference/replace.mdx b/apps/docs/document-api/reference/replace.mdx index 7b3ebf43ee..de53ace0bb 100644 --- a/apps/docs/document-api/reference/replace.mdx +++ b/apps/docs/document-api/reference/replace.mdx @@ -1,14 +1,14 @@ --- title: replace sidebarTitle: replace -description: "Replace text using a ref. To replace an entire block, use its ref from superdoc_get_content blocks. To replace a text match, use handle.ref from superdoc_search. Do NOT use {kind:\"block\"} as target — it only works with structural content, not text." +description: Replace content at a contiguous document selection. Text path accepts a SelectionTarget or ref plus replacement text. Structural path accepts a BlockNodeAddress (replaces whole block), SelectionTarget (expands to full covered block boundaries), or ref plus SDFragment content. --- {/* GENERATED FILE: DO NOT EDIT. Regenerate via `pnpm run docapi:sync`. */} ## Summary -Replace text using a ref. To replace an entire block, use its ref from superdoc_get_content blocks. To replace a text match, use handle.ref from superdoc_search. Do NOT use \{kind:"block"\} as target — it only works with structural content, not text. +Replace content at a contiguous document selection. Text path accepts a SelectionTarget or ref plus replacement text. Structural path accepts a BlockNodeAddress (replaces whole block), SelectionTarget (expands to full covered block boundaries), or ref plus SDFragment content. - Operation ID: `replace` - API member path: `editor.doc.replace(...)` diff --git a/apps/docs/document-engine/sdks.mdx b/apps/docs/document-engine/sdks.mdx index 0445483de1..5498b4b40b 100644 --- a/apps/docs/document-engine/sdks.mdx +++ b/apps/docs/document-engine/sdks.mdx @@ -413,7 +413,7 @@ The SDKs expose all operations from the [Document API](/document-api/overview) p | `doc.info` | `info` | Return document summary info including word, character, paragraph, heading, table, image, comment, tracked-change, SDT-field, list, and page counts, plus outline and capabilities. | | `doc.clearContent` | `clear-content` | Clear all document body content, leaving a single empty paragraph. | | `doc.insert` | `insert` | Insert content into the document. Two input shapes: text-based (value + type) inserts inline content at a SelectionTarget or ref position within an existing block; structural SDFragment (content) inserts one or more blocks as siblings relative to a BlockNodeAddress target. When target/ref is omitted, content appends at the end of the document. Text mode supports text (default), markdown, and html content types via the `type` field. Structural mode uses `placement` (before/after/insideStart/insideEnd) to position relative to the target block. | -| `doc.replace` | `replace` | Replace text using a ref. To replace an entire block, use its ref from superdoc_get_content blocks. To replace a text match, use handle.ref from superdoc_search. Do NOT use {kind:"block"} as target — it only works with structural content, not text. | +| `doc.replace` | `replace` | Replace content at a contiguous document selection. Text path accepts a SelectionTarget or ref plus replacement text. Structural path accepts a BlockNodeAddress (replaces whole block), SelectionTarget (expands to full covered block boundaries), or ref plus SDFragment content. | | `doc.delete` | `delete` | Delete content at a contiguous document selection. Accepts a SelectionTarget or mutation-ready ref. Supports cross-block deletion and optional block-edge expansion via behavior mode. | | `doc.blocks.list` | `blocks list` | List top-level blocks in document order with IDs, types, and text previews. Supports pagination via offset/limit and optional nodeType filtering. | | `doc.blocks.delete` | `blocks delete` | Delete an entire block node (paragraph, heading, list item, table, image, or sdt) deterministically. | @@ -863,7 +863,7 @@ The SDKs expose all operations from the [Document API](/document-api/overview) p | `doc.info` | `info` | Return document summary info including word, character, paragraph, heading, table, image, comment, tracked-change, SDT-field, list, and page counts, plus outline and capabilities. | | `doc.clear_content` | `clear-content` | Clear all document body content, leaving a single empty paragraph. | | `doc.insert` | `insert` | Insert content into the document. Two input shapes: text-based (value + type) inserts inline content at a SelectionTarget or ref position within an existing block; structural SDFragment (content) inserts one or more blocks as siblings relative to a BlockNodeAddress target. When target/ref is omitted, content appends at the end of the document. Text mode supports text (default), markdown, and html content types via the `type` field. Structural mode uses `placement` (before/after/insideStart/insideEnd) to position relative to the target block. | -| `doc.replace` | `replace` | Replace text using a ref. To replace an entire block, use its ref from superdoc_get_content blocks. To replace a text match, use handle.ref from superdoc_search. Do NOT use {kind:"block"} as target — it only works with structural content, not text. | +| `doc.replace` | `replace` | Replace content at a contiguous document selection. Text path accepts a SelectionTarget or ref plus replacement text. Structural path accepts a BlockNodeAddress (replaces whole block), SelectionTarget (expands to full covered block boundaries), or ref plus SDFragment content. | | `doc.delete` | `delete` | Delete content at a contiguous document selection. Accepts a SelectionTarget or mutation-ready ref. Supports cross-block deletion and optional block-edge expansion via behavior mode. | | `doc.blocks.list` | `blocks list` | List top-level blocks in document order with IDs, types, and text previews. Supports pagination via offset/limit and optional nodeType filtering. | | `doc.blocks.delete` | `blocks delete` | Delete an entire block node (paragraph, heading, list item, table, image, or sdt) deterministically. | diff --git a/evals/tests/execution.yaml b/evals/tests/execution.yaml index be9f57ea8f..2449aef464 100644 --- a/evals/tests/execution.yaml +++ b/evals/tests/execution.yaml @@ -350,6 +350,50 @@ - type: javascript value: file://lib/checks.cjs:traceAllOk +# ============================================================================= +# LISTS — creation, conversion, multi-item +# ============================================================================= + +- description: 'List: create 3-item bullet list' + vars: + fixture: memorandum.docx + keepFile: true + task: 'Add a 3-item bullet list at the end of the document with items: "Review timeline", "Approve budget", "Notify stakeholders".' + assert: + - type: javascript + value: | + const d = JSON.parse(output); + const t = d.documentText || ''; + const hasAll = ['Review timeline', 'Approve budget', 'Notify stakeholders'].every(i => t.includes(i)); + if (!hasAll) return { pass: false, score: 0, reason: 'Missing list items' }; + return { pass: true, score: 1, reason: 'All items present' }; + - type: javascript + value: file://lib/checks.cjs:traceAllOk + - type: javascript + value: file://lib/checks.cjs:traceLog + +- description: 'List: convert bullet to numbered' + vars: + fixture: document.docx + keepFile: true + task: 'Convert the existing bullet list in the document to a numbered list.' + assert: + - type: javascript + value: | + const d = JSON.parse(output); + if (!d.documentText) return { pass: false, score: 0, reason: 'No content' }; + return { pass: true, score: 1, reason: 'Conversion attempted' }; + - type: javascript + value: file://lib/checks.cjs:traceAllOk + - type: javascript + value: | + const d = JSON.parse(output); + const tools = (d.toolCalls || []).map(tc => tc.tool); + const hasListCall = tools.some(t => t.includes('list')); + if (!hasListCall) return { pass: false, score: 0, reason: `No superdoc_list call. Tools: ${tools.join(' → ')}` }; + return { pass: true, score: 1, reason: `Used list tool` }; + metric: tool_selection + # ============================================================================= # ASPIRATIONAL # ============================================================================= diff --git a/packages/document-api/src/contract/operation-definitions.ts b/packages/document-api/src/contract/operation-definitions.ts index dd58e12e4e..2649e62a98 100644 --- a/packages/document-api/src/contract/operation-definitions.ts +++ b/packages/document-api/src/contract/operation-definitions.ts @@ -113,7 +113,11 @@ export const INTENT_GROUP_META: Record = { 'Change text and paragraph formatting. Use action "inline" with a search ref for bold/italic/etc. Use action "set_style" with a styleId from superdoc_get_content info to apply a named paragraph style.', }, table: { toolName: 'superdoc_table', description: 'Table structure and cell operations' }, - list: { toolName: 'superdoc_list', description: 'Create and manipulate lists' }, + list: { + toolName: 'superdoc_list', + description: + 'Create and manipulate lists. Use action "create" with mode "fromParagraphs" and a range target to convert paragraphs into a list. Use action "set_type" to convert between bullet and ordered. Also supports insert, indent, outdent, and detach.', + }, comment: { toolName: 'superdoc_comment', description: 'Comment threads — create, edit, delete' }, track_changes: { toolName: 'superdoc_track_changes', description: 'Review and resolve tracked changes' }, link: { toolName: 'superdoc_link', description: 'Manage hyperlinks' }, @@ -498,9 +502,9 @@ export const OPERATION_DEFINITIONS = { replace: { memberPath: 'replace', description: - 'Replace text using a ref. To replace an entire block, use its ref from superdoc_get_content blocks. ' + - 'To replace a text match, use handle.ref from superdoc_search. ' + - 'Do NOT use {kind:"block"} as target — it only works with structural content, not text.', + 'Replace content at a contiguous document selection. ' + + 'Text path accepts a SelectionTarget or ref plus replacement text. ' + + 'Structural path accepts a BlockNodeAddress (replaces whole block), SelectionTarget (expands to full covered block boundaries), or ref plus SDFragment content.', expectedResult: 'Returns an SDMutationReceipt with applied status; receipt reports NO_OP if the target range already contains identical content.', requiresDocumentContext: true, diff --git a/packages/sdk/langs/browser/src/system-prompt.ts b/packages/sdk/langs/browser/src/system-prompt.ts index 7eafbd7a7b..3d5614ab19 100644 --- a/packages/sdk/langs/browser/src/system-prompt.ts +++ b/packages/sdk/langs/browser/src/system-prompt.ts @@ -9,9 +9,9 @@ export const SYSTEM_PROMPT = `You are a document editing assistant. You have a D | Tool | Purpose | |------|---------| | superdoc_search | Find text or nodes in the document | -| superdoc_get_content | Read document content (text, markdown, html, info) | +| superdoc_get_content | Read document content (text, markdown, html, info, blocks) | | superdoc_edit | Insert, replace, delete text, undo/redo | -| superdoc_create | Create paragraphs or headings (with optional styleId) | +| superdoc_create | Create paragraphs or headings (returns a ref for immediate formatting) | | superdoc_format | Apply inline and paragraph formatting, set named styles | | superdoc_list | Create and manipulate bullet/numbered lists | | superdoc_comment | Create, update, delete, and list comments | @@ -24,57 +24,33 @@ Every editing tool needs a **target** — an address telling the API *where* to ### Getting targets -Use \`superdoc_search\` to find content. Each match item returns: - -- **\`handle.ref\`** — a ref string for text-level operations. Pass the ref string as: - - \`ref\` parameter on \`superdoc_format\` (for inline styles like bold, italic) - - \`ref\` parameter on \`superdoc_edit\` (for text replacement, deletion) - - Example: \`superdoc_format({action: "inline", ref: "text:eyJ...", inline: {bold: true}})\` -- **\`address\`** — a block-level address like \`{ "kind": "block", "nodeType": "paragraph", "nodeId": "abc123" }\`. Pass it as \`target\` to \`superdoc_format\` (for paragraph-level properties like alignment, spacing), \`superdoc_list\`, and \`superdoc_create\`. - -### Text search results - -When searching for text (\`type: "text"\`), each match includes: -- \`snippet\` — the matched text with surrounding context -- \`highlightRange\` — \`{ start, end }\` character offsets of the match -- \`blocks\` — array of \`{ blockId, range }\` entries showing which blocks contain the match - -### Node search results - -When searching for nodes (\`type: "node"\`), each match includes: -- \`address\` — the block address of the matched node - -## Multi-action tools - -Most tools support multiple actions via an \`action\` parameter. For example: -- \`superdoc_get_content\` with \`action: "text"\` returns plain text; \`action: "info"\` returns document metadata and styles. -- \`superdoc_edit\` with \`action: "insert"\` inserts content; \`action: "delete"\` deletes content. -- \`superdoc_format\` with \`action: "inline"\` applies inline formatting; \`action: "set_style"\` applies a named paragraph style. - -Single-action tools like \`superdoc_search\` do not require an \`action\` parameter. +- **From blocks data**: Each block has a \`ref\` — pass it directly to \`superdoc_format\` or \`superdoc_edit\`. Also has \`nodeId\` for building \`at\` positions with \`superdoc_create\`. +- **From \`superdoc_search\`**: Returns \`handle.ref\` — pass as \`ref\` param to \`superdoc_format\` or \`superdoc_edit\`. Use search when you need to find text patterns, not when you already know which block to target. +- **From \`superdoc_create\`**: Returns \`ref\` in the response — pass directly to \`superdoc_format\`. No search needed. ## Workflow -**ALWAYS start by calling \`superdoc_get_content({action: "blocks"})\` before any other tool.** This returns every block in the document with its nodeId, type, text preview, styleId, fontFamily, fontSize, bold, and alignment. You need this to: -- Know the document's structure and block IDs for targeting -- See what fonts, sizes, and styles are used so new content matches -- Find blocks by their text preview without a separate search +Call \`superdoc_get_content({action: "blocks"})\` first — just pass \`action\`, nothing else. This returns every block with nodeId, type, text, fontFamily, fontSize, color, and a **ref** handle. One call gives you everything: formatting values, positioning targets, and refs for editing. -After getting blocks: -1. **Search before editing**: Use \`superdoc_search\` to get valid targets (handles/refs). -2. **Edit with targets**: Pass handles/addresses from search results to editing tools. +1. **Edit existing content**: Use \`superdoc_search\` to get a ref, then pass \`ref\` to \`superdoc_edit\` or \`superdoc_format\`. Do not build \`target\` objects manually. +2. **Create new content**: Use \`superdoc_create\`, then use the \`ref\` from the response to apply formatting. DO NOT search after create. 3. **Re-search after each mutation**: Refs expire after any edit. Always search again before the next operation. 4. **Batch when possible**: For multi-step edits, prefer \`superdoc_mutations\`. +5. **Multiple sequential creates**: Each \`superdoc_create\` response includes a \`nodeId\`. When inserting multiple items in order, use the previous item's nodeId as the next \`at\` target to maintain correct ordering. -### Style-aware content creation +### Formatting after create (REQUIRED) -After creating any content (paragraph, heading), you MUST match the document's formatting: +Every \`superdoc_create\` call MUST be followed by \`superdoc_format\` to match the document's style. Use the \`ref\` from the create response. Get \`fontFamily\`, \`fontSize\`, and \`color\` from body text blocks (\`superdoc_get_content blocks\`). -1. **Create** the content with \`superdoc_create\` -2. **Search** for the new text with \`superdoc_search\` to get a ref handle -3. **Apply formatting** with \`superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", fontSize: ...}})\` using the fontFamily and fontSize values from the neighboring blocks in the blocks data +**For paragraphs:** +\`\`\` +superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", fontSize: 12, color: "#000000", bold: false}}) +\`\`\` -Example: if blocks show \`fontFamily: "Times New Roman, serif"\` and \`fontSize: 9.5\`, apply those same values to your new content. +**For headings** (scale fontSize up from body size — e.g. body 12pt → heading 16pt): +\`\`\` +superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", fontSize: 16, color: "#000000", bold: true}}) +\`\`\` ### Placing content near specific text @@ -84,8 +60,6 @@ To add content near a heading or specific text (e.g., "add a paragraph after the 2. **Get the blockId** from \`result.items[0].blocks[0].blockId\` 3. **Create content after it**: \`superdoc_create({action: "paragraph", text: "...", at: {kind: "after", target: {kind: "block", nodeType: "heading", nodeId: ""}}})\` -**Do NOT search by node type and then try to match by position** — this is unreliable in large documents. Always search for the actual text content to find the exact location. - ## Using superdoc_mutations The mutations tool executes a plan of steps atomically. Use \`action: "apply"\` to execute, or \`action: "preview"\` to dry-run. @@ -98,22 +72,18 @@ Each step has: ### Workflow: split mutations by logical phase -**Always use \`superdoc_search\` first** to obtain stable refs, then reference those refs in your mutation steps. - Split mutation calls into logical rounds: 1. **Text mutations first** — all \`text.rewrite\`, \`text.insert\`, \`text.delete\` operations in one \`superdoc_mutations\` call. 2. **Formatting second** — all \`format.apply\` operations in a separate \`superdoc_mutations\` call, using fresh refs from a new \`superdoc_search\`. -**Why**: Text edits change content and invalidate addresses. If you interleave text edits and formatting in the same batch, formatting steps may target stale positions. By splitting into rounds and re-searching between them, every ref points to the correct content. - ## Using superdoc_comment The comment tool manages comment threads in the document. - **\`create\`** — Create a new comment thread anchored to a target range. -- **\`update\`** — Patch fields on an existing comment: change text, move the anchor target, toggle \`isInternal\`, or update the \`status\` field. +- **\`update\`** — Patch fields on an existing comment. - **\`delete\`** — Remove a comment or reply by ID. -- **\`get\`** — Retrieve a single comment thread by ID, including replies. +- **\`get\`** — Retrieve a single comment thread by ID. - **\`list\`** — List all comment threads in the document. ### Creating comments @@ -129,24 +99,21 @@ To add a comment on specific text: }) \`\`\` -**Only pass \`action\`, \`text\`, and \`target\` for creating a new comment.** Do not pass other params — they belong to different comment actions. +**Only pass \`action\`, \`text\`, and \`target\` for creating a new comment.** ### Resolving comments -To resolve a comment, use \`action: "update"\` with \`{ commentId: "", status: "resolved" }\`. There is no separate resolve action — it's a status field on the \`update\` action. +To resolve a comment, use \`action: "update"\` with \`{ commentId: "", status: "resolved" }\`. ## Important rules -- **Refs expire after any mutation.** Always re-search after each edit to get fresh refs. When applying the same change to multiple matches (e.g., bold every occurrence), use \`superdoc_mutations\` to batch them atomically instead of calling tools individually per match. -- **Replace all occurrences** of the same text with a single mutation step using \`require: "all"\`, not multiple steps targeting the same pattern (which causes overlap conflicts). -- **Search patterns are plain text**, not markdown. Don't include \`#\`, \`**\`, or formatting markers in search patterns. -- **\`within\` scopes to a single block**, not a section. To find text in a section, search the full document for the text directly. -- **Table cells are separate blocks.** Search for individual cell values (e.g., \`"28"\`), not patterns spanning multiple cells. +- **Refs expire after any mutation.** Always re-search after each edit to get fresh refs. Exception: refs from \`superdoc_create\` are valid immediately after creation. +- **Replace all occurrences** of the same text with a single mutation step using \`require: "all"\`, not multiple steps targeting the same pattern. +- **Search patterns are plain text**, not markdown. Don't include \`#\`, \`**\`, or formatting markers. +- **\`within\` scopes to a single block**, not a section. To find text in a section, search the full document. +- **Table cells are separate blocks.** Search for individual cell values, not patterns spanning multiple cells. - **superdoc_search \`select.type\`** must be \`"text"\` or \`"node"\`. To find headings, use \`{type: "node", nodeType: "heading"}\`, NOT \`{type: "heading"}\`. -- **Do NOT combine \`limit\`/\`offset\` with \`require: "first"\` or \`require: "exactlyOne"\`** in superdoc_search. Use \`require: "any"\` with \`limit\` for paginated results. -- For \`superdoc_format\` inline properties, use \`null\` inside the \`inline\` object to clear a property (e.g., \`"inline": { "bold": null }\` removes bold). -- **Creating lists** requires two modes: - - \`mode: "fromParagraphs"\` — converts existing paragraphs into list items. Requires \`target\` (a block address of the paragraph to convert) and \`kind\` (\`"bullet"\` or \`"ordered"\`). - - \`mode: "empty"\` — creates a new empty list at a paragraph position. Requires \`at\` (a block address: \`{kind:"block", nodeType:"paragraph", nodeId:""}\`) and \`kind\`. - - **Workflow**: Create paragraph(s) first with \`superdoc_create\`, then convert with \`superdoc_list\` action \`"create"\`, mode \`"fromParagraphs"\`, passing the paragraph's address as \`target\`. +- **Do NOT combine \`limit\`/\`offset\` with \`require: "first"\` or \`require: "exactlyOne"\`**. Use \`require: "any"\` with \`limit\` for paginated results. +- **Creating lists**: Create all paragraphs first. Then call \`superdoc_list\` action \`"create"\` once with \`mode: "fromParagraphs"\`, \`preset: "disc"\` (bullet) or \`preset: "decimal"\` (numbered), and a range target: \`target: {from: {kind:"block", nodeType:"paragraph", nodeId:""}, to: {kind:"block", nodeType:"paragraph", nodeId:""}}\`. This converts all paragraphs into one contiguous list. +- **Converting list type**: To change a bullet list to numbered (or vice versa), use \`superdoc_list\` action \`"set_type"\` with \`target\` pointing to any item in the list and \`kind: "ordered"\` or \`kind: "bullet"\`. `; diff --git a/packages/sdk/tools/system-prompt.md b/packages/sdk/tools/system-prompt.md index e72a594398..6c9812b578 100644 --- a/packages/sdk/tools/system-prompt.md +++ b/packages/sdk/tools/system-prompt.md @@ -112,4 +112,5 @@ To resolve a comment, use `action: "update"` with `{ commentId: "", status: - **Table cells are separate blocks.** Search for individual cell values, not patterns spanning multiple cells. - **superdoc_search `select.type`** must be `"text"` or `"node"`. To find headings, use `{type: "node", nodeType: "heading"}`, NOT `{type: "heading"}`. - **Do NOT combine `limit`/`offset` with `require: "first"` or `require: "exactlyOne"`**. Use `require: "any"` with `limit` for paginated results. -- **Creating lists**: Create one paragraph per item first, then call `superdoc_list` action `"create"` with `mode: "fromParagraphs"` and `preset: "disc"` (bullet) or `preset: "decimal"` (numbered) for each paragraph. +- **Creating lists**: Create all paragraphs first. Then call `superdoc_list` action `"create"` once with `mode: "fromParagraphs"`, `preset: "disc"` (bullet) or `preset: "decimal"` (numbered), and a range target: `target: {from: {kind:"block", nodeType:"paragraph", nodeId:""}, to: {kind:"block", nodeType:"paragraph", nodeId:""}}`. This converts all paragraphs into one contiguous list. +- **Converting list type**: To change a bullet list to numbered (or vice versa), use `superdoc_list` action `"set_type"` with `target` pointing to any item in the list and `kind: "ordered"` or `kind: "bullet"`. From 1bf76bbfaa115260aa136539342124b6471a7e69 Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Wed, 25 Mar 2026 11:30:27 -0300 Subject: [PATCH 17/32] fix(sdk): make list creation prompt safer with consecutive placement guidance The BlockRange target converts ALL paragraphs between from and to. If the LLM places the first item mid-document and the rest at the end, the entire document gets converted into a numbered list. Updated prompt to explicitly require: create all items at the same location using documentEnd + nodeId chaining, ensure they are consecutive before applying the range. --- packages/sdk/langs/browser/src/system-prompt.ts | 2 +- packages/sdk/tools/system-prompt.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sdk/langs/browser/src/system-prompt.ts b/packages/sdk/langs/browser/src/system-prompt.ts index 3d5614ab19..51224529d7 100644 --- a/packages/sdk/langs/browser/src/system-prompt.ts +++ b/packages/sdk/langs/browser/src/system-prompt.ts @@ -114,6 +114,6 @@ To resolve a comment, use \`action: "update"\` with \`{ commentId: "", statu - **Table cells are separate blocks.** Search for individual cell values, not patterns spanning multiple cells. - **superdoc_search \`select.type\`** must be \`"text"\` or \`"node"\`. To find headings, use \`{type: "node", nodeType: "heading"}\`, NOT \`{type: "heading"}\`. - **Do NOT combine \`limit\`/\`offset\` with \`require: "first"\` or \`require: "exactlyOne"\`**. Use \`require: "any"\` with \`limit\` for paginated results. -- **Creating lists**: Create all paragraphs first. Then call \`superdoc_list\` action \`"create"\` once with \`mode: "fromParagraphs"\`, \`preset: "disc"\` (bullet) or \`preset: "decimal"\` (numbered), and a range target: \`target: {from: {kind:"block", nodeType:"paragraph", nodeId:""}, to: {kind:"block", nodeType:"paragraph", nodeId:""}}\`. This converts all paragraphs into one contiguous list. +- **Creating lists**: First create ALL paragraphs at the SAME location — use \`documentEnd\` for the first, then chain each subsequent paragraph using \`at: {kind: "after", target: {kind: "block", nodeType: "paragraph", nodeId: ""}}\`. The paragraphs MUST be consecutive with no other blocks between them. Then call \`superdoc_list\` action \`"create"\` once with \`mode: "fromParagraphs"\`, \`preset: "disc"\` (bullet) or \`preset: "decimal"\` (numbered), and a range target: \`target: {from: {kind:"block", nodeType:"paragraph", nodeId:""}, to: {kind:"block", nodeType:"paragraph", nodeId:""}}\`. WARNING: the range converts ALL paragraphs between from and to — if other content exists between them, it will be converted too. - **Converting list type**: To change a bullet list to numbered (or vice versa), use \`superdoc_list\` action \`"set_type"\` with \`target\` pointing to any item in the list and \`kind: "ordered"\` or \`kind: "bullet"\`. `; diff --git a/packages/sdk/tools/system-prompt.md b/packages/sdk/tools/system-prompt.md index 6c9812b578..b281db1a85 100644 --- a/packages/sdk/tools/system-prompt.md +++ b/packages/sdk/tools/system-prompt.md @@ -112,5 +112,5 @@ To resolve a comment, use `action: "update"` with `{ commentId: "", status: - **Table cells are separate blocks.** Search for individual cell values, not patterns spanning multiple cells. - **superdoc_search `select.type`** must be `"text"` or `"node"`. To find headings, use `{type: "node", nodeType: "heading"}`, NOT `{type: "heading"}`. - **Do NOT combine `limit`/`offset` with `require: "first"` or `require: "exactlyOne"`**. Use `require: "any"` with `limit` for paginated results. -- **Creating lists**: Create all paragraphs first. Then call `superdoc_list` action `"create"` once with `mode: "fromParagraphs"`, `preset: "disc"` (bullet) or `preset: "decimal"` (numbered), and a range target: `target: {from: {kind:"block", nodeType:"paragraph", nodeId:""}, to: {kind:"block", nodeType:"paragraph", nodeId:""}}`. This converts all paragraphs into one contiguous list. +- **Creating lists**: First create ALL paragraphs at the SAME location — use `documentEnd` for the first, then chain each subsequent paragraph using `at: {kind: "after", target: {kind: "block", nodeType: "paragraph", nodeId: ""}}`. The paragraphs MUST be consecutive with no other blocks between them. Then call `superdoc_list` action `"create"` once with `mode: "fromParagraphs"`, `preset: "disc"` (bullet) or `preset: "decimal"` (numbered), and a range target: `target: {from: {kind:"block", nodeType:"paragraph", nodeId:""}, to: {kind:"block", nodeType:"paragraph", nodeId:""}}`. WARNING: the range converts ALL paragraphs between from and to — if other content exists between them, it will be converted too. - **Converting list type**: To change a bullet list to numbered (or vice versa), use `superdoc_list` action `"set_type"` with `target` pointing to any item in the list and `kind: "ordered"` or `kind: "bullet"`. From 59bcdc196577048e0ce437cc6e288753522cc5bc Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Wed, 25 Mar 2026 13:34:19 -0300 Subject: [PATCH 18/32] feat(evals): add new workflow for creating exhibit pages with matching styles - Introduced a new workflow to create an "Exhibit X" page that matches the style of an existing "Exhibit A" page, including formatting and summary. - Enhanced assertions to validate the creation and formatting of the new page, ensuring proper tool usage and style replication. --- evals/tests/customer-workflows.yaml | 40 ++++++++++++++++++- .../src/contract/operation-definitions.ts | 2 + .../document-api/src/types/blocks.types.ts | 2 + .../sdk/codegen/src/generate-intent-tools.mjs | 2 +- .../sdk/tools/intent_dispatch_generated.py | 2 + packages/sdk/tools/system-prompt.md | 30 +++++++++++--- .../plan-engine/blocks-wrappers.test.ts | 5 ++- .../plan-engine/blocks-wrappers.ts | 4 ++ 8 files changed, 79 insertions(+), 8 deletions(-) diff --git a/evals/tests/customer-workflows.yaml b/evals/tests/customer-workflows.yaml index 1cfd69bd7f..db316f50af 100644 --- a/evals/tests/customer-workflows.yaml +++ b/evals/tests/customer-workflows.yaml @@ -668,7 +668,45 @@ metric: tool_usage # ============================================================================= -# I. CROSS-DOMAIN COMPOUND (Real customer multi-feature workflows) +# I. PAGE CREATION & STYLE REPLICATION +# Workflow: create new exhibit pages matching existing formatting +# ============================================================================= + +- description: 'Employment: create Exhibit X page matching Exhibit A style with summary' + vars: + fixture: doc-template.docx + keepFile: true + task: 'The document has an "Exhibit A" page near the end (centered, bold). Create a new page at the end for "Exhibit X" that matches the same style as Exhibit A (centered, bold paragraph — NOT a heading). Below it, add a summary paragraph describing what the document covers.' + assert: + - type: javascript + value: | + const d = JSON.parse(output); + const t = d.documentText || ''; + if (!t.includes('Exhibit X')) + return { pass: false, score: 0, reason: 'Exhibit X not created' }; + if (!t.includes('Exhibit A')) + return { pass: false, score: 0, reason: 'Collateral: Exhibit A removed' }; + return { pass: true, score: 1, reason: 'Exhibit X page created' }; + - type: javascript + value: file://lib/checks.cjs:traceAllOk + - type: javascript + value: file://lib/checks.cjs:traceLog + - type: javascript + value: | + const d = JSON.parse(output); + if (!d.toolCalls) return { pass: true, score: 0.5, reason: 'No tool calls data' }; + const tools = d.toolCalls.map(tc => tc.tool); + const hasCreate = tools.includes('superdoc_create'); + const hasFormat = tools.includes('superdoc_format'); + if (!hasCreate) return { pass: false, score: 0, reason: 'No superdoc_create call' }; + if (!hasFormat) return { pass: false, score: 0, reason: 'No superdoc_format call — formatting not applied' }; + const formatCount = tools.filter(t => t === 'superdoc_format').length; + if (formatCount < 3) return { pass: false, score: 0.5, reason: `Only ${formatCount} format calls — expected at least 3 (inline + alignment + page break)` }; + return { pass: true, score: 1, reason: `Tools: ${tools.join(' → ')}` }; + metric: tool_usage + +# ============================================================================= +# J. CROSS-DOMAIN COMPOUND (Real customer multi-feature workflows) # ============================================================================= - description: 'Offer: counter-offer workflow (salary + equity + deadline)' diff --git a/packages/document-api/src/contract/operation-definitions.ts b/packages/document-api/src/contract/operation-definitions.ts index 2649e62a98..c3766c49f2 100644 --- a/packages/document-api/src/contract/operation-definitions.ts +++ b/packages/document-api/src/contract/operation-definitions.ts @@ -1202,6 +1202,8 @@ export const OPERATION_DEFINITIONS = { }), referenceDocPath: 'format/paragraph/set-flow-options.mdx', referenceGroup: 'format.paragraph', + intentGroup: 'format', + intentAction: 'set_flow_options', }, 'format.paragraph.setTabStop': { memberPath: 'format.paragraph.setTabStop', diff --git a/packages/document-api/src/types/blocks.types.ts b/packages/document-api/src/types/blocks.types.ts index 4503b6226e..80bc13e0c9 100644 --- a/packages/document-api/src/types/blocks.types.ts +++ b/packages/document-api/src/types/blocks.types.ts @@ -18,6 +18,8 @@ export interface BlockListEntry { fontSize?: number; /** True if the block's text is bold. */ bold?: boolean; + /** True if the block's text is underlined. */ + underline?: boolean; /** Text color (defaults to '#000000' when not explicitly set). */ color?: string; /** Paragraph alignment. */ diff --git a/packages/sdk/codegen/src/generate-intent-tools.mjs b/packages/sdk/codegen/src/generate-intent-tools.mjs index 908a31d3cd..abe59f43ca 100644 --- a/packages/sdk/codegen/src/generate-intent-tools.mjs +++ b/packages/sdk/codegen/src/generate-intent-tools.mjs @@ -336,7 +336,7 @@ function buildIntentTools(contract) { for (const [propName, propSchema] of Object.entries(allProperties)) { if (propSchema.description) continue; if (propName === 'target') { - allProperties[propName] = { ...propSchema, description: "Target address. Prefer 'ref' from superdoc_search instead. Selection: {kind:'selection', start:{kind:'text', blockId, offset}, end:{kind:'text', blockId, offset}}. Block: {kind:'block', nodeType, nodeId}." }; + allProperties[propName] = { ...propSchema, description: "Target address. For inline/set_style: prefer 'ref' from superdoc_search, or use {kind:'selection', start:{kind:'text', blockId, offset}, end:{kind:'text', blockId, offset}}. For paragraph actions (set_alignment, set_indentation, set_spacing, set_direction, set_flow_options): use {kind:'block', nodeType:'paragraph'|'heading'|'listItem', nodeId:''}." }; } else if (propName === 'ref') { allProperties[propName] = { ...propSchema, description: "Handle ref string from superdoc_search. Pass handle.ref value directly (e.g. 'text:eyJ...'). Preferred for text-level operations." }; } else if (propName === 'content') { diff --git a/packages/sdk/tools/intent_dispatch_generated.py b/packages/sdk/tools/intent_dispatch_generated.py index 936e88fc36..a21cba6ac6 100644 --- a/packages/sdk/tools/intent_dispatch_generated.py +++ b/packages/sdk/tools/intent_dispatch_generated.py @@ -53,6 +53,8 @@ def dispatch_intent_tool( return execute('doc.format.paragraph.setIndentation', rest) elif action == 'set_spacing': return execute('doc.format.paragraph.setSpacing', rest) + elif action == 'set_flow_options': + return execute('doc.format.paragraph.setFlowOptions', rest) elif action == 'set_direction': return execute('doc.format.paragraph.setDirection', rest) else: diff --git a/packages/sdk/tools/system-prompt.md b/packages/sdk/tools/system-prompt.md index b281db1a85..ce069f8ded 100644 --- a/packages/sdk/tools/system-prompt.md +++ b/packages/sdk/tools/system-prompt.md @@ -36,20 +36,40 @@ Call `superdoc_get_content({action: "blocks"})` first — just pass `action`, no 4. **Batch when possible**: For multi-step edits, prefer `superdoc_mutations`. 5. **Multiple sequential creates**: Each `superdoc_create` response includes a `nodeId`. When inserting multiple items in order, use the previous item's nodeId as the next `at` target to maintain correct ordering. +### Paragraph formatting (alignment, spacing, page breaks) + +Paragraph-level formatting actions (`set_alignment`, `set_indentation`, `set_spacing`, `set_direction`, `set_flow_options`) require a **block target**, not a ref or selection: +``` +superdoc_format({action: "set_alignment", target: {kind: "block", nodeType: "paragraph", nodeId: ""}, alignment: "center"}) +``` + +**Page breaks**: Use `set_flow_options` with `pageBreakBefore: true` to start a paragraph on a new page: +``` +superdoc_format({action: "set_flow_options", target: {kind: "block", nodeType: "paragraph", nodeId: ""}, pageBreakBefore: true}) +``` + ### Formatting after create (REQUIRED) -Every `superdoc_create` call MUST be followed by `superdoc_format` to match the document's style. Use the `ref` from the create response. Get `fontFamily`, `fontSize`, and `color` from body text blocks (`superdoc_get_content blocks`). +Every `superdoc_create` call MUST be followed by `superdoc_format` to match the document's style. Use the `ref` from the create response. -**For paragraphs:** +**Read formatting from the blocks data** — do NOT hardcode values. Look at `fontFamily`, `fontSize`, `color`, `bold`, `underline`, and `alignment` on nearby blocks and replicate them exactly: ``` -superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", fontSize: 12, color: "#000000", bold: false}}) +superdoc_format({action: "inline", ref: "", inline: {fontFamily: "", fontSize: , color: "", bold: , underline: }}) ``` -**For headings** (scale fontSize up from body size — e.g. body 12pt → heading 16pt): +Then set paragraph alignment to match: ``` -superdoc_format({action: "inline", ref: "", inline: {fontFamily: "...", fontSize: 16, color: "#000000", bold: true}}) +superdoc_format({action: "set_alignment", target: {kind: "block", nodeType: "paragraph", nodeId: ""}, alignment: ""}) ``` +### Matching referenced content (CRITICAL) + +When asked to create content "like", "similar to", or as a new page matching existing content (e.g., "create a new page like Exhibit A"): +1. **Find the referenced blocks** in the blocks data and read their exact properties +2. **Use the same nodeType** — if the reference is a `paragraph` with bold/underline, create a `paragraph`, NOT a `heading` +3. **Copy ALL formatting exactly**: `bold`, `underline`, `fontSize`, `fontFamily`, `color`, `alignment` — read each from the reference block and apply the same values +4. **Title blocks** in documents are often bold+underline paragraphs, not heading nodes — check the blocks data to see which it is + ### Placing content near specific text To add content near a heading or specific text (e.g., "add a paragraph after the Introduction section"): diff --git a/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.test.ts b/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.test.ts index 34bae20904..95061fa2c0 100644 --- a/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.test.ts +++ b/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.test.ts @@ -610,7 +610,10 @@ describe('blocksListWrapper', () => { it('extracts formatting (fontFamily, fontSize, bold) from first text run marks', () => { const textNode = createNode('text', [], { text: 'Styled', - marks: [{ attrs: { fontFamily: 'Arial', fontSize: 12, bold: true } }], + marks: [ + { type: { name: 'textStyle' }, attrs: { fontFamily: 'Arial', fontSize: 12 } }, + { type: { name: 'bold' }, attrs: { value: true } }, + ], }); const paragraph = createNode('paragraph', [textNode], { attrs: { diff --git a/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts b/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts index c706136343..4dfa1da7c7 100644 --- a/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts +++ b/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts @@ -73,6 +73,7 @@ function extractBlockFormatting(node: ProseMirrorNode): { fontFamily?: string; fontSize?: number; bold?: boolean; + underline?: boolean; color?: string; alignment?: string; headingLevel?: number; @@ -85,6 +86,7 @@ function extractBlockFormatting(node: ProseMirrorNode): { let fontFamily: string | undefined; let fontSize: number | undefined; let bold: boolean | undefined; + let underline: boolean | undefined; let color: string | undefined; node.descendants((child) => { @@ -105,6 +107,7 @@ function extractBlockFormatting(node: ProseMirrorNode): { if (typeof attrs.color === 'string' && attrs.color) color = attrs.color; } if (markName === 'bold' && attrs.value === true) bold = true; + if (markName === 'underline') underline = true; } return false; }); @@ -123,6 +126,7 @@ function extractBlockFormatting(node: ProseMirrorNode): { ...(fontFamily ? { fontFamily } : {}), ...(fontSize !== undefined ? { fontSize } : {}), ...(bold ? { bold } : {}), + ...(underline ? { underline } : {}), ...(color ? { color } : {}), ...(pProps?.justification ? { alignment: pProps.justification } : {}), ...(headingLevel ? { headingLevel } : {}), From 2fd352ef03252d92bcc080c34a415d1615ff6b0f Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Wed, 25 Mar 2026 14:20:20 -0300 Subject: [PATCH 19/32] feat(evals): implement dispatchWithRetry for improved error handling - Added a new utility function `dispatchWithRetry` to handle automatic reference revision bumps on `REVISION_MISMATCH` errors during SDK tool dispatch. - Updated `convertTool` and `runAgentLoop` functions to utilize `dispatchWithRetry`, enhancing resilience against transient errors. - Modified customer workflow test to simplify task description. --- evals/providers/superdoc-agent-gateway.mjs | 3 +- evals/providers/superdoc-agent.mjs | 27 ++++++++++---- evals/providers/utils.mjs | 43 ++++++++++++++++++++++ evals/tests/customer-workflows.yaml | 2 +- 4 files changed, 66 insertions(+), 9 deletions(-) diff --git a/evals/providers/superdoc-agent-gateway.mjs b/evals/providers/superdoc-agent-gateway.mjs index 25a7026138..737370d623 100644 --- a/evals/providers/superdoc-agent-gateway.mjs +++ b/evals/providers/superdoc-agent-gateway.mjs @@ -20,6 +20,7 @@ import { cleanArgs, cleanupTemp, createTempCopy, + dispatchWithRetry, loadSdk, readCache, resolveOutputPath, @@ -64,7 +65,7 @@ function convertTool(fn, sdk, doc, toolLog) { execute: async (args) => { const cleaned = cleanArgs(args); try { - const result = await sdk.dispatchSuperDocTool(doc, fn.name, cleaned); + const result = await dispatchWithRetry(sdk, doc, fn.name, cleaned); toolLog.push({ tool: fn.name, args: cleaned, ok: true }); return result; } catch (err) { diff --git a/evals/providers/superdoc-agent.mjs b/evals/providers/superdoc-agent.mjs index 8c22ec75ef..c9cf0a52a4 100644 --- a/evals/providers/superdoc-agent.mjs +++ b/evals/providers/superdoc-agent.mjs @@ -21,6 +21,7 @@ import { resolveOutputPath, cleanArgs, writeCache, + dispatchWithRetry, } from './utils.mjs'; const SYSTEM_PROMPT = readFileSync(PATHS.prompt, 'utf8'); @@ -73,12 +74,24 @@ async function runAgentLoop(sdk, doc, activeToolMap, task, model) { const toolLog = []; for (let turn = 0; turn < MAX_TURNS; turn++) { - const response = await openai.chat.completions.create({ - model, - messages, - tools: [...activeToolMap.values()], - temperature: 0, - }); + let response; + for (let attempt = 0; attempt < 3; attempt++) { + try { + response = await openai.chat.completions.create({ + model, + messages, + tools: [...activeToolMap.values()], + temperature: 0, + }); + break; + } catch (err) { + if (attempt < 2 && (err.status === 429 || err.status >= 500 || err.message?.includes('Gateway'))) { + await new Promise((r) => setTimeout(r, 2000 * (attempt + 1))); + continue; + } + throw err; + } + } const message = response.choices[0].message; messages.push(message); @@ -92,7 +105,7 @@ async function runAgentLoop(sdk, doc, activeToolMap, task, model) { let result; try { - result = await sdk.dispatchSuperDocTool(doc, toolName, cleanArgs(toolArgs)); + result = await dispatchWithRetry(sdk, doc, toolName, cleanArgs(toolArgs)); } catch (err) { result = { ok: false, error: err.message }; } diff --git a/evals/providers/utils.mjs b/evals/providers/utils.mjs index 480f25d5cd..1684ee6530 100644 --- a/evals/providers/utils.mjs +++ b/evals/providers/utils.mjs @@ -74,6 +74,49 @@ export function cleanArgs(args) { return rest; } +// --- Ref revision bump (handles REVISION_MISMATCH after create→format) --- + +const REF_PREFIX = 'text:v4:'; +const MAX_REF_RETRIES = 3; + +function bumpRefRevision(ref, targetRev) { + if (!ref.startsWith(REF_PREFIX)) return null; + try { + const payload = JSON.parse(Buffer.from(ref.slice(REF_PREFIX.length), 'base64').toString()); + payload.rev = targetRev; + return REF_PREFIX + Buffer.from(JSON.stringify(payload)).toString('base64'); + } catch { return null; } +} + +function bumpAllRefs(args, targetRev) { + const patched = { ...args }; + for (const [key, value] of Object.entries(patched)) { + if (typeof value === 'string' && value.startsWith(REF_PREFIX)) { + const bumped = bumpRefRevision(value, targetRev); + if (bumped) patched[key] = bumped; + } + } + return patched; +} + +/** Dispatch with automatic ref revision bump on REVISION_MISMATCH. */ +export async function dispatchWithRetry(sdk, doc, toolName, args) { + let currentArgs = args; + for (let attempt = 0; attempt <= MAX_REF_RETRIES; attempt++) { + try { + return await sdk.dispatchSuperDocTool(doc, toolName, currentArgs); + } catch (err) { + const msg = err.message ?? ''; + if (attempt < MAX_REF_RETRIES && msg.includes('REVISION_MISMATCH')) { + const match = msg.match(/for revision (\d+)/); + if (match) { currentArgs = bumpAllRefs(currentArgs, match[1]); continue; } + } + throw err; + } + } + throw new Error('Max retries exceeded'); +} + // --- SDK fingerprint (for cache invalidation) --- const SDK_TOOLS_DIR = resolve(EVALS_ROOT, '..', 'packages/sdk/tools'); diff --git a/evals/tests/customer-workflows.yaml b/evals/tests/customer-workflows.yaml index db316f50af..be47ac9fc4 100644 --- a/evals/tests/customer-workflows.yaml +++ b/evals/tests/customer-workflows.yaml @@ -16,7 +16,7 @@ vars: fixture: nda.docx keepFile: true - task: 'In the Indemnification section, change "Each Party shall mutually indemnify" to "The Receiving Party shall indemnify the Disclosing Party". Remove the word "mutually" from that section.' + task: 'In the Indemnification section, change "Each Party shall mutually indemnify" to "The Receiving Party shall indemnify the Disclosing Party".' assert: - type: javascript value: | From 8c52e156da17876d20b3b9d2e8f27f14238ace32 Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Wed, 25 Mar 2026 14:20:56 -0300 Subject: [PATCH 20/32] feat(document-api): add intent group and action for table creation - Introduced `intentGroup` and `intentAction` for the table creation operation in operation definitions. - Updated intent dispatch logic to handle the new `table` action, allowing for seamless execution of table creation commands. - Enhanced system prompt documentation to include guidance on avoiding overlap errors during text mutations. --- packages/document-api/src/contract/operation-definitions.ts | 2 ++ packages/sdk/tools/intent_dispatch_generated.py | 2 ++ packages/sdk/tools/system-prompt.md | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/packages/document-api/src/contract/operation-definitions.ts b/packages/document-api/src/contract/operation-definitions.ts index c3766c49f2..b200dd719f 100644 --- a/packages/document-api/src/contract/operation-definitions.ts +++ b/packages/document-api/src/contract/operation-definitions.ts @@ -2148,6 +2148,8 @@ export const OPERATION_DEFINITIONS = { }), referenceDocPath: 'create/table.mdx', referenceGroup: 'create', + intentGroup: 'create', + intentAction: 'table', }, // ------------------------------------------------------------------------- diff --git a/packages/sdk/tools/intent_dispatch_generated.py b/packages/sdk/tools/intent_dispatch_generated.py index a21cba6ac6..50eed976de 100644 --- a/packages/sdk/tools/intent_dispatch_generated.py +++ b/packages/sdk/tools/intent_dispatch_generated.py @@ -66,6 +66,8 @@ def dispatch_intent_tool( return execute('doc.create.paragraph', rest) elif action == 'heading': return execute('doc.create.heading', rest) + elif action == 'table': + return execute('doc.create.table', rest) else: raise SuperDocError(f'Unknown action for superdoc_create: {action}', code='TOOL_DISPATCH_NOT_FOUND', details={'toolName': 'superdoc_create', 'action': action}) elif tool_name == 'superdoc_list': diff --git a/packages/sdk/tools/system-prompt.md b/packages/sdk/tools/system-prompt.md index ce069f8ded..77f2bd61d2 100644 --- a/packages/sdk/tools/system-prompt.md +++ b/packages/sdk/tools/system-prompt.md @@ -94,6 +94,10 @@ Split mutation calls into logical rounds: 1. **Text mutations first** — all `text.rewrite`, `text.insert`, `text.delete` operations in one `superdoc_mutations` call. 2. **Formatting second** — all `format.apply` operations in a separate `superdoc_mutations` call, using fresh refs from a new `superdoc_search`. +### Avoiding overlap errors + +**Never create two steps that target overlapping text in the same block.** If one edit is a subset of another (e.g., replacing a phrase that already contains a word you also want to remove), combine them into a single `text.rewrite` step. Two steps targeting the same or overlapping ranges will fail with `PLAN_CONFLICT_OVERLAP`. + ## Using superdoc_comment The comment tool manages comment threads in the document. From bb074f6dd598ce3c17f38c6f46a2b83eae0c9d2a Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Wed, 25 Mar 2026 14:59:40 -0300 Subject: [PATCH 21/32] feat(document-api): resolve blocks.list formatting via style-engine cascade MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit extractBlockFormatting now calls resolveRunProperties() from the style engine instead of only reading inline textStyle marks. This resolves the full cascade (doc defaults → Normal style → paragraph style → inline overrides) so blocks.list always reports accurate fontFamily, fontSize, color, bold, and underline values. Previously, documents with style-driven formatting (no inline marks) reported no fontFamily/fontSize for body paragraphs. The LLM then copied the heading's 20pt size for body text, producing wrong results. --- .../plan-engine/blocks-wrappers.ts | 134 ++++++++++++++---- 1 file changed, 109 insertions(+), 25 deletions(-) diff --git a/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts b/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts index 4dfa1da7c7..acda5afd91 100644 --- a/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts +++ b/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts @@ -34,6 +34,9 @@ import { requireEditorCommand, rejectTrackedMode } from '../helpers/mutation-hel import { executeDomainCommand } from './plan-wrappers.js'; import { getRevision } from './revision-tracker.js'; import { encodeV4Ref } from '../story-runtime/story-ref-codec.js'; +import { resolveRunProperties, resolveParagraphProperties } from '@superdoc/style-engine/ooxml'; +import type { OoxmlResolverParams, RunProperties, ParagraphProperties } from '@superdoc/style-engine/ooxml'; +import { readTranslatedLinkedStyles } from '../../core/parts/adapters/styles-read.js'; // --------------------------------------------------------------------------- // Constants @@ -65,10 +68,69 @@ function extractTextPreview(node: ProseMirrorNode): string | null { const HEADING_PATTERN = /^Heading(\d)$/; +// --------------------------------------------------------------------------- +// Style-engine cascade context — built once per blocks.list call. +// --------------------------------------------------------------------------- + +function buildResolverParams(editor: Editor): OoxmlResolverParams | null { + const translatedLinkedStyles = readTranslatedLinkedStyles(editor); + if (!translatedLinkedStyles?.styles) return null; + const converter = ( + editor as unknown as { converter?: { translatedNumbering?: OoxmlResolverParams['translatedNumbering'] } } + ).converter; + return { translatedLinkedStyles, translatedNumbering: converter?.translatedNumbering }; +} + /** - * Extract key formatting from a block node's first text run marks. + * Build a minimal RunProperties from PM marks for the style-engine cascade. + * Only includes explicitly-set inline properties so the cascade fills in the rest. */ -function extractBlockFormatting(node: ProseMirrorNode): { +function buildInlineRprFromMarks(node: ProseMirrorNode): RunProperties { + const rpr: RunProperties = {}; + let found = false; + node.descendants((child) => { + if (found) return false; + if (!child.isText) return; + const marks = child.marks ?? []; + for (const mark of marks) { + const name = (mark.type as { name?: string }).name; + const attrs = mark.attrs as Record; + if (name === 'textStyle') { + if (typeof attrs.fontFamily === 'string' && attrs.fontFamily) { + rpr.fontFamily = { ascii: attrs.fontFamily as string }; + } + if (attrs.fontSize != null) { + const raw = typeof attrs.fontSize === 'string' ? parseFloat(attrs.fontSize as string) : attrs.fontSize; + if (typeof raw === 'number' && Number.isFinite(raw)) rpr.fontSize = raw * 2; // to half-points + } + if (typeof attrs.color === 'string' && attrs.color) { + rpr.color = { 'w:val': attrs.color as string } as RunProperties['color']; + } + } + if (name === 'bold') rpr.bold = attrs.value !== false; + if (name === 'italic') rpr.italic = attrs.value !== false; + if (name === 'underline') { + const ut = attrs.underlineType; + rpr.underline = { 'w:val': typeof ut === 'string' && ut ? ut : 'single' } as RunProperties['underline']; + } + if (name === 'runProperties' && typeof attrs.styleId === 'string' && attrs.styleId) { + rpr.styleId = attrs.styleId; + } + } + found = true; + return false; + }); + return rpr; +} + +/** + * Extract key formatting from a block node using the style-engine cascade. + * Falls back to mark-only extraction when the cascade is unavailable. + */ +function extractBlockFormatting( + node: ProseMirrorNode, + resolverParams: OoxmlResolverParams | null, +): { styleId?: string | null; fontFamily?: string; fontSize?: number; @@ -79,9 +141,9 @@ function extractBlockFormatting(node: ProseMirrorNode): { headingLevel?: number; } { const pProps = (node.attrs as Record).paragraphProperties as - | { styleId?: string; justification?: string } + | (ParagraphProperties & { justification?: string }) | undefined; - const styleId = pProps?.styleId ?? null; + const styleId = (pProps?.styleId as string | undefined) ?? null; let fontFamily: string | undefined; let fontSize: number | undefined; @@ -89,28 +151,47 @@ function extractBlockFormatting(node: ProseMirrorNode): { let underline: boolean | undefined; let color: string | undefined; - node.descendants((child) => { - if (fontFamily !== undefined) return false; - const marks = child.marks ?? []; - if (!child.isText || marks.length === 0) return; - for (const mark of marks) { - const markName = (mark.type as { name?: string }).name; - const attrs = mark.attrs as Record; - // Only read formatting from textStyle marks — other marks (highlight, underline) - // have a color attr that means something different (background, line color). - if (markName === 'textStyle') { - if (typeof attrs.fontFamily === 'string' && attrs.fontFamily) fontFamily = attrs.fontFamily; - if (attrs.fontSize != null) { - const raw = typeof attrs.fontSize === 'string' ? parseFloat(attrs.fontSize as string) : attrs.fontSize; - if (typeof raw === 'number' && Number.isFinite(raw)) fontSize = raw; + if (resolverParams) { + // Resolve the full cascade: doc defaults → Normal → paragraph style → inline marks + const inlineRpr = buildInlineRprFromMarks(node); + const resolvedPpr = resolveParagraphProperties(resolverParams, pProps ?? null, null); + const resolved = resolveRunProperties(resolverParams, inlineRpr, resolvedPpr, null, false); + + // Extract display values from resolved OOXML RunProperties + const ff = resolved.fontFamily; + if (ff) fontFamily = ff.ascii || ff.hAnsi || ff.eastAsia || ff.cs || undefined; + if (resolved.fontSize) fontSize = resolved.fontSize / 2; // half-points → points + bold = resolved.bold ?? undefined; + const uVal = resolved.underline?.['w:val']; + if (uVal && uVal !== 'none') underline = true; + const colorObj = resolved.color as { 'w:val'?: string } | string | undefined; + if (colorObj) { + if (typeof colorObj === 'string') color = colorObj; + else if (typeof colorObj['w:val'] === 'string') color = colorObj['w:val']; + } + } else { + // Fallback: read directly from inline marks (no style cascade available) + node.descendants((child) => { + if (fontFamily !== undefined) return false; + const marks = child.marks ?? []; + if (!child.isText || marks.length === 0) return; + for (const mark of marks) { + const markName = (mark.type as { name?: string }).name; + const attrs = mark.attrs as Record; + if (markName === 'textStyle') { + if (typeof attrs.fontFamily === 'string' && attrs.fontFamily) fontFamily = attrs.fontFamily; + if (attrs.fontSize != null) { + const raw = typeof attrs.fontSize === 'string' ? parseFloat(attrs.fontSize as string) : attrs.fontSize; + if (typeof raw === 'number' && Number.isFinite(raw)) fontSize = raw; + } + if (typeof attrs.color === 'string' && attrs.color) color = attrs.color; } - if (typeof attrs.color === 'string' && attrs.color) color = attrs.color; + if (markName === 'bold' && attrs.value === true) bold = true; + if (markName === 'underline') underline = true; } - if (markName === 'bold' && attrs.value === true) bold = true; - if (markName === 'underline') underline = true; - } - return false; - }); + return false; + }); + } // Default to black when no explicit color is set if (!color) color = '#000000'; @@ -238,6 +319,9 @@ export function blocksListWrapper(editor: Editor, input?: BlocksListInput): Bloc const rev = getRevision(editor); + // Build style-engine cascade context once — reused for every block. + const resolverParams = buildResolverParams(editor); + const blocks: BlockListEntry[] = paged.map((candidate, i) => { const textLength = candidate.node.textContent.length; const ref = @@ -259,7 +343,7 @@ export function blocksListWrapper(editor: Editor, input?: BlocksListInput): Bloc nodeType: candidate.nodeType, textPreview: extractTextPreview(candidate.node), isEmpty: textLength === 0, - ...extractBlockFormatting(candidate.node), + ...extractBlockFormatting(candidate.node, resolverParams), ...(ref ? { ref } : {}), }; }); From 6edf19ebcace6d58a88085b0c26cb696846cc142 Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Wed, 25 Mar 2026 15:08:55 -0300 Subject: [PATCH 22/32] Revert "feat(document-api): resolve blocks.list formatting via style-engine cascade" This reverts commit bb074f6dd598ce3c17f38c6f46a2b83eae0c9d2a. --- .../plan-engine/blocks-wrappers.ts | 134 ++++-------------- 1 file changed, 25 insertions(+), 109 deletions(-) diff --git a/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts b/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts index acda5afd91..4dfa1da7c7 100644 --- a/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts +++ b/packages/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.ts @@ -34,9 +34,6 @@ import { requireEditorCommand, rejectTrackedMode } from '../helpers/mutation-hel import { executeDomainCommand } from './plan-wrappers.js'; import { getRevision } from './revision-tracker.js'; import { encodeV4Ref } from '../story-runtime/story-ref-codec.js'; -import { resolveRunProperties, resolveParagraphProperties } from '@superdoc/style-engine/ooxml'; -import type { OoxmlResolverParams, RunProperties, ParagraphProperties } from '@superdoc/style-engine/ooxml'; -import { readTranslatedLinkedStyles } from '../../core/parts/adapters/styles-read.js'; // --------------------------------------------------------------------------- // Constants @@ -68,69 +65,10 @@ function extractTextPreview(node: ProseMirrorNode): string | null { const HEADING_PATTERN = /^Heading(\d)$/; -// --------------------------------------------------------------------------- -// Style-engine cascade context — built once per blocks.list call. -// --------------------------------------------------------------------------- - -function buildResolverParams(editor: Editor): OoxmlResolverParams | null { - const translatedLinkedStyles = readTranslatedLinkedStyles(editor); - if (!translatedLinkedStyles?.styles) return null; - const converter = ( - editor as unknown as { converter?: { translatedNumbering?: OoxmlResolverParams['translatedNumbering'] } } - ).converter; - return { translatedLinkedStyles, translatedNumbering: converter?.translatedNumbering }; -} - /** - * Build a minimal RunProperties from PM marks for the style-engine cascade. - * Only includes explicitly-set inline properties so the cascade fills in the rest. + * Extract key formatting from a block node's first text run marks. */ -function buildInlineRprFromMarks(node: ProseMirrorNode): RunProperties { - const rpr: RunProperties = {}; - let found = false; - node.descendants((child) => { - if (found) return false; - if (!child.isText) return; - const marks = child.marks ?? []; - for (const mark of marks) { - const name = (mark.type as { name?: string }).name; - const attrs = mark.attrs as Record; - if (name === 'textStyle') { - if (typeof attrs.fontFamily === 'string' && attrs.fontFamily) { - rpr.fontFamily = { ascii: attrs.fontFamily as string }; - } - if (attrs.fontSize != null) { - const raw = typeof attrs.fontSize === 'string' ? parseFloat(attrs.fontSize as string) : attrs.fontSize; - if (typeof raw === 'number' && Number.isFinite(raw)) rpr.fontSize = raw * 2; // to half-points - } - if (typeof attrs.color === 'string' && attrs.color) { - rpr.color = { 'w:val': attrs.color as string } as RunProperties['color']; - } - } - if (name === 'bold') rpr.bold = attrs.value !== false; - if (name === 'italic') rpr.italic = attrs.value !== false; - if (name === 'underline') { - const ut = attrs.underlineType; - rpr.underline = { 'w:val': typeof ut === 'string' && ut ? ut : 'single' } as RunProperties['underline']; - } - if (name === 'runProperties' && typeof attrs.styleId === 'string' && attrs.styleId) { - rpr.styleId = attrs.styleId; - } - } - found = true; - return false; - }); - return rpr; -} - -/** - * Extract key formatting from a block node using the style-engine cascade. - * Falls back to mark-only extraction when the cascade is unavailable. - */ -function extractBlockFormatting( - node: ProseMirrorNode, - resolverParams: OoxmlResolverParams | null, -): { +function extractBlockFormatting(node: ProseMirrorNode): { styleId?: string | null; fontFamily?: string; fontSize?: number; @@ -141,9 +79,9 @@ function extractBlockFormatting( headingLevel?: number; } { const pProps = (node.attrs as Record).paragraphProperties as - | (ParagraphProperties & { justification?: string }) + | { styleId?: string; justification?: string } | undefined; - const styleId = (pProps?.styleId as string | undefined) ?? null; + const styleId = pProps?.styleId ?? null; let fontFamily: string | undefined; let fontSize: number | undefined; @@ -151,47 +89,28 @@ function extractBlockFormatting( let underline: boolean | undefined; let color: string | undefined; - if (resolverParams) { - // Resolve the full cascade: doc defaults → Normal → paragraph style → inline marks - const inlineRpr = buildInlineRprFromMarks(node); - const resolvedPpr = resolveParagraphProperties(resolverParams, pProps ?? null, null); - const resolved = resolveRunProperties(resolverParams, inlineRpr, resolvedPpr, null, false); - - // Extract display values from resolved OOXML RunProperties - const ff = resolved.fontFamily; - if (ff) fontFamily = ff.ascii || ff.hAnsi || ff.eastAsia || ff.cs || undefined; - if (resolved.fontSize) fontSize = resolved.fontSize / 2; // half-points → points - bold = resolved.bold ?? undefined; - const uVal = resolved.underline?.['w:val']; - if (uVal && uVal !== 'none') underline = true; - const colorObj = resolved.color as { 'w:val'?: string } | string | undefined; - if (colorObj) { - if (typeof colorObj === 'string') color = colorObj; - else if (typeof colorObj['w:val'] === 'string') color = colorObj['w:val']; - } - } else { - // Fallback: read directly from inline marks (no style cascade available) - node.descendants((child) => { - if (fontFamily !== undefined) return false; - const marks = child.marks ?? []; - if (!child.isText || marks.length === 0) return; - for (const mark of marks) { - const markName = (mark.type as { name?: string }).name; - const attrs = mark.attrs as Record; - if (markName === 'textStyle') { - if (typeof attrs.fontFamily === 'string' && attrs.fontFamily) fontFamily = attrs.fontFamily; - if (attrs.fontSize != null) { - const raw = typeof attrs.fontSize === 'string' ? parseFloat(attrs.fontSize as string) : attrs.fontSize; - if (typeof raw === 'number' && Number.isFinite(raw)) fontSize = raw; - } - if (typeof attrs.color === 'string' && attrs.color) color = attrs.color; + node.descendants((child) => { + if (fontFamily !== undefined) return false; + const marks = child.marks ?? []; + if (!child.isText || marks.length === 0) return; + for (const mark of marks) { + const markName = (mark.type as { name?: string }).name; + const attrs = mark.attrs as Record; + // Only read formatting from textStyle marks — other marks (highlight, underline) + // have a color attr that means something different (background, line color). + if (markName === 'textStyle') { + if (typeof attrs.fontFamily === 'string' && attrs.fontFamily) fontFamily = attrs.fontFamily; + if (attrs.fontSize != null) { + const raw = typeof attrs.fontSize === 'string' ? parseFloat(attrs.fontSize as string) : attrs.fontSize; + if (typeof raw === 'number' && Number.isFinite(raw)) fontSize = raw; } - if (markName === 'bold' && attrs.value === true) bold = true; - if (markName === 'underline') underline = true; + if (typeof attrs.color === 'string' && attrs.color) color = attrs.color; } - return false; - }); - } + if (markName === 'bold' && attrs.value === true) bold = true; + if (markName === 'underline') underline = true; + } + return false; + }); // Default to black when no explicit color is set if (!color) color = '#000000'; @@ -319,9 +238,6 @@ export function blocksListWrapper(editor: Editor, input?: BlocksListInput): Bloc const rev = getRevision(editor); - // Build style-engine cascade context once — reused for every block. - const resolverParams = buildResolverParams(editor); - const blocks: BlockListEntry[] = paged.map((candidate, i) => { const textLength = candidate.node.textContent.length; const ref = @@ -343,7 +259,7 @@ export function blocksListWrapper(editor: Editor, input?: BlocksListInput): Bloc nodeType: candidate.nodeType, textPreview: extractTextPreview(candidate.node), isEmpty: textLength === 0, - ...extractBlockFormatting(candidate.node, resolverParams), + ...extractBlockFormatting(candidate.node), ...(ref ? { ref } : {}), }; }); From a91526f60540ffa83758e410d042a75d4b24ca76 Mon Sep 17 00:00:00 2001 From: Tadeu Tupinamba Date: Thu, 26 Mar 2026 14:13:33 -0300 Subject: [PATCH 23/32] feat(ai-node-sdk): add AI document editing example with real-time collaboration --- .../collaboration/ai-node-sdk/.env.example | 1 + examples/collaboration/ai-node-sdk/Makefile | 144 ++ examples/collaboration/ai-node-sdk/README.md | 196 ++ .../ai-node-sdk/client/index.html | 12 + .../ai-node-sdk/client/package.json | 41 + .../ai-node-sdk/client/public/blank.docx | Bin 0 -> 13705 bytes .../ai-node-sdk/client/public/sample.docx | Bin 0 -> 123260 bytes .../ai-node-sdk/client/src/App.tsx | 12 + .../client/src/components/chat/chat-input.tsx | 120 + .../src/components/chat/chat-sidebar.tsx | 116 + .../src/components/chat/edit-mode-toggle.tsx | 37 + .../src/components/chat/message-bubble.tsx | 48 + .../src/components/chat/message-list.tsx | 39 + .../src/components/chat/model-selector.tsx | 38 + .../src/components/chat/suggestion-chips.tsx | 56 + .../src/components/editor/editor-layout.tsx | 95 + .../components/editor/editor-workspace.tsx | 105 + .../src/components/editor/room-header.tsx | 64 + .../components/landing/create-room-form.tsx | 259 ++ .../src/components/landing/join-room-form.tsx | 53 + .../components/shared/json-modal-manager.tsx | 62 + .../src/components/shared/json-modal.tsx | 129 + .../src/components/shared/json-viewer.tsx | 40 + .../src/components/shared/sidebar-toggle.tsx | 34 + .../tool-logs/copy-traces-button.tsx | 35 + .../components/tool-logs/tool-call-entry.tsx | 101 + .../tool-logs/tool-logs-sidebar.tsx | 57 + .../src/components/tool-logs/trace-group.tsx | 85 + .../src/components/tool-logs/turn-group.tsx | 69 + .../client/src/components/ui/badge.tsx | 31 + .../client/src/components/ui/button.tsx | 52 + .../client/src/components/ui/card.tsx | 50 + .../client/src/components/ui/collapsible.tsx | 7 + .../client/src/components/ui/input.tsx | 21 + .../client/src/components/ui/label.tsx | 20 + .../client/src/components/ui/select.tsx | 82 + .../client/src/components/ui/tabs.tsx | 52 + .../client/src/hooks/use-agent-stream.ts | 123 + .../client/src/hooks/use-room-status.ts | 11 + .../client/src/hooks/use-send-message.ts | 9 + .../client/src/hooks/use-start-room.ts | 17 + .../ai-node-sdk/client/src/index.css | 39 + .../ai-node-sdk/client/src/lib/agent-api.ts | 62 + .../ai-node-sdk/client/src/lib/cn.ts | 6 + .../ai-node-sdk/client/src/lib/room-names.ts | 18 + .../ai-node-sdk/client/src/lib/sse-parser.ts | 45 + .../ai-node-sdk/client/src/main.tsx | 29 + .../ai-node-sdk/client/src/pages/landing.tsx | 41 + .../ai-node-sdk/client/src/pages/room.tsx | 58 + .../ai-node-sdk/client/src/types/agent.ts | 47 + .../ai-node-sdk/client/src/types/room.ts | 17 + .../ai-node-sdk/client/src/vite-env.d.ts | 1 + .../ai-node-sdk/client/tsconfig.app.json | 25 + .../ai-node-sdk/client/tsconfig.json | 4 + .../ai-node-sdk/client/vite.config.ts | 16 + .../ai-node-sdk/server/Dockerfile | 7 + .../ai-node-sdk/server/package.json | 25 + .../ai-node-sdk/server/src/agent/runner.ts | 155 ++ .../ai-node-sdk/server/src/agent/tools.ts | 21 + .../ai-node-sdk/server/src/index.ts | 36 + .../ai-node-sdk/server/src/routes/rooms.ts | 133 + .../server/src/runtime/room-manager.ts | 221 ++ .../ai-node-sdk/server/src/superdoc/editor.ts | 60 + .../ai-node-sdk/server/tsconfig.json | 12 + pnpm-lock.yaml | 2189 ++++++++--------- pnpm-workspace.yaml | 1 + 66 files changed, 4611 insertions(+), 1180 deletions(-) create mode 100644 examples/collaboration/ai-node-sdk/.env.example create mode 100644 examples/collaboration/ai-node-sdk/Makefile create mode 100644 examples/collaboration/ai-node-sdk/README.md create mode 100644 examples/collaboration/ai-node-sdk/client/index.html create mode 100644 examples/collaboration/ai-node-sdk/client/package.json create mode 100644 examples/collaboration/ai-node-sdk/client/public/blank.docx create mode 100644 examples/collaboration/ai-node-sdk/client/public/sample.docx create mode 100644 examples/collaboration/ai-node-sdk/client/src/App.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/chat/chat-input.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/chat/chat-sidebar.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/chat/edit-mode-toggle.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/chat/message-bubble.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/chat/message-list.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/chat/model-selector.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/chat/suggestion-chips.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/editor/editor-layout.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/editor/editor-workspace.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/editor/room-header.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/landing/create-room-form.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/landing/join-room-form.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/shared/json-modal-manager.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/shared/json-modal.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/shared/json-viewer.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/shared/sidebar-toggle.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/tool-logs/copy-traces-button.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/tool-logs/tool-call-entry.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/tool-logs/tool-logs-sidebar.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/tool-logs/trace-group.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/tool-logs/turn-group.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/ui/badge.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/ui/button.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/ui/card.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/ui/collapsible.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/ui/input.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/ui/label.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/ui/select.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/components/ui/tabs.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/hooks/use-agent-stream.ts create mode 100644 examples/collaboration/ai-node-sdk/client/src/hooks/use-room-status.ts create mode 100644 examples/collaboration/ai-node-sdk/client/src/hooks/use-send-message.ts create mode 100644 examples/collaboration/ai-node-sdk/client/src/hooks/use-start-room.ts create mode 100644 examples/collaboration/ai-node-sdk/client/src/index.css create mode 100644 examples/collaboration/ai-node-sdk/client/src/lib/agent-api.ts create mode 100644 examples/collaboration/ai-node-sdk/client/src/lib/cn.ts create mode 100644 examples/collaboration/ai-node-sdk/client/src/lib/room-names.ts create mode 100644 examples/collaboration/ai-node-sdk/client/src/lib/sse-parser.ts create mode 100644 examples/collaboration/ai-node-sdk/client/src/main.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/pages/landing.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/pages/room.tsx create mode 100644 examples/collaboration/ai-node-sdk/client/src/types/agent.ts create mode 100644 examples/collaboration/ai-node-sdk/client/src/types/room.ts create mode 100644 examples/collaboration/ai-node-sdk/client/src/vite-env.d.ts create mode 100644 examples/collaboration/ai-node-sdk/client/tsconfig.app.json create mode 100644 examples/collaboration/ai-node-sdk/client/tsconfig.json create mode 100644 examples/collaboration/ai-node-sdk/client/vite.config.ts create mode 100644 examples/collaboration/ai-node-sdk/server/Dockerfile create mode 100644 examples/collaboration/ai-node-sdk/server/package.json create mode 100644 examples/collaboration/ai-node-sdk/server/src/agent/runner.ts create mode 100644 examples/collaboration/ai-node-sdk/server/src/agent/tools.ts create mode 100644 examples/collaboration/ai-node-sdk/server/src/index.ts create mode 100644 examples/collaboration/ai-node-sdk/server/src/routes/rooms.ts create mode 100644 examples/collaboration/ai-node-sdk/server/src/runtime/room-manager.ts create mode 100644 examples/collaboration/ai-node-sdk/server/src/superdoc/editor.ts create mode 100644 examples/collaboration/ai-node-sdk/server/tsconfig.json diff --git a/examples/collaboration/ai-node-sdk/.env.example b/examples/collaboration/ai-node-sdk/.env.example new file mode 100644 index 0000000000..3103e1b6d9 --- /dev/null +++ b/examples/collaboration/ai-node-sdk/.env.example @@ -0,0 +1 @@ +OPENAI_API_KEY=sk-your-key-here diff --git a/examples/collaboration/ai-node-sdk/Makefile b/examples/collaboration/ai-node-sdk/Makefile new file mode 100644 index 0000000000..e573c06e49 --- /dev/null +++ b/examples/collaboration/ai-node-sdk/Makefile @@ -0,0 +1,144 @@ +.PHONY: install dev dev-local dev-server dev-client link-local-sdk rebuild-local-sdk kill clean help + +# ─── Config ─────────────────────────────────────────────────────────────────── + +PNPM := pnpm +ROOT := $(shell cd ../../.. && pwd) +SDK_SRC := $(ROOT)/packages/sdk/langs/node +CLI_SRC := $(ROOT)/apps/cli +CLI_ARTIFACT = $(CLI_SRC)/artifacts/$(CLI_TARGET)/$(CLI_BINARY) + +# Platform detection for CLI binary +UNAME_S := $(shell uname -s) +UNAME_M := $(shell uname -m) +ifeq ($(UNAME_S),Darwin) + ifeq ($(UNAME_M),arm64) + CLI_TARGET := darwin-arm64 + else + CLI_TARGET := darwin-x64 + endif +else ifeq ($(UNAME_S),Linux) + ifeq ($(UNAME_M),aarch64) + CLI_TARGET := linux-arm64 + else + CLI_TARGET := linux-x64 + endif +endif +CLI_BINARY := superdoc +CLI_PKG := @superdoc-dev/sdk-$(CLI_TARGET) + +# ─── Default ────────────────────────────────────────────────────────────────── + +help: ## Show this help + @echo "" + @echo " SuperDoc AI Agent Example" + @echo " ─────────────────────────" + @echo "" + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ + awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-16s\033[0m %s\n", $$1, $$2}' + @echo "" + +# ─── Setup ──────────────────────────────────────────────────────────────────── + +install: check-env ## Install all dependencies (SDK from npm) + @echo "Installing server dependencies..." + @cd server && npm install + @echo "Installing client dependencies..." + @cd client && $(PNPM) install + @echo "" + @echo "✓ Dependencies installed. Run 'make dev' to start." + +check-env: + @if [ ! -f .env ]; then \ + cp .env.example .env; \ + echo ""; \ + echo " ⚠ Created .env from template. Add your OpenAI API key:"; \ + echo " OPENAI_API_KEY=sk-..."; \ + echo ""; \ + exit 1; \ + fi + @grep -q "OPENAI_API_KEY=sk-" .env 2>/dev/null || { \ + echo " ⚠ OPENAI_API_KEY not set in .env"; \ + exit 1; \ + } + +# ─── Development ────────────────────────────────────────────────────────────── + +kill: ## Kill any running instances + @-pkill -f "y-websocket" 2>/dev/null || true + @-pkill -f "tsx watch.*ai-node-sdk" 2>/dev/null || true + @-pkill -f "vite.*ai-node-sdk" 2>/dev/null || true + @-pkill -f "superdoc.*host" 2>/dev/null || true + @sleep 1 + +dev: check-env kill ## Start with npm SDK (default) + @echo "" + @echo " Server → http://localhost:8090 + ws://localhost:8081" + @echo " Client → http://localhost:5173" + @echo "" + @npx concurrently -k \ + -n SERVER,CLIENT \ + -c magenta,green \ + "cd server && npm run dev" \ + "cd client && $(PNPM) run dev" + +dev-local: check-env kill link-local-sdk ## Start with local SDK (built from monorepo) + @echo "" + @echo " Server → http://localhost:8090 + ws://localhost:8081 (local SDK)" + @echo " Client → http://localhost:5173" + @echo "" + @npx concurrently -k \ + -n SERVER,CLIENT \ + -c magenta,green \ + "cd server && npm run dev" \ + "cd client && $(PNPM) run dev" + +dev-server: check-env ## Start server only + cd server && npm run dev + +dev-client: ## Start client only + cd client && $(PNPM) run dev + +# ─── Local SDK ──────────────────────────────────────────────────────────────── + +link-local-sdk: ## Build and link local SuperDoc SDK + CLI + @echo "Linking local SuperDoc SDK ($(CLI_TARGET))..." + @# 1. Build CLI native binary if not already built + @if [ ! -f $(CLI_ARTIFACT) ]; then \ + echo " Building CLI binary..."; \ + cd $(ROOT) && $(PNPM) --filter @superdoc-dev/cli run build:native:host; \ + else \ + echo " CLI binary found"; \ + fi + @# 2. Ensure server node_modules exists + @if [ ! -d server/node_modules ]; then \ + echo " Installing server deps first..."; \ + cd server && npm install; \ + fi + @# 3. Replace npm SDK with symlink to workspace source + @rm -rf server/node_modules/@superdoc-dev/sdk + @ln -sf $(SDK_SRC) server/node_modules/@superdoc-dev/sdk + @echo " ✓ Linked SDK → $(SDK_SRC)" + @# 4. Place CLI binary where the workspace SDK can find it via require.resolve + @# Node follows the symlink real path, so the binary must be in the + @# workspace SDK's own node_modules, not the server's. + @mkdir -p $(SDK_SRC)/node_modules/$(CLI_PKG)/bin + @cp $(CLI_ARTIFACT) $(SDK_SRC)/node_modules/$(CLI_PKG)/bin/$(CLI_BINARY) + @chmod +x $(SDK_SRC)/node_modules/$(CLI_PKG)/bin/$(CLI_BINARY) + @echo " ✓ Linked CLI binary" + @echo "✓ Local SDK ready" + +rebuild-local-sdk: ## Rebuild CLI binary and re-link + @echo "Rebuilding CLI binary..." + @cd $(ROOT) && $(PNPM) --filter @superdoc-dev/cli run build:native:host + @mkdir -p $(SDK_SRC)/node_modules/$(CLI_PKG)/bin + @cp $(CLI_ARTIFACT) $(SDK_SRC)/node_modules/$(CLI_PKG)/bin/$(CLI_BINARY) + @chmod +x $(SDK_SRC)/node_modules/$(CLI_PKG)/bin/$(CLI_BINARY) + @echo "✓ CLI binary updated" + +# ─── Cleanup ────────────────────────────────────────────────────────────────── + +clean: ## Remove node_modules and build artifacts + rm -rf server/node_modules client/node_modules + rm -rf client/dist + @echo "✓ Cleaned" diff --git a/examples/collaboration/ai-node-sdk/README.md b/examples/collaboration/ai-node-sdk/README.md new file mode 100644 index 0000000000..c9d4e242f0 --- /dev/null +++ b/examples/collaboration/ai-node-sdk/README.md @@ -0,0 +1,196 @@ +# SuperDoc AI Agent Example + +Real-time collaborative document editing with an AI agent. You upload a `.docx` file, the AI edits it through SuperDoc's tool system, and every change appears live in your browser via Y.js CRDT sync. + +## How It Works + +There are two processes. The **client** is a React app that renders the SuperDoc editor and a chat interface. The **server** runs the AI agent (OpenAI function calling loop) and a Y.js WebSocket relay. Both connect to the same Y.js collaboration room, so edits made by the AI agent appear instantly in the browser. + +``` +You (browser) Server +┌──────────────────────┐ ┌────────────────────────────┐ +│ │ │ │ +│ SuperDoc Editor │◄── Y.js CRDT ──► │ y-websocket (port 8081) │ +│ (renders document) │ (WebSocket) │ (syncs Y.js state) │ +│ │ │ │ +│ Chat + Tool Logs │── HTTP / SSE ──► │ Agent API (port 8090) │ +│ (sends prompts, │ │ ├─ OpenAI streaming │ +│ shows tool calls) │ │ ├─ SuperDoc SDK │ +│ │ │ └─ Room manager │ +└──────────────────────┘ └────────────────────────────┘ + port 5173 │ + ▼ + OpenAI API +``` + +**The data flow for a single prompt:** + +1. You type "Make the title bold" in the chat sidebar +2. The client sends the prompt to the agent API via `POST /v1/rooms/:id/messages` +3. The agent server builds a message array (system prompt + conversation history + your prompt) and calls the OpenAI API with SuperDoc tool definitions +4. OpenAI responds with tool calls (e.g., `superdoc_search` to find the title, then `superdoc_format` to bold it) +5. The agent executes each tool call against the SuperDoc SDK, which modifies the document via ProseMirror +6. ProseMirror changes propagate through `y-prosemirror` to the Y.js document +7. The y-websocket server relays the Y.js update to the browser +8. The browser's Y.js provider receives the update, applies it to its local Y.Doc, and SuperDoc re-renders +9. Meanwhile, each tool call and token is streamed back to the chat UI via Server-Sent Events + +## Quick Start + +Prerequisites: Node.js 22+, pnpm (for client), an OpenAI API key. + +```bash +# 1. Install dependencies +make install + +# 2. Add your OpenAI API key +# (make install creates .env from template if missing) +echo "OPENAI_API_KEY=sk-..." > .env + +# 3. Start everything +make dev +``` + +Open [http://localhost:5173](http://localhost:5173). Upload a `.docx` file (or click "Use sample document"), then chat with the AI to edit it. + +## Project Structure + +``` +ai-node-sdk/ +├── .env Your OpenAI API key (git-ignored) +├── .env.example Template +├── Makefile All dev commands +│ +├── client/ React frontend (Vite, port 5173) +│ ├── src/ +│ │ ├── pages/ +│ │ │ ├── landing.tsx Create/join room form +│ │ │ └── room.tsx Three-panel editor view +│ │ ├── components/ +│ │ │ ├── editor/ +│ │ │ │ ├── editor-workspace.tsx SuperDoc + Y.js provider wiring +│ │ │ │ ├── editor-layout.tsx Three-panel layout (tools | editor | chat) +│ │ │ │ └── room-header.tsx Room ID, connection status +│ │ │ ├── chat/ +│ │ │ │ ├── chat-sidebar.tsx Chat container, model/mode controls +│ │ │ │ ├── chat-input.tsx Input with inline suggestions +│ │ │ │ ├── message-bubble.tsx User/assistant message rendering +│ │ │ │ └── suggestion-chips.tsx Prompt suggestions +│ │ │ ├── tool-logs/ +│ │ │ │ ├── tool-logs-sidebar.tsx Trace list container +│ │ │ │ ├── trace-group.tsx One trace per prompt +│ │ │ │ └── tool-call-entry.tsx Single tool call with I/O +│ │ │ └── shared/ +│ │ │ ├── json-viewer.tsx Inline JSON display +│ │ │ ├── json-modal.tsx Draggable/resizable JSON window +│ │ │ └── json-modal-manager.tsx Multi-instance modal system +│ │ ├── hooks/ +│ │ │ ├── use-agent-stream.ts SSE consumer, manages traces +│ │ │ ├── use-start-room.ts TanStack mutation for room creation +│ │ │ ├── use-room-status.ts TanStack query, polls agent readiness +│ │ │ └── use-send-message.ts TanStack mutation for chat messages +│ │ ├── lib/ +│ │ │ ├── agent-api.ts Fetch wrappers for all server endpoints +│ │ │ ├── sse-parser.ts Async generator for SSE streams +│ │ │ └── room-names.ts Random room name generator +│ │ └── types/ +│ │ ├── agent.ts SSE events, Trace, ToolCallEntry, ChatMessage +│ │ └── room.ts RoomStatus, RoomConfig +│ └── package.json +│ +└── server/ Agent + collab server (Fastify, ports 8090 + 8081) + ├── src/ + │ ├── index.ts Fastify app, CORS, route registration + │ ├── routes/ + │ │ └── rooms.ts REST endpoints + SSE streaming + │ ├── agent/ + │ │ ├── runner.ts OpenAI streaming loop (async generator) + │ │ └── tools.ts chooseTools + dispatchSuperDocTool wrappers + │ ├── runtime/ + │ │ └── room-manager.ts Multi-room state, conversation history, SSE dispatch + │ └── superdoc/ + │ └── editor.ts SDK client lifecycle (create/dispose) + └── package.json +``` + +## How the Pieces Connect + +### Room creation + +When you click "Create Room", the client sends a `POST /v1/rooms/:roomId/start` request (with the uploaded file as multipart form data). The server saves the file to a temp directory, then boots a SuperDoc SDK client: + +``` +client.open({ doc: '/tmp/room.docx', collaboration: { url: 'ws://localhost:8081', documentId: roomId } }) +``` + +This spawns a headless SuperDoc CLI process that opens the document and connects to the y-websocket room. The CLI's `y-prosemirror` plugin syncs the ProseMirror document state into the Y.js room. Once this completes, `agentReady` becomes `true`. + +The browser polls `GET /v1/rooms/:roomId/status` every second. When `agentReady` is true, the room page renders the editor. The `EditorWorkspace` component creates a `Y.Doc` + `WebsocketProvider` (cached at module level to survive HMR), waits for the `sync` event, then renders `` with the synced Y.Doc. + +### Chat and streaming + +When you send a message, the client calls `POST /v1/rooms/:roomId/messages` which returns a `messageId`. The client immediately opens an SSE stream at `GET /v1/rooms/:roomId/messages/:messageId/stream`. + +The server fires the OpenAI streaming loop (`runner.ts`) as an async generator. Each event (token, tool_call_start, tool_call_end, done) is yielded, pushed to SSE subscribers, and written to the HTTP response as `data: {...}\n\n` lines. + +The client's `useAgentStream` hook parses these events and updates React state: tokens accumulate into the chat bubble, tool calls populate the trace in the left sidebar. + +### Tool execution + +The runner loads all SuperDoc tool definitions via `chooseTools({ provider: 'openai' })` and sends them with the OpenAI request. When OpenAI responds with tool calls, the runner: + +1. Assembles streaming tool call deltas (OpenAI splits function arguments across multiple chunks) +2. Parses the accumulated JSON arguments +3. Dispatches each call via `dispatchSuperDocTool(documentHandle, toolName, args)` +4. The SDK validates the args against the tool schema, routes to the correct document API operation, and executes it +5. The result is sent back to OpenAI as a tool response for the next turn + +This continues for up to 15 turns until OpenAI responds without tool calls (just text). + +### Y.js collaboration + +Both the browser and the SDK use the same `y-websocket` protocol to connect to port 8081. The y-websocket server is a standard Y.js relay: it maintains Y.Doc state per room in memory, syncs new clients on connect, and broadcasts updates between peers. No persistence. Rooms are ephemeral and lost on server restart. + +The browser creates its Y.Doc and provider at module level (not inside a React effect) so they survive Vite HMR. This means you can edit frontend code without losing the document state. + +## Commands + +| Command | What it does | +|---------|-------------| +| `make install` | Install server deps (npm) and client deps (pnpm) | +| `make dev` | Start server + client using the published npm SDK | +| `make dev-local` | Start using the local monorepo SDK (builds CLI binary if needed) | +| `make dev-server` | Start server only | +| `make dev-client` | Start client only | +| `make rebuild-local-sdk` | Rebuild the CLI binary after changes to `apps/cli/` | +| `make kill` | Kill any running instances | +| `make clean` | Remove all node_modules | +| `make help` | Show all commands | + +### Local SDK development + +`make dev-local` symlinks `server/node_modules/@superdoc-dev/sdk` to the workspace source at `packages/sdk/langs/node/` and copies the locally-built CLI binary. Changes to the SDK source are picked up immediately (symlink). Changes to the CLI require `make rebuild-local-sdk`. + +## Server API + +| Method | Path | Purpose | +|--------|------|---------| +| `POST` | `/v1/rooms/:roomId/start` | Create room, upload file, boot SDK client | +| `GET` | `/v1/rooms/:roomId/status` | Room status (agentReady, model, mode) | +| `POST` | `/v1/rooms/:roomId/messages` | Send prompt, returns messageId | +| `GET` | `/v1/rooms/:roomId/messages/:id/stream` | SSE stream of execution events | +| `POST` | `/v1/rooms/:roomId/messages/:id/cancel` | Abort active execution | +| `POST` | `/v1/rooms/:roomId/settings` | Update model or edit mode | +| `POST` | `/v1/rooms/:roomId/stop` | Dispose SDK client, clean up room | + +## Technologies + +| Layer | Technology | Purpose | +|-------|-----------|---------| +| Editor | `@superdoc-dev/react` | SuperDoc React wrapper | +| Collaboration | `yjs` + `y-websocket` | CRDT sync between browser and agent | +| AI | `openai` (streaming) | Chat completions with function calling | +| SDK | `@superdoc-dev/sdk` | Document operations via tool dispatch | +| Frontend | React 19, Vite, Tailwind v4, shadcn/ui | UI framework | +| API calls | TanStack Query | Mutations and polling | +| Server | Fastify | HTTP server with SSE | diff --git a/examples/collaboration/ai-node-sdk/client/index.html b/examples/collaboration/ai-node-sdk/client/index.html new file mode 100644 index 0000000000..760cf42db0 --- /dev/null +++ b/examples/collaboration/ai-node-sdk/client/index.html @@ -0,0 +1,12 @@ + + + + + + SuperDoc AI Agent Example + + +
+ + + diff --git a/examples/collaboration/ai-node-sdk/client/package.json b/examples/collaboration/ai-node-sdk/client/package.json new file mode 100644 index 0000000000..df3b049d86 --- /dev/null +++ b/examples/collaboration/ai-node-sdk/client/package.json @@ -0,0 +1,41 @@ +{ + "name": "ai-node-sdk-client", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@radix-ui/react-collapsible": "^1.1.0", + "@radix-ui/react-scroll-area": "^1.2.0", + "@radix-ui/react-select": "^2.1.0", + "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-tabs": "^1.1.0", + "@radix-ui/react-tooltip": "^1.1.0", + "@superdoc-dev/react": "^1.0.0-rc.1", + "@tanstack/react-query": "^5.0.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.0.0", + "lucide-react": "^0.400.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-markdown": "^9.0.0", + "react-router-dom": "^7.0.0", + "tailwind-merge": "^2.0.0", + "y-websocket": "^2.1.0", + "yjs": "13.6.19" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.0.0", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^4.3.0", + "tailwindcss": "^4.0.0", + "typescript": "~5.5.0", + "vite": "^5.4.0" + } +} diff --git a/examples/collaboration/ai-node-sdk/client/public/blank.docx b/examples/collaboration/ai-node-sdk/client/public/blank.docx new file mode 100644 index 0000000000000000000000000000000000000000..7deeb3f0c037df43e46dc1b2dbb376e564563dd2 GIT binary patch literal 13705 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 V<|&4LC>=2X#ZQqw$ok{x{{bLlgAD)x literal 0 HcmV?d00001 diff --git a/examples/collaboration/ai-node-sdk/client/public/sample.docx b/examples/collaboration/ai-node-sdk/client/public/sample.docx new file mode 100644 index 0000000000000000000000000000000000000000..3dfdba3cb2e7458c789c2e8ff29569de4a8af4bc GIT binary patch literal 123260 zcmeHwTa4^lT3!z`49WoFPPofyq0x-8yX#)n)pYl$yQ*vU=Ik50`<#Pj7)GutSC>z_ z>>AtEwR%C=YyJQ8w?6)fPwmjpum9%HfAKed=udw2kG^eZhkm~g z*S^?uY~Qf`FJIoy4ev|)FK5=#=kSkqW4NB_*vGrI{pzk}*du3b+E>TBZ(k1f4t6!q z*X^-xIks`Uduw>RpF8=^PaQEB8d}@l@$S_3=ZBSwH<}tV-P?EOhK)ND$DQduzPeYH zxjwqquZ&8)T5VTGydQf$^<($ssBcX4h2?AKFVQ{T6W6f3T}^bD-gUgI&*zpo(tY%_ za$}EUZ`l)X*hfqDj5jss-akb*b}NZ*pgZX=5bd5}YFu+{XwP-mf2z;Wjmpw-$Ca@& zTFfw)G>I8t68h;(Cg#Wp+7q<7>x>M~!<^5o{ou|_H*MMf)PC5D+0by&viOb!pzrL2 z=igd}S9}jR+`C_I_&#Rfb#y>LzOxHUV|ek}dJzJCXGbQEj$;ogG8Piu5TK_3X&v&gEwMn+IpT1TKvYwIN{wDw%DFL zkF4%L@moLgr%%6SXNP{j9jp77Y00e6^5<>7s=o*?o*S<2kp&p5dl;tnXnefuJ{mW6 zHNL3dtvT@ZvM<(Ku0TXyQAwCNfY;qC!$00ta0G22sYmtodlb=SqFtF8zCPA{ozY+j zlL`F^s5GTRwe>r6_Y_5+SoKELWzd^Scz(PX*?sNslbye|cXsIadq8#ygbj)BXn6=! zF`bIj-QjXRQZ&n%IdUD(nfUu7XI9~(;tE;4TC1{8D`l#u+c!G2NT_JGcQ|^v9<;Hm zFQH9<&}z-fXbQd0c)5a6%MGMe=~fO@K=lm(VTARX3aXJCRJ%gGQU=%D2oQRuKx%CU zDPeH!%^=m)K6N&O)KDQEYz9dorDU1fqOxF>iQw)Rq-ciVOZ7jSW3DE)wx$e}KxAh^9T_ha>;&wYu$0ytvL6Jq)*dfH zu)MK9p5_C`S7xA_+Cn{=>R!M!%UT;(Cu<4pQs_L97DIeG@S8x1u?=5y6?mqinbdUY|? z=f;M|_xA^kKZvNF>5mSRM|Y z@h$zGYs*7;CC4v>bMSb#Dt>m+q#e#;WFMLPbHf;>*&@v`4 zFyJvIof$pmFd1N%e;zrO<4W*d_9Gy;16a`>Zt3301Xa9nhK}!OkIkzoR=DM%p?m(R zXX@&m=_y>K>g5rz83n=z@=CtG0SkwBRCLZidG5mNsKJ84+YB0l&jx}K&~S2Lq1S1) z2L0x}#KMr{G=dCHOPR<>LIYikAb>8cre47Ff=O>;Mq-oxP&6EK&ww>`sM-8jcW3Oc3>kg_1zdbQr% ztJU}F)yr!0uwFf^R=>dLKTM?eX?if;ORzBMNsI?EhB=7TaBqy=6RrQO_p?Nr;;9g^ z;tG-LeH~WXfFe8xJliA@2-`6JKLXhHPvF|tY)1H+wEiP=0%T)S-bBzrxfL%7%!ornAl1Hl9~kMBxO9<&t~jL@}H!m zX)nN&P=JSqHa00jj{N{BGZ6Io$&&jlB6z9hE^c7NrR;YjqB<&JjKkR)I-bxTCnqf4@4KEKj0~7U4Iv-uqMC z*ARuh!7}FI1ET;#XpziS%LrgG2Q`?px#RkX?9d+&%ovO0+*x8jBHU8Cwdb2N=9 ziDU0;4;@Amt3Ftcb4_G4VX7+u5n3#*$uD7dVL_gv5y*x=$`)q+YEU!Co4?-}Z@03x zd$rm@vyL5;Z{*6_=~O%C_3q%FbU(VX=5|sAhEcJ$l7I5<^cE^A{J#bSE=eOFi|6O! zYfGw5lcbVWn+N^#Mz3>EWOJc=}X;Z z<`S)q*ivCxhJ6JQsw0L3p*Ey#z9egfbd$zZuu#LqxFyeWg2|vkGk_@;q0+Fwu?5_1 zX^Y-h??#F)H6slQrfFnKR%ZH}unL<9AdR5FIWt->iFSk@Wf@n{hDasj+K~wtWbhm* zU8G7~IoiZ^W~*fs+XE&(zvr1(Ha_W|_LYS>x+dDhO738bI)Z!;VAz_YDHdqlgmWG) zA*|IiEWSjXpk2I9oG5@DjD7#O{DACNs08R1qL9}U3+^_y+(Y*?t|;{3!1oOumPlXh z;M!MklS`;}PWzo!|KRMNNTs|&wb7{ePCIA)d(!>;CR9&gez47gU;)?}Hq<+~jsl&I zX_8E-1Q{<)e+r_4Zw4W0zFB}YP)5gaYC=IULE*yX`5>%rt_YXYFc~$70%Ok)nKHtK zEXb7@Vc{}SE%*R$lQP=VK4a`(?LW{ibexnxA0Uhua|+VI)ERM6xI^y(9V0t2u9C}o6wWl0!%o=ZspH1-X|~j44d8qKGlY|D@!dd=5n!8t5HAe z_d53_@{pI6TFtX&zkW(?==-Oi+#kjEEg0P7do^5g+pZt0O44W>2i4j^zuvtkQ=XS% z>gU~B?Yz^wC*6+fPE| zyG5$>{Sz}Eycu-z$fia3#&i}?{d^ye9xQEe6_NeS{C)6B{=Qr=MKr|w=2yQ#%OClY zU;#m6hk{4}b@G5x7?(LP7g%Yb1duN2+T;hM4{%hPSYO40PhOsfmrov37wDV~TcRE2 z57I328tp@2PSPIm9-Bem)BQbs*+V1Eqkl+6br$}7!91r9e=~wu9vodb5sJ>)QvIck zD>&>a6lRzlSkw{b0)UkoBGm}EOwo1ei3&7_2O4%~$?h((D~vRB@`_O>NtY&F-kZbc zN*8db1bPm0kCOJWlIGiawrXe9UbjEEFBX1Y&TO978s~$4$(gjvG0)BkMyaNY7y*&o zefOygmkNbVBkNFf`TXD|VTw;(MpdM|gP?F1Fia44*%N!DB5@gbv0?HXI;;S)U10nO zkw@k_WWgB5IrDvcI>IC*6dfjd;1I`Rt-+;)@ZT*7LI##?@VM9Wc0%DV4ckkwPm+9L z_qwwwNH$)M4D#zCM5ZWDbctbzo3Xm>?*Wf{_Ckj~j<}kPma)hPZRQRZ3Ga~BHMZIS zofZ}%tf(OL#mvSB78VgZnjdKV0JB%&2Z?FrrJdXCc@PjbCBs((>LJ52x@bh%=-${Z zDHEL*CF1*=G9yEB4UP^!YtczEf!h7^=D}(AzHEuk>VDEbi%#RT)odNyPyf^XF@erV z5bcrMeGhK;J#yucjtJh9d%7JvBB!$OkVHoHcKftmy*K9@vbvu{My+b64b|&@lF@xt z1)kBSjX5_AU?5E>{KH(1Z-@r=X&teGpL!#euvK&d*#k6vhLl4SQ~HoSW3+Ig22Wsy zJxJT207YwLEtthdii-3rb1yVP9rnV~mAzQ^E8KK~jbSqr(H@6FIuY>|RRZoS12GMT zdCP%1L{ce?`XKNR>^bfp<&0py0=N=L>%ll5!1!kQr+_r+O4viJ^%j`EF=;Y1u}v;b zL&_44NwU4u@AvwHIvwq~4<4he?kCCiTEBhJ@AgWwI*(a>3Fi;nEVqPy59-vliG^Kq zP{DbKl*~D1*m3iYpIv~uI>Bi%iaIejEA$K6X@`gxTwj1eNin>@-Q%-}5~(4=b4Jl& zrj*zd^J*cYtq-vMjI51YZ3Kftbj8J9Y&7I#PhK``Lx!!wwsfHrcyLUyvbnXmx+1fI zTa^?_7n%=t@Q!$wAq7wmx!X+_|%h%qa|V{AtacoEY=TmMY^#v%V1g2(tA z3Z8wIMg7owY%%2FJIjDkhzxVgfC_dSvd|wMLr9u-MX-ZpIORcSkcT+)$QgMh?GVB< z{Kb4CZs8{KaIz8s5q zGxV%WxtPI9ksI2U?0lGo#U(;cYn(SY_^_Ne2yO1B6$FbX5*j4 z=_l82p5{TTUOOMWsT<>Jwa!_q*}gAZOYWPXK4GU3In6?u}FLWAYD1<@Y@QQNu1n~gRR-hDw`UKOD>XtX=n<#A8U^(f`tn|RF0 zr7@b?Od?-C?!Q=DR3#~8)%JPstkuqOFaq1yDQnPkoMfz?H97|a!WK^f^c;y(s?`<( z8{J+w3D7pVeo|p4B><`o>J2&_#8Mf=69AneySagU`fiE&G0kKdpcQALJJeIZJr~C`)y%m!T4je%@ZAcb}Me&-Z`k9=E<~E66i;RKu@J-Q+RiU$CKQtq^`nh zT}72xy85l?u+!|Gw_3d%5xtTQKN@s6V5+HpgRHk~GXmSvt|5`~6m%F5Ki%orP&_h4 zxGzqgQKFxV#6&-WOkXIDDdGEgEgeePE-j)p+GkEb|NQYy9nJdtV6>$d82o9EqnCr4cM|Mq5}W=PyXM3`1;m;FJ%3c z+e-F$E(?|%4r-@NsZCLM#5QRQZ{Ge!HZNz#W{Ma|3X#wPMZwizXG5^)M#dvo0__SSe91e%|YaA@Vvv;8WRM6vpF4cXzcQ-zP$4EHuSWhON`0#*1Gdh3nM? z)jU`tbA7$uWVH%VBBs_lpwA5G{OSp|z2oK195pR2{rMmM?l1i?>MGOkkI6E4yac0cK@}mlDaRNoQ|J--Y*1=BQl1b|&v0o! zS&R`O$>NGJ23wg{MFy!#jYs97Mb(OZ$n}c6{R9cvk9W_-c6^4Rq&^l}FcSMBC_sbK zfU-)Yyuzz^f*O+gfH3s?GEd9pavy$4suDu}NrM$=l6_rszG_I;Q(R{upk_#`D`$&+ zjns8bnXy7U!K*>9dcnVEVhkK#+$03`uvc9OE@k!txvGon1>!EOw(_bI@=9hOD6~>s zCxQ~dt6l_`GP{AZB1QH>)VdD$B2xZ3g)C{=Dz+O`g-3D+UzkL}t zMWTf+W?}@3esMkFOY~|g`1jRRWLB1a_NBl2#tfB=>Gyl(l1h^q)DqvYwCs0&3Z;Pp zKzt!BtIJ}0Zbejtq*}MFN?BcYrhEH|CGbM?M5S|UWp&x4I?Rz-Dyz$yb10a+;A>f3 zHde2;tS+0QbZ1Q#bSzbI@f`(uy4-x`=nbn$Y`tqtUH54%SIgyMFHzdyzGg(6GFi zzw1@woj<#RVotx`BbD>8<++V+F5#4_xihQq((0vZzGl($h|*cA=Iaa(Jkq?pG$oTw4Y&L`>Ro!V)uf3{W;nf3dg z*o%yDKrNRVa!f0KF#LnvU;EU~4*h<&)XGCn_YIYD%-nSB1|&Gzjs$VU=td7*VWTw# zY)G$bR*=HYMZt5)6{DB6^|}-S(yDYT2P&ZY27pROdFd$Ur#;~esUo_|Wi<+-U+1Q# zcBRzDOKrT=#;b^_#Z;eC8?QISoUlK&_IM#>&9c_^#{L+4>~biFr8fSd(#Ge|!ztIv zi;x35*bIt%veGkNJMEzM$%bW#H%^WcILe_(#Qfn=>R%|Xc6#V9-72;%v$W zwGp=0TA@kCwAS&>kAK?v!p;u;{($tg#!o_QsJdc@vVO>5NneseJ_+lS@NUj5zBJ9? zfZEk;eFl1YHknY~{7ZIj<3s{Kx7a~Bk1mWX_X5?XQAjeS#rV2L&w1|EuxFv7I~6$) zxy8s=tsja9EMI+Yz zX|LCgJkK8D&$pH52c2%a8GW8TG)39BYvpOe;9wx22aik~>tW*KgF)!=)lf zI{cAMO*8#HhaGOE$59vp)f{Md*MuFxduUiUhL4n?+EZg;Q0H`{zP#gs5mMV`KtLBG z@0^+T``>}pJJFrhB(W)*-7#aR$7o&nx0dnP^Qi%9TA1SjF0wC-bpyVfPw`P8HS!$N z2(dPr>-dzQn(fr1laK`D$`hckP-5OepphbAcu^8;x&fs5Tn@B|j5wY=-N%tMez`%H z*>wyz0Kt3$!HkoCd&@3FFPt%dtS2l~Z$#wejf9cB!=P@h;6a`xce0LeeCtP4qV1noo5hEhSB$&qB*${1)_qeG7FD&n5Pq4eld7 z6pn{tuyQ~+71Ym>m=7yaED5?AUeU@Orosqk1#2azjQ4vvXM{{+j;*kP^d<_;SQB`A z)?7Xn9tho7=?+av_K_u_+ZEHkVHeg}mO?8KTbR`m*ITl4i6h3vV3mhEb*j-nSQSin zWEpH>pk?OLc>#%|!Cd0=r$KJ)5miBOkl5g#hR_E1MNVr3iZ8c9AD~&2OIX3`Tkzi4 zWK+)q+LxH*or~gm#8h z7fwXq*aUfVd}Dktf9|rs5k(=qCPYl+h%iW5%vEp_L!8&ReJC}|2*eciK|gexk@nB_PnoW(~cSTF30`G`^HeDoZGk9mrOh>*0kdg4qn$mlteI&-g*TyE#1 z)!owxw|W6H;W=@4xPaYz`4Vpd|1K_G1s?|(M)2h+iYBs0Q1lV&G5d%aK;A{|dNDJp z*ajP%hxs6xysJSt<6nMtalC5-0E{@_HLu}Yvz-g}N$9xZ<{Y~u(FRV28A^1%G9I$8 zRAdtNAX>?}qORINre(>wVN;hXCzy~7gmU9ZkHSaA^?ajZn{ zL_8{yJKpUqBlVI-0x9)T z7Fi075Mc-!X_Pcl(gLkuqRW(#TyjQU)wa8o7%`%78^lBX`kA z8L%j6W07PmhQb;%6DJQf%S0|Aajp>44p&s{Tn59% zhyLUPckO%Sxrg}qi1OTnj6|wFIq*s>uSDpe0-A*rN<{9I=N{r@RvyElXma?tUjAb^ zWf%c7fJ1Jj$VwMk3XPOugi_tUOWiKR2qlf&MI&Vxp`?+!Xrv4ylr(Y|jg(=8l1A>L zkur=>(#TyjQic&q8o7%`KDuE95j}u6KusxSy!2fiyL2yDwkPiO#DgpuRV+jGul!Bx zAO7+?c6R7DsL|~iJ~H@RdHX1Cuwiy;lmnDdWWfWqBw#{*>N{&sILEsS*XF6^bZ;-n zkWS?)4tX7H@kb^@#~GJ5wr)eMy2fy+29_Kw@>AVCSZc5;9~R98E^3I@nhKy`s`o?X zVh9vciHl_Pp(3QURz3h_DX&!x9xtncLzT5yNTgFo$d=uw3Z(jolEcpR5#aT3n9X%8`QX@j>i9hr*>O=+ zTQs4HRyK-S(FwLCvVZe$Xkj9&>>kbwF~G6w{Cy~%C9m_=qW){-OB~Xw*e$&v02FD; z>i|)I7M?LUf2`jk$)6Y@D-m?TmkYq=WdV2tlb5?hqHp9uLt8gTc?)X5CbK4y$6?0b zM5*{(b8G+wmccTmQbwc;q*6Pz$3MOBd=n)N5a4qd5;yFE#Af1H4Vzy5426I$kyw6U z=>7ue++x6)Z(}4gu*~@r({&xB45T!DukURp@*ul-g9*NP0!lYsXUV4ep@HP!?rVE7 z=A zdDdw(Btu4TwK|Q{ZciXGdP^33P5^k;=o}1i>@ne1MmPEg)o!6rq`!c+$i+go;58vn>`yz6(9`DNJtZ2+X;wkZg z8u5<}d9AU!2Gxz$i(sx|IW%B(2zlq9|V`ub;*7hd9(d-=z z`t{zqxZeuyxA^^EsGc^v=Y!L;y;i-^-D@|S?Y+}MyT8}3o>zO-cE8!|H-C|}2JuT% zBxd~l=+FJ_`5*t}&JO*4uPo1lbgM(d1rE2fegZJE$QLF1j44KIXw)k;y)23DhYgQV znf7*t3biZs-q*BXVt`=DD3I1PW#W)(Dx|WwrPo*@{RPPEa&h)Y@;s-^;r1x%HopbLt6QYwB@|kWDX;Jh$QWB(>z^} z-zfC$5%-9||8xkG-q&4vgsX*)q-l*1L0}91=Mwatq*qQ>dL!Fj8Pa+b^{WI2x>LqV4y9?j;C>liV3 za!=sCi9gJr1H)r(LGwIq^_tb%**P0B8;pb^8$w|n%mUkYxUeh(<*eA70qhbn1=-@8 zzw`Cg4OnGDm$!_GY{0Tnp%*q8%yj*Dx7~#~1}lRX13-zS1~<>3or|Yk?x|uG|2#aZ zdm|G*qf=y|$LuVz8Qb$uJrgAvf=km=%zNnj2*nk|P1f-tnu&eNd?dpjL5^H9l?&=K zD37JIV^(f2=?2U6ABQ^Tr2yiW;Yy=i|MANPEGSQTr3qgl)zgcOVB}aUi>fxLH|hb& zaK~f3!BSpeRkzqoT^laynMG#?_5Dopw#2V{ujG|FEJse8uU3;5T%5xAWd^W(oR>Xd z4X8xMDQ*V9Wz_=)ko*-y4fqS%BmN4LHMgf3S+|<)(_RBCLeFeX*1w*gtZU6$N!Q5Y zBvH(ndP#L)-Z;8`UG&O*Je*#ut$H87h0yD7|C{{uTCb7ZE#+`Yuj%rYxe~eB(C*dR z=WrtzLa&>s4fTUoNw1}R&C~~&n_H;4?QXr_Juiq}H_!(ftxid=CB0_SD+|GJdTn%i z&9j5S2d57->!n>rCE7}TAYC6|;XzKXy+Nnf>7Nxtubb!tEo?O__1BVKv-|_t4k6uM zXRY&Iw=*~`Mt|KvAHZIal3q*snyC-KTPNxDyxOj|Tm53_brb(U8>O~O`C7`?sCV5t6gY0sW5rOM#AKO zd0Z;CziB!-zxn#tc6R9ZyX5{R7Dn3kXa`jm@rpgzfz8#iaOXBVAj)$PW1Q<4883r_ zA&k(JInLaI)~?X53W8&<4w%%|+`}XeG1LwOkWfd)sE-}Pbyh##u=xGfM;Ndb61!yS zXaV1r{M;2^Ng|{~NiWSA81kvH)Lu9B{m$Z6}x1yAJ!ZrRI9st7ppzV!sf)7LL)>tIQor-JwF?>BN3s4 z7NIU6!Yl>u>gtf~8dtBov?o`+JT&~JVFdBW5FA|@HDoUD5PcAX2zMKoV@O1rF>G39 zD-nft$HwHbGrFeOJ#L6dJubfe=(%e;uIb+%?{={noIQDA%*==87<>Ig586|ldw3Tc z;@|cRu~C7b{>*@i$s^v*w78M8pffOyPMfVJmN!0sIWp!VsLM}lJZ07A=~WAJ^>Wty zD-xL8BajGSio*c3<(Y+L!!TI?^TA-DGA}gVWT1=K=-E^G-o%0&@5`H*d-{EO6LT!S zFK=Qlq4(uY%$R>)-o(tX_vKBDF<$GNu=57T;}~10?@^hDN%utN=73VzGC!acuFDT7 zg{krbO5vIOfKpf@KcEzf&krbtpz{Mtq1QZsd}owKj-geD%D!P8$_qG!Jhum&Lay5b zP9fjz0jH4j_JC8!dwaksHep;P7=$sIuF43mZn|IaL*pVM1a2njr9&hwG`cJ{>>SoQXCu zujI*N^^JK1s$pX{GF&g3J|6Rv>D$s`0MRvYI+`8D-mZ%Qak~aPpgdwH%(sIXqVNKt zvOSRS`N2K6JyFf|D?=*^m^}Gk;9w=lVnj|r+4{ntl1XgxbM@Pyd8UtCXM0rmj;<9Z zEFR-z?DkzEDB79Ww!baQGGI>&qFV+mMMujcnHZcDl`J=$6b&ploD_vCHyn;Rt*B`d z;EI|p0j{V?6X1%PJ5H#D&7A;O)Z7VhMa`W6SHRp|n!d$zvxGDfzP)BW<)dfegou5$ zz3jTcK@gTXWqVMnNKy!+mH-5JZyR*K@Us!jGQ^+TaAuICBx1m00K~j zssBt=QobS6UKF4lMZgutXR?1mw zU>4C&3xTzQ1apw{W_!XO#M9_(5Ap)pt~-7`JvO9V!a@L%5< zEoO*qB5l-s`!PMYkpH6~?49q;bkoubR4yJ~K6$KNBG(@rE)*Nxe!L7K&u>;7P~l7b z%)7?$vjuhW6lSx1ThxG0i*hZo>Fc2kUO~g`iEM@2IT={5pop3_J3n1e-`+BAhmKCE zUbnUGS^u8H^TYNEAcH_bATM-eFDMEXlq_Khw@(qCGdAFNbYv2Mw{-i#3jSiL5VwaG z@;o9p-FwEU0E^7Hk%MriX7SOP3;#1dfPLoUEn|=4$=va%H z?G-v`2C&F6Gk}E;xk$=kJuJYWbvTgH{179`0p4xYQt1kP?`4&#a2 zwlk)A7s=aQs7B7=6^3fKT8dk730R>$D}egWkkj2kF1TVMUMoF?XgKV8q%EN7K{wv+ z5*cy}FyrBC92rx`!bY^TVWsy37Pcts5g$R0_{(E<6a{ri=m13=P8&|x^!M|oBv+Mo z=)hg=NSjdFf#lNLJu${6PDF~na#|1LtqmGmyEP;3NNcRAceZAW2%FtVQ!JqCHC5k= z)$-1!Oz~3RiluSArs`X<4zAafv2A3mnat5g34y@v6K+N+iPGN~n3*Yb*vX`)pmh={ zb}~sSXqrTgolJU)FphRQqKXg+G?_W>6$hmQ$Q(Kc!002j2bmKP=c)95WKKp5Og$aU z`dpR{Ba_`;7&j&@{3Kgq%YHfmGQJM>YsAG;gQ?r=#j}29fnaPLK%MQ^UJt+{C|5R0 zO(g>2nLO45ByhrpmVuD<1yDLd)|W)-FxD4I=`hxlO{wkk38{22nJgQK9EO-QuFWB~ z()*FgvWfCbT`6+PFBL%MWT^5>1+bC)Qo&?SMwGE}xz0c6fZjNbybRl#IV zMhr~AwkjB0NuN^zhG90NEBV=0?MHsLRbk|3TNOrrwpC%|V_T*DW^Aj1$)wbP<-%;M z!pJ1n07jT?RT!C+n#i^wsO?r;6+q@>sBEhO$ef87zXiOag2|kW7?^-GE}xz0c6fZjNbybRl#IVMhr~AE-IM(Y^%ZmrgE~a3IkW}gu$pIV@mR~ zt=f1Xcs{yfzebXqgT>sCY}Q zVovj@%xr+Ka3xnn{#lQmI7>a86gmT$ntf;8!HB~fEF}d)OBhkjOfCpFWk`rL%_RPC zQ#SLFrkOM!ZmKA!%}j|LZmKMh%}hben3PAd*)qkD8p4ApT#lk=N%{Iht!s$(A(x@j z9-N;p!b9!ViOv+H7O+(5Sf%2>Om(R zL?(rXKnRpcmz&BZYvV2*#M($q2eCFb(?R4zYbu-#@S6@RKcdrNZHRG|=W=6Q1(6%$ zDu~<|S3zusaRts67*}C!j&T(huB;_#Vmz+O%G?-NLFC4`3L-bgRS=tDT!FI%##LCG zV_b!`A;#4;E;q(i5V*p_Yn7Yi43I)N&K^D%5;a^C|>lQ}ZeWBBpwQ zYGN1wHKglsAwYqnRt2#(5>su5^|6@_A|F~);bb#uXhK%_O^21qq#;-vjH@7WV_XHX8O9YjTVPy;wK>LBSQ}zo(b}_> z?a)#atm7((+!$9u3TtzWtFSi2I5>J+%}oW78{;a7+!$9uY=&_K z&K4L~VQr3a6;>w3pWvWY^7$a3J5ONqVy3&kR$zj@hq^cQ^#YRFzHK9IzGK}OW3AxP zQVmPu3pGfbICH2%7A`wRWz<;lM?mnAT0ah$V=9hlxd8 z+>%&$(fTA}krJz5Vp*{%M|f1e@oTS_pla(96la$YBSAGJa>E2AE^bLsja2CaQ|EO^ zpEro0_^hWB)LnAu{gF0xsm_IoLtMO@I7U;fpCgf=GG+M`>F9&g%`6#xd@&UdDLLyI z4XKNfT-)v@2aF+QS@mTm%#?mJ4|wLZN>{3#xghOF@5VQ597z8bb@& zrLlUTeluGOxuPDNiSi2vM)}E$E9biWyxioeF8- ztXo1ASxAL|3Pe!ORoui&^C)|xh37lGczawaFaC` z-P&WRXz*3Hu26A!UwVf0W|8R|Fg4-M22<7mgX zP#=mU1WF*UkR-dvx*<{I1*$d`e?4rO_iilkoejvK4%3Fe4 z`_c$gYyN0i_WdC4#QTgy;KEN^SGpxGJy||0s}p;aKvpXzwx&yGExo9 z6>20S7mu2i?VROkfp<+}Tdv5Pp)lezVlzkn7=8{Sz6Oia5ln(914o&9OHfx1M+}vx zV(>By=d(_|-Il&yK@_VMAnsimQ9{L+{zA7zJ~ts;vX+5F2gzL~%?7TORj(QI?FFO1 zHr&9c6*6KZid$IT*er$Z8gcP%E=@);9mHX$UE){{ZtzzYg=i_vaw0n5e$!g{%i_!r zo)0tvK@ZGTf;p3NLFlUZLna&fEp=~XniBJ-y{S_z(sDgBx7DTpNa+YW)re{_FmdtH zwBfrw4G}xwd?{9p3XNP{jAJ>+SJFYB^;f3L&sNI#f|8iy>eGdO~ z1M#Nj+>_9t&fg7<=4S3XBTBk!U(GBI55E#=S=*445q?+RAJLx zuhy#U(+n%L1klO{psoODkBpc3U>pb-6|`J+q&+gBal~dNb1>}y4%w%2K<#`$WM@JE z#*17a>J8Zsn&n!1ya>Va#{PJk51hnNh1%-Aj#6IJFhmf1o>^+i-g&n(n(x`@@X-~P zIr0=9?}CD0U$*euMt(&63oOtd_R)CBuG0|c0|r)!vGYIs&%a&$nVA520HYPoemu)ARU^x#^D}M!0L@Mi%Yj+N(+7 z@`X379`ByR4^}@NAcV}W)Q)$1xY9Xj@_mNhur7UNRi-+lRU^2K^qN0a?m4l(FoJabCF03Z>R^O2eH$IPPea+2(JU4$u!j}Ge6g7nimdCB&tkD zNej|uLrjJI!|7lx8IpfC=p_*m!ltLzk+cv{2hUiNIUBVuYn694%6T}QQ?0!o+eLIf zbKWx(r$o|2=+!xE3>`$D@j2VS^a-_DXHPR#`oZ{S-6ALq#9L4cMK~lQWp! zw2d+0(ea4i44!`JnZbk0<#K=7VBLVgtyO;Z$>R%V@b8&6c?(7qb;A6hD5C!a&V-3+ zjL&XQp6EW@Z%a_BZDR|MJVD|(XRBNx=*{ioNtF^=0!C|%fg`_}cc?6_ z2l}`~5hmJQd-9Zu=vw<@$DbWlf~!ZDj;~v!C7x7qIrwt)9BkvA)Q>9s!_m8N1$ZZ& z8m{nA=yRF?W(i0FEl*M~>iPx-doy)X}}A zj)cD+vAw7#4ZMMWLf>4SrK0jqy41no+tI~Hw~QV*`(&b9o^e!JT{!BIE6lzH?F63y z@7jBNe(CgShD4L-#n3R{HT@~YUNA4sPP-i*aOl<%HjTQ*7$cAXR~L?gK%0ljvagJ> zd`7)NQ}_;d8J^VI`y`&(oXKk#cp$-Iv=4F*em;p$Uxv%ht3>^l!2|g4t@tHZPsSr~ zhww-4f)zZ-LI4>M{}CWcYK=Yi@!Nmwe>?b=e!nmL7!Sp6!M;bUIpgcdrhLYG@_JcU ztWdWaH)$^xSg$Z+f&g~4$;>AY<1h4Ey?(z{ZSB?1yFJ9-YG-@hMz^z9g(grxtM>-o z)AL{4)#mgt#eQ%6Lu_ydM<3poQ@B3-V5G@^adU zx_VXhwAno$oSyBq>W%JRyV-2-oetXly?*t)+N-wv&1S!u*0m_@f9zYne`n>9|BWB| zlVAO#Z`;|SU!tDq&lg!?I@|v;6OdmbT6+Fg6u?jX){p$@Q;;705;?Da{ue-U2G}Q- ziZ}e);U_zPZSU;RFR4MRpSRIH#$mu8o5ZB|{`nvN?l1i?-ax-UwrYz{KX)79zA%u) zjy(I)UwvbSuG24hF;_qT?yCaQ1l!AO>@Z^iiugcYHQxENE3~EG=s+I-hG>taE4BH9 z;UDb&8b(aNwDzukzWF<%Ih}tn+*;B!eB$^1{+E+m|EoU;bv~u__~yqy?R;Tphkk!x z^Wu~#($575D2ue(Hb9Z7GFta!=0V~8E&>(SD(N2t!&&^ CmJad& literal 0 HcmV?d00001 diff --git a/examples/collaboration/ai-node-sdk/client/src/App.tsx b/examples/collaboration/ai-node-sdk/client/src/App.tsx new file mode 100644 index 0000000000..a8bd2dc894 --- /dev/null +++ b/examples/collaboration/ai-node-sdk/client/src/App.tsx @@ -0,0 +1,12 @@ +import { Routes, Route } from 'react-router-dom'; +import { LandingPage } from './pages/landing'; +import { RoomPage } from './pages/room'; + +export function App() { + return ( + + } /> + } /> + + ); +} diff --git a/examples/collaboration/ai-node-sdk/client/src/components/chat/chat-input.tsx b/examples/collaboration/ai-node-sdk/client/src/components/chat/chat-input.tsx new file mode 100644 index 0000000000..9d0297c7a8 --- /dev/null +++ b/examples/collaboration/ai-node-sdk/client/src/components/chat/chat-input.tsx @@ -0,0 +1,120 @@ +import { Button } from '@/components/ui/button'; +import { cn } from '@/lib/cn'; +import { Send, Square } from 'lucide-react'; +import { useCallback, useRef, useState, type KeyboardEvent } from 'react'; + +const QUICK_SUGGESTIONS = [ + { label: 'Add heading', prompt: 'Add a heading "Executive Summary" at the top of the document' }, + { label: 'Write paragraphs', prompt: 'Add 3 lorem ipsum paragraphs under the first heading' }, + { label: 'Summarize', prompt: 'Add a 5-item numbered list summarizing the entire document under the first heading' }, + { label: 'Format', prompt: 'Make the first heading bold and increase its font size' }, +]; + + +interface ChatInputProps { + onSend: (text: string) => void; + onCancel: () => void; + isStreaming: boolean; + disabled?: boolean; + suggestions?: boolean; + onSuggestionSelect?: (text: string) => void; +} + +export function ChatInput({ + onSend, + onCancel, + isStreaming, + disabled, + suggestions, + onSuggestionSelect, +}: ChatInputProps) { + const [text, setText] = useState(''); + const textareaRef = useRef(null); + + const adjustHeight = useCallback(() => { + const el = textareaRef.current; + if (!el) return; + el.style.height = 'auto'; + const lineHeight = 20; + const maxHeight = lineHeight * 4; + el.style.height = `${Math.min(el.scrollHeight, maxHeight)}px`; + }, []); + + const handleSend = useCallback(() => { + const trimmed = text.trim(); + if (!trimmed) return; + onSend(trimmed); + setText(''); + if (textareaRef.current) { + textareaRef.current.style.height = 'auto'; + } + }, [text, onSend]); + + const handleKeyDown = useCallback( + (e: KeyboardEvent) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + handleSend(); + } + }, + [handleSend], + ); + + return ( +
+ {suggestions && onSuggestionSelect && ( +
+ {QUICK_SUGGESTIONS.map(({ label, prompt }) => ( + + ))} +
+ )} +
+