@wrongstack/cli 1.1.5 → 1.1.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.
@@ -4,13 +4,13 @@ import {
4
4
  loadCachedAcpRegistry,
5
5
  refreshAcpRegistry,
6
6
  setupProvider
7
- } from "./chunk-M7FNHCE3.js";
7
+ } from "./chunk-EAATL6FL.js";
8
8
  import {
9
9
  createHqCommandDispatcher,
10
10
  wrongstackBridgeSetup
11
- } from "./chunk-5SGMUDP5.js";
11
+ } from "./chunk-QRWXHGLB.js";
12
12
  import "./chunk-3LEIFO5D.js";
13
- import "./chunk-VEESMPTX.js";
13
+ import "./chunk-PGC44T7N.js";
14
14
  import {
15
15
  startCliHqConnection
16
16
  } from "./chunk-76JE54WD.js";
@@ -18,7 +18,7 @@ import {
18
18
  WebSocketServer
19
19
  } from "./chunk-OZCYZYN2.js";
20
20
  import "./chunk-UFRVTBV6.js";
21
- import "./chunk-LUEO5HLZ.js";
21
+ import "./chunk-X4DEQLAZ.js";
22
22
  import "./chunk-HKMOIIPQ.js";
23
23
  import "./chunk-W23PY4IJ.js";
24
24
 
@@ -1205,4 +1205,4 @@ parallel:
1205
1205
  export {
1206
1206
  acpCmd
1207
1207
  };
