@wrongstack/cli 1.0.3 → 1.0.6

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 (83) hide show
  1. package/dist/{acp-JK4ZQO3R.js → acp-GOQURNC2.js} +128 -43
  2. package/dist/acp-agent-list.d.ts +14 -0
  3. package/dist/acp-hq-telemetry.d.ts +9 -2
  4. package/dist/acp-mcp-servers.d.ts +49 -0
  5. package/dist/acp-server-agent.d.ts +18 -6
  6. package/dist/{auth-XD3GN5RJ.js → auth-WBXXIQUO.js} +3 -3
  7. package/dist/boot/short-circuit-desktop.d.ts +1 -0
  8. package/dist/boot/short-circuit-hq.d.ts +2 -0
  9. package/dist/boot/tool-registry.d.ts +18 -1
  10. package/dist/{chunk-JHPXJRRI.js → chunk-4XCBEUBX.js} +13 -3
  11. package/dist/{chunk-ONOT5OJ2.js → chunk-5A5GCSJC.js} +1 -1
  12. package/dist/chunk-5EA6OTLJ.js +239 -0
  13. package/dist/{chunk-O4A3HHKD.js → chunk-672UXYL3.js} +2 -2
  14. package/dist/{chunk-FPIWTJ2G.js → chunk-6WRKAACA.js} +4 -4
  15. package/dist/chunk-AUQDGU5D.js +32 -0
  16. package/dist/{chunk-VOTTENR5.js → chunk-CDY4D5QK.js} +2 -2
  17. package/dist/{chunk-E6RFXHWD.js → chunk-EK2P53GL.js} +3 -2
  18. package/dist/{chunk-MXEJEYT7.js → chunk-JX6KL7OF.js} +15 -5
  19. package/dist/{chunk-GMY45LO6.js → chunk-KEPABQYT.js} +101 -2
  20. package/dist/{chunk-IMWXXF4J.js → chunk-KNMIBKLV.js} +79 -1
  21. package/dist/{chunk-4NHD5OXJ.js → chunk-NR7BD73C.js} +5 -5
  22. package/dist/{chunk-C2E24IXZ.js → chunk-PQZPHGGD.js} +272 -299
  23. package/dist/chunk-Q7E3BPDU.js +62 -0
  24. package/dist/{chunk-IUEKNHPT.js → chunk-QDQPF4PB.js} +11 -11
  25. package/dist/{chunk-VFCJOWJB.js → chunk-VPS2SJW4.js} +4 -5
  26. package/dist/{chunk-U6KCWRMC.js → chunk-XJ7K67PP.js} +5 -1
  27. package/dist/{cli-context-Q6QP534K.js → cli-context-BYKJDAFF.js} +129 -25
  28. package/dist/{cli-main-JQXCDZEA.js → cli-main-5WZBH3WA.js} +1345 -800
  29. package/dist/{diag-doctor-7LYUYU35.js → diag-doctor-PCER6KHH.js} +2 -2
  30. package/dist/{execution-KH7WJNAX.js → execution-Z6A26EG6.js} +132 -40
  31. package/dist/execution-specialist-trigger.d.ts +28 -0
  32. package/dist/fleet/acp-live-progress.d.ts +19 -0
  33. package/dist/fleet/host-acp-runner-cache.d.ts +3 -1
  34. package/dist/fleet/host-acp.d.ts +14 -2
  35. package/dist/fleet/host.d.ts +1 -0
  36. package/dist/{hq-IG3YRGCO.js → hq-V4PHEETW.js} +127 -8
  37. package/dist/hq-command-controller.d.ts +31 -2
  38. package/dist/hq-server/auth-state.d.ts +6 -0
  39. package/dist/hq-server/auth.d.ts +10 -1
  40. package/dist/hq-server/client-address.d.ts +2 -0
  41. package/dist/hq-server/ip-allowlist.d.ts +16 -0
  42. package/dist/hq-server/preflight.d.ts +1 -0
  43. package/dist/hq-server/routes/auth/common.d.ts +34 -0
  44. package/dist/hq-server/routes/auth/password-routes.d.ts +4 -2
  45. package/dist/hq-server/routes.d.ts +5 -4
  46. package/dist/hq-server/secret-input.d.ts +7 -0
  47. package/dist/hq-server/types.d.ts +21 -2
  48. package/dist/hq-server/upgrade-handler.d.ts +2 -0
  49. package/dist/hq-server/utils.d.ts +6 -0
  50. package/dist/{hq-server-OILU3NPI.js → hq-server-MZ7DV6X7.js} +4 -3
  51. package/dist/hq-server.d.ts +4 -0
  52. package/dist/hq-service-L5INQFM4.js +507 -0
  53. package/dist/hq-service.d.ts +22 -0
  54. package/dist/index.js +9 -6
  55. package/dist/ip-allowlist-NHXO6AKJ.js +9 -0
  56. package/dist/live-settings-input.d.ts +2 -0
  57. package/dist/{mcp-HOMLC4WE.js → mcp-FX7TKPTV.js} +10 -8
  58. package/dist/mcp-serve.d.ts +31 -0
  59. package/dist/{per-subcommand-help-BWBHYVJO.js → per-subcommand-help-DHTYU524.js} +2 -2
  60. package/dist/{plugins-U7KGQAUG.js → plugins-WJLW6ULV.js} +2 -2
  61. package/dist/projects-LMNAGGEU.js +36 -0
  62. package/dist/{proxy-wiring-MGRSKZZB.js → proxy-wiring-K2DORFFL.js} +3 -3
  63. package/dist/short-circuit-flags-KBTYSJTW.js +10 -0
  64. package/dist/slash-commands/acp.d.ts +3 -0
  65. package/dist/slash-commands/command-context.d.ts +22 -0
  66. package/dist/slash-commands/ensemble.d.ts +1 -1
  67. package/dist/slash-commands/profile.d.ts +7 -0
  68. package/dist/subcommands/handlers/hq.d.ts +1 -0
  69. package/dist/subcommands/handlers/projects.d.ts +14 -0
  70. package/dist/{subcommands-CUTGBDKP.js → subcommands-DEYSYHIM.js} +2 -2
  71. package/dist/{version-help-MYKF724O.js → version-help-WXI42PZ3.js} +2 -2
  72. package/dist/{webui-server-QWBUT7BO.js → webui-server-OBV5JYJV.js} +9 -3
  73. package/dist/wiring/cli-slash-commands-setup.d.ts +7 -0
  74. package/dist/wiring/codebase-embeddings.d.ts +2 -2
  75. package/dist/wiring/command-host-state.d.ts +7 -0
  76. package/dist/wiring/pipeline.d.ts +2 -0
  77. package/dist/wiring/provider-runtime-setup.d.ts +1 -1
  78. package/dist/wiring/session-command-handlers.d.ts +2 -1
  79. package/dist/wiring/slash-commands.d.ts +1 -0
  80. package/package.json +28 -28
  81. package/dist/chunk-Q5GTM25S.js +0 -17
  82. package/dist/projects-L6C6XLDY.js +0 -37
  83. package/dist/short-circuit-flags-ZNZX44MC.js +0 -10
