@particle-academy/agent-integrations 0.2.4 → 0.3.4

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 (107) hide show
  1. package/dist/bridges/charts.d.cts +39 -0
  2. package/dist/bridges/charts.d.ts +39 -0
  3. package/dist/bridges/code.d.cts +47 -0
  4. package/dist/bridges/code.d.ts +47 -0
  5. package/dist/bridges/flow.d.cts +3 -2
  6. package/dist/bridges/flow.d.ts +3 -2
  7. package/dist/bridges/forms.d.cts +76 -0
  8. package/dist/bridges/forms.d.ts +76 -0
  9. package/dist/bridges/scene.d.cts +54 -0
  10. package/dist/bridges/scene.d.ts +54 -0
  11. package/dist/bridges/sheets.d.cts +62 -0
  12. package/dist/bridges/sheets.d.ts +62 -0
  13. package/dist/bridges/whiteboard.d.cts +3 -2
  14. package/dist/bridges/whiteboard.d.ts +3 -2
  15. package/dist/bridges-charts.cjs +167 -0
  16. package/dist/bridges-charts.cjs.map +1 -0
  17. package/dist/bridges-charts.js +6 -0
  18. package/dist/bridges-charts.js.map +1 -0
  19. package/dist/bridges-code.cjs +219 -0
  20. package/dist/bridges-code.cjs.map +1 -0
  21. package/dist/bridges-code.js +6 -0
  22. package/dist/bridges-code.js.map +1 -0
  23. package/dist/bridges-flow.cjs +76 -17
  24. package/dist/bridges-flow.cjs.map +1 -1
  25. package/dist/bridges-flow.js +3 -1
  26. package/dist/bridges-forms.cjs +205 -0
  27. package/dist/bridges-forms.cjs.map +1 -0
  28. package/dist/bridges-forms.js +6 -0
  29. package/dist/bridges-forms.js.map +1 -0
  30. package/dist/bridges-scene.cjs +250 -0
  31. package/dist/bridges-scene.cjs.map +1 -0
  32. package/dist/bridges-scene.js +6 -0
  33. package/dist/bridges-scene.js.map +1 -0
  34. package/dist/bridges-sheets.cjs +327 -0
  35. package/dist/bridges-sheets.cjs.map +1 -0
  36. package/dist/bridges-sheets.js +6 -0
  37. package/dist/bridges-sheets.js.map +1 -0
  38. package/dist/bridges-whiteboard.cjs +224 -38
  39. package/dist/bridges-whiteboard.cjs.map +1 -1
  40. package/dist/bridges-whiteboard.js +4 -1
  41. package/dist/{chunk-2VOQJKSU.js → chunk-4IAVAFUV.js} +41 -19
  42. package/dist/chunk-4IAVAFUV.js.map +1 -0
  43. package/dist/chunk-52S7XYZK.js +38 -0
  44. package/dist/chunk-52S7XYZK.js.map +1 -0
  45. package/dist/chunk-ACBENYYO.js +124 -0
  46. package/dist/chunk-ACBENYYO.js.map +1 -0
  47. package/dist/chunk-DJOWMF6Q.js +25 -0
  48. package/dist/chunk-DJOWMF6Q.js.map +1 -0
  49. package/dist/{chunk-FLEOQUKF.js → chunk-JMYPUAFH.js} +17 -2
  50. package/dist/chunk-JMYPUAFH.js.map +1 -0
  51. package/dist/chunk-JU2N4KK6.js +34 -0
  52. package/dist/chunk-JU2N4KK6.js.map +1 -0
  53. package/dist/chunk-OEIULP2L.js +158 -0
  54. package/dist/chunk-OEIULP2L.js.map +1 -0
  55. package/dist/chunk-PDBF4W7E.js +280 -0
  56. package/dist/chunk-PDBF4W7E.js.map +1 -0
  57. package/dist/chunk-PHPXKSWI.js +120 -0
  58. package/dist/chunk-PHPXKSWI.js.map +1 -0
  59. package/dist/chunk-QJUTISFC.js +203 -0
  60. package/dist/chunk-QJUTISFC.js.map +1 -0
  61. package/dist/{chunk-5ZUHNNLR.js → chunk-TBEITXF4.js} +79 -41
  62. package/dist/chunk-TBEITXF4.js.map +1 -0
  63. package/dist/chunk-X66JWQBB.js +37 -0
  64. package/dist/chunk-X66JWQBB.js.map +1 -0
  65. package/dist/chunk-XYYSTJHW.js +172 -0
  66. package/dist/chunk-XYYSTJHW.js.map +1 -0
  67. package/dist/index.cjs +1411 -57
  68. package/dist/index.cjs.map +1 -1
  69. package/dist/index.d.cts +96 -3
  70. package/dist/index.d.ts +96 -3
  71. package/dist/index.js +111 -7
  72. package/dist/index.js.map +1 -1
  73. package/dist/mcp/index.d.cts +4 -2
  74. package/dist/mcp/index.d.ts +4 -2
  75. package/dist/presence/index.d.cts +136 -0
  76. package/dist/presence/index.d.ts +136 -0
  77. package/dist/presence.cjs +107 -0
  78. package/dist/presence.cjs.map +1 -0
  79. package/dist/presence.js +5 -0
  80. package/dist/presence.js.map +1 -0
  81. package/dist/registry-2DRURS6U.js +3 -0
  82. package/dist/registry-2DRURS6U.js.map +1 -0
  83. package/dist/server-BJu_AMH3.d.ts +64 -0
  84. package/dist/server-si-VvFxI.d.cts +64 -0
  85. package/dist/sharing/index.d.cts +2 -1
  86. package/dist/sharing/index.d.ts +2 -1
  87. package/dist/sharing.cjs +68 -0
  88. package/dist/sharing.cjs.map +1 -1
  89. package/dist/sharing.js +1 -1
  90. package/dist/styles.css +57 -0
  91. package/dist/styles.css.map +1 -1
  92. package/dist/{types-DR5AS6Rd.d.cts → types-Bf1ZoGmI.d.cts} +1 -1
  93. package/dist/{types-CRPA_D0z.d.ts → types-DXKpLuia.d.ts} +1 -1
  94. package/dist/types-DksGd5Y7.d.cts +112 -0
  95. package/dist/types-DksGd5Y7.d.ts +112 -0
  96. package/dist/undo/index.d.cts +69 -0
  97. package/dist/undo/index.d.ts +69 -0
  98. package/dist/undo.cjs +163 -0
  99. package/dist/undo.cjs.map +1 -0
  100. package/dist/undo.js +5 -0
  101. package/dist/undo.js.map +1 -0
  102. package/package.json +1 -1
  103. package/dist/chunk-2VOQJKSU.js.map +0 -1
  104. package/dist/chunk-5ZUHNNLR.js.map +0 -1
  105. package/dist/chunk-FLEOQUKF.js.map +0 -1
  106. package/dist/server-Bv985us3.d.cts +0 -173
  107. package/dist/server-Bv985us3.d.ts +0 -173
