@nimblebrain/synapse 0.10.2 → 0.12.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +1 -0
  2. package/dist/chunk-3HQGHPNC.js +20 -0
  3. package/dist/chunk-3HQGHPNC.js.map +1 -0
  4. package/dist/{chunk-74EGUVGE.cjs → chunk-A4ENX6XW.cjs} +7 -79
  5. package/dist/chunk-A4ENX6XW.cjs.map +1 -0
  6. package/dist/chunk-ANUZ7WFQ.cjs +476 -0
  7. package/dist/chunk-ANUZ7WFQ.cjs.map +1 -0
  8. package/dist/chunk-JVKQNMAP.js +463 -0
  9. package/dist/chunk-JVKQNMAP.js.map +1 -0
  10. package/dist/chunk-KTXASIFJ.cjs +75 -0
  11. package/dist/chunk-KTXASIFJ.cjs.map +1 -0
  12. package/dist/chunk-RX6XCLFF.cjs +23 -0
  13. package/dist/chunk-RX6XCLFF.cjs.map +1 -0
  14. package/dist/chunk-VXTMI266.js +73 -0
  15. package/dist/chunk-VXTMI266.js.map +1 -0
  16. package/dist/{chunk-S7QIWD46.js → chunk-XGJAADVV.js} +4 -75
  17. package/dist/chunk-XGJAADVV.js.map +1 -0
  18. package/dist/codegen/index.cjs +5 -5
  19. package/dist/codegen/index.js +1 -1
  20. package/dist/connect.iife.global.js +18 -18
  21. package/dist/detect-DSnLT-_m.d.cts +171 -0
  22. package/dist/detect-DSnLT-_m.d.ts +171 -0
  23. package/dist/host/index.cjs +57 -0
  24. package/dist/host/index.cjs.map +1 -0
  25. package/dist/host/index.d.cts +68 -0
  26. package/dist/host/index.d.ts +68 -0
  27. package/dist/host/index.js +4 -0
  28. package/dist/host/index.js.map +1 -0
  29. package/dist/index.cjs +21 -3
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +1 -0
  32. package/dist/index.d.ts +1 -0
  33. package/dist/index.js +3 -1
  34. package/dist/index.js.map +1 -1
  35. package/dist/react/index.cjs +5 -4
  36. package/dist/react/index.cjs.map +1 -1
  37. package/dist/react/index.js +2 -1
  38. package/dist/react/index.js.map +1 -1
  39. package/dist/synapse-runtime.iife.global.js +18 -18
  40. package/dist/synapse-ui.iife.global.js +1 -0
  41. package/dist/ui/base.cjs +13 -0
  42. package/dist/ui/base.cjs.map +1 -0
  43. package/dist/ui/base.d.cts +27 -0
  44. package/dist/ui/base.d.ts +27 -0
  45. package/dist/ui/base.js +7 -0
  46. package/dist/ui/base.js.map +1 -0
  47. package/dist/ui/index.cjs +14 -24
  48. package/dist/ui/index.cjs.map +1 -1
  49. package/dist/ui/index.js +2 -12
  50. package/dist/ui/index.js.map +1 -1
  51. package/package.json +14 -1
  52. package/dist/chunk-74EGUVGE.cjs.map +0 -1
  53. package/dist/chunk-S7QIWD46.js.map +0 -1
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Cross-host UI client — types and wire constants.
3
+ *
4
+ * The cross-host client (`connectUI`) renders one Synapse-authored component in
5
+ * hosts that each speak a different bridge: ChatGPT (OpenAI Apps SDK), Claude
6
+ * (mcp-ui), and plain/standalone. Apps code against `synapse.*` and never touch
7
+ * a host protocol. This is a **push-first** surface: the tool output that spawned
8
+ * the widget is delivered at render (`data()` / `onData()`); `callTool()` is the
9
+ * pull escape hatch, advertised per host via `capabilities()`.
10
+ *
11
+ * This layer intentionally has ZERO dependency on `@modelcontextprotocol/*` — the
12
+ * ChatGPT / mcp-ui / inline bridges are pure `window.openai` + `postMessage`, so
13
+ * the IIFE that apps inline stays tiny (no Zod, no ext-apps schemas).
14
+ */
15
+ /**
16
+ * The host the client resolved to, as reported by `synapse.host()`. An escape
17
+ * hatch — apps should rarely branch on it; `capabilities()` is the supported way
18
+ * to feature-detect. `"nimblebrain"` is reserved for the runtime adapter (P3).
19
+ */
20
+ type HostKind = "chatgpt" | "claude" | "nimblebrain" | "generic";
21
+ /** Resolved theme. `mode` always resolves to light or dark. `tokens` are CSS
22
+ * custom properties the host publishes — the MCP Apps adapter reads them from
23
+ * `hostContext.styles.variables`; where a host sends none they stay empty and the
24
+ * SDK's neutral defaults back them. */
25
+ interface SynapseUITheme {
26
+ mode: "light" | "dark";
27
+ tokens: Record<string, string>;
28
+ }
29
+ /** What the active host actually supports. `data()`/`onData()`/`theme()`/
30
+ * `resize()` work everywhere; these three vary. */
31
+ interface HostCapabilities {
32
+ /** `callTool()` can reach the server (widget→server fetch). */
33
+ pull: boolean;
34
+ /** `sendPrompt()` reaches the agent conversation. */
35
+ sendPrompt: boolean;
36
+ /** `openLink()` opens an external URL through the host. */
37
+ openLink: boolean;
38
+ }
39
+ /** Thrown by `callTool()` when the active host offers no widget→server call. */
40
+ declare class HostUnsupportedError extends Error {
41
+ constructor(feature: string, host: HostKind);
42
+ }
43
+ interface ConnectUIOptions {
44
+ /** App name — informational; forwarded to hosts that accept an appInfo. */
45
+ name?: string;
46
+ /** App semver — informational. */
47
+ version?: string;
48
+ /**
49
+ * Force a host adapter instead of auto-detecting. Used by preview harnesses,
50
+ * SSR, and tests; production apps omit it and let the SDK feature-detect.
51
+ * `"claude"` → MCP Apps standard adapter, `"chatgpt"` → OpenAI Apps adapter,
52
+ * `"generic"` → inline adapter.
53
+ */
54
+ host?: HostKind;
55
+ /**
56
+ * `id` of the `<script type="application/json">` element carrying pushed data
57
+ * baked into the HTML (the mcp-ui / SSR path). Defaults to
58
+ * {@link SYNAPSE_DATA_ELEMENT_ID}.
59
+ */
60
+ dataElementId?: string;
61
+ /**
62
+ * Auto-report content height to the host on layout changes (mcp-ui only).
63
+ * Defaults to `true`. Set `false` to size manually via `resize()`.
64
+ */
65
+ autoResize?: boolean;
66
+ /** Window to bind to. Defaults to the global `window`. Injectable for tests. */
67
+ window?: Window & typeof globalThis;
68
+ }
69
+ /**
70
+ * The public cross-host client. Bound to `synapse` by convention.
71
+ *
72
+ * ```ts
73
+ * const synapse = connectUI();
74
+ * synapse.onData(render); // future pushes/updates
75
+ * render(synapse.data()); // current value (may be null → empty state)
76
+ * ```
77
+ */
78
+ interface SynapseUIClient {
79
+ /** The current pushed data, or `null` before anything has been delivered. */
80
+ data<T = unknown>(): T | null;
81
+ /** Subscribe to data updates (NOT replayed — read `data()` for the current
82
+ * value). Returns an unsubscribe. */
83
+ onData<T = unknown>(cb: (data: T) => void): () => void;
84
+ /** The current resolved theme. */
85
+ theme(): SynapseUITheme;
86
+ /** Subscribe to theme changes. The client already applies the theme to the DOM
87
+ * (`data-theme` attribute + CSS variables) before this fires. */
88
+ onTheme(cb: (theme: SynapseUITheme) => void): () => void;
89
+ /** Widget→server tool call. Rejects with {@link HostUnsupportedError} where the
90
+ * host advertises no pull (`capabilities().pull === false`). */
91
+ callTool<O = unknown>(name: string, args?: Record<string, unknown>): Promise<O>;
92
+ /** Send a follow-up message to the agent conversation. No-op where unsupported. */
93
+ sendPrompt(text: string): void;
94
+ /** Open an external URL through the host (falls back to `window.open`). */
95
+ openLink(url: string): void;
96
+ /** Report content height to the host. Omit `height` to measure `document.body`. */
97
+ resize(height?: number): void;
98
+ /** What the active host supports. */
99
+ capabilities(): HostCapabilities;
100
+ /** The resolved host — an escape hatch; prefer `capabilities()`. */
101
+ host(): HostKind;
102
+ /** Tear down listeners/observers. */
103
+ destroy(): void;
104
+ }
105
+ /**
106
+ * Internal adapter contract. One per host bridge; the client is a thin façade
107
+ * over the selected adapter.
108
+ */
109
+ interface HostAdapter {
110
+ readonly host: HostKind;
111
+ getData<T = unknown>(): T | null;
112
+ onData<T = unknown>(cb: (data: T) => void): () => void;
113
+ getTheme(): SynapseUITheme;
114
+ onTheme(cb: (theme: SynapseUITheme) => void): () => void;
115
+ callTool<O = unknown>(name: string, args?: Record<string, unknown>): Promise<O>;
116
+ sendPrompt(text: string): void;
117
+ openLink(url: string): void;
118
+ resize(height?: number): void;
119
+ capabilities(): HostCapabilities;
120
+ /** Begin listening / send the ready handshake / read baked-in data. Called once
121
+ * by `connectUI` synchronously so `getData()` is populated on return. */
122
+ start(): void;
123
+ destroy(): void;
124
+ }
125
+ /** Default `id` of the baked-in data `<script type="application/json">`. */
126
+ declare const SYNAPSE_DATA_ELEMENT_ID = "synapse-ui-data";
127
+
128
+ /**
129
+ * Connect a Synapse-authored component to whatever host it renders in — ChatGPT
130
+ * (OpenAI Apps SDK), Claude (MCP Apps standard), or a plain/standalone page — behind one
131
+ * push-first API. Feature-detects the host, selects an adapter, and applies the
132
+ * host theme to the DOM before returning.
133
+ *
134
+ * Synchronous: `data()` is populated from baked-in data (where present) on
135
+ * return, and pushed updates arrive via `onData`. Bind the result to `synapse`:
136
+ *
137
+ * ```ts
138
+ * const synapse = connectUI({ name: "my-widget", version: "1.0.0" });
139
+ * synapse.onData(render); // future pushes/updates
140
+ * render(synapse.data()); // current value (null → empty state)
141
+ * ```
142
+ */
143
+ declare function connectUI(options?: ConnectUIOptions): SynapseUIClient;
144
+
145
+ /**
146
+ * Minimal window shape the detector inspects. Kept structural so detection is
147
+ * unit-testable with a plain object — no full `Window` fake required.
148
+ */
149
+ interface DetectableWindow {
150
+ openai?: unknown;
151
+ parent?: unknown;
152
+ self?: unknown;
153
+ }
154
+ /**
155
+ * Feature-detect the host from the browsing context.
156
+ *
157
+ * - `window.openai` present → **chatgpt** (OpenAI Apps SDK).
158
+ * - otherwise, a nested browsing context (`parent !== self`, or a cross-origin
159
+ * access that throws) → **claude** (MCP Apps standard postMessage host).
160
+ * - top-level document → **generic** (inline / standalone).
161
+ *
162
+ * Returns the host *kind*; `chooseAdapter` maps it to a concrete adapter and
163
+ * honors an explicit `options.host` override for previews/SSR/tests.
164
+ */
165
+ declare function detectHostKind(win: DetectableWindow): HostKind;
166
+ /** Build the adapter for an explicit host kind (`options.host` or a detected one). */
167
+ declare function adapterForKind(kind: HostKind, win: Window & typeof globalThis, options: ConnectUIOptions): HostAdapter;
168
+ /** Select and construct the host adapter, honoring `options.host` when set. */
169
+ declare function selectAdapter(win: Window & typeof globalThis, options: ConnectUIOptions): HostAdapter;
170
+
171
+ export { type ConnectUIOptions as C, type HostCapabilities as H, SYNAPSE_DATA_ELEMENT_ID as S, type HostKind as a, HostUnsupportedError as b, type SynapseUIClient as c, type SynapseUITheme as d, connectUI as e, detectHostKind as f, type HostAdapter as g, adapterForKind as h, selectAdapter as s };
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Cross-host UI client — types and wire constants.
3
+ *
4
+ * The cross-host client (`connectUI`) renders one Synapse-authored component in
5
+ * hosts that each speak a different bridge: ChatGPT (OpenAI Apps SDK), Claude
6
+ * (mcp-ui), and plain/standalone. Apps code against `synapse.*` and never touch
7
+ * a host protocol. This is a **push-first** surface: the tool output that spawned
8
+ * the widget is delivered at render (`data()` / `onData()`); `callTool()` is the
9
+ * pull escape hatch, advertised per host via `capabilities()`.
10
+ *
11
+ * This layer intentionally has ZERO dependency on `@modelcontextprotocol/*` — the
12
+ * ChatGPT / mcp-ui / inline bridges are pure `window.openai` + `postMessage`, so
13
+ * the IIFE that apps inline stays tiny (no Zod, no ext-apps schemas).
14
+ */
15
+ /**
16
+ * The host the client resolved to, as reported by `synapse.host()`. An escape
17
+ * hatch — apps should rarely branch on it; `capabilities()` is the supported way
18
+ * to feature-detect. `"nimblebrain"` is reserved for the runtime adapter (P3).
19
+ */
20
+ type HostKind = "chatgpt" | "claude" | "nimblebrain" | "generic";
21
+ /** Resolved theme. `mode` always resolves to light or dark. `tokens` are CSS
22
+ * custom properties the host publishes — the MCP Apps adapter reads them from
23
+ * `hostContext.styles.variables`; where a host sends none they stay empty and the
24
+ * SDK's neutral defaults back them. */
25
+ interface SynapseUITheme {
26
+ mode: "light" | "dark";
27
+ tokens: Record<string, string>;
28
+ }
29
+ /** What the active host actually supports. `data()`/`onData()`/`theme()`/
30
+ * `resize()` work everywhere; these three vary. */
31
+ interface HostCapabilities {
32
+ /** `callTool()` can reach the server (widget→server fetch). */
33
+ pull: boolean;
34
+ /** `sendPrompt()` reaches the agent conversation. */
35
+ sendPrompt: boolean;
36
+ /** `openLink()` opens an external URL through the host. */
37
+ openLink: boolean;
38
+ }
39
+ /** Thrown by `callTool()` when the active host offers no widget→server call. */
40
+ declare class HostUnsupportedError extends Error {
41
+ constructor(feature: string, host: HostKind);
42
+ }
43
+ interface ConnectUIOptions {
44
+ /** App name — informational; forwarded to hosts that accept an appInfo. */
45
+ name?: string;
46
+ /** App semver — informational. */
47
+ version?: string;
48
+ /**
49
+ * Force a host adapter instead of auto-detecting. Used by preview harnesses,
50
+ * SSR, and tests; production apps omit it and let the SDK feature-detect.
51
+ * `"claude"` → MCP Apps standard adapter, `"chatgpt"` → OpenAI Apps adapter,
52
+ * `"generic"` → inline adapter.
53
+ */
54
+ host?: HostKind;
55
+ /**
56
+ * `id` of the `<script type="application/json">` element carrying pushed data
57
+ * baked into the HTML (the mcp-ui / SSR path). Defaults to
58
+ * {@link SYNAPSE_DATA_ELEMENT_ID}.
59
+ */
60
+ dataElementId?: string;
61
+ /**
62
+ * Auto-report content height to the host on layout changes (mcp-ui only).
63
+ * Defaults to `true`. Set `false` to size manually via `resize()`.
64
+ */
65
+ autoResize?: boolean;
66
+ /** Window to bind to. Defaults to the global `window`. Injectable for tests. */
67
+ window?: Window & typeof globalThis;
68
+ }
69
+ /**
70
+ * The public cross-host client. Bound to `synapse` by convention.
71
+ *
72
+ * ```ts
73
+ * const synapse = connectUI();
74
+ * synapse.onData(render); // future pushes/updates
75
+ * render(synapse.data()); // current value (may be null → empty state)
76
+ * ```
77
+ */
78
+ interface SynapseUIClient {
79
+ /** The current pushed data, or `null` before anything has been delivered. */
80
+ data<T = unknown>(): T | null;
81
+ /** Subscribe to data updates (NOT replayed — read `data()` for the current
82
+ * value). Returns an unsubscribe. */
83
+ onData<T = unknown>(cb: (data: T) => void): () => void;
84
+ /** The current resolved theme. */
85
+ theme(): SynapseUITheme;
86
+ /** Subscribe to theme changes. The client already applies the theme to the DOM
87
+ * (`data-theme` attribute + CSS variables) before this fires. */
88
+ onTheme(cb: (theme: SynapseUITheme) => void): () => void;
89
+ /** Widget→server tool call. Rejects with {@link HostUnsupportedError} where the
90
+ * host advertises no pull (`capabilities().pull === false`). */
91
+ callTool<O = unknown>(name: string, args?: Record<string, unknown>): Promise<O>;
92
+ /** Send a follow-up message to the agent conversation. No-op where unsupported. */
93
+ sendPrompt(text: string): void;
94
+ /** Open an external URL through the host (falls back to `window.open`). */
95
+ openLink(url: string): void;
96
+ /** Report content height to the host. Omit `height` to measure `document.body`. */
97
+ resize(height?: number): void;
98
+ /** What the active host supports. */
99
+ capabilities(): HostCapabilities;
100
+ /** The resolved host — an escape hatch; prefer `capabilities()`. */
101
+ host(): HostKind;
102
+ /** Tear down listeners/observers. */
103
+ destroy(): void;
104
+ }
105
+ /**
106
+ * Internal adapter contract. One per host bridge; the client is a thin façade
107
+ * over the selected adapter.
108
+ */
109
+ interface HostAdapter {
110
+ readonly host: HostKind;
111
+ getData<T = unknown>(): T | null;
112
+ onData<T = unknown>(cb: (data: T) => void): () => void;
113
+ getTheme(): SynapseUITheme;
114
+ onTheme(cb: (theme: SynapseUITheme) => void): () => void;
115
+ callTool<O = unknown>(name: string, args?: Record<string, unknown>): Promise<O>;
116
+ sendPrompt(text: string): void;
117
+ openLink(url: string): void;
118
+ resize(height?: number): void;
119
+ capabilities(): HostCapabilities;
120
+ /** Begin listening / send the ready handshake / read baked-in data. Called once
121
+ * by `connectUI` synchronously so `getData()` is populated on return. */
122
+ start(): void;
123
+ destroy(): void;
124
+ }
125
+ /** Default `id` of the baked-in data `<script type="application/json">`. */
126
+ declare const SYNAPSE_DATA_ELEMENT_ID = "synapse-ui-data";
127
+
128
+ /**
129
+ * Connect a Synapse-authored component to whatever host it renders in — ChatGPT
130
+ * (OpenAI Apps SDK), Claude (MCP Apps standard), or a plain/standalone page — behind one
131
+ * push-first API. Feature-detects the host, selects an adapter, and applies the
132
+ * host theme to the DOM before returning.
133
+ *
134
+ * Synchronous: `data()` is populated from baked-in data (where present) on
135
+ * return, and pushed updates arrive via `onData`. Bind the result to `synapse`:
136
+ *
137
+ * ```ts
138
+ * const synapse = connectUI({ name: "my-widget", version: "1.0.0" });
139
+ * synapse.onData(render); // future pushes/updates
140
+ * render(synapse.data()); // current value (null → empty state)
141
+ * ```
142
+ */
143
+ declare function connectUI(options?: ConnectUIOptions): SynapseUIClient;
144
+
145
+ /**
146
+ * Minimal window shape the detector inspects. Kept structural so detection is
147
+ * unit-testable with a plain object — no full `Window` fake required.
148
+ */
149
+ interface DetectableWindow {
150
+ openai?: unknown;
151
+ parent?: unknown;
152
+ self?: unknown;
153
+ }
154
+ /**
155
+ * Feature-detect the host from the browsing context.
156
+ *
157
+ * - `window.openai` present → **chatgpt** (OpenAI Apps SDK).
158
+ * - otherwise, a nested browsing context (`parent !== self`, or a cross-origin
159
+ * access that throws) → **claude** (MCP Apps standard postMessage host).
160
+ * - top-level document → **generic** (inline / standalone).
161
+ *
162
+ * Returns the host *kind*; `chooseAdapter` maps it to a concrete adapter and
163
+ * honors an explicit `options.host` override for previews/SSR/tests.
164
+ */
165
+ declare function detectHostKind(win: DetectableWindow): HostKind;
166
+ /** Build the adapter for an explicit host kind (`options.host` or a detected one). */
167
+ declare function adapterForKind(kind: HostKind, win: Window & typeof globalThis, options: ConnectUIOptions): HostAdapter;
168
+ /** Select and construct the host adapter, honoring `options.host` when set. */
169
+ declare function selectAdapter(win: Window & typeof globalThis, options: ConnectUIOptions): HostAdapter;
170
+
171
+ export { type ConnectUIOptions as C, type HostCapabilities as H, SYNAPSE_DATA_ELEMENT_ID as S, type HostKind as a, HostUnsupportedError as b, type SynapseUIClient as c, type SynapseUITheme as d, connectUI as e, detectHostKind as f, type HostAdapter as g, adapterForKind as h, selectAdapter as s };
@@ -0,0 +1,57 @@
1
+ 'use strict';
2
+
3
+ var chunkANUZ7WFQ_cjs = require('../chunk-ANUZ7WFQ.cjs');
4
+ require('../chunk-KTXASIFJ.cjs');
5
+
6
+
7
+
8
+ Object.defineProperty(exports, "HostUnsupportedError", {
9
+ enumerable: true,
10
+ get: function () { return chunkANUZ7WFQ_cjs.HostUnsupportedError; }
11
+ });
12
+ Object.defineProperty(exports, "SYNAPSE_DATA_ELEMENT_ID", {
13
+ enumerable: true,
14
+ get: function () { return chunkANUZ7WFQ_cjs.SYNAPSE_DATA_ELEMENT_ID; }
15
+ });
16
+ Object.defineProperty(exports, "adapterForKind", {
17
+ enumerable: true,
18
+ get: function () { return chunkANUZ7WFQ_cjs.adapterForKind; }
19
+ });
20
+ Object.defineProperty(exports, "applyHostTheme", {
21
+ enumerable: true,
22
+ get: function () { return chunkANUZ7WFQ_cjs.applyHostTheme; }
23
+ });
24
+ Object.defineProperty(exports, "coerceMode", {
25
+ enumerable: true,
26
+ get: function () { return chunkANUZ7WFQ_cjs.coerceMode; }
27
+ });
28
+ Object.defineProperty(exports, "connectUI", {
29
+ enumerable: true,
30
+ get: function () { return chunkANUZ7WFQ_cjs.connectUI; }
31
+ });
32
+ Object.defineProperty(exports, "createChatGPTAdapter", {
33
+ enumerable: true,
34
+ get: function () { return chunkANUZ7WFQ_cjs.createChatGPTAdapter; }
35
+ });
36
+ Object.defineProperty(exports, "createInlineAdapter", {
37
+ enumerable: true,
38
+ get: function () { return chunkANUZ7WFQ_cjs.createInlineAdapter; }
39
+ });
40
+ Object.defineProperty(exports, "createMcpAppsAdapter", {
41
+ enumerable: true,
42
+ get: function () { return chunkANUZ7WFQ_cjs.createMcpAppsAdapter; }
43
+ });
44
+ Object.defineProperty(exports, "detectHostKind", {
45
+ enumerable: true,
46
+ get: function () { return chunkANUZ7WFQ_cjs.detectHostKind; }
47
+ });
48
+ Object.defineProperty(exports, "preferredMode", {
49
+ enumerable: true,
50
+ get: function () { return chunkANUZ7WFQ_cjs.preferredMode; }
51
+ });
52
+ Object.defineProperty(exports, "selectAdapter", {
53
+ enumerable: true,
54
+ get: function () { return chunkANUZ7WFQ_cjs.selectAdapter; }
55
+ });
56
+ //# sourceMappingURL=index.cjs.map
57
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs"}
@@ -0,0 +1,68 @@
1
+ import { C as ConnectUIOptions, g as HostAdapter, d as SynapseUITheme } from '../detect-DSnLT-_m.cjs';
2
+ export { H as HostCapabilities, a as HostKind, b as HostUnsupportedError, S as SYNAPSE_DATA_ELEMENT_ID, c as SynapseUIClient, h as adapterForKind, e as connectUI, f as detectHostKind, s as selectAdapter } from '../detect-DSnLT-_m.cjs';
3
+
4
+ /**
5
+ * ChatGPT (OpenAI Apps SDK) adapter.
6
+ *
7
+ * Data arrives on `window.openai.toolOutput` (available synchronously before the
8
+ * widget script runs) and updates via the `openai:set_globals` event. Theme is a
9
+ * mode string on the same surface. The host auto-sizes the iframe, so `resize()`
10
+ * is a no-op. `callTool` is available when the host exposes `window.openai.callTool`.
11
+ */
12
+ declare function createChatGPTAdapter(win: Window & typeof globalThis, _options: ConnectUIOptions): HostAdapter;
13
+
14
+ /**
15
+ * Inline / standalone fallback adapter.
16
+ *
17
+ * No live host bridge — used for SSR, previews, and a plain browser render. Data
18
+ * comes only from the baked-in `<script type="application/json">` blob; there is
19
+ * nothing to push, so `onData` never fires after `start()`. Theme follows the OS
20
+ * color scheme and tracks `prefers-color-scheme` changes. `openLink` opens a new
21
+ * tab; `sendPrompt`/`callTool` have no destination.
22
+ */
23
+ declare function createInlineAdapter(win: Window & typeof globalThis, options: ConnectUIOptions): HostAdapter;
24
+
25
+ /**
26
+ * MCP Apps standard (SEP-1865) adapter — the convergence bridge for Claude
27
+ * Desktop and other MCP Apps hosts.
28
+ *
29
+ * The View iframe is an MCP client speaking JSON-RPC 2.0 to `window.parent`:
30
+ *
31
+ * 1. posts `ui/initialize` and awaits the host context (theme, style variables);
32
+ * 2. posts `ui/notifications/initialized`, then a `size-changed` — a host keeps
33
+ * the frame hidden until it has both the handshake and a size;
34
+ * 3. receives data via `ui/notifications/tool-result` (`params` IS the
35
+ * `CallToolResult`, so data is at `params.structuredContent`) and theme via
36
+ * `ui/notifications/host-context-changed`.
37
+ *
38
+ * Actions go up as requests: `ui/open-link`, `ui/message` (follow-up), and
39
+ * `tools/call` (pull). The legacy mcp-ui `ui-lifecycle-*` messages are sent and
40
+ * accepted alongside so a pre-standard host still renders — a standard host drops
41
+ * the non-JSON-RPC frames, and a legacy host ignores the JSON-RPC ones.
42
+ */
43
+ declare function createMcpAppsAdapter(win: Window & typeof globalThis, options: ConnectUIOptions): HostAdapter;
44
+
45
+ /**
46
+ * Apply a resolved theme to the DOM for the cross-host client.
47
+ *
48
+ * Two conventions coexist across Synapse components, so the client drives both:
49
+ *
50
+ * - `document.documentElement[data-theme="light"|"dark"]` — how self-contained
51
+ * HTML components (Bassethound's report) gate their `--var` palettes, and the
52
+ * lever a host's light/dark signal actually flips.
53
+ * - CSS custom properties via {@link applyThemeVariables} — how the
54
+ * `@nimblebrain/synapse/ui` token components consume theme, backed by the
55
+ * SDK's neutral defaults so every referenced var resolves in both modes.
56
+ *
57
+ * Setting both means an app can use either convention (or a host that supplies
58
+ * only a mode string, like the OpenAI Apps SDK, still themes correctly). SSR-safe.
59
+ */
60
+ declare function applyHostTheme(theme: SynapseUITheme): void;
61
+ /** Read the OS-level color scheme as a sane default for hosts that don't push a
62
+ * theme until later (mcp-ui) or ever (standalone). */
63
+ declare function preferredMode(win: Window | undefined): "light" | "dark";
64
+ /** Coerce an arbitrary host-supplied theme signal to a mode. Accepts the string
65
+ * form (`"dark"`) both hosts use; anything else falls back. */
66
+ declare function coerceMode(value: unknown, fallback: "light" | "dark"): "light" | "dark";
67
+
68
+ export { ConnectUIOptions, HostAdapter, SynapseUITheme, applyHostTheme, coerceMode, createChatGPTAdapter, createInlineAdapter, createMcpAppsAdapter, preferredMode };
@@ -0,0 +1,68 @@
1
+ import { C as ConnectUIOptions, g as HostAdapter, d as SynapseUITheme } from '../detect-DSnLT-_m.js';
2
+ export { H as HostCapabilities, a as HostKind, b as HostUnsupportedError, S as SYNAPSE_DATA_ELEMENT_ID, c as SynapseUIClient, h as adapterForKind, e as connectUI, f as detectHostKind, s as selectAdapter } from '../detect-DSnLT-_m.js';
3
+
4
+ /**
5
+ * ChatGPT (OpenAI Apps SDK) adapter.
6
+ *
7
+ * Data arrives on `window.openai.toolOutput` (available synchronously before the
8
+ * widget script runs) and updates via the `openai:set_globals` event. Theme is a
9
+ * mode string on the same surface. The host auto-sizes the iframe, so `resize()`
10
+ * is a no-op. `callTool` is available when the host exposes `window.openai.callTool`.
11
+ */
12
+ declare function createChatGPTAdapter(win: Window & typeof globalThis, _options: ConnectUIOptions): HostAdapter;
13
+
14
+ /**
15
+ * Inline / standalone fallback adapter.
16
+ *
17
+ * No live host bridge — used for SSR, previews, and a plain browser render. Data
18
+ * comes only from the baked-in `<script type="application/json">` blob; there is
19
+ * nothing to push, so `onData` never fires after `start()`. Theme follows the OS
20
+ * color scheme and tracks `prefers-color-scheme` changes. `openLink` opens a new
21
+ * tab; `sendPrompt`/`callTool` have no destination.
22
+ */
23
+ declare function createInlineAdapter(win: Window & typeof globalThis, options: ConnectUIOptions): HostAdapter;
24
+
25
+ /**
26
+ * MCP Apps standard (SEP-1865) adapter — the convergence bridge for Claude
27
+ * Desktop and other MCP Apps hosts.
28
+ *
29
+ * The View iframe is an MCP client speaking JSON-RPC 2.0 to `window.parent`:
30
+ *
31
+ * 1. posts `ui/initialize` and awaits the host context (theme, style variables);
32
+ * 2. posts `ui/notifications/initialized`, then a `size-changed` — a host keeps
33
+ * the frame hidden until it has both the handshake and a size;
34
+ * 3. receives data via `ui/notifications/tool-result` (`params` IS the
35
+ * `CallToolResult`, so data is at `params.structuredContent`) and theme via
36
+ * `ui/notifications/host-context-changed`.
37
+ *
38
+ * Actions go up as requests: `ui/open-link`, `ui/message` (follow-up), and
39
+ * `tools/call` (pull). The legacy mcp-ui `ui-lifecycle-*` messages are sent and
40
+ * accepted alongside so a pre-standard host still renders — a standard host drops
41
+ * the non-JSON-RPC frames, and a legacy host ignores the JSON-RPC ones.
42
+ */
43
+ declare function createMcpAppsAdapter(win: Window & typeof globalThis, options: ConnectUIOptions): HostAdapter;
44
+
45
+ /**
46
+ * Apply a resolved theme to the DOM for the cross-host client.
47
+ *
48
+ * Two conventions coexist across Synapse components, so the client drives both:
49
+ *
50
+ * - `document.documentElement[data-theme="light"|"dark"]` — how self-contained
51
+ * HTML components (Bassethound's report) gate their `--var` palettes, and the
52
+ * lever a host's light/dark signal actually flips.
53
+ * - CSS custom properties via {@link applyThemeVariables} — how the
54
+ * `@nimblebrain/synapse/ui` token components consume theme, backed by the
55
+ * SDK's neutral defaults so every referenced var resolves in both modes.
56
+ *
57
+ * Setting both means an app can use either convention (or a host that supplies
58
+ * only a mode string, like the OpenAI Apps SDK, still themes correctly). SSR-safe.
59
+ */
60
+ declare function applyHostTheme(theme: SynapseUITheme): void;
61
+ /** Read the OS-level color scheme as a sane default for hosts that don't push a
62
+ * theme until later (mcp-ui) or ever (standalone). */
63
+ declare function preferredMode(win: Window | undefined): "light" | "dark";
64
+ /** Coerce an arbitrary host-supplied theme signal to a mode. Accepts the string
65
+ * form (`"dark"`) both hosts use; anything else falls back. */
66
+ declare function coerceMode(value: unknown, fallback: "light" | "dark"): "light" | "dark";
67
+
68
+ export { ConnectUIOptions, HostAdapter, SynapseUITheme, applyHostTheme, coerceMode, createChatGPTAdapter, createInlineAdapter, createMcpAppsAdapter, preferredMode };
@@ -0,0 +1,4 @@
1
+ export { HostUnsupportedError, SYNAPSE_DATA_ELEMENT_ID, adapterForKind, applyHostTheme, coerceMode, connectUI, createChatGPTAdapter, createInlineAdapter, createMcpAppsAdapter, detectHostKind, preferredMode, selectAdapter } from '../chunk-JVKQNMAP.js';
2
+ import '../chunk-VXTMI266.js';
3
+ //# sourceMappingURL=index.js.map
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
package/dist/index.cjs CHANGED
@@ -1,6 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunk74EGUVGE_cjs = require('./chunk-74EGUVGE.cjs');
3
+ var chunkANUZ7WFQ_cjs = require('./chunk-ANUZ7WFQ.cjs');
4
+ var chunkA4ENX6XW_cjs = require('./chunk-A4ENX6XW.cjs');
5
+ require('./chunk-KTXASIFJ.cjs');
4
6
 