1208
- //# sourceMappingURL=acp-NKUEYJDZ.js.map
1208
+ //# sourceMappingURL=acp-CZBSFQB7.js.map
@@ -40,6 +40,13 @@ export interface AcpLeaderHost {
40
40
  runTool(name: string, input: Record<string, unknown>, run?: {
41
41
  sessionId?: string | undefined;
42
42
  approve?: ((tool: Tool, input: Record<string, unknown>) => Promise<boolean>) | undefined;
43
+ /**
44
+ * Settle the call's tool card here: no tool_result reaches the
45
+ * conversation, and the caller's own stream does not draw one (the
46
+ * WrongForge leader's `wstack_*` calls). An ACP agent reports its fleet
47
+ * calls itself, so its cards come from its stream instead.
48
+ */
49
+ announce?: boolean | undefined;
43
50
  }): Promise<{
44
51
  content: string;
45
52
  isError: boolean;
@@ -1,6 +1,15 @@
1
1
  import type { AgentContextUsage, Capabilities, Config, Provider, ProviderFactory, Request, Response, StreamEvent } from '@wrongstack/core/types';
2
2
  import { ACP_LEADER_PROVIDER_ID } from './acp-leader-host.js';
3
3
  export { ACP_LEADER_PROVIDER_ID };
4
+ /**
5
+ * The side model the user set for an agent leader (`acp.leader.sideModel`),
6
+ * without falling back to the fallback chain: a leader that can answer side
7
+ * requests itself (WrongForge) must not hand them to `fallbackModels[0]`.
8
+ */
9
+ export declare function explicitLeaderSideModel(config: Config): {
10
+ provider: string;
11
+ model: string;
12
+ } | undefined;
4
13
  export declare function leaderSideModel(config: Config): {
5
14
  provider: string;
6
15
  model: string;
@@ -58,6 +67,7 @@ export declare class AcpLeaderProvider implements Provider {
58
67
  private observeContext;
59
68
  private publishContext;
60
69
  private loadAcp;
70
+ private dropFleetGrants;
61
71
  private drop;
62
72
  /** The persistent agent session for this conversation, started on first use. */
63
73
  private sessionFor;
@@ -0,0 +1,5 @@
1
+ /** The WrongStack `skill` tool as an agent sees it on this route, if offered. */
2
+ export declare function externalSkillLoader(offered: readonly string[] | undefined, prefix: string): string | undefined;
3
+ /** `text` with its required-skills marker rewritten for an agent leader. */
4
+ export declare function externalSkillDirective(text: string, loader: string | undefined): string;
5
+ //# sourceMappingURL=acp-leader-skills.d.ts.map
@@ -34,6 +34,13 @@ export declare class TextBlocks {
34
34
  text(chunk: string): void;
35
35
  close(): void;
36
36
  }
37
+ interface CardOutput {
38
+ output: string;
39
+ fullOutput?: string | undefined;
40
+ outputBytes: number;
41
+ }
42
+ /** A card's output fields for a result text that no tool_result will carry. */
43
+ export declare function cardOutputForText(text: string): CardOutput;
37
44
  /**
38
45
  * The agent's own tool calls as the host's tool cards: `tool.started` once a
39
46
  * call is announced, `tool.executed` once it settles. Named by the agent's
@@ -80,4 +87,5 @@ export declare function agentTurnError(err: unknown, agentId: string, classify:
80
87
  error: ProviderError;
81
88
  dead: boolean;
82
89
  };
90
+ export {};
83
91
  //# sourceMappingURL=acp-leader-stream.d.ts.map
@@ -3,7 +3,7 @@ import {
3
3
  reportWrongForgeQuota,
4
4
  writeWrongForgeInfoCache,
5
5
  wrongstackBridgeSetup
6
- } from "./chunk-5SGMUDP5.js";
6
+ } from "./chunk-QRWXHGLB.js";
7
7
  import {
8
8
  isRestrictedMode
9
9
  } from "./chunk-3LEIFO5D.js";
@@ -21,7 +21,7 @@ import {
21
21
  toProgress,
22
22
  wfTokens,
23
23
  wrongForgeCall
24
- } from "./chunk-VEESMPTX.js";
24
+ } from "./chunk-PGC44T7N.js";
25
25
  import {
26
26
  buildProviderForId,
27
27
  resolveProviderCfgWithProxy
@@ -30,7 +30,7 @@ import {
30
30
  ACP_LEADER_PROVIDER_ID,
31
31
  acpLeaderHost,
32
32
  trackAcpLeader
33
- } from "./chunk-LUEO5HLZ.js";
33
+ } from "./chunk-X4DEQLAZ.js";
34
34
 
35
35
  // src/acp-agent-list.ts
36
36
  import { REGISTRY_ID_ALIASES } from "@wrongstack/acp";
@@ -569,6 +569,7 @@ function publishLeaderContext(events, sessionId, reading, fallbackMaxContext) {
569
569
 
570
570
  // src/acp-leader/acp-leader-fleet.ts
571
571
  import { randomBytes } from "node:crypto";
572
+ import { toErrorMessage as toErrorMessage2 } from "@wrongstack/core/utils";
572
573
  import { MCPServer, serveHttp } from "@wrongstack/mcp";
573
574
  var FLEET_SERVER_NAME = "wrongstack-fleet";
574
575
  var FLEET_TOOLS = [
@@ -579,7 +580,10 @@ var FLEET_TOOLS = [
579
580
  "roll_up",
580
581
  "fleet_status",
581
582
  "session_note",
582
- "terminate_subagent"
583
+ "terminate_subagent",
584
+ // Not a fleet tool, but it too must run in this process: WrongStack's
585
+ // skills (a /bughunt playbook) reach the agent only through it.
586
+ "skill"
583
587
  ];
584
588
  var MCP_PREFIX = `mcp__${FLEET_SERVER_NAME}__`;
585
589
  function fleetToolName(mcpName) {
@@ -605,7 +609,11 @@ async function startFleetEndpoint(host, run) {
605
609
  if (!offered.has(name)) {
606
610
  return { content: `Tool "${name}" is not offered here`, isError: true };
607
611
  }
608
- return run ? host.runTool(name, args, run) : host.runTool(name, args);
612
+ try {
613
+ return await (run ? host.runTool(name, args, run) : host.runTool(name, args));
614
+ } catch (err) {
615
+ return { content: `Failed to execute ${name}: ${toErrorMessage2(err)}`, isError: true };
616
+ }
609
617
  }
610
618
  }
611
619
  });
@@ -631,7 +639,11 @@ function fleetNote(tools) {
631
639
  ...has("fleet_status") ? ["- fleet_status: what is running and its progress."] : [],
632
640
  ...has("roll_up") ? ["- roll_up: the full result of finished tasks."] : [],
633
641
  ...has("session_note") ? ["- session_note: steer a running worker."] : [],
634
- ...has("terminate_subagent") ? ["- terminate_subagent: stop a worker."] : []
642
+ ...has("terminate_subagent") ? ["- terminate_subagent: stop a worker."] : [],
643
+ ...has("skill") ? [
644
+ "- skill: load one of WrongStack's skills by name (follow nextOffset to the last page);",
645
+ " a task that names WrongStack skills means these."
646
+ ] : []
635
647
  ].join("\n");
636
648
  }
637
649
 
@@ -674,9 +686,28 @@ function writeLeaderSession(stateDir, sessionId, record) {
674
686
  return writing.catch(() => void 0);
675
687
  }
676
688
 
689
+ // src/acp-leader/acp-leader-skills.ts
690
+ import { parseRequiredSkillsMarker } from "@wrongstack/core/skills";
691
+ var MARKERS = /<!--\s*wrongstack:required-skills\s+[\s\S]*?-->/g;
692
+ function externalSkillLoader(offered, prefix) {
693
+ return offered?.includes("skill") ? `${prefix}skill` : void 0;
694
+ }
695
+ function externalSkillDirective(text, loader) {
696
+ const skills = parseRequiredSkillsMarker(text);
697
+ if (!skills) return text;
698
+ const list = skills.join(", ");
699
+ const line = loader ? `[WrongStack] This task's playbook skills: ${list}. They are WrongStack skills: load each with the \`${loader}\` tool, following nextOffset to the last page, before changing code. Where the text below names the \`skill\` tool or a $name, it means that tool and these skills.` : `[WrongStack] This task's playbook skills: ${list}. This route offers no WrongStack skill tool: load them with your own skill tool if you have them, otherwise follow the protocol below without them.`;
700
+ let first = true;
701
+ return text.replace(MARKERS, () => {
702
+ if (!first) return "";
703
+ first = false;
704
+ return line;
705
+ });
706
+ }
707
+
677
708
  // src/acp-leader/acp-leader-stream.ts
678
709
  import { ProviderError } from "@wrongstack/core/types";
679
- import { toErrorMessage as toErrorMessage2 } from "@wrongstack/core/utils";
710
+ import { toErrorMessage as toErrorMessage3 } from "@wrongstack/core/utils";
680
711
  var StreamQueue = class {
681
712
  items = [];
682
713
  wake;
@@ -742,10 +773,7 @@ function clip(text, max) {
742
773
  if (last >= 55296 && last <= 56319) end -= 1;
743
774
  return `${text.slice(0, end)}\u2026`;
744
775
  }
745
- function cardOutput(call) {
746
- const raw = call.rawOutput;
747
- const text = call.output ?? (raw ? typeof raw.output === "string" ? raw.output : JSON.stringify(raw) : void 0);
748
- if (text === void 0) return void 0;
776
+ function cardOutputForText(text) {
749
777
  const output = clip(text, OUTPUT_PREVIEW_CHARS);
750
778
  return {
751
779
  output,
@@ -754,6 +782,12 @@ function cardOutput(call) {
754
782
  outputBytes: Buffer.byteLength(text)
755
783
  };
756
784
  }
785
+ function cardOutput(call) {
786
+ const raw = call.rawOutput;
787
+ const text = call.output ?? (raw ? typeof raw.output === "string" ? raw.output : JSON.stringify(raw) : void 0);
788
+ if (text === void 0) return void 0;
789
+ return cardOutputForText(text);
790
+ }
757
791
  var ToolCardRelay = class {
758
792
  constructor(events, meta) {
759
793
  this.events = events;
@@ -886,7 +920,7 @@ function agentTurnError(err, agentId, classify) {
886
920
  };
887
921
  }
888
922
  const kind = err?.kind;
889
- const message = `${agentId}: ${toErrorMessage2(err)}`;
923
+ const message = `${agentId}: ${toErrorMessage3(err)}`;
890
924
  if (kind === "stalled") {
891
925
  return {
892
926
  error: new ProviderError(message, 408, false, "acp", { kind: "timeout", cause: err }),
@@ -941,8 +975,11 @@ function parseSideModel(ref) {
941
975
  if (provider === ACP_LEADER_PROVIDER_ID) return void 0;
942
976
  return { provider, model: ref.slice(slash + 1) };
943
977
  }
978
+ function explicitLeaderSideModel(config) {
979
+ return parseSideModel(config.acp?.leader?.sideModel);
980
+ }
944
981
  function leaderSideModel(config) {
945
- return parseSideModel(config.acp?.leader?.sideModel) ?? parseSideModel(config.fallbackBridge) ?? parseSideModel(config.fallbackModels?.[0]);
982
+ return explicitLeaderSideModel(config) ?? parseSideModel(config.fallbackBridge) ?? parseSideModel(config.fallbackModels?.[0]);
946
983
  }
947
984
  function isLeaderTurn(req) {
948
985
  const { sessionId, threadId } = req.cache ?? {};
@@ -1060,7 +1097,10 @@ var AcpLeaderProvider = class {
1060
1097
  }
1061
1098
  /** The turn's prompt; an agent joining a conversation under way gets the turns before it. */
1062
1099
  promptText(leader, req) {
1063
- const latest = latestUserText(req.messages);
1100
+ const latest = externalSkillDirective(
1101
+ latestUserText(req.messages),
1102
+ externalSkillLoader(leader.fleet?.tools, `mcp__${FLEET_SERVER_NAME}__`)
1103
+ );
1064
1104
  const earlier = leader.joined ? void 0 : earlierConversation(req.messages);
1065
1105
  leader.joined = true;
1066
1106
  const prompt = earlier ? `${earlier}
@@ -1136,8 +1176,20 @@ ${withNotes}` : withNotes;
1136
1176
  this.acp ??= await import("@wrongstack/acp");
1137
1177
  return this.acp;
1138
1178
  }
1179
+ dropFleetGrants(sessionId) {
1180
+ for (const grantKey of this.fleetGrants.keys()) {
1181
+ try {
1182
+ const parsed = JSON.parse(grantKey);
1183
+ if (Array.isArray(parsed) && parsed[0] === sessionId) {
1184
+ this.fleetGrants.delete(grantKey);
1185
+ }
1186
+ } catch {
1187
+ }
1188
+ }
1189
+ }
1139
1190
  drop(key, leader) {
1140
1191
  this.sessions.delete(key);
1192
+ this.dropFleetGrants(key);
1141
1193
  void leader.session.close().catch(() => {
1142
1194
  });
1143
1195
  void leader.fleet?.close().catch(() => {
@@ -1312,6 +1364,7 @@ ${fleetNote(fleet.tools)}` : "")
1312
1364
  async closeAll() {
1313
1365
  const all = [...this.sessions.values()];
1314
1366
  this.sessions.clear();
1367
+ this.fleetGrants.clear();
1315
1368
  await Promise.all(
1316
1369
  all.map(
1317
1370
  (p) => p.then((leader) => {
@@ -1371,7 +1424,7 @@ import { registerBuiltinProviderAuthStrategies } from "@wrongstack/providers/oau
1371
1424
  // src/wrongforge-leader/wrongforge-leader-provider.ts
1372
1425
  import { consumeBtwNotes as consumeBtwNotes3 } from "@wrongstack/core/agent";
1373
1426
  import { ProviderError as ProviderError3 } from "@wrongstack/core/types";
1374
- import { toErrorMessage as toErrorMessage4 } from "@wrongstack/core/utils";
1427
+ import { toErrorMessage as toErrorMessage5 } from "@wrongstack/core/utils";
1375
1428
 
1376
1429
  // src/wrongforge-leader/wrongforge-leader-gateway.ts
1377
1430
  import { randomBytes as randomBytes2 } from "node:crypto";
@@ -1379,7 +1432,7 @@ import http from "node:http";
1379
1432
  import {
1380
1433
  compactToolDefinitionForWire,
1381
1434
  subjectForToolInput as subjectForToolInput2,
1382
- toErrorMessage as toErrorMessage3
1435
+ toErrorMessage as toErrorMessage4
1383
1436
  } from "@wrongstack/core/utils";
1384
1437
  import { timingSafeTokenEqual } from "@wrongstack/primitives";
1385
1438
  var NOT_OFFERED = /* @__PURE__ */ new Set([
@@ -1475,14 +1528,17 @@ async function startLeaderGateway(host, sessionId) {
1475
1528
  }
1476
1529
  host.runTool(name, input, {
1477
1530
  sessionId,
1478
- approve: (t, i) => askUser(host, sessionId, t, i)
1531
+ approve: (t, i) => askUser(host, sessionId, t, i),
1532
+ // The provider draws no card for a `wstack_*` call (its events are
1533
+ // marked external), so the session's card is settled here.
1534
+ announce: true
1479
1535
  }).then(
1480
1536
  (r) => send(res, 200, { ok: !r.isError, tool: name, content: r.content }),
1481
1537
  (err) => send(res, 200, {
1482
1538
  ok: false,
1483
1539
  tool: name,
1484
1540
  error: "tool_failed",
1485
- message: toErrorMessage3(err)
1541
+ message: toErrorMessage4(err)
1486
1542
  })
1487
1543
  );
1488
1544
  });
@@ -1582,7 +1638,7 @@ function providerError(err, id) {
1582
1638
  if (err.status >= 500) return make(err.message, err.status, true, "server");
1583
1639
  return make(`${err.code}: ${err.message}`, err.status, false, "invalid_request");
1584
1640
  }
1585
- return make(toErrorMessage4(err), 0, false, "unknown");
1641
+ return make(toErrorMessage5(err), 0, false, "unknown");
1586
1642
  }
1587
1643
  function taskError(record, id) {
1588
1644
  const make = (message, status, retryable, kind) => new ProviderError3(`WrongForge: ${message}`, status, retryable, id, { kind });
@@ -1657,19 +1713,27 @@ var WrongForgeLeaderProvider = class {
1657
1713
  }
1658
1714
  return choice.id;
1659
1715
  }
1660
- /** A configured side model, when the user named one. */
1661
- sideProvider() {
1662
- const ref = leaderSideModel(this.config());
1716
+ /**
1717
+ * A side model for a turn WrongForge does not lead. `explicitOnly` (a side
1718
+ * request through `complete()`) takes only the model the user named in
1719
+ * `acp.leader.sideModel`: WrongForge answers those itself (`oneShot`), and
1720
+ * handing them to `fallbackModels[0]` let that model take over the session.
1721
+ * A worker's turn may still fall back to the fallback chain, since `oneShot`
1722
+ * would leave it without tools.
1723
+ */
1724
+ sideProvider(explicitOnly = false) {
1725
+ const config = this.config();
1726
+ const ref = explicitOnly ? explicitLeaderSideModel(config) : leaderSideModel(config);
1663
1727
  if (!ref || ref.provider === this.id) return void 0;
1664
1728
  let provider = this.sideProviders.get(ref.provider);
1665
1729
  if (!provider) {
1666
- provider = this.opts.buildProvider(ref.provider, this.config());
1730
+ provider = this.opts.buildProvider(ref.provider, config);
1667
1731
  if (provider) this.sideProviders.set(ref.provider, provider);
1668
1732
  }
1669
1733
  return provider ? { provider, model: ref.model } : void 0;
1670
1734
  }
1671
1735
  async complete(req, opts) {
1672
- const side = this.sideProvider();
1736
+ const side = this.sideProvider(true);
1673
1737
  if (side) return side.provider.complete({ ...req, model: side.model }, opts);
1674
1738
  return this.oneShot(req, opts.signal);
1675
1739
  }
@@ -1739,8 +1803,16 @@ var WrongForgeLeaderProvider = class {
1739
1803
  try {
1740
1804
  info = await this.info(call, opts.signal);
1741
1805
  model = this.model(req.model, info);
1742
- if (host) leader.gateway ??= startLeaderGateway(host, key).catch(() => void 0);
1806
+ if (host && !leader.gateway) {
1807
+ leader.gateway = startLeaderGateway(host, key).catch(() => {
1808
+ leader.gateway = void 0;
1809
+ return void 0;
1810
+ });
1811
+ }
1743
1812
  gateway = await leader.gateway;
1813
+ if (!gateway) {
1814
+ leader.gateway = void 0;
1815
+ }
1744
1816
  joinedBefore = leader.joined ?? await this.wfSessionExists(call, leader, opts.signal);
1745
1817
  } catch (err) {
1746
1818
  throw providerError(err, this.id);
@@ -1764,7 +1836,7 @@ var WrongForgeLeaderProvider = class {
1764
1836
  "POST",
1765
1837
  "/v1/tasks",
1766
1838
  {
1767
- prompt: this.promptText(req, joinedBefore),
1839
+ prompt: this.promptText(req, joinedBefore, gateway),
1768
1840
  session_id: leader.wfSessionId,
1769
1841
  workdir: host?.projectRoot ?? process.cwd(),
1770
1842
  ...model ? { model } : {},
@@ -1780,6 +1852,10 @@ var WrongForgeLeaderProvider = class {
1780
1852
  );
1781
1853
  taskId = task.id;
1782
1854
  leader.joined = true;
1855
+ if (opts.signal.aborted) {
1856
+ cancelTask(call, taskId, "interrupted in WrongStack");
1857
+ throw new WfAborted();
1858
+ }
1783
1859
  for await (const ev of followTask(call, task.id, opts.signal)) {
1784
1860
  if (ev.type === "task.heartbeat" || ev.type === "step.finished") {
1785
1861
  void reportWrongForgeQuota({ providerId: this.id, fetchImpl: this.opts.fetchImpl });
@@ -1831,8 +1907,11 @@ var WrongForgeLeaderProvider = class {
1831
1907
  }
1832
1908
  }
1833
1909
  /** The turn's prompt; WrongForge joining a conversation under way gets the turns before it. */
1834
- promptText(req, joined) {
1835
- const latest = latestUserText(req.messages);
1910
+ promptText(req, joined, gateway) {
1911
+ const latest = externalSkillDirective(
1912
+ latestUserText(req.messages),
1913
+ gateway ? externalSkillLoader(gateway.tools, gateway.spec.name_prefix ?? "") : void 0
1914
+ );
1836
1915
  const earlier = joined ? void 0 : earlierConversation(req.messages);
1837
1916
  const prompt = earlier ? `${earlier}
1838
1917
 
@@ -2043,7 +2122,7 @@ Try \`wstack models refresh\` once you have network access.`,
2043
2122
  cause: err
2044
2123
  });
2045
2124
  }
2046
- if (config.features.modelsRegistry && !acpLeader) {
2125
+ if (config.features.modelsRegistry && !acpLeader && !wrongForgeLeader) {
2047
2126
  provider = await withCatalogCapabilities(
2048
2127
  modelsRegistry,
2049
2128
  config.provider,
@@ -2062,9 +2141,10 @@ export {
2062
2141
  wrongstackAcpPermissionPolicy,
2063
2142
  recordAcpRateLimit,
2064
2143
  startAcpTurnReminders,
2144
+ cardOutputForText,
2065
2145
  WRONGFORGE_REASONING,
2066
2146
  wrongForgeRuntime,
2067
2147
  setupProvider,
2068
2148
  createGracefulShutdown
2069
2149
  };
2070
- //# sourceMappingURL=chunk-M7FNHCE3.js.map
2150
+ //# sourceMappingURL=chunk-EAATL6FL.js.map
@@ -201,6 +201,7 @@ var LoginAttemptStore = class _LoginAttemptStore {
201
201
  store = /* @__PURE__ */ new Map();
202
202
  writeTimer;
203
203
  dirty = false;
204
+ writeTail = Promise.resolve();
204
205
  filePath;
205
206
  debounceMs;
206
207
  retentionMs;
@@ -339,9 +340,7 @@ var LoginAttemptStore = class _LoginAttemptStore {
339
340
  clearTimeout(this.writeTimer);
340
341
  this.writeTimer = void 0;
341
342
  }
342
- if (this.dirty) {
343
- await this.writeToDisk();
344
- }
343
+ await this.writeToDisk();
345
344
  }
346
345
  scheduleWrite() {
347
346
  this.dirty = true;
@@ -352,7 +351,14 @@ var LoginAttemptStore = class _LoginAttemptStore {
352
351
  }, this.debounceMs);
353
352
  this.writeTimer.unref?.();
354
353
  }
355
- async writeToDisk() {
354
+ writeToDisk() {
355
+ const pending = this.writeTail.then(() => {
356
+ return this.dirty ? this.writeSnapshotToDisk() : void 0;
357
+ });
358
+ this.writeTail = pending.catch(() => void 0);
359
+ return pending;
360
+ }
361
+ async writeSnapshotToDisk() {
356
362
  this.dirty = false;
357
363
  const now = Date.now();
358
364
  const cutoff = now - this.retentionMs;
@@ -3733,52 +3739,51 @@ ${terminalText("Reachable from other machines on your network:", "blue", { bold:
3733
3739
 
3734
3740
  // src/hq-server/server-lifecycle.ts
3735
3741
  function createHqServerShutdown(params) {
3736
- let closed = false;
3737
- return () => new Promise((res) => {
3738
- if (closed) {
3739
- res();
3740
- return;
3741
- }
3742
- closed = true;
3743
- clearInterval(params.cleanupTimer);
3744
- clearInterval(params.browserHeartbeatTimer);
3745
- clearInterval(params.timeseriesFlushTimer);
3746
- clearInterval(params.sessionCleanupTimer);
3747
- params.stopAlertEngine();
3748
- params.authWatcher.close();
3749
- params.snapshotBroadcaster.close();
3750
- params.bootstrapStore.clear();
3751
- params.persistence.timeseries.flush();
3752
- for (const ws of [...params.browsers, ...params.clients.keys()]) {
3753
- try {
3754
- ws.close(1001, "HQ shutting down");
3755
- ws.terminate();
3756
- } catch {
3742
+ let closing;
3743
+ return () => {
3744
+ if (closing) return closing;
3745
+ closing = new Promise((res) => {
3746
+ clearInterval(params.cleanupTimer);
3747
+ clearInterval(params.browserHeartbeatTimer);
3748
+ clearInterval(params.timeseriesFlushTimer);
3749
+ clearInterval(params.sessionCleanupTimer);
3750
+ params.stopAlertEngine();
3751
+ params.authWatcher.close();
3752
+ params.snapshotBroadcaster.close();
3753
+ params.bootstrapStore.clear();
3754
+ params.persistence.timeseries.flush();
3755
+ for (const ws of [...params.browsers, ...params.clients.keys()]) {
3756
+ try {
3757
+ ws.close(1001, "HQ shutting down");
3758
+ ws.terminate();
3759
+ } catch {
3760
+ }
3757
3761
  }
3758
- }
3759
- params.wss.close();
3760
- params.mailboxManager.close();
3761
- params.httpServer.close(() => {
3762
- const mailboxCloses = [...params.mailboxManager.mailboxGateways.values()].map(
3763
- ({ mailbox }) => mailbox.close().catch(() => void 0)
3764
- );
3765
- params.mailboxManager.mailboxGateways.clear();
3766
- params.mailboxManager.mailboxGatewayLastUsed.clear();
3767
- void Promise.all([
3768
- ...mailboxCloses,
3769
- // Chimera/race: flush the login-attempt store INSIDE the awaited
3770
- // shutdown set — the old fire-and-forget `void flush()` let close()
3771
- // resolve before the debounced write landed, so persistence tests
3772
- // had to sleep past it (and restarts could miss lockout state).
3773
- params.loginAttempts.flush(),
3774
- params.persistence.eventLog.drain(),
3775
- params.persistence.snapshotStore.drain(),
3776
- params.persistence.timeseries.drain(),
3777
- params.persistence.kanban.drain(),
3778
- params.persistence.sage?.drain()
3779
- ]).then(() => clearHqRuntimeMarker(params.dataDir, params.hqUrl)).catch(() => void 0).finally(() => res());
3762
+ params.wss.close();
3763
+ params.mailboxManager.close();
3764
+ params.httpServer.close(() => {
3765
+ const mailboxCloses = [...params.mailboxManager.mailboxGateways.values()].map(
3766
+ ({ mailbox }) => mailbox.close().catch(() => void 0)
3767
+ );
3768
+ params.mailboxManager.mailboxGateways.clear();
3769
+ params.mailboxManager.mailboxGatewayLastUsed.clear();
3770
+ void Promise.allSettled([
3771
+ ...mailboxCloses,
3772
+ // Chimera/race: flush the login-attempt store INSIDE the awaited
3773
+ // shutdown set — the old fire-and-forget `void flush()` let close()
3774
+ // resolve before the debounced write landed, so persistence tests
3775
+ // had to sleep past it (and restarts could miss lockout state).
3776
+ params.loginAttempts.flush(),
3777
+ params.persistence.eventLog.drain(),
3778
+ params.persistence.snapshotStore.drain(),
3779
+ params.persistence.timeseries.drain(),
3780
+ params.persistence.kanban.drain(),
3781
+ params.persistence.sage?.drain()
3782
+ ]).then(() => clearHqRuntimeMarker(params.dataDir, params.hqUrl)).catch(() => void 0).finally(() => res());
3783
+ });
3780
3784
  });
3781
- });
3785
+ return closing;
3786
+ };
3782
3787
  }
3783
3788
 
3784
3789
  // src/hq-server/socket-credentials.ts
@@ -5385,4 +5390,4 @@ export {
5385
5390
  startHqServer,
5386
5391
  HqInsecureExposureError2 as HqInsecureExposureError
5387
5392
  };
5388
- //# sourceMappingURL=chunk-JFYQGMMM.js.map
5393
+ //# sourceMappingURL=chunk-FWUIKCCO.js.map
@@ -22,7 +22,7 @@ async function handleHelpVersionShortCircuit(argv) {
22
22
  }
23
23
  if (earlyFlags["help"] === true) {
24
24
  if (positional.length > 0) {
25
- const { subcommandNames } = await import("./subcommands-OCJNO57E.js");
25
+ const { subcommandNames } = await import("./subcommands-SKJPUJ7N.js");
26
26
  if (subcommandNames.includes(positional[0])) {
27
27
  const first = positional[0];
28
28
  const deep = positional[1];
@@ -43,4 +43,4 @@ async function handleHelpVersionShortCircuit(argv) {
43
43
  export {
44
44
  handleHelpVersionShortCircuit
45
45
  };
46
- //# sourceMappingURL=chunk-MEBXWI7U.js.map
46
+ //# sourceMappingURL=chunk-H5DCQFUI.js.map
@@ -225,6 +225,7 @@ function wfTokens(usage) {
225
225
  };
226
226
  }
227
227
  function sleep(ms, signal) {
228
+ if (signal.aborted) return Promise.resolve();
228
229
  return new Promise((resolve) => {
229
230
  const t = setTimeout(done, ms);
230
231
  function done() {
@@ -251,4 +252,4 @@ export {
251
252
  toProgress,
252
253
  wfTokens
253
254
  };
254
- //# sourceMappingURL=chunk-VEESMPTX.js.map
255
+ //# sourceMappingURL=chunk-PGC44T7N.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  resolveWrongForgeEndpoint,
3
3
  wrongForgeCall
4
- } from "./chunk-VEESMPTX.js";
4
+ } from "./chunk-PGC44T7N.js";
5
5
 
6
6
  // src/fleet/acp-wrongstack-bridge.ts
7
7
  import { statSync } from "node:fs";
@@ -749,4 +749,4 @@ export {
749
749
  refreshWrongForgeInfoCache,
750
750
  reportWrongForgeQuota
751
751
  };
752
- //# sourceMappingURL=chunk-5SGMUDP5.js.map
752
+ //# sourceMappingURL=chunk-QRWXHGLB.js.map
@@ -3,7 +3,7 @@
3
3
  var loaders = {
4
4
  automation: async () => (await import("./automation-O7ZRZSFS.js")).automationCmd,
5
5
  sandbox: async () => (await import("./sandbox-EZQ76MNY.js")).sandboxCmd,
6
- acp: async () => (await import("./acp-NKUEYJDZ.js")).acpCmd,
6
+ acp: async () => (await import("./acp-CZBSFQB7.js")).acpCmd,
7
7
  init: async () => (await import("./init-5PLABNLR.js")).initCmd,
8
8
  auth: async () => (await import("./auth-2ZG5DBHS.js")).authCmd,
9
9
  update: async () => (await import("./update-54W7GUS5.js")).updateCmd,
@@ -36,7 +36,7 @@ var loaders = {
36
36
  quick: async () => (await import("./quick-NPC3N3ZX.js")).quickCmd,
37
37
  bench: async () => (await import("./bench-NDYES33Y.js")).benchCmd,
38
38
  chronicle: async () => (await import("./chronicle-WBK3TJRB.js")).chronicleCmd,
39
- hq: async () => (await import("./hq-54PQYR5O.js")).hqCmd,
39
+ hq: async () => (await import("./hq-V2M4IYCI.js")).hqCmd,
40
40
  mailbox: async () => (await import("./mailbox-serve-MMQCHOHI.js")).mailboxServeCmd,
41
41
  permissions: async () => (await import("./permissions-6YJ64W65.js")).permissionsCmd,
42
42
  project: async () => (await import("./project-V5KNTLV4.js")).projectCmd,
@@ -58,4 +58,4 @@ export {
58
58
  subcommands,
59
59
  subcommandNames
60
60
  };
61
- //# sourceMappingURL=chunk-7BM4LGKQ.js.map
61
+ //# sourceMappingURL=chunk-W7X23HI6.js.map
@@ -47,4 +47,4 @@ export {
47
47
  trackAcpLeader,
48
48
  closeAcpLeaderSessions
49
49
  };
50
- //# sourceMappingURL=chunk-LUEO5HLZ.js.map
50
+ //# sourceMappingURL=chunk-X4DEQLAZ.js.map
@@ -22,7 +22,7 @@ import {
22
22
  } from "./chunk-FUJHWQV4.js";
23
23
  import {
24
24
  handleHelpVersionShortCircuit
25
- } from "./chunk-MEBXWI7U.js";
25
+ } from "./chunk-H5DCQFUI.js";
26
26
  import {
27
27
  fmtTok,
28
28
  patchConfig
@@ -32,14 +32,14 @@ import {
32
32
  } from "./chunk-NL2ABOAS.js";
33
33
  import {
34
34
  subcommands
35
- } from "./chunk-7BM4LGKQ.js";
35
+ } from "./chunk-W7X23HI6.js";
36
36
  import {
37
37
  renderDeepHelp,
38
38
  renderFocusedHelp
39
39
  } from "./chunk-P7MEEUGT.js";
40
40
  import {
41
41
  DEFAULT_PORT
42
- } from "./chunk-JFYQGMMM.js";
42
+ } from "./chunk-FWUIKCCO.js";
43
43
  import "./chunk-QVITQ425.js";
44
44
  import {
45
45
  resolveHqPasswordInput
@@ -86,7 +86,7 @@ import {
86
86
  } from "./chunk-3LEIFO5D.js";
87
87
  import {
88
88
  WRONGFORGE_AGENT_ID
89
- } from "./chunk-VEESMPTX.js";
89
+ } from "./chunk-PGC44T7N.js";
90
90
  import "./chunk-OZCYZYN2.js";
91
91
  import {
92
92
  runUpdateCommand
@@ -103,7 +103,7 @@ import {
103
103
  } from "./chunk-M7PSENGF.js";
104
104
  import {
105
105
  ACP_LEADER_PROVIDER_ID
106
- } from "./chunk-LUEO5HLZ.js";
106
+ } from "./chunk-X4DEQLAZ.js";
107
107
  import "./chunk-H53EXXAU.js";
108
108
  import {
109
109
  applyAsciiMode
@@ -948,7 +948,7 @@ async function isPortInUse(host, port) {
948
948
  }
949
949
  async function handleHqShortCircuit(flags) {
950
950
  if (flags["hq"] !== true) return null;
951
- const { startHqServer } = await import("./hq-server-YK7FBLL6.js");
951
+ const { startHqServer } = await import("./hq-server-QM7EIVGJ.js");
952
952
  const tunnelRequested = flags["tunnel"] === true;
953
953
  const rawPublicUrl = typeof flags["hq-public-url"] === "string" ? flags["hq-public-url"] : process.env.WRONGSTACK_HQ_PUBLIC_URL;
954
954
  let publicOrigin;
@@ -3639,4 +3639,4 @@ async function initializeCli(argv, options = {}) {
3639
3639
  export {
3640
3640
  initializeCli
3641
3641
  };
3642
- //# sourceMappingURL=cli-context-CQYGIWOU.js.map
3642
+ //# sourceMappingURL=cli-context-6KS3HV5R.js.map
@@ -132,6 +132,7 @@ import {
132
132
  } from "./chunk-KNYIEQAY.js";
133
133
  import {
134
134
  WRONGFORGE_REASONING,
135
+ cardOutputForText,
135
136
  createGracefulShutdown,
136
137
  formatAcpAgentList,
137
138
  loadCachedAcpRegistry,
@@ -141,7 +142,7 @@ import {
141
142
  startAcpTurnReminders,
142
143
  wrongForgeRuntime,
143
144
  wrongstackAcpPermissionPolicy
144
- } from "./chunk-M7FNHCE3.js";
145
+ } from "./chunk-EAATL6FL.js";
145
146
  import {
146
147
  DEFAULT_BRIDGE_SERVERS,
147
148
  createHqCommandDispatcher,
@@ -154,7 +155,7 @@ import {
154
155
  reportWrongForgeQuota,
155
156
  writeWrongForgeInfoCache,
156
157
  wrongstackBridgeSetup
157
- } from "./chunk-5SGMUDP5.js";
158
+ } from "./chunk-QRWXHGLB.js";
158
159
  import {
159
160
  isRestrictedMode,
160
161
  withRestrictedTools
@@ -173,7 +174,7 @@ import {
173
174
  toProgress,
174
175
  wfTokens,
175
176
  wrongForgeCall
176
- } from "./chunk-VEESMPTX.js";
177
+ } from "./chunk-PGC44T7N.js";
177
178
  import {
178
179
  startCliHqConnection
179
180
  } from "./chunk-76JE54WD.js";
@@ -196,7 +197,7 @@ import {
196
197
  ACP_LEADER_PROVIDER_ID,
197
198
  acpLeaderSessionAgent,
198
199
  bindAcpLeaderHost
199
- } from "./chunk-LUEO5HLZ.js";
200
+ } from "./chunk-X4DEQLAZ.js";
200
201
  import {
201
202
  checkForUpdate
202
203
  } from "./chunk-H53EXXAU.js";
@@ -1028,6 +1029,7 @@ function makeWrongForgeRunner(options) {
1028
1029
  }
1029
1030
  const cancel = () => cancelTask(call, record.id, "cancelled by WrongStack");
1030
1031
  ctx.signal.addEventListener("abort", cancel, { once: true });
1032
+ if (ctx.signal.aborted) cancel();
1031
1033
  const publish = (event) => {
1032
1034
  try {
1033
1035
  options.publishLive?.(ctx, task, event);
@@ -1040,6 +1042,7 @@ function makeWrongForgeRunner(options) {
1040
1042
  } catch {
1041
1043
  }
1042
1044
  };
1045
+ const stepTexts = [""];
1043
1046
  try {
1044
1047
  for await (const ev of followTask(call, record.id, ctx.signal, {
1045
1048
  retryDelayMs: options.retryDelayMs,
@@ -1055,6 +1058,11 @@ function makeWrongForgeRunner(options) {
1055
1058
  void reportWrongForgeQuota({ endpoint: ep, fetchImpl: options.fetchImpl });
1056
1059
  }
1057
1060
  for (const progress of toProgress(ev)) publish(progress);
1061
+ if (ev.type === "agent.text" && typeof ev.data["text"] === "string") {
1062
+ stepTexts[stepTexts.length - 1] += ev.data["text"];
1063
+ } else if (ev.type === "tool.started" && stepTexts[stepTexts.length - 1]?.trim()) {
1064
+ stepTexts.push("");
1065
+ }
1058
1066
  }
1059
1067
  record = await terminalTaskRecord(call, record.id, ctx.signal, {
1060
1068
  retryDelayMs: options.retryDelayMs
@@ -1080,7 +1088,8 @@ function makeWrongForgeRunner(options) {
1080
1088
  if (!result || !result.text.trim() && result.tool_calls === 0) {
1081
1089
  throw subagentError("empty_response", "WrongForge finished with no text and no tool calls");
1082
1090
  }
1083
- return { result: result.text, iterations: result.steps, toolCalls: result.tool_calls };
1091
+ const text = stepTexts.map((t) => t.trim()).filter(Boolean).join("\n\n") || result.text;
1092
+ return { result: text, iterations: result.steps, toolCalls: result.tool_calls };
1084
1093
  };
1085
1094
  }
1086
1095
  function taskFailure(record, signal) {
@@ -3243,13 +3252,31 @@ function createAcpLeaderHost(opts) {
3243
3252
  runTool: async (name, input, run = {}) => {
3244
3253
  const agent = agentFor(run.sessionId);
3245
3254
  const use = { type: "tool_use", id: `acp_fleet_${randomUUID()}`, name, input };
3255
+ const startedAt = Date.now();
3256
+ const settle = (content2, ok, settlement) => {
3257
+ if (!run.announce) return;
3258
+ opts.events.emit("tool.executed", {
3259
+ sessionId: agent.ctx.activeRunSessionId ?? agent.ctx.session?.id,
3260
+ agentId: "leader",
3261
+ id: use.id,
3262
+ name,
3263
+ durationMs: Date.now() - startedAt,
3264
+ ok,
3265
+ settlement,
3266
+ input: use.input,
3267
+ outsideConversation: true,
3268
+ ...cardOutputForText(content2)
3269
+ });
3270
+ };
3246
3271
  const batch = await agent.toolExecutor.executeBatch([use], agent.ctx, "sequential");
3247
3272
  let result = batch.outputs[0]?.result;
3248
3273
  if (result?.type === "tool_confirm_pending") {
3249
3274
  const tool = opts.getTool(name);
3250
3275
  const approved = { ...use, input: result.input };
3251
3276
  if (!tool || !await run.approve?.(tool, approved.input)) {
3252
- return { content: `${name} was not approved by the user.`, isError: true };
3277
+ const content2 = `${name} was not approved by the user.`;
3278
+ settle(content2, false, "declined");
3279
+ return { content: content2, isError: true };
3253
3280
  }
3254
3281
  result = (await agent.toolExecutor.executeTool(
3255
3282
  tool,
@@ -3258,8 +3285,13 @@ function createAcpLeaderHost(opts) {
3258
3285
  agent.perIterationOutputCapBytes
3259
3286
  )).block;
3260
3287
  }
3261
- if (!result) return { content: `${name} returned no result.`, isError: true };
3288
+ if (!result) {
3289
+ const content2 = `${name} returned no result.`;
3290
+ settle(content2, false, "failed");
3291
+ return { content: content2, isError: true };
3292
+ }
3262
3293
  const content = typeof result.content === "string" ? result.content : JSON.stringify(result.content);
3294
+ settle(content, !result.is_error, result.is_error ? "failed" : "completed");
3263
3295
  return { content, isError: Boolean(result.is_error) };
3264
3296
  },
3265
3297
  confirmAwaiter: opts.confirmAwaiter
@@ -8977,6 +9009,7 @@ ${JSON.stringify({
8977
9009
 
8978
9010
  // src/fleet/host-skill-companion.ts
8979
9011
  import { createHash as createHash2, randomUUID as randomUUID6 } from "node:crypto";
9012
+ import { keepsOwnContext } from "@wrongstack/core/agent";
8980
9013
  import {
8981
9014
  extractSkillMentions,
8982
9015
  isSkillRecommendable,
@@ -9127,7 +9160,7 @@ var HostSkillCompanion = class {
9127
9160
  input.events.on("agent.run.started", (event) => {
9128
9161
  const sessionId = event.sessionId;
9129
9162
  if (!sessionId || event.ctx.meta?.["agentRole"]) return;
9130
- if (isProofDrivenBugHuntRequest(event.inputText ?? "")) {
9163
+ if (keepsOwnContext(event.ctx.provider) || isProofDrivenBugHuntRequest(event.inputText ?? "")) {
9131
9164
  this.release(sessionId);
9132
9165
  if (event.ctx.meta) delete event.ctx.meta[SKILL_COMPANION_META_KEY];
9133
9166
  return;
@@ -43411,7 +43444,7 @@ async function runCliExecution(params) {
43411
43444
  governanceHandle,
43412
43445
  setConfig
43413
43446
  } = params;
43414
- const { execute } = await import("./execution-IV72RUSM.js");
43447
+ const { execute } = await import("./execution-RVDUXLNT.js");
43415
43448
  return execute(
43416
43449
  toExecuteDeps({
43417
43450
  core: {
@@ -43832,4 +43865,4 @@ export {
43832
43865
  CLI_VERSION,
43833
43866
  runInteractive
43834
43867
  };
43835
- //# sourceMappingURL=cli-main-VRUJNUBX.js.map
43868
+ //# sourceMappingURL=cli-main-NF3YGDME.js.map
@@ -63,7 +63,7 @@ import {
63
63
  import "./chunk-OZCYZYN2.js";
64
64
  import {
65
65
  confirmAcpLeaderThroughEvents
66
- } from "./chunk-LUEO5HLZ.js";
66
+ } from "./chunk-X4DEQLAZ.js";
67
67
  import {
68
68
  CLI_VERSION
69
69
  } from "./chunk-HKMOIIPQ.js";
@@ -6181,6 +6181,11 @@ async function resumeSession(ctx, sessionId) {
6181
6181
  );
6182
6182
  warn(`could not restore ${targetProviderId}/${targetModel}`, err);
6183
6183
  }
6184
+ } else if (targetProviderId && targetProviderId !== currentProviderId) {
6185
+ warn(
6186
+ "could not restore saved route without a provider switch",
6187
+ `${targetProviderId}/${targetModel}`
6188
+ );
6184
6189
  } else if (targetModel !== agent.ctx.model) {
6185
6190
  agent.ctx.model = targetModel;
6186
6191
  }
@@ -6834,7 +6839,7 @@ async function runWebUIDispatch(ctx) {
6834
6839
  agent.disableInteractiveConfirmation();
6835
6840
  confirmAcpLeaderThroughEvents();
6836
6841
  renderer.setSilent(true);
6837
- const { runWebUI } = await import("./webui-server-V2R5WQUK.js");
6842
+ const { runWebUI } = await import("./webui-server-6I6QOECV.js");
6838
6843
  const flagValue = (names) => {
6839
6844
  for (const name of names) {
6840
6845
  if (!Object.hasOwn(flags, name)) continue;
@@ -7675,4 +7680,4 @@ export {
7675
7680
  execute,
7676
7681
  resolveReviewerFallbackModels
7677
7682
  };
7678
- //# sourceMappingURL=execution-IV72RUSM.js.map
7683
+ //# sourceMappingURL=execution-RVDUXLNT.js.map
@@ -552,18 +552,21 @@ async function tokenRevoke(args, deps) {
552
552
  const dataDir = resolveDataDir(deps);
553
553
  const tokenField = scope === "client" ? "clientTokens" : "browserTokens";
554
554
  let revoked;
555
+ let ambiguous = [];
555
556
  try {
556
557
  await mutateHqAuthFile(
557
558
  dataDir,
558
559
  (current) => {
559
560
  const tokens = current[tokenField] ?? [];
560
561
  const matches = tokens.filter((t) => t.id.startsWith(idPrefix));
562
+ ambiguous = [];
561
563
  if (matches.length === 0) {
562
564
  revoked = void 0;
563
565
  return current;
564
566
  }
565
567
  if (matches.length > 1) {
566
- revoked = matches[0];
568
+ revoked = void 0;
569
+ ambiguous = matches;
567
570
  return current;
568
571
  }
569
572
  revoked = matches[0];
@@ -580,6 +583,13 @@ async function tokenRevoke(args, deps) {
580
583
  `);
581
584
  return 1;
582
585
  }
586
+ if (ambiguous.length > 0) {
587
+ deps.renderer.writeError(
588
+ `Id-prefix "${idPrefix}" matches ${ambiguous.length} ${scope} tokens (${ambiguous.map((t) => t.id).join(", ")}); nothing revoked. Use a longer prefix.
589
+ `
590
+ );
591
+ return 1;
592
+ }
583
593
  if (!revoked) {
584
594
  deps.renderer.writeError(`No ${scope} token found matching id-prefix "${idPrefix}".
585
595
  `);
@@ -704,7 +714,7 @@ var hqCmd = async (args, deps) => {
704
714
  return 1;
705
715
  };
706
716
  async function startServer(deps) {
707
- const { startHqServer } = await import("./hq-server-YK7FBLL6.js");
717
+ const { startHqServer } = await import("./hq-server-QM7EIVGJ.js");
708
718
  const dataDir = resolveDataDir(deps);
709
719
  const flags = deps.flags ?? {};
710
720
  const rawPublicUrl = typeof flags["hq-public-url"] === "string" ? flags["hq-public-url"] : process.env.WRONGSTACK_HQ_PUBLIC_URL;
@@ -1014,4 +1024,4 @@ function printHelp(deps) {
1014
1024
  export {
1015
1025
  hqCmd
1016
1026
  };
1017
- //# sourceMappingURL=hq-54PQYR5O.js.map
1027
+ //# sourceMappingURL=hq-V2M4IYCI.js.map
@@ -22,6 +22,7 @@ export declare class LoginAttemptStore {
22
22
  private store;
23
23
  private writeTimer;
24
24
  private dirty;
25
+ private writeTail;
25
26
  private readonly filePath;
26
27
  private readonly debounceMs;
27
28
  private readonly retentionMs;
@@ -92,6 +93,7 @@ export declare class LoginAttemptStore {
92
93
  flush(): Promise<void>;
93
94
  private scheduleWrite;
94
95
  private writeToDisk;
96
+ private writeSnapshotToDisk;
95
97
  /** Iterate entries (for cleanup timers). */
96
98
  entries(): IterableIterator<[string, LoginAttemptEntry]>;
97
99
  }
@@ -10,7 +10,7 @@ import {
10
10
  readLocalSubagentTranscript,
11
11
  sanitizeApiError,
12
12
  startHqServer
13
- } from "./chunk-JFYQGMMM.js";
13
+ } from "./chunk-FWUIKCCO.js";
14
14
  import "./chunk-QVITQ425.js";
15
15
  import "./chunk-5TQ65PXQ.js";
16
16
  import "./chunk-OGVSKS4Q.js";
@@ -29,4 +29,4 @@ export {
29
29
  sanitizeApiError,
30
30
  startHqServer
31
31
  };
32
- //# sourceMappingURL=hq-server-YK7FBLL6.js.map
32
+ //# sourceMappingURL=hq-server-QM7EIVGJ.js.map
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-M7PSENGF.js";
9
9
  import {
10
10
  closeAcpLeaderSessions
11
- } from "./chunk-LUEO5HLZ.js";
11
+ } from "./chunk-X4DEQLAZ.js";
12
12
  import {
13
13
  CLI_VERSION
14
14
  } from "./chunk-HKMOIIPQ.js";
@@ -125,7 +125,7 @@ async function main(argv) {
125
125
  applyAsciiMode(earlyFlags);
126
126
  }
127
127
  if (earlyFlags["help"] === true || earlyFlags["version"] === true) {
128
- const { handleHelpVersionShortCircuit } = await import("./short-circuit-flags-AGHURHMQ.js");
128
+ const { handleHelpVersionShortCircuit } = await import("./short-circuit-flags-276OLPIN.js");
129
129
  const earlyExit = await handleHelpVersionShortCircuit(argv);
130
130
  if (earlyExit !== null) return earlyExit;
131
131
  }
@@ -134,7 +134,7 @@ async function main(argv) {
134
134
  shouldCaptureTuiStartup(parsed.flags, parsed.positional)
135
135
  );
136
136
  try {
137
- const { initializeCli } = await import("./cli-context-CQYGIWOU.js");
137
+ const { initializeCli } = await import("./cli-context-6KS3HV5R.js");
138
138
  const cliCtx = await initializeCli(argv, {
139
139
  onNonTuiLaunch: () => startupOutput.stop()
140
140
  });
@@ -144,7 +144,7 @@ async function main(argv) {
144
144
  } else {
145
145
  startupOutput.stop();
146
146
  }
147
- const { runInteractive } = await import("./cli-main-VRUJNUBX.js");
147
+ const { runInteractive } = await import("./cli-main-NF3YGDME.js");
148
148
  return await runInteractive(cliCtx);
149
149
  } finally {
150
150
  startupOutput.stop();
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  handleHelpVersionShortCircuit
3
- } from "./chunk-MEBXWI7U.js";
3
+ } from "./chunk-H5DCQFUI.js";
4
4
  import "./chunk-M7PSENGF.js";
5
5
  import "./chunk-UROB7MK5.js";
6
6
  import "./chunk-HKMOIIPQ.js";
@@ -8,4 +8,4 @@ import "./chunk-W23PY4IJ.js";
8
8
  export {
9
9
  handleHelpVersionShortCircuit
10
10
  };
11
- //# sourceMappingURL=short-circuit-flags-AGHURHMQ.js.map
11
+ //# sourceMappingURL=short-circuit-flags-276OLPIN.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  subcommandNames,
3
3
  subcommands
4
- } from "./chunk-7BM4LGKQ.js";
4
+ } from "./chunk-W7X23HI6.js";
5
5
  import "./chunk-W23PY4IJ.js";
6
6
  export {
7
7
  subcommandNames,
8
8
  subcommands
9
9
  };
10
- //# sourceMappingURL=subcommands-OCJNO57E.js.map
10
+ //# sourceMappingURL=subcommands-SKJPUJ7N.js.map
@@ -19,11 +19,11 @@ import {
19
19
  readCachedWrongForgeInfo,
20
20
  refreshWrongForgeInfoCache,
21
21
  reportWrongForgeQuota
22
- } from "./chunk-5SGMUDP5.js";
22
+ } from "./chunk-QRWXHGLB.js";
23
23
  import {
24
24
  WRONGFORGE_AGENT_ID,
25
25
  resolveWrongForgeEndpoint
26
- } from "./chunk-VEESMPTX.js";
26
+ } from "./chunk-PGC44T7N.js";
27
27
  import {
28
28
  startCliHqConnection
29
29
  } from "./chunk-76JE54WD.js";
@@ -33,7 +33,7 @@ import {
33
33
  import {
34
34
  ACP_LEADER_PROVIDER_ID,
35
35
  setAcpLeaderSessionAgents
36
- } from "./chunk-LUEO5HLZ.js";
36
+ } from "./chunk-X4DEQLAZ.js";
37
37
  import {
38
38
  CLI_VERSION
39
39
  } from "./chunk-HKMOIIPQ.js";
@@ -2534,4 +2534,4 @@ async function runWebUI(opts) {
2534
2534
  export {
2535
2535
  runWebUI
2536
2536
  };
2537
- //# sourceMappingURL=webui-server-V2R5WQUK.js.map
2537
+ //# sourceMappingURL=webui-server-6I6QOECV.js.map
@@ -18,7 +18,14 @@ export declare class WrongForgeLeaderProvider implements Provider {
18
18
  private client;
19
19
  private info;
20
20
  private model;
21
- /** A configured side model, when the user named one. */
21
+ /**
22
+ * A side model for a turn WrongForge does not lead. `explicitOnly` (a side
23
+ * request through `complete()`) takes only the model the user named in
24
+ * `acp.leader.sideModel`: WrongForge answers those itself (`oneShot`), and
25
+ * handing them to `fallbackModels[0]` let that model take over the session.
26
+ * A worker's turn may still fall back to the fallback chain, since `oneShot`
27
+ * would leave it without tools.
28
+ */
22
29
  private sideProvider;
23
30
  complete(req: Request, opts: {
24
31
  signal: AbortSignal;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/cli",
3
- "version": "1.1.5",
3
+ "version": "1.1.6",
4
4
  "license": "MIT",
5
5
  "description": "WrongStack CLI — terminal AI coding agent with provider catalog from models.dev. Provides `wrongstack` and `wstack` binaries.",
6
6
  "keywords": [