@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,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
|
+
backgroundColor: 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 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"]}
|
|
@@ -0,0 +1,119 @@
|
|
|
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
|
+
}>;
|
|
43
|
+
activeSheetId: string;
|
|
44
|
+
};
|
|
45
|
+
type SheetsAdapterOptions = {
|
|
46
|
+
/** Tags the bridge's screen id so presence events route correctly. */
|
|
47
|
+
screenId?: string;
|
|
48
|
+
};
|
|
49
|
+
type UseSheetsAdapterResult<W extends WorkbookLike> = {
|
|
50
|
+
/** Controlled workbook state. Wire to `<SheetWorkbook data={…} />`. */
|
|
51
|
+
workbook: W;
|
|
52
|
+
/** Setter for the controlled state. Wire to `<SheetWorkbook onChange={…} />`. */
|
|
53
|
+
setWorkbook: (next: W) => void;
|
|
54
|
+
/** Wire to `<SheetWorkbook onActiveCellChange={…} />` to track focus. */
|
|
55
|
+
onActiveCellChange: (address: string) => void;
|
|
56
|
+
/** Stable adapter to hand to `registerSheetsBridge({ adapter })`. */
|
|
57
|
+
adapter: SheetsBridgeAdapter;
|
|
58
|
+
/** Imperative: set the active sheet + cell. Mirrors the adapter's hook. */
|
|
59
|
+
setActiveCell: (sheetId: string, address: string) => void;
|
|
60
|
+
/** Read-only: the address last focused (any source). */
|
|
61
|
+
activeCell: string | null;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* useSheetsAdapter — one-liner glue between fancy-sheets' SheetWorkbook
|
|
65
|
+
* and the sheets bridge.
|
|
66
|
+
*
|
|
67
|
+
* const wb = useSheetsAdapter(initialWorkbook, { screenId: "..." });
|
|
68
|
+
*
|
|
69
|
+
* useEffect(() => registerSheetsBridge(host, { adapter: wb.adapter }).dispose,
|
|
70
|
+
* [host, wb.adapter]);
|
|
71
|
+
*
|
|
72
|
+
* <SheetWorkbook
|
|
73
|
+
* data={wb.workbook}
|
|
74
|
+
* onChange={wb.setWorkbook}
|
|
75
|
+
* onActiveCellChange={wb.onActiveCellChange}
|
|
76
|
+
* />
|
|
77
|
+
*/
|
|
78
|
+
declare function useSheetsAdapter<W extends WorkbookLike>(initial: W, options?: SheetsAdapterOptions): UseSheetsAdapterResult<W>;
|
|
79
|
+
/**
|
|
80
|
+
* Mirror of fancy-sheets' `CellHighlight` — structurally identical so the
|
|
81
|
+
* map returned from {@link useSheetsActivityHighlights} can be passed
|
|
82
|
+
* straight into `<SheetWorkbook highlights={…} />` without any casts.
|
|
83
|
+
*
|
|
84
|
+
* Fields match `@particle-academy/fancy-sheets` exactly:
|
|
85
|
+
* - `color: string` (required) — border/outline color
|
|
86
|
+
* - `backgroundColor?: string` — auto-derived from `color` if omitted
|
|
87
|
+
* - `label?: string` — small badge in the cell's top-left corner
|
|
88
|
+
*/
|
|
89
|
+
type SheetsCellHighlight = {
|
|
90
|
+
/** Border/outline color (any CSS color value). Required. */
|
|
91
|
+
color: string;
|
|
92
|
+
/** Background tint; if omitted, derived from `color` at low alpha. */
|
|
93
|
+
backgroundColor?: string;
|
|
94
|
+
/** Optional label rendered in a chip on the cell. */
|
|
95
|
+
label?: string;
|
|
96
|
+
};
|
|
97
|
+
type SheetsCellHighlightMap = Record<string, SheetsCellHighlight>;
|
|
98
|
+
type SheetsHighlightOptions = {
|
|
99
|
+
/** Only include events for this screen (recommended). */
|
|
100
|
+
screenId?: string;
|
|
101
|
+
/** Highlight TTL in ms before a hit fades from the map. Default 2200. */
|
|
102
|
+
ttlMs?: number;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* useSheetsActivityHighlights — subscribe to the presence registry,
|
|
106
|
+
* produce a CellHighlightMap reflecting recent sheet-bridge activity.
|
|
107
|
+
*
|
|
108
|
+
* Pass the result straight into `<SheetWorkbook highlights={…} />`. Each
|
|
109
|
+
* agent edit pulses in the agent's color for `ttlMs` then fades out.
|
|
110
|
+
*
|
|
111
|
+
* The bridge's target shape is `${sheetId}!${address}` — this hook
|
|
112
|
+
* filters for the currently-active sheet and exposes only its cells.
|
|
113
|
+
*
|
|
114
|
+
* const highlights = useSheetsActivityHighlights({ screenId: "deal-sheet" });
|
|
115
|
+
* <SheetWorkbook highlights={highlights} … />
|
|
116
|
+
*/
|
|
117
|
+
declare function useSheetsActivityHighlights(options?: SheetsHighlightOptions): SheetsCellHighlightMap;
|
|
118
|
+
|
|
119
|
+
export { type SheetsAdapterOptions, type SheetsCellHighlight, type SheetsCellHighlightMap, type SheetsHighlightOptions, type UseSheetsAdapterResult, type WorkbookLike, useSheetsActivityHighlights, useSheetsAdapter };
|
|
@@ -0,0 +1,119 @@
|
|
|
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
|
+
}>;
|
|
43
|
+
activeSheetId: string;
|
|
44
|
+
};
|
|
45
|
+
type SheetsAdapterOptions = {
|
|
46
|
+
/** Tags the bridge's screen id so presence events route correctly. */
|
|
47
|
+
screenId?: string;
|
|
48
|
+
};
|
|
49
|
+
type UseSheetsAdapterResult<W extends WorkbookLike> = {
|
|
50
|
+
/** Controlled workbook state. Wire to `<SheetWorkbook data={…} />`. */
|
|
51
|
+
workbook: W;
|
|
52
|
+
/** Setter for the controlled state. Wire to `<SheetWorkbook onChange={…} />`. */
|
|
53
|
+
setWorkbook: (next: W) => void;
|
|
54
|
+
/** Wire to `<SheetWorkbook onActiveCellChange={…} />` to track focus. */
|
|
55
|
+
onActiveCellChange: (address: string) => void;
|
|
56
|
+
/** Stable adapter to hand to `registerSheetsBridge({ adapter })`. */
|
|
57
|
+
adapter: SheetsBridgeAdapter;
|
|
58
|
+
/** Imperative: set the active sheet + cell. Mirrors the adapter's hook. */
|
|
59
|
+
setActiveCell: (sheetId: string, address: string) => void;
|
|
60
|
+
/** Read-only: the address last focused (any source). */
|
|
61
|
+
activeCell: string | null;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* useSheetsAdapter — one-liner glue between fancy-sheets' SheetWorkbook
|
|
65
|
+
* and the sheets bridge.
|
|
66
|
+
*
|
|
67
|
+
* const wb = useSheetsAdapter(initialWorkbook, { screenId: "..." });
|
|
68
|
+
*
|
|
69
|
+
* useEffect(() => registerSheetsBridge(host, { adapter: wb.adapter }).dispose,
|
|
70
|
+
* [host, wb.adapter]);
|
|
71
|
+
*
|
|
72
|
+
* <SheetWorkbook
|
|
73
|
+
* data={wb.workbook}
|
|
74
|
+
* onChange={wb.setWorkbook}
|
|
75
|
+
* onActiveCellChange={wb.onActiveCellChange}
|
|
76
|
+
* />
|
|
77
|
+
*/
|
|
78
|
+
declare function useSheetsAdapter<W extends WorkbookLike>(initial: W, options?: SheetsAdapterOptions): UseSheetsAdapterResult<W>;
|
|
79
|
+
/**
|
|
80
|
+
* Mirror of fancy-sheets' `CellHighlight` — structurally identical so the
|
|
81
|
+
* map returned from {@link useSheetsActivityHighlights} can be passed
|
|
82
|
+
* straight into `<SheetWorkbook highlights={…} />` without any casts.
|
|
83
|
+
*
|
|
84
|
+
* Fields match `@particle-academy/fancy-sheets` exactly:
|
|
85
|
+
* - `color: string` (required) — border/outline color
|
|
86
|
+
* - `backgroundColor?: string` — auto-derived from `color` if omitted
|
|
87
|
+
* - `label?: string` — small badge in the cell's top-left corner
|
|
88
|
+
*/
|
|
89
|
+
type SheetsCellHighlight = {
|
|
90
|
+
/** Border/outline color (any CSS color value). Required. */
|
|
91
|
+
color: string;
|
|
92
|
+
/** Background tint; if omitted, derived from `color` at low alpha. */
|
|
93
|
+
backgroundColor?: string;
|
|
94
|
+
/** Optional label rendered in a chip on the cell. */
|
|
95
|
+
label?: string;
|
|
96
|
+
};
|
|
97
|
+
type SheetsCellHighlightMap = Record<string, SheetsCellHighlight>;
|
|
98
|
+
type SheetsHighlightOptions = {
|
|
99
|
+
/** Only include events for this screen (recommended). */
|
|
100
|
+
screenId?: string;
|
|
101
|
+
/** Highlight TTL in ms before a hit fades from the map. Default 2200. */
|
|
102
|
+
ttlMs?: number;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* useSheetsActivityHighlights — subscribe to the presence registry,
|
|
106
|
+
* produce a CellHighlightMap reflecting recent sheet-bridge activity.
|
|
107
|
+
*
|
|
108
|
+
* Pass the result straight into `<SheetWorkbook highlights={…} />`. Each
|
|
109
|
+
* agent edit pulses in the agent's color for `ttlMs` then fades out.
|
|
110
|
+
*
|
|
111
|
+
* The bridge's target shape is `${sheetId}!${address}` — this hook
|
|
112
|
+
* filters for the currently-active sheet and exposes only its cells.
|
|
113
|
+
*
|
|
114
|
+
* const highlights = useSheetsActivityHighlights({ screenId: "deal-sheet" });
|
|
115
|
+
* <SheetWorkbook highlights={highlights} … />
|
|
116
|
+
*/
|
|
117
|
+
declare function useSheetsActivityHighlights(options?: SheetsHighlightOptions): SheetsCellHighlightMap;
|
|
118
|
+
|
|
119
|
+
export { type SheetsAdapterOptions, type SheetsCellHighlight, type SheetsCellHighlightMap, type SheetsHighlightOptions, type UseSheetsAdapterResult, type WorkbookLike, useSheetsActivityHighlights, useSheetsAdapter };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"sheets-adapter.js"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-token utilities. The token is a high-entropy secret; possession
|
|
3
|
+
* grants read/write on the session. We don't HMAC frames — frames carry
|
|
4
|
+
* the token directly (which is fine for in-process / same-origin / TLS
|
|
5
|
+
* transports). For lower-trust transports, host apps can layer signing
|
|
6
|
+
* on top of the BroadcastChannelTransport.
|
|
7
|
+
*/
|
|
8
|
+
type SessionDescriptor = {
|
|
9
|
+
/** Stable session identifier. Channel name = `fai:share:${id}`. */
|
|
10
|
+
id: string;
|
|
11
|
+
/** Secret token. Treat as a password — anyone with it can read/write. */
|
|
12
|
+
token: string;
|
|
13
|
+
/** Pretty hash for display (first 8 chars of token). */
|
|
14
|
+
display: string;
|
|
15
|
+
};
|
|
16
|
+
declare function createSessionDescriptor(): SessionDescriptor;
|
|
17
|
+
declare function describeSession(id: string, token: string): SessionDescriptor;
|
|
18
|
+
/** Build the shareable URL for the current page (preserves path, adds session+token). */
|
|
19
|
+
declare function buildShareUrl(descriptor: SessionDescriptor, baseUrl?: string): string;
|
|
20
|
+
/** Build the JSON config form (suitable for Claude Desktop / Cline / etc.). */
|
|
21
|
+
declare function buildShareConfig(descriptor: SessionDescriptor, transport?: string): {
|
|
22
|
+
name: string;
|
|
23
|
+
transport: string;
|
|
24
|
+
session: string;
|
|
25
|
+
token: string;
|
|
26
|
+
channel: string;
|
|
27
|
+
protocol_version: string;
|
|
28
|
+
};
|
|
29
|
+
/** Read session descriptor from current URL, or null if not a shared link. */
|
|
30
|
+
declare function readSessionFromUrl(): SessionDescriptor | null;
|
|
31
|
+
/** Constant-time string compare so a mismatched token leaks no timing info. */
|
|
32
|
+
declare function constantTimeEqual(a: string, b: string): boolean;
|
|
33
|
+
|
|
34
|
+
export { type SessionDescriptor as S, buildShareUrl as a, buildShareConfig as b, createSessionDescriptor as c, describeSession as d, constantTimeEqual as e, readSessionFromUrl as r };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-token utilities. The token is a high-entropy secret; possession
|
|
3
|
+
* grants read/write on the session. We don't HMAC frames — frames carry
|
|
4
|
+
* the token directly (which is fine for in-process / same-origin / TLS
|
|
5
|
+
* transports). For lower-trust transports, host apps can layer signing
|
|
6
|
+
* on top of the BroadcastChannelTransport.
|
|
7
|
+
*/
|
|
8
|
+
type SessionDescriptor = {
|
|
9
|
+
/** Stable session identifier. Channel name = `fai:share:${id}`. */
|
|
10
|
+
id: string;
|
|
11
|
+
/** Secret token. Treat as a password — anyone with it can read/write. */
|
|
12
|
+
token: string;
|
|
13
|
+
/** Pretty hash for display (first 8 chars of token). */
|
|
14
|
+
display: string;
|
|
15
|
+
};
|
|
16
|
+
declare function createSessionDescriptor(): SessionDescriptor;
|
|
17
|
+
declare function describeSession(id: string, token: string): SessionDescriptor;
|
|
18
|
+
/** Build the shareable URL for the current page (preserves path, adds session+token). */
|
|
19
|
+
declare function buildShareUrl(descriptor: SessionDescriptor, baseUrl?: string): string;
|
|
20
|
+
/** Build the JSON config form (suitable for Claude Desktop / Cline / etc.). */
|
|
21
|
+
declare function buildShareConfig(descriptor: SessionDescriptor, transport?: string): {
|
|
22
|
+
name: string;
|
|
23
|
+
transport: string;
|
|
24
|
+
session: string;
|
|
25
|
+
token: string;
|
|
26
|
+
channel: string;
|
|
27
|
+
protocol_version: string;
|
|
28
|
+
};
|
|
29
|
+
/** Read session descriptor from current URL, or null if not a shared link. */
|
|
30
|
+
declare function readSessionFromUrl(): SessionDescriptor | null;
|
|
31
|
+
/** Constant-time string compare so a mismatched token leaks no timing info. */
|
|
32
|
+
declare function constantTimeEqual(a: string, b: string): boolean;
|
|
33
|
+
|
|
34
|
+
export { type SessionDescriptor as S, buildShareUrl as a, buildShareConfig as b, createSessionDescriptor as c, describeSession as d, constantTimeEqual as e, readSessionFromUrl as r };
|
|
@@ -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 };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { T as ToolDefinition, b as ToolHandler, R as RegisteredTool, c as JsonObject, C as CallToolResult } from './types-aOQLTW0E.js';
|
|
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 };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { T as ToolHost } from './tool-host-BQuUygLF.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Bridge — registers a cohesive set of MCP tools/resources for a single
|
|
@@ -13,6 +13,6 @@ type Bridge = {
|
|
|
13
13
|
/** Disposes the bridge. Must remove every tool it registered. */
|
|
14
14
|
dispose: () => void;
|
|
15
15
|
};
|
|
16
|
-
type BridgeFactory<TOptions> = (
|
|
16
|
+
type BridgeFactory<TOptions> = (host: ToolHost, options: TOptions) => Bridge;
|
|
17
17
|
|
|
18
18
|
export type { Bridge as B, BridgeFactory as a };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { T as ToolHost } from './tool-host-C8JMMGYq.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Bridge — registers a cohesive set of MCP tools/resources for a single
|
|
@@ -13,6 +13,6 @@ type Bridge = {
|
|
|
13
13
|
/** Disposes the bridge. Must remove every tool it registered. */
|
|
14
14
|
dispose: () => void;
|
|
15
15
|
};
|
|
16
|
-
type BridgeFactory<TOptions> = (
|
|
16
|
+
type BridgeFactory<TOptions> = (host: ToolHost, options: TOptions) => Bridge;
|
|
17
17
|
|
|
18
18
|
export type { Bridge as B, BridgeFactory as a };
|
|
@@ -109,4 +109,4 @@ type RegisteredTool = {
|
|
|
109
109
|
};
|
|
110
110
|
declare const MCP_PROTOCOL_VERSION = "2025-06-18";
|
|
111
111
|
|
|
112
|
-
export { type CallToolResult as C, type InitializeResult as I, type JsonRpcMessage as J, MCP_PROTOCOL_VERSION as M, type RegisteredTool as R, type ServerInfo as S, type ToolDefinition as T, type ServerCapabilities as a, type ToolHandler as b, type
|
|
112
|
+
export { type CallToolResult as C, type InitializeResult as I, type JsonRpcMessage as J, MCP_PROTOCOL_VERSION as M, type RegisteredTool as R, type ServerInfo as S, type ToolDefinition as T, type ServerCapabilities as a, type ToolHandler as b, type JsonObject as c, type ContentBlock as d, type JsonRpcNotification as e, type JsonRpcRequest as f, type JsonValue as g, JSONRPC_INTERNAL_ERROR as h, JSONRPC_INVALID_PARAMS as i, JSONRPC_INVALID_REQUEST as j, JSONRPC_METHOD_NOT_FOUND as k, JSONRPC_PARSE_ERROR as l, type JsonRpcError as m, type JsonRpcId as n, type JsonRpcSuccess as o, type ToolInputSchema as p };
|
|
@@ -109,4 +109,4 @@ type RegisteredTool = {
|
|
|
109
109
|
};
|
|
110
110
|
declare const MCP_PROTOCOL_VERSION = "2025-06-18";
|
|
111
111
|
|
|
112
|
-
export { type CallToolResult as C, type InitializeResult as I, type JsonRpcMessage as J, MCP_PROTOCOL_VERSION as M, type RegisteredTool as R, type ServerInfo as S, type ToolDefinition as T, type ServerCapabilities as a, type ToolHandler as b, type
|
|
112
|
+
export { type CallToolResult as C, type InitializeResult as I, type JsonRpcMessage as J, MCP_PROTOCOL_VERSION as M, type RegisteredTool as R, type ServerInfo as S, type ToolDefinition as T, type ServerCapabilities as a, type ToolHandler as b, type JsonObject as c, type ContentBlock as d, type JsonRpcNotification as e, type JsonRpcRequest as f, type JsonValue as g, JSONRPC_INTERNAL_ERROR as h, JSONRPC_INVALID_PARAMS as i, JSONRPC_INVALID_REQUEST as j, JSONRPC_METHOD_NOT_FOUND as k, JSONRPC_PARSE_ERROR as l, type JsonRpcError as m, type JsonRpcId as n, type JsonRpcSuccess as o, type ToolInputSchema as p };
|
package/dist/undo/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import '../types-
|
|
1
|
+
import { T as ToolHost } from '../tool-host-BQuUygLF.cjs';
|
|
2
|
+
import '../types-aOQLTW0E.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Generic undo/redo stack keyed by `agentId`. Each entry holds:
|
|
@@ -48,12 +48,12 @@ type UndoToolsOptions = {
|
|
|
48
48
|
* ensureUndoToolsRegistered — bridges call this on construction. Safe to
|
|
49
49
|
* call repeatedly with the same server; subsequent calls are no-ops.
|
|
50
50
|
*/
|
|
51
|
-
declare function ensureUndoToolsRegistered(
|
|
51
|
+
declare function ensureUndoToolsRegistered(host: ToolHost, options?: UndoToolsOptions): void;
|
|
52
52
|
/**
|
|
53
53
|
* registerUndoTools — add agent_undo / agent_redo / agent_history to the
|
|
54
54
|
* server. Returns a disposer that unregisters all three.
|
|
55
55
|
*/
|
|
56
|
-
declare function registerUndoTools(
|
|
56
|
+
declare function registerUndoTools(host: ToolHost, options?: UndoToolsOptions): () => void;
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
59
|
* useUndoStack — minimal React snapshot of an agent's history. Polls every
|