@pixerate/editor 0.19.0 → 0.20.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.
Files changed (112) hide show
  1. package/README.md +91 -2
  2. package/dist/agent/index.cjs +625 -2
  3. package/dist/agent/index.cjs.map +1 -1
  4. package/dist/agent/index.d.cts +286 -2
  5. package/dist/agent/index.d.ts +286 -2
  6. package/dist/agent/index.js +624 -1
  7. package/dist/agent/index.js.map +1 -1
  8. package/dist/canvas/index.cjs +1240 -22
  9. package/dist/canvas/index.cjs.map +1 -1
  10. package/dist/canvas/index.d.cts +515 -3
  11. package/dist/canvas/index.d.ts +515 -3
  12. package/dist/canvas/index.js +1219 -1
  13. package/dist/canvas/index.js.map +1 -1
  14. package/dist/chunk-3TYMNULT.js +1367 -0
  15. package/dist/chunk-3TYMNULT.js.map +1 -0
  16. package/dist/chunk-4QPLEUL2.cjs +4480 -0
  17. package/dist/chunk-4QPLEUL2.cjs.map +1 -0
  18. package/dist/chunk-4SUNJZWB.cjs +553 -0
  19. package/dist/chunk-4SUNJZWB.cjs.map +1 -0
  20. package/dist/chunk-A7DKIA72.js +2657 -0
  21. package/dist/chunk-A7DKIA72.js.map +1 -0
  22. package/dist/chunk-AXV2ZW34.cjs +118 -0
  23. package/dist/chunk-AXV2ZW34.cjs.map +1 -0
  24. package/dist/chunk-B2ZRLN4S.js +118 -0
  25. package/dist/chunk-B2ZRLN4S.js.map +1 -0
  26. package/dist/chunk-CYFJCKC4.js +4480 -0
  27. package/dist/chunk-CYFJCKC4.js.map +1 -0
  28. package/dist/chunk-GVW4P7BG.js +2706 -0
  29. package/dist/chunk-GVW4P7BG.js.map +1 -0
  30. package/dist/chunk-JACER6TE.cjs +1 -0
  31. package/dist/chunk-JACER6TE.cjs.map +1 -0
  32. package/dist/chunk-JYRIOFEN.cjs +2657 -0
  33. package/dist/chunk-JYRIOFEN.cjs.map +1 -0
  34. package/dist/chunk-KYRZDWM4.js +299 -0
  35. package/dist/chunk-KYRZDWM4.js.map +1 -0
  36. package/dist/chunk-LA7PEGU3.cjs +299 -0
  37. package/dist/chunk-LA7PEGU3.cjs.map +1 -0
  38. package/dist/chunk-N7FG6CBO.js +1 -0
  39. package/dist/chunk-N7FG6CBO.js.map +1 -0
  40. package/dist/chunk-OYXSKQFR.js +553 -0
  41. package/dist/chunk-OYXSKQFR.js.map +1 -0
  42. package/dist/chunk-TVRC4KVT.cjs +1367 -0
  43. package/dist/chunk-TVRC4KVT.cjs.map +1 -0
  44. package/dist/chunk-U6NDQFOK.cjs +2706 -0
  45. package/dist/chunk-U6NDQFOK.cjs.map +1 -0
  46. package/dist/controller-OUdxPY-X.d.cts +754 -0
  47. package/dist/controller-OUdxPY-X.d.ts +754 -0
  48. package/dist/extensions/index.cjs +144 -3
  49. package/dist/extensions/index.cjs.map +1 -1
  50. package/dist/extensions/index.d.cts +9 -144
  51. package/dist/extensions/index.d.ts +9 -144
  52. package/dist/extensions/index.js +145 -4
  53. package/dist/grammar/index.cjs +31 -3
  54. package/dist/grammar/index.cjs.map +1 -1
  55. package/dist/grammar/index.d.cts +239 -19
  56. package/dist/grammar/index.d.ts +239 -19
  57. package/dist/grammar/index.js +31 -3
  58. package/dist/history/index.d.cts +2 -41
  59. package/dist/history/index.d.ts +2 -41
  60. package/dist/index-Ng1pG7JE.d.ts +899 -0
  61. package/dist/index-k3mFbPx_.d.cts +899 -0
  62. package/dist/index.cjs +457 -20
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +99 -12
  65. package/dist/index.d.ts +99 -12
  66. package/dist/index.js +457 -20
  67. package/dist/index.js.map +1 -1
  68. package/dist/registry-iAHbqkYt.d.cts +128 -0
  69. package/dist/registry-iAHbqkYt.d.ts +128 -0
  70. package/dist/serializers/index.cjs +26 -3
  71. package/dist/serializers/index.cjs.map +1 -1
  72. package/dist/serializers/index.d.cts +119 -6
  73. package/dist/serializers/index.d.ts +119 -6
  74. package/dist/serializers/index.js +24 -1
  75. package/dist/spreadsheet/index.cjs +122 -2
  76. package/dist/spreadsheet/index.cjs.map +1 -1
  77. package/dist/spreadsheet/index.d.cts +371 -313
  78. package/dist/spreadsheet/index.d.ts +371 -313
  79. package/dist/spreadsheet/index.js +127 -7
  80. package/dist/tokens-CyLZmIei.d.cts +76 -0
  81. package/dist/tokens-CyLZmIei.d.ts +76 -0
  82. package/dist/track-changes-G8JcWB8b.d.cts +306 -0
  83. package/dist/track-changes-G8JcWB8b.d.ts +306 -0
  84. package/dist/types-BZgcDsC5.d.cts +42 -0
  85. package/dist/types-BZgcDsC5.d.ts +42 -0
  86. package/dist/{types-JV3S8VeR.d.cts → types-DMe0vFB1.d.cts} +1 -1
  87. package/dist/{types-JV3S8VeR.d.ts → types-DMe0vFB1.d.ts} +1 -1
  88. package/package.json +1 -1
  89. package/dist/chunk-7FWEWE6T.js +0 -1888
  90. package/dist/chunk-7FWEWE6T.js.map +0 -1
  91. package/dist/chunk-AIZUKWTL.js +0 -1715
  92. package/dist/chunk-AIZUKWTL.js.map +0 -1
  93. package/dist/chunk-GLSIZKOX.js +0 -17
  94. package/dist/chunk-GLSIZKOX.js.map +0 -1
  95. package/dist/chunk-LDES3EOS.cjs +0 -1888
  96. package/dist/chunk-LDES3EOS.cjs.map +0 -1
  97. package/dist/chunk-LLUAKTLW.cjs +0 -532
  98. package/dist/chunk-LLUAKTLW.cjs.map +0 -1
  99. package/dist/chunk-MPPXH7U5.cjs +0 -336
  100. package/dist/chunk-MPPXH7U5.cjs.map +0 -1
  101. package/dist/chunk-O7LOPQMH.js +0 -336
  102. package/dist/chunk-O7LOPQMH.js.map +0 -1
  103. package/dist/chunk-QGVMBCT5.js +0 -532
  104. package/dist/chunk-QGVMBCT5.js.map +0 -1
  105. package/dist/chunk-SEDR75VH.cjs +0 -17
  106. package/dist/chunk-SEDR75VH.cjs.map +0 -1
  107. package/dist/chunk-YQCI4CCN.cjs +0 -1715
  108. package/dist/chunk-YQCI4CCN.cjs.map +0 -1
  109. package/dist/mention-Dcevh3ff.d.cts +0 -32
  110. package/dist/mention-Dcevh3ff.d.ts +0 -32
  111. package/dist/tokens-7kRTEtPb.d.cts +0 -39
  112. package/dist/tokens-7kRTEtPb.d.ts +0 -39
