@pixerate/editor 0.139.1 → 0.140.1

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.
Files changed (152) hide show
  1. package/README.md +25 -4
  2. package/dist/agent/formatTools.d.cts +15 -0
  3. package/dist/agent/formatTools.d.ts +15 -0
  4. package/dist/agent/index.cjs +408 -49
  5. package/dist/agent/index.js +375 -16
  6. package/dist/agent/providers.d.cts +5 -3
  7. package/dist/agent/providers.d.ts +5 -3
  8. package/dist/animation-editor/effect-tools.d.cts +1 -1
  9. package/dist/animation-editor/effect-tools.d.ts +1 -1
  10. package/dist/animation-editor/index.cjs +250 -116
  11. package/dist/animation-editor/index.js +228 -94
  12. package/dist/animation-editor/instructions.d.cts +1 -1
  13. package/dist/animation-editor/instructions.d.ts +1 -1
  14. package/dist/animation-editor/parse.d.cts +3 -1
  15. package/dist/animation-editor/parse.d.ts +3 -1
  16. package/dist/animation-editor/tools.d.cts +8 -3
  17. package/dist/animation-editor/tools.d.ts +8 -3
  18. package/dist/bridge/cli.cjs +4 -3
  19. package/dist/bridge/cli.js +3 -2
  20. package/dist/bridge/index.cjs +8 -3
  21. package/dist/bridge/index.d.cts +7 -0
  22. package/dist/bridge/index.d.ts +7 -0
  23. package/dist/bridge/index.js +9 -4
  24. package/dist/bridge/skills.d.cts +9 -0
  25. package/dist/bridge/skills.d.ts +9 -0
  26. package/dist/canvas/effect-tools.d.cts +1 -1
  27. package/dist/canvas/effect-tools.d.ts +1 -1
  28. package/dist/canvas/index.cjs +22 -17
  29. package/dist/canvas/index.js +8 -3
  30. package/dist/chart/file-tools.d.cts +1 -1
  31. package/dist/chart/file-tools.d.ts +1 -1
  32. package/dist/chart/index.cjs +7 -1
  33. package/dist/chart/index.js +7 -1
  34. package/dist/chart/tools.d.cts +1 -1
  35. package/dist/chart/tools.d.ts +1 -1
  36. package/dist/chunk-2BSBFBOA.cjs +46 -0
  37. package/dist/{chunk-SWZTQWY7.js → chunk-2INPJDNY.js} +1 -1
  38. package/dist/{chunk-CCKP4XAN.cjs → chunk-34RQAGWI.cjs} +27 -7
  39. package/dist/{chunk-HXCBQ7A6.cjs → chunk-3AJMR7EG.cjs} +7 -4
  40. package/dist/{chunk-BKMU3V6K.js → chunk-5ED73EC6.js} +8 -1
  41. package/dist/{chunk-NKBUVQJW.cjs → chunk-5WOY52O6.cjs} +15 -15
  42. package/dist/{chunk-VRIR53SW.js → chunk-6GAYGQDC.js} +10 -8
  43. package/dist/{chunk-HZZXBTLB.js → chunk-6IN474P4.js} +25 -5
  44. package/dist/{chunk-KHMVB3SJ.js → chunk-7KWJEYIK.js} +4 -1
  45. package/dist/{chunk-R47NQICB.cjs → chunk-AGCD3EHB.cjs} +47 -10
  46. package/dist/{chunk-6I63VZ45.js → chunk-CXXKJBQZ.js} +5 -1
  47. package/dist/{chunk-6NXVDJDR.cjs → chunk-G43MNQ4C.cjs} +5 -5
  48. package/dist/chunk-HDK3T2QS.cjs +1159 -0
  49. package/dist/chunk-HF5QZS7Z.js +46 -0
  50. package/dist/{chunk-S7I3RI5Z.cjs → chunk-HMGWFXEC.cjs} +27 -24
  51. package/dist/{chunk-6NCBFBXA.js → chunk-IQ6KKXOU.js} +1 -1
  52. package/dist/{chunk-T6Y5FV7G.cjs → chunk-L434J57V.cjs} +10 -8
  53. package/dist/{chunk-UCRL6JEV.cjs → chunk-L5OWG2NA.cjs} +8 -3
  54. package/dist/{chunk-CZRWP6IW.cjs → chunk-N2FGYZ4Q.cjs} +8 -1
  55. package/dist/{chunk-GUPQ5BNA.cjs → chunk-PUR6BZFA.cjs} +112 -111
  56. package/dist/chunk-RB62U6MS.js +1159 -0
  57. package/dist/{chunk-3V746PF4.cjs → chunk-RUZQMYXH.cjs} +4 -1
  58. package/dist/{chunk-HGHXGCKG.cjs → chunk-SVFEVKLF.cjs} +1 -1
  59. package/dist/{chunk-PCNCT4ZY.js → chunk-UMS6YFA6.js} +40 -3
  60. package/dist/{chunk-4LGWAJDI.js → chunk-V5OOP74P.js} +5 -2
  61. package/dist/{chunk-BWT4IWLK.cjs → chunk-VKF3PWKR.cjs} +7 -7
  62. package/dist/{chunk-PQMADRCI.js → chunk-WBJ6BG4R.js} +23 -22
  63. package/dist/{chunk-WIYAOZZU.js → chunk-WHKNYFM2.js} +7 -2
  64. package/dist/{chunk-TBSPPVTT.js → chunk-XCK7QK5D.js} +1 -1
  65. package/dist/{chunk-F652BKMS.cjs → chunk-YN6JKAUE.cjs} +6 -2
  66. package/dist/{chunk-YTGF4TJR.js → chunk-ZLZKGHSZ.js} +5 -2
  67. package/dist/{chunk-USU2FL3N.js → chunk-ZNHB5RG6.js} +1 -1
  68. package/dist/commands/agentTools.d.cts +1 -1
  69. package/dist/commands/agentTools.d.ts +1 -1
  70. package/dist/commands/index.cjs +3 -0
  71. package/dist/commands/index.js +3 -0
  72. package/dist/compare/index.cjs +4 -3
  73. package/dist/compare/index.js +3 -2
  74. package/dist/diagram/index.cjs +3 -0
  75. package/dist/diagram/index.js +3 -0
  76. package/dist/diagram/tools.d.cts +1 -1
  77. package/dist/diagram/tools.d.ts +1 -1
  78. package/dist/effects/index.cjs +32 -32
  79. package/dist/effects/index.js +1 -1
  80. package/dist/effects/tools.d.cts +5 -1
  81. package/dist/effects/tools.d.ts +5 -1
  82. package/dist/export/index.cjs +4 -3
  83. package/dist/export/index.js +3 -2
  84. package/dist/extensions/index.cjs +11 -8
  85. package/dist/extensions/index.d.cts +1 -0
  86. package/dist/extensions/index.d.ts +1 -0
  87. package/dist/extensions/index.js +10 -7
  88. package/dist/extensions/safe-merge-attributes.d.cts +10 -0
  89. package/dist/extensions/safe-merge-attributes.d.ts +10 -0
  90. package/dist/generation/index.cjs +7 -1
  91. package/dist/generation/index.js +7 -1
  92. package/dist/image-editor/index.cjs +25 -18
  93. package/dist/image-editor/index.js +10 -3
  94. package/dist/image-editor/provider-effect-tools.d.cts +1 -1
  95. package/dist/image-editor/provider-effect-tools.d.ts +1 -1
  96. package/dist/image-editor/tools.d.cts +1 -1
  97. package/dist/image-editor/tools.d.ts +1 -1
  98. package/dist/index.cjs +42 -29
  99. package/dist/index.d.cts +1 -0
  100. package/dist/index.d.ts +1 -0
  101. package/dist/index.js +22 -9
  102. package/dist/paint-editor/effect-tools.d.cts +1 -1
  103. package/dist/paint-editor/effect-tools.d.ts +1 -1
  104. package/dist/paint-editor/index.cjs +18 -8
  105. package/dist/paint-editor/index.js +13 -3
  106. package/dist/paint-editor/tools.d.cts +1 -1
  107. package/dist/paint-editor/tools.d.ts +1 -1
  108. package/dist/persistence/index.cjs +3 -2
  109. package/dist/persistence/index.js +2 -1
  110. package/dist/serializers/index.cjs +5 -4
  111. package/dist/serializers/index.js +4 -3
  112. package/dist/tools/bridge-client.d.cts +3 -3
  113. package/dist/tools/bridge-client.d.ts +3 -3
  114. package/dist/tools/capture.d.cts +5 -1
  115. package/dist/tools/capture.d.ts +5 -1
  116. package/dist/tools/definitions.d.cts +2 -2
  117. package/dist/tools/definitions.d.ts +2 -2
  118. package/dist/tools/index.cjs +39 -5
  119. package/dist/tools/index.d.cts +4 -0
  120. package/dist/tools/index.d.ts +4 -0
  121. package/dist/tools/index.js +39 -5
  122. package/dist/tools/mcp-server.d.cts +24 -6
  123. package/dist/tools/mcp-server.d.ts +24 -6
  124. package/dist/tools/registry.d.cts +81 -6
  125. package/dist/tools/registry.d.ts +81 -6
  126. package/dist/tools/safe-json.d.cts +27 -0
  127. package/dist/tools/safe-json.d.ts +27 -0
  128. package/dist/tools/search.d.cts +30 -0
  129. package/dist/tools/search.d.ts +30 -0
  130. package/dist/tools/skills.d.cts +26 -0
  131. package/dist/tools/skills.d.ts +26 -0
  132. package/dist/tools/view.d.cts +95 -0
  133. package/dist/tools/view.d.ts +95 -0
  134. package/dist/vector/effect-tools.d.cts +1 -1
  135. package/dist/vector/effect-tools.d.ts +1 -1
  136. package/dist/vector/index.cjs +13 -7
  137. package/dist/vector/index.js +8 -2
  138. package/dist/video-editor/effect-tools.d.cts +1 -1
  139. package/dist/video-editor/effect-tools.d.ts +1 -1
  140. package/dist/video-editor/index.cjs +275 -269
  141. package/dist/video-editor/index.js +8 -2
  142. package/dist/video-editor/tools.d.cts +1 -1
  143. package/dist/video-editor/tools.d.ts +1 -1
  144. package/package.json +31 -29
  145. package/skills/README.md +8 -3
  146. package/skills/pixerate-agent-tools/SKILL.md +33 -7
  147. package/skills/pixerate-animation-editor/SKILL.md +7 -0
  148. package/skills/pixerate-rich-text/SKILL.md +18 -4
  149. package/dist/chunk-5RRYDFU2.js +0 -466
  150. package/dist/chunk-SPVIXXIB.cjs +0 -466
  151. /package/dist/{chunk-SMJK5HBJ.js → chunk-K73HMKQP.js} +0 -0
  152. /package/dist/{chunk-DDF6WQ62.cjs → chunk-LACYURUW.cjs} +0 -0
