devframe 0.7.16 → 0.8.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 (80) hide show
  1. package/bin/devframe.mjs +8 -0
  2. package/dist/adapters/build.d.mts +1 -1
  3. package/dist/adapters/build.mjs +4 -4
  4. package/dist/adapters/cac.d.mts +1 -1
  5. package/dist/adapters/cac.mjs +1 -1
  6. package/dist/adapters/cli.d.mts +1 -1
  7. package/dist/adapters/cli.mjs +1 -1
  8. package/dist/adapters/dev.d.mts +2 -2
  9. package/dist/adapters/dev.mjs +1 -1
  10. package/dist/adapters/embedded.d.mts +1 -1
  11. package/dist/adapters/mcp.d.mts +51 -3
  12. package/dist/adapters/mcp.mjs +2 -2
  13. package/dist/agent-tool-name-C3b5vEwJ.mjs +34 -0
  14. package/dist/{cac-CPaOy3LD.mjs → cac-B1LM3zit.mjs} +18 -13
  15. package/dist/cli/main.d.mts +11 -0
  16. package/dist/cli/main.mjs +284 -0
  17. package/dist/client/index.d.mts +40 -11
  18. package/dist/client/index.mjs +129 -19
  19. package/dist/constants.d.mts +13 -6
  20. package/dist/constants.mjs +13 -6
  21. package/dist/{context-DY72brRI.mjs → context-CQefP2jR.mjs} +3 -2
  22. package/dist/{context-CzqPrJSz.d.mts → context-DFzmxCLa.d.mts} +1 -1
  23. package/dist/{revoke-BtQDKTp7.mjs → crypto-token-XCqTSMg9.mjs} +1 -35
  24. package/dist/{dev-BCeaQuGE.mjs → dev-BSHFZGZr.mjs} +22 -11
  25. package/dist/{devframe-Ckhf3kFw.d.mts → devframe-qgCKL683.d.mts} +77 -15
  26. package/dist/diagnostics-B5-qHeqD.mjs +94 -0
  27. package/dist/{diagnostics-BXwBQmoN.mjs → diagnostics-hwjXp_UV.mjs} +8 -0
  28. package/dist/{dump-Cz7yVvsB.mjs → dump-CgZShDRB.mjs} +82 -6
  29. package/dist/fetch-CK0S253E.mjs +534 -0
  30. package/dist/helpers/vite.d.mts +15 -14
  31. package/dist/helpers/vite.mjs +8 -8
  32. package/dist/{host-h3-CgOetlNE.mjs → host-h3-Kz7t5Xab.mjs} +83 -28
  33. package/dist/http-Dvgxujcu.mjs +38 -0
  34. package/dist/{index-8dndvIxR.d.mts → index-B7RgLw--.d.mts} +11 -6
  35. package/dist/{index-DgsLFhZg.d.mts → index-Dbw1p5ch.d.mts} +27 -3
  36. package/dist/{index-YDSJgsyG.d.mts → index-vAX6bYuc.d.mts} +1 -1
  37. package/dist/index.d.mts +5 -5
  38. package/dist/instance-registry-D6fxYu36.mjs +190 -0
  39. package/dist/node/auth.d.mts +2 -2
  40. package/dist/node/auth.mjs +2 -2
  41. package/dist/node/hub-internals.d.mts +2 -2
  42. package/dist/node/hub-internals.mjs +1 -1
  43. package/dist/node/index.d.mts +124 -6
  44. package/dist/node/index.mjs +5 -4
  45. package/dist/recipes/common-rpc-functions.d.mts +33 -33
  46. package/dist/recipes/common-rpc-functions.mjs +6 -6
  47. package/dist/recipes/interactive-auth.d.mts +2 -2
  48. package/dist/recipes/interactive-auth.mjs +23 -15
  49. package/dist/revoke-DZbJ7Cl0.mjs +35 -0
  50. package/dist/rpc/dump.d.mts +1 -1
  51. package/dist/rpc/dump.mjs +1 -1
  52. package/dist/rpc/index.d.mts +3 -3
  53. package/dist/rpc/index.mjs +4 -4
  54. package/dist/rpc/transports/ws-client.d.mts +1 -1
  55. package/dist/rpc/transports/ws-client.mjs +1 -1
  56. package/dist/rpc/transports/ws-server.d.mts +2 -2
  57. package/dist/rpc/transports/ws-server.mjs +50 -3
  58. package/dist/{serialization-DpLXCy13.mjs → serialization-C8Mnw9hK.mjs} +1 -1
  59. package/dist/{server-DykHCza_.mjs → server-CXaDDUl0.mjs} +2 -2
  60. package/dist/{server-B0wiP_Oi.d.mts → server-E9z4ZWbd.d.mts} +4 -3
  61. package/dist/simple-schema-BDzLeJDk.d.mts +102 -0
  62. package/dist/simple-schema-DQPZrAaZ.mjs +154 -0
  63. package/dist/{state-WX3HT5a3.mjs → state-BeUHDDjk.mjs} +13 -6
  64. package/dist/{storage-gEnj9ASQ.mjs → storage-Dzoc3NVC.mjs} +2 -66
  65. package/dist/{transports-BmDVn4SF.mjs → transports-vhizgqXM.mjs} +1 -1
  66. package/dist/types/index.d.mts +4 -4
  67. package/dist/{types-CrzNxXKq.d.mts → types-CnJSgRVa.d.mts} +33 -19
  68. package/dist/utils/agent-tool-name.d.mts +27 -0
  69. package/dist/utils/agent-tool-name.mjs +34 -0
  70. package/dist/utils/events.d.mts +1 -1
  71. package/dist/utils/shared-state.d.mts +1 -1
  72. package/dist/utils/simple-schema.d.mts +2 -0
  73. package/dist/utils/simple-schema.mjs +154 -0
  74. package/dist/utils/streaming-channel.d.mts +1 -1
  75. package/dist/{ws-client-DSXiI2h7.d.mts → ws-client-B6Tnr0ic.d.mts} +1 -1
  76. package/dist/{ws-server-9-wn7MNQ.d.mts → ws-server-J-zkiOyp.d.mts} +24 -3
  77. package/package.json +18 -7
  78. package/skills/devframe/SKILL.md +4 -3
  79. package/dist/build-server-C7vTKjiQ.mjs +0 -359
  80. package/dist/http-_pPbryTQ.mjs +0 -114
