@particle-academy/agent-integrations 0.25.0 → 0.27.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 (141) hide show
  1. package/dist/bridges/artboard.d.cts +3 -3
  2. package/dist/bridges/artboard.d.ts +3 -3
  3. package/dist/bridges/catalog.d.cts +3 -3
  4. package/dist/bridges/catalog.d.ts +3 -3
  5. package/dist/bridges/charts.d.cts +3 -3
  6. package/dist/bridges/charts.d.ts +3 -3
  7. package/dist/bridges/cms.d.cts +50 -0
  8. package/dist/bridges/cms.d.ts +50 -0
  9. package/dist/bridges/code.d.cts +3 -3
  10. package/dist/bridges/code.d.ts +3 -3
  11. package/dist/bridges/doc.d.cts +68 -0
  12. package/dist/bridges/doc.d.ts +68 -0
  13. package/dist/bridges/features.d.cts +3 -3
  14. package/dist/bridges/features.d.ts +3 -3
  15. package/dist/bridges/files.d.cts +3 -3
  16. package/dist/bridges/files.d.ts +3 -3
  17. package/dist/bridges/flow.d.cts +3 -3
  18. package/dist/bridges/flow.d.ts +3 -3
  19. package/dist/bridges/forms.d.cts +3 -3
  20. package/dist/bridges/forms.d.ts +3 -3
  21. package/dist/bridges/map.d.cts +3 -3
  22. package/dist/bridges/map.d.ts +3 -3
  23. package/dist/bridges/scene.d.cts +3 -3
  24. package/dist/bridges/scene.d.ts +3 -3
  25. package/dist/bridges/screens.d.cts +3 -3
  26. package/dist/bridges/screens.d.ts +3 -3
  27. package/dist/bridges/sheets.d.cts +3 -3
  28. package/dist/bridges/sheets.d.ts +3 -3
  29. package/dist/bridges/slides.d.cts +3 -3
  30. package/dist/bridges/slides.d.ts +3 -3
  31. package/dist/bridges/terminal.d.cts +3 -3
  32. package/dist/bridges/terminal.d.ts +3 -3
  33. package/dist/bridges/whiteboard.d.cts +3 -3
  34. package/dist/bridges/whiteboard.d.ts +3 -3
  35. package/dist/bridges-artboard.js +1 -1
  36. package/dist/bridges-catalog.js +2 -2
  37. package/dist/bridges-charts.cjs +77 -0
  38. package/dist/bridges-charts.cjs.map +1 -1
  39. package/dist/bridges-charts.js +2 -1
  40. package/dist/bridges-cms.cjs +437 -0
  41. package/dist/bridges-cms.cjs.map +1 -0
  42. package/dist/bridges-cms.js +8 -0
  43. package/dist/bridges-cms.js.map +1 -0
  44. package/dist/bridges-code.cjs +77 -0
  45. package/dist/bridges-code.cjs.map +1 -1
  46. package/dist/bridges-code.js +2 -1
  47. package/dist/bridges-doc.cjs +364 -0
  48. package/dist/bridges-doc.cjs.map +1 -0
  49. package/dist/bridges-doc.js +7 -0
  50. package/dist/bridges-doc.js.map +1 -0
  51. package/dist/bridges-features.js +2 -2
  52. package/dist/bridges-files.cjs +1 -1
  53. package/dist/bridges-files.cjs.map +1 -1
  54. package/dist/bridges-files.js +2 -2
  55. package/dist/bridges-flow.cjs +77 -0
  56. package/dist/bridges-flow.cjs.map +1 -1
  57. package/dist/bridges-flow.js +2 -0
  58. package/dist/bridges-flow.js.map +1 -1
  59. package/dist/bridges-forms.cjs +77 -0
  60. package/dist/bridges-forms.cjs.map +1 -1
  61. package/dist/bridges-forms.js +2 -1
  62. package/dist/bridges-map.cjs +1 -1
  63. package/dist/bridges-map.cjs.map +1 -1
  64. package/dist/bridges-map.js +2 -2
  65. package/dist/bridges-scene.cjs +77 -0
  66. package/dist/bridges-scene.cjs.map +1 -1
  67. package/dist/bridges-scene.js +2 -1
  68. package/dist/bridges-screens.cjs +77 -0
  69. package/dist/bridges-screens.cjs.map +1 -1
  70. package/dist/bridges-screens.js +2 -1
  71. package/dist/bridges-sheets.cjs +77 -0
  72. package/dist/bridges-sheets.cjs.map +1 -1
  73. package/dist/bridges-sheets.js +2 -1
  74. package/dist/bridges-slides.cjs +77 -0
  75. package/dist/bridges-slides.cjs.map +1 -1
  76. package/dist/bridges-slides.js +2 -1
  77. package/dist/bridges-terminal.js +2 -2
  78. package/dist/bridges-whiteboard.js +2 -2
  79. package/dist/{chunk-CKK4QKD2.js → chunk-66WOHZZJ.js} +4 -2
  80. package/dist/chunk-66WOHZZJ.js.map +1 -0
  81. package/dist/chunk-A57CRGEK.js +79 -0
  82. package/dist/chunk-A57CRGEK.js.map +1 -0
  83. package/dist/{chunk-XQZGB4FP.js → chunk-AAD3Z5E7.js} +3 -3
  84. package/dist/{chunk-XQZGB4FP.js.map → chunk-AAD3Z5E7.js.map} +1 -1
  85. package/dist/{chunk-3QJSOS7G.js → chunk-AAMQOXZC.js} +3 -3
  86. package/dist/{chunk-3QJSOS7G.js.map → chunk-AAMQOXZC.js.map} +1 -1
  87. package/dist/{chunk-SJ7H242B.js → chunk-AROVENCE.js} +4 -2
  88. package/dist/chunk-AROVENCE.js.map +1 -0
  89. package/dist/chunk-FF5F526J.js +245 -0
  90. package/dist/chunk-FF5F526J.js.map +1 -0
  91. package/dist/{chunk-57KAMBAR.js → chunk-HWVVS6HE.js} +3 -3
  92. package/dist/{chunk-57KAMBAR.js.map → chunk-HWVVS6HE.js.map} +1 -1
  93. package/dist/{chunk-FYGMFIY5.js → chunk-NN3ELTVO.js} +4 -2
  94. package/dist/chunk-NN3ELTVO.js.map +1 -0
  95. package/dist/{chunk-5AD35HS5.js → chunk-PCW2EK5G.js} +4 -2
  96. package/dist/chunk-PCW2EK5G.js.map +1 -0
  97. package/dist/{chunk-DR7X4TWE.js → chunk-QDD4WHIV.js} +4 -2
  98. package/dist/chunk-QDD4WHIV.js.map +1 -0
  99. package/dist/{chunk-HIMTURWL.js → chunk-QRDVJW6Q.js} +4 -2
  100. package/dist/chunk-QRDVJW6Q.js.map +1 -0
  101. package/dist/{chunk-267JS64O.js → chunk-VFKO2VUR.js} +3 -3
  102. package/dist/{chunk-267JS64O.js.map → chunk-VFKO2VUR.js.map} +1 -1
  103. package/dist/{chunk-UOMSY7MZ.js → chunk-XMMCSQ4I.js} +4 -4
  104. package/dist/{chunk-UOMSY7MZ.js.map → chunk-XMMCSQ4I.js.map} +1 -1
  105. package/dist/{chunk-VUMFO2UW.js → chunk-YGD2VTUM.js} +4 -2
  106. package/dist/chunk-YGD2VTUM.js.map +1 -0
  107. package/dist/{chunk-3VRQGDKV.js → chunk-ZX6UQURN.js} +4 -4
  108. package/dist/{chunk-3VRQGDKV.js.map → chunk-ZX6UQURN.js.map} +1 -1
  109. package/dist/components-shared-whiteboard.js +2 -2
  110. package/dist/index.cjs +399 -80
  111. package/dist/index.cjs.map +1 -1
  112. package/dist/index.d.cts +10 -7
  113. package/dist/index.d.ts +10 -7
  114. package/dist/index.js +20 -18
  115. package/dist/index.js.map +1 -1
  116. package/dist/mcp/index.d.cts +5 -5
  117. package/dist/mcp/index.d.ts +5 -5
  118. package/dist/presence/index.d.cts +1 -1
  119. package/dist/presence/index.d.ts +1 -1
  120. package/dist/{server-BsSwfemr.d.cts → server-Dr3j48CU.d.cts} +2 -2
  121. package/dist/{server-Du3-IGqM.d.ts → server-FFZpYPyM.d.ts} +2 -2
  122. package/dist/sharing/index.d.cts +3 -3
  123. package/dist/sharing/index.d.ts +3 -3
  124. package/dist/sheets-adapter.d.cts +3 -3
  125. package/dist/sheets-adapter.d.ts +3 -3
  126. package/dist/{tool-host-C8JMMGYq.d.ts → tool-host-C_Vh17J_.d.ts} +1 -1
  127. package/dist/{tool-host-BQuUygLF.d.cts → tool-host-IDecPrF1.d.cts} +1 -1
  128. package/dist/{types-CCSBGW9T.d.cts → types-B0rmWyoR.d.cts} +1 -1
  129. package/dist/{types-aOQLTW0E.d.cts → types-BDI_g5UG.d.cts} +1 -1
  130. package/dist/{types-aOQLTW0E.d.ts → types-BDI_g5UG.d.ts} +1 -1
  131. package/dist/{types-DIVNcIQO.d.ts → types-CBoQhR8L.d.ts} +1 -1
  132. package/dist/undo/index.d.cts +2 -2
  133. package/dist/undo/index.d.ts +2 -2
  134. package/package.json +23 -2
  135. package/dist/chunk-5AD35HS5.js.map +0 -1
  136. package/dist/chunk-CKK4QKD2.js.map +0 -1
  137. package/dist/chunk-DR7X4TWE.js.map +0 -1
  138. package/dist/chunk-FYGMFIY5.js.map +0 -1
  139. package/dist/chunk-HIMTURWL.js.map +0 -1
  140. package/dist/chunk-SJ7H242B.js.map +0 -1
  141. package/dist/chunk-VUMFO2UW.js.map +0 -1
