@pixerate/editor 0.140.3 → 0.141.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 (85) hide show
  1. package/dist/agent/canvasPlayback.d.cts +15 -0
  2. package/dist/agent/canvasPlayback.d.ts +15 -0
  3. package/dist/agent/index.cjs +144 -23
  4. package/dist/agent/index.d.cts +1 -0
  5. package/dist/agent/index.d.ts +1 -0
  6. package/dist/agent/index.js +125 -4
  7. package/dist/agent/providers.d.cts +8 -0
  8. package/dist/agent/providers.d.ts +8 -0
  9. package/dist/agent/types.d.cts +3 -0
  10. package/dist/agent/types.d.ts +3 -0
  11. package/dist/animation/index.cjs +2 -2
  12. package/dist/animation/index.js +1 -1
  13. package/dist/animation/presence.d.cts +1 -75
  14. package/dist/animation/presence.d.ts +1 -75
  15. package/dist/animation-editor/index.cjs +55 -55
  16. package/dist/animation-editor/index.js +2 -2
  17. package/dist/bridge/cli.cjs +3 -3
  18. package/dist/bridge/cli.js +2 -2
  19. package/dist/bridge/index.cjs +3 -3
  20. package/dist/bridge/index.js +2 -2
  21. package/dist/canvas/index.cjs +336 -646
  22. package/dist/canvas/index.d.cts +1 -0
  23. package/dist/canvas/index.d.ts +1 -0
  24. package/dist/canvas/index.js +44 -354
  25. package/dist/canvas/playback.d.cts +14 -0
  26. package/dist/canvas/playback.d.ts +14 -0
  27. package/dist/chart/index.cjs +7 -7
  28. package/dist/chart/index.js +1 -1
  29. package/dist/chunk-6SFREX6H.cjs +406 -0
  30. package/dist/{chunk-XGOU44RJ.js → chunk-77SG47WT.js} +80 -9
  31. package/dist/{chunk-2SHFIVC3.js → chunk-DAS7M4RY.js} +1 -1
  32. package/dist/chunk-DW4CV5H4.js +591 -0
  33. package/dist/{chunk-UMS6YFA6.js → chunk-EAQ4BGNS.js} +1 -1
  34. package/dist/{chunk-AGCD3EHB.cjs → chunk-ENIZYNEF.cjs} +7 -7
  35. package/dist/{chunk-VSR5A22L.cjs → chunk-H6FX45CP.cjs} +35 -35
  36. package/dist/{chunk-RCUX6CT2.cjs → chunk-HRI3ZMDM.cjs} +110 -39
  37. package/dist/chunk-MFFE55CS.js +406 -0
  38. package/dist/{chunk-BSGPXPTW.js → chunk-PEEP2YR7.js} +1 -1
  39. package/dist/{chunk-RB62U6MS.js → chunk-RFBFTLVN.js} +27 -5
  40. package/dist/chunk-UBRYHNRU.cjs +591 -0
  41. package/dist/{chunk-GEY73RUW.cjs → chunk-UJGAA6AK.cjs} +1 -1
  42. package/dist/{chunk-6UZCFD7Y.js → chunk-VM6JYWXQ.js} +1 -1
  43. package/dist/{chunk-O3ZU6QIZ.cjs → chunk-XNZWATSB.cjs} +81 -81
  44. package/dist/{chunk-HDK3T2QS.cjs → chunk-Y4BWZB6J.cjs} +29 -7
  45. package/dist/commands/index.cjs +37 -1
  46. package/dist/commands/index.js +36 -0
  47. package/dist/commands/registry.d.cts +11 -0
  48. package/dist/commands/registry.d.ts +11 -0
  49. package/dist/diagram/index.cjs +7 -7
  50. package/dist/diagram/index.js +1 -1
  51. package/dist/image-editor/index.cjs +720 -628
  52. package/dist/image-editor/index.d.cts +1 -0
  53. package/dist/image-editor/index.d.ts +1 -0
  54. package/dist/image-editor/index.js +109 -17
  55. package/dist/image-editor/playback.d.cts +22 -0
  56. package/dist/image-editor/playback.d.ts +22 -0
  57. package/dist/paint-editor/index.cjs +13 -13
  58. package/dist/paint-editor/index.js +3 -3
  59. package/dist/tools/index.cjs +33 -3
  60. package/dist/tools/index.d.cts +2 -0
  61. package/dist/tools/index.d.ts +2 -0
  62. package/dist/tools/index.js +32 -2
  63. package/dist/tools/playback.d.cts +205 -0
  64. package/dist/tools/playback.d.ts +205 -0
  65. package/dist/tools/presence.d.cts +82 -0
  66. package/dist/tools/presence.d.ts +82 -0
  67. package/dist/tools/registry.d.cts +45 -6
  68. package/dist/tools/registry.d.ts +45 -6
  69. package/dist/tools/view.d.cts +2 -4
  70. package/dist/tools/view.d.ts +2 -4
  71. package/dist/vector/index.cjs +1159 -1042
  72. package/dist/vector/index.d.cts +1 -0
  73. package/dist/vector/index.d.ts +1 -0
  74. package/dist/vector/index.js +142 -25
  75. package/dist/vector/playback.d.cts +13 -0
  76. package/dist/vector/playback.d.ts +13 -0
  77. package/package.json +1 -1
  78. package/skills/pixerate-agent-tools/SKILL.md +13 -0
  79. package/skills/pixerate-canvas/SKILL.md +3 -0
  80. package/skills/pixerate-image-editor/SKILL.md +2 -2
  81. package/skills/pixerate-vector/SKILL.md +5 -0
  82. package/dist/chunk-BTZS3KZY.js +0 -221
  83. package/dist/chunk-MRD3NXKR.cjs +0 -221
  84. /package/dist/{chunk-K73HMKQP.js → chunk-PLKIYNJZ.js} +0 -0
  85. /package/dist/{chunk-LACYURUW.cjs → chunk-TNCWKC5M.cjs} +0 -0
@@ -0,0 +1,15 @@
1
+ import { type NodeRectOptions } from '../canvas/arrange.cjs';
2
+ import type { CanvasEdge, CanvasNode } from '../canvas/types.cjs';
3
+ import { type PlaybackStep } from '../tools/playback.cjs';
4
+ import { type planToolCall } from './planner.cjs';
5
+ import type { AgentStep, EditorSnapshot } from './types.cjs';
6
+ /**
7
+ * Turns the planner's model steps into cursor steps (flow coordinates), against the nodes as they
8
+ * are before the call. Steps after `commit` play once the change is on the canvas.
9
+ */
10
+ export declare function planCanvasPlaybackSteps<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge>(steps: readonly AgentStep<TNode, TEdge>[], nodes: readonly TNode[], rectOptions?: NodeRectOptions): PlaybackStep[];
11
+ /**
12
+ * The cursor steps for one canvas edit tool call (`canvas_add_node`, `edit_canvas`, ...), or `null`
13
+ * when the call is invalid (the handler then reports the error) or is not a canvas edit.
14
+ */
15
+ export declare function planCanvasToolPlayback<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge>(name: string, args: Record<string, any>, snapshot: EditorSnapshot<TNode, TEdge>, plannerOptions?: Parameters<typeof planToolCall>[3], rectOptions?: NodeRectOptions): PlaybackStep[] | null;
@@ -0,0 +1,15 @@
1
+ import { type NodeRectOptions } from '../canvas/arrange.js';
2
+ import type { CanvasEdge, CanvasNode } from '../canvas/types.js';
3
+ import { type PlaybackStep } from '../tools/playback.js';
4
+ import { type planToolCall } from './planner.js';
5
+ import type { AgentStep, EditorSnapshot } from './types.js';
6
+ /**
7
+ * Turns the planner's model steps into cursor steps (flow coordinates), against the nodes as they
8
+ * are before the call. Steps after `commit` play once the change is on the canvas.
9
+ */
10
+ export declare function planCanvasPlaybackSteps<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge>(steps: readonly AgentStep<TNode, TEdge>[], nodes: readonly TNode[], rectOptions?: NodeRectOptions): PlaybackStep[];
11
+ /**
12
+ * The cursor steps for one canvas edit tool call (`canvas_add_node`, `edit_canvas`, ...), or `null`
13
+ * when the call is invalid (the handler then reports the error) or is not a canvas edit.
14
+ */
15
+ export declare function planCanvasToolPlayback<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge>(name: string, args: Record<string, any>, snapshot: EditorSnapshot<TNode, TEdge>, plannerOptions?: Parameters<typeof planToolCall>[3], rectOptions?: NodeRectOptions): PlaybackStep[] | null;
@@ -10,9 +10,16 @@ var _chunkGLQQ2VILcjs = require('../chunk-GLQQ2VIL.cjs');
10
10
 