package/dist/index.cjs CHANGED
@@ -4,6 +4,59 @@ var react = require('react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var fancyWhiteboard = require('@particle-academy/fancy-whiteboard');
6
6
 
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropNames = Object.getOwnPropertyNames;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+
17
+ // src/presence/registry.ts
18
+ var registry_exports = {};
19
+ __export(registry_exports, {
20
+ emitActivity: () => emitActivity,
21
+ onActivity: () => onActivity,
22
+ readActivityHistory: () => readActivityHistory,
23
+ resetActivityRegistry: () => resetActivityRegistry
24
+ });
25
+ function emitActivity(event) {
26
+ history.push(event);
27
+ if (history.length > HISTORY_CAP) history.splice(0, history.length - HISTORY_CAP);
28
+ for (const l of listeners) l(event);
29
+ }
30
+ function onActivity(listener, filter) {
31
+ const wrapped = filter ? (e) => {
32
+ if (matches(e, filter)) listener(e);
33
+ } : listener;
34
+ listeners.add(wrapped);
35
+ return () => listeners.delete(wrapped);
36
+ }
37
+ function readActivityHistory(filter) {
38
+ if (!filter) return history.slice();
39
+ return history.filter((e) => matches(e, filter));
40
+ }
41
+ function resetActivityRegistry() {
42
+ listeners.clear();
43
+ history.length = 0;
44
+ }
45
+ function matches(e, f) {
46
+ if (f.agentId !== void 0 && e.agentId !== f.agentId) return false;
47
+ if (f.screenId !== void 0 && e.target.screenId !== f.screenId) return false;
48
+ if (f.kind !== void 0 && e.target.kind !== f.kind) return false;
49
+ return true;
50
+ }
51
+ var HISTORY_CAP, listeners, history;
52
+ var init_registry = __esm({
53
+ "src/presence/registry.ts"() {
54
+ HISTORY_CAP = 200;
55
+ listeners = /* @__PURE__ */ new Set();
56
+ history = [];
57
+ }
58
+ });
59
+
7
60
  // src/mcp/types.ts
8
61
  var JSONRPC_METHOD_NOT_FOUND = -32601;
9
62
  var JSONRPC_INVALID_PARAMS = -32602;
@@ -194,6 +247,159 @@ function attachRelay(server, channel) {
194
247
  return transport;
195
248
  }
196
249
 
250
+ // src/presence/wrap-tool-with-activity.ts
251
+ init_registry();
252
+ function wrapToolWithActivity(handler, options) {
253
+ return async (args) => {
254
+ const result = await handler(args);
255
+ if (result.isError) return result;
256
+ let target;
257
+ if (options.resolveTarget) {
258
+ target = options.resolveTarget({ toolName: options.toolName, args, result });
259
+ } else {
260
+ target = { kind: options.kind, screenId: options.screenId };
261
+ }
262
+ if (!target) return result;
263
+ emitActivity({
264
+ agentId: options.agent.id,
265
+ agentName: options.agent.name,
266
+ agentColor: options.agent.color,
267
+ target: { ...target, kind: target.kind ?? options.kind, screenId: target.screenId ?? options.screenId },
268
+ action: options.toolName,
269
+ timestamp: Date.now(),
270
+ meta: extractMeta(result),
271
+ ttlMs: options.ttlMs
272
+ });
273
+ return result;
274
+ };
275
+ }
276
+ function extractMeta(result) {
277
+ const sc = result.structuredContent;
278
+ if (sc && typeof sc === "object" && !Array.isArray(sc)) {
279
+ return sc;
280
+ }
281
+ return void 0;
282
+ }
283
+
284
+ // src/undo/undo-stack.ts
285
+ var stacks = /* @__PURE__ */ new Map();
286
+ var CAP = 200;
287
+ function getStack(agentId) {
288
+ let s = stacks.get(agentId);
289
+ if (!s) {
290
+ s = { past: [], future: [] };
291
+ stacks.set(agentId, s);
292
+ }
293
+ return s;
294
+ }
295
+ function pushUndoEntry(agentId, entry) {
296
+ const s = getStack(agentId);
297
+ s.past.push(entry);
298
+ if (s.past.length > CAP) s.past.splice(0, s.past.length - CAP);
299
+ s.future.length = 0;
300
+ }
301
+ async function undoOne(agentId) {
302
+ const s = getStack(agentId);
303
+ const entry = s.past.pop();
304
+ if (!entry) return null;
305
+ await entry.undo();
306
+ s.future.push(entry);
307
+ return entry;
308
+ }
309
+ async function redoOne(agentId) {
310
+ const s = getStack(agentId);
311
+ const entry = s.future.pop();
312
+ if (!entry) return null;
313
+ await entry.redo();
314
+ s.past.push(entry);
315
+ return entry;
316
+ }
317
+ function readHistory(agentId) {
318
+ return getStack(agentId).past.slice();
319
+ }
320
+ function clearStack(agentId) {
321
+ stacks.delete(agentId);
322
+ }
323
+ function resetAllUndoStacks() {
324
+ stacks.clear();
325
+ }
326
+
327
+ // src/undo/undo-tools.ts
328
+ var installedServers = /* @__PURE__ */ new WeakSet();
329
+ function ensureUndoToolsRegistered(server, options = {}) {
330
+ if (installedServers.has(server)) return;
331
+ installedServers.add(server);
332
+ registerUndoTools(server, options);
333
+ }
334
+ function registerUndoTools(server, options = {}) {
335
+ const defaultAgent = options.defaultAgentId ?? "agent";
336
+ const disposers = [];
337
+ const agentOf = (args) => typeof args?.agentId === "string" ? args.agentId : defaultAgent;
338
+ disposers.push(
339
+ server.registerTool(
340
+ {
341
+ name: "agent_undo",
342
+ description: "Undo the most recent action on the agent's stack. Optional agentId targets a specific agent.",
343
+ inputSchema: {
344
+ type: "object",
345
+ properties: { agentId: { type: "string" } },
346
+ additionalProperties: false
347
+ }
348
+ },
349
+ async (args) => {
350
+ const entry = await undoOne(agentOf(args));
351
+ if (!entry) return errorResult("Nothing to undo.");
352
+ return textResult(`Undid: ${entry.label}`, { entry: serialize(entry) });
353
+ }
354
+ )
355
+ );
356
+ disposers.push(
357
+ server.registerTool(
358
+ {
359
+ name: "agent_redo",
360
+ description: "Redo the most recently undone action.",
361
+ inputSchema: {
362
+ type: "object",
363
+ properties: { agentId: { type: "string" } },
364
+ additionalProperties: false
365
+ }
366
+ },
367
+ async (args) => {
368
+ const entry = await redoOne(agentOf(args));
369
+ if (!entry) return errorResult("Nothing to redo.");
370
+ return textResult(`Redid: ${entry.label}`, { entry: serialize(entry) });
371
+ }
372
+ )
373
+ );
374
+ disposers.push(
375
+ server.registerTool(
376
+ {
377
+ name: "agent_history",
378
+ description: "List the agent's undo stack (oldest first). Useful for understanding what's reversible.",
379
+ inputSchema: {
380
+ type: "object",
381
+ properties: { agentId: { type: "string" } },
382
+ additionalProperties: false
383
+ }
384
+ },
385
+ async (args) => {
386
+ const history2 = readHistory(agentOf(args)).map(serialize);
387
+ const text = history2.map((e) => `${new Date(e.timestamp).toISOString()} ${e.bridgeId} ${e.action}: ${e.label}`).join("\n");
388
+ return textResult(text || "(empty)", history2);
389
+ }
390
+ )
391
+ );
392
+ return () => disposers.forEach((d) => d());
393
+ }
394
+ function serialize(entry) {
395
+ return {
396
+ timestamp: entry.timestamp,
397
+ bridgeId: entry.bridgeId,
398
+ action: entry.action,
399
+ label: entry.label
400
+ };
401
+ }
402
+
197
403
  // src/bridges/whiteboard.ts
198
404
  var DEFAULT_AGENT = { id: "agent", name: "Agent", color: "#a855f7" };
199
405
  var VALID_SHAPES = ["rect", "rounded-rect", "ellipse", "diamond", "triangle", "line", "arrow", "text"];
@@ -205,7 +411,25 @@ function registerWhiteboardBridge(server, options) {
205
411
  const { adapter } = options;
206
412
  const agent = { ...DEFAULT_AGENT, ...options.agent ?? {} };
207
413
  const disposers = [];
208
- const reg = (name, description, inputProperties, required, handler) => {
414
+ ensureUndoToolsRegistered(server, { defaultAgentId: agent.id });
415
+ const wbTarget = (args, result) => ({
416
+ kind: "whiteboard",
417
+ elementId: result?.structuredContent?.id ?? args?.id
418
+ });
419
+ const reg = (name, description, inputProperties, required, handler, resolveTarget) => {
420
+ const wrapped = async (args) => {
421
+ try {
422
+ return await handler(args);
423
+ } catch (e) {
424
+ return errorResult(e instanceof Error ? e.message : String(e));
425
+ }
426
+ };
427
+ const final = resolveTarget ? wrapToolWithActivity(wrapped, {
428
+ toolName: name,
429
+ agent: { id: agent.id, name: agent.name, color: agent.color },
430
+ kind: "whiteboard",
431
+ resolveTarget: ({ args, result }) => resolveTarget(args, result)
432
+ }) : wrapped;
209
433
  disposers.push(
210
434
  server.registerTool(
211
435
  {
@@ -218,13 +442,7 @@ function registerWhiteboardBridge(server, options) {
218
442
  additionalProperties: false
219
443
  }
220
444
  },
221
- async (args) => {
222
- try {
223
- return await handler(args);
224
- } catch (e) {
225
- return errorResult(e instanceof Error ? e.message : String(e));
226
- }
227
- }
445
+ final
228
446
  )
229
447
  );
230
448
  };
@@ -301,8 +519,17 @@ function registerWhiteboardBridge(server, options) {
301
519
  authorId: agent.id
302
520
  };
303
521
  adapter.setNotes((all) => [...all, note]);
522
+ pushUndoEntry(agent.id, {
523
+ timestamp: Date.now(),
524
+ bridgeId: "whiteboard",
525
+ action: "whiteboard_add_sticky",
526
+ label: `Added sticky ${note.id}`,
527
+ undo: () => adapter.setNotes((all) => all.filter((n) => n.id !== note.id)),
528
+ redo: () => adapter.setNotes((all) => [...all, note])
529
+ });
304
530
  return textResult(`Added sticky ${note.id}`, note);
305
- }
531
+ },
532
+ wbTarget
306
533
  );
307
534
  reg(
308
535
  "whiteboard_stream_text",
@@ -369,7 +596,8 @@ function registerWhiteboardBridge(server, options) {
369
596
  })
370
597
  );
371
598
  return textResult(`Updated sticky ${id}`, updated);
372
- }
599
+ },
600
+ wbTarget
373
601
  );
374
602
  reg(
375
603
  "whiteboard_add_shape",
@@ -410,7 +638,8 @@ function registerWhiteboardBridge(server, options) {
410
638
  };
411
639
  adapter.setShapes((all) => [...all, shape]);
412
640
  return textResult(`Added ${kind} ${shape.id}`, shape);
413
- }
641
+ },
642
+ wbTarget
414
643
  );
415
644
  reg(
416
645
  "whiteboard_update_shape",
@@ -452,7 +681,8 @@ function registerWhiteboardBridge(server, options) {
452
681
  })
453
682
  );
454
683
  return textResult(`Updated shape ${id}`, updated);
455
- }
684
+ },
685
+ wbTarget
456
686
  );
457
687
  reg(
458
688
  "whiteboard_add_connector",
@@ -473,7 +703,8 @@ function registerWhiteboardBridge(server, options) {
473
703
  };
474
704
  adapter.setConnectors((all) => [...all, c]);
475
705
  return textResult(`Added connector ${c.id}`, c);
476
- }
706
+ },
707
+ wbTarget
477
708
  );
478
709
  reg(
479
710
  "whiteboard_add_stroke",
@@ -502,7 +733,8 @@ function registerWhiteboardBridge(server, options) {
502
733
  };
503
734
  adapter.setStrokes((all) => [...all, stroke]);
504
735
  return textResult(`Added stroke ${stroke.id} (${points.length} points)`, stroke);
505
- }
736
+ },
737
+ wbTarget
506
738
  );
