devframe 0.1.19 → 0.1.21

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 (78) hide show
  1. package/README.md +2 -2
  2. package/dist/{_shared-BcPXmcjq.mjs → _shared-iZy45oG3.mjs} +2 -2
  3. package/dist/adapters/build.d.mts +3 -3
  4. package/dist/adapters/build.mjs +12 -9
  5. package/dist/adapters/cli.d.mts +1 -1
  6. package/dist/adapters/cli.mjs +2 -2
  7. package/dist/adapters/dev.d.mts +2 -2
  8. package/dist/adapters/dev.mjs +1 -1
  9. package/dist/adapters/embedded.d.mts +2 -2
  10. package/dist/adapters/embedded.mjs +1 -1
  11. package/dist/adapters/mcp.d.mts +1 -1
  12. package/dist/adapters/mcp.mjs +6 -2
  13. package/dist/adapters/vite.d.mts +5 -4
  14. package/dist/adapters/vite.mjs +4 -3
  15. package/dist/client/index.d.mts +51 -145
  16. package/dist/client/index.mjs +1664 -2
  17. package/dist/constants.d.mts +12 -15
  18. package/dist/constants.mjs +12 -29
  19. package/dist/context-BJ4r2SmR.mjs +1051 -0
  20. package/dist/context-internal-Dx_NoSv1.mjs +199 -0
  21. package/dist/context-internal-saIAfNVw.d.mts +51 -0
  22. package/dist/{dev-Djy5hbgs.mjs → dev-CdAy400a.mjs} +7 -6
  23. package/dist/{devtool-CIqONpYU.d.mts → devtool-CNvLs2_Y.d.mts} +367 -530
  24. package/dist/diagnostics-DxPnRoXO.mjs +51 -0
  25. package/dist/host-h3-9jeHcltx.mjs +24 -0
  26. package/dist/{human-id-CHS0s28X.mjs → human-id-BLoGo_e5.mjs} +0 -1
  27. package/dist/{index-BwrLhNmz.d.mts → index-CuLRIMto.d.mts} +1 -1
  28. package/dist/index.d.mts +4 -5
  29. package/dist/index.mjs +1 -4
  30. package/dist/internal/index.d.mts +16 -0
  31. package/dist/internal/index.mjs +3 -0
  32. package/dist/node/index.d.mts +45 -140
  33. package/dist/node/index.mjs +7 -6
  34. package/dist/recipes/open-helpers.d.mts +1 -1
  35. package/dist/recipes/open-helpers.mjs +3 -1
  36. package/dist/rpc/index.d.mts +2 -2
  37. package/dist/rpc/index.mjs +2 -2
  38. package/dist/rpc/transports/ws-client.d.mts +1 -1
  39. package/dist/rpc/transports/ws-client.mjs +1 -1
  40. package/dist/rpc/transports/ws-server.d.mts +1 -1
  41. package/dist/rpc/transports/ws-server.mjs +1 -1
  42. package/dist/{rpc-D7LxIh8t.mjs → rpc-INbWfHoX.mjs} +1 -1
  43. package/dist/{serialization-BN2ZQEE9.mjs → serialization-DwKi05Pn.mjs} +1 -1
  44. package/dist/{server-CaUeMcAh.d.mts → server-BAqOajx_.d.mts} +1 -1
  45. package/dist/{server-DrBxa6ZV.mjs → server-CBsxXIH5.mjs} +27 -2
  46. package/dist/{static-dump-cyGfMmRf.mjs → static-dump-D5VH8Iqk.mjs} +1 -1
  47. package/dist/types/index.d.mts +4 -4
  48. package/dist/utils/events.d.mts +1 -1
  49. package/dist/utils/human-id.mjs +1 -1
  50. package/dist/utils/shared-state.d.mts +2 -2
  51. package/dist/utils/shared-state.mjs +1 -1
  52. package/dist/utils/state.d.mts +2 -1
  53. package/dist/utils/state.mjs +1 -1
  54. package/dist/utils/streaming-channel.d.mts +2 -0
  55. package/dist/utils/streaming-channel.mjs +255 -0
  56. package/dist/utils/when.d.mts +401 -2
  57. package/dist/{ws-client-DOYwYluO.d.mts → ws-client-CjPuPFbA.d.mts} +1 -1
  58. package/dist/{ws-server-DHMeNOY_.d.mts → ws-server-C7LnhOHi.d.mts} +13 -1
  59. package/package.json +10 -21
  60. package/skills/devframe/README.md +13 -0
  61. package/skills/devframe/SKILL.md +406 -0
  62. package/skills/devframe/templates/counter-devtool.ts +24 -0
  63. package/skills/devframe/templates/spa-devtool.ts +28 -0
  64. package/skills/devframe/templates/vite-client.ts +11 -0
  65. package/dist/adapters/kit.d.mts +0 -23
  66. package/dist/adapters/kit.mjs +0 -16
  67. package/dist/client-C6w_NshP.mjs +0 -1569
  68. package/dist/context-BsNZMCnr.mjs +0 -6827
  69. package/dist/helpers/nuxt/index.d.mts +0 -46
  70. package/dist/helpers/nuxt/index.mjs +0 -58
  71. package/dist/helpers/nuxt/runtime/plugin.client.d.mts +0 -8
  72. package/dist/helpers/nuxt/runtime/plugin.client.mjs +0 -12
  73. package/dist/host-h3-w3c0t8ZO.mjs +0 -18
  74. package/dist/immer-HjMAm3b6.mjs +0 -894
  75. package/dist/main-CuGOfqoX.mjs +0 -601
  76. package/dist/when-BAE663Hv.d.mts +0 -401
  77. package/dist/{open-JfacLHs0.mjs → open-Dede_w9r.mjs} +4 -4
  78. /package/dist/{types-gWbe-b2R.d.mts → types-C5OVe4AC.d.mts} +0 -0