@@ -12,20 +12,33 @@ import {
12
12
  placeBeside
13
13
  } from "../chunk-BTZS3KZY.js";
14
14
  import "../chunk-7KZ2HKKC.js";
15
- import "../chunk-SMJK5HBJ.js";
15
+ import "../chunk-K73HMKQP.js";
16
16
  import {
17
17
  JSON_RPC_ERRORS,
18
18
  MCP_PROTOCOL_VERSIONS,
19
19
  TOOL_BRIDGE_DEFAULT_PORT,
20
20
  TOOL_BRIDGE_PROTOCOL,
21
+ TOOL_DISCOVERY_TOOLS,
21
22
  TOOL_NAMESPACE_SEPARATOR,
22
23
  ToolRegistry,
23
24
  ToolRegistryError,
25
+ ToolRegistryView,
26
+ baseToolName,
24
27
  connectToolBridge,
25
28
  createMcpServer,
26
29
  createToolRegistry,
27
- toToolResult
28
- } from "../chunk-5RRYDFU2.js";
30
+ errorResult,
31
+ listSkills,
32
+ parseSkillFrontmatter,
33
+ readSkillFile,
34
+ searchTokens,
35
+ searchTools,
36
+ summarize,
37
+ toToolResult,
38
+ toolsetInstructions,
39
+ toolsetName,
40
+ unknownToolMessage
41
+ } from "../chunk-RB62U6MS.js";
29
42
  import {
30
43
  CAPTURE_EXCLUDE_SELECTOR,
31
44
  CAPTURE_OVERLAY_SELECTORS,
@@ -53,7 +66,7 @@ import {
53
66
  createElementCaptureSurface,
54
67
  elementToSvg,
55
68
  rasterizeElement
56
- } from "../chunk-TBSPPVTT.js";
69
+ } from "../chunk-XCK7QK5D.js";
57
70
  import {
58
71
  captureInputSchema,
59
72
  captureOutputSize,
@@ -62,7 +75,7 @@ import {
62
75
  resolveCaptureRequest,
63
76
  toCapturedImageData,
64
77
  unionCaptureRects
65
- } from "../chunk-BKMU3V6K.js";
78
+ } from "../chunk-5ED73EC6.js";
66
79
  import {
67
80
  DEFAULT_AGENT_CARET_COLOR,
68
81
  DEFAULT_AGENT_CARET_NAME,
@@ -83,7 +96,7 @@ import {
83
96
  setAgentCaret,
84
97
  sparklineLabel,
85
98
  typeAgentText
86
- } from "../chunk-VRIR53SW.js";
99
+ } from "../chunk-6GAYGQDC.js";
87
100
  import {
88
101
  describeChart
89
102
  } from "../chunk-KI2VBONS.js";