507
739
  reg(
508
740
  "whiteboard_delete_item",
@@ -511,29 +743,37 @@ function registerWhiteboardBridge(server, options) {
511
743
  ["id"],
512
744
  (args) => {
513
745
  const id = str(args.id);
514
- let removed = false;
515
- adapter.setNotes((all) => {
516
- const next = all.filter((x) => x.id !== id);
517
- if (next.length !== all.length) removed = true;
518
- return next;
519
- });
520
- adapter.setShapes((all) => {
521
- const next = all.filter((x) => x.id !== id);
522
- if (next.length !== all.length) removed = true;
523
- return next;
524
- });
525
- adapter.setConnectors((all) => {
526
- const next = all.filter((x) => x.id !== id);
527
- if (next.length !== all.length) removed = true;
528
- return next;
529
- });
530
- adapter.setStrokes((all) => {
531
- const next = all.filter((x) => x.id !== id);
532
- if (next.length !== all.length) removed = true;
533
- return next;
746
+ const removedNotes = adapter.getNotes().filter((x) => x.id === id);
747
+ const removedShapes = adapter.getShapes().filter((x) => x.id === id);
748
+ const removedConnectors = adapter.getConnectors().filter((x) => x.id === id);
749
+ const removedStrokes = adapter.getStrokes().filter((x) => x.id === id);
750
+ const removed = removedNotes.length + removedShapes.length + removedConnectors.length + removedStrokes.length > 0;
751
+ if (!removed) return errorResult(`No item with id ${id}`);
752
+ adapter.setNotes((all) => all.filter((x) => x.id !== id));
753
+ adapter.setShapes((all) => all.filter((x) => x.id !== id));
754
+ adapter.setConnectors((all) => all.filter((x) => x.id !== id));
755
+ adapter.setStrokes((all) => all.filter((x) => x.id !== id));
756
+ pushUndoEntry(agent.id, {
757
+ timestamp: Date.now(),
758
+ bridgeId: "whiteboard",
759
+ action: "whiteboard_delete_item",
760
+ label: `Deleted ${id}`,
761
+ undo: () => {
762
+ if (removedNotes.length) adapter.setNotes((all) => [...all, ...removedNotes]);
763
+ if (removedShapes.length) adapter.setShapes((all) => [...all, ...removedShapes]);
764
+ if (removedConnectors.length) adapter.setConnectors((all) => [...all, ...removedConnectors]);
765
+ if (removedStrokes.length) adapter.setStrokes((all) => [...all, ...removedStrokes]);
766
+ },
767
+ redo: () => {
768
+ adapter.setNotes((all) => all.filter((x) => x.id !== id));
769
+ adapter.setShapes((all) => all.filter((x) => x.id !== id));
770
+ adapter.setConnectors((all) => all.filter((x) => x.id !== id));
771
+ adapter.setStrokes((all) => all.filter((x) => x.id !== id));
772
+ }
534
773
  });
535
- return removed ? textResult(`Deleted ${id}`) : errorResult(`No item with id ${id}`);
536
- }
774
+ return textResult(`Deleted ${id}`);
775
+ },
776
+ wbTarget
537
777
  );
538
778
  reg(
539
779
  "whiteboard_set_viewport",
@@ -549,7 +789,8 @@ function registerWhiteboardBridge(server, options) {
549
789
  };
550
790
  adapter.setViewport(next);
551
791
  return textResult(`Viewport \u2192 ${JSON.stringify(next)}`, next);
552
- }
792
+ },
793
+ wbTarget
553
794
  );
554
795
  reg(
555
796
  "whiteboard_set_agent_cursor",
@@ -575,7 +816,8 @@ function registerWhiteboardBridge(server, options) {
575
816
  };
576
817
  adapter.setAgentCursor(cursor);
577
818
  return textResult(`Cursor \u2192 (${cursor.x}, ${cursor.y})`, cursor);
578
- }
819
+ },
820
+ wbTarget
579
821
  );
580
822
  return {
581
823
  id: "whiteboard",
@@ -586,14 +828,34 @@ function registerWhiteboardBridge(server, options) {
586
828
  }
587
829
  };
588
830
  }
831
+
832
+ // src/bridges/flow.ts
833
+ var DEFAULT_AGENT2 = { id: "agent", name: "Agent", color: "#a855f7" };
589
834
  var num2 = (v, fallback) => typeof v === "number" && Number.isFinite(v) ? v : 0;
590
835
  var str2 = (v, fallback = "") => typeof v === "string" ? v : fallback;
591
836
  var newId2 = (prefix) => `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`;
592
837
  function registerFlowBridge(server, options) {
593
838
  const { adapter } = options;
594
- ({ ...options.agent ?? {} });
839
+ const agent = { ...DEFAULT_AGENT2, ...options.agent ?? {} };
595
840
  const disposers = [];
596
- const reg = (name, description, properties, required, handler) => {
841
+ const flTarget = (args, result) => ({
842
+ kind: "flow",
843
+ elementId: result?.structuredContent?.id ?? args?.id
844
+ });
845
+ const reg = (name, description, properties, required, handler, resolveTarget) => {
846
+ const wrapped = async (args) => {
847
+ try {
848
+ return await handler(args);
849
+ } catch (e) {
850
+ return errorResult(e instanceof Error ? e.message : String(e));
851
+ }
852
+ };
853
+ const final = resolveTarget ? wrapToolWithActivity(wrapped, {
854
+ toolName: name,
855
+ agent: { id: agent.id, name: agent.name, color: agent.color },
856
+ kind: "flow",
857
+ resolveTarget: ({ args, result }) => resolveTarget(args, result)
858
+ }) : wrapped;
597
859
  disposers.push(
598
860
  server.registerTool(
599
861
  {
@@ -601,13 +863,7 @@ function registerFlowBridge(server, options) {
601
863
  description,
602
864
  inputSchema: { type: "object", properties, required, additionalProperties: false }
603
865
  },
604
- async (args) => {
605
- try {
606
- return await handler(args);
607
- } catch (e) {
608
- return errorResult(e instanceof Error ? e.message : String(e));
609
- }
610
- }
866
+ final
611
867
  )
612
868
  );
613
869
  };
@@ -743,7 +999,8 @@ function registerFlowBridge(server, options) {
743
999
  };
744
1000
  adapter.setNodes((all) => [...all, node]);
745
1001
  return textResult(`Added ${kindName} ${id} ("${str2(args.label)}")`, node);
746
- }
1002
+ },
1003
+ flTarget
747
1004
  );
748
1005
  reg(
749
1006
  "flow_update_node",
@@ -781,7 +1038,8 @@ function registerFlowBridge(server, options) {
781
1038
  );
782
1039
  if (!updated) return errorResult(`No node with id ${id}`);
783
1040
  return textResult(`Updated node ${id}`, updated);
784
- }
1041
+ },
1042
+ flTarget
785
1043
  );
786
1044
  reg(
787
1045
  "flow_delete_node",
@@ -796,7 +1054,8 @@ function registerFlowBridge(server, options) {
796
1054
  adapter.setNodes((all) => all.filter((n) => n.id !== id));
797
1055
  adapter.setEdges((all) => all.filter((e) => e.source !== id && e.target !== id));
798
1056
  return textResult(`Deleted node ${id}`);
799
- }
1057
+ },
1058
+ flTarget
800
1059
  );
801
1060
  reg(
802
1061
  "flow_connect",
@@ -825,7 +1084,8 @@ function registerFlowBridge(server, options) {
825
1084
  };
826
1085
  adapter.setEdges((existing) => [...existing, edge]);
827
1086
  return textResult(`Connected ${source}${edge.sourceHandle ? `:${edge.sourceHandle}` : ""} \u2192 ${target}${edge.targetHandle ? `:${edge.targetHandle}` : ""}`, edge);
828
- }
1087
+ },
1088
+ flTarget
829
1089
  );
830
1090
  reg(
831
1091
  "flow_disconnect",
@@ -839,7 +1099,8 @@ function registerFlowBridge(server, options) {
839
1099
  }
840
1100
  adapter.setEdges((all) => all.filter((e) => e.id !== id));
841
1101
  return textResult(`Disconnected ${id}`);
842
- }
1102
+ },
1103
+ flTarget
843
1104
  );
844
1105
  reg(
845
1106
  "flow_set_node_status",
@@ -868,7 +1129,8 @@ function registerFlowBridge(server, options) {
868
1129
  if (!found) return errorResult(`No node with id ${id}`);
869
1130
  }
870
1131
  return textResult(`${id} \u2192 ${status}${text ? ` (${text})` : ""}`);
871
- }
1132
+ },
1133
+ flTarget
872
1134
  );
873
1135
  reg(
874
1136
  "flow_run",
@@ -879,7 +1141,8 @@ function registerFlowBridge(server, options) {
879
1141
  if (!adapter.run) return errorResult("Host did not provide a run handler.");
880
1142
  const result = await adapter.run();
881
1143
  return textResult(result.ok ? "Run complete" : `Run failed: ${result.error ?? "unknown"}`, result);
882
- }
1144
+ },
1145
+ flTarget
883
1146
  );
884
1147
  reg(
885
1148
  "flow_cancel",
@@ -890,7 +1153,8 @@ function registerFlowBridge(server, options) {
890
1153
  if (!adapter.cancel) return errorResult("Host did not provide a cancel handler.");
891
1154
  adapter.cancel();
892
1155
  return textResult("Run cancelled");
893
- }
1156
+ },
1157
+ flTarget
894
1158
  );
895
1159
  return {
896
1160
  id: "flow",
@@ -900,6 +1164,909 @@ function registerFlowBridge(server, options) {
900
1164
  }
901
1165
  };
902
1166
  }
