devframe 1.2.5 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/{_shared-DlRoV7v3.mjs → _shared-C06DH07o.mjs} +4 -1
  2. package/dist/{_shared-NSl4p_om.d.mts → _shared-DbO-OtUC.d.mts} +8 -2
  3. package/dist/adapters/build.d.mts +1 -1
  4. package/dist/adapters/build.mjs +3 -3
  5. package/dist/adapters/cac.d.mts +1 -1
  6. package/dist/adapters/cac.mjs +4 -7
  7. package/dist/adapters/dev.d.mts +10 -4
  8. package/dist/adapters/dev.mjs +2 -2
  9. package/dist/adapters/embedded.d.mts +1 -1
  10. package/dist/adapters/initiate.d.mts +2 -2
  11. package/dist/adapters/initiate.mjs +1 -1
  12. package/dist/adapters/mcp.d.mts +3 -3
  13. package/dist/{agentic-D61fXLzA.d.mts → agentic-D6HePbWg.d.mts} +1 -1
  14. package/dist/{browser-agent-rpc-BXhoSh1z.mjs → browser-agent-rpc-KH4HHvHf.mjs} +24 -2
  15. package/dist/cli/main.mjs +1 -1
  16. package/dist/client/index.d.mts +1 -1
  17. package/dist/client/index.mjs +2 -2
  18. package/dist/{host-agent-CJu735ch.mjs → client-agent-DuLhUF6d.mjs} +148 -2
  19. package/dist/{context-CNq7GLeT.mjs → context-BY72d2gV.mjs} +1 -1
  20. package/dist/{context-BKw9KkCR.mjs → context-CmSDJAEI.mjs} +6 -46
  21. package/dist/{context-DhycZ2lx.d.mts → context-Dko5QFWF.d.mts} +216 -93
  22. package/dist/{context-Bgvuxv1C.d.mts → context-eIUOSrKu.d.mts} +1 -1
  23. package/dist/{dev-BViAfnlw.mjs → dev-C-wQTIrV.mjs} +43 -23
  24. package/dist/{diagnostics-Cx4_VjlG.mjs → diagnostics-BJjvKfVK.mjs} +12 -0
  25. package/dist/in-page-channel/index.d.mts +1 -1
  26. package/dist/in-page-channel/index.mjs +1 -1
  27. package/dist/{index-DFPsvDGu.d.mts → index-BMj-o_sP.d.mts} +2 -2
  28. package/dist/index.d.mts +3 -2
  29. package/dist/index.mjs +2 -1
  30. package/dist/{instance-registry-DFrZdU4B.mjs → instance-registry-vlz81P9X.mjs} +1 -1
  31. package/dist/{instance-shell-DmyVIJzj.mjs → instance-shell-CBgy8YzK.mjs} +56 -15
  32. package/dist/{instance-shell-fl3ir6RC.d.mts → instance-shell-yfm1AYk8.d.mts} +2 -2
  33. package/dist/{interactive-auth-FFOGnYIC.mjs → interactive-auth-BsqLFXw8.mjs} +1 -1
  34. package/dist/internal/index.d.mts +40 -6
  35. package/dist/internal/index.mjs +8 -7
  36. package/dist/mcp-content-DN3O212x.mjs +40 -0
  37. package/dist/mcp-content-wcQxvrrW.d.mts +25 -0
  38. package/dist/node/auth.d.mts +2 -2
  39. package/dist/node/hub-internals.d.mts +2 -2
  40. package/dist/node/hub-internals.mjs +2 -2
  41. package/dist/node/index.d.mts +1 -1
  42. package/dist/node/index.mjs +2 -2
  43. package/dist/recipes/interactive-auth.d.mts +2 -2
  44. package/dist/recipes/interactive-auth.mjs +1 -1
  45. package/dist/{remote-assets-B9MeWmW6.mjs → remote-assets-DOva7l3s.mjs} +1 -1
  46. package/dist/rpc/transports/ws-bun.d.mts +1 -1
  47. package/dist/rpc/transports/ws-deno.d.mts +1 -1
  48. package/dist/{rpc-core-BcThIWzY.d.mts → rpc-core-BQ1mesqZ.d.mts} +2 -2
  49. package/dist/{rpc-core-CXgALhUi.mjs → rpc-core-oXIq2hjO.mjs} +1 -1
  50. package/dist/{shared-state-Cow3u-_m.mjs → shared-state-Cc-Jrhma.mjs} +5 -2
  51. package/dist/{storage-DPoitS2X.mjs → storage-BzAr-S6I.mjs} +1 -1
  52. package/dist/types/index.d.mts +2 -2
  53. package/dist/utils/events.d.mts +1 -1
  54. package/dist/utils/remote-assets.mjs +1 -1
  55. package/dist/utils/shared-state.d.mts +1 -1
  56. package/dist/utils/shared-state.mjs +1 -1
  57. package/dist/utils/streaming-channel.d.mts +1 -1
  58. package/package.json +8 -8