@@ -95,9 +108,14 @@ import {
95
108
  import {
96
109
  getEditorMarkdown,
97
110
  getEditorText
98
- } from "../chunk-SWZTQWY7.js";
111
+ } from "../chunk-2INPJDNY.js";
99
112
  import "../chunk-RTRQ7XFI.js";
100
- import "../chunk-HZZXBTLB.js";
113
+ import "../chunk-6IN474P4.js";
114
+ import {
115
+ UNSAFE_JSON_KEYS,
116
+ isUnsafeJsonKey,
117
+ stripPrototypeKeys
118
+ } from "../chunk-HF5QZS7Z.js";
101
119
  import {
102
120
  isSingleCellRange,
103
121
  normalizeRange,
@@ -438,7 +456,8 @@ function planToolCall(name, args, snapshot, options) {
438
456
  }
439
457
 
440
458
  // src/agent/providers.ts
441
- import { TextSelection } from "@tiptap/pm/state";
459
+ import { TextSelection as TextSelection2 } from "@tiptap/pm/state";
460
+ import { closeHistory as closeHistory3 } from "@tiptap/pm/history";
442
461
 
443
462
  // src/agent/documentChartTools.ts
444
463
  import { closeHistory } from "@tiptap/pm/history";
@@ -636,6 +655,309 @@ function createDocumentChartTools(editor) {
636
655
  };
637
656
  }
638
657
 
