@particle-academy/agent-integrations 0.3.4 → 0.4.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 (110) hide show
  1. package/README.md +20 -0
  2. package/dist/bridges/charts.d.cts +4 -4
  3. package/dist/bridges/charts.d.ts +4 -4
  4. package/dist/bridges/code.d.cts +4 -4
  5. package/dist/bridges/code.d.ts +4 -4
  6. package/dist/bridges/flow.d.cts +4 -4
  7. package/dist/bridges/flow.d.ts +4 -4
  8. package/dist/bridges/forms.d.cts +4 -4
  9. package/dist/bridges/forms.d.ts +4 -4
  10. package/dist/bridges/scene.d.cts +4 -4
  11. package/dist/bridges/scene.d.ts +4 -4
  12. package/dist/bridges/screens.d.cts +78 -0
  13. package/dist/bridges/screens.d.ts +78 -0
  14. package/dist/bridges/sheets.d.cts +4 -4
  15. package/dist/bridges/sheets.d.ts +4 -4
  16. package/dist/bridges/whiteboard.d.cts +4 -4
  17. package/dist/bridges/whiteboard.d.ts +4 -4
  18. package/dist/bridges-charts.cjs +2 -2
  19. package/dist/bridges-charts.cjs.map +1 -1
  20. package/dist/bridges-charts.js +2 -2
  21. package/dist/bridges-code.cjs +2 -2
  22. package/dist/bridges-code.cjs.map +1 -1
  23. package/dist/bridges-code.js +2 -2
  24. package/dist/bridges-flow.cjs +2 -2
  25. package/dist/bridges-flow.cjs.map +1 -1
  26. package/dist/bridges-flow.js +2 -2
  27. package/dist/bridges-forms.cjs +2 -2
  28. package/dist/bridges-forms.cjs.map +1 -1
  29. package/dist/bridges-forms.js +2 -2
  30. package/dist/bridges-scene.cjs +2 -2
  31. package/dist/bridges-scene.cjs.map +1 -1
  32. package/dist/bridges-scene.js +2 -2
  33. package/dist/bridges-screens.cjs +227 -0
  34. package/dist/bridges-screens.cjs.map +1 -0
  35. package/dist/bridges-screens.js +6 -0
  36. package/dist/bridges-screens.js.map +1 -0
  37. package/dist/bridges-sheets.cjs +2 -2
  38. package/dist/bridges-sheets.cjs.map +1 -1
  39. package/dist/bridges-sheets.js +2 -2
  40. package/dist/bridges-whiteboard.cjs +12 -12
  41. package/dist/bridges-whiteboard.cjs.map +1 -1
  42. package/dist/bridges-whiteboard.js +3 -3
  43. package/dist/{chunk-TBEITXF4.js → chunk-3KSZNGNW.js} +7 -7
  44. package/dist/chunk-3KSZNGNW.js.map +1 -0
  45. package/dist/{chunk-OEIULP2L.js → chunk-4BL5M3U3.js} +5 -5
  46. package/dist/chunk-4BL5M3U3.js.map +1 -0
  47. package/dist/{chunk-QGCF7YKW.js → chunk-4KAIV6OD.js} +40 -12
  48. package/dist/chunk-4KAIV6OD.js.map +1 -0
  49. package/dist/chunk-57ZDHD53.js +180 -0
  50. package/dist/chunk-57ZDHD53.js.map +1 -0
  51. package/dist/chunk-E4AICMFZ.js +83 -0
  52. package/dist/chunk-E4AICMFZ.js.map +1 -0
  53. package/dist/{chunk-ACBENYYO.js → chunk-GQ7XXK7G.js} +12 -12
  54. package/dist/chunk-GQ7XXK7G.js.map +1 -0
  55. package/dist/{chunk-XYYSTJHW.js → chunk-HSTW7ZNO.js} +5 -5
  56. package/dist/chunk-HSTW7ZNO.js.map +1 -0
  57. package/dist/{chunk-PDBF4W7E.js → chunk-IANI25IT.js} +5 -5
  58. package/dist/chunk-IANI25IT.js.map +1 -0
  59. package/dist/{chunk-4IAVAFUV.js → chunk-N3H4DXY5.js} +5 -5
  60. package/dist/chunk-N3H4DXY5.js.map +1 -0
  61. package/dist/{chunk-PHPXKSWI.js → chunk-NTDZWGYB.js} +5 -5
  62. package/dist/chunk-NTDZWGYB.js.map +1 -0
  63. package/dist/{chunk-DJOWMF6Q.js → chunk-RGO42EQ6.js} +3 -3
  64. package/dist/{chunk-DJOWMF6Q.js.map → chunk-RGO42EQ6.js.map} +1 -1
  65. package/dist/{chunk-QJUTISFC.js → chunk-XRAJSOPS.js} +5 -5
  66. package/dist/chunk-XRAJSOPS.js.map +1 -0
  67. package/dist/index.cjs +320 -35
  68. package/dist/index.cjs.map +1 -1
  69. package/dist/index.d.cts +7 -4
  70. package/dist/index.d.ts +7 -4
  71. package/dist/index.js +15 -13
  72. package/dist/index.js.map +1 -1
  73. package/dist/mcp/index.d.cts +5 -4
  74. package/dist/mcp/index.d.ts +5 -4
  75. package/dist/mcp.cjs +37 -9
  76. package/dist/mcp.cjs.map +1 -1
  77. package/dist/mcp.js +1 -1
  78. package/dist/presence/index.d.cts +1 -1
  79. package/dist/presence/index.d.ts +1 -1
  80. package/dist/{server-BJu_AMH3.d.ts → server-BsSwfemr.d.cts} +4 -5
  81. package/dist/{server-si-VvFxI.d.cts → server-Du3-IGqM.d.ts} +4 -5
  82. package/dist/sharing/index.d.cts +3 -2
  83. package/dist/sharing/index.d.ts +3 -2
  84. package/dist/sheets-adapter.cjs +96 -0
  85. package/dist/sheets-adapter.cjs.map +1 -0
  86. package/dist/sheets-adapter.d.cts +115 -0
  87. package/dist/sheets-adapter.d.ts +115 -0
  88. package/dist/sheets-adapter.js +4 -0
  89. package/dist/sheets-adapter.js.map +1 -0
  90. package/dist/tool-host-BQuUygLF.d.cts +60 -0
  91. package/dist/tool-host-C8JMMGYq.d.ts +60 -0
  92. package/dist/{types-DXKpLuia.d.ts → types-CCSBGW9T.d.cts} +2 -2
  93. package/dist/{types-Bf1ZoGmI.d.cts → types-DIVNcIQO.d.ts} +2 -2
  94. package/dist/{types-DksGd5Y7.d.cts → types-aOQLTW0E.d.cts} +1 -1
  95. package/dist/{types-DksGd5Y7.d.ts → types-aOQLTW0E.d.ts} +1 -1
  96. package/dist/undo/index.d.cts +4 -4
  97. package/dist/undo/index.d.ts +4 -4
  98. package/dist/undo.cjs +9 -9
  99. package/dist/undo.cjs.map +1 -1
  100. package/dist/undo.js +3 -3
  101. package/package.json +1 -1
  102. package/dist/chunk-4IAVAFUV.js.map +0 -1
  103. package/dist/chunk-ACBENYYO.js.map +0 -1
  104. package/dist/chunk-OEIULP2L.js.map +0 -1
  105. package/dist/chunk-PDBF4W7E.js.map +0 -1
  106. package/dist/chunk-PHPXKSWI.js.map +0 -1
  107. package/dist/chunk-QGCF7YKW.js.map +0 -1
  108. package/dist/chunk-QJUTISFC.js.map +0 -1
  109. package/dist/chunk-TBEITXF4.js.map +0 -1
  110. package/dist/chunk-XYYSTJHW.js.map +0 -1