@@ -1,5 +1,5 @@
1
1
  import "./constants.mjs";
2
- import { t as diagnostics } from "./diagnostics-Cx4_VjlG.mjs";
2
+ import { t as diagnostics } from "./diagnostics-BJjvKfVK.mjs";
3
3
  import { n as getPort } from "./dist-CZXfGEkd.mjs";
4
4
  import { n as isRuntimeModuleResolvable, t as importRuntimeModule } from "./import-runtime-module-BzlEQ9PI.mjs";
5
5
  //#region src/utils/url.ts
@@ -144,6 +144,9 @@ function resolveMcpConfig(mcp) {
144
144
  ...mcp.path !== void 0 ? { path: mcp.path } : {},
145
145
  ...mcp.allowedOrigins !== void 0 ? { allowedOrigins: mcp.allowedOrigins } : {},
146
146
  ...mcp.exposeSharedState !== void 0 ? { exposeSharedState: mcp.exposeSharedState } : {},
147
+ ...mcp.instructions !== void 0 ? { instructions: mcp.instructions } : {},
148
+ ...mcp.resourceTemplates !== void 0 ? { resourceTemplates: mcp.resourceTemplates } : {},
149
+ ...mcp.onResourcesChanged !== void 0 ? { onResourcesChanged: mcp.onResourcesChanged } : {},
147
150
  authorization
148
151
  };
149
152
  }
@@ -1,5 +1,5 @@
1
- import { B as DevframeDefinition, Q as McpSetting, V as DevframeDeploymentKind, Wt as DevframeAgentHost, X as McpAuthorization, t as ConnectionMeta } from "./context-DhycZ2lx.mjs";
2
- import { t as AgenticMcpModule } from "./agentic-D61fXLzA.mjs";
1
+ import { F as DevframeDefinition, G as McpAuthorization, I as DevframeDeploymentKind, Pt as McpResourcesChangedHook, Xt as DevframeAgentHost, jt as McpResourceTemplate, q as McpSetting, t as ConnectionMeta } from "./context-Dko5QFWF.mjs";
2
+ import { t as AgenticMcpModule } from "./agentic-D6HePbWg.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
@@ -37,6 +37,12 @@ interface ResolvedMcpConfig {
37
37
  allowedOrigins?: readonly string[] | false;
38
38
  /** Shared-state exposure from the route options; omitted means every key. */
39
39
  exposeSharedState?: boolean | ((key: string) => boolean);
40
+ /** Handshake `instructions` from the route options; omitted means none. */
41
+ instructions?: string;
42
+ /** Resource templates from the route options; omitted means none. */
43
+ resourceTemplates?: McpResourceTemplate[];
44
+ /** Resource-list change subscription from the route options; omitted means none. */
45
+ onResourcesChanged?: McpResourcesChangedHook;
40
46
  /** The resolved identity policy: a bearer token, callback, or `false`. */
41
47
  authorization: McpAuthorization;
42
48
  }
@@ -1,4 +1,4 @@
1
- import { B as DevframeDefinition, K as DevframeSnapshotRpcEntry, o as DevframeNodeContext } from "../context-DhycZ2lx.mjs";
1
+ import { F as DevframeDefinition, V as DevframeSnapshotRpcEntry, o as DevframeNodeContext } from "../context-Dko5QFWF.mjs";
2
2
  import { o as StaticAssetsSource } from "../remote-assets-eBvSKZMS.mjs";
3
3
  //#region src/adapters/build.d.ts