5
7
  // src/store.ts
6
8
  function createStore(synapse, config) {
@@ -78,13 +80,29 @@ function createStore(synapse, config) {
78
80
  return store;
79
81
  }
80
82
 
83
+ Object.defineProperty(exports, "HostUnsupportedError", {
84
+ enumerable: true,
85
+ get: function () { return chunkANUZ7WFQ_cjs.HostUnsupportedError; }
86
+ });
87
+ Object.defineProperty(exports, "SYNAPSE_DATA_ELEMENT_ID", {
88
+ enumerable: true,
89
+ get: function () { return chunkANUZ7WFQ_cjs.SYNAPSE_DATA_ELEMENT_ID; }
90
+ });
91
+ Object.defineProperty(exports, "connectUI", {
92
+ enumerable: true,
93
+ get: function () { return chunkANUZ7WFQ_cjs.connectUI; }
94
+ });
95
+ Object.defineProperty(exports, "detectHostKind", {
96
+ enumerable: true,
97
+ get: function () { return chunkANUZ7WFQ_cjs.detectHostKind; }
98
+ });
81
99
  Object.defineProperty(exports, "connect", {
82
100
  enumerable: true,
83
- get: function () { return chunk74EGUVGE_cjs.connect; }
101
+ get: function () { return chunkA4ENX6XW_cjs.connect; }
84
102
  });
85
103
  Object.defineProperty(exports, "createSynapse", {
86
104
  enumerable: true,
87
- get: function () { return chunk74EGUVGE_cjs.createSynapse; }
105
+ get: function () { return chunkA4ENX6XW_cjs.createSynapse; }
88
106
  });
89
107
  exports.createStore = createStore;
90
108
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/store.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ActionReducer, Store, StoreConfig, StoreDispatch, Synapse } from \"./types.js\";\n\n/**\n * Create a typed state store with optional persistence and agent visibility.\n *\n * - `persist: true` — state survives iframe reloads via host storage\n * - `visibleToAgent: true` — state is pushed to the LLM context\n * - Both are independent and can be enabled separately\n */\nexport function createStore<\n TState,\n TActions extends Record<string, ActionReducer<TState, any>> = Record<\n string,\n ActionReducer<TState, any>\n >,\n>(synapse: Synapse, config: StoreConfig<TState> & { actions: TActions }): Store<TState, TActions> {\n let state = structuredClone(config.initialState);\n const subscribers = new Set<(state: TState) => void>();\n let destroyed = false;\n let persistTimer: ReturnType<typeof setTimeout> | null = null;\n\n // Build dispatch object from action reducers\n const dispatch = {} as StoreDispatch<TActions>;\n for (const key of Object.keys(config.actions)) {\n (dispatch as any)[key] = (payload: unknown) => {\n if (destroyed) return;\n state = config.actions[key](state, payload);\n notify();\n };\n }\n\n function notify(): void {\n for (const cb of subscribers) cb(state);\n if (config.visibleToAgent) pushToAgent();\n if (config.persist) schedulePersist();\n }\n\n function pushToAgent(): void {\n const summary = config.summarize?.(state);\n synapse.setVisibleState(state as unknown as Record<string, unknown>, summary);\n }\n\n function schedulePersist(): void {\n if (persistTimer) clearTimeout(persistTimer);\n persistTimer = setTimeout(() => {\n synapse\n ._request(\"synapse/persist-state\", {\n state: state as unknown as Record<string, unknown>,\n version: config.version,\n })\n .catch(() => {\n // Silently ignore persist failures (host may not support it)\n });\n persistTimer = null;\n }, 500);\n }\n\n // Listen for state loaded from host (on init)\n let unsubStateLoaded: (() => void) | undefined;\n if (config.persist) {\n unsubStateLoaded = synapse._onMessage(\"synapse/state-loaded\", (params) => {\n if (!params?.state) return;\n let loaded = params.state as TState;\n const loadedVersion = (params.version as number) ?? 1;\n const currentVersion = config.version ?? 1;\n\n // Run migrations if needed\n if (config.migrations && loadedVersion < currentVersion) {\n const startIdx = loadedVersion - 1;\n for (let i = startIdx; i < config.migrations.length; i++) {\n loaded = config.migrations[i](loaded);\n }\n }\n\n store.hydrate(loaded);\n });\n }\n\n const store: Store<TState, TActions> = {\n getState(): TState {\n return state;\n },\n\n subscribe(callback: (state: TState) => void): () => void {\n subscribers.add(callback);\n return () => {\n subscribers.delete(callback);\n };\n },\n\n dispatch,\n\n hydrate(newState: TState): void {\n state = newState;\n for (const cb of subscribers) cb(state);\n },\n\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n if (persistTimer) clearTimeout(persistTimer);\n subscribers.clear();\n unsubStateLoaded?.();\n },\n };\n\n return store;\n}\n"]}
1
+ {"version":3,"sources":["../src/store.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ActionReducer, Store, StoreConfig, StoreDispatch, Synapse } from \"./types.js\";\n\n/**\n * Create a typed state store with optional persistence and agent visibility.\n *\n * - `persist: true` — state survives iframe reloads via host storage\n * - `visibleToAgent: true` — state is pushed to the LLM context\n * - Both are independent and can be enabled separately\n */\nexport function createStore<\n TState,\n TActions extends Record<string, ActionReducer<TState, any>> = Record<\n string,\n ActionReducer<TState, any>\n >,\n>(synapse: Synapse, config: StoreConfig<TState> & { actions: TActions }): Store<TState, TActions> {\n let state = structuredClone(config.initialState);\n const subscribers = new Set<(state: TState) => void>();\n let destroyed = false;\n let persistTimer: ReturnType<typeof setTimeout> | null = null;\n\n // Build dispatch object from action reducers\n const dispatch = {} as StoreDispatch<TActions>;\n for (const key of Object.keys(config.actions)) {\n (dispatch as any)[key] = (payload: unknown) => {\n if (destroyed) return;\n state = config.actions[key](state, payload);\n notify();\n };\n }\n\n function notify(): void {\n for (const cb of subscribers) cb(state);\n if (config.visibleToAgent) pushToAgent();\n if (config.persist) schedulePersist();\n }\n\n function pushToAgent(): void {\n const summary = config.summarize?.(state);\n synapse.setVisibleState(state as unknown as Record<string, unknown>, summary);\n }\n\n function schedulePersist(): void {\n if (persistTimer) clearTimeout(persistTimer);\n persistTimer = setTimeout(() => {\n synapse\n ._request(\"synapse/persist-state\", {\n state: state as unknown as Record<string, unknown>,\n version: config.version,\n })\n .catch(() => {\n // Silently ignore persist failures (host may not support it)\n });\n persistTimer = null;\n }, 500);\n }\n\n // Listen for state loaded from host (on init)\n let unsubStateLoaded: (() => void) | undefined;\n if (config.persist) {\n unsubStateLoaded = synapse._onMessage(\"synapse/state-loaded\", (params) => {\n if (!params?.state) return;\n let loaded = params.state as TState;\n const loadedVersion = (params.version as number) ?? 1;\n const currentVersion = config.version ?? 1;\n\n // Run migrations if needed\n if (config.migrations && loadedVersion < currentVersion) {\n const startIdx = loadedVersion - 1;\n for (let i = startIdx; i < config.migrations.length; i++) {\n loaded = config.migrations[i](loaded);\n }\n }\n\n store.hydrate(loaded);\n });\n }\n\n const store: Store<TState, TActions> = {\n getState(): TState {\n return state;\n },\n\n subscribe(callback: (state: TState) => void): () => void {\n subscribers.add(callback);\n return () => {\n subscribers.delete(callback);\n };\n },\n\n dispatch,\n\n hydrate(newState: TState): void {\n state = newState;\n for (const cb of subscribers) cb(state);\n },\n\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n if (persistTimer) clearTimeout(persistTimer);\n subscribers.clear();\n unsubStateLoaded?.();\n },\n };\n\n return store;\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { CreateTaskResult, ReadResourceRequest, ReadResourceResult, Task, TaskStatus } from '@modelcontextprotocol/sdk/types.js';
2
2
  import { C as ConnectOptions, A as App, S as SynapseOptions, a as Synapse, b as ActionReducer, c as StoreConfig, d as Store } from './types-C9utGXv_.cjs';
3
3
  export { e as AgentAction, f as AppEventName, B as BuiltinActionType, g as CallToolAsTaskOptions, D as DataChangedEvent, h as Dimensions, F as FileResult, H as HostInfo, K as KeyForwardConfig, N as NavigatePayload, i as NotifyPayload, R as RequestFileOptions, j as StateAcknowledgement, k as StoreDispatch, l as SynapseTheme, m as TaskHandle, n as TasksCapability, o as Theme, p as ToolCallResult, T as ToolDefinition, q as ToolResultData, V as VisibleState } from './types-C9utGXv_.cjs';
4
+ export { C as ConnectUIOptions, H as HostCapabilities, a as HostKind, b as HostUnsupportedError, S as SYNAPSE_DATA_ELEMENT_ID, c as SynapseUIClient, d as SynapseUITheme, e as connectUI, f as detectHostKind } from './detect-DSnLT-_m.cjs';
4
5
  import '@modelcontextprotocol/ext-apps';
5
6
 
6
7
  /**
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { CreateTaskResult, ReadResourceRequest, ReadResourceResult, Task, TaskStatus } from '@modelcontextprotocol/sdk/types.js';
2
2
  import { C as ConnectOptions, A as App, S as SynapseOptions, a as Synapse, b as ActionReducer, c as StoreConfig, d as Store } from './types-C9utGXv_.js';
3
3
  export { e as AgentAction, f as AppEventName, B as BuiltinActionType, g as CallToolAsTaskOptions, D as DataChangedEvent, h as Dimensions, F as FileResult, H as HostInfo, K as KeyForwardConfig, N as NavigatePayload, i as NotifyPayload, R as RequestFileOptions, j as StateAcknowledgement, k as StoreDispatch, l as SynapseTheme, m as TaskHandle, n as TasksCapability, o as Theme, p as ToolCallResult, T as ToolDefinition, q as ToolResultData, V as VisibleState } from './types-C9utGXv_.js';
4
+ export { C as ConnectUIOptions, H as HostCapabilities, a as HostKind, b as HostUnsupportedError, S as SYNAPSE_DATA_ELEMENT_ID, c as SynapseUIClient, d as SynapseUITheme, e as connectUI, f as detectHostKind } from './detect-DSnLT-_m.js';
4
5
  import '@modelcontextprotocol/ext-apps';
5
6
 
6
7
  /**
package/dist/index.js CHANGED
@@ -1,4 +1,6 @@
1
- export { connect, createSynapse } from './chunk-S7QIWD46.js';
1
+ export { HostUnsupportedError, SYNAPSE_DATA_ELEMENT_ID, connectUI, detectHostKind } from './chunk-JVKQNMAP.js';
2
+ export { connect, createSynapse } from './chunk-XGJAADVV.js';
3
+ import './chunk-VXTMI266.js';
2
4
 
3
5
  // src/store.ts
4
6
  function createStore(synapse, config) {