@@ -1,4 +1,14 @@
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; }
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
+
4
+
5
+ var _chunkTVRC4KVTcjs = require('../chunk-TVRC4KVT.cjs');
6
+
7
+
8
+
9
+
10
+ var _chunkJYRIOFENcjs = require('../chunk-JYRIOFEN.cjs');
11
+
2
12
 
3
13
 
4
14
 
@@ -203,11 +213,65 @@ function planAgentCommand(command, snapshot, options = {}) {
203
213
  }
204
214
  ];
205
215
  }
216
+ case "tool:call": {
217
+ return [
218
+ {
219
+ type: "step:tool_call",
220
+ name: command.name,
221
+ arguments: _nullishCoalesce(command.arguments, () => ( {}))
222
+ }
223
+ ];
224
+ }
206
225
  default: {
207
226
  return [];
208
227
  }
209
228
  }
210
229
  }
230
+ function toolCallToAgentCommand(name, args = {}) {
231
+ const ids = (value) => Array.isArray(value) && value.every((v) => typeof v === "string") ? value : null;
232
+ const num = (value) => typeof value === "number" && Number.isFinite(value);
233
+ if (name === "edit_canvas") {
234
+ switch (args.operation) {
235
+ case "add_node":
236
+ return args.node && typeof args.node === "object" ? { type: "canvas:add_node", node: args.node, nearNodeId: args.nearNodeId, side: args.side } : null;
237
+ case "remove_nodes":
238
+ return ids(args.nodeIds) ? { type: "canvas:remove_nodes", nodeIds: args.nodeIds } : null;
239
+ case "connect":
240
+ return typeof args.source === "string" && typeof args.target === "string" ? { type: "canvas:connect", source: args.source, target: args.target, label: args.label } : null;
241
+ case "update_node": {
242
+ const id = _nullishCoalesce(_optionalChain([args, 'access', _9 => _9.node, 'optionalAccess', _10 => _10.id]), () => ( args.id));
243
+ return typeof id === "string" ? { type: "canvas:update_node", id, data: _nullishCoalesce(_nullishCoalesce(_optionalChain([args, 'access', _11 => _11.node, 'optionalAccess', _12 => _12.data]), () => ( args.data)), () => ( {})) } : null;
244
+ }
245
+ case "layout":
246
+ return { type: "canvas:layout", direction: args.direction, incremental: args.incremental };
247
+ case "select":
248
+ return ids(args.nodeIds) ? { type: "canvas:select", nodeIds: args.nodeIds } : null;
249
+ case "highlight":
250
+ return ids(args.nodeIds) ? { type: "canvas:highlight", nodeIds: args.nodeIds } : null;
251
+ default:
252
+ return null;
253
+ }
254
+ }
255
+ if (name === "edit_prompt") {
256
+ switch (args.operation) {
257
+ case "insert_text":
258
+ return typeof args.text === "string" ? { type: "prompt:insert_text", text: args.text, at: num(args.at) ? args.at : void 0 } : null;
259
+ case "replace_range":
260
+ return typeof args.text === "string" && num(args.from) && num(args.to) ? { type: "prompt:replace_range", from: args.from, to: args.to, text: args.text } : null;
261
+ case "set_variable":
262
+ return typeof args.name === "string" ? { type: "prompt:set_variable", name: args.name, value: args.value } : null;
263
+ case "select":
264
+ return num(args.from) && num(args.to) ? { type: "prompt:select", from: args.from, to: args.to } : null;
265
+ default:
266
+ return null;
267
+ }
268
+ }
269
+ return { type: "tool:call", name, arguments: args };
270
+ }
271
+ function planToolCall(name, args, snapshot, options) {
272
+ const command = toolCallToAgentCommand(name, args);
273
+ return command ? planAgentCommand(command, snapshot, options) : [];
274
+ }
211
275
 