11
11
 
12
12
 
13
- var _chunkMRD3NXKRcjs = require('../chunk-MRD3NXKR.cjs');
13
+
14
+
15
+ var _chunkUBRYHNRUcjs = require('../chunk-UBRYHNRU.cjs');
14
16
  require('../chunk-4EFNS2HV.cjs');
15
- require('../chunk-LACYURUW.cjs');
17
+ require('../chunk-TNCWKC5M.cjs');
18
+
19
+
20
+
21
+
22
+
16
23
 
17
24
 
18
25
 
@@ -33,12 +40,16 @@ require('../chunk-LACYURUW.cjs');
33
40
 
34
41
 
35
42
 
43
+ var _chunkY4BWZB6Jcjs = require('../chunk-Y4BWZB6J.cjs');
36
44
 
37
45
 
38
46
 
39
47
 
40
48
 
41
- var _chunkHDK3T2QScjs = require('../chunk-HDK3T2QS.cjs');
49
+
50
+
51
+
52
+ var _chunk6SFREX6Hcjs = require('../chunk-6SFREX6H.cjs');
42
53
 
43
54
 
44
55
 
@@ -130,6 +141,14 @@ var _chunk55AKPTLMcjs = require('../chunk-55AKPTLM.cjs');
130
141
  require('../chunk-N3KJFGXT.cjs');
131
142
 
132
143
 
144
+
145
+
146
+
147
+
148
+
149
+ var _chunkUJGAA6AKcjs = require('../chunk-UJGAA6AK.cjs');
150
+
151
+
133
152
  var _chunkWOFXZ3XUcjs = require('../chunk-WOFXZ3XU.cjs');
134
153
  require('../chunk-FJ2MSI43.cjs');
135
154
 
@@ -170,10 +189,10 @@ function planAgentCommand(command, snapshot, options = {}) {
170
189
  };
171
190
  }
172
191
  if (anchorId) {
173
- pos = _chunkMRD3NXKRcjs.placeBeside.call(void 0, rects, defaultNodeSize, normalizeSide(command.side), anchorId);
192
+ pos = _chunkUBRYHNRUcjs.placeBeside.call(void 0, rects, defaultNodeSize, normalizeSide(command.side), anchorId);
174
193
  } else if (nodes.length > 0) {
175
194
  const lastNode = nodes[nodes.length - 1];
176
- pos = _chunkMRD3NXKRcjs.placeBeside.call(void 0, rects, defaultNodeSize, "right", lastNode.id);
195
+ pos = _chunkUBRYHNRUcjs.placeBeside.call(void 0, rects, defaultNodeSize, "right", lastNode.id);
177
196
  } else {
178
197
  pos = { x: 100, y: 100 };
179
198
  }
@@ -241,12 +260,12 @@ function planAgentCommand(command, snapshot, options = {}) {
241
260
  stored[n.id] = { ...n.position };
242
261
  }
243
262
  }
