@nimblebrain/synapse 0.2.1 → 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-Y4ZDNAYQ.cjs → chunk-B3T6NB32.cjs} +349 -80
- package/dist/chunk-B3T6NB32.cjs.map +1 -0
- package/dist/{chunk-7KEYXJWD.js → chunk-GQ4L63CL.js} +349 -81
- package/dist/chunk-GQ4L63CL.js.map +1 -0
- package/dist/codegen/cli.cjs +1 -1
- package/dist/codegen/cli.js +1 -1
- 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 +8 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +119 -3
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +18 -2
- package/dist/react/index.d.ts +18 -2
- package/dist/react/index.js +114 -5
- package/dist/react/index.js.map +1 -1
- package/dist/{server-NNW54YW5.js → server-7BRGSPT3.js} +13 -13
- package/dist/{server-NNW54YW5.js.map → server-7BRGSPT3.js.map} +1 -1
- package/dist/{server-3BDZ5S72.cjs → server-SRE7E3G3.cjs} +13 -13
- package/dist/{server-3BDZ5S72.cjs.map → server-SRE7E3G3.cjs.map} +1 -1
- package/dist/synapse-runtime.iife.global.js +1 -1
- package/dist/{types-DElq_otH.d.cts → types-DJ32F5EL.d.cts} +79 -4
- package/dist/{types-DElq_otH.d.ts → types-DJ32F5EL.d.ts} +79 -4
- package/dist/vite/index.cjs +6 -6
- package/dist/vite/index.cjs.map +1 -1
- package/dist/vite/index.js +6 -6
- package/dist/vite/index.js.map +1 -1
- package/package.json +4 -1
- package/dist/chunk-7KEYXJWD.js.map +0 -1
- package/dist/chunk-Y4ZDNAYQ.cjs.map +0 -1
|
@@ -1,82 +1,89 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// src/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
};
|
|
9
|
-
function detectHost(initResponse) {
|
|
10
|
-
const resp = initResponse;
|
|
11
|
-
const serverInfo = safeObj(resp?.serverInfo);
|
|
12
|
-
const serverName = typeof serverInfo?.name === "string" ? serverInfo.name : "unknown";
|
|
13
|
-
const protocolVersion = typeof resp?.protocolVersion === "string" ? resp.protocolVersion : "unknown";
|
|
14
|
-
const hostContext = safeObj(resp?.hostContext);
|
|
15
|
-
const theme = extractTheme(hostContext?.theme);
|
|
16
|
-
return {
|
|
17
|
-
isNimbleBrain: serverName === "nimblebrain",
|
|
18
|
-
serverName,
|
|
19
|
-
protocolVersion,
|
|
20
|
-
theme
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
function extractTheme(raw) {
|
|
24
|
-
const obj = safeObj(raw);
|
|
25
|
-
if (!obj) return { ...DEFAULT_THEME };
|
|
26
|
-
const mode = obj.mode === "light" || obj.mode === "dark" ? obj.mode : DEFAULT_THEME.mode;
|
|
27
|
-
const primaryColor = typeof obj.primaryColor === "string" ? obj.primaryColor : DEFAULT_THEME.primaryColor;
|
|
28
|
-
const tokens = obj.tokens !== null && typeof obj.tokens === "object" && !Array.isArray(obj.tokens) ? obj.tokens : {};
|
|
29
|
-
return { mode, primaryColor, tokens };
|
|
30
|
-
}
|
|
31
|
-
function safeObj(value) {
|
|
32
|
-
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
33
|
-
return value;
|
|
3
|
+
// src/content-parser.ts
|
|
4
|
+
function parseToolResultParams(params) {
|
|
5
|
+
const raw = params ?? {};
|
|
6
|
+
const structuredContent = raw.structuredContent ?? null;
|
|
7
|
+
if (structuredContent != null) {
|
|
8
|
+
return { content: structuredContent, structuredContent, raw };
|
|
34
9
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (this.shouldForward(event, config)) {
|
|
47
|
-
event.preventDefault();
|
|
48
|
-
transport.send("ui/keydown", {
|
|
49
|
-
key: event.key,
|
|
50
|
-
ctrlKey: event.ctrlKey,
|
|
51
|
-
metaKey: event.metaKey,
|
|
52
|
-
shiftKey: event.shiftKey,
|
|
53
|
-
altKey: event.altKey
|
|
54
|
-
});
|
|
10
|
+
const rawContent = raw.content;
|
|
11
|
+
if (Array.isArray(rawContent)) {
|
|
12
|
+
const texts = rawContent.filter(
|
|
13
|
+
(block) => block != null && typeof block === "object" && block.type === "text" && typeof block.text === "string"
|
|
14
|
+
).map((block) => block.text);
|
|
15
|
+
if (texts.length > 0) {
|
|
16
|
+
const joined = texts.join("");
|
|
17
|
+
try {
|
|
18
|
+
return { content: JSON.parse(joined), structuredContent: null, raw };
|
|
19
|
+
} catch {
|
|
20
|
+
return { content: joined, structuredContent: null, raw };
|
|
55
21
|
}
|
|
56
|
-
};
|
|
57
|
-
document.addEventListener("keydown", this.listener);
|
|
58
|
-
}
|
|
59
|
-
destroy() {
|
|
60
|
-
if (this.destroyed) return;
|
|
61
|
-
this.destroyed = true;
|
|
62
|
-
document.removeEventListener("keydown", this.listener);
|
|
63
|
-
}
|
|
64
|
-
shouldForward(event, config) {
|
|
65
|
-
if (config && config.length === 0) return false;
|
|
66
|
-
if (config) {
|
|
67
|
-
return config.some(
|
|
68
|
-
(k) => event.key.toLowerCase() === k.key.toLowerCase() && (k.ctrl === void 0 || event.ctrlKey === k.ctrl) && (k.meta === void 0 || event.metaKey === k.meta) && (k.shift === void 0 || event.shiftKey === k.shift) && (k.alt === void 0 || event.altKey === k.alt)
|
|
69
|
-
);
|
|
70
22
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return
|
|
23
|
+
return { content: rawContent, structuredContent: null, raw };
|
|
24
|
+
}
|
|
25
|
+
if (typeof rawContent === "string") {
|
|
26
|
+
try {
|
|
27
|
+
return { content: JSON.parse(rawContent), structuredContent: null, raw };
|
|
28
|
+
} catch {
|
|
29
|
+
return { content: rawContent, structuredContent: null, raw };
|
|
76
30
|
}
|
|
77
|
-
return false;
|
|
78
31
|
}
|
|
32
|
+
return { content: rawContent ?? null, structuredContent: null, raw };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/event-map.ts
|
|
36
|
+
var EVENT_MAP = {
|
|
37
|
+
"tool-result": "ui/notifications/tool-result",
|
|
38
|
+
"tool-input": "ui/notifications/tool-input",
|
|
39
|
+
"tool-input-partial": "ui/notifications/tool-input-partial",
|
|
40
|
+
"tool-cancelled": "ui/notifications/tool-cancelled",
|
|
41
|
+
"theme-changed": "ui/notifications/host-context-changed",
|
|
42
|
+
teardown: "ui/resource-teardown"
|
|
79
43
|
};
|
|
44
|
+
function resolveEventMethod(name) {
|
|
45
|
+
return EVENT_MAP[name] ?? name;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/resize.ts
|
|
49
|
+
function createResizer(send, autoResize) {
|
|
50
|
+
let destroyed = false;
|
|
51
|
+
let observer = null;
|
|
52
|
+
let rafId = null;
|
|
53
|
+
function measureAndSend() {
|
|
54
|
+
if (destroyed) return;
|
|
55
|
+
const width = document.body.scrollWidth;
|
|
56
|
+
const height = document.body.scrollHeight;
|
|
57
|
+
send("ui/notifications/size-changed", { width, height });
|
|
58
|
+
}
|
|
59
|
+
function resize(width, height) {
|
|
60
|
+
if (destroyed) return;
|
|
61
|
+
if (width !== void 0 && height !== void 0) {
|
|
62
|
+
send("ui/notifications/size-changed", { width, height });
|
|
63
|
+
} else {
|
|
64
|
+
measureAndSend();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (autoResize && typeof ResizeObserver !== "undefined") {
|
|
68
|
+
observer = new ResizeObserver(() => {
|
|
69
|
+
if (destroyed) return;
|
|
70
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
71
|
+
rafId = requestAnimationFrame(() => {
|
|
72
|
+
rafId = null;
|
|
73
|
+
measureAndSend();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
observer.observe(document.body);
|
|
77
|
+
}
|
|
78
|
+
function destroy() {
|
|
79
|
+
if (destroyed) return;
|
|
80
|
+
destroyed = true;
|
|
81
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
82
|
+
observer?.disconnect();
|
|
83
|
+
observer = null;
|
|
84
|
+
}
|
|
85
|
+
return { resize, measureAndSend, destroy };
|
|
86
|
+
}
|
|
80
87
|
|
|
81
88
|
// src/result-parser.ts
|
|
82
89
|
function parseToolResult(raw) {
|
|
@@ -211,6 +218,245 @@ var SynapseTransport = class {
|
|
|
211
218
|
}
|
|
212
219
|
};
|
|
213
220
|
|
|
221
|
+
// src/connect.ts
|
|
222
|
+
async function connect(options) {
|
|
223
|
+
const { name, version, autoResize = false } = options;
|
|
224
|
+
const transport = new SynapseTransport();
|
|
225
|
+
let destroyed = false;
|
|
226
|
+
let currentTheme = { mode: "light", tokens: {} };
|
|
227
|
+
let hostInfo = { name: "unknown", version: "unknown" };
|
|
228
|
+
let toolInfo = null;
|
|
229
|
+
let containerDimensions = null;
|
|
230
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
231
|
+
const resizer = createResizer((method, params) => transport.send(method, params), autoResize);
|
|
232
|
+
resizer.measureAndSend();
|
|
233
|
+
const result = await transport.request("ui/initialize", {
|
|
234
|
+
protocolVersion: "2026-01-26",
|
|
235
|
+
clientInfo: { name, version },
|
|
236
|
+
capabilities: {}
|
|
237
|
+
});
|
|
238
|
+
const resp = result ?? {};
|
|
239
|
+
const serverInfo = safeObj(resp.serverInfo);
|
|
240
|
+
hostInfo = {
|
|
241
|
+
name: typeof serverInfo?.name === "string" ? serverInfo.name : "unknown",
|
|
242
|
+
version: typeof serverInfo?.version === "string" ? serverInfo.version : "unknown"
|
|
243
|
+
};
|
|
244
|
+
const hostContext = safeObj(resp.hostContext);
|
|
245
|
+
if (hostContext) {
|
|
246
|
+
const themeRaw = safeObj(hostContext.theme);
|
|
247
|
+
if (themeRaw) {
|
|
248
|
+
currentTheme = {
|
|
249
|
+
mode: themeRaw.mode === "dark" ? "dark" : "light",
|
|
250
|
+
tokens: themeRaw.tokens && typeof themeRaw.tokens === "object" && !Array.isArray(themeRaw.tokens) ? themeRaw.tokens : {}
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
if (hostContext.toolInfo && typeof hostContext.toolInfo === "object") {
|
|
254
|
+
const ti = hostContext.toolInfo;
|
|
255
|
+
toolInfo = { tool: ti.tool ?? ti };
|
|
256
|
+
}
|
|
257
|
+
if (hostContext.containerDimensions && typeof hostContext.containerDimensions === "object") {
|
|
258
|
+
containerDimensions = hostContext.containerDimensions;
|
|
259
|
+
}
|
|
260
|
+
const styles = safeObj(hostContext.styles);
|
|
261
|
+
injectCssVariables(styles?.variables);
|
|
262
|
+
}
|
|
263
|
+
transport.send("ui/notifications/initialized", {});
|
|
264
|
+
const themeMethod = resolveEventMethod("theme-changed");
|
|
265
|
+
transport.onMessage(themeMethod, (params) => {
|
|
266
|
+
if (destroyed || !params) return;
|
|
267
|
+
const mode = params.theme === "dark" ? "dark" : "light";
|
|
268
|
+
const tokens = params.tokens && typeof params.tokens === "object" && !Array.isArray(params.tokens) ? params.tokens : currentTheme.tokens;
|
|
269
|
+
currentTheme = { mode, tokens };
|
|
270
|
+
injectCssVariables(tokens);
|
|
271
|
+
const set = handlers.get(themeMethod);
|
|
272
|
+
if (set) {
|
|
273
|
+
for (const handler of set) handler(currentTheme);
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
const subscribedMethods = /* @__PURE__ */ new Set([themeMethod]);
|
|
277
|
+
function ensureTransportSub(method) {
|
|
278
|
+
if (subscribedMethods.has(method)) return;
|
|
279
|
+
subscribedMethods.add(method);
|
|
280
|
+
const toolResultMethod = resolveEventMethod("tool-result");
|
|
281
|
+
const isToolResult = method === toolResultMethod;
|
|
282
|
+
transport.onMessage(method, (params) => {
|
|
283
|
+
if (destroyed) return;
|
|
284
|
+
const set = handlers.get(method);
|
|
285
|
+
if (!set) return;
|
|
286
|
+
for (const handler of set) {
|
|
287
|
+
if (isToolResult) {
|
|
288
|
+
handler(parseToolResultParams(params));
|
|
289
|
+
} else {
|
|
290
|
+
handler(params);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
const app = {
|
|
296
|
+
get theme() {
|
|
297
|
+
return { ...currentTheme };
|
|
298
|
+
},
|
|
299
|
+
get hostInfo() {
|
|
300
|
+
return { ...hostInfo };
|
|
301
|
+
},
|
|
302
|
+
get toolInfo() {
|
|
303
|
+
return toolInfo;
|
|
304
|
+
},
|
|
305
|
+
get containerDimensions() {
|
|
306
|
+
return containerDimensions;
|
|
307
|
+
},
|
|
308
|
+
on(event, handler) {
|
|
309
|
+
const method = resolveEventMethod(event);
|
|
310
|
+
if (!handlers.has(method)) {
|
|
311
|
+
handlers.set(method, /* @__PURE__ */ new Set());
|
|
312
|
+
}
|
|
313
|
+
handlers.get(method)?.add(handler);
|
|
314
|
+
ensureTransportSub(method);
|
|
315
|
+
return () => {
|
|
316
|
+
const set = handlers.get(method);
|
|
317
|
+
if (set) {
|
|
318
|
+
set.delete(handler);
|
|
319
|
+
if (set.size === 0) handlers.delete(method);
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
},
|
|
323
|
+
resize(width, height) {
|
|
324
|
+
resizer.resize(width, height);
|
|
325
|
+
},
|
|
326
|
+
openLink(url) {
|
|
327
|
+
if (destroyed) return;
|
|
328
|
+
transport.send("ui/open-link", { url });
|
|
329
|
+
},
|
|
330
|
+
updateModelContext(state, summary) {
|
|
331
|
+
if (destroyed) return;
|
|
332
|
+
transport.send("ui/update-model-context", {
|
|
333
|
+
structuredContent: state,
|
|
334
|
+
...summary !== void 0 && {
|
|
335
|
+
content: [{ type: "text", text: summary }]
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
},
|
|
339
|
+
async callTool(toolName, args) {
|
|
340
|
+
const raw = await transport.request("tools/call", {
|
|
341
|
+
name: toolName,
|
|
342
|
+
arguments: args ?? {}
|
|
343
|
+
});
|
|
344
|
+
return parseToolResult(raw);
|
|
345
|
+
},
|
|
346
|
+
sendMessage(text, context) {
|
|
347
|
+
if (destroyed) return;
|
|
348
|
+
const textBlock = { type: "text", text };
|
|
349
|
+
if (context) {
|
|
350
|
+
textBlock._meta = { context };
|
|
351
|
+
}
|
|
352
|
+
transport.send("ui/message", {
|
|
353
|
+
role: "user",
|
|
354
|
+
content: [textBlock]
|
|
355
|
+
});
|
|
356
|
+
},
|
|
357
|
+
destroy() {
|
|
358
|
+
if (destroyed) return;
|
|
359
|
+
destroyed = true;
|
|
360
|
+
resizer.destroy();
|
|
361
|
+
handlers.clear();
|
|
362
|
+
transport.destroy();
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
return app;
|
|
366
|
+
}
|
|
367
|
+
function safeObj(value) {
|
|
368
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
369
|
+
return value;
|
|
370
|
+
}
|
|
371
|
+
return void 0;
|
|
372
|
+
}
|
|
373
|
+
function injectCssVariables(vars) {
|
|
374
|
+
if (!vars || typeof vars !== "object") return;
|
|
375
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
376
|
+
if (typeof k === "string" && typeof v === "string") {
|
|
377
|
+
document.documentElement.style.setProperty(k, v);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// src/detection.ts
|
|
383
|
+
var DEFAULT_THEME = {
|
|
384
|
+
mode: "light",
|
|
385
|
+
primaryColor: "#6366f1",
|
|
386
|
+
tokens: {}
|
|
387
|
+
};
|
|
388
|
+
function detectHost(initResponse) {
|
|
389
|
+
const resp = initResponse;
|
|
390
|
+
const serverInfo = safeObj2(resp?.serverInfo);
|
|
391
|
+
const serverName = typeof serverInfo?.name === "string" ? serverInfo.name : "unknown";
|
|
392
|
+
const protocolVersion = typeof resp?.protocolVersion === "string" ? resp.protocolVersion : "unknown";
|
|
393
|
+
const hostContext = safeObj2(resp?.hostContext);
|
|
394
|
+
const theme = extractTheme(hostContext?.theme);
|
|
395
|
+
return {
|
|
396
|
+
isNimbleBrain: serverName === "nimblebrain",
|
|
397
|
+
serverName,
|
|
398
|
+
protocolVersion,
|
|
399
|
+
theme
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
function extractTheme(raw) {
|
|
403
|
+
const obj = safeObj2(raw);
|
|
404
|
+
if (!obj) return { ...DEFAULT_THEME };
|
|
405
|
+
const mode = obj.mode === "light" || obj.mode === "dark" ? obj.mode : DEFAULT_THEME.mode;
|
|
406
|
+
const primaryColor = typeof obj.primaryColor === "string" ? obj.primaryColor : DEFAULT_THEME.primaryColor;
|
|
407
|
+
const tokens = obj.tokens !== null && typeof obj.tokens === "object" && !Array.isArray(obj.tokens) ? obj.tokens : {};
|
|
408
|
+
return { mode, primaryColor, tokens };
|
|
409
|
+
}
|
|
410
|
+
function safeObj2(value) {
|
|
411
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
412
|
+
return value;
|
|
413
|
+
}
|
|
414
|
+
return void 0;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// src/keyboard.ts
|
|
418
|
+
var KeyboardForwarder = class {
|
|
419
|
+
listener;
|
|
420
|
+
destroyed = false;
|
|
421
|
+
constructor(transport, customKeys) {
|
|
422
|
+
const config = customKeys ?? null;
|
|
423
|
+
this.listener = (event) => {
|
|
424
|
+
if (this.destroyed) return;
|
|
425
|
+
if (this.shouldForward(event, config)) {
|
|
426
|
+
event.preventDefault();
|
|
427
|
+
transport.send("synapse/keydown", {
|
|
428
|
+
key: event.key,
|
|
429
|
+
ctrlKey: event.ctrlKey,
|
|
430
|
+
metaKey: event.metaKey,
|
|
431
|
+
shiftKey: event.shiftKey,
|
|
432
|
+
altKey: event.altKey
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
document.addEventListener("keydown", this.listener);
|
|
437
|
+
}
|
|
438
|
+
destroy() {
|
|
439
|
+
if (this.destroyed) return;
|
|
440
|
+
this.destroyed = true;
|
|
441
|
+
document.removeEventListener("keydown", this.listener);
|
|
442
|
+
}
|
|
443
|
+
shouldForward(event, config) {
|
|
444
|
+
if (config && config.length === 0) return false;
|
|
445
|
+
if (config) {
|
|
446
|
+
return config.some(
|
|
447
|
+
(k) => event.key.toLowerCase() === k.key.toLowerCase() && (k.ctrl === void 0 || event.ctrlKey === k.ctrl) && (k.meta === void 0 || event.metaKey === k.meta) && (k.shift === void 0 || event.shiftKey === k.shift) && (k.alt === void 0 || event.altKey === k.alt)
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
if (event.key === "Escape") return true;
|
|
451
|
+
if (event.ctrlKey || event.metaKey) {
|
|
452
|
+
const key = event.key.toLowerCase();
|
|
453
|
+
if (key === "c" || key === "v" || key === "x" || key === "a") return false;
|
|
454
|
+
return true;
|
|
455
|
+
}
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
|
|
214
460
|
// src/core.ts
|
|
215
461
|
function createSynapse(options) {
|
|
216
462
|
const { name, version, internal = false, forwardKeys } = options;
|
|
@@ -241,7 +487,7 @@ function createSynapse(options) {
|
|
|
241
487
|
currentTheme = { mode, primaryColor: currentTheme.primaryColor, tokens };
|
|
242
488
|
for (const cb of themeCallbacks) cb(currentTheme);
|
|
243
489
|
});
|
|
244
|
-
const unsubNbTheme = transport.onMessage("
|
|
490
|
+
const unsubNbTheme = transport.onMessage("synapse/theme-changed", (params) => {
|
|
245
491
|
if (!params) return;
|
|
246
492
|
const mode = params.mode === "dark" || params.mode === "light" ? params.mode : currentTheme.mode;
|
|
247
493
|
const tokens = params.tokens && typeof params.tokens === "object" ? params.tokens : currentTheme.tokens;
|
|
@@ -251,7 +497,7 @@ function createSynapse(options) {
|
|
|
251
497
|
const themeCallbacks = /* @__PURE__ */ new Set();
|
|
252
498
|
const dataCallbacks = /* @__PURE__ */ new Set();
|
|
253
499
|
const actionCallbacks = /* @__PURE__ */ new Set();
|
|
254
|
-
const unsubData = transport.onMessage("
|
|
500
|
+
const unsubData = transport.onMessage("synapse/data-changed", (params) => {
|
|
255
501
|
if (!params) return;
|
|
256
502
|
const event = {
|
|
257
503
|
source: "agent",
|
|
@@ -260,7 +506,7 @@ function createSynapse(options) {
|
|
|
260
506
|
};
|
|
261
507
|
for (const cb of dataCallbacks) cb(event);
|
|
262
508
|
});
|
|
263
|
-
const unsubAction = transport.onMessage("
|
|
509
|
+
const unsubAction = transport.onMessage("synapse/action", (params) => {
|
|
264
510
|
if (!params || typeof params.type !== "string") return;
|
|
265
511
|
const action = {
|
|
266
512
|
type: params.type,
|
|
@@ -315,7 +561,7 @@ function createSynapse(options) {
|
|
|
315
561
|
},
|
|
316
562
|
action(action, params) {
|
|
317
563
|
if (!isNB()) return;
|
|
318
|
-
transport.send("
|
|
564
|
+
transport.send("synapse/action", { action, ...params });
|
|
319
565
|
},
|
|
320
566
|
chat(message, context) {
|
|
321
567
|
const textBlock = { type: "text", text: message };
|
|
@@ -339,10 +585,9 @@ function createSynapse(options) {
|
|
|
339
585
|
stateTimer = null;
|
|
340
586
|
}, 250);
|
|
341
587
|
},
|
|
342
|
-
|
|
343
|
-
if (!isNB()) return;
|
|
588
|
+
saveFile(filename, content, mimeType) {
|
|
344
589
|
const data = typeof content === "string" ? content : "[Blob content not serializable]";
|
|
345
|
-
transport.send("
|
|
590
|
+
transport.send("synapse/save-file", {
|
|
346
591
|
data,
|
|
347
592
|
filename,
|
|
348
593
|
mimeType: mimeType ?? "application/octet-stream"
|
|
@@ -354,6 +599,29 @@ function createSynapse(options) {
|
|
|
354
599
|
window.open(url, "_blank", "noopener");
|
|
355
600
|
}
|
|
356
601
|
},
|
|
602
|
+
async pickFile(options2) {
|
|
603
|
+
if (!isNB()) {
|
|
604
|
+
throw new Error("pickFile is not supported in this host");
|
|
605
|
+
}
|
|
606
|
+
const result = await transport.request("synapse/pick-file", {
|
|
607
|
+
accept: options2?.accept,
|
|
608
|
+
maxSize: options2?.maxSize ?? 26214400,
|
|
609
|
+
multiple: false
|
|
610
|
+
});
|
|
611
|
+
return result ?? null;
|
|
612
|
+
},
|
|
613
|
+
async pickFiles(options2) {
|
|
614
|
+
if (!isNB()) {
|
|
615
|
+
throw new Error("pickFiles is not supported in this host");
|
|
616
|
+
}
|
|
617
|
+
const result = await transport.request("synapse/pick-file", {
|
|
618
|
+
accept: options2?.accept,
|
|
619
|
+
maxSize: options2?.maxSize ?? 26214400,
|
|
620
|
+
multiple: true
|
|
621
|
+
});
|
|
622
|
+
if (!result) return [];
|
|
623
|
+
return Array.isArray(result) ? result : [result];
|
|
624
|
+
},
|
|
357
625
|
_onMessage(method, callback) {
|
|
358
626
|
return transport.onMessage(method, callback);
|
|
359
627
|
},
|
|
@@ -378,6 +646,7 @@ function createSynapse(options) {
|
|
|
378
646
|
return synapse;
|
|
379
647
|
}
|
|
380
648
|
|
|
649
|
+
exports.connect = connect;
|
|
381
650
|
exports.createSynapse = createSynapse;
|
|
382
|
-
//# sourceMappingURL=chunk-
|
|
383
|
-
//# sourceMappingURL=chunk-
|
|
651
|
+
//# sourceMappingURL=chunk-B3T6NB32.cjs.map
|
|
652
|
+
//# sourceMappingURL=chunk-B3T6NB32.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/content-parser.ts","../src/event-map.ts","../src/resize.ts","../src/result-parser.ts","../src/transport.ts","../src/connect.ts","../src/detection.ts","../src/keyboard.ts","../src/core.ts"],"names":["safeObj","options"],"mappings":"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","file":"chunk-B3T6NB32.cjs","sourcesContent":["import type { ToolResultData } from \"./types.js\";\n\nexport type { ToolResultData };\n\n/**\n * Parse inbound `ui/notifications/tool-result` notification params into\n * a consistent `ToolResultData` shape.\n *\n * Implements the 5-step parsing algorithm from the RFC:\n * 1. If `params.structuredContent` exists → use it as content.\n * 2. Else if `params.content` is an array of `{type:\"text\", text}` blocks →\n * join the text values and try JSON.parse.\n * 3. Else if `params.content` is a string → try JSON.parse.\n * 4. If JSON.parse fails in steps 2 or 3 → deliver the raw string.\n * 5. Return `{ content, structuredContent, raw }`.\n */\nexport function parseToolResultParams(params: Record<string, unknown> | undefined): ToolResultData {\n const raw = params ?? {};\n const structuredContent = raw.structuredContent ?? null;\n\n // Step 1: If structuredContent exists, use it as content\n if (structuredContent != null) {\n return { content: structuredContent, structuredContent, raw };\n }\n\n const rawContent = raw.content;\n\n // Step 2: If content is array of {type:\"text\", text} blocks, join texts and try JSON.parse\n if (Array.isArray(rawContent)) {\n const texts = rawContent\n .filter(\n (block: unknown) =>\n block != null &&\n typeof block === \"object\" &&\n (block as Record<string, unknown>).type === \"text\" &&\n typeof (block as Record<string, unknown>).text === \"string\",\n )\n .map((block: unknown) => (block as Record<string, unknown>).text as string);\n\n if (texts.length > 0) {\n const joined = texts.join(\"\");\n try {\n return { content: JSON.parse(joined), structuredContent: null, raw };\n } catch {\n return { content: joined, structuredContent: null, raw };\n }\n }\n\n // No text blocks — return raw content array\n return { content: rawContent, structuredContent: null, raw };\n }\n\n // Step 3: If content is string, try JSON.parse\n if (typeof rawContent === \"string\") {\n try {\n return { content: JSON.parse(rawContent), structuredContent: null, raw };\n } catch {\n return { content: rawContent, structuredContent: null, raw };\n }\n }\n\n // Fallback: return content as-is (could be null, object, etc.)\n return { content: rawContent ?? null, structuredContent: null, raw };\n}\n","/**\n * Maps short event names used in App.on() to full MCP method names.\n */\nconst EVENT_MAP: Record<string, string> = {\n \"tool-result\": \"ui/notifications/tool-result\",\n \"tool-input\": \"ui/notifications/tool-input\",\n \"tool-input-partial\": \"ui/notifications/tool-input-partial\",\n \"tool-cancelled\": \"ui/notifications/tool-cancelled\",\n \"theme-changed\": \"ui/notifications/host-context-changed\",\n teardown: \"ui/resource-teardown\",\n};\n\n/**\n * Resolve a short event name to a full MCP method name.\n * Returns the mapped method if found, otherwise passes through as-is.\n */\nexport function resolveEventMethod(name: string): string {\n return EVENT_MAP[name] ?? name;\n}\n","type SendFn = (method: string, params: Record<string, unknown>) => void;\n\ninterface Resizer {\n resize(width?: number, height?: number): void;\n measureAndSend(): void;\n destroy(): void;\n}\n\nexport function createResizer(send: SendFn, autoResize: boolean): Resizer {\n let destroyed = false;\n let observer: ResizeObserver | null = null;\n let rafId: number | null = null;\n\n function measureAndSend(): void {\n if (destroyed) return;\n const width = document.body.scrollWidth;\n const height = document.body.scrollHeight;\n send(\"ui/notifications/size-changed\", { width, height });\n }\n\n function resize(width?: number, height?: number): void {\n if (destroyed) return;\n if (width !== undefined && height !== undefined) {\n send(\"ui/notifications/size-changed\", { width, height });\n } else {\n measureAndSend();\n }\n }\n\n // Auto mode: attach ResizeObserver, debounced at 16ms via requestAnimationFrame\n if (autoResize && typeof ResizeObserver !== \"undefined\") {\n observer = new ResizeObserver(() => {\n if (destroyed) return;\n if (rafId !== null) cancelAnimationFrame(rafId);\n rafId = requestAnimationFrame(() => {\n rafId = null;\n measureAndSend();\n });\n });\n observer.observe(document.body);\n }\n\n function destroy(): void {\n if (destroyed) return;\n destroyed = true;\n if (rafId !== null) cancelAnimationFrame(rafId);\n observer?.disconnect();\n observer = null;\n }\n\n return { resize, measureAndSend, destroy };\n}\n","import type { ToolCallResult } from \"./types.js\";\n\n/**\n * Normalize a raw tool call response into a consistent `ToolCallResult`.\n *\n * Handles three shapes:\n * 1. MCP `CallToolResult` — has a `content` array with typed blocks.\n * 2. Raw JSON object (NimbleBrain bridge) — used as-is.\n * 3. Null / undefined — returns `{ data: null, isError: false }`.\n */\nexport function parseToolResult(raw: unknown): ToolCallResult {\n if (raw == null) {\n return { data: null, isError: false };\n }\n\n if (isCallToolResult(raw)) {\n return parseCallToolResult(raw);\n }\n\n // Raw JSON object — pass through.\n return { data: raw, isError: false };\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\ninterface McpTextBlock {\n type: \"text\";\n text: string;\n}\n\ninterface McpCallToolResult {\n content: unknown[];\n isError?: boolean;\n}\n\nfunction isCallToolResult(value: unknown): value is McpCallToolResult {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n return false;\n }\n return Array.isArray((value as Record<string, unknown>).content);\n}\n\nfunction isTextBlock(block: unknown): block is McpTextBlock {\n if (block === null || typeof block !== \"object\" || Array.isArray(block)) {\n return false;\n }\n const obj = block as Record<string, unknown>;\n return obj.type === \"text\" && typeof obj.text === \"string\";\n}\n\nfunction parseCallToolResult(result: McpCallToolResult): ToolCallResult {\n const isError = result.isError === true;\n const content = result.content;\n\n if (content.length === 0) {\n return { data: null, isError };\n }\n\n const firstText = content.find(isTextBlock);\n\n if (!firstText) {\n // No text blocks — return the full content array so callers can inspect it.\n return { data: content, isError };\n }\n\n // Try to parse JSON from the text block.\n try {\n return { data: JSON.parse(firstText.text), isError };\n } catch {\n // Invalid JSON — return the raw string.\n return { data: firstText.text, isError };\n }\n}\n","import type {\n JsonRpcMessage,\n JsonRpcNotification,\n JsonRpcRequest,\n JsonRpcResponse,\n} from \"./types.js\";\n\ntype PendingEntry = {\n resolve: (value: unknown) => void;\n reject: (reason: unknown) => void;\n};\n\ntype MessageHandler = (params: Record<string, unknown> | undefined) => void;\n\nexport class SynapseTransport {\n private counter = 0;\n private destroyed = false;\n private pending = new Map<string, PendingEntry>();\n private handlers = new Map<string, Set<MessageHandler>>();\n private listener: (event: MessageEvent) => void;\n\n constructor() {\n this.listener = (event: MessageEvent) => this.handleMessage(event);\n window.addEventListener(\"message\", this.listener);\n }\n\n send(method: string, params?: Record<string, unknown>): void {\n if (this.destroyed) return;\n\n const msg: JsonRpcNotification = {\n jsonrpc: \"2.0\",\n method,\n ...(params !== undefined && { params }),\n };\n window.parent.postMessage(msg, \"*\");\n }\n\n request(method: string, params?: Record<string, unknown>): Promise<unknown> {\n if (this.destroyed) {\n return Promise.reject(new Error(\"Transport destroyed\"));\n }\n\n const id = `syn-${++this.counter}`;\n const msg: JsonRpcRequest = {\n jsonrpc: \"2.0\",\n method,\n id,\n ...(params !== undefined && { params }),\n };\n\n return new Promise<unknown>((resolve, reject) => {\n this.pending.set(id, { resolve, reject });\n window.parent.postMessage(msg, \"*\");\n });\n }\n\n onMessage(method: string, callback: MessageHandler): () => void {\n if (!this.handlers.has(method)) {\n this.handlers.set(method, new Set());\n }\n this.handlers.get(method)?.add(callback);\n\n return () => {\n const set = this.handlers.get(method);\n if (set) {\n set.delete(callback);\n if (set.size === 0) {\n this.handlers.delete(method);\n }\n }\n };\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n\n window.removeEventListener(\"message\", this.listener);\n\n const error = new Error(\"Transport destroyed\");\n for (const entry of this.pending.values()) {\n entry.reject(error);\n }\n this.pending.clear();\n this.handlers.clear();\n }\n\n private handleMessage(event: MessageEvent): void {\n if (this.destroyed) return;\n\n const data = event.data as JsonRpcMessage;\n if (!data || data.jsonrpc !== \"2.0\") return;\n\n // Response to a pending request\n if (\"id\" in data && data.id && !(\"method\" in data)) {\n const response = data as JsonRpcResponse;\n const entry = this.pending.get(response.id);\n if (!entry) return;\n this.pending.delete(response.id);\n\n if (response.error) {\n const err = new Error(response.error.message);\n (err as any).code = response.error.code;\n (err as any).data = response.error.data;\n entry.reject(err);\n } else {\n entry.resolve(response.result);\n }\n return;\n }\n\n // Incoming notification\n if (\"method\" in data && !(\"id\" in data && data.id)) {\n const notification = data as JsonRpcNotification;\n const set = this.handlers.get(notification.method);\n if (set) {\n for (const handler of set) {\n handler(notification.params);\n }\n }\n }\n }\n}\n","import { parseToolResultParams } from \"./content-parser.js\";\nimport { resolveEventMethod } from \"./event-map.js\";\nimport { createResizer } from \"./resize.js\";\nimport { parseToolResult } from \"./result-parser.js\";\nimport { SynapseTransport } from \"./transport.js\";\nimport type { App, ConnectOptions, Dimensions, Theme, ToolCallResult } from \"./types.js\";\n\n/**\n * Connect to a MCP Apps host.\n *\n * Owns the full ext-apps handshake (steps 1-9 from the RFC), content parsing,\n * resize management, and event routing. Returns a ready-to-use `App` object.\n */\nexport async function connect(options: ConnectOptions): Promise<App> {\n const { name, version, autoResize = false } = options;\n\n const transport = new SynapseTransport();\n let destroyed = false;\n\n // --- Mutable state ---\n let currentTheme: Theme = { mode: \"light\", tokens: {} };\n let hostInfo: { name: string; version: string } = { name: \"unknown\", version: \"unknown\" };\n let toolInfo: { tool: Record<string, unknown> } | null = null;\n let containerDimensions: Dimensions | null = null;\n\n // --- Event handlers ---\n // Maps full MCP method names to sets of handlers.\n const handlers = new Map<string, Set<(params: unknown) => void>>();\n\n // --- Step 1: Set up message listener (handled by SynapseTransport constructor) ---\n\n // --- Step 2: Send initial size ---\n const resizer = createResizer((method, params) => transport.send(method, params), autoResize);\n resizer.measureAndSend();\n\n // --- Steps 3-4: Send ui/initialize and wait for response ---\n const result = (await transport.request(\"ui/initialize\", {\n protocolVersion: \"2026-01-26\",\n clientInfo: { name, version },\n capabilities: {},\n })) as Record<string, unknown> | null;\n\n // --- Step 5: Extract theme, hostInfo, toolInfo, containerDimensions ---\n const resp = result ?? {};\n const serverInfo = safeObj(resp.serverInfo);\n hostInfo = {\n name: typeof serverInfo?.name === \"string\" ? serverInfo.name : \"unknown\",\n version: typeof serverInfo?.version === \"string\" ? serverInfo.version : \"unknown\",\n };\n\n const hostContext = safeObj(resp.hostContext);\n if (hostContext) {\n const themeRaw = safeObj(hostContext.theme);\n if (themeRaw) {\n currentTheme = {\n mode: themeRaw.mode === \"dark\" ? \"dark\" : \"light\",\n tokens:\n themeRaw.tokens && typeof themeRaw.tokens === \"object\" && !Array.isArray(themeRaw.tokens)\n ? (themeRaw.tokens as Record<string, string>)\n : {},\n };\n }\n if (hostContext.toolInfo && typeof hostContext.toolInfo === \"object\") {\n const ti = hostContext.toolInfo as Record<string, unknown>;\n toolInfo = { tool: (ti.tool as Record<string, unknown>) ?? ti };\n }\n if (hostContext.containerDimensions && typeof hostContext.containerDimensions === \"object\") {\n containerDimensions = hostContext.containerDimensions as Dimensions;\n }\n\n // Inject host CSS variables into the DOM\n const styles = safeObj(hostContext.styles);\n injectCssVariables(styles?.variables as Record<string, string> | undefined);\n }\n\n // --- Step 6: Send initialized ---\n transport.send(\"ui/notifications/initialized\", {});\n\n // --- Step 7: autoResize already handled by createResizer ---\n\n // --- Step 9: Route ALL incoming notifications to registered handlers ---\n // We register a wildcard-style listener on the transport for every known\n // method. The transport routes by exact method name, so we subscribe to\n // each unique method that has handlers. We use a different approach:\n // intercept at the transport level by subscribing once per method as\n // handlers are added.\n\n // Special handling for theme-changed: update internal state\n const themeMethod = resolveEventMethod(\"theme-changed\");\n transport.onMessage(themeMethod, (params) => {\n if (destroyed || !params) return;\n const mode = params.theme === \"dark\" ? \"dark\" : \"light\";\n const tokens =\n params.tokens && typeof params.tokens === \"object\" && !Array.isArray(params.tokens)\n ? (params.tokens as Record<string, string>)\n : currentTheme.tokens;\n currentTheme = { mode, tokens };\n injectCssVariables(tokens);\n // Fire theme-changed handlers\n const set = handlers.get(themeMethod);\n if (set) {\n for (const handler of set) handler(currentTheme);\n }\n });\n\n // Helper to ensure transport subscription exists for a method\n const subscribedMethods = new Set<string>([themeMethod]);\n\n function ensureTransportSub(method: string): void {\n if (subscribedMethods.has(method)) return;\n subscribedMethods.add(method);\n\n const toolResultMethod = resolveEventMethod(\"tool-result\");\n const isToolResult = method === toolResultMethod;\n\n transport.onMessage(method, (params) => {\n if (destroyed) return;\n const set = handlers.get(method);\n if (!set) return;\n for (const handler of set) {\n if (isToolResult) {\n handler(parseToolResultParams(params));\n } else {\n handler(params);\n }\n }\n });\n }\n\n // --- Step 8: Build and return the App object ---\n const app: App = {\n get theme() {\n return { ...currentTheme };\n },\n get hostInfo() {\n return { ...hostInfo };\n },\n get toolInfo() {\n return toolInfo;\n },\n get containerDimensions() {\n return containerDimensions;\n },\n\n on(event: string, handler: (params: any) => void): () => void {\n const method = resolveEventMethod(event);\n\n if (!handlers.has(method)) {\n handlers.set(method, new Set());\n }\n handlers.get(method)?.add(handler);\n ensureTransportSub(method);\n\n return () => {\n const set = handlers.get(method);\n if (set) {\n set.delete(handler);\n if (set.size === 0) handlers.delete(method);\n }\n };\n },\n\n resize(width?: number, height?: number): void {\n resizer.resize(width, height);\n },\n\n openLink(url: string): void {\n if (destroyed) return;\n transport.send(\"ui/open-link\", { url });\n },\n\n updateModelContext(state: Record<string, unknown>, summary?: string): void {\n if (destroyed) return;\n transport.send(\"ui/update-model-context\", {\n structuredContent: state,\n ...(summary !== undefined && {\n content: [{ type: \"text\", text: summary }],\n }),\n });\n },\n\n async callTool(toolName: string, args?: Record<string, unknown>): Promise<ToolCallResult> {\n const raw = await transport.request(\"tools/call\", {\n name: toolName,\n arguments: args ?? {},\n });\n return parseToolResult(raw);\n },\n\n sendMessage(text: string, context?: { action?: string; entity?: string }): void {\n if (destroyed) return;\n const textBlock: Record<string, unknown> = { type: \"text\", text };\n if (context) {\n textBlock._meta = { context };\n }\n transport.send(\"ui/message\", {\n role: \"user\",\n content: [textBlock],\n });\n },\n\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n resizer.destroy();\n handlers.clear();\n transport.destroy();\n },\n };\n\n return app;\n}\n\n// --- Helpers ---\n\nfunction safeObj(value: unknown): Record<string, unknown> | undefined {\n if (value !== null && typeof value === \"object\" && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n return undefined;\n}\n\n/** Inject CSS custom properties onto :root so widgets inherit host theming. */\nfunction injectCssVariables(vars: Record<string, string> | undefined | null): void {\n if (!vars || typeof vars !== \"object\") return;\n for (const [k, v] of Object.entries(vars)) {\n if (typeof k === \"string\" && typeof v === \"string\") {\n document.documentElement.style.setProperty(k, v);\n }\n }\n}\n","import type { HostInfo, SynapseTheme } from \"./types\";\n\nconst DEFAULT_THEME: SynapseTheme = {\n mode: \"light\",\n primaryColor: \"#6366f1\",\n tokens: {},\n};\n\n/**\n * Detect the host environment from the ext-apps `ui/initialize` response.\n *\n * Handles missing or malformed fields gracefully — never throws.\n */\nexport function detectHost(initResponse: unknown): HostInfo {\n const resp = initResponse as Record<string, unknown> | null | undefined;\n\n const serverInfo = safeObj(resp?.serverInfo);\n const serverName = typeof serverInfo?.name === \"string\" ? serverInfo.name : \"unknown\";\n\n const protocolVersion =\n typeof resp?.protocolVersion === \"string\" ? resp.protocolVersion : \"unknown\";\n\n const hostContext = safeObj(resp?.hostContext);\n const theme = extractTheme(hostContext?.theme);\n\n return {\n isNimbleBrain: serverName === \"nimblebrain\",\n serverName,\n protocolVersion,\n theme,\n };\n}\n\nfunction extractTheme(raw: unknown): SynapseTheme {\n const obj = safeObj(raw);\n if (!obj) return { ...DEFAULT_THEME };\n\n const mode = obj.mode === \"light\" || obj.mode === \"dark\" ? obj.mode : DEFAULT_THEME.mode;\n\n const primaryColor =\n typeof obj.primaryColor === \"string\" ? obj.primaryColor : DEFAULT_THEME.primaryColor;\n\n const tokens =\n obj.tokens !== null && typeof obj.tokens === \"object\" && !Array.isArray(obj.tokens)\n ? (obj.tokens as Record<string, string>)\n : {};\n\n return { mode, primaryColor, tokens };\n}\n\nfunction safeObj(value: unknown): Record<string, unknown> | undefined {\n if (value !== null && typeof value === \"object\" && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n return undefined;\n}\n","import type { SynapseTransport } from \"./transport.js\";\nimport type { KeyForwardConfig } from \"./types.js\";\n\n/**\n * Forward keyboard shortcuts from the iframe document to the host.\n *\n * By default, forwards all Ctrl/Cmd+key combos and Escape.\n * Apps can customize via `forwardKeys` config.\n */\nexport class KeyboardForwarder {\n private listener: (event: KeyboardEvent) => void;\n private destroyed = false;\n\n constructor(transport: SynapseTransport, customKeys?: KeyForwardConfig[]) {\n const config = customKeys ?? null; // null = default behavior\n\n this.listener = (event: KeyboardEvent) => {\n if (this.destroyed) return;\n if (this.shouldForward(event, config)) {\n event.preventDefault();\n transport.send(\"synapse/keydown\", {\n key: event.key,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n altKey: event.altKey,\n });\n }\n };\n\n document.addEventListener(\"keydown\", this.listener);\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n document.removeEventListener(\"keydown\", this.listener);\n }\n\n private shouldForward(event: KeyboardEvent, config: KeyForwardConfig[] | null): boolean {\n // Empty array = forwarding disabled\n if (config && config.length === 0) return false;\n\n // Custom config: match exactly\n if (config) {\n return config.some(\n (k) =>\n event.key.toLowerCase() === k.key.toLowerCase() &&\n (k.ctrl === undefined || event.ctrlKey === k.ctrl) &&\n (k.meta === undefined || event.metaKey === k.meta) &&\n (k.shift === undefined || event.shiftKey === k.shift) &&\n (k.alt === undefined || event.altKey === k.alt),\n );\n }\n\n // Default: forward all Ctrl/Cmd combos + Escape,\n // EXCEPT clipboard shortcuts (c, v, x, a) which the browser must handle natively.\n if (event.key === \"Escape\") return true;\n if (event.ctrlKey || event.metaKey) {\n const key = event.key.toLowerCase();\n if (key === \"c\" || key === \"v\" || key === \"x\" || key === \"a\") return false;\n return true;\n }\n return false;\n }\n}\n","import { detectHost } from \"./detection.js\";\nimport { KeyboardForwarder } from \"./keyboard.js\";\nimport { parseToolResult } from \"./result-parser.js\";\nimport { SynapseTransport } from \"./transport.js\";\nimport type {\n AgentAction,\n DataChangedEvent,\n FileResult,\n HostInfo,\n RequestFileOptions,\n Synapse,\n SynapseOptions,\n SynapseTheme,\n ToolCallResult,\n} from \"./types.js\";\n\n/**\n * Create a Synapse instance.\n *\n * Wraps the ext-apps protocol handshake via `SynapseTransport` and provides\n * a typed, framework-agnostic API for calling tools, reacting to data changes,\n * dispatching actions, and pushing LLM-visible state.\n *\n * In non-NimbleBrain hosts, NB-specific methods degrade to no-ops.\n */\nexport function createSynapse(options: SynapseOptions): Synapse {\n const { name, version, internal = false, forwardKeys } = options;\n\n const transport = new SynapseTransport();\n let hostInfo: HostInfo | null = null;\n let currentTheme: SynapseTheme = {\n mode: \"light\",\n primaryColor: \"#6366f1\",\n tokens: {},\n };\n let destroyed = false;\n\n // --- Debounce for setVisibleState ---\n let stateTimer: ReturnType<typeof setTimeout> | null = null;\n\n // --- Keyboard forwarding ---\n let keyboard: KeyboardForwarder | null = null;\n\n // --- ext-apps handshake ---\n // We send ui/initialize as a JSON-RPC request and wait for the response.\n const ready = transport\n .request(\"ui/initialize\", {\n protocolVersion: \"2026-01-26\",\n clientInfo: { name, version },\n capabilities: {},\n })\n .then((result) => {\n hostInfo = detectHost(result);\n currentTheme = hostInfo.theme;\n\n // Send initialized notification per ext-apps spec\n transport.send(\"ui/notifications/initialized\", {});\n\n // Set up keyboard forwarding after we know the host\n keyboard = new KeyboardForwarder(transport, forwardKeys);\n });\n\n // Listen for theme changes from the host\n const unsubTheme = transport.onMessage(\"ui/notifications/host-context-changed\", (params) => {\n if (!params) return;\n const mode = params.theme === \"dark\" ? \"dark\" : \"light\";\n const tokens =\n params.tokens && typeof params.tokens === \"object\"\n ? (params.tokens as Record<string, string>)\n : currentTheme.tokens;\n currentTheme = { mode, primaryColor: currentTheme.primaryColor, tokens };\n for (const cb of themeCallbacks) cb(currentTheme);\n });\n\n // Also listen for NB-specific synapse/theme-changed message\n const unsubNbTheme = transport.onMessage(\"synapse/theme-changed\", (params) => {\n if (!params) return;\n const mode =\n params.mode === \"dark\" || params.mode === \"light\" ? params.mode : currentTheme.mode;\n const tokens =\n params.tokens && typeof params.tokens === \"object\"\n ? (params.tokens as Record<string, string>)\n : currentTheme.tokens;\n currentTheme = { mode, primaryColor: currentTheme.primaryColor, tokens };\n for (const cb of themeCallbacks) cb(currentTheme);\n });\n\n const themeCallbacks = new Set<(theme: SynapseTheme) => void>();\n const dataCallbacks = new Set<(event: DataChangedEvent) => void>();\n const actionCallbacks = new Set<(action: AgentAction) => void>();\n\n // Listen for data change events\n const unsubData = transport.onMessage(\"synapse/data-changed\", (params) => {\n if (!params) return;\n const event: DataChangedEvent = {\n source: \"agent\",\n server: (params.server as string) ?? \"\",\n tool: (params.tool as string) ?? \"\",\n };\n for (const cb of dataCallbacks) cb(event);\n });\n\n // Listen for agent actions (typed, declarative commands from the server)\n const unsubAction = transport.onMessage(\"synapse/action\", (params) => {\n if (!params || typeof params.type !== \"string\") return;\n const action: AgentAction = {\n type: params.type as string,\n payload: (params.payload as Record<string, unknown>) ?? {},\n requiresConfirmation: params.requiresConfirmation === true,\n label: typeof params.label === \"string\" ? params.label : undefined,\n };\n for (const cb of actionCallbacks) cb(action);\n });\n\n const isNB = () => hostInfo?.isNimbleBrain === true;\n\n const synapse: Synapse = {\n get ready() {\n return ready;\n },\n\n get isNimbleBrainHost() {\n return isNB();\n },\n\n get destroyed() {\n return destroyed;\n },\n\n async callTool<TInput = Record<string, unknown>, TOutput = unknown>(\n toolName: string,\n args?: TInput,\n ): Promise<ToolCallResult<TOutput>> {\n const params: Record<string, unknown> = {\n name: toolName,\n arguments: args ?? {},\n };\n // Internal apps can cross-call\n if (internal) {\n params.server = name;\n }\n const raw = await transport.request(\"tools/call\", params);\n return parseToolResult(raw) as ToolCallResult<TOutput>;\n },\n\n onDataChanged(callback: (event: DataChangedEvent) => void): () => void {\n dataCallbacks.add(callback);\n return () => {\n dataCallbacks.delete(callback);\n };\n },\n\n onAction(callback: (action: AgentAction) => void): () => void {\n actionCallbacks.add(callback);\n return () => {\n actionCallbacks.delete(callback);\n };\n },\n\n getTheme(): SynapseTheme {\n return { ...currentTheme };\n },\n\n onThemeChanged(callback: (theme: SynapseTheme) => void): () => void {\n themeCallbacks.add(callback);\n return () => {\n themeCallbacks.delete(callback);\n };\n },\n\n action(action: string, params?: Record<string, unknown>): void {\n if (!isNB()) return;\n transport.send(\"synapse/action\", { action, ...params });\n },\n\n chat(message: string, context?: { action?: string; entity?: string }): void {\n const textBlock: Record<string, unknown> = { type: \"text\", text: message };\n if (isNB() && context) {\n textBlock._meta = { context };\n }\n transport.send(\"ui/message\", {\n role: \"user\",\n content: [textBlock],\n });\n },\n\n setVisibleState(state: Record<string, unknown>, summary?: string): void {\n // Debounce: 250ms\n if (stateTimer) clearTimeout(stateTimer);\n stateTimer = setTimeout(() => {\n transport.send(\"ui/update-model-context\", {\n structuredContent: state,\n ...(summary !== undefined && {\n content: [{ type: \"text\", text: summary }],\n }),\n });\n stateTimer = null;\n }, 250);\n },\n\n saveFile(filename: string, content: string | Blob, mimeType?: string): void {\n // Always send — the bridge handles this for any host that supports it.\n // Removing the isNB() guard fixes silent failures when host detection\n // hasn't completed yet or when the handshake response is delayed.\n const data = typeof content === \"string\" ? content : \"[Blob content not serializable]\";\n transport.send(\"synapse/save-file\", {\n data,\n filename,\n mimeType: mimeType ?? \"application/octet-stream\",\n });\n },\n\n openLink(url: string): void {\n transport.send(\"ui/open-link\", { url });\n if (!isNB()) {\n window.open(url, \"_blank\", \"noopener\");\n }\n },\n\n async pickFile(options?: RequestFileOptions): Promise<FileResult | null> {\n if (!isNB()) {\n throw new Error(\"pickFile is not supported in this host\");\n }\n const result = await transport.request(\"synapse/pick-file\", {\n accept: options?.accept,\n maxSize: options?.maxSize ?? 26_214_400,\n multiple: false,\n });\n return (result as FileResult) ?? null;\n },\n\n async pickFiles(options?: RequestFileOptions): Promise<FileResult[]> {\n if (!isNB()) {\n throw new Error(\"pickFiles is not supported in this host\");\n }\n const result = await transport.request(\"synapse/pick-file\", {\n accept: options?.accept,\n maxSize: options?.maxSize ?? 26_214_400,\n multiple: true,\n });\n if (!result) return [];\n return Array.isArray(result) ? (result as FileResult[]) : [result as FileResult];\n },\n\n _onMessage(\n method: string,\n callback: (params: Record<string, unknown> | undefined) => void,\n ): () => void {\n return transport.onMessage(method, callback);\n },\n\n _request(method: string, params?: Record<string, unknown>): Promise<unknown> {\n return transport.request(method, params);\n },\n\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n\n if (stateTimer) clearTimeout(stateTimer);\n keyboard?.destroy();\n unsubTheme();\n unsubNbTheme();\n unsubData();\n unsubAction();\n themeCallbacks.clear();\n dataCallbacks.clear();\n actionCallbacks.clear();\n transport.destroy();\n },\n };\n\n return synapse;\n}\n"]}
|