@@ -46,12 +46,89 @@ function extractMeta(result) {
46
46
  return void 0;
47
47
  }
48
48
 
49
+ // src/undo/undo-tools.ts
50
+ var installedHosts = /* @__PURE__ */ new WeakSet();
51
+ function ensureUndoToolsRegistered(host, options = {}) {
52
+ if (installedHosts.has(host)) return;
53
+ installedHosts.add(host);
54
+ registerUndoTools(host, options);
55
+ }
56
+ function registerUndoTools(host, options = {}) {
57
+ const defaultAgent = options.defaultAgentId ?? "agent";
58
+ const disposers = [];
59
+ const agentOf = (args) => typeof args?.agentId === "string" ? args.agentId : defaultAgent;
60
+ disposers.push(
61
+ host.registerTool(
62
+ {
63
+ name: "agent_undo",
64
+ description: "Undo the most recent action on the agent's stack. Optional agentId targets a specific agent.",
65
+ inputSchema: {
66
+ type: "object",
67
+ properties: { agentId: { type: "string" } },
68
+ additionalProperties: false
69
+ }
70
+ },
71
+ async (args) => {
72
+ const entry = await fancyAutoCommon.undoOne(agentOf(args));
73
+ if (!entry) return errorResult("Nothing to undo.");
74
+ return textResult(`Undid: ${entry.label}`, { entry: serialize(entry) });
75
+ }
76
+ )
77
+ );
78
+ disposers.push(
79
+ host.registerTool(
80
+ {
81
+ name: "agent_redo",
82
+ description: "Redo the most recently undone action.",
83
+ inputSchema: {
84
+ type: "object",
85
+ properties: { agentId: { type: "string" } },
86
+ additionalProperties: false
87
+ }
88
+ },
89
+ async (args) => {
90
+ const entry = await fancyAutoCommon.redoOne(agentOf(args));
91
+ if (!entry) return errorResult("Nothing to redo.");
92
+ return textResult(`Redid: ${entry.label}`, { entry: serialize(entry) });
93
+ }
94
+ )
95
+ );
96
+ disposers.push(
97
+ host.registerTool(
98
+ {
99
+ name: "agent_history",
100
+ description: "List the agent's undo stack (oldest first). Useful for understanding what's reversible.",
101
+ inputSchema: {
102
+ type: "object",
103
+ properties: { agentId: { type: "string" } },
104
+ additionalProperties: false
105
+ }
106
+ },
107
+ async (args) => {
108
+ const history = fancyAutoCommon.readHistory(agentOf(args)).map(serialize);
109
+ const text = history.map((e) => `${new Date(e.timestamp).toISOString()} ${e.bridgeId} ${e.action}: ${e.label}`).join("\n");
110
+ return textResult(text || "(empty)", history);
111
+ }
112
+ )
113
+ );
114
+ return () => disposers.forEach((d) => d());
115
+ }
116
+ function serialize(entry) {
117
+ return {
118
+ timestamp: entry.timestamp,
119
+ bridgeId: entry.bridgeId,
120
+ action: entry.action,
121
+ label: entry.label
122
+ };
123
+ }
124
+
49
125
  // src/bridges/charts.ts
50
126
  var DEFAULT_AGENT = { id: "agent", name: "Agent", color: "#a855f7" };
