@particle-academy/agent-integrations 0.3.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -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 +2 -2
- 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-E4AICMFZ.js +83 -0
- package/dist/chunk-E4AICMFZ.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-4IAVAFUV.js → chunk-N3H4DXY5.js} +5 -5
- package/dist/chunk-N3H4DXY5.js.map +1 -0
- 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/index.cjs +320 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -4
- package/dist/index.d.ts +7 -4
- package/dist/index.js +15 -13
- 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 +1 -1
- 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 +3 -2
- package/dist/sharing/index.d.ts +3 -2
- package/dist/sheets-adapter.cjs +96 -0
- package/dist/sheets-adapter.cjs.map +1 -0
- package/dist/sheets-adapter.d.cts +115 -0
- package/dist/sheets-adapter.d.ts +115 -0
- package/dist/sheets-adapter.js +4 -0
- package/dist/sheets-adapter.js.map +1 -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 +1 -1
- package/dist/chunk-4IAVAFUV.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
package/README.md
CHANGED
|
@@ -16,6 +16,26 @@ npm install @particle-academy/agent-integrations
|
|
|
16
16
|
import "@particle-academy/agent-integrations/styles.css";
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
## When you don't need an MCP server
|
|
20
|
+
|
|
21
|
+
If your agent runs in the same JS process as the surfaces it drives (an embedded chat widget, an in-page worker, an SSR-time tool loop), you don't need any of MCP's JSON-RPC framing. Use **`ToolRegistry`** — a plain in-memory tool host that the bridges register against. Agents drive the surface with `host.callTool("sheet_set_cell", { … })` directly.
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import {
|
|
25
|
+
ToolRegistry,
|
|
26
|
+
registerSheetsBridge,
|
|
27
|
+
useSheetsAdapter,
|
|
28
|
+
} from "@particle-academy/agent-integrations";
|
|
29
|
+
|
|
30
|
+
const host = new ToolRegistry();
|
|
31
|
+
registerSheetsBridge(host, { adapter });
|
|
32
|
+
|
|
33
|
+
// in-process agent:
|
|
34
|
+
await host.callTool("sheet_set_cell", { address: "B3", value: 42 });
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Need both? `MicroMcpServer` extends `ToolRegistry`, so the same instance serves direct in-process calls **and** SSE-relayed remote agents at the same time. Bridges accept either — every `register*Bridge(host, …)` signature takes a `ToolHost`.
|
|
38
|
+
|
|
19
39
|
## Architecture
|
|
20
40
|
|
|
21
41
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { B as Bridge } from '../types-
|
|
3
|
-
import '../types-
|
|
1
|
+
import { T as ToolHost } from '../tool-host-BQuUygLF.cjs';
|
|
2
|
+
import { B as Bridge } from '../types-CCSBGW9T.cjs';
|
|
3
|
+
import '../types-aOQLTW0E.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Adapter wires a single fancy-echarts chart to the bridge. Charts are
|
|
@@ -34,6 +34,6 @@ type ChartsBridgeOptions = {
|
|
|
34
34
|
/**
|
|
35
35
|
* registerChartsBridge — schema-aware MCP access to a single chart.
|
|
36
36
|
*/
|
|
37
|
-
declare function registerChartsBridge(
|
|
37
|
+
declare function registerChartsBridge(host: ToolHost, options: ChartsBridgeOptions): Bridge;
|
|
38
38
|
|
|
39
39
|
export { type ChartsBridgeAdapter, type ChartsBridgeOptions, registerChartsBridge };
|
package/dist/bridges/charts.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { B as Bridge } from '../types-
|
|
3
|
-
import '../types-
|
|
1
|
+
import { T as ToolHost } from '../tool-host-C8JMMGYq.js';
|
|
2
|
+
import { B as Bridge } from '../types-DIVNcIQO.js';
|
|
3
|
+
import '../types-aOQLTW0E.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Adapter wires a single fancy-echarts chart to the bridge. Charts are
|
|
@@ -34,6 +34,6 @@ type ChartsBridgeOptions = {
|
|
|
34
34
|
/**
|
|
35
35
|
* registerChartsBridge — schema-aware MCP access to a single chart.
|
|
36
36
|
*/
|
|
37
|
-
declare function registerChartsBridge(
|
|
37
|
+
declare function registerChartsBridge(host: ToolHost, options: ChartsBridgeOptions): Bridge;
|
|
38
38
|
|
|
39
39
|
export { type ChartsBridgeAdapter, type ChartsBridgeOptions, registerChartsBridge };
|
package/dist/bridges/code.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { B as Bridge } from '../types-
|
|
3
|
-
import '../types-
|
|
1
|
+
import { T as ToolHost } from '../tool-host-BQuUygLF.cjs';
|
|
2
|
+
import { B as Bridge } from '../types-CCSBGW9T.cjs';
|
|
3
|
+
import '../types-aOQLTW0E.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Adapter the host wires to a fancy-code CodeEditor (typically via the
|
|
@@ -42,6 +42,6 @@ type CodeBridgeOptions = {
|
|
|
42
42
|
* switch, and a streaming append helper for "type characters into the
|
|
43
43
|
* editor over time" UX.
|
|
44
44
|
*/
|
|
45
|
-
declare function registerCodeBridge(
|
|
45
|
+
declare function registerCodeBridge(host: ToolHost, options: CodeBridgeOptions): Bridge;
|
|
46
46
|
|
|
47
47
|
export { type CodeBridgeAdapter, type CodeBridgeOptions, registerCodeBridge };
|
package/dist/bridges/code.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { B as Bridge } from '../types-
|
|
3
|
-
import '../types-
|
|
1
|
+
import { T as ToolHost } from '../tool-host-C8JMMGYq.js';
|
|
2
|
+
import { B as Bridge } from '../types-DIVNcIQO.js';
|
|
3
|
+
import '../types-aOQLTW0E.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Adapter the host wires to a fancy-code CodeEditor (typically via the
|
|
@@ -42,6 +42,6 @@ type CodeBridgeOptions = {
|
|
|
42
42
|
* switch, and a streaming append helper for "type characters into the
|
|
43
43
|
* editor over time" UX.
|
|
44
44
|
*/
|
|
45
|
-
declare function registerCodeBridge(
|
|
45
|
+
declare function registerCodeBridge(host: ToolHost, options: CodeBridgeOptions): Bridge;
|
|
46
46
|
|
|
47
47
|
export { type CodeBridgeAdapter, type CodeBridgeOptions, registerCodeBridge };
|
package/dist/bridges/flow.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { B as Bridge } from '../types-
|
|
3
|
-
import '../types-
|
|
1
|
+
import { T as ToolHost } from '../tool-host-BQuUygLF.cjs';
|
|
2
|
+
import { B as Bridge } from '../types-CCSBGW9T.cjs';
|
|
3
|
+
import '../types-aOQLTW0E.cjs';
|
|
4
4
|
|
|
5
5
|
type FlowNode = {
|
|
6
6
|
id: string;
|
|
@@ -68,6 +68,6 @@ type FlowBridgeOptions = {
|
|
|
68
68
|
* mutation tools (add / update / delete nodes + edges), and optional
|
|
69
69
|
* run/cancel if the host provides those callbacks.
|
|
70
70
|
*/
|
|
71
|
-
declare function registerFlowBridge(
|
|
71
|
+
declare function registerFlowBridge(host: ToolHost, options: FlowBridgeOptions): Bridge;
|
|
72
72
|
|
|
73
73
|
export { type FlowBridgeAdapter, type FlowBridgeOptions, registerFlowBridge };
|
package/dist/bridges/flow.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { B as Bridge } from '../types-
|
|
3
|
-
import '../types-
|
|
1
|
+
import { T as ToolHost } from '../tool-host-C8JMMGYq.js';
|
|
2
|
+
import { B as Bridge } from '../types-DIVNcIQO.js';
|
|
3
|
+
import '../types-aOQLTW0E.js';
|
|
4
4
|
|
|
5
5
|
type FlowNode = {
|
|
6
6
|
id: string;
|
|
@@ -68,6 +68,6 @@ type FlowBridgeOptions = {
|
|
|
68
68
|
* mutation tools (add / update / delete nodes + edges), and optional
|
|
69
69
|
* run/cancel if the host provides those callbacks.
|
|
70
70
|
*/
|
|
71
|
-
declare function registerFlowBridge(
|
|
71
|
+
declare function registerFlowBridge(host: ToolHost, options: FlowBridgeOptions): Bridge;
|
|
72
72
|
|
|
73
73
|
export { type FlowBridgeAdapter, type FlowBridgeOptions, registerFlowBridge };
|
package/dist/bridges/forms.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { B as Bridge } from '../types-
|
|
3
|
-
import '../types-
|
|
1
|
+
import { T as ToolHost } from '../tool-host-BQuUygLF.cjs';
|
|
2
|
+
import { B as Bridge } from '../types-CCSBGW9T.cjs';
|
|
3
|
+
import '../types-aOQLTW0E.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Field descriptor — what the host says about each form field. Mirrors the
|
|
@@ -71,6 +71,6 @@ type FormBridgeOptions = {
|
|
|
71
71
|
* Hosts can register multiple bridges (one per form on the screen) by
|
|
72
72
|
* giving each adapter a distinct `id`.
|
|
73
73
|
*/
|
|
74
|
-
declare function registerFormBridge(
|
|
74
|
+
declare function registerFormBridge(host: ToolHost, options: FormBridgeOptions): Bridge;
|
|
75
75
|
|
|
76
76
|
export { type FormBridgeAdapter, type FormBridgeOptions, type FormFieldDescriptor, registerFormBridge };
|
package/dist/bridges/forms.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { B as Bridge } from '../types-
|
|
3
|
-
import '../types-
|
|
1
|
+
import { T as ToolHost } from '../tool-host-C8JMMGYq.js';
|
|
2
|
+
import { B as Bridge } from '../types-DIVNcIQO.js';
|
|
3
|
+
import '../types-aOQLTW0E.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Field descriptor — what the host says about each form field. Mirrors the
|
|
@@ -71,6 +71,6 @@ type FormBridgeOptions = {
|
|
|
71
71
|
* Hosts can register multiple bridges (one per form on the screen) by
|
|
72
72
|
* giving each adapter a distinct `id`.
|
|
73
73
|
*/
|
|
74
|
-
declare function registerFormBridge(
|
|
74
|
+
declare function registerFormBridge(host: ToolHost, options: FormBridgeOptions): Bridge;
|
|
75
75
|
|
|
76
76
|
export { type FormBridgeAdapter, type FormBridgeOptions, type FormFieldDescriptor, registerFormBridge };
|
package/dist/bridges/scene.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { B as Bridge } from '../types-
|
|
3
|
-
import '../types-
|
|
1
|
+
import { T as ToolHost } from '../tool-host-BQuUygLF.cjs';
|
|
2
|
+
import { B as Bridge } from '../types-CCSBGW9T.cjs';
|
|
3
|
+
import '../types-aOQLTW0E.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Loose Scene types — mirror the public surface of fancy-3d's Scene
|
|
@@ -49,6 +49,6 @@ type SceneBridgeOptions = {
|
|
|
49
49
|
* registerSceneBridge — schema-aware MCP access to a fancy-3d Scene.
|
|
50
50
|
* Tools cover read, add/update/delete object, set camera, set background.
|
|
51
51
|
*/
|
|
52
|
-
declare function registerSceneBridge(
|
|
52
|
+
declare function registerSceneBridge(host: ToolHost, options: SceneBridgeOptions): Bridge;
|
|
53
53
|
|
|
54
54
|
export { type SceneBridgeAdapter, type SceneBridgeOptions, type SceneCamera, type SceneObject, type SceneObjectKind, type SceneState, registerSceneBridge };
|
package/dist/bridges/scene.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { B as Bridge } from '../types-
|
|
3
|
-
import '../types-
|
|
1
|
+
import { T as ToolHost } from '../tool-host-C8JMMGYq.js';
|
|
2
|
+
import { B as Bridge } from '../types-DIVNcIQO.js';
|
|
3
|
+
import '../types-aOQLTW0E.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Loose Scene types — mirror the public surface of fancy-3d's Scene
|
|
@@ -49,6 +49,6 @@ type SceneBridgeOptions = {
|
|
|
49
49
|
* registerSceneBridge — schema-aware MCP access to a fancy-3d Scene.
|
|
50
50
|
* Tools cover read, add/update/delete object, set camera, set background.
|
|
51
51
|
*/
|
|
52
|
-
declare function registerSceneBridge(
|
|
52
|
+
declare function registerSceneBridge(host: ToolHost, options: SceneBridgeOptions): Bridge;
|
|
53
53
|
|
|
54
54
|
export { type SceneBridgeAdapter, type SceneBridgeOptions, type SceneCamera, type SceneObject, type SceneObjectKind, type SceneState, registerSceneBridge };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { T as ToolHost } from '../tool-host-BQuUygLF.cjs';
|
|
2
|
+
import { B as Bridge } from '../types-CCSBGW9T.cjs';
|
|
3
|
+
import '../types-aOQLTW0E.cjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Loose snapshot of a screen — what's in fancy-screens' ScreenMeta plus
|
|
7
|
+
* the host's optional activity status. Kept here so this bridge has no
|
|
8
|
+
* hard dep on fancy-screens.
|
|
9
|
+
*/
|
|
10
|
+
type ScreenSnapshot = {
|
|
11
|
+
id: string;
|
|
12
|
+
title?: string;
|
|
13
|
+
/** Whether this screen is the one the human / agent is looking at. */
|
|
14
|
+
active: boolean;
|
|
15
|
+
/** Optional category / kind (e.g. "form", "whiteboard"). */
|
|
16
|
+
kind?: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Spec for a dynamically-created screen. The host's `createScreen`
|
|
20
|
+
* implementation looks up `kind` in its template registry and instantiates
|
|
21
|
+
* the matching surface (form / whiteboard / sheet / chart / markdown / etc.).
|
|
22
|
+
*/
|
|
23
|
+
type ScreenCreateSpec = {
|
|
24
|
+
id: string;
|
|
25
|
+
title?: string;
|
|
26
|
+
/** Template kind. Hosts decide the catalog. */
|
|
27
|
+
kind: string;
|
|
28
|
+
/** Template-specific config. Form: { fields }. Sheet: { headers }. etc. */
|
|
29
|
+
config?: Record<string, unknown>;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Adapter exposes the host's screen-navigation surface to the bridge.
|
|
33
|
+
* Hosts wire this up against react-router, a custom tab state, or the
|
|
34
|
+
* fancy-screens registry — wherever "current screen" lives.
|
|
35
|
+
*
|
|
36
|
+
* The optional create / destroy / update hooks let agents author screens
|
|
37
|
+
* dynamically against a host-defined template catalog.
|
|
38
|
+
*/
|
|
39
|
+
type ScreensBridgeAdapter = {
|
|
40
|
+
/** List every available screen. */
|
|
41
|
+
listScreens: () => ScreenSnapshot[];
|
|
42
|
+
/** Read which screen is currently active. */
|
|
43
|
+
getActive: () => string | null;
|
|
44
|
+
/** Navigate to a screen by id. Host updates router / tab state. */
|
|
45
|
+
setActive: (screenId: string) => void;
|
|
46
|
+
/** Optional: instantiate a new screen from a template + config. */
|
|
47
|
+
createScreen?: (spec: ScreenCreateSpec) => void;
|
|
48
|
+
/** Optional: remove a previously-created screen. */
|
|
49
|
+
destroyScreen?: (screenId: string) => void;
|
|
50
|
+
/** Optional: shallow-merge new config into an existing screen. */
|
|
51
|
+
updateScreenContent?: (screenId: string, partial: Record<string, unknown>) => void;
|
|
52
|
+
/** Optional: enumerate the kinds the host knows how to instantiate. */
|
|
53
|
+
listKinds?: () => Array<{
|
|
54
|
+
kind: string;
|
|
55
|
+
label?: string;
|
|
56
|
+
description?: string;
|
|
57
|
+
configSchema?: unknown;
|
|
58
|
+
}>;
|
|
59
|
+
};
|
|
60
|
+
type ScreensBridgeOptions = {
|
|
61
|
+
adapter: ScreensBridgeAdapter;
|
|
62
|
+
agent?: {
|
|
63
|
+
id: string;
|
|
64
|
+
name?: string;
|
|
65
|
+
color?: string;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* registerScreensBridge — top-level navigation bridge so agents can
|
|
70
|
+
* switch between screens (`screens_navigate`) and discover what surfaces
|
|
71
|
+
* exist (`screens_list`, `screens_describe_active`).
|
|
72
|
+
*
|
|
73
|
+
* Pair with the per-surface bridges (whiteboard, form, sheet, etc.) so
|
|
74
|
+
* the agent has both navigation and per-screen control.
|
|
75
|
+
*/
|
|
76
|
+
declare function registerScreensBridge(host: ToolHost, options: ScreensBridgeOptions): Bridge;
|
|
77
|
+
|
|
78
|
+
export { type ScreenCreateSpec, type ScreenSnapshot, type ScreensBridgeAdapter, type ScreensBridgeOptions, registerScreensBridge };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { T as ToolHost } from '../tool-host-C8JMMGYq.js';
|
|
2
|
+
import { B as Bridge } from '../types-DIVNcIQO.js';
|
|
3
|
+
import '../types-aOQLTW0E.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Loose snapshot of a screen — what's in fancy-screens' ScreenMeta plus
|
|
7
|
+
* the host's optional activity status. Kept here so this bridge has no
|
|
8
|
+
* hard dep on fancy-screens.
|
|
9
|
+
*/
|
|
10
|
+
type ScreenSnapshot = {
|
|
11
|
+
id: string;
|
|
12
|
+
title?: string;
|
|
13
|
+
/** Whether this screen is the one the human / agent is looking at. */
|
|
14
|
+
active: boolean;
|
|
15
|
+
/** Optional category / kind (e.g. "form", "whiteboard"). */
|
|
16
|
+
kind?: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Spec for a dynamically-created screen. The host's `createScreen`
|
|
20
|
+
* implementation looks up `kind` in its template registry and instantiates
|
|
21
|
+
* the matching surface (form / whiteboard / sheet / chart / markdown / etc.).
|
|
22
|
+
*/
|
|
23
|
+
type ScreenCreateSpec = {
|
|
24
|
+
id: string;
|
|
25
|
+
title?: string;
|
|
26
|
+
/** Template kind. Hosts decide the catalog. */
|
|
27
|
+
kind: string;
|
|
28
|
+
/** Template-specific config. Form: { fields }. Sheet: { headers }. etc. */
|
|
29
|
+
config?: Record<string, unknown>;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Adapter exposes the host's screen-navigation surface to the bridge.
|
|
33
|
+
* Hosts wire this up against react-router, a custom tab state, or the
|
|
34
|
+
* fancy-screens registry — wherever "current screen" lives.
|
|
35
|
+
*
|
|
36
|
+
* The optional create / destroy / update hooks let agents author screens
|
|
37
|
+
* dynamically against a host-defined template catalog.
|
|
38
|
+
*/
|
|
39
|
+
type ScreensBridgeAdapter = {
|
|
40
|
+
/** List every available screen. */
|
|
41
|
+
listScreens: () => ScreenSnapshot[];
|
|
42
|
+
/** Read which screen is currently active. */
|
|
43
|
+
getActive: () => string | null;
|
|
44
|
+
/** Navigate to a screen by id. Host updates router / tab state. */
|
|
45
|
+
setActive: (screenId: string) => void;
|
|
46
|
+
/** Optional: instantiate a new screen from a template + config. */
|
|
47
|
+
createScreen?: (spec: ScreenCreateSpec) => void;
|
|
48
|
+
/** Optional: remove a previously-created screen. */
|
|
49
|
+
destroyScreen?: (screenId: string) => void;
|
|
50
|
+
/** Optional: shallow-merge new config into an existing screen. */
|
|
51
|
+
updateScreenContent?: (screenId: string, partial: Record<string, unknown>) => void;
|
|
52
|
+
/** Optional: enumerate the kinds the host knows how to instantiate. */
|
|
53
|
+
listKinds?: () => Array<{
|
|
54
|
+
kind: string;
|
|
55
|
+
label?: string;
|
|
56
|
+
description?: string;
|
|
57
|
+
configSchema?: unknown;
|
|
58
|
+
}>;
|
|
59
|
+
};
|
|
60
|
+
type ScreensBridgeOptions = {
|
|
61
|
+
adapter: ScreensBridgeAdapter;
|
|
62
|
+
agent?: {
|
|
63
|
+
id: string;
|
|
64
|
+
name?: string;
|
|
65
|
+
color?: string;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* registerScreensBridge — top-level navigation bridge so agents can
|
|
70
|
+
* switch between screens (`screens_navigate`) and discover what surfaces
|
|
71
|
+
* exist (`screens_list`, `screens_describe_active`).
|
|
72
|
+
*
|
|
73
|
+
* Pair with the per-surface bridges (whiteboard, form, sheet, etc.) so
|
|
74
|
+
* the agent has both navigation and per-screen control.
|
|
75
|
+
*/
|
|
76
|
+
declare function registerScreensBridge(host: ToolHost, options: ScreensBridgeOptions): Bridge;
|
|
77
|
+
|
|
78
|
+
export { type ScreenCreateSpec, type ScreenSnapshot, type ScreensBridgeAdapter, type ScreensBridgeOptions, registerScreensBridge };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { B as Bridge } from '../types-
|
|
3
|
-
import '../types-
|
|
1
|
+
import { T as ToolHost } from '../tool-host-BQuUygLF.cjs';
|
|
2
|
+
import { B as Bridge } from '../types-CCSBGW9T.cjs';
|
|
3
|
+
import '../types-aOQLTW0E.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Loose types — kept here so the bridge builds without a hard dep on
|
|
@@ -57,6 +57,6 @@ type SheetsBridgeOptions = {
|
|
|
57
57
|
* Tools are sheet-aware (every mutator takes an explicit `sheet` id, defaulting
|
|
58
58
|
* to the active sheet when omitted) so an agent can author multi-sheet docs.
|
|
59
59
|
*/
|
|
60
|
-
declare function registerSheetsBridge(
|
|
60
|
+
declare function registerSheetsBridge(host: ToolHost, options: SheetsBridgeOptions): Bridge;
|
|
61
61
|
|
|
62
62
|
export { type SheetsBridgeAdapter, type SheetsBridgeOptions, registerSheetsBridge };
|
package/dist/bridges/sheets.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { B as Bridge } from '../types-
|
|
3
|
-
import '../types-
|
|
1
|
+
import { T as ToolHost } from '../tool-host-C8JMMGYq.js';
|
|
2
|
+
import { B as Bridge } from '../types-DIVNcIQO.js';
|
|
3
|
+
import '../types-aOQLTW0E.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Loose types — kept here so the bridge builds without a hard dep on
|
|
@@ -57,6 +57,6 @@ type SheetsBridgeOptions = {
|
|
|
57
57
|
* Tools are sheet-aware (every mutator takes an explicit `sheet` id, defaulting
|
|
58
58
|
* to the active sheet when omitted) so an agent can author multi-sheet docs.
|
|
59
59
|
*/
|
|
60
|
-
declare function registerSheetsBridge(
|
|
60
|
+
declare function registerSheetsBridge(host: ToolHost, options: SheetsBridgeOptions): Bridge;
|
|
61
61
|
|
|
62
62
|
export { type SheetsBridgeAdapter, type SheetsBridgeOptions, registerSheetsBridge };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { StickyNoteItem, ShapeItem, ConnectorItem, Stroke, Viewport, RemoteCursor } from '@particle-academy/fancy-whiteboard';
|
|
2
|
-
import {
|
|
3
|
-
import { B as Bridge } from '../types-
|
|
4
|
-
import '../types-
|
|
2
|
+
import { T as ToolHost } from '../tool-host-BQuUygLF.cjs';
|
|
3
|
+
import { B as Bridge } from '../types-CCSBGW9T.cjs';
|
|
4
|
+
import '../types-aOQLTW0E.cjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* State accessors / mutators the bridge needs from the host. The host owns
|
|
@@ -36,6 +36,6 @@ type WhiteboardBridgeOptions = {
|
|
|
36
36
|
* whiteboard session controlled by the host. Returns a Bridge handle the
|
|
37
37
|
* host can dispose to tear everything down.
|
|
38
38
|
*/
|
|
39
|
-
declare function registerWhiteboardBridge(
|
|
39
|
+
declare function registerWhiteboardBridge(host: ToolHost, options: WhiteboardBridgeOptions): Bridge;
|
|
40
40
|
|
|
41
41
|
export { type WhiteboardBridgeAdapter, type WhiteboardBridgeOptions, registerWhiteboardBridge };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { StickyNoteItem, ShapeItem, ConnectorItem, Stroke, Viewport, RemoteCursor } from '@particle-academy/fancy-whiteboard';
|
|
2
|
-
import {
|
|
3
|
-
import { B as Bridge } from '../types-
|
|
4
|
-
import '../types-
|
|
2
|
+
import { T as ToolHost } from '../tool-host-C8JMMGYq.js';
|
|
3
|
+
import { B as Bridge } from '../types-DIVNcIQO.js';
|
|
4
|
+
import '../types-aOQLTW0E.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* State accessors / mutators the bridge needs from the host. The host owns
|
|
@@ -36,6 +36,6 @@ type WhiteboardBridgeOptions = {
|
|
|
36
36
|
* whiteboard session controlled by the host. Returns a Bridge handle the
|
|
37
37
|
* host can dispose to tear everything down.
|
|
38
38
|
*/
|
|
39
|
-
declare function registerWhiteboardBridge(
|
|
39
|
+
declare function registerWhiteboardBridge(host: ToolHost, options: WhiteboardBridgeOptions): Bridge;
|
|
40
40
|
|
|
41
41
|
export { type WhiteboardBridgeAdapter, type WhiteboardBridgeOptions, registerWhiteboardBridge };
|
package/dist/bridges-charts.cjs
CHANGED
|
@@ -50,7 +50,7 @@ function extractMeta(result) {
|
|
|
50
50
|
|
|
51
51
|
// src/bridges/charts.ts
|
|
52
52
|
var DEFAULT_AGENT = { id: "agent", name: "Agent", color: "#a855f7" };
|
|
53
|
-
function registerChartsBridge(
|
|
53
|
+
function registerChartsBridge(host, options) {
|
|
54
54
|
const { adapter } = options;
|
|
55
55
|
const agent = { ...DEFAULT_AGENT, ...options.agent ?? {} };
|
|
56
56
|
const disposers = [];
|
|
@@ -76,7 +76,7 @@ function registerChartsBridge(server, options) {
|
|
|
76
76
|
resolveTarget: () => target
|
|
77
77
|
}) : wrapped;
|
|
78
78
|
disposers.push(
|
|
79
|
-
|
|
79
|
+
host.registerTool(
|
|
80
80
|
{ name, description, inputSchema: { type: "object", properties, required, additionalProperties: false } },
|
|
81
81
|
final
|
|
82
82
|
)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp/server.ts","../src/presence/registry.ts","../src/presence/wrap-tool-with-activity.ts","../src/bridges/charts.ts"],"names":[],"mappings":";;;AAqLO,SAAS,UAAA,CAAW,MAAc,UAAA,EAAkC;AACzE,EAAA,OAAO;AAAA,IACL,SAAS,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAM,CAAA;AAAA,IAChC,GAAI,UAAA,KAAe,MAAA,GAAY,EAAE,iBAAA,EAAmB,UAAA,KAAe;AAAC,GACtE;AACF;AAEO,SAAS,YAAY,IAAA,EAA8B;AACxD,EAAA,OAAO,EAAE,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,QAAQ,IAAA,EAAM,CAAA,EAAG,OAAA,EAAS,IAAA,EAAK;AAC5D;AChLA,IAAM,SAAA,uBAAgB,GAAA,EAA2B;AAI1C,SAAS,aAAa,KAAA,EAAiC;AAG5D,EAAA,KAAA,MAAW,CAAA,IAAK,SAAA,EAAW,CAAA,CAAE,KAAK,CAAA;AACpC;;;ACyBO,SAAS,oBAAA,CACd,SACA,OAAA,EAYoB;AACpB,EAAA,OAAO,OAAO,IAAA,KAAS;AACrB,IAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,IAAI,CAAA;AACjC,IAAA,IAAI,MAAA,CAAO,SAAS,OAAO,MAAA;AAE3B,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI,QAAQ,aAAA,EAAe;AACzB,MAAA,MAAA,GAAS,OAAA,CAAQ,cAAc,EAAE,QAAA,EAAU,QAAQ,QAAA,EAAU,IAAA,EAAM,QAAQ,CAAA;AAAA,IAC7E,CAAA,MAAO;AACL,MAAA,MAAA,GAAS,EAAE,IAAA,EAAM,OAAA,CAAQ,IAAA,EAAM,QAAA,EAAU,QAAQ,QAAA,EAAS;AAAA,IAC5D;AACA,IAAA,IAAI,CAAC,QAAQ,OAAO,MAAA;AAEpB,IAAA,YAAA,CAAa;AAAA,MACX,OAAA,EAAS,QAAQ,KAAA,CAAM,EAAA;AAAA,MACvB,SAAA,EAAW,QAAQ,KAAA,CAAM,IAAA;AAAA,MACzB,UAAA,EAAY,QAAQ,KAAA,CAAM,KAAA;AAAA,MAC1B,MAAA,EAAQ,EAAE,GAAG,MAAA,EAAQ,IAAA,EAAM,MAAA,CAAO,IAAA,IAAQ,OAAA,CAAQ,IAAA,EAAM,QAAA,EAAU,MAAA,CAAO,QAAA,IAAY,QAAQ,QAAA,EAAS;AAAA,MACtG,QAAQ,OAAA,CAAQ,QAAA;AAAA,MAChB,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,MACpB,IAAA,EAAM,YAAY,MAAM,CAAA;AAAA,MACxB,OAAO,OAAA,CAAQ;AAAA,KAChB,CAAA;AACD,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAEA,SAAS,YAAY,MAAA,EAA6D;AAChF,EAAA,MAAM,KAAK,MAAA,CAAO,iBAAA;AAClB,EAAA,IAAI,EAAA,IAAM,OAAO,EAAA,KAAO,QAAA,IAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,EAAE,CAAA,EAAG;AACtD,IAAA,OAAO,EAAA;AAAA,EACT;AACA,EAAA,OAAO,MAAA;AACT;;;AC5DA,IAAM,gBAAgB,EAAE,EAAA,EAAI,SAAS,IAAA,EAAM,OAAA,EAAS,OAAO,SAAA,EAAU;AAK9D,SAAS,oBAAA,CACd,QACA,OAAA,EACQ;AACR,EAAA,MAAM,EAAE,SAAQ,GAAI,OAAA;AACpB,EAAA,MAAM,KAAA,GAAQ,EAAE,GAAG,aAAA,EAAe,GAAI,OAAA,CAAQ,KAAA,IAAS,EAAC,EAAG;AAC3D,EAAA,MAAM,YAA+B,EAAC;AAEtC,EAAA,MAAM,MAAA,GAAsB;AAAA,IAC1B,IAAA,EAAM,OAAA;AAAA,IACN,UAAU,OAAA,CAAQ,QAAA;AAAA,IAClB,WAAW,OAAA,CAAQ,EAAA;AAAA,IACnB,KAAA,EAAO,OAAA,CAAQ,KAAA,IAAS,OAAA,CAAQ;AAAA,GAClC;AAEA,EAAA,MAAM,MAAM,CACV,IAAA,EACA,aACA,UAAA,EACA,QAAA,EACA,SACA,UAAA,KACG;AACH,IAAA,MAAM,OAAA,GAAU,OAAO,IAAA,KAAqB;AAC1C,MAAA,IAAI;AAAE,QAAA,OAAO,MAAM,QAAQ,IAAI,CAAA;AAAA,MAAG,SAC3B,CAAA,EAAG;AAAE,QAAA,OAAO,YAAY,CAAA,YAAa,KAAA,GAAQ,EAAE,OAAA,GAAU,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,MAAG;AAAA,IAC9E,CAAA;AACA,IAAA,MAAM,KAAA,GAAQ,UAAA,GACV,oBAAA,CAAqB,OAAA,EAAS;AAAA,MAC5B,QAAA,EAAU,IAAA;AAAA,MAAM,KAAA;AAAA,MAAO,IAAA,EAAM,OAAA;AAAA,MAAS,UAAU,OAAA,CAAQ,QAAA;AAAA,MACxD,eAAe,MAAM;AAAA,KACtB,CAAA,GACD,OAAA;AACJ,IAAA,SAAA,CAAU,IAAA;AAAA,MACR,MAAA,CAAO,YAAA;AAAA,QACL,EAAE,IAAA,EAAM,WAAA,EAAa,WAAA,EAAa,EAAE,IAAA,EAAM,QAAA,EAAU,UAAA,EAA+B,QAAA,EAAU,oBAAA,EAAsB,KAAA,EAAM,EAAE;AAAA,QAC3H;AAAA;AACF,KACF;AAAA,EACF,CAAA;AAEA,EAAA,GAAA;AAAA,IACE,gBAAA;AAAA,IACA,CAAA,oBAAA,EAAuB,QAAQ,EAAE,CAAA,+CAAA,CAAA;AAAA,IACjC,EAAC;AAAA,IACD,EAAC;AAAA,IACD,MAAM;AACJ,MAAA,MAAM,GAAA,GAAM,QAAQ,SAAA,EAAU;AAC9B,MAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA,GAAI,GAAA,CAAI,SAAS,EAAC;AACzD,MAAA,MAAM,OAAA,GAAU;AAAA,QACd,IAAI,OAAA,CAAQ,EAAA;AAAA,QACZ,OAAO,OAAA,CAAQ,KAAA;AAAA,QACf,aAAa,MAAA,CAAO,MAAA;AAAA,QACpB,aAAa,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,KAAW,CAAA,EAAG,QAAQ,SAAS,CAAA;AAAA,QACxD,QAAA,EAAU,CAAC,CAAC,GAAA,CAAI,KAAA;AAAA,QAChB,QAAA,EAAU,CAAC,CAAC,GAAA,CAAI;AAAA,OAClB;AACA,MAAA,OAAO,UAAA,CAAW,IAAA,CAAK,SAAA,CAAU,OAAO,GAAG,OAAO,CAAA;AAAA,IACpD,CAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,GAAA;AAAA,IACE,kBAAA;AAAA,IACA,6DAAA;AAAA,IACA,EAAC;AAAA,IACD,EAAC;AAAA,IACD,MAAM;AACJ,MAAA,MAAM,GAAA,GAAM,QAAQ,SAAA,EAAU;AAC9B,MAAA,OAAO,WAAW,IAAA,CAAK,SAAA,CAAU,KAAK,IAAA,EAAM,CAAC,GAAG,GAAG,CAAA;AAAA,IACrD,CAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,GAAA;AAAA,IACE,kBAAA;AAAA,IACA,iFAAA;AAAA,IACA,EAAE,MAAA,EAAQ,EAAE,IAAA,EAAM,UAAS,EAAE;AAAA,IAC7B,CAAC,QAAQ,CAAA;AAAA,IACT,CAAC,IAAA,KAAS;AACR,MAAA,MAAM,GAAA,GAAO,KAAK,MAAA,IAAU,OAAO,KAAK,MAAA,KAAW,QAAA,GAAY,IAAA,CAAK,MAAA,GAAoC,EAAC;AACzG,MAAA,OAAA,CAAQ,UAAU,GAAG,CAAA;AACrB,MAAA,OAAO,UAAA,CAAW,uBAAA,EAAyB,EAAG,CAAA;AAAA,IAChD,CAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,GAAA;AAAA,IACE,qBAAA;AAAA,IACA,gFAAA;AAAA,IACA,EAAE,OAAA,EAAS,EAAE,IAAA,EAAM,UAAS,EAAE;AAAA,IAC9B,CAAC,SAAS,CAAA;AAAA,IACV,CAAC,IAAA,KAAS;AACR,MAAA,MAAM,OAAA,GAAW,KAAK,OAAA,IAAW,OAAO,KAAK,OAAA,KAAY,QAAA,GAAY,IAAA,CAAK,OAAA,GAAqC,EAAC;AAChH,MAAA,IAAI,QAAQ,YAAA,EAAc;AACxB,QAAA,OAAA,CAAQ,aAAa,OAAO,CAAA;AAAA,MAC9B,CAAA,MAAO;AACL,QAAA,OAAA,CAAQ,SAAA,CAAU,EAAE,GAAG,OAAA,CAAQ,WAAU,EAAG,GAAG,SAAS,CAAA;AAAA,MAC1D;AACA,MAAA,OAAO,UAAA,CAAW,uBAAuB,EAAE,IAAA,EAAM,OAAO,IAAA,CAAK,OAAO,GAAG,CAAA;AAAA,IACzE,CAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,GAAA;AAAA,IACE,mBAAA;AAAA,IACA,2FAAA;AAAA,IACA,EAAE,IAAA,EAAM,EAAE,WAAA,EAAa,oEAAmE,EAAE;AAAA,IAC5F,CAAC,MAAM,CAAA;AAAA,IACP,CAAC,IAAA,KAAS;AACR,MAAA,IAAI,CAAC,OAAA,CAAQ,UAAA,EAAY,OAAO,YAAY,kCAAkC,CAAA;AAC9E,MAAA,OAAA,CAAQ,UAAA,CAAW,KAAK,IAAI,CAAA;AAC5B,MAAA,OAAO,UAAA,CAAW,oBAAA,EAAsB,EAAG,CAAA;AAAA,IAC7C,CAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,CAAA,MAAA,EAAS,OAAA,CAAQ,EAAE,CAAA,CAAA;AAAA,IACvB,KAAA,EAAO,OAAA,CAAQ,KAAA,IAAS,OAAA,CAAQ,EAAA;AAAA,IAChC,SAAS,MAAM;AAAE,MAAA,KAAA,MAAW,CAAA,IAAK,WAAW,CAAA,EAAE;AAAA,IAAG;AAAA,GACnD;AACF","file":"bridges-charts.cjs","sourcesContent":["import {\n type CallToolResult,\n type JsonObject,\n type JsonRpcMessage,\n type JsonRpcRequest,\n type JsonRpcId,\n type RegisteredTool,\n type ServerCapabilities,\n type ServerInfo,\n type ToolDefinition,\n type ToolHandler,\n JSONRPC_INTERNAL_ERROR,\n JSONRPC_INVALID_PARAMS,\n JSONRPC_METHOD_NOT_FOUND,\n MCP_PROTOCOL_VERSION,\n} from \"./types\";\n\nexport type McpServerOptions = {\n info: ServerInfo;\n /** Defaults to { tools: { listChanged: true } } */\n capabilities?: ServerCapabilities;\n /** Free-text instructions surfaced to clients during initialize. */\n instructions?: string;\n};\n\nexport type Transport = {\n /** Called by the server when it has a message to deliver to the client. */\n send: (message: JsonRpcMessage) => void;\n /** Called by the server when it's torn down so the transport can clean up. */\n close?: () => void;\n};\n\n/**\n * MicroMcpServer — protocol-level MCP server, transport-agnostic.\n *\n * Use it like:\n *\n * const server = new MicroMcpServer({ info: { name: \"session\", version: \"0.1\" } });\n * server.registerTool({ name: \"...\", inputSchema: { type: \"object\" } }, async (args) => ({...}));\n * const transport = new InProcessTransport();\n * server.attach(transport);\n * transport.deliver({ ... }); // client → server frames\n *\n * The same server can serve multiple transports (e.g. an in-process agent\n * AND a relayed external client) by attaching each one.\n */\nexport class MicroMcpServer {\n private tools = new Map<string, RegisteredTool>();\n private transports = new Set<Transport>();\n private notifyListChangedScheduled = false;\n\n readonly info: ServerInfo;\n readonly capabilities: ServerCapabilities;\n readonly instructions?: string;\n\n constructor(options: McpServerOptions) {\n this.info = options.info;\n this.capabilities = options.capabilities ?? { tools: { listChanged: true } };\n this.instructions = options.instructions;\n }\n\n attach(transport: Transport): () => void {\n this.transports.add(transport);\n return () => this.detach(transport);\n }\n\n detach(transport: Transport): void {\n if (this.transports.delete(transport)) {\n transport.close?.();\n }\n }\n\n registerTool(definition: ToolDefinition, handler: ToolHandler): () => void {\n this.tools.set(definition.name, { definition, handler });\n this.scheduleListChangedNotification();\n return () => this.unregisterTool(definition.name);\n }\n\n unregisterTool(name: string): void {\n if (this.tools.delete(name)) {\n this.scheduleListChangedNotification();\n }\n }\n\n listTools(): ToolDefinition[] {\n return Array.from(this.tools.values()).map((t) => t.definition);\n }\n\n /**\n * Receive a JSON-RPC frame from a client (called by the transport).\n * The transport is responsible for sending the response back.\n */\n async receive(transport: Transport, message: JsonRpcMessage): Promise<void> {\n if (!(\"method\" in message)) return; // It's a response, not a request — ignore.\n\n const isNotification = !(\"id\" in message);\n if (isNotification) {\n // Notifications are fire-and-forget. We ignore unknown methods.\n return;\n }\n\n const request = message as JsonRpcRequest;\n try {\n const result = await this.handle(request);\n transport.send({ jsonrpc: \"2.0\", id: request.id, result });\n } catch (err) {\n transport.send({\n jsonrpc: \"2.0\",\n id: request.id,\n error: this.toRpcError(err),\n });\n }\n }\n\n private async handle(request: JsonRpcRequest): Promise<any> {\n const { method, params } = request;\n switch (method) {\n case \"initialize\":\n return {\n protocolVersion: MCP_PROTOCOL_VERSION,\n capabilities: this.capabilities,\n serverInfo: this.info,\n ...(this.instructions ? { instructions: this.instructions } : {}),\n };\n\n case \"tools/list\":\n return { tools: this.listTools() };\n\n case \"tools/call\": {\n const name = params?.name;\n const args = (params?.arguments ?? {}) as JsonObject;\n if (typeof name !== \"string\") {\n throw rpcError(JSONRPC_INVALID_PARAMS, \"tools/call requires `name`\");\n }\n const tool = this.tools.get(name);\n if (!tool) {\n throw rpcError(JSONRPC_METHOD_NOT_FOUND, `Unknown tool: ${name}`);\n }\n const result = await tool.handler(args);\n return result satisfies CallToolResult;\n }\n\n case \"ping\":\n return {};\n\n default:\n throw rpcError(JSONRPC_METHOD_NOT_FOUND, `Unsupported method: ${method}`);\n }\n }\n\n private scheduleListChangedNotification(): void {\n if (this.notifyListChangedScheduled) return;\n this.notifyListChangedScheduled = true;\n queueMicrotask(() => {\n this.notifyListChangedScheduled = false;\n this.broadcast({ jsonrpc: \"2.0\", method: \"notifications/tools/list_changed\" });\n });\n }\n\n private broadcast(message: JsonRpcMessage): void {\n for (const t of this.transports) t.send(message);\n }\n\n private toRpcError(err: unknown): { code: number; message: string; data?: any } {\n if (err && typeof err === \"object\" && \"code\" in err && \"message\" in err) {\n return err as any;\n }\n return {\n code: JSONRPC_INTERNAL_ERROR,\n message: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\nexport function rpcError(code: number, message: string, data?: any) {\n return { code, message, ...(data !== undefined ? { data } : {}) };\n}\n\n/**\n * Helper to build a CallToolResult from a string or structured value.\n */\nexport function textResult(text: string, structured?: any): CallToolResult {\n return {\n content: [{ type: \"text\", text }],\n ...(structured !== undefined ? { structuredContent: structured } : {}),\n };\n}\n\nexport function errorResult(text: string): CallToolResult {\n return { content: [{ type: \"text\", text }], isError: true };\n}\n\n// Internal helper so the JsonRpcId import isn't dropped by tsup\ntype _KeepIdImport = JsonRpcId;\n","import type { 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 type { CallToolResult } from \"../mcp/types\";\nimport { emitActivity } from \"./registry\";\nimport type { AgentTarget } from \"./types\";\n\nexport type ActivityAgent = { id: string; name?: string; color?: string };\n\nexport type ActivityResolverContext<TArgs = Record<string, unknown>> = {\n /** Tool name as registered. */\n toolName: string;\n /** Arguments the tool was called with. */\n args: TArgs;\n /** The CallToolResult the underlying handler produced. */\n result: CallToolResult;\n};\n\n/**\n * Resolves an `AgentTarget` for an executed tool. Bridges declare one of\n * these per registration so the wrapper knows which surface / element /\n * screen the activity belongs to.\n *\n * The resolver runs AFTER the tool handler so it can inspect the result\n * (e.g. read a newly-created item id from `structuredContent`).\n */\nexport type ActivityTargetResolver<TArgs = Record<string, unknown>> = (\n ctx: ActivityResolverContext<TArgs>,\n) => AgentTarget | null;\n\nexport type ToolHandler<TArgs = Record<string, unknown>> = (\n args: TArgs,\n) => Promise<CallToolResult> | CallToolResult;\n\n/**\n * wrapToolWithActivity — decorate a bridge tool handler so every successful\n * call emits an `AgentActivityEvent`. Returns a new handler with the same shape.\n *\n * Usage in a bridge:\n *\n * server.registerTool(\n * definition,\n * wrapToolWithActivity(\n * handler,\n * { agent, kind: \"whiteboard\", resolveTarget: ({ args }) => ({\n * kind: \"whiteboard\", elementId: args.id as string,\n * }) },\n * ),\n * );\n */\nexport function wrapToolWithActivity<TArgs = Record<string, unknown>>(\n handler: ToolHandler<TArgs>,\n options: {\n toolName: string;\n agent: ActivityAgent;\n /** Optional fancy-screens screen id this bridge is scoped to. */\n screenId?: string;\n /** Default target kind if the resolver returns one without `kind`. */\n kind: AgentTarget[\"kind\"];\n /** Per-call resolver. Return `null` to skip emitting (e.g. for read-only tools). */\n resolveTarget?: ActivityTargetResolver<TArgs>;\n /** Optional ttl override. */\n ttlMs?: number;\n },\n): ToolHandler<TArgs> {\n return async (args) => {\n const result = await handler(args);\n if (result.isError) return result;\n\n let target: AgentTarget | null;\n if (options.resolveTarget) {\n target = options.resolveTarget({ toolName: options.toolName, args, result });\n } else {\n target = { kind: options.kind, screenId: options.screenId };\n }\n if (!target) return result;\n\n emitActivity({\n agentId: options.agent.id,\n agentName: options.agent.name,\n agentColor: options.agent.color,\n target: { ...target, kind: target.kind ?? options.kind, screenId: target.screenId ?? options.screenId },\n action: options.toolName,\n timestamp: Date.now(),\n meta: extractMeta(result),\n ttlMs: options.ttlMs,\n });\n return result;\n };\n}\n\nfunction extractMeta(result: CallToolResult): Record<string, unknown> | undefined {\n const sc = result.structuredContent;\n if (sc && typeof sc === \"object\" && !Array.isArray(sc)) {\n return sc as Record<string, unknown>;\n }\n return undefined;\n}\n","import { textResult, errorResult } from \"../mcp/server\";\nimport type { MicroMcpServer } from \"../mcp/server\";\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 server: MicroMcpServer,\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 server.registerTool(\n { name, description, inputSchema: { type: \"object\", properties: properties as any, required, additionalProperties: false } },\n final as any,\n ),\n );\n };\n\n reg(\n \"chart_describe\",\n `Describe the chart \"${adapter.id}\" — series count, type guesses, axis info.`,\n {},\n [],\n () => {\n const opt = adapter.getOption();\n const series = Array.isArray(opt.series) ? opt.series : [];\n const summary = {\n id: adapter.id,\n title: adapter.title,\n seriesCount: series.length,\n seriesTypes: series.map((s: any) => s?.type ?? \"unknown\"),\n hasXAxis: !!opt.xAxis,\n hasYAxis: !!opt.yAxis,\n };\n return textResult(JSON.stringify(summary), summary);\n },\n false,\n );\n\n reg(\n \"chart_get_option\",\n \"Read the full ECharts option object the chart is rendering.\",\n {},\n [],\n () => {\n const opt = adapter.getOption();\n return textResult(JSON.stringify(opt, null, 2), opt);\n },\n false,\n );\n\n reg(\n \"chart_set_option\",\n \"Replace the entire ECharts option. Use chart_update_option for partial updates.\",\n { option: { type: \"object\" } },\n [\"option\"],\n (args) => {\n const opt = (args.option && typeof args.option === \"object\") ? args.option as Record<string, unknown> : {};\n adapter.setOption(opt);\n return textResult(\"Replaced chart option\", { });\n },\n true,\n );\n\n reg(\n \"chart_update_option\",\n \"Shallow-merge a partial option update — only the keys you provide change.\",\n { partial: { type: \"object\" } },\n [\"partial\"],\n (args) => {\n const partial = (args.partial && typeof args.partial === \"object\") ? args.partial as Record<string, unknown> : {};\n if (adapter.updateOption) {\n adapter.updateOption(partial);\n } else {\n adapter.setOption({ ...adapter.getOption(), ...partial });\n }\n return textResult(\"Merged chart option\", { keys: Object.keys(partial) });\n },\n true,\n );\n\n reg(\n \"chart_update_data\",\n \"Update only the data (typically the `series` field). Leaves layout / axes / colors alone.\",\n { data: { description: \"New series array (or whatever shape the host's adapter expects).\" } },\n [\"data\"],\n (args) => {\n if (!adapter.updateData) return errorResult(\"Host did not provide updateData.\");\n adapter.updateData(args.data);\n return textResult(\"Updated chart data\", { });\n },\n true,\n );\n\n return {\n id: `chart:${adapter.id}`,\n title: adapter.title ?? adapter.id,\n dispose: () => { for (const d of disposers) d(); },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/mcp/server.ts","../src/presence/registry.ts","../src/presence/wrap-tool-with-activity.ts","../src/bridges/charts.ts"],"names":[],"mappings":"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","file":"bridges-charts.cjs","sourcesContent":["import {\n type CallToolResult,\n type JsonObject,\n type JsonRpcMessage,\n type JsonRpcRequest,\n type JsonRpcId,\n type RegisteredTool,\n type ServerCapabilities,\n type ServerInfo,\n type ToolDefinition,\n type ToolHandler,\n JSONRPC_INTERNAL_ERROR,\n JSONRPC_INVALID_PARAMS,\n JSONRPC_METHOD_NOT_FOUND,\n MCP_PROTOCOL_VERSION,\n} from \"./types\";\nimport { ToolRegistry } from \"./tool-host\";\n\nexport type McpServerOptions = {\n info: ServerInfo;\n /** Defaults to { tools: { listChanged: true } } */\n capabilities?: ServerCapabilities;\n /** Free-text instructions surfaced to clients during initialize. */\n instructions?: string;\n};\n\nexport type Transport = {\n /** Called by the server when it has a message to deliver to the client. */\n send: (message: JsonRpcMessage) => void;\n /** Called by the server when it's torn down so the transport can clean up. */\n close?: () => void;\n};\n\n/**\n * MicroMcpServer — protocol-level MCP server, transport-agnostic.\n *\n * Use it like:\n *\n * const server = new MicroMcpServer({ info: { name: \"session\", version: \"0.1\" } });\n * server.registerTool({ name: \"...\", inputSchema: { type: \"object\" } }, async (args) => ({...}));\n * const transport = new InProcessTransport();\n * server.attach(transport);\n * transport.deliver({ ... }); // client → server frames\n *\n * The same server can serve multiple transports (e.g. an in-process agent\n * AND a relayed external client) by attaching each one.\n */\nexport class MicroMcpServer extends ToolRegistry {\n private transports = new Set<Transport>();\n private notifyListChangedScheduled = false;\n\n readonly info: ServerInfo;\n readonly capabilities: ServerCapabilities;\n readonly instructions?: string;\n\n constructor(options: McpServerOptions) {\n super();\n this.info = options.info;\n this.capabilities = options.capabilities ?? { tools: { listChanged: true } };\n this.instructions = options.instructions;\n }\n\n attach(transport: Transport): () => void {\n this.transports.add(transport);\n return () => this.detach(transport);\n }\n\n detach(transport: Transport): void {\n if (this.transports.delete(transport)) {\n transport.close?.();\n }\n }\n\n unregisterTool(name: string): void {\n if (this.tools.delete(name)) {\n this.scheduleListChangedNotification();\n }\n }\n\n protected onToolsChanged(): void {\n this.scheduleListChangedNotification();\n }\n\n /**\n * Receive a JSON-RPC frame from a client (called by the transport).\n * The transport is responsible for sending the response back.\n */\n async receive(transport: Transport, message: JsonRpcMessage): Promise<void> {\n if (!(\"method\" in message)) return; // It's a response, not a request — ignore.\n\n const isNotification = !(\"id\" in message);\n if (isNotification) {\n // Notifications are fire-and-forget. We ignore unknown methods.\n return;\n }\n\n const request = message as JsonRpcRequest;\n try {\n const result = await this.handle(request);\n transport.send({ jsonrpc: \"2.0\", id: request.id, result });\n } catch (err) {\n transport.send({\n jsonrpc: \"2.0\",\n id: request.id,\n error: this.toRpcError(err),\n });\n }\n }\n\n private async handle(request: JsonRpcRequest): Promise<any> {\n const { method, params } = request;\n switch (method) {\n case \"initialize\":\n return {\n protocolVersion: MCP_PROTOCOL_VERSION,\n capabilities: this.capabilities,\n serverInfo: this.info,\n ...(this.instructions ? { instructions: this.instructions } : {}),\n };\n\n case \"tools/list\":\n return { tools: this.listTools() };\n\n case \"tools/call\": {\n const name = params?.name;\n const args = (params?.arguments ?? {}) as JsonObject;\n if (typeof name !== \"string\") {\n throw rpcError(JSONRPC_INVALID_PARAMS, \"tools/call requires `name`\");\n }\n const tool = this.tools.get(name);\n if (!tool) {\n throw rpcError(JSONRPC_METHOD_NOT_FOUND, `Unknown tool: ${name}`);\n }\n const result = await tool.handler(args);\n return result satisfies CallToolResult;\n }\n\n case \"ping\":\n return {};\n\n default:\n throw rpcError(JSONRPC_METHOD_NOT_FOUND, `Unsupported method: ${method}`);\n }\n }\n\n private scheduleListChangedNotification(): void {\n if (this.notifyListChangedScheduled) return;\n this.notifyListChangedScheduled = true;\n queueMicrotask(() => {\n this.notifyListChangedScheduled = false;\n this.broadcast({ jsonrpc: \"2.0\", method: \"notifications/tools/list_changed\" });\n });\n }\n\n private broadcast(message: JsonRpcMessage): void {\n for (const t of this.transports) t.send(message);\n }\n\n private toRpcError(err: unknown): { code: number; message: string; data?: any } {\n if (err && typeof err === \"object\" && \"code\" in err && \"message\" in err) {\n return err as any;\n }\n return {\n code: JSONRPC_INTERNAL_ERROR,\n message: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\nexport function rpcError(code: number, message: string, data?: any) {\n return { code, message, ...(data !== undefined ? { data } : {}) };\n}\n\n/**\n * Helper to build a CallToolResult from a string or structured value.\n */\nexport function textResult(text: string, structured?: any): CallToolResult {\n return {\n content: [{ type: \"text\", text }],\n ...(structured !== undefined ? { structuredContent: structured } : {}),\n };\n}\n\nexport function errorResult(text: string): CallToolResult {\n return { content: [{ type: \"text\", text }], isError: true };\n}\n\n// Internal helper so the JsonRpcId import isn't dropped by tsup\ntype _KeepIdImport = JsonRpcId;\n","import type { 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 type { CallToolResult } from \"../mcp/types\";\nimport { emitActivity } from \"./registry\";\nimport type { AgentTarget } from \"./types\";\n\nexport type ActivityAgent = { id: string; name?: string; color?: string };\n\nexport type ActivityResolverContext<TArgs = Record<string, unknown>> = {\n /** Tool name as registered. */\n toolName: string;\n /** Arguments the tool was called with. */\n args: TArgs;\n /** The CallToolResult the underlying handler produced. */\n result: CallToolResult;\n};\n\n/**\n * Resolves an `AgentTarget` for an executed tool. Bridges declare one of\n * these per registration so the wrapper knows which surface / element /\n * screen the activity belongs to.\n *\n * The resolver runs AFTER the tool handler so it can inspect the result\n * (e.g. read a newly-created item id from `structuredContent`).\n */\nexport type ActivityTargetResolver<TArgs = Record<string, unknown>> = (\n ctx: ActivityResolverContext<TArgs>,\n) => AgentTarget | null;\n\nexport type ToolHandler<TArgs = Record<string, unknown>> = (\n args: TArgs,\n) => Promise<CallToolResult> | CallToolResult;\n\n/**\n * wrapToolWithActivity — decorate a bridge tool handler so every successful\n * call emits an `AgentActivityEvent`. Returns a new handler with the same shape.\n *\n * Usage in a bridge:\n *\n * server.registerTool(\n * definition,\n * wrapToolWithActivity(\n * handler,\n * { agent, kind: \"whiteboard\", resolveTarget: ({ args }) => ({\n * kind: \"whiteboard\", elementId: args.id as string,\n * }) },\n * ),\n * );\n */\nexport function wrapToolWithActivity<TArgs = Record<string, unknown>>(\n handler: ToolHandler<TArgs>,\n options: {\n toolName: string;\n agent: ActivityAgent;\n /** Optional fancy-screens screen id this bridge is scoped to. */\n screenId?: string;\n /** Default target kind if the resolver returns one without `kind`. */\n kind: AgentTarget[\"kind\"];\n /** Per-call resolver. Return `null` to skip emitting (e.g. for read-only tools). */\n resolveTarget?: ActivityTargetResolver<TArgs>;\n /** Optional ttl override. */\n ttlMs?: number;\n },\n): ToolHandler<TArgs> {\n return async (args) => {\n const result = await handler(args);\n if (result.isError) return result;\n\n let target: AgentTarget | null;\n if (options.resolveTarget) {\n target = options.resolveTarget({ toolName: options.toolName, args, result });\n } else {\n target = { kind: options.kind, screenId: options.screenId };\n }\n if (!target) return result;\n\n emitActivity({\n agentId: options.agent.id,\n agentName: options.agent.name,\n agentColor: options.agent.color,\n target: { ...target, kind: target.kind ?? options.kind, screenId: target.screenId ?? options.screenId },\n action: options.toolName,\n timestamp: Date.now(),\n meta: extractMeta(result),\n ttlMs: options.ttlMs,\n });\n return result;\n };\n}\n\nfunction extractMeta(result: CallToolResult): Record<string, unknown> | undefined {\n const sc = result.structuredContent;\n if (sc && typeof sc === \"object\" && !Array.isArray(sc)) {\n return sc as Record<string, unknown>;\n }\n return undefined;\n}\n","import { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport type { AgentTarget } from \"../presence/types\";\n\n/**\n * Adapter wires a single fancy-echarts chart to the bridge. Charts are\n * already prop-driven, so the adapter just exposes the data + option\n * setters and a way to read what's currently rendered.\n */\nexport type ChartsBridgeAdapter = {\n /** Stable id for this chart instance. */\n id: string;\n title?: string;\n screenId?: string;\n /** Read the current ECharts option object the chart is rendering. */\n getOption: () => Record<string, unknown>;\n /** Replace the entire option. */\n setOption: (option: Record<string, unknown>) => void;\n /** Convenience: shallow-merge a partial option update. */\n updateOption?: (partial: Record<string, unknown>) => void;\n /** Read just the data series (subset of option for quick agent reads). */\n getData?: () => unknown;\n /** Update only the data, leaving axes/colors/etc. alone. */\n updateData?: (data: unknown) => void;\n};\n\nexport type ChartsBridgeOptions = {\n adapter: ChartsBridgeAdapter;\n agent?: { id: string; name?: string; color?: string };\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\n/**\n * registerChartsBridge — schema-aware MCP access to a single chart.\n */\nexport function registerChartsBridge(\n host: ToolHost,\n options: ChartsBridgeOptions,\n): Bridge {\n const { adapter } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const disposers: Array<() => void> = [];\n\n const target: AgentTarget = {\n kind: \"chart\",\n screenId: adapter.screenId,\n elementId: adapter.id,\n label: adapter.title ?? adapter.id,\n };\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<any> | any,\n isMutation: boolean,\n ) => {\n const wrapped = async (args: JsonObject) => {\n try { return await handler(args); }\n catch (e) { return errorResult(e instanceof Error ? e.message : String(e)); }\n };\n const final = isMutation\n ? wrapToolWithActivity(wrapped, {\n toolName: name, agent, kind: \"chart\", screenId: adapter.screenId,\n resolveTarget: () => target,\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n { name, description, inputSchema: { type: \"object\", properties: properties as any, required, additionalProperties: false } },\n final as any,\n ),\n );\n };\n\n reg(\n \"chart_describe\",\n `Describe the chart \"${adapter.id}\" — series count, type guesses, axis info.`,\n {},\n [],\n () => {\n const opt = adapter.getOption();\n const series = Array.isArray(opt.series) ? opt.series : [];\n const summary = {\n id: adapter.id,\n title: adapter.title,\n seriesCount: series.length,\n seriesTypes: series.map((s: any) => s?.type ?? \"unknown\"),\n hasXAxis: !!opt.xAxis,\n hasYAxis: !!opt.yAxis,\n };\n return textResult(JSON.stringify(summary), summary);\n },\n false,\n );\n\n reg(\n \"chart_get_option\",\n \"Read the full ECharts option object the chart is rendering.\",\n {},\n [],\n () => {\n const opt = adapter.getOption();\n return textResult(JSON.stringify(opt, null, 2), opt);\n },\n false,\n );\n\n reg(\n \"chart_set_option\",\n \"Replace the entire ECharts option. Use chart_update_option for partial updates.\",\n { option: { type: \"object\" } },\n [\"option\"],\n (args) => {\n const opt = (args.option && typeof args.option === \"object\") ? args.option as Record<string, unknown> : {};\n adapter.setOption(opt);\n return textResult(\"Replaced chart option\", { });\n },\n true,\n );\n\n reg(\n \"chart_update_option\",\n \"Shallow-merge a partial option update — only the keys you provide change.\",\n { partial: { type: \"object\" } },\n [\"partial\"],\n (args) => {\n const partial = (args.partial && typeof args.partial === \"object\") ? args.partial as Record<string, unknown> : {};\n if (adapter.updateOption) {\n adapter.updateOption(partial);\n } else {\n adapter.setOption({ ...adapter.getOption(), ...partial });\n }\n return textResult(\"Merged chart option\", { keys: Object.keys(partial) });\n },\n true,\n );\n\n reg(\n \"chart_update_data\",\n \"Update only the data (typically the `series` field). Leaves layout / axes / colors alone.\",\n { data: { description: \"New series array (or whatever shape the host's adapter expects).\" } },\n [\"data\"],\n (args) => {\n if (!adapter.updateData) return errorResult(\"Host did not provide updateData.\");\n adapter.updateData(args.data);\n return textResult(\"Updated chart data\", { });\n },\n true,\n );\n\n return {\n id: `chart:${adapter.id}`,\n title: adapter.title ?? adapter.id,\n dispose: () => { for (const d of disposers) d(); },\n };\n}\n"]}
|
package/dist/bridges-charts.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { registerChartsBridge } from './chunk-
|
|
1
|
+
export { registerChartsBridge } from './chunk-NTDZWGYB.js';
|
|
2
2
|
import './chunk-52S7XYZK.js';
|
|
3
3
|
import './chunk-JU2N4KK6.js';
|
|
4
|
-
import './chunk-
|
|
4
|
+
import './chunk-4KAIV6OD.js';
|
|
5
5
|
//# sourceMappingURL=bridges-charts.js.map
|
|
6
6
|
//# sourceMappingURL=bridges-charts.js.map
|
package/dist/bridges-code.cjs
CHANGED
|
@@ -50,7 +50,7 @@ function extractMeta(result) {
|
|
|
50
50
|
|
|
51
51
|
// src/bridges/code.ts
|
|
52
52
|
var DEFAULT_AGENT = { id: "agent", name: "Agent", color: "#a855f7" };
|
|
53
|
-
function registerCodeBridge(
|
|
53
|
+
function registerCodeBridge(host, options) {
|
|
54
54
|
const { adapter } = options;
|
|
55
55
|
const agent = { ...DEFAULT_AGENT, ...options.agent ?? {} };
|
|
56
56
|
const disposers = [];
|
|
@@ -76,7 +76,7 @@ function registerCodeBridge(server, options) {
|
|
|
76
76
|
resolveTarget: () => target
|
|
77
77
|
}) : wrapped;
|
|
78
78
|
disposers.push(
|
|
79
|
-
|
|
79
|
+
host.registerTool(
|
|
80
80
|
{
|
|
81
81
|
name,
|
|
82
82
|
description,
|