@@ -1,8 +1,9 @@
1
1
  import { t as devframeReporter } from "./diagnostics-reporter-CsIG85Q5.mjs";
2
- import { t as diagnostics } from "./diagnostics-BXwBQmoN.mjs";
2
+ import { t as diagnostics } from "./diagnostics-hwjXp_UV.mjs";
3
3
  import { RpcFunctionsCollectorBase } from "./rpc/index.mjs";
4
4
  import { defineRpcFunction } from "./index.mjs";
5
- import { a as diagnostics$1, i as createEventEmitter, n as createSharedState, r as nanoid, t as createStorage } from "./storage-gEnj9ASQ.mjs";
5
+ import { t as diagnostics$1 } from "./diagnostics-B5-qHeqD.mjs";
6
+ import { i as createEventEmitter, n as createSharedState, r as nanoid, t as createStorage } from "./storage-Dzoc3NVC.mjs";
6
7
  import { defineDiagnostics } from "nostics";
7
8
  import { isatty } from "node:tty";
8
9
  import { formatWithOptions, inspect } from "node:util";
@@ -10,6 +11,43 @@ import { existsSync } from "node:fs";
10
11
  import { join } from "pathe";
11
12
  import process$1 from "node:process";
12
13
  import { homedir } from "node:os";
14
+ //#region src/node/agent-args.ts
15
+ /**
16
+ * Map the args payload an agent surface receives (MCP sends an object
17
+ * keyed `arg0`/`arg1`/…, matching the schema the adapter advertises) onto
18
+ * a handler's positional parameters. Shared by the agent host's RPC
19
+ * bridge and the hub's command-derived tools so the coercion cannot
20
+ * drift between them.
21
+ *
22
+ * - an array passes through as-is
23
+ * - `null`/`undefined` become a zero-argument call
24
+ * - with declared schemas, each schema reads its own `argN` key, in order
25
+ * - without schemas, `arg0`/`arg1`/… keys are collected when present
26
+ * - an empty object becomes a zero-argument call
27
+ * - anything else follows the {@link AgentArgsFallback}
28
+ *
29
+ * @experimental
30
+ */
31
+ function coerceAgentPositionalArgs(args, schemas, fallback = "wrap") {
32
+ if (Array.isArray(args)) return args;
33
+ if (args === void 0 || args === null) return [];
34
+ if (typeof args === "object") {
35
+ const obj = args;
36
+ if (schemas && schemas.length) return schemas.map((_, i) => obj[`arg${i}`]);
37
+ if ("arg0" in obj) {
38
+ const out = [];
39
+ let i = 0;
40
+ while (`arg${i}` in obj) {
41
+ out.push(obj[`arg${i}`]);
42
+ i++;
43
+ }
44
+ return out;
45
+ }
46
+ if (Object.keys(obj).length === 0) return [];
47
+ }
48
+ return fallback === "drop" ? [] : [args];
49
+ }
50
+ //#endregion
13
51
  //#region src/node/host-agent.ts
14
52
  /**
15
53
  * Framework-neutral host aggregating the agent-exposed surface of a
@@ -24,6 +62,7 @@ var DevframeAgentHost = class {
24
62
  events = createEventEmitter();
25
63
  tools = /* @__PURE__ */ new Map();
26
64
  resources = /* @__PURE__ */ new Map();
65
+ providers = /* @__PURE__ */ new Set();
27
66
  _rpcUnsubscribe;
28
67
  constructor(context) {
29
68
  this.context = context;
@@ -50,6 +89,19 @@ var DevframeAgentHost = class {
50
89
  }
51
90
  return existed;
52
91
  }
