@nimblebrain/synapse 0.2.2 → 0.3.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 +181 -45
- package/dist/{chunk-MQNKIR7K.cjs → chunk-B3T6NB32.cjs} +328 -82
- package/dist/chunk-B3T6NB32.cjs.map +1 -0
- package/dist/{chunk-QY4IBJKV.js → chunk-GQ4L63CL.js} +328 -83
- package/dist/chunk-GQ4L63CL.js.map +1 -0
- package/dist/codegen/index.d.cts +1 -1
- package/dist/codegen/index.d.ts +1 -1
- package/dist/connect.iife.global.js +1 -0
- package/dist/index.cjs +6 -2
- package/dist/index.d.cts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +1 -1
- package/dist/react/index.cjs +96 -8
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +15 -4
- package/dist/react/index.d.ts +15 -4
- package/dist/react/index.js +92 -10
- package/dist/react/index.js.map +1 -1
- package/dist/synapse-runtime.iife.global.js +1 -1
- package/dist/{types-CG7zrCn-.d.cts → types-DJ32F5EL.d.cts} +52 -5
- package/dist/{types-CG7zrCn-.d.ts → types-DJ32F5EL.d.ts} +52 -5
- package/package.json +4 -1
- package/dist/chunk-MQNKIR7K.cjs.map +0 -1
- package/dist/chunk-QY4IBJKV.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import { S as SynapseOptions, a as Synapse,
|
|
2
|
-
export {
|
|
1
|
+
import { C as ConnectOptions, A as App, S as SynapseOptions, a as Synapse, b as ActionReducer, c as StoreConfig, d as Store } from './types-DJ32F5EL.cjs';
|
|
2
|
+
export { e as AgentAction, f as AppEventName, B as BuiltinActionType, D as DataChangedEvent, g as Dimensions, F as FileResult, H as HostInfo, K as KeyForwardConfig, N as NavigatePayload, h as NotifyPayload, R as RequestFileOptions, i as StateAcknowledgement, j as StoreDispatch, k as SynapseTheme, l as Theme, m as ToolCallResult, T as ToolDefinition, n as ToolResultData, V as VisibleState } from './types-DJ32F5EL.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Connect to a MCP Apps host.
|
|
6
|
+
*
|
|
7
|
+
* Owns the full ext-apps handshake (steps 1-9 from the RFC), content parsing,
|
|
8
|
+
* resize management, and event routing. Returns a ready-to-use `App` object.
|
|
9
|
+
*/
|
|
10
|
+
declare function connect(options: ConnectOptions): Promise<App>;
|
|
3
11
|
|
|
4
12
|
/**
|
|
5
13
|
* Create a Synapse instance.
|
|
@@ -23,4 +31,4 @@ declare function createStore<TState, TActions extends Record<string, ActionReduc
|
|
|
23
31
|
actions: TActions;
|
|
24
32
|
}): Store<TState, TActions>;
|
|
25
33
|
|
|
26
|
-
export { ActionReducer, Store, StoreConfig, Synapse, SynapseOptions, createStore, createSynapse };
|
|
34
|
+
export { ActionReducer, App, ConnectOptions, Store, StoreConfig, Synapse, SynapseOptions, connect, createStore, createSynapse };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import { S as SynapseOptions, a as Synapse,
|
|
2
|
-
export {
|
|
1
|
+
import { C as ConnectOptions, A as App, S as SynapseOptions, a as Synapse, b as ActionReducer, c as StoreConfig, d as Store } from './types-DJ32F5EL.js';
|
|
2
|
+
export { e as AgentAction, f as AppEventName, B as BuiltinActionType, D as DataChangedEvent, g as Dimensions, F as FileResult, H as HostInfo, K as KeyForwardConfig, N as NavigatePayload, h as NotifyPayload, R as RequestFileOptions, i as StateAcknowledgement, j as StoreDispatch, k as SynapseTheme, l as Theme, m as ToolCallResult, T as ToolDefinition, n as ToolResultData, V as VisibleState } from './types-DJ32F5EL.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Connect to a MCP Apps host.
|
|
6
|
+
*
|
|
7
|
+
* Owns the full ext-apps handshake (steps 1-9 from the RFC), content parsing,
|
|
8
|
+
* resize management, and event routing. Returns a ready-to-use `App` object.
|
|
9
|
+
*/
|
|
10
|
+
declare function connect(options: ConnectOptions): Promise<App>;
|
|
3
11
|
|
|
4
12
|
/**
|
|
5
13
|
* Create a Synapse instance.
|
|
@@ -23,4 +31,4 @@ declare function createStore<TState, TActions extends Record<string, ActionReduc
|
|
|
23
31
|
actions: TActions;
|
|
24
32
|
}): Store<TState, TActions>;
|
|
25
33
|
|
|
26
|
-
export { ActionReducer, Store, StoreConfig, Synapse, SynapseOptions, createStore, createSynapse };
|
|
34
|
+
export { ActionReducer, App, ConnectOptions, Store, StoreConfig, Synapse, SynapseOptions, connect, createStore, createSynapse };
|
package/dist/index.js
CHANGED
package/dist/react/index.cjs
CHANGED
|
@@ -1,16 +1,98 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkB3T6NB32_cjs = require('../chunk-B3T6NB32.cjs');
|
|
4
4
|
var react = require('react');
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
|
|
7
|
+
var AppContext = react.createContext(null);
|
|
8
|
+
function AppProvider({ children, name, version, autoResize }) {
|
|
9
|
+
const [app, setApp] = react.useState(null);
|
|
10
|
+
const connectingRef = react.useRef(false);
|
|
11
|
+
react.useEffect(() => {
|
|
12
|
+
if (connectingRef.current) return;
|
|
13
|
+
connectingRef.current = true;
|
|
14
|
+
chunkB3T6NB32_cjs.connect({ name, version, autoResize }).then((a) => {
|
|
15
|
+
setApp(a);
|
|
16
|
+
});
|
|
17
|
+
}, []);
|
|
18
|
+
if (!app) return null;
|
|
19
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AppContext.Provider, { value: app, children });
|
|
20
|
+
}
|
|
21
|
+
function useAppContext() {
|
|
22
|
+
const ctx = react.useContext(AppContext);
|
|
23
|
+
if (!ctx) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
"useApp must be used within an <AppProvider>. Wrap your component tree with <AppProvider>."
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return ctx;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/react/connect-hooks.ts
|
|
32
|
+
function useApp() {
|
|
33
|
+
return useAppContext();
|
|
34
|
+
}
|
|
35
|
+
function useToolResult() {
|
|
36
|
+
const app = useAppContext();
|
|
37
|
+
const [data, setData] = react.useState(null);
|
|
38
|
+
react.useEffect(() => {
|
|
39
|
+
return app.on("tool-result", (result) => {
|
|
40
|
+
setData(result);
|
|
41
|
+
});
|
|
42
|
+
}, [app]);
|
|
43
|
+
return data;
|
|
44
|
+
}
|
|
45
|
+
function useToolInput() {
|
|
46
|
+
const app = useAppContext();
|
|
47
|
+
const [input, setInput] = react.useState(null);
|
|
48
|
+
react.useEffect(() => {
|
|
49
|
+
return app.on("tool-input", (args) => {
|
|
50
|
+
setInput(args);
|
|
51
|
+
});
|
|
52
|
+
}, [app]);
|
|
53
|
+
return input;
|
|
54
|
+
}
|
|
55
|
+
function useConnectTheme() {
|
|
56
|
+
const app = useAppContext();
|
|
57
|
+
const [theme, setTheme] = react.useState(() => app.theme);
|
|
58
|
+
react.useEffect(() => {
|
|
59
|
+
setTheme(app.theme);
|
|
60
|
+
return app.on("theme-changed", (t) => {
|
|
61
|
+
setTheme(t);
|
|
62
|
+
});
|
|
63
|
+
}, [app]);
|
|
64
|
+
return theme;
|
|
65
|
+
}
|
|
66
|
+
function useResize() {
|
|
67
|
+
const app = useAppContext();
|
|
68
|
+
return react.useCallback((width, height) => app.resize(width, height), [app]);
|
|
69
|
+
}
|
|
7
70
|
var SynapseContext = react.createContext(null);
|
|
8
71
|
function SynapseProvider({ children, ...options }) {
|
|
9
72
|
const ref = react.useRef(null);
|
|
10
73
|
if (ref.current === null || ref.current.destroyed) {
|
|
11
|
-
ref.current =
|
|
74
|
+
ref.current = chunkB3T6NB32_cjs.createSynapse(options);
|
|
12
75
|
}
|
|
13
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
76
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(SynapseContext.Provider, { value: ref.current, children: [
|
|
77
|
+
/* @__PURE__ */ jsxRuntime.jsx(ThemeInjector, { synapse: ref.current }),
|
|
78
|
+
children
|
|
79
|
+
] });
|
|
80
|
+
}
|
|
81
|
+
function ThemeInjector({ synapse }) {
|
|
82
|
+
const [theme, setTheme] = react.useState(() => synapse.getTheme());
|
|
83
|
+
react.useEffect(() => {
|
|
84
|
+
setTheme(synapse.getTheme());
|
|
85
|
+
return synapse.onThemeChanged(setTheme);
|
|
86
|
+
}, [synapse]);
|
|
87
|
+
react.useEffect(() => {
|
|
88
|
+
if (theme.tokens) {
|
|
89
|
+
const style = document.documentElement.style;
|
|
90
|
+
for (const [k, v] of Object.entries(theme.tokens)) {
|
|
91
|
+
style.setProperty(k, v);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}, [theme]);
|
|
95
|
+
return null;
|
|
14
96
|
}
|
|
15
97
|
function useSynapseContext() {
|
|
16
98
|
const ctx = react.useContext(SynapseContext);
|
|
@@ -114,29 +196,29 @@ function useVisibleState(factory, deps) {
|
|
|
114
196
|
function useFileUpload() {
|
|
115
197
|
const synapse = useSynapseContext();
|
|
116
198
|
const [isPending, setIsPending] = react.useState(false);
|
|
117
|
-
const
|
|
199
|
+
const pickFile = react.useCallback(
|
|
118
200
|
async (options) => {
|
|
119
201
|
setIsPending(true);
|
|
120
202
|
try {
|
|
121
|
-
return await synapse.
|
|
203
|
+
return await synapse.pickFile(options);
|
|
122
204
|
} finally {
|
|
123
205
|
setIsPending(false);
|
|
124
206
|
}
|
|
125
207
|
},
|
|
126
208
|
[synapse]
|
|
127
209
|
);
|
|
128
|
-
const
|
|
210
|
+
const pickFiles = react.useCallback(
|
|
129
211
|
async (options) => {
|
|
130
212
|
setIsPending(true);
|
|
131
213
|
try {
|
|
132
|
-
return await synapse.
|
|
214
|
+
return await synapse.pickFiles(options);
|
|
133
215
|
} finally {
|
|
134
216
|
setIsPending(false);
|
|
135
217
|
}
|
|
136
218
|
},
|
|
137
219
|
[synapse]
|
|
138
220
|
);
|
|
139
|
-
return {
|
|
221
|
+
return { pickFile, pickFiles, isPending };
|
|
140
222
|
}
|
|
141
223
|
function useStore(store) {
|
|
142
224
|
const state = react.useSyncExternalStore(
|
|
@@ -147,16 +229,22 @@ function useStore(store) {
|
|
|
147
229
|
return { state, dispatch: store.dispatch };
|
|
148
230
|
}
|
|
149
231
|
|
|
232
|
+
exports.AppProvider = AppProvider;
|
|
150
233
|
exports.SynapseProvider = SynapseProvider;
|
|
151
234
|
exports.useAction = useAction;
|
|
152
235
|
exports.useAgentAction = useAgentAction;
|
|
236
|
+
exports.useApp = useApp;
|
|
153
237
|
exports.useCallTool = useCallTool;
|
|
154
238
|
exports.useChat = useChat;
|
|
239
|
+
exports.useConnectTheme = useConnectTheme;
|
|
155
240
|
exports.useDataSync = useDataSync;
|
|
156
241
|
exports.useFileUpload = useFileUpload;
|
|
242
|
+
exports.useResize = useResize;
|
|
157
243
|
exports.useStore = useStore;
|
|
158
244
|
exports.useSynapse = useSynapse;
|
|
159
245
|
exports.useTheme = useTheme;
|
|
246
|
+
exports.useToolInput = useToolInput;
|
|
247
|
+
exports.useToolResult = useToolResult;
|
|
160
248
|
exports.useVisibleState = useVisibleState;
|
|
161
249
|
//# sourceMappingURL=index.cjs.map
|
|
162
250
|
//# sourceMappingURL=index.cjs.map
|
package/dist/react/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/react/provider.tsx","../../src/react/hooks.ts"],"names":["createContext","useRef","createSynapse","useContext","useState","useCallback","useEffect","useSyncExternalStore"],"mappings":"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","file":"index.cjs","sourcesContent":["import { createContext, type ReactNode, useContext, useRef } from \"react\";\nimport { createSynapse } from \"../core.js\";\nimport type { Synapse, SynapseOptions } from \"../types.js\";\n\nconst SynapseContext = createContext<Synapse | null>(null);\n\nexport interface SynapseProviderProps extends SynapseOptions {\n children: ReactNode;\n}\n\nexport function SynapseProvider({ children, ...options }: SynapseProviderProps) {\n // Use a ref so the same Synapse instance survives StrictMode's\n // unmount/remount cycle. We intentionally do NOT destroy on unmount\n // because StrictMode re-mounts immediately and the transport must\n // stay alive. The instance is GC'd when the provider is truly removed.\n const ref = useRef<Synapse | null>(null);\n\n if (ref.current === null || ref.current.destroyed) {\n ref.current = createSynapse(options);\n }\n\n return <SynapseContext.Provider value={ref.current}>{children}</SynapseContext.Provider>;\n}\n\nexport function useSynapseContext(): Synapse {\n const ctx = useContext(SynapseContext);\n if (!ctx) {\n throw new Error(\n \"useSynapse must be used within a <SynapseProvider>. \" +\n \"Wrap your app component tree with <SynapseProvider>.\",\n );\n }\n return ctx;\n}\n","import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from \"react\";\nimport type {\n ActionReducer,\n AgentAction,\n DataChangedEvent,\n FileResult,\n RequestFileOptions,\n Store,\n StoreDispatch,\n Synapse,\n SynapseTheme,\n ToolCallResult,\n} from \"../types.js\";\nimport { SynapseProvider, useSynapseContext } from \"./provider.js\";\n\n// Re-export provider components\nexport { SynapseProvider };\n\nexport function useSynapse(): Synapse {\n return useSynapseContext();\n}\n\nexport function useCallTool<TOutput = unknown>(\n toolName: string,\n): {\n call: (args?: Record<string, unknown>) => Promise<ToolCallResult<TOutput>>;\n isPending: boolean;\n error: Error | null;\n data: TOutput | null;\n} {\n const synapse = useSynapseContext();\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [data, setData] = useState<TOutput | null>(null);\n const callIdRef = useRef(0);\n\n const call = useCallback(\n async (args?: Record<string, unknown>): Promise<ToolCallResult<TOutput>> => {\n const id = ++callIdRef.current;\n setIsPending(true);\n setError(null);\n\n try {\n const result = await synapse.callTool<Record<string, unknown>, TOutput>(toolName, args);\n // Stale guard: only update if this is still the latest call\n if (id === callIdRef.current) {\n setData(result.data);\n setIsPending(false);\n }\n return result;\n } catch (err) {\n if (id === callIdRef.current) {\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n setIsPending(false);\n }\n throw err;\n }\n },\n [synapse, toolName],\n );\n\n return { call, isPending, error, data };\n}\n\nexport function useDataSync(callback: (event: DataChangedEvent) => void): void {\n const synapse = useSynapseContext();\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n useEffect(() => {\n return synapse.onDataChanged((event) => callbackRef.current(event));\n }, [synapse]);\n}\n\n/**\n * Subscribe to agent actions — typed, declarative commands from the server.\n *\n * Actions are emitted by tools as deterministic side effects (e.g., \"navigate\n * to the board I just created\"). The UI decides how to handle each action type.\n *\n * @example\n * ```tsx\n * useAgentAction((action) => {\n * if (action.type === \"navigate\") {\n * const { entity, id } = action.payload as NavigatePayload;\n * if (entity === \"board\") setSelectedBoardId(id);\n * }\n * });\n * ```\n */\nexport function useAgentAction(callback: (action: AgentAction) => void): void {\n const synapse = useSynapseContext();\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n useEffect(() => {\n return synapse.onAction((action) => callbackRef.current(action));\n }, [synapse]);\n}\n\nexport function useTheme(): SynapseTheme {\n const synapse = useSynapseContext();\n const [theme, setTheme] = useState<SynapseTheme>(() => synapse.getTheme());\n\n useEffect(() => {\n // Sync in case theme changed between render and effect\n setTheme(synapse.getTheme());\n return synapse.onThemeChanged(setTheme);\n }, [synapse]);\n\n return theme;\n}\n\nexport function useAction(): (action: string, params?: Record<string, unknown>) => void {\n const synapse = useSynapseContext();\n return useCallback(\n (action: string, params?: Record<string, unknown>) => synapse.action(action, params),\n [synapse],\n );\n}\n\nexport function useChat(): (\n message: string,\n context?: { action?: string; entity?: string },\n) => void {\n const synapse = useSynapseContext();\n return useCallback(\n (message: string, context?: { action?: string; entity?: string }) =>\n synapse.chat(message, context),\n [synapse],\n );\n}\n\n/**\n * Push the app's visible state to the agent via ext-apps `ui/update-model-context`.\n *\n * **Imperative** (no args) — returns a push function you call manually:\n * ```tsx\n * const push = useVisibleState();\n * push({ board: selectedBoard }, \"Viewing board X\");\n * ```\n *\n * **Declarative** (factory + deps) — auto-pushes when deps change:\n * ```tsx\n * useVisibleState(() => ({\n * state: { board: selectedBoard },\n * summary: `Viewing \"${selectedBoard?.name}\"`,\n * }), [selectedBoard]);\n * ```\n */\nexport function useVisibleState(): (state: Record<string, unknown>, summary?: string) => void;\nexport function useVisibleState(\n factory: () => { state: Record<string, unknown>; summary?: string },\n deps: unknown[],\n): void;\nexport function useVisibleState(\n factory?: () => { state: Record<string, unknown>; summary?: string },\n deps?: unknown[],\n): ((state: Record<string, unknown>, summary?: string) => void) | undefined {\n const synapse = useSynapseContext();\n const push = useCallback(\n (state: Record<string, unknown>, summary?: string) => synapse.setVisibleState(state, summary),\n [synapse],\n );\n\n // Declarative mode: auto-push when deps change.\n // The deps array is caller-provided (mirrors useMemo/useEffect pattern).\n const factoryRef = useRef(factory);\n factoryRef.current = factory;\n useEffect(() => {\n if (!factoryRef.current) return;\n const { state, summary } = factoryRef.current();\n push(state, summary);\n }, [...(deps ?? []), push]);\n\n if (!factory) return push;\n}\n\nexport function useFileUpload(): {\n requestFile: (options?: RequestFileOptions) => Promise<FileResult | null>;\n requestFiles: (options?: RequestFileOptions) => Promise<FileResult[]>;\n isPending: boolean;\n} {\n const synapse = useSynapseContext();\n const [isPending, setIsPending] = useState(false);\n\n const requestFile = useCallback(\n async (options?: RequestFileOptions) => {\n setIsPending(true);\n try {\n return await synapse.requestFile(options);\n } finally {\n setIsPending(false);\n }\n },\n [synapse],\n );\n\n const requestFiles = useCallback(\n async (options?: RequestFileOptions) => {\n setIsPending(true);\n try {\n return await synapse.requestFiles(options);\n } finally {\n setIsPending(false);\n }\n },\n [synapse],\n );\n\n return { requestFile, requestFiles, isPending };\n}\n\nexport function useStore<TState, TActions extends Record<string, ActionReducer<TState, any>>>(\n store: Store<TState, TActions>,\n): {\n state: TState;\n dispatch: StoreDispatch<TActions>;\n} {\n const state = useSyncExternalStore(\n (onStoreChange) => store.subscribe(onStoreChange),\n () => store.getState(),\n () => store.getState(),\n );\n\n return { state, dispatch: store.dispatch };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/react/app-provider.tsx","../../src/react/connect-hooks.ts","../../src/react/provider.tsx","../../src/react/hooks.ts"],"names":["createContext","useState","useRef","useEffect","connect","useContext","useCallback","createSynapse","jsx","useSyncExternalStore"],"mappings":"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","file":"index.cjs","sourcesContent":["import { createContext, type ReactNode, useContext, useEffect, useRef, useState } from \"react\";\nimport { connect } from \"../connect.js\";\nimport type { App, ConnectOptions } from \"../types.js\";\n\nconst AppContext = createContext<App | null>(null);\n\nexport interface AppProviderProps extends ConnectOptions {\n children: ReactNode;\n}\n\nexport function AppProvider({ children, name, version, autoResize }: AppProviderProps) {\n const [app, setApp] = useState<App | null>(null);\n const connectingRef = useRef(false);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: connect once on mount\n useEffect(() => {\n if (connectingRef.current) return;\n connectingRef.current = true;\n\n connect({ name, version, autoResize }).then((a) => {\n setApp(a);\n });\n }, []);\n\n if (!app) return null; // Don't render children until connected\n\n return <AppContext.Provider value={app}>{children}</AppContext.Provider>;\n}\n\nexport function useAppContext(): App {\n const ctx = useContext(AppContext);\n if (!ctx) {\n throw new Error(\n \"useApp must be used within an <AppProvider>. Wrap your component tree with <AppProvider>.\",\n );\n }\n return ctx;\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport type { App, Theme, ToolResultData } from \"../types.js\";\nimport { AppProvider, useAppContext } from \"./app-provider.js\";\n\nexport { AppProvider };\n\nexport function useApp(): App {\n return useAppContext();\n}\n\nexport function useToolResult(): ToolResultData | null {\n const app = useAppContext();\n const [data, setData] = useState<ToolResultData | null>(null);\n\n useEffect(() => {\n return app.on(\"tool-result\", (result: ToolResultData) => {\n setData(result);\n });\n }, [app]);\n\n return data;\n}\n\nexport function useToolInput(): Record<string, unknown> | null {\n const app = useAppContext();\n const [input, setInput] = useState<Record<string, unknown> | null>(null);\n\n useEffect(() => {\n return app.on(\"tool-input\", (args: Record<string, unknown>) => {\n setInput(args);\n });\n }, [app]);\n\n return input;\n}\n\nexport function useConnectTheme(): Theme {\n const app = useAppContext();\n const [theme, setTheme] = useState<Theme>(() => app.theme);\n\n useEffect(() => {\n setTheme(app.theme); // Sync in case it changed between render and effect\n return app.on(\"theme-changed\", (t: Theme) => {\n setTheme(t);\n });\n }, [app]);\n\n return theme;\n}\n\nexport function useResize(): (width?: number, height?: number) => void {\n const app = useAppContext();\n return useCallback((width?: number, height?: number) => app.resize(width, height), [app]);\n}\n","import { createContext, type ReactNode, useContext, useEffect, useRef, useState } from \"react\";\nimport { createSynapse } from \"../core.js\";\nimport type { Synapse, SynapseOptions, SynapseTheme } from \"../types.js\";\n\nconst SynapseContext = createContext<Synapse | null>(null);\n\nexport interface SynapseProviderProps extends SynapseOptions {\n children: ReactNode;\n}\n\nexport function SynapseProvider({ children, ...options }: SynapseProviderProps) {\n // Use a ref so the same Synapse instance survives StrictMode's\n // unmount/remount cycle. We intentionally do NOT destroy on unmount\n // because StrictMode re-mounts immediately and the transport must\n // stay alive. The instance is GC'd when the provider is truly removed.\n const ref = useRef<Synapse | null>(null);\n\n if (ref.current === null || ref.current.destroyed) {\n ref.current = createSynapse(options);\n }\n\n return (\n <SynapseContext.Provider value={ref.current}>\n <ThemeInjector synapse={ref.current} />\n {children}\n </SynapseContext.Provider>\n );\n}\n\n/** Injects theme CSS variables onto document.documentElement whenever the theme changes. */\nfunction ThemeInjector({ synapse }: { synapse: Synapse }) {\n const [theme, setTheme] = useState<SynapseTheme>(() => synapse.getTheme());\n\n useEffect(() => {\n setTheme(synapse.getTheme());\n return synapse.onThemeChanged(setTheme);\n }, [synapse]);\n\n useEffect(() => {\n if (theme.tokens) {\n const style = document.documentElement.style;\n for (const [k, v] of Object.entries(theme.tokens)) {\n style.setProperty(k, v);\n }\n }\n }, [theme]);\n\n return null;\n}\n\nexport function useSynapseContext(): Synapse {\n const ctx = useContext(SynapseContext);\n if (!ctx) {\n throw new Error(\n \"useSynapse must be used within a <SynapseProvider>. \" +\n \"Wrap your app component tree with <SynapseProvider>.\",\n );\n }\n return ctx;\n}\n","import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from \"react\";\nimport type {\n ActionReducer,\n AgentAction,\n DataChangedEvent,\n FileResult,\n RequestFileOptions,\n Store,\n StoreDispatch,\n Synapse,\n SynapseTheme,\n ToolCallResult,\n} from \"../types.js\";\nimport { SynapseProvider, useSynapseContext } from \"./provider.js\";\n\n// Re-export provider components\nexport { SynapseProvider };\n\nexport function useSynapse(): Synapse {\n return useSynapseContext();\n}\n\nexport function useCallTool<TOutput = unknown>(\n toolName: string,\n): {\n call: (args?: Record<string, unknown>) => Promise<ToolCallResult<TOutput>>;\n isPending: boolean;\n error: Error | null;\n data: TOutput | null;\n} {\n const synapse = useSynapseContext();\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [data, setData] = useState<TOutput | null>(null);\n const callIdRef = useRef(0);\n\n const call = useCallback(\n async (args?: Record<string, unknown>): Promise<ToolCallResult<TOutput>> => {\n const id = ++callIdRef.current;\n setIsPending(true);\n setError(null);\n\n try {\n const result = await synapse.callTool<Record<string, unknown>, TOutput>(toolName, args);\n // Stale guard: only update if this is still the latest call\n if (id === callIdRef.current) {\n setData(result.data);\n setIsPending(false);\n }\n return result;\n } catch (err) {\n if (id === callIdRef.current) {\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n setIsPending(false);\n }\n throw err;\n }\n },\n [synapse, toolName],\n );\n\n return { call, isPending, error, data };\n}\n\nexport function useDataSync(callback: (event: DataChangedEvent) => void): void {\n const synapse = useSynapseContext();\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n useEffect(() => {\n return synapse.onDataChanged((event) => callbackRef.current(event));\n }, [synapse]);\n}\n\n/**\n * Subscribe to agent actions — typed, declarative commands from the server.\n *\n * Actions are emitted by tools as deterministic side effects (e.g., \"navigate\n * to the board I just created\"). The UI decides how to handle each action type.\n *\n * @example\n * ```tsx\n * useAgentAction((action) => {\n * if (action.type === \"navigate\") {\n * const { entity, id } = action.payload as NavigatePayload;\n * if (entity === \"board\") setSelectedBoardId(id);\n * }\n * });\n * ```\n */\nexport function useAgentAction(callback: (action: AgentAction) => void): void {\n const synapse = useSynapseContext();\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n useEffect(() => {\n return synapse.onAction((action) => callbackRef.current(action));\n }, [synapse]);\n}\n\nexport function useTheme(): SynapseTheme {\n const synapse = useSynapseContext();\n const [theme, setTheme] = useState<SynapseTheme>(() => synapse.getTheme());\n\n useEffect(() => {\n // Sync in case theme changed between render and effect\n setTheme(synapse.getTheme());\n return synapse.onThemeChanged(setTheme);\n }, [synapse]);\n\n return theme;\n}\n\nexport function useAction(): (action: string, params?: Record<string, unknown>) => void {\n const synapse = useSynapseContext();\n return useCallback(\n (action: string, params?: Record<string, unknown>) => synapse.action(action, params),\n [synapse],\n );\n}\n\nexport function useChat(): (\n message: string,\n context?: { action?: string; entity?: string },\n) => void {\n const synapse = useSynapseContext();\n return useCallback(\n (message: string, context?: { action?: string; entity?: string }) =>\n synapse.chat(message, context),\n [synapse],\n );\n}\n\n/**\n * Push the app's visible state to the agent via ext-apps `ui/update-model-context`.\n *\n * **Imperative** (no args) — returns a push function you call manually:\n * ```tsx\n * const push = useVisibleState();\n * push({ board: selectedBoard }, \"Viewing board X\");\n * ```\n *\n * **Declarative** (factory + deps) — auto-pushes when deps change:\n * ```tsx\n * useVisibleState(() => ({\n * state: { board: selectedBoard },\n * summary: `Viewing \"${selectedBoard?.name}\"`,\n * }), [selectedBoard]);\n * ```\n */\nexport function useVisibleState(): (state: Record<string, unknown>, summary?: string) => void;\nexport function useVisibleState(\n factory: () => { state: Record<string, unknown>; summary?: string },\n deps: unknown[],\n): void;\nexport function useVisibleState(\n factory?: () => { state: Record<string, unknown>; summary?: string },\n deps?: unknown[],\n): ((state: Record<string, unknown>, summary?: string) => void) | undefined {\n const synapse = useSynapseContext();\n const push = useCallback(\n (state: Record<string, unknown>, summary?: string) => synapse.setVisibleState(state, summary),\n [synapse],\n );\n\n // Declarative mode: auto-push when deps change.\n // The deps array is caller-provided (mirrors useMemo/useEffect pattern).\n const factoryRef = useRef(factory);\n factoryRef.current = factory;\n useEffect(() => {\n if (!factoryRef.current) return;\n const { state, summary } = factoryRef.current();\n push(state, summary);\n }, [...(deps ?? []), push]);\n\n if (!factory) return push;\n}\n\nexport function useFileUpload(): {\n pickFile: (options?: RequestFileOptions) => Promise<FileResult | null>;\n pickFiles: (options?: RequestFileOptions) => Promise<FileResult[]>;\n isPending: boolean;\n} {\n const synapse = useSynapseContext();\n const [isPending, setIsPending] = useState(false);\n\n const pickFile = useCallback(\n async (options?: RequestFileOptions) => {\n setIsPending(true);\n try {\n return await synapse.pickFile(options);\n } finally {\n setIsPending(false);\n }\n },\n [synapse],\n );\n\n const pickFiles = useCallback(\n async (options?: RequestFileOptions) => {\n setIsPending(true);\n try {\n return await synapse.pickFiles(options);\n } finally {\n setIsPending(false);\n }\n },\n [synapse],\n );\n\n return { pickFile, pickFiles, isPending };\n}\n\nexport function useStore<TState, TActions extends Record<string, ActionReducer<TState, any>>>(\n store: Store<TState, TActions>,\n): {\n state: TState;\n dispatch: StoreDispatch<TActions>;\n} {\n const state = useSyncExternalStore(\n (onStoreChange) => store.subscribe(onStoreChange),\n () => store.getState(),\n () => store.getState(),\n );\n\n return { state, dispatch: store.dispatch };\n}\n"]}
|
package/dist/react/index.d.cts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
import { S as SynapseOptions, d as AgentAction, T as ToolCallResult, D as DataChangedEvent, R as RequestFileOptions, F as FileResult, A as ActionReducer, c as Store, g as StoreDispatch, a as Synapse, h as SynapseTheme } from '../types-CG7zrCn-.cjs';
|
|
2
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
2
|
import { ReactNode } from 'react';
|
|
3
|
+
import { C as ConnectOptions, A as App, l as Theme, n as ToolResultData, S as SynapseOptions, e as AgentAction, m as ToolCallResult, D as DataChangedEvent, R as RequestFileOptions, F as FileResult, b as ActionReducer, d as Store, j as StoreDispatch, a as Synapse, k as SynapseTheme } from '../types-DJ32F5EL.cjs';
|
|
4
|
+
|
|
5
|
+
interface AppProviderProps extends ConnectOptions {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
declare function AppProvider({ children, name, version, autoResize }: AppProviderProps): react_jsx_runtime.JSX.Element | null;
|
|
9
|
+
|
|
10
|
+
declare function useApp(): App;
|
|
11
|
+
declare function useToolResult(): ToolResultData | null;
|
|
12
|
+
declare function useToolInput(): Record<string, unknown> | null;
|
|
13
|
+
declare function useConnectTheme(): Theme;
|
|
14
|
+
declare function useResize(): (width?: number, height?: number) => void;
|
|
4
15
|
|
|
5
16
|
interface SynapseProviderProps extends SynapseOptions {
|
|
6
17
|
children: ReactNode;
|
|
@@ -61,8 +72,8 @@ declare function useVisibleState(factory: () => {
|
|
|
61
72
|
summary?: string;
|
|
62
73
|
}, deps: unknown[]): void;
|
|
63
74
|
declare function useFileUpload(): {
|
|
64
|
-
|
|
65
|
-
|
|
75
|
+
pickFile: (options?: RequestFileOptions) => Promise<FileResult | null>;
|
|
76
|
+
pickFiles: (options?: RequestFileOptions) => Promise<FileResult[]>;
|
|
66
77
|
isPending: boolean;
|
|
67
78
|
};
|
|
68
79
|
declare function useStore<TState, TActions extends Record<string, ActionReducer<TState, any>>>(store: Store<TState, TActions>): {
|
|
@@ -70,4 +81,4 @@ declare function useStore<TState, TActions extends Record<string, ActionReducer<
|
|
|
70
81
|
dispatch: StoreDispatch<TActions>;
|
|
71
82
|
};
|
|
72
83
|
|
|
73
|
-
export { SynapseProvider, type SynapseProviderProps, useAction, useAgentAction, useCallTool, useChat, useDataSync, useFileUpload, useStore, useSynapse, useTheme, useVisibleState };
|
|
84
|
+
export { AppProvider, type AppProviderProps, SynapseProvider, type SynapseProviderProps, useAction, useAgentAction, useApp, useCallTool, useChat, useConnectTheme, useDataSync, useFileUpload, useResize, useStore, useSynapse, useTheme, useToolInput, useToolResult, useVisibleState };
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
import { S as SynapseOptions, d as AgentAction, T as ToolCallResult, D as DataChangedEvent, R as RequestFileOptions, F as FileResult, A as ActionReducer, c as Store, g as StoreDispatch, a as Synapse, h as SynapseTheme } from '../types-CG7zrCn-.js';
|
|
2
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
2
|
import { ReactNode } from 'react';
|
|
3
|
+
import { C as ConnectOptions, A as App, l as Theme, n as ToolResultData, S as SynapseOptions, e as AgentAction, m as ToolCallResult, D as DataChangedEvent, R as RequestFileOptions, F as FileResult, b as ActionReducer, d as Store, j as StoreDispatch, a as Synapse, k as SynapseTheme } from '../types-DJ32F5EL.js';
|
|
4
|
+
|
|
5
|
+
interface AppProviderProps extends ConnectOptions {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
declare function AppProvider({ children, name, version, autoResize }: AppProviderProps): react_jsx_runtime.JSX.Element | null;
|
|
9
|
+
|
|
10
|
+
declare function useApp(): App;
|
|
11
|
+
declare function useToolResult(): ToolResultData | null;
|
|
12
|
+
declare function useToolInput(): Record<string, unknown> | null;
|
|
13
|
+
declare function useConnectTheme(): Theme;
|
|
14
|
+
declare function useResize(): (width?: number, height?: number) => void;
|
|
4
15
|
|
|
5
16
|
interface SynapseProviderProps extends SynapseOptions {
|
|
6
17
|
children: ReactNode;
|
|
@@ -61,8 +72,8 @@ declare function useVisibleState(factory: () => {
|
|
|
61
72
|
summary?: string;
|
|
62
73
|
}, deps: unknown[]): void;
|
|
63
74
|
declare function useFileUpload(): {
|
|
64
|
-
|
|
65
|
-
|
|
75
|
+
pickFile: (options?: RequestFileOptions) => Promise<FileResult | null>;
|
|
76
|
+
pickFiles: (options?: RequestFileOptions) => Promise<FileResult[]>;
|
|
66
77
|
isPending: boolean;
|
|
67
78
|
};
|
|
68
79
|
declare function useStore<TState, TActions extends Record<string, ActionReducer<TState, any>>>(store: Store<TState, TActions>): {
|
|
@@ -70,4 +81,4 @@ declare function useStore<TState, TActions extends Record<string, ActionReducer<
|
|
|
70
81
|
dispatch: StoreDispatch<TActions>;
|
|
71
82
|
};
|
|
72
83
|
|
|
73
|
-
export { SynapseProvider, type SynapseProviderProps, useAction, useAgentAction, useCallTool, useChat, useDataSync, useFileUpload, useStore, useSynapse, useTheme, useVisibleState };
|
|
84
|
+
export { AppProvider, type AppProviderProps, SynapseProvider, type SynapseProviderProps, useAction, useAgentAction, useApp, useCallTool, useChat, useConnectTheme, useDataSync, useFileUpload, useResize, useStore, useSynapse, useTheme, useToolInput, useToolResult, useVisibleState };
|
package/dist/react/index.js
CHANGED
|
@@ -1,14 +1,96 @@
|
|
|
1
|
-
import { createSynapse } from '../chunk-
|
|
2
|
-
import { createContext, useRef,
|
|
3
|
-
import { jsx } from 'react/jsx-runtime';
|
|
1
|
+
import { connect, createSynapse } from '../chunk-GQ4L63CL.js';
|
|
2
|
+
import { createContext, useState, useRef, useEffect, useCallback, useSyncExternalStore, useContext } from 'react';
|
|
3
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
4
|
|
|
5
|
+
var AppContext = createContext(null);
|
|
6
|
+
function AppProvider({ children, name, version, autoResize }) {
|
|
7
|
+
const [app, setApp] = useState(null);
|
|
8
|
+
const connectingRef = useRef(false);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (connectingRef.current) return;
|
|
11
|
+
connectingRef.current = true;
|
|
12
|
+
connect({ name, version, autoResize }).then((a) => {
|
|
13
|
+
setApp(a);
|
|
14
|
+
});
|
|
15
|
+
}, []);
|
|
16
|
+
if (!app) return null;
|
|
17
|
+
return /* @__PURE__ */ jsx(AppContext.Provider, { value: app, children });
|
|
18
|
+
}
|
|
19
|
+
function useAppContext() {
|
|
20
|
+
const ctx = useContext(AppContext);
|
|
21
|
+
if (!ctx) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
"useApp must be used within an <AppProvider>. Wrap your component tree with <AppProvider>."
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
return ctx;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/react/connect-hooks.ts
|
|
30
|
+
function useApp() {
|
|
31
|
+
return useAppContext();
|
|
32
|
+
}
|
|
33
|
+
function useToolResult() {
|
|
34
|
+
const app = useAppContext();
|
|
35
|
+
const [data, setData] = useState(null);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
return app.on("tool-result", (result) => {
|
|
38
|
+
setData(result);
|
|
39
|
+
});
|
|
40
|
+
}, [app]);
|
|
41
|
+
return data;
|
|
42
|
+
}
|
|
43
|
+
function useToolInput() {
|
|
44
|
+
const app = useAppContext();
|
|
45
|
+
const [input, setInput] = useState(null);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
return app.on("tool-input", (args) => {
|
|
48
|
+
setInput(args);
|
|
49
|
+
});
|
|
50
|
+
}, [app]);
|
|
51
|
+
return input;
|
|
52
|
+
}
|
|
53
|
+
function useConnectTheme() {
|
|
54
|
+
const app = useAppContext();
|
|
55
|
+
const [theme, setTheme] = useState(() => app.theme);
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
setTheme(app.theme);
|
|
58
|
+
return app.on("theme-changed", (t) => {
|
|
59
|
+
setTheme(t);
|
|
60
|
+
});
|
|
61
|
+
}, [app]);
|
|
62
|
+
return theme;
|
|
63
|
+
}
|
|
64
|
+
function useResize() {
|
|
65
|
+
const app = useAppContext();
|
|
66
|
+
return useCallback((width, height) => app.resize(width, height), [app]);
|
|
67
|
+
}
|
|
5
68
|
var SynapseContext = createContext(null);
|
|
6
69
|
function SynapseProvider({ children, ...options }) {
|
|
7
70
|
const ref = useRef(null);
|
|
8
71
|
if (ref.current === null || ref.current.destroyed) {
|
|
9
72
|
ref.current = createSynapse(options);
|
|
10
73
|
}
|
|
11
|
-
return /* @__PURE__ */
|
|
74
|
+
return /* @__PURE__ */ jsxs(SynapseContext.Provider, { value: ref.current, children: [
|
|
75
|
+
/* @__PURE__ */ jsx(ThemeInjector, { synapse: ref.current }),
|
|
76
|
+
children
|
|
77
|
+
] });
|
|
78
|
+
}
|
|
79
|
+
function ThemeInjector({ synapse }) {
|
|
80
|
+
const [theme, setTheme] = useState(() => synapse.getTheme());
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
setTheme(synapse.getTheme());
|
|
83
|
+
return synapse.onThemeChanged(setTheme);
|
|
84
|
+
}, [synapse]);
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
if (theme.tokens) {
|
|
87
|
+
const style = document.documentElement.style;
|
|
88
|
+
for (const [k, v] of Object.entries(theme.tokens)) {
|
|
89
|
+
style.setProperty(k, v);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}, [theme]);
|
|
93
|
+
return null;
|
|
12
94
|
}
|
|
13
95
|
function useSynapseContext() {
|
|
14
96
|
const ctx = useContext(SynapseContext);
|
|
@@ -112,29 +194,29 @@ function useVisibleState(factory, deps) {
|
|
|
112
194
|
function useFileUpload() {
|
|
113
195
|
const synapse = useSynapseContext();
|
|
114
196
|
const [isPending, setIsPending] = useState(false);
|
|
115
|
-
const
|
|
197
|
+
const pickFile = useCallback(
|
|
116
198
|
async (options) => {
|
|
117
199
|
setIsPending(true);
|
|
118
200
|
try {
|
|
119
|
-
return await synapse.
|
|
201
|
+
return await synapse.pickFile(options);
|
|
120
202
|
} finally {
|
|
121
203
|
setIsPending(false);
|
|
122
204
|
}
|
|
123
205
|
},
|
|
124
206
|
[synapse]
|
|
125
207
|
);
|
|
126
|
-
const
|
|
208
|
+
const pickFiles = useCallback(
|
|
127
209
|
async (options) => {
|
|
128
210
|
setIsPending(true);
|
|
129
211
|
try {
|
|
130
|
-
return await synapse.
|
|
212
|
+
return await synapse.pickFiles(options);
|
|
131
213
|
} finally {
|
|
132
214
|
setIsPending(false);
|
|
133
215
|
}
|
|
134
216
|
},
|
|
135
217
|
[synapse]
|
|
136
218
|
);
|
|
137
|
-
return {
|
|
219
|
+
return { pickFile, pickFiles, isPending };
|
|
138
220
|
}
|
|
139
221
|
function useStore(store) {
|
|
140
222
|
const state = useSyncExternalStore(
|
|
@@ -145,6 +227,6 @@ function useStore(store) {
|
|
|
145
227
|
return { state, dispatch: store.dispatch };
|
|
146
228
|
}
|
|
147
229
|
|
|
148
|
-
export { SynapseProvider, useAction, useAgentAction, useCallTool, useChat, useDataSync, useFileUpload, useStore, useSynapse, useTheme, useVisibleState };
|
|
230
|
+
export { AppProvider, SynapseProvider, useAction, useAgentAction, useApp, useCallTool, useChat, useConnectTheme, useDataSync, useFileUpload, useResize, useStore, useSynapse, useTheme, useToolInput, useToolResult, useVisibleState };
|
|
149
231
|
//# sourceMappingURL=index.js.map
|
|
150
232
|
//# sourceMappingURL=index.js.map
|
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/react/provider.tsx","../../src/react/hooks.ts"],"names":["useRef"],"mappings":"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","file":"index.js","sourcesContent":["import { createContext, type ReactNode, useContext, useRef } from \"react\";\nimport { createSynapse } from \"../core.js\";\nimport type { Synapse, SynapseOptions } from \"../types.js\";\n\nconst SynapseContext = createContext<Synapse | null>(null);\n\nexport interface SynapseProviderProps extends SynapseOptions {\n children: ReactNode;\n}\n\nexport function SynapseProvider({ children, ...options }: SynapseProviderProps) {\n // Use a ref so the same Synapse instance survives StrictMode's\n // unmount/remount cycle. We intentionally do NOT destroy on unmount\n // because StrictMode re-mounts immediately and the transport must\n // stay alive. The instance is GC'd when the provider is truly removed.\n const ref = useRef<Synapse | null>(null);\n\n if (ref.current === null || ref.current.destroyed) {\n ref.current = createSynapse(options);\n }\n\n return <SynapseContext.Provider value={ref.current}>{children}</SynapseContext.Provider>;\n}\n\nexport function useSynapseContext(): Synapse {\n const ctx = useContext(SynapseContext);\n if (!ctx) {\n throw new Error(\n \"useSynapse must be used within a <SynapseProvider>. \" +\n \"Wrap your app component tree with <SynapseProvider>.\",\n );\n }\n return ctx;\n}\n","import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from \"react\";\nimport type {\n ActionReducer,\n AgentAction,\n DataChangedEvent,\n FileResult,\n RequestFileOptions,\n Store,\n StoreDispatch,\n Synapse,\n SynapseTheme,\n ToolCallResult,\n} from \"../types.js\";\nimport { SynapseProvider, useSynapseContext } from \"./provider.js\";\n\n// Re-export provider components\nexport { SynapseProvider };\n\nexport function useSynapse(): Synapse {\n return useSynapseContext();\n}\n\nexport function useCallTool<TOutput = unknown>(\n toolName: string,\n): {\n call: (args?: Record<string, unknown>) => Promise<ToolCallResult<TOutput>>;\n isPending: boolean;\n error: Error | null;\n data: TOutput | null;\n} {\n const synapse = useSynapseContext();\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [data, setData] = useState<TOutput | null>(null);\n const callIdRef = useRef(0);\n\n const call = useCallback(\n async (args?: Record<string, unknown>): Promise<ToolCallResult<TOutput>> => {\n const id = ++callIdRef.current;\n setIsPending(true);\n setError(null);\n\n try {\n const result = await synapse.callTool<Record<string, unknown>, TOutput>(toolName, args);\n // Stale guard: only update if this is still the latest call\n if (id === callIdRef.current) {\n setData(result.data);\n setIsPending(false);\n }\n return result;\n } catch (err) {\n if (id === callIdRef.current) {\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n setIsPending(false);\n }\n throw err;\n }\n },\n [synapse, toolName],\n );\n\n return { call, isPending, error, data };\n}\n\nexport function useDataSync(callback: (event: DataChangedEvent) => void): void {\n const synapse = useSynapseContext();\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n useEffect(() => {\n return synapse.onDataChanged((event) => callbackRef.current(event));\n }, [synapse]);\n}\n\n/**\n * Subscribe to agent actions — typed, declarative commands from the server.\n *\n * Actions are emitted by tools as deterministic side effects (e.g., \"navigate\n * to the board I just created\"). The UI decides how to handle each action type.\n *\n * @example\n * ```tsx\n * useAgentAction((action) => {\n * if (action.type === \"navigate\") {\n * const { entity, id } = action.payload as NavigatePayload;\n * if (entity === \"board\") setSelectedBoardId(id);\n * }\n * });\n * ```\n */\nexport function useAgentAction(callback: (action: AgentAction) => void): void {\n const synapse = useSynapseContext();\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n useEffect(() => {\n return synapse.onAction((action) => callbackRef.current(action));\n }, [synapse]);\n}\n\nexport function useTheme(): SynapseTheme {\n const synapse = useSynapseContext();\n const [theme, setTheme] = useState<SynapseTheme>(() => synapse.getTheme());\n\n useEffect(() => {\n // Sync in case theme changed between render and effect\n setTheme(synapse.getTheme());\n return synapse.onThemeChanged(setTheme);\n }, [synapse]);\n\n return theme;\n}\n\nexport function useAction(): (action: string, params?: Record<string, unknown>) => void {\n const synapse = useSynapseContext();\n return useCallback(\n (action: string, params?: Record<string, unknown>) => synapse.action(action, params),\n [synapse],\n );\n}\n\nexport function useChat(): (\n message: string,\n context?: { action?: string; entity?: string },\n) => void {\n const synapse = useSynapseContext();\n return useCallback(\n (message: string, context?: { action?: string; entity?: string }) =>\n synapse.chat(message, context),\n [synapse],\n );\n}\n\n/**\n * Push the app's visible state to the agent via ext-apps `ui/update-model-context`.\n *\n * **Imperative** (no args) — returns a push function you call manually:\n * ```tsx\n * const push = useVisibleState();\n * push({ board: selectedBoard }, \"Viewing board X\");\n * ```\n *\n * **Declarative** (factory + deps) — auto-pushes when deps change:\n * ```tsx\n * useVisibleState(() => ({\n * state: { board: selectedBoard },\n * summary: `Viewing \"${selectedBoard?.name}\"`,\n * }), [selectedBoard]);\n * ```\n */\nexport function useVisibleState(): (state: Record<string, unknown>, summary?: string) => void;\nexport function useVisibleState(\n factory: () => { state: Record<string, unknown>; summary?: string },\n deps: unknown[],\n): void;\nexport function useVisibleState(\n factory?: () => { state: Record<string, unknown>; summary?: string },\n deps?: unknown[],\n): ((state: Record<string, unknown>, summary?: string) => void) | undefined {\n const synapse = useSynapseContext();\n const push = useCallback(\n (state: Record<string, unknown>, summary?: string) => synapse.setVisibleState(state, summary),\n [synapse],\n );\n\n // Declarative mode: auto-push when deps change.\n // The deps array is caller-provided (mirrors useMemo/useEffect pattern).\n const factoryRef = useRef(factory);\n factoryRef.current = factory;\n useEffect(() => {\n if (!factoryRef.current) return;\n const { state, summary } = factoryRef.current();\n push(state, summary);\n }, [...(deps ?? []), push]);\n\n if (!factory) return push;\n}\n\nexport function useFileUpload(): {\n requestFile: (options?: RequestFileOptions) => Promise<FileResult | null>;\n requestFiles: (options?: RequestFileOptions) => Promise<FileResult[]>;\n isPending: boolean;\n} {\n const synapse = useSynapseContext();\n const [isPending, setIsPending] = useState(false);\n\n const requestFile = useCallback(\n async (options?: RequestFileOptions) => {\n setIsPending(true);\n try {\n return await synapse.requestFile(options);\n } finally {\n setIsPending(false);\n }\n },\n [synapse],\n );\n\n const requestFiles = useCallback(\n async (options?: RequestFileOptions) => {\n setIsPending(true);\n try {\n return await synapse.requestFiles(options);\n } finally {\n setIsPending(false);\n }\n },\n [synapse],\n );\n\n return { requestFile, requestFiles, isPending };\n}\n\nexport function useStore<TState, TActions extends Record<string, ActionReducer<TState, any>>>(\n store: Store<TState, TActions>,\n): {\n state: TState;\n dispatch: StoreDispatch<TActions>;\n} {\n const state = useSyncExternalStore(\n (onStoreChange) => store.subscribe(onStoreChange),\n () => store.getState(),\n () => store.getState(),\n );\n\n return { state, dispatch: store.dispatch };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/react/app-provider.tsx","../../src/react/connect-hooks.ts","../../src/react/provider.tsx","../../src/react/hooks.ts"],"names":["useState","useEffect","createContext","useRef","jsx","useContext","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["import { createContext, type ReactNode, useContext, useEffect, useRef, useState } from \"react\";\nimport { connect } from \"../connect.js\";\nimport type { App, ConnectOptions } from \"../types.js\";\n\nconst AppContext = createContext<App | null>(null);\n\nexport interface AppProviderProps extends ConnectOptions {\n children: ReactNode;\n}\n\nexport function AppProvider({ children, name, version, autoResize }: AppProviderProps) {\n const [app, setApp] = useState<App | null>(null);\n const connectingRef = useRef(false);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: connect once on mount\n useEffect(() => {\n if (connectingRef.current) return;\n connectingRef.current = true;\n\n connect({ name, version, autoResize }).then((a) => {\n setApp(a);\n });\n }, []);\n\n if (!app) return null; // Don't render children until connected\n\n return <AppContext.Provider value={app}>{children}</AppContext.Provider>;\n}\n\nexport function useAppContext(): App {\n const ctx = useContext(AppContext);\n if (!ctx) {\n throw new Error(\n \"useApp must be used within an <AppProvider>. Wrap your component tree with <AppProvider>.\",\n );\n }\n return ctx;\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport type { App, Theme, ToolResultData } from \"../types.js\";\nimport { AppProvider, useAppContext } from \"./app-provider.js\";\n\nexport { AppProvider };\n\nexport function useApp(): App {\n return useAppContext();\n}\n\nexport function useToolResult(): ToolResultData | null {\n const app = useAppContext();\n const [data, setData] = useState<ToolResultData | null>(null);\n\n useEffect(() => {\n return app.on(\"tool-result\", (result: ToolResultData) => {\n setData(result);\n });\n }, [app]);\n\n return data;\n}\n\nexport function useToolInput(): Record<string, unknown> | null {\n const app = useAppContext();\n const [input, setInput] = useState<Record<string, unknown> | null>(null);\n\n useEffect(() => {\n return app.on(\"tool-input\", (args: Record<string, unknown>) => {\n setInput(args);\n });\n }, [app]);\n\n return input;\n}\n\nexport function useConnectTheme(): Theme {\n const app = useAppContext();\n const [theme, setTheme] = useState<Theme>(() => app.theme);\n\n useEffect(() => {\n setTheme(app.theme); // Sync in case it changed between render and effect\n return app.on(\"theme-changed\", (t: Theme) => {\n setTheme(t);\n });\n }, [app]);\n\n return theme;\n}\n\nexport function useResize(): (width?: number, height?: number) => void {\n const app = useAppContext();\n return useCallback((width?: number, height?: number) => app.resize(width, height), [app]);\n}\n","import { createContext, type ReactNode, useContext, useEffect, useRef, useState } from \"react\";\nimport { createSynapse } from \"../core.js\";\nimport type { Synapse, SynapseOptions, SynapseTheme } from \"../types.js\";\n\nconst SynapseContext = createContext<Synapse | null>(null);\n\nexport interface SynapseProviderProps extends SynapseOptions {\n children: ReactNode;\n}\n\nexport function SynapseProvider({ children, ...options }: SynapseProviderProps) {\n // Use a ref so the same Synapse instance survives StrictMode's\n // unmount/remount cycle. We intentionally do NOT destroy on unmount\n // because StrictMode re-mounts immediately and the transport must\n // stay alive. The instance is GC'd when the provider is truly removed.\n const ref = useRef<Synapse | null>(null);\n\n if (ref.current === null || ref.current.destroyed) {\n ref.current = createSynapse(options);\n }\n\n return (\n <SynapseContext.Provider value={ref.current}>\n <ThemeInjector synapse={ref.current} />\n {children}\n </SynapseContext.Provider>\n );\n}\n\n/** Injects theme CSS variables onto document.documentElement whenever the theme changes. */\nfunction ThemeInjector({ synapse }: { synapse: Synapse }) {\n const [theme, setTheme] = useState<SynapseTheme>(() => synapse.getTheme());\n\n useEffect(() => {\n setTheme(synapse.getTheme());\n return synapse.onThemeChanged(setTheme);\n }, [synapse]);\n\n useEffect(() => {\n if (theme.tokens) {\n const style = document.documentElement.style;\n for (const [k, v] of Object.entries(theme.tokens)) {\n style.setProperty(k, v);\n }\n }\n }, [theme]);\n\n return null;\n}\n\nexport function useSynapseContext(): Synapse {\n const ctx = useContext(SynapseContext);\n if (!ctx) {\n throw new Error(\n \"useSynapse must be used within a <SynapseProvider>. \" +\n \"Wrap your app component tree with <SynapseProvider>.\",\n );\n }\n return ctx;\n}\n","import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from \"react\";\nimport type {\n ActionReducer,\n AgentAction,\n DataChangedEvent,\n FileResult,\n RequestFileOptions,\n Store,\n StoreDispatch,\n Synapse,\n SynapseTheme,\n ToolCallResult,\n} from \"../types.js\";\nimport { SynapseProvider, useSynapseContext } from \"./provider.js\";\n\n// Re-export provider components\nexport { SynapseProvider };\n\nexport function useSynapse(): Synapse {\n return useSynapseContext();\n}\n\nexport function useCallTool<TOutput = unknown>(\n toolName: string,\n): {\n call: (args?: Record<string, unknown>) => Promise<ToolCallResult<TOutput>>;\n isPending: boolean;\n error: Error | null;\n data: TOutput | null;\n} {\n const synapse = useSynapseContext();\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [data, setData] = useState<TOutput | null>(null);\n const callIdRef = useRef(0);\n\n const call = useCallback(\n async (args?: Record<string, unknown>): Promise<ToolCallResult<TOutput>> => {\n const id = ++callIdRef.current;\n setIsPending(true);\n setError(null);\n\n try {\n const result = await synapse.callTool<Record<string, unknown>, TOutput>(toolName, args);\n // Stale guard: only update if this is still the latest call\n if (id === callIdRef.current) {\n setData(result.data);\n setIsPending(false);\n }\n return result;\n } catch (err) {\n if (id === callIdRef.current) {\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n setIsPending(false);\n }\n throw err;\n }\n },\n [synapse, toolName],\n );\n\n return { call, isPending, error, data };\n}\n\nexport function useDataSync(callback: (event: DataChangedEvent) => void): void {\n const synapse = useSynapseContext();\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n useEffect(() => {\n return synapse.onDataChanged((event) => callbackRef.current(event));\n }, [synapse]);\n}\n\n/**\n * Subscribe to agent actions — typed, declarative commands from the server.\n *\n * Actions are emitted by tools as deterministic side effects (e.g., \"navigate\n * to the board I just created\"). The UI decides how to handle each action type.\n *\n * @example\n * ```tsx\n * useAgentAction((action) => {\n * if (action.type === \"navigate\") {\n * const { entity, id } = action.payload as NavigatePayload;\n * if (entity === \"board\") setSelectedBoardId(id);\n * }\n * });\n * ```\n */\nexport function useAgentAction(callback: (action: AgentAction) => void): void {\n const synapse = useSynapseContext();\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n useEffect(() => {\n return synapse.onAction((action) => callbackRef.current(action));\n }, [synapse]);\n}\n\nexport function useTheme(): SynapseTheme {\n const synapse = useSynapseContext();\n const [theme, setTheme] = useState<SynapseTheme>(() => synapse.getTheme());\n\n useEffect(() => {\n // Sync in case theme changed between render and effect\n setTheme(synapse.getTheme());\n return synapse.onThemeChanged(setTheme);\n }, [synapse]);\n\n return theme;\n}\n\nexport function useAction(): (action: string, params?: Record<string, unknown>) => void {\n const synapse = useSynapseContext();\n return useCallback(\n (action: string, params?: Record<string, unknown>) => synapse.action(action, params),\n [synapse],\n );\n}\n\nexport function useChat(): (\n message: string,\n context?: { action?: string; entity?: string },\n) => void {\n const synapse = useSynapseContext();\n return useCallback(\n (message: string, context?: { action?: string; entity?: string }) =>\n synapse.chat(message, context),\n [synapse],\n );\n}\n\n/**\n * Push the app's visible state to the agent via ext-apps `ui/update-model-context`.\n *\n * **Imperative** (no args) — returns a push function you call manually:\n * ```tsx\n * const push = useVisibleState();\n * push({ board: selectedBoard }, \"Viewing board X\");\n * ```\n *\n * **Declarative** (factory + deps) — auto-pushes when deps change:\n * ```tsx\n * useVisibleState(() => ({\n * state: { board: selectedBoard },\n * summary: `Viewing \"${selectedBoard?.name}\"`,\n * }), [selectedBoard]);\n * ```\n */\nexport function useVisibleState(): (state: Record<string, unknown>, summary?: string) => void;\nexport function useVisibleState(\n factory: () => { state: Record<string, unknown>; summary?: string },\n deps: unknown[],\n): void;\nexport function useVisibleState(\n factory?: () => { state: Record<string, unknown>; summary?: string },\n deps?: unknown[],\n): ((state: Record<string, unknown>, summary?: string) => void) | undefined {\n const synapse = useSynapseContext();\n const push = useCallback(\n (state: Record<string, unknown>, summary?: string) => synapse.setVisibleState(state, summary),\n [synapse],\n );\n\n // Declarative mode: auto-push when deps change.\n // The deps array is caller-provided (mirrors useMemo/useEffect pattern).\n const factoryRef = useRef(factory);\n factoryRef.current = factory;\n useEffect(() => {\n if (!factoryRef.current) return;\n const { state, summary } = factoryRef.current();\n push(state, summary);\n }, [...(deps ?? []), push]);\n\n if (!factory) return push;\n}\n\nexport function useFileUpload(): {\n pickFile: (options?: RequestFileOptions) => Promise<FileResult | null>;\n pickFiles: (options?: RequestFileOptions) => Promise<FileResult[]>;\n isPending: boolean;\n} {\n const synapse = useSynapseContext();\n const [isPending, setIsPending] = useState(false);\n\n const pickFile = useCallback(\n async (options?: RequestFileOptions) => {\n setIsPending(true);\n try {\n return await synapse.pickFile(options);\n } finally {\n setIsPending(false);\n }\n },\n [synapse],\n );\n\n const pickFiles = useCallback(\n async (options?: RequestFileOptions) => {\n setIsPending(true);\n try {\n return await synapse.pickFiles(options);\n } finally {\n setIsPending(false);\n }\n },\n [synapse],\n );\n\n return { pickFile, pickFiles, isPending };\n}\n\nexport function useStore<TState, TActions extends Record<string, ActionReducer<TState, any>>>(\n store: Store<TState, TActions>,\n): {\n state: TState;\n dispatch: StoreDispatch<TActions>;\n} {\n const state = useSyncExternalStore(\n (onStoreChange) => store.subscribe(onStoreChange),\n () => store.getState(),\n () => store.getState(),\n );\n\n return { state, dispatch: store.dispatch };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(){'use strict';var C={mode:"light",primaryColor:"#6366f1",tokens:{}};function x(s){let e=s,o=A(e?.serverInfo),n=typeof o?.name=="string"?o.name:"unknown",a=typeof e?.protocolVersion=="string"?e.protocolVersion:"unknown",r=A(e?.hostContext),c=q(r?.theme);return {isNimbleBrain:n==="nimblebrain",serverName:n,protocolVersion:a,theme:c}}function q(s){let e=A(s);if(!e)return {...C};let o=e.mode==="light"||e.mode==="dark"?e.mode:C.mode,n=typeof e.primaryColor=="string"?e.primaryColor:C.primaryColor,a=e.tokens!==null&&typeof e.tokens=="object"&&!Array.isArray(e.tokens)?e.tokens:{};return {mode:o,primaryColor:n,tokens:a}}function A(s){if(s!==null&&typeof s=="object"&&!Array.isArray(s))return s}var S=class{listener;destroyed=false;constructor(e,o){let n=o??null;this.listener=a=>{this.destroyed||this.shouldForward(a,n)&&(a.preventDefault(),e.send("synapse/keydown",{key:a.key,ctrlKey:a.ctrlKey,metaKey:a.metaKey,shiftKey:a.shiftKey,altKey:a.altKey}));},document.addEventListener("keydown",this.listener);}destroy(){this.destroyed||(this.destroyed=true,document.removeEventListener("keydown",this.listener));}shouldForward(e,o){if(o&&o.length===0)return false;if(o)return o.some(n=>e.key.toLowerCase()===n.key.toLowerCase()&&(n.ctrl===void 0||e.ctrlKey===n.ctrl)&&(n.meta===void 0||e.metaKey===n.meta)&&(n.shift===void 0||e.shiftKey===n.shift)&&(n.alt===void 0||e.altKey===n.alt));if(e.key==="Escape")return true;if(e.ctrlKey||e.metaKey){let n=e.key.toLowerCase();return !(n==="c"||n==="v"||n==="x"||n==="a")}return false}};function E(s){return s==null?{data:null,isError:false}:F(s)?I(s):{data:s,isError:false}}function F(s){return s===null||typeof s!="object"||Array.isArray(s)?false:Array.isArray(s.content)}function H(s){if(s===null||typeof s!="object"||Array.isArray(s))return false;let e=s;return e.type==="text"&&typeof e.text=="string"}function I(s){let e=s.isError===true,o=s.content;if(o.length===0)return {data:null,isError:e};let n=o.find(H);if(!n)return {data:o,isError:e};try{return {data:JSON.parse(n.text),isError:e}}catch{return {data:n.text,isError:e}}}var b=class{counter=0;destroyed=false;pending=new Map;handlers=new Map;listener;constructor(){this.listener=e=>this.handleMessage(e),window.addEventListener("message",this.listener);}send(e,o){if(this.destroyed)return;let n={jsonrpc:"2.0",method:e,...o!==void 0&&{params:o}};window.parent.postMessage(n,"*");}request(e,o){if(this.destroyed)return Promise.reject(new Error("Transport destroyed"));let n=`syn-${++this.counter}`,a={jsonrpc:"2.0",method:e,id:n,...o!==void 0&&{params:o}};return new Promise((r,c)=>{this.pending.set(n,{resolve:r,reject:c}),window.parent.postMessage(a,"*");})}onMessage(e,o){return this.handlers.has(e)||this.handlers.set(e,new Set),this.handlers.get(e)?.add(o),()=>{let n=this.handlers.get(e);n&&(n.delete(o),n.size===0&&this.handlers.delete(e));}}destroy(){if(this.destroyed)return;this.destroyed=true,window.removeEventListener("message",this.listener);let e=new Error("Transport destroyed");for(let o of this.pending.values())o.reject(e);this.pending.clear(),this.handlers.clear();}handleMessage(e){if(this.destroyed)return;let o=e.data;if(!(!o||o.jsonrpc!=="2.0")){if("id"in o&&o.id&&!("method"in o)){let n=o,a=this.pending.get(n.id);if(!a)return;if(this.pending.delete(n.id),n.error){let r=new Error(n.error.message);r.code=n.error.code,r.data=n.error.data,a.reject(r);}else a.resolve(n.result);return}if("method"in o&&!("id"in o&&o.id)){let n=o,a=this.handlers.get(n.method);if(a)for(let r of a)r(n.params);}}}};function M(s){let{name:e,version:o,internal:n=false,forwardKeys:a}=s,r=new b,c=null,u={mode:"light",primaryColor:"#6366f1",tokens:{}},T=false,y=null,k=null,R=r.request("ui/initialize",{protocolVersion:"2026-01-26",clientInfo:{name:e,version:o},capabilities:{}}).then(t=>{c=x(t),u=c.theme,r.send("ui/notifications/initialized",{}),k=new S(r,a);}),d=r.onMessage("ui/notifications/host-context-changed",t=>{if(!t)return;let i=t.theme==="dark"?"dark":"light",l=t.tokens&&typeof t.tokens=="object"?t.tokens:u.tokens;u={mode:i,primaryColor:u.primaryColor,tokens:l};for(let m of f)m(u);}),p=r.onMessage("synapse/theme-changed",t=>{if(!t)return;let i=t.mode==="dark"||t.mode==="light"?t.mode:u.mode,l=t.tokens&&typeof t.tokens=="object"?t.tokens:u.tokens;u={mode:i,primaryColor:u.primaryColor,tokens:l};for(let m of f)m(u);}),f=new Set,h=new Set,w=new Set,v=r.onMessage("synapse/data-changed",t=>{if(!t)return;let i={source:"agent",server:t.server??"",tool:t.tool??""};for(let l of h)l(i);}),K=r.onMessage("synapse/action",t=>{if(!t||typeof t.type!="string")return;let i={type:t.type,payload:t.payload??{},requiresConfirmation:t.requiresConfirmation===true,label:typeof t.label=="string"?t.label:void 0};for(let l of w)l(i);}),g=()=>c?.isNimbleBrain===true;return {get ready(){return R},get isNimbleBrainHost(){return g()},get destroyed(){return T},async callTool(t,i){let l={name:t,arguments:i??{}};n&&(l.server=e);let m=await r.request("tools/call",l);return E(m)},onDataChanged(t){return h.add(t),()=>{h.delete(t);}},onAction(t){return w.add(t),()=>{w.delete(t);}},getTheme(){return {...u}},onThemeChanged(t){return f.add(t),()=>{f.delete(t);}},action(t,i){g()&&r.send("synapse/action",{action:t,...i});},chat(t,i){let l={type:"text",text:t};g()&&i&&(l._meta={context:i}),r.send("ui/message",{role:"user",content:[l]});},setVisibleState(t,i){y&&clearTimeout(y),y=setTimeout(()=>{r.send("ui/update-model-context",{structuredContent:t,...i!==void 0&&{content:[{type:"text",text:i}]}}),y=null;},250);},downloadFile(t,i,l){if(!g())return;let m=typeof i=="string"?i:"[Blob content not serializable]";r.send("synapse/download-file",{data:m,filename:t,mimeType:l??"application/octet-stream"});},openLink(t){r.send("ui/open-link",{url:t}),g()||window.open(t,"_blank","noopener");},async requestFile(t){if(!g())throw new Error("requestFile is not supported in this host");return await r.request("synapse/request-file",{accept:t?.accept,maxSize:t?.maxSize??26214400,multiple:false})??null},async requestFiles(t){if(!g())throw new Error("requestFiles is not supported in this host");let i=await r.request("synapse/request-file",{accept:t?.accept,maxSize:t?.maxSize??26214400,multiple:true});return i?Array.isArray(i)?i:[i]:[]},_onMessage(t,i){return r.onMessage(t,i)},_request(t,i){return r.request(t,i)},destroy(){T||(T=true,y&&clearTimeout(y),k?.destroy(),d(),p(),v(),K(),f.clear(),h.clear(),w.clear(),r.destroy());}}}function j(s,e){let o=structuredClone(e.initialState),n=new Set,a=false,r=null,c={};for(let d of Object.keys(e.actions))c[d]=p=>{a||(o=e.actions[d](o,p),u());};function u(){for(let d of n)d(o);e.visibleToAgent&&T(),e.persist&&y();}function T(){let d=e.summarize?.(o);s.setVisibleState(o,d);}function y(){r&&clearTimeout(r),r=setTimeout(()=>{s._request("synapse/persist-state",{state:o,version:e.version}).catch(()=>{}),r=null;},500);}let k;e.persist&&(k=s._onMessage("synapse/state-loaded",d=>{if(!d?.state)return;let p=d.state,f=d.version??1,h=e.version??1;if(e.migrations&&f<h){let w=f-1;for(let v=w;v<e.migrations.length;v++)p=e.migrations[v](p);}R.hydrate(p);}));let R={getState(){return o},subscribe(d){return n.add(d),()=>{n.delete(d);}},dispatch:c,hydrate(d){o=d;for(let p of n)p(o);},destroy(){a||(a=true,r&&clearTimeout(r),n.clear(),k?.());}};return R}window.NbSynapse={createSynapse:M,createStore:j};})();
|
|
1
|
+
(function(){'use strict';function I(s){let e=s??{},o=e.structuredContent??null;if(o!=null)return {content:o,structuredContent:o,raw:e};let n=e.content;if(Array.isArray(n)){let a=n.filter(r=>r!=null&&typeof r=="object"&&r.type==="text"&&typeof r.text=="string").map(r=>r.text);if(a.length>0){let r=a.join("");try{return {content:JSON.parse(r),structuredContent:null,raw:e}}catch{return {content:r,structuredContent:null,raw:e}}}return {content:n,structuredContent:null,raw:e}}if(typeof n=="string")try{return {content:JSON.parse(n),structuredContent:null,raw:e}}catch{return {content:n,structuredContent:null,raw:e}}return {content:n??null,structuredContent:null,raw:e}}var _={"tool-result":"ui/notifications/tool-result","tool-input":"ui/notifications/tool-input","tool-input-partial":"ui/notifications/tool-input-partial","tool-cancelled":"ui/notifications/tool-cancelled","theme-changed":"ui/notifications/host-context-changed",teardown:"ui/resource-teardown"};function C(s){return _[s]??s}function K(s,e){let o=false,n=null,a=null;function r(){if(o)return;let m=document.body.scrollWidth,p=document.body.scrollHeight;s("ui/notifications/size-changed",{width:m,height:p});}function d(m,p){o||(m!==void 0&&p!==void 0?s("ui/notifications/size-changed",{width:m,height:p}):r());}e&&typeof ResizeObserver<"u"&&(n=new ResizeObserver(()=>{o||(a!==null&&cancelAnimationFrame(a),a=requestAnimationFrame(()=>{a=null,r();}));}),n.observe(document.body));function c(){o||(o=true,a!==null&&cancelAnimationFrame(a),n?.disconnect(),n=null);}return {resize:d,measureAndSend:r,destroy:c}}function A(s){return s==null?{data:null,isError:false}:H(s)?B(s):{data:s,isError:false}}function H(s){return s===null||typeof s!="object"||Array.isArray(s)?false:Array.isArray(s.content)}function J(s){if(s===null||typeof s!="object"||Array.isArray(s))return false;let e=s;return e.type==="text"&&typeof e.text=="string"}function B(s){let e=s.isError===true,o=s.content;if(o.length===0)return {data:null,isError:e};let n=o.find(J);if(!n)return {data:o,isError:e};try{return {data:JSON.parse(n.text),isError:e}}catch{return {data:n.text,isError:e}}}var S=class{counter=0;destroyed=false;pending=new Map;handlers=new Map;listener;constructor(){this.listener=e=>this.handleMessage(e),window.addEventListener("message",this.listener);}send(e,o){if(this.destroyed)return;let n={jsonrpc:"2.0",method:e,...o!==void 0&&{params:o}};window.parent.postMessage(n,"*");}request(e,o){if(this.destroyed)return Promise.reject(new Error("Transport destroyed"));let n=`syn-${++this.counter}`,a={jsonrpc:"2.0",method:e,id:n,...o!==void 0&&{params:o}};return new Promise((r,d)=>{this.pending.set(n,{resolve:r,reject:d}),window.parent.postMessage(a,"*");})}onMessage(e,o){return this.handlers.has(e)||this.handlers.set(e,new Set),this.handlers.get(e)?.add(o),()=>{let n=this.handlers.get(e);n&&(n.delete(o),n.size===0&&this.handlers.delete(e));}}destroy(){if(this.destroyed)return;this.destroyed=true,window.removeEventListener("message",this.listener);let e=new Error("Transport destroyed");for(let o of this.pending.values())o.reject(e);this.pending.clear(),this.handlers.clear();}handleMessage(e){if(this.destroyed)return;let o=e.data;if(!(!o||o.jsonrpc!=="2.0")){if("id"in o&&o.id&&!("method"in o)){let n=o,a=this.pending.get(n.id);if(!a)return;if(this.pending.delete(n.id),n.error){let r=new Error(n.error.message);r.code=n.error.code,r.data=n.error.data,a.reject(r);}else a.resolve(n.result);return}if("method"in o&&!("id"in o&&o.id)){let n=o,a=this.handlers.get(n.method);if(a)for(let r of a)r(n.params);}}}};async function O(s){let{name:e,version:o,autoResize:n=false}=s,a=new S,r=false,d={mode:"light",tokens:{}},c={name:"unknown",version:"unknown"},m=null,p=null,g=new Map,v=K((u,t)=>a.send(u,t),n);v.measureAndSend();let w=await a.request("ui/initialize",{protocolVersion:"2026-01-26",clientInfo:{name:e,version:o},capabilities:{}})??{},h=x(w.serverInfo);c={name:typeof h?.name=="string"?h.name:"unknown",version:typeof h?.version=="string"?h.version:"unknown"};let y=x(w.hostContext);if(y){let u=x(y.theme);if(u&&(d={mode:u.mode==="dark"?"dark":"light",tokens:u.tokens&&typeof u.tokens=="object"&&!Array.isArray(u.tokens)?u.tokens:{}}),y.toolInfo&&typeof y.toolInfo=="object"){let i=y.toolInfo;m={tool:i.tool??i};}y.containerDimensions&&typeof y.containerDimensions=="object"&&(p=y.containerDimensions);let t=x(y.styles);D(t?.variables);}a.send("ui/notifications/initialized",{});let R=C("theme-changed");a.onMessage(R,u=>{if(r||!u)return;let t=u.theme==="dark"?"dark":"light",i=u.tokens&&typeof u.tokens=="object"&&!Array.isArray(u.tokens)?u.tokens:d.tokens;d={mode:t,tokens:i},D(i);let l=g.get(R);if(l)for(let k of l)k(d);});let T=new Set([R]);function j(u){if(T.has(u))return;T.add(u);let t=C("tool-result"),i=u===t;a.onMessage(u,l=>{if(r)return;let k=g.get(u);if(k)for(let F of k)F(i?I(l):l);});}return {get theme(){return {...d}},get hostInfo(){return {...c}},get toolInfo(){return m},get containerDimensions(){return p},on(u,t){let i=C(u);return g.has(i)||g.set(i,new Set),g.get(i)?.add(t),j(i),()=>{let l=g.get(i);l&&(l.delete(t),l.size===0&&g.delete(i));}},resize(u,t){v.resize(u,t);},openLink(u){r||a.send("ui/open-link",{url:u});},updateModelContext(u,t){r||a.send("ui/update-model-context",{structuredContent:u,...t!==void 0&&{content:[{type:"text",text:t}]}});},async callTool(u,t){let i=await a.request("tools/call",{name:u,arguments:t??{}});return A(i)},sendMessage(u,t){if(r)return;let i={type:"text",text:u};t&&(i._meta={context:t}),a.send("ui/message",{role:"user",content:[i]});},destroy(){r||(r=true,v.destroy(),g.clear(),a.destroy());}}}function x(s){if(s!==null&&typeof s=="object"&&!Array.isArray(s))return s}function D(s){if(!(!s||typeof s!="object"))for(let[e,o]of Object.entries(s))typeof e=="string"&&typeof o=="string"&&document.documentElement.style.setProperty(e,o);}var E={mode:"light",primaryColor:"#6366f1",tokens:{}};function q(s){let e=s,o=z(e?.serverInfo),n=typeof o?.name=="string"?o.name:"unknown",a=typeof e?.protocolVersion=="string"?e.protocolVersion:"unknown",r=z(e?.hostContext),d=L(r?.theme);return {isNimbleBrain:n==="nimblebrain",serverName:n,protocolVersion:a,theme:d}}function L(s){let e=z(s);if(!e)return {...E};let o=e.mode==="light"||e.mode==="dark"?e.mode:E.mode,n=typeof e.primaryColor=="string"?e.primaryColor:E.primaryColor,a=e.tokens!==null&&typeof e.tokens=="object"&&!Array.isArray(e.tokens)?e.tokens:{};return {mode:o,primaryColor:n,tokens:a}}function z(s){if(s!==null&&typeof s=="object"&&!Array.isArray(s))return s}var M=class{listener;destroyed=false;constructor(e,o){let n=o??null;this.listener=a=>{this.destroyed||this.shouldForward(a,n)&&(a.preventDefault(),e.send("synapse/keydown",{key:a.key,ctrlKey:a.ctrlKey,metaKey:a.metaKey,shiftKey:a.shiftKey,altKey:a.altKey}));},document.addEventListener("keydown",this.listener);}destroy(){this.destroyed||(this.destroyed=true,document.removeEventListener("keydown",this.listener));}shouldForward(e,o){if(o&&o.length===0)return false;if(o)return o.some(n=>e.key.toLowerCase()===n.key.toLowerCase()&&(n.ctrl===void 0||e.ctrlKey===n.ctrl)&&(n.meta===void 0||e.metaKey===n.meta)&&(n.shift===void 0||e.shiftKey===n.shift)&&(n.alt===void 0||e.altKey===n.alt));if(e.key==="Escape")return true;if(e.ctrlKey||e.metaKey){let n=e.key.toLowerCase();return !(n==="c"||n==="v"||n==="x"||n==="a")}return false}};function P(s){let{name:e,version:o,internal:n=false,forwardKeys:a}=s,r=new S,d=null,c={mode:"light",primaryColor:"#6366f1",tokens:{}},m=false,p=null,g=null,v=r.request("ui/initialize",{protocolVersion:"2026-01-26",clientInfo:{name:e,version:o},capabilities:{}}).then(t=>{d=q(t),c=d.theme,r.send("ui/notifications/initialized",{}),g=new M(r,a);}),f=r.onMessage("ui/notifications/host-context-changed",t=>{if(!t)return;let i=t.theme==="dark"?"dark":"light",l=t.tokens&&typeof t.tokens=="object"?t.tokens:c.tokens;c={mode:i,primaryColor:c.primaryColor,tokens:l};for(let k of h)k(c);}),w=r.onMessage("synapse/theme-changed",t=>{if(!t)return;let i=t.mode==="dark"||t.mode==="light"?t.mode:c.mode,l=t.tokens&&typeof t.tokens=="object"?t.tokens:c.tokens;c={mode:i,primaryColor:c.primaryColor,tokens:l};for(let k of h)k(c);}),h=new Set,y=new Set,R=new Set,T=r.onMessage("synapse/data-changed",t=>{if(!t)return;let i={source:"agent",server:t.server??"",tool:t.tool??""};for(let l of y)l(i);}),j=r.onMessage("synapse/action",t=>{if(!t||typeof t.type!="string")return;let i={type:t.type,payload:t.payload??{},requiresConfirmation:t.requiresConfirmation===true,label:typeof t.label=="string"?t.label:void 0};for(let l of R)l(i);}),b=()=>d?.isNimbleBrain===true;return {get ready(){return v},get isNimbleBrainHost(){return b()},get destroyed(){return m},async callTool(t,i){let l={name:t,arguments:i??{}};n&&(l.server=e);let k=await r.request("tools/call",l);return A(k)},onDataChanged(t){return y.add(t),()=>{y.delete(t);}},onAction(t){return R.add(t),()=>{R.delete(t);}},getTheme(){return {...c}},onThemeChanged(t){return h.add(t),()=>{h.delete(t);}},action(t,i){b()&&r.send("synapse/action",{action:t,...i});},chat(t,i){let l={type:"text",text:t};b()&&i&&(l._meta={context:i}),r.send("ui/message",{role:"user",content:[l]});},setVisibleState(t,i){p&&clearTimeout(p),p=setTimeout(()=>{r.send("ui/update-model-context",{structuredContent:t,...i!==void 0&&{content:[{type:"text",text:i}]}}),p=null;},250);},saveFile(t,i,l){let k=typeof i=="string"?i:"[Blob content not serializable]";r.send("synapse/save-file",{data:k,filename:t,mimeType:l??"application/octet-stream"});},openLink(t){r.send("ui/open-link",{url:t}),b()||window.open(t,"_blank","noopener");},async pickFile(t){if(!b())throw new Error("pickFile is not supported in this host");return await r.request("synapse/pick-file",{accept:t?.accept,maxSize:t?.maxSize??26214400,multiple:false})??null},async pickFiles(t){if(!b())throw new Error("pickFiles is not supported in this host");let i=await r.request("synapse/pick-file",{accept:t?.accept,maxSize:t?.maxSize??26214400,multiple:true});return i?Array.isArray(i)?i:[i]:[]},_onMessage(t,i){return r.onMessage(t,i)},_request(t,i){return r.request(t,i)},destroy(){m||(m=true,p&&clearTimeout(p),g?.destroy(),f(),w(),T(),j(),h.clear(),y.clear(),R.clear(),r.destroy());}}}function N(s,e){let o=structuredClone(e.initialState),n=new Set,a=false,r=null,d={};for(let f of Object.keys(e.actions))d[f]=w=>{a||(o=e.actions[f](o,w),c());};function c(){for(let f of n)f(o);e.visibleToAgent&&m(),e.persist&&p();}function m(){let f=e.summarize?.(o);s.setVisibleState(o,f);}function p(){r&&clearTimeout(r),r=setTimeout(()=>{s._request("synapse/persist-state",{state:o,version:e.version}).catch(()=>{}),r=null;},500);}let g;e.persist&&(g=s._onMessage("synapse/state-loaded",f=>{if(!f?.state)return;let w=f.state,h=f.version??1,y=e.version??1;if(e.migrations&&h<y){let R=h-1;for(let T=R;T<e.migrations.length;T++)w=e.migrations[T](w);}v.hydrate(w);}));let v={getState(){return o},subscribe(f){return n.add(f),()=>{n.delete(f);}},dispatch:d,hydrate(f){o=f;for(let w of n)w(o);},destroy(){a||(a=true,r&&clearTimeout(r),n.clear(),g?.());}};return v}window.Synapse={connect:O,createSynapse:P,createStore:N};})();
|