212
276
  // src/agent/tools.ts
213
277
  var MCP_TOOL_GET_EDITOR_STATE = {
@@ -362,6 +426,565 @@ var EDITOR_MCP_TOOLS = [
362
426
  MCP_TOOL_VIEW_EDITOR
363
427
  ];
364
428
 
429
+ // src/agent/schema.ts
430
+ function typeOf(value) {
431
+ if (value === null) return "null";
432
+ if (Array.isArray(value)) return "array";
433
+ if (typeof value === "number") return Number.isInteger(value) ? "integer" : "number";
434
+ if (typeof value === "string" || typeof value === "boolean" || typeof value === "object") {
435
+ return typeof value;
436
+ }
437
+ return "undefined";
438
+ }
439
+ function matchesType(value, type) {
440
+ const actual = typeOf(value);
441
+ if (type === "number") return actual === "number" || actual === "integer";
442
+ return actual === type;
443
+ }
444
+ var isEqual = (a, b) => a === b || JSON.stringify(a) === JSON.stringify(b);
445
+ function validateJsonSchema(value, schema, path = "") {
446
+ if (!schema || typeof schema !== "object") return [];
447
+ const errors = [];
448
+ const at = path || "/";
449
+ if (schema.type !== void 0) {
450
+ const types = Array.isArray(schema.type) ? schema.type : [schema.type];
451
+ if (!types.some((t) => matchesType(value, t))) {
452
+ errors.push({ path: at, message: `Expected ${types.join(" | ")}, got ${typeOf(value)}.` });
453
+ return errors;
454
+ }
455
+ }
456
+ if (schema.const !== void 0 && !isEqual(value, schema.const)) {
457
+ errors.push({ path: at, message: `Expected ${JSON.stringify(schema.const)}.` });
458
+ }
459
+ if (schema.enum && !schema.enum.some((option) => isEqual(value, option))) {
460
+ errors.push({
461
+ path: at,
462
+ message: `Expected one of ${schema.enum.map((o) => JSON.stringify(o)).join(", ")}, got ${JSON.stringify(value)}.`
463
+ });
464
+ }
465
+ if (typeof value === "string") {
466
+ if (schema.minLength !== void 0 && value.length < schema.minLength) {
467
+ errors.push({ path: at, message: `Must be at least ${schema.minLength} characters.` });
468
+ }
469
+ if (schema.maxLength !== void 0 && value.length > schema.maxLength) {
470
+ errors.push({ path: at, message: `Must be at most ${schema.maxLength} characters.` });
471
+ }
472
+ if (schema.pattern !== void 0) {
473
+ let regex = null;
474
+ try {
475
+ regex = new RegExp(schema.pattern, "u");
476
+ } catch (e2) {
477
+ }
478
+ if (regex && !regex.test(value)) {
479
+ errors.push({ path: at, message: `Must match pattern ${schema.pattern}.` });
480
+ }
481
+ }
482
+ }
483
+ if (typeof value === "number") {
484
+ if (schema.minimum !== void 0 && value < schema.minimum) {
485
+ errors.push({ path: at, message: `Must be >= ${schema.minimum}.` });
486
+ }
487
+ if (schema.maximum !== void 0 && value > schema.maximum) {
488
+ errors.push({ path: at, message: `Must be <= ${schema.maximum}.` });
489
+ }
490
+ }
491
+ if (Array.isArray(value)) {
492
+ if (schema.minItems !== void 0 && value.length < schema.minItems) {
493
+ errors.push({ path: at, message: `Must have at least ${schema.minItems} items.` });
494
+ }
495
+ if (schema.maxItems !== void 0 && value.length > schema.maxItems) {
496
+ errors.push({ path: at, message: `Must have at most ${schema.maxItems} items.` });
497
+ }
498
+ if (schema.items) {
499
+ value.forEach((item, index) => {
500
+ errors.push(...validateJsonSchema(item, schema.items, `${path}/${index}`));
501
+ });
502
+ }
503
+ }
504
+ if (typeOf(value) === "object") {
505
+ const obj = value;
506
+ for (const key of _nullishCoalesce(schema.required, () => ( []))) {
507
+ if (obj[key] === void 0) {
508
+ errors.push({ path: `${path}/${key}`, message: `Missing required property "${key}".` });
509
+ }
510
+ }
511
+ const properties = _nullishCoalesce(schema.properties, () => ( {}));
512
+ for (const [key, child] of Object.entries(obj)) {
513
+ if (child === void 0) continue;
514
+ if (key in properties) {
515
+ errors.push(...validateJsonSchema(child, properties[key], `${path}/${key}`));
516
+ } else if (schema.additionalProperties === false) {
517
+ errors.push({ path: `${path}/${key}`, message: `Unknown property "${key}".` });
518
+ } else if (typeof schema.additionalProperties === "object") {
519
+ errors.push(...validateJsonSchema(child, schema.additionalProperties, `${path}/${key}`));
520
+ }
521
+ }
522
+ }
523
+ return errors;
524
+ }
525
+
526
+ // src/agent/registry.ts
527
+ var ToolRegistryError = class extends Error {
528
+
529
+ constructor(code, message) {
530
+ super(message);
531
+ this.name = "ToolRegistryError";
532
+ this.code = code;
533
+ }
534
+ };
535
+ var TOOL_NAMESPACE_SEPARATOR = "__";
536
+ var TOOL_NAME_REGEX = /^[A-Za-z0-9_.-]{1,128}$/;
537
+ var sanitizeNamespace = (id) => id.replace(/[^A-Za-z0-9_-]/g, "_");
538
+ function readTools(provider) {
539
+ return typeof provider.tools === "function" ? provider.tools() : provider.tools;
540
+ }
541
+ function toDefinition(name, tool) {
542
+ const { handler: _handler, name: _name, ...rest } = tool;
543
+ return { name, ...rest };
544
+ }
545
+ function errorResult(error) {
546
+ const details = _optionalChain([error, 'access', _13 => _13.details, 'optionalAccess', _14 => _14.length]) ? "\n" + error.details.map((d) => `- ${d.path}: ${d.message}`).join("\n") : "";
547
+ return {
548
+ isError: true,
549
+ content: [{ type: "text", text: `${error.message}${details}` }],
550
+ structuredContent: { error }
551
+ };
552
+ }
553
+ function toToolResult(value) {
554
+ if (value && typeof value === "object" && Array.isArray(value.content)) {
555
+ return value;
556
+ }
557
+ if (value === void 0) return { content: [] };
558
+ if (typeof value === "string") return { content: [{ type: "text", text: value }] };
559
+ const text = JSON.stringify(value);
560
+ const isPlainObject = typeof value === "object" && value !== null && !Array.isArray(value);
561
+ return {
562
+ content: [{ type: "text", text: _nullishCoalesce(text, () => ( String(value))) }],
563
+ ...isPlainObject ? { structuredContent: value } : {}
564
+ };
565
+ }
566
+ var ToolRegistry = (_class = class {
567
+ /** MCP server capabilities this registry supports. */
568
+ __init() {this.capabilities = { tools: { listChanged: true } }}
569
+ __init2() {this.entries = []}
570
+ __init3() {this.listeners = /* @__PURE__ */ new Set()}
571
+
572
+ __init4() {this.timer = null}
573
+
574
+ constructor(options = {}) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);
575
+ this.options = {
576
+ onCollision: _nullishCoalesce(options.onCollision, () => ( "namespace")),
577
+ listChangedDelayMs: _nullishCoalesce(options.listChangedDelayMs, () => ( 0)),
578
+ validateArguments: _nullishCoalesce(options.validateArguments, () => ( true))
579
+ };
580
+ this.lastSignature = this.signature();
581
+ }
582
+ /**
583
+ * Registers a provider and returns a function that unregisters it.
584
+ * Throws a {@link ToolRegistryError} for a duplicate provider id, an invalid
585
+ * tool name, or (with `onCollision: 'error'`) a tool name collision.
586
+ */
587
+ register(provider) {
588
+ if (this.entries.some((e) => e.provider.id === provider.id)) {
589
+ throw new ToolRegistryError("duplicate_provider", `Tool provider "${provider.id}" is already registered.`);
590
+ }
591
+ for (const tool of readTools(provider)) {
592
+ if (!TOOL_NAME_REGEX.test(tool.name)) {
593
+ throw new ToolRegistryError("invalid_tool", `Invalid tool name "${tool.name}" from provider "${provider.id}".`);
594
+ }
595
+ }
596
+ const entry = { provider };
597
+ this.entries.push(entry);
598
+ try {
599
+ const names = this.resolve(this.options.onCollision === "error").map((t) => t.name);
600
+ const duplicate = names.find((name, i) => names.indexOf(name) !== i);
601
+ if (duplicate) {
602
+ throw new ToolRegistryError("name_collision", `Tool name "${duplicate}" is exposed more than once.`);
603
+ }
604
+ } catch (error) {
605
+ this.entries.pop();
606
+ throw error;
607
+ }
608
+ if (provider.subscribe) {
609
+ entry.unsubscribe = provider.subscribe(() => this.notifyListChanged());
610
+ }
611
+ this.notifyListChanged();
612
+ let registered = true;
613
+ return () => {
614
+ if (!registered) return;
615
+ registered = false;
616
+ this.unregister(provider);
617
+ };
618
+ }
619
+ /** Removes a provider by id or instance. Returns whether it was registered. */
620
+ unregister(providerOrId) {
621
+ const index = this.entries.findIndex(
622
+ (e) => typeof providerOrId === "string" ? e.provider.id === providerOrId : e.provider === providerOrId
623
+ );
624
+ if (index === -1) return false;
625
+ const [entry] = this.entries.splice(index, 1);
626
+ _optionalChain([entry, 'access', _15 => _15.unsubscribe, 'optionalCall', _16 => _16()]);
627
+ this.notifyListChanged();
628
+ return true;
629
+ }
630
+ /** Registered provider ids in registration order. */
631
+ providerIds() {
632
+ return this.entries.map((e) => e.provider.id);
633
+ }
634
+ /**
635
+ * Resolves exposed names. Tools are ordered by provider registration, then
636
+ * by their order within the provider.
637
+ */
638
+ resolve(throwOnCollision = false) {
639
+ const all = [];
640
+ const counts = /* @__PURE__ */ new Map();
641
+ for (const { provider } of this.entries) {
642
+ for (const tool of readTools(provider)) {
643
+ all.push({ name: tool.name, tool, provider });
644
+ if (!provider.namespace) counts.set(tool.name, (_nullishCoalesce(counts.get(tool.name), () => ( 0))) + 1);
645
+ }
646
+ }
647
+ for (const item of all) {
648
+ const prefix = _nullishCoalesce(item.provider.namespace, () => ( ((_nullishCoalesce(counts.get(item.name), () => ( 0))) > 1 ? item.provider.id : void 0)));
649
+ if (prefix !== void 0) {
650
+ if (throwOnCollision && !item.provider.namespace) {
651
+ throw new ToolRegistryError(
652
+ "name_collision",
653
+ `Tool "${item.name}" from provider "${item.provider.id}" collides with another provider's tool.`
654
+ );
655
+ }
656
+ item.name = `${sanitizeNamespace(prefix)}${TOOL_NAMESPACE_SEPARATOR}${item.name}`;
657
+ }
658
+ }
659
+ return all;
660
+ }
661
+ /** MCP `tools/list` result for the current providers. */
662
+ listTools() {
663
+ return { tools: this.resolve().map(({ name, tool }) => toDefinition(name, tool)) };
664
+ }
665
+ /** Whether a tool with this exposed name exists. */
666
+ hasTool(name) {
667
+ return this.resolve().some((t) => t.name === name);
668
+ }
669
+ /** Looks up a tool definition by exposed name. */
670
+ getTool(name) {
671
+ const found = this.resolve().find((t) => t.name === name);
672
+ return found ? toDefinition(found.name, found.tool) : void 0;
673
+ }
674
+ /**
675
+ * Calls a tool by exposed name and returns an MCP `tools/call` result.
676
+ * Never rejects: unknown tools, invalid arguments and handler errors come
677
+ * back as `isError: true` results with a {@link ToolCallError} in
678
+ * `structuredContent.error` (MCP transports may map `unknown_tool` to a
679
+ * JSON-RPC `-32602` error instead).
680
+ */
681
+ async callTool(name, args = {}, options = {}) {
682
+ const found = this.resolve().find((t) => t.name === name);
683
+ if (!found) {
684
+ return errorResult({ code: "unknown_tool", message: `Unknown tool "${name}".`, tool: name });
685
+ }
686
+ const input = _nullishCoalesce(args, () => ( {}));
687
+ if (this.options.validateArguments) {
688
+ const details = validateJsonSchema(input, found.tool.inputSchema);
689
+ if (details.length > 0) {
690
+ return errorResult({
691
+ code: "invalid_arguments",
692
+ message: `Invalid arguments for tool "${name}".`,
693
+ tool: name,
694
+ details
695
+ });
696
+ }
697
+ }
698
+ try {
699
+ const value = await found.tool.handler(input, {
700
+ name,
701
+ providerId: found.provider.id,
702
+ signal: options.signal
703
+ });
704
+ return toToolResult(value);
705
+ } catch (error) {
706
+ return errorResult({
707
+ code: "tool_failed",
708
+ message: error instanceof Error ? error.message : String(error),
709
+ tool: name
710
+ });
711
+ }
712
+ }
713
+ /**
714
+ * Subscribes to tool-list changes. Notifications are coalesced: many
715
+ * registrations or provider signals within the delay window produce one
716
+ * call, and none if the exposed list ends up unchanged (e.g. a provider
717
+ * unmounted and remounted). Returns an unsubscribe function.
718
+ */
719
+ onListChanged(listener) {
720
+ this.listeners.add(listener);
721
+ return () => {
722
+ this.listeners.delete(listener);
723
+ };
724
+ }
725
+ /** Schedules a coalesced `listChanged` check; providers may call it directly. */
726
+ notifyListChanged() {
727
+ if (this.timer !== null) return;
728
+ this.timer = setTimeout(() => this.flush(), this.options.listChangedDelayMs);
729
+ }
730
+ /** Runs a pending `listChanged` check immediately. */
731
+ flush() {
732
+ if (this.timer !== null) {
733
+ clearTimeout(this.timer);
734
+ this.timer = null;
735
+ }
736
+ const signature = this.signature();
737
+ if (signature === this.lastSignature) return;
738
+ this.lastSignature = signature;
739
+ const { tools } = this.listTools();
740
+ for (const listener of Array.from(this.listeners)) listener(tools);
741
+ }
742
+ signature() {
743
+ try {
744
+ return JSON.stringify(this.listTools().tools);
745
+ } catch (e3) {
746
+ return String(Math.random());
747
+ }
748
+ }
749
+ /** Unregisters every provider and listener and cancels pending notifications. */
750
+ dispose() {
751
+ if (this.timer !== null) clearTimeout(this.timer);
752
+ this.timer = null;
753
+ for (const entry of this.entries.splice(0)) _optionalChain([entry, 'access', _17 => _17.unsubscribe, 'optionalCall', _18 => _18()]);
754
+ this.listeners.clear();
755
+ }
756
+ }, _class);
757
+ function createToolRegistry(options) {
758
+ return new ToolRegistry(options);
759
+ }
760
+
761
+ // src/agent/providers.ts
762
+ var toEditor = (target) => "commands" in target ? target : target.editor;
763
+ function replaceWithText(editor, from, to, text) {
764
+ const { state, view } = editor;
765
+ const tr = /[\r\n]/.test(text) ? state.tr.replace(from, to, _chunkTVRC4KVTcjs.plainTextToSlice.call(void 0, text, state.schema)) : text ? state.tr.insertText(text, from, to) : state.tr.delete(from, to);
766
+ view.dispatch(tr.scrollIntoView());
767
+ }
768
+ function selectionInfo(editor) {
769
+ const { from, to } = editor.state.selection;
770
+ return { from, to, text: editor.state.doc.textBetween(from, to, "\n") };
771
+ }
772
+ function createRichTextToolProvider(target, options) {
773
+ const editor = () => toEditor(target);
774
+ const getText = {
775
+ name: "get_text",
776
+ description: "Returns the document content (plain text by default, or HTML / markdown) and the current selection.",
777
+ inputSchema: {
778
+ type: "object",
779
+ properties: {
780
+ format: {
781
+ type: "string",
782
+ enum: ["text", "html", "markdown"],
783
+ description: "Content format (default: text)."
784
+ }
785
+ },
786
+ additionalProperties: false
787
+ },
788
+ annotations: { readOnlyHint: true },
789
+ handler: ({ format = "text" }) => {
790
+ const ed = editor();
791
+ const content = format === "html" ? ed.getHTML() : format === "markdown" ? _chunkTVRC4KVTcjs.getEditorMarkdown.call(void 0, ed) : _chunkTVRC4KVTcjs.getEditorText.call(void 0, ed);
792
+ return { format, content, selection: selectionInfo(ed), size: ed.state.doc.content.size };
793
+ }
794
+ };
795
+ const insertText = {
796
+ name: "insert_text",
797
+ description: "Inserts literal text (newlines start new paragraphs) at a document position, or at the cursor when `at` is omitted.",
798
+ inputSchema: {
799
+ type: "object",
800
+ properties: {
801
+ text: { type: "string", description: "Text to insert." },
802
+ at: { type: "integer", minimum: 0, description: "Document position (default: the selection)." }
803
+ },
804
+ required: ["text"],
805
+ additionalProperties: false
806
+ },
807
+ handler: ({ text, at }) => {
808
+ const ed = editor();
809
+ const size = ed.state.doc.content.size;
810
+ if (at !== void 0 && at > size) {
811
+ throw new Error(`Position ${at} is outside the document (size ${size}).`);
812
+ }
813
+ const { from, to } = ed.state.selection;
814
+ replaceWithText(ed, _nullishCoalesce(at, () => ( from)), _nullishCoalesce(at, () => ( to)), text);
815
+ return { inserted: text.length, selection: selectionInfo(ed) };
816
+ }
817
+ };
818
+ const replaceSelection = {
819
+ name: "replace_selection",
820
+ description: "Replaces the selected content with literal text (an empty string deletes the selection).",
821
+ inputSchema: {
822
+ type: "object",
823
+ properties: { text: { type: "string", description: "Replacement text." } },
824
+ required: ["text"],
825
+ additionalProperties: false
826
+ },
827
+ annotations: { destructiveHint: true },
828
+ handler: ({ text }) => {
829
+ const ed = editor();
830
+ const { from, to } = ed.state.selection;
831
+ replaceWithText(ed, from, to, text);
832
+ return { replaced: { from, to }, selection: selectionInfo(ed) };
833
+ }
834
+ };
835
+ return {
836
+ id: options.id,
837
+ namespace: options.namespace,
838
+ tools: () => {
839
+ const ed = editor();
840
+ if (!ed || ed.isDestroyed) return [];
841
+ return ed.isEditable ? [getText, insertText, replaceSelection] : [getText];
842
+ },
843
+ subscribe: (notify) => {
844
+ const ed = editor();
845
+ ed.on("update", notify);
846
+ ed.on("destroy", notify);
847
+ return () => {
848
+ ed.off("update", notify);
849
+ ed.off("destroy", notify);
850
+ };
851
+ }
852
+ };
853
+ }
854
+ var CELL_REF_REGEX = /^\$?([A-Za-z]{1,3})\$?(\d{1,7})$/;
855
+ function parseCell(ref) {
856
+ const match = CELL_REF_REGEX.exec(ref.trim());
857
+ if (!match) throw new Error(`Invalid cell reference "${ref}". Use A1 notation, e.g. "B3".`);
858
+ return { col: _chunkJYRIOFENcjs.colNameToIndex.call(void 0, match[1].toUpperCase()), row: parseInt(match[2], 10) - 1 };
859
+ }
860
+ function createSpreadsheetToolProvider(controller, options) {
861
+ const lookup = (row, col) => {
862
+ const rowDef = controller.document.rows[row];
863
+ const colDef = controller.document.columns[col];
864
+ return rowDef && colDef ? { rowDef, colDef } : null;
865
+ };
866
+ const getRange = {
867
+ name: "get_range",
868
+ description: 'Reads a cell range in A1 notation (e.g. "A1:C5" or "B2") and returns computed values, raw input and errors.',
869
+ inputSchema: {
870
+ type: "object",
871
+ properties: {
872
+ range: { type: "string", description: "A1-notation cell or range." }
873
+ },
874
+ required: ["range"],
875
+ additionalProperties: false
876
+ },
877
+ annotations: { readOnlyHint: true },
878
+ handler: ({ range }) => {
879
+ const [startRef, endRef = startRef] = String(range).split(":");
880
+ const start = parseCell(startRef);
881
+ const end = parseCell(endRef);
882
+ const rowCount = controller.document.rows.length;
883
+ const colCount = controller.document.columns.length;
884
+ const r0 = Math.min(start.row, end.row);
885
+ const r1 = Math.min(Math.max(start.row, end.row), rowCount - 1);
886
+ const c0 = Math.min(start.col, end.col);
887
+ const c1 = Math.min(Math.max(start.col, end.col), colCount - 1);
888
+ const values = [];
889
+ const raw = [];
890
+ const errors = [];
891
+ for (let r = r0; r <= r1; r++) {
892
+ const valueRow = [];
893
+ const rawRow = [];
894
+ for (let c = c0; c <= c1; c++) {
895
+ const found = lookup(r, c);
896
+ const cell = controller.getCell(found.rowDef.id, found.colDef.id);
897
+ valueRow.push(_nullishCoalesce(cell.error, () => ( cell.value)));
898
+ rawRow.push(cell.raw);
899
+ const error = _nullishCoalesce(cell.error, () => ( (_chunkJYRIOFENcjs.isFormulaError.call(void 0, cell.value) ? cell.value : void 0)));
900
+ if (error) errors.push({ cell: `${_chunkJYRIOFENcjs.indexToColName.call(void 0, c)}${r + 1}`, error });
901
+ }
902
+ values.push(valueRow);
903
+ raw.push(rawRow);
904
+ }
905
+ return {
906
+ range: values.length && values[0].length ? `${_chunkJYRIOFENcjs.indexToColName.call(void 0, c0)}${r0 + 1}:${_chunkJYRIOFENcjs.indexToColName.call(void 0, c1)}${r1 + 1}` : null,
907
+ values,
908
+ raw,
909
+ errors,
910
+ sheet: { rows: rowCount, columns: colCount }
911
+ };
912
+ }
913
+ };
914
+ const setCell = {
915
+ name: "set_cell",
916
+ description: 'Sets the raw input of one cell (A1 notation). Values starting with "=" are formulas.',
917
+ inputSchema: {
918
+ type: "object",
919
+ properties: {
920
+ cell: { type: "string", description: 'A1-notation cell, e.g. "B3".' },
921
+ value: { type: ["string", "number", "boolean"], description: "Raw cell input." }
922
+ },
923
+ required: ["cell", "value"],
924
+ additionalProperties: false
925
+ },
926
+ handler: ({ cell, value }) => {
927
+ const { row, col } = parseCell(cell);
928
+ const found = lookup(row, col);
929
+ if (!found) throw new Error(`Cell ${cell} is outside the sheet.`);
930
+ const { rowDef, colDef } = found;
931
+ if (colDef.readOnly || controller.getCell(rowDef.id, colDef.id).readOnly || colDef.type === "formula") {
932
+ throw new Error(`Cell ${cell} is read-only.`);
933
+ }
934
+ controller.setCellValue(rowDef.id, colDef.id, String(value));
935
+ const updated = controller.getCell(rowDef.id, colDef.id);
936
+ return { cell: cell.toUpperCase(), raw: updated.raw, value: _nullishCoalesce(updated.error, () => ( updated.value)) };
937
+ }
938
+ };
939
+ return { id: options.id, namespace: options.namespace, tools: [getRange, setCell] };
940
+ }
941
+ function createEditorMcpToolProvider(options) {
942
+ const edit = (name) => async (args) => {
943
+ const steps = planToolCall(name, args, options.getSnapshot(), options.plannerOptions);
944
+ if (steps.length === 0) {
945
+ throw new Error(`Operation "${args.operation}" is missing required arguments.`);
946
+ }
947
+ await options.applySteps(steps);
948
+ return { applied: steps.length, steps: steps.map((s) => s.type) };
949
+ };
950
+ const tools = [
951
+ {
952
+ ...MCP_TOOL_GET_EDITOR_STATE,
953
+ handler: ({ includeDocument = true, includeCanvas = true }) => {
954
+ const snapshot = options.getSnapshot();
955
+ return {
956
+ ...includeDocument && snapshot.document ? { document: snapshot.document } : {},
957
+ ...includeCanvas && snapshot.canvas ? { canvas: snapshot.canvas } : {}
958
+ };
959
+ }
960
+ },
961
+ { ...MCP_TOOL_EDIT_CANVAS, handler: edit(MCP_TOOL_EDIT_CANVAS.name) },
962
+ { ...MCP_TOOL_EDIT_PROMPT, handler: edit(MCP_TOOL_EDIT_PROMPT.name) }
963
+ ];
964
+ if (options.captureView) {
965
+ const capture = options.captureView;
966
+ tools.push({
967
+ ...MCP_TOOL_VIEW_EDITOR,
968
+ handler: async (args) => {
969
+ const image = await capture(args);
970
+ return { content: [{ type: "image", data: image.data, mimeType: image.mimeType }] };
971
+ }
972
+ });
973
+ }
974
+ return { id: options.id, namespace: options.namespace, tools };
975
+ }
976
+
977
+
978
+
979
+
980
+
981
+
982
+
983
+
984
+
985
+
986
+
987
+
365
988
 