244
- layouted = _chunkMRD3NXKRcjs.ensureLayout.call(void 0, nodes, edges, {
263
+ layouted = _chunkUBRYHNRUcjs.ensureLayout.call(void 0, nodes, edges, {
245
264
  direction: dir,
246
265
  storedPositions: stored
247
266
  });
248
267
  } else {
249
- layouted = _chunkMRD3NXKRcjs.getLayoutedNodes.call(void 0, nodes, edges, void 0, { direction: dir });
268
+ layouted = _chunkUBRYHNRUcjs.getLayoutedNodes.call(void 0, nodes, edges, void 0, { direction: dir });
250
269
  }
251
270
  const positions = {};
252
271
  for (const node of layouted) {
@@ -459,6 +478,87 @@ function planToolCall(name, args, snapshot, options) {
459
478
  var _state = require('@tiptap/pm/state');
460
479
  var _history = require('@tiptap/pm/history');
461
480
 
481
+ // src/agent/canvasPlayback.ts
482
+ var centre = (r) => ({ x: r.x + r.width / 2, y: r.y + r.height / 2 });
483
+ var labelOf = (data) => {
484
+ const label = _nullishCoalesce(_nullishCoalesce(_optionalChain([data, 'optionalAccess', _16 => _16.label]), () => ( _optionalChain([data, 'optionalAccess', _17 => _17.title]))), () => ( _optionalChain([data, 'optionalAccess', _18 => _18.text])));
485
+ return typeof label === "string" && label.trim() ? label : null;
486
+ };
487
+ function planCanvasPlaybackSteps(steps, nodes, rectOptions) {
488
+ const placed = new Map(_chunkUBRYHNRUcjs.createNodeLookup.call(void 0, nodes));
489
+ const rectOf = (id) => {
490
+ const node = placed.get(id);
491
+ return node ? _chunkUBRYHNRUcjs.getNodeRect.call(void 0, node, placed, rectOptions) : null;
492
+ };
493
+ const before = [];
494
+ const after = [];
495
+ const click = (rect) => rect ? [{ type: "move", to: centre(rect) }, { type: "focus", rect }, { type: "press" }, { type: "release" }] : [];
496
+ for (const step of steps) {
497
+ switch (step.type) {
498
+ case "step:canvas_add_node": {
499
+ placed.set(step.node.id, step.node);
500
+ const rect = rectOf(step.node.id);
501
+ const label = labelOf(step.node.data);
502
+ before.push(...click(rect), ...label ? [{ type: "type", text: label }] : []);
503
+ break;
504
+ }
505
+ case "step:canvas_add_edge": {
506
+ const a = rectOf(step.edge.source);
507
+ const b = rectOf(step.edge.target);
508
+ if (!a || !b) break;
509
+ const label = typeof step.edge.label === "string" ? step.edge.label : labelOf(step.edge.data);
510
+ before.push(
511
+ { type: "move", to: { x: a.x + a.width, y: a.y + a.height / 2 } },
512
+ { type: "press" },
513
+ { type: "drag", to: { x: b.x, y: b.y + b.height / 2 } },
514
+ { type: "release" },
515
+ ...label ? [{ type: "type", text: label }] : []
516
+ );
517
+ break;
518
+ }
519
+ case "step:canvas_update_node": {
520
+ const rect = rectOf(step.id);
521
+ const label = labelOf(step.data);
522
+ before.push(...click(rect), ...rect && label ? [{ type: "type", text: label }] : []);
523
+ break;
524
+ }
525
+ case "step:canvas_remove_nodes":
526
+ for (const id of step.nodeIds.slice(0, 8)) before.push(...click(rectOf(id)));
527
+ break;
528
+ case "step:canvas_select":
529
+ for (const id of step.nodeIds.slice(0, 8)) before.push(...click(rectOf(id)));
530
+ break;
531
+ case "step:canvas_highlight":
532
+ for (const id of step.nodeIds.slice(0, 8)) {
533
+ const rect = rectOf(id);
534
+ if (rect) before.push({ type: "move", to: centre(rect) }, { type: "focus", rect });
535
+ }
536
+ break;
537
+ case "step:canvas_move_nodes": {
538
+ const moved = Object.entries(step.positions);
539
+ for (const [id, position] of moved) {
540
+ const node = placed.get(id);
541
+ if (node) placed.set(id, { ...node, position });
542
+ }
543
+ const rect = _chunk6SFREX6Hcjs.unionRects.call(void 0, moved.map(([id]) => rectOf(id)));
544
+ if (rect) after.push({ type: "move", to: centre(rect) }, { type: "focus", rect }, { type: "wait", ms: 450 });
545
+ break;
546
+ }
547
+ default:
548
+ break;
549
+ }
550
+ }
551
+ if (!before.length && !after.length) return [];
552
+ return [...before, { type: "commit" }, ...after];
553
+ }
554
+ function planCanvasToolPlayback(name, args, snapshot, plannerOptions, rectOptions) {
555
+ const command = toolCallToAgentCommand(name, args);
556
+ if (!command || !command.type.startsWith("canvas:") || validateAgentCommand(command, snapshot)) return null;
557
+ const steps = planAgentCommand(command, snapshot, plannerOptions);
558
+ const planned = planCanvasPlaybackSteps(steps, _nullishCoalesce(_optionalChain([snapshot, 'access', _19 => _19.canvas, 'optionalAccess', _20 => _20.nodes]), () => ( [])), rectOptions);
559
+ return planned.length ? planned : null;
560
+ }
561
+
462
562
  // src/agent/documentChartTools.ts
463
563
 
464
564
  var READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
@@ -573,7 +673,7 @@ function createDocumentChartTools(editor) {
573
673
  const ed = editor();
574
674
  checkPosition(ed, at);
575
675
  const spec = checkedSpec(input);
576
- const id = _nullishCoalesce(_optionalChain([ed, 'access', _16 => _16.extensionManager, 'access', _17 => _17.extensions, 'access', _18 => _18.find, 'call', _19 => _19((e) => e.name === "chart"), 'optionalAccess', _20 => _20.options, 'access', _21 => _21.generateId, 'optionalCall', _22 => _22()]), () => ( `chart-${Date.now().toString(36)}`));
676
+ const id = _nullishCoalesce(_optionalChain([ed, 'access', _21 => _21.extensionManager, 'access', _22 => _22.extensions, 'access', _23 => _23.find, 'call', _24 => _24((e) => e.name === "chart"), 'optionalAccess', _25 => _25.options, 'access', _26 => _26.generateId, 'optionalCall', _27 => _27()]), () => ( `chart-${Date.now().toString(36)}`));
577
677
  const node = { type: "chart", attrs: { id, spec, width, ...height !== void 0 ? { height } : {} } };
578
678
  const chain = ed.chain().command(({ tr }) => (_history.closeHistory.call(void 0, tr), true));
579
679
  const ok = (at !== void 0 ? chain.insertContentAt(at, node) : chain.insertContent(node)).run();
@@ -788,7 +888,7 @@ function createDocumentFormatTools(editor, changed) {
788
888
  const formatText = (ed) => {
789
889
  const { schema } = ed;
790
890
  const has = (name) => !!schema.marks[name];
791
- const hasAttr = (mark, attr) => !!_optionalChain([schema, 'access', _23 => _23.marks, 'access', _24 => _24[mark], 'optionalAccess', _25 => _25.spec, 'access', _26 => _26.attrs, 'optionalAccess', _27 => _27[attr]]);
891
+ const hasAttr = (mark, attr) => !!_optionalChain([schema, 'access', _28 => _28.marks, 'access', _29 => _29[mark], 'optionalAccess', _30 => _30.spec, 'access', _31 => _31.attrs, 'optionalAccess', _32 => _32[attr]]);
792
892
  const properties = { ...RANGE_PROPERTIES };
793
893
  for (const [arg, mark, what] of TOGGLE_MARKS) {
794
894
  if (has(mark)) properties[arg] = { type: "boolean", description: `${what} true sets it, false clears it; omit to leave it.` };
@@ -863,7 +963,7 @@ function createDocumentFormatTools(editor, changed) {
863
963
  const blockTypes = (ed) => BLOCK_TYPES.filter(([, node]) => !!ed.schema.nodes[node] && (!LIST_ITEMS[node] || !!ed.schema.nodes[LIST_ITEMS[node]]));
864
964
  const headingLevels = (ed) => {
865
965
  const ext = ed.extensionManager.extensions.find((e) => e.name === "heading");
866
- return _nullishCoalesce(_optionalChain([ext, 'optionalAccess', _28 => _28.options, 'optionalAccess', _29 => _29.levels]), () => ( [1, 2, 3, 4, 5, 6]));
966
+ return _nullishCoalesce(_optionalChain([ext, 'optionalAccess', _33 => _33.options, 'optionalAccess', _34 => _34.levels]), () => ( [1, 2, 3, 4, 5, 6]));
867
967
  };
868
968
  const setBlockType = (ed) => {
869
969
  const types = blockTypes(ed);
@@ -913,8 +1013,8 @@ function createDocumentFormatTools(editor, changed) {
913
1013
  const setTextAlign = (ed) => {
914
1014
  const ext = ed.extensionManager.extensions.find((e) => e.name === "textAlign");
915
1015
  if (!ext) return null;
916
- const alignments = (_nullishCoalesce(_optionalChain([ext, 'access', _30 => _30.options, 'optionalAccess', _31 => _31.alignments]), () => ( ["left", "center", "right", "justify"]))).slice();
917
- const types = _nullishCoalesce(_optionalChain([ext, 'access', _32 => _32.options, 'optionalAccess', _33 => _33.types]), () => ( ["heading", "paragraph"]));
1016
+ const alignments = (_nullishCoalesce(_optionalChain([ext, 'access', _35 => _35.options, 'optionalAccess', _36 => _36.alignments]), () => ( ["left", "center", "right", "justify"]))).slice();
1017
+ const types = _nullishCoalesce(_optionalChain([ext, 'access', _37 => _37.options, 'optionalAccess', _38 => _38.types]), () => ( ["heading", "paragraph"]));
918
1018
  return {
919
1019
  name: "set_text_align",
920
1020
  title: "Align text",
@@ -981,13 +1081,13 @@ function textBlocks(editor) {
981
1081
  function createTextPresence(editor, providerId, option) {
982
1082
  const config = option === false ? null : option === true || option === void 0 ? {} : option;
983
1083
  const caret = {
984
- id: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _34 => _34.id]), () => ( providerId)),
985
- name: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _35 => _35.name]), () => ( _chunkL434J57Vcjs.DEFAULT_AGENT_CARET_NAME)),
986
- color: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _36 => _36.color]), () => ( _chunkL434J57Vcjs.DEFAULT_AGENT_CARET_COLOR))
1084
+ id: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _39 => _39.id]), () => ( providerId)),
1085
+ name: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _40 => _40.name]), () => ( _chunkL434J57Vcjs.DEFAULT_AGENT_CARET_NAME)),
1086
+ color: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _41 => _41.color]), () => ( _chunkL434J57Vcjs.DEFAULT_AGENT_CARET_COLOR))
987
1087
  };