658
+ // src/agent/formatTools.ts
659
+ import { closeHistory as closeHistory2 } from "@tiptap/pm/history";
660
+ import { TextSelection } from "@tiptap/pm/state";
661
+ var WRITE_IDEMPOTENT2 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
662
+ var TOGGLE_MARKS = [
663
+ ["bold", "bold", "Bold (strong) text."],
664
+ ["italic", "italic", "Italic (emphasis)."],
665
+ ["underline", "underline", "Underlined text."],
666
+ ["strike", "strike", "Struck-through text."],
667
+ ["code", "code", "Inline code (monospace; in most schemas it removes the other marks)."],
668
+ ["subscript", "subscript", "Subscript."],
669
+ ["superscript", "superscript", "Superscript."]
670
+ ];
671
+ var BLOCK_TYPES = [
672
+ ["paragraph", "paragraph", "a plain paragraph (also takes the blocks out of lists, quotes and code blocks)"],
673
+ ["heading", "heading", "a heading of `level`"],
674
+ ["bullet_list", "bulletList", "items of a bulleted list"],
675
+ ["ordered_list", "orderedList", "items of a numbered list"],
676
+ ["task_list", "taskList", "items of a checklist"],
677
+ ["blockquote", "blockquote", "a quote"],
678
+ ["code_block", "codeBlock", "a code block (plain text: marks are dropped)"]
679
+ ];
680
+ var LIST_ITEMS = { bulletList: "listItem", orderedList: "listItem", taskList: "taskItem" };
681
+ var UNSAFE_LINK = /^\s*(javascript|data|vbscript):/i;
682
+ var RANGE_PROPERTIES = {
683
+ from: { type: "integer", minimum: 0, description: "Start document position (from find_text or get_text `blocks`). Default: the selection." },
684
+ to: { type: "integer", minimum: 0, description: "End document position. Default: the selection." }
685
+ };
686
+ function targetRange(editor, args, allowEmpty) {
687
+ if (args.from === void 0 !== (args.to === void 0)) throw new Error('Pass both "from" and "to", or neither to use the selection.');
688
+ const { from, to } = args.from === void 0 ? editor.state.selection : { from: args.from, to: args.to };
689
+ const size = editor.state.doc.content.size;
690
+ if (from > to) throw new Error(`"from" (${from}) must not be after "to" (${to}).`);
691
+ if (to > size) throw new Error(`Position ${to} is outside the document (size ${size}).`);
692
+ if (!allowEmpty && from === to) {
693
+ throw new Error('The range is empty: pass "from" and "to" around the text (find_text returns them), or select it first.');
694
+ }
695
+ return { from, to };
696
+ }
697
+ function checkEditable(editor) {
698
+ if (!editor.isEditable) throw new Error("The document is read-only, so it cannot be formatted.");
699
+ }
700
+ function selectionGuard(editor, range) {
701
+ const before = editor.state.selection;
702
+ return {
703
+ select: ({ tr }) => {
704
+ closeHistory2(tr);
705
+ tr.setSelection(TextSelection.between(tr.doc.resolve(range.from), tr.doc.resolve(range.to)));
706
+ return true;
707
+ },
708
+ restore: ({ tr }) => {
709
+ const anchor = tr.mapping.map(before.anchor);
710
+ const head = tr.mapping.map(before.head);
711
+ tr.setSelection(TextSelection.between(tr.doc.resolve(anchor), tr.doc.resolve(head)));
712
+ return true;
713
+ },
714
+ /** The acted-on range in the changed document. */
715
+ mapped: (tr) => ({ from: tr.mapping.map(range.from, -1), to: tr.mapping.map(range.to, 1) })
716
+ };
717
+ }
718
+ function blocksIn(doc, from, to) {
719
+ const blocks = [];
720
+ doc.nodesBetween(from, Math.max(to, from + 1), (node, pos, parent) => {
721
+ if (!node.isTextblock) return true;
722
+ const $pos = doc.resolve(pos + 1);
723
+ let wrapper;
724
+ for (let d = $pos.depth - 1; d > 0; d--) {
725
+ const name = $pos.node(d).type.name;
726
+ if (name === "bulletList" || name === "orderedList" || name === "taskList" || name === "blockquote") {
727
+ wrapper = name;
728
+ break;
729
+ }
730
+ }
731
+ blocks.push({
732
+ type: node.type.name,
733
+ from: pos + 1,
734
+ to: pos + 1 + node.content.size,
735
+ text: node.textContent,
736
+ ...node.attrs.level !== void 0 ? { level: node.attrs.level } : {},
737
+ ...node.attrs.textAlign ? { align: node.attrs.textAlign } : {},
738
+ ...wrapper ? { in: wrapper } : {},
739
+ ...parent && parent.type.name === "taskItem" ? { checked: !!parent.attrs.checked } : {}
740
+ });
741
+ return false;
742
+ });
743
+ return blocks;
744
+ }
745
+ function marksOn(doc, schema, from, to) {
746
+ const out = {};
747
+ for (const [arg, mark] of TOGGLE_MARKS) {
748
+ const type = schema.marks[mark];
749
+ if (!type) continue;
750
+ let all = true;
751
+ let any = false;
752
+ doc.nodesBetween(from, to, (node) => {
753
+ if (!node.isText) return true;
754
+ if (type.isInSet(node.marks)) any = true;
755
+ else all = false;
756
+ return false;
757
+ });
758
+ if (any) out[arg] = all ? true : "partly";
759
+ }
760
+ const attrOf = (markName, attr) => {
761
+ const values = /* @__PURE__ */ new Set();
762
+ doc.nodesBetween(from, to, (node) => {
763
+ if (!node.isText) return true;
764
+ const mark = node.marks.find((m) => m.type.name === markName);
765
+ values.add(mark ? mark.attrs[attr] ?? null : null);
766
+ return false;
767
+ });
768
+ const [only] = values;
769
+ return values.size === 1 ? only : values.size > 1 ? "mixed" : null;
770
+ };
771
+ if (schema.marks.link) {
772
+ const href = attrOf("link", "href");
773
+ if (href !== null) out.link = href;
774
+ }
775
+ if (schema.marks.highlight) {
776
+ const color = attrOf("highlight", "color");
777
+ if (color !== null) out.highlight = color;
778
+ }
779
+ if (schema.marks.textStyle) {
780
+ const color = attrOf("textStyle", "color");
781
+ if (color !== null) out.color = color;
782
+ const size = attrOf("textStyle", "fontSize");
783
+ if (size !== null) out.fontSize = size;
784
+ }
785
+ return out;
786
+ }
787
+ function createDocumentFormatTools(editor, changed) {
788
+ const formatText = (ed) => {
789
+ const { schema } = ed;
790
+ const has = (name) => !!schema.marks[name];
791
+ const hasAttr = (mark, attr) => !!schema.marks[mark]?.spec.attrs?.[attr];
792
+ const properties = { ...RANGE_PROPERTIES };
793
+ for (const [arg, mark, what] of TOGGLE_MARKS) {
794
+ if (has(mark)) properties[arg] = { type: "boolean", description: `${what} true sets it, false clears it; omit to leave it.` };
795
+ }
796
+ if (has("link")) {
797
+ properties.link = {
798
+ type: ["string", "null"],
799
+ minLength: 1,
800
+ description: "Link the text to this URL (https://\u2026, mailto:\u2026), or null to remove links. Omit to leave links."
801
+ };
802
+ }
803
+ if (has("highlight")) {
804
+ properties.highlight = {
805
+ type: ["string", "null"],
806
+ minLength: 1,
807
+ maxLength: 64,
808
+ description: 'Highlight (background) colour as a CSS colour, e.g. "#fef08a" or "yellow", or null to remove it.'
809
+ };
810
+ }
811
+ if (hasAttr("textStyle", "color")) {
812
+ properties.color = { type: ["string", "null"], minLength: 1, maxLength: 64, description: "Text colour as a CSS colour, or null for the default colour." };
813
+ }
814
+ if (hasAttr("textStyle", "fontSize")) {
815
+ properties.fontSize = { type: ["string", "null"], pattern: "^\\d+(\\.\\d+)?(px|pt|em|rem|%)$", description: 'Font size with a unit, e.g. "18px" or "1.25em", or null for the default size.' };
816
+ }
817
+ const formatting = Object.keys(properties).filter((k) => k !== "from" && k !== "to");
818
+ if (formatting.length === 0) return null;
819
+ return {
820
+ name: "format_text",
821
+ title: "Format text",
822
+ description: `Sets or clears inline formatting on a range of text (or the selection): ${formatting.join(", ")}. Only the properties you pass change. Positions come from find_text or get_text \`blocks\`. One undo step; the selection is left where it was. Returns the \`range\` and the formatting now on it (\`partly\` / \`mixed\` where only some of the text has it). For headings and lists use set_block_type.`,
823
+ inputSchema: { type: "object", properties, additionalProperties: false },
824
+ annotations: { title: "Format text", ...WRITE_IDEMPOTENT2 },
825
+ handler: (args) => {
826
+ const ed2 = editor();
827
+ checkEditable(ed2);
828
+ const asked = formatting.filter((k) => args[k] !== void 0);
829
+ if (asked.length === 0) throw new Error(`Pass at least one formatting property: ${formatting.join(", ")}.`);
830
+ const range = targetRange(ed2, args, false);
831
+ if (typeof args.link === "string" && UNSAFE_LINK.test(args.link)) {
832
+ throw new Error("Links may not use javascript:, data: or vbscript: URLs. Nothing was changed.");
833
+ }
834
+ const guard = selectionGuard(ed2, range);
835
+ let tr = null;
836
+ let chain = ed2.chain().command(guard.select);
837
+ for (const [arg, mark] of TOGGLE_MARKS) {
838
+ if (args[arg] === true) chain = chain.setMark(mark);
839
+ else if (args[arg] === false) chain = chain.unsetMark(mark, { extendEmptyMarkRange: false });
840
+ }
841
+ if (args.link === null) chain = chain.unsetMark("link");
842
+ else if (typeof args.link === "string") chain = chain.setMark("link", { href: args.link.trim() });
843
+ if (args.highlight === null) chain = chain.unsetMark("highlight");
844
+ else if (typeof args.highlight === "string") chain = chain.setMark("highlight", { color: args.highlight });
845
+ const style = {};
846
+ if (args.color !== void 0) style.color = args.color;
847
+ if (args.fontSize !== void 0) style.fontSize = args.fontSize;
848
+ if (Object.keys(style).length) {
849
+ chain = chain.setMark("textStyle", style);
850
+ if (Object.values(style).includes(null)) chain = chain.removeEmptyTextStyle();
851
+ }
852
+ chain.command((props) => {
853
+ tr = props.tr;
854
+ return guard.restore(props);
855
+ }).run();
856
+ const after = tr ? guard.mapped(tr) : range;
857
+ changed([after]);
858
+ const doc = ed2.state.doc;
859
+ return { range: after, text: doc.textBetween(after.from, after.to, "\n"), formatting: marksOn(doc, ed2.schema, after.from, after.to) };
860
+ }
861
+ };
862
+ };
863
+ const blockTypes = (ed) => BLOCK_TYPES.filter(([, node]) => !!ed.schema.nodes[node] && (!LIST_ITEMS[node] || !!ed.schema.nodes[LIST_ITEMS[node]]));
864
+ const headingLevels = (ed) => {
865
+ const ext = ed.extensionManager.extensions.find((e) => e.name === "heading");
866
+ return ext?.options?.levels ?? [1, 2, 3, 4, 5, 6];
867
+ };
868
+ const setBlockType = (ed) => {
869
+ const types = blockTypes(ed);
870
+ if (types.length < 2) return null;
871
+ const levels = ed.schema.nodes.heading ? headingLevels(ed) : [];
872
+ return {
873
+ name: "set_block_type",
874
+ title: "Set the block type",
875
+ description: "Turns every paragraph the range touches (or the one at the cursor) into " + types.map(([value, , what]) => `${value} (${what})`).join(", ") + ". The blocks are first taken out of any list, quote or code block, so one call switches between kinds. One undo step; the selection is left where it was. Returns the resulting `blocks` with their type, positions, text, level, alignment and the list or quote they are in.",
876
+ inputSchema: {
877
+ type: "object",
878
+ properties: {
879
+ ...RANGE_PROPERTIES,
880
+ type: { type: "string", enum: types.map(([value]) => value), description: "What the blocks become." },
881
+ ...levels.length ? { level: { type: "integer", enum: levels, description: `Heading level for type "heading" (${levels.join(", ")}; 1 is the largest).` } } : {}
882
+ },
883
+ required: ["type"],
884
+ additionalProperties: false
885
+ },
886
+ annotations: { title: "Set the block type", ...WRITE_IDEMPOTENT2 },
887
+ handler: (args) => {
888
+ const ed2 = editor();
889
+ checkEditable(ed2);
890
+ const type = args.type;
891
+ if (type === "heading" && args.level === void 0) throw new Error(`Pass a heading "level" (${levels.join(", ")}).`);
892
+ if (type !== "heading" && args.level !== void 0) throw new Error('"level" only applies to type "heading".');
893
+ const range = targetRange(ed2, args, true);
894
+ const node = BLOCK_TYPES.find(([value]) => value === type)[1];
895
+ const guard = selectionGuard(ed2, range);
896
+ let tr = null;
897
+ let chain = ed2.chain().command(guard.select).clearNodes();
898
+ if (type === "heading") chain = chain.setNode("heading", { level: args.level });
899
+ else if (type === "code_block") chain = chain.setNode("codeBlock");
900
+ else if (type === "blockquote") chain = chain.wrapIn("blockquote");
901
+ else if (LIST_ITEMS[node]) chain = chain.toggleList(node, LIST_ITEMS[node]);
902
+ const ok = chain.command((props) => {
903
+ tr = props.tr;
904
+ return guard.restore(props);
905
+ }).run();
906
+ if (!ok || !tr) throw new Error(`Those blocks cannot become ${type} here (for example inside a table cell or a code block). Nothing was changed.`);
907
+ const after = guard.mapped(tr);
908
+ changed([after]);
909
+ return { type, range: after, blocks: blocksIn(ed2.state.doc, after.from, after.to) };
910
+ }
911
+ };
912
+ };
913
+ const setTextAlign = (ed) => {
914
+ const ext = ed.extensionManager.extensions.find((e) => e.name === "textAlign");
915
+ if (!ext) return null;
916
+ const alignments = (ext.options?.alignments ?? ["left", "center", "right", "justify"]).slice();
917
+ const types = ext.options?.types ?? ["heading", "paragraph"];
918
+ return {
919
+ name: "set_text_align",
920
+ title: "Align text",
921
+ description: `Aligns every ${types.join(" and ")} the range touches (or the one at the cursor): ${alignments.join(", ")}, or null for the default. One undo step; the selection is left where it was. Returns the resulting \`blocks\` with their alignment.`,
922
+ inputSchema: {
923
+ type: "object",
924
+ properties: {
925
+ ...RANGE_PROPERTIES,
926
+ align: { type: ["string", "null"], enum: [...alignments, null], description: "The alignment, or null for the default (usually left)." }
927
+ },
928
+ required: ["align"],
929
+ additionalProperties: false
930
+ },
931
+ annotations: { title: "Align text", ...WRITE_IDEMPOTENT2 },
932
+ handler: (args) => {
933
+ const ed2 = editor();
934
+ checkEditable(ed2);
935
+ const range = targetRange(ed2, args, true);
936
+ const blocks = blocksIn(ed2.state.doc, range.from, range.to);
937
+ if (!blocks.some((b) => types.includes(b.type))) {
938
+ throw new Error(`Only ${types.join(" and ")} blocks can be aligned; the range has ${[...new Set(blocks.map((b) => b.type))].join(", ") || "no text blocks"}.`);
939
+ }
940
+ const guard = selectionGuard(ed2, range);
941
+ let tr = null;
942
+ const chain = ed2.chain().command(guard.select);
943
+ (args.align === null ? chain.unsetTextAlign() : chain.setTextAlign(args.align)).command((props) => {
944
+ tr = props.tr;
945
+ return guard.restore(props);
946
+ }).run();
947
+ const after = tr ? guard.mapped(tr) : range;
948
+ changed([after]);
949
+ return { align: args.align, range: after, blocks: blocksIn(ed2.state.doc, after.from, after.to) };
950
+ }
951
+ };
952
+ };
953
+ return {
954
+ /** The formatting tools this editor's schema supports. */
955
+ tools(ed) {
956
+ return [formatText(ed), setBlockType(ed), setTextAlign(ed)].filter((t) => t !== null);
957
+ }
958
+ };
959
+ }
960
+
639
961
  // src/agent/providers.ts
