@nimblebrain/synapse 0.15.0 → 0.17.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 +61 -111
- package/dist/{chunk-SN7YXLAV.cjs → chunk-EHLQWCYV.cjs} +6 -6
- package/dist/{chunk-SN7YXLAV.cjs.map → chunk-EHLQWCYV.cjs.map} +1 -1
- package/dist/{chunk-ZMNYUGSF.cjs → chunk-FDMRJZKT.cjs} +576 -662
- package/dist/chunk-FDMRJZKT.cjs.map +1 -0
- package/dist/{chunk-E7OOOYVR.js → chunk-SRQNQ26I.js} +3 -3
- package/dist/{chunk-E7OOOYVR.js.map → chunk-SRQNQ26I.js.map} +1 -1
- package/dist/{chunk-RYWW6EHB.cjs → chunk-TXJMGQYF.cjs} +3 -5
- package/dist/chunk-TXJMGQYF.cjs.map +1 -0
- package/dist/{chunk-J5ICAHK2.js → chunk-UPDBDXQB.js} +4 -5
- package/dist/chunk-UPDBDXQB.js.map +1 -0
- package/dist/{chunk-GNTQJSQX.js → chunk-VYR6V47N.js} +573 -663
- package/dist/chunk-VYR6V47N.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 +28 -28
- package/dist/{detect-C_qmYsh9.d.cts → detect-BHYg26_d.d.cts} +1 -1
- package/dist/{detect-Dfd0upoz.d.ts → detect-Bf8Q_0dK.d.ts} +1 -1
- package/dist/host/index.cjs +14 -14
- package/dist/host/index.d.cts +3 -3
- package/dist/host/index.d.ts +3 -3
- package/dist/host/index.js +2 -2
- package/dist/index.cjs +28 -87
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -26
- package/dist/index.d.ts +58 -26
- package/dist/index.js +3 -81
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +81 -140
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +66 -82
- package/dist/react/index.d.ts +66 -82
- package/dist/react/index.js +82 -136
- package/dist/react/index.js.map +1 -1
- package/dist/{server-ERRDGEZ7.js → server-5N76YCWC.js} +3 -3
- package/dist/{server-ERRDGEZ7.js.map → server-5N76YCWC.js.map} +1 -1
- package/dist/{server-P54IYX2G.cjs → server-QIYIJHD5.cjs} +3 -3
- package/dist/{server-P54IYX2G.cjs.map → server-QIYIJHD5.cjs.map} +1 -1
- package/dist/synapse-runtime.iife.global.js +28 -28
- package/dist/synapse-ui.iife.global.js +2 -2
- package/dist/{types-BSZasM8q.d.cts → types-uEO4VFJ2.d.cts} +87 -166
- package/dist/{types-BSZasM8q.d.ts → types-uEO4VFJ2.d.ts} +87 -166
- package/dist/ui/index.cjs +403 -91
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +115 -3
- package/dist/ui/index.d.ts +115 -3
- package/dist/ui/index.js +401 -93
- package/dist/ui/index.js.map +1 -1
- package/dist/vite/index.cjs +1 -1
- package/dist/vite/index.cjs.map +1 -1
- package/dist/vite/index.js +1 -1
- package/dist/vite/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-GNTQJSQX.js.map +0 -1
- package/dist/chunk-J5ICAHK2.js.map +0 -1
- package/dist/chunk-RYWW6EHB.cjs.map +0 -1
- package/dist/chunk-ZMNYUGSF.cjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
(function(){'use strict';var be=new Set(["auto","block","swap","fallback","optional"]),ke={"--color-background-primary":"#ffffff","--color-background-secondary":"#fafafa","--color-background-tertiary":"#f3f4f6","--color-text-primary":"#111827","--color-text-secondary":"#6b7280","--color-text-tertiary":"#9ca3af","--color-text-accent":"#2563eb","--nb-color-accent-foreground":"#ffffff","--color-border-primary":"#e5e7eb","--color-border-secondary":"#d1d5db","--color-ring-primary":"#2563eb","--nb-color-danger":"#dc2626","--nb-color-success":"#059669","--nb-color-warning":"#f59e0b","--nb-color-processing":"#7c3aed","--nb-color-processing-light":"#f3eeff","--nb-color-info-light":"#eef4ff"},Pe={"--color-background-primary":"#18181b","--color-background-secondary":"#27272a","--color-background-tertiary":"#2f2f34","--color-text-primary":"#fafafa","--color-text-secondary":"#a1a1aa","--color-text-tertiary":"#71717a","--color-text-accent":"#818cf8","--nb-color-accent-foreground":"#ffffff","--color-border-primary":"#3f3f46","--color-border-secondary":"#52525b","--color-ring-primary":"#818cf8","--nb-color-danger":"#f87171","--nb-color-success":"#34d399","--nb-color-warning":"#fbbf24","--nb-color-processing":"#a78bfa","--nb-color-processing-light":"#2a2440","--nb-color-info-light":"#1e2a44"},Ee={light:ke,dark:Pe},Ie="synapse-defaults",G="synapse-theme-defaults",W=new Set;function ve(){return typeof document<"u"&&typeof document.getElementById=="function"&&typeof document.createElement=="function"&&typeof document.head?.prepend=="function"}function
|
|
1
|
+
(function(){'use strict';var be=new Set(["auto","block","swap","fallback","optional"]),ke={"--color-background-primary":"#ffffff","--color-background-secondary":"#fafafa","--color-background-tertiary":"#f3f4f6","--color-text-primary":"#111827","--color-text-secondary":"#6b7280","--color-text-tertiary":"#9ca3af","--color-text-accent":"#2563eb","--nb-color-accent-foreground":"#ffffff","--color-border-primary":"#e5e7eb","--color-border-secondary":"#d1d5db","--color-ring-primary":"#2563eb","--nb-color-danger":"#dc2626","--nb-color-success":"#059669","--nb-color-warning":"#f59e0b","--nb-color-processing":"#7c3aed","--nb-color-processing-light":"#f3eeff","--nb-color-info-light":"#eef4ff"},Pe={"--color-background-primary":"#18181b","--color-background-secondary":"#27272a","--color-background-tertiary":"#2f2f34","--color-text-primary":"#fafafa","--color-text-secondary":"#a1a1aa","--color-text-tertiary":"#71717a","--color-text-accent":"#818cf8","--nb-color-accent-foreground":"#ffffff","--color-border-primary":"#3f3f46","--color-border-secondary":"#52525b","--color-ring-primary":"#818cf8","--nb-color-danger":"#f87171","--nb-color-success":"#34d399","--nb-color-warning":"#fbbf24","--nb-color-processing":"#a78bfa","--nb-color-processing-light":"#2a2440","--nb-color-info-light":"#1e2a44"},Ee={light:ke,dark:Pe},Ie="synapse-defaults",G="synapse-theme-defaults",W=new Set;function ve(){return typeof document<"u"&&typeof document.getElementById=="function"&&typeof document.createElement=="function"&&typeof document.head?.prepend=="function"}function we(e){if(!ve())return;let o=Object.entries(Ee[e]).map(([a,p])=>` ${a}: ${p};`).join(`
|
|
2
2
|
`),n=`@layer ${Ie} {
|
|
3
3
|
:root {
|
|
4
4
|
${o}
|
|
5
5
|
}
|
|
6
|
-
}`,s=document.getElementById(G);if(s){s.textContent!==n&&(s.textContent=n);return}let i=document.createElement("style");i.id=G,i.textContent=n,document.head.prepend(i);}function
|
|
6
|
+
}`,s=document.getElementById(G);if(s){s.textContent!==n&&(s.textContent=n);return}let i=document.createElement("style");i.id=G,i.textContent=n,document.head.prepend(i);}function Ae(e,o){if(typeof document>"u")return;we(e);let n={};if(o&&typeof o=="object")for(let[i,a]of Object.entries(o))typeof i=="string"&&typeof a=="string"&&(n[i]=a);let s=document.documentElement.style;if(typeof s.removeProperty=="function")for(let i of W)i in n||s.removeProperty(i);for(let[i,a]of Object.entries(n))s.setProperty(i,a);W=new Set(Object.keys(n));}var F=new Set,Y="";function C(e){return Array.isArray(e)?JSON.stringify(e.map(o=>[o.family,o.src,o.weight,o.style,o.display])):""}function M(e){if(!Array.isArray(e))return;let o=e.filter(Oe);if(!(e.length>0&&o.length===0))return o}function Ce(e){let o=M(e);if(o===void 0||typeof document>"u"||!document.fonts||typeof FontFace>"u")return;let n=C(o);if(n!==Y){Y=n;for(let s of F)try{document.fonts.delete(s);}catch{}F.clear();for(let s of o)try{let i=new FontFace(s.family,s.src,{weight:s.weight,style:s.style,display:s.display&&be.has(s.display)?s.display:"swap"});document.fonts.add(i),F.add(i);}catch{}}}function Oe(e){if(!e||typeof e!="object")return false;let o=e;return typeof o.family=="string"&&typeof o.src=="string"}function V(e,o,n){Ae(e,o),Ce(n);}function R(e){typeof document<"u"&&document.documentElement.setAttribute("data-theme",e.mode),V(e.mode,e.tokens,e.fontFaces);}function O(e){try{if(e?.matchMedia?.("(prefers-color-scheme: dark)").matches)return "dark"}catch{}return "light"}function h(e,o){return e==="light"||e==="dark"?e:o}var T=class extends Error{constructor(o,n){super(`"${o}" is not supported by the "${n}" host`),this.name="HostUnsupportedError";}},_="synapse-ui-data",Z="ui-lifecycle-iframe-ready",$="ui-lifecycle-iframe-render-data",B="ui-size-change",q="link",Q="prompt",U="openai:set_globals",X="2026-01-26",J="ui/initialize",ee="ui/notifications/initialized",te="ui/notifications/tool-result",ne="ui/notifications/host-context-changed",oe="ui/notifications/size-changed",re="ui/open-link",se="ui/message",ie="ui/resource-teardown",ae="tools/call";function ce(e,o){let n=()=>e.openai,s=n()?.toolOutput??null,i={mode:h(n()?.theme,"light"),tokens:{}},a=new Set,p=new Set,f=false,m=c=>{if(f)return;let l=c.detail?.globals;if(l){if("toolOutput"in l&&l.toolOutput!=null){s=l.toolOutput;for(let u of a)u(s);}if("theme"in l&&l.theme!=null){let u=h(l.theme,i.mode);if(u!==i.mode){i={mode:u,tokens:{}};for(let b of p)b(i);}}}};return {host:"chatgpt",getData:()=>s,onData(c){return a.add(c),()=>a.delete(c)},getTheme:()=>i,onTheme(c){return p.add(c),()=>p.delete(c)},async callTool(c,l){let u=n()?.callTool;if(!u)throw new T("callTool","chatgpt");return await u(c,l??{})},sendPrompt(c){let l=n();(l?.sendFollowUpMessage??l?.sendFollowupMessage)?.({prompt:c});},openLink(c){let l=n()?.openExternal;l?l({href:c}):e.open(c,"_blank","noopener,noreferrer");},resize(){},capabilities(){let c=n();return {pull:typeof c?.callTool=="function",sendPrompt:typeof c?.sendFollowUpMessage=="function"||typeof c?.sendFollowupMessage=="function",openLink:true}},start(){e.addEventListener(U,m,{passive:true}),s=n()?.toolOutput??s;},destroy(){f||(f=true,e.removeEventListener(U,m),a.clear(),p.clear());}}}function x(e,o){if(!e)return null;let s=e.getElementById(o)?.textContent;if(!s)return null;try{return JSON.parse(s)??null}catch{return null}}function L(e){if(e==null||typeof e!="object")return null;let o=e,n=o.renderData,s=n!=null&&typeof n=="object"?n:o;return s.toolOutput!=null?s.toolOutput:s.structuredContent!=null?s.structuredContent:s}function le(e,o){let n=o.dataElementId??_,s=null,i={mode:O(e),tokens:{}},a=new Set,p=false,f=null,m=c=>{if(p)return;let l=h(c.matches?"dark":"light",i.mode);if(l!==i.mode){i={mode:l,tokens:{}};for(let u of a)u(i);}};return {host:"generic",getData:()=>s,onData(){return ()=>{}},getTheme:()=>i,onTheme(c){return a.add(c),()=>a.delete(c)},async callTool(c){throw new T("callTool","generic")},sendPrompt(){},openLink(c){e.open(c,"_blank","noopener,noreferrer");},resize(){},capabilities(){return {pull:false,sendPrompt:false,openLink:true}},start(){s=x(e.document,n);try{f=e.matchMedia?.("(prefers-color-scheme: dark)")??null,f?.addEventListener?.("change",m);}catch{f=null;}},destroy(){p||(p=true,f?.removeEventListener?.("change",m),f=null,a.clear());}}}var _e="synapse/fontFaces";function xe(e){return M(e?.[_e])}function de(e,o){return xe(o)??e}var De=3e4;function pe(e,o){let n=o.dataElementId??_,s=o.autoResize!==false,i=null,a={mode:O(e),tokens:{}},p=new Set,f=new Set,m=false,c=false,l=1,u=new Map,b=-1,v=null,k=null,H=()=>e.parent??e;function P(t){H().postMessage(t,"*");}function D(t){c||P(t);}function N(t,r){P({jsonrpc:"2.0",method:t,params:r??{}});}function w(t,r){let d=l++;return new Promise((y,g)=>{let I=setTimeout(()=>{u.delete(d),g(new Error(`"${t}" timed out`));},De);u.set(d,{resolve:y,reject:g,timer:I}),P({jsonrpc:"2.0",id:d,method:t,params:r??{}});})}function z(t){if(t!=null){i=t;for(let r of p)r(t);}}function S(t){if(!t||typeof t!="object")return;let{mode:r,tokens:d,fontFaces:y}=a,g=false;if(t.theme!=null){let A=h(t.theme,r);A!==r&&(r=A,g=true);}let I=t.styles;I?.variables&&typeof I.variables=="object"&&(d={...d,...I.variables},g=true);let K=de(y,t);if(C(K)!==C(y)&&(y=K,g=true),g){a={mode:r,tokens:d,...y?{fontFaces:y}:{}};for(let A of f)A(a);}}function E(t){if(m)return;let r=typeof t=="number"?t:Math.ceil(e.document.body.scrollHeight);r!==b&&(b=r,N(oe,{height:r}),D({type:B,payload:{height:r}}));}function me(t){let r=Number(t.id),d=u.get(r);if(d)if(u.delete(r),clearTimeout(d.timer),t.error!=null){let y=t.error;d.reject(new Error(y.message??"request failed"));}else d.resolve(t.result);}function ye(t,r){if(t===te){let d=r.structuredContent;z(d??L(r));}else t===ne&&S(r);}function ge(t){t.method===ie&&P({jsonrpc:"2.0",id:t.id,result:{}});}function he(t){if(t.type===$||t.type==="renderData"){let{theme:r,...d}=t.payload??{};r!=null&&S({theme:r}),Object.keys(d).length>0&&z(L(d));}}let j=t=>{if(m||t.source&&t.source!==H())return;let r=t.data;if(!(!r||typeof r!="object")){if(r.jsonrpc!=="2.0"){he(r);return}r.id!=null&&("result"in r||"error"in r)?me(r):typeof r.method=="string"&&(r.id!=null?ge(r):ye(r.method,r.params??{}));}};function Te(){k=()=>E(),e.addEventListener("resize",k),typeof e.ResizeObserver<"u"&&(v=new e.ResizeObserver(()=>E()),v.observe(e.document.body));}return {host:"claude",getData:()=>i,onData(t){return p.add(t),()=>p.delete(t)},getTheme:()=>a,onTheme(t){return f.add(t),()=>f.delete(t)},async callTool(t,r){return await w(ae,{name:t,arguments:r??{}})},sendPrompt(t){w(se,{role:"user",content:[{type:"text",text:t}]}).catch(()=>{}),D({type:Q,payload:{prompt:t}});},openLink(t){w(re,{url:t}).catch(()=>{}),D({type:q,payload:{url:t}});},resize(t){E(t);},capabilities(){return {pull:true,sendPrompt:true,openLink:true}},start(){e.addEventListener("message",j),i=x(e.document,n),s&&Te(),P({type:Z}),w(J,{appInfo:{name:o.name??"synapse-ui",version:o.version??"0.0.0"},appCapabilities:{availableDisplayModes:["inline"]},protocolVersion:X}).then(t=>{m||(c=true,S(t?.hostContext),N(ee,{}),b=-1,E());}).catch(()=>{}),E();},destroy(){if(!m){m=true,e.removeEventListener("message",j),k&&e.removeEventListener("resize",k),k=null,v?.disconnect(),v=null;for(let t of u.values())clearTimeout(t.timer),t.reject(new Error("adapter destroyed"));u.clear(),p.clear(),f.clear();}}}}function Se(e){if(e.openai!=null)return "chatgpt";try{if(e.parent!=null&&e.parent!==e)return "claude"}catch{return "claude"}return "generic"}function Fe(e,o,n){switch(e){case "chatgpt":return ce(o);case "claude":case "nimblebrain":return pe(o,n);default:return le(o,n)}}function ue(e,o){let n=o.host??Se(e);return Fe(n,e,o)}function fe(e={}){let o=e.window??globalThis,n=ue(o,e);R(n.getTheme());let s=n.onTheme(R);n.start();let i=false;return {data:()=>n.getData(),onData:a=>n.onData(a),theme:()=>n.getTheme(),onTheme:a=>n.onTheme(a),callTool:(a,p)=>n.callTool(a,p),sendPrompt:a=>n.sendPrompt(a),openLink:a=>n.openLink(a),resize:a=>n.resize(a),capabilities:()=>n.capabilities(),host:()=>n.host,destroy(){i||(i=true,s(),n.destroy());}}}globalThis.SynapseUI={connect:fe};})();
|
|
@@ -100,19 +100,6 @@ interface TaskHandle<TOutput = unknown> {
|
|
|
100
100
|
onStatus(cb: (task: Task) => void): () => void;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
interface SynapseOptions {
|
|
104
|
-
/** App name — must match the bundle name registered with the host */
|
|
105
|
-
name: string;
|
|
106
|
-
/** Semver version string */
|
|
107
|
-
version: string;
|
|
108
|
-
/**
|
|
109
|
-
* Mark as internal NimbleBrain app. Enables cross-server tool calls.
|
|
110
|
-
* External apps MUST NOT set this.
|
|
111
|
-
*/
|
|
112
|
-
internal?: boolean;
|
|
113
|
-
/** Key combos to forward from iframe to host. Default: all Ctrl/Cmd combos + Escape. */
|
|
114
|
-
forwardKeys?: KeyForwardConfig[];
|
|
115
|
-
}
|
|
116
103
|
/**
|
|
117
104
|
* One `@font-face` a host asks the app to load.
|
|
118
105
|
*
|
|
@@ -143,9 +130,8 @@ interface FontFaceDescriptor {
|
|
|
143
130
|
}
|
|
144
131
|
/** The CSS `font-display` values. Closed set — anything else is ignored. */
|
|
145
132
|
type FontDisplayValue = "auto" | "block" | "swap" | "fallback" | "optional";
|
|
146
|
-
interface
|
|
133
|
+
interface Theme {
|
|
147
134
|
mode: "light" | "dark";
|
|
148
|
-
primaryColor: string;
|
|
149
135
|
tokens: Record<string, string>;
|
|
150
136
|
/**
|
|
151
137
|
* Font faces the host wants loaded into the app document. Optional — a host
|
|
@@ -248,149 +234,13 @@ interface RequestFileOptions {
|
|
|
248
234
|
/** Allow multiple file selection. Default: false */
|
|
249
235
|
multiple?: boolean;
|
|
250
236
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
callTool<TInput = Record<string, unknown>, TOutput = unknown>(name: string, args?: TInput): Promise<ToolCallResult<TOutput>>;
|
|
255
|
-
/**
|
|
256
|
-
* Task-augmented variant of `callTool` per MCP 2025-11-25. Sends
|
|
257
|
-
* `tools/call` with a `task` param; the receiver returns a
|
|
258
|
-
* `CreateTaskResult` promptly and the actual `CallToolResult` lands
|
|
259
|
-
* via `tasks/result`. Returns a `TaskHandle` that exposes
|
|
260
|
-
* `result()`/`refresh()`/`cancel()`/`onStatus()`.
|
|
261
|
-
*
|
|
262
|
-
* Throws if the host did not advertise `tasks.requests.tools.call` in
|
|
263
|
-
* its init-response capabilities — requestors MUST NOT task-augment
|
|
264
|
-
* without matching receiver capability.
|
|
265
|
-
*/
|
|
266
|
-
callToolAsTask<TInput = Record<string, unknown>, TOutput = unknown>(name: string, args?: TInput, options?: CallToolAsTaskOptions): Promise<TaskHandle<TOutput>>;
|
|
267
|
-
/**
|
|
268
|
-
* Read an MCP resource from the originating server via the host bridge
|
|
269
|
-
* (ext-apps `resources/read`).
|
|
270
|
-
*
|
|
271
|
-
* Use this to resolve `resource_link` content blocks returned by tools, or
|
|
272
|
-
* to fetch any known resource URI exposed by the MCP server. The host
|
|
273
|
-
* proxies the request to the server and forwards the result unchanged.
|
|
274
|
-
*
|
|
275
|
-
* @param uri The resource URI (e.g. `"videos://bunny-1mb"`).
|
|
276
|
-
* @returns The server's `ReadResourceResult` — `contents` is an array of
|
|
277
|
-
* blocks, each with a `uri`, optional `mimeType`, and either `text` or
|
|
278
|
-
* `blob` (base64).
|
|
279
|
-
*/
|
|
280
|
-
readResource(uri: string): Promise<ReadResourceResult>;
|
|
281
|
-
onDataChanged(callback: (event: DataChangedEvent) => void): () => void;
|
|
282
|
-
/**
|
|
283
|
-
* Subscribe to agent actions — typed, declarative commands from the server.
|
|
284
|
-
*
|
|
285
|
-
* Actions are deterministic side effects of tool execution. The server/tool
|
|
286
|
-
* decides what action to emit; the UI decides how to handle it.
|
|
287
|
-
*
|
|
288
|
-
* The callback receives an AgentAction with a `type` discriminator and typed
|
|
289
|
-
* `payload`. Apps should handle known types and ignore unknown ones.
|
|
290
|
-
*/
|
|
291
|
-
onAction(callback: (action: AgentAction) => void): () => void;
|
|
292
|
-
/**
|
|
293
|
-
* Read the current ext-apps host context as last received from the host.
|
|
294
|
-
*
|
|
295
|
-
* Spec-standardized fields (`theme`, `styles`, `displayMode`, `toolInfo`)
|
|
296
|
-
* are typed; the open `[key: string]: unknown` allows hosts to publish
|
|
297
|
-
* extensions (e.g. NimbleBrain populates `workspace`). Apps reading
|
|
298
|
-
* host-specific fields should treat them as optional and tolerate
|
|
299
|
-
* missing values when running on other hosts.
|
|
300
|
-
*
|
|
301
|
-
* Returns the empty object before the `ui/initialize` handshake completes.
|
|
302
|
-
*/
|
|
303
|
-
getHostContext(): McpUiHostContext;
|
|
304
|
-
/**
|
|
305
|
-
* Subscribe to host-context updates. Fires once per
|
|
306
|
-
* `ui/notifications/host-context-changed` notification (which carries a
|
|
307
|
-
* full snapshot, not a delta) and once on handshake completion.
|
|
308
|
-
*
|
|
309
|
-
* `getTheme`/`onThemeChanged` are typed selectors over this same state —
|
|
310
|
-
* prefer them when only theming matters, since they filter no-op fires.
|
|
311
|
-
*/
|
|
312
|
-
onHostContextChanged(callback: (ctx: McpUiHostContext) => void): () => void;
|
|
313
|
-
getTheme(): SynapseTheme;
|
|
314
|
-
onThemeChanged(callback: (theme: SynapseTheme) => void): () => void;
|
|
315
|
-
/** NimbleBrain-only: trigger a host-side action. No-op in other hosts. */
|
|
316
|
-
action(action: string, params?: Record<string, unknown>): void;
|
|
317
|
-
/**
|
|
318
|
-
* Send a user message into the agent conversation (ext-apps `ui/message`).
|
|
319
|
-
*
|
|
320
|
-
* @param context NimbleBrain-specific metadata, included as `_meta.context`
|
|
321
|
-
* on the content block. Ignored by non-NimbleBrain hosts.
|
|
322
|
-
*/
|
|
323
|
-
chat(message: string, context?: {
|
|
324
|
-
action?: string;
|
|
325
|
-
entity?: string;
|
|
326
|
-
}): void;
|
|
327
|
-
/**
|
|
328
|
-
* Push the app's current visible state to the agent (ext-apps `ui/update-model-context`).
|
|
329
|
-
*
|
|
330
|
-
* The `summary` string is what the LLM reads as a text content block.
|
|
331
|
-
* The `state` object is included as `structuredContent` for tools that need IDs/values.
|
|
332
|
-
* Debounced at 250ms. Each call overwrites the previous context.
|
|
333
|
-
*/
|
|
334
|
-
setVisibleState(state: Record<string, unknown>, summary?: string): void;
|
|
335
|
-
downloadFile(filename: string, content: string | Blob, mimeType?: string): void;
|
|
336
|
-
openLink(url: string): void;
|
|
337
|
-
/**
|
|
338
|
-
* Request a file from the user via the host's native file picker.
|
|
339
|
-
* NimbleBrain-only: throws in non-NimbleBrain hosts.
|
|
340
|
-
* Returns null if the user cancels.
|
|
341
|
-
*/
|
|
342
|
-
pickFile(options?: RequestFileOptions): Promise<FileResult | null>;
|
|
343
|
-
/**
|
|
344
|
-
* Pick multiple files from the user.
|
|
345
|
-
* NimbleBrain-only: throws in non-NimbleBrain hosts.
|
|
346
|
-
* Returns empty array if the user cancels.
|
|
347
|
-
*/
|
|
348
|
-
pickFiles(options?: RequestFileOptions): Promise<FileResult[]>;
|
|
349
|
-
/** @internal — used by createStore for synapse/state-loaded */
|
|
350
|
-
_onMessage(method: string, callback: (params: Record<string, unknown> | undefined) => void): () => void;
|
|
351
|
-
/** @internal — used by createStore for synapse/persist-state */
|
|
352
|
-
_request(method: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
353
|
-
/**
|
|
354
|
-
* @internal — host's declared `tasks` capability from the `ui/initialize`
|
|
355
|
-
* response, or `undefined` if absent. Read by the task-augmented tool call
|
|
356
|
-
* path (future `callToolAsTask`) to decide whether task augmentation is
|
|
357
|
-
* negotiated. `null` before the handshake completes.
|
|
358
|
-
*
|
|
359
|
-
* Requestors MUST NOT task-augment a tool call unless this is defined and
|
|
360
|
-
* carries `requests.tools.call` per MCP 2025-11-25.
|
|
361
|
-
*/
|
|
362
|
-
readonly _hostTasksCapability: TasksCapability | undefined | null;
|
|
363
|
-
/** True after destroy() has been called. */
|
|
364
|
-
readonly destroyed: boolean;
|
|
365
|
-
destroy(): void;
|
|
366
|
-
}
|
|
367
|
-
interface VisibleState {
|
|
237
|
+
/** What `useModelContext`'s declarative factory returns. */
|
|
238
|
+
interface ModelContext {
|
|
239
|
+
/** Structured state the agent's tools can read ids and values out of. */
|
|
368
240
|
state: Record<string, unknown>;
|
|
241
|
+
/** The one line the model actually reads. */
|
|
369
242
|
summary?: string;
|
|
370
243
|
}
|
|
371
|
-
interface StateAcknowledgement {
|
|
372
|
-
truncated: boolean;
|
|
373
|
-
}
|
|
374
|
-
type ActionReducer<TState, TPayload = unknown> = (state: TState, payload: TPayload) => TState;
|
|
375
|
-
interface StoreConfig<TState> {
|
|
376
|
-
initialState: TState;
|
|
377
|
-
actions: Record<string, ActionReducer<TState, any>>;
|
|
378
|
-
persist?: boolean;
|
|
379
|
-
visibleToAgent?: boolean;
|
|
380
|
-
summarize?: (state: TState) => string;
|
|
381
|
-
version?: number;
|
|
382
|
-
migrations?: Array<(oldState: any) => any>;
|
|
383
|
-
}
|
|
384
|
-
type StoreDispatch<TActions extends Record<string, ActionReducer<any, any>>> = {
|
|
385
|
-
[K in keyof TActions]: Parameters<TActions[K]>[1] extends undefined ? () => void : (payload: Parameters<TActions[K]>[1]) => void;
|
|
386
|
-
};
|
|
387
|
-
interface Store<TState, TActions extends Record<string, ActionReducer<TState, any>> = Record<string, ActionReducer<TState, any>>> {
|
|
388
|
-
getState(): TState;
|
|
389
|
-
subscribe(callback: (state: TState) => void): () => void;
|
|
390
|
-
dispatch: StoreDispatch<TActions>;
|
|
391
|
-
hydrate(state: TState): void;
|
|
392
|
-
destroy(): void;
|
|
393
|
-
}
|
|
394
244
|
interface KeyForwardConfig {
|
|
395
245
|
key: string;
|
|
396
246
|
ctrl?: boolean;
|
|
@@ -410,19 +260,35 @@ interface HostInfo {
|
|
|
410
260
|
protocolVersion: string;
|
|
411
261
|
}
|
|
412
262
|
interface ConnectOptions {
|
|
263
|
+
/** App name — must match the bundle name registered with the host. */
|
|
413
264
|
name: string;
|
|
265
|
+
/** Semver version string. */
|
|
414
266
|
version: string;
|
|
267
|
+
/** Track the document height and re-send `size-changed` as it moves. */
|
|
415
268
|
autoResize?: boolean;
|
|
269
|
+
/**
|
|
270
|
+
* Mark as an internal NimbleBrain app. Enables cross-server tool calls:
|
|
271
|
+
* `callTool` carries a `server` param so the host can route the call to a
|
|
272
|
+
* sibling server. External apps MUST NOT set this.
|
|
273
|
+
*/
|
|
274
|
+
internal?: boolean;
|
|
275
|
+
/**
|
|
276
|
+
* Forward keyboard shortcuts from this iframe up to the host, so the host's
|
|
277
|
+
* own shortcuts still fire while focus is inside the app.
|
|
278
|
+
*
|
|
279
|
+
* `true` forwards the default set (Escape plus every Ctrl/Cmd combo except
|
|
280
|
+
* the clipboard keys the browser must handle itself); an array forwards
|
|
281
|
+
* exactly the listed combos. Absent means no forwarding.
|
|
282
|
+
*
|
|
283
|
+
* Only a NimbleBrain host consumes `synapse/keydown`, so forwarding stays
|
|
284
|
+
* off everywhere else — a `preventDefault` on a host that does nothing with
|
|
285
|
+
* the key would swallow it for no one's benefit.
|
|
286
|
+
*/
|
|
287
|
+
forwardKeys?: boolean | KeyForwardConfig[];
|
|
416
288
|
/** Pre-register event handlers before the handshake completes.
|
|
417
289
|
* These are wired before `initialized` is sent, so no messages are lost. */
|
|
418
290
|
on?: Record<string, (data: any) => void>;
|
|
419
291
|
}
|
|
420
|
-
interface Theme {
|
|
421
|
-
mode: "light" | "dark";
|
|
422
|
-
tokens: Record<string, string>;
|
|
423
|
-
/** Font faces the host wants loaded. See {@link FontFaceDescriptor}. */
|
|
424
|
-
fontFaces?: FontFaceDescriptor[];
|
|
425
|
-
}
|
|
426
292
|
interface Dimensions {
|
|
427
293
|
width?: number;
|
|
428
294
|
height?: number;
|
|
@@ -434,8 +300,27 @@ interface ToolResultData {
|
|
|
434
300
|
structuredContent: unknown;
|
|
435
301
|
raw: Record<string, unknown>;
|
|
436
302
|
}
|
|
437
|
-
/**
|
|
438
|
-
|
|
303
|
+
/** Per-call overrides for {@link App.callTool}. */
|
|
304
|
+
interface CallToolOptions {
|
|
305
|
+
/**
|
|
306
|
+
* Route the call to a sibling MCP server rather than the app's own.
|
|
307
|
+
* Internal apps only — the host rejects it otherwise. Defaults to this
|
|
308
|
+
* app's name when `connect({ internal: true })` was used, which is what
|
|
309
|
+
* makes a plain `callTool` work for an internal app.
|
|
310
|
+
*/
|
|
311
|
+
server?: string;
|
|
312
|
+
}
|
|
313
|
+
/** Known short event names for {@link App.on}. */
|
|
314
|
+
type AppEventName = "tool-result" | "tool-input" | "tool-input-partial" | "tool-cancelled" | "theme-changed" | "host-context-changed" | "data-changed" | "action" | "teardown";
|
|
315
|
+
/**
|
|
316
|
+
* A connected app — what `connect()` resolves to, and the only runtime object
|
|
317
|
+
* this SDK hands out.
|
|
318
|
+
*
|
|
319
|
+
* Deliberately small: it carries the ext-apps spec surface plus the state the
|
|
320
|
+
* handshake established. NimbleBrain's own extensions (the file picker,
|
|
321
|
+
* `action`, `downloadFile`) and the MCP tasks utility are composable functions
|
|
322
|
+
* over this object rather than more methods on it.
|
|
323
|
+
*/
|
|
439
324
|
interface App {
|
|
440
325
|
readonly theme: Theme;
|
|
441
326
|
readonly hostInfo: {
|
|
@@ -446,21 +331,57 @@ interface App {
|
|
|
446
331
|
tool: Record<string, unknown>;
|
|
447
332
|
} | null;
|
|
448
333
|
readonly containerDimensions: Dimensions | null;
|
|
334
|
+
/**
|
|
335
|
+
* The current host context: the handshake's, with every
|
|
336
|
+
* `host-context-changed` delta merged into it. Spec fields (`theme`,
|
|
337
|
+
* `styles`, `displayMode`, `toolInfo`) are typed; the open index signature
|
|
338
|
+
* carries host extensions — NimbleBrain publishes `workspace` here. Read
|
|
339
|
+
* host-specific fields as optional; another host will not send them.
|
|
340
|
+
*/
|
|
341
|
+
readonly hostContext: McpUiHostContext;
|
|
342
|
+
/** True when the host identified itself as NimbleBrain in the handshake. */
|
|
343
|
+
readonly isNimbleBrainHost: boolean;
|
|
344
|
+
/** True after `destroy()` has been called. */
|
|
345
|
+
readonly destroyed: boolean;
|
|
346
|
+
/**
|
|
347
|
+
* Whether the host negotiated the MCP tasks utility for `tools/call`.
|
|
348
|
+
*
|
|
349
|
+
* `callToolAsTask` throws when this is false — per MCP 2025-11-25 a
|
|
350
|
+
* requestor MUST NOT task-augment a call the receiver did not advertise. Read
|
|
351
|
+
* it to decide whether to offer a long-running action at all, rather than to
|
|
352
|
+
* discover the answer from an exception.
|
|
353
|
+
*/
|
|
354
|
+
readonly supportsTasks: boolean;
|
|
449
355
|
on(event: "tool-input", handler: (args: Record<string, unknown>) => void): () => void;
|
|
450
356
|
on(event: "tool-result", handler: (data: ToolResultData) => void): () => void;
|
|
451
357
|
on(event: "theme-changed", handler: (theme: Theme) => void): () => void;
|
|
358
|
+
/** Fires with the merged snapshot — the same value as `hostContext`. For the
|
|
359
|
+
* notification exactly as sent, subscribe to the wire method instead:
|
|
360
|
+
* `on("ui/notifications/host-context-changed", …)`. */
|
|
361
|
+
on(event: "host-context-changed", handler: (ctx: McpUiHostContext) => void): () => void;
|
|
362
|
+
on(event: "data-changed", handler: (event: DataChangedEvent) => void): () => void;
|
|
363
|
+
on(event: "action", handler: (action: AgentAction) => void): () => void;
|
|
452
364
|
on(event: "teardown", handler: () => void): () => void;
|
|
453
|
-
on(event: string, handler: (params:
|
|
365
|
+
on(event: string, handler: (params: any) => void): () => void;
|
|
454
366
|
resize(width?: number, height?: number): void;
|
|
455
367
|
openLink(url: string): void;
|
|
368
|
+
/**
|
|
369
|
+
* Push the app's visible state to the agent (ext-apps
|
|
370
|
+
* `ui/update-model-context`). `summary` is what the model reads as text;
|
|
371
|
+
* `state` rides along as `structuredContent` for tools that need the ids.
|
|
372
|
+
*
|
|
373
|
+
* Sends immediately. Callers that push on every keystroke or selection
|
|
374
|
+
* change want `useModelContext`, which debounces.
|
|
375
|
+
*/
|
|
456
376
|
updateModelContext(state: Record<string, unknown>, summary?: string): void;
|
|
457
|
-
callTool(name: string, args?: Record<string, unknown
|
|
377
|
+
callTool<TOutput = unknown>(name: string, args?: Record<string, unknown>, options?: CallToolOptions): Promise<ToolCallResult<TOutput>>;
|
|
458
378
|
/**
|
|
459
379
|
* Read an MCP resource from the originating server via the host bridge
|
|
460
380
|
* (ext-apps `resources/read`). Named to mirror the ext-apps spec's
|
|
461
381
|
* `App.readServerResource`.
|
|
462
382
|
*/
|
|
463
383
|
readServerResource(params: ReadResourceRequest["params"]): Promise<ReadResourceResult>;
|
|
384
|
+
/** Send a user message into the agent conversation (ext-apps `ui/message`). */
|
|
464
385
|
sendMessage(text: string, context?: {
|
|
465
386
|
action?: string;
|
|
466
387
|
entity?: string;
|
|
@@ -468,4 +389,4 @@ interface App {
|
|
|
468
389
|
destroy(): void;
|
|
469
390
|
}
|
|
470
391
|
|
|
471
|
-
export type { App as A, BuiltinActionType as B, ConnectOptions as C, DataChangedEvent as D,
|
|
392
|
+
export type { App as A, BuiltinActionType as B, ConnectOptions as C, DataChangedEvent as D, FileResult as F, HostInfo as H, KeyForwardConfig as K, ModelContext as M, NavigatePayload as N, RequestFileOptions as R, TaskHandle as T, CallToolAsTaskOptions as a, ToolCallResult as b, CallToolOptions as c, Theme as d, ToolResultData as e, ToolDefinition as f, FontFaceDescriptor as g, AgentAction as h, AppEventName as i, Dimensions as j, FontDisplayValue as k, NotifyPayload as l, TasksCapability as m };
|