devframe 0.9.20 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/dist/_shared-B2PZsp-J.mjs +191 -0
  2. package/dist/{_shared-BIUet_Jh.d.mts → _shared-D1ebaX_J.d.mts} +13 -14
  3. package/dist/adapters/build.d.mts +3 -4
  4. package/dist/adapters/build.mjs +4 -5
  5. package/dist/adapters/cac.d.mts +3 -4
  6. package/dist/adapters/cac.mjs +3 -3
  7. package/dist/adapters/dev.d.mts +8 -8
  8. package/dist/adapters/dev.mjs +2 -2
  9. package/dist/adapters/embedded.d.mts +1 -1
  10. package/dist/adapters/initiate.d.mts +8 -8
  11. package/dist/adapters/initiate.mjs +1 -1
  12. package/dist/adapters/mcp.d.mts +4 -142
  13. package/dist/adapters/mcp.mjs +1 -597
  14. package/dist/agentic-DLqHMOyN.d.mts +30 -0
  15. package/dist/browser-agent-Pu-FLk6I.mjs +26 -0
  16. package/dist/browser-agent-rpc-BXhoSh1z.mjs +70 -0
  17. package/dist/cli/main.mjs +12 -260
  18. package/dist/client/index.d.mts +6 -6
  19. package/dist/client/index.mjs +12 -87
  20. package/dist/constants.d.mts +2 -1
  21. package/dist/constants.mjs +2 -1
  22. package/dist/{context-BLHBDQcZ.d.mts → context--tVkJw3W.d.mts} +127 -47
  23. package/dist/{context-BLXXjoBW.mjs → context-BqpgC5tq.mjs} +55 -5
  24. package/dist/{context-jXO5vzjH.mjs → context-CHpyLX8W.mjs} +1 -1
  25. package/dist/{context-BA5FPz7K.d.mts → context-D3qBv0IX.d.mts} +1 -1
  26. package/dist/{dev-BdKKOH8S.mjs → dev-BTbLJekh.mjs} +16 -24
  27. package/dist/{diagnostics-DZA6KQ_Z.mjs → diagnostics-Cx4_VjlG.mjs} +11 -3
  28. package/dist/dist-CO98PBnQ.mjs +265 -0
  29. package/dist/{host-agent-C3MBpNCd.mjs → host-agent-mIbQ6Qi5.mjs} +14 -13
  30. package/dist/import-runtime-module-BzlEQ9PI.mjs +24 -0
  31. package/dist/in-page-channel/index.d.mts +16 -12
  32. package/dist/in-page-channel/index.mjs +42 -14
  33. package/dist/index-Bia1vKjL.d.mts +218 -0
  34. package/dist/index-CeEtxDmK.d.mts +78 -0
  35. package/dist/{index-r6NstVmM.d.mts → index-D-2IdY1I.d.mts} +2 -2
  36. package/dist/{index-CiA6C705.d.mts → index-DuEm0sDH.d.mts} +1 -1
  37. package/dist/index.d.mts +4 -11
  38. package/dist/index.mjs +1 -10
  39. package/dist/{instance-registry-DCq762YJ.mjs → instance-registry-DtvYxc0Y.mjs} +1 -1
  40. package/dist/{instance-shell-C6Vg97lg.d.mts → instance-shell-CXnpSuK7.d.mts} +31 -5
  41. package/dist/{instance-shell-yfrM3_vK.mjs → instance-shell-wC2sfEU_.mjs} +7 -7
  42. package/dist/interactive-auth-BCa_iamv.mjs +384 -0
  43. package/dist/internal/index.d.mts +66 -22
  44. package/dist/internal/index.mjs +143 -8
  45. package/dist/mrmime-40h5OOIp.mjs +448 -0
  46. package/dist/node/auth.d.mts +2 -2
  47. package/dist/node/hub-internals.d.mts +2 -2
  48. package/dist/node/hub-internals.mjs +2 -2
  49. package/dist/node/index.d.mts +2 -4
  50. package/dist/node/index.mjs +2 -2
  51. package/dist/{nostics-0sKe5HIj.d.mts → nostics-DWvukRwa.d.mts} +11 -2
  52. package/dist/{origin-D_eBKEzr.mjs → origin-DZit9g29.mjs} +1 -21
  53. package/dist/recipes/interactive-auth.d.mts +2 -2
  54. package/dist/recipes/interactive-auth.mjs +1 -231
  55. package/dist/{remote-assets-D0StJVLp.mjs → remote-assets-B9MeWmW6.mjs} +2 -2
  56. package/dist/rpc/client.d.mts +1 -1
  57. package/dist/rpc/client.mjs +1 -1
  58. package/dist/rpc/dump.d.mts +2 -1
  59. package/dist/rpc/index.d.mts +3 -2
  60. package/dist/rpc/server.d.mts +1 -1
  61. package/dist/rpc/server.mjs +1 -1
  62. package/dist/rpc/transports/sse-client.d.mts +1 -1
  63. package/dist/rpc/transports/sse-server.d.mts +3 -3
  64. package/dist/rpc/transports/sse-server.mjs +1 -1
  65. package/dist/rpc/transports/ws-bun.d.mts +2 -2
  66. package/dist/rpc/transports/ws-bun.mjs +1 -1
  67. package/dist/rpc/transports/ws-client.d.mts +1 -1
  68. package/dist/rpc/transports/ws-deno.d.mts +2 -2
  69. package/dist/rpc/transports/ws-deno.mjs +1 -1
  70. package/dist/rpc/transports/ws-server.d.mts +1 -1
  71. package/dist/rpc/transports/ws-server.mjs +1 -1
  72. package/dist/{rpc-core-BlL-Ip8n.d.mts → rpc-core-B6n9MQsc.d.mts} +4 -4
  73. package/dist/{rpc-core-CvkU23bQ.mjs → rpc-core-BXyMjbKG.mjs} +1 -1
  74. package/dist/{services-install-Ben4yh52.mjs → services-install-D5YUwFXW.mjs} +17 -1
  75. package/dist/{sse-client-BcbYwXdD.d.mts → sse-client-DNdscfu_.d.mts} +2 -2
  76. package/dist/{storage-B70AXK64.mjs → storage-CHD1IkqU.mjs} +1 -1
  77. package/dist/tool-input-BAQXvvqL.mjs +393 -0
  78. package/dist/types/index.d.mts +4 -4
  79. package/dist/{types-D2vGd7-2.d.mts → types-BmDbfHCx.d.mts} +2 -3
  80. package/dist/utils/debounce.d.mts +50 -0
  81. package/dist/utils/debounce.mjs +88 -0
  82. package/dist/utils/events.d.mts +1 -1
  83. package/dist/utils/launch-editor.d.mts +8 -0
  84. package/dist/utils/launch-editor.mjs +36 -1
  85. package/dist/utils/nostics.d.mts +2 -2
  86. package/dist/utils/remote-assets.mjs +1 -1
  87. package/dist/utils/serve-static.mjs +1 -1
  88. package/dist/utils/shared-state.d.mts +1 -1
  89. package/dist/utils/simple-schema.d.mts +3 -2
  90. package/dist/utils/streaming-channel.d.mts +1 -1
  91. package/dist/utils/url.d.mts +31 -0
  92. package/dist/utils/url.mjs +58 -0
  93. package/dist/{ws-client-CNpP6Ium.d.mts → ws-client-6Mrz6eC4.d.mts} +2 -2
  94. package/dist/{ws-server-BB8jhxeT.d.mts → ws-server-y2R76aSW.d.mts} +2 -2
  95. package/package.json +10 -11
  96. package/dist/_shared-U8D-xzrp.mjs +0 -115
  97. package/dist/agent-tool-name-DGzeuWcO.mjs +0 -31
  98. package/dist/client-assets-DNdhagGm.mjs +0 -16
  99. package/dist/nostics-DD6gsDZA.mjs +0 -108
  100. package/dist/recipes/common-rpc-functions.d.mts +0 -70
  101. package/dist/recipes/common-rpc-functions.mjs +0 -115
  102. package/dist/simple-schema-Bi40l-P6.mjs +0 -154