package/dist/mcp.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mcp/types.ts","../src/mcp/server.ts","../src/mcp/transports/in-process.ts","../src/mcp/transports/relay.ts"],"names":[],"mappings":"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","file":"mcp.cjs","sourcesContent":["/**\n * Minimal MCP (Model Context Protocol) types — covers the subset this\n * package implements: initialize, tools/list, tools/call, plus JSON-RPC.\n *\n * Aligned with the public MCP spec but trimmed to v0.1 needs. See\n * https://spec.modelcontextprotocol.io/ for the full surface.\n */\n\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | { [key: string]: JsonValue }\n | JsonValue[];\n\nexport type JsonObject = { [key: string]: JsonValue };\n\nexport type JsonRpcId = string | number | null;\n\nexport type JsonRpcRequest = {\n jsonrpc: \"2.0\";\n id: JsonRpcId;\n method: string;\n params?: JsonObject;\n};\n\nexport type JsonRpcNotification = {\n jsonrpc: \"2.0\";\n method: string;\n params?: JsonObject;\n};\n\nexport type JsonRpcSuccess = {\n jsonrpc: \"2.0\";\n id: JsonRpcId;\n result: JsonValue;\n};\n\nexport type JsonRpcError = {\n jsonrpc: \"2.0\";\n id: JsonRpcId;\n error: { code: number; message: string; data?: JsonValue };\n};\n\nexport type JsonRpcMessage = JsonRpcRequest | JsonRpcNotification | JsonRpcSuccess | JsonRpcError;\n\nexport const JSONRPC_PARSE_ERROR = -32700;\nexport const JSONRPC_INVALID_REQUEST = -32600;\nexport const JSONRPC_METHOD_NOT_FOUND = -32601;\nexport const JSONRPC_INVALID_PARAMS = -32602;\nexport const JSONRPC_INTERNAL_ERROR = -32603;\n\nexport type ServerCapabilities = {\n tools?: { listChanged?: boolean };\n resources?: { listChanged?: boolean; subscribe?: boolean };\n prompts?: { listChanged?: boolean };\n logging?: Record<string, never>;\n};\n\nexport type ServerInfo = {\n name: string;\n version: string;\n title?: string;\n};\n\nexport type InitializeResult = {\n protocolVersion: string;\n capabilities: ServerCapabilities;\n serverInfo: ServerInfo;\n instructions?: string;\n};\n\nexport type ToolInputSchema = {\n type: \"object\";\n properties?: Record<string, JsonValue>;\n required?: string[];\n additionalProperties?: boolean;\n};\n\nexport type ToolDefinition = {\n name: string;\n title?: string;\n description?: string;\n inputSchema: ToolInputSchema;\n};\n\nexport type ContentBlock =\n | { type: \"text\"; text: string }\n | { type: \"image\"; data: string; mimeType: string }\n | { type: \"resource\"; resource: { uri: string; text?: string; mimeType?: string } };\n\nexport type CallToolResult = {\n content: ContentBlock[];\n isError?: boolean;\n /** Structured tool output — non-spec but useful for typed bridges. */\n structuredContent?: JsonValue;\n};\n\n/** Handler signature for a tool registered on the MicroMcpServer. */\nexport type ToolHandler = (args: JsonObject) => Promise<CallToolResult> | CallToolResult;\n\n/** Internal record kept by the server. */\nexport type RegisteredTool = {\n definition: ToolDefinition;\n handler: ToolHandler;\n};\n\nexport const MCP_PROTOCOL_VERSION = \"2025-06-18\";\n","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\";\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 {\n private tools = new Map<string, RegisteredTool>();\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 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 registerTool(definition: ToolDefinition, handler: ToolHandler): () => void {\n this.tools.set(definition.name, { definition, handler });\n this.scheduleListChangedNotification();\n return () => this.unregisterTool(definition.name);\n }\n\n unregisterTool(name: string): void {\n if (this.tools.delete(name)) {\n this.scheduleListChangedNotification();\n }\n }\n\n listTools(): ToolDefinition[] {\n return Array.from(this.tools.values()).map((t) => t.definition);\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 { JsonRpcMessage } from \"../types\";\nimport type { MicroMcpServer, Transport } from \"../server\";\n\n/**\n * InProcessTransport — direct function-call wiring between an in-page MCP\n * client (e.g. an embedded chat agent) and a MicroMcpServer running in\n * the same JS context. No serialization, no network.\n *\n * Usage:\n *\n * const t = new InProcessTransport();\n * server.attach(t);\n * t.onServerMessage((msg) => { ... }); // client subscribes\n * t.send({ jsonrpc: \"2.0\", id: 1, method: \"tools/list\" }); // client → server\n */\nexport class InProcessTransport implements Transport {\n private server?: MicroMcpServer;\n private listeners = new Set<(msg: JsonRpcMessage) => void>();\n\n /** Bind to a server. Called from the client's setup, not directly. */\n bindServer(server: MicroMcpServer): void {\n this.server = server;\n }\n\n /** Server → client (delivered to subscribed listeners). */\n send(message: JsonRpcMessage): void {\n for (const l of this.listeners) l(message);\n }\n\n /** Client → server. Awaitable so callers can flush. */\n async deliver(message: JsonRpcMessage): Promise<void> {\n if (!this.server) throw new Error(\"InProcessTransport has no bound server\");\n await this.server.receive(this, message);\n }\n\n /** Subscribe to messages the server pushes to this client. */\n onServerMessage(listener: (msg: JsonRpcMessage) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n close(): void {\n this.listeners.clear();\n }\n}\n\n/**\n * Convenience: create a server-attached in-process transport in one call.\n */\nexport function attachInProcess(server: MicroMcpServer): InProcessTransport {\n const transport = new InProcessTransport();\n transport.bindServer(server);\n server.attach(transport);\n return transport;\n}\n","import type { JsonRpcMessage } from \"../types\";\nimport type { MicroMcpServer, Transport } from \"../server\";\n\n/**\n * RelayTransport — wraps any duplex JSON-frame channel (e.g. a Reverb\n * websocket private channel, a WebRTC data channel) so external agents\n * can talk to a browser-side MicroMcpServer.\n *\n * The host app owns the actual channel. This class only handles framing\n * (JSON.stringify / JSON.parse) and the server contract.\n *\n * Channel contract:\n * - host calls `transport.deliverFromRemote(payload)` with each frame\n * it receives from the remote agent\n * - host implements `sendToRemote(frame)` so the transport can deliver\n * server → client frames outward\n *\n * See docs/relay-protocol.md for the wire format.\n */\nexport type RelayChannel = {\n sendToRemote: (frame: JsonRpcMessage) => void;\n /** Optional: notify the channel that the server is gone. */\n onClose?: () => void;\n};\n\nexport class RelayTransport implements Transport {\n private server?: MicroMcpServer;\n constructor(private channel: RelayChannel) {}\n\n bindServer(server: MicroMcpServer): void {\n this.server = server;\n }\n\n send(message: JsonRpcMessage): void {\n this.channel.sendToRemote(message);\n }\n\n /**\n * Host calls this with each frame received from the remote agent. Accepts\n * either a parsed object or a raw JSON string.\n */\n async deliverFromRemote(payload: JsonRpcMessage | string): Promise<void> {\n if (!this.server) throw new Error(\"RelayTransport has no bound server\");\n const message = typeof payload === \"string\"\n ? (JSON.parse(payload) as JsonRpcMessage)\n : payload;\n await this.server.receive(this, message);\n }\n\n close(): void {\n this.channel.onClose?.();\n }\n}\n\n/**\n * Convenience wiring. Returns the bound transport.\n */\nexport function attachRelay(server: MicroMcpServer, channel: RelayChannel): RelayTransport {\n const transport = new RelayTransport(channel);\n transport.bindServer(server);\n server.attach(transport);\n return transport;\n}\n"]}
1
+ {"version":3,"sources":["../src/mcp/types.ts","../src/mcp/tool-host.ts","../src/mcp/server.ts","../src/mcp/transports/in-process.ts","../src/mcp/transports/relay.ts"],"names":[],"mappings":"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","file":"mcp.cjs","sourcesContent":["/**\n * Minimal MCP (Model Context Protocol) types — covers the subset this\n * package implements: initialize, tools/list, tools/call, plus JSON-RPC.\n *\n * Aligned with the public MCP spec but trimmed to v0.1 needs. See\n * https://spec.modelcontextprotocol.io/ for the full surface.\n */\n\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | { [key: string]: JsonValue }\n | JsonValue[];\n\nexport type JsonObject = { [key: string]: JsonValue };\n\nexport type JsonRpcId = string | number | null;\n\nexport type JsonRpcRequest = {\n jsonrpc: \"2.0\";\n id: JsonRpcId;\n method: string;\n params?: JsonObject;\n};\n\nexport type JsonRpcNotification = {\n jsonrpc: \"2.0\";\n method: string;\n params?: JsonObject;\n};\n\nexport type JsonRpcSuccess = {\n jsonrpc: \"2.0\";\n id: JsonRpcId;\n result: JsonValue;\n};\n\nexport type JsonRpcError = {\n jsonrpc: \"2.0\";\n id: JsonRpcId;\n error: { code: number; message: string; data?: JsonValue };\n};\n\nexport type JsonRpcMessage = JsonRpcRequest | JsonRpcNotification | JsonRpcSuccess | JsonRpcError;\n\nexport const JSONRPC_PARSE_ERROR = -32700;\nexport const JSONRPC_INVALID_REQUEST = -32600;\nexport const JSONRPC_METHOD_NOT_FOUND = -32601;\nexport const JSONRPC_INVALID_PARAMS = -32602;\nexport const JSONRPC_INTERNAL_ERROR = -32603;\n\nexport type ServerCapabilities = {\n tools?: { listChanged?: boolean };\n resources?: { listChanged?: boolean; subscribe?: boolean };\n prompts?: { listChanged?: boolean };\n logging?: Record<string, never>;\n};\n\nexport type ServerInfo = {\n name: string;\n version: string;\n title?: string;\n};\n\nexport type InitializeResult = {\n protocolVersion: string;\n capabilities: ServerCapabilities;\n serverInfo: ServerInfo;\n instructions?: string;\n};\n\nexport type ToolInputSchema = {\n type: \"object\";\n properties?: Record<string, JsonValue>;\n required?: string[];\n additionalProperties?: boolean;\n};\n\nexport type ToolDefinition = {\n name: string;\n title?: string;\n description?: string;\n inputSchema: ToolInputSchema;\n};\n\nexport type ContentBlock =\n | { type: \"text\"; text: string }\n | { type: \"image\"; data: string; mimeType: string }\n | { type: \"resource\"; resource: { uri: string; text?: string; mimeType?: string } };\n\nexport type CallToolResult = {\n content: ContentBlock[];\n isError?: boolean;\n /** Structured tool output — non-spec but useful for typed bridges. */\n structuredContent?: JsonValue;\n};\n\n/** Handler signature for a tool registered on the MicroMcpServer. */\nexport type ToolHandler = (args: JsonObject) => Promise<CallToolResult> | CallToolResult;\n\n/** Internal record kept by the server. */\nexport type RegisteredTool = {\n definition: ToolDefinition;\n handler: ToolHandler;\n};\n\nexport const MCP_PROTOCOL_VERSION = \"2025-06-18\";\n","import type {\n CallToolResult,\n JsonObject,\n RegisteredTool,\n ToolDefinition,\n ToolHandler,\n} from \"./types\";\n\n/**\n * ToolHost — the minimal surface a bridge needs to register its tools.\n *\n * Bridges (whiteboard, flow, sheets, code, charts, screens, scene, form)\n * speak only through this interface. The MCP server implements it\n * alongside its transport / JSON-RPC duties, and the standalone\n * {@link ToolRegistry} implements it for in-process agents that don't\n * need any of MCP's wire framing.\n *\n * Net effect: every bridge works equally well behind an MCP server\n * (browser ↔ external agents over SSE) or behind a plain registry\n * (in-process agent calling `host.callTool(\"sheet_set_cell\", { … })`).\n */\nexport interface ToolHost {\n /** Register a tool. Returns a disposer that unregisters it. */\n registerTool(definition: ToolDefinition, handler: ToolHandler): () => void;\n\n /** Look up an already-registered tool's definition + handler, or null. */\n getTool(name: string): RegisteredTool | null;\n\n /** Snapshot of all currently-registered tool definitions. */\n listTools(): ToolDefinition[];\n\n /**\n * Invoke a registered tool directly, bypassing any transport layer.\n * Throws if no tool is registered under `name`.\n *\n * This is the single entry point in-process agents use to drive the\n * surface — no JSON-RPC framing, no transport plumbing.\n */\n callTool(name: string, args?: JsonObject): Promise<CallToolResult>;\n}\n\n/**\n * Standalone in-memory ToolHost. Use this when no MCP server is needed —\n * e.g. an in-process agent that just wants to register the same bridges\n * and call them directly.\n *\n * Example:\n *\n * const host = new ToolRegistry();\n * registerSheetsBridge(host, { adapter });\n * const result = await host.callTool(\"sheet_set_cell\", { address: \"B3\", value: 42 });\n *\n * Pair with a MicroMcpServer in the same app to expose the same tools\n * to remote agents over SSE while in-process agents still get\n * zero-overhead direct calls.\n */\nexport class ToolRegistry implements ToolHost {\n protected readonly tools = new Map<string, RegisteredTool>();\n\n registerTool(definition: ToolDefinition, handler: ToolHandler): () => void {\n this.tools.set(definition.name, { definition, handler });\n this.onToolsChanged();\n return () => {\n if (this.tools.delete(definition.name)) this.onToolsChanged();\n };\n }\n\n getTool(name: string): RegisteredTool | null {\n return this.tools.get(name) ?? null;\n }\n\n listTools(): ToolDefinition[] {\n return Array.from(this.tools.values()).map((t) => t.definition);\n }\n\n async callTool(name: string, args: JsonObject = {}): Promise<CallToolResult> {\n const tool = this.tools.get(name);\n if (!tool) {\n throw new Error(`Unknown tool: ${name}`);\n }\n return tool.handler(args);\n }\n\n /**\n * Hook for subclasses (e.g. MicroMcpServer) to notify subscribers\n * when the tool catalog changes. Default no-op.\n */\n protected onToolsChanged(): void {}\n}\n","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 { JsonRpcMessage } from \"../types\";\nimport type { MicroMcpServer, Transport } from \"../server\";\n\n/**\n * InProcessTransport — direct function-call wiring between an in-page MCP\n * client (e.g. an embedded chat agent) and a MicroMcpServer running in\n * the same JS context. No serialization, no network.\n *\n * Usage:\n *\n * const t = new InProcessTransport();\n * server.attach(t);\n * t.onServerMessage((msg) => { ... }); // client subscribes\n * t.send({ jsonrpc: \"2.0\", id: 1, method: \"tools/list\" }); // client → server\n */\nexport class InProcessTransport implements Transport {\n private server?: MicroMcpServer;\n private listeners = new Set<(msg: JsonRpcMessage) => void>();\n\n /** Bind to a server. Called from the client's setup, not directly. */\n bindServer(server: MicroMcpServer): void {\n this.server = server;\n }\n\n /** Server → client (delivered to subscribed listeners). */\n send(message: JsonRpcMessage): void {\n for (const l of this.listeners) l(message);\n }\n\n /** Client → server. Awaitable so callers can flush. */\n async deliver(message: JsonRpcMessage): Promise<void> {\n if (!this.server) throw new Error(\"InProcessTransport has no bound server\");\n await this.server.receive(this, message);\n }\n\n /** Subscribe to messages the server pushes to this client. */\n onServerMessage(listener: (msg: JsonRpcMessage) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n close(): void {\n this.listeners.clear();\n }\n}\n\n/**\n * Convenience: create a server-attached in-process transport in one call.\n */\nexport function attachInProcess(server: MicroMcpServer): InProcessTransport {\n const transport = new InProcessTransport();\n transport.bindServer(server);\n server.attach(transport);\n return transport;\n}\n","import type { JsonRpcMessage } from \"../types\";\nimport type { MicroMcpServer, Transport } from \"../server\";\n\n/**\n * RelayTransport — wraps any duplex JSON-frame channel (e.g. a Reverb\n * websocket private channel, a WebRTC data channel) so external agents\n * can talk to a browser-side MicroMcpServer.\n *\n * The host app owns the actual channel. This class only handles framing\n * (JSON.stringify / JSON.parse) and the server contract.\n *\n * Channel contract:\n * - host calls `transport.deliverFromRemote(payload)` with each frame\n * it receives from the remote agent\n * - host implements `sendToRemote(frame)` so the transport can deliver\n * server → client frames outward\n *\n * See docs/relay-protocol.md for the wire format.\n */\nexport type RelayChannel = {\n sendToRemote: (frame: JsonRpcMessage) => void;\n /** Optional: notify the channel that the server is gone. */\n onClose?: () => void;\n};\n\nexport class RelayTransport implements Transport {\n private server?: MicroMcpServer;\n constructor(private channel: RelayChannel) {}\n\n bindServer(server: MicroMcpServer): void {\n this.server = server;\n }\n\n send(message: JsonRpcMessage): void {\n this.channel.sendToRemote(message);\n }\n\n /**\n * Host calls this with each frame received from the remote agent. Accepts\n * either a parsed object or a raw JSON string.\n */\n async deliverFromRemote(payload: JsonRpcMessage | string): Promise<void> {\n if (!this.server) throw new Error(\"RelayTransport has no bound server\");\n const message = typeof payload === \"string\"\n ? (JSON.parse(payload) as JsonRpcMessage)\n : payload;\n await this.server.receive(this, message);\n }\n\n close(): void {\n this.channel.onClose?.();\n }\n}\n\n/**\n * Convenience wiring. Returns the bound transport.\n */\nexport function attachRelay(server: MicroMcpServer, channel: RelayChannel): RelayTransport {\n const transport = new RelayTransport(channel);\n transport.bindServer(server);\n server.attach(transport);\n return transport;\n}\n"]}
package/dist/mcp.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export { InProcessTransport, RelayTransport, attachInProcess, attachRelay } from './chunk-6LTKCNLF.js';
2
- export { JSONRPC_INTERNAL_ERROR, JSONRPC_INVALID_PARAMS, JSONRPC_INVALID_REQUEST, JSONRPC_METHOD_NOT_FOUND, JSONRPC_PARSE_ERROR, MCP_PROTOCOL_VERSION, MicroMcpServer, errorResult, rpcError, textResult } from './chunk-QGCF7YKW.js';
2
+ export { JSONRPC_INTERNAL_ERROR, JSONRPC_INVALID_PARAMS, JSONRPC_INVALID_REQUEST, JSONRPC_METHOD_NOT_FOUND, JSONRPC_PARSE_ERROR, MCP_PROTOCOL_VERSION, MicroMcpServer, errorResult, rpcError, textResult } from './chunk-4KAIV6OD.js';
3
3
  //# sourceMappingURL=mcp.js.map
