@pixerate/editor 0.44.0 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -2
- package/dist/agent/index.cjs +548 -45
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +47 -17
- package/dist/agent/index.d.ts +47 -17
- package/dist/agent/index.js +536 -33
- package/dist/agent/index.js.map +1 -1
- package/dist/{builtins-BLud97fC.d.cts → builtins-CZW-aYKS.d.cts} +1 -1
- package/dist/{builtins-D0BDyAgw.d.ts → builtins-DghNQbT-.d.ts} +1 -1
- package/dist/{chunk-I6BZB5ZH.cjs → chunk-EFDCLENW.cjs} +73 -6
- package/dist/chunk-EFDCLENW.cjs.map +1 -0
- package/dist/chunk-HHQ4XJWT.js +826 -0
- package/dist/chunk-HHQ4XJWT.js.map +1 -0
- package/dist/chunk-J3R2OWOE.cjs +1465 -0
- package/dist/chunk-J3R2OWOE.cjs.map +1 -0
- package/dist/chunk-K2LVZ4FA.cjs +826 -0
- package/dist/chunk-K2LVZ4FA.cjs.map +1 -0
- package/dist/{chunk-6MDQKHRH.cjs → chunk-N4MLNJPO.cjs} +21 -899
- package/dist/chunk-N4MLNJPO.cjs.map +1 -0
- package/dist/chunk-PQM5W7ZN.js +168 -0
- package/dist/chunk-PQM5W7ZN.js.map +1 -0
- package/dist/{chunk-DDADOHJW.js → chunk-Q25ZS4F7.js} +5 -883
- package/dist/chunk-Q25ZS4F7.js.map +1 -0
- package/dist/chunk-TK2XZK6Z.js +1465 -0
- package/dist/chunk-TK2XZK6Z.js.map +1 -0
- package/dist/commands/index.cjs +3 -2
- package/dist/commands/index.cjs.map +1 -1
- package/dist/commands/index.d.cts +5 -5
- package/dist/commands/index.d.ts +5 -5
- package/dist/commands/index.js +2 -1
- package/dist/commands/index.js.map +1 -1
- package/dist/extensions/index.cjs +4 -4
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +3 -3
- package/dist/extensions/index.d.ts +3 -3
- package/dist/extensions/index.js +12 -12
- package/dist/generation/index.cjs +2 -2
- package/dist/generation/index.d.cts +4 -4
- package/dist/generation/index.d.ts +4 -4
- package/dist/generation/index.js +1 -1
- package/dist/image-editor/index.cjs +24 -24
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +2 -2
- package/dist/image-editor/index.d.ts +2 -2
- package/dist/image-editor/index.js +24 -24
- package/dist/image-editor/index.js.map +1 -1
- package/dist/{index-C6gaQRH0.d.cts → index-CfOQf70b.d.cts} +1 -1
- package/dist/{index-DXAv_R08.d.ts → index-jwJ_onWf.d.ts} +1 -1
- package/dist/index.cjs +9 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +12 -12
- package/dist/parameters/index.d.cts +2 -2
- package/dist/parameters/index.d.ts +2 -2
- package/dist/{registry-DnzpgY27.d.cts → registry-B4l-lYts.d.cts} +1 -1
- package/dist/{registry-DhVUZioj.d.ts → registry-BfVD-vVg.d.ts} +1 -1
- package/dist/{registry-BDe-vlv3.d.ts → registry-CSlH4iUn.d.ts} +1 -1
- package/dist/{registry-D0GADKc7.d.cts → registry-vz6HOiiy.d.cts} +1 -1
- package/dist/{schema-DYDGdYL9.d.cts → schema-Di0CS6Pe.d.cts} +26 -2
- package/dist/{schema-DYDGdYL9.d.ts → schema-Di0CS6Pe.d.ts} +26 -2
- package/dist/tools/index.cjs +37 -3
- package/dist/tools/index.cjs.map +1 -1
- package/dist/tools/index.d.cts +871 -11
- package/dist/tools/index.d.ts +871 -11
- package/dist/tools/index.js +36 -2
- package/dist/vector/index.d.cts +2 -2
- package/dist/vector/index.d.ts +2 -2
- package/package.json +1 -1
- package/dist/chunk-36BLROHV.js +0 -438
- package/dist/chunk-36BLROHV.js.map +0 -1
- package/dist/chunk-5H2OPMXZ.js +0 -586
- package/dist/chunk-5H2OPMXZ.js.map +0 -1
- package/dist/chunk-6MDQKHRH.cjs.map +0 -1
- package/dist/chunk-D6S5M7HV.js +0 -101
- package/dist/chunk-D6S5M7HV.js.map +0 -1
- package/dist/chunk-DDADOHJW.js.map +0 -1
- package/dist/chunk-I6BZB5ZH.cjs.map +0 -1
- package/dist/chunk-MC2LQN5S.cjs +0 -586
- package/dist/chunk-MC2LQN5S.cjs.map +0 -1
- package/dist/chunk-V7CC7RZ6.cjs +0 -438
- package/dist/chunk-V7CC7RZ6.cjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-MC2LQN5S.cjs","../src/extensions/table/nesting.ts","../src/extensions/table/extension.ts","../src/extensions/table/actions.ts"],"names":["skip","CellSelection"],"mappings":"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;AACF,IAAA;AACwB,MAAA;AAC1B,EAAA;AACmB,EAAA;AACrB;AAkC0B;AACqB,EAAA;AAC/C;AAE2D;AAChD,EAAA;AACA,EAAA;AACM,EAAA;AACT,EAAA;AACG,EAAA;AACJ,EAAA;AACG,EAAA;AACG,EAAA;AACG,EAAA;AACF,EAAA;AACG,EAAA;AACC,EAAA;AACP,EAAA;AACV;AAG4E;AACjD,EAAA;AACH,EAAA;AACa,IAAA;AACW,MAAA;AACE,MAAA;AAC9C,IAAA;AACH,EAAA;AACqB,EAAA;AACqC,EAAA;AACT,EAAA;AAC7C,EAAA;AAC6B,IAAA;AACR,IAAA;AACuC,IAAA;AAElD,IAAA;AACgC,IAAA;AACG,IAAA;AACR,IAAA;AAChC,IAAA;AACF,MAAA;AACM,MAAA;AACiCA,MAAAA;AAChC,MAAA;AACG,MAAA;AACH,MAAA;AACG,MAAA;AACiB,MAAA;AACM,MAAA;AACJ,MAAA;AACW,MAAA;AACH,MAAA;AAC1C,IAAA;AACM,EAAA;AAC0B,IAAA;AAClC,EAAA;AACF;AAE4D;AAcoB;AACxC,EAAA;AACH,EAAA;AACR,EAAA;AAEN,EAAA;AACc,IAAA;AACJ,IAAA;AACR,IAAA;AACV,IAAA;AACL,IAAA;AACoC,IAAA;AAC5C,EAAA;AACqB,EAAA;AACc,oBAAA;AACL,oBAAA;AACD,oBAAA;AACE,oBAAA;AAC/B,EAAA;AAEO,EAAA;AACc,IAAA;AACI,MAAA;AACc,QAAA;AACJ,QAAA;AACR,QAAA;AACR,UAAA;AACL,UAAA;AACR,QAAA;AACF,MAAA;AACO,MAAA;AACT,IAAA;AACoB,IAAA;AACa,MAAA;AACtB,QAAA;AACwB,QAAA;AAEL,QAAA;AACD,QAAA;AACE,QAAA;AAC7B,MAAA;AACsB,MAAA;AACT,MAAA;AACc,QAAA;AACG,QAAA;AAC9B,MAAA;AACF,IAAA;AACU,IAAA;AACD,MAAA;AACS,MAAA;AAClB,IAAA;AACF,EAAA;AACF;AH8ImD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-MC2LQN5S.cjs","sourcesContent":[null,"import { Fragment, Slice, type Node as ProsemirrorNode, type ResolvedPos } from \"@tiptap/pm/model\";\nimport { Plugin, PluginKey, Selection, type Transaction } from \"@tiptap/pm/state\";\nimport type { EditorView } from \"@tiptap/pm/view\";\nimport {\n CellSelection,\n __pastedCells,\n handlePaste as handleTablePaste,\n} from \"@tiptap/pm/tables\";\n\n/**\n * Set this meta on a transaction to let it create tables inside table cells\n * (the nesting guard leaves it alone), e.g. when loading legacy content\n * through a transaction that does not replace the whole document.\n */\nexport const ALLOW_NESTED_TABLES_META = \"allowNestedTables\";\n\nexport const tableNestingPluginKey = new PluginKey(\"tableNesting\");\n\nconst roleOf = (node: ProsemirrorNode) => node.type.spec.tableRole as string | undefined;\nconst isTableNode = (node: ProsemirrorNode) => roleOf(node) === \"table\";\n\n/** Depth of the outermost table around `$pos`, or `-1` outside tables. */\nexport function outermostTableDepth($pos: ResolvedPos): number {\n for (let d = 1; d <= $pos.depth; d++) if (isTableNode($pos.node(d))) return d;\n return -1;\n}\n\n/** Whether `$pos` lies inside a table cell or header cell. */\nexport function isInTableCell($pos: ResolvedPos): boolean {\n for (let d = $pos.depth; d > 0; d--) {\n const role = roleOf($pos.node(d));\n if (role === \"cell\" || role === \"header_cell\") return true;\n }\n return false;\n}\n\n/** Whether a slice or fragment contains a table node at any depth. */\nexport function sliceContainsTable(content: Slice | Fragment): boolean {\n const fragment = content instanceof Slice ? content.content : content;\n let found = false;\n fragment.descendants((node) => {\n if (found) return false;\n if (isTableNode(node)) found = true;\n return !found;\n });\n return found;\n}\n\n/**\n * Inserts `slice` right after the outermost table around `from` instead of\n * inside the cell, deleting `from`–`to` first when both lie in that table.\n * Returns the position right after the inserted content, or `null` (and\n * leaves `tr` unchanged) when `from` is not in a table.\n */\nexport function insertSliceAfterTable(tr: Transaction, from: number, to: number, slice: Slice): number | null {\n const $from = tr.doc.resolve(from);\n const depth = outermostTableDepth($from);\n if (depth < 0) return null;\n const tableStart = $from.before(depth);\n const tableEnd = $from.after(depth);\n if (to > from && to < tableEnd) {\n if (tr.selection instanceof CellSelection && tr.selection.from === from && tr.selection.to === to) {\n tr.deleteSelection();\n } else {\n tr.delete(from, to);\n }\n }\n const table = tr.doc.nodeAt(tableStart);\n if (!table) return null;\n const after = tableStart + table.nodeSize;\n const before = tr.doc.content.size;\n // A closed slice: the content becomes blocks of its own after the table\n // instead of merging into whatever follows it.\n tr.replace(after, after, new Slice(slice.content, 0, 0));\n return after + (tr.doc.content.size - before);\n}\n\n/**\n * Paste handling for slices that contain a table while the selection is in a\n * table: a cell selection or a pasted table (rows, cells) fills the cells from\n * the cursor (prosemirror-tables), and anything else that contains a table is\n * inserted after the outermost table, with the cursor at its end. Returns\n * `false` when the paste needs no special handling.\n */\nexport function handleTablePasteWithoutNesting(view: EditorView, event: ClipboardEvent | null, slice: Slice): boolean {\n const { state } = view;\n const { selection } = state;\n if (outermostTableDepth(selection.$from) < 0) return false;\n if (selection instanceof CellSelection || __pastedCells(slice)) {\n if (handleTablePaste(view, event as ClipboardEvent, slice)) return true;\n }\n if (!sliceContainsTable(slice)) return false;\n const tr = state.tr;\n const end = insertSliceAfterTable(tr, selection.from, selection.to, slice);\n if (end === null) return false;\n tr.setSelection(Selection.near(tr.doc.resolve(end), -1));\n view.dispatch(tr.scrollIntoView().setMeta(\"paste\", true).setMeta(\"uiEvent\", \"paste\"));\n return true;\n}\n\n/**\n * Ranges of the final document that `transactions` changed, leaving out the\n * changes of skipped transactions (their steps still map the other ranges).\n */\nfunction changedRanges(transactions: readonly Transaction[], skip: (tr: Transaction) => boolean): [number, number][] {\n let ranges: [number, number][] = [];\n for (const tr of transactions) {\n const skipped = skip(tr);\n for (const step of tr.steps) {\n const map = step.getMap();\n // Content that later (skipped) steps insert at a range's edge is not\n // part of it; pure deletions leave nothing to check.\n ranges = ranges\n .map(([from, to]): [number, number] => [map.map(from, 1), map.map(to, -1)])\n .filter(([from, to]) => to > from);\n if (skipped) continue;\n map.forEach((_oldStart, _oldEnd, newStart, newEnd) => {\n if (newEnd > newStart) ranges.push([newStart, newEnd]);\n });\n }\n }\n return ranges;\n}\n\n/** Tables starting inside `ranges` that sit in a table cell. */\nfunction findNestedTables(doc: ProsemirrorNode, ranges: [number, number][]): number[] {\n const found = new Set<number>();\n for (const [from, to] of ranges) {\n doc.nodesBetween(from, to, (node, pos) => {\n if (!isTableNode(node) || pos < from) return true;\n if (isInTableCell(doc.resolve(pos))) {\n found.add(pos);\n return false;\n }\n return true;\n });\n }\n // A table inside another found table moves with it.\n const sorted = [...found].sort((a, b) => a - b);\n const outer: number[] = [];\n for (const pos of sorted) {\n const last = outer[outer.length - 1];\n if (last === undefined || pos >= last + doc.nodeAt(last)!.nodeSize) outer.push(pos);\n }\n return outer;\n}\n\n/**\n * Moves tables that sit in table cells (at positions in `ranges`) to right\n * after their outermost table, keeping their content, and repeats for tables\n * nested in the moved ones. A cell left without content gets an empty\n * paragraph. Returns whether `tr` changed.\n */\nexport function unnestTables(tr: Transaction, ranges: [number, number][]): boolean {\n let changed = false;\n for (let round = 0; round < 32 && ranges.length; round++) {\n const nested = findNestedTables(tr.doc, ranges);\n if (!nested.length) break;\n // Group by outermost table; handle later tables first so earlier\n // positions stay valid.\n const groups = new Map<number, number[]>();\n for (const pos of nested) {\n const $pos = tr.doc.resolve(pos);\n const outer = $pos.before(outermostTableDepth($pos));\n groups.set(outer, [...(groups.get(outer) ?? []), pos]);\n }\n const next: [number, number][] = [];\n for (const outer of [...groups.keys()].sort((a, b) => b - a)) {\n const positions = groups.get(outer)!;\n const nodes = positions.map((pos) => tr.doc.nodeAt(pos)!);\n for (let i = positions.length - 1; i >= 0; i--) {\n const pos = positions[i];\n const node = nodes[i];\n const $pos = tr.doc.resolve(pos);\n const parent = $pos.parent;\n const filler = parent.childCount === 1 ? parent.type.contentMatch.defaultType?.createAndFill() : null;\n if (filler) tr.replaceWith(pos, pos + node.nodeSize, filler);\n else tr.delete(pos, pos + node.nodeSize);\n }\n const table = tr.doc.nodeAt(outer)!;\n const after = outer + table.nodeSize;\n const fragment = Fragment.fromArray(nodes);\n tr.insert(after, fragment);\n // Later groups are before this one, so this range stays valid.\n next.push([after, after + fragment.size]);\n changed = true;\n }\n ranges = next;\n }\n return changed;\n}\n\n/**\n * Whether a transaction replaces the whole document (`setContent`, loading):\n * existing documents keep their nested tables.\n */\nfunction replacesDocument(tr: Transaction): boolean {\n return tr.steps.some((step, i) => {\n const { from, to } = step as unknown as { from?: number; to?: number };\n return from === 0 && to !== undefined && to >= tr.docs[i].content.size;\n });\n}\n\nconst skip = (tr: Transaction) =>\n !tr.docChanged ||\n tr.getMeta(ALLOW_NESTED_TABLES_META) === true ||\n // Undo/redo and remote collaborative changes restore what was there.\n !!tr.getMeta(\"history$\") ||\n !!tr.getMeta(\"y-sync$\") ||\n // Other plugins' housekeeping, e.g. Track Changes putting a deleted\n // (nested) table back so the deletion can be reviewed.\n !!tr.getMeta(\"appendedTransaction\") ||\n replacesDocument(tr);\n\n/**\n * Keeps tables out of table cells: paste handling (see\n * `handleTablePasteWithoutNesting`) plus a guard that moves any table a\n * local edit puts into a cell (`insertContent`, `insertTable`, drops) to\n * right after the outermost table. Documents that already contain nested\n * tables (initial content, `setContent`, undo/redo, collaboration, Track\n * Changes restoring a deleted table) are left as they are.\n */\nexport function createTableNestingPlugin(): Plugin {\n return new Plugin({\n key: tableNestingPluginKey,\n props: {\n handlePaste: (view, event, slice) => handleTablePasteWithoutNesting(view, event, slice),\n },\n appendTransaction(transactions, _oldState, newState) {\n if (transactions.every(skip)) return null;\n const ranges = changedRanges(transactions, skip);\n if (!ranges.length) return null;\n const tr = newState.tr;\n if (!unnestTables(tr, ranges)) return null;\n return tr;\n },\n });\n}\n","import { getHTMLFromFragment, type Extensions } from \"@tiptap/core\";\nimport { Fragment, type Node as ProsemirrorNode } from \"@tiptap/pm/model\";\nimport * as _Table from \"@tiptap/extension-table\";\nimport * as _TableRow from \"@tiptap/extension-table-row\";\nimport * as _TableHeader from \"@tiptap/extension-table-header\";\nimport * as _TableCell from \"@tiptap/extension-table-cell\";\nimport { createTableNestingPlugin } from \"./nesting\";\n\nconst resolveExt = (mod: any, name: string) =>\n mod?.[name] || mod?.default?.[name] || mod?.default?.default || mod?.default || mod;\n\nconst BaseTable = resolveExt(_Table, \"Table\");\nconst BaseTableRow = resolveExt(_TableRow, \"TableRow\");\nconst BaseTableHeader = resolveExt(_TableHeader, \"TableHeader\");\nconst BaseTableCell = resolveExt(_TableCell, \"TableCell\");\n\n/** Horizontal alignment of a table cell (`align` attribute). */\nexport type TableCellAlignment = \"left\" | \"center\" | \"right\" | \"justify\";\n\nconst ALIGNMENTS = new Set<TableCellAlignment>([\"left\", \"center\", \"right\", \"justify\"]);\n\n/** Returns a valid cell alignment, or `null`. */\nexport function normalizeTableCellAlignment(value: unknown): TableCellAlignment | null {\n const v = typeof value === \"string\" ? value.trim().toLowerCase() : \"\";\n return ALIGNMENTS.has(v as TableCellAlignment) ? (v as TableCellAlignment) : null;\n}\n\n/**\n * Color values allowed as a cell background: hex, `rgb()/rgba()/hsl()/hsla()`\n * with numeric arguments, or a CSS color keyword. Anything else (e.g.\n * `url(...)`, `expression(...)`, `;`) is rejected because the value ends up in\n * a `style` attribute.\n */\nconst COLOR_REGEX =\n /^(?:#[0-9a-f]{3,8}|(?:rgb|rgba|hsl|hsla)\\(\\s*[-0-9.%\\s,/deg]+\\)|[a-z]{3,20})$/i;\n\n/** Returns a safe CSS color for a cell background, or `null`. */\nexport function normalizeTableCellColor(value: unknown): string | null {\n const v = typeof value === \"string\" ? value.trim() : \"\";\n if (!v || v.length > 64 || !COLOR_REGEX.test(v)) return null;\n if (/^(?:inherit|initial|unset|revert|transparent)$/i.test(v)) return null;\n return v;\n}\n\n/** Cell attributes added on top of TipTap's `colspan` / `rowspan` / `colwidth`. */\nconst cellAttributes = () => ({\n align: {\n default: null,\n parseHTML: (element: HTMLElement) =>\n normalizeTableCellAlignment(element.style?.textAlign || element.getAttribute(\"align\")),\n renderHTML: (attrs: Record<string, any>) => {\n const align = normalizeTableCellAlignment(attrs.align);\n return align ? { style: `text-align: ${align}` } : {};\n },\n },\n backgroundColor: {\n default: null,\n parseHTML: (element: HTMLElement) =>\n normalizeTableCellColor(\n element.getAttribute(\"data-background-color\") ||\n element.style?.backgroundColor ||\n element.getAttribute(\"bgcolor\"),\n ),\n renderHTML: (attrs: Record<string, any>) => {\n const color = normalizeTableCellColor(attrs.backgroundColor);\n return color ? { style: `background-color: ${color}`, \"data-background-color\": color } : {};\n },\n },\n});\n\n// ---------------------------------------------------------------------------\n// Markdown (tiptap-markdown)\n// ---------------------------------------------------------------------------\n\nconst children = (node: ProsemirrorNode) => {\n const list: ProsemirrorNode[] = [];\n node.forEach((child) => list.push(child));\n return list;\n};\n\nconst hasSpan = (cell: ProsemirrorNode) => (cell.attrs.colspan ?? 1) > 1 || (cell.attrs.rowspan ?? 1) > 1;\n\n/**\n * Whether a table can be written as a GFM pipe table: the first row is all\n * header cells, the other rows have none, no cell spans rows or columns, and\n * every cell holds a single paragraph.\n */\nexport function isGfmTable(node: ProsemirrorNode): boolean {\n const rows = children(node);\n if (rows.length === 0) return false;\n const width = rows[0].childCount;\n return rows.every(\n (row, r) =>\n row.childCount === width &&\n children(row).every(\n (cell) =>\n (r === 0 ? cell.type.name === \"tableHeader\" : cell.type.name === \"tableCell\") &&\n !hasSpan(cell) &&\n cell.childCount === 1 &&\n cell.firstChild!.type.name === \"paragraph\",\n ),\n );\n}\n\nconst DELIMITERS: Record<string, string> = { left: \":---\", center: \":---:\", right: \"---:\" };\n\n/**\n * tiptap-markdown serializer for tables: GFM pipe tables (with column\n * alignment from the header cells and `|` escaped) when `isGfmTable`, HTML\n * otherwise (spans, header columns, multi-paragraph cells).\n */\nfunction serializeTableMarkdown(state: any, node: ProsemirrorNode) {\n if (!isGfmTable(node)) {\n const html = getHTMLFromFragment(Fragment.from(node), node.type.schema);\n // An HTML block must start on its own line and contain no blank lines.\n state.write(html.replace(/\\n{2,}/g, \"\\n\"));\n state.closeBlock(node);\n return;\n }\n const previous = state.inTable;\n state.inTable = true;\n children(node).forEach((row, r) => {\n if (r) state.ensureNewLine();\n state.write(\"| \");\n children(row).forEach((cell, c) => {\n if (c) state.write(\" | \");\n const paragraph = cell.firstChild!;\n // Render in place (mid-line, so no block prefix is added), then escape\n // the cell's pipes and line breaks, which would end the cell or row.\n const start = state.out.length;\n if (paragraph.childCount) state.renderInline(paragraph);\n const text: string = state.out.slice(start);\n state.out = state.out.slice(0, start) + text.replace(/\\n/g, \" \").replace(/\\|/g, \"\\\\|\");\n });\n state.write(\" |\");\n if (r === 0) {\n const delimiter = children(row).map((cell) => DELIMITERS[cell.attrs.align] ?? \"---\");\n state.ensureNewLine();\n state.write(`| ${delimiter.join(\" | \")} |`);\n }\n });\n state.inTable = previous;\n state.closeBlock(node);\n}\n\n// ---------------------------------------------------------------------------\n// Extensions\n// ---------------------------------------------------------------------------\n\nexport interface RichTextTableOptions {\n /** Drag column borders to resize columns (stored as `colwidth`). Default `true`. */\n resizable: boolean;\n /** Width of the resize handle in pixels. Default 5. */\n handleWidth: number;\n /** Minimum cell width in pixels. Default 25. */\n cellMinWidth: number;\n /** Whether the last column can be resized. Default `true`. */\n lastColumnResizable: boolean;\n /** Allow selecting the whole table as a node (click its border, Esc from a cell selection). Default `true`. */\n allowTableNodeSelection: boolean;\n /** HTML attributes of the `<table>` element. */\n HTMLAttributes: Record<string, any>;\n /** HTML attributes of `<td>` elements. */\n cellHTMLAttributes: Record<string, any>;\n /** HTML attributes of `<th>` elements. */\n headerHTMLAttributes: Record<string, any>;\n /** HTML attributes of `<tr>` elements. */\n rowHTMLAttributes: Record<string, any>;\n}\n\nexport const DEFAULT_TABLE_OPTIONS: RichTextTableOptions = {\n resizable: true,\n handleWidth: 5,\n cellMinWidth: 25,\n lastColumnResizable: true,\n allowTableNodeSelection: true,\n HTMLAttributes: { class: \"pixerate-table\" },\n cellHTMLAttributes: {},\n headerHTMLAttributes: {},\n rowHTMLAttributes: {},\n};\n\n/**\n * TipTap's `Table` with the GFM-aware markdown serializer and the nesting\n * guard (`createTableNestingPlugin`): tables are never pasted, imported or\n * inserted into table cells.\n */\nexport const Table = BaseTable.extend({\n addStorage() {\n return { markdown: { serialize: serializeTableMarkdown } };\n },\n addProseMirrorPlugins() {\n return [...(this.parent?.() ?? []), createTableNestingPlugin()];\n },\n});\n\nexport const TableRow = BaseTableRow;\n\n/** TipTap's `TableCell` plus `align` and `backgroundColor` attributes. */\nexport const TableCell = BaseTableCell.extend({\n addAttributes() {\n return { ...this.parent?.(), ...cellAttributes() };\n },\n});\n\n/** TipTap's `TableHeader` plus `align` and `backgroundColor` attributes. */\nexport const TableHeader = BaseTableHeader.extend({\n addAttributes() {\n return { ...this.parent?.(), ...cellAttributes() };\n },\n});\n\n/**\n * The table extensions (`table`, `tableRow`, `tableHeader`, `tableCell`)\n * configured for rich documents: resizable columns, header rows, columns and\n * cells, `colspan` / `rowspan` from imported HTML, cell alignment and\n * background, table node selection and GFM markdown. `createRichTextPreset`\n * adds them unless `table: false`.\n */\nexport function createTableExtensions(options: Partial<RichTextTableOptions> = {}): Extensions {\n const o = { ...DEFAULT_TABLE_OPTIONS, ...options };\n return [\n Table.configure({\n resizable: o.resizable,\n handleWidth: o.handleWidth,\n cellMinWidth: o.cellMinWidth,\n lastColumnResizable: o.lastColumnResizable,\n allowTableNodeSelection: o.allowTableNodeSelection,\n HTMLAttributes: o.HTMLAttributes,\n }),\n TableRow.configure({ HTMLAttributes: o.rowHTMLAttributes }),\n TableHeader.configure({ HTMLAttributes: o.headerHTMLAttributes }),\n TableCell.configure({ HTMLAttributes: o.cellHTMLAttributes }),\n ];\n}\n","import type { Editor } from \"@tiptap/core\";\nimport type { EditorState } from \"@tiptap/pm/state\";\nimport { CellSelection, isInTable, selectedRect } from \"@tiptap/pm/tables\";\nimport { isTrackChangesEnabled } from \"../track-changes\";\nimport {\n normalizeTableCellAlignment,\n normalizeTableCellColor,\n type TableCellAlignment,\n} from \"./extension\";\n\n/** Table operations shared by the command registry, the toolbars and agent tools. */\nexport type TableAction =\n | \"insertTable\"\n | \"addRowBefore\"\n | \"addRowAfter\"\n | \"deleteRow\"\n | \"addColumnBefore\"\n | \"addColumnAfter\"\n | \"deleteColumn\"\n | \"deleteTable\"\n | \"mergeCells\"\n | \"splitCell\"\n | \"toggleHeaderRow\"\n | \"toggleHeaderColumn\"\n | \"toggleHeaderCell\"\n | \"goToNextCell\"\n | \"goToPreviousCell\"\n | \"setCellAlignment\"\n | \"setCellBackground\";\n\n/** Parameters of `insertTable`, `setCellAlignment` and `setCellBackground`. */\nexport interface TableActionParams {\n /** `insertTable`: number of rows (1–100, default 3). */\n rows?: number;\n /** `insertTable`: number of columns (1–50, default 3). */\n cols?: number;\n /** `insertTable`: make the first row a header row (default `true`). */\n withHeaderRow?: boolean;\n /** `setCellAlignment`: `left`, `center`, `right`, `justify`, or `null` to clear. */\n align?: TableCellAlignment | null;\n /** `setCellBackground`: a CSS color, or `null` to clear. */\n color?: string | null;\n}\n\nexport interface TableActionInfo {\n action: TableAction;\n label: string;\n description: string;\n keywords: readonly string[];\n}\n\n/** Every table action with its label, in toolbar order. */\nexport const TABLE_ACTIONS: readonly TableActionInfo[] = [\n { action: \"insertTable\", label: \"Insert Table\", description: \"Inserts a table (rows, cols, withHeaderRow) at the cursor.\", keywords: [\"table\", \"grid\", \"new\"] },\n { action: \"addRowBefore\", label: \"Insert Row Above\", description: \"Adds a row above the current row.\", keywords: [\"row\", \"add\", \"above\"] },\n { action: \"addRowAfter\", label: \"Insert Row Below\", description: \"Adds a row below the current row.\", keywords: [\"row\", \"add\", \"below\"] },\n { action: \"deleteRow\", label: \"Delete Row\", description: \"Deletes the selected rows.\", keywords: [\"row\", \"remove\"] },\n { action: \"addColumnBefore\", label: \"Insert Column Left\", description: \"Adds a column left of the current column.\", keywords: [\"column\", \"add\", \"left\", \"before\"] },\n { action: \"addColumnAfter\", label: \"Insert Column Right\", description: \"Adds a column right of the current column.\", keywords: [\"column\", \"add\", \"right\", \"after\"] },\n { action: \"deleteColumn\", label: \"Delete Column\", description: \"Deletes the selected columns.\", keywords: [\"column\", \"remove\"] },\n { action: \"deleteTable\", label: \"Delete Table\", description: \"Deletes the table around the cursor.\", keywords: [\"table\", \"remove\"] },\n { action: \"mergeCells\", label: \"Merge Cells\", description: \"Merges the selected cells into one.\", keywords: [\"combine\", \"join\", \"span\"] },\n { action: \"splitCell\", label: \"Split Cell\", description: \"Splits a merged cell back into single cells.\", keywords: [\"unmerge\", \"span\"] },\n { action: \"toggleHeaderRow\", label: \"Toggle Header Row\", description: \"Turns the first row into header cells, or back.\", keywords: [\"header\", \"row\", \"th\"] },\n { action: \"toggleHeaderColumn\", label: \"Toggle Header Column\", description: \"Turns the first column into header cells, or back.\", keywords: [\"header\", \"column\", \"th\"] },\n { action: \"toggleHeaderCell\", label: \"Toggle Header Cell\", description: \"Turns the selected cells into header cells, or back.\", keywords: [\"header\", \"cell\", \"th\"] },\n { action: \"goToNextCell\", label: \"Next Cell\", description: \"Moves the cursor to the next cell.\", keywords: [\"tab\", \"navigate\"] },\n { action: \"goToPreviousCell\", label: \"Previous Cell\", description: \"Moves the cursor to the previous cell.\", keywords: [\"shift tab\", \"navigate\"] },\n { action: \"setCellAlignment\", label: \"Align Cells…\", description: \"Sets the horizontal alignment (align: left | center | right | justify | null) of the selected cells.\", keywords: [\"align\", \"left\", \"center\", \"right\"] },\n { action: \"setCellBackground\", label: \"Cell Background…\", description: \"Sets the background color (color: CSS color or null) of the selected cells.\", keywords: [\"shading\", \"fill\", \"color\"] },\n];\n\n/** A button of the table toolbars (`TableToolbar` in React and Svelte). */\nexport interface TableToolbarItem {\n /** Unique id (also the button's `data-action`). */\n id: string;\n action: TableAction;\n params?: TableActionParams;\n /** Short button text. */\n label: string;\n /** Accessible name and tooltip. */\n title: string;\n /** Items of one group are separated from the next group. */\n group: string;\n /** Toggle buttons: whether the button shows as pressed. */\n active?: (state: TableState) => boolean;\n}\n\n/** The default table toolbar: rows, columns, cells, headers, alignment, delete. */\nexport const DEFAULT_TABLE_TOOLBAR: readonly TableToolbarItem[] = [\n { id: \"addRowBefore\", action: \"addRowBefore\", label: \"+ Row ↑\", title: \"Insert row above\", group: \"rows\" },\n { id: \"addRowAfter\", action: \"addRowAfter\", label: \"+ Row ↓\", title: \"Insert row below\", group: \"rows\" },\n { id: \"deleteRow\", action: \"deleteRow\", label: \"− Row\", title: \"Delete row\", group: \"rows\" },\n { id: \"addColumnBefore\", action: \"addColumnBefore\", label: \"+ Col ←\", title: \"Insert column left\", group: \"columns\" },\n { id: \"addColumnAfter\", action: \"addColumnAfter\", label: \"+ Col →\", title: \"Insert column right\", group: \"columns\" },\n { id: \"deleteColumn\", action: \"deleteColumn\", label: \"− Col\", title: \"Delete column\", group: \"columns\" },\n { id: \"mergeCells\", action: \"mergeCells\", label: \"Merge\", title: \"Merge cells\", group: \"cells\" },\n { id: \"splitCell\", action: \"splitCell\", label: \"Split\", title: \"Split cell\", group: \"cells\" },\n { id: \"toggleHeaderRow\", action: \"toggleHeaderRow\", label: \"Header row\", title: \"Toggle header row\", group: \"headers\", active: (s) => s.headerRow },\n { id: \"toggleHeaderColumn\", action: \"toggleHeaderColumn\", label: \"Header col\", title: \"Toggle header column\", group: \"headers\", active: (s) => s.headerColumn },\n { id: \"toggleHeaderCell\", action: \"toggleHeaderCell\", label: \"Header cell\", title: \"Toggle header cell\", group: \"headers\", active: (s) => s.headerCell },\n { id: \"alignLeft\", action: \"setCellAlignment\", params: { align: \"left\" }, label: \"Left\", title: \"Align cell left\", group: \"align\", active: (s) => s.cellAlignment === \"left\" },\n { id: \"alignCenter\", action: \"setCellAlignment\", params: { align: \"center\" }, label: \"Center\", title: \"Align cell center\", group: \"align\", active: (s) => s.cellAlignment === \"center\" },\n { id: \"alignRight\", action: \"setCellAlignment\", params: { align: \"right\" }, label: \"Right\", title: \"Align cell right\", group: \"align\", active: (s) => s.cellAlignment === \"right\" },\n { id: \"deleteTable\", action: \"deleteTable\", label: \"Delete table\", title: \"Delete table\", group: \"table\" },\n];\n\nexport const MAX_TABLE_ROWS = 100;\nexport const MAX_TABLE_COLUMNS = 50;\n\nconst live = (editor: Editor | null | undefined): editor is Editor => !!editor && !editor.isDestroyed;\n\n/** Whether the editor's schema has the table nodes (`createRichTextPreset({ table })`). */\nexport function isTableEnabled(editor: Editor | null | undefined): boolean {\n return live(editor) && !!editor.schema.nodes.table && !!editor.schema.nodes.tableRow;\n}\n\n/** Whether the selection (cursor, text or cell selection) is inside a table. */\nexport function isSelectionInTable(state: EditorState): boolean {\n if (!state.schema.nodes.table) return false;\n return state.selection instanceof CellSelection || isInTable(state);\n}\n\n/**\n * `shouldShow` for a table bubble menu (TipTap's `BubbleMenuPlugin`): shown\n * while an editable editor's selection is in a table, even a collapsed cursor.\n */\nexport function shouldShowTableBubbleMenu({ editor, state }: { editor: Editor; state: EditorState }): boolean {\n return editor.isEditable && isSelectionInTable(state);\n}\n\nconst isInt = (value: unknown, min: number, max: number) =>\n typeof value === \"number\" && Number.isInteger(value) && value >= min && value <= max;\n\nconst can = (editor: Editor, run: (chain: any) => any): boolean => {\n try {\n return !!run(editor.can().chain()).run();\n } catch {\n return false;\n }\n};\n\n/**\n * Whether a table action can run: `true`, or the reason it cannot (e.g.\n * \"Place the cursor in a table first.\").\n */\nexport function getTableActionState(\n editor: Editor | null | undefined,\n action: TableAction,\n params: TableActionParams = {},\n): true | string {\n if (!live(editor)) return \"The editor is not available.\";\n if (!isTableEnabled(editor)) return \"Tables are not enabled in this editor.\";\n if (!editor.isEditable) return \"The editor is read-only.\";\n const state = editor.state;\n const inTable = isSelectionInTable(state);\n\n if (action === \"insertTable\") {\n if (inTable) return \"Tables cannot be nested: move the cursor out of the table first.\";\n if (params.rows !== undefined && !isInt(params.rows, 1, MAX_TABLE_ROWS)) {\n return `Rows must be a whole number from 1 to ${MAX_TABLE_ROWS}.`;\n }\n if (params.cols !== undefined && !isInt(params.cols, 1, MAX_TABLE_COLUMNS)) {\n return `Columns must be a whole number from 1 to ${MAX_TABLE_COLUMNS}.`;\n }\n return can(editor, (c) => c.insertTable({ rows: 1, cols: 1 })) ? true : \"A table cannot be inserted here.\";\n }\n\n if (!inTable) return \"Place the cursor in a table first.\";\n\n switch (action) {\n case \"mergeCells\":\n case \"splitCell\": {\n if (isTrackChangesEnabled(editor)) {\n return `${action === \"mergeCells\" ? \"Merging\" : \"Splitting\"} cells cannot be tracked: turn off Track Changes first.`;\n }\n if (action === \"mergeCells\") {\n return can(editor, (c) => c.mergeCells()) ? true : \"Select two or more adjacent cells to merge.\";\n }\n return can(editor, (c) => c.splitCell()) ? true : \"Only a merged cell can be split.\";\n }\n case \"deleteRow\":\n case \"deleteColumn\": {\n // prosemirror-tables only refuses to delete every row/column when dispatching.\n const rect = selectedRect(state);\n const all = action === \"deleteRow\"\n ? rect.top === 0 && rect.bottom === rect.map.height\n : rect.left === 0 && rect.right === rect.map.width;\n const what = action === \"deleteRow\" ? \"rows\" : \"columns\";\n if (all || !can(editor, (c) => c[action]())) return `These are all the ${what}: delete the table instead.`;\n return true;\n }\n case \"goToNextCell\":\n return can(editor, (c) => c.goToNextCell()) ? true : \"This is the last cell.\";\n case \"goToPreviousCell\":\n return can(editor, (c) => c.goToPreviousCell()) ? true : \"This is the first cell.\";\n case \"setCellAlignment\":\n if (params.align !== undefined && params.align !== null && !normalizeTableCellAlignment(params.align)) {\n return 'Alignment must be \"left\", \"center\", \"right\", \"justify\" or null.';\n }\n if (!editor.schema.nodes.tableCell?.spec.attrs?.align) return \"Cell alignment is not supported by this schema.\";\n return true;\n case \"setCellBackground\":\n if (params.color !== undefined && params.color !== null && !normalizeTableCellColor(params.color)) {\n return \"Color must be a CSS color such as #fde68a, rgb(…) or a color name, or null.\";\n }\n if (!editor.schema.nodes.tableCell?.spec.attrs?.backgroundColor) return \"Cell backgrounds are not supported by this schema.\";\n return true;\n default:\n return can(editor, (c) => c[action]()) ? true : \"This table action is not available here.\";\n }\n}\n\nexport interface RunTableActionOptions {\n /** Focus the editor (toolbars). Default `false`. */\n focus?: boolean;\n}\n\n/**\n * Runs a table action. Returns `false` (and changes nothing) when it cannot\n * run; check `getTableActionState` for the reason.\n */\nexport function runTableAction(\n editor: Editor | null | undefined,\n action: TableAction,\n params: TableActionParams = {},\n options: RunTableActionOptions = {},\n): boolean {\n if (getTableActionState(editor, action, params) !== true) return false;\n const ed = editor as Editor;\n let chain: any = ed.chain();\n if (options.focus) chain = chain.focus();\n switch (action) {\n case \"insertTable\":\n chain = chain.insertTable({\n rows: params.rows ?? 3,\n cols: params.cols ?? 3,\n withHeaderRow: params.withHeaderRow ?? true,\n });\n break;\n case \"setCellAlignment\":\n chain = chain.setCellAttribute(\"align\", normalizeTableCellAlignment(params.align));\n break;\n case \"setCellBackground\":\n chain = chain.setCellAttribute(\"backgroundColor\", normalizeTableCellColor(params.color));\n break;\n default:\n chain = chain[action]();\n }\n return !!chain.run();\n}\n\nexport interface TableActionStatus {\n enabled: boolean;\n /** Why the action cannot run (only when `enabled` is false). */\n reason?: string;\n}\n\n/** The table at the selection and what can be done there. */\nexport interface TableState {\n /** The schema has tables. */\n enabled: boolean;\n /** The selection is inside a table. */\n inTable: boolean;\n /** Cells are selected (a `CellSelection`). */\n cellSelection: boolean;\n /** Size of the table (0 outside a table). */\n rows: number;\n columns: number;\n /** Row and column (0-based) of the selection's first cell, or -1. */\n row: number;\n column: number;\n /** The first row / first column are all header cells. */\n headerRow: boolean;\n headerColumn: boolean;\n /** The cell at the selection is a header cell. */\n headerCell: boolean;\n /** Alignment / background of the cell at the selection. */\n cellAlignment: TableCellAlignment | null;\n cellBackground: string | null;\n /** Enablement of every action (with the default params). */\n actions: Record<TableAction, TableActionStatus>;\n}\n\nconst NO_ACTIONS = Object.fromEntries(\n TABLE_ACTIONS.map(({ action }) => [action, { enabled: false, reason: \"The editor is not available.\" }]),\n) as Record<TableAction, TableActionStatus>;\n\nexport const EMPTY_TABLE_STATE: TableState = Object.freeze({\n enabled: false,\n inTable: false,\n cellSelection: false,\n rows: 0,\n columns: 0,\n row: -1,\n column: -1,\n headerRow: false,\n headerColumn: false,\n headerCell: false,\n cellAlignment: null,\n cellBackground: null,\n actions: NO_ACTIONS,\n}) as TableState;\n\n/** Computes the table state at the editor's selection. */\nexport function getTableState(editor: Editor | null | undefined): TableState {\n if (!live(editor)) return EMPTY_TABLE_STATE;\n const actions = Object.fromEntries(\n TABLE_ACTIONS.map(({ action }) => {\n const result = getTableActionState(editor, action);\n return [action, result === true ? { enabled: true } : { enabled: false, reason: result }];\n }),\n ) as Record<TableAction, TableActionStatus>;\n const state = editor.state;\n const base: TableState = { ...EMPTY_TABLE_STATE, enabled: isTableEnabled(editor), actions };\n if (!base.enabled || !isSelectionInTable(state)) return base;\n try {\n const rect = selectedRect(state);\n const { map, table } = rect;\n const cellAt = (row: number, col: number) => table.nodeAt(map.map[row * map.width + col]);\n const allHeaders = (positions: number[]) =>\n positions.length > 0 && positions.every((pos) => table.nodeAt(pos)?.type.name === \"tableHeader\");\n const firstRow = map.cellsInRect({ left: 0, right: map.width, top: 0, bottom: 1 });\n const firstColumn = map.cellsInRect({ left: 0, right: 1, top: 0, bottom: map.height });\n const cell = cellAt(rect.top, rect.left);\n return {\n ...base,\n inTable: true,\n cellSelection: state.selection instanceof CellSelection,\n rows: map.height,\n columns: map.width,\n row: rect.top,\n column: rect.left,\n headerRow: allHeaders(firstRow),\n headerColumn: allHeaders(firstColumn),\n headerCell: cell?.type.name === \"tableHeader\",\n cellAlignment: normalizeTableCellAlignment(cell?.attrs.align),\n cellBackground: normalizeTableCellColor(cell?.attrs.backgroundColor),\n };\n } catch {\n return { ...base, inTable: true };\n }\n}\n\nconst stateKey = (state: TableState) => JSON.stringify(state);\n\nexport interface TableStore {\n getSnapshot(): TableState;\n subscribe(listener: () => void): () => void;\n destroy(): void;\n}\n\n/**\n * An external store of `getTableState(editor)` for UI bindings (React's\n * `useSyncExternalStore`, Svelte runes). The snapshot object only changes\n * when the state does, and the store listens to the editor only while it\n * has subscribers.\n */\nexport function createTableStore(editor: Editor | null | undefined): TableStore {\n const listeners = new Set<() => void>();\n let snapshot = getTableState(editor);\n let key = stateKey(snapshot);\n\n const update = () => {\n const next = getTableState(editor);\n const nextKey = stateKey(next);\n if (nextKey === key) return;\n snapshot = next;\n key = nextKey;\n listeners.forEach((listener) => listener());\n };\n const detach = () => {\n editor?.off(\"transaction\", update);\n editor?.off(\"update\", update);\n editor?.off(\"focus\", update);\n editor?.off(\"destroy\", update);\n };\n\n return {\n getSnapshot: () => {\n if (!listeners.size) {\n const next = getTableState(editor);\n const nextKey = stateKey(next);\n if (nextKey !== key) {\n snapshot = next;\n key = nextKey;\n }\n }\n return snapshot;\n },\n subscribe(listener) {\n if (!listeners.size && editor) {\n update();\n editor.on(\"transaction\", update);\n // `setEditable` emits `update` without a transaction.\n editor.on(\"update\", update);\n editor.on(\"focus\", update);\n editor.on(\"destroy\", update);\n }\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n if (!listeners.size) detach();\n };\n },\n destroy() {\n detach();\n listeners.clear();\n },\n };\n}\n"]}
|
package/dist/chunk-V7CC7RZ6.cjs
DELETED
|
@@ -1,438 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;
|
|
2
|
-
|
|
3
|
-
var _chunkI6BZB5ZHcjs = require('./chunk-I6BZB5ZH.cjs');
|
|
4
|
-
|
|
5
|
-
// src/tools/registry.ts
|
|
6
|
-
var ToolRegistryError = class extends Error {
|
|
7
|
-
|
|
8
|
-
constructor(code, message) {
|
|
9
|
-
super(message);
|
|
10
|
-
this.name = "ToolRegistryError";
|
|
11
|
-
this.code = code;
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
var TOOL_NAMESPACE_SEPARATOR = "__";
|
|
15
|
-
var TOOL_NAME_REGEX = /^[A-Za-z0-9_.-]{1,128}$/;
|
|
16
|
-
var sanitizeNamespace = (id) => id.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
17
|
-
function readTools(provider) {
|
|
18
|
-
return typeof provider.tools === "function" ? provider.tools() : provider.tools;
|
|
19
|
-
}
|
|
20
|
-
function toDefinition(name, tool) {
|
|
21
|
-
const { handler: _handler, name: _name, ...rest } = tool;
|
|
22
|
-
return { name, ...rest };
|
|
23
|
-
}
|
|
24
|
-
function errorResult(error) {
|
|
25
|
-
const details = _optionalChain([error, 'access', _ => _.details, 'optionalAccess', _2 => _2.length]) ? "\n" + error.details.map((d) => `- ${d.path}: ${d.message}`).join("\n") : "";
|
|
26
|
-
return {
|
|
27
|
-
isError: true,
|
|
28
|
-
content: [{ type: "text", text: `${error.message}${details}` }],
|
|
29
|
-
structuredContent: { error }
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
function toToolResult(value) {
|
|
33
|
-
if (value && typeof value === "object" && Array.isArray(value.content)) {
|
|
34
|
-
return value;
|
|
35
|
-
}
|
|
36
|
-
if (value === void 0) return { content: [] };
|
|
37
|
-
if (typeof value === "string") return { content: [{ type: "text", text: value }] };
|
|
38
|
-
const text = JSON.stringify(value);
|
|
39
|
-
const isPlainObject = typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40
|
-
return {
|
|
41
|
-
content: [{ type: "text", text: _nullishCoalesce(text, () => ( String(value))) }],
|
|
42
|
-
...isPlainObject ? { structuredContent: value } : {}
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
var ToolRegistry = (_class = class {
|
|
46
|
-
/** MCP server capabilities this registry supports. */
|
|
47
|
-
__init() {this.capabilities = { tools: { listChanged: true } }}
|
|
48
|
-
__init2() {this.entries = []}
|
|
49
|
-
__init3() {this.listeners = /* @__PURE__ */ new Set()}
|
|
50
|
-
|
|
51
|
-
__init4() {this.timer = null}
|
|
52
|
-
|
|
53
|
-
constructor(options = {}) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);
|
|
54
|
-
this.options = {
|
|
55
|
-
onCollision: _nullishCoalesce(options.onCollision, () => ( "namespace")),
|
|
56
|
-
listChangedDelayMs: _nullishCoalesce(options.listChangedDelayMs, () => ( 0)),
|
|
57
|
-
validateArguments: _nullishCoalesce(options.validateArguments, () => ( true))
|
|
58
|
-
};
|
|
59
|
-
this.lastSignature = this.signature();
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Registers a provider and returns a function that unregisters it.
|
|
63
|
-
* Throws a {@link ToolRegistryError} for a duplicate provider id, an invalid
|
|
64
|
-
* tool name, or (with `onCollision: 'error'`) a tool name collision.
|
|
65
|
-
*/
|
|
66
|
-
register(provider) {
|
|
67
|
-
if (this.entries.some((e) => e.provider.id === provider.id)) {
|
|
68
|
-
throw new ToolRegistryError("duplicate_provider", `Tool provider "${provider.id}" is already registered.`);
|
|
69
|
-
}
|
|
70
|
-
for (const tool of readTools(provider)) {
|
|
71
|
-
if (!TOOL_NAME_REGEX.test(tool.name)) {
|
|
72
|
-
throw new ToolRegistryError("invalid_tool", `Invalid tool name "${tool.name}" from provider "${provider.id}".`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
const entry = { provider };
|
|
76
|
-
this.entries.push(entry);
|
|
77
|
-
try {
|
|
78
|
-
const names = this.resolve(this.options.onCollision === "error").map((t) => t.name);
|
|
79
|
-
const duplicate = names.find((name, i) => names.indexOf(name) !== i);
|
|
80
|
-
if (duplicate) {
|
|
81
|
-
throw new ToolRegistryError("name_collision", `Tool name "${duplicate}" is exposed more than once.`);
|
|
82
|
-
}
|
|
83
|
-
} catch (error) {
|
|
84
|
-
this.entries.pop();
|
|
85
|
-
throw error;
|
|
86
|
-
}
|
|
87
|
-
if (provider.subscribe) {
|
|
88
|
-
entry.unsubscribe = provider.subscribe(() => this.notifyListChanged());
|
|
89
|
-
}
|
|
90
|
-
this.notifyListChanged();
|
|
91
|
-
let registered = true;
|
|
92
|
-
return () => {
|
|
93
|
-
if (!registered) return;
|
|
94
|
-
registered = false;
|
|
95
|
-
this.unregister(provider);
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
/** Removes a provider by id or instance. Returns whether it was registered. */
|
|
99
|
-
unregister(providerOrId) {
|
|
100
|
-
const index = this.entries.findIndex(
|
|
101
|
-
(e) => typeof providerOrId === "string" ? e.provider.id === providerOrId : e.provider === providerOrId
|
|
102
|
-
);
|
|
103
|
-
if (index === -1) return false;
|
|
104
|
-
const [entry] = this.entries.splice(index, 1);
|
|
105
|
-
_optionalChain([entry, 'access', _3 => _3.unsubscribe, 'optionalCall', _4 => _4()]);
|
|
106
|
-
this.notifyListChanged();
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
|
-
/** Registered provider ids in registration order. */
|
|
110
|
-
providerIds() {
|
|
111
|
-
return this.entries.map((e) => e.provider.id);
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Resolves exposed names. Tools are ordered by provider registration, then
|
|
115
|
-
* by their order within the provider.
|
|
116
|
-
*/
|
|
117
|
-
resolve(throwOnCollision = false) {
|
|
118
|
-
const all = [];
|
|
119
|
-
const counts = /* @__PURE__ */ new Map();
|
|
120
|
-
for (const { provider } of this.entries) {
|
|
121
|
-
for (const tool of readTools(provider)) {
|
|
122
|
-
all.push({ name: tool.name, tool, provider });
|
|
123
|
-
if (!provider.namespace) counts.set(tool.name, (_nullishCoalesce(counts.get(tool.name), () => ( 0))) + 1);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
for (const item of all) {
|
|
127
|
-
const prefix = _nullishCoalesce(item.provider.namespace, () => ( ((_nullishCoalesce(counts.get(item.name), () => ( 0))) > 1 ? item.provider.id : void 0)));
|
|
128
|
-
if (prefix !== void 0) {
|
|
129
|
-
if (throwOnCollision && !item.provider.namespace) {
|
|
130
|
-
throw new ToolRegistryError(
|
|
131
|
-
"name_collision",
|
|
132
|
-
`Tool "${item.name}" from provider "${item.provider.id}" collides with another provider's tool.`
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
item.name = `${sanitizeNamespace(prefix)}${TOOL_NAMESPACE_SEPARATOR}${item.name}`;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return all;
|
|
139
|
-
}
|
|
140
|
-
/** MCP `tools/list` result for the current providers. */
|
|
141
|
-
listTools() {
|
|
142
|
-
return { tools: this.resolve().map(({ name, tool }) => toDefinition(name, tool)) };
|
|
143
|
-
}
|
|
144
|
-
/** Whether a tool with this exposed name exists. */
|
|
145
|
-
hasTool(name) {
|
|
146
|
-
return this.resolve().some((t) => t.name === name);
|
|
147
|
-
}
|
|
148
|
-
/** Looks up a tool definition by exposed name. */
|
|
149
|
-
getTool(name) {
|
|
150
|
-
const found = this.resolve().find((t) => t.name === name);
|
|
151
|
-
return found ? toDefinition(found.name, found.tool) : void 0;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Calls a tool by exposed name and returns an MCP `tools/call` result.
|
|
155
|
-
* Never rejects: unknown tools, invalid arguments and handler errors come
|
|
156
|
-
* back as `isError: true` results with a {@link ToolCallError} in
|
|
157
|
-
* `structuredContent.error` (MCP transports may map `unknown_tool` to a
|
|
158
|
-
* JSON-RPC `-32602` error instead).
|
|
159
|
-
*/
|
|
160
|
-
async callTool(name, args = {}, options = {}) {
|
|
161
|
-
const found = this.resolve().find((t) => t.name === name);
|
|
162
|
-
if (!found) {
|
|
163
|
-
return errorResult({ code: "unknown_tool", message: `Unknown tool "${name}".`, tool: name });
|
|
164
|
-
}
|
|
165
|
-
const input = _nullishCoalesce(args, () => ( {}));
|
|
166
|
-
if (this.options.validateArguments) {
|
|
167
|
-
const details = _chunkI6BZB5ZHcjs.validateJsonSchema.call(void 0, input, found.tool.inputSchema);
|
|
168
|
-
if (details.length > 0) {
|
|
169
|
-
return errorResult({
|
|
170
|
-
code: "invalid_arguments",
|
|
171
|
-
message: `Invalid arguments for tool "${name}".`,
|
|
172
|
-
tool: name,
|
|
173
|
-
details
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
try {
|
|
178
|
-
const value = await found.tool.handler(input, {
|
|
179
|
-
name,
|
|
180
|
-
providerId: found.provider.id,
|
|
181
|
-
signal: options.signal
|
|
182
|
-
});
|
|
183
|
-
return toToolResult(value);
|
|
184
|
-
} catch (error) {
|
|
185
|
-
return errorResult({
|
|
186
|
-
code: "tool_failed",
|
|
187
|
-
message: error instanceof Error ? error.message : String(error),
|
|
188
|
-
tool: name
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Subscribes to tool-list changes. Notifications are coalesced: many
|
|
194
|
-
* registrations or provider signals within the delay window produce one
|
|
195
|
-
* call, and none if the exposed list ends up unchanged (e.g. a provider
|
|
196
|
-
* unmounted and remounted). Returns an unsubscribe function.
|
|
197
|
-
*/
|
|
198
|
-
onListChanged(listener) {
|
|
199
|
-
this.listeners.add(listener);
|
|
200
|
-
return () => {
|
|
201
|
-
this.listeners.delete(listener);
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
/** Schedules a coalesced `listChanged` check; providers may call it directly. */
|
|
205
|
-
notifyListChanged() {
|
|
206
|
-
if (this.timer !== null) return;
|
|
207
|
-
this.timer = setTimeout(() => this.flush(), this.options.listChangedDelayMs);
|
|
208
|
-
}
|
|
209
|
-
/** Runs a pending `listChanged` check immediately. */
|
|
210
|
-
flush() {
|
|
211
|
-
if (this.timer !== null) {
|
|
212
|
-
clearTimeout(this.timer);
|
|
213
|
-
this.timer = null;
|
|
214
|
-
}
|
|
215
|
-
const signature = this.signature();
|
|
216
|
-
if (signature === this.lastSignature) return;
|
|
217
|
-
this.lastSignature = signature;
|
|
218
|
-
const { tools } = this.listTools();
|
|
219
|
-
for (const listener of Array.from(this.listeners)) listener(tools);
|
|
220
|
-
}
|
|
221
|
-
signature() {
|
|
222
|
-
try {
|
|
223
|
-
return JSON.stringify(this.listTools().tools);
|
|
224
|
-
} catch (e2) {
|
|
225
|
-
return String(Math.random());
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
/** Unregisters every provider and listener and cancels pending notifications. */
|
|
229
|
-
dispose() {
|
|
230
|
-
if (this.timer !== null) clearTimeout(this.timer);
|
|
231
|
-
this.timer = null;
|
|
232
|
-
for (const entry of this.entries.splice(0)) _optionalChain([entry, 'access', _5 => _5.unsubscribe, 'optionalCall', _6 => _6()]);
|
|
233
|
-
this.listeners.clear();
|
|
234
|
-
}
|
|
235
|
-
}, _class);
|
|
236
|
-
function createToolRegistry(options) {
|
|
237
|
-
return new ToolRegistry(options);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// src/tools/definitions.ts
|
|
241
|
-
var MCP_TOOL_GET_EDITOR_STATE = {
|
|
242
|
-
name: "get_editor_state",
|
|
243
|
-
title: "Get editor state",
|
|
244
|
-
annotations: {
|
|
245
|
-
title: "Get editor state",
|
|
246
|
-
readOnlyHint: true,
|
|
247
|
-
destructiveHint: false,
|
|
248
|
-
idempotentHint: true,
|
|
249
|
-
openWorldHint: false
|
|
250
|
-
},
|
|
251
|
-
description: "Retrieves the current state of the document, variables, selection, and canvas graph (nodes and edges).",
|
|
252
|
-
inputSchema: {
|
|
253
|
-
type: "object",
|
|
254
|
-
properties: {
|
|
255
|
-
includeDocument: {
|
|
256
|
-
type: "boolean",
|
|
257
|
-
description: "Whether to include the prompt document text and variables (default: true)."
|
|
258
|
-
},
|
|
259
|
-
includeCanvas: {
|
|
260
|
-
type: "boolean",
|
|
261
|
-
description: "Whether to include the canvas nodes and edges (default: true)."
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
};
|
|
266
|
-
var MCP_TOOL_EDIT_CANVAS = {
|
|
267
|
-
name: "edit_canvas",
|
|
268
|
-
title: "Edit the canvas",
|
|
269
|
-
annotations: {
|
|
270
|
-
title: "Edit the canvas",
|
|
271
|
-
readOnlyHint: false,
|
|
272
|
-
destructiveHint: true,
|
|
273
|
-
idempotentHint: false,
|
|
274
|
-
openWorldHint: false
|
|
275
|
-
},
|
|
276
|
-
description: "Applies high-level structural operations to the visual canvas (adding nodes, connecting edges, organizing layout, or moving elements).",
|
|
277
|
-
inputSchema: {
|
|
278
|
-
type: "object",
|
|
279
|
-
properties: {
|
|
280
|
-
operation: {
|
|
281
|
-
type: "string",
|
|
282
|
-
enum: [
|
|
283
|
-
"add_node",
|
|
284
|
-
"remove_nodes",
|
|
285
|
-
"connect",
|
|
286
|
-
"update_node",
|
|
287
|
-
"layout",
|
|
288
|
-
"select",
|
|
289
|
-
"highlight"
|
|
290
|
-
],
|
|
291
|
-
description: "The canvas operation to execute."
|
|
292
|
-
},
|
|
293
|
-
node: {
|
|
294
|
-
type: "object",
|
|
295
|
-
description: "Node definition when operation is add_node. Can omit position to auto-place."
|
|
296
|
-
},
|
|
297
|
-
nearNodeId: {
|
|
298
|
-
type: "string",
|
|
299
|
-
description: "Anchor node ID to position beside using collision-aware placement."
|
|
300
|
-
},
|
|
301
|
-
side: {
|
|
302
|
-
type: "string",
|
|
303
|
-
enum: ["top", "right", "bottom", "left"],
|
|
304
|
-
description: "Side of the anchor node to place the new node beside."
|
|
305
|
-
},
|
|
306
|
-
nodeIds: {
|
|
307
|
-
type: "array",
|
|
308
|
-
items: { type: "string" },
|
|
309
|
-
description: "Array of node IDs for remove_nodes, select, or highlight."
|
|
310
|
-
},
|
|
311
|
-
source: {
|
|
312
|
-
type: "string",
|
|
313
|
-
description: "Source node ID for connect operation."
|
|
314
|
-
},
|
|
315
|
-
target: {
|
|
316
|
-
type: "string",
|
|
317
|
-
description: "Target node ID for connect operation."
|
|
318
|
-
},
|
|
319
|
-
label: {
|
|
320
|
-
type: "string",
|
|
321
|
-
description: "Optional edge label for connect operation."
|
|
322
|
-
},
|
|
323
|
-
direction: {
|
|
324
|
-
type: "string",
|
|
325
|
-
enum: ["LR", "TB", "RL", "BT"],
|
|
326
|
-
description: "Layout direction (default LR)."
|
|
327
|
-
},
|
|
328
|
-
incremental: {
|
|
329
|
-
type: "boolean",
|
|
330
|
-
description: "Preserve existing node coordinates and blend layout (default true)."
|
|
331
|
-
}
|
|
332
|
-
},
|
|
333
|
-
required: ["operation"]
|
|
334
|
-
}
|
|
335
|
-
};
|
|
336
|
-
var MCP_TOOL_EDIT_PROMPT = {
|
|
337
|
-
name: "edit_prompt",
|
|
338
|
-
title: "Edit the prompt",
|
|
339
|
-
annotations: {
|
|
340
|
-
title: "Edit the prompt",
|
|
341
|
-
readOnlyHint: false,
|
|
342
|
-
destructiveHint: true,
|
|
343
|
-
idempotentHint: false,
|
|
344
|
-
openWorldHint: false
|
|
345
|
-
},
|
|
346
|
-
description: "Applies edits to the prompt template document, including inserting text, replacing ranges, and setting variables.",
|
|
347
|
-
inputSchema: {
|
|
348
|
-
type: "object",
|
|
349
|
-
properties: {
|
|
350
|
-
operation: {
|
|
351
|
-
type: "string",
|
|
352
|
-
enum: ["insert_text", "replace_range", "set_variable", "select"],
|
|
353
|
-
description: "The prompt operation to execute."
|
|
354
|
-
},
|
|
355
|
-
text: {
|
|
356
|
-
type: "string",
|
|
357
|
-
description: "Text to insert or replace."
|
|
358
|
-
},
|
|
359
|
-
at: {
|
|
360
|
-
type: "number",
|
|
361
|
-
description: "Position to insert text at."
|
|
362
|
-
},
|
|
363
|
-
from: {
|
|
364
|
-
type: "number",
|
|
365
|
-
description: "Start offset for replace_range or select."
|
|
366
|
-
},
|
|
367
|
-
to: {
|
|
368
|
-
type: "number",
|
|
369
|
-
description: "End offset for replace_range or select."
|
|
370
|
-
},
|
|
371
|
-
name: {
|
|
372
|
-
type: "string",
|
|
373
|
-
description: "Variable name for set_variable."
|
|
374
|
-
},
|
|
375
|
-
value: {
|
|
376
|
-
description: "Variable value for set_variable."
|
|
377
|
-
}
|
|
378
|
-
},
|
|
379
|
-
required: ["operation"]
|
|
380
|
-
}
|
|
381
|
-
};
|
|
382
|
-
var MCP_TOOL_VIEW_EDITOR = {
|
|
383
|
-
name: "view_editor",
|
|
384
|
-
title: "View the editor",
|
|
385
|
-
annotations: {
|
|
386
|
-
title: "View the editor",
|
|
387
|
-
readOnlyHint: true,
|
|
388
|
-
destructiveHint: false,
|
|
389
|
-
idempotentHint: true,
|
|
390
|
-
openWorldHint: false
|
|
391
|
-
},
|
|
392
|
-
description: "Captures a visual image snapshot (JPEG or PNG) of the editor canvas or viewport for multimodal evaluation. Active agent cursor indicators are automatically excluded from the snapshot.",
|
|
393
|
-
inputSchema: {
|
|
394
|
-
type: "object",
|
|
395
|
-
properties: {
|
|
396
|
-
scope: {
|
|
397
|
-
type: "string",
|
|
398
|
-
enum: ["viewport", "canvas"],
|
|
399
|
-
description: "Whether to capture only the visible viewport or the full canvas bounding box (default: viewport)."
|
|
400
|
-
},
|
|
401
|
-
format: {
|
|
402
|
-
type: "string",
|
|
403
|
-
enum: ["jpeg", "png"],
|
|
404
|
-
description: "Image format of the base64 snapshot (default: jpeg)."
|
|
405
|
-
},
|
|
406
|
-
maxEdge: {
|
|
407
|
-
type: "integer",
|
|
408
|
-
description: "Maximum width or height dimension in pixels (default: 1024)."
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
};
|
|
413
|
-
var EXPORT_EXCLUDED_SELECTORS = [
|
|
414
|
-
".pixerate-presence",
|
|
415
|
-
".agent-presence",
|
|
416
|
-
".ursula-presence"
|
|
417
|
-
];
|
|
418
|
-
var EDITOR_MCP_TOOLS = [
|
|
419
|
-
MCP_TOOL_GET_EDITOR_STATE,
|
|
420
|
-
MCP_TOOL_EDIT_CANVAS,
|
|
421
|
-
MCP_TOOL_EDIT_PROMPT,
|
|
422
|
-
MCP_TOOL_VIEW_EDITOR
|
|
423
|
-
];
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
exports.ToolRegistryError = ToolRegistryError; exports.TOOL_NAMESPACE_SEPARATOR = TOOL_NAMESPACE_SEPARATOR; exports.toToolResult = toToolResult; exports.ToolRegistry = ToolRegistry; exports.createToolRegistry = createToolRegistry; exports.MCP_TOOL_GET_EDITOR_STATE = MCP_TOOL_GET_EDITOR_STATE; exports.MCP_TOOL_EDIT_CANVAS = MCP_TOOL_EDIT_CANVAS; exports.MCP_TOOL_EDIT_PROMPT = MCP_TOOL_EDIT_PROMPT; exports.MCP_TOOL_VIEW_EDITOR = MCP_TOOL_VIEW_EDITOR; exports.EXPORT_EXCLUDED_SELECTORS = EXPORT_EXCLUDED_SELECTORS; exports.EDITOR_MCP_TOOLS = EDITOR_MCP_TOOLS;
|
|
438
|
-
//# sourceMappingURL=chunk-V7CC7RZ6.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-V7CC7RZ6.cjs","../src/tools/registry.ts","../src/tools/definitions.ts"],"names":[],"mappings":"AAAA;AACE;AACF,wDAA6B;AAC7B;AACA;AC8EO,IAAM,kBAAA,EAAN,MAAA,QAAgC,MAAM;AAAA,EACnC;AAAA,EAET,WAAA,CAAY,IAAA,EAAiC,OAAA,EAAiB;AAC7D,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,KAAA,EAAO,mBAAA;AACZ,IAAA,IAAA,CAAK,KAAA,EAAO,IAAA;AAAA,EACb;AACD,CAAA;AAgBO,IAAM,yBAAA,EAA2B,IAAA;AAExC,IAAM,gBAAA,EAAkB,yBAAA;AACxB,IAAM,kBAAA,EAAoB,CAAC,EAAA,EAAA,GAAe,EAAA,CAAG,OAAA,CAAQ,iBAAA,EAAmB,GAAG,CAAA;AAa3E,SAAS,SAAA,CAAU,QAAA,EAAmD;AACrE,EAAA,OAAO,OAAO,QAAA,CAAS,MAAA,IAAU,WAAA,EAAa,QAAA,CAAS,KAAA,CAAM,EAAA,EAAI,QAAA,CAAS,KAAA;AAC3E;AAEA,SAAS,YAAA,CAAa,IAAA,EAAc,IAAA,EAAoC;AACvE,EAAA,MAAM,EAAE,OAAA,EAAS,QAAA,EAAU,IAAA,EAAM,KAAA,EAAO,GAAG,KAAK,EAAA,EAAI,IAAA;AACpD,EAAA,OAAO,EAAE,IAAA,EAAM,GAAG,KAAK,CAAA;AACxB;AAEA,SAAS,WAAA,CAAY,KAAA,EAAqC;AACzD,EAAA,MAAM,QAAA,kBAAU,KAAA,mBAAM,OAAA,6BAAS,SAAA,EAC5B,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,EAAA,GAAM,CAAA,EAAA,EAAK,CAAA,CAAE,IAAI,CAAA,EAAA,EAAK,CAAA,CAAE,OAAO,CAAA,CAAA;AAErD,EAAA;AACG,IAAA;AACqD,IAAA;AACU,IAAA;AACzE,EAAA;AACD;AAG4D;AAKzD,EAAA;AACM,IAAA;AACR,EAAA;AAC8C,EAAA;AACmC,EAAA;AAChD,EAAA;AACwD,EAAA;AAClF,EAAA;AACiD,IAAA;AACwB,IAAA;AAChF,EAAA;AACD;AAU0B;AAAA;AAE8B,iBAAA;AAEV,kBAAA;AAC8B,kBAAA;AAC1D,EAAA;AACqC,kBAAA;AAC9C,EAAA;AAEuC,EAAA;AAC/B,IAAA;AACsB,MAAA;AACc,MAAA;AACF,MAAA;AACjD,IAAA;AACoC,IAAA;AACrC,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOkD,EAAA;AACY,IAAA;AACmB,MAAA;AAChF,IAAA;AACwC,IAAA;AACD,MAAA;AACsC,QAAA;AAC5E,MAAA;AACD,IAAA;AACwC,IAAA;AACjB,IAAA;AACnB,IAAA;AAC+E,MAAA;AACf,MAAA;AACpD,MAAA;AAEuD,QAAA;AACtE,MAAA;AACe,IAAA;AACE,MAAA;AACX,MAAA;AACP,IAAA;AACwB,IAAA;AAC8C,MAAA;AACtE,IAAA;AACuB,IAAA;AACN,IAAA;AACJ,IAAA;AACK,MAAA;AACJ,MAAA;AACW,MAAA;AACzB,IAAA;AACD,EAAA;AAAA;AAG8D,EAAA;AAClC,IAAA;AACyD,MAAA;AACpF,IAAA;AACyB,IAAA;AACmB,IAAA;AACxB,oBAAA;AACG,IAAA;AAChB,IAAA;AACR,EAAA;AAAA;AAGwB,EAAA;AACqB,IAAA;AAC7C,EAAA;AAAA;AAAA;AAAA;AAAA;AAM0D,EAAA;AAC5B,IAAA;AACU,IAAA;AACE,IAAA;AACA,MAAA;AACK,QAAA;AACmC,QAAA;AAChF,MAAA;AACD,IAAA;AACwB,IAAA;AACqE,MAAA;AAClE,MAAA;AACyB,QAAA;AACvC,UAAA;AACT,YAAA;AACsD,YAAA;AACvD,UAAA;AACD,QAAA;AAC+E,QAAA;AAChF,MAAA;AACD,IAAA;AACO,IAAA;AACR,EAAA;AAAA;AAGgC,EAAA;AACkD,IAAA;AAClF,EAAA;AAAA;AAG+B,EAAA;AACmB,IAAA;AAClD,EAAA;AAAA;AAGqD,EAAA;AACI,IAAA;AACF,IAAA;AACvD,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASiI,EAAA;AACxE,IAAA;AAC5C,IAAA;AACgF,MAAA;AAC5F,IAAA;AACuB,IAAA;AACa,IAAA;AAC6B,MAAA;AACxC,MAAA;AACJ,QAAA;AACZ,UAAA;AACsC,UAAA;AACtC,UAAA;AACN,UAAA;AACA,QAAA;AACF,MAAA;AACD,IAAA;AACI,IAAA;AACkE,MAAA;AACpE,QAAA;AAC2B,QAAA;AACX,QAAA;AAChB,MAAA;AACwB,MAAA;AACV,IAAA;AACI,MAAA;AACZ,QAAA;AACwD,QAAA;AACxD,QAAA;AACN,MAAA;AACF,IAAA;AACD,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQ0E,EAAA;AAC9C,IAAA;AACd,IAAA;AACkB,MAAA;AAC/B,IAAA;AACD,EAAA;AAAA;AAG0B,EAAA;AACA,IAAA;AACkD,IAAA;AAC5E,EAAA;AAAA;AAGc,EAAA;AACY,IAAA;AACD,MAAA;AACV,MAAA;AACd,IAAA;AACiC,IAAA;AACK,IAAA;AACjB,IAAA;AACY,IAAA;AACgC,IAAA;AAClE,EAAA;AAE4B,EAAA;AACvB,IAAA;AACyC,MAAA;AACrC,IAAA;AACoB,MAAA;AAC5B,IAAA;AACD,EAAA;AAAA;AAGgB,EAAA;AACiC,IAAA;AACnC,IAAA;AACmD,IAAA;AAC3C,IAAA;AACtB,EAAA;AACD;AAEgF;AAChD,EAAA;AAChC;AD7IoG;AACA;AE1O3D;AAClC,EAAA;AACC,EAAA;AACM,EAAA;AACL,IAAA;AACO,IAAA;AACG,IAAA;AACD,IAAA;AACD,IAAA;AAChB,EAAA;AAEC,EAAA;AACY,EAAA;AACN,IAAA;AACM,IAAA;AACM,MAAA;AACV,QAAA;AACO,QAAA;AACd,MAAA;AACe,MAAA;AACR,QAAA;AACO,QAAA;AACd,MAAA;AACD,IAAA;AACD,EAAA;AACD;AAEoC;AAC7B,EAAA;AACC,EAAA;AACM,EAAA;AACL,IAAA;AACO,IAAA;AACG,IAAA;AACD,IAAA;AACD,IAAA;AAChB,EAAA;AAEC,EAAA;AACY,EAAA;AACN,IAAA;AACM,IAAA;AACA,MAAA;AACJ,QAAA;AACA,QAAA;AACL,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACD,QAAA;AACa,QAAA;AACd,MAAA;AACM,MAAA;AACC,QAAA;AACO,QAAA;AACd,MAAA;AACY,MAAA;AACL,QAAA;AACO,QAAA;AACd,MAAA;AACM,MAAA;AACC,QAAA;AACiC,QAAA;AAC1B,QAAA;AACd,MAAA;AACS,MAAA;AACF,QAAA;AACkB,QAAA;AACX,QAAA;AACd,MAAA;AACQ,MAAA;AACD,QAAA;AACO,QAAA;AACd,MAAA;AACQ,MAAA;AACD,QAAA;AACO,QAAA;AACd,MAAA;AACO,MAAA;AACA,QAAA;AACO,QAAA;AACd,MAAA;AACW,MAAA;AACJ,QAAA;AACuB,QAAA;AAChB,QAAA;AACd,MAAA;AACa,MAAA;AACN,QAAA;AACO,QAAA;AACd,MAAA;AACD,IAAA;AACsB,IAAA;AACvB,EAAA;AACD;AAEoC;AAC7B,EAAA;AACC,EAAA;AACM,EAAA;AACL,IAAA;AACO,IAAA;AACG,IAAA;AACD,IAAA;AACD,IAAA;AAChB,EAAA;AAEC,EAAA;AACY,EAAA;AACN,IAAA;AACM,IAAA;AACA,MAAA;AACJ,QAAA;AACyD,QAAA;AAClD,QAAA;AACd,MAAA;AACM,MAAA;AACC,QAAA;AACO,QAAA;AACd,MAAA;AACI,MAAA;AACG,QAAA;AACO,QAAA;AACd,MAAA;AACM,MAAA;AACC,QAAA;AACO,QAAA;AACd,MAAA;AACI,MAAA;AACG,QAAA;AACO,QAAA;AACd,MAAA;AACM,MAAA;AACC,QAAA;AACO,QAAA;AACd,MAAA;AACO,MAAA;AACO,QAAA;AACd,MAAA;AACD,IAAA;AACsB,IAAA;AACvB,EAAA;AACD;AAEoC;AAC7B,EAAA;AACC,EAAA;AACM,EAAA;AACL,IAAA;AACO,IAAA;AACG,IAAA;AACD,IAAA;AACD,IAAA;AAChB,EAAA;AAEC,EAAA;AACY,EAAA;AACN,IAAA;AACM,IAAA;AACJ,MAAA;AACA,QAAA;AACqB,QAAA;AACd,QAAA;AACd,MAAA;AACQ,MAAA;AACD,QAAA;AACc,QAAA;AACP,QAAA;AACd,MAAA;AACS,MAAA;AACF,QAAA;AACO,QAAA;AACd,MAAA;AACD,IAAA;AACD,EAAA;AACD;AAMyC;AACxC,EAAA;AACA,EAAA;AACA,EAAA;AACD;AAEgC;AAC/B,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACD;AF+NoG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-V7CC7RZ6.cjs","sourcesContent":[null,"import { validateJsonSchema, type JsonSchema, type SchemaValidationError } from './schema.js';\n\n/**\n * MCP-shaped tool definition, as returned by `tools/list`.\n */\nexport interface McpToolDefinition {\n\tname: string;\n\ttitle?: string;\n\tdescription?: string;\n\tinputSchema: JsonSchema & { type: 'object' };\n\toutputSchema?: JsonSchema;\n\tannotations?: {\n\t\ttitle?: string;\n\t\treadOnlyHint?: boolean;\n\t\tdestructiveHint?: boolean;\n\t\tidempotentHint?: boolean;\n\t\topenWorldHint?: boolean;\n\t\t[key: string]: unknown;\n\t};\n}\n\nexport type McpToolContent =\n\t| { type: 'text'; text: string }\n\t| { type: 'image'; data: string; mimeType: string }\n\t| { type: string; [key: string]: unknown };\n\n/** MCP `tools/call` result. */\nexport interface McpToolResult {\n\tcontent: McpToolContent[];\n\tstructuredContent?: Record<string, unknown>;\n\tisError?: boolean;\n}\n\n/** MCP `tools/list` result. */\nexport interface McpListToolsResult {\n\ttools: McpToolDefinition[];\n}\n\nexport interface ToolCallContext {\n\t/** Name the tool was called by (possibly namespaced). */\n\tname: string;\n\t/** Id of the provider that owns the tool. */\n\tproviderId: string;\n\tsignal?: AbortSignal;\n}\n\n/**\n * Handler return values are normalized into an {@link McpToolResult}: a full\n * result (`{ content: [...] }`) is passed through, a string becomes a text\n * block, `undefined` becomes an empty result, and anything else is returned\n * as `structuredContent` (plain objects) plus a JSON text block.\n */\nexport type AgentToolHandler = (args: Record<string, any>, context: ToolCallContext) => unknown | Promise<unknown>;\n\nexport interface AgentTool extends McpToolDefinition {\n\thandler: AgentToolHandler;\n}\n\n/**\n * A source of tools, typically one per mounted editor, spreadsheet or canvas.\n */\nexport interface AgentToolProvider {\n\t/** Unique id within a registry, e.g. `doc-1`. Used as the namespace on collisions. */\n\tid: string;\n\t/** Always prefix this provider's tools with `<namespace>__`. */\n\tnamespace?: string;\n\t/** Tools, or a function returning the current tools (re-read on every `listTools`). */\n\ttools: readonly AgentTool[] | (() => readonly AgentTool[]);\n\t/** Lets the provider signal that its tool list changed; returns an unsubscribe function. */\n\tsubscribe?: (notify: () => void) => () => void;\n}\n\nexport type ToolErrorCode = 'unknown_tool' | 'invalid_arguments' | 'tool_failed';\n\n/** Structured error carried in `structuredContent.error` of a failed call. */\nexport interface ToolCallError {\n\tcode: ToolErrorCode;\n\tmessage: string;\n\ttool: string;\n\tdetails?: SchemaValidationError[];\n}\n\nexport class ToolRegistryError extends Error {\n\treadonly code: 'duplicate_provider' | 'name_collision' | 'invalid_tool';\n\n\tconstructor(code: ToolRegistryError['code'], message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'ToolRegistryError';\n\t\tthis.code = code;\n\t}\n}\n\nexport interface ToolRegistryOptions {\n\t/**\n\t * What to do when two providers contribute the same tool name:\n\t * `namespace` (default) exposes every colliding tool as `<providerId>__<name>`;\n\t * `error` makes `register` throw.\n\t */\n\tonCollision?: 'namespace' | 'error';\n\t/** Coalescing window for `listChanged` notifications in ms (default 0: same tick). */\n\tlistChangedDelayMs?: number;\n\t/** Validate arguments against `inputSchema` before calling handlers (default `true`). */\n\tvalidateArguments?: boolean;\n}\n\n/** Separator between namespace and tool name; valid in MCP and LLM tool-name charsets. */\nexport const TOOL_NAMESPACE_SEPARATOR = '__';\n\nconst TOOL_NAME_REGEX = /^[A-Za-z0-9_.-]{1,128}$/;\nconst sanitizeNamespace = (id: string) => id.replace(/[^A-Za-z0-9_-]/g, '_');\n\ninterface ResolvedTool {\n\tname: string;\n\ttool: AgentTool;\n\tprovider: AgentToolProvider;\n}\n\ninterface ProviderEntry {\n\tprovider: AgentToolProvider;\n\tunsubscribe?: () => void;\n}\n\nfunction readTools(provider: AgentToolProvider): readonly AgentTool[] {\n\treturn typeof provider.tools === 'function' ? provider.tools() : provider.tools;\n}\n\nfunction toDefinition(name: string, tool: AgentTool): McpToolDefinition {\n\tconst { handler: _handler, name: _name, ...rest } = tool;\n\treturn { name, ...rest };\n}\n\nfunction errorResult(error: ToolCallError): McpToolResult {\n\tconst details = error.details?.length\n\t\t? '\\n' + error.details.map((d) => `- ${d.path}: ${d.message}`).join('\\n')\n\t\t: '';\n\treturn {\n\t\tisError: true,\n\t\tcontent: [{ type: 'text', text: `${error.message}${details}` }],\n\t\tstructuredContent: { error: error as unknown as Record<string, unknown> }\n\t};\n}\n\n/** Normalizes a handler's return value into an MCP `tools/call` result. */\nexport function toToolResult(value: unknown): McpToolResult {\n\tif (\n\t\tvalue &&\n\t\ttypeof value === 'object' &&\n\t\tArray.isArray((value as McpToolResult).content)\n\t) {\n\t\treturn value as McpToolResult;\n\t}\n\tif (value === undefined) return { content: [] };\n\tif (typeof value === 'string') return { content: [{ type: 'text', text: value }] };\n\tconst text = JSON.stringify(value);\n\tconst isPlainObject = typeof value === 'object' && value !== null && !Array.isArray(value);\n\treturn {\n\t\tcontent: [{ type: 'text', text: text ?? String(value) }],\n\t\t...(isPlainObject ? { structuredContent: value as Record<string, unknown> } : {})\n\t};\n}\n\n/**\n * Transport-agnostic registry of agent tools contributed by live providers.\n *\n * `listTools()` and `callTool()` return MCP `tools/list` / `tools/call`\n * result shapes, and `onListChanged` fires (coalesced) whenever the exposed\n * tool list changes, mirroring MCP's `notifications/tools/list_changed`, so an\n * MCP server can be a thin wrapper around it.\n */\nexport class ToolRegistry {\n\t/** MCP server capabilities this registry supports. */\n\treadonly capabilities = { tools: { listChanged: true } } as const;\n\n\tprivate readonly entries: ProviderEntry[] = [];\n\tprivate readonly listeners = new Set<(tools: McpToolDefinition[]) => void>();\n\tprivate readonly options: Required<ToolRegistryOptions>;\n\tprivate timer: ReturnType<typeof setTimeout> | null = null;\n\tprivate lastSignature: string;\n\n\tconstructor(options: ToolRegistryOptions = {}) {\n\t\tthis.options = {\n\t\t\tonCollision: options.onCollision ?? 'namespace',\n\t\t\tlistChangedDelayMs: options.listChangedDelayMs ?? 0,\n\t\t\tvalidateArguments: options.validateArguments ?? true\n\t\t};\n\t\tthis.lastSignature = this.signature();\n\t}\n\n\t/**\n\t * Registers a provider and returns a function that unregisters it.\n\t * Throws a {@link ToolRegistryError} for a duplicate provider id, an invalid\n\t * tool name, or (with `onCollision: 'error'`) a tool name collision.\n\t */\n\tregister(provider: AgentToolProvider): () => void {\n\t\tif (this.entries.some((e) => e.provider.id === provider.id)) {\n\t\t\tthrow new ToolRegistryError('duplicate_provider', `Tool provider \"${provider.id}\" is already registered.`);\n\t\t}\n\t\tfor (const tool of readTools(provider)) {\n\t\t\tif (!TOOL_NAME_REGEX.test(tool.name)) {\n\t\t\t\tthrow new ToolRegistryError('invalid_tool', `Invalid tool name \"${tool.name}\" from provider \"${provider.id}\".`);\n\t\t\t}\n\t\t}\n\t\tconst entry: ProviderEntry = { provider };\n\t\tthis.entries.push(entry);\n\t\ttry {\n\t\t\tconst names = this.resolve(this.options.onCollision === 'error').map((t) => t.name);\n\t\t\tconst duplicate = names.find((name, i) => names.indexOf(name) !== i);\n\t\t\tif (duplicate) {\n\t\t\t\t// Only possible with explicit namespaces (or duplicate names within one provider).\n\t\t\t\tthrow new ToolRegistryError('name_collision', `Tool name \"${duplicate}\" is exposed more than once.`);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.entries.pop();\n\t\t\tthrow error;\n\t\t}\n\t\tif (provider.subscribe) {\n\t\t\tentry.unsubscribe = provider.subscribe(() => this.notifyListChanged());\n\t\t}\n\t\tthis.notifyListChanged();\n\t\tlet registered = true;\n\t\treturn () => {\n\t\t\tif (!registered) return;\n\t\t\tregistered = false;\n\t\t\tthis.unregister(provider);\n\t\t};\n\t}\n\n\t/** Removes a provider by id or instance. Returns whether it was registered. */\n\tunregister(providerOrId: string | AgentToolProvider): boolean {\n\t\tconst index = this.entries.findIndex((e) =>\n\t\t\ttypeof providerOrId === 'string' ? e.provider.id === providerOrId : e.provider === providerOrId\n\t\t);\n\t\tif (index === -1) return false;\n\t\tconst [entry] = this.entries.splice(index, 1);\n\t\tentry.unsubscribe?.();\n\t\tthis.notifyListChanged();\n\t\treturn true;\n\t}\n\n\t/** Registered provider ids in registration order. */\n\tproviderIds(): string[] {\n\t\treturn this.entries.map((e) => e.provider.id);\n\t}\n\n\t/**\n\t * Resolves exposed names. Tools are ordered by provider registration, then\n\t * by their order within the provider.\n\t */\n\tprivate resolve(throwOnCollision = false): ResolvedTool[] {\n\t\tconst all: ResolvedTool[] = [];\n\t\tconst counts = new Map<string, number>();\n\t\tfor (const { provider } of this.entries) {\n\t\t\tfor (const tool of readTools(provider)) {\n\t\t\t\tall.push({ name: tool.name, tool, provider });\n\t\t\t\tif (!provider.namespace) counts.set(tool.name, (counts.get(tool.name) ?? 0) + 1);\n\t\t\t}\n\t\t}\n\t\tfor (const item of all) {\n\t\t\tconst prefix = item.provider.namespace ?? ((counts.get(item.name) ?? 0) > 1 ? item.provider.id : undefined);\n\t\t\tif (prefix !== undefined) {\n\t\t\t\tif (throwOnCollision && !item.provider.namespace) {\n\t\t\t\t\tthrow new ToolRegistryError(\n\t\t\t\t\t\t'name_collision',\n\t\t\t\t\t\t`Tool \"${item.name}\" from provider \"${item.provider.id}\" collides with another provider's tool.`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\titem.name = `${sanitizeNamespace(prefix)}${TOOL_NAMESPACE_SEPARATOR}${item.name}`;\n\t\t\t}\n\t\t}\n\t\treturn all;\n\t}\n\n\t/** MCP `tools/list` result for the current providers. */\n\tlistTools(): McpListToolsResult {\n\t\treturn { tools: this.resolve().map(({ name, tool }) => toDefinition(name, tool)) };\n\t}\n\n\t/** Whether a tool with this exposed name exists. */\n\thasTool(name: string): boolean {\n\t\treturn this.resolve().some((t) => t.name === name);\n\t}\n\n\t/** Looks up a tool definition by exposed name. */\n\tgetTool(name: string): McpToolDefinition | undefined {\n\t\tconst found = this.resolve().find((t) => t.name === name);\n\t\treturn found ? toDefinition(found.name, found.tool) : undefined;\n\t}\n\n\t/**\n\t * Calls a tool by exposed name and returns an MCP `tools/call` result.\n\t * Never rejects: unknown tools, invalid arguments and handler errors come\n\t * back as `isError: true` results with a {@link ToolCallError} in\n\t * `structuredContent.error` (MCP transports may map `unknown_tool` to a\n\t * JSON-RPC `-32602` error instead).\n\t */\n\tasync callTool(name: string, args: Record<string, unknown> = {}, options: { signal?: AbortSignal } = {}): Promise<McpToolResult> {\n\t\tconst found = this.resolve().find((t) => t.name === name);\n\t\tif (!found) {\n\t\t\treturn errorResult({ code: 'unknown_tool', message: `Unknown tool \"${name}\".`, tool: name });\n\t\t}\n\t\tconst input = args ?? {};\n\t\tif (this.options.validateArguments) {\n\t\t\tconst details = validateJsonSchema(input, found.tool.inputSchema);\n\t\t\tif (details.length > 0) {\n\t\t\t\treturn errorResult({\n\t\t\t\t\tcode: 'invalid_arguments',\n\t\t\t\t\tmessage: `Invalid arguments for tool \"${name}\".`,\n\t\t\t\t\ttool: name,\n\t\t\t\t\tdetails\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tconst value = await found.tool.handler(input as Record<string, any>, {\n\t\t\t\tname,\n\t\t\t\tproviderId: found.provider.id,\n\t\t\t\tsignal: options.signal\n\t\t\t});\n\t\t\treturn toToolResult(value);\n\t\t} catch (error) {\n\t\t\treturn errorResult({\n\t\t\t\tcode: 'tool_failed',\n\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\ttool: name\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Subscribes to tool-list changes. Notifications are coalesced: many\n\t * registrations or provider signals within the delay window produce one\n\t * call, and none if the exposed list ends up unchanged (e.g. a provider\n\t * unmounted and remounted). Returns an unsubscribe function.\n\t */\n\tonListChanged(listener: (tools: McpToolDefinition[]) => void): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.listeners.delete(listener);\n\t\t};\n\t}\n\n\t/** Schedules a coalesced `listChanged` check; providers may call it directly. */\n\tnotifyListChanged(): void {\n\t\tif (this.timer !== null) return;\n\t\tthis.timer = setTimeout(() => this.flush(), this.options.listChangedDelayMs);\n\t}\n\n\t/** Runs a pending `listChanged` check immediately. */\n\tflush(): void {\n\t\tif (this.timer !== null) {\n\t\t\tclearTimeout(this.timer);\n\t\t\tthis.timer = null;\n\t\t}\n\t\tconst signature = this.signature();\n\t\tif (signature === this.lastSignature) return;\n\t\tthis.lastSignature = signature;\n\t\tconst { tools } = this.listTools();\n\t\tfor (const listener of Array.from(this.listeners)) listener(tools);\n\t}\n\n\tprivate signature(): string {\n\t\ttry {\n\t\t\treturn JSON.stringify(this.listTools().tools);\n\t\t} catch {\n\t\t\treturn String(Math.random());\n\t\t}\n\t}\n\n\t/** Unregisters every provider and listener and cancels pending notifications. */\n\tdispose(): void {\n\t\tif (this.timer !== null) clearTimeout(this.timer);\n\t\tthis.timer = null;\n\t\tfor (const entry of this.entries.splice(0)) entry.unsubscribe?.();\n\t\tthis.listeners.clear();\n\t}\n}\n\nexport function createToolRegistry(options?: ToolRegistryOptions): ToolRegistry {\n\treturn new ToolRegistry(options);\n}\n","/**\n * Standard MCP Tool Definitions for @pixerate/editor.\n * Compatible with the Model Context Protocol (MCP) tool specification schema.\n */\n\nexport const MCP_TOOL_GET_EDITOR_STATE = {\n\tname: 'get_editor_state',\n\ttitle: 'Get editor state',\n\tannotations: {\n\t\ttitle: 'Get editor state',\n\t\treadOnlyHint: true,\n\t\tdestructiveHint: false,\n\t\tidempotentHint: true,\n\t\topenWorldHint: false\n\t},\n\tdescription:\n\t\t'Retrieves the current state of the document, variables, selection, and canvas graph (nodes and edges).',\n\tinputSchema: {\n\t\ttype: 'object',\n\t\tproperties: {\n\t\t\tincludeDocument: {\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdescription: 'Whether to include the prompt document text and variables (default: true).'\n\t\t\t},\n\t\t\tincludeCanvas: {\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdescription: 'Whether to include the canvas nodes and edges (default: true).'\n\t\t\t}\n\t\t}\n\t}\n} as const;\n\nexport const MCP_TOOL_EDIT_CANVAS = {\n\tname: 'edit_canvas',\n\ttitle: 'Edit the canvas',\n\tannotations: {\n\t\ttitle: 'Edit the canvas',\n\t\treadOnlyHint: false,\n\t\tdestructiveHint: true,\n\t\tidempotentHint: false,\n\t\topenWorldHint: false\n\t},\n\tdescription:\n\t\t'Applies high-level structural operations to the visual canvas (adding nodes, connecting edges, organizing layout, or moving elements).',\n\tinputSchema: {\n\t\ttype: 'object',\n\t\tproperties: {\n\t\t\toperation: {\n\t\t\t\ttype: 'string',\n\t\t\t\tenum: [\n\t\t\t\t\t'add_node',\n\t\t\t\t\t'remove_nodes',\n\t\t\t\t\t'connect',\n\t\t\t\t\t'update_node',\n\t\t\t\t\t'layout',\n\t\t\t\t\t'select',\n\t\t\t\t\t'highlight'\n\t\t\t\t],\n\t\t\t\tdescription: 'The canvas operation to execute.'\n\t\t\t},\n\t\t\tnode: {\n\t\t\t\ttype: 'object',\n\t\t\t\tdescription: 'Node definition when operation is add_node. Can omit position to auto-place.'\n\t\t\t},\n\t\t\tnearNodeId: {\n\t\t\t\ttype: 'string',\n\t\t\t\tdescription: 'Anchor node ID to position beside using collision-aware placement.'\n\t\t\t},\n\t\t\tside: {\n\t\t\t\ttype: 'string',\n\t\t\t\tenum: ['top', 'right', 'bottom', 'left'],\n\t\t\t\tdescription: 'Side of the anchor node to place the new node beside.'\n\t\t\t},\n\t\t\tnodeIds: {\n\t\t\t\ttype: 'array',\n\t\t\t\titems: { type: 'string' },\n\t\t\t\tdescription: 'Array of node IDs for remove_nodes, select, or highlight.'\n\t\t\t},\n\t\t\tsource: {\n\t\t\t\ttype: 'string',\n\t\t\t\tdescription: 'Source node ID for connect operation.'\n\t\t\t},\n\t\t\ttarget: {\n\t\t\t\ttype: 'string',\n\t\t\t\tdescription: 'Target node ID for connect operation.'\n\t\t\t},\n\t\t\tlabel: {\n\t\t\t\ttype: 'string',\n\t\t\t\tdescription: 'Optional edge label for connect operation.'\n\t\t\t},\n\t\t\tdirection: {\n\t\t\t\ttype: 'string',\n\t\t\t\tenum: ['LR', 'TB', 'RL', 'BT'],\n\t\t\t\tdescription: 'Layout direction (default LR).'\n\t\t\t},\n\t\t\tincremental: {\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdescription: 'Preserve existing node coordinates and blend layout (default true).'\n\t\t\t}\n\t\t},\n\t\trequired: ['operation']\n\t}\n} as const;\n\nexport const MCP_TOOL_EDIT_PROMPT = {\n\tname: 'edit_prompt',\n\ttitle: 'Edit the prompt',\n\tannotations: {\n\t\ttitle: 'Edit the prompt',\n\t\treadOnlyHint: false,\n\t\tdestructiveHint: true,\n\t\tidempotentHint: false,\n\t\topenWorldHint: false\n\t},\n\tdescription:\n\t\t'Applies edits to the prompt template document, including inserting text, replacing ranges, and setting variables.',\n\tinputSchema: {\n\t\ttype: 'object',\n\t\tproperties: {\n\t\t\toperation: {\n\t\t\t\ttype: 'string',\n\t\t\t\tenum: ['insert_text', 'replace_range', 'set_variable', 'select'],\n\t\t\t\tdescription: 'The prompt operation to execute.'\n\t\t\t},\n\t\t\ttext: {\n\t\t\t\ttype: 'string',\n\t\t\t\tdescription: 'Text to insert or replace.'\n\t\t\t},\n\t\t\tat: {\n\t\t\t\ttype: 'number',\n\t\t\t\tdescription: 'Position to insert text at.'\n\t\t\t},\n\t\t\tfrom: {\n\t\t\t\ttype: 'number',\n\t\t\t\tdescription: 'Start offset for replace_range or select.'\n\t\t\t},\n\t\t\tto: {\n\t\t\t\ttype: 'number',\n\t\t\t\tdescription: 'End offset for replace_range or select.'\n\t\t\t},\n\t\t\tname: {\n\t\t\t\ttype: 'string',\n\t\t\t\tdescription: 'Variable name for set_variable.'\n\t\t\t},\n\t\t\tvalue: {\n\t\t\t\tdescription: 'Variable value for set_variable.'\n\t\t\t}\n\t\t},\n\t\trequired: ['operation']\n\t}\n} as const;\n\nexport const MCP_TOOL_VIEW_EDITOR = {\n\tname: 'view_editor',\n\ttitle: 'View the editor',\n\tannotations: {\n\t\ttitle: 'View the editor',\n\t\treadOnlyHint: true,\n\t\tdestructiveHint: false,\n\t\tidempotentHint: true,\n\t\topenWorldHint: false\n\t},\n\tdescription:\n\t\t'Captures a visual image snapshot (JPEG or PNG) of the editor canvas or viewport for multimodal evaluation. Active agent cursor indicators are automatically excluded from the snapshot.',\n\tinputSchema: {\n\t\ttype: 'object',\n\t\tproperties: {\n\t\t\tscope: {\n\t\t\t\ttype: 'string',\n\t\t\t\tenum: ['viewport', 'canvas'],\n\t\t\t\tdescription: 'Whether to capture only the visible viewport or the full canvas bounding box (default: viewport).'\n\t\t\t},\n\t\t\tformat: {\n\t\t\t\ttype: 'string',\n\t\t\t\tenum: ['jpeg', 'png'],\n\t\t\t\tdescription: 'Image format of the base64 snapshot (default: jpeg).'\n\t\t\t},\n\t\t\tmaxEdge: {\n\t\t\t\ttype: 'integer',\n\t\t\t\tdescription: 'Maximum width or height dimension in pixels (default: 1024).'\n\t\t\t}\n\t\t}\n\t}\n} as const;\n\n/**\n * CSS selectors for ephemeral UI overlays (such as agent cursors, presence tags, and transient bubbles)\n * that should be excluded during canvas image export and visual snapshot generation.\n */\nexport const EXPORT_EXCLUDED_SELECTORS = [\n\t'.pixerate-presence',\n\t'.agent-presence',\n\t'.ursula-presence'\n] as const;\n\nexport const EDITOR_MCP_TOOLS = [\n\tMCP_TOOL_GET_EDITOR_STATE,\n\tMCP_TOOL_EDIT_CANVAS,\n\tMCP_TOOL_EDIT_PROMPT,\n\tMCP_TOOL_VIEW_EDITOR\n] as const;\n\n"]}
|