devframe 0.1.20 → 0.1.22

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