4
4
  //# sourceMappingURL=mcp.js.map
@@ -1,4 +1,4 @@
1
- import { C as CallToolResult } from '../types-DksGd5Y7.cjs';
1
+ import { C as CallToolResult } from '../types-aOQLTW0E.cjs';
2
2
 
3
3
  /**
4
4
  * Presence layer types — describe what the agent is doing right now and
@@ -1,4 +1,4 @@
1
- import { C as CallToolResult } from '../types-DksGd5Y7.js';
1
+ import { C as CallToolResult } from '../types-aOQLTW0E.js';
2
2
 
3
3
  /**
4
4
  * Presence layer types — describe what the agent is doing right now and
@@ -1,4 +1,5 @@
1
- import { S as ServerInfo, a as ServerCapabilities, J as JsonRpcMessage, T as ToolDefinition, b as ToolHandler, C as CallToolResult } from './types-DksGd5Y7.js';
1
+ import { S as ServerInfo, a as ServerCapabilities, J as JsonRpcMessage, C as CallToolResult } from './types-aOQLTW0E.cjs';
2
+ import { a as ToolRegistry } from './tool-host-BQuUygLF.cjs';
2
3
 
3
4
  type McpServerOptions = {
4
5
  info: ServerInfo;
@@ -27,8 +28,7 @@ type Transport = {
27
28
  * The same server can serve multiple transports (e.g. an in-process agent
28
29
  * AND a relayed external client) by attaching each one.
29
30
  */