@@ -1,9 +1,10 @@
1
1
  import {
2
2
  createGracefulShutdown,
3
+ formatAcpAgentList,
3
4
  loadCachedAcpRegistry,
4
5
  refreshAcpRegistry,
5
6
  setupProvider
6
- } from "./chunk-GMY45LO6.js";
7
+ } from "./chunk-KEPABQYT.js";
7
8
  import {
8
9
  startCliHqConnection
9
10
  } from "./chunk-TE3Q32JP.js";
@@ -89,14 +90,15 @@ function startAcpHqTelemetry(options) {
89
90
  };
90
91
  return {
91
92
  wrapAgentFactory(agentFor) {
92
- const wrapped = async (sessionId, cwd, api) => {
93
- const agent = await agentFor(sessionId, cwd, api);
93
+ const wrapped = async (sessionId, cwd, ...rest) => {
94
+ const agent = await agentFor(sessionId, cwd, ...rest);
94
95
  try {
95
96
  attach(sessionId, agent, cwd);
96
97
  } catch {
97
98
  }
98
99
  return agent;
99
100
  };
101
+ Object.assign(wrapped, agentFor);
100
102
  return wrapped;
101
103
  },
102
104
  wrapDispose(dispose) {
@@ -120,7 +122,6 @@ function startAcpHqTelemetry(options) {
120
122
  // src/acp-server-agent.ts
121
123
  import { Agent, Context, createDefaultPipelines } from "@wrongstack/core/agent";
122
124
  import { ToolExecutor } from "@wrongstack/core/execution";
123
- import { wireKanbanPorts } from "@wrongstack/runtime";
124
125
  import { DefaultLogger, DefaultTokenCounter } from "@wrongstack/core/infrastructure";
125
126
  import { EventBus, TOKENS } from "@wrongstack/core/kernel";
126
127
  import { ToolRegistry } from "@wrongstack/core/registry";
@@ -128,7 +129,65 @@ import { AutoApprovePermissionPolicy, ToolCapabilities } from "@wrongstack/core/
128
129
  import {
129
130
  ToolValidationError
130
131
  } from "@wrongstack/core/types";
131
- import { createDefaultContainer } from "@wrongstack/runtime";
132
+ import { createDefaultContainer, wireKanbanPorts } from "@wrongstack/runtime";
133
+
134
+ // src/acp-mcp-servers.ts
135
+ import { MCPRegistry } from "@wrongstack/mcp";
136
+ function pairsToRecord(pairs) {
137
+ if (!pairs || pairs.length === 0) return void 0;
138
+ const out = {};
139
+ for (const { name, value } of pairs) out[name] = value;
140
+ return out;
141
+ }
142
+ function acpMcpServerToConfig(server) {
143
+ const type = "type" in server ? server.type : "stdio";
144
+ if (type === "http" || type === "sse") {
145
+ const headers = pairsToRecord(
146
+ server.headers
147
+ );
148
+ return {
149
+ name: server.name,
150
+ transport: type === "http" ? "streamable-http" : "sse",
151
+ url: server.url,
152
+ ...headers ? { headers } : {},
153
+ description: "Supplied by the ACP client for this session."
154
+ };
155
+ }
156
+ const stdio = server;
157
+ const env = pairsToRecord(server.env);
158
+ return {
159
+ name: server.name,
160
+ transport: "stdio",
161
+ command: stdio.command,
162
+ ...stdio.args && stdio.args.length > 0 ? { args: [...stdio.args] } : {},
163
+ ...env ? { env } : {},
164
+ description: "Supplied by the ACP client for this session."
165
+ };
166
+ }
167
+ async function connectAcpSessionMcpServers(opts) {
168
+ if (opts.servers.length === 0) return void 0;
169
+ const registry = new MCPRegistry({
170
+ toolRegistry: opts.toolRegistry,
171
+ events: opts.events,
172
+ log: opts.logger,
173
+ // Eager, not lazy: the tool list has to be complete before the session's
174
+ // Context snapshots `listForProvider()`, which happens immediately below
175
+ // this call. A lazily registered tool would exist in the registry but be
176
+ // absent from the very first turn's provider payload.
177
+ lazyMode: false,
178
+ ...opts.cacheDir ? { cacheDir: opts.cacheDir } : {}
179
+ });
180
+ for (const server of opts.servers) {
181
+ try {
182
+ await registry.start(acpMcpServerToConfig(server));
183
+ } catch (err) {
184
+ opts.logger.warn(`ACP client MCP server "${server.name}" failed to start`, err);
185
+ }
186
+ }
187
+ return registry;
188
+ }
189
+
190
+ // src/acp-server-agent.ts
132
191
  var AcpServerConfigError = class extends Error {
133
192
  constructor(message) {
134
193
  super(message);
@@ -311,7 +370,8 @@ function buildAcpServerAgentFactory(deps, options = {}) {
311
370
  logger,
312
371
  modelsRegistry: deps.modelsRegistry
313
372
  });
314
- return async function agentFor(_sessionId, cwd, api) {
373
+ const sessionMcp = /* @__PURE__ */ new Map();
374
+ const agentFor = async function agentFor2(sessionId, cwd, api, mcpServers) {
315
375
  await container.resolve(TOKENS.MemoryStore).initialize();
316
376
  const { provider, providerRegistry } = await bootProvider();
317
377
  const events = new EventBus();
@@ -321,6 +381,19 @@ function buildAcpServerAgentFactory(deps, options = {}) {
321
381
  if (api) {
322
382
  wireClientBackedTools(tools, api);
323
383
  }
384
+ if (mcpServers && mcpServers.length > 0) {
385
+ const previous = sessionMcp.get(sessionId);
386
+ if (previous) void previous.stopAll().catch(() => {
387
+ });
388
+ const mcp = await connectAcpSessionMcpServers({
389
+ servers: mcpServers,
390
+ toolRegistry: tools,
391
+ events,
392
+ logger,
393
+ ...wpaths.cacheDir ? { cacheDir: wpaths.cacheDir } : {}
394
+ });
395
+ if (mcp) sessionMcp.set(sessionId, mcp);
396
+ }
324
397
  const permissionPolicy = api?.requestPermission ? new ACPClientPermissionPolicy(api.requestPermission) : new AutoApprovePermissionPolicy();
325
398
  const tokenCounter = new DefaultTokenCounter({
326
399
  registry: deps.modelsRegistry,
@@ -366,9 +439,25 @@ function buildAcpServerAgentFactory(deps, options = {}) {
366
439
  context,
367
440
  permissionPolicy,
368
441
  toolExecutor,
369
- loopDetection: config.tools?.loopDetection
442
+ loopDetection: config.tools?.loopDetection,
443
+ // `tools.maxIterations` was never read on this host, so an operator who
444
+ // set a turn budget got it honoured on the CLI and WebUI hosts and
445
+ // silently ignored here. Only a POSITIVE value is forwarded: the shipped
446
+ // default is `0` ("no hard limit"), and handing that to the agent loop
447
+ // would trade a missing setting for a missing safety net. Absent an
448
+ // explicit budget the Agent keeps its own DEFAULT_MAX_ITERATIONS.
449
+ ...typeof config.tools?.maxIterations === "number" && Number.isFinite(config.tools.maxIterations) && config.tools.maxIterations > 0 ? { maxIterations: config.tools.maxIterations } : {}
370
450
  });
371
451
  };
452
+ agentFor.disposeSession = (sessionId) => {
453
+ const mcp = sessionMcp.get(sessionId);
454
+ if (!mcp) return;
455
+ sessionMcp.delete(sessionId);
456
+ void mcp.stopAll().catch((err) => {
457
+ logger.warn(`ACP session ${sessionId}: MCP teardown failed`, err);
458
+ });
459
+ };
460
+ return agentFor;
372
461
  }
373
462
 
374
463
  // src/subcommands/handlers/acp-connection-gate.ts
@@ -516,10 +605,20 @@ function parseWsPort(flag) {
516
605
  const n = Number(flag);
517
606
  return Number.isInteger(n) && n > 0 && n < 65536 ? n : 8889;
518
607
  }
608
+ function composeDispose(disposeTurn, factory) {
609
+ return (sessionId) => {
610
+ try {
611
+ disposeTurn(sessionId);
612
+ } finally {
613
+ factory?.disposeSession(sessionId);
614
+ }
615
+ };
616
+ }
519
617
  async function runACPWebSocketServer(deps, port) {
520
618
  const host = "127.0.0.1";
521
619
  const echo = deps.flags?.echo === true || deps.flags?.echo === "true";
522
620
  let turnFactory;
621
+ let wsAgentFactory;
523
622
  let echoTurn;
524
623
  let store;
525
624
  let hqTelemetry;
@@ -543,19 +642,23 @@ async function runACPWebSocketServer(deps, port) {
543
642
  appConfig: deps.config
544
643
  });
545
644
  const tracked = hqTelemetry.wrapAgentFactory(agentFor);
645
+ wsAgentFactory = agentFor;
546
646
  turnFactory = () => makeACPServerAgentTurn({ agentFor: tracked });
547
647
  store = deps.paths?.projectDir ? new ACPSessionStore({ dir: path.join(deps.paths.projectDir, "acp-sessions") }) : void 0;
548
648
  }
549
649
  const acpToken = process.env["WRONGSTACK_ACP_TOKEN"]?.trim() || randomBytes(32).toString("hex");
550
650
  const gate = createAcpConnectionGate({ host, port, token: acpToken });
551
651
  let liveConnections = 0;
552
- const wss = new WebSocketServer({ host, port, maxPayload: 20 * 1024 * 1024 });
553
- wss.on("connection", (socket, req) => {
554
- const verdict = gate.check(req, liveConnections);
555
- if (!verdict.ok) {
556
- socket.close(verdict.code ?? 1008, verdict.reason ?? "forbidden");
652
+ const verifyClient = (info, cb) => {
653
+ const verdict = gate.check(info.req, liveConnections);
654
+ if (verdict.ok) {
655
+ cb(true);
557
656
  return;
558
657
  }
658
+ cb(false, 403, verdict.reason ?? "forbidden");
659
+ };
660
+ const wss = new WebSocketServer({ host, port, maxPayload: 20 * 1024 * 1024, verifyClient });
661
+ wss.on("connection", (socket) => {
559
662
  liveConnections++;
560
663
  socket.once("close", () => {
561
664
  liveConnections--;
@@ -576,7 +679,10 @@ async function runACPWebSocketServer(deps, port) {
576
679
  ...connectionTurn ? {
577
680
  replayFor: connectionTurn.replay,
578
681
  seedFor: connectionTurn.seed,
579
- disposeFor: hqTelemetry?.wrapDispose(connectionTurn.dispose) ?? connectionTurn.dispose
682
+ disposeFor: composeDispose(
683
+ hqTelemetry?.wrapDispose(connectionTurn.dispose) ?? connectionTurn.dispose,
684
+ wsAgentFactory
685
+ )
580
686
  } : {},
581
687
  ...store ? { store } : {}
582
688
  });
@@ -651,6 +757,7 @@ async function runACPServer(deps) {
651
757
  projectName: path.basename(deps.cwd ?? process.cwd()),
652
758
  appConfig: deps.config
653
759
  });
760
+ const stdioAgentFactory = agentFor;
654
761
  const turn = makeACPServerAgentTurn({
655
762
  agentFor: stdioHqTelemetry.wrapAgentFactory(agentFor)
656
763
  });
@@ -659,7 +766,10 @@ async function runACPServer(deps) {
659
766
  runTurn: turn,
660
767
  replayFor: turn.replay,
661
768
  seedFor: turn.seed,
662
- disposeFor: stdioHqTelemetry.wrapDispose(turn.dispose),
769
+ disposeFor: composeDispose(
770
+ stdioHqTelemetry.wrapDispose(turn.dispose),
771
+ stdioAgentFactory
772
+ ),
663
773
  ...store ? { store } : {}
664
774
  };
665
775
  })()
@@ -702,35 +812,10 @@ async function runACPServer(deps) {
702
812
  return 0;
703
813
  }
704
814
  async function listACPAgents(deps) {
705
- const registry = new EnsembleRegistry();
706
- const detected = await registry.list();
707
- deps.renderer.write("Detected ACP agents:\n\n");
708
- const installed = detected.filter((a) => a.installed);
709
- const missing = detected.filter((a) => !a.installed);
710
- for (const a of installed) {
711
- const ver = a.version ? ` (${a.version.split("\n")[0]})` : "";
712
- deps.renderer.write(` \u2713 ${a.id.padEnd(16)} ${a.displayName}${ver}
713
- `);
714
- }
715
- for (const a of missing) {
716
- deps.renderer.write(
717
- ` \u2717 ${a.id.padEnd(16)} ${a.displayName} (${a.reason ?? "not installed"})
718
- `
719
- );
720
- }
721
- deps.renderer.write(`
722
- ${installed.length} of ${detected.length} agents available.
723
- `);
815
+ const detected = await new EnsembleRegistry().list();
724
816
  const live = await loadLive(deps);
725
- if (live && live.agents.length > 0) {
726
- deps.renderer.write(
727
- `Synced registry: ${live.agents.length} agents available (run \`wstack acp spawn <id> <task>\`).
728
- `
729
- );
730
- } else {
731
- deps.renderer.write("Run `wstack acp sync` to pull the full official registry (37+ agents).\n");
732
- }
733
- deps.renderer.write("Use `wstack acp spawn <agent-id> <task>` to delegate a task.\n");
817
+ deps.renderer.write(`${formatAcpAgentList({ live, detected })}
818
+ `);
734
819
  return 0;
735
820
  }
736
821
  async function syncACPRegistry(deps) {
@@ -1017,4 +1102,4 @@ ${renderAcpBenchText(result)}
1017
1102
  export {
1018
1103
  acpCmd
1019
1104
  };
1020
- //# sourceMappingURL=acp-JK4ZQO3R.js.map
1105
+ //# sourceMappingURL=acp-GOQURNC2.js.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Shared `/acp` + `wstack acp list` renderer.
3
+ *
4
+ * After `sync`, the official registry is the list the user sees — not the
5
+ * 13-entry bundled offline catalog (which still includes experimental ids
6
+ * that are not in https://github.com/agentclientprotocol/registry).
7
+ */
8
+ import { type DetectedAgent } from '@wrongstack/acp';
9
+ import type { LoadedAcpRegistry } from './acp-registry-cache.js';
10
+ export declare function formatAcpAgentList(opts: {
11
+ live: LoadedAcpRegistry | null;
12
+ detected: readonly DetectedAgent[];
13
+ }): string;
14
+ //# sourceMappingURL=acp-agent-list.d.ts.map
@@ -23,8 +23,15 @@
23
23
  */
24
24
  import type { Agent } from '@wrongstack/core/agent';
25
25
  import type { Config } from '@wrongstack/core/types';
26
- /** The per-session Agent factory shape `makeACPServerAgentTurn` consumes. */
27
- type AcpAgentFactory = (sessionId: string, cwd: string, api?: never) => Promise<Agent>;
26
+ /**
27
+ * The per-session Agent factory shape `makeACPServerAgentTurn` consumes.
28
+ *
29
+ * Typed on `...args` rather than a fixed parameter list on purpose: the
30
+ * wrapper below must forward every argument the adapter passes, and the list
31
+ * has grown (it now carries the client's `mcpServers`). A wrapper that names
32
+ * its parameters silently drops the ones added after it was written.
33
+ */
34
+ type AcpAgentFactory = (sessionId: string, cwd: string, ...rest: never[]) => Promise<Agent>;
28
35
  export interface AcpHqTelemetryOptions {
29
36
  projectRoot: string;
30
37
  projectName?: string | undefined;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Client-supplied MCP servers for ACP sessions.
3
+ *
4
+ * The ACP spec lets a client hand the agent a list of MCP servers with
5
+ * `session/new` (and `session/load` / `session/fork`): the editor owns the
6
+ * user's MCP configuration, and the agent is expected to connect to those
7
+ * servers and expose their tools for the session's lifetime.
8
+ *
9
+ * WrongStack advertised `mcpCapabilities: {http: false, sse: false}` and then
10
+ * destructured `mcpServers` at every entry point without ever reading it — so
11
+ * even the mandatory stdio transport was silently dropped. A client got a
12
+ * successful `session/new` and no tools, with nothing anywhere saying why.
13
+ * This module is the missing half: it maps the ACP wire shape onto
14
+ * `MCPServerConfig` and drives a per-session `MCPRegistry` whose tools land in
15
+ * that session's own `ToolRegistry` clone.
16
+ *
17
+ * Per-session, not per-process, deliberately: two ACP sessions may ask for
18
+ * different servers, and closing one must not tear down the other's.
19
+ */
20
+ import type { McpServer } from '@wrongstack/acp/agent';
21
+ import type { EventBus } from '@wrongstack/core/kernel';
22
+ import type { ToolRegistry } from '@wrongstack/core/registry';
23
+ import type { Logger, MCPServerConfig } from '@wrongstack/core/types';
24
+ import { MCPRegistry } from '@wrongstack/mcp';
25
+ /**
26
+ * Translate one ACP server entry into the config shape `MCPRegistry` consumes.
27
+ *
28
+ * Transport names differ between the two specs: ACP's `http` is MCP's
29
+ * `streamable-http`, and an entry with no `type` is stdio (the spec's default,
30
+ * and the only transport a client may assume).
31
+ */
32
+ export declare function acpMcpServerToConfig(server: McpServer): MCPServerConfig;
33
+ export interface AcpSessionMcpOptions {
34
+ servers: readonly McpServer[];
35
+ toolRegistry: ToolRegistry;
36
+ events: EventBus;
37
+ logger: Logger;
38
+ cacheDir?: string | undefined;
39
+ }
40
+ /**
41
+ * Connect the session's MCP servers and register their tools.
42
+ *
43
+ * Returns the registry so the caller can stop it when the session ends, or
44
+ * `undefined` when the client asked for nothing. A server that fails to start
45
+ * is logged and skipped — one unreachable server must not cost the client its
46
+ * whole session, and the failure is visible in `wstack mcp` health output.
47
+ */
48
+ export declare function connectAcpSessionMcpServers(opts: AcpSessionMcpOptions): Promise<MCPRegistry | undefined>;
49
+ //# sourceMappingURL=acp-mcp-servers.d.ts.map
@@ -8,12 +8,14 @@
8
8
  * module is that factory, reusing the same boot pieces the interactive CLI
9
9
  * uses (`setupProvider`, `createDefaultContainer`, builtin tools).
10
10
  *
11
- * Scope: a minimal but real agent. It deliberately does NOT wire MCP servers,
12
- * compaction middleware, model-runtime overlays, or lifecycle hooks — those
13
- * belong in the interactive host. The ACP server is a headless single-turn
14
- * surface; a future PR can layer richer session behaviour if needed.
11
+ * Scope: a minimal but real agent. It deliberately does NOT wire compaction
12
+ * middleware, model-runtime overlays, or lifecycle hooks — those belong in the
13
+ * interactive host. It DOES wire the MCP servers the ACP client supplies with
14
+ * `session/new`, because the spec makes those part of the session contract:
15
+ * the client hands over its MCP configuration and expects the tools to be
16
+ * there (see `acp-mcp-servers.ts`).
15
17
  */
16
- import type { RunTurnApi } from '@wrongstack/acp/agent';
18
+ import type { McpServer, RunTurnApi } from '@wrongstack/acp/agent';
17
19
  import { Agent } from '@wrongstack/core/agent';
18
20
  import { type Logger, type PermissionDecision, type PermissionPolicy, type Tool } from '@wrongstack/core/types';
19
21
  import type { SubcommandDeps } from './subcommands/contracts.js';
@@ -25,6 +27,16 @@ import type { SubcommandDeps } from './subcommands/contracts.js';
25
27
  export declare class AcpServerConfigError extends Error {
26
28
  constructor(message: string);
27
29
  }
30
+ /**
31
+ * The per-session Agent factory, plus the teardown hook for anything the
32
+ * session owns outside the Agent itself (currently the client's MCP servers).
33
+ * `dispose` on the turn adapter drops the Agent; this drops the connections.
34
+ */
35
+ export interface AcpServerAgentFactory {
36
+ (sessionId: string, cwd: string, api?: RunTurnApi, mcpServers?: readonly McpServer[]): Promise<Agent>;
37
+ /** Stop and forget the MCP servers connected for this ACP session. */
38
+ disposeSession(sessionId: string): void;
39
+ }
28
40
  interface AcpAgentFactoryOptions {
29
41
  /** Caller-supplied logger; a minimal stderr logger is created when omitted. */
30
42
  logger?: Logger | undefined;
@@ -63,6 +75,6 @@ export declare class ACPClientPermissionPolicy implements PermissionPolicy {
63
75
  *
64
76
  * Throws `AcpServerConfigError` up front if no provider is configured.
65
77
  */
66
- export declare function buildAcpServerAgentFactory(deps: SubcommandDeps, options?: AcpAgentFactoryOptions): (sessionId: string, cwd: string, api?: RunTurnApi) => Promise<Agent>;
78
+ export declare function buildAcpServerAgentFactory(deps: SubcommandDeps, options?: AcpAgentFactoryOptions): AcpServerAgentFactory;
67
79
  export {};
68
80
  //# sourceMappingURL=acp-server-agent.d.ts.map
@@ -14,7 +14,7 @@ import {
14
14
  runOAuthLoginKind,
15
15
  runOAuthLoginMenu,
16
16
  validateFamily
17
- } from "./chunk-ONOT5OJ2.js";
17
+ } from "./chunk-5A5GCSJC.js";
18
18
  import {
19
19
  renderAuthLocalHelpToString,
20
20
  wantsLocalHelp
@@ -29,7 +29,7 @@ import {
29
29
  } from "./chunk-YMXXOOFN.js";
30
30
  import {
31
31
  parseAuthFlags
32
- } from "./chunk-E6RFXHWD.js";
32
+ } from "./chunk-EK2P53GL.js";
33
33
  import "./chunk-SIGUWXAA.js";
34
34
  import "./chunk-DAKVBMD4.js";
35
35
  import {
@@ -619,4 +619,4 @@ async function runAuthRemove(deps, providerId) {
619
619
  export {
620
620
  authCmd
621
621
  };
622
- //# sourceMappingURL=auth-XD3GN5RJ.js.map
622
+ //# sourceMappingURL=auth-WBXXIQUO.js.map
@@ -1,3 +1,4 @@
1
1
  export declare function stripDesktopLauncherArgs(argv: string[]): string[];
2
+ export declare function selectDesktopLauncherExecutable(execPath: string, runningUnderBun: boolean, nodeOverride?: string): string;
2
3
  export declare function handleDesktopShortCircuit(flags: Record<string, string | boolean>, argv: string[]): Promise<number | null>;
3
4
  //# sourceMappingURL=short-circuit-desktop.d.ts.map
@@ -7,6 +7,8 @@
7
7
  * Returns 0 when the HQ flag was present and the server ran, or null
8
8
  * when the flag was absent (caller should proceed to boot()).
9
9
  */
10
+ /** Detect a PID-namespace collision with a marker left by a prior container. */
11
+ export declare function isReusedContainerPid(markerPid: number | undefined, containerMode: string | undefined, currentPid?: number): boolean;
10
12
  /**
11
13
  * Check for --hq flag and start the HQ server if present.
12
14
  *
@@ -1,7 +1,7 @@
1
1
  /** CLI boot adapter for canonical runtime tool registration and host policies. */
2
2
  import type { EventBus } from '@wrongstack/core/kernel';
3
3
  import type { ToolRegistry } from '@wrongstack/core/registry';
4
- import type { AutoThinConfig, DisabledToolMeta, MemoryPort, TokenSavingTier, ToolDescriptionModeConfig, ToolResultRenderModeConfig } from '@wrongstack/core/types';
4
+ import type { AutoThinConfig, ConcreteTokenSavingTier, DisabledToolMeta, MemoryPort, TokenSavingTier, ToolDescriptionModeConfig, ToolResultRenderModeConfig } from '@wrongstack/core/types';
5
5
  import type { WstackPaths } from '@wrongstack/core/utils';
6
6
  import type { VectorMemoryStore } from '@wrongstack/vector-memory';
7
7
  interface RegisterBuiltinToolsDeps {
@@ -36,6 +36,23 @@ interface RegisterBuiltinToolsDeps {
36
36
  } | undefined;
37
37
  } | undefined;
38
38
  };
39
+ /**
40
+ * The concrete tier this session runs at, resolved ONCE by the caller.
41
+ *
42
+ * `features.tokenSavingMode` defaults to `'auto'`, and `'auto'` has two
43
+ * different expansions: `normalizeTokenSavingTier` (window-blind, always
44
+ * `'medium'`) and `resolveTokenSavingTier` (window-aware — `'minimal'` on a
45
+ * modern window). The prompt builder uses the second. Letting this function
46
+ * fall back to the first meant every default session shipped a `'minimal'`
47
+ * shaped prompt over a `'medium'` tool surface: the two halves of one tier
48
+ * disagreed on which tools exist.
49
+ *
50
+ * Hosts therefore resolve the tier once, from the model window they already
51
+ * know at boot, and hand the same concrete value to the registry AND to the
52
+ * prompt builder. The `normalizeTokenSavingTier` fallback below stays for
53
+ * embedders that have no window to resolve against.
54
+ */
55
+ tier?: ConcreteTokenSavingTier | undefined;
39
56
  memoryStore: MemoryPort | null | undefined;
40
57
  /**
41
58
  * Optional vector memory store. When provided, the four
@@ -129,11 +129,21 @@ function scheduleImmediateProbe(runner) {
129
129
  void runner.poke();
130
130
  }
131
131
  function buildHealthUrl(rawBase) {
132
- const trimmed = rawBase.trim().replace(/\/+$/, "");
133
- return `${trimmed}${HEALTH_PATH}`;
132
+ const trimmed = rawBase.trim();
133
+ try {
134
+ const base = new URL(trimmed);
135
+ base.search = "";
136
+ base.hash = "";
137
+ base.pathname = `${base.pathname.replace(/\/+$/, "")}${HEALTH_PATH}`;
138
+ return base.toString();
139
+ } catch {
140
+ const boundary = trimmed.search(/[?#]/);
141
+ const pathBase = boundary === -1 ? trimmed : trimmed.slice(0, boundary);
142
+ return `${pathBase.replace(/\/+$/, "")}${HEALTH_PATH}`;
143
+ }
134
144
  }
135
145
 
136
146
  export {
137
147
  startProxyProbe
138
148
  };
139
- //# sourceMappingURL=chunk-JHPXJRRI.js.map
149
+ //# sourceMappingURL=chunk-4XCBEUBX.js.map
@@ -1813,4 +1813,4 @@ export {
1813
1813
  addCustomProvider,
1814
1814
  addKeyForProvider
1815
1815
  };
1816
- //# sourceMappingURL=chunk-ONOT5OJ2.js.map
1816
+ //# sourceMappingURL=chunk-5A5GCSJC.js.map