@@ -0,0 +1,1051 @@
1
+ import { o as RpcFunctionsCollectorBase } from "./rpc-INbWfHoX.mjs";
2
+ import { s as diagnostics } from "./serialization-DwKi05Pn.mjs";
3
+ import { defineRpcFunction } from "./index.mjs";
4
+ import { n as logger, t as diagnostics$1 } from "./diagnostics-DxPnRoXO.mjs";
5
+ import { createEventEmitter } from "./utils/events.mjs";
6
+ import { createSharedState } from "./utils/shared-state.mjs";
7
+ import { createStreamReader, createStreamSink } from "./utils/streaming-channel.mjs";
8
+ import { consoleReporter, createLogger, defineDiagnostics } from "logs-sdk";
9
+ import c from "ansis";
10
+ import { ansiFormatter } from "logs-sdk/formatters/ansi";
11
+ import { isatty } from "node:tty";
12
+ import { formatWithOptions, inspect } from "node:util";
13
+ import { existsSync } from "node:fs";
14
+ //#region src/node/host-agent.ts
15
+ /**
16
+ * Framework-neutral host aggregating the agent-exposed surface of a
17
+ * devtool. Auto-discovers RPC functions with an `agent` field from
18
+ * `ctx.rpc.definitions`, and accepts plugin-registered tools /
19
+ * resources via `registerTool` / `registerResource`.
20
+ *
21
+ * @experimental
22
+ */
23
+ var DevToolsAgentHost = class {
24
+ events = createEventEmitter();
25
+ tools = /* @__PURE__ */ new Map();
26
+ resources = /* @__PURE__ */ new Map();
27
+ _rpcUnsubscribe;
28
+ constructor(context) {
29
+ this.context = context;
30
+ this._rpcUnsubscribe = context.rpc.onChanged(() => {
31
+ this.events.emit("agent:manifest:changed");
32
+ });
33
+ }
34
+ registerTool(input) {
35
+ this._validateToolId(input.id);
36
+ const tool = this._projectTool(input);
37
+ this.tools.set(tool.id, {
38
+ tool,
39
+ handler: input.handler
40
+ });
41
+ this.events.emit("agent:tool:registered", tool);
42
+ this.events.emit("agent:manifest:changed");
43
+ return { unregister: () => this.unregisterTool(tool.id) };
44
+ }
45
+ unregisterTool(id) {
46
+ const existed = this.tools.delete(id);
47
+ if (existed) {
48
+ this.events.emit("agent:tool:unregistered", id);
49
+ this.events.emit("agent:manifest:changed");
50
+ }
51
+ return existed;
52
+ }
53
+ registerResource(input) {
54
+ if (this.resources.has(input.id)) throw logger.DF0016({ id: input.id }).throw();
55
+ const resource = {
56
+ id: input.id,
57
+ name: input.name,
58
+ description: input.description,
59
+ mimeType: input.mimeType ?? "application/json",
60
+ uri: input.uri ?? `devframe://resource/${encodeURIComponent(input.id)}`
61
+ };
62
+ this.resources.set(resource.id, {
63
+ resource,
64
+ read: input.read
65
+ });
66
+ this.events.emit("agent:resource:registered", resource);
67
+ this.events.emit("agent:manifest:changed");
68
+ return { unregister: () => this.unregisterResource(resource.id) };
69
+ }
70
+ unregisterResource(id) {
71
+ const existed = this.resources.delete(id);
72
+ if (existed) {
73
+ this.events.emit("agent:resource:unregistered", id);
74
+ this.events.emit("agent:manifest:changed");
75
+ }
76
+ return existed;
77
+ }
78
+ list() {
79
+ const rpcTools = this._collectRpcTools();
80
+ const plainTools = Array.from(this.tools.values()).map((t) => t.tool);
81
+ const resources = Array.from(this.resources.values()).map((r) => r.resource);
82
+ return {
83
+ tools: [...rpcTools, ...plainTools],
84
+ resources
85
+ };
86
+ }
87
+ getTool(id) {
88
+ const plain = this.tools.get(id);
89
+ if (plain) return plain.tool;
90
+ return this._collectRpcTools().find((t) => t.id === id);
91
+ }
92
+ getResource(id) {
93
+ return this.resources.get(id)?.resource;
94
+ }
95
+ async invoke(id, args) {
96
+ const plain = this.tools.get(id);
97
+ if (plain?.handler) return await plain.handler(args);
98
+ const rpcDef = this._findRpcDefinition(id);
99
+ if (rpcDef) {
100
+ const positional = this._coercePositionalArgs(args, rpcDef);
101
+ return await this.context.rpc.invokeLocal(id, ...positional);
102
+ }
103
+ throw new Error(`[devframe/agent] tool "${id}" not found`);
104
+ }
105
+ async read(id) {
106
+ const entry = this.resources.get(id);
107
+ if (!entry) throw new Error(`[devframe/agent] resource "${id}" not found`);
108
+ return await entry.read();
109
+ }
110
+ /** @internal */
111
+ _dispose() {
112
+ this._rpcUnsubscribe?.();
113
+ this._rpcUnsubscribe = void 0;
114
+ }
115
+ _validateToolId(id) {
116
+ if (this.tools.has(id)) throw logger.DF0015({ id }).throw();
117
+ if (this.context.rpc.definitions.get(id)?.agent) throw logger.DF0015({ id }).throw();
118
+ }
119
+ _projectTool(input) {
120
+ if (!input.description || typeof input.description !== "string") throw logger.DF0014({ name: input.id }).throw();
121
+ return {
122
+ id: input.id,
123
+ kind: "tool",
124
+ title: input.title ?? input.id,
125
+ description: input.description,
126
+ safety: input.safety ?? "action",
127
+ tags: input.tags,
128
+ inputSchema: input.inputSchema,
129
+ outputSchema: input.outputSchema,
130
+ examples: input.examples
131
+ };
132
+ }
133
+ _collectRpcTools() {
134
+ const out = [];
135
+ for (const [name, def] of this.context.rpc.definitions) {
136
+ const agent = def.agent;
137
+ if (!agent) continue;
138
+ if (!agent.description || typeof agent.description !== "string") throw logger.DF0014({ name }).throw();
139
+ const type = def.type ?? "query";
140
+ const safety = agent.safety ?? inferSafety(type);
141
+ out.push({
142
+ id: name,
143
+ kind: "rpc",
144
+ title: agent.title ?? name,
145
+ description: agent.description,
146
+ safety,
147
+ tags: agent.tags,
148
+ rpcName: name,
149
+ examples: agent.examples
150
+ });
151
+ }
152
+ return out;
153
+ }
154
+ _findRpcDefinition(id) {
155
+ const def = this.context.rpc.definitions.get(id);
156
+ if (def?.agent) return def;
157
+ }
158
+ _coercePositionalArgs(args, def) {
159
+ if (Array.isArray(args)) return args;
160
+ if (args === void 0 || args === null) return [];
161
+ if (args && typeof args === "object") {
162
+ const obj = args;
163
+ const schemas = def.args;
164
+ if (schemas && schemas.length) return schemas.map((_, i) => obj[`arg${i}`]);
165
+ if (hasPositionalKeys(obj)) {
166
+ const out = [];
167
+ let i = 0;
168
+ while (`arg${i}` in obj) {
169
+ out.push(obj[`arg${i}`]);
170
+ i++;
171
+ }
172
+ return out;
173
+ }
174
+ }
175
+ return [args];
176
+ }
177
+ };
178
+ function inferSafety(type) {
179
+ if (type === "static" || type === "query") return "read";
180
+ return "action";
181
+ }
182
+ function hasPositionalKeys(obj) {
183
+ return "arg0" in obj;
184
+ }
185
+ //#endregion
186
+ //#region src/node/host-diagnostics.ts
187
+ var DevToolsDiagnosticsHost = class {
188
+ _definitions = [];
189
+ _logger;
190
+ defineDiagnostics = defineDiagnostics;
191
+ createLogger = createLogger;
192
+ constructor(context, initialDefinitions = []) {
193
+ this.context = context;
194
+ this._definitions = [...initialDefinitions];
195
+ this._rebuild();
196
+ }
197
+ get logger() {
198
+ return this._logger;
199
+ }
200
+ register(definitions) {
201
+ this._definitions.push(definitions);
202
+ this._rebuild();
203
+ }
204
+ _rebuild() {
205
+ this._logger = createLogger({
206
+ diagnostics: this._definitions,
207
+ formatter: ansiFormatter(c),
208
+ reporters: consoleReporter
209
+ });
210
+ }
211
+ };
212
+ //#endregion
213
+ //#region ../../../node_modules/.pnpm/obug@2.1.1/node_modules/obug/dist/core.js
214
+ function coerce(value) {
215
+ if (value instanceof Error) return value.stack || value.message;
216
+ return value;
217
+ }
218
+ function selectColor(colors, namespace) {
219
+ let hash = 0;
220
+ for (let i = 0; i < namespace.length; i++) {
221
+ hash = (hash << 5) - hash + namespace.charCodeAt(i);
222
+ hash |= 0;
223
+ }
224
+ return colors[Math.abs(hash) % colors.length];
225
+ }
226
+ function matchesTemplate(search, template) {
227
+ let searchIndex = 0;
228
+ let templateIndex = 0;
229
+ let starIndex = -1;
230
+ let matchIndex = 0;
231
+ while (searchIndex < search.length) if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === "*")) if (template[templateIndex] === "*") {
232
+ starIndex = templateIndex;
233
+ matchIndex = searchIndex;
234
+ templateIndex++;
235
+ } else {
236
+ searchIndex++;
237
+ templateIndex++;
238
+ }
239
+ else if (starIndex !== -1) {
240
+ templateIndex = starIndex + 1;
241
+ matchIndex++;
242
+ searchIndex = matchIndex;
243
+ } else return false;
244
+ while (templateIndex < template.length && template[templateIndex] === "*") templateIndex++;
245
+ return templateIndex === template.length;
246
+ }
247
+ function humanize(value) {
248
+ if (value >= 1e3) return `${(value / 1e3).toFixed(1)}s`;
249
+ return `${value}ms`;
250
+ }
251
+ let globalNamespaces = "";
252
+ function createDebug$1(namespace, options) {
253
+ let prevTime;
254
+ let enableOverride;
255
+ let namespacesCache;
256
+ let enabledCache;
257
+ const debug = (...args) => {
258
+ if (!debug.enabled) return;
259
+ const curr = Date.now();
260
+ const diff = curr - (prevTime || curr);
261
+ prevTime = curr;
262
+ args[0] = coerce(args[0]);
263
+ if (typeof args[0] !== "string") args.unshift("%O");
264
+ let index = 0;
265
+ args[0] = args[0].replace(/%([a-z%])/gi, (match, format) => {
266
+ if (match === "%%") return "%";
267
+ index++;
268
+ const formatter = options.formatters[format];
269
+ if (typeof formatter === "function") {
270
+ const value = args[index];
271
+ match = formatter.call(debug, value);
272
+ args.splice(index, 1);
273
+ index--;
274
+ }
275
+ return match;
276
+ });
277
+ options.formatArgs.call(debug, diff, args);
278
+ debug.log(...args);
279
+ };
280
+ debug.extend = function(namespace$1, delimiter = ":") {
281
+ return createDebug$1(this.namespace + delimiter + namespace$1, {
282
+ useColors: this.useColors,
283
+ color: this.color,
284
+ formatArgs: this.formatArgs,
285
+ formatters: this.formatters,
286
+ inspectOpts: this.inspectOpts,
287
+ log: this.log,
288
+ humanize: this.humanize
289
+ });
290
+ };
291
+ Object.assign(debug, options);
292
+ debug.namespace = namespace;
293
+ Object.defineProperty(debug, "enabled", {
294
+ enumerable: true,
295
+ configurable: false,
296
+ get: () => {
297
+ if (enableOverride != null) return enableOverride;
298
+ if (namespacesCache !== globalNamespaces) {
299
+ namespacesCache = globalNamespaces;
300
+ enabledCache = enabled(namespace);
301
+ }
302
+ return enabledCache;
303
+ },
304
+ set: (v) => {
305
+ enableOverride = v;
306
+ }
307
+ });
308
+ return debug;
309
+ }
310
+ let names = [];
311
+ let skips = [];
312
+ function enable(namespaces$1) {
313
+ globalNamespaces = namespaces$1;
314
+ names = [];
315
+ skips = [];
316
+ const split = globalNamespaces.trim().replace(/\s+/g, ",").split(",").filter(Boolean);
317
+ for (const ns of split) if (ns[0] === "-") skips.push(ns.slice(1));
318
+ else names.push(ns);
319
+ }
320
+ function enabled(name) {
321
+ for (const skip of skips) if (matchesTemplate(name, skip)) return false;
322
+ for (const ns of names) if (matchesTemplate(name, ns)) return true;
323
+ return false;
324
+ }
325
+ //#endregion
326
+ //#region ../../../node_modules/.pnpm/obug@2.1.1/node_modules/obug/dist/node.js
327
+ const colors = process.stderr.getColorDepth && process.stderr.getColorDepth() > 2 ? [
328
+ 20,
329
+ 21,
330
+ 26,
331
+ 27,
332
+ 32,
333
+ 33,
334
+ 38,
335
+ 39,
336
+ 40,
337
+ 41,
338
+ 42,
339
+ 43,
340
+ 44,
341
+ 45,
342
+ 56,
343
+ 57,
344
+ 62,
345
+ 63,
346
+ 68,
347
+ 69,
348
+ 74,
349
+ 75,
350
+ 76,
351
+ 77,
352
+ 78,
353
+ 79,
354
+ 80,
355
+ 81,
356
+ 92,
357
+ 93,
358
+ 98,
359
+ 99,
360
+ 112,
361
+ 113,
362
+ 128,
363
+ 129,
364
+ 134,
365
+ 135,
366
+ 148,
367
+ 149,
368
+ 160,
369
+ 161,
370
+ 162,
371
+ 163,
372
+ 164,
373
+ 165,
374
+ 166,
375
+ 167,
376
+ 168,
377
+ 169,
378
+ 170,
379
+ 171,
380
+ 172,
381
+ 173,
382
+ 178,
383
+ 179,
384
+ 184,
385
+ 185,
386
+ 196,
387
+ 197,
388
+ 198,
389
+ 199,
390
+ 200,
391
+ 201,
392
+ 202,
393
+ 203,
394
+ 204,
395
+ 205,
396
+ 206,
397
+ 207,
398
+ 208,
399
+ 209,
400
+ 214,
401
+ 215,
402
+ 220,
403
+ 221
404
+ ] : [
405
+ 6,
406
+ 2,
407
+ 3,
408
+ 4,
409
+ 5,
410
+ 1
411
+ ];
412
+ const inspectOpts = Object.keys(process.env).filter((key) => /^debug_/i.test(key)).reduce((obj, key) => {
413
+ const prop = key.slice(6).toLowerCase().replace(/_([a-z])/g, (_, k) => k.toUpperCase());
414
+ let value = process.env[key];
415
+ const lowerCase = typeof value === "string" && value.toLowerCase();
416
+ if (value === "null") value = null;
417
+ else if (lowerCase === "yes" || lowerCase === "on" || lowerCase === "true" || lowerCase === "enabled") value = true;
418
+ else if (lowerCase === "no" || lowerCase === "off" || lowerCase === "false" || lowerCase === "disabled") value = false;
419
+ else value = Number(value);
420
+ obj[prop] = value;
421
+ return obj;
422
+ }, {});
423
+ function useColors() {
424
+ return "colors" in inspectOpts ? Boolean(inspectOpts.colors) : isatty(process.stderr.fd);
425
+ }
426
+ function getDate() {
427
+ if (inspectOpts.hideDate) return "";
428
+ return `${(/* @__PURE__ */ new Date()).toISOString()} `;
429
+ }
430
+ function formatArgs(diff, args) {
431
+ const { namespace: name, useColors: useColors$1 } = this;
432
+ if (useColors$1) {
433
+ const c = this.color;
434
+ const colorCode = `\u001B[3${c < 8 ? c : `8;5;${c}`}`;
435
+ const prefix = ` ${colorCode};1m${name} \u001B[0m`;
436
+ args[0] = prefix + args[0].split("\n").join(`\n${prefix}`);
437
+ args.push(`${colorCode}m+${this.humanize(diff)}\u001B[0m`);
438
+ } else args[0] = `${getDate()}${name} ${args[0]}`;
439
+ }
440
+ function log(...args) {
441
+ process.stderr.write(`${formatWithOptions(this.inspectOpts, ...args)}\n`);
442
+ }
443
+ const defaultOptions = {
444
+ useColors: useColors(),
445
+ formatArgs,
446
+ formatters: {
447
+ o(v) {
448
+ this.inspectOpts.colors = this.useColors;
449
+ return inspect(v, this.inspectOpts).split("\n").map((str) => str.trim()).join(" ");
450
+ },
451
+ O(v) {
452
+ this.inspectOpts.colors = this.useColors;
453
+ return inspect(v, this.inspectOpts);
454
+ }
455
+ },
456
+ inspectOpts,
457
+ log,
458
+ humanize
459
+ };
460
+ function createDebug(namespace, options) {
461
+ var _ref;
462
+ const color = (_ref = options && options.color) !== null && _ref !== void 0 ? _ref : selectColor(colors, namespace);
463
+ return createDebug$1(namespace, Object.assign(defaultOptions, { color }, options));
464
+ }
465
+ enable(process.env.DEBUG || "");
466
+ //#endregion
467
+ //#region src/node/rpc-shared-state.ts
468
+ const debug$1 = createDebug("vite:devtools:rpc:state:changed");
469
+ const debugSubscribe = createDebug("vite:devtools:rpc:state:subscribe");
470
+ function createRpcSharedStateServerHost(rpc) {
471
+ const sharedState = /* @__PURE__ */ new Map();
472
+ const keyAddedListeners = /* @__PURE__ */ new Set();
473
+ function registerSharedState(key, state) {
474
+ const offs = [];
475
+ offs.push(state.on("updated", (fullState, patches, syncId) => {
476
+ if (patches) {
477
+ debug$1("patch", {
478
+ key,
479
+ syncId
480
+ });
481
+ rpc.broadcast({
482
+ method: "devframe:rpc:client-state:patch",
483
+ args: [
484
+ key,
485
+ patches,
486
+ syncId
487
+ ],
488
+ filter: (client) => client.$meta.subscribedStates.has(key)
489
+ });
490
+ } else {
491
+ debug$1("updated", {
492
+ key,
493
+ syncId
494
+ });
495
+ rpc.broadcast({
496
+ method: "devframe:rpc:client-state:updated",
497
+ args: [
498
+ key,
499
+ fullState,
500
+ syncId
501
+ ],
502
+ filter: (client) => client.$meta.subscribedStates.has(key)
503
+ });
504
+ }
505
+ }));
506
+ return () => {
507
+ for (const off of offs) off();
508
+ };
509
+ }
510
+ const host = {
511
+ get: async (key, options) => {
512
+ if (sharedState.has(key)) return sharedState.get(key);
513
+ if (options?.initialValue === void 0 && options?.sharedState === void 0) throw logger.DF0013({ key }).throw();
514
+ debug$1("new-state", key);
515
+ const state = options.sharedState ?? createSharedState({
516
+ initialValue: options.initialValue,
517
+ enablePatches: false
518
+ });
519
+ registerSharedState(key, state);
520
+ sharedState.set(key, state);
521
+ for (const fn of keyAddedListeners) fn(key);
522
+ return state;
523
+ },
524
+ keys() {
525
+ return Array.from(sharedState.keys());
526
+ },
527
+ onKeyAdded(fn) {
528
+ keyAddedListeners.add(fn);
529
+ return () => {
530
+ keyAddedListeners.delete(fn);
531
+ };
532
+ }
533
+ };
534
+ rpc.register({
535
+ name: "devframe:rpc:server-state:subscribe",
536
+ type: "event",
537
+ handler(key) {
538
+ const session = rpc.getCurrentRpcSession();
539
+ if (!session) return;
540
+ debugSubscribe("subscribe", {
541
+ key,
542
+ session: session.meta.id
543
+ });
544
+ session.meta.subscribedStates.add(key);
545
+ }
546
+ });
547
+ rpc.register({
548
+ name: "devframe:rpc:server-state:get",
549
+ type: "query",
550
+ handler: async (key) => {
551
+ if (!sharedState.has(key)) return void 0;
552
+ return (await host.get(key)).value();
553
+ },
554
+ dump: () => ({ inputs: host.keys().map((key) => [key]) })
555
+ });
556
+ rpc.register({
557
+ name: "devframe:rpc:server-state:set",
558
+ type: "query",
559
+ handler: async (key, value, syncId) => {
560
+ (await host.get(key, { initialValue: value })).mutate(() => value, syncId);
561
+ }
562
+ });
563
+ rpc.register({
564
+ name: "devframe:rpc:server-state:patch",
565
+ type: "query",
566
+ handler: async (key, patches, syncId) => {
567
+ if (!sharedState.has(key)) return;
568
+ (await host.get(key)).patch(patches, syncId);
569
+ }
570
+ });
571
+ return host;
572
+ }
573
+ //#endregion
574
+ //#region src/node/rpc-streaming.ts
575
+ const debug = createDebug("vite:devtools:rpc:streaming");
576
+ const STREAM_KEY_SEPARATOR = "";
577
+ function streamKey(channel, id) {
578
+ return `${channel}${STREAM_KEY_SEPARATOR}${id}`;
579
+ }
580
+ /**
581
+ * Build the server-side streaming host. Mirrors the layout of
582
+ * `createRpcSharedStateServerHost` — registers a fixed set of internal
583
+ * RPC methods (`subscribe` / `unsubscribe` / `cancel`) once, then per-channel
584
+ * state lives in a `Map<channelName, ChannelState>`.
585
+ */
586
+ function createRpcStreamingServerHost(rpc) {
587
+ const channels = /* @__PURE__ */ new Map();
588
+ function findStream(channelName, id) {
589
+ return channels.get(channelName)?.streams.get(id);
590
+ }
591
+ function freeStreamNow(state, id) {
592
+ const record = state.streams.get(id);
593
+ if (!record) return;
594
+ if (record.retentionTimer) {
595
+ clearTimeout(record.retentionTimer);
596
+ record.retentionTimer = void 0;
597
+ }
598
+ for (const off of record.unbinders) off();
599
+ state.streams.delete(id);
600
+ debug("freed", state.name, id);
601
+ }
602
+ function maybeFreeStream(state, id) {
603
+ const record = state.streams.get(id);
604
+ if (!record) return;
605
+ if (!record.sink.closed || record.subscribers.size > 0) return;
606
+ const retention = state.options.closedStreamRetention;
607
+ if (retention <= 0) {
608
+ freeStreamNow(state, id);
609
+ return;
610
+ }
611
+ if (record.retentionTimer) return;
612
+ record.retentionTimer = setTimeout(freeStreamNow, retention, state, id);
613
+ }
614
+ function cancelRetention(record) {
615
+ if (record.retentionTimer) {
616
+ clearTimeout(record.retentionTimer);
617
+ record.retentionTimer = void 0;
618
+ }
619
+ }
620
+ rpc.register({
621
+ name: "devframe:streaming:subscribe",
622
+ type: "event",
623
+ handler(channelName, id, opts) {
624
+ const state = channels.get(channelName);
625
+ if (!state) {
626
+ logger.DF0030({
627
+ channel: channelName,
628
+ id
629
+ }).log();
630
+ return;
631
+ }
632
+ const record = state.streams.get(id);
633
+ if (!record) {
634
+ logger.DF0030({
635
+ channel: channelName,
636
+ id
637
+ }).log();
638
+ return;
639
+ }
640
+ const session = rpc.getCurrentRpcSession();
641
+ if (!session) return;
642
+ const key = streamKey(channelName, id);
643
+ session.meta.subscribedStreams ??= /* @__PURE__ */ new Set();
644
+ session.meta.subscribedStreams.add(key);
645
+ record.subscribers.add(session.meta);
646
+ cancelRetention(record);
647
+ const afterSeq = opts?.afterSeq ?? 0;
648
+ for (const buffered of record.sink.buffer) if (buffered.seq > afterSeq) rpc.broadcast({
649
+ method: "devframe:streaming:chunk",
650
+ args: [
651
+ channelName,
652
+ id,
653
+ buffered.seq,
654
+ buffered.chunk
655
+ ],
656
+ event: true,
657
+ optional: true,
658
+ filter: (client) => client.$meta === session.meta
659
+ });
660
+ if (record.sink.closed) rpc.broadcast({
661
+ method: "devframe:streaming:end",
662
+ args: [
663
+ channelName,
664
+ id,
665
+ void 0
666
+ ],
667
+ event: true,
668
+ optional: true,
669
+ filter: (client) => client.$meta === session.meta
670
+ });
671
+ }
672
+ });
673
+ rpc.register({
674
+ name: "devframe:streaming:unsubscribe",
675
+ type: "event",
676
+ handler(channelName, id) {
677
+ const state = channels.get(channelName);
678
+ const record = state?.streams.get(id);
679
+ const session = rpc.getCurrentRpcSession();
680
+ if (!session) return;
681
+ session.meta.subscribedStreams?.delete(streamKey(channelName, id));
682
+ if (state && record) {
683
+ record.subscribers.delete(session.meta);
684
+ maybeFreeStream(state, id);
685
+ }
686
+ }
687
+ });
688
+ rpc.register({
689
+ name: "devframe:streaming:cancel",
690
+ type: "event",
691
+ handler(channelName, id) {
692
+ const record = findStream(channelName, id);
693
+ if (!record) return;
694
+ const session = rpc.getCurrentRpcSession();
695
+ if (!session) return;
696
+ record.subscribers.delete(session.meta);
697
+ session.meta.subscribedStreams?.delete(streamKey(channelName, id));
698
+ if (record.subscribers.size === 0) record.sink.abort("cancelled by client");
699
+ }
700
+ });
701
+ rpc.register({
702
+ name: "devframe:streaming:upload-chunk",
703
+ type: "event",
704
+ handler(channelName, id, seq, chunk) {
705
+ const record = channels.get(channelName)?.inbound.get(id);
706
+ if (!record) {
707
+ logger.DF0030({
708
+ channel: channelName,
709
+ id
710
+ }).log();
711
+ return;
712
+ }
713
+ if (!record.uploaderMeta) {
714
+ const session = rpc.getCurrentRpcSession();
715
+ if (session) {
716
+ record.uploaderMeta = session.meta;
717
+ session.meta.uploadingStreams ??= /* @__PURE__ */ new Set();
718
+ session.meta.uploadingStreams.add(streamKey(channelName, id));
719
+ }
720
+ }
721
+ record.reader._push(seq, chunk);
722
+ }
723
+ });
724
+ rpc.register({
725
+ name: "devframe:streaming:upload-end",
726
+ type: "event",
727
+ handler(channelName, id, error) {
728
+ const state = channels.get(channelName);
729
+ const record = state?.inbound.get(id);
730
+ if (!record) return;
731
+ record.reader._end(error);
732
+ if (record.uploaderMeta) record.uploaderMeta.uploadingStreams?.delete(streamKey(channelName, id));
733
+ state?.inbound.delete(id);
734
+ }
735
+ });
736
+ function createChannel(name, opts = {}) {
737
+ if (channels.has(name)) throw logger.DF0032({ channel: name }).throw();
738
+ const replayWindow = opts.replayWindow ?? 0;
739
+ const state = {
740
+ name,
741
+ options: {
742
+ replayWindow,
743
+ closedStreamRetention: opts.closedStreamRetention ?? (replayWindow > 0 ? 3e4 : 0)
744
+ },
745
+ streams: /* @__PURE__ */ new Map(),
746
+ inbound: /* @__PURE__ */ new Map()
747
+ };
748
+ channels.set(name, state);
749
+ function start(startOpts = {}) {
750
+ const sink = createStreamSink({
751
+ id: startOpts.id,
752
+ replayWindow: state.options.replayWindow
753
+ });
754
+ const record = {
755
+ sink,
756
+ subscribers: /* @__PURE__ */ new Set(),
757
+ unbinders: []
758
+ };
759
+ state.streams.set(sink.id, record);
760
+ record.unbinders.push(sink.events.on("chunk", (seq, chunk) => {
761
+ rpc.broadcast({
762
+ method: "devframe:streaming:chunk",
763
+ args: [
764
+ name,
765
+ sink.id,
766
+ seq,
767
+ chunk
768
+ ],
769
+ event: true,
770
+ optional: true,
771
+ filter: (client) => record.subscribers.has(client.$meta)
772
+ });
773
+ }));
774
+ record.unbinders.push(sink.events.on("end", (error) => {
775
+ rpc.broadcast({
776
+ method: "devframe:streaming:end",
777
+ args: [
778
+ name,
779
+ sink.id,
780
+ error
781
+ ],
782
+ event: true,
783
+ optional: true,
784
+ filter: (client) => record.subscribers.has(client.$meta)
785
+ });
786
+ maybeFreeStream(state, sink.id);
787
+ }));
788
+ return sink;
789
+ }
790
+ async function pipeFrom(readable, startOpts = {}) {
791
+ const sink = start(startOpts);
792
+ readable.pipeTo(sink.writable, { signal: sink.signal }).catch(() => {});
793
+ return sink;
794
+ }
795
+ function get(id) {
796
+ return state.streams.get(id)?.sink;
797
+ }
798
+ function ids() {
799
+ return Array.from(state.streams.keys());
800
+ }
801
+ function openInbound(inboundOpts = {}) {
802
+ let inboundRecord;
803
+ const reader = createStreamReader({
804
+ id: inboundOpts.id,
805
+ onCancel() {
806
+ const targetMeta = inboundRecord?.uploaderMeta;
807
+ if (!targetMeta) return;
808
+ rpc.broadcast({
809
+ method: "devframe:streaming:upload-cancel",
810
+ args: [name, reader.id],
811
+ event: true,
812
+ optional: true,
813
+ filter: (client) => client.$meta === targetMeta
814
+ });
815
+ }
816
+ });
817
+ inboundRecord = { reader };
818
+ state.inbound.set(reader.id, inboundRecord);
819
+ debug("opened-inbound", name, reader.id);
820
+ return reader;
821
+ }
822
+ return {
823
+ name,
824
+ start,
825
+ pipeFrom,
826
+ get,
827
+ ids,
828
+ openInbound
829
+ };
830
+ }
831
+ function parseKey(key) {
832
+ const sepIdx = key.indexOf(STREAM_KEY_SEPARATOR);
833
+ if (sepIdx < 0) return void 0;
834
+ return {
835
+ channelName: key.slice(0, sepIdx),
836
+ id: key.slice(sepIdx + 1)
837
+ };
838
+ }
839
+ return {
840
+ create: createChannel,
841
+ _onSessionDisconnected(meta) {
842
+ if (meta.subscribedStreams) {
843
+ for (const key of meta.subscribedStreams) {
844
+ const parsed = parseKey(key);
845
+ if (!parsed) continue;
846
+ const state = channels.get(parsed.channelName);
847
+ const record = state?.streams.get(parsed.id);
848
+ if (!state || !record) continue;
849
+ record.subscribers.delete(meta);
850
+ if (record.subscribers.size === 0 && !record.sink.closed) record.sink.abort("all subscribers disconnected");
851
+ maybeFreeStream(state, parsed.id);
852
+ }
853
+ meta.subscribedStreams.clear();
854
+ }
855
+ if (meta.uploadingStreams) {
856
+ for (const key of meta.uploadingStreams) {
857
+ const parsed = parseKey(key);
858
+ if (!parsed) continue;
859
+ const state = channels.get(parsed.channelName);
860
+ const record = state?.inbound.get(parsed.id);
861
+ if (!state || !record) continue;
862
+ record.reader._end({
863
+ name: "UploadDisconnected",
864
+ message: "Uploader disconnected before completing the stream"
865
+ });
866
+ state.inbound.delete(parsed.id);
867
+ }
868
+ meta.uploadingStreams.clear();
869
+ }
870
+ }
871
+ };
872
+ }
873
+ //#endregion
874
+ //#region src/node/host-functions.ts
875
+ const debugBroadcast = createDebug("vite:devtools:rpc:broadcast");
876
+ var RpcFunctionsHost = class extends RpcFunctionsCollectorBase {
877
+ /**
878
+ * @internal
879
+ */
880
+ _rpcGroup = void 0;
881
+ _asyncStorage = void 0;
882
+ constructor(context) {
883
+ super(context);
884
+ this.sharedState = createRpcSharedStateServerHost(this);
885
+ this.streaming = createRpcStreamingServerHost(this);
886
+ }
887
+ sharedState;
888
+ streaming;
889
+ /**
890
+ * Adapters call this from their WS `onDisconnected` hook so downstream
891
+ * hosts (streaming, …) can free per-session state. Public-ish because
892
+ * tests / custom adapters may want to mirror it.
893
+ *
894
+ * @internal
895
+ */
896
+ _emitSessionDisconnected(meta) {
897
+ this.streaming._onSessionDisconnected(meta);
898
+ }
899
+ async invokeLocal(method, ...args) {
900
+ if (!this.definitions.has(method)) throw logger.DF0006({ name: String(method) }).throw();
901
+ const handler = await this.getHandler(method);
902
+ return await Promise.resolve(handler(...args));
903
+ }
904
+ async broadcast(options) {
905
+ if (!this._rpcGroup) return;
906
+ debugBroadcast(JSON.stringify(options.method));
907
+ await Promise.allSettled(this._rpcGroup.clients.map((client) => {
908
+ if (options.filter?.(client) === false) return void 0;
909
+ return client.$callRaw({
910
+ optional: true,
911
+ event: true,
912
+ ...options
913
+ });
914
+ }));
915
+ }
916
+ getCurrentRpcSession() {
917
+ if (!this._asyncStorage) throw logger.DF0007().throw();
918
+ return this._asyncStorage.getStore();
919
+ }
920
+ };
921
+ //#endregion
922
+ //#region src/node/host-views.ts
923
+ var DevToolsViewHost = class {
924
+ /**
925
+ * @internal
926
+ */
927
+ buildStaticDirs = [];
928
+ constructor(context) {
929
+ this.context = context;
930
+ }
931
+ hostStatic(baseUrl, distDir) {
932
+ if (!existsSync(distDir)) throw logger.DF0008({ distDir }).throw();
933
+ this.buildStaticDirs.push({
934
+ baseUrl,
935
+ distDir
936
+ });
937
+ this.context.host.mountStatic(baseUrl, distDir);
938
+ }
939
+ };
940
+ //#endregion
941
+ //#region src/node/rpc/agent-invoke-tool.ts
942
+ const agentInvokeTool = defineRpcFunction({
943
+ name: "devframe:agent:invoke-tool",
944
+ type: "action",
945
+ setup: (ctx) => {
946
+ return { async handler(id, args) {
947
+ return await ctx.agent.invoke(id, args);
948
+ } };
949
+ }
950
+ });
951
+ //#endregion
952
+ //#region src/node/rpc/agent-list-resources.ts
953
+ const agentListResources = defineRpcFunction({
954
+ name: "devframe:agent:list-resources",
955
+ type: "query",
956
+ jsonSerializable: true,
957
+ setup: (ctx) => {
958
+ return { async handler() {
959
+ return ctx.agent.list().resources;
960
+ } };
961
+ }
962
+ });
963
+ //#endregion
964
+ //#region src/node/rpc/index.ts
965
+ /**
966
+ * Built-in agent introspection RPC functions. Registered automatically
967
+ * by `createHostContext`. Not themselves agent-exposed (no `agent`
968
+ * field) — they power the MCP adapter and any future agent CLI.
969
+ *
970
+ * @experimental
971
+ */
972
+ const BUILTIN_AGENT_RPC = [
973
+ defineRpcFunction({
974
+ name: "devframe:agent:list-tools",
975
+ type: "query",
976
+ jsonSerializable: true,
977
+ setup: (ctx) => {
978
+ return { async handler() {
979
+ return ctx.agent.list().tools;
980
+ } };
981
+ }
982
+ }),
983
+ agentInvokeTool,
984
+ agentListResources,
985
+ defineRpcFunction({
986
+ name: "devframe:agent:read-resource",
987
+ type: "query",
988
+ jsonSerializable: true,
989
+ setup: (ctx) => {
990
+ return { async handler(id) {
991
+ return await ctx.agent.read(id);
992
+ } };
993
+ }
994
+ })
995
+ ];
996
+ //#endregion
997
+ //#region src/node/context.ts
998
+ /**
999
+ * Framework-neutral core of the DevTools node context. Wires the RPC
1000
+ * host, view (HTTP file-serving) host, diagnostics, and agent
1001
+ * subsystems plus the JSON-render factory. Hub-level subsystems
1002
+ * (`docks`, `terminals`, `messages`, `commands`) are owned by
1003
+ * `@vitejs/devtools-kit` — its `createKitContext` wraps this and
1004
+ * attaches them when the devtool is mounted into a multi-integration
1005
+ * hub.
1006
+ */
1007
+ async function createHostContext(options) {
1008
+ const { cwd, workspaceRoot = cwd, mode, host, builtinRpcDeclarations = [] } = options;
1009
+ const context = {
1010
+ cwd,
1011
+ workspaceRoot,
1012
+ mode,
1013
+ host,
1014
+ rpc: void 0,
1015
+ views: void 0,
1016
+ diagnostics: void 0,
1017
+ agent: void 0,
1018
+ createJsonRenderer: void 0
1019
+ };
1020
+ const rpcHost = new RpcFunctionsHost(context);
1021
+ const viewsHost = new DevToolsViewHost(context);
1022
+ const diagnosticsHost = new DevToolsDiagnosticsHost(context, [diagnostics$1, diagnostics]);
1023
+ context.rpc = rpcHost;
1024
+ context.views = viewsHost;
1025
+ context.diagnostics = diagnosticsHost;
1026
+ context.agent = new DevToolsAgentHost(context);
1027
+ let jrCounter = 0;
1028
+ context.createJsonRenderer = (initialSpec) => {
1029
+ const stateKey = `devframe:json-render:${jrCounter++}`;
1030
+ const statePromise = rpcHost.sharedState.get(stateKey, { initialValue: initialSpec });
1031
+ return {
1032
+ _stateKey: stateKey,
1033
+ async updateSpec(spec) {
1034
+ (await statePromise).mutate(() => spec);
1035
+ },
1036
+ async updateState(newState) {
1037
+ (await statePromise).mutate((draft) => {
1038
+ draft.state = {
1039
+ ...draft.state,
1040
+ ...newState
1041
+ };
1042
+ });
1043
+ }
1044
+ };
1045
+ };
1046
+ for (const fn of BUILTIN_AGENT_RPC) rpcHost.register(fn);
1047
+ for (const fn of builtinRpcDeclarations) rpcHost.register(fn);
1048
+ return context;
1049
+ }
1050
+ //#endregion
1051
+ export { createRpcSharedStateServerHost as a, createRpcStreamingServerHost as i, DevToolsViewHost as n, DevToolsDiagnosticsHost as o, RpcFunctionsHost as r, DevToolsAgentHost as s, createHostContext as t };