@wrongstack/cli 0.319.0 → 1.0.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 (113) hide show
  1. package/data/providers.json +22 -15
  2. package/dist/{acp-5ANIAOZC.js → acp-3LARESEO.js} +113 -10
  3. package/dist/acp-hq-telemetry.d.ts +44 -0
  4. package/dist/{audit-ZPCLCC3C.js → audit-46YK5DSC.js} +1 -2
  5. package/dist/{auth-KF5TAD7V.js → auth-KIBJZZIE.js} +5 -6
  6. package/dist/auth-menu/add-provider.d.ts +7 -0
  7. package/dist/auth-menu/panel-service.d.ts +2 -20
  8. package/dist/{auto-discover-providers-MHFLDSD3.js → auto-discover-providers-VQU3IZMR.js} +1 -2
  9. package/dist/{bench-XYG56AMO.js → bench-YBU6BVQP.js} +175 -35
  10. package/dist/boot/brain-decision-log.d.ts +22 -2
  11. package/dist/{boot-auto-thin-BZ675EVT.js → boot-auto-thin-MANHOYHE.js} +1 -2
  12. package/dist/{chronicle-6EPPMUC5.js → chronicle-UTFETHP6.js} +1 -2
  13. package/dist/{chunk-VWCZL4OH.js → chunk-4HV5RKZH.js} +5 -5
  14. package/dist/{chunk-42JD25KU.js → chunk-5IA5337I.js} +3 -3
  15. package/dist/{chunk-7JBKXVMK.js → chunk-C2E24IXZ.js} +44 -32
  16. package/dist/{chunk-7CECQDNH.js → chunk-D3K4NYQL.js} +1 -1
  17. package/dist/{chunk-XPX432BZ.js → chunk-DR2OXU46.js} +50 -39
  18. package/dist/{chunk-4JRIWVJ4.js → chunk-ERX4BLKP.js} +1 -1
  19. package/dist/chunk-ETYHZPXP.js +52 -0
  20. package/dist/{chunk-TYO2OVAD.js → chunk-EWKESL4L.js} +8 -4
  21. package/dist/{chunk-QAC263FZ.js → chunk-FPIWTJ2G.js} +2 -3
  22. package/dist/{chunk-7YLN7YUA.js → chunk-IMWXXF4J.js} +61 -9
  23. package/dist/{chunk-G7337TTK.js → chunk-IS2PPBQV.js} +1 -1
  24. package/dist/{chunk-G3IMKQRH.js → chunk-JHPXJRRI.js} +1 -1
  25. package/dist/{chunk-XHIEA6LG.js → chunk-MNQQ4ZNF.js} +26 -22
  26. package/dist/{chunk-P2OKBDCH.js → chunk-MXEJEYT7.js} +53 -14
  27. package/dist/{chunk-PCBJSXYV.js → chunk-O4A3HHKD.js} +2 -2
  28. package/dist/{chunk-XYKYXFEE.js → chunk-TE3Q32JP.js} +10 -4
  29. package/dist/{chunk-H7GABTGS.js → chunk-TEBMCYZN.js} +69 -30
  30. package/dist/{chunk-E4I2TF5S.js → chunk-TNK6237M.js} +2 -2
  31. package/dist/{chunk-SYIBTG3X.js → chunk-VOTTENR5.js} +3 -5
  32. package/dist/chunk-WHOIR577.js +1 -0
  33. package/dist/{chunk-2ZNBRZ4W.js → chunk-WQZW3RDP.js} +2 -2
  34. package/dist/{chunk-GGGUZSAU.js → chunk-Z7A5MXKJ.js} +18 -12
  35. package/dist/{chunk-F5GA2QW2.js → chunk-ZSZ3EYWH.js} +2 -2
  36. package/dist/{cli-context-LH4QP4W2.js → cli-context-CYMKNOK3.js} +58 -307
  37. package/dist/{cli-main-72XUFUCL.js → cli-main-TTIVR4DI.js} +925 -329
  38. package/dist/{diag-doctor-LFCCBPMD.js → diag-doctor-7LYUYU35.js} +4 -6
  39. package/dist/execute-deps.d.ts +5 -1
  40. package/dist/{execution-DKJDNPYF.js → execution-3Y55IWBK.js} +512 -469
  41. package/dist/{export-ROG3DKTZ.js → export-VVRIOWFV.js} +1 -2
  42. package/dist/{governance-JSGHHA2R.js → governance-RYSHV675.js} +1 -2
  43. package/dist/{hq-3GWBFLON.js → hq-IG3YRGCO.js} +2 -3
  44. package/dist/hq-command-controller.d.ts +37 -7
  45. package/dist/hq-server/routes.d.ts +1 -1
  46. package/dist/hq-server/ws.d.ts +1 -1
  47. package/dist/{hq-server-OARPUSQJ.js → hq-server-OILU3NPI.js} +2 -3
  48. package/dist/{hq-ttl-KUO3AU7X.js → hq-ttl-VJR65OBJ.js} +1 -2
  49. package/dist/{hq-tunnel-LO55RCZE.js → hq-tunnel-NIJ5EP2Y.js} +1 -2
  50. package/dist/index.js +5 -6
  51. package/dist/{init-4JQSG66Q.js → init-DRMMFG2G.js} +1 -2
  52. package/dist/{kanban-run-mirror-EKVNGXWW.js → kanban-run-mirror-22HQ5FNG.js} +1 -2
  53. package/dist/live-settings-input.d.ts +2 -0
  54. package/dist/{mailbox-serve-VKQIRCCB.js → mailbox-serve-VUCWZ2SJ.js} +2 -3
  55. package/dist/{mcp-AQKSASHD.js → mcp-HOMLC4WE.js} +1 -2
  56. package/dist/{modeldiag-5FRMT6FQ.js → modeldiag-FMJT37SN.js} +2 -3
  57. package/dist/{per-subcommand-help-6VCIKDUW.js → per-subcommand-help-BWBHYVJO.js} +2 -3
  58. package/dist/{permissions-2PWBL4YU.js → permissions-CFDLXETM.js} +1 -2
  59. package/dist/{plugin-usage-CYUORYM6.js → plugin-usage-HFBI3TFT.js} +2 -3
  60. package/dist/{plugins-RV3OBBND.js → plugins-PZ2VZL7V.js} +4 -5
  61. package/dist/{project-BLQ3ALVL.js → project-AOQI5XTK.js} +1 -2
  62. package/dist/{project-manifest-YFTJ3D5N.js → project-manifest-7NSFVBM3.js} +2 -3
  63. package/dist/{project-picker-R5TYAE3Q.js → project-picker-SVBXMPKX.js} +3 -4
  64. package/dist/{projects-5J727S4L.js → projects-L6C6XLDY.js} +1 -2
  65. package/dist/provider-config-utils.d.ts +1 -1
  66. package/dist/{providers-models-OKKQZIWU.js → providers-models-YVMVYWRS.js} +3 -4
  67. package/dist/{proxy-wiring-EQB5X5YH.js → proxy-wiring-MGRSKZZB.js} +3 -4
  68. package/dist/{quick-XLYLZX4B.js → quick-CNB4Z3HS.js} +1 -2
  69. package/dist/{replay-RZXZKP2U.js → replay-JJ2NOWD6.js} +1 -2
  70. package/dist/{replay-FJ2JBXUA.js → replay-Z3FTJEMM.js} +1 -2
  71. package/dist/{rewind-2FFNOOKS.js → rewind-JA3ZLCNM.js} +1 -2
  72. package/dist/{sdd-runtime-FLKCSTYV.js → sdd-runtime-PTOSPYI4.js} +2 -3
  73. package/dist/services/sdd-runtime.d.ts +1 -1
  74. package/dist/services/statusline-config.d.ts +43 -13
  75. package/dist/{sessions-config-KAMEBVOX.js → sessions-config-UL45XKX7.js} +2 -3
  76. package/dist/{sessions-doctor-EXHAZSSE.js → sessions-doctor-QUL37U32.js} +1 -2
  77. package/dist/short-circuit-flags-6PSP56L7.js +10 -0
  78. package/dist/{simpleui-dist-JKNRCRRK.js → simpleui-dist-CXSIDAXZ.js} +1 -2
  79. package/dist/slash-commands/command-context.d.ts +10 -0
  80. package/dist/slash-commands/sdd.d.ts +1 -1
  81. package/dist/slash-commands/statusline.d.ts +1 -1
  82. package/dist/subcommands/handlers/bench-run-config.d.ts +18 -0
  83. package/dist/subcommands/handlers/bench.d.ts +8 -7
  84. package/dist/subcommands-HZQKA4G2.js +9 -0
  85. package/dist/{tools-skills-Q4P27URS.js → tools-skills-GH24UCBY.js} +1 -2
  86. package/dist/{update-K45CS6SS.js → update-5DPB4YD4.js} +1 -2
  87. package/dist/{update-check-PKSMSMD6.js → update-check-BS3DHTSI.js} +1 -2
  88. package/dist/version-help-MYKF724O.js +10 -0
  89. package/dist/webui-server/client-registration.d.ts +9 -1
  90. package/dist/{webui-server-SY4EQCKD.js → webui-server-T6AMOXJJ.js} +54 -13
  91. package/dist/wiring/brain-and-orchestration.d.ts +2 -0
  92. package/dist/wiring/cli-execute-builder.d.ts +4 -0
  93. package/dist/wiring/cli-slash-commands-setup.d.ts +1 -0
  94. package/dist/wiring/command-host-state.d.ts +50 -5
  95. package/dist/wiring/external-plugins.d.ts +9 -0
  96. package/dist/wiring/provider-runtime-setup.d.ts +2 -0
  97. package/dist/wiring/runtime-controller-deps.d.ts +3 -0
  98. package/dist/wiring/vector-memory-setup.d.ts +12 -0
  99. package/dist/wiring/wrongtrace-gate.d.ts +2 -2
  100. package/dist/wiring/wrongtrace-hooks.d.ts +1 -1
  101. package/dist/wiring/wrongtrace-prompt-contributor.d.ts +5 -2
  102. package/dist/{wrongtrace-gate-counters-P5BCBXQN.js → wrongtrace-gate-counters-7C2EAAZL.js} +2 -3
  103. package/dist/{wrongtrace-telemetry-FNLANZ5I.js → wrongtrace-telemetry-3ASFKOZO.js} +2 -3
  104. package/package.json +28 -28
  105. package/dist/chunk-7OCVIDC7.js +0 -11
  106. package/dist/chunk-ALE5KHCA.js +0 -1
  107. package/dist/chunk-OZDE3OWD.js +0 -52
  108. package/dist/launch-hints.d.ts +0 -49
  109. package/dist/short-circuit-flags-U6CJAF6J.js +0 -11
  110. package/dist/subcommands-J4JMWC5W.js +0 -10
  111. package/dist/version-help-WMPSEL4U.js +0 -11
  112. package/dist/webui-server/privileged-actions.d.ts +0 -14
  113. package/dist/wiring/cli-heap-watchdog.d.ts +0 -34