@@ -0,0 +1,265 @@
1
+ //#region ../../node_modules/.pnpm/birpc@4.2.0/node_modules/birpc/dist/index.mjs
2
+ function createPromiseWithResolvers() {
3
+ let resolve;
4
+ let reject;
5
+ return {
6
+ promise: new Promise((res, rej) => {
7
+ resolve = res;
8
+ reject = rej;
9
+ }),
10
+ resolve,
11
+ reject
12
+ };
13
+ }
14
+ const _cacheMap = /* @__PURE__ */ new WeakMap();
15
+ function cachedMap(items, fn) {
16
+ return items.map((i) => {
17
+ let r = _cacheMap.get(i);
18
+ if (!r) {
19
+ r = fn(i);
20
+ _cacheMap.set(i, r);
21
+ }
22
+ return r;
23
+ });
24
+ }
25
+ const random = Math.random.bind(Math);
26
+ const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
27
+ function nanoid(size = 21) {
28
+ let id = "";
29
+ let i = size;
30
+ while (i--) id += urlAlphabet[random() * 64 | 0];
31
+ return id;
32
+ }
33
+ const DEFAULT_TIMEOUT = 6e4;
34
+ const defaultSerialize = (i) => i;
35
+ const defaultDeserialize = defaultSerialize;
36
+ const { clearTimeout, setTimeout } = globalThis;
37
+ function createBirpc($functions, options) {
38
+ const { post, on, off = () => {}, eventNames = [], serialize = defaultSerialize, deserialize = defaultDeserialize, resolver, bind = "rpc", timeout = DEFAULT_TIMEOUT, proxify = true } = options;
39
+ let $closed = false;
40
+ const _rpcPromiseMap = /* @__PURE__ */ new Map();
41
+ let _promiseInit;
42
+ let rpc;
43
+ async function _call(method, args, event, optional) {
44
+ if ($closed) throw new Error(`[birpc] rpc is closed, cannot call "${method}"`);
45
+ const req = {
46
+ m: method,
47
+ a: args,
48
+ t: "q"
49
+ };
50
+ if (optional) req.o = true;
51
+ const send = async (_req) => post(serialize(_req));
52
+ if (event) {
53
+ await send(req);
54
+ return;
55
+ }
56
+ if (_promiseInit) try {
57
+ await _promiseInit;
58
+ } finally {
59
+ _promiseInit = void 0;
60
+ }
61
+ let { promise, resolve, reject } = createPromiseWithResolvers();
62
+ const id = nanoid();
63
+ req.i = id;
64
+ let timeoutId;
65
+ async function handler(newReq = req) {
66
+ if (timeout >= 0) {
67
+ timeoutId = setTimeout(() => {
68
+ try {
69
+ if (options.onTimeoutError?.call(rpc, method, args) !== true) throw new Error(`[birpc] timeout on calling "${method}"`);
70
+ } catch (e) {
71
+ reject(e);
72
+ }
73
+ _rpcPromiseMap.delete(id);
74
+ }, timeout);
75
+ if (typeof timeoutId === "object") timeoutId = timeoutId.unref?.();
76
+ }
77
+ _rpcPromiseMap.set(id, {
78
+ resolve,
79
+ reject,
80
+ timeoutId,
81
+ method
82
+ });
83
+ await send(newReq);
84
+ return promise;
85
+ }
86
+ try {
87
+ if (options.onRequest) await options.onRequest.call(rpc, req, handler, resolve);
88
+ else await handler();
89
+ } catch (e) {
90
+ if (options.onGeneralError?.call(rpc, e) !== true) throw e;
91
+ return;
92
+ } finally {
93
+ clearTimeout(timeoutId);
94
+ _rpcPromiseMap.delete(id);
95
+ }
96
+ return promise;
97
+ }
98
+ const builtinMethods = {
99
+ $call: (method, ...args) => _call(method, args, false),
100
+ $callOptional: (method, ...args) => _call(method, args, false, true),
101
+ $callEvent: (method, ...args) => _call(method, args, true),
102
+ $callRaw: (options) => _call(options.method, options.args, options.event, options.optional),
103
+ $rejectPendingCalls,
104
+ get $closed() {
105
+ return $closed;
106
+ },
107
+ get $meta() {
108
+ return options.meta;
109
+ },
110
+ $close,
111
+ $functions
112
+ };
113
+ if (proxify) rpc = new Proxy({}, { get(_, method) {
114
+ if (Object.hasOwn(builtinMethods, method)) return builtinMethods[method];
115
+ if (method === "then" && !eventNames.includes("then") && !("then" in $functions)) return void 0;
116
+ const sendEvent = (...args) => _call(method, args, true);
117
+ if (eventNames.includes(method)) {
118
+ sendEvent.asEvent = sendEvent;
119
+ return sendEvent;
120
+ }
121
+ const sendCall = (...args) => _call(method, args, false);
122
+ sendCall.asEvent = sendEvent;
123
+ return sendCall;
124
+ } });
125
+ else rpc = builtinMethods;
126
+ function $close(customError) {
127
+ $closed = true;
128
+ _rpcPromiseMap.forEach(({ reject, method }) => {
129
+ const error = /* @__PURE__ */ new Error(`[birpc] rpc is closed, cannot call "${method}"`);
130
+ if (customError) {
131
+ customError.cause ??= error;
132
+ return reject(customError);
133
+ }
134
+ reject(error);
135
+ });
136
+ _rpcPromiseMap.clear();
137
+ off(onMessage);
138
+ }
139
+ function $rejectPendingCalls(handler) {
140
+ const handlerResults = Array.from(_rpcPromiseMap.values()).map(({ method, reject }) => {
141
+ if (!handler) return reject(/* @__PURE__ */ new Error(`[birpc]: rejected pending call "${method}".`));
142
+ return handler({
143
+ method,
144
+ reject
145
+ });
146
+ });
147
+ _rpcPromiseMap.clear();
148
+ return handlerResults;
149
+ }
150
+ async function onMessage(data, ...extra) {
151
+ let msg;
152
+ try {
153
+ msg = deserialize(data);
154
+ } catch (e) {
155
+ if (options.onGeneralError?.call(rpc, e) !== true) throw e;
156
+ return;
157
+ }
158
+ if (msg.t === "q") {
159
+ const { m: method, a: args, o: optional } = msg;
160
+ let result, error;
161
+ let fn = await (resolver ? resolver.call(rpc, method, $functions[method]) : $functions[method]);
162
+ if (optional) fn ||= () => void 0;
163
+ if (!fn) error = /* @__PURE__ */ new Error(`[birpc] function "${method}" not found`);
164
+ else try {
165
+ result = await fn.apply(bind === "rpc" ? rpc : $functions, args);
166
+ } catch (e) {
167
+ error = e;
168
+ }
169
+ if (msg.i) {
170
+ if (error && options.onFunctionError) {
171
+ if (options.onFunctionError.call(rpc, error, method, args) === true) return;
172
+ }
173
+ if (!error) try {
174
+ await post(serialize({
175
+ t: "s",
176
+ i: msg.i,
177
+ r: result
178
+ }), ...extra);
179
+ return;
180
+ } catch (e) {
181
+ error = e;
182
+ if (options.onGeneralError?.call(rpc, e, method, args) !== true) throw e;
183
+ }
184
+ try {
185
+ await post(serialize({
186
+ t: "s",
187
+ i: msg.i,
188
+ e: error
189
+ }), ...extra);
190
+ } catch (e) {
191
+ if (options.onGeneralError?.call(rpc, e, method, args) !== true) throw e;
192
+ }
193
+ }
194
+ } else {
195
+ const { i: ack, r: result, e: error } = msg;
196
+ const promise = _rpcPromiseMap.get(ack);
197
+ if (promise) {
198
+ clearTimeout(promise.timeoutId);
199
+ if (error) promise.reject(error);
200
+ else promise.resolve(result);
201
+ }
202
+ _rpcPromiseMap.delete(ack);
203
+ }
204
+ }
205
+ _promiseInit = on(onMessage);
206
+ return rpc;
207
+ }
208
+ function createBirpcGroup(functions, channels, options = {}) {
209
+ const { proxify = true } = options;
210
+ const getChannels = () => typeof channels === "function" ? channels() : channels;
211
+ const getClients = (channels = getChannels()) => cachedMap(channels, (s) => createBirpc(functions, {
212
+ ...options,
213
+ ...s
214
+ }));
215
+ function _boardcast(options) {
216
+ const clients = getClients();
217
+ return Promise.all(clients.map((c) => c.$callRaw(options)));
218
+ }
219
+ const broadcastBuiltin = {
220
+ $call: (method, ...args) => _boardcast({
221
+ method,
222
+ args,
223
+ event: false
224
+ }),
225
+ $callOptional: (method, ...args) => _boardcast({
226
+ method,
227
+ args,
228
+ event: false,
229
+ optional: true
230
+ }),
231
+ $callEvent: (method, ...args) => _boardcast({
232
+ method,
233
+ args,
234
+ event: true
235
+ }),
236
+ $callRaw: (options) => _boardcast(options)
237
+ };
238
+ const broadcastProxy = proxify ? new Proxy({}, { get(_, method) {
239
+ if (Object.hasOwn(broadcastBuiltin, method)) return broadcastBuiltin[method];
240
+ const callbacks = getClients().map((c) => c[method]);
241
+ const sendCall = (...args) => {
242
+ return Promise.all(callbacks.map((i) => i(...args)));
243
+ };
244
+ sendCall.asEvent = async (...args) => {
245
+ await Promise.all(callbacks.map((i) => i.asEvent(...args)));
246
+ };
247
+ return sendCall;
248
+ } }) : broadcastBuiltin;
249
+ function updateChannels(fn) {
250
+ const channels = getChannels();
251
+ fn?.(channels);
252
+ return getClients(channels);
253
+ }
254
+ getClients();
255
+ return {
256
+ get clients() {
257
+ return getClients();
258
+ },
259
+ functions,
260
+ updateChannels,
261
+ broadcast: broadcastProxy
262
+ };
263
+ }
264
+ //#endregion
265
+ export { createBirpcGroup as n, createBirpc as t };
@@ -1,5 +1,5 @@
1
1
  import { t as DEVFRAME_EVENTS } from "./events-BV4Dj59a.mjs";