1167
+
1168
+ // src/bridges/forms.ts
1169
+ var DEFAULT_AGENT3 = { id: "agent", name: "Agent", color: "#a855f7" };
1170
+ function registerFormBridge(server, options) {
1171
+ const { adapter } = options;
1172
+ const agent = { ...DEFAULT_AGENT3, ...options.agent ?? {} };
1173
+ const disposers = [];
1174
+ const formId = adapter.id;
1175
+ const target = (args) => ({
1176
+ kind: "form",
1177
+ screenId: adapter.screenId,
1178
+ elementId: typeof args?.field === "string" ? `${formId}:${args.field}` : formId,
1179
+ label: typeof args?.field === "string" ? `${adapter.title ?? formId} \u2192 ${args.field}` : adapter.title ?? formId
1180
+ });
1181
+ const reg = (name, description, properties, required, handler, isMutation) => {
1182
+ const wrapped = async (args) => {
1183
+ try {
1184
+ return await handler(args);
1185
+ } catch (e) {
1186
+ return errorResult(e instanceof Error ? e.message : String(e));
1187
+ }
1188
+ };
1189
+ const final = isMutation ? wrapToolWithActivity(wrapped, {
1190
+ toolName: name,
1191
+ agent: { id: agent.id, name: agent.name, color: agent.color },
1192
+ kind: "form",
1193
+ screenId: adapter.screenId,
1194
+ resolveTarget: ({ args }) => target(args)
1195
+ }) : wrapped;
1196
+ disposers.push(
1197
+ server.registerTool(
1198
+ {
1199
+ name,
1200
+ description,
1201
+ inputSchema: { type: "object", properties, required, additionalProperties: false }
1202
+ },
1203
+ final
1204
+ )
1205
+ );
1206
+ };
1207
+ reg(
1208
+ "form_describe",
1209
+ `Describe the form "${formId}" \u2014 fields, types, options, required flags. Call this first to know what's fillable.`,
1210
+ {},
1211
+ [],
1212
+ () => {
1213
+ const fields = adapter.getFields();
1214
+ const text = fields.map((f) => `${f.name}${f.required ? "*" : ""} (${f.type})${f.label ? ` \u2014 ${f.label}` : ""}`).join("\n");
1215
+ return textResult(text || "(no fields)", { id: formId, title: adapter.title, fields });
1216
+ },
1217
+ false
1218
+ );
1219
+ reg(
1220
+ "form_get_value",
1221
+ "Read a single field's current value.",
1222
+ { field: { type: "string" } },
1223
+ ["field"],
1224
+ (args) => {
1225
+ const name = String(args.field ?? "");
1226
+ if (!adapter.getFields().find((f) => f.name === name)) {
1227
+ return errorResult(`Unknown field: ${name}`);
1228
+ }
1229
+ const value = adapter.getValue(name);
1230
+ return textResult(JSON.stringify(value), { field: name, value });
1231
+ },
1232
+ false
1233
+ );
1234
+ reg(
1235
+ "form_get_values",
1236
+ "Read every field's current value as a JSON object.",
1237
+ {},
1238
+ [],
1239
+ () => {
1240
+ const values = adapter.getValues();
1241
+ return textResult(JSON.stringify(values, null, 2), values);
1242
+ },
1243
+ false
1244
+ );
1245
+ reg(
1246
+ "form_set_value",
1247
+ "Set one field's value. The host's controlled state updates and the human sees the field change.",
1248
+ {
1249
+ field: { type: "string" },
1250
+ value: { description: "Value to set. Type depends on the field's `type`." }
1251
+ },
1252
+ ["field", "value"],
1253
+ (args) => {
1254
+ const name = String(args.field ?? "");
1255
+ const fieldDef = adapter.getFields().find((f) => f.name === name);
1256
+ if (!fieldDef) return errorResult(`Unknown field: ${name}`);
1257
+ adapter.setValue(name, args.value);
1258
+ return textResult(`${name} \u2190 ${JSON.stringify(args.value)}`, { field: name, value: args.value });
1259
+ },
1260
+ true
1261
+ );
1262
+ reg(
1263
+ "form_set_values",
1264
+ "Set multiple fields atomically. Pass a `values` object keyed by field name.",
1265
+ { values: { type: "object" } },
1266
+ ["values"],
1267
+ (args) => {
1268
+ const values = args.values && typeof args.values === "object" ? args.values : {};
1269
+ const fields = adapter.getFields();
1270
+ const known = new Set(fields.map((f) => f.name));
1271
+ const unknownKeys = Object.keys(values).filter((k) => !known.has(k));
1272
+ if (unknownKeys.length) return errorResult(`Unknown fields: ${unknownKeys.join(", ")}`);
1273
+ if (adapter.setValues) {
1274
+ adapter.setValues(values);
1275
+ } else {
1276
+ for (const [k, v] of Object.entries(values)) adapter.setValue(k, v);
1277
+ }
1278
+ return textResult(`Set ${Object.keys(values).length} field(s)`, { values });
1279
+ },
1280
+ true
1281
+ );
1282
+ reg(
1283
+ "form_focus",
1284
+ "Move browser focus to a field (host-implemented). Useful before streaming text into it.",
1285
+ { field: { type: "string" } },
1286
+ ["field"],
1287
+ (args) => {
1288
+ const name = String(args.field ?? "");
1289
+ if (!adapter.focus) return errorResult("Host did not provide a focus implementation.");
1290
+ if (!adapter.getFields().find((f) => f.name === name)) {
1291
+ return errorResult(`Unknown field: ${name}`);
1292
+ }
1293
+ adapter.focus(name);
1294
+ return textResult(`Focused ${name}`, { field: name });
1295
+ },
1296
+ true
1297
+ );
1298
+ reg(
1299
+ "form_submit",
1300
+ "Submit the form. Host returns ok + values (or an error).",
1301
+ {},
1302
+ [],
1303
+ async () => {
1304
+ if (!adapter.submit) return errorResult("Host did not provide a submit implementation.");
1305
+ const result = await adapter.submit();
1306
+ if (!result.ok) return errorResult(result.error ?? "Submit failed");
1307
+ return textResult("Submitted", { values: result.values });
1308
+ },
1309
+ true
1310
+ );
1311
+ return {
1312
+ id: `form:${formId}`,
1313
+ title: adapter.title ?? formId,
1314
+ dispose: () => {
1315
+ for (const d of disposers) d();
1316
+ }
1317
+ };
1318
+ }
1319
+
1320
+ // src/bridges/sheets.ts
1321
+ var DEFAULT_AGENT4 = { id: "agent", name: "Agent", color: "#a855f7" };
1322
+ function registerSheetsBridge(server, options) {
1323
+ const { adapter } = options;
1324
+ const agent = { ...DEFAULT_AGENT4, ...options.agent ?? {} };
1325
+ const disposers = [];
1326
+ const target = (sheetId, address) => ({
1327
+ kind: "sheet",
1328
+ screenId: adapter.screenId,
1329
+ elementId: address ? `${sheetId}!${address}` : sheetId,
1330
+ label: address ? `${sheetId}!${address}` : sheetId
1331
+ });
1332
+ const reg = (name, description, properties, required, handler, isMutation, resolveTarget) => {
1333
+ const wrapped = async (args) => {
1334
+ try {
1335
+ return await handler(args);
1336
+ } catch (e) {
1337
+ return errorResult(e instanceof Error ? e.message : String(e));
1338
+ }
1339
+ };
1340
+ const final = isMutation ? wrapToolWithActivity(wrapped, {
1341
+ toolName: name,
1342
+ agent,
1343
+ kind: "sheet",
1344
+ screenId: adapter.screenId,
1345
+ resolveTarget: ({ args, result }) => resolveTarget?.(args, result) ?? target(getSheetId(args))
1346
+ }) : wrapped;
1347
+ disposers.push(
1348
+ server.registerTool(
1349
+ {
1350
+ name,
1351
+ description,
1352
+ inputSchema: { type: "object", properties, required, additionalProperties: false }
1353
+ },
1354
+ final
1355
+ )
1356
+ );
1357
+ };
1358
+ function activeSheetId() {
1359
+ return adapter.getWorkbook().activeSheetId;
1360
+ }
1361
+ function getSheetId(args) {
1362
+ return typeof args.sheet === "string" ? args.sheet : activeSheetId();
1363
+ }
1364
+ function getSheet(workbook, sheetId) {
1365
+ return workbook.sheets.find((s) => s.id === sheetId);
1366
+ }
1367
+ reg(
1368
+ "sheet_describe",
1369
+ "Describe the workbook: every sheet's id, name, dimensions, cell count, active sheet. Call before reading or writing.",
1370
+ {},
1371
+ [],
1372
+ () => {
1373
+ const wb = adapter.getWorkbook();
1374
+ const summary = {
1375
+ activeSheetId: wb.activeSheetId,
1376
+ sheets: wb.sheets.map((s) => ({
1377
+ id: s.id,
1378
+ name: s.name,
1379
+ cellCount: Object.keys(s.cells).length,
1380
+ columnCount: Object.keys(s.columnWidths).length,
1381
+ frozenRows: s.frozenRows,
1382
+ frozenCols: s.frozenCols
1383
+ }))
1384
+ };
1385
+ const text = `Active: ${summary.activeSheetId}
1386
+ ` + summary.sheets.map((s) => `${s.id} "${s.name}" \u2014 ${s.cellCount} cells`).join("\n");
1387
+ return textResult(text, summary);
1388
+ },
1389
+ false
1390
+ );
1391
+ reg(
1392
+ "sheet_get_cell",
1393
+ "Read a single cell's raw + computed value.",
1394
+ {
1395
+ sheet: { type: "string", description: "Sheet id (defaults to active)." },
1396
+ address: { type: "string", description: 'A1-style address, e.g. "B12".' }
1397
+ },
1398
+ ["address"],
1399
+ (args) => {
1400
+ const sheetId = getSheetId(args);
1401
+ const address = String(args.address);
1402
+ const sheet = getSheet(adapter.getWorkbook(), sheetId);
1403
+ if (!sheet) return errorResult(`No sheet ${sheetId}`);
1404
+ const cell = sheet.cells[address];
1405
+ if (!cell) {
1406
+ return textResult(`(empty)`, { sheet: sheetId, address, value: null });
1407
+ }
1408
+ return textResult(`${address} = ${JSON.stringify(cell.computedValue ?? cell.value)}`, { ...cell, sheet: sheetId, address });
1409
+ },
1410
+ false
1411
+ );
1412
+ reg(
1413
+ "sheet_get_range",
1414
+ "Read a rectangular range as a 2D array of values.",
1415
+ {
1416
+ sheet: { type: "string" },
1417
+ start: { type: "string", description: "Top-left A1 address." },
1418
+ end: { type: "string", description: "Bottom-right A1 address." }
1419
+ },
1420
+ ["start", "end"],
1421
+ (args) => {
1422
+ const sheetId = getSheetId(args);
1423
+ const sheet = getSheet(adapter.getWorkbook(), sheetId);
1424
+ if (!sheet) return errorResult(`No sheet ${sheetId}`);
1425
+ const grid = readRange(sheet, String(args.start), String(args.end));
1426
+ return textResult(JSON.stringify(grid), { sheet: sheetId, start: args.start, end: args.end, values: grid });
1427
+ },
1428
+ false
1429
+ );
1430
+ reg(
1431
+ "sheet_set_cell",
1432
+ "Set a single cell's value. To set a formula, pass a string starting with '='.",
1433
+ {
1434
+ sheet: { type: "string" },
1435
+ address: { type: "string" },
1436
+ value: { description: "string | number | boolean | null. Strings starting with '=' are stored as formulas." }
1437
+ },
1438
+ ["address", "value"],
1439
+ (args) => {
1440
+ const sheetId = getSheetId(args);
1441
+ const address = String(args.address);
1442
+ const value = args.value;
1443
+ const wb = adapter.getWorkbook();
1444
+ const sheet = getSheet(wb, sheetId);
1445
+ if (!sheet) return errorResult(`No sheet ${sheetId}`);
1446
+ const next = mergeCells(wb, sheetId, { [address]: cellOf(address, value) });
1447
+ adapter.setWorkbook(next);
1448
+ return textResult(`${sheetId}!${address} \u2190 ${JSON.stringify(value)}`, { sheet: sheetId, address, value });
1449
+ },
1450
+ true,
1451
+ (args) => target(getSheetId(args), String(args.address ?? ""))
1452
+ );
1453
+ reg(
1454
+ "sheet_set_range",
1455
+ 'Set many cells atomically. `cells` is an object map of { "A1": value, "B2": value, ... }.',
1456
+ {
1457
+ sheet: { type: "string" },
1458
+ cells: { type: "object" }
1459
+ },
1460
+ ["cells"],
1461
+ (args) => {
1462
+ const sheetId = getSheetId(args);
1463
+ const wb = adapter.getWorkbook();
1464
+ const sheet = getSheet(wb, sheetId);
1465
+ if (!sheet) return errorResult(`No sheet ${sheetId}`);
1466
+ const cells = args.cells && typeof args.cells === "object" ? args.cells : {};
1467
+ const updates = {};
1468
+ for (const [addr, v] of Object.entries(cells)) updates[addr] = cellOf(addr, v);
1469
+ const next = mergeCells(wb, sheetId, updates);
1470
+ adapter.setWorkbook(next);
1471
+ return textResult(`Set ${Object.keys(cells).length} cells in ${sheetId}`, { sheet: sheetId, count: Object.keys(cells).length });
1472
+ },
1473
+ true
1474
+ );
1475
+ reg(
1476
+ "sheet_add_sheet",
1477
+ "Add a new sheet (tab) to the workbook.",
1478
+ { id: { type: "string" }, name: { type: "string" } },
1479
+ ["id", "name"],
1480
+ (args) => {
1481
+ const wb = adapter.getWorkbook();
1482
+ const id = String(args.id);
1483
+ const name = String(args.name);
1484
+ if (wb.sheets.find((s) => s.id === id)) return errorResult(`Sheet ${id} already exists`);
1485
+ const next = {
1486
+ ...wb,
1487
+ sheets: [
1488
+ ...wb.sheets,
1489
+ {
1490
+ id,
1491
+ name,
1492
+ cells: {},
1493
+ columnWidths: {},
1494
+ mergedRegions: [],
1495
+ columnFilters: {},
1496
+ frozenRows: 0,
1497
+ frozenCols: 0
1498
+ }
1499
+ ]
1500
+ };
1501
+ adapter.setWorkbook(next);
1502
+ return textResult(`Added sheet ${id} ("${name}")`, { id, name });
1503
+ },
1504
+ true,
1505
+ (args) => target(String(args.id ?? ""))
1506
+ );
1507
+ reg(
1508
+ "sheet_set_active",
1509
+ "Switch to a different sheet tab.",
1510
+ { sheet: { type: "string" } },
1511
+ ["sheet"],
1512
+ (args) => {
1513
+ const sheetId = String(args.sheet);
1514
+ const wb = adapter.getWorkbook();
1515
+ if (!getSheet(wb, sheetId)) return errorResult(`No sheet ${sheetId}`);
1516
+ adapter.setWorkbook({ ...wb, activeSheetId: sheetId });
1517
+ return textResult(`Active sheet \u2192 ${sheetId}`, { sheet: sheetId });
1518
+ },
1519
+ true
1520
+ );
1521
+ reg(
1522
+ "sheet_set_active_cell",
1523
+ "Move the active cell selection (host implements DOM focus + scroll).",
1524
+ { sheet: { type: "string" }, address: { type: "string" } },
1525
+ ["address"],
1526
+ (args) => {
1527
+ if (!adapter.setActiveCell) return errorResult("Host did not provide setActiveCell.");
1528
+ const sheetId = getSheetId(args);
1529
+ adapter.setActiveCell(sheetId, String(args.address));
1530
+ return textResult(`Active cell \u2192 ${sheetId}!${args.address}`, { sheet: sheetId, address: args.address });
1531
+ },
1532
+ true,
1533
+ (args) => target(getSheetId(args), String(args.address ?? ""))
1534
+ );
1535
+ return {
1536
+ id: "sheets",
1537
+ title: "Sheets",
1538
+ dispose: () => {
1539
+ for (const d of disposers) d();
1540
+ }
1541
+ };
1542
+ }
1543
+ function cellOf(address, value) {
1544
+ return { address, value };
1545
+ }
1546
+ function mergeCells(wb, sheetId, updates) {
1547
+ return {
1548
+ ...wb,
1549
+ sheets: wb.sheets.map(
1550
+ (s) => s.id !== sheetId ? s : { ...s, cells: { ...s.cells, ...updates } }
1551
+ )
1552
+ };
1553
+ }
1554
+ function parseAddress(addr) {
1555
+ const m = /^([A-Za-z]+)(\d+)$/.exec(addr.trim());
1556
+ if (!m) throw new Error(`Bad address: ${addr}`);
1557
+ const letters = m[1].toUpperCase();
1558
+ let col = 0;
1559
+ for (let i = 0; i < letters.length; i++) {
1560
+ col = col * 26 + (letters.charCodeAt(i) - 64);
1561
+ }
1562
+ return { col: col - 1, row: parseInt(m[2], 10) - 1 };
1563
+ }
1564
+ function colToLetter(col) {
1565
+ let s = "";
1566
+ let n = col + 1;
1567
+ while (n > 0) {
1568
+ const r = (n - 1) % 26;
1569
+ s = String.fromCharCode(65 + r) + s;
1570
+ n = Math.floor((n - 1) / 26);
1571
+ }
1572
+ return s;
1573
+ }
1574
+ function readRange(sheet, startAddr, endAddr) {
1575
+ const start = parseAddress(startAddr);
1576
+ const end = parseAddress(endAddr);
1577
+ const r0 = Math.min(start.row, end.row);
1578
+ const r1 = Math.max(start.row, end.row);
1579
+ const c0 = Math.min(start.col, end.col);
1580
+ const c1 = Math.max(start.col, end.col);
1581
+ const grid = [];
1582
+ for (let r = r0; r <= r1; r++) {
1583
+ const row = [];
1584
+ for (let c = c0; c <= c1; c++) {
1585
+ const addr = `${colToLetter(c)}${r + 1}`;
1586
+ const cell = sheet.cells[addr];
1587
+ row.push(cell?.computedValue ?? cell?.value ?? null);
1588
+ }
1589
+ grid.push(row);
1590
+ }
1591
+ return grid;
1592
+ }
1593
+
1594
+ // src/bridges/code.ts
1595
+ var DEFAULT_AGENT5 = { id: "agent", name: "Agent", color: "#a855f7" };
1596
+ function registerCodeBridge(server, options) {
1597
+ const { adapter } = options;
1598
+ const agent = { ...DEFAULT_AGENT5, ...options.agent ?? {} };
1599
+ const disposers = [];
1600
+ const target = {
1601
+ kind: "code",
1602
+ screenId: adapter.screenId,
1603
+ elementId: adapter.id,
1604
+ label: adapter.title ?? adapter.id
1605
+ };
1606
+ const reg = (name, description, properties, required, handler, isMutation) => {
1607
+ const wrapped = async (args) => {
1608
+ try {
1609
+ return await handler(args);
1610
+ } catch (e) {
1611
+ return errorResult(e instanceof Error ? e.message : String(e));
1612
+ }
1613
+ };
1614
+ const final = isMutation ? wrapToolWithActivity(wrapped, {
1615
+ toolName: name,
1616
+ agent,
1617
+ kind: "code",
1618
+ screenId: adapter.screenId,
1619
+ resolveTarget: () => target
1620
+ }) : wrapped;
1621
+ disposers.push(
1622
+ server.registerTool(
1623
+ {
1624
+ name,
1625
+ description,
1626
+ inputSchema: { type: "object", properties, required, additionalProperties: false }
1627
+ },
1628
+ final
1629
+ )
1630
+ );
1631
+ };
1632
+ reg(
1633
+ "code_describe",
1634
+ `Describe the editor "${adapter.id}" \u2014 language + length + has-selection.`,
1635
+ {},
1636
+ [],
1637
+ () => {
1638
+ const value = adapter.getValue();
1639
+ const language = adapter.getLanguage?.() ?? "unknown";
1640
+ const summary = { id: adapter.id, language, length: value.length, lines: value.split("\n").length };
1641
+ return textResult(JSON.stringify(summary), summary);
1642
+ },
1643
+ false
1644
+ );
1645
+ reg(
1646
+ "code_get_value",
1647
+ "Read the full document text.",
1648
+ {},
1649
+ [],
1650
+ () => {
1651
+ const value = adapter.getValue();
1652
+ return textResult(value, { value });
1653
+ },
1654
+ false
1655
+ );
1656
+ reg(
1657
+ "code_get_selection",
1658
+ "Read the currently-selected text (empty string if no selection).",
1659
+ {},
1660
+ [],
1661
+ () => {
1662
+ if (!adapter.getSelection) return errorResult("Host did not provide getSelection.");
1663
+ const value = adapter.getSelection();
1664
+ return textResult(value, { value });
1665
+ },
1666
+ false
1667
+ );
1668
+ reg(
1669
+ "code_set_value",
1670
+ "Replace the entire document.",
1671
+ { value: { type: "string" } },
1672
+ ["value"],
1673
+ (args) => {
1674
+ const value = String(args.value ?? "");
1675
+ adapter.setValue(value);
1676
+ return textResult(`Replaced document (${value.length} chars)`, { length: value.length });
1677
+ },
1678
+ true
1679
+ );
1680
+ reg(
1681
+ "code_append",
1682
+ "Append text to the end of the document.",
1683
+ { text: { type: "string" } },
1684
+ ["text"],
1685
+ (args) => {
1686
+ const text = String(args.text ?? "");
1687
+ const next = adapter.getValue() + text;
1688
+ adapter.setValue(next);
1689
+ return textResult(`Appended ${text.length} chars`, { length: next.length });
1690
+ },
1691
+ true
1692
+ );
1693
+ reg(
1694
+ "code_stream_append",
1695
+ "Type characters into the document one at a time so the human can read it forming. Returns when streaming finishes.",
1696
+ {
1697
+ text: { type: "string" },
1698
+ cps: { type: "number", description: "Characters per second. Default 25." }
1699
+ },
1700
+ ["text"],
1701
+ async (args) => {
1702
+ const text = String(args.text ?? "");
1703
+ const cps = Math.max(1, Number(args.cps ?? 25));
1704
+ const interval = Math.max(8, Math.round(1e3 / cps));
1705
+ const start = adapter.getValue();
1706
+ for (let i = 1; i <= text.length; i++) {
1707
+ adapter.setValue(start + text.slice(0, i));
1708
+ if (i < text.length) await new Promise((r) => setTimeout(r, interval));
1709
+ }
1710
+ return textResult(`Streamed ${text.length} chars`, { length: text.length });
1711
+ },
1712
+ true
1713
+ );
1714
+ reg(
1715
+ "code_replace_selection",
1716
+ "Replace the currently-selected text with the supplied text.",
1717
+ { text: { type: "string" } },
1718
+ ["text"],
1719
+ (args) => {
1720
+ if (!adapter.replaceSelection) return errorResult("Host did not provide replaceSelection.");
1721
+ adapter.replaceSelection(String(args.text ?? ""));
1722
+ return textResult("Selection replaced", {});
1723
+ },
1724
+ true
1725
+ );
1726
+ reg(
1727
+ "code_set_language",
1728
+ "Switch the active syntax highlighting / formatter.",
1729
+ { language: { type: "string", description: "e.g. 'javascript', 'php', 'sql'." } },
1730
+ ["language"],
1731
+ (args) => {
1732
+ if (!adapter.setLanguage) return errorResult("Host did not provide setLanguage.");
1733
+ const lang = String(args.language ?? "");
1734
+ adapter.setLanguage(lang);
1735
+ return textResult(`Language \u2192 ${lang}`, { language: lang });
1736
+ },
1737
+ true
1738
+ );
1739
+ reg(
1740
+ "code_focus",
1741
+ "Move browser focus to the editor.",
1742
+ {},
1743
+ [],
1744
+ () => {
1745
+ if (!adapter.focus) return errorResult("Host did not provide focus.");
1746
+ adapter.focus();
1747
+ return textResult("Focused", {});
1748
+ },
1749
+ true
1750
+ );
1751
+ return {
1752
+ id: `code:${adapter.id}`,
1753
+ title: adapter.title ?? adapter.id,
1754
+ dispose: () => {
1755
+ for (const d of disposers) d();
1756
+ }
1757
+ };
1758
+ }
1759
+
1760
+ // src/bridges/charts.ts
1761
+ var DEFAULT_AGENT6 = { id: "agent", name: "Agent", color: "#a855f7" };
1762
+ function registerChartsBridge(server, options) {
1763
+ const { adapter } = options;
1764
+ const agent = { ...DEFAULT_AGENT6, ...options.agent ?? {} };
1765
+ const disposers = [];
1766
+ const target = {
1767
+ kind: "chart",
1768
+ screenId: adapter.screenId,
1769
+ elementId: adapter.id,
1770
+ label: adapter.title ?? adapter.id
1771
+ };
1772
+ const reg = (name, description, properties, required, handler, isMutation) => {
1773
+ const wrapped = async (args) => {
1774
+ try {
1775
+ return await handler(args);
1776
+ } catch (e) {
1777
+ return errorResult(e instanceof Error ? e.message : String(e));
1778
+ }
1779
+ };
1780
+ const final = isMutation ? wrapToolWithActivity(wrapped, {
1781
+ toolName: name,
1782
+ agent,
1783
+ kind: "chart",
1784
+ screenId: adapter.screenId,
1785
+ resolveTarget: () => target
1786
+ }) : wrapped;
1787
+ disposers.push(
1788
+ server.registerTool(
1789
+ { name, description, inputSchema: { type: "object", properties, required, additionalProperties: false } },
1790
+ final
1791
+ )
1792
+ );
1793
+ };
1794
+ reg(
1795
+ "chart_describe",
1796
+ `Describe the chart "${adapter.id}" \u2014 series count, type guesses, axis info.`,
1797
+ {},
1798
+ [],
1799
+ () => {
1800
+ const opt = adapter.getOption();
1801
+ const series = Array.isArray(opt.series) ? opt.series : [];
1802
+ const summary = {
1803
+ id: adapter.id,
1804
+ title: adapter.title,
1805
+ seriesCount: series.length,
1806
+ seriesTypes: series.map((s) => s?.type ?? "unknown"),
1807
+ hasXAxis: !!opt.xAxis,
1808
+ hasYAxis: !!opt.yAxis
1809
+ };
1810
+ return textResult(JSON.stringify(summary), summary);
1811
+ },
1812
+ false
1813
+ );
1814
+ reg(
1815
+ "chart_get_option",
1816
+ "Read the full ECharts option object the chart is rendering.",
1817
+ {},
1818
+ [],
1819
+ () => {
1820
+ const opt = adapter.getOption();
1821
+ return textResult(JSON.stringify(opt, null, 2), opt);
1822
+ },
1823
+ false
1824
+ );
1825
+ reg(
1826
+ "chart_set_option",
1827
+ "Replace the entire ECharts option. Use chart_update_option for partial updates.",
1828
+ { option: { type: "object" } },
1829
+ ["option"],
1830
+ (args) => {
1831
+ const opt = args.option && typeof args.option === "object" ? args.option : {};
1832
+ adapter.setOption(opt);
1833
+ return textResult("Replaced chart option", {});
1834
+ },
1835
+ true
1836
+ );
1837
+ reg(
1838
+ "chart_update_option",
1839
+ "Shallow-merge a partial option update \u2014 only the keys you provide change.",
1840
+ { partial: { type: "object" } },
1841
+ ["partial"],
1842
+ (args) => {
1843
+ const partial = args.partial && typeof args.partial === "object" ? args.partial : {};
1844
+ if (adapter.updateOption) {
1845
+ adapter.updateOption(partial);
1846
+ } else {
1847
+ adapter.setOption({ ...adapter.getOption(), ...partial });
1848
+ }
1849
+ return textResult("Merged chart option", { keys: Object.keys(partial) });
1850
+ },
1851
+ true
1852
+ );
1853
+ reg(
1854
+ "chart_update_data",
1855
+ "Update only the data (typically the `series` field). Leaves layout / axes / colors alone.",
1856
+ { data: { description: "New series array (or whatever shape the host's adapter expects)." } },
1857
+ ["data"],
1858
+ (args) => {
1859
+ if (!adapter.updateData) return errorResult("Host did not provide updateData.");
1860
+ adapter.updateData(args.data);
1861
+ return textResult("Updated chart data", {});
1862
+ },
1863
+ true
1864
+ );
1865
+ return {
1866
+ id: `chart:${adapter.id}`,
1867
+ title: adapter.title ?? adapter.id,
1868
+ dispose: () => {
1869
+ for (const d of disposers) d();
1870
+ }
1871
+ };
1872
+ }
1873
+
1874
+ // src/bridges/scene.ts
1875
+ var DEFAULT_AGENT7 = { id: "agent", name: "Agent", color: "#a855f7" };
1876
+ function registerSceneBridge(server, options) {
1877
+ const { adapter } = options;
1878
+ const agent = { ...DEFAULT_AGENT7, ...options.agent ?? {} };
1879
+ const disposers = [];
1880
+ const target = (objectId) => ({
1881
+ kind: "scene",
1882
+ screenId: adapter.screenId,
1883
+ elementId: objectId ? `${adapter.id}:${objectId}` : adapter.id,
1884
+ label: objectId ? `${adapter.title ?? adapter.id} \u2192 ${objectId}` : adapter.title ?? adapter.id
1885
+ });
1886
+ const reg = (name, description, properties, required, handler, isMutation, objectIdFromArgs) => {
1887
+ const wrapped = async (args) => {
1888
+ try {
1889
+ return await handler(args);
1890
+ } catch (e) {
1891
+ return errorResult(e instanceof Error ? e.message : String(e));
1892
+ }
1893
+ };
1894
+ const final = isMutation ? wrapToolWithActivity(wrapped, {
1895
+ toolName: name,
1896
+ agent,
1897
+ kind: "scene",
1898
+ screenId: adapter.screenId,
1899
+ resolveTarget: ({ args }) => target(objectIdFromArgs?.(args))
1900
+ }) : wrapped;
1901
+ disposers.push(
1902
+ server.registerTool(
1903
+ { name, description, inputSchema: { type: "object", properties, required, additionalProperties: false } },
1904
+ final
1905
+ )
1906
+ );
1907
+ };
1908
+ const newId3 = (kind) => `${kind}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
1909
+ reg(
1910
+ "scene_describe",
1911
+ "Describe the scene \u2014 object count, kinds, camera position.",
1912
+ {},
1913
+ [],
1914
+ () => {
1915
+ const scene = adapter.getScene();
1916
+ const summary = {
1917
+ id: adapter.id,
1918
+ objectCount: scene.objects.length,
1919
+ kinds: scene.objects.map((o) => o.kind),
1920
+ camera: scene.camera,
1921
+ background: scene.background
1922
+ };
1923
+ return textResult(JSON.stringify(summary, null, 2), summary);
1924
+ },
1925
+ false
1926
+ );
1927
+ reg(
1928
+ "scene_get_state",
1929
+ "Read the full SceneState (objects + camera + background).",
1930
+ {},
1931
+ [],
1932
+ () => {
1933
+ const scene = adapter.getScene();
1934
+ return textResult(JSON.stringify(scene, null, 2), scene);
1935
+ },
1936
+ false
1937
+ );
1938
+ reg(
1939
+ "scene_add_object",
1940
+ "Add an object to the scene root. Returns the new object's id.",
1941
+ {
1942
+ kind: { type: "string", description: "box | sphere | cylinder | plane | screen | group | custom kind" },
1943
+ position: { type: "array", description: "[x, y, z]" },
1944
+ rotation: { type: "array", description: "[x, y, z] euler" },
1945
+ scale: { type: "array", description: "[x, y, z]" },
1946
+ color: { type: "string" },
1947
+ props: { type: "object", description: "Per-kind config." }
1948
+ },
1949
+ ["kind"],
1950
+ (args) => {
1951
+ const obj = {
1952
+ id: newId3(String(args.kind)),
1953
+ kind: String(args.kind),
1954
+ position: parseTriple(args.position),
1955
+ rotation: parseTriple(args.rotation),
1956
+ scale: parseTriple(args.scale),
1957
+ color: typeof args.color === "string" ? args.color : void 0,
1958
+ props: args.props && typeof args.props === "object" ? args.props : void 0
1959
+ };
1960
+ const scene = adapter.getScene();
1961
+ adapter.setScene({ ...scene, objects: [...scene.objects, obj] });
1962
+ return textResult(`Added ${obj.kind} ${obj.id}`, obj);
1963
+ },
1964
+ true,
1965
+ (args) => void 0
1966
+ // id resolved from result.structuredContent.id
1967
+ );
1968
+ reg(
1969
+ "scene_update_object",
1970
+ "Update fields on an object. Only provided fields change.",
1971
+ {
1972
+ id: { type: "string" },
1973
+ position: { type: "array" },
1974
+ rotation: { type: "array" },
1975
+ scale: { type: "array" },
1976
+ color: { type: "string" },
1977
+ props: { type: "object" }
1978
+ },
1979
+ ["id"],
1980
+ (args) => {
1981
+ const id = String(args.id);
1982
+ const scene = adapter.getScene();
1983
+ const idx = scene.objects.findIndex((o) => o.id === id);
1984
+ if (idx === -1) return errorResult(`No object ${id}`);
1985
+ const orig = scene.objects[idx];
1986
+ const next = {
1987
+ ...orig,
1988
+ ...args.position !== void 0 ? { position: parseTriple(args.position) } : {},
1989
+ ...args.rotation !== void 0 ? { rotation: parseTriple(args.rotation) } : {},
1990
+ ...args.scale !== void 0 ? { scale: parseTriple(args.scale) } : {},
1991
+ ...args.color !== void 0 ? { color: String(args.color) } : {},
1992
+ ...args.props && typeof args.props === "object" ? { props: { ...orig.props ?? {}, ...args.props } } : {}
1993
+ };
1994
+ const objects = [...scene.objects];
1995
+ objects[idx] = next;
1996
+ adapter.setScene({ ...scene, objects });
1997
+ return textResult(`Updated ${id}`, next);
1998
+ },
1999
+ true,
2000
+ (args) => String(args.id ?? "")
2001
+ );
2002
+ reg(
2003
+ "scene_delete_object",
2004
+ "Remove an object from the scene root.",
2005
+ { id: { type: "string" } },
2006
+ ["id"],
2007
+ (args) => {
2008
+ const id = String(args.id);
2009
+ const scene = adapter.getScene();
2010
+ const next = scene.objects.filter((o) => o.id !== id);
2011
+ if (next.length === scene.objects.length) return errorResult(`No object ${id}`);
2012
+ adapter.setScene({ ...scene, objects: next });
2013
+ return textResult(`Deleted ${id}`);
2014
+ },
2015
+ true,
2016
+ (args) => String(args.id ?? "")
2017
+ );
2018
+ reg(
2019
+ "scene_set_camera",
2020
+ "Move the camera. Pass any subset of position/target/fov.",
2021
+ {
2022
+ position: { type: "array", description: "[x, y, z]" },
2023
+ target: { type: "array", description: "[x, y, z] look-at point" },
2024
+ fov: { type: "number" }
2025
+ },
2026
+ [],
2027
+ (args) => {
2028
+ const scene = adapter.getScene();
2029
+ const next = {
2030
+ ...scene.camera ?? {},
2031
+ ...args.position !== void 0 ? { position: parseTriple(args.position) } : {},
2032
+ ...args.target !== void 0 ? { target: parseTriple(args.target) } : {},
2033
+ ...args.fov !== void 0 ? { fov: Number(args.fov) } : {}
2034
+ };
2035
+ if (adapter.setCamera) {
2036
+ adapter.setCamera(next);
2037
+ } else {
2038
+ adapter.setScene({ ...scene, camera: next });
2039
+ }
2040
+ return textResult(`Camera updated`, next);
2041
+ },
2042
+ true
2043
+ );
2044
+ reg(
2045
+ "scene_set_background",
2046
+ "Change the scene background color (CSS color).",
2047
+ { color: { type: "string" } },
2048
+ ["color"],
2049
+ (args) => {
2050
+ const scene = adapter.getScene();
2051
+ adapter.setScene({ ...scene, background: String(args.color) });
2052
+ return textResult(`Background \u2192 ${args.color}`, { background: args.color });
2053
+ },
2054
+ true
2055
+ );
2056
+ return {
2057
+ id: `scene:${adapter.id}`,
2058
+ title: adapter.title ?? adapter.id,
2059
+ dispose: () => {
2060
+ for (const d of disposers) d();
2061
+ }
2062
+ };
2063
+ }
2064
+ function parseTriple(v) {
2065
+ if (!Array.isArray(v) || v.length !== 3) return void 0;
2066
+ const out = v.map((x) => Number(x));
2067
+ if (out.some((x) => !Number.isFinite(x))) return void 0;
2068
+ return out;
2069
+ }
903
2070
  function AgentPanel({ agent, activity, onSubmit, busy, actions, className, style }) {
904
2071
  const scrollRef = react.useRef(null);
905
2072
  const inputRef = react.useRef(null);
@@ -1063,6 +2230,101 @@ function AgentActivityHighlight({
1063
2230
  }
1064
2231
  );
1065
2232
  }
2233
+ function BridgedForm({
2234
+ id,
2235
+ title,
2236
+ screenId,
2237
+ fields,
2238
+ values,
2239
+ onChange,
2240
+ onSubmit,
2241
+ server,
2242
+ agent,
2243
+ children
2244
+ }) {
2245
+ const valuesRef = react.useRef(values);
2246
+ const onChangeRef = react.useRef(onChange);
2247
+ const fieldsRef = react.useRef(fields);
2248
+ const submitRef = react.useRef(onSubmit);
2249
+ react.useEffect(() => {
2250
+ valuesRef.current = values;
2251
+ }, [values]);
2252
+ react.useEffect(() => {
2253
+ onChangeRef.current = onChange;
2254
+ }, [onChange]);
2255
+ react.useEffect(() => {
2256
+ fieldsRef.current = fields;
2257
+ }, [fields]);
2258
+ react.useEffect(() => {
2259
+ submitRef.current = onSubmit;
2260
+ }, [onSubmit]);
2261
+ const focusElement = (name) => {
2262
+ if (typeof document === "undefined") return;
2263
+ const el = document.querySelector(`[data-form-id="${id}"] [name="${name}"]`);
2264
+ el?.focus();
2265
+ };
2266
+ const adapter = react.useMemo(() => ({
2267
+ id,
2268
+ title,
2269
+ screenId,
2270
+ getFields: () => fieldsRef.current,
2271
+ getValue: (name) => valuesRef.current[name],
2272
+ getValues: () => ({ ...valuesRef.current }),
2273
+ setValue: (name, v) => onChangeRef.current({ ...valuesRef.current, [name]: v }),
2274
+ setValues: (next) => onChangeRef.current({ ...valuesRef.current, ...next }),
2275
+ focus: focusElement,
2276
+ submit: async () => {
2277
+ if (!submitRef.current) {
2278
+ return { ok: true, values: { ...valuesRef.current } };
2279
+ }
2280
+ return submitRef.current();
2281
+ }
2282
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2283
+ }), [id, title, screenId]);
2284
+ react.useEffect(() => {
2285
+ if (!server) return;
2286
+ const bridge = registerFormBridge(server, { adapter, agent });
2287
+ return () => bridge.dispose();
2288
+ }, [server, adapter, agent]);
2289
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-form-id": id, children });
2290
+ }
2291
+
2292
+ // src/components/ScreensActivityBridge/ScreensActivityBridge.tsx
2293
+ init_registry();
2294
+ function ScreensActivityBridge({ system, fadeMs = 1500 }) {
2295
+ react.useEffect(() => {
2296
+ const fadeTimers = /* @__PURE__ */ new Map();
2297
+ const off = onActivity((event) => {
2298
+ const screenId = event.target.screenId;
2299
+ if (!screenId) return;
2300
+ if (!system.registry.has(screenId)) return;
2301
+ const activity = {
2302
+ agentId: event.agentId,
2303
+ agentName: event.agentName,
2304
+ agentColor: event.agentColor,
2305
+ action: event.action,
2306
+ timestamp: event.timestamp,
2307
+ elementId: event.target.elementId,
2308
+ label: event.target.label
2309
+ };
2310
+ system.updateScreen(screenId, { agentActivity: activity });
2311
+ const prev = fadeTimers.get(screenId);
2312
+ if (prev) clearTimeout(prev);
2313
+ fadeTimers.set(
2314
+ screenId,
2315
+ setTimeout(() => {
2316
+ system.updateScreen(screenId, { agentActivity: null });
2317
+ fadeTimers.delete(screenId);
2318
+ }, event.ttlMs ?? fadeMs)
2319
+ );
2320
+ });
2321
+ return () => {
2322
+ off();
2323
+ for (const t of fadeTimers.values()) clearTimeout(t);
2324
+ };
2325
+ }, [system, fadeMs]);
2326
+ return null;
2327
+ }
1066
2328
 
1067
2329
  // src/sharing/token.ts
1068
2330
  var TOKEN_BYTES = 24;
@@ -1333,16 +2595,31 @@ function attachSseRelay(server, options) {
1333
2595
  transport.bindServer(server);
1334
2596
  server.attach(transport);
1335
2597
  transport.start();
2598
+ Promise.resolve().then(() => (init_registry(), registry_exports)).then(({ onActivity: onActivity2 }) => {
2599
+ const off = onActivity2((event) => {
2600
+ transport.send({
2601
+ jsonrpc: "2.0",
2602
+ method: "notifications/agent_activity",
2603
+ params: event
2604
+ });
2605
+ });
2606
+ const origClose = transport.close.bind(transport);
2607
+ transport.close = () => {
2608
+ off();
2609
+ origClose();
2610
+ };
2611
+ }).catch(() => {
2612
+ });
1336
2613
  return transport;
1337
2614
  }
1338
- var DEFAULT_AGENT3 = { id: "agent", name: "Agent", color: "#a855f7" };
2615
+ var DEFAULT_AGENT8 = { id: "agent", name: "Agent", color: "#a855f7" };
1339
2616
  function SharedWhiteboard({
1340
2617
  initialNotes = [],
1341
2618
  initialShapes = [],
1342
2619
  initialConnectors = [],
1343
2620
  initialStrokes = [],
1344
2621
  initialViewport = { x: 0, y: 0, zoom: 1 },
1345
- agent = DEFAULT_AGENT3,
2622
+ agent = DEFAULT_AGENT8,
1346
2623
  shareBaseUrl = "/whiteboard-share",
1347
2624
  onRegisterSession,
1348
2625
  showAgentPanel = true,
@@ -1605,13 +2882,69 @@ function resolveCenter(ref, notes, shapes) {
1605
2882
  return ref;
1606
2883
  }
1607
2884
 
2885
+ // src/presence/index.ts
2886
+ init_registry();
2887
+
2888
+ // src/presence/use-agent-activity.ts
2889
+ init_registry();
2890
+ function useAgentActivity(filter, options = {}) {
2891
+ const cap = options.capacity ?? 50;
2892
+ const [events, setEvents] = react.useState(() => readActivityHistory(filter).slice(-cap));
2893
+ react.useEffect(() => {
2894
+ setEvents(readActivityHistory(filter).slice(-cap));
2895
+ return onActivity((event) => {
2896
+ setEvents((prev) => {
2897
+ const next = prev.length >= cap ? prev.slice(prev.length - cap + 1) : prev.slice();
2898
+ next.push(event);
2899
+ return next;
2900
+ });
2901
+ }, filter);
2902
+ }, [filter?.agentId, filter?.screenId, filter?.kind, cap]);
2903
+ return { events, latest: events.length > 0 ? events[events.length - 1] : null };
2904
+ }
2905
+ function useAgentActivityForScreen(screenId, options = {}) {
2906
+ const { events, latest } = useAgentActivity({ screenId }, options);
2907
+ const fadeAfter = latest?.ttlMs ?? 1500;
2908
+ const [isAgentActive, setActive] = react.useState(false);
2909
+ react.useEffect(() => {
2910
+ if (!latest) {
2911
+ setActive(false);
2912
+ return;
2913
+ }
2914
+ setActive(true);
2915
+ const timer = setTimeout(() => setActive(false), fadeAfter);
2916
+ return () => clearTimeout(timer);
2917
+ }, [latest, fadeAfter]);
2918
+ return { events, latest, isAgentActive };
2919
+ }
2920
+ function useUndoStack(agentId, intervalMs = 500) {
2921
+ const [history2, setHistory] = react.useState(() => readHistory(agentId));
2922
+ react.useEffect(() => {
2923
+ let cancelled = false;
2924
+ const tick = () => {
2925
+ if (cancelled) return;
2926
+ setHistory(readHistory(agentId));
2927
+ };
2928
+ const id = setInterval(tick, intervalMs);
2929
+ tick();
2930
+ return () => {
2931
+ cancelled = true;
2932
+ clearInterval(id);
2933
+ };
2934
+ }, [agentId, intervalMs]);
2935
+ const refresh = react.useCallback(() => setHistory(readHistory(agentId)), [agentId]);
2936
+ return { history: history2, refresh };
2937
+ }
2938
+
1608
2939
  exports.AgentActivityHighlight = AgentActivityHighlight;
1609
2940
  exports.AgentCursor = AgentCursor;
1610
2941
  exports.AgentPanel = AgentPanel;
2942
+ exports.BridgedForm = BridgedForm;
1611
2943
  exports.InProcessTransport = InProcessTransport;
1612
2944
  exports.MCP_PROTOCOL_VERSION = MCP_PROTOCOL_VERSION;
1613
2945
  exports.MicroMcpServer = MicroMcpServer;
1614
2946
  exports.RelayTransport = RelayTransport;
2947
+ exports.ScreensActivityBridge = ScreensActivityBridge;
1615
2948
  exports.ShareControls = ShareControls;
1616
2949
  exports.SharedWhiteboard = SharedWhiteboard;
1617
2950
  exports.SseRelayTransport = SseRelayTransport;
@@ -1620,13 +2953,34 @@ exports.attachRelay = attachRelay;
1620
2953
  exports.attachSseRelay = attachSseRelay;
1621
2954
  exports.buildShareConfig = buildShareConfig;
1622
2955
  exports.buildShareUrl = buildShareUrl;
2956
+ exports.clearUndoStack = clearStack;
1623
2957
  exports.createSessionDescriptor = createSessionDescriptor;
1624
2958
  exports.describeSession = describeSession;
2959
+ exports.emitActivity = emitActivity;
2960
+ exports.ensureUndoToolsRegistered = ensureUndoToolsRegistered;
1625
2961
  exports.errorResult = errorResult;
2962
+ exports.onActivity = onActivity;
2963
+ exports.pushUndoEntry = pushUndoEntry;
2964
+ exports.readActivityHistory = readActivityHistory;
1626
2965
  exports.readSessionFromUrl = readSessionFromUrl;
2966
+ exports.readUndoHistory = readHistory;
2967
+ exports.redoOne = redoOne;
2968
+ exports.registerChartsBridge = registerChartsBridge;
2969
+ exports.registerCodeBridge = registerCodeBridge;
1627
2970
  exports.registerFlowBridge = registerFlowBridge;
2971
+ exports.registerFormBridge = registerFormBridge;
2972
+ exports.registerSceneBridge = registerSceneBridge;
2973
+ exports.registerSheetsBridge = registerSheetsBridge;
2974
+ exports.registerUndoTools = registerUndoTools;
1628
2975
  exports.registerWhiteboardBridge = registerWhiteboardBridge;
2976
+ exports.resetActivityRegistry = resetActivityRegistry;
2977
+ exports.resetAllUndoStacks = resetAllUndoStacks;
1629
2978
  exports.rpcError = rpcError;
1630
2979
  exports.textResult = textResult;
2980
+ exports.undoOne = undoOne;
2981
+ exports.useAgentActivity = useAgentActivity;
2982
+ exports.useAgentActivityForScreen = useAgentActivityForScreen;
2983
+ exports.useUndoStack = useUndoStack;
2984
+ exports.wrapToolWithActivity = wrapToolWithActivity;
1631
2985
  //# sourceMappingURL=index.cjs.map
1632
2986
  //# sourceMappingURL=index.cjs.map