640
962
  var toEditor = (target) => "commands" in target ? target : target.editor;
641
963
  function selectionInfo(editor) {
@@ -707,7 +1029,7 @@ function createTextPresence(editor, providerId, option) {
707
1029
  touch();
708
1030
  return range2;
709
1031
  }
710
- const tr = replaceWithTextTransaction(ed.state, from, to, text);
1032
+ const tr = closeHistory3(replaceWithTextTransaction(ed.state, from, to, text));
711
1033
  const end = tr.mapping.map(to, 1);
712
1034
  const range = { from: Math.min(tr.mapping.map(from, -1), end), to: end };
713
1035
  ed.view.dispatch(tr.scrollIntoView());
@@ -744,6 +1066,7 @@ function createRichTextToolProvider(target, options) {
744
1066
  const editor = () => toEditor(target);
745
1067
  const charts = createDocumentChartTools(editor);
746
1068
  const presence = createTextPresence(editor, options.id, options.presence);
1069
+ const formatting = createDocumentFormatTools(editor, (ranges) => presence.changed(ranges.filter((r) => r.from < r.to)));
747
1070
  const getText = {
748
1071
  name: "get_text",
749
1072
  title: "Get document text",
@@ -889,7 +1212,7 @@ function createRichTextToolProvider(target, options) {
889
1212
  ...m,
890
1213
  replacement: String(replace).replace(/\r\n?|\n/g, "\r")
891
1214
  }));
892
- const tr = ed.state.tr;
1215
+ const tr = closeHistory3(ed.state.tr);
893
1216
  const ends = applyReplacements(tr, chosen);
894
1217
  ed.view.dispatch(tr.scrollIntoView());
895
1218
  const ranges = chosen.map((m, i) => ({ from: tr.mapping.map(m.from, -1), to: ends[i] }));
@@ -954,7 +1277,7 @@ function createRichTextToolProvider(target, options) {
954
1277
  const ed = editor();
955
1278
  checkRange(ed, from, to);
956
1279
  const { doc } = ed.state;
957
- ed.view.dispatch(ed.state.tr.setSelection(TextSelection.between(doc.resolve(from), doc.resolve(to))));
1280
+ ed.view.dispatch(ed.state.tr.setSelection(TextSelection2.between(doc.resolve(from), doc.resolve(to))));
958
1281
  const selection = selectionInfo(ed);
959
1282
  presence.show(selection.from, selection.to);
960
1283
  return { selection };
@@ -1018,7 +1341,7 @@ function createRichTextToolProvider(target, options) {
1018
1341
  if (at !== void 0) {
1019
1342
  const size = ed.state.doc.content.size;
1020
1343
  if (at > size) throw new Error(`Position ${at} is outside the document (size ${size}).`);
1021
- ed.view.dispatch(ed.state.tr.setSelection(TextSelection.near(ed.state.doc.resolve(at))));
1344
+ ed.view.dispatch(ed.state.tr.setSelection(TextSelection2.near(ed.state.doc.resolve(at))));
1022
1345
  }
1023
1346
  const action = operation;
1024
1347
  const state = getTableActionState(ed, action, params);
@@ -1035,11 +1358,14 @@ function createRichTextToolProvider(target, options) {
1035
1358
  return {
1036
1359
  id: options.id,
1037
1360
  namespace: options.namespace,
1361
+ title: "Document",
1362
+ description: "A rich text document: read and find text, insert, replace and format it, tables, and charts in the document.",
1363
+ skill: "pixerate-rich-text",
1038
1364
  tools: () => {
1039
1365
  const ed = editor();
1040
1366
  if (!ed || ed.isDestroyed) return [];
1041
1367
  if (!ed.isEditable) return [getText, findText, ...charts.read()];
1042
- const tools = [getText, findText, insertText, replaceText, replaceRange, replaceSelection, setSelection];
1368
+ const tools = [getText, findText, insertText, replaceText, replaceRange, replaceSelection, setSelection, ...formatting.tools(ed)];
1043
1369
  return [...tools, ...isTableEnabled(ed) ? [editTable] : [], ...charts.read(), ...charts.write()];
1044
1370
  },
1045
1371
  subscribe: (notify) => {
@@ -1387,6 +1713,9 @@ function createSpreadsheetToolProvider(controller, options) {
1387
1713
  return {
1388
1714
  id: options.id,
1389
1715
  namespace: options.namespace,
1716
+ title: "Spreadsheet",
1717
+ description: "A spreadsheet: read and set cells and ranges, insert and delete rows and columns, merge and transpose.",
1718
+ skill: "pixerate-spreadsheet",
1390
1719
  tools: [getRange, setCell, setRange, insertRows, deleteRows, insertColumns, deleteColumns, mergeCells, unmergeCells, transposeRange]
1391
1720
  };
1392
1721
  }
@@ -1452,7 +1781,14 @@ function createEditorMcpToolProvider(options) {
1452
1781
  }
1453
1782
  });
1454
1783
  }
1455
- return { id: options.id, namespace: options.namespace, tools };
1784
+ return {
1785
+ id: options.id,
1786
+ namespace: options.namespace,
1787
+ title: "Canvas and prompt editor",
1788
+ description: "The node canvas and the prompt: editor state, nodes and edges, layout, prompt text, and a view of the editor.",
1789
+ skill: "pixerate-canvas",
1790
+ tools
1791
+ };
1456
1792
  }
1457
1793
 
1458
1794
  // src/agent/componentTools.ts
@@ -1648,7 +1984,14 @@ function createCanvasComponentToolProvider(controller, options = { id: "canvas-c
1648
1984
  )
1649
1985
  );
1650
1986
  }
1651
- return { id: options.id, namespace: options.namespace, tools };
1987
+ return {
1988
+ id: options.id,
1989
+ namespace: options.namespace,
1990
+ title: "Canvas components",
1991
+ description: "Reusable canvas components: define them, place instances, manage variants and overrides.",
1992
+ skill: "pixerate-canvas",
1993
+ tools
1994
+ };
1652
1995
  }