@@ -1775,10 +1775,7 @@ function handleApiAuthAudit(_req, res, dataDir) {
1775
1775
 
1776
1776
  // src/hq-server/routes/command-handlers.ts
1777
1777
  import { randomUUID as randomUUID4 } from "node:crypto";
1778
- import {
1779
- tokenHasCapability,
1780
- validateHqCommand
1781
- } from "@wrongstack/core/hq";
1778
+ import { tokenHasCapability, validateHqCommand } from "@wrongstack/core/hq";
1782
1779
 
1783
1780
  // src/hq-server/snapshot.ts
1784
1781
  import { WebSocket } from "ws";
@@ -1872,17 +1869,9 @@ function buildSnapshot(clients, options) {
1872
1869
  project.governance = governance;
1873
1870
  }
1874
1871
  for (const tracked of client.sessions.values()) {
1875
- const cutoff = Date.now() - 5 * 6e4;
1876
- const agents = tracked.payload.agents.filter((agent) => {
1877
- if (agent.id === "leader") return true;
1878
- const lastActivityAt = Date.parse(agent.lastActivityAt);
1879
- return Number.isFinite(lastActivityAt) && lastActivityAt >= cutoff;
1880
- });
1881
1872
  sessionById.set(tracked.payload.sessionId, {
1882
1873
  ...tracked.payload,
1883
- clientId: client.clientId,
1884
- agents,
1885
- agentCount: agents.length
1874
+ clientId: client.clientId
1886
1875
  });
1887
1876
  }
1888
1877
  for (const snapshot of client.mailboxes.values()) {
@@ -2267,9 +2256,7 @@ async function authorizeHqCommand(input) {
2267
2256
 
2268
2257
  // src/hq-server/routes/mailbox-handlers.ts
2269
2258
  import * as path4 from "node:path";
2270
- import {
2271
- resolveProjectDir
2272
- } from "@wrongstack/core/coordination";
2259
+ import { resolveProjectDir } from "@wrongstack/core/coordination";
2273
2260
 
2274
2261
  // src/hq-server/project-root.ts
2275
2262
  import { deriveHqProjectId } from "@wrongstack/core/hq";
@@ -2435,6 +2422,7 @@ async function handleApiMailboxSend(_req, res, mutableAuth, sessions, dataDir, g
2435
2422
  const mailbox = getMailboxGateway(projectDir).mailbox;
2436
2423
  const from = `hq@${hqSessionTag}`;
2437
2424
  const deliveryTo = mailboxType === "broadcast" ? "all" : to;
2425
+ const scopeSessionId = typeof mbody.sessionId === "string" && mbody.sessionId.length > 0 && deliveryTo.trim().toLowerCase() === "leader" ? mbody.sessionId : void 0;
2438
2426
  const sent = await mailbox.send({
2439
2427
  from,
2440
2428
  to: deliveryTo,
@@ -2442,7 +2430,8 @@ async function handleApiMailboxSend(_req, res, mutableAuth, sessions, dataDir, g
2442
2430
  subject,
2443
2431
  body: mbody.body,
2444
2432
  priority,
2445
- audience
2433
+ audience,
2434
+ ...scopeSessionId !== void 0 ? { sessionAffinity: { sessionId: scopeSessionId } } : {}
2446
2435
  });
2447
2436
  res.writeHead(202, { "Content-Type": "application/json" });
2448
2437
  res.end(
@@ -2843,8 +2832,8 @@ async function handleApiAgentMessages(req, res, match, agentMessages) {
2843
2832
  // src/hq-server/routes/system-handlers.ts
2844
2833
  async function handleApiSystemUpdate(res) {
2845
2834
  const [{ checkForUpdate }, { detectUpdatePackageName }] = await Promise.all([
2846
- import("./update-check-PKSMSMD6.js"),
2847
- import("./update-K45CS6SS.js")
2835
+ import("./update-check-BS3DHTSI.js"),
2836
+ import("./update-5DPB4YD4.js")
2848
2837
  ]);
2849
2838
  const packageName = detectUpdatePackageName();
2850
2839
  const info = await checkForUpdate({ packageName });
@@ -3316,7 +3305,12 @@ var MailboxGatewayManager = class {
3316
3305
  MAILBOX_GATEWAY_SWEEP_INTERVAL_MS = 6e4;
3317
3306
  authorizeMailboxGateway(req, projectDir) {
3318
3307
  const requestUrl = new URL(req.url ?? "/", `http://${this.deps.host}:${this.deps.port}`);
3319
- const auth = authenticateBrowserRequest2(req, requestUrl, this.deps.mutableAuth, this.deps.sessions);
3308
+ const auth = authenticateBrowserRequest2(
3309
+ req,
3310
+ requestUrl,
3311
+ this.deps.mutableAuth,
3312
+ this.deps.sessions
3313
+ );
3320
3314
  const tokenMode = this.deps.mutableAuth.browserTokens.size > 0;
3321
3315
  if (hqAuthRequired(this.deps.mutableAuth) && auth === void 0) {
3322
3316
  return {
@@ -3638,10 +3632,7 @@ function handleIncomingClientEvent(ws, incomingEvent, clients, browsers, auth, s
3638
3632
  const event = redactHqEvent(
3639
3633
  { ...incomingEvent, payload: parsedPayload.payload },
3640
3634
  {
3641
- policy: tightenHqRedactionPolicy(
3642
- client.declaredRedactionPolicy,
3643
- auth.getOperatorPolicy()
3644
- ),
3635
+ policy: tightenHqRedactionPolicy(client.declaredRedactionPolicy, auth.getOperatorPolicy()),
3645
3636
  projectRoot: client.project.projectRoot,
3646
3637
  // Chat-transcript events carry full turns — the generic 500-char
3647
3638
  // summary cap would truncate them a second time after the
@@ -3807,10 +3798,7 @@ function handleIncomingClientEvent(ws, incomingEvent, clients, browsers, auth, s
3807
3798
  }
3808
3799
 
3809
3800
  // src/hq-server/ws-leader.ts
3810
- import {
3811
- HQ_BROWSER_PEER_RESUME_CLIENT_ID,
3812
- HQ_PROTOCOL_VERSION
3813
- } from "@wrongstack/core/hq";
3801
+ import { HQ_BROWSER_PEER_RESUME_CLIENT_ID, HQ_PROTOCOL_VERSION } from "@wrongstack/core/hq";
3814
3802
  var MAX_EVENT_LOG = 5e3;
3815
3803
  var PEER_DEDUP_WINDOW_MS = 60 * 60 * 1e3;
3816
3804
  var peerDedupMap = /* @__PURE__ */ new Map();
@@ -3998,13 +3986,17 @@ function handleClientResume(ws, clients, eventLog, frame, snapshotBroadcaster) {
3998
3986
  const now = Date.now();
3999
3987
  const recent = [];
4000
3988
  let cursorTimestamp;
3989
+ let cursorAnchorSeq = -1;
4001
3990
  const skipPeerEnvelopes = client.clientId !== HQ_BROWSER_PEER_RESUME_CLIENT_ID2;
4002
3991
  for (const env of eventLog) {
4003
3992
  if (env.clientId !== client.clientId) continue;
4004
3993
  if (skipPeerEnvelopes && (env.type === "peer.rehydrate" || env.type === "peer.lost")) {
4005
3994
  continue;
4006
3995
  }
4007
- if (env.seq === cursor) cursorTimestamp = env.timestamp;
3996
+ if (env.seq <= cursor && env.seq > cursorAnchorSeq) {
3997
+ cursorAnchorSeq = env.seq;
3998
+ cursorTimestamp = env.timestamp;
3999
+ }
4008
4000
  if (env.seq > cursor) {
4009
4001
  recent.push(env);
4010
4002
  }
@@ -4125,6 +4117,22 @@ function handleBrowser(ws, snapshotBroadcaster, browsers, eventLog) {
4125
4117
  browsers.delete(ws);
4126
4118
  });
4127
4119
  }
4120
+ function failUndeliveredCommands(lostClient, browsers, auditLog) {
4121
+ if (auditLog === void 0 || lostClient.commandQueue.length === 0) return;
4122
+ const disconnectedAt = (/* @__PURE__ */ new Date()).toISOString();
4123
+ for (const queued of lostClient.commandQueue) {
4124
+ if (auditLog.get(queued.commandId)?.status !== "queued") continue;
4125
+ const updated = auditLog.updateForClient(queued.commandId, lostClient.clientId, {
4126
+ status: "acked",
4127
+ ackStatus: "failed",
4128
+ ackMessage: "client disconnected before the command was delivered",
4129
+ ackedAt: disconnectedAt
4130
+ });
4131
+ if (!updated) continue;
4132
+ const entry = auditLog.get(queued.commandId);
4133
+ if (entry !== void 0) broadcastCommandStatus(entry, browsers);
4134
+ }
4135
+ }
4128
4136
  function handleClient(ws, clients, browsers, eventLog, auth, snapshotBroadcaster, transcripts, agentMessages, persistence, auditLog) {
4129
4137
  let registered = false;
4130
4138
  function persistEvent(event) {
@@ -4171,9 +4179,10 @@ function handleClient(ws, clients, browsers, eventLog, auth, snapshotBroadcaster
4171
4179
  const declaredRedactionPolicy = resolveHqRedactionPolicy(payload.redactionPolicy);
4172
4180
  const supersededLeaders = [];
4173
4181
  let inheritedLeader = false;
4182
+ const isSessionSurface = acceptedCapabilities.includes("session.summary");
4174
4183
  for (const [otherWs, otherClient] of clients) {
4175
4184
  const sameClientId = otherClient.clientId === payload.client.clientId;
4176
- const samePublisher = otherClient.projectId === payload.project.projectId && otherClient.kind === payload.client.kind && otherClient.pid !== void 0 && payload.client.pid !== void 0 && otherClient.pid === payload.client.pid && (otherClient.machineId || otherClient.project.machineId) === (payload.client.machineId || payload.project.machineId);
4185
+ const samePublisher = otherClient.projectId === payload.project.projectId && otherClient.kind === payload.client.kind && otherClient.pid !== void 0 && payload.client.pid !== void 0 && otherClient.pid === payload.client.pid && (otherClient.machineId || otherClient.project.machineId) === (payload.client.machineId || payload.project.machineId) && isSessionSurface === otherClient.capabilities.includes("session.summary");
4177
4186
  if (otherWs !== ws && (sameClientId || samePublisher && otherClient.sessions.size === 0)) {
4178
4187
  if (otherClient.isLeader) {
4179
4188
  if (sameClientId) inheritedLeader = true;
@@ -4321,6 +4330,7 @@ function handleClient(ws, clients, browsers, eventLog, auth, snapshotBroadcaster
4321
4330
  const lostClient = clients.get(ws);
4322
4331
  clients.delete(ws);
4323
4332
  if (lostClient) {
4333
+ failUndeliveredCommands(lostClient, browsers, auditLog);
4324
4334
  detectLeaderLoss(lostClient, clients, browsers, "graceful", { eventLog, persistence });
4325
4335
  }
4326
4336
  snapshotBroadcaster.broadcast();
@@ -4418,7 +4428,9 @@ function handleHqConnection(ws, req, pathname, deps) {
4418
4428
  if (pathname === "/ws/browser") {
4419
4429
  handleBrowser(ws, deps.snapshotBroadcaster, deps.browsers, deps.eventLog);
4420
4430
  } else {
4421
- const token = new URL(req.url ?? "/", `http://${deps.host}:${deps.port}`).searchParams.get("token");
4431
+ const token = new URL(req.url ?? "/", `http://${deps.host}:${deps.port}`).searchParams.get(
4432
+ "token"
4433
+ );
4422
4434
  const authToken = token ? deps.mutableAuth.clientTokenObjs.get(hqTokenVerifier2(token)) : void 0;
4423
4435
  deps.clientSocketTokens.set(ws, authToken);
4424
4436
  ws.once("close", () => deps.clientSocketTokens.delete(ws));
@@ -4914,4 +4926,4 @@ export {
4914
4926
  startHqServer,
4915
4927
  HqInsecureExposureError2 as HqInsecureExposureError
4916
4928
  };
4917
- //# sourceMappingURL=chunk-7JBKXVMK.js.map
4929
+ //# sourceMappingURL=chunk-C2E24IXZ.js.map
@@ -21,4 +21,4 @@ export {
21
21
  resetGateDecisions,
22
22
  snapshotGateDecisions
23
23
  };
24
- //# sourceMappingURL=chunk-7CECQDNH.js.map
24
+ //# sourceMappingURL=chunk-D3K4NYQL.js.map
@@ -107,47 +107,58 @@ async function loadConfigProviders(configPath, vault, opts) {
107
107
  const decrypted = decryptConfigSecrets(parsed, vault);
108
108
  return decrypted.providers ?? {};
109
109
  }
110
+ var configMutationChain = Promise.resolve();
111
+ function queueConfigMutation(mutate) {
112
+ const run = configMutationChain.then(mutate, mutate);
113
+ configMutationChain = run.then(
114
+ () => void 0,
115
+ () => void 0
116
+ );
117
+ return run;
118
+ }
110
119
  async function mutateConfigProviders(configPath, vault, mutator, profileConfigPath) {
111
- const targetPath = profileConfigPath ?? configPath;
112
- let raw;
113
- let fileExists = true;
114
- try {
115
- raw = await fs.readFile(targetPath, "utf8");
116
- } catch (err) {
117
- if (err.code !== "ENOENT") {
118
- throw new FsError({
119
- message: `Refusing to mutate ${configPath}: ${err.message}`,
120
- code: "FS_READ_FAILED",
121
- path: targetPath,
122
- context: { operation: "mutateConfigProviders", phase: "read" },
123
- cause: err
124
- });
120
+ await queueConfigMutation(async () => {
121
+ const targetPath = profileConfigPath ?? configPath;
122
+ let raw;
123
+ let fileExists = true;
124
+ try {
125
+ raw = await fs.readFile(targetPath, "utf8");
126
+ } catch (err) {
127
+ if (err.code !== "ENOENT") {
128
+ throw new FsError({
129
+ message: `Refusing to mutate ${configPath}: ${err.message}`,
130
+ code: "FS_READ_FAILED",
131
+ path: targetPath,
132
+ context: { operation: "mutateConfigProviders", phase: "read" },
133
+ cause: err
134
+ });
135
+ }
136
+ fileExists = false;
137
+ raw = "{}";
125
138
  }
126
- fileExists = false;
127
- raw = "{}";
128
- }
129
- let parsed;
130
- try {
131
- parsed = JSON.parse(raw);
132
- } catch (err) {
133
- if (fileExists) {
134
- throw new FsError({
135
- message: `Refusing to overwrite corrupt config at ${targetPath} (${err.message}). Fix or move the file aside before retrying.`,
136
- code: "FS_READ_FAILED",
137
- path: targetPath,
138
- context: { operation: "mutateConfigProviders", phase: "parse" },
139
- cause: err
140
- });
139
+ let parsed;
140
+ try {
141
+ parsed = JSON.parse(raw);
142
+ } catch (err) {
143
+ if (fileExists) {
144
+ throw new FsError({
145
+ message: `Refusing to overwrite corrupt config at ${targetPath} (${err.message}). Fix or move the file aside before retrying.`,
146
+ code: "FS_READ_FAILED",
147
+ path: targetPath,
148
+ context: { operation: "mutateConfigProviders", phase: "parse" },
149
+ cause: err
150
+ });
151
+ }
152
+ parsed = {};
141
153
  }
142
- parsed = {};
143
- }
144
- const decrypted = decryptConfigSecrets(parsed, vault);
145
- const providers = decrypted.providers ?? {};
146
- mutator(providers);
147
- decrypted.providers = providers;
148
- clearStaleProviderDefaults(decrypted);
149
- const encrypted = encryptConfigSecrets(decrypted, vault);
150
- await atomicWrite(targetPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
154
+ const decrypted = decryptConfigSecrets(parsed, vault);
155
+ const providers = decrypted.providers ?? {};
156
+ mutator(providers, decrypted);
157
+ decrypted.providers = providers;
158
+ clearStaleProviderDefaults(decrypted);
159
+ const encrypted = encryptConfigSecrets(decrypted, vault);
160
+ await atomicWrite(targetPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
161
+ });
151
162
  }
152
163
 
153
164
  export {
@@ -160,4 +171,4 @@ export {
160
171
  mutateConfigProviders,
161
172
  nowIso
162
173
  };
163
- //# sourceMappingURL=chunk-XPX432BZ.js.map
174
+ //# sourceMappingURL=chunk-DR2OXU46.js.map
@@ -10,4 +10,4 @@ import {
10
10
  export {
11
11
  getWrongTrace
12
12
  };
13
- //# sourceMappingURL=chunk-4JRIWVJ4.js.map
13
+ //# sourceMappingURL=chunk-ERX4BLKP.js.map
@@ -0,0 +1,52 @@
1
+
2
+ // src/subcommands/index.ts
3
+ var loaders = {
4
+ acp: async () => (await import("./acp-3LARESEO.js")).acpCmd,
5
+ init: async () => (await import("./init-DRMMFG2G.js")).initCmd,
6
+ auth: async () => (await import("./auth-KIBJZZIE.js")).authCmd,
7
+ update: async () => (await import("./update-5DPB4YD4.js")).updateCmd,
8
+ sessions: async () => (await import("./sessions-config-UL45XKX7.js")).sessionsCmd,
9
+ config: async () => (await import("./sessions-config-UL45XKX7.js")).configCmd,
10
+ rewind: async () => (await import("./rewind-JA3ZLCNM.js")).rewindCmd,
11
+ replay: async () => (await import("./replay-JJ2NOWD6.js")).replayCmd,
12
+ audit: async () => (await import("./audit-46YK5DSC.js")).auditCmd,
13
+ tools: async () => (await import("./tools-skills-GH24UCBY.js")).toolsCmd,
14
+ skills: async () => (await import("./tools-skills-GH24UCBY.js")).skillsCmd,
15
+ providers: async () => (await import("./providers-models-YVMVYWRS.js")).providersCmd,
16
+ models: async () => (await import("./providers-models-YVMVYWRS.js")).modelsCmd,
17
+ mcp: async () => (await import("./mcp-HOMLC4WE.js")).mcpCmd,
18
+ plugin: async () => (await import("./plugin-usage-HFBI3TFT.js")).pluginCmd,
19
+ plugins: async () => (await import("./plugin-usage-HFBI3TFT.js")).pluginCmd,
20
+ diag: async () => (await import("./diag-doctor-7LYUYU35.js")).diagCmd,
21
+ doctor: async () => (await import("./diag-doctor-7LYUYU35.js")).doctorCmd,
22
+ "proxy-status": async () => (await import("./diag-doctor-7LYUYU35.js")).proxyCmd,
23
+ export: async () => (await import("./export-VVRIOWFV.js")).exportCmd,
24
+ usage: async () => (await import("./plugin-usage-HFBI3TFT.js")).usageCmd,
25
+ version: async () => (await import("./version-help-MYKF724O.js")).versionCmd,
26
+ help: async () => (await import("./version-help-MYKF724O.js")).helpCmd,
27
+ projects: async () => (await import("./projects-L6C6XLDY.js")).projectsCmd,
28
+ modeldiag: async () => (await import("./modeldiag-FMJT37SN.js")).modeldiagCmd,
29
+ quick: async () => (await import("./quick-CNB4Z3HS.js")).quickCmd,
30
+ bench: async () => (await import("./bench-YBU6BVQP.js")).benchCmd,
31
+ chronicle: async () => (await import("./chronicle-UTFETHP6.js")).chronicleCmd,
32
+ hq: async () => (await import("./hq-IG3YRGCO.js")).hqCmd,
33
+ mailbox: async () => (await import("./mailbox-serve-VUCWZ2SJ.js")).mailboxServeCmd,
34
+ permissions: async () => (await import("./permissions-CFDLXETM.js")).permissionsCmd,
35
+ project: async () => (await import("./project-AOQI5XTK.js")).projectCmd,
36
+ governance: async () => (await import("./governance-RYSHV675.js")).governanceCmd
37
+ };
38
+ var subcommands = Object.fromEntries(
39
+ Object.entries(loaders).map(
40
+ ([name, load]) => [
41
+ name,
42
+ async (args, deps) => (await load())(args, deps)
43
+ ]
44
+ )
45
+ );
46
+ var subcommandNames = Object.keys(loaders);
47
+
48
+ export {
49
+ subcommands,
50
+ subcommandNames
51
+ };
52
+ //# sourceMappingURL=chunk-ETYHZPXP.js.map
@@ -11,9 +11,13 @@ function patchConfig(base, patch) {
11
11
  function fmtDuration(ms) {
12
12
  if (ms < 1e3) return `${ms}ms`;
13
13
  const s = ms / 1e3;
14
- if (s < 60) return `${s.toFixed(s < 10 ? 1 : 0)}s`;
15
- const m = Math.floor(s / 60);
16
- const remSec = Math.round(s - m * 60);
14
+ if (s < 59.5) return `${s.toFixed(s < 10 ? 1 : 0)}s`;
15
+ let m = Math.floor(s / 60);
16
+ let remSec = Math.round(s - m * 60);
17
+ if (remSec === 60) {
18
+ remSec = 0;
19
+ m++;
20
+ }
17
21
  if (m < 60) return remSec === 0 ? `${m}m` : `${m}m${remSec}s`;
18
22
  const h = Math.floor(m / 60);
19
23
  const remMin = m - h * 60;
@@ -47,4 +51,4 @@ export {
47
51
  patchConfig,
48
52
  fmtTaskResultLine
49
53
  };
50
- //# sourceMappingURL=chunk-TYO2OVAD.js.map
54
+ //# sourceMappingURL=chunk-EWKESL4L.js.map
@@ -55,7 +55,7 @@ var helpCmd = async (_args, deps) => {
55
55
  " wstack mailbox serve [opts] Start external-agent mailbox HTTP bridge",
56
56
  " wstack permissions explain Explain tool permission policy decisions",
57
57
  " wstack modeldiag [test] Model benchmarks and capability diagnostics",
58
- " wstack bench [run|list] Agentic benchmarks against standard suites",
58
+ " wstack bench [run|compare] Agentic benchmarks against standard suites",
59
59
  " wstack acp [serve] Agent Client Protocol (ACP) server",
60
60
  " wstack update [--check-only] Self-update the CLI",
61
61
  " wstack diag Full diagnostics",
@@ -81,7 +81,6 @@ var helpCmd = async (_args, deps) => {
81
81
  " Serve the independent minimal chat UI",
82
82
  " --full-auto SimpleUI: runtime-only YOLO + Director + autonomy override",
83
83
  ' --eternal "<mission>" Start an eternal-autonomy loop',
84
- " --no-hints Hide launch hints",
85
84
  " --skip-index Skip codebase indexing on startup",
86
85
  " --chimera-auto-fix off|ask|auto",
87
86
  " How to handle Chimera review findings (default: config value)"
@@ -94,4 +93,4 @@ export {
94
93
  versionCmd,
95
94
  helpCmd
96
95
  };
97
- //# sourceMappingURL=chunk-QAC263FZ.js.map
96
+ //# sourceMappingURL=chunk-FPIWTJ2G.js.map
@@ -20,7 +20,34 @@ function createHqCommandDispatcher(controller) {
20
20
  }
21
21
  };
22
22
  }
23
+ function resolveCommandSessionId(controller, payload) {
24
+ const named = payload["sessionId"];
25
+ if (typeof named === "string" && named.length > 0) return named;
26
+ return controller.sessionId?.();
27
+ }
28
+ function rejectUnknownSession(controller, commandId, sessionId) {
29
+ const named = sessionId;
30
+ if (named === void 0) return null;
31
+ const owns = controller.ownsSession?.(named) ?? (controller.sessionId === void 0 ? true : controller.sessionId() === named);
32
+ if (owns) return null;
33
+ return {
34
+ commandId,
35
+ status: "rejected",
36
+ message: `session ${named} is not active on this client`
37
+ };
38
+ }
39
+ function leaderSessionAffinity(to, sessionId) {
40
+ if (to.trim().toLowerCase() !== "leader") return {};
41
+ if (typeof sessionId !== "string" || sessionId.length === 0) return {};
42
+ return { sessionAffinity: { sessionId } };
43
+ }
23
44
  async function dispatch(controller, commandId, type, payload) {
45
+ const sessionId = resolveCommandSessionId(controller, payload);
46
+ const namedSession = typeof payload["sessionId"] === "string" ? payload["sessionId"] : void 0;
47
+ if (type !== "broadcast") {
48
+ const rejected = rejectUnknownSession(controller, commandId, namedSession);
49
+ if (rejected !== null) return rejected;
50
+ }
24
51
  switch (type) {
25
52
  case "steer": {
26
53
  const mailbox = controller.steerMailbox;
@@ -32,7 +59,15 @@ async function dispatch(controller, commandId, type, payload) {
32
59
  const body = typeof payload["body"] === "string" ? payload["body"] : "";
33
60
  const priority = payload["priority"] === "high" ? "high" : payload["priority"] === "low" ? "low" : "normal";
34
61
  const from = `hq@${controller.sessionTag()}`;
35
- await mailbox.send({ from, to, type: "steer", subject, body, priority });
62
+ await mailbox.send({
63
+ from,
64
+ to,
65
+ type: "steer",
66
+ subject,
67
+ body,
68
+ priority,
69
+ ...leaderSessionAffinity(to, sessionId)
70
+ });
36
71
  return { commandId, status: "accepted", message: `steered ${to}` };
37
72
  }
38
73
  case "btw": {
@@ -45,7 +80,15 @@ async function dispatch(controller, commandId, type, payload) {
45
80
  const body = typeof payload["body"] === "string" ? payload["body"] : "";
46
81
  const priority = payload["priority"] === "high" ? "high" : payload["priority"] === "low" ? "low" : "normal";
47
82
  const from = `hq@${controller.sessionTag()}`;
48
- await mailbox.send({ from, to, type: "btw", subject, body, priority });
83
+ await mailbox.send({
84
+ from,
85
+ to,
86
+ type: "btw",
87
+ subject,
88
+ body,
89
+ priority,
90
+ ...leaderSessionAffinity(to, sessionId)
91
+ });
49
92
  return { commandId, status: "accepted", message: `noted ${to}` };
50
93
  }
51
94
  case "queue": {
@@ -58,7 +101,15 @@ async function dispatch(controller, commandId, type, payload) {
58
101
  const body = typeof payload["body"] === "string" ? payload["body"] : "";
59
102
  const priority = payload["priority"] === "high" ? "high" : payload["priority"] === "low" ? "low" : "normal";
60
103
  const from = `hq@${controller.sessionTag()}`;
61
- await mailbox.send({ from, to, type: "note", subject, body, priority });
104
+ await mailbox.send({
105
+ from,
106
+ to,
107
+ type: "note",
108
+ subject,
109
+ body,
110
+ priority,
111
+ ...leaderSessionAffinity(to, sessionId)
112
+ });
62
113
  return { commandId, status: "accepted", message: `queued for ${to}` };
63
114
  }
64
115
  case "broadcast": {
@@ -76,7 +127,7 @@ async function dispatch(controller, commandId, type, payload) {
76
127
  case "abort": {
77
128
  const target = typeof payload["target"] === "string" ? payload["target"] : "leader";
78
129
  if (target === "leader") {
79
- const aborted = controller.interruptLeader();
130
+ const aborted = controller.interruptLeader(sessionId);
80
131
  return {
81
132
  commandId,
82
133
  status: aborted ? "completed" : "accepted",
@@ -84,14 +135,14 @@ async function dispatch(controller, commandId, type, payload) {
84
135
  };
85
136
  }
86
137
  if (target === "fleet") {
87
- const killed = await controller.killFleet?.() ?? 0;
138
+ const killed = await controller.killFleet?.(sessionId) ?? 0;
88
139
  return {
89
140
  commandId,
90
141
  status: "completed",
91
142
  message: `fleet stopped (${killed} agents)`
92
143
  };
93
144
  }
94
- const terminated = await controller.terminateAgent?.(target) ?? false;
145
+ const terminated = await controller.terminateAgent?.(target, sessionId) ?? false;
95
146
  return {
96
147
  commandId,
97
148
  status: terminated ? "completed" : "rejected",
@@ -105,7 +156,7 @@ async function dispatch(controller, commandId, type, payload) {
105
156
  if (controller.spawnAgent === void 0) {
106
157
  return { commandId, status: "rejected", message: "no director active" };
107
158
  }
108
- const subagentId = await controller.spawnAgent(role, task, maxIterations);
159
+ const subagentId = await controller.spawnAgent(role, task, maxIterations, sessionId);
109
160
  return { commandId, status: "completed", message: `spawned ${subagentId}` };
110
161
  }
111
162
  case "run-command": {
@@ -130,7 +181,8 @@ async function dispatch(controller, commandId, type, payload) {
130
181
  \`\`\`
131
182
  ${command}
132
183
  \`\`\``,
133
- priority: "high"
184
+ priority: "high",
185
+ ...leaderSessionAffinity("leader", sessionId)
134
186
  });
135
187
  return { commandId, status: "accepted", message: "run-command routed to leader as steer" };
136
188
  }
@@ -144,4 +196,4 @@ ${command}
144
196
  export {
145
197
  createHqCommandDispatcher
146
198
  };
147
- //# sourceMappingURL=chunk-7YLN7YUA.js.map
199
+ //# sourceMappingURL=chunk-IMWXXF4J.js.map
@@ -116,4 +116,4 @@ export {
116
116
  ensureProjectDataDir,
117
117
  touchProjectInManifest
118
118
  };
119
- //# sourceMappingURL=chunk-G7337TTK.js.map
119
+ //# sourceMappingURL=chunk-IS2PPBQV.js.map
@@ -136,4 +136,4 @@ function buildHealthUrl(rawBase) {
136
136
  export {
137
137
  startProxyProbe
138
138
  };
139
- //# sourceMappingURL=chunk-G3IMKQRH.js.map
139
+ //# sourceMappingURL=chunk-JHPXJRRI.js.map
@@ -11,7 +11,7 @@ import {
11
11
  openBrowser,
12
12
  runCodexOAuthLogin,
13
13
  startLoopbackServer
14
- } from "./chunk-E4I2TF5S.js";
14
+ } from "./chunk-TNK6237M.js";
15
15
  import {
16
16
  activeLabel,
17
17
  loadConfigProviders,
@@ -20,7 +20,7 @@ import {
20
20
  normalizeKeys,
21
21
  nowIso,
22
22
  writeKeysBack
23
- } from "./chunk-XPX432BZ.js";
23
+ } from "./chunk-DR2OXU46.js";
24
24
 
25
25
  // src/auth-menu/local.ts
26
26
  import { DefaultSecretScrubber as DefaultSecretScrubber2 } from "@wrongstack/core/security";
@@ -1444,11 +1444,11 @@ function renderLiveProviderList(query, filtered, selectedIdx, savedSet) {
1444
1444
  }
1445
1445
  async function saveToGlobalConfig(configPath, provider, model, homeFn = () => process.env.HOME ?? os.homedir()) {
1446
1446
  try {
1447
- const { atomicWrite: atomicWrite2 } = await import("@wrongstack/core/utils");
1448
- const fs2 = await import("node:fs/promises");
1447
+ const { atomicWrite } = await import("@wrongstack/core/utils");
1448
+ const fs = await import("node:fs/promises");
1449
1449
  let existing = {};
1450
1450
  try {
1451
- const raw = await fs2.readFile(configPath, "utf8");
1451
+ const raw = await fs.readFile(configPath, "utf8");
1452
1452
  existing = JSON.parse(raw);
1453
1453
  } catch {
1454
1454
  }
@@ -1467,7 +1467,7 @@ async function saveToGlobalConfig(configPath, provider, model, homeFn = () => pr
1467
1467
  })
1468
1468
  );
1469
1469
  }
1470
- await atomicWrite2(configPath, JSON.stringify(existing, null, 2), { mode: 384 });
1470
+ await atomicWrite(configPath, JSON.stringify(existing, null, 2), { mode: 384 });
1471
1471
  try {
1472
1472
  await appendHistory(
1473
1473
  oldCfg,
@@ -1899,8 +1899,7 @@ async function resolveModelSelection(answer, models, provider, _registry, render
1899
1899
  }
1900
1900
 
1901
1901
  // src/auth-menu/add-provider.ts
1902
- import * as fs from "node:fs/promises";
1903
- import { atomicWrite, color as color9 } from "@wrongstack/core/utils";
1902
+ import { color as color9 } from "@wrongstack/core/utils";
1904
1903
  import { catalogProviderIdFor, PROVIDER_DEFINITIONS } from "@wrongstack/providers";
1905
1904
 
1906
1905
  // src/provider-id.ts
@@ -2148,22 +2147,26 @@ async function resolveDefaultModelId(deps, providerId, template) {
2148
2147
  return provider?.models?.[0]?.id;
2149
2148
  }
2150
2149
  async function adoptAsDefaultIfUnset(deps, providerId, template) {
2151
- const targetPath = deps.profileConfigPath;
2152
- let cfg = {};
2153
- try {
2154
- cfg = JSON.parse(await fs.readFile(targetPath, "utf8"));
2155
- } catch {
2156
- }
2157
- if (cfg["provider"] && cfg["model"]) return;
2158
2150
  const modelId = await resolveDefaultModelId(deps, providerId, template);
2159
2151
  if (!modelId) return;
2160
- cfg["provider"] = providerId;
2161
- cfg["model"] = modelId;
2162
- await atomicWrite(targetPath, JSON.stringify(cfg, null, 2), { mode: 384 });
2163
- deps.renderer.write(
2164
- ` ${color9.green("\u2713")} Set ${color9.bold(providerId)}/${color9.bold(modelId)} as the default.
2165
- `
2152
+ let adopted = false;
2153
+ await mutateConfigProviders(
2154
+ deps.profileConfigPath,
2155
+ deps.vault,
2156
+ (_providers, config) => {
2157
+ if (config["provider"] && config["model"]) return;
2158
+ config["provider"] = providerId;
2159
+ config["model"] = modelId;
2160
+ adopted = true;
2161
+ },
2162
+ deps.profileConfigPath
2166
2163
  );
2164
+ if (adopted) {
2165
+ deps.renderer.write(
2166
+ ` ${color9.green("\u2713")} Set ${color9.bold(providerId)}/${color9.bold(modelId)} as the default.
2167
+ `
2168
+ );
2169
+ }
2167
2170
  }
2168
2171
  async function promptForLabel(deps, usedLabels) {
2169
2172
  const defaultLabel = suggestLabel(usedLabels);
@@ -2201,9 +2204,10 @@ export {
2201
2204
  saveToGlobalConfig,
2202
2205
  runPicker,
2203
2206
  nextCustomProviderId,
2207
+ ownDefinitionsAsCatalog,
2204
2208
  addFromCatalog,
2205
2209
  addKeyForCatalogProvider,
2206
2210
  addCustomProvider,
2207
2211
  addKeyForProvider
2208
2212
  };
2209
- //# sourceMappingURL=chunk-XHIEA6LG.js.map
2213
+ //# sourceMappingURL=chunk-MNQQ4ZNF.js.map