51
127
  function registerChartsBridge(host, options) {
52
128
  const { adapter } = options;
53
129
  const agent = { ...DEFAULT_AGENT, ...options.agent ?? {} };
54
130
  const disposers = [];
131
+ ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });
55
132
  const target = {
56
133
  kind: "chart",
57
134
  screenId: adapter.screenId,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mcp/server.ts","../src/presence/wrap-tool-with-activity.ts","../src/bridges/charts.ts"],"names":["emitActivity"],"mappings":"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","file":"bridges-charts.cjs","sourcesContent":["import {\n type CallToolResult,\n type JsonObject,\n type JsonRpcMessage,\n type JsonRpcRequest,\n type JsonRpcId,\n type RegisteredTool,\n type ServerCapabilities,\n type ServerInfo,\n type ToolDefinition,\n type ToolHandler,\n JSONRPC_INTERNAL_ERROR,\n JSONRPC_INVALID_PARAMS,\n JSONRPC_METHOD_NOT_FOUND,\n MCP_PROTOCOL_VERSION,\n} from \"./types\";\nimport { ToolRegistry } from \"./tool-host\";\n\nexport type McpServerOptions = {\n info: ServerInfo;\n /** Defaults to { tools: { listChanged: true } } */\n capabilities?: ServerCapabilities;\n /** Free-text instructions surfaced to clients during initialize. */\n instructions?: string;\n};\n\nexport type Transport = {\n /** Called by the server when it has a message to deliver to the client. */\n send: (message: JsonRpcMessage) => void;\n /** Called by the server when it's torn down so the transport can clean up. */\n close?: () => void;\n};\n\n/**\n * MicroMcpServer — protocol-level MCP server, transport-agnostic.\n *\n * Use it like:\n *\n * const server = new MicroMcpServer({ info: { name: \"session\", version: \"0.1\" } });\n * server.registerTool({ name: \"...\", inputSchema: { type: \"object\" } }, async (args) => ({...}));\n * const transport = new InProcessTransport();\n * server.attach(transport);\n * transport.deliver({ ... }); // client → server frames\n *\n * The same server can serve multiple transports (e.g. an in-process agent\n * AND a relayed external client) by attaching each one.\n */\nexport class MicroMcpServer extends ToolRegistry {\n private transports = new Set<Transport>();\n private notifyListChangedScheduled = false;\n\n readonly info: ServerInfo;\n readonly capabilities: ServerCapabilities;\n readonly instructions?: string;\n\n constructor(options: McpServerOptions) {\n super();\n this.info = options.info;\n this.capabilities = options.capabilities ?? { tools: { listChanged: true } };\n this.instructions = options.instructions;\n }\n\n attach(transport: Transport): () => void {\n this.transports.add(transport);\n return () => this.detach(transport);\n }\n\n detach(transport: Transport): void {\n if (this.transports.delete(transport)) {\n transport.close?.();\n }\n }\n\n unregisterTool(name: string): void {\n if (this.tools.delete(name)) {\n this.scheduleListChangedNotification();\n }\n }\n\n protected onToolsChanged(): void {\n this.scheduleListChangedNotification();\n }\n\n /**\n * Receive a JSON-RPC frame from a client (called by the transport).\n * The transport is responsible for sending the response back.\n */\n async receive(transport: Transport, message: JsonRpcMessage): Promise<void> {\n if (!(\"method\" in message)) return; // It's a response, not a request — ignore.\n\n const isNotification = !(\"id\" in message);\n if (isNotification) {\n // Notifications are fire-and-forget. We ignore unknown methods.\n return;\n }\n\n const request = message as JsonRpcRequest;\n try {\n const result = await this.handle(request);\n transport.send({ jsonrpc: \"2.0\", id: request.id, result });\n } catch (err) {\n transport.send({\n jsonrpc: \"2.0\",\n id: request.id,\n error: this.toRpcError(err),\n });\n }\n }\n\n private async handle(request: JsonRpcRequest): Promise<any> {\n const { method, params } = request;\n switch (method) {\n case \"initialize\":\n return {\n protocolVersion: MCP_PROTOCOL_VERSION,\n capabilities: this.capabilities,\n serverInfo: this.info,\n ...(this.instructions ? { instructions: this.instructions } : {}),\n };\n\n case \"tools/list\":\n return { tools: this.listTools() };\n\n case \"tools/call\": {\n const name = params?.name;\n const args = (params?.arguments ?? {}) as JsonObject;\n if (typeof name !== \"string\") {\n throw rpcError(JSONRPC_INVALID_PARAMS, \"tools/call requires `name`\");\n }\n const tool = this.tools.get(name);\n if (!tool) {\n throw rpcError(JSONRPC_METHOD_NOT_FOUND, `Unknown tool: ${name}`);\n }\n const result = await tool.handler(args);\n return result satisfies CallToolResult;\n }\n\n case \"ping\":\n return {};\n\n default:\n throw rpcError(JSONRPC_METHOD_NOT_FOUND, `Unsupported method: ${method}`);\n }\n }\n\n private scheduleListChangedNotification(): void {\n if (this.notifyListChangedScheduled) return;\n this.notifyListChangedScheduled = true;\n queueMicrotask(() => {\n this.notifyListChangedScheduled = false;\n this.broadcast({ jsonrpc: \"2.0\", method: \"notifications/tools/list_changed\" });\n });\n }\n\n private broadcast(message: JsonRpcMessage): void {\n for (const t of this.transports) t.send(message);\n }\n\n private toRpcError(err: unknown): { code: number; message: string; data?: any } {\n if (err && typeof err === \"object\" && \"code\" in err && \"message\" in err) {\n return err as any;\n }\n return {\n code: JSONRPC_INTERNAL_ERROR,\n message: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\nexport function rpcError(code: number, message: string, data?: any) {\n return { code, message, ...(data !== undefined ? { data } : {}) };\n}\n\n/**\n * Helper to build a CallToolResult from a string or structured value.\n */\nexport function textResult(text: string, structured?: any): CallToolResult {\n return {\n content: [{ type: \"text\", text }],\n ...(structured !== undefined ? { structuredContent: structured } : {}),\n };\n}\n\nexport function errorResult(text: string): CallToolResult {\n return { content: [{ type: \"text\", text }], isError: true };\n}\n\n// Internal helper so the JsonRpcId import isn't dropped by tsup\ntype _KeepIdImport = JsonRpcId;\n","import type { CallToolResult } from \"../mcp/types\";\nimport { emitActivity } from \"./registry\";\nimport type { AgentTarget } from \"./types\";\n\nexport type ActivityAgent = { id: string; name?: string; color?: string };\n\nexport type ActivityResolverContext<TArgs = Record<string, unknown>> = {\n /** Tool name as registered. */\n toolName: string;\n /** Arguments the tool was called with. */\n args: TArgs;\n /** The CallToolResult the underlying handler produced. */\n result: CallToolResult;\n};\n\n/**\n * Resolves an `AgentTarget` for an executed tool. Bridges declare one of\n * these per registration so the wrapper knows which surface / element /\n * screen the activity belongs to.\n *\n * The resolver runs AFTER the tool handler so it can inspect the result\n * (e.g. read a newly-created item id from `structuredContent`).\n */\nexport type ActivityTargetResolver<TArgs = Record<string, unknown>> = (\n ctx: ActivityResolverContext<TArgs>,\n) => AgentTarget | null;\n\nexport type ToolHandler<TArgs = Record<string, unknown>> = (\n args: TArgs,\n) => Promise<CallToolResult> | CallToolResult;\n\n/**\n * wrapToolWithActivity — decorate a bridge tool handler so every successful\n * call emits an `AgentActivityEvent`. Returns a new handler with the same shape.\n *\n * Usage in a bridge:\n *\n * server.registerTool(\n * definition,\n * wrapToolWithActivity(\n * handler,\n * { agent, kind: \"whiteboard\", resolveTarget: ({ args }) => ({\n * kind: \"whiteboard\", elementId: args.id as string,\n * }) },\n * ),\n * );\n */\nexport function wrapToolWithActivity<TArgs = Record<string, unknown>>(\n handler: ToolHandler<TArgs>,\n options: {\n toolName: string;\n agent: ActivityAgent;\n /** Optional fancy-screens screen id this bridge is scoped to. */\n screenId?: string;\n /** Default target kind if the resolver returns one without `kind`. */\n kind: AgentTarget[\"kind\"];\n /** Per-call resolver. Return `null` to skip emitting (e.g. for read-only tools). */\n resolveTarget?: ActivityTargetResolver<TArgs>;\n /** Optional ttl override. */\n ttlMs?: number;\n },\n): ToolHandler<TArgs> {\n return async (args) => {\n const result = await handler(args);\n if (result.isError) return result;\n\n let target: AgentTarget | null;\n if (options.resolveTarget) {\n target = options.resolveTarget({ toolName: options.toolName, args, result });\n } else {\n target = { kind: options.kind, screenId: options.screenId };\n }\n if (!target) return result;\n\n emitActivity({\n agentId: options.agent.id,\n agentName: options.agent.name,\n agentColor: options.agent.color,\n target: { ...target, kind: target.kind ?? options.kind, screenId: target.screenId ?? options.screenId },\n action: options.toolName,\n timestamp: Date.now(),\n meta: extractMeta(result),\n ttlMs: options.ttlMs,\n });\n return result;\n };\n}\n\nfunction extractMeta(result: CallToolResult): Record<string, unknown> | undefined {\n const sc = result.structuredContent;\n if (sc && typeof sc === \"object\" && !Array.isArray(sc)) {\n return sc as Record<string, unknown>;\n }\n return undefined;\n}\n","import { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport type { AgentTarget } from \"../presence/types\";\n\n/**\n * Adapter wires a single fancy-echarts chart to the bridge. Charts are\n * already prop-driven, so the adapter just exposes the data + option\n * setters and a way to read what's currently rendered.\n */\nexport type ChartsBridgeAdapter = {\n /** Stable id for this chart instance. */\n id: string;\n title?: string;\n screenId?: string;\n /** Read the current ECharts option object the chart is rendering. */\n getOption: () => Record<string, unknown>;\n /** Replace the entire option. */\n setOption: (option: Record<string, unknown>) => void;\n /** Convenience: shallow-merge a partial option update. */\n updateOption?: (partial: Record<string, unknown>) => void;\n /** Read just the data series (subset of option for quick agent reads). */\n getData?: () => unknown;\n /** Update only the data, leaving axes/colors/etc. alone. */\n updateData?: (data: unknown) => void;\n};\n\nexport type ChartsBridgeOptions = {\n adapter: ChartsBridgeAdapter;\n agent?: { id: string; name?: string; color?: string };\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\n/**\n * registerChartsBridge — schema-aware MCP access to a single chart.\n */\nexport function registerChartsBridge(\n host: ToolHost,\n options: ChartsBridgeOptions,\n): Bridge {\n const { adapter } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const disposers: Array<() => void> = [];\n\n const target: AgentTarget = {\n kind: \"chart\",\n screenId: adapter.screenId,\n elementId: adapter.id,\n label: adapter.title ?? adapter.id,\n };\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<any> | any,\n isMutation: boolean,\n ) => {\n const wrapped = async (args: JsonObject) => {\n try { return await handler(args); }\n catch (e) { return errorResult(e instanceof Error ? e.message : String(e)); }\n };\n const final = isMutation\n ? wrapToolWithActivity(wrapped, {\n toolName: name, agent, kind: \"chart\", screenId: adapter.screenId,\n resolveTarget: () => target,\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n { name, description, inputSchema: { type: \"object\", properties: properties as any, required, additionalProperties: false } },\n final as any,\n ),\n );\n };\n\n reg(\n \"chart_describe\",\n `Describe the chart \"${adapter.id}\" — series count, type guesses, axis info.`,\n {},\n [],\n () => {\n const opt = adapter.getOption();\n const series = Array.isArray(opt.series) ? opt.series : [];\n const summary = {\n id: adapter.id,\n title: adapter.title,\n seriesCount: series.length,\n seriesTypes: series.map((s: any) => s?.type ?? \"unknown\"),\n hasXAxis: !!opt.xAxis,\n hasYAxis: !!opt.yAxis,\n };\n return textResult(JSON.stringify(summary), summary);\n },\n false,\n );\n\n reg(\n \"chart_get_option\",\n \"Read the full ECharts option object the chart is rendering.\",\n {},\n [],\n () => {\n const opt = adapter.getOption();\n return textResult(JSON.stringify(opt, null, 2), opt);\n },\n false,\n );\n\n reg(\n \"chart_set_option\",\n \"Replace the entire ECharts option. Use chart_update_option for partial updates.\",\n { option: { type: \"object\" } },\n [\"option\"],\n (args) => {\n const opt = (args.option && typeof args.option === \"object\") ? args.option as Record<string, unknown> : {};\n adapter.setOption(opt);\n return textResult(\"Replaced chart option\", { });\n },\n true,\n );\n\n reg(\n \"chart_update_option\",\n \"Shallow-merge a partial option update — only the keys you provide change.\",\n { partial: { type: \"object\" } },\n [\"partial\"],\n (args) => {\n const partial = (args.partial && typeof args.partial === \"object\") ? args.partial as Record<string, unknown> : {};\n if (adapter.updateOption) {\n adapter.updateOption(partial);\n } else {\n adapter.setOption({ ...adapter.getOption(), ...partial });\n }\n return textResult(\"Merged chart option\", { keys: Object.keys(partial) });\n },\n true,\n );\n\n reg(\n \"chart_update_data\",\n \"Update only the data (typically the `series` field). Leaves layout / axes / colors alone.\",\n { data: { description: \"New series array (or whatever shape the host's adapter expects).\" } },\n [\"data\"],\n (args) => {\n if (!adapter.updateData) return errorResult(\"Host did not provide updateData.\");\n adapter.updateData(args.data);\n return textResult(\"Updated chart data\", { });\n },\n true,\n );\n\n return {\n id: `chart:${adapter.id}`,\n title: adapter.title ?? adapter.id,\n dispose: () => { for (const d of disposers) d(); },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/mcp/server.ts","../src/presence/wrap-tool-with-activity.ts","../src/undo/undo-tools.ts","../src/bridges/charts.ts"],"names":["emitActivity","undoOne","redoOne","readHistory"],"mappings":"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","file":"bridges-charts.cjs","sourcesContent":["import {\n type CallToolResult,\n type JsonObject,\n type JsonRpcMessage,\n type JsonRpcRequest,\n type JsonRpcId,\n type RegisteredTool,\n type ServerCapabilities,\n type ServerInfo,\n type ToolDefinition,\n type ToolHandler,\n JSONRPC_INTERNAL_ERROR,\n JSONRPC_INVALID_PARAMS,\n JSONRPC_METHOD_NOT_FOUND,\n MCP_PROTOCOL_VERSION,\n} from \"./types\";\nimport { ToolRegistry } from \"./tool-host\";\n\nexport type McpServerOptions = {\n info: ServerInfo;\n /** Defaults to { tools: { listChanged: true } } */\n capabilities?: ServerCapabilities;\n /** Free-text instructions surfaced to clients during initialize. */\n instructions?: string;\n};\n\nexport type Transport = {\n /** Called by the server when it has a message to deliver to the client. */\n send: (message: JsonRpcMessage) => void;\n /** Called by the server when it's torn down so the transport can clean up. */\n close?: () => void;\n};\n\n/**\n * MicroMcpServer — protocol-level MCP server, transport-agnostic.\n *\n * Use it like:\n *\n * const server = new MicroMcpServer({ info: { name: \"session\", version: \"0.1\" } });\n * server.registerTool({ name: \"...\", inputSchema: { type: \"object\" } }, async (args) => ({...}));\n * const transport = new InProcessTransport();\n * server.attach(transport);\n * transport.deliver({ ... }); // client → server frames\n *\n * The same server can serve multiple transports (e.g. an in-process agent\n * AND a relayed external client) by attaching each one.\n */\nexport class MicroMcpServer extends ToolRegistry {\n private transports = new Set<Transport>();\n private notifyListChangedScheduled = false;\n\n readonly info: ServerInfo;\n readonly capabilities: ServerCapabilities;\n readonly instructions?: string;\n\n constructor(options: McpServerOptions) {\n super();\n this.info = options.info;\n this.capabilities = options.capabilities ?? { tools: { listChanged: true } };\n this.instructions = options.instructions;\n }\n\n attach(transport: Transport): () => void {\n this.transports.add(transport);\n return () => this.detach(transport);\n }\n\n detach(transport: Transport): void {\n if (this.transports.delete(transport)) {\n transport.close?.();\n }\n }\n\n unregisterTool(name: string): void {\n if (this.tools.delete(name)) {\n this.scheduleListChangedNotification();\n }\n }\n\n protected onToolsChanged(): void {\n this.scheduleListChangedNotification();\n }\n\n /**\n * Receive a JSON-RPC frame from a client (called by the transport).\n * The transport is responsible for sending the response back.\n */\n async receive(transport: Transport, message: JsonRpcMessage): Promise<void> {\n if (!(\"method\" in message)) return; // It's a response, not a request — ignore.\n\n const isNotification = !(\"id\" in message);\n if (isNotification) {\n // Notifications are fire-and-forget. We ignore unknown methods.\n return;\n }\n\n const request = message as JsonRpcRequest;\n try {\n const result = await this.handle(request);\n transport.send({ jsonrpc: \"2.0\", id: request.id, result });\n } catch (err) {\n transport.send({\n jsonrpc: \"2.0\",\n id: request.id,\n error: this.toRpcError(err),\n });\n }\n }\n\n private async handle(request: JsonRpcRequest): Promise<any> {\n const { method, params } = request;\n switch (method) {\n case \"initialize\":\n return {\n protocolVersion: MCP_PROTOCOL_VERSION,\n capabilities: this.capabilities,\n serverInfo: this.info,\n ...(this.instructions ? { instructions: this.instructions } : {}),\n };\n\n case \"tools/list\":\n return { tools: this.listTools() };\n\n case \"tools/call\": {\n const name = params?.name;\n const args = (params?.arguments ?? {}) as JsonObject;\n if (typeof name !== \"string\") {\n throw rpcError(JSONRPC_INVALID_PARAMS, \"tools/call requires `name`\");\n }\n const tool = this.tools.get(name);\n if (!tool) {\n throw rpcError(JSONRPC_METHOD_NOT_FOUND, `Unknown tool: ${name}`);\n }\n const result = await tool.handler(args);\n return result satisfies CallToolResult;\n }\n\n case \"ping\":\n return {};\n\n default:\n throw rpcError(JSONRPC_METHOD_NOT_FOUND, `Unsupported method: ${method}`);\n }\n }\n\n private scheduleListChangedNotification(): void {\n if (this.notifyListChangedScheduled) return;\n this.notifyListChangedScheduled = true;\n queueMicrotask(() => {\n this.notifyListChangedScheduled = false;\n this.broadcast({ jsonrpc: \"2.0\", method: \"notifications/tools/list_changed\" });\n });\n }\n\n private broadcast(message: JsonRpcMessage): void {\n for (const t of this.transports) t.send(message);\n }\n\n private toRpcError(err: unknown): { code: number; message: string; data?: any } {\n if (err && typeof err === \"object\" && \"code\" in err && \"message\" in err) {\n return err as any;\n }\n return {\n code: JSONRPC_INTERNAL_ERROR,\n message: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\nexport function rpcError(code: number, message: string, data?: any) {\n return { code, message, ...(data !== undefined ? { data } : {}) };\n}\n\n/**\n * Helper to build a CallToolResult from a string or structured value.\n */\nexport function textResult(text: string, structured?: any): CallToolResult {\n return {\n content: [{ type: \"text\", text }],\n ...(structured !== undefined ? { structuredContent: structured } : {}),\n };\n}\n\nexport function errorResult(text: string): CallToolResult {\n return { content: [{ type: \"text\", text }], isError: true };\n}\n\n// Internal helper so the JsonRpcId import isn't dropped by tsup\ntype _KeepIdImport = JsonRpcId;\n","import type { CallToolResult } from \"../mcp/types\";\nimport { emitActivity } from \"./registry\";\nimport type { AgentTarget } from \"./types\";\n\nexport type ActivityAgent = { id: string; name?: string; color?: string };\n\nexport type ActivityResolverContext<TArgs = Record<string, unknown>> = {\n /** Tool name as registered. */\n toolName: string;\n /** Arguments the tool was called with. */\n args: TArgs;\n /** The CallToolResult the underlying handler produced. */\n result: CallToolResult;\n};\n\n/**\n * Resolves an `AgentTarget` for an executed tool. Bridges declare one of\n * these per registration so the wrapper knows which surface / element /\n * screen the activity belongs to.\n *\n * The resolver runs AFTER the tool handler so it can inspect the result\n * (e.g. read a newly-created item id from `structuredContent`).\n */\nexport type ActivityTargetResolver<TArgs = Record<string, unknown>> = (\n ctx: ActivityResolverContext<TArgs>,\n) => AgentTarget | null;\n\nexport type ToolHandler<TArgs = Record<string, unknown>> = (\n args: TArgs,\n) => Promise<CallToolResult> | CallToolResult;\n\n/**\n * wrapToolWithActivity — decorate a bridge tool handler so every successful\n * call emits an `AgentActivityEvent`. Returns a new handler with the same shape.\n *\n * Usage in a bridge:\n *\n * server.registerTool(\n * definition,\n * wrapToolWithActivity(\n * handler,\n * { agent, kind: \"whiteboard\", resolveTarget: ({ args }) => ({\n * kind: \"whiteboard\", elementId: args.id as string,\n * }) },\n * ),\n * );\n */\nexport function wrapToolWithActivity<TArgs = Record<string, unknown>>(\n handler: ToolHandler<TArgs>,\n options: {\n toolName: string;\n agent: ActivityAgent;\n /** Optional fancy-screens screen id this bridge is scoped to. */\n screenId?: string;\n /** Default target kind if the resolver returns one without `kind`. */\n kind: AgentTarget[\"kind\"];\n /** Per-call resolver. Return `null` to skip emitting (e.g. for read-only tools). */\n resolveTarget?: ActivityTargetResolver<TArgs>;\n /** Optional ttl override. */\n ttlMs?: number;\n },\n): ToolHandler<TArgs> {\n return async (args) => {\n const result = await handler(args);\n if (result.isError) return result;\n\n let target: AgentTarget | null;\n if (options.resolveTarget) {\n target = options.resolveTarget({ toolName: options.toolName, args, result });\n } else {\n target = { kind: options.kind, screenId: options.screenId };\n }\n if (!target) return result;\n\n emitActivity({\n agentId: options.agent.id,\n agentName: options.agent.name,\n agentColor: options.agent.color,\n target: { ...target, kind: target.kind ?? options.kind, screenId: target.screenId ?? options.screenId },\n action: options.toolName,\n timestamp: Date.now(),\n meta: extractMeta(result),\n ttlMs: options.ttlMs,\n });\n return result;\n };\n}\n\nfunction extractMeta(result: CallToolResult): Record<string, unknown> | undefined {\n const sc = result.structuredContent;\n if (sc && typeof sc === \"object\" && !Array.isArray(sc)) {\n return sc as Record<string, unknown>;\n }\n return undefined;\n}\n","import { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport { readHistory, redoOne, undoOne } from \"./undo-stack\";\n\nexport type UndoToolsOptions = {\n /** Default agent id when the caller doesn't pass one. */\n defaultAgentId?: string;\n};\n\n/**\n * Idempotent tracker so multiple bridges on the same server only register\n * agent_undo / agent_redo / agent_history once.\n */\nconst installedHosts = new WeakSet<ToolHost>();\n\n/**\n * ensureUndoToolsRegistered — bridges call this on construction. Safe to\n * call repeatedly with the same server; subsequent calls are no-ops.\n */\nexport function ensureUndoToolsRegistered(host: ToolHost, options: UndoToolsOptions = {}): void {\n if (installedHosts.has(host)) return;\n installedHosts.add(host);\n registerUndoTools(host, options);\n}\n\n/**\n * registerUndoTools — add agent_undo / agent_redo / agent_history to the\n * server. Returns a disposer that unregisters all three.\n */\nexport function registerUndoTools(host: ToolHost, options: UndoToolsOptions = {}): () => void {\n const defaultAgent = options.defaultAgentId ?? \"agent\";\n const disposers: Array<() => void> = [];\n const agentOf = (args: any): string =>\n typeof args?.agentId === \"string\" ? args.agentId : defaultAgent;\n\n disposers.push(\n host.registerTool(\n {\n name: \"agent_undo\",\n description: \"Undo the most recent action on the agent's stack. Optional agentId targets a specific agent.\",\n inputSchema: {\n type: \"object\",\n properties: { agentId: { type: \"string\" } },\n additionalProperties: false,\n },\n },\n async (args) => {\n const entry = await undoOne(agentOf(args));\n if (!entry) return errorResult(\"Nothing to undo.\");\n return textResult(`Undid: ${entry.label}`, { entry: serialize(entry) });\n },\n ),\n );\n\n disposers.push(\n host.registerTool(\n {\n name: \"agent_redo\",\n description: \"Redo the most recently undone action.\",\n inputSchema: {\n type: \"object\",\n properties: { agentId: { type: \"string\" } },\n additionalProperties: false,\n },\n },\n async (args) => {\n const entry = await redoOne(agentOf(args));\n if (!entry) return errorResult(\"Nothing to redo.\");\n return textResult(`Redid: ${entry.label}`, { entry: serialize(entry) });\n },\n ),\n );\n\n disposers.push(\n host.registerTool(\n {\n name: \"agent_history\",\n description: \"List the agent's undo stack (oldest first). Useful for understanding what's reversible.\",\n inputSchema: {\n type: \"object\",\n properties: { agentId: { type: \"string\" } },\n additionalProperties: false,\n },\n },\n async (args) => {\n const history = readHistory(agentOf(args)).map(serialize);\n const text = history.map((e) => `${new Date(e.timestamp).toISOString()} ${e.bridgeId} ${e.action}: ${e.label}`).join(\"\\n\");\n return textResult(text || \"(empty)\", history);\n },\n ),\n );\n\n return () => disposers.forEach((d) => d());\n}\n\nfunction serialize(entry: import(\"./undo-stack\").UndoEntry) {\n return {\n timestamp: entry.timestamp,\n bridgeId: entry.bridgeId,\n action: entry.action,\n label: entry.label,\n };\n}\n","import { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport { ensureUndoToolsRegistered } from \"../undo/undo-tools\";\nimport type { AgentTarget } from \"../presence/types\";\n\n/**\n * Adapter wires a single fancy-echarts chart to the bridge. Charts are\n * already prop-driven, so the adapter just exposes the data + option\n * setters and a way to read what's currently rendered.\n */\nexport type ChartsBridgeAdapter = {\n /** Stable id for this chart instance. */\n id: string;\n title?: string;\n screenId?: string;\n /** Read the current ECharts option object the chart is rendering. */\n getOption: () => Record<string, unknown>;\n /** Replace the entire option. */\n setOption: (option: Record<string, unknown>) => void;\n /** Convenience: shallow-merge a partial option update. */\n updateOption?: (partial: Record<string, unknown>) => void;\n /** Read just the data series (subset of option for quick agent reads). */\n getData?: () => unknown;\n /** Update only the data, leaving axes/colors/etc. alone. */\n updateData?: (data: unknown) => void;\n};\n\nexport type ChartsBridgeOptions = {\n adapter: ChartsBridgeAdapter;\n agent?: { id: string; name?: string; color?: string };\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\n/**\n * registerChartsBridge — schema-aware MCP access to a single chart.\n */\nexport function registerChartsBridge(\n host: ToolHost,\n options: ChartsBridgeOptions,\n): Bridge {\n const { adapter } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const disposers: Array<() => void> = [];\n\n // agent_undo / agent_redo / agent_history are registered whenever any bridge\n // mounts, so undo availability doesn't hinge on which bridges are co-present.\n ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });\n\n const target: AgentTarget = {\n kind: \"chart\",\n screenId: adapter.screenId,\n elementId: adapter.id,\n label: adapter.title ?? adapter.id,\n };\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<any> | any,\n isMutation: boolean,\n ) => {\n const wrapped = async (args: JsonObject) => {\n try { return await handler(args); }\n catch (e) { return errorResult(e instanceof Error ? e.message : String(e)); }\n };\n const final = isMutation\n ? wrapToolWithActivity(wrapped, {\n toolName: name, agent, kind: \"chart\", screenId: adapter.screenId,\n resolveTarget: () => target,\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n { name, description, inputSchema: { type: \"object\", properties: properties as any, required, additionalProperties: false } },\n final as any,\n ),\n );\n };\n\n reg(\n \"chart_describe\",\n `Describe the chart \"${adapter.id}\" — series count, type guesses, axis info.`,\n {},\n [],\n () => {\n const opt = adapter.getOption();\n const series = Array.isArray(opt.series) ? opt.series : [];\n const summary = {\n id: adapter.id,\n title: adapter.title,\n seriesCount: series.length,\n seriesTypes: series.map((s: any) => s?.type ?? \"unknown\"),\n hasXAxis: !!opt.xAxis,\n hasYAxis: !!opt.yAxis,\n };\n return textResult(JSON.stringify(summary), summary);\n },\n false,\n );\n\n reg(\n \"chart_get_option\",\n \"Read the full ECharts option object the chart is rendering.\",\n {},\n [],\n () => {\n const opt = adapter.getOption();\n return textResult(JSON.stringify(opt, null, 2), opt);\n },\n false,\n );\n\n reg(\n \"chart_set_option\",\n \"Replace the entire ECharts option. Use chart_update_option for partial updates.\",\n { option: { type: \"object\" } },\n [\"option\"],\n (args) => {\n const opt = (args.option && typeof args.option === \"object\") ? args.option as Record<string, unknown> : {};\n adapter.setOption(opt);\n return textResult(\"Replaced chart option\", { });\n },\n true,\n );\n\n reg(\n \"chart_update_option\",\n \"Shallow-merge a partial option update — only the keys you provide change.\",\n { partial: { type: \"object\" } },\n [\"partial\"],\n (args) => {\n const partial = (args.partial && typeof args.partial === \"object\") ? args.partial as Record<string, unknown> : {};\n if (adapter.updateOption) {\n adapter.updateOption(partial);\n } else {\n adapter.setOption({ ...adapter.getOption(), ...partial });\n }\n return textResult(\"Merged chart option\", { keys: Object.keys(partial) });\n },\n true,\n );\n\n reg(\n \"chart_update_data\",\n \"Update only the data (typically the `series` field). Leaves layout / axes / colors alone.\",\n { data: { description: \"New series array (or whatever shape the host's adapter expects).\" } },\n [\"data\"],\n (args) => {\n if (!adapter.updateData) return errorResult(\"Host did not provide updateData.\");\n adapter.updateData(args.data);\n return textResult(\"Updated chart data\", { });\n },\n true,\n );\n\n return {\n id: `chart:${adapter.id}`,\n title: adapter.title ?? adapter.id,\n dispose: () => { for (const d of disposers) d(); },\n };\n}\n"]}