988
- const typing = !_optionalChain([config, 'optionalAccess', _37 => _37.typing]) ? null : config.typing === true ? {} : config.typing;
989
- const idleMs = _nullishCoalesce(_optionalChain([config, 'optionalAccess', _38 => _38.idleMs]), () => ( 12e3));
990
- const changedMs = _nullishCoalesce(_optionalChain([config, 'optionalAccess', _39 => _39.changedMs]), () => ( 1500));
1088
+ const typing = !_optionalChain([config, 'optionalAccess', _42 => _42.typing]) ? null : config.typing === true ? {} : config.typing;
1089
+ const idleMs = _nullishCoalesce(_optionalChain([config, 'optionalAccess', _43 => _43.idleMs]), () => ( 12e3));
1090
+ const changedMs = _nullishCoalesce(_optionalChain([config, 'optionalAccess', _44 => _44.changedMs]), () => ( 1500));
991
1091
  let idleTimer;
992
1092
  let tintTimer;
993
1093
  const live = () => {
@@ -1723,7 +1823,7 @@ function missingArgumentsMessage(name, args) {
1723
1823
  const required = _chunkSVFEVKLFcjs.EDIT_OPERATION_REQUIRED_ARGUMENTS[name][args.operation];
1724
1824
  if (!required) return `Unknown operation "${args.operation}".`;
1725
1825
  const missing = required.filter(
1726
- (key) => key === "id" ? args.id === void 0 && _optionalChain([args, 'access', _40 => _40.node, 'optionalAccess', _41 => _41.id]) === void 0 : args[key] === void 0
1826
+ (key) => key === "id" ? args.id === void 0 && _optionalChain([args, 'access', _45 => _45.node, 'optionalAccess', _46 => _46.id]) === void 0 : args[key] === void 0
1727
1827
  );
1728
1828
  return missing.length ? `Operation "${args.operation}" requires ${required.join(", ")}; missing: ${missing.join(", ")}.` : `Operation "${args.operation}" has invalid arguments (expected ${required.join(", ")} with the types in the schema).`;
1729
1829
  }
@@ -1755,8 +1855,8 @@ function createEditorMcpToolProvider(options) {
1755
1855
  await options.applySteps(steps);
1756
1856
  return describeSteps(steps);
1757
1857
  };
1758
- const canvas = _nullishCoalesce(_optionalChain([options, 'access', _42 => _42.surfaces, 'optionalAccess', _43 => _43.canvas]), () => ( true));
1759
- const prompt = _nullishCoalesce(_optionalChain([options, 'access', _44 => _44.surfaces, 'optionalAccess', _45 => _45.prompt]), () => ( true));
1858
+ const canvas = _nullishCoalesce(_optionalChain([options, 'access', _47 => _47.surfaces, 'optionalAccess', _48 => _48.canvas]), () => ( true));
1859
+ const prompt = _nullishCoalesce(_optionalChain([options, 'access', _49 => _49.surfaces, 'optionalAccess', _50 => _50.prompt]), () => ( true));
1760
1860
  const editTools = options.toolStyle === "combined" ? [...canvas ? [_chunkSVFEVKLFcjs.MCP_TOOL_EDIT_CANVAS] : [], ...prompt ? [_chunkSVFEVKLFcjs.MCP_TOOL_EDIT_PROMPT] : []] : [...canvas ? _chunkSVFEVKLFcjs.EDITOR_CANVAS_TOOLS : [], ...prompt ? _chunkSVFEVKLFcjs.EDITOR_PROMPT_TOOLS : []];
1761
1861
  const tools = [
1762
1862
  {
@@ -1769,7 +1869,12 @@ function createEditorMcpToolProvider(options) {
1769
1869
  };
1770
1870
  }
1771
1871
  },
1772
- ...editTools.map((definition) => ({ ...definition, handler: edit(definition.name) }))
1872
+ ...editTools.map((definition) => ({
1873
+ ...definition,
1874
+ handler: edit(definition.name),
1875
+ // The cursor goes where the planner puts the change (see `planCanvasToolPlayback`).
1876
+ plan: (args) => planCanvasToolPlayback(definition.name, args, options.getSnapshot(), options.plannerOptions, options.rectOptions)
1877
+ }))
1773
1878
  ];
1774
1879
  if (options.captureView) {
1775
1880
  const capture = options.captureView;
@@ -1787,6 +1892,7 @@ function createEditorMcpToolProvider(options) {
1787
1892
  title: "Canvas and prompt editor",
1788
1893
  description: "The node canvas and the prompt: editor state, nodes and edges, layout, prompt text, and a view of the editor.",
1789
1894
  skill: "pixerate-canvas",
1895
+ ...options.playbackSurface ? { playbackSurface: options.playbackSurface } : {},
1790
1896
  tools
1791
1897
  };
1792
1898
  }