366
989
 
367
990
 
@@ -370,5 +993,5 @@ var EDITOR_MCP_TOOLS = [
370
993
 
371
994
 
372
995
 
373
- exports.EDITOR_MCP_TOOLS = EDITOR_MCP_TOOLS; exports.EXPORT_EXCLUDED_SELECTORS = EXPORT_EXCLUDED_SELECTORS; exports.MCP_TOOL_EDIT_CANVAS = MCP_TOOL_EDIT_CANVAS; exports.MCP_TOOL_EDIT_PROMPT = MCP_TOOL_EDIT_PROMPT; exports.MCP_TOOL_GET_EDITOR_STATE = MCP_TOOL_GET_EDITOR_STATE; exports.MCP_TOOL_VIEW_EDITOR = MCP_TOOL_VIEW_EDITOR; exports.normalizeSide = normalizeSide; exports.planAgentCommand = planAgentCommand;
996
+ exports.EDITOR_MCP_TOOLS = EDITOR_MCP_TOOLS; exports.EXPORT_EXCLUDED_SELECTORS = EXPORT_EXCLUDED_SELECTORS; exports.MCP_TOOL_EDIT_CANVAS = MCP_TOOL_EDIT_CANVAS; exports.MCP_TOOL_EDIT_PROMPT = MCP_TOOL_EDIT_PROMPT; exports.MCP_TOOL_GET_EDITOR_STATE = MCP_TOOL_GET_EDITOR_STATE; exports.MCP_TOOL_VIEW_EDITOR = MCP_TOOL_VIEW_EDITOR; exports.TOOL_NAMESPACE_SEPARATOR = TOOL_NAMESPACE_SEPARATOR; exports.ToolRegistry = ToolRegistry; exports.ToolRegistryError = ToolRegistryError; exports.createEditorMcpToolProvider = createEditorMcpToolProvider; exports.createRichTextToolProvider = createRichTextToolProvider; exports.createSpreadsheetToolProvider = createSpreadsheetToolProvider; exports.createToolRegistry = createToolRegistry; exports.normalizeSide = normalizeSide; exports.planAgentCommand = planAgentCommand; exports.planToolCall = planToolCall; exports.toToolResult = toToolResult; exports.toolCallToAgentCommand = toolCallToAgentCommand; exports.validateJsonSchema = validateJsonSchema;
374
997
  //# sourceMappingURL=index.cjs.map