2
- import { t as diagnostics } from "./diagnostics-DZA6KQ_Z.mjs";
2
+ import { t as diagnostics } from "./diagnostics-Cx4_VjlG.mjs";
3
3
  //#region src/utils/events.ts
4
4
  /**
5
5
  * Create event emitter.
@@ -39,6 +39,17 @@ function createEventEmitter() {
39
39
  };
40
40
  }
41
41
  //#endregion
42
+ //#region src/agent/safety.ts
43
+ /**
44
+ * An agent tool's safety classification: the explicit `agent.safety`, else
45
+ * inferred from the function `type` (`static`/`query` are read-only, the rest
46
+ * mutate). Shared by every agent surface (MCP host, WebMCP, in-page bridge).
47
+ */
48
+ function resolveAgentSafety(type, agent) {
49
+ if (agent.safety) return agent.safety;
50
+ return type === "static" || type === "query" || type == null ? "read" : "action";
51
+ }
52
+ //#endregion
42
53
  //#region src/tool-input.ts
43
54
  /**
44
55
  * Convert an object-shaped tool input into positional arguments.
@@ -67,11 +78,6 @@ function toolInputToRpcArgs(input, argumentCount) {
67
78
  function toolInputToCommandArgs(input, argumentCount) {
68
79
  return collectPositionalArgs(input, argumentCount) ?? [];
69
80
  }
70
- /** @deprecated Use {@link toolInputToRpcArgs} or {@link toolInputToCommandArgs}. */
71
- function coerceAgentPositionalArgs(input, schemas, fallback = "wrap") {
72
- const argumentCount = schemas?.length;
73
- return fallback === "drop" ? toolInputToCommandArgs(input, argumentCount) : toolInputToRpcArgs(input, argumentCount);
74
- }
75
81
  //#endregion
