@particle-academy/agent-integrations 0.3.4 → 0.5.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.
- package/README.md +65 -0
- package/dist/bridges/charts.d.cts +4 -4
- package/dist/bridges/charts.d.ts +4 -4
- package/dist/bridges/code.d.cts +4 -4
- package/dist/bridges/code.d.ts +4 -4
- package/dist/bridges/flow.d.cts +4 -4
- package/dist/bridges/flow.d.ts +4 -4
- package/dist/bridges/forms.d.cts +4 -4
- package/dist/bridges/forms.d.ts +4 -4
- package/dist/bridges/scene.d.cts +4 -4
- package/dist/bridges/scene.d.ts +4 -4
- package/dist/bridges/screens.d.cts +78 -0
- package/dist/bridges/screens.d.ts +78 -0
- package/dist/bridges/sheets.d.cts +4 -4
- package/dist/bridges/sheets.d.ts +4 -4
- package/dist/bridges/whiteboard.d.cts +4 -4
- package/dist/bridges/whiteboard.d.ts +4 -4
- package/dist/bridges-charts.cjs +2 -2
- package/dist/bridges-charts.cjs.map +1 -1
- package/dist/bridges-charts.js +2 -2
- package/dist/bridges-code.cjs +2 -2
- package/dist/bridges-code.cjs.map +1 -1
- package/dist/bridges-code.js +2 -2
- package/dist/bridges-flow.cjs +2 -2
- package/dist/bridges-flow.cjs.map +1 -1
- package/dist/bridges-flow.js +340 -3
- package/dist/bridges-flow.js.map +1 -1
- package/dist/bridges-forms.cjs +2 -2
- package/dist/bridges-forms.cjs.map +1 -1
- package/dist/bridges-forms.js +2 -2
- package/dist/bridges-scene.cjs +2 -2
- package/dist/bridges-scene.cjs.map +1 -1
- package/dist/bridges-scene.js +2 -2
- package/dist/bridges-screens.cjs +227 -0
- package/dist/bridges-screens.cjs.map +1 -0
- package/dist/bridges-screens.js +6 -0
- package/dist/bridges-screens.js.map +1 -0
- package/dist/bridges-sheets.cjs +2 -2
- package/dist/bridges-sheets.cjs.map +1 -1
- package/dist/bridges-sheets.js +2 -2
- package/dist/bridges-whiteboard.cjs +12 -12
- package/dist/bridges-whiteboard.cjs.map +1 -1
- package/dist/bridges-whiteboard.js +3 -3
- package/dist/{chunk-TBEITXF4.js → chunk-3KSZNGNW.js} +7 -7
- package/dist/chunk-3KSZNGNW.js.map +1 -0
- package/dist/{chunk-OEIULP2L.js → chunk-4BL5M3U3.js} +5 -5
- package/dist/chunk-4BL5M3U3.js.map +1 -0
- package/dist/{chunk-QGCF7YKW.js → chunk-4KAIV6OD.js} +40 -12
- package/dist/chunk-4KAIV6OD.js.map +1 -0
- package/dist/chunk-57ZDHD53.js +180 -0
- package/dist/chunk-57ZDHD53.js.map +1 -0
- package/dist/chunk-5XELJIJR.js +83 -0
- package/dist/chunk-5XELJIJR.js.map +1 -0
- package/dist/{chunk-6LTKCNLF.js → chunk-AFUULW5E.js} +3 -34
- package/dist/chunk-AFUULW5E.js.map +1 -0
- package/dist/chunk-G6N2TQVO.js +34 -0
- package/dist/chunk-G6N2TQVO.js.map +1 -0
- package/dist/{chunk-ACBENYYO.js → chunk-GQ7XXK7G.js} +12 -12
- package/dist/chunk-GQ7XXK7G.js.map +1 -0
- package/dist/{chunk-XYYSTJHW.js → chunk-HSTW7ZNO.js} +5 -5
- package/dist/chunk-HSTW7ZNO.js.map +1 -0
- package/dist/{chunk-PDBF4W7E.js → chunk-IANI25IT.js} +5 -5
- package/dist/chunk-IANI25IT.js.map +1 -0
- package/dist/chunk-IJ6JX5VC.js +3 -0
- package/dist/chunk-IJ6JX5VC.js.map +1 -0
- package/dist/{chunk-JMYPUAFH.js → chunk-LVQXIUJH.js} +2 -2
- package/dist/{chunk-JMYPUAFH.js.map → chunk-LVQXIUJH.js.map} +1 -1
- package/dist/{chunk-PHPXKSWI.js → chunk-NTDZWGYB.js} +5 -5
- package/dist/chunk-NTDZWGYB.js.map +1 -0
- package/dist/{chunk-DJOWMF6Q.js → chunk-RGO42EQ6.js} +3 -3
- package/dist/{chunk-DJOWMF6Q.js.map → chunk-RGO42EQ6.js.map} +1 -1
- package/dist/{chunk-QJUTISFC.js → chunk-XRAJSOPS.js} +5 -5
- package/dist/chunk-XRAJSOPS.js.map +1 -0
- package/dist/chunk-ZHAK2DQR.js +289 -0
- package/dist/chunk-ZHAK2DQR.js.map +1 -0
- package/dist/components/SharedWhiteboard/index.d.cts +55 -0
- package/dist/components/SharedWhiteboard/index.d.ts +55 -0
- package/dist/components-shared-whiteboard.cjs +1533 -0
- package/dist/components-shared-whiteboard.cjs.map +1 -0
- package/dist/components-shared-whiteboard.js +285 -0
- package/dist/components-shared-whiteboard.js.map +1 -0
- package/dist/index.cjs +618 -1371
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -59
- package/dist/index.d.ts +11 -59
- package/dist/index.js +19 -571
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.cts +5 -4
- package/dist/mcp/index.d.ts +5 -4
- package/dist/mcp.cjs +37 -9
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.js +3 -2
- package/dist/presence/index.d.cts +1 -1
- package/dist/presence/index.d.ts +1 -1
- package/dist/{server-BJu_AMH3.d.ts → server-BsSwfemr.d.cts} +4 -5
- package/dist/{server-si-VvFxI.d.cts → server-Du3-IGqM.d.ts} +4 -5
- package/dist/sharing/index.d.cts +5 -36
- package/dist/sharing/index.d.ts +5 -36
- package/dist/sharing.js +2 -1
- package/dist/sheets-adapter.cjs +96 -0
- package/dist/sheets-adapter.cjs.map +1 -0
- package/dist/sheets-adapter.d.cts +119 -0
- package/dist/sheets-adapter.d.ts +119 -0
- package/dist/sheets-adapter.js +4 -0
- package/dist/sheets-adapter.js.map +1 -0
- package/dist/token-CrJF76oH.d.cts +34 -0
- package/dist/token-CrJF76oH.d.ts +34 -0
- package/dist/tool-host-BQuUygLF.d.cts +60 -0
- package/dist/tool-host-C8JMMGYq.d.ts +60 -0
- package/dist/{types-DXKpLuia.d.ts → types-CCSBGW9T.d.cts} +2 -2
- package/dist/{types-Bf1ZoGmI.d.cts → types-DIVNcIQO.d.ts} +2 -2
- package/dist/{types-DksGd5Y7.d.cts → types-aOQLTW0E.d.cts} +1 -1
- package/dist/{types-DksGd5Y7.d.ts → types-aOQLTW0E.d.ts} +1 -1
- package/dist/undo/index.d.cts +4 -4
- package/dist/undo/index.d.ts +4 -4
- package/dist/undo.cjs +9 -9
- package/dist/undo.cjs.map +1 -1
- package/dist/undo.js +3 -3
- package/package.json +57 -7
- package/dist/chunk-4IAVAFUV.js +0 -342
- package/dist/chunk-4IAVAFUV.js.map +0 -1
- package/dist/chunk-6LTKCNLF.js.map +0 -1
- package/dist/chunk-ACBENYYO.js.map +0 -1
- package/dist/chunk-OEIULP2L.js.map +0 -1
- package/dist/chunk-PDBF4W7E.js.map +0 -1
- package/dist/chunk-PHPXKSWI.js.map +0 -1
- package/dist/chunk-QGCF7YKW.js.map +0 -1
- package/dist/chunk-QJUTISFC.js.map +0 -1
- package/dist/chunk-TBEITXF4.js.map +0 -1
- package/dist/chunk-XYYSTJHW.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sheets-adapter.ts"],"names":[],"mappings":"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","file":"chunk-5XELJIJR.js","sourcesContent":["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 structural mirror of fancy-sheets' WorkbookData — kept local so\n// this helper doesn't pull a runtime dep on the package. The constraint\n// only names the fields the hook itself reads (`sheets` + `activeSheetId`);\n// it does NOT add a `[k: string]: unknown` index signature, so consumers\n// can pass the real `WorkbookData` from fancy-sheets through without\n// triggering an \"index signature missing\" error.\nexport type WorkbookLike = {\n sheets: Array<{ id: string; name: string }>;\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 * Mirror of fancy-sheets' `CellHighlight` — structurally identical so the\n * map returned from {@link useSheetsActivityHighlights} can be passed\n * straight into `<SheetWorkbook highlights={…} />` without any casts.\n *\n * Fields match `@particle-academy/fancy-sheets` exactly:\n * - `color: string` (required) — border/outline color\n * - `backgroundColor?: string` — auto-derived from `color` if omitted\n * - `label?: string` — small badge in the cell's top-left corner\n */\nexport type SheetsCellHighlight = {\n /** Border/outline color (any CSS color value). Required. */\n color: string;\n /** Background tint; if omitted, derived from `color` at low alpha. */\n backgroundColor?: string;\n /** Optional label rendered in a chip on the cell. */\n label?: 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 backgroundColor: color + \"33\",\n label: event.agentName ?? event.agentId ?? \"agent\",\n };\n }\n return out;\n}\n"]}
|
|
@@ -32,37 +32,6 @@ function attachInProcess(server) {
|
|
|
32
32
|
return transport;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
this.channel = channel;
|
|
39
|
-
}
|
|
40
|
-
bindServer(server) {
|
|
41
|
-
this.server = server;
|
|
42
|
-
}
|
|
43
|
-
send(message) {
|
|
44
|
-
this.channel.sendToRemote(message);
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Host calls this with each frame received from the remote agent. Accepts
|
|
48
|
-
* either a parsed object or a raw JSON string.
|
|
49
|
-
*/
|
|
50
|
-
async deliverFromRemote(payload) {
|
|
51
|
-
if (!this.server) throw new Error("RelayTransport has no bound server");
|
|
52
|
-
const message = typeof payload === "string" ? JSON.parse(payload) : payload;
|
|
53
|
-
await this.server.receive(this, message);
|
|
54
|
-
}
|
|
55
|
-
close() {
|
|
56
|
-
this.channel.onClose?.();
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
function attachRelay(server, channel) {
|
|
60
|
-
const transport = new RelayTransport(channel);
|
|
61
|
-
transport.bindServer(server);
|
|
62
|
-
server.attach(transport);
|
|
63
|
-
return transport;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export { InProcessTransport, RelayTransport, attachInProcess, attachRelay };
|
|
67
|
-
//# sourceMappingURL=chunk-6LTKCNLF.js.map
|
|
68
|
-
//# sourceMappingURL=chunk-6LTKCNLF.js.map
|
|
35
|
+
export { InProcessTransport, attachInProcess };
|
|
36
|
+
//# sourceMappingURL=chunk-AFUULW5E.js.map
|
|
37
|
+
//# sourceMappingURL=chunk-AFUULW5E.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp/transports/in-process.ts"],"names":[],"mappings":";AAeO,IAAM,qBAAN,MAA8C;AAAA,EAA9C,WAAA,GAAA;AAEL,IAAA,IAAA,CAAQ,SAAA,uBAAgB,GAAA,EAAmC;AAAA,EAAA;AAAA;AAAA,EAG3D,WAAW,MAAA,EAA8B;AACvC,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA;AAAA,EAGA,KAAK,OAAA,EAA+B;AAClC,IAAA,KAAA,MAAW,CAAA,IAAK,IAAA,CAAK,SAAA,EAAW,CAAA,CAAE,OAAO,CAAA;AAAA,EAC3C;AAAA;AAAA,EAGA,MAAM,QAAQ,OAAA,EAAwC;AACpD,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,EAAQ,MAAM,IAAI,MAAM,wCAAwC,CAAA;AAC1E,IAAA,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA;AAAA,EACzC;AAAA;AAAA,EAGA,gBAAgB,QAAA,EAAqD;AACnE,IAAA,IAAA,CAAK,SAAA,CAAU,IAAI,QAAQ,CAAA;AAC3B,IAAA,OAAO,MAAM,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,QAAQ,CAAA;AAAA,EAC7C;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,UAAU,KAAA,EAAM;AAAA,EACvB;AACF;AAKO,SAAS,gBAAgB,MAAA,EAA4C;AAC1E,EAAA,MAAM,SAAA,GAAY,IAAI,kBAAA,EAAmB;AACzC,EAAA,SAAA,CAAU,WAAW,MAAM,CAAA;AAC3B,EAAA,MAAA,CAAO,OAAO,SAAS,CAAA;AACvB,EAAA,OAAO,SAAA;AACT","file":"chunk-AFUULW5E.js","sourcesContent":["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"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// src/mcp/transports/relay.ts
|
|
2
|
+
var RelayTransport = class {
|
|
3
|
+
constructor(channel) {
|
|
4
|
+
this.channel = channel;
|
|
5
|
+
}
|
|
6
|
+
bindServer(server) {
|
|
7
|
+
this.server = server;
|
|
8
|
+
}
|
|
9
|
+
send(message) {
|
|
10
|
+
this.channel.sendToRemote(message);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Host calls this with each frame received from the remote agent. Accepts
|
|
14
|
+
* either a parsed object or a raw JSON string.
|
|
15
|
+
*/
|
|
16
|
+
async deliverFromRemote(payload) {
|
|
17
|
+
if (!this.server) throw new Error("RelayTransport has no bound server");
|
|
18
|
+
const message = typeof payload === "string" ? JSON.parse(payload) : payload;
|
|
19
|
+
await this.server.receive(this, message);
|
|
20
|
+
}
|
|
21
|
+
close() {
|
|
22
|
+
this.channel.onClose?.();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
function attachRelay(server, channel) {
|
|
26
|
+
const transport = new RelayTransport(channel);
|
|
27
|
+
transport.bindServer(server);
|
|
28
|
+
server.attach(transport);
|
|
29
|
+
return transport;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { RelayTransport, attachRelay };
|
|
33
|
+
//# sourceMappingURL=chunk-G6N2TQVO.js.map
|
|
34
|
+
//# sourceMappingURL=chunk-G6N2TQVO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp/transports/relay.ts"],"names":[],"mappings":";AAyBO,IAAM,iBAAN,MAA0C;AAAA,EAE/C,YAAoB,OAAA,EAAuB;AAAvB,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAAwB;AAAA,EAE5C,WAAW,MAAA,EAA8B;AACvC,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA,EAEA,KAAK,OAAA,EAA+B;AAClC,IAAA,IAAA,CAAK,OAAA,CAAQ,aAAa,OAAO,CAAA;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,kBAAkB,OAAA,EAAiD;AACvE,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,EAAQ,MAAM,IAAI,MAAM,oCAAoC,CAAA;AACtE,IAAA,MAAM,UAAU,OAAO,OAAA,KAAY,WAC9B,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA,GACnB,OAAA;AACJ,IAAA,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA;AAAA,EACzC;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,QAAQ,OAAA,IAAU;AAAA,EACzB;AACF;AAKO,SAAS,WAAA,CAAY,QAAwB,OAAA,EAAuC;AACzF,EAAA,MAAM,SAAA,GAAY,IAAI,cAAA,CAAe,OAAO,CAAA;AAC5C,EAAA,SAAA,CAAU,WAAW,MAAM,CAAA;AAC3B,EAAA,MAAA,CAAO,OAAO,SAAS,CAAA;AACvB,EAAA,OAAO,SAAA;AACT","file":"chunk-G6N2TQVO.js","sourcesContent":["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,4 +1,4 @@
|
|
|
1
|
-
import { errorResult, textResult } from './chunk-
|
|
1
|
+
import { errorResult, textResult } from './chunk-4KAIV6OD.js';
|
|
2
2
|
|
|
3
3
|
// src/undo/undo-stack.ts
|
|
4
4
|
var stacks = /* @__PURE__ */ new Map();
|
|
@@ -44,18 +44,18 @@ function resetAllUndoStacks() {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// src/undo/undo-tools.ts
|
|
47
|
-
var
|
|
48
|
-
function ensureUndoToolsRegistered(
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
registerUndoTools(
|
|
47
|
+
var installedHosts = /* @__PURE__ */ new WeakSet();
|
|
48
|
+
function ensureUndoToolsRegistered(host, options = {}) {
|
|
49
|
+
if (installedHosts.has(host)) return;
|
|
50
|
+
installedHosts.add(host);
|
|
51
|
+
registerUndoTools(host, options);
|
|
52
52
|
}
|
|
53
|
-
function registerUndoTools(
|
|
53
|
+
function registerUndoTools(host, options = {}) {
|
|
54
54
|
const defaultAgent = options.defaultAgentId ?? "agent";
|
|
55
55
|
const disposers = [];
|
|
56
56
|
const agentOf = (args) => typeof args?.agentId === "string" ? args.agentId : defaultAgent;
|
|
57
57
|
disposers.push(
|
|
58
|
-
|
|
58
|
+
host.registerTool(
|
|
59
59
|
{
|
|
60
60
|
name: "agent_undo",
|
|
61
61
|
description: "Undo the most recent action on the agent's stack. Optional agentId targets a specific agent.",
|
|
@@ -73,7 +73,7 @@ function registerUndoTools(server, options = {}) {
|
|
|
73
73
|
)
|
|
74
74
|
);
|
|
75
75
|
disposers.push(
|
|
76
|
-
|
|
76
|
+
host.registerTool(
|
|
77
77
|
{
|
|
78
78
|
name: "agent_redo",
|
|
79
79
|
description: "Redo the most recently undone action.",
|
|
@@ -91,7 +91,7 @@ function registerUndoTools(server, options = {}) {
|
|
|
91
91
|
)
|
|
92
92
|
);
|
|
93
93
|
disposers.push(
|
|
94
|
-
|
|
94
|
+
host.registerTool(
|
|
95
95
|
{
|
|
96
96
|
name: "agent_history",
|
|
97
97
|
description: "List the agent's undo stack (oldest first). Useful for understanding what's reversible.",
|
|
@@ -120,5 +120,5 @@ function serialize(entry) {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
export { clearStack, ensureUndoToolsRegistered, pushUndoEntry, readHistory, redoOne, registerUndoTools, resetAllUndoStacks, undoOne };
|
|
123
|
-
//# sourceMappingURL=chunk-
|
|
124
|
-
//# sourceMappingURL=chunk-
|
|
123
|
+
//# sourceMappingURL=chunk-GQ7XXK7G.js.map
|
|
124
|
+
//# sourceMappingURL=chunk-GQ7XXK7G.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/undo/undo-stack.ts","../src/undo/undo-tools.ts"],"names":[],"mappings":"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","file":"chunk-GQ7XXK7G.js","sourcesContent":["/**\n * Generic undo/redo stack keyed by `agentId`. Each entry holds:\n * - `do` — re-applies the action (for redo)\n * - `undo` — reverses it\n * - `label` — human-readable summary surfaced in agent_history\n *\n * Bridges register entries by calling `pushUndoEntry` after a successful\n * mutation. The corresponding MCP tools (`agent_undo`, `agent_redo`,\n * `agent_history`) are registered once per server via `registerUndoTools`.\n *\n * Stacks are per-agent so multiple agents can rewind independently.\n */\n\nexport type UndoEntry = {\n /** Wall-clock ms. */\n timestamp: number;\n /** Bridge id (e.g. \"whiteboard\", \"form:signup\"). */\n bridgeId: string;\n /** Tool name that produced the entry. */\n action: string;\n /** Short human label, e.g. `Added sticky n_abc`. */\n label: string;\n /** Reverse the action. */\n undo: () => void | Promise<void>;\n /** Re-apply the action (used when redoing after an undo). */\n redo: () => void | Promise<void>;\n};\n\ntype Stack = { past: UndoEntry[]; future: UndoEntry[] };\n\nconst stacks = new Map<string, Stack>();\nconst CAP = 200;\n\nfunction getStack(agentId: string): Stack {\n let s = stacks.get(agentId);\n if (!s) {\n s = { past: [], future: [] };\n stacks.set(agentId, s);\n }\n return s;\n}\n\n/** Push a new undo entry on the agent's stack. Clears the redo (future) stack. */\nexport function pushUndoEntry(agentId: string, entry: UndoEntry): void {\n const s = getStack(agentId);\n s.past.push(entry);\n if (s.past.length > CAP) s.past.splice(0, s.past.length - CAP);\n s.future.length = 0;\n}\n\n/** Pop and undo the most recent entry. Returns the entry that ran, or null. */\nexport async function undoOne(agentId: string): Promise<UndoEntry | null> {\n const s = getStack(agentId);\n const entry = s.past.pop();\n if (!entry) return null;\n await entry.undo();\n s.future.push(entry);\n return entry;\n}\n\n/** Re-apply the most recently undone entry. Returns it, or null if no future. */\nexport async function redoOne(agentId: string): Promise<UndoEntry | null> {\n const s = getStack(agentId);\n const entry = s.future.pop();\n if (!entry) return null;\n await entry.redo();\n s.past.push(entry);\n return entry;\n}\n\n/** Read the past stack (oldest first). */\nexport function readHistory(agentId: string): UndoEntry[] {\n return getStack(agentId).past.slice();\n}\n\n/** Wipe an agent's stacks. */\nexport function clearStack(agentId: string): void {\n stacks.delete(agentId);\n}\n\n/** Test/teardown helper. */\nexport function resetAllUndoStacks(): void {\n stacks.clear();\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"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { wrapToolWithActivity } from './chunk-52S7XYZK.js';
|
|
2
|
-
import { textResult, errorResult } from './chunk-
|
|
2
|
+
import { textResult, errorResult } from './chunk-4KAIV6OD.js';
|
|
3
3
|
|
|
4
4
|
// src/bridges/code.ts
|
|
5
5
|
var DEFAULT_AGENT = { id: "agent", name: "Agent", color: "#a855f7" };
|
|
6
|
-
function registerCodeBridge(
|
|
6
|
+
function registerCodeBridge(host, options) {
|
|
7
7
|
const { adapter } = options;
|
|
8
8
|
const agent = { ...DEFAULT_AGENT, ...options.agent ?? {} };
|
|
9
9
|
const disposers = [];
|
|
@@ -29,7 +29,7 @@ function registerCodeBridge(server, options) {
|
|
|
29
29
|
resolveTarget: () => target
|
|
30
30
|
}) : wrapped;
|
|
31
31
|
disposers.push(
|
|
32
|
-
|
|
32
|
+
host.registerTool(
|
|
33
33
|
{
|
|
34
34
|
name,
|
|
35
35
|
description,
|
|
@@ -168,5 +168,5 @@ function registerCodeBridge(server, options) {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
export { registerCodeBridge };
|
|
171
|
-
//# sourceMappingURL=chunk-
|
|
172
|
-
//# sourceMappingURL=chunk-
|
|
171
|
+
//# sourceMappingURL=chunk-HSTW7ZNO.js.map
|
|
172
|
+
//# sourceMappingURL=chunk-HSTW7ZNO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/bridges/code.ts"],"names":[],"mappings":"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","file":"chunk-HSTW7ZNO.js","sourcesContent":["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 the host wires to a fancy-code CodeEditor (typically via the\n * useCodeEditor hook's context value).\n */\nexport type CodeBridgeAdapter = {\n /** Stable id for this editor instance. */\n id: string;\n /** Display label. */\n title?: string;\n /** Optional fancy-screens screen id. */\n screenId?: string;\n /** Read the current document text. */\n getValue: () => string;\n /** Replace the document. */\n setValue: (value: string) => void;\n /** Read the current selection text (empty string if none). */\n getSelection?: () => string;\n /** Replace the current selection with text. */\n replaceSelection?: (text: string) => void;\n /** Programmatic focus. */\n focus?: () => void;\n /** Read / set the active language. */\n getLanguage?: () => string;\n /** Set the active language. */\n setLanguage?: (lang: string) => void;\n};\n\nexport type CodeBridgeOptions = {\n adapter: CodeBridgeAdapter;\n agent?: { id: string; name?: string; color?: string };\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\n/**\n * registerCodeBridge — schema-aware MCP access to a single CodeEditor.\n * Tools cover read, full replace, append, selection replace, language\n * switch, and a streaming append helper for \"type characters into the\n * editor over time\" UX.\n */\nexport function registerCodeBridge(\n host: ToolHost,\n options: CodeBridgeOptions,\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: \"code\",\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 {\n return await handler(args);\n } catch (e) {\n return errorResult(e instanceof Error ? e.message : String(e));\n }\n };\n const final = isMutation\n ? wrapToolWithActivity(wrapped, {\n toolName: name,\n agent,\n kind: \"code\",\n screenId: adapter.screenId,\n resolveTarget: () => target,\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n {\n name,\n description,\n inputSchema: { type: \"object\", properties: properties as any, required, additionalProperties: false },\n },\n final as any,\n ),\n );\n };\n\n reg(\n \"code_describe\",\n `Describe the editor \"${adapter.id}\" — language + length + has-selection.`,\n {},\n [],\n () => {\n const value = adapter.getValue();\n const language = adapter.getLanguage?.() ?? \"unknown\";\n const summary = { id: adapter.id, language, length: value.length, lines: value.split(\"\\n\").length };\n return textResult(JSON.stringify(summary), summary);\n },\n false,\n );\n\n reg(\n \"code_get_value\",\n \"Read the full document text.\",\n {},\n [],\n () => {\n const value = adapter.getValue();\n return textResult(value, { value });\n },\n false,\n );\n\n reg(\n \"code_get_selection\",\n \"Read the currently-selected text (empty string if no selection).\",\n {},\n [],\n () => {\n if (!adapter.getSelection) return errorResult(\"Host did not provide getSelection.\");\n const value = adapter.getSelection();\n return textResult(value, { value });\n },\n false,\n );\n\n reg(\n \"code_set_value\",\n \"Replace the entire document.\",\n { value: { type: \"string\" } },\n [\"value\"],\n (args) => {\n const value = String(args.value ?? \"\");\n adapter.setValue(value);\n return textResult(`Replaced document (${value.length} chars)`, { length: value.length });\n },\n true,\n );\n\n reg(\n \"code_append\",\n \"Append text to the end of the document.\",\n { text: { type: \"string\" } },\n [\"text\"],\n (args) => {\n const text = String(args.text ?? \"\");\n const next = adapter.getValue() + text;\n adapter.setValue(next);\n return textResult(`Appended ${text.length} chars`, { length: next.length });\n },\n true,\n );\n\n reg(\n \"code_stream_append\",\n \"Type characters into the document one at a time so the human can read it forming. Returns when streaming finishes.\",\n {\n text: { type: \"string\" },\n cps: { type: \"number\", description: \"Characters per second. Default 25.\" },\n },\n [\"text\"],\n async (args) => {\n const text = String(args.text ?? \"\");\n const cps = Math.max(1, Number(args.cps ?? 25));\n const interval = Math.max(8, Math.round(1000 / cps));\n const start = adapter.getValue();\n for (let i = 1; i <= text.length; i++) {\n adapter.setValue(start + text.slice(0, i));\n if (i < text.length) await new Promise((r) => setTimeout(r, interval));\n }\n return textResult(`Streamed ${text.length} chars`, { length: text.length });\n },\n true,\n );\n\n reg(\n \"code_replace_selection\",\n \"Replace the currently-selected text with the supplied text.\",\n { text: { type: \"string\" } },\n [\"text\"],\n (args) => {\n if (!adapter.replaceSelection) return errorResult(\"Host did not provide replaceSelection.\");\n adapter.replaceSelection(String(args.text ?? \"\"));\n return textResult(\"Selection replaced\", { });\n },\n true,\n );\n\n reg(\n \"code_set_language\",\n \"Switch the active syntax highlighting / formatter.\",\n { language: { type: \"string\", description: \"e.g. 'javascript', 'php', 'sql'.\" } },\n [\"language\"],\n (args) => {\n if (!adapter.setLanguage) return errorResult(\"Host did not provide setLanguage.\");\n const lang = String(args.language ?? \"\");\n adapter.setLanguage(lang);\n return textResult(`Language → ${lang}`, { language: lang });\n },\n true,\n );\n\n reg(\n \"code_focus\",\n \"Move browser focus to the editor.\",\n {},\n [],\n () => {\n if (!adapter.focus) return errorResult(\"Host did not provide focus.\");\n adapter.focus();\n return textResult(\"Focused\", { });\n },\n true,\n );\n\n return {\n id: `code:${adapter.id}`,\n title: adapter.title ?? adapter.id,\n dispose: () => {\n for (const d of disposers) d();\n },\n };\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { wrapToolWithActivity } from './chunk-52S7XYZK.js';
|
|
2
|
-
import { textResult, errorResult } from './chunk-
|
|
2
|
+
import { textResult, errorResult } from './chunk-4KAIV6OD.js';
|
|
3
3
|
|
|
4
4
|
// src/bridges/sheets.ts
|
|
5
5
|
var DEFAULT_AGENT = { id: "agent", name: "Agent", color: "#a855f7" };
|
|
6
|
-
function registerSheetsBridge(
|
|
6
|
+
function registerSheetsBridge(host, options) {
|
|
7
7
|
const { adapter } = options;
|
|
8
8
|
const agent = { ...DEFAULT_AGENT, ...options.agent ?? {} };
|
|
9
9
|
const disposers = [];
|
|
@@ -29,7 +29,7 @@ function registerSheetsBridge(server, options) {
|
|
|
29
29
|
resolveTarget: ({ args, result }) => resolveTarget?.(args, result) ?? target(getSheetId(args))
|
|
30
30
|
}) : wrapped;
|
|
31
31
|
disposers.push(
|
|
32
|
-
|
|
32
|
+
host.registerTool(
|
|
33
33
|
{
|
|
34
34
|
name,
|
|
35
35
|
description,
|
|
@@ -276,5 +276,5 @@ function readRange(sheet, startAddr, endAddr) {
|
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
export { registerSheetsBridge };
|
|
279
|
-
//# sourceMappingURL=chunk-
|
|
280
|
-
//# sourceMappingURL=chunk-
|
|
279
|
+
//# sourceMappingURL=chunk-IANI25IT.js.map
|
|
280
|
+
//# sourceMappingURL=chunk-IANI25IT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/bridges/sheets.ts"],"names":[],"mappings":"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","file":"chunk-IANI25IT.js","sourcesContent":["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 * Loose types — kept here so the bridge builds without a hard dep on\n * @particle-academy/fancy-sheets. They mirror the public surface of\n * `WorkbookData` / `SheetData` / `CellData` from that package.\n */\ntype CellValue = string | number | boolean | null;\ntype CellData = { address: string; value: CellValue; format?: unknown; comment?: unknown; computedValue?: CellValue };\ntype SheetData = {\n id: string;\n name: string;\n cells: Record<string, CellData>;\n columnWidths: Record<number, number>;\n mergedRegions: Array<{ start: string; end: string }>;\n columnFilters: Record<number, string>;\n sortColumn?: number;\n sortDirection?: \"asc\" | \"desc\";\n frozenRows: number;\n frozenCols: number;\n};\ntype WorkbookData = { sheets: SheetData[]; activeSheetId: string };\n\nexport type SheetsBridgeAdapter = {\n /** fancy-screens screen id (optional) so activity events know which screen the sheet lives in. */\n screenId?: string;\n /** Read the current workbook. */\n getWorkbook: () => WorkbookData;\n /** Replace the workbook. Host wires this to its onChange. */\n setWorkbook: (next: WorkbookData) => void;\n /** Optional: programmatically change the active cell. */\n setActiveCell?: (sheetId: string, address: string) => void;\n};\n\nexport type SheetsBridgeOptions = {\n adapter: SheetsBridgeAdapter;\n agent?: { id: string; name?: string; color?: string };\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\n/**\n * registerSheetsBridge — schema-aware MCP access to a fancy-sheets workbook.\n * Tools are sheet-aware (every mutator takes an explicit `sheet` id, defaulting\n * to the active sheet when omitted) so an agent can author multi-sheet docs.\n */\nexport function registerSheetsBridge(\n host: ToolHost,\n options: SheetsBridgeOptions,\n): Bridge {\n const { adapter } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const disposers: Array<() => void> = [];\n\n const target = (sheetId: string, address?: string): AgentTarget => ({\n kind: \"sheet\",\n screenId: adapter.screenId,\n elementId: address ? `${sheetId}!${address}` : sheetId,\n label: address ? `${sheetId}!${address}` : sheetId,\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 resolveTarget?: (args: JsonObject, result: any) => AgentTarget | null,\n ) => {\n const wrapped = async (args: JsonObject) => {\n try {\n return await handler(args);\n } catch (e) {\n return errorResult(e instanceof Error ? e.message : String(e));\n }\n };\n const final = isMutation\n ? wrapToolWithActivity(wrapped, {\n toolName: name,\n agent,\n kind: \"sheet\",\n screenId: adapter.screenId,\n resolveTarget: ({ args, result }) =>\n resolveTarget?.(args, result) ?? target(getSheetId(args)),\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n {\n name,\n description,\n inputSchema: { type: \"object\", properties: properties as any, required, additionalProperties: false },\n },\n final as any,\n ),\n );\n };\n\n function activeSheetId(): string {\n return adapter.getWorkbook().activeSheetId;\n }\n function getSheetId(args: JsonObject): string {\n return typeof args.sheet === \"string\" ? args.sheet : activeSheetId();\n }\n function getSheet(workbook: WorkbookData, sheetId: string): SheetData | undefined {\n return workbook.sheets.find((s) => s.id === sheetId);\n }\n\n // ───────────── Read tools ─────────────\n\n reg(\n \"sheet_describe\",\n \"Describe the workbook: every sheet's id, name, dimensions, cell count, active sheet. Call before reading or writing.\",\n {},\n [],\n () => {\n const wb = adapter.getWorkbook();\n const summary = {\n activeSheetId: wb.activeSheetId,\n sheets: wb.sheets.map((s) => ({\n id: s.id,\n name: s.name,\n cellCount: Object.keys(s.cells).length,\n columnCount: Object.keys(s.columnWidths).length,\n frozenRows: s.frozenRows,\n frozenCols: s.frozenCols,\n })),\n };\n const text = `Active: ${summary.activeSheetId}\\n` + summary.sheets\n .map((s) => `${s.id} \"${s.name}\" — ${s.cellCount} cells`)\n .join(\"\\n\");\n return textResult(text, summary);\n },\n false,\n );\n\n reg(\n \"sheet_get_cell\",\n \"Read a single cell's raw + computed value.\",\n {\n sheet: { type: \"string\", description: \"Sheet id (defaults to active).\" },\n address: { type: \"string\", description: \"A1-style address, e.g. \\\"B12\\\".\" },\n },\n [\"address\"],\n (args) => {\n const sheetId = getSheetId(args);\n const address = String(args.address);\n const sheet = getSheet(adapter.getWorkbook(), sheetId);\n if (!sheet) return errorResult(`No sheet ${sheetId}`);\n const cell = sheet.cells[address];\n if (!cell) {\n return textResult(`(empty)`, { sheet: sheetId, address, value: null });\n }\n return textResult(`${address} = ${JSON.stringify(cell.computedValue ?? cell.value)}`, { ...cell, sheet: sheetId, address });\n },\n false,\n );\n\n reg(\n \"sheet_get_range\",\n \"Read a rectangular range as a 2D array of values.\",\n {\n sheet: { type: \"string\" },\n start: { type: \"string\", description: \"Top-left A1 address.\" },\n end: { type: \"string\", description: \"Bottom-right A1 address.\" },\n },\n [\"start\", \"end\"],\n (args) => {\n const sheetId = getSheetId(args);\n const sheet = getSheet(adapter.getWorkbook(), sheetId);\n if (!sheet) return errorResult(`No sheet ${sheetId}`);\n const grid = readRange(sheet, String(args.start), String(args.end));\n return textResult(JSON.stringify(grid), { sheet: sheetId, start: args.start, end: args.end, values: grid });\n },\n false,\n );\n\n // ───────────── Mutation tools ─────────────\n\n reg(\n \"sheet_set_cell\",\n \"Set a single cell's value. To set a formula, pass a string starting with '='.\",\n {\n sheet: { type: \"string\" },\n address: { type: \"string\" },\n value: { description: \"string | number | boolean | null. Strings starting with '=' are stored as formulas.\" },\n },\n [\"address\", \"value\"],\n (args) => {\n const sheetId = getSheetId(args);\n const address = String(args.address);\n const value = args.value as CellValue;\n const wb = adapter.getWorkbook();\n const sheet = getSheet(wb, sheetId);\n if (!sheet) return errorResult(`No sheet ${sheetId}`);\n const next = mergeCells(wb, sheetId, { [address]: cellOf(address, value) });\n adapter.setWorkbook(next);\n return textResult(`${sheetId}!${address} ← ${JSON.stringify(value)}`, { sheet: sheetId, address, value });\n },\n true,\n (args) => target(getSheetId(args), String(args.address ?? \"\")),\n );\n\n reg(\n \"sheet_set_range\",\n \"Set many cells atomically. `cells` is an object map of { \\\"A1\\\": value, \\\"B2\\\": value, ... }.\",\n {\n sheet: { type: \"string\" },\n cells: { type: \"object\" },\n },\n [\"cells\"],\n (args) => {\n const sheetId = getSheetId(args);\n const wb = adapter.getWorkbook();\n const sheet = getSheet(wb, sheetId);\n if (!sheet) return errorResult(`No sheet ${sheetId}`);\n const cells = (args.cells && typeof args.cells === \"object\") ? args.cells as Record<string, CellValue> : {};\n const updates: Record<string, CellData> = {};\n for (const [addr, v] of Object.entries(cells)) updates[addr] = cellOf(addr, v);\n const next = mergeCells(wb, sheetId, updates);\n adapter.setWorkbook(next);\n return textResult(`Set ${Object.keys(cells).length} cells in ${sheetId}`, { sheet: sheetId, count: Object.keys(cells).length });\n },\n true,\n );\n\n reg(\n \"sheet_add_sheet\",\n \"Add a new sheet (tab) to the workbook.\",\n { id: { type: \"string\" }, name: { type: \"string\" } },\n [\"id\", \"name\"],\n (args) => {\n const wb = adapter.getWorkbook();\n const id = String(args.id);\n const name = String(args.name);\n if (wb.sheets.find((s) => s.id === id)) return errorResult(`Sheet ${id} already exists`);\n const next: WorkbookData = {\n ...wb,\n sheets: [\n ...wb.sheets,\n {\n id, name, cells: {}, columnWidths: {}, mergedRegions: [],\n columnFilters: {}, frozenRows: 0, frozenCols: 0,\n },\n ],\n };\n adapter.setWorkbook(next);\n return textResult(`Added sheet ${id} (\"${name}\")`, { id, name });\n },\n true,\n (args) => target(String(args.id ?? \"\")),\n );\n\n reg(\n \"sheet_set_active\",\n \"Switch to a different sheet tab.\",\n { sheet: { type: \"string\" } },\n [\"sheet\"],\n (args) => {\n const sheetId = String(args.sheet);\n const wb = adapter.getWorkbook();\n if (!getSheet(wb, sheetId)) return errorResult(`No sheet ${sheetId}`);\n adapter.setWorkbook({ ...wb, activeSheetId: sheetId });\n return textResult(`Active sheet → ${sheetId}`, { sheet: sheetId });\n },\n true,\n );\n\n reg(\n \"sheet_set_active_cell\",\n \"Move the active cell selection (host implements DOM focus + scroll).\",\n { sheet: { type: \"string\" }, address: { type: \"string\" } },\n [\"address\"],\n (args) => {\n if (!adapter.setActiveCell) return errorResult(\"Host did not provide setActiveCell.\");\n const sheetId = getSheetId(args);\n adapter.setActiveCell(sheetId, String(args.address));\n return textResult(`Active cell → ${sheetId}!${args.address}`, { sheet: sheetId, address: args.address });\n },\n true,\n (args) => target(getSheetId(args), String(args.address ?? \"\")),\n );\n\n return {\n id: \"sheets\",\n title: \"Sheets\",\n dispose: () => {\n for (const d of disposers) d();\n },\n };\n}\n\n// ───────────── helpers ─────────────\n\nfunction cellOf(address: string, value: CellValue): CellData {\n return { address, value };\n}\n\nfunction mergeCells(wb: WorkbookData, sheetId: string, updates: Record<string, CellData>): WorkbookData {\n return {\n ...wb,\n sheets: wb.sheets.map((s) =>\n s.id !== sheetId ? s : { ...s, cells: { ...s.cells, ...updates } },\n ),\n };\n}\n\n/** Parse \"B12\" → { col: 1, row: 11 }. Letters are 1-based, rows 1-based. */\nfunction parseAddress(addr: string): { col: number; row: number } {\n const m = /^([A-Za-z]+)(\\d+)$/.exec(addr.trim());\n if (!m) throw new Error(`Bad address: ${addr}`);\n const letters = m[1].toUpperCase();\n let col = 0;\n for (let i = 0; i < letters.length; i++) {\n col = col * 26 + (letters.charCodeAt(i) - 64);\n }\n return { col: col - 1, row: parseInt(m[2], 10) - 1 };\n}\n\nfunction colToLetter(col: number): string {\n let s = \"\";\n let n = col + 1;\n while (n > 0) {\n const r = (n - 1) % 26;\n s = String.fromCharCode(65 + r) + s;\n n = Math.floor((n - 1) / 26);\n }\n return s;\n}\n\nfunction readRange(sheet: SheetData, startAddr: string, endAddr: string): CellValue[][] {\n const start = parseAddress(startAddr);\n const end = parseAddress(endAddr);\n const r0 = Math.min(start.row, end.row);\n const r1 = Math.max(start.row, end.row);\n const c0 = Math.min(start.col, end.col);\n const c1 = Math.max(start.col, end.col);\n const grid: CellValue[][] = [];\n for (let r = r0; r <= r1; r++) {\n const row: CellValue[] = [];\n for (let c = c0; c <= c1; c++) {\n const addr = `${colToLetter(c)}${r + 1}`;\n const cell = sheet.cells[addr];\n row.push(cell?.computedValue ?? cell?.value ?? null);\n }\n grid.push(row);\n }\n return grid;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-IJ6JX5VC.js"}
|
|
@@ -168,5 +168,5 @@ function attachSseRelay(server, options) {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
export { SseRelayTransport, attachSseRelay, buildShareConfig, buildShareUrl, constantTimeEqual, createSessionDescriptor, describeSession, readSessionFromUrl };
|
|
171
|
-
//# sourceMappingURL=chunk-
|
|
172
|
-
//# sourceMappingURL=chunk-
|
|
171
|
+
//# sourceMappingURL=chunk-LVQXIUJH.js.map
|
|
172
|
+
//# sourceMappingURL=chunk-LVQXIUJH.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sharing/token.ts","../src/sharing/sse-relay.ts"],"names":[],"mappings":"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","file":"chunk-JMYPUAFH.js","sourcesContent":["/**\n * Session-token utilities. The token is a high-entropy secret; possession\n * grants read/write on the session. We don't HMAC frames — frames carry\n * the token directly (which is fine for in-process / same-origin / TLS\n * transports). For lower-trust transports, host apps can layer signing\n * on top of the BroadcastChannelTransport.\n */\n\nconst TOKEN_BYTES = 24; // 192 bits, base64url-encoded → 32 chars\n\nexport type SessionDescriptor = {\n /** Stable session identifier. Channel name = `fai:share:${id}`. */\n id: string;\n /** Secret token. Treat as a password — anyone with it can read/write. */\n token: string;\n /** Pretty hash for display (first 8 chars of token). */\n display: string;\n};\n\nexport function createSessionDescriptor(): SessionDescriptor {\n const id = randomId(8);\n const token = randomToken();\n return { id, token, display: token.slice(0, 8) };\n}\n\nexport function describeSession(id: string, token: string): SessionDescriptor {\n return { id, token, display: token.slice(0, 8) };\n}\n\n/** Build the shareable URL for the current page (preserves path, adds session+token). */\nexport function buildShareUrl(\n descriptor: SessionDescriptor,\n baseUrl: string = typeof window !== \"undefined\" ? window.location.href.split(\"?\")[0] : \"\",\n): string {\n const u = new URL(baseUrl);\n u.searchParams.set(\"session\", descriptor.id);\n u.searchParams.set(\"token\", descriptor.token);\n return u.toString();\n}\n\n/** Build the JSON config form (suitable for Claude Desktop / Cline / etc.). */\nexport function buildShareConfig(descriptor: SessionDescriptor, transport = \"broadcast-channel\") {\n return {\n name: `whiteboard-${descriptor.id}`,\n transport,\n session: descriptor.id,\n token: descriptor.token,\n channel: `fai:share:${descriptor.id}`,\n protocol_version: \"2025-06-18\",\n };\n}\n\n/** Read session descriptor from current URL, or null if not a shared link. */\nexport function readSessionFromUrl(): SessionDescriptor | null {\n if (typeof window === \"undefined\") return null;\n const params = new URL(window.location.href).searchParams;\n const id = params.get(\"session\");\n const token = params.get(\"token\");\n if (!id || !token) return null;\n return describeSession(id, token);\n}\n\nfunction randomToken(): string {\n const bytes = new Uint8Array(TOKEN_BYTES);\n crypto.getRandomValues(bytes);\n return base64Url(bytes);\n}\n\nfunction randomId(len: number): string {\n const bytes = new Uint8Array(Math.ceil((len * 3) / 4));\n crypto.getRandomValues(bytes);\n return base64Url(bytes).slice(0, len);\n}\n\nfunction base64Url(bytes: Uint8Array): string {\n let s = \"\";\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n/** Constant-time string compare so a mismatched token leaks no timing info. */\nexport function constantTimeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let diff = 0;\n for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\n return diff === 0;\n}\n","import type { JsonRpcMessage } from \"../mcp/types\";\nimport type { Transport } from \"../mcp/server\";\nimport type { MicroMcpServer } from \"../mcp/server\";\nimport { constantTimeEqual } from \"./token\";\n\n/**\n * SseRelayTransport — bridges the in-page MicroMcpServer to a host-app\n * relay broker over Server-Sent Events (inbound) + POST (outbound).\n *\n * Wire model:\n * - Browser opens an EventSource at `${baseUrl}/${sessionId}/events?token=…`.\n * Each `event: mcp` carries one JSON-RPC frame from a remote client.\n * - Browser POSTs JSON-RPC frames to `${baseUrl}/${sessionId}/outbox?token=…`\n * when the local server has a response/notification to send.\n *\n * The host provides the relay endpoint (any HTTP server). See the demo\n * `WhiteboardShareController` for the reference implementation.\n *\n * Token authentication is the host's job — this transport just carries the\n * token in the query string. For lower-trust deployments, layer signing on\n * top by wrapping `send` / `deliverFromRemote`.\n */\nexport type SseRelayOptions = {\n baseUrl: string;\n sessionId: string;\n token: string;\n /** Override fetch (testing / non-browser). Defaults to global fetch. */\n fetch?: typeof fetch;\n};\n\nexport class SseRelayTransport implements Transport {\n private server?: MicroMcpServer;\n private es?: EventSource;\n private opts: SseRelayOptions;\n private sendQueue: JsonRpcMessage[] = [];\n private connected = false;\n private listeners = new Set<(state: RelayState) => void>();\n private state: RelayState = \"idle\";\n private expectedToken: string;\n\n constructor(options: SseRelayOptions) {\n this.opts = options;\n this.expectedToken = options.token;\n }\n\n bindServer(server: MicroMcpServer): void {\n this.server = server;\n }\n\n /** Open the SSE channel. Idempotent. */\n start(): void {\n if (this.connected || typeof window === \"undefined\") return;\n const url = `${this.opts.baseUrl}/${encodeURIComponent(this.opts.sessionId)}/events?token=${encodeURIComponent(this.opts.token)}`;\n this.setState(\"connecting\");\n const es = new EventSource(url, { withCredentials: false });\n this.es = es;\n\n es.addEventListener(\"open\", () => {\n this.connected = true;\n this.setState(\"open\");\n // Flush queued outbound frames (tool list_changed notifications, etc.)\n const queued = this.sendQueue.splice(0);\n for (const msg of queued) this.postOut(msg);\n });\n\n es.addEventListener(\"mcp\", (ev: MessageEvent) => {\n const raw = ev.data;\n this.handleInbound(raw);\n });\n\n es.addEventListener(\"error\", () => {\n this.setState(\"error\");\n // EventSource auto-reconnects; no need to dispose.\n });\n }\n\n send(message: JsonRpcMessage): void {\n if (!this.connected) {\n this.sendQueue.push(message);\n return;\n }\n this.postOut(message);\n }\n\n close(): void {\n this.es?.close();\n this.es = undefined;\n this.connected = false;\n this.setState(\"closed\");\n }\n\n onStateChange(listener: (state: RelayState) => void): () => void {\n this.listeners.add(listener);\n listener(this.state);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * For relays that wrap each frame with auth metadata: hosts can call this\n * directly when a frame arrives via a non-SSE path. The transport will\n * dispatch it to the bound server.\n */\n async deliverFromRemote(payload: JsonRpcMessage | string, token?: string): Promise<void> {\n if (token !== undefined && !constantTimeEqual(token, this.expectedToken)) return;\n if (!this.server) throw new Error(\"SseRelayTransport has no bound server\");\n const message: JsonRpcMessage = typeof payload === \"string\" ? JSON.parse(payload) : payload;\n await this.server.receive(this, message);\n }\n\n private async postOut(message: JsonRpcMessage): Promise<void> {\n const url = `${this.opts.baseUrl}/${encodeURIComponent(this.opts.sessionId)}/outbox?token=${encodeURIComponent(this.opts.token)}`;\n const f = this.opts.fetch ?? fetch;\n try {\n await f(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"accept\": \"application/json\" },\n body: JSON.stringify(message),\n });\n } catch {\n // Drop — relay errors are surfaced via state change separately.\n }\n }\n\n private async handleInbound(raw: string): Promise<void> {\n if (!this.server) return;\n let message: JsonRpcMessage;\n try {\n message = JSON.parse(raw);\n } catch {\n return;\n }\n await this.server.receive(this, message);\n }\n\n private setState(state: RelayState): void {\n this.state = state;\n for (const l of this.listeners) l(state);\n }\n}\n\nexport type RelayState = \"idle\" | \"connecting\" | \"open\" | \"closed\" | \"error\";\n\nexport function attachSseRelay(server: MicroMcpServer, options: SseRelayOptions): SseRelayTransport {\n const transport = new SseRelayTransport(options);\n transport.bindServer(server);\n server.attach(transport);\n transport.start();\n\n // Forward in-process agent activity events out over the relay so external\n // subscribers can render presence indicators in real time. Uses a dynamic\n // import so the relay doesn't hard-depend on the presence module if it's\n // tree-shaken out.\n import(\"../presence/registry\").then(({ onActivity }) => {\n const off = onActivity((event) => {\n transport.send({\n jsonrpc: \"2.0\",\n method: \"notifications/agent_activity\",\n params: event as any,\n });\n });\n // Tear down the subscription when the transport closes.\n const origClose = transport.close.bind(transport);\n transport.close = () => {\n off();\n origClose();\n };\n }).catch(() => {\n // Presence module unavailable — silently no-op (relay still works).\n });\n\n return transport;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/sharing/token.ts","../src/sharing/sse-relay.ts"],"names":[],"mappings":"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","file":"chunk-LVQXIUJH.js","sourcesContent":["/**\n * Session-token utilities. The token is a high-entropy secret; possession\n * grants read/write on the session. We don't HMAC frames — frames carry\n * the token directly (which is fine for in-process / same-origin / TLS\n * transports). For lower-trust transports, host apps can layer signing\n * on top of the BroadcastChannelTransport.\n */\n\nconst TOKEN_BYTES = 24; // 192 bits, base64url-encoded → 32 chars\n\nexport type SessionDescriptor = {\n /** Stable session identifier. Channel name = `fai:share:${id}`. */\n id: string;\n /** Secret token. Treat as a password — anyone with it can read/write. */\n token: string;\n /** Pretty hash for display (first 8 chars of token). */\n display: string;\n};\n\nexport function createSessionDescriptor(): SessionDescriptor {\n const id = randomId(8);\n const token = randomToken();\n return { id, token, display: token.slice(0, 8) };\n}\n\nexport function describeSession(id: string, token: string): SessionDescriptor {\n return { id, token, display: token.slice(0, 8) };\n}\n\n/** Build the shareable URL for the current page (preserves path, adds session+token). */\nexport function buildShareUrl(\n descriptor: SessionDescriptor,\n baseUrl: string = typeof window !== \"undefined\" ? window.location.href.split(\"?\")[0] : \"\",\n): string {\n const u = new URL(baseUrl);\n u.searchParams.set(\"session\", descriptor.id);\n u.searchParams.set(\"token\", descriptor.token);\n return u.toString();\n}\n\n/** Build the JSON config form (suitable for Claude Desktop / Cline / etc.). */\nexport function buildShareConfig(descriptor: SessionDescriptor, transport = \"broadcast-channel\") {\n return {\n name: `whiteboard-${descriptor.id}`,\n transport,\n session: descriptor.id,\n token: descriptor.token,\n channel: `fai:share:${descriptor.id}`,\n protocol_version: \"2025-06-18\",\n };\n}\n\n/** Read session descriptor from current URL, or null if not a shared link. */\nexport function readSessionFromUrl(): SessionDescriptor | null {\n if (typeof window === \"undefined\") return null;\n const params = new URL(window.location.href).searchParams;\n const id = params.get(\"session\");\n const token = params.get(\"token\");\n if (!id || !token) return null;\n return describeSession(id, token);\n}\n\nfunction randomToken(): string {\n const bytes = new Uint8Array(TOKEN_BYTES);\n crypto.getRandomValues(bytes);\n return base64Url(bytes);\n}\n\nfunction randomId(len: number): string {\n const bytes = new Uint8Array(Math.ceil((len * 3) / 4));\n crypto.getRandomValues(bytes);\n return base64Url(bytes).slice(0, len);\n}\n\nfunction base64Url(bytes: Uint8Array): string {\n let s = \"\";\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n/** Constant-time string compare so a mismatched token leaks no timing info. */\nexport function constantTimeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let diff = 0;\n for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\n return diff === 0;\n}\n","import type { JsonRpcMessage } from \"../mcp/types\";\nimport type { Transport } from \"../mcp/server\";\nimport type { MicroMcpServer } from \"../mcp/server\";\nimport { constantTimeEqual } from \"./token\";\n\n/**\n * SseRelayTransport — bridges the in-page MicroMcpServer to a host-app\n * relay broker over Server-Sent Events (inbound) + POST (outbound).\n *\n * Wire model:\n * - Browser opens an EventSource at `${baseUrl}/${sessionId}/events?token=…`.\n * Each `event: mcp` carries one JSON-RPC frame from a remote client.\n * - Browser POSTs JSON-RPC frames to `${baseUrl}/${sessionId}/outbox?token=…`\n * when the local server has a response/notification to send.\n *\n * The host provides the relay endpoint (any HTTP server). See the demo\n * `WhiteboardShareController` for the reference implementation.\n *\n * Token authentication is the host's job — this transport just carries the\n * token in the query string. For lower-trust deployments, layer signing on\n * top by wrapping `send` / `deliverFromRemote`.\n */\nexport type SseRelayOptions = {\n baseUrl: string;\n sessionId: string;\n token: string;\n /** Override fetch (testing / non-browser). Defaults to global fetch. */\n fetch?: typeof fetch;\n};\n\nexport class SseRelayTransport implements Transport {\n private server?: MicroMcpServer;\n private es?: EventSource;\n private opts: SseRelayOptions;\n private sendQueue: JsonRpcMessage[] = [];\n private connected = false;\n private listeners = new Set<(state: RelayState) => void>();\n private state: RelayState = \"idle\";\n private expectedToken: string;\n\n constructor(options: SseRelayOptions) {\n this.opts = options;\n this.expectedToken = options.token;\n }\n\n bindServer(server: MicroMcpServer): void {\n this.server = server;\n }\n\n /** Open the SSE channel. Idempotent. */\n start(): void {\n if (this.connected || typeof window === \"undefined\") return;\n const url = `${this.opts.baseUrl}/${encodeURIComponent(this.opts.sessionId)}/events?token=${encodeURIComponent(this.opts.token)}`;\n this.setState(\"connecting\");\n const es = new EventSource(url, { withCredentials: false });\n this.es = es;\n\n es.addEventListener(\"open\", () => {\n this.connected = true;\n this.setState(\"open\");\n // Flush queued outbound frames (tool list_changed notifications, etc.)\n const queued = this.sendQueue.splice(0);\n for (const msg of queued) this.postOut(msg);\n });\n\n es.addEventListener(\"mcp\", (ev: MessageEvent) => {\n const raw = ev.data;\n this.handleInbound(raw);\n });\n\n es.addEventListener(\"error\", () => {\n this.setState(\"error\");\n // EventSource auto-reconnects; no need to dispose.\n });\n }\n\n send(message: JsonRpcMessage): void {\n if (!this.connected) {\n this.sendQueue.push(message);\n return;\n }\n this.postOut(message);\n }\n\n close(): void {\n this.es?.close();\n this.es = undefined;\n this.connected = false;\n this.setState(\"closed\");\n }\n\n onStateChange(listener: (state: RelayState) => void): () => void {\n this.listeners.add(listener);\n listener(this.state);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * For relays that wrap each frame with auth metadata: hosts can call this\n * directly when a frame arrives via a non-SSE path. The transport will\n * dispatch it to the bound server.\n */\n async deliverFromRemote(payload: JsonRpcMessage | string, token?: string): Promise<void> {\n if (token !== undefined && !constantTimeEqual(token, this.expectedToken)) return;\n if (!this.server) throw new Error(\"SseRelayTransport has no bound server\");\n const message: JsonRpcMessage = typeof payload === \"string\" ? JSON.parse(payload) : payload;\n await this.server.receive(this, message);\n }\n\n private async postOut(message: JsonRpcMessage): Promise<void> {\n const url = `${this.opts.baseUrl}/${encodeURIComponent(this.opts.sessionId)}/outbox?token=${encodeURIComponent(this.opts.token)}`;\n const f = this.opts.fetch ?? fetch;\n try {\n await f(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"accept\": \"application/json\" },\n body: JSON.stringify(message),\n });\n } catch {\n // Drop — relay errors are surfaced via state change separately.\n }\n }\n\n private async handleInbound(raw: string): Promise<void> {\n if (!this.server) return;\n let message: JsonRpcMessage;\n try {\n message = JSON.parse(raw);\n } catch {\n return;\n }\n await this.server.receive(this, message);\n }\n\n private setState(state: RelayState): void {\n this.state = state;\n for (const l of this.listeners) l(state);\n }\n}\n\nexport type RelayState = \"idle\" | \"connecting\" | \"open\" | \"closed\" | \"error\";\n\nexport function attachSseRelay(server: MicroMcpServer, options: SseRelayOptions): SseRelayTransport {\n const transport = new SseRelayTransport(options);\n transport.bindServer(server);\n server.attach(transport);\n transport.start();\n\n // Forward in-process agent activity events out over the relay so external\n // subscribers can render presence indicators in real time. Uses a dynamic\n // import so the relay doesn't hard-depend on the presence module if it's\n // tree-shaken out.\n import(\"../presence/registry\").then(({ onActivity }) => {\n const off = onActivity((event) => {\n transport.send({\n jsonrpc: \"2.0\",\n method: \"notifications/agent_activity\",\n params: event as any,\n });\n });\n // Tear down the subscription when the transport closes.\n const origClose = transport.close.bind(transport);\n transport.close = () => {\n off();\n origClose();\n };\n }).catch(() => {\n // Presence module unavailable — silently no-op (relay still works).\n });\n\n return transport;\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { wrapToolWithActivity } from './chunk-52S7XYZK.js';
|
|
2
|
-
import { textResult, errorResult } from './chunk-
|
|
2
|
+
import { textResult, errorResult } from './chunk-4KAIV6OD.js';
|
|
3
3
|
|
|
4
4
|
// src/bridges/charts.ts
|
|
5
5
|
var DEFAULT_AGENT = { id: "agent", name: "Agent", color: "#a855f7" };
|
|
6
|
-
function registerChartsBridge(
|
|
6
|
+
function registerChartsBridge(host, options) {
|
|
7
7
|
const { adapter } = options;
|
|
8
8
|
const agent = { ...DEFAULT_AGENT, ...options.agent ?? {} };
|
|
9
9
|
const disposers = [];
|
|
@@ -29,7 +29,7 @@ function registerChartsBridge(server, options) {
|
|
|
29
29
|
resolveTarget: () => target
|
|
30
30
|
}) : wrapped;
|
|
31
31
|
disposers.push(
|
|
32
|
-
|
|
32
|
+
host.registerTool(
|
|
33
33
|
{ name, description, inputSchema: { type: "object", properties, required, additionalProperties: false } },
|
|
34
34
|
final
|
|
35
35
|
)
|
|
@@ -116,5 +116,5 @@ function registerChartsBridge(server, options) {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
export { registerChartsBridge };
|
|
119
|
-
//# sourceMappingURL=chunk-
|
|
120
|
-
//# sourceMappingURL=chunk-
|
|
119
|
+
//# sourceMappingURL=chunk-NTDZWGYB.js.map
|
|
120
|
+
//# sourceMappingURL=chunk-NTDZWGYB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/bridges/charts.ts"],"names":[],"mappings":"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","file":"chunk-NTDZWGYB.js","sourcesContent":["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,4 +1,4 @@
|
|
|
1
|
-
import { readHistory } from './chunk-
|
|
1
|
+
import { readHistory } from './chunk-GQ7XXK7G.js';
|
|
2
2
|
import { useState, useEffect, useCallback } from 'react';
|
|
3
3
|
|
|
4
4
|
function useUndoStack(agentId, intervalMs = 500) {
|
|
@@ -21,5 +21,5 @@ function useUndoStack(agentId, intervalMs = 500) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export { useUndoStack };
|
|
24
|
-
//# sourceMappingURL=chunk-
|
|
25
|
-
//# sourceMappingURL=chunk-
|
|
24
|
+
//# sourceMappingURL=chunk-RGO42EQ6.js.map
|
|
25
|
+
//# sourceMappingURL=chunk-RGO42EQ6.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/undo/use-undo-stack.ts"],"names":[],"mappings":";;;AASO,SAAS,YAAA,CAAa,OAAA,EAAiB,UAAA,GAAa,GAAA,EAAK;AAC9D,EAAA,MAAM,CAAC,SAAS,UAAU,CAAA,GAAI,SAAS,MAAM,WAAA,CAAY,OAAO,CAAC,CAAA;AAEjE,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,MAAM,OAAO,MAAM;AACjB,MAAA,IAAI,SAAA,EAAW;AACf,MAAA,UAAA,CAAW,WAAA,CAAY,OAAO,CAAC,CAAA;AAAA,IACjC,CAAA;AACA,IAAA,MAAM,EAAA,GAAK,WAAA,CAAY,IAAA,EAAM,UAAU,CAAA;AACvC,IAAA,IAAA,EAAK;AACL,IAAA,OAAO,MAAM;AAAE,MAAA,SAAA,GAAY,IAAA;AAAM,MAAA,aAAA,CAAc,EAAE,CAAA;AAAA,IAAG,CAAA;AAAA,EACtD,CAAA,EAAG,CAAC,OAAA,EAAS,UAAU,CAAC,CAAA;AAExB,EAAA,MAAM,OAAA,GAAU,WAAA,CAAY,MAAM,UAAA,CAAW,WAAA,CAAY,OAAO,CAAC,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAC7E,EAAA,OAAO,EAAE,SAAS,OAAA,EAAQ;AAC5B","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/undo/use-undo-stack.ts"],"names":[],"mappings":";;;AASO,SAAS,YAAA,CAAa,OAAA,EAAiB,UAAA,GAAa,GAAA,EAAK;AAC9D,EAAA,MAAM,CAAC,SAAS,UAAU,CAAA,GAAI,SAAS,MAAM,WAAA,CAAY,OAAO,CAAC,CAAA;AAEjE,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,MAAM,OAAO,MAAM;AACjB,MAAA,IAAI,SAAA,EAAW;AACf,MAAA,UAAA,CAAW,WAAA,CAAY,OAAO,CAAC,CAAA;AAAA,IACjC,CAAA;AACA,IAAA,MAAM,EAAA,GAAK,WAAA,CAAY,IAAA,EAAM,UAAU,CAAA;AACvC,IAAA,IAAA,EAAK;AACL,IAAA,OAAO,MAAM;AAAE,MAAA,SAAA,GAAY,IAAA;AAAM,MAAA,aAAA,CAAc,EAAE,CAAA;AAAA,IAAG,CAAA;AAAA,EACtD,CAAA,EAAG,CAAC,OAAA,EAAS,UAAU,CAAC,CAAA;AAExB,EAAA,MAAM,OAAA,GAAU,WAAA,CAAY,MAAM,UAAA,CAAW,WAAA,CAAY,OAAO,CAAC,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAC7E,EAAA,OAAO,EAAE,SAAS,OAAA,EAAQ;AAC5B","file":"chunk-RGO42EQ6.js","sourcesContent":["import { useState, useEffect, useCallback } from \"react\";\nimport { readHistory } from \"./undo-stack\";\n\n/**\n * useUndoStack — minimal React snapshot of an agent's history. Polls every\n * `intervalMs` (default 500). Use this to render an inline \"agent timeline\"\n * in a sidebar or activity panel. No subscription model in v1 — keeping it\n * simple; bridge mutations are infrequent enough that polling is fine.\n */\nexport function useUndoStack(agentId: string, intervalMs = 500) {\n const [history, setHistory] = useState(() => readHistory(agentId));\n\n useEffect(() => {\n let cancelled = false;\n const tick = () => {\n if (cancelled) return;\n setHistory(readHistory(agentId));\n };\n const id = setInterval(tick, intervalMs);\n tick();\n return () => { cancelled = true; clearInterval(id); };\n }, [agentId, intervalMs]);\n\n const refresh = useCallback(() => setHistory(readHistory(agentId)), [agentId]);\n return { history, refresh };\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { wrapToolWithActivity } from './chunk-52S7XYZK.js';
|
|
2
|
-
import { textResult, errorResult } from './chunk-
|
|
2
|
+
import { textResult, errorResult } from './chunk-4KAIV6OD.js';
|
|
3
3
|
|
|
4
4
|
// src/bridges/scene.ts
|
|
5
5
|
var DEFAULT_AGENT = { id: "agent", name: "Agent", color: "#a855f7" };
|
|
6
|
-
function registerSceneBridge(
|
|
6
|
+
function registerSceneBridge(host, options) {
|
|
7
7
|
const { adapter } = options;
|
|
8
8
|
const agent = { ...DEFAULT_AGENT, ...options.agent ?? {} };
|
|
9
9
|
const disposers = [];
|
|
@@ -29,7 +29,7 @@ function registerSceneBridge(server, options) {
|
|
|
29
29
|
resolveTarget: ({ args }) => target(objectIdFromArgs?.(args))
|
|
30
30
|
}) : wrapped;
|
|
31
31
|
disposers.push(
|
|
32
|
-
|
|
32
|
+
host.registerTool(
|
|
33
33
|
{ name, description, inputSchema: { type: "object", properties, required, additionalProperties: false } },
|
|
34
34
|
final
|
|
35
35
|
)
|
|
@@ -199,5 +199,5 @@ function parseTriple(v) {
|
|
|
199
199
|
}
|
|
200
200
|
|
|
201
201
|
export { registerSceneBridge };
|
|
202
|
-
//# sourceMappingURL=chunk-
|
|
203
|
-
//# sourceMappingURL=chunk-
|
|
202
|
+
//# sourceMappingURL=chunk-XRAJSOPS.js.map
|
|
203
|
+
//# sourceMappingURL=chunk-XRAJSOPS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/bridges/scene.ts"],"names":[],"mappings":"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","file":"chunk-XRAJSOPS.js","sourcesContent":["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 * Loose Scene types — mirror the public surface of fancy-3d's Scene\n * descriptor (engine-agnostic JSON the package's adapters consume).\n */\nexport type SceneObjectKind = \"box\" | \"sphere\" | \"cylinder\" | \"plane\" | \"screen\" | \"group\" | \"custom\";\n\nexport type SceneObject = {\n id: string;\n kind: SceneObjectKind | string;\n position?: [number, number, number];\n rotation?: [number, number, number];\n scale?: [number, number, number];\n color?: string;\n /** Free-form per-kind config (e.g. text content for screens). */\n props?: Record<string, unknown>;\n children?: SceneObject[];\n};\n\nexport type SceneCamera = {\n position?: [number, number, number];\n target?: [number, number, number];\n fov?: number;\n};\n\nexport type SceneState = {\n objects: SceneObject[];\n camera?: SceneCamera;\n background?: string;\n};\n\nexport type SceneBridgeAdapter = {\n id: string;\n title?: string;\n screenId?: string;\n getScene: () => SceneState;\n setScene: (next: SceneState) => void;\n /** Convenience: set just the camera without touching objects. */\n setCamera?: (next: SceneCamera) => void;\n};\n\nexport type SceneBridgeOptions = {\n adapter: SceneBridgeAdapter;\n agent?: { id: string; name?: string; color?: string };\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\n/**\n * registerSceneBridge — schema-aware MCP access to a fancy-3d Scene.\n * Tools cover read, add/update/delete object, set camera, set background.\n */\nexport function registerSceneBridge(\n host: ToolHost,\n options: SceneBridgeOptions,\n): Bridge {\n const { adapter } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const disposers: Array<() => void> = [];\n\n const target = (objectId?: string): AgentTarget => ({\n kind: \"scene\",\n screenId: adapter.screenId,\n elementId: objectId ? `${adapter.id}:${objectId}` : adapter.id,\n label: objectId ? `${adapter.title ?? adapter.id} → ${objectId}` : 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 objectIdFromArgs?: (args: JsonObject) => string | undefined,\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: \"scene\", screenId: adapter.screenId,\n resolveTarget: ({ args }) => target(objectIdFromArgs?.(args)),\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 const newId = (kind: string) => `${kind}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;\n\n // ───────────── Read ─────────────\n\n reg(\n \"scene_describe\",\n \"Describe the scene — object count, kinds, camera position.\",\n {},\n [],\n () => {\n const scene = adapter.getScene();\n const summary = {\n id: adapter.id,\n objectCount: scene.objects.length,\n kinds: scene.objects.map((o) => o.kind),\n camera: scene.camera,\n background: scene.background,\n };\n return textResult(JSON.stringify(summary, null, 2), summary);\n },\n false,\n );\n\n reg(\n \"scene_get_state\",\n \"Read the full SceneState (objects + camera + background).\",\n {},\n [],\n () => {\n const scene = adapter.getScene();\n return textResult(JSON.stringify(scene, null, 2), scene);\n },\n false,\n );\n\n // ───────────── Mutations ─────────────\n\n reg(\n \"scene_add_object\",\n \"Add an object to the scene root. Returns the new object's id.\",\n {\n kind: { type: \"string\", description: \"box | sphere | cylinder | plane | screen | group | custom kind\" },\n position: { type: \"array\", description: \"[x, y, z]\" },\n rotation: { type: \"array\", description: \"[x, y, z] euler\" },\n scale: { type: \"array\", description: \"[x, y, z]\" },\n color: { type: \"string\" },\n props: { type: \"object\", description: \"Per-kind config.\" },\n },\n [\"kind\"],\n (args) => {\n const obj: SceneObject = {\n id: newId(String(args.kind)),\n kind: String(args.kind),\n position: parseTriple(args.position),\n rotation: parseTriple(args.rotation),\n scale: parseTriple(args.scale),\n color: typeof args.color === \"string\" ? args.color : undefined,\n props: (args.props && typeof args.props === \"object\") ? args.props as Record<string, unknown> : undefined,\n };\n const scene = adapter.getScene();\n adapter.setScene({ ...scene, objects: [...scene.objects, obj] });\n return textResult(`Added ${obj.kind} ${obj.id}`, obj);\n },\n true,\n (args) => undefined, // id resolved from result.structuredContent.id\n );\n\n reg(\n \"scene_update_object\",\n \"Update fields on an object. Only provided fields change.\",\n {\n id: { type: \"string\" },\n position: { type: \"array\" },\n rotation: { type: \"array\" },\n scale: { type: \"array\" },\n color: { type: \"string\" },\n props: { type: \"object\" },\n },\n [\"id\"],\n (args) => {\n const id = String(args.id);\n const scene = adapter.getScene();\n const idx = scene.objects.findIndex((o) => o.id === id);\n if (idx === -1) return errorResult(`No object ${id}`);\n const orig = scene.objects[idx];\n const next: SceneObject = {\n ...orig,\n ...(args.position !== undefined ? { position: parseTriple(args.position) } : {}),\n ...(args.rotation !== undefined ? { rotation: parseTriple(args.rotation) } : {}),\n ...(args.scale !== undefined ? { scale: parseTriple(args.scale) } : {}),\n ...(args.color !== undefined ? { color: String(args.color) } : {}),\n ...(args.props && typeof args.props === \"object\" ? { props: { ...(orig.props ?? {}), ...(args.props as Record<string, unknown>) } } : {}),\n };\n const objects = [...scene.objects];\n objects[idx] = next;\n adapter.setScene({ ...scene, objects });\n return textResult(`Updated ${id}`, next);\n },\n true,\n (args) => String(args.id ?? \"\"),\n );\n\n reg(\n \"scene_delete_object\",\n \"Remove an object from the scene root.\",\n { id: { type: \"string\" } },\n [\"id\"],\n (args) => {\n const id = String(args.id);\n const scene = adapter.getScene();\n const next = scene.objects.filter((o) => o.id !== id);\n if (next.length === scene.objects.length) return errorResult(`No object ${id}`);\n adapter.setScene({ ...scene, objects: next });\n return textResult(`Deleted ${id}`);\n },\n true,\n (args) => String(args.id ?? \"\"),\n );\n\n reg(\n \"scene_set_camera\",\n \"Move the camera. Pass any subset of position/target/fov.\",\n {\n position: { type: \"array\", description: \"[x, y, z]\" },\n target: { type: \"array\", description: \"[x, y, z] look-at point\" },\n fov: { type: \"number\" },\n },\n [],\n (args) => {\n const scene = adapter.getScene();\n const next: SceneCamera = {\n ...(scene.camera ?? {}),\n ...(args.position !== undefined ? { position: parseTriple(args.position) } : {}),\n ...(args.target !== undefined ? { target: parseTriple(args.target) } : {}),\n ...(args.fov !== undefined ? { fov: Number(args.fov) } : {}),\n };\n if (adapter.setCamera) {\n adapter.setCamera(next);\n } else {\n adapter.setScene({ ...scene, camera: next });\n }\n return textResult(`Camera updated`, next);\n },\n true,\n );\n\n reg(\n \"scene_set_background\",\n \"Change the scene background color (CSS color).\",\n { color: { type: \"string\" } },\n [\"color\"],\n (args) => {\n const scene = adapter.getScene();\n adapter.setScene({ ...scene, background: String(args.color) });\n return textResult(`Background → ${args.color}`, { background: args.color });\n },\n true,\n );\n\n return {\n id: `scene:${adapter.id}`,\n title: adapter.title ?? adapter.id,\n dispose: () => { for (const d of disposers) d(); },\n };\n}\n\nfunction parseTriple(v: unknown): [number, number, number] | undefined {\n if (!Array.isArray(v) || v.length !== 3) return undefined;\n const out = v.map((x) => Number(x));\n if (out.some((x) => !Number.isFinite(x))) return undefined;\n return out as [number, number, number];\n}\n"]}
|