1653
1996
  export {
1654
1997
  CAPTURE_EXCLUDE_SELECTOR,
@@ -1677,9 +2020,13 @@ export {
1677
2020
  MCP_TOOL_VIEW_EDITOR,
1678
2021
  TOOL_BRIDGE_DEFAULT_PORT,
1679
2022
  TOOL_BRIDGE_PROTOCOL,
2023
+ TOOL_DISCOVERY_TOOLS,
1680
2024
  TOOL_NAMESPACE_SEPARATOR,
1681
2025
  ToolRegistry,
1682
2026
  ToolRegistryError,
2027
+ ToolRegistryView,
2028
+ UNSAFE_JSON_KEYS,
2029
+ baseToolName,
1683
2030
  captureInputSchema,
1684
2031
  captureOutputSize,
1685
2032
  cloneElementWithStyles,
@@ -1695,15 +2042,27 @@ export {
1695
2042
  createSpreadsheetToolProvider,
1696
2043
  createToolRegistry,
1697
2044
  elementToSvg,
2045
+ errorResult,
2046
+ isUnsafeJsonKey,
2047
+ listSkills,
1698
2048
  normalizeSide,
2049
+ parseSkillFrontmatter,
1699
2050
  planAgentCommand,
1700
2051
  planToolCall,
1701
2052
  rasterizeElement,
2053
+ readSkillFile,
1702
2054
  resolveCaptureRequest,
2055
+ searchTokens,
2056
+ searchTools,
2057
+ stripPrototypeKeys,
2058
+ summarize,
1703
2059
  toCapturedImageData,
1704
2060
  toToolResult,
1705
2061
  toolCallToAgentCommand,
2062
+ toolsetInstructions,
2063
+ toolsetName,
1706
2064
  unionCaptureRects,
2065
+ unknownToolMessage,
1707
2066
  validateAgentCommand,
1708
2067
  validateJsonSchema
1709
2068
  };
@@ -8,7 +8,7 @@ import { type AgentTypingOptions } from '../extensions/agent-caret.cjs';
8
8
  export interface ToolProviderOptions {
9
9
  /** Provider id (unique per registry). */
10
10
  id: string;
11
- /** Always prefix tool names with `<namespace>__`. */
11
+ /** Tool-name prefix (`<namespace>__<name>`); defaults to the provider id, `''` for bare names. */
12
12
  namespace?: string;
13
13
  }
14
14
  /** A TipTap editor, or anything exposing one as `.editor` (e.g. `EditorController`). */
@@ -42,8 +42,10 @@ export interface RichTextToolProviderOptions extends ToolProviderOptions {
42
42
  }
43
43
  /**
44
44
  * Tools for a mounted rich-text editor: `get_text` and `find_text` (always),
45
- * plus `insert_text`, `replace_text`, `replace_range`, `replace_selection` and
46
- * `set_selection` while the editor is editable, `edit_table` when the
45
+ * plus `insert_text`, `replace_text`, `replace_range`, `replace_selection`,
46
+ * `set_selection` and the formatting tools (`format_text`, `set_block_type`,
47
+ * `set_text_align`, as far as the schema supports them) while the editor is
48
+ * editable, `edit_table` when the
47
49
  * schema has tables (`createRichTextPreset`'s `table`), and the chart tools
48
50
  * (`list_document_charts`; `insert_chart`, `update_chart_in_document` and
49
51
  * `insert_sparkline` while editable) when it has charts (`chart`).
@@ -8,7 +8,7 @@ import { type AgentTypingOptions } from '../extensions/agent-caret.js';
8
8
  export interface ToolProviderOptions {
9
9
  /** Provider id (unique per registry). */
10
10
  id: string;
11
- /** Always prefix tool names with `<namespace>__`. */
11
+ /** Tool-name prefix (`<namespace>__<name>`); defaults to the provider id, `''` for bare names. */
12
12
  namespace?: string;
13
13
  }
14
14
  /** A TipTap editor, or anything exposing one as `.editor` (e.g. `EditorController`). */
@@ -42,8 +42,10 @@ export interface RichTextToolProviderOptions extends ToolProviderOptions {
42
42
  }
43
43
  /**
44
44
  * Tools for a mounted rich-text editor: `get_text` and `find_text` (always),
45
- * plus `insert_text`, `replace_text`, `replace_range`, `replace_selection` and
46
- * `set_selection` while the editor is editable, `edit_table` when the
45
+ * plus `insert_text`, `replace_text`, `replace_range`, `replace_selection`,
46
+ * `set_selection` and the formatting tools (`format_text`, `set_block_type`,
47
+ * `set_text_align`, as far as the schema supports them) while the editor is
48
+ * editable, `edit_table` when the
47
49
  * schema has tables (`createRichTextPreset`'s `table`), and the chart tools
48
50
  * (`list_document_charts`; `insert_chart`, `update_chart_in_document` and
49
51
  * `insert_sparkline` while editable) when it has charts (`chart`).
@@ -8,7 +8,7 @@ import type { AnimationEditorController } from './controller.cjs';
8
8
  export interface AnimationEffectsToolProviderOptions {
9
9
  /** Provider id (unique per registry). Default `animation-effects`. */
10
10
  id?: string;
11
- /** Always prefix tool names with `<namespace>__`. */
11
+ /** Tool-name prefix (`<namespace>__<name>`); defaults to the provider id, `''` for bare names. */
12
12
  namespace?: string;
13
13
  /** The scene cannot be edited: write tools are hidden. A string is the reason. */
14
14
  readOnly?: boolean | string | (() => boolean | string);
@@ -8,7 +8,7 @@ import type { AnimationEditorController } from './controller.js';
8
8
  export interface AnimationEffectsToolProviderOptions {
9
9
  /** Provider id (unique per registry). Default `animation-effects`. */
10
10
  id?: string;
11
- /** Always prefix tool names with `<namespace>__`. */
11
+ /** Tool-name prefix (`<namespace>__<name>`); defaults to the provider id, `''` for bare names. */
12
12
  namespace?: string;
13
13
  /** The scene cannot be edited: write tools are hidden. A string is the reason. */
14
14
  readOnly?: boolean | string | (() => boolean | string);