76
82
  //#region src/node/host-agent.ts
77
83
  /**
@@ -248,8 +254,7 @@ var DevframeAgentHost = class {
248
254
  const agent = def.agent;
249
255
  if (!agent) continue;
250
256
  if (!agent.description || typeof agent.description !== "string") throw diagnostics.DF0014({ name });
251
- const type = def.type ?? "query";
252
- const safety = agent.safety ?? inferSafety(type);
257
+ const safety = resolveAgentSafety(def.type, agent);
253
258
  out.push({
254
259
  id: name,
255
260
  kind: "rpc",
@@ -268,9 +273,5 @@ var DevframeAgentHost = class {
268
273
  if (def?.agent) return def;
269
274
  }
270
275
  };
271
- function inferSafety(type) {
272
- if (type === "static" || type === "query") return "read";
273
- return "action";
274
- }
275
276
  //#endregion
276
- export { createEventEmitter as i, coerceAgentPositionalArgs as n, toolInputToCommandArgs as r, DevframeAgentHost as t };
277
+ export { toolInputToCommandArgs as n, createEventEmitter as r, DevframeAgentHost as t };
@@ -0,0 +1,24 @@
1
+ import { i as resolveServicePackage, r as importServicePackage } from "./services-install-D5YUwFXW.mjs";
2
+ //#region src/node/import-runtime-module.ts
3
+ /**
4
+ * Resolve and import a package at runtime without adding it to a consumer's
5
+ * bundle graph. First-party adapters use this for modules whose code is
6
+ * needed only when the matching feature is enabled (optional peers, and the
7
+ * MCP adapter with the SDK behind it).
8
+ *
9
+ * @internal
10
+ */
11
+ async function importRuntimeModule(specifier) {
12
+ return await importServicePackage(specifier, [import.meta.url]);
13
+ }
14
+ /**
15
+ * Whether {@link importRuntimeModule} would resolve `specifier`, without
16
+ * importing anything. The zero-cost probe behind optional-peer decisions.
17
+ *
18
+ * @internal
19
+ */
20
+ function isRuntimeModuleResolvable(specifier) {
21
+ return resolveServicePackage(specifier, [import.meta.url]) !== void 0;
22
+ }
23
+ //#endregion
24
+ export { isRuntimeModuleResolvable as n, importRuntimeModule as t };
@@ -1,6 +1,5 @@
1
- import { A as InferReturnType, D as RpcReturnSchema, O as Thenable, i as RpcArgsSchema, k as InferArgsType } from "../types-D2vGd7-2.mjs";
2
- import { Vt as EventEmitter, k as SharedState } from "../context-BLHBDQcZ.mjs";
3
- import { BirpcReturn } from "birpc";
1
+ import { D as InferArgsType, E as Thenable, O as InferReturnType, T as RpcReturnSchema, m as RpcFunctionAgentOptions, n as RpcArgsSchema } from "../types-BmDbfHCx.mjs";
2
+ import { Kt as EventEmitter, k as SharedState } from "../context--tVkJw3W.mjs";
4
3
  //#region src/in-page-channel/types.d.ts