4
4
  export interface CreateBuildOptions {
@@ -1,9 +1,9 @@
1
1
  import { s as colors } from "../nostics-D0PvLZsn.mjs";
2
2
  import { DEVFRAME_CONNECTION_META_FILENAME, DEVFRAME_RPC_DUMP_MANIFEST_FILENAME } from "../constants.mjs";
3
3
  import { n as collectStaticRpcDump, t as writeStaticRpcDump } from "../write-DK7rBUN3.mjs";
4
- import { t as diagnostics } from "../diagnostics-Cx4_VjlG.mjs";
5
- import { t as createHostContext } from "../context-BKw9KkCR.mjs";
6
- import { t as resolveStaticAssetsSource } from "../remote-assets-B9MeWmW6.mjs";
4
+ import { t as diagnostics } from "../diagnostics-BJjvKfVK.mjs";
5
+ import { t as createHostContext } from "../context-CmSDJAEI.mjs";
6
+ import { t as resolveStaticAssetsSource } from "../remote-assets-DOva7l3s.mjs";
7
7
  import { t as createH3DevframeHost } from "../host-h3-BROI6SQ4.mjs";
8
8
  import fs from "node:fs/promises";
9
9
  import { resolve } from "pathe";
@@ -1,4 +1,4 @@
1
- import { B as DevframeDefinition, Mt as InferCliFlags, Nt as defineCliFlags, Pt as parseCliFlags, Q as McpSetting, jt as CliFlagsSchema } from "../context-DhycZ2lx.mjs";
1
+ import { Bt as parseCliFlags, F as DevframeDefinition, Lt as CliFlagsSchema, Rt as InferCliFlags, q as McpSetting, zt as defineCliFlags } from "../context-Dko5QFWF.mjs";
2
2
  import { CAC } from "cac";
3
3
  import { H3 } from "h3";
4
4
  //#region src/adapters/cac.d.ts
@@ -1,7 +1,7 @@
1
1
  import { s as colors } from "../nostics-D0PvLZsn.mjs";
2
- import { i as resolveDevServerPort, s as importAgenticMcp } from "../_shared-DlRoV7v3.mjs";
2
+ import { s as importAgenticMcp } from "../_shared-C06DH07o.mjs";
3
3
  import { createBuild } from "./build.mjs";
4
- import { t as createDevServer } from "../dev-BViAfnlw.mjs";
4
+ import { t as createDevServer } from "../dev-C-wQTIrV.mjs";
5
5
  import process from "node:process";
6
6
  import cac$1 from "cac";
7
7
  //#region src/adapters/flags.ts
@@ -105,14 +105,11 @@ function createCac(d, options = {}) {
105
105
  devCommand.action(async (_args, rawFlags) => {
106
106
  const flags = resolveTypedFlags(d, rawFlags);
107
107
  const host = flags.host ?? defaultHost;
108
- const port = flags.port ?? await resolveDevServerPort(d, {
109
- host,
110
- defaultPort
111
- });
112
108
  const mcp = flags.mcp ?? options.mcp;
113
109
  await createDevServer(d, {
114
110
  host,
115
- port,
111
+ port: flags.port,
112
+ defaultPort,
116
113
  flags,
117
114
  mcp,
118
115
  onReady: options.onReady
@@ -1,9 +1,9 @@
1
- import { At as DevframeAuthHandler, B as DevframeDefinition, J as DevframeSseOptions, Q as McpSetting, Y as DevframeWsOptions, s as DevframeNodeRpcSession } from "../context-DhycZ2lx.mjs";
1
+ import { F as DevframeDefinition, It as DevframeAuthHandler, U as DevframeSseOptions, W as DevframeWsOptions, q as McpSetting, s as DevframeNodeRpcSession } from "../context-Dko5QFWF.mjs";
2
2
  import { n as DevframeRpcConnection, t as DevframeNodeRpcSessionMeta } from "../session-r6PDixP6.mjs";
3
3
  import { o as StaticAssetsSource } from "../remote-assets-eBvSKZMS.mjs";
4
4
  import { n as WsOriginRegistry } from "../ws-server-y2R76aSW.mjs";
5
- import { c as StartedServer } from "../instance-shell-fl3ir6RC.mjs";
6
- import { c as resolveMcpConnectionMeta, o as resolveDevServerPort, t as ResolveDevServerPortOptions } from "../_shared-NSl4p_om.mjs";
5
+ import { c as StartedServer } from "../instance-shell-yfm1AYk8.mjs";
6
+ import { c as resolveMcpConnectionMeta, o as resolveDevServerPort, t as ResolveDevServerPortOptions } from "../_shared-DbO-OtUC.mjs";
7
7
  import { H3 } from "h3";
8
8
  //#region src/adapters/dev.d.ts
9
9
  export interface CreateDevServerOptions {
@@ -12,9 +12,15 @@ export interface CreateDevServerOptions {
12
12
  /**
13
13
  * Port to listen on. When omitted, falls back to
14
14
  * {@link resolveDevServerPort}, which respects `def.cli?.port` /
15
- * `portRange` / `random`.
15
+ * `portRange` / `random`. A port set here is used as given: if it is
16
+ * taken, startup fails (`DF0052`) instead of moving to another port.
16
17
  */
17
18
  port?: number;
19
+ /**
20
+ * Preferred port when `port` is omitted, passed to
21
+ * {@link resolveDevServerPort}. Default: `def.cli?.port ?? 9999`.
22
+ */
23
+ defaultPort?: number;
18
24
  /**
19
25
  * Parsed flag bag forwarded to `setup(ctx, { flags })`. The dev
20
26
  * server itself only reads `flags.open` from this bag, and only when
@@ -1,3 +1,3 @@
1
- import { i as resolveDevServerPort, o as resolveMcpConnectionMeta } from "../_shared-DlRoV7v3.mjs";
2
- import { t as createDevServer } from "../dev-BViAfnlw.mjs";
1
+ import { i as resolveDevServerPort, o as resolveMcpConnectionMeta } from "../_shared-C06DH07o.mjs";
2
+ import { t as createDevServer } from "../dev-C-wQTIrV.mjs";
3
3
  export { createDevServer, resolveDevServerPort, resolveMcpConnectionMeta };
@@ -1,4 +1,4 @@
1
- import { B as DevframeDefinition, o as DevframeNodeContext } from "../context-DhycZ2lx.mjs";
1
+ import { F as DevframeDefinition, o as DevframeNodeContext } from "../context-Dko5QFWF.mjs";
2
2
  //#region src/adapters/embedded.d.ts
3
3
  export interface CreateEmbeddedOptions {
4
4
  /** Target context the devframe is registered into. Required. */
@@ -1,8 +1,8 @@
1
- import { At as DevframeAuthHandler, B as DevframeDefinition, Dt as DevframeStorageScope, J as DevframeSseOptions, Q as McpSetting, Y as DevframeWsOptions, o as DevframeNodeContext, s as DevframeNodeRpcSession, t as ConnectionMeta } from "../context-DhycZ2lx.mjs";
1
+ import { Ct as DevframeStorageScope, F as DevframeDefinition, It as DevframeAuthHandler, U as DevframeSseOptions, W as DevframeWsOptions, o as DevframeNodeContext, q as McpSetting, s as DevframeNodeRpcSession, t as ConnectionMeta } from "../context-Dko5QFWF.mjs";
2
2
  import { n as DevframeRpcConnection, t as DevframeNodeRpcSessionMeta } from "../session-r6PDixP6.mjs";
3
3
  import { o as StaticAssetsSource } from "../remote-assets-eBvSKZMS.mjs";
4
4
  import { n as WsOriginRegistry } from "../ws-server-y2R76aSW.mjs";
5
- import { c as StartedServer, f as DevframeInstanceRecord } from "../instance-shell-fl3ir6RC.mjs";
5
+ import { c as StartedServer, f as DevframeInstanceRecord } from "../instance-shell-yfm1AYk8.mjs";
6
6
  import { H3 } from "h3";
7
7
  import { Buffer } from "node:buffer";
8
8
  import { IncomingMessage, Server, ServerResponse } from "node:http";
@@ -1,2 +1,2 @@
1
- import { n as getInstanceInternals, r as initDevframe } from "../dev-BViAfnlw.mjs";
1
+ import { n as getInstanceInternals, r as initDevframe } from "../dev-C-wQTIrV.mjs";
2
2
  export { getInstanceInternals, initDevframe };
@@ -1,4 +1,4 @@
1
- import { F as CreateMcpServerOptions, I as McpConnectionInfo, L as McpFetchHandler, P as CreateMcpFetchHandlerOptions, R as McpServerHandle } from "../context-DhycZ2lx.mjs";
2
- import { n as MountMcpHttpOptions, r as MountedMcpHttp } from "../agentic-D61fXLzA.mjs";
1
+ import { At as McpFetchHandler, Dt as CreateMcpServerOptions, Et as CreateMcpFetchHandlerOptions, Ft as McpServerHandle, Mt as McpResourceTemplateContent, Nt as McpResourceTemplateEntry, Ot as McpConnectionInfo, Pt as McpResourcesChangedHook, jt as McpResourceTemplate } from "../context-Dko5QFWF.mjs";
2
+ import { n as MountMcpHttpOptions, r as MountedMcpHttp } from "../agentic-D6HePbWg.mjs";
3
3
  import { createMcpFetchHandler, createMcpServer, mountMcpHttp } from "@devframes/agentic/mcp";
4
- export { type CreateMcpFetchHandlerOptions, type CreateMcpServerOptions, type McpConnectionInfo, type McpFetchHandler, type McpServerHandle, type MountMcpHttpOptions, type MountedMcpHttp, createMcpFetchHandler, createMcpServer, mountMcpHttp };
4
+ export { type CreateMcpFetchHandlerOptions, type CreateMcpServerOptions, type McpConnectionInfo, type McpFetchHandler, type McpResourceTemplate, type McpResourceTemplateContent, type McpResourceTemplateEntry, type McpResourcesChangedHook, type McpServerHandle, type MountMcpHttpOptions, type MountedMcpHttp, createMcpFetchHandler, createMcpServer, mountMcpHttp };
@@ -1,4 +1,4 @@
1
- import { B as DevframeDefinition, F as CreateMcpServerOptions, L as McpFetchHandler, P as CreateMcpFetchHandlerOptions, R as McpServerHandle, o as DevframeNodeContext } from "./context-DhycZ2lx.mjs";
1
+ import { At as McpFetchHandler, Dt as CreateMcpServerOptions, Et as CreateMcpFetchHandlerOptions, F as DevframeDefinition, Ft as McpServerHandle, o as DevframeNodeContext } from "./context-Dko5QFWF.mjs";
2
2
  import { H3 } from "h3";
3
3
  //#region src/node/agentic.d.ts
4
4
  /**
@@ -28,7 +28,22 @@ function resolveClientId(win = globalThis.window) {
28
28
  }
29
29
  //#endregion
30
30
  //#region src/client/browser-agent-rpc.ts
31
- /** Mirror this document's browser-agent registry over its existing RPC connection. */
31
+ /** Snapshot of this document as seen by a coding agent picking a tab. */
32
+ function describeBrowserAgentClient() {
33
+ const doc = typeof document === "undefined" ? void 0 : document;
34
+ return {
35
+ url: doc?.location?.href ?? "",
36
+ title: doc?.title ?? "",
37
+ visible: doc ? doc.visibilityState === "visible" : true,
38
+ focused: doc?.hasFocus() ?? true
39
+ };
40
+ }
41
+ /**
42
+ * Mirror this document's browser-agent registry over its existing RPC
43
+ * connection. Re-syncs on tool changes, reconnects, and focus/visibility
44
+ * changes so the node can route unaddressed calls to the tab the user
45
+ * looked at last.
46
+ */
32
47
  function setupBrowserAgentRpcBridge(rpc) {
33
48
  rpc.client.register({
34
49
  name: "devframe:agent:invoke-client-tool",
@@ -52,18 +67,25 @@ function setupBrowserAgentRpcBridge(rpc) {
52
67
  const manifests = listBrowserAgentTools().map(({ invoke: _, ...manifest }) => manifest);
53
68
  if (manifests.length === 0 && lastSyncedCount === 0) return;
54
69
  lastSyncedCount = manifests.length;
55
- await rpc.callOptional("devframe:agent:sync-client-tools", resolveClientId(), manifests).catch(() => {});
70
+ await rpc.callOptional("devframe:agent:sync-client-tools", resolveClientId(), manifests, describeBrowserAgentClient()).catch(() => {});
56
71
  });
57
72
  };
58
73
  const stopTools = onBrowserAgentToolsChanged(sync);
59
74
  const stopConnection = rpc.events.on("connection:status", (status) => {
60
75
  if (status === "connected") sync();
61
76
  });
77
+ const win = typeof window === "undefined" ? void 0 : window;
78
+ win?.addEventListener("focus", sync);
79
+ win?.addEventListener("blur", sync);
80
+ win?.document.addEventListener("visibilitychange", sync);
62
81
  sync();
63
82
  return () => {
64
83
  disposed = true;
65
84
  stopTools();
66
85
  stopConnection();
86
+ win?.removeEventListener("focus", sync);
87
+ win?.removeEventListener("blur", sync);
88
+ win?.document.removeEventListener("visibilitychange", sync);
67
89
  };
68
90
  }
69
91
  //#endregion
package/dist/cli/main.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as diagnostics } from "../diagnostics-Cx4_VjlG.mjs";
1
+ import { t as diagnostics } from "../diagnostics-BJjvKfVK.mjs";
2
2
  import { t as importRuntimeModule } from "../import-runtime-module-BzlEQ9PI.mjs";
3
3
  import process from "node:process";
4
4
  import { cac } from "cac";
@@ -1,7 +1,7 @@
1
1
  import { i as BirpcReturn, r as BirpcOptions } from "../index-Bia1vKjL.mjs";
2
2
  import { f as RpcCacheManager, p as RpcCacheOptions } from "../index-DuEm0sDH.mjs";
3
3
  import { h as RpcFunctionDefinition, w as RpcFunctionsCollector } from "../types-BmDbfHCx.mjs";
4
- import { Ct as DevframeRpcClientFunctions, Kt as EventEmitter, at as DevframeServiceScopeOf, b as StreamSink, bt as ScopedSharedStates, d as RpcSharedStateHost, k as SharedState, lt as DevframeServicesState, pt as DevframeSettings, rt as DevframeServiceMeta, t as ConnectionMeta, u as RpcSharedStateGetOptions, vt as ScopedRpcFn, wt as DevframeRpcServerFunctions, xt as SettingsForNamespace, y as StreamReader, yt as ScopedServerFunctions } from "../context-DhycZ2lx.mjs";
4
+ import { Q as DevframeServiceMeta, Qt as EventEmitter, b as StreamSink, ct as DevframeSettings, d as RpcSharedStateHost, et as DevframeServiceScopeOf, gt as SettingsForNamespace, ht as ScopedSharedStates, it as DevframeServicesState, k as SharedState, mt as ScopedServerFunctions, pt as ScopedRpcFn, t as ConnectionMeta, u as RpcSharedStateGetOptions, vt as DevframeRpcClientFunctions, y as StreamReader, yt as DevframeRpcServerFunctions } from "../context-Dko5QFWF.mjs";
5
5
  import { t as SseRpcChannelOptions } from "../sse-client-DNdscfu_.mjs";
6
6
  import { t as WsRpcChannelOptions } from "../ws-client-6Mrz6eC4.mjs";
7
7
  //#region src/client/connection.d.ts
@@ -2,7 +2,7 @@ import { a as defineDiagnostics, i as createBirpc, n as argsToJsonSchema, o as D
2
2
  import { t as hash } from "../hash-DdPnc4k3.mjs";
3
3
  import { createEventEmitter } from "../utils/events.mjs";
4
4
  import { withBase, withProtocol } from "../utils/url.mjs";
5
- import { t as createSharedState } from "../shared-state-Cow3u-_m.mjs";
5
+ import { t as createSharedState } from "../shared-state-Cc-Jrhma.mjs";
6
6
  import { i as structuredCloneStringify, n as structuredCloneParse, t as structuredCloneDeserialize } from "../structured-clone-CgtQ61SA.mjs";
7
7
  import { createStreamReader, createStreamSink } from "../utils/streaming-channel.mjs";
8
8
  import { toAgentToolName } from "../utils/agent-tool-name.mjs";
@@ -2044,7 +2044,7 @@ async function getDevframeRpcClient(options = {}) {
2044
2044
  }, () => {
2045
2045
  bootstrapAuthSettled = true;
2046
2046
  });
2047
- if (connectionMeta.mcp) import("../browser-agent-rpc-BXhoSh1z.mjs").then(({ setupBrowserAgentRpcBridge }) => {
2047
+ if (connectionMeta.mcp) import("../browser-agent-rpc-KH4HHvHf.mjs").then(({ setupBrowserAgentRpcBridge }) => {
2048
2048
  if (!closed) disposeBrowserAgentBridge = setupBrowserAgentRpcBridge(rpc);
2049
2049
  }).catch(() => {});
2050
2050
  if (authChannel) authChannel.onmessage = (event) => {
@@ -1,5 +1,5 @@
1
1
  import { t as DEVFRAME_EVENTS } from "./events-0wDwalmL.mjs";
2
- import { t as diagnostics } from "./diagnostics-Cx4_VjlG.mjs";
2
+ import { t as diagnostics } from "./diagnostics-BJjvKfVK.mjs";
3
3
  //#region src/utils/events.ts
4
4
  /**
5
5
  * Create event emitter.
@@ -274,4 +274,150 @@ var DevframeAgentHost = class {
274
274
  }
275
275
  };
276
276
  //#endregion
277
- export { toolInputToCommandArgs as n, createEventEmitter as r, DevframeAgentHost as t };
277
+ //#region src/node/client-agent.ts
278
+ /** Id of the built-in tool listing connected browser tabs (wire name `devframe_agent_list-clients`). */
279
+ const LIST_CLIENTS_TOOL = "devframe:agent:list-clients";
280
+ /** Reserved argument a forwarded client tool accepts to address one tab. */
281
+ const CLIENT_ID_ARG = "client_id";
282
+ const states = /* @__PURE__ */ new WeakMap();
283
+ /**
284
+ * Prefer the most recently focused visible tab, then any visible tab, then
285
+ * whichever synced last. Ties go to the later entry, so a re-sync moves a
286
+ * tab ahead of its peers.
287
+ */
288
+ function pickTarget(candidates) {
289
+ const rank = (e) => e.info.visible ? [
290
+ 1,
291
+ e.focusedAt,
292
+ e.syncedAt
293
+ ] : [
294
+ 0,
295
+ 0,
296
+ e.syncedAt
297
+ ];
298
+ let best;
299
+ for (const entry of candidates) {
300
+ if (!best) {
301
+ best = entry;
302
+ continue;
303
+ }
304
+ const a = rank(entry);
305
+ const b = rank(best);
306
+ const i = a.findIndex((v, i) => v !== b[i]);
307
+ if (i === -1 || a[i] > b[i]) best = entry;
308
+ }
309
+ return best;
310
+ }
311
+ function withClientIdArg(inputSchema) {
312
+ const base = inputSchema && typeof inputSchema === "object" ? inputSchema : {};
313
+ return {
314
+ type: "object",
315
+ ...base,
316
+ properties: {
317
+ ...base.properties,
318
+ [CLIENT_ID_ARG]: {
319
+ type: "string",
320
+ description: `Id of the connected browser tab to run this on, from ${LIST_CLIENTS_TOOL}. Omit to target the most recently focused tab.`
321
+ }
322
+ }
323
+ };
324
+ }
325
+ function listClients(sessions) {
326
+ return [...sessions.values()].map((entry) => ({
327
+ id: entry.clientId,
328
+ ...entry.info,
329
+ connectedAt: entry.connectedAt,
330
+ tools: entry.tools.map((tool) => tool.id)
331
+ }));
332
+ }
333
+ function forwardedTool(sessions, manifest) {
334
+ return {
335
+ ...manifest,
336
+ inputSchema: withClientIdArg(manifest.inputSchema),
337
+ handler: (args) => {
338
+ const { [CLIENT_ID_ARG]: clientId, ...rest } = args ?? {};
339
+ const target = pickTarget([...sessions.values()].filter((e) => e.tools.some((t) => t.id === manifest.id) && (clientId === void 0 || e.clientId === clientId)));
340
+ if (!target) throw diagnostics.DF0082({
341
+ clientId: String(clientId),
342
+ tool: manifest.id,
343
+ live: [...sessions.values()].map((e) => e.clientId)
344
+ });
345
+ return target.session.rpc.$callRaw({
346
+ method: "devframe:agent:invoke-client-tool",
347
+ args: [manifest.id, rest]
348
+ });
349
+ }
350
+ };
351
+ }
352
+ function listClientsTool(sessions) {
353
+ return {
354
+ id: LIST_CLIENTS_TOOL,
355
+ title: "List connected browser tabs",
356
+ description: `List every browser tab connected to this devframe: its client id, URL, title, visibility/focus, and the tools it exposes. Pass a client id as \`${CLIENT_ID_ARG}\` to a client tool to run it on that tab. Safe to call freely.`,
357
+ safety: "read",
358
+ inputSchema: {
359
+ type: "object",
360
+ properties: {}
361
+ },
362
+ outputSchema: {
363
+ type: "object",
364
+ properties: { clients: {
365
+ type: "array",
366
+ items: {
367
+ type: "object",
368
+ properties: {
369
+ id: { type: "string" },
370
+ url: { type: "string" },
371
+ title: { type: "string" },
372
+ visible: { type: "boolean" },
373
+ focused: { type: "boolean" },
374
+ connectedAt: { type: "number" },
375
+ tools: {
376
+ type: "array",
377
+ items: { type: "string" }
378
+ }
379
+ }
380
+ }
381
+ } }
382
+ },
383
+ handler: () => ({ clients: listClients(sessions) })
384
+ };
385
+ }
386
+ function getState(context) {
387
+ let state = states.get(context);
388
+ if (state) return state;
389
+ const sessions = /* @__PURE__ */ new Map();
390
+ state = {
391
+ sessions,
392
+ notifyChanged: context.agent.registerToolProvider(() => {
393
+ if (sessions.size === 0) return [];
394
+ const tools = /* @__PURE__ */ new Map();
395
+ for (const entry of sessions.values()) for (const manifest of entry.tools) if (!tools.has(manifest.id)) tools.set(manifest.id, forwardedTool(sessions, manifest));
396
+ tools.set(LIST_CLIENTS_TOOL, listClientsTool(sessions));
397
+ return [...tools.values()];
398
+ }).notifyChanged
399
+ };
400
+ states.set(context, state);
401
+ return state;
402
+ }
403
+ function syncClientAgentTools(context, session, clientId, tools, info) {
404
+ const state = getState(context);
405
+ const now = Date.now();
406
+ const previous = state.sessions.get(session.meta);
407
+ state.sessions.set(session.meta, {
408
+ session,
409
+ clientId,
410
+ info,
411
+ tools,
412
+ connectedAt: previous?.connectedAt ?? now,
413
+ syncedAt: now,
414
+ focusedAt: info.focused ? now : previous?.focusedAt ?? 0
415
+ });
416
+ if (!(previous && previous.tools.length === tools.length && previous.tools.every((tool, i) => tool.id === tools[i].id))) state.notifyChanged();
417
+ }
418
+ function removeClientAgentSession(context, meta) {
419
+ const state = states.get(context);
420
+ if (state?.sessions.delete(meta)) state.notifyChanged();
421
+ }
422
+ //#endregion
423
+ export { toolInputToCommandArgs as a, DevframeAgentHost as i, removeClientAgentSession as n, createEventEmitter as o, syncClientAgentTools as r, LIST_CLIENTS_TOOL as t };
@@ -1,5 +1,5 @@
1
1
  import { n as randomToken } from "./crypto-token-TVbGGFuj.mjs";
2
- import { t as createStorage } from "./storage-DPoitS2X.mjs";
2
+ import { t as createStorage } from "./storage-BzAr-S6I.mjs";
3
3
  import { n as revokeAuthToken, t as revokeActiveConnectionsForToken } from "./revoke-CeQUo6KI.mjs";
4
4
  import { join } from "pathe";
5
5
  //#region src/node/hub-internals/context.ts
@@ -4,10 +4,10 @@ import { RpcFunctionsCollectorBase } from "./rpc/index.mjs";
4
4
  import { defineRpcFunction } from "./index.mjs";
5
5
  import { t as DEVFRAME_EVENTS } from "./events-0wDwalmL.mjs";
6
6
  import { DEVFRAME_SERVICES_STATE_KEY } from "./constants.mjs";
7
- import { t as diagnostics$1 } from "./diagnostics-Cx4_VjlG.mjs";
8
- import { r as createEventEmitter, t as DevframeAgentHost } from "./host-agent-CJu735ch.mjs";
9
- import { n as createDebug, t as resolveStaticAssetsSource } from "./remote-assets-B9MeWmW6.mjs";
10
- import { t as createStorage } from "./storage-DPoitS2X.mjs";
7
+ import { t as diagnostics$1 } from "./diagnostics-BJjvKfVK.mjs";
8
+ import { i as DevframeAgentHost, n as removeClientAgentSession, o as createEventEmitter, r as syncClientAgentTools } from "./client-agent-DuLhUF6d.mjs";
9
+ import { n as createDebug, t as resolveStaticAssetsSource } from "./remote-assets-DOva7l3s.mjs";
10
+ import { t as createStorage } from "./storage-BzAr-S6I.mjs";
11
11
  import { a as satisfiesVersionRange, n as expandResolveFrom, r as importServicePackage, t as deepMergeOptionSets } from "./services-install-D5YUwFXW.mjs";
12
12
  import { isAbsolute, join, relative } from "pathe";
13
13
  import { createSharedState } from "devframe/utils/shared-state";
@@ -32,46 +32,6 @@ var DevframeDiagnosticsHost = class {
32
32
  }
33
33
  };
34
34
  //#endregion
35
- //#region src/node/client-agent.ts
36
- const states = /* @__PURE__ */ new WeakMap();
37
- function getState(context) {
38
- let state = states.get(context);
39
- if (state) return state;
40
- const sessions = /* @__PURE__ */ new Map();
41
- state = {
42
- sessions,
43
- notifyChanged: context.agent.registerToolProvider(() => {
44
- const tools = /* @__PURE__ */ new Map();
45
- for (const { session, tools: manifests } of sessions.values()) for (const manifest of manifests) {
46
- if (tools.has(manifest.id)) continue;
47
- tools.set(manifest.id, {
48
- ...manifest,
49
- handler: (args) => session.rpc.$callRaw({
50
- method: "devframe:agent:invoke-client-tool",
51
- args: [manifest.id, args]
52
- })
53
- });
54
- }
55
- return [...tools.values()];
56
- }).notifyChanged
57
- };
58
- states.set(context, state);
59
- return state;
60
- }
61
- function syncClientAgentTools(context, session, clientId, tools) {
62
- const state = getState(context);
63
- state.sessions.set(session.meta, {
64
- session,
65
- clientId,
66
- tools
67
- });
68
- state.notifyChanged();
69
- }
70
- function removeClientAgentSession(context, meta) {
71
- const state = states.get(context);
72
- if (state?.sessions.delete(meta)) state.notifyChanged();
73
- }
74
- //#endregion
75
35
  //#region src/node/rpc-shared-state.ts
76
36
  const debug$2 = createDebug("devframe:rpc:state:changed");
77
37
  const debugSubscribe = createDebug("devframe:rpc:state:subscribe");
@@ -1261,9 +1221,9 @@ const BUILTIN_AGENT_RPC = [
1261
1221
  name: "devframe:agent:sync-client-tools",
1262
1222
  type: "action",
1263
1223
  jsonSerializable: true,
1264
- setup: (context) => ({ handler(clientId, tools) {
1224
+ setup: (context) => ({ handler(clientId, tools, info) {
1265
1225
  const session = context.rpc.getCurrentRpcSession();
1266
- if (session) syncClientAgentTools(context, session, clientId, tools);
1226
+ if (session) syncClientAgentTools(context, session, clientId, tools, info);
1267
1227
  } })
1268
1228
  })
1269
1229
  ];