30
- declare class MicroMcpServer {
31
- private tools;
31
+ declare class MicroMcpServer extends ToolRegistry {
32
32
  private transports;
33
33
  private notifyListChangedScheduled;
34
34
  readonly info: ServerInfo;
@@ -37,9 +37,8 @@ declare class MicroMcpServer {
37
37
  constructor(options: McpServerOptions);
38
38
  attach(transport: Transport): () => void;
39
39
  detach(transport: Transport): void;
40
- registerTool(definition: ToolDefinition, handler: ToolHandler): () => void;
41
40
  unregisterTool(name: string): void;
42
- listTools(): ToolDefinition[];
41
+ protected onToolsChanged(): void;
43
42
  /**
44
43
  * Receive a JSON-RPC frame from a client (called by the transport).
45
44
  * The transport is responsible for sending the response back.
@@ -1,4 +1,5 @@
1
- import { S as ServerInfo, a as ServerCapabilities, J as JsonRpcMessage, T as ToolDefinition, b as ToolHandler, C as CallToolResult } from './types-DksGd5Y7.cjs';
1
+ import { S as ServerInfo, a as ServerCapabilities, J as JsonRpcMessage, C as CallToolResult } from './types-aOQLTW0E.js';
2
+ import { a as ToolRegistry } from './tool-host-C8JMMGYq.js';
2
3
 
3
4
  type McpServerOptions = {
4
5
  info: ServerInfo;
@@ -27,8 +28,7 @@ type Transport = {
27
28
  * The same server can serve multiple transports (e.g. an in-process agent
28
29
  * AND a relayed external client) by attaching each one.
29
30
  */
30
- declare class MicroMcpServer {
31
- private tools;
31
+ declare class MicroMcpServer extends ToolRegistry {
32
32
  private transports;
33
33
  private notifyListChangedScheduled;
34
34
  readonly info: ServerInfo;
@@ -37,9 +37,8 @@ declare class MicroMcpServer {
37
37
  constructor(options: McpServerOptions);
38
38
  attach(transport: Transport): () => void;
39
39
  detach(transport: Transport): void;
40
- registerTool(definition: ToolDefinition, handler: ToolHandler): () => void;
41
40
  unregisterTool(name: string): void;
42
- listTools(): ToolDefinition[];
41
+ protected onToolsChanged(): void;
43
42
  /**
44
43
  * Receive a JSON-RPC frame from a client (called by the transport).
45
44
  * The transport is responsible for sending the response back.
@@ -1,5 +1,6 @@
1
- import { J as JsonRpcMessage } from '../types-DksGd5Y7.cjs';
2
- import { T as Transport, M as MicroMcpServer } from '../server-si-VvFxI.cjs';
1
+ import { J as JsonRpcMessage } from '../types-aOQLTW0E.cjs';
2
+ import { T as Transport, M as MicroMcpServer } from '../server-BsSwfemr.cjs';
3
+ import '../tool-host-BQuUygLF.cjs';
3
4
 
4
5
  /**
5
6
  * Session-token utilities. The token is a high-entropy secret; possession
@@ -1,5 +1,6 @@
1
- import { J as JsonRpcMessage } from '../types-DksGd5Y7.js';
2
- import { T as Transport, M as MicroMcpServer } from '../server-BJu_AMH3.js';
1
+ import { J as JsonRpcMessage } from '../types-aOQLTW0E.js';
2
+ import { T as Transport, M as MicroMcpServer } from '../server-Du3-IGqM.js';
3
+ import '../tool-host-C8JMMGYq.js';
3
4
 
4
5
  /**
5
6
  * Session-token utilities. The token is a high-entropy secret; possession
@@ -0,0 +1,96 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ // src/sheets-adapter.ts
6
+
7
+ // src/presence/registry.ts
8
+ var listeners = /* @__PURE__ */ new Set();
9
+ function onActivity(listener, filter) {
10
+ const wrapped = listener;
11
+ listeners.add(wrapped);
12
+ return () => listeners.delete(wrapped);
13
+ }
14
+
15
+ // src/sheets-adapter.ts
16
+ function useSheetsAdapter(initial, options = {}) {
17
+ const [workbook, setWorkbook] = react.useState(initial);
18
+ const [activeCell, setActiveCellState] = react.useState(null);
19
+ const workbookRef = react.useRef(workbook);
20
+ workbookRef.current = workbook;
21
+ const setActiveCell = react.useCallback((sheetId, address) => {
22
+ setWorkbook((cur) => cur.activeSheetId === sheetId ? cur : { ...cur, activeSheetId: sheetId });
23
+ setActiveCellState(address);
24
+ }, []);
25
+ const onActiveCellChange = react.useCallback((address) => {
26
+ setActiveCellState(address);
27
+ }, []);
28
+ const setWorkbookRef = react.useRef(setWorkbook);
29
+ setWorkbookRef.current = setWorkbook;
30
+ const adapter = react.useMemo(
31
+ () => ({
32
+ screenId: options.screenId,
33
+ getWorkbook: () => workbookRef.current,
34
+ setWorkbook: (next) => setWorkbookRef.current(next),
35
+ setActiveCell
36
+ }),
37
+ [options.screenId, setActiveCell]
38
+ );
39
+ return {
40
+ workbook,
41
+ setWorkbook,
42
+ onActiveCellChange,
43
+ adapter,
44
+ setActiveCell,
45
+ activeCell
46
+ };
47
+ }
48
+ function useSheetsActivityHighlights(options = {}) {
49
+ const ttlMs = options.ttlMs ?? 2200;
50
+ const screenId = options.screenId;
51
+ const [, force] = react.useState(0);
52
+ const hitsRef = react.useRef(/* @__PURE__ */ new Map());
53
+ react.useEffect(() => {
54
+ const off = onActivity((event) => {
55
+ if (event.target?.kind !== "sheet") return;
56
+ if (screenId && event.target.screenId && event.target.screenId !== screenId) return;
57
+ const elementId = event.target.elementId;
58
+ if (!elementId || !elementId.includes("!")) return;
59
+ hitsRef.current.set(elementId, { event, expiresAt: Date.now() + ttlMs });
60
+ force((n) => n + 1);
61
+ });
62
+ return off;
63
+ }, [screenId, ttlMs]);
64
+ react.useEffect(() => {
65
+ const t = window.setInterval(() => {
66
+ const now = Date.now();
67
+ let dirty = false;
68
+ for (const [k, v] of hitsRef.current) {
69
+ if (v.expiresAt < now) {
70
+ hitsRef.current.delete(k);
71
+ dirty = true;
72
+ }
73
+ }
74
+ if (dirty) force((n) => n + 1);
75
+ }, 500);
76
+ return () => window.clearInterval(t);
77
+ }, []);
78
+ const out = {};
79
+ for (const [elementId, { event }] of hitsRef.current) {
80
+ const idx = elementId.indexOf("!");
81
+ const address = elementId.slice(idx + 1);
82
+ if (!address) continue;
83
+ const color = event.agentColor ?? "#a855f7";
84
+ out[address] = {
85
+ color,
86
+ background: color + "33",
87
+ label: event.agentName ?? event.agentId ?? "agent"
88
+ };
89
+ }
90
+ return out;
91
+ }
92
+
93
+ exports.useSheetsActivityHighlights = useSheetsActivityHighlights;
94
+ exports.useSheetsAdapter = useSheetsAdapter;
95
+ //# sourceMappingURL=sheets-adapter.cjs.map
96
+ //# sourceMappingURL=sheets-adapter.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/presence/registry.ts","../src/sheets-adapter.ts"],"names":["useState","useRef","useCallback","useMemo","useEffect"],"mappings":"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","file":"sheets-adapter.cjs","sourcesContent":["import type { ActivityFilter, AgentActivityEvent, AgentActivityListener } from \"./types\";\n\n/**\n * In-process registry of agent activity events. Bridges call `emitActivity`\n * after a tool runs; React hooks + the SSE relay subscribe via\n * `onActivity()`.\n *\n * Holds a short scrollback of recent events (default 200) so newly-mounted\n * subscribers can render the recent past — useful for activity-log UIs\n * that rejoin a session mid-stream.\n */\n\nconst HISTORY_CAP = 200;\n\nconst listeners = new Set<AgentActivityListener>();\nconst history: AgentActivityEvent[] = [];\n\n/** Emit an activity event. All current listeners receive it synchronously. */\nexport function emitActivity(event: AgentActivityEvent): void {\n history.push(event);\n if (history.length > HISTORY_CAP) history.splice(0, history.length - HISTORY_CAP);\n for (const l of listeners) l(event);\n}\n\n/**\n * Subscribe to all events (or a filtered subset). Returns an unsubscribe\n * function. Filter checks all provided keys with strict equality; omit a\n * key to ignore it.\n */\nexport function onActivity(listener: AgentActivityListener, filter?: ActivityFilter): () => void {\n const wrapped: AgentActivityListener = filter\n ? (e) => { if (matches(e, filter)) listener(e); }\n : listener;\n listeners.add(wrapped);\n return () => listeners.delete(wrapped);\n}\n\n/** Read the recent history (newest last). Optional filter. */\nexport function readActivityHistory(filter?: ActivityFilter): AgentActivityEvent[] {\n if (!filter) return history.slice();\n return history.filter((e) => matches(e, filter));\n}\n\n/** Wipe history + clear listeners. Test/teardown helper. */\nexport function resetActivityRegistry(): void {\n listeners.clear();\n history.length = 0;\n}\n\nfunction matches(e: AgentActivityEvent, f: ActivityFilter): boolean {\n if (f.agentId !== undefined && e.agentId !== f.agentId) return false;\n if (f.screenId !== undefined && e.target.screenId !== f.screenId) return false;\n if (f.kind !== undefined && e.target.kind !== f.kind) return false;\n return true;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { SheetsBridgeAdapter } from \"./bridges/sheets\";\nimport { onActivity } from \"./presence/registry\";\nimport type { AgentActivityEvent } from \"./presence/types\";\n\n/**\n * Shared-session helpers for `@particle-academy/fancy-sheets`.\n *\n * fancy-sheets' `SheetWorkbook` is already controlled (`data` + `onChange`).\n * The two missing pieces for a clean shared-session experience are:\n *\n * 1. an adapter object the host can hand to {@link registerSheetsBridge}\n * without writing boilerplate, and\n * 2. a derived `CellHighlightMap` so agent edits visibly pulse on the\n * humans' screens — wired from the presence registry's per-bridge\n * activity stream.\n *\n * These are kept as host-side hooks (not part of the bridge itself) so\n * agent-integrations keeps zero hard deps on fancy-sheets. The host\n * imports SheetWorkbook directly and feeds these hooks' outputs into\n * its props.\n *\n * const wb = useSheetsAdapter(initial, { screenId: \"deal-sheet\" });\n * const highlights = useSheetsActivityHighlights({ screenId: \"deal-sheet\" });\n *\n * useEffect(() => {\n * const bridge = registerSheetsBridge(host, { adapter: wb.adapter });\n * return bridge.dispose;\n * }, [host, wb.adapter]);\n *\n * <SheetWorkbook\n * data={wb.workbook}\n * onChange={wb.setWorkbook}\n * highlights={highlights}\n * onActiveCellChange={wb.onActiveCellChange}\n * />\n */\n\n// Loose type mirror of fancy-sheets' WorkbookData — kept local so this\n// helper doesn't pull a runtime dep on the package. Apps using the helper\n// import the real `WorkbookData` from fancy-sheets and pass it through.\nexport type WorkbookLike = {\n sheets: Array<{ id: string; name: string; [k: string]: unknown }>;\n activeSheetId: string;\n};\n\nexport type SheetsAdapterOptions = {\n /** Tags the bridge's screen id so presence events route correctly. */\n screenId?: string;\n};\n\nexport type UseSheetsAdapterResult<W extends WorkbookLike> = {\n /** Controlled workbook state. Wire to `<SheetWorkbook data={…} />`. */\n workbook: W;\n /** Setter for the controlled state. Wire to `<SheetWorkbook onChange={…} />`. */\n setWorkbook: (next: W) => void;\n /** Wire to `<SheetWorkbook onActiveCellChange={…} />` to track focus. */\n onActiveCellChange: (address: string) => void;\n /** Stable adapter to hand to `registerSheetsBridge({ adapter })`. */\n adapter: SheetsBridgeAdapter;\n /** Imperative: set the active sheet + cell. Mirrors the adapter's hook. */\n setActiveCell: (sheetId: string, address: string) => void;\n /** Read-only: the address last focused (any source). */\n activeCell: string | null;\n};\n\n/**\n * useSheetsAdapter — one-liner glue between fancy-sheets' SheetWorkbook\n * and the sheets bridge.\n *\n * const wb = useSheetsAdapter(initialWorkbook, { screenId: \"...\" });\n *\n * useEffect(() => registerSheetsBridge(host, { adapter: wb.adapter }).dispose,\n * [host, wb.adapter]);\n *\n * <SheetWorkbook\n * data={wb.workbook}\n * onChange={wb.setWorkbook}\n * onActiveCellChange={wb.onActiveCellChange}\n * />\n */\nexport function useSheetsAdapter<W extends WorkbookLike>(\n initial: W,\n options: SheetsAdapterOptions = {},\n): UseSheetsAdapterResult<W> {\n const [workbook, setWorkbook] = useState<W>(initial);\n const [activeCell, setActiveCellState] = useState<string | null>(null);\n const workbookRef = useRef(workbook);\n workbookRef.current = workbook;\n\n const setActiveCell = useCallback((sheetId: string, address: string) => {\n setWorkbook((cur) => (cur.activeSheetId === sheetId ? cur : { ...cur, activeSheetId: sheetId }));\n setActiveCellState(address);\n }, []);\n\n const onActiveCellChange = useCallback((address: string) => {\n setActiveCellState(address);\n }, []);\n\n // Adapter must be stable across renders so the bridge's tool catalog\n // doesn't churn — bind it to refs that hold the latest state + setter.\n const setWorkbookRef = useRef(setWorkbook);\n setWorkbookRef.current = setWorkbook;\n\n const adapter = useMemo<SheetsBridgeAdapter>(\n () => ({\n screenId: options.screenId,\n getWorkbook: () => workbookRef.current as unknown as ReturnType<SheetsBridgeAdapter[\"getWorkbook\"]>,\n setWorkbook: (next) => setWorkbookRef.current(next as unknown as W),\n setActiveCell,\n }),\n [options.screenId, setActiveCell],\n );\n\n return {\n workbook,\n setWorkbook,\n onActiveCellChange,\n adapter,\n setActiveCell,\n activeCell,\n };\n}\n\n/**\n * Loose mirror of fancy-sheets' `CellHighlightMap`. Each key is a cell\n * address (`\"B12\"`); each value is the visual treatment to apply.\n */\nexport type SheetsCellHighlight = {\n color?: string;\n /** Background tint; if omitted, derived from `color` at low alpha. */\n background?: string;\n /** Optional label rendered in a chip on the cell. */\n label?: string;\n /** Optional className appended to the cell. */\n className?: string;\n};\n\nexport type SheetsCellHighlightMap = Record<string, SheetsCellHighlight>;\n\nexport type SheetsHighlightOptions = {\n /** Only include events for this screen (recommended). */\n screenId?: string;\n /** Highlight TTL in ms before a hit fades from the map. Default 2200. */\n ttlMs?: number;\n};\n\n/**\n * useSheetsActivityHighlights — subscribe to the presence registry,\n * produce a CellHighlightMap reflecting recent sheet-bridge activity.\n *\n * Pass the result straight into `<SheetWorkbook highlights={…} />`. Each\n * agent edit pulses in the agent's color for `ttlMs` then fades out.\n *\n * The bridge's target shape is `${sheetId}!${address}` — this hook\n * filters for the currently-active sheet and exposes only its cells.\n *\n * const highlights = useSheetsActivityHighlights({ screenId: \"deal-sheet\" });\n * <SheetWorkbook highlights={highlights} … />\n */\nexport function useSheetsActivityHighlights(\n options: SheetsHighlightOptions = {},\n): SheetsCellHighlightMap {\n const ttlMs = options.ttlMs ?? 2200;\n const screenId = options.screenId;\n const [, force] = useState(0);\n const hitsRef = useRef<\n Map<string, { event: AgentActivityEvent; expiresAt: number }>\n >(new Map());\n\n useEffect(() => {\n const off = onActivity((event) => {\n if (event.target?.kind !== \"sheet\") return;\n if (screenId && event.target.screenId && event.target.screenId !== screenId) return;\n const elementId = event.target.elementId;\n if (!elementId || !elementId.includes(\"!\")) return;\n hitsRef.current.set(elementId, { event, expiresAt: Date.now() + ttlMs });\n force((n) => n + 1);\n });\n return off;\n }, [screenId, ttlMs]);\n\n // Periodic GC — drop expired entries and force a re-render.\n useEffect(() => {\n const t = window.setInterval(() => {\n const now = Date.now();\n let dirty = false;\n for (const [k, v] of hitsRef.current) {\n if (v.expiresAt < now) {\n hitsRef.current.delete(k);\n dirty = true;\n }\n }\n if (dirty) force((n) => n + 1);\n }, 500);\n return () => window.clearInterval(t);\n }, []);\n\n // Re-derived on every render — the listener + GC timer above call\n // `force` so renders happen exactly when the map changes.\n const out: SheetsCellHighlightMap = {};\n for (const [elementId, { event }] of hitsRef.current) {\n const idx = elementId.indexOf(\"!\");\n const address = elementId.slice(idx + 1);\n if (!address) continue;\n const color = event.agentColor ?? \"#a855f7\";\n out[address] = {\n color,\n background: color + \"33\",\n label: event.agentName ?? event.agentId ?? \"agent\",\n };\n }\n return out;\n}\n"]}
@@ -0,0 +1,115 @@
1
+ import { SheetsBridgeAdapter } from './bridges/sheets.cjs';
2
+ import './tool-host-BQuUygLF.cjs';
3
+ import './types-aOQLTW0E.cjs';
4
+ import './types-CCSBGW9T.cjs';
5
+
6
+ /**
7
+ * Shared-session helpers for `@particle-academy/fancy-sheets`.
8
+ *
9
+ * fancy-sheets' `SheetWorkbook` is already controlled (`data` + `onChange`).
10
+ * The two missing pieces for a clean shared-session experience are:
11
+ *
12
+ * 1. an adapter object the host can hand to {@link registerSheetsBridge}
13
+ * without writing boilerplate, and
14
+ * 2. a derived `CellHighlightMap` so agent edits visibly pulse on the
15
+ * humans' screens — wired from the presence registry's per-bridge
16
+ * activity stream.
17
+ *
18
+ * These are kept as host-side hooks (not part of the bridge itself) so
19
+ * agent-integrations keeps zero hard deps on fancy-sheets. The host
20
+ * imports SheetWorkbook directly and feeds these hooks' outputs into
21
+ * its props.
22
+ *
23
+ * const wb = useSheetsAdapter(initial, { screenId: "deal-sheet" });
24
+ * const highlights = useSheetsActivityHighlights({ screenId: "deal-sheet" });
25
+ *
26
+ * useEffect(() => {
27
+ * const bridge = registerSheetsBridge(host, { adapter: wb.adapter });
28
+ * return bridge.dispose;
29
+ * }, [host, wb.adapter]);
30
+ *
31
+ * <SheetWorkbook
32
+ * data={wb.workbook}
33
+ * onChange={wb.setWorkbook}
34
+ * highlights={highlights}
35
+ * onActiveCellChange={wb.onActiveCellChange}
36
+ * />
37
+ */
38
+ type WorkbookLike = {
39
+ sheets: Array<{
40
+ id: string;
41
+ name: string;
42
+ [k: string]: unknown;
43
+ }>;
44
+ activeSheetId: string;
45
+ };
46
+ type SheetsAdapterOptions = {
47
+ /** Tags the bridge's screen id so presence events route correctly. */
48
+ screenId?: string;
49
+ };
50
+ type UseSheetsAdapterResult<W extends WorkbookLike> = {
51
+ /** Controlled workbook state. Wire to `<SheetWorkbook data={…} />`. */
52
+ workbook: W;
53
+ /** Setter for the controlled state. Wire to `<SheetWorkbook onChange={…} />`. */
54
+ setWorkbook: (next: W) => void;
55
+ /** Wire to `<SheetWorkbook onActiveCellChange={…} />` to track focus. */
56
+ onActiveCellChange: (address: string) => void;
57
+ /** Stable adapter to hand to `registerSheetsBridge({ adapter })`. */
58
+ adapter: SheetsBridgeAdapter;
59
+ /** Imperative: set the active sheet + cell. Mirrors the adapter's hook. */
60
+ setActiveCell: (sheetId: string, address: string) => void;
61
+ /** Read-only: the address last focused (any source). */
62
+ activeCell: string | null;
63
+ };
64
+ /**
65
+ * useSheetsAdapter — one-liner glue between fancy-sheets' SheetWorkbook
66
+ * and the sheets bridge.
67
+ *
68
+ * const wb = useSheetsAdapter(initialWorkbook, { screenId: "..." });
69
+ *
70
+ * useEffect(() => registerSheetsBridge(host, { adapter: wb.adapter }).dispose,
71
+ * [host, wb.adapter]);
72
+ *
73
+ * <SheetWorkbook
74
+ * data={wb.workbook}
75
+ * onChange={wb.setWorkbook}
76
+ * onActiveCellChange={wb.onActiveCellChange}
77
+ * />
78
+ */
79
+ declare function useSheetsAdapter<W extends WorkbookLike>(initial: W, options?: SheetsAdapterOptions): UseSheetsAdapterResult<W>;
80
+ /**
81
+ * Loose mirror of fancy-sheets' `CellHighlightMap`. Each key is a cell
82
+ * address (`"B12"`); each value is the visual treatment to apply.
83
+ */
84
+ type SheetsCellHighlight = {
85
+ color?: string;
86
+ /** Background tint; if omitted, derived from `color` at low alpha. */
87
+ background?: string;
88
+ /** Optional label rendered in a chip on the cell. */
89
+ label?: string;
90
+ /** Optional className appended to the cell. */
91
+ className?: string;
92
+ };
93
+ type SheetsCellHighlightMap = Record<string, SheetsCellHighlight>;
94
+ type SheetsHighlightOptions = {
95
+ /** Only include events for this screen (recommended). */
96
+ screenId?: string;
97
+ /** Highlight TTL in ms before a hit fades from the map. Default 2200. */
98
+ ttlMs?: number;
99
+ };
100
+ /**
101
+ * useSheetsActivityHighlights — subscribe to the presence registry,
102
+ * produce a CellHighlightMap reflecting recent sheet-bridge activity.
103
+ *
104
+ * Pass the result straight into `<SheetWorkbook highlights={…} />`. Each
105
+ * agent edit pulses in the agent's color for `ttlMs` then fades out.
106
+ *
107
+ * The bridge's target shape is `${sheetId}!${address}` — this hook
108
+ * filters for the currently-active sheet and exposes only its cells.
109
+ *
110
+ * const highlights = useSheetsActivityHighlights({ screenId: "deal-sheet" });
111
+ * <SheetWorkbook highlights={highlights} … />
112
+ */
113
+ declare function useSheetsActivityHighlights(options?: SheetsHighlightOptions): SheetsCellHighlightMap;
114
+
115
+ export { type SheetsAdapterOptions, type SheetsCellHighlight, type SheetsCellHighlightMap, type SheetsHighlightOptions, type UseSheetsAdapterResult, type WorkbookLike, useSheetsActivityHighlights, useSheetsAdapter };
@@ -0,0 +1,115 @@
1
+ import { SheetsBridgeAdapter } from './bridges/sheets.js';
2
+ import './tool-host-C8JMMGYq.js';
3
+ import './types-aOQLTW0E.js';
4
+ import './types-DIVNcIQO.js';
5
+
6
+ /**
7
+ * Shared-session helpers for `@particle-academy/fancy-sheets`.
8
+ *
9
+ * fancy-sheets' `SheetWorkbook` is already controlled (`data` + `onChange`).
10
+ * The two missing pieces for a clean shared-session experience are:
11
+ *
12
+ * 1. an adapter object the host can hand to {@link registerSheetsBridge}
13
+ * without writing boilerplate, and
14
+ * 2. a derived `CellHighlightMap` so agent edits visibly pulse on the
15
+ * humans' screens — wired from the presence registry's per-bridge
16
+ * activity stream.
17
+ *
18
+ * These are kept as host-side hooks (not part of the bridge itself) so
19
+ * agent-integrations keeps zero hard deps on fancy-sheets. The host
20
+ * imports SheetWorkbook directly and feeds these hooks' outputs into
21
+ * its props.
22
+ *
23
+ * const wb = useSheetsAdapter(initial, { screenId: "deal-sheet" });
24
+ * const highlights = useSheetsActivityHighlights({ screenId: "deal-sheet" });
25
+ *
26
+ * useEffect(() => {
27
+ * const bridge = registerSheetsBridge(host, { adapter: wb.adapter });
28
+ * return bridge.dispose;
29
+ * }, [host, wb.adapter]);
30
+ *
31
+ * <SheetWorkbook
32
+ * data={wb.workbook}
33
+ * onChange={wb.setWorkbook}
34
+ * highlights={highlights}
35
+ * onActiveCellChange={wb.onActiveCellChange}
36
+ * />
37
+ */
38
+ type WorkbookLike = {
39
+ sheets: Array<{
40
+ id: string;
41
+ name: string;
42
+ [k: string]: unknown;
43
+ }>;
44
+ activeSheetId: string;
45
+ };
46
+ type SheetsAdapterOptions = {
47
+ /** Tags the bridge's screen id so presence events route correctly. */
48
+ screenId?: string;
49
+ };
50
+ type UseSheetsAdapterResult<W extends WorkbookLike> = {
51
+ /** Controlled workbook state. Wire to `<SheetWorkbook data={…} />`. */
52
+ workbook: W;
53
+ /** Setter for the controlled state. Wire to `<SheetWorkbook onChange={…} />`. */
54
+ setWorkbook: (next: W) => void;
55
+ /** Wire to `<SheetWorkbook onActiveCellChange={…} />` to track focus. */
56
+ onActiveCellChange: (address: string) => void;
57
+ /** Stable adapter to hand to `registerSheetsBridge({ adapter })`. */
58
+ adapter: SheetsBridgeAdapter;
59
+ /** Imperative: set the active sheet + cell. Mirrors the adapter's hook. */
60
+ setActiveCell: (sheetId: string, address: string) => void;
61
+ /** Read-only: the address last focused (any source). */
62
+ activeCell: string | null;
63
+ };
64
+ /**
65
+ * useSheetsAdapter — one-liner glue between fancy-sheets' SheetWorkbook
66
+ * and the sheets bridge.
67
+ *
68
+ * const wb = useSheetsAdapter(initialWorkbook, { screenId: "..." });
69
+ *
70
+ * useEffect(() => registerSheetsBridge(host, { adapter: wb.adapter }).dispose,
71
+ * [host, wb.adapter]);
72
+ *
73
+ * <SheetWorkbook
74
+ * data={wb.workbook}
75
+ * onChange={wb.setWorkbook}
76
+ * onActiveCellChange={wb.onActiveCellChange}
77
+ * />
78
+ */
79
+ declare function useSheetsAdapter<W extends WorkbookLike>(initial: W, options?: SheetsAdapterOptions): UseSheetsAdapterResult<W>;
80
+ /**
81
+ * Loose mirror of fancy-sheets' `CellHighlightMap`. Each key is a cell
82
+ * address (`"B12"`); each value is the visual treatment to apply.
83
+ */
84
+ type SheetsCellHighlight = {
85
+ color?: string;
86
+ /** Background tint; if omitted, derived from `color` at low alpha. */
87
+ background?: string;
88
+ /** Optional label rendered in a chip on the cell. */
89
+ label?: string;
90
+ /** Optional className appended to the cell. */
91
+ className?: string;
92
+ };
93
+ type SheetsCellHighlightMap = Record<string, SheetsCellHighlight>;
94
+ type SheetsHighlightOptions = {
95
+ /** Only include events for this screen (recommended). */
96
+ screenId?: string;
97
+ /** Highlight TTL in ms before a hit fades from the map. Default 2200. */
98
+ ttlMs?: number;
99
+ };
100
+ /**
101
+ * useSheetsActivityHighlights — subscribe to the presence registry,
102
+ * produce a CellHighlightMap reflecting recent sheet-bridge activity.
103
+ *
104
+ * Pass the result straight into `<SheetWorkbook highlights={…} />`. Each
105
+ * agent edit pulses in the agent's color for `ttlMs` then fades out.
106
+ *
107
+ * The bridge's target shape is `${sheetId}!${address}` — this hook
108
+ * filters for the currently-active sheet and exposes only its cells.
109
+ *
110
+ * const highlights = useSheetsActivityHighlights({ screenId: "deal-sheet" });
111
+ * <SheetWorkbook highlights={highlights} … />
112
+ */
113
+ declare function useSheetsActivityHighlights(options?: SheetsHighlightOptions): SheetsCellHighlightMap;
114
+
115
+ export { type SheetsAdapterOptions, type SheetsCellHighlight, type SheetsCellHighlightMap, type SheetsHighlightOptions, type UseSheetsAdapterResult, type WorkbookLike, useSheetsActivityHighlights, useSheetsAdapter };
@@ -0,0 +1,4 @@
1
+ export { useSheetsActivityHighlights, useSheetsAdapter } from './chunk-E4AICMFZ.js';
2
+ import './chunk-JU2N4KK6.js';
3
+ //# sourceMappingURL=sheets-adapter.js.map
4
+ //# sourceMappingURL=sheets-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"sheets-adapter.js"}
@@ -0,0 +1,60 @@
1
+ import { T as ToolDefinition, b as ToolHandler, R as RegisteredTool, c as JsonObject, C as CallToolResult } from './types-aOQLTW0E.cjs';
2
+
3
+ /**
4
+ * ToolHost — the minimal surface a bridge needs to register its tools.
5
+ *
6
+ * Bridges (whiteboard, flow, sheets, code, charts, screens, scene, form)
7
+ * speak only through this interface. The MCP server implements it
8
+ * alongside its transport / JSON-RPC duties, and the standalone
9
+ * {@link ToolRegistry} implements it for in-process agents that don't
10
+ * need any of MCP's wire framing.
11
+ *
12
+ * Net effect: every bridge works equally well behind an MCP server
13
+ * (browser ↔ external agents over SSE) or behind a plain registry
14
+ * (in-process agent calling `host.callTool("sheet_set_cell", { … })`).
15
+ */
16
+ interface ToolHost {
17
+ /** Register a tool. Returns a disposer that unregisters it. */
18
+ registerTool(definition: ToolDefinition, handler: ToolHandler): () => void;
19
+ /** Look up an already-registered tool's definition + handler, or null. */
20
+ getTool(name: string): RegisteredTool | null;
21
+ /** Snapshot of all currently-registered tool definitions. */
22
+ listTools(): ToolDefinition[];
23
+ /**
24
+ * Invoke a registered tool directly, bypassing any transport layer.
25
+ * Throws if no tool is registered under `name`.
26
+ *
27
+ * This is the single entry point in-process agents use to drive the
28
+ * surface — no JSON-RPC framing, no transport plumbing.
29
+ */
30
+ callTool(name: string, args?: JsonObject): Promise<CallToolResult>;
31
+ }
32
+ /**
33
+ * Standalone in-memory ToolHost. Use this when no MCP server is needed —
34
+ * e.g. an in-process agent that just wants to register the same bridges
35
+ * and call them directly.
36
+ *
37
+ * Example:
38
+ *
39
+ * const host = new ToolRegistry();
40
+ * registerSheetsBridge(host, { adapter });
41
+ * const result = await host.callTool("sheet_set_cell", { address: "B3", value: 42 });
42
+ *
43
+ * Pair with a MicroMcpServer in the same app to expose the same tools
44
+ * to remote agents over SSE while in-process agents still get
45
+ * zero-overhead direct calls.
46
+ */
47
+ declare class ToolRegistry implements ToolHost {
48
+ protected readonly tools: Map<string, RegisteredTool>;
49
+ registerTool(definition: ToolDefinition, handler: ToolHandler): () => void;
50
+ getTool(name: string): RegisteredTool | null;
51
+ listTools(): ToolDefinition[];
52
+ callTool(name: string, args?: JsonObject): Promise<CallToolResult>;
53
+ /**
54
+ * Hook for subclasses (e.g. MicroMcpServer) to notify subscribers
55
+ * when the tool catalog changes. Default no-op.
56
+ */
57
+ protected onToolsChanged(): void;
58
+ }
59
+
60
+ export { type ToolHost as T, ToolRegistry as a };