@@ -1,5 +1,6 @@
1
- export { registerChartsBridge } from './chunk-SJ7H242B.js';
1
+ export { registerChartsBridge } from './chunk-AROVENCE.js';
2
2
  import './chunk-ULJL53DL.js';
3
+ import './chunk-KJ5AOOV7.js';
3
4
  import './chunk-C3TYI5TJ.js';
4
5
  import './chunk-4KAIV6OD.js';
5
6
  //# sourceMappingURL=bridges-charts.js.map
@@ -0,0 +1,437 @@
1
+ 'use strict';
2
+
3
+ var fancyAutoCommon = require('@particle-academy/fancy-auto-common');
4
+ var fancyDocCommons = require('@particle-academy/fancy-doc-commons');
5
+
6
+ // src/mcp/server.ts
7
+ function textResult(text, structured) {
8
+ return {
9
+ content: [{ type: "text", text }],
10
+ ...structured !== void 0 ? { structuredContent: structured } : {}
11
+ };
12
+ }
13
+ function errorResult(text) {
14
+ return { content: [{ type: "text", text }], isError: true };
15
+ }
16
+
17
+ // src/presence/wrap-tool-with-activity.ts
18
+ function wrapToolWithActivity(handler, options) {
19
+ return async (args) => {
20
+ const result = await handler(args);
21
+ if (result.isError) return result;
22
+ let target;
23
+ if (options.resolveTarget) {
24
+ target = options.resolveTarget({ toolName: options.toolName, args, result });
25
+ } else {
26
+ target = { kind: options.kind, screenId: options.screenId };
27
+ }
28
+ if (!target) return result;
29
+ fancyAutoCommon.emitActivity({
30
+ agentId: options.agent.id,
31
+ agentName: options.agent.name,
32
+ agentColor: options.agent.color,
33
+ target: { ...target, kind: target.kind ?? options.kind, screenId: target.screenId ?? options.screenId },
34
+ action: options.toolName,
35
+ timestamp: Date.now(),
36
+ meta: extractMeta(result),
37
+ ttlMs: options.ttlMs
38
+ });
39
+ return result;
40
+ };
41
+ }
42
+ function extractMeta(result) {
43
+ const sc = result.structuredContent;
44
+ if (sc && typeof sc === "object" && !Array.isArray(sc)) {
45
+ return sc;
46
+ }
47
+ return void 0;
48
+ }
49
+
50
+ // src/undo/undo-tools.ts
51
+ var installedHosts = /* @__PURE__ */ new WeakSet();
52
+ function ensureUndoToolsRegistered(host, options = {}) {
53
+ if (installedHosts.has(host)) return;
54
+ installedHosts.add(host);
55
+ registerUndoTools(host, options);
56
+ }
57
+ function registerUndoTools(host, options = {}) {
58
+ const defaultAgent = options.defaultAgentId ?? "agent";
59
+ const disposers = [];
60
+ const agentOf = (args) => typeof args?.agentId === "string" ? args.agentId : defaultAgent;
61
+ disposers.push(
62
+ host.registerTool(
63
+ {
64
+ name: "agent_undo",
65
+ description: "Undo the most recent action on the agent's stack. Optional agentId targets a specific agent.",
66
+ inputSchema: {
67
+ type: "object",
68
+ properties: { agentId: { type: "string" } },
69
+ additionalProperties: false
70
+ }
71
+ },
72
+ async (args) => {
73
+ const entry = await fancyAutoCommon.undoOne(agentOf(args));
74
+ if (!entry) return errorResult("Nothing to undo.");
75
+ return textResult(`Undid: ${entry.label}`, { entry: serialize(entry) });
76
+ }
77
+ )
78
+ );
79
+ disposers.push(
80
+ host.registerTool(
81
+ {
82
+ name: "agent_redo",
83
+ description: "Redo the most recently undone action.",
84
+ inputSchema: {
85
+ type: "object",
86
+ properties: { agentId: { type: "string" } },
87
+ additionalProperties: false
88
+ }
89
+ },
90
+ async (args) => {
91
+ const entry = await fancyAutoCommon.redoOne(agentOf(args));
92
+ if (!entry) return errorResult("Nothing to redo.");
93
+ return textResult(`Redid: ${entry.label}`, { entry: serialize(entry) });
94
+ }
95
+ )
96
+ );
97
+ disposers.push(
98
+ host.registerTool(
99
+ {
100
+ name: "agent_history",
101
+ description: "List the agent's undo stack (oldest first). Useful for understanding what's reversible.",
102
+ inputSchema: {
103
+ type: "object",
104
+ properties: { agentId: { type: "string" } },
105
+ additionalProperties: false
106
+ }
107
+ },
108
+ async (args) => {
109
+ const history = fancyAutoCommon.readHistory(agentOf(args)).map(serialize);
110
+ const text = history.map((e) => `${new Date(e.timestamp).toISOString()} ${e.bridgeId} ${e.action}: ${e.label}`).join("\n");
111
+ return textResult(text || "(empty)", history);
112
+ }
113
+ )
114
+ );
115
+ return () => disposers.forEach((d) => d());
116
+ }
117
+ function serialize(entry) {
118
+ return {
119
+ timestamp: entry.timestamp,
120
+ bridgeId: entry.bridgeId,
121
+ action: entry.action,
122
+ label: entry.label
123
+ };
124
+ }
125
+ var DEFAULT_AGENT = { id: "agent", name: "Agent", color: "#a855f7" };
126
+ function registerDocBridge(host, options) {
127
+ const { adapter, surface } = options;
128
+ const agent = { ...DEFAULT_AGENT, ...options.agent ?? {} };
129
+ const reducer = options.reducer ?? fancyDocCommons.treeReducer();
130
+ const stage = options.stagePolicy ?? fancyDocCommons.autoApply;
131
+ const makeNode = options.makeNode ?? (({ id, type, parent, order }, props) => ({ id, type, parent, order, props }));
132
+ const describeNode = options.describeNode ?? ((n) => ({ id: n.id, type: n.type, parent: n.parent, props: Object.keys(n.props ?? {}) }));
133
+ const disposers = [];
134
+ ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });
135
+ let idSeq = 0;
136
+ const mintId = () => adapter.newId?.() ?? `${surface}-${idSeq += 1}`;
137
+ const target = (elementId) => ({ kind: surface, screenId: adapter.screenId, elementId });
138
+ const pending = /* @__PURE__ */ new Map();
139
+ function commit(op, label, targetId) {
140
+ const prev = adapter.get();
141
+ const next = reducer.reduce(prev, op);
142
+ adapter.set(next);
143
+ fancyAutoCommon.pushUndoEntry(agent.id, {
144
+ timestamp: Date.now(),
145
+ bridgeId: surface,
146
+ action: label,
147
+ label,
148
+ undo: () => adapter.set(prev),
149
+ redo: () => adapter.set(next)
150
+ });
151
+ return { ok: true, id: targetId };
152
+ }
153
+ function submit(op, label, targetId) {
154
+ if (stage(op) === "confirm") {
155
+ const id = `${surface}-pending-${idSeq += 1}`;
156
+ pending.set(id, { op, label, targetId });
157
+ options.onPending?.({ id, op, label });
158
+ return { staged: true, id };
159
+ }
160
+ commit(op, label, targetId);
161
+ return { staged: false, id: targetId };
162
+ }
163
+ const reg = (verb, description, properties, required, handler, isMutation, resolveTarget) => {
164
+ const name = `${surface}_${verb}`;
165
+ const wrapped = async (args) => {
166
+ try {
167
+ const { _text, ...structured } = await handler(args);
168
+ return textResult(typeof _text === "string" ? _text : name, structured);
169
+ } catch (e) {
170
+ return errorResult(e instanceof Error ? e.message : String(e));
171
+ }
172
+ };
173
+ const final = isMutation ? wrapToolWithActivity(wrapped, {
174
+ toolName: name,
175
+ agent,
176
+ kind: surface,
177
+ screenId: adapter.screenId,
178
+ resolveTarget: ({ args, result }) => {
179
+ if (result.structuredContent?.staged) return null;
180
+ return resolveTarget?.(args, result.structuredContent ?? {}) ?? target();
181
+ }
182
+ }) : wrapped;
183
+ disposers.push(
184
+ host.registerTool(
185
+ { name, description, inputSchema: { type: "object", properties, required, additionalProperties: false } },
186
+ final
187
+ )
188
+ );
189
+ };
190
+ reg(
191
+ "describe",
192
+ `Summarize the ${surface} document: node count, roots, and the active surface. Call before reading or writing.`,
193
+ {},
194
+ [],
195
+ () => {
196
+ const tree = adapter.get();
197
+ const ids = Object.keys(tree.nodes);
198
+ return { nodeCount: ids.length, roots: fancyDocCommons.childrenOf(tree, null).map((n) => n.id), _text: `${ids.length} nodes` };
199
+ },
200
+ false
201
+ );
202
+ reg(
203
+ "get",
204
+ `Get the whole ${surface} document tree as JSON.`,
205
+ {},
206
+ [],
207
+ () => ({ tree: adapter.get(), _text: "full tree" }),
208
+ false
209
+ );
210
+ reg(
211
+ "list",
212
+ "List nodes (optionally the children of `parent`), in order.",
213
+ { parent: { type: ["string", "null"], description: "Parent id, or null/omitted for roots." } },
214
+ [],
215
+ (args) => {
216
+ const tree = adapter.get();
217
+ const parent = typeof args.parent === "string" ? args.parent : null;
218
+ return { nodes: fancyDocCommons.childrenOf(tree, parent).map(describeNode), _text: `children of ${parent ?? "root"}` };
219
+ },
220
+ false
221
+ );
222
+ reg(
223
+ "get_node",
224
+ "Get one node by id.",
225
+ { id: { type: "string" } },
226
+ ["id"],
227
+ (args) => {
228
+ const node = adapter.get().nodes[String(args.id)];
229
+ if (!node) throw new Error(`No node ${args.id}`);
230
+ return { node, _text: `node ${node.id}` };
231
+ },
232
+ false
233
+ );
234
+ reg(
235
+ "add",
236
+ "Insert a node. Returns its id. Appends under `parent` (or roots) unless `order` is given.",
237
+ {
238
+ type: { type: "string", description: "Node type discriminant." },
239
+ parent: { type: ["string", "null"], description: "Parent id, or null for a root." },
240
+ props: { type: "object", description: "JSON props bag." },
241
+ order: { type: "string", description: "Fractional order key (default: append)." }
242
+ },
243
+ ["type"],
244
+ (args) => {
245
+ const tree = adapter.get();
246
+ const parent = typeof args.parent === "string" ? args.parent : null;
247
+ const id = mintId();
248
+ const order = typeof args.order === "string" ? args.order : fancyDocCommons.appendOrder(tree, parent);
249
+ const props = args.props && typeof args.props === "object" ? args.props : {};
250
+ const node = makeNode({ id, type: String(args.type), parent, order }, props);
251
+ const res = submit({ t: "insert", node }, `add ${args.type} ${id}`, id);
252
+ return { ...res, _text: res.staged ? `staged add ${id}` : `added ${id}` };
253
+ },
254
+ true,
255
+ (_args, result) => target(result.id)
256
+ );
257
+ reg(
258
+ "update",
259
+ "Merge a props patch into a node.",
260
+ { id: { type: "string" }, patch: { type: "object" } },
261
+ ["id", "patch"],
262
+ (args) => {
263
+ const id = String(args.id);
264
+ if (!adapter.get().nodes[id]) throw new Error(`No node ${id}`);
265
+ const patch = args.patch && typeof args.patch === "object" ? args.patch : {};
266
+ const res = submit({ t: "set_props", id, patch }, `update ${id}`, id);
267
+ return { ...res, id, _text: res.staged ? `staged update ${id}` : `updated ${id}` };
268
+ },
269
+ true,
270
+ (args) => target(String(args.id))
271
+ );
272
+ reg(
273
+ "remove",
274
+ "Remove a node and its subtree.",
275
+ { id: { type: "string" } },
276
+ ["id"],
277
+ (args) => {
278
+ const id = String(args.id);
279
+ const tree = adapter.get();
280
+ if (!tree.nodes[id]) throw new Error(`No node ${id}`);
281
+ const count = fancyDocCommons.descendantsOf(tree, id).length + 1;
282
+ const res = submit({ t: "remove", id }, `remove ${id} (${count} node${count === 1 ? "" : "s"})`, id);
283
+ return { ...res, id, removed: count, _text: res.staged ? `staged remove ${id}` : `removed ${id}` };
284
+ },
285
+ true,
286
+ (args) => target(String(args.id))
287
+ );
288
+ reg(
289
+ "move",
290
+ "Reparent + reorder a node.",
291
+ { id: { type: "string" }, parent: { type: ["string", "null"] }, order: { type: "string", description: "Fractional order key (default: append under the new parent)." } },
292
+ ["id"],
293
+ (args) => {
294
+ const id = String(args.id);
295
+ const tree = adapter.get();
296
+ if (!tree.nodes[id]) throw new Error(`No node ${id}`);
297
+ const parent = args.parent === null ? null : typeof args.parent === "string" ? args.parent : tree.nodes[id].parent;
298
+ const order = typeof args.order === "string" ? args.order : fancyDocCommons.appendOrder(tree, parent);
299
+ const res = submit({ t: "move", id, parent, order }, `move ${id}`, id);
300
+ return { ...res, id, _text: res.staged ? `staged move ${id}` : `moved ${id}` };
301
+ },
302
+ true,
303
+ (args) => target(String(args.id))
304
+ );
305
+ for (const t of options.opTools ?? []) {
306
+ reg(
307
+ t.verb,
308
+ t.description,
309
+ t.properties,
310
+ t.required,
311
+ (args) => {
312
+ const built = t.build(args, adapter.get());
313
+ if (built && typeof built === "object" && "error" in built) throw new Error(built.error);
314
+ const tid = t.targetId?.(args);
315
+ const res = submit(built, `${t.verb} ${tid ?? ""}`.trim(), tid);
316
+ return { ...res, id: tid, _text: res.staged ? `staged ${t.verb}` : t.verb };
317
+ },
318
+ true,
319
+ (args) => target(t.targetId?.(args))
320
+ );
321
+ }
322
+ reg(
323
+ "confirm",
324
+ "Apply a staged op by its pending id (from a staged mutation).",
325
+ { id: { type: "string" } },
326
+ ["id"],
327
+ (args) => {
328
+ const id = String(args.id);
329
+ const p = pending.get(id);
330
+ if (!p) throw new Error(`No pending op ${id}`);
331
+ pending.delete(id);
332
+ commit(p.op, p.label, p.targetId);
333
+ return { ok: true, applied: p.label, id: p.targetId, _text: `applied ${p.label}` };
334
+ },
335
+ true,
336
+ (_args, result) => target(result.id)
337
+ );
338
+ reg(
339
+ "reject",
340
+ "Discard a staged op by its pending id.",
341
+ { id: { type: "string" } },
342
+ ["id"],
343
+ (args) => {
344
+ const id = String(args.id);
345
+ const p = pending.get(id);
346
+ if (!p) throw new Error(`No pending op ${id}`);
347
+ pending.delete(id);
348
+ return { ok: true, rejected: p.label, _text: `rejected ${p.label}` };
349
+ },
350
+ false
351
+ );
352
+ return {
353
+ id: surface,
354
+ title: surface,
355
+ dispose: () => {
356
+ for (const d of disposers) d();
357
+ pending.clear();
358
+ }
359
+ };
360
+ }
361
+ function cmsReducer() {
362
+ const base = fancyDocCommons.treeReducer();
363
+ return {
364
+ reduce(doc, op) {
365
+ if (op.t === "set_style") {
366
+ const node = doc.nodes[op.id];
367
+ if (!node) return doc;
368
+ return { nodes: { ...doc.nodes, [op.id]: { ...node, style: { ...node.style, base: { ...node.style.base, ...op.patch } } } } };
369
+ }
370
+ if (op.t === "set_layout") {
371
+ const node = doc.nodes[op.id];
372
+ if (!node) return doc;
373
+ return { nodes: { ...doc.nodes, [op.id]: { ...node, layout: op.layout } } };
374
+ }
375
+ return base.reduce(doc, op);
376
+ },
377
+ invert(doc, op) {
378
+ if (op.t === "set_style") {
379
+ const node = doc.nodes[op.id];
380
+ if (!node) return [];
381
+ const prev = {};
382
+ for (const k in op.patch) prev[k] = node.style.base[k];
383
+ return [{ t: "set_style", id: op.id, patch: prev }];
384
+ }
385
+ if (op.t === "set_layout") {
386
+ const node = doc.nodes[op.id];
387
+ if (!node) return [];
388
+ return [{ t: "set_layout", id: op.id, layout: node.layout }];
389
+ }
390
+ return base.invert(doc, op);
391
+ }
392
+ };
393
+ }
394
+ function registerCmsBridge(host, options) {
395
+ return registerDocBridge(host, {
396
+ adapter: options.adapter,
397
+ surface: "cms",
398
+ agent: options.agent,
399
+ reducer: cmsReducer(),
400
+ stagePolicy: options.stagePolicy,
401
+ onPending: options.onPending,
402
+ // New nodes get an empty base style so they satisfy StyledNode.
403
+ makeNode: ({ id, type, parent, order }, props) => ({ id, type, parent, order, props, style: { base: {} } }),
404
+ describeNode: (n) => ({ id: n.id, type: n.type, parent: n.parent, layout: n.layout }),
405
+ opTools: [
406
+ {
407
+ verb: "set_style",
408
+ description: "Merge a StyleProps patch into a node's base style (color, background, padding, fontSize, gap, \u2026).",
409
+ properties: { id: { type: "string" }, patch: { type: "object", description: "Partial StyleProps." } },
410
+ required: ["id", "patch"],
411
+ build: (args, tree) => {
412
+ const id = String(args.id);
413
+ if (!tree.nodes[id]) return { error: `No node ${id}` };
414
+ return { t: "set_style", id, patch: args.patch && typeof args.patch === "object" ? args.patch : {} };
415
+ },
416
+ targetId: (args) => String(args.id)
417
+ },
418
+ {
419
+ verb: "set_layout",
420
+ description: "Set a container node's layout mode (free | stack | grid).",
421
+ properties: { id: { type: "string" }, layout: { type: "string", enum: ["free", "stack", "grid"] } },
422
+ required: ["id"],
423
+ build: (args, tree) => {
424
+ const id = String(args.id);
425
+ if (!tree.nodes[id]) return { error: `No node ${id}` };
426
+ return { t: "set_layout", id, layout: args.layout };
427
+ },
428
+ targetId: (args) => String(args.id)
429
+ }
430
+ ]
431
+ });
432
+ }
433
+
434
+ exports.cmsReducer = cmsReducer;
435
+ exports.registerCmsBridge = registerCmsBridge;
436
+ //# sourceMappingURL=bridges-cms.cjs.map
437
+ //# sourceMappingURL=bridges-cms.cjs.map