92
+ registerToolProvider(provider) {
93
+ this.providers.add(provider);
94
+ this.events.emit("agent:manifest:changed");
95
+ const notifyChanged = () => {
96
+ if (this.providers.has(provider)) this.events.emit("agent:manifest:changed");
97
+ };
98
+ return {
99
+ notifyChanged,
100
+ unregister: () => {
101
+ if (this.providers.delete(provider)) this.events.emit("agent:manifest:changed");
102
+ }
103
+ };
104
+ }
53
105
  registerResource(input) {
54
106
  if (this.resources.has(input.id)) throw diagnostics$1.DF0016({ id: input.id });
55
107
  const resource = {
@@ -79,15 +131,28 @@ var DevframeAgentHost = class {
79
131
  const rpcTools = this._collectRpcTools();
80
132
  const plainTools = Array.from(this.tools.values()).map((t) => t.tool);
81
133
  const resources = Array.from(this.resources.values()).map((r) => r.resource);
134
+ const seen = new Set([...rpcTools, ...plainTools].map((t) => t.id));
135
+ const providerTools = [];
136
+ for (const { tool } of this._collectProviderTools()) {
137
+ if (seen.has(tool.id)) continue;
138
+ seen.add(tool.id);
139
+ providerTools.push(tool);
140
+ }
82
141
  return {
83
- tools: [...rpcTools, ...plainTools],
142
+ tools: [
143
+ ...rpcTools,
144
+ ...plainTools,
145
+ ...providerTools
146
+ ],
84
147
  resources
85
148
  };
86
149
  }
87
150
  getTool(id) {
88
151
  const plain = this.tools.get(id);
89
152
  if (plain) return plain.tool;
90
- return this._collectRpcTools().find((t) => t.id === id);
153
+ const rpc = this._collectRpcTools().find((t) => t.id === id);
154
+ if (rpc) return rpc;
155
+ return this._collectProviderTools().find((t) => t.tool.id === id)?.tool;
91
156
  }
92
157
  getResource(id) {
93
158
  return this.resources.get(id)?.resource;
@@ -97,9 +162,11 @@ var DevframeAgentHost = class {
97
162
  if (plain?.handler) return await plain.handler(args);
98
163
  const rpcDef = this._findRpcDefinition(id);
99
164
  if (rpcDef) {
100
- const positional = this._coercePositionalArgs(args, rpcDef);
165
+ const positional = coerceAgentPositionalArgs(args, rpcDef.args, "wrap");
101
166
  return await this.context.rpc.invokeLocal(id, ...positional);
102
167
  }
168
+ const provided = this._collectProviderTools().find((t) => t.tool.id === id);
169
+ if (provided) return await provided.input.handler(args);
103
170
  throw new Error(`[devframe/agent] tool "${id}" not found`);
104
171
  }
105
172
  async read(id) {
@@ -125,11 +192,21 @@ var DevframeAgentHost = class {
125
192
  description: input.description,
126
193
  safety: input.safety ?? "action",
127
194
  tags: input.tags,
195
+ args: input.args,
128
196
  inputSchema: input.inputSchema,
129
197
  outputSchema: input.outputSchema,
130
198
  examples: input.examples
131
199
  };
132
200
  }
201
+ /** Query every registered provider, projecting inputs to serializable tools. */
202
+ _collectProviderTools() {
203
+ const out = [];
204
+ for (const provider of this.providers) for (const input of provider()) out.push({
205
+ input,
206
+ tool: this._projectTool(input)
207
+ });
208
+ return out;
209
+ }
133
210
  _collectRpcTools() {
134
211
  const out = [];
135
212
  for (const [name, def] of this.context.rpc.definitions) {
@@ -155,33 +232,11 @@ var DevframeAgentHost = class {
155
232
  const def = this.context.rpc.definitions.get(id);
156
233
  if (def?.agent) return def;
157
234
  }
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
235
  };
178
236
  function inferSafety(type) {
179
237
  if (type === "static" || type === "query") return "read";
180
238
  return "action";
181
239
  }
182
- function hasPositionalKeys(obj) {
183
- return "arg0" in obj;
184
- }
185
240
  //#endregion
186
241
  //#region src/node/host-diagnostics.ts
187
242
  var DevframeDiagnosticsHost = class {
@@ -1517,4 +1572,4 @@ function createH3DevframeHost(options) {
1517
1572
  };
1518
1573
  }
1519
1574
  //#endregion
1520
- export { DevframeViewHost as a, createRpcSharedStateServerHost as c, createNodeSettings as i, DevframeDiagnosticsHost as l, createHostContext as n, DevframeServicesHostImpl as o, createScopedNodeContext as r, createRpcStreamingServerHost as s, createH3DevframeHost as t, DevframeAgentHost as u };
1575
+ export { DevframeViewHost as a, createRpcSharedStateServerHost as c, coerceAgentPositionalArgs as d, createNodeSettings as i, DevframeDiagnosticsHost as l, createHostContext as n, DevframeServicesHostImpl as o, createScopedNodeContext as r, createRpcStreamingServerHost as s, createH3DevframeHost as t, DevframeAgentHost as u };
@@ -0,0 +1,38 @@
1
+ import { t as createMcpFetchHandler } from "./fetch-CK0S253E.mjs";
2
+ import { defineHandler } from "h3";
3
+ //#region src/adapters/mcp/http.ts
4
+ /**
5
+ * Mount an MCP Streamable-HTTP endpoint on an h3 app at `path` — the h3
6
+ * binding over {@link createMcpFetchHandler}, which owns the sessions, the
7
+ * origin gate, and the transport plumbing.
8
+ *
9
+ * The handler is web-standard — it takes the h3 event's web `Request` and
10
+ * returns a web `Response` (an SSE `ReadableStream` body for the
11
+ * server→client stream). We copy that response onto `event.res` and return
12
+ * its body rather than returning the `Response` object directly, so a
13
+ * legitimate MCP 404 (unknown session) isn't swallowed by h3's
14
+ * "Response-with-404 falls through to the next handler" rule (which would
15
+ * otherwise hand the request to the SPA static catch-all).
16
+ *
17
+ * @experimental
18
+ */
19
+ function mountMcpHttp(app, ctx, path, options) {
20
+ const handler = createMcpFetchHandler(ctx, options);
21
+ app.use(path, defineHandler(async (event) => respond(event, await handler.fetch(event.req))));
22
+ return { dispose: handler.dispose };
23
+ }
24
+ /**
25
+ * Copy a web `Response` from the MCP transport onto the h3 event's response
26
+ * and return its body. Returning the body (a `ReadableStream` or `null`)
27
+ * rather than the `Response` object avoids h3's 404-fall-through behavior.
28
+ */
29
+ function respond(event, response) {
30
+ event.res.status = response.status;
31
+ event.res.statusText = response.statusText;
32
+ response.headers.forEach((value, key) => {
33
+ event.res.headers.set(key, value);
34
+ });
35
+ return response.body ?? "";
36
+ }
37
+ //#endregion
38
+ export { mountMcpHttp };
@@ -1,5 +1,5 @@
1
- import { W as DevframeNodeRpcSession, b as DevframeNodeContext, ht as SharedState } from "./devframe-Ckhf3kFw.mjs";
2
- import { n as InternalAnonymousAuthStorage } from "./context-CzqPrJSz.mjs";
1
+ import { W as DevframeNodeRpcSession, b as DevframeNodeContext, ht as SharedState } from "./devframe-qgCKL683.mjs";
2
+ import { n as InternalAnonymousAuthStorage } from "./context-DFzmxCLa.mjs";
3
3
  //#region src/node/auth/revoke.d.ts
4
4
  /**
5
5
  * Flip `isTrusted` to false on any live WS clients connected with `token`
@@ -28,10 +28,15 @@ declare function getTempAuthCode(): string;
28
28
  */
29
29
  declare function refreshTempAuthCode(): string;
30
30
  /**
31
- * Build a "magic link" authentication URL that embeds a one-time code (OTP) as
32
- * a query parameter. Opening it authenticates the client without typing — print
33
- * it on startup (devframe stays headless, so the host prints its own banner).
34
- * Defaults to the current code; the link is subject to the same TTL.
31
+ * Build a "magic link" authentication URL that embeds a one-time code (OTP) in
32
+ * the URL **fragment**. Opening it authenticates the client without typing —
33
+ * print it on startup (devframe stays headless, so the host prints its own
34
+ * banner). Defaults to the current code; the link is subject to the same TTL.
35
+ *
36
+ * The code rides the fragment (`#devframe_otp=…`), not the query string, so it
37
+ * is never sent to the server, written to an access log, or leaked in a
38
+ * `Referer` header — the browser client reads it locally (see
39
+ * `consumeOtpFromUrl`). Any existing fragment parameters are preserved.
35
40
  */
36
41
  declare function buildOtpAuthUrl(baseUrl: string, code?: string): string;
37
42
  /**
@@ -1,5 +1,5 @@
1
- import { C as RpcFunctionType, S as RpcFunctionSetupResult, T as RpcReturnSchema, _ as RpcFunctionDefinition, i as RpcArgsSchema, v as RpcFunctionDefinitionAny, w as RpcFunctionsCollector } from "./types-CrzNxXKq.mjs";
2
- import { a as getDefinitionsWithDumps$1, c as StaticRpcDumpManifest$1, d as StaticRpcDumpManifestValue$1, f as StaticRpcDumpSerialization$1, i as dumpFunctions$1, l as StaticRpcDumpManifestQueryEntry$1, n as serializeDumpError$1, o as StaticRpcDumpCollection$1, p as collectStaticRpcDump$1, r as createClientFromDump$1, s as StaticRpcDumpFile$1, t as reviveDumpError$1, u as StaticRpcDumpManifestStaticEntry$1 } from "./index-YDSJgsyG.mjs";
1
+ import { C as RpcFunctionType, S as RpcFunctionSetupResult, T as RpcReturnSchema, _ as RpcFunctionDefinition, i as RpcArgsSchema, v as RpcFunctionDefinitionAny, w as RpcFunctionsCollector } from "./types-CnJSgRVa.mjs";
2
+ import { a as getDefinitionsWithDumps$1, c as StaticRpcDumpManifest$1, d as StaticRpcDumpManifestValue$1, f as StaticRpcDumpSerialization$1, i as dumpFunctions$1, l as StaticRpcDumpManifestQueryEntry$1, n as serializeDumpError$1, o as StaticRpcDumpCollection$1, p as collectStaticRpcDump$1, r as createClientFromDump$1, s as StaticRpcDumpFile$1, t as reviveDumpError$1, u as StaticRpcDumpManifestStaticEntry$1 } from "./index-vAX6bYuc.mjs";
3
3
  //#region src/rpc/cache.d.ts
4
4
  interface RpcCacheOptions {
5
5
  functions: string[];
@@ -94,6 +94,30 @@ declare const STRUCTURED_CLONE_PREFIX = "s:";
94
94
  */
95
95
  declare function strictJsonStringify(value: unknown, fnName?: string): string;
96
96
  //#endregion
97
+ //#region src/rpc/validate-io.d.ts
98
+ /**
99
+ * Validate positional arguments against their declared schemas. Only
100
+ * indices with a schema are checked; extra arguments pass through
101
+ * untouched. Throws `DF0038` on the first failing argument.
102
+ *
103
+ * Validation guards the payload without rewriting it: the original values
104
+ * are handed to the handler unchanged, so a schema that describes a subset
105
+ * of an object never silently strips the sender's extra fields (and any
106
+ * declared transforms stay a purely type-level concern).
107
+ *
108
+ * @internal
109
+ */
110
+ declare function validateRpcArgs(name: string, argsSchema: RpcArgsSchema | undefined, args: readonly unknown[]): Promise<unknown[]>;
111
+ /**
112
+ * Validate a handler's resolved return value against its declared schema.
113
+ * Throws `DF0039` when the value fails the schema, otherwise returns the
114
+ * original value unchanged (guard-only, never rewriting the payload — see
115
+ * {@link validateRpcArgs}). Passes through when no return schema is set.
116
+ *
117
+ * @internal
118
+ */
119
+ declare function validateRpcReturn(name: string, returnSchema: RpcReturnSchema | undefined, value: unknown): Promise<unknown>;
120
+ //#endregion
97
121
  //#region src/rpc/validation.d.ts
98
122
  /**
99
123
  * Validates RPC function definitions.
@@ -137,4 +161,4 @@ type StaticRpcDumpManifestValue = StaticRpcDumpManifestValue$1;
137
161
  /** @deprecated Import from `devframe/rpc/dump` instead. */
138
162
  type StaticRpcDumpSerialization = StaticRpcDumpSerialization$1;
139
163
  //#endregion
140
- export { RpcCacheManager as C, RpcFunctionsCollectorBase as S, strictJsonStringify as _, StaticRpcDumpManifestStaticEntry as a, createDefineWrapperWithContext as b, collectStaticRpcDump as c, getDefinitionsWithDumps as d, reviveDumpError as f, STRUCTURED_CLONE_PREFIX as g, validateDefinitions as h, StaticRpcDumpManifestQueryEntry as i, createClientFromDump as l, validateDefinition as m, StaticRpcDumpFile as n, StaticRpcDumpManifestValue as o, serializeDumpError as p, StaticRpcDumpManifest as r, StaticRpcDumpSerialization as s, StaticRpcDumpCollection as t, dumpFunctions as u, getRpcHandler as v, RpcCacheOptions as w, defineRpcFunction as x, getRpcResolvedSetupResult as y };
164
+ export { defineRpcFunction as C, RpcCacheOptions as E, createDefineWrapperWithContext as S, RpcCacheManager as T, validateRpcReturn as _, StaticRpcDumpManifestStaticEntry as a, getRpcHandler as b, collectStaticRpcDump as c, getDefinitionsWithDumps as d, reviveDumpError as f, validateRpcArgs as g, validateDefinitions as h, StaticRpcDumpManifestQueryEntry as i, createClientFromDump as l, validateDefinition as m, StaticRpcDumpFile as n, StaticRpcDumpManifestValue as o, serializeDumpError as p, StaticRpcDumpManifest as r, StaticRpcDumpSerialization as s, StaticRpcDumpCollection as t, dumpFunctions as u, STRUCTURED_CLONE_PREFIX as v, RpcFunctionsCollectorBase as w, getRpcResolvedSetupResult as x, strictJsonStringify as y };
@@ -1,4 +1,4 @@
1
- import { h as RpcDumpStore, l as RpcDumpClientOptions, m as RpcDumpRecordError, n as BirpcReturn, o as RpcDefinitionsToFunctions, u as RpcDumpCollectionOptions, v as RpcFunctionDefinitionAny } from "./types-CrzNxXKq.mjs";
1
+ import { h as RpcDumpStore, l as RpcDumpClientOptions, m as RpcDumpRecordError, n as BirpcReturn, o as RpcDefinitionsToFunctions, u as RpcDumpCollectionOptions, v as RpcFunctionDefinitionAny } from "./types-CnJSgRVa.mjs";
2
2
  //#region src/rpc/dump/static.d.ts
3
3
  type StaticRpcDumpSerialization = 'json' | 'structured-clone';
4
4
  interface StaticRpcDumpManifestStaticEntry {
package/dist/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- import { $ as DevframeRpcServerFunctions, A as DevframeSettingsStore, At as EventUnsubscribe, B as DevframeDefineDiagnosticsOptions, C as DevframeServicesHost, Ct as AgentResourceContent, D as DevframeScopedStreamingHost, Dt as DevframeAgentHost, E as DevframeScopedNodeRpc, Et as AgentToolInput, F as ScopedSharedStates, G as RpcBroadcastOptions, H as DevframeDiagnosticsHost, I as SettingsForNamespace, J as RpcSharedStateHost, K as RpcFunctionsHost, L as DevframeViewHost, M as ScopedClientFunctions, N as ScopedRpcFn, O as DevframeSettings, Ot as DevframeAgentHostEvents, P as ScopedServerFunctions, Q as DevframeRpcClientFunctions, R as DevframeHost, S as DevframeServiceOf, St as AgentResource, T as DevframeScopedNodeContext, Tt as AgentTool, U as DevframeDiagnosticsLogger, V as DevframeDiagnosticsDefinition, W as DevframeNodeRpcSession, X as RpcStreamingChannelOptions, Y as RpcStreamingChannel, Z as RpcStreamingHost, _ as ConnectionMeta, a as DevframeDockDefaults, b as DevframeNodeContext, bt as AgentHandle, c as DevframeSetupInfo, d as McpRouteOptions, et as DevframeRpcSharedStates, f as defineDevframe, g as Thenable, h as PartialWithoutId, i as DevframeDeploymentKind, j as ScopedBroadcastOptions, jt as EventsMap, k as DevframeSettingsRegistry, kt as EventEmitter, l as DevframeSpaOptions, m as EntriesToObject, n as DevframeCliOptions, o as DevframeDuplicationStrategy, q as RpcSharedStateGetOptions, r as DevframeDefinition, s as DevframeRuntime, t as DevframeBrowserContext, u as DevframeWsOptions, v as ConnectionMetaWebsocket, w as DevframeServicesRegistry, wt as AgentResourceInput, x as DevframeServiceId, xt as AgentManifest, y as DevframeCapabilities, z as DevframeStorageScope } from "./devframe-Ckhf3kFw.mjs";
2
- import { C as RpcFunctionType, T as RpcReturnSchema, _ as RpcFunctionDefinition, g as RpcFunctionAgentOptions, i as RpcArgsSchema } from "./types-CrzNxXKq.mjs";
3
- import "./index-DgsLFhZg.mjs";
4
- import { t as DevframeNodeRpcSessionMeta } from "./ws-server-9-wn7MNQ.mjs";
1
+ import { $ as DevframeRpcServerFunctions, A as DevframeSettingsStore, At as DevframeAgentHostEvents, B as DevframeDefineDiagnosticsOptions, C as DevframeServicesHost, Ct as AgentResourceContent, D as DevframeScopedStreamingHost, Dt as AgentToolProvider, E as DevframeScopedNodeRpc, Et as AgentToolInput, F as ScopedSharedStates, G as RpcBroadcastOptions, H as DevframeDiagnosticsHost, I as SettingsForNamespace, J as RpcSharedStateHost, K as RpcFunctionsHost, L as DevframeViewHost, M as ScopedClientFunctions, Mt as EventUnsubscribe, N as ScopedRpcFn, Nt as EventsMap, O as DevframeSettings, Ot as AgentToolProviderHandle, P as ScopedServerFunctions, Q as DevframeRpcClientFunctions, R as DevframeHost, S as DevframeServiceOf, St as AgentResource, T as DevframeScopedNodeContext, Tt as AgentTool, U as DevframeDiagnosticsLogger, V as DevframeDiagnosticsDefinition, W as DevframeNodeRpcSession, X as RpcStreamingChannelOptions, Y as RpcStreamingChannel, Z as RpcStreamingHost, _ as ConnectionMeta, a as DevframeDockDefaults, b as DevframeNodeContext, bt as AgentHandle, c as DevframeSetupInfo, d as McpRouteOptions, et as DevframeRpcSharedStates, f as defineDevframe, g as Thenable, h as PartialWithoutId, i as DevframeDeploymentKind, j as ScopedBroadcastOptions, jt as EventEmitter, k as DevframeSettingsRegistry, kt as DevframeAgentHost, l as DevframeSpaOptions, m as EntriesToObject, n as DevframeCliOptions, o as DevframeDuplicationStrategy, q as RpcSharedStateGetOptions, r as DevframeDefinition, s as DevframeRuntime, t as DevframeBrowserContext, u as DevframeWsOptions, v as ConnectionMetaWebsocket, w as DevframeServicesRegistry, wt as AgentResourceInput, x as DevframeServiceId, xt as AgentManifest, y as DevframeCapabilities, z as DevframeStorageScope } from "./devframe-qgCKL683.mjs";
2
+ import { C as RpcFunctionType, T as RpcReturnSchema, _ as RpcFunctionDefinition, g as RpcFunctionAgentOptions, i as RpcArgsSchema } from "./types-CnJSgRVa.mjs";
3
+ import "./index-Dbw1p5ch.mjs";
4
+ import { n as DevframeNodeRpcSessionMeta } from "./ws-server-J-zkiOyp.mjs";
5
5
  //#region src/define.d.ts
6
6
  declare const defineRpcFunction: <NAME extends string, TYPE extends RpcFunctionType, ARGS extends any[], RETURN = void, const AS extends RpcArgsSchema | undefined = undefined, const RS extends RpcReturnSchema | undefined = undefined>(definition: RpcFunctionDefinition<NAME, TYPE, ARGS, RETURN, AS, RS, DevframeNodeContext>) => RpcFunctionDefinition<NAME, TYPE, ARGS, RETURN, AS, RS, DevframeNodeContext>;
7
7
  //#endregion
8
- export { type AgentHandle, type AgentManifest, type AgentResource, type AgentResourceContent, type AgentResourceInput, type AgentTool, type AgentToolInput, type ConnectionMeta, type ConnectionMetaWebsocket, type DevframeAgentHost, type DevframeAgentHostEvents, type DevframeBrowserContext, type DevframeCapabilities, type DevframeCliOptions, type DevframeDefineDiagnosticsOptions, type DevframeDefinition, type DevframeDeploymentKind, type DevframeDiagnosticsDefinition, type DevframeDiagnosticsHost, type DevframeDiagnosticsLogger, type DevframeDockDefaults, type DevframeDuplicationStrategy, type DevframeHost, type DevframeNodeContext, type DevframeNodeRpcSession, type DevframeNodeRpcSessionMeta, type DevframeRpcClientFunctions, type DevframeRpcServerFunctions, type DevframeRpcSharedStates, type DevframeRuntime, type DevframeScopedNodeContext, type DevframeScopedNodeRpc, type DevframeScopedStreamingHost, type DevframeServiceId, type DevframeServiceOf, type DevframeServicesHost, type DevframeServicesRegistry, type DevframeSettings, type DevframeSettingsRegistry, type DevframeSettingsStore, type DevframeSetupInfo, type DevframeSpaOptions, type DevframeStorageScope, type DevframeViewHost, type DevframeWsOptions, type EntriesToObject, type EventEmitter, type EventUnsubscribe, type EventsMap, type McpRouteOptions, type PartialWithoutId, type RpcBroadcastOptions, type RpcFunctionAgentOptions, type RpcFunctionsHost, type RpcSharedStateGetOptions, type RpcSharedStateHost, type RpcStreamingChannel, type RpcStreamingChannelOptions, type RpcStreamingHost, type ScopedBroadcastOptions, type ScopedClientFunctions, type ScopedRpcFn, type ScopedServerFunctions, type ScopedSharedStates, type SettingsForNamespace, type Thenable, type defineDevframe, defineRpcFunction };
8
+ export { type AgentHandle, type AgentManifest, type AgentResource, type AgentResourceContent, type AgentResourceInput, type AgentTool, type AgentToolInput, type AgentToolProvider, type AgentToolProviderHandle, type ConnectionMeta, type ConnectionMetaWebsocket, type DevframeAgentHost, type DevframeAgentHostEvents, type DevframeBrowserContext, type DevframeCapabilities, type DevframeCliOptions, type DevframeDefineDiagnosticsOptions, type DevframeDefinition, type DevframeDeploymentKind, type DevframeDiagnosticsDefinition, type DevframeDiagnosticsHost, type DevframeDiagnosticsLogger, type DevframeDockDefaults, type DevframeDuplicationStrategy, type DevframeHost, type DevframeNodeContext, type DevframeNodeRpcSession, type DevframeNodeRpcSessionMeta, type DevframeRpcClientFunctions, type DevframeRpcServerFunctions, type DevframeRpcSharedStates, type DevframeRuntime, type DevframeScopedNodeContext, type DevframeScopedNodeRpc, type DevframeScopedStreamingHost, type DevframeServiceId, type DevframeServiceOf, type DevframeServicesHost, type DevframeServicesRegistry, type DevframeSettings, type DevframeSettingsRegistry, type DevframeSettingsStore, type DevframeSetupInfo, type DevframeSpaOptions, type DevframeStorageScope, type DevframeViewHost, type DevframeWsOptions, type EntriesToObject, type EventEmitter, type EventUnsubscribe, type EventsMap, type McpRouteOptions, type PartialWithoutId, type RpcBroadcastOptions, type RpcFunctionAgentOptions, type RpcFunctionsHost, type RpcSharedStateGetOptions, type RpcSharedStateHost, type RpcStreamingChannel, type RpcStreamingChannelOptions, type RpcStreamingHost, type ScopedBroadcastOptions, type ScopedClientFunctions, type ScopedRpcFn, type ScopedServerFunctions, type ScopedSharedStates, type SettingsForNamespace, type Thenable, type defineDevframe, defineRpcFunction };
@@ -0,0 +1,190 @@
1
+ import { t as diagnostics } from "./diagnostics-B5-qHeqD.mjs";
2
+ import { mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
3
+ import { join } from "pathe";
4
+ import process from "node:process";
5
+ import { homedir } from "node:os";
6
+ //#region src/node/instance-registry.ts
7
+ /** Environment variable overriding the registry directory (tests, CI). */
8
+ const DEVFRAME_INSTANCES_DIR_ENV = "DEVFRAME_INSTANCES_DIR";
9
+ /** Environment variable disabling instance registration entirely. */
10
+ const DEVFRAME_DISABLE_INSTANCE_REGISTRY_ENV = "DEVFRAME_DISABLE_INSTANCE_REGISTRY";
11
+ /**
12
+ * Resolve the registry directory: `~/.devframe/instances/` by default —
13
+ * the framework's own global dir, deliberately outside the per-app
14
+ * `~/.<appName>/devframe/` storage convention since the registry spans apps —
15
+ * overridable via `DEVFRAME_INSTANCES_DIR`.
16
+ */
17
+ function resolveInstancesDir(override) {
18
+ return override ?? process.env[DEVFRAME_INSTANCES_DIR_ENV] ?? join(homedir(), ".devframe", "instances");
19
+ }
20
+ function isRegistryDisabled() {
21
+ const value = process.env[DEVFRAME_DISABLE_INSTANCE_REGISTRY_ENV];
22
+ return value === "1" || value === "true";
23
+ }
24
+ /**
25
+ * Record a running devframe instance in the global instance registry so
26
+ * discovery tooling (`devframe connect`, editor integrations) can find it
27
+ * without port guessing.
28
+ *
29
+ * `createDevServer` registers automatically; custom hosts that serve a
30
+ * devframe in-process (e.g. `@devframes/next`'s host inside a Next dev
31
+ * server) call this explicitly with the origin they are reachable at.
32
+ *
33
+ * The record is written atomically to `<dir>/<pid>-<port>.json` and removed
34
+ * by {@link DevframeInstanceRegistration.unregister}. Records surviving a
35
+ * crash are pruned by readers whose liveness probe fails. Registration never
36
+ * throws — a write failure degrades to a coded warning (`DF0045`), since a
37
+ * dev server must not die over discovery metadata.
38
+ *
39
+ * @experimental
40
+ */
41
+ function registerDevframeInstance(record, options = {}) {
42
+ const dir = resolveInstancesDir(options.instancesDir);
43
+ const file = join(dir, `${record.pid}-${record.port}.json`);
44
+ if (!isRegistryDisabled()) try {
45
+ mkdirSync(dir, { recursive: true });
46
+ const tmp = join(dir, `.${record.pid}-${record.port}.${Date.now()}.tmp`);
47
+ writeFileSync(tmp, `${JSON.stringify(record, null, 2)}\n`);
48
+ renameSync(tmp, file);
49
+ } catch (error) {
50
+ diagnostics.DF0045({
51
+ file,
52
+ reason: error instanceof Error ? error.message : String(error),
53
+ cause: error
54
+ });
55
+ }
56
+ return {
57
+ file,
58
+ unregister: () => {
59
+ try {
60
+ rmSync(file, { force: true });
61
+ } catch (error) {
62
+ diagnostics.DF0045({
63
+ file,
64
+ reason: error instanceof Error ? error.message : String(error),
65
+ cause: error
66
+ });
67
+ }
68
+ }
69
+ };
70
+ }
71
+ /**
72
+ * Read every record in the registry directory, dropping unparseable files.
73
+ * Liveness is the caller's concern — see {@link probeDevframeInstance}.
74
+ *
75
+ * @experimental
76
+ */
77
+ function readDevframeInstances(options = {}) {
78
+ const dir = resolveInstancesDir(options.instancesDir);
79
+ let files;
80
+ try {
81
+ files = readdirSync(dir).filter((f) => f.endsWith(".json"));
82
+ } catch {
83
+ return [];
84
+ }
85
+ const records = [];
86
+ for (const file of files) try {
87
+ const parsed = JSON.parse(readFileSync(join(dir, file), "utf8"));
88
+ if (typeof parsed?.origin === "string" && typeof parsed?.pid === "number") records.push(parsed);
89
+ } catch {}
90
+ return records;
91
+ }
92
+ /**
93
+ * Dialable-origin candidates for a recorded origin. A `localhost` bind is
94
+ * ambiguous — the server may listen on `127.0.0.1`, `::1`, or both, and
95
+ * HTTP clients differ in which family they try — so probe the explicit
96
+ * addresses too and adopt whichever answers.
97
+ */
98
+ function originCandidates(origin) {
99
+ try {
100
+ const url = new URL(origin);
101
+ if (url.hostname !== "localhost") return [origin];
102
+ const port = url.port ? `:${url.port}` : "";
103
+ return [
104
+ origin,
105
+ `${url.protocol}//127.0.0.1${port}`,
106
+ `${url.protocol}//[::1]${port}`
107
+ ];
108
+ } catch {
109
+ return [origin];
110
+ }
111
+ }
112
+ /**
113
+ * Probe `<origin><basePath>__connection.json`, trying each dialable
114
+ * candidate for the origin (see {@link originCandidates}). The single
115
+ * probe primitive behind both registry liveness checks and the
116
+ * connector's explicit `--port` probes.
117
+ *
118
+ * @internal
119
+ */
120
+ async function probeDevframeOrigin(origin, basePath, timeoutMs) {
121
+ const base = basePath.endsWith("/") ? basePath : `${basePath}/`;
122
+ for (const candidate of originCandidates(origin)) try {
123
+ const response = await fetch(`${candidate}${base}__connection.json`, { signal: AbortSignal.timeout(timeoutMs ?? 1e3) });
124
+ if (!response.ok) continue;
125
+ return {
126
+ origin: candidate,
127
+ meta: await response.json().catch(() => ({}))
128
+ };
129
+ } catch {}
130
+ return null;
131
+ }
132
+ /**
133
+ * Probe a record's `__connection.json` to check the instance is alive.
134
+ * Returns the **dialable origin** that answered (for `localhost` records
135
+ * this may be an explicit `127.0.0.1` / `[::1]` origin), or `null` when
136
+ * unreachable.
137
+ */
138
+ async function probeDevframeInstance(record, options = {}) {
139
+ return (await probeDevframeOrigin(record.origin, record.basePath, options.timeoutMs))?.origin ?? null;
140
+ }
141
+ /**
142
+ * Read the registry and split records into live and dead by probing each
143
+ * one's `__connection.json`, deleting dead records (prune-on-read). Live
144
+ * records carry the dialable origin the probe confirmed (a `localhost`
145
+ * record may come back as `127.0.0.1` / `[::1]`).
146
+ *
147
+ * A liveness probe only proves *something* answers on the record's port, so
148
+ * records left behind by killed processes shadow the server currently bound
149
+ * there: per `(port, basePath)` only the newest record survives, older
150
+ * ghosts are pruned with the dead.
151
+ *
152
+ * @experimental
153
+ */
154
+ async function listLiveDevframeInstances(options = {}) {
155
+ const dir = resolveInstancesDir(options.instancesDir);
156
+ const records = readDevframeInstances({ instancesDir: dir });
157
+ const pruned = [];
158
+ const prune = (record) => {
159
+ pruned.push(record);
160
+ try {
161
+ rmSync(join(dir, `${record.pid}-${record.port}.json`), { force: true });
162
+ } catch {}
163
+ };
164
+ const newest = /* @__PURE__ */ new Map();
165
+ for (const record of records) {
166
+ const key = `${record.port}|${record.basePath}`;
167
+ const existing = newest.get(key);
168
+ if (!existing) newest.set(key, record);
169
+ else if (record.startedAt > existing.startedAt) {
170
+ prune(existing);
171
+ newest.set(key, record);
172
+ } else prune(record);
173
+ }
174
+ const live = [];
175
+ await Promise.all([...newest.values()].map(async (record) => {
176
+ const origin = await probeDevframeInstance(record, options);
177
+ if (origin) live.push(origin === record.origin ? record : {
178
+ ...record,
179
+ origin
180
+ });
181
+ else prune(record);
182
+ }));
183
+ live.sort((a, b) => a.startedAt - b.startedAt);
184
+ return {
185
+ live,
186
+ pruned
187
+ };
188
+ }
189
+ //#endregion
190
+ export { probeDevframeOrigin as n, registerDevframeInstance as r, listLiveDevframeInstances as t };
@@ -1,3 +1,3 @@
1
- import { p as DevframeAuthHandler } from "../devframe-Ckhf3kFw.mjs";
2
- import { a as verifyAuthToken, i as refreshTempAuthCode, n as exchangeTempAuthCode, o as revokeActiveConnectionsForToken, r as getTempAuthCode, s as revokeAuthToken, t as buildOtpAuthUrl } from "../index-8dndvIxR.mjs";
1
+ import { p as DevframeAuthHandler } from "../devframe-qgCKL683.mjs";
2
+ import { a as verifyAuthToken, i as refreshTempAuthCode, n as exchangeTempAuthCode, o as revokeActiveConnectionsForToken, r as getTempAuthCode, s as revokeAuthToken, t as buildOtpAuthUrl } from "../index-B7RgLw--.mjs";
3
3
  export { DevframeAuthHandler, buildOtpAuthUrl, exchangeTempAuthCode, getTempAuthCode, refreshTempAuthCode, revokeActiveConnectionsForToken, revokeAuthToken, verifyAuthToken };
@@ -1,3 +1,3 @@
1
- import { n as revokeAuthToken, t as revokeActiveConnectionsForToken } from "../revoke-BtQDKTp7.mjs";
2
- import { a as verifyAuthToken, i as refreshTempAuthCode, n as exchangeTempAuthCode, r as getTempAuthCode, t as buildOtpAuthUrl } from "../state-WX3HT5a3.mjs";
1
+ import { n as revokeAuthToken, t as revokeActiveConnectionsForToken } from "../revoke-DZbJ7Cl0.mjs";
2
+ import { a as verifyAuthToken, i as refreshTempAuthCode, n as exchangeTempAuthCode, r as getTempAuthCode, t as buildOtpAuthUrl } from "../state-BeUHDDjk.mjs";
3
3
  export { buildOtpAuthUrl, exchangeTempAuthCode, getTempAuthCode, refreshTempAuthCode, revokeActiveConnectionsForToken, revokeAuthToken, verifyAuthToken };
@@ -1,5 +1,5 @@
1
- import { i as DevframeDeploymentKind, r as DevframeDefinition } from "../devframe-Ckhf3kFw.mjs";
2
- import { a as internalContextMap, i as getInternalContext, n as InternalAnonymousAuthStorage, r as RemoteTokenRecord, t as DevframeInternalContext } from "../context-CzqPrJSz.mjs";
1
+ import { i as DevframeDeploymentKind, r as DevframeDefinition } from "../devframe-qgCKL683.mjs";
2
+ import { a as internalContextMap, i as getInternalContext, n as InternalAnonymousAuthStorage, r as RemoteTokenRecord, t as DevframeInternalContext } from "../context-DFzmxCLa.mjs";
3
3
  //#region src/adapters/_shared.d.ts
4
4
  /**
5
5
  * Resolve the mount base path for a devframe's SPA. Hosted adapters
@@ -1,3 +1,3 @@
1
- import { n as internalContextMap, t as getInternalContext } from "../context-DY72brRI.mjs";
1
+ import { n as internalContextMap, t as getInternalContext } from "../context-CQefP2jR.mjs";
2
2
  import { n as resolveBasePath, t as normalizeBasePath } from "../_shared-bWRzeSa0.mjs";
3
3
  export { getInternalContext, internalContextMap, normalizeBasePath, resolveBasePath };