@@ -2065,4 +2171,19 @@ function createCanvasComponentToolProvider(controller, options = { id: "canvas-c
2065
2171
 
2066
2172
 
2067
2173
 
2068
- exports.CAPTURE_EXCLUDE_SELECTOR = _chunkSVFEVKLFcjs.CAPTURE_EXCLUDE_SELECTOR; exports.CAPTURE_OVERLAY_SELECTORS = _chunkSVFEVKLFcjs.CAPTURE_OVERLAY_SELECTORS; exports.EDITOR_CANVAS_TOOLS = _chunkSVFEVKLFcjs.EDITOR_CANVAS_TOOLS; exports.EDITOR_MCP_TOOLS = _chunkSVFEVKLFcjs.EDITOR_MCP_TOOLS; exports.EDITOR_PROMPT_TOOLS = _chunkSVFEVKLFcjs.EDITOR_PROMPT_TOOLS; exports.EDIT_OPERATION_REQUIRED_ARGUMENTS = _chunkSVFEVKLFcjs.EDIT_OPERATION_REQUIRED_ARGUMENTS; exports.EXPORT_EXCLUDED_SELECTORS = _chunkSVFEVKLFcjs.EXPORT_EXCLUDED_SELECTORS; exports.JSON_RPC_ERRORS = _chunkHDK3T2QScjs.JSON_RPC_ERRORS; exports.MCP_PROTOCOL_VERSIONS = _chunkHDK3T2QScjs.MCP_PROTOCOL_VERSIONS; exports.MCP_TOOL_CANVAS_ADD_NODE = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_ADD_NODE; exports.MCP_TOOL_CANVAS_CONNECT = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_CONNECT; exports.MCP_TOOL_CANVAS_HIGHLIGHT = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_HIGHLIGHT; exports.MCP_TOOL_CANVAS_LAYOUT = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_LAYOUT; exports.MCP_TOOL_CANVAS_REMOVE_NODES = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_REMOVE_NODES; exports.MCP_TOOL_CANVAS_SELECT = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_SELECT; exports.MCP_TOOL_CANVAS_UPDATE_NODE = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_UPDATE_NODE; exports.MCP_TOOL_EDIT_CANVAS = _chunkSVFEVKLFcjs.MCP_TOOL_EDIT_CANVAS; exports.MCP_TOOL_EDIT_PROMPT = _chunkSVFEVKLFcjs.MCP_TOOL_EDIT_PROMPT; exports.MCP_TOOL_GET_EDITOR_STATE = _chunkSVFEVKLFcjs.MCP_TOOL_GET_EDITOR_STATE; exports.MCP_TOOL_PROMPT_INSERT_TEXT = _chunkSVFEVKLFcjs.MCP_TOOL_PROMPT_INSERT_TEXT; exports.MCP_TOOL_PROMPT_REPLACE_RANGE = _chunkSVFEVKLFcjs.MCP_TOOL_PROMPT_REPLACE_RANGE; exports.MCP_TOOL_PROMPT_SELECT = _chunkSVFEVKLFcjs.MCP_TOOL_PROMPT_SELECT; exports.MCP_TOOL_PROMPT_SET_VARIABLE = _chunkSVFEVKLFcjs.MCP_TOOL_PROMPT_SET_VARIABLE; exports.MCP_TOOL_VIEW_EDITOR = _chunkSVFEVKLFcjs.MCP_TOOL_VIEW_EDITOR; exports.TOOL_BRIDGE_DEFAULT_PORT = _chunkHDK3T2QScjs.TOOL_BRIDGE_DEFAULT_PORT; exports.TOOL_BRIDGE_PROTOCOL = _chunkHDK3T2QScjs.TOOL_BRIDGE_PROTOCOL; exports.TOOL_DISCOVERY_TOOLS = _chunkHDK3T2QScjs.TOOL_DISCOVERY_TOOLS; exports.TOOL_NAMESPACE_SEPARATOR = _chunkHDK3T2QScjs.TOOL_NAMESPACE_SEPARATOR; exports.ToolRegistry = _chunkHDK3T2QScjs.ToolRegistry; exports.ToolRegistryError = _chunkHDK3T2QScjs.ToolRegistryError; exports.ToolRegistryView = _chunkHDK3T2QScjs.ToolRegistryView; exports.UNSAFE_JSON_KEYS = _chunk2BSBFBOAcjs.UNSAFE_JSON_KEYS; exports.baseToolName = _chunkHDK3T2QScjs.baseToolName; exports.captureInputSchema = _chunkN2FGYZ4Qcjs.captureInputSchema; exports.captureOutputSize = _chunkN2FGYZ4Qcjs.captureOutputSize; exports.cloneElementWithStyles = _chunkSVFEVKLFcjs.cloneElementWithStyles; exports.connectToolBridge = _chunkHDK3T2QScjs.connectToolBridge; exports.createCanvasComponentToolProvider = createCanvasComponentToolProvider; exports.createCaptureTool = _chunkN2FGYZ4Qcjs.createCaptureTool; exports.createCaptureToolProvider = _chunkN2FGYZ4Qcjs.createCaptureToolProvider; exports.createDocumentChartTools = createDocumentChartTools; exports.createEditorMcpToolProvider = createEditorMcpToolProvider; exports.createElementCaptureSurface = _chunkSVFEVKLFcjs.createElementCaptureSurface; exports.createMcpServer = _chunkHDK3T2QScjs.createMcpServer; exports.createRichTextToolProvider = createRichTextToolProvider; exports.createSpreadsheetToolProvider = createSpreadsheetToolProvider; exports.createToolRegistry = _chunkHDK3T2QScjs.createToolRegistry; exports.elementToSvg = _chunkSVFEVKLFcjs.elementToSvg; exports.errorResult = _chunkHDK3T2QScjs.errorResult; exports.isUnsafeJsonKey = _chunk2BSBFBOAcjs.isUnsafeJsonKey; exports.listSkills = _chunkHDK3T2QScjs.listSkills; exports.normalizeSide = normalizeSide; exports.parseSkillFrontmatter = _chunkHDK3T2QScjs.parseSkillFrontmatter; exports.planAgentCommand = planAgentCommand; exports.planToolCall = planToolCall; exports.rasterizeElement = _chunkSVFEVKLFcjs.rasterizeElement; exports.readSkillFile = _chunkHDK3T2QScjs.readSkillFile; exports.resolveCaptureRequest = _chunkN2FGYZ4Qcjs.resolveCaptureRequest; exports.searchTokens = _chunkHDK3T2QScjs.searchTokens; exports.searchTools = _chunkHDK3T2QScjs.searchTools; exports.stripPrototypeKeys = _chunk2BSBFBOAcjs.stripPrototypeKeys; exports.summarize = _chunkHDK3T2QScjs.summarize; exports.toCapturedImageData = _chunkN2FGYZ4Qcjs.toCapturedImageData; exports.toToolResult = _chunkHDK3T2QScjs.toToolResult; exports.toolCallToAgentCommand = toolCallToAgentCommand; exports.toolsetInstructions = _chunkHDK3T2QScjs.toolsetInstructions; exports.toolsetName = _chunkHDK3T2QScjs.toolsetName; exports.unionCaptureRects = _chunkN2FGYZ4Qcjs.unionCaptureRects; exports.unknownToolMessage = _chunkHDK3T2QScjs.unknownToolMessage; exports.validateAgentCommand = validateAgentCommand; exports.validateJsonSchema = _chunkWOFXZ3XUcjs.validateJsonSchema;
2174
+
2175
+
2176
+
2177
+
2178
+
2179
+
2180
+
2181
+
2182
+
2183
+
2184
+
2185
+
2186
+
2187
+
2188
+
2189
+ exports.AgentPlayback = _chunk6SFREX6Hcjs.AgentPlayback; exports.CAPTURE_EXCLUDE_SELECTOR = _chunkSVFEVKLFcjs.CAPTURE_EXCLUDE_SELECTOR; exports.CAPTURE_OVERLAY_SELECTORS = _chunkSVFEVKLFcjs.CAPTURE_OVERLAY_SELECTORS; exports.EDITOR_CANVAS_TOOLS = _chunkSVFEVKLFcjs.EDITOR_CANVAS_TOOLS; exports.EDITOR_MCP_TOOLS = _chunkSVFEVKLFcjs.EDITOR_MCP_TOOLS; exports.EDITOR_PROMPT_TOOLS = _chunkSVFEVKLFcjs.EDITOR_PROMPT_TOOLS; exports.EDIT_OPERATION_REQUIRED_ARGUMENTS = _chunkSVFEVKLFcjs.EDIT_OPERATION_REQUIRED_ARGUMENTS; exports.EXPORT_EXCLUDED_SELECTORS = _chunkSVFEVKLFcjs.EXPORT_EXCLUDED_SELECTORS; exports.JSON_RPC_ERRORS = _chunkY4BWZB6Jcjs.JSON_RPC_ERRORS; exports.MCP_PROTOCOL_VERSIONS = _chunkY4BWZB6Jcjs.MCP_PROTOCOL_VERSIONS; exports.MCP_TOOL_CANVAS_ADD_NODE = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_ADD_NODE; exports.MCP_TOOL_CANVAS_CONNECT = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_CONNECT; exports.MCP_TOOL_CANVAS_HIGHLIGHT = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_HIGHLIGHT; exports.MCP_TOOL_CANVAS_LAYOUT = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_LAYOUT; exports.MCP_TOOL_CANVAS_REMOVE_NODES = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_REMOVE_NODES; exports.MCP_TOOL_CANVAS_SELECT = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_SELECT; exports.MCP_TOOL_CANVAS_UPDATE_NODE = _chunkSVFEVKLFcjs.MCP_TOOL_CANVAS_UPDATE_NODE; exports.MCP_TOOL_EDIT_CANVAS = _chunkSVFEVKLFcjs.MCP_TOOL_EDIT_CANVAS; exports.MCP_TOOL_EDIT_PROMPT = _chunkSVFEVKLFcjs.MCP_TOOL_EDIT_PROMPT; exports.MCP_TOOL_GET_EDITOR_STATE = _chunkSVFEVKLFcjs.MCP_TOOL_GET_EDITOR_STATE; exports.MCP_TOOL_PROMPT_INSERT_TEXT = _chunkSVFEVKLFcjs.MCP_TOOL_PROMPT_INSERT_TEXT; exports.MCP_TOOL_PROMPT_REPLACE_RANGE = _chunkSVFEVKLFcjs.MCP_TOOL_PROMPT_REPLACE_RANGE; exports.MCP_TOOL_PROMPT_SELECT = _chunkSVFEVKLFcjs.MCP_TOOL_PROMPT_SELECT; exports.MCP_TOOL_PROMPT_SET_VARIABLE = _chunkSVFEVKLFcjs.MCP_TOOL_PROMPT_SET_VARIABLE; exports.MCP_TOOL_VIEW_EDITOR = _chunkSVFEVKLFcjs.MCP_TOOL_VIEW_EDITOR; exports.PRESENCE_COLORS = _chunkUJGAA6AKcjs.PRESENCE_COLORS; exports.PerformanceQueue = _chunkUJGAA6AKcjs.PerformanceQueue; exports.PresenceStore = _chunkUJGAA6AKcjs.PresenceStore; exports.TOOL_BRIDGE_DEFAULT_PORT = _chunkY4BWZB6Jcjs.TOOL_BRIDGE_DEFAULT_PORT; exports.TOOL_BRIDGE_PROTOCOL = _chunkY4BWZB6Jcjs.TOOL_BRIDGE_PROTOCOL; exports.TOOL_DISCOVERY_TOOLS = _chunkY4BWZB6Jcjs.TOOL_DISCOVERY_TOOLS; exports.TOOL_NAMESPACE_SEPARATOR = _chunkY4BWZB6Jcjs.TOOL_NAMESPACE_SEPARATOR; exports.ToolRegistry = _chunkY4BWZB6Jcjs.ToolRegistry; exports.ToolRegistryError = _chunkY4BWZB6Jcjs.ToolRegistryError; exports.ToolRegistryView = _chunkY4BWZB6Jcjs.ToolRegistryView; exports.UNSAFE_JSON_KEYS = _chunk2BSBFBOAcjs.UNSAFE_JSON_KEYS; exports.baseToolName = _chunkY4BWZB6Jcjs.baseToolName; exports.captureInputSchema = _chunkN2FGYZ4Qcjs.captureInputSchema; exports.captureOutputSize = _chunkN2FGYZ4Qcjs.captureOutputSize; exports.cloneElementWithStyles = _chunkSVFEVKLFcjs.cloneElementWithStyles; exports.connectToolBridge = _chunkY4BWZB6Jcjs.connectToolBridge; exports.createAgentPlayback = _chunk6SFREX6Hcjs.createAgentPlayback; exports.createCanvasComponentToolProvider = createCanvasComponentToolProvider; exports.createCaptureTool = _chunkN2FGYZ4Qcjs.createCaptureTool; exports.createCaptureToolProvider = _chunkN2FGYZ4Qcjs.createCaptureToolProvider; exports.createDocumentChartTools = createDocumentChartTools; exports.createEditorMcpToolProvider = createEditorMcpToolProvider; exports.createElementCaptureSurface = _chunkSVFEVKLFcjs.createElementCaptureSurface; exports.createInstantPresenceClock = _chunkUJGAA6AKcjs.createInstantPresenceClock; exports.createMcpServer = _chunkY4BWZB6Jcjs.createMcpServer; exports.createRichTextToolProvider = createRichTextToolProvider; exports.createSpreadsheetToolProvider = createSpreadsheetToolProvider; exports.createToolRegistry = _chunkY4BWZB6Jcjs.createToolRegistry; exports.derivePlaybackSteps = _chunk6SFREX6Hcjs.derivePlaybackSteps; exports.elementToSvg = _chunkSVFEVKLFcjs.elementToSvg; exports.errorResult = _chunkY4BWZB6Jcjs.errorResult; exports.isUnsafeJsonKey = _chunk2BSBFBOAcjs.isUnsafeJsonKey; exports.listSkills = _chunkY4BWZB6Jcjs.listSkills; exports.normalizeSide = normalizeSide; exports.parseSkillFrontmatter = _chunkY4BWZB6Jcjs.parseSkillFrontmatter; exports.planAgentCommand = planAgentCommand; exports.planCanvasPlaybackSteps = planCanvasPlaybackSteps; exports.planCanvasToolPlayback = planCanvasToolPlayback; exports.planToolCall = planToolCall; exports.playbackRefsFromArgs = _chunk6SFREX6Hcjs.playbackRefsFromArgs; exports.playbackRefsFromResult = _chunk6SFREX6Hcjs.playbackRefsFromResult; exports.rasterizeElement = _chunkSVFEVKLFcjs.rasterizeElement; exports.readSkillFile = _chunkY4BWZB6Jcjs.readSkillFile; exports.readingTime = _chunk6SFREX6Hcjs.readingTime; exports.realPresenceClock = _chunkUJGAA6AKcjs.realPresenceClock; exports.resolveCaptureRequest = _chunkN2FGYZ4Qcjs.resolveCaptureRequest; exports.searchTokens = _chunkY4BWZB6Jcjs.searchTokens; exports.searchTools = _chunkY4BWZB6Jcjs.searchTools; exports.stripPrototypeKeys = _chunk2BSBFBOAcjs.stripPrototypeKeys; exports.summarize = _chunkY4BWZB6Jcjs.summarize; exports.toCapturedImageData = _chunkN2FGYZ4Qcjs.toCapturedImageData; exports.toToolResult = _chunkY4BWZB6Jcjs.toToolResult; exports.toolCallToAgentCommand = toolCallToAgentCommand; exports.toolsetInstructions = _chunkY4BWZB6Jcjs.toolsetInstructions; exports.toolsetName = _chunkY4BWZB6Jcjs.toolsetName; exports.tweenPresenceCursor = _chunkUJGAA6AKcjs.tweenPresenceCursor; exports.unionCaptureRects = _chunkN2FGYZ4Qcjs.unionCaptureRects; exports.unionRects = _chunk6SFREX6Hcjs.unionRects; exports.unknownToolMessage = _chunkY4BWZB6Jcjs.unknownToolMessage; exports.validateAgentCommand = validateAgentCommand; exports.validateJsonSchema = _chunkWOFXZ3XUcjs.validateJsonSchema;
@@ -4,3 +4,4 @@ export * from '../tools/index.cjs';
4
4
  export * from './providers.cjs';
5
5
  export * from './documentChartTools.cjs';
6
6
  export * from './componentTools.cjs';
7
+ export * from './canvasPlayback.cjs';
@@ -4,3 +4,4 @@ export * from '../tools/index.js';
4
4
  export * from './providers.js';
5
5
  export * from './documentChartTools.js';
6
6
  export * from './componentTools.js';
7
+ export * from './canvasPlayback.js';
@@ -7,12 +7,14 @@ import {
7
7
  hasVariantCommands
8
8
  } from "../chunk-3TNA7JKI.js";
9
9
  import {
10
+ createNodeLookup,
10
11
  ensureLayout,
11
12
  getLayoutedNodes,
13
+ getNodeRect,
12
14
  placeBeside
13
- } from "../chunk-BTZS3KZY.js";
15
+ } from "../chunk-DW4CV5H4.js";
14
16
  import "../chunk-7KZ2HKKC.js";
15
- import "../chunk-K73HMKQP.js";
17
+ import "../chunk-PLKIYNJZ.js";
16
18
  import {
17
19
  JSON_RPC_ERRORS,
18
20
  MCP_PROTOCOL_VERSIONS,
@@ -38,7 +40,16 @@ import {
38
40
  toolsetInstructions,
39
41
  toolsetName,
40
42
  unknownToolMessage
41
- } from "../chunk-RB62U6MS.js";
43
+ } from "../chunk-RFBFTLVN.js";
44
+ import {
45
+ AgentPlayback,
46
+ createAgentPlayback,
47
+ derivePlaybackSteps,
48
+ playbackRefsFromArgs,
49
+ playbackRefsFromResult,
50
+ readingTime,
51
+ unionRects
52
+ } from "../chunk-MFFE55CS.js";
42
53
  import {
43
54
  CAPTURE_EXCLUDE_SELECTOR,
44
55
  CAPTURE_OVERLAY_SELECTORS,
@@ -128,6 +139,14 @@ import {
128
139
  isFormulaError
129
140
  } from "../chunk-II2WIF5Z.js";
130
141
  import "../chunk-WJSD3MAZ.js";
142
+ import {
143
+ PRESENCE_COLORS,
144
+ PerformanceQueue,
145
+ PresenceStore,
146
+ createInstantPresenceClock,
147
+ realPresenceClock,
148
+ tweenPresenceCursor
149
+ } from "../chunk-PEEP2YR7.js";
131
150
  import {
132
151
  validateJsonSchema
133
152
  } from "../chunk-V2ZCJRDM.js";
@@ -459,6 +478,87 @@ function planToolCall(name, args, snapshot, options) {
459
478
  import { TextSelection as TextSelection2 } from "@tiptap/pm/state";
460
479
  import { closeHistory as closeHistory3 } from "@tiptap/pm/history";
461
480
 
481
+ // src/agent/canvasPlayback.ts
482
+ var centre = (r) => ({ x: r.x + r.width / 2, y: r.y + r.height / 2 });
483
+ var labelOf = (data) => {
484
+ const label = data?.label ?? data?.title ?? data?.text;
485
+ return typeof label === "string" && label.trim() ? label : null;
486
+ };
487
+ function planCanvasPlaybackSteps(steps, nodes, rectOptions) {
488
+ const placed = new Map(createNodeLookup(nodes));
489
+ const rectOf = (id) => {
490
+ const node = placed.get(id);
491
+ return node ? getNodeRect(node, placed, rectOptions) : null;
492
+ };
493
+ const before = [];
494
+ const after = [];
495
+ const click = (rect) => rect ? [{ type: "move", to: centre(rect) }, { type: "focus", rect }, { type: "press" }, { type: "release" }] : [];
496
+ for (const step of steps) {
497
+ switch (step.type) {
498
+ case "step:canvas_add_node": {
499
+ placed.set(step.node.id, step.node);
500
+ const rect = rectOf(step.node.id);
501
+ const label = labelOf(step.node.data);
502
+ before.push(...click(rect), ...label ? [{ type: "type", text: label }] : []);
503
+ break;
504
+ }
505
+ case "step:canvas_add_edge": {
506
+ const a = rectOf(step.edge.source);
507
+ const b = rectOf(step.edge.target);
508
+ if (!a || !b) break;
509
+ const label = typeof step.edge.label === "string" ? step.edge.label : labelOf(step.edge.data);
510
+ before.push(
511
+ { type: "move", to: { x: a.x + a.width, y: a.y + a.height / 2 } },
512
+ { type: "press" },
513
+ { type: "drag", to: { x: b.x, y: b.y + b.height / 2 } },
514
+ { type: "release" },
515
+ ...label ? [{ type: "type", text: label }] : []
516
+ );
517
+ break;
518
+ }
519
+ case "step:canvas_update_node": {
520
+ const rect = rectOf(step.id);
521
+ const label = labelOf(step.data);
522
+ before.push(...click(rect), ...rect && label ? [{ type: "type", text: label }] : []);
523
+ break;
524
+ }
525
+ case "step:canvas_remove_nodes":
526
+ for (const id of step.nodeIds.slice(0, 8)) before.push(...click(rectOf(id)));
527
+ break;
528
+ case "step:canvas_select":
529
+ for (const id of step.nodeIds.slice(0, 8)) before.push(...click(rectOf(id)));
530
+ break;
531
+ case "step:canvas_highlight":
532
+ for (const id of step.nodeIds.slice(0, 8)) {
533
+ const rect = rectOf(id);
534
+ if (rect) before.push({ type: "move", to: centre(rect) }, { type: "focus", rect });
535
+ }
536
+ break;
537
+ case "step:canvas_move_nodes": {
538
+ const moved = Object.entries(step.positions);
539
+ for (const [id, position] of moved) {
540
+ const node = placed.get(id);
541
+ if (node) placed.set(id, { ...node, position });
542
+ }
543
+ const rect = unionRects(moved.map(([id]) => rectOf(id)));
544
+ if (rect) after.push({ type: "move", to: centre(rect) }, { type: "focus", rect }, { type: "wait", ms: 450 });
545
+ break;
546
+ }
547
+ default:
548
+ break;
549
+ }
550
+ }
551
+ if (!before.length && !after.length) return [];
552
+ return [...before, { type: "commit" }, ...after];
553
+ }
554
+ function planCanvasToolPlayback(name, args, snapshot, plannerOptions, rectOptions) {
555
+ const command = toolCallToAgentCommand(name, args);
556
+ if (!command || !command.type.startsWith("canvas:") || validateAgentCommand(command, snapshot)) return null;
557
+ const steps = planAgentCommand(command, snapshot, plannerOptions);
558
+ const planned = planCanvasPlaybackSteps(steps, snapshot.canvas?.nodes ?? [], rectOptions);
559
+ return planned.length ? planned : null;
560
+ }
561
+
462
562
  // src/agent/documentChartTools.ts
463
563
  import { closeHistory } from "@tiptap/pm/history";
464
564
  var READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
@@ -1769,7 +1869,12 @@ function createEditorMcpToolProvider(options) {
1769
1869
  };
1770
1870
  }
1771
1871
  },
1772
- ...editTools.map((definition) => ({ ...definition, handler: edit(definition.name) }))
1872
+ ...editTools.map((definition) => ({
1873
+ ...definition,
1874
+ handler: edit(definition.name),
1875
+ // The cursor goes where the planner puts the change (see `planCanvasToolPlayback`).
1876
+ plan: (args) => planCanvasToolPlayback(definition.name, args, options.getSnapshot(), options.plannerOptions, options.rectOptions)
1877
+ }))
1773
1878
  ];