5
4
  /**
6
5
  * The shared contract of one in-page channel, declared once (usually in a
@@ -49,11 +48,15 @@ type ProtocolHandler<F> = F extends ((...args: any[]) => any) ? (...args: FnArgs
49
48
  * fan-out), `action` performs, `query` requests data (the default).
50
49
  */
51
50
  type InPageFunctionType = 'action' | 'event' | 'query';
52
- interface InPageFunctionDefinitionBase<NAME extends string> {
51
+ interface InPageDefinitionBase<NAME extends string> {
53
52
  name: NAME;
54
53
  jsonSerializable?: boolean;
55
54
  }
56
- interface InPageEventFunctionDefinition<NAME extends string, HANDLER> extends InPageFunctionDefinitionBase<NAME> {
55
+ interface InPageFunctionDefinitionBase<NAME extends string> extends InPageDefinitionBase<NAME> {
56
+ /** Expose this function through DevFrame's browser-to-node agent bridge. */
57
+ agent?: RpcFunctionAgentOptions;
58
+ }
59
+ interface InPageEventFunctionDefinition<NAME extends string, HANDLER> extends InPageDefinitionBase<NAME> {
57
60
  type: 'event';
58
61
  handler?: HANDLER;
59
62
  }
@@ -80,7 +83,8 @@ type InPageFunctionDefinitionHandler<ARGS extends any[], RETURN, AS extends RpcA
80
83
  * An in-page channel function definition: the `defineRpcFunction` authoring
81
84
  * shape (`name`, `type`, Standard-Schema `args`/`returns`,
82
85
  * `jsonSerializable`, `handler`) narrowed to the browser: there is no
83
- * `dump`/`snapshot`/`cacheable`/`agent`. When `jsonSerializable` is `true`,
86
+ * `dump`/`snapshot`/`cacheable`. An optional `agent` exposes the function to
87
+ * DevFrame's browser-to-node agent bridge. When `jsonSerializable` is `true`,
84
88
  * payloads are strictly validated at the receiving endpoint and misshapen
85
89
  * values reject the call with a descriptive `InPageChannelError` instead of
86
90
  * a cryptic `DataCloneError` in the port. Event definitions may omit their
@@ -92,14 +96,18 @@ type InPageFunctionDefinition<NAME extends string, TYPE extends InPageFunctionTy
92
96
  *
93
97
  * @internal
94
98
  */
95
- interface InPageFunctionOptionBase {
99
+ interface InPageDefinitionOptionBase {
96
100
  /** Optional Standard Schema array validating the arguments. */
97
101
  args?: RpcArgsSchema;
98
102
  /** Optional Standard Schema validating the resolved return value. */
99
103
  returns?: RpcReturnSchema;
100
104
  jsonSerializable?: boolean;
101
105
  }
102
- interface InPageEventFunctionOption<F> extends InPageFunctionOptionBase {
106
+ interface InPageFunctionOptionBase extends InPageDefinitionOptionBase {
107
+ /** Expose this function through DevFrame's browser-to-node agent bridge. */
108
+ agent?: RpcFunctionAgentOptions;
109
+ }
110
+ interface InPageEventFunctionOption<F> extends InPageDefinitionOptionBase {
103
111
  type?: 'event';
104
112
  handler?: ProtocolHandler<F>;
105
113
  }
@@ -269,8 +277,6 @@ interface PageScriptChannel<P extends InPageChannelProtocol> {
269
277
  readonly events: Pick<EventEmitter<PageScriptChannelEvents<P>>, 'on' | 'once'>;
270
278
  /** Fan an event out to every connected panel. */
271
279
  emit: <K extends keyof PanelEvents<P> & string>(name: K, ...args: FnArgs<PanelEvents<P>[K]>) => void;
272
- /** @deprecated Use `emit()` instead. */
273
- callEvent: <K extends keyof PanelEvents<P> & string>(name: K, ...args: FnArgs<PanelEvents<P>[K]>) => void;
274
280
  /** Subscribe to an event emitted by a panel. Returns an unsubscribe function. */
275
281
  on: <K extends keyof PageScriptEvents<P> & string>(name: K, listener: (...args: FnArgs<PageScriptEvents<P>[K]>) => void) => () => void;
276
282
  /** Page-script-authoritative shared states, replayed to joining panels. */
@@ -314,8 +320,6 @@ interface PanelChannel<P extends InPageChannelProtocol> {
314
320
  * (up to `eventBufferLimit`) and flushed on connect.
315
321
  */
316
322
  emit: <K extends keyof PageScriptEvents<P> & string>(name: K, ...args: FnArgs<PageScriptEvents<P>[K]>) => void;
317
- /** @deprecated Use `emit()` instead. */
318
- callEvent: <K extends keyof PageScriptEvents<P> & string>(name: K, ...args: FnArgs<PageScriptEvents<P>[K]>) => void;
319
323
  /** Subscribe to an event emitted by the page script. Returns an unsubscribe function. */
320
324
  on: <K extends keyof PanelEvents<P> & string>(name: K, listener: (...args: FnArgs<PanelEvents<P>[K]>) => void) => () => void;
321
325
  /** Shared states mirrored from the page-script authority. */
@@ -1,15 +1,21 @@
1
- import { n as DEVFRAME_EVENTS, t as defineDiagnostics } from "../nostics-DD6gsDZA.mjs";
1
+ import { a as defineDiagnostics, i as createBirpc, n as argsToJsonSchema, o as DEVFRAME_EVENTS, r as resolveAgentSafety, t as toolInputToRpcArgs } from "../tool-input-BAQXvvqL.mjs";
2
2
  import { createEventEmitter } from "../utils/events.mjs";
3
3
  import { t as createSharedState } from "../shared-state-eQVYHNqA.mjs";
4
4
  import { nanoid } from "../utils/nanoid.mjs";
5
- import { createBirpc } from "birpc";
5
+ import { r as registerBrowserAgentTool } from "../browser-agent-Pu-FLk6I.mjs";
6
6
  //#region src/in-page-channel/diagnostics.ts
7
7
  const diagnostics = /* #__PURE__ */ defineDiagnostics({
8
8
  docsBase: "https://devfra.me/errors",
9
- codes: { DF0077: {
10
- why: (p) => `In-page channel function "${p.name}" is not registered on this endpoint.`,
11
- fix: "Declare the function in this endpoint's `functions` option."
12
- } }
9
+ codes: {
10
+ DF0077: {
11
+ why: (p) => `In-page channel function "${p.name}" is not registered on this endpoint.`,
12
+ fix: "Declare the function in this endpoint's `functions` option."
13
+ },
14
+ DF0080: {
15
+ why: (p) => `In-page channel function "${p.name}" has \`agent\` set but \`jsonSerializable\` is \`false\`; MCP requires JSON-serializable data.`,
16
+ fix: "Remove `jsonSerializable: false`, or remove `agent` to keep it channel-only."
17
+ }
18
+ }
13
19
  });
14
20
  //#endregion
15
21
  //#region src/in-page-channel/protocol.ts
@@ -173,17 +179,16 @@ function channelMethod(type, name) {
173
179
  return `devframe:in-page:${type === "event" ? "event" : "function"}:${name}`;
174
180
  }
175
181
  const FUNCTION_METHOD_PREFIX = channelMethod("function", "");
176
- /**
177
- * An endpoint's local function table, resolved by name when the remote side
178
- * calls in. Each handler is wrapped with the receive pipeline: deserialize
179
- * hook, `jsonSerializable` enforcement, Standard-Schema argument validation,
180
- * then serialize hook + `jsonSerializable` enforcement on the result.
181
- */
182
182
  function createLocalFunctionRegistry(codec) {
183
183
  const definitions = /* @__PURE__ */ new Map();
184
184
  const listeners = /* @__PURE__ */ new Map();
185
185
  return {
186
+ definitions,
186
187
  register(definition) {
188
+ if ("agent" in definition && definition.agent) {
189
+ if (definition.jsonSerializable === false) throw diagnostics.DF0080({ name: definition.name });
190
+ definition.jsonSerializable = true;
191
+ }
187
192
  definitions.set(channelMethod(definition.type, definition.name), definition);
188
193
  },
189
194
  registerInternal(method, handler) {
@@ -237,6 +242,27 @@ function resolveLocalHandler(name, registries) {
237
242
  throw diagnostics.DF0077({ name: name.slice(FUNCTION_METHOD_PREFIX.length) });
238
243
  };
239
244
  }
245
+ /** Register an endpoint's local agent functions for browser-backed transports. */
246
+ function registerInPageAgentTools(channelName, registry) {
247
+ const disposals = [];
248
+ for (const definition of registry.definitions.values()) {
249
+ if (definition.type === "event" || !("agent" in definition) || !definition.agent) continue;
250
+ const agent = definition.agent;
251
+ disposals.push(registerBrowserAgentTool({
252
+ id: `${channelName}:${definition.name}`,
253
+ title: agent.title ?? definition.name,
254
+ description: agent.description,
255
+ safety: resolveAgentSafety(definition.type, agent),
256
+ tags: agent.tags,
257
+ inputSchema: argsToJsonSchema(definition.args),
258
+ invoke: (args) => {
259
+ const positional = toolInputToRpcArgs(args, definition.args?.length);
260
+ return registry.resolve(channelMethod(definition.type, definition.name))(...positional);
261
+ }
262
+ }));
263
+ }
264
+ return () => disposals.forEach((dispose) => dispose());
265
+ }
240
266
  function wrapPostError(error) {
241
267
  if (error instanceof DOMException && error.name === "DataCloneError") return new InPageChannelError("not-cloneable", `a payload could not be structured-cloned across the in-page channel: ${error.message}. Strip non-cloneable values (functions, DOM nodes, framework reactivity proxies) before sending: declare the function \`jsonSerializable: true\` for a precise error, or provide a \`serialize\` hook.`, { cause: error });
242
268
  return error;
@@ -513,6 +539,7 @@ function createPageScriptChannel(options) {
513
539
  name: eventName,
514
540
  type: "event"
515
541
  });
542
+ const disposeAgentTools = registerInPageAgentTools(name, registry);
516
543
  const stateHost = createPageScriptStateHost(function* () {
517
544
  for (const peer of peers.values()) yield {
518
545
  subscribedStates: peer.subscribedStates,
@@ -632,13 +659,13 @@ function createPageScriptChannel(options) {
632
659
  once: events.once
633
660
  },
634
661
  emit,
635
- callEvent: emit,
636
662
  on: (fnName, listener) => registry.on(fnName, listener),
637
663
  sharedState: stateHost,
638
664
  addPanelPort: (port) => addPeer(port, `transport:${nanoid(8)}`),
639
665
  close: () => {
640
666
  if (closed) return;
641
667
  closed = true;
668
+ disposeAgentTools();
642
669
  win?.removeEventListener("message", onWindowMessage);
643
670
  for (const id of [...peers.keys()]) removePeer(id, {
644
671
  bye: true,
@@ -689,6 +716,7 @@ function connectPanelChannel(options) {
689
716
  name: eventName,
690
717
  type: "event"
691
718
  });
719
+ const disposeAgentTools = registerInPageAgentTools(name, registry);
692
720
  let status = "connecting";
693
721
  let attached;
694
722
  let pageScriptInfo;
@@ -867,12 +895,12 @@ function connectPanelChannel(options) {
867
895
  },
868
896
  call: (fnName, ...args) => enqueueCall(channelMethod("function", fnName), serializeArgs(codec, args)),
869
897
  emit: (fnName, ...args) => sendEvent(channelMethod("event", fnName), serializeArgs(codec, args)),
870
- callEvent: (fnName, ...args) => sendEvent(channelMethod("event", fnName), serializeArgs(codec, args)),
871
898
  on: (fnName, listener) => registry.on(fnName, listener),
872
899
  sharedState: stateHost,
873
900
  close: () => {
874
901
  if (status === "closed") return;
875
902
  setStatus("closed");
903
+ disposeAgentTools();
876
904
  stopTimers();
877
905
  win?.removeEventListener("message", onWindowMessage);
878
906
  attached?.dispose({