1774
1879
  if (options.captureView) {
1775
1880
  const capture = options.captureView;
@@ -1787,6 +1892,7 @@ function createEditorMcpToolProvider(options) {
1787
1892
  title: "Canvas and prompt editor",
1788
1893
  description: "The node canvas and the prompt: editor state, nodes and edges, layout, prompt text, and a view of the editor.",
1789
1894
  skill: "pixerate-canvas",
1895
+ ...options.playbackSurface ? { playbackSurface: options.playbackSurface } : {},
1790
1896
  tools
1791
1897
  };
1792
1898
  }
@@ -1994,6 +2100,7 @@ function createCanvasComponentToolProvider(controller, options = { id: "canvas-c
1994
2100
  };
1995
2101
  }
1996
2102
  export {
2103
+ AgentPlayback,
1997
2104
  CAPTURE_EXCLUDE_SELECTOR,
1998
2105
  CAPTURE_OVERLAY_SELECTORS,
1999
2106
  EDITOR_CANVAS_TOOLS,
@@ -2018,6 +2125,9 @@ export {
2018
2125
  MCP_TOOL_PROMPT_SELECT,
2019
2126
  MCP_TOOL_PROMPT_SET_VARIABLE,
2020
2127
  MCP_TOOL_VIEW_EDITOR,
2128
+ PRESENCE_COLORS,
2129
+ PerformanceQueue,
2130
+ PresenceStore,
2021
2131
  TOOL_BRIDGE_DEFAULT_PORT,
2022
2132
  TOOL_BRIDGE_PROTOCOL,
2023
2133
  TOOL_DISCOVERY_TOOLS,
@@ -2031,16 +2141,19 @@ export {
2031
2141
  captureOutputSize,
2032
2142
  cloneElementWithStyles,
2033
2143
  connectToolBridge,
2144
+ createAgentPlayback,
2034
2145
  createCanvasComponentToolProvider,
2035
2146
  createCaptureTool,
2036
2147
  createCaptureToolProvider,
2037
2148
  createDocumentChartTools,
2038
2149
  createEditorMcpToolProvider,
2039
2150
  createElementCaptureSurface,
2151
+ createInstantPresenceClock,
2040
2152
  createMcpServer,
2041
2153
  createRichTextToolProvider,
2042
2154
  createSpreadsheetToolProvider,
2043
2155
  createToolRegistry,
2156
+ derivePlaybackSteps,
2044
2157
  elementToSvg,
2045
2158
  errorResult,
2046
2159
  isUnsafeJsonKey,
@@ -2048,9 +2161,15 @@ export {
2048
2161
  normalizeSide,
2049
2162
  parseSkillFrontmatter,
2050
2163
  planAgentCommand,
2164
+ planCanvasPlaybackSteps,
2165
+ planCanvasToolPlayback,
2051
2166
  planToolCall,
2167
+ playbackRefsFromArgs,
2168
+ playbackRefsFromResult,
2052
2169
  rasterizeElement,
2053
2170
  readSkillFile,
2171
+ readingTime,
2172
+ realPresenceClock,
2054
2173
  resolveCaptureRequest,
2055
2174
  searchTokens,
2056
2175
  searchTools,
@@ -2061,7 +2180,9 @@ export {
2061
2180
  toolCallToAgentCommand,
2062
2181
  toolsetInstructions,
2063
2182
  toolsetName,
2183
+ tweenPresenceCursor,
2064
2184
  unionCaptureRects,
2185
+ unionRects,
2065
2186
  unknownToolMessage,
2066
2187
  validateAgentCommand,
2067
2188
  validateJsonSchema
@@ -1,6 +1,7 @@
1
1
  import type { Editor } from '@tiptap/core';
2
2
  import type { SpreadsheetController } from '../spreadsheet/controller.cjs';
3
3
  import { type planToolCall } from './planner.cjs';
4
+ import type { NodeRectOptions } from '../canvas/arrange.cjs';
4
5
  import type { AgentToolProvider } from '../tools/registry.cjs';
5
6
  import type { AgentStep, EditorSnapshot } from './types.cjs';
6
7
  import type { CanvasEdge, CanvasNode } from '../canvas/types.cjs';
@@ -95,6 +96,13 @@ export interface EditorMcpToolProviderOptions<TNode extends CanvasNode = CanvasN
95
96
  canvas?: boolean;
96
97
  prompt?: boolean;
97
98
  };
99
+ /**
100
+ * The agent playback surface the canvas edits are acted out on (default: the provider id).
101
+ * Attach it with `useCanvasPlaybackSurface` / `createCanvasPlaybackSurface`.
102
+ */
103
+ playbackSurface?: string;
104
+ /** Node size resolution for the cursor's targets (match the canvas' own). */
105
+ rectOptions?: NodeRectOptions;
98
106
  }
99
107
  /**
100
108
  * Exposes the editor MCP tools (`get_editor_state`, the canvas and prompt
@@ -1,6 +1,7 @@
1
1
  import type { Editor } from '@tiptap/core';
2
2
  import type { SpreadsheetController } from '../spreadsheet/controller.js';
3
3
  import { type planToolCall } from './planner.js';
4
+ import type { NodeRectOptions } from '../canvas/arrange.js';
4
5
  import type { AgentToolProvider } from '../tools/registry.js';
5
6
  import type { AgentStep, EditorSnapshot } from './types.js';
6
7
  import type { CanvasEdge, CanvasNode } from '../canvas/types.js';
@@ -95,6 +96,13 @@ export interface EditorMcpToolProviderOptions<TNode extends CanvasNode = CanvasN
95
96
  canvas?: boolean;
96
97
  prompt?: boolean;
97
98
  };
99
+ /**
100
+ * The agent playback surface the canvas edits are acted out on (default: the provider id).
101
+ * Attach it with `useCanvasPlaybackSurface` / `createCanvasPlaybackSurface`.
102
+ */
103
+ playbackSurface?: string;
104
+ /** Node size resolution for the cursor's targets (match the canvas' own). */
105
+ rectOptions?: NodeRectOptions;
98
106
  }
99
107
  /**
100
108
  * Exposes the editor MCP tools (`get_editor_state`, the canvas and prompt
@@ -1,6 +1,9 @@
1
1
  import type { CanvasEdge, CanvasNode, Side, XYPosition } from '../canvas/types.cjs';
2
2
  /**
3
3
  * Agent presence state for visual multiplayer/agent choreography.
4
+ *
5
+ * @deprecated Agent playback (`createAgentPlayback` in `@pixerate/editor/tools`) keeps cursors in a
6
+ * `PresenceStore` per surface and plays every tool call; draw them with `PresenceLayer`.
4
7
  */
5
8
  export interface AgentPresence {
6
9
  agentId: string;
@@ -1,6 +1,9 @@
1
1
  import type { CanvasEdge, CanvasNode, Side, XYPosition } from '../canvas/types.js';
2
2
  /**
3
3
  * Agent presence state for visual multiplayer/agent choreography.
4
+ *
5
+ * @deprecated Agent playback (`createAgentPlayback` in `@pixerate/editor/tools`) keeps cursors in a
6
+ * `PresenceStore` per surface and plays every tool call; draw them with `PresenceLayer`.
4
7
  */
5
8
  export interface AgentPresence {
6
9
  agentId: string;