@wrongstack/cli 0.305.1 → 0.306.2

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.
@@ -25,8 +25,9 @@ import {
25
25
  persistConfigSetting,
26
26
  persistTelegramConfig,
27
27
  removeSuggestions,
28
+ runGit,
28
29
  setSuggestions
29
- } from "./chunk-V3XH6XBJ.js";
30
+ } from "./chunk-T6YAVFXA.js";
30
31
  import {
31
32
  startCliHqConnection
32
33
  } from "./chunk-FKWHSFX4.js";
@@ -44,6 +45,27 @@ import {
44
45
  PLUGIN_AUDIT_ENTRIES,
45
46
  runPluginManagementCommand
46
47
  } from "./chunk-RK7E3IXT.js";
48
+ import {
49
+ configureSimpleUiRuntimeContext,
50
+ detectProjectFacts,
51
+ makeConfirmAwaiter,
52
+ renderAgentsTemplate
53
+ } from "./chunk-YKBRFSGL.js";
54
+ import "./chunk-QD544J2B.js";
55
+ import {
56
+ fmtTaskResultLine,
57
+ fmtTok,
58
+ patchConfig
59
+ } from "./chunk-TYO2OVAD.js";
60
+ import {
61
+ CLI_VERSION
62
+ } from "./chunk-XJXDOF63.js";
63
+ import {
64
+ buildWin32CmdShimInvocation
65
+ } from "./chunk-U3SS4NRH.js";
66
+ import {
67
+ checkForUpdate
68
+ } from "./chunk-NUIHRGPY.js";
47
69
  import {
48
70
  createGracefulShutdown,
49
71
  loadCachedAcpRegistry,
@@ -59,30 +81,18 @@ import {
59
81
  runClaudeOAuthLogin,
60
82
  runCopilotOAuthLogin,
61
83
  validateFamily
62
- } from "./chunk-5KFLLTSQ.js";
63
- import {
64
- runCodexOAuthLogin
65
- } from "./chunk-SSSJQVUY.js";
66
- import {
67
- configureSimpleUiRuntimeContext,
68
- detectProjectFacts,
69
- makeConfirmAwaiter,
70
- renderAgentsTemplate
71
- } from "./chunk-YKBRFSGL.js";
72
- import "./chunk-QD544J2B.js";
73
- import {
74
- fmtTaskResultLine,
75
- fmtTok,
76
- patchConfig
77
- } from "./chunk-TYO2OVAD.js";
84
+ } from "./chunk-HITHEXE3.js";
78
85
  import {
79
86
  LOCAL_LLM_PRESETS,
80
87
  parseSpawnFlags
81
- } from "./chunk-2H47YMCV.js";
88
+ } from "./chunk-KXN5HZDL.js";
82
89
  import {
83
90
  buildPickableProviders,
84
91
  visibleModelIds
85
- } from "./chunk-3IC4IEZC.js";
92
+ } from "./chunk-VUVOMXWP.js";
93
+ import {
94
+ runCodexOAuthLogin
95
+ } from "./chunk-SSSJQVUY.js";
86
96
  import {
87
97
  activeLabel,
88
98
  loadConfigProviders,
@@ -97,15 +107,6 @@ import {
97
107
  import {
98
108
  activeProfileConfigPath
99
109
  } from "./chunk-YMXXOOFN.js";
100
- import {
101
- buildWin32CmdShimInvocation
102
- } from "./chunk-U3SS4NRH.js";
103
- import {
104
- checkForUpdate
105
- } from "./chunk-NUIHRGPY.js";
106
- import {
107
- CLI_VERSION
108
- } from "./chunk-XJXDOF63.js";
109
110
  import {
110
111
  __require
111
112
  } from "./chunk-7OCVIDC7.js";
@@ -8033,6 +8034,12 @@ function registerProviderUtilityTools(input) {
8033
8034
  fallbackProfileManager: input.fallbackProfileManager,
8034
8035
  defaultProvider: config.provider,
8035
8036
  defaultModel: config.model,
8037
+ // Same live router the council gets below. Without it the `role` input
8038
+ // was inert (the orchestrator's pickForTask path no-ops), and without the
8039
+ // tracker no llm-tool call ever recorded provider health, so blocked
8040
+ // entries were neither skipped nor reported for this tool's traffic.
8041
+ modelRouter: createLiveModelRouter(input.getConfig),
8042
+ statusTracker: input.statusTracker,
8036
8043
  wrapProviderCall: input.wrapProviderCall
8037
8044
  });
8038
8045
  registerOrOverride(input.toolRegistry, "llm", llmTool);
@@ -8362,27 +8369,40 @@ async function setupLifecycleAndPlugins(deps) {
8362
8369
  }
8363
8370
 
8364
8371
  // src/wiring/management-tools.ts
8365
- import * as fs5 from "node:fs/promises";
8366
8372
  import {
8367
8373
  createFallbackManageTools,
8368
8374
  createPluginManagerTool
8369
8375
  } from "@wrongstack/core/tools";
8376
+ import { updateJsonObjectFile } from "@wrongstack/core/utils";
8370
8377
  function registerCliManagementTools({
8371
8378
  toolRegistry,
8372
8379
  configStore,
8373
8380
  profileConfigPath,
8374
8381
  stdinInteractive,
8375
- getHookRunner
8382
+ getHookRunner,
8383
+ getSwitchProviderAndModel
8376
8384
  }) {
8377
8385
  const fallbackManageTools = createFallbackManageTools({
8378
8386
  getConfig: () => configStore.get(),
8387
+ // updateJsonObjectFile is the same atomic read-mutate-write helper
8388
+ // mcp_control uses on this very file — the previous bare
8389
+ // readFile→JSON.parse→writeFile raced it and could drop concurrent
8390
+ // updates (and tore the file on a crash mid-write).
8379
8391
  updateConfig: async (mutate) => {
8380
- const raw = await fs5.readFile(profileConfigPath, "utf8").catch(() => "{}");
8381
- const parsed = JSON.parse(raw);
8382
- mutate(parsed);
8383
- await fs5.writeFile(profileConfigPath, JSON.stringify(parsed, null, 2), { mode: 384 });
8384
- configStore.update(parsed);
8392
+ const next = await updateJsonObjectFile(profileConfigPath, (cfg) => {
8393
+ mutate(cfg);
8394
+ });
8395
+ configStore.update(next);
8385
8396
  },
8397
+ ...getSwitchProviderAndModel ? {
8398
+ switchProviderAndModel: async (providerId, modelId) => {
8399
+ const switchFn = getSwitchProviderAndModel();
8400
+ if (!switchFn) {
8401
+ return "the live model switch is not ready yet (still booting) \u2014 try again shortly";
8402
+ }
8403
+ return switchFn(providerId, modelId);
8404
+ }
8405
+ } : {},
8386
8406
  // Interactive key entry for REPL mode reads a line from stdin without echo.
8387
8407
  ...stdinInteractive ? {
8388
8408
  requestInput: async (prompt) => {
@@ -8739,14 +8759,14 @@ function setupProviderRuntime(deps) {
8739
8759
  }
8740
8760
 
8741
8761
  // src/wiring/provider-status.ts
8742
- import * as fs6 from "node:fs/promises";
8762
+ import * as fs5 from "node:fs/promises";
8743
8763
  import { ProviderModelStatusTracker } from "@wrongstack/core/coordination";
8744
8764
  import { atomicWrite as atomicWrite2, withFileLock } from "@wrongstack/core/utils";
8745
8765
  async function setupProviderStatus(input) {
8746
8766
  const tracker = new ProviderModelStatusTracker({ events: input.events });
8747
8767
  const statusFile = input.paths.profileProviderStatus(input.paths.profileName);
8748
8768
  try {
8749
- const saved = JSON.parse(await fs6.readFile(statusFile, "utf8"));
8769
+ const saved = JSON.parse(await fs5.readFile(statusFile, "utf8"));
8750
8770
  const restored = tracker.restoreSnapshot(saved);
8751
8771
  if (restored > 0) input.logger.info(`Restored ${restored} provider waiting-room entries`);
8752
8772
  } catch (error) {
@@ -8758,7 +8778,7 @@ async function setupProviderStatus(input) {
8758
8778
  tracker.sweepExpired();
8759
8779
  if (syncRunning) return;
8760
8780
  syncRunning = true;
8761
- void fs6.readFile(statusFile, "utf8").then((raw) => tracker.restoreSnapshot(JSON.parse(raw))).catch((error) => warnUnlessMissing(input.logger, "sync", error)).finally(() => {
8781
+ void fs5.readFile(statusFile, "utf8").then((raw) => tracker.restoreSnapshot(JSON.parse(raw))).catch((error) => warnUnlessMissing(input.logger, "sync", error)).finally(() => {
8762
8782
  syncRunning = false;
8763
8783
  });
8764
8784
  }, 3e4);
@@ -8773,7 +8793,7 @@ async function setupProviderStatus(input) {
8773
8793
  await withFileLock(statusFile, async () => {
8774
8794
  let statuses = [];
8775
8795
  try {
8776
- const current = JSON.parse(await fs6.readFile(statusFile, "utf8"));
8796
+ const current = JSON.parse(await fs5.readFile(statusFile, "utf8"));
8777
8797
  if (Array.isArray(current.statuses)) statuses = current.statuses;
8778
8798
  } catch (error) {
8779
8799
  if (error.code !== "ENOENT") throw error;
@@ -9814,7 +9834,7 @@ import {
9814
9834
  readJsonObjectFile,
9815
9835
  removeJsonPath,
9816
9836
  setJsonPath,
9817
- updateJsonObjectFile
9837
+ updateJsonObjectFile as updateJsonObjectFile2
9818
9838
  } from "@wrongstack/core/utils";
9819
9839
  function parseMcpArgs(args) {
9820
9840
  const trimmed = args.trim();
@@ -9912,7 +9932,7 @@ async function runAdd(name, enable, configured, configPath, mcpRegistry, all) {
9912
9932
  }
9913
9933
  const existing = configured[name];
9914
9934
  const nextCfg = existing ? { ...preset, ...existing, enabled: enable } : { ...preset, enabled: enable };
9915
- await updateJsonObjectFile(configPath, (full) => {
9935
+ await updateJsonObjectFile2(configPath, (full) => {
9916
9936
  const current = isMcpServerRecord(full.mcpServers) ? full.mcpServers : {};
9917
9937
  setJsonPath(full, ["mcpServers", name], { ...current[name], ...nextCfg });
9918
9938
  });
@@ -9951,7 +9971,7 @@ async function runRemove(name, configured, configPath, mcpRegistry) {
9951
9971
  );
9952
9972
  }
9953
9973
  if (typeof mcpRegistry.forget === "function") mcpRegistry.forget(name);
9954
- await updateJsonObjectFile(configPath, (full) => {
9974
+ await updateJsonObjectFile2(configPath, (full) => {
9955
9975
  const current = isMcpServerRecord(full.mcpServers) ? full.mcpServers : configured;
9956
9976
  setJsonPath(full, ["mcpServers"], { ...current });
9957
9977
  removeJsonPath(full, ["mcpServers", name]);
@@ -9970,7 +9990,7 @@ async function runEnable(name, configured, configPath, mcpRegistry) {
9970
9990
  return `${color8.green("Enabled")} "${name}" and started.`;
9971
9991
  }
9972
9992
  }
9973
- await updateJsonObjectFile(configPath, (full) => {
9993
+ await updateJsonObjectFile2(configPath, (full) => {
9974
9994
  const current = isMcpServerRecord(full.mcpServers) ? full.mcpServers : {};
9975
9995
  setJsonPath(full, ["mcpServers", name], { ...cfg, ...current[name], enabled: true });
9976
9996
  });
@@ -9998,7 +10018,7 @@ async function runDisable(name, configured, configPath, mcpRegistry) {
9998
10018
  })
9999
10019
  );
10000
10020
  }
10001
- await updateJsonObjectFile(configPath, (full) => {
10021
+ await updateJsonObjectFile2(configPath, (full) => {
10002
10022
  const current = isMcpServerRecord(full.mcpServers) ? full.mcpServers : {};
10003
10023
  setJsonPath(full, ["mcpServers", name], { ...cfg, ...current[name], enabled: false });
10004
10024
  });
@@ -11342,7 +11362,7 @@ ${color13.dim("YOLO enabled; tool calls run without approval unless an explicit
11342
11362
 
11343
11363
  // src/slash-commands/brain.ts
11344
11364
  import { randomUUID as randomUUID5 } from "node:crypto";
11345
- import { readFile as readFile7 } from "node:fs/promises";
11365
+ import { readFile as readFile6 } from "node:fs/promises";
11346
11366
  import { parseModelRef } from "@wrongstack/core/agent";
11347
11367
  import { BUILTIN_COUNCIL_PERSONA_IDS, BUILTIN_COUNCIL_PERSONAS } from "@wrongstack/core/execution";
11348
11368
  import { color as color14 } from "@wrongstack/core/utils";
@@ -11788,7 +11808,7 @@ function buildBrainCommand(opts) {
11788
11808
  const n = Math.max(1, Math.min(100, Number.parseInt(rest[0] ?? "15", 10) || 15));
11789
11809
  let raw;
11790
11810
  try {
11791
- raw = await readFile7(ledgerPath, "utf8");
11811
+ raw = await readFile6(ledgerPath, "utf8");
11792
11812
  } catch {
11793
11813
  const msg3 = `No ledger entries yet (${ledgerPath}).`;
11794
11814
  opts.renderer.write(msg3);
@@ -12667,7 +12687,7 @@ function buildCompactCommand(opts) {
12667
12687
  }
12668
12688
 
12669
12689
  // src/slash-commands/context.ts
12670
- import * as fs7 from "node:fs/promises";
12690
+ import * as fs6 from "node:fs/promises";
12671
12691
  import {
12672
12692
  formatContextWindowModeList,
12673
12693
  getContextWindowMode,
@@ -12981,6 +13001,7 @@ var SOURCE_LABELS = {
12981
13001
  contributor: "contributor",
12982
13002
  ledger: "completed-work ledger",
12983
13003
  glossary: "project jargon dictionary",
13004
+ peers: "fleet peer awareness",
12984
13005
  nextsteps: "next-steps gate",
12985
13006
  other: "other (untagged)"
12986
13007
  };
@@ -13029,7 +13050,7 @@ async function persistContextConfig(opts, patch) {
13029
13050
  const configPath = activeProfileConfigPath(opts.paths, opts.configStore.get());
13030
13051
  let raw = "{}";
13031
13052
  try {
13032
- raw = await fs7.readFile(configPath, "utf8");
13053
+ raw = await fs6.readFile(configPath, "utf8");
13033
13054
  } catch (err) {
13034
13055
  if (err.code !== "ENOENT") {
13035
13056
  return `Could not read ${configPath}: ${err.message}`;
@@ -13434,7 +13455,7 @@ function listRoles() {
13434
13455
  }
13435
13456
 
13436
13457
  // src/slash-commands/design.ts
13437
- import * as fs8 from "node:fs/promises";
13458
+ import * as fs7 from "node:fs/promises";
13438
13459
  import * as path19 from "node:path";
13439
13460
  import {
13440
13461
  applyTokenOverrides,
@@ -13594,8 +13615,8 @@ ${menu}` };
13594
13615
  return { message: e.message };
13595
13616
  }
13596
13617
  try {
13597
- await fs8.mkdir(path19.dirname(abs), { recursive: true });
13598
- await fs8.writeFile(abs, result.content);
13618
+ await fs7.mkdir(path19.dirname(abs), { recursive: true });
13619
+ await fs7.writeFile(abs, result.content);
13599
13620
  } catch (e) {
13600
13621
  return { message: `Failed to write ${result.path}: ${e.message}` };
13601
13622
  }
@@ -13762,7 +13783,7 @@ function buildStatsCommand(opts) {
13762
13783
  }
13763
13784
 
13764
13785
  // src/slash-commands/doctor.ts
13765
- import * as fs9 from "node:fs/promises";
13786
+ import * as fs8 from "node:fs/promises";
13766
13787
  import * as path20 from "node:path";
13767
13788
  import { atomicWrite as atomicWrite4, color as color22, toErrorMessage as toErrorMessage10 } from "@wrongstack/core/utils";
13768
13789
 
@@ -14327,7 +14348,7 @@ function buildDoctorCommand(opts) {
14327
14348
  const base = path20.basename(file);
14328
14349
  const candidates = [`${base}.last`];
14329
14350
  try {
14330
- const siblings = await fs9.readdir(dir);
14351
+ const siblings = await fs8.readdir(dir);
14331
14352
  candidates.push(
14332
14353
  ...siblings.filter((f) => f.startsWith(`${base}.`) && f.endsWith(".bak")).sort().reverse()
14333
14354
  );
@@ -14335,7 +14356,7 @@ function buildDoctorCommand(opts) {
14335
14356
  }
14336
14357
  for (const name of candidates) {
14337
14358
  try {
14338
- const raw = await fs9.readFile(path20.join(dir, name), "utf8");
14359
+ const raw = await fs8.readFile(path20.join(dir, name), "utf8");
14339
14360
  JSON.parse(raw);
14340
14361
  return { name, raw };
14341
14362
  } catch {
@@ -14388,7 +14409,7 @@ function buildDoctorCommand(opts) {
14388
14409
  for (const target of targets) {
14389
14410
  let raw;
14390
14411
  try {
14391
- raw = await fs9.readFile(target.file, "utf8");
14412
+ raw = await fs8.readFile(target.file, "utf8");
14392
14413
  } catch {
14393
14414
  if (!target.isProject) {
14394
14415
  lines.push(
@@ -14703,7 +14724,7 @@ function buildFKeyAliasCommands(opts) {
14703
14724
  }
14704
14725
 
14705
14726
  // src/slash-commands/fallback.ts
14706
- import * as fs10 from "node:fs/promises";
14727
+ import * as fs9 from "node:fs/promises";
14707
14728
  import {
14708
14729
  normalizeModelRef,
14709
14730
  parseModelRef as parseModelRef2,
@@ -14747,7 +14768,7 @@ async function patchGlobalConfig(globalConfigPath, mutate) {
14747
14768
  let raw = "{}";
14748
14769
  let fileExists2 = true;
14749
14770
  try {
14750
- raw = await fs10.readFile(globalConfigPath, "utf8");
14771
+ raw = await fs9.readFile(globalConfigPath, "utf8");
14751
14772
  } catch (err) {
14752
14773
  if (err.code !== "ENOENT") throw err;
14753
14774
  fileExists2 = false;
@@ -16483,35 +16504,8 @@ function handleFleetHelp(opts) {
16483
16504
  }
16484
16505
 
16485
16506
  // src/slash-commands/git.ts
16486
- import { spawn as spawn5 } from "node:child_process";
16487
16507
  import { assessCommitSafety } from "@wrongstack/core/coordination";
16488
- import { color as color27, toErrorMessage as toErrorMessage14 } from "@wrongstack/core/utils";
16489
- async function runGit(args, cwd) {
16490
- try {
16491
- return await new Promise((resolve8, reject) => {
16492
- const child = spawn5("git", args, {
16493
- cwd,
16494
- stdio: ["ignore", "pipe", "pipe"],
16495
- signal: AbortSignal.timeout(3e4),
16496
- windowsHide: true
16497
- });
16498
- let stdout = "";
16499
- let stderr = "";
16500
- child.stdout?.on("data", (d) => {
16501
- stdout += d;
16502
- });
16503
- child.stderr?.on("data", (d) => {
16504
- stderr += d;
16505
- });
16506
- child.on("error", (err) => {
16507
- reject(new Error(`Failed to run git: ${err.message}`));
16508
- });
16509
- child.on("close", (code) => resolve8({ stdout, stderr, code: code ?? 0 }));
16510
- });
16511
- } catch (err) {
16512
- throw new Error(toErrorMessage14(err));
16513
- }
16514
- }
16508
+ import { color as color27 } from "@wrongstack/core/utils";
16515
16509
  async function isGitRepo2(cwd) {
16516
16510
  const result = await runGit(["rev-parse", "--git-dir"], cwd);
16517
16511
  return result.code === 0;
@@ -16808,7 +16802,7 @@ ${color27.dim("(dry-run)")}`
16808
16802
  }
16809
16803
 
16810
16804
  // src/slash-commands/gitid.ts
16811
- import * as fs11 from "node:fs/promises";
16805
+ import * as fs10 from "node:fs/promises";
16812
16806
  import { decryptConfigSecrets as decryptConfigSecrets2, encryptConfigSecrets as encryptConfigSecrets2, noOpVault as noOpVault3 } from "@wrongstack/core/security";
16813
16807
  import { ConfigError as ConfigError2 } from "@wrongstack/core/types";
16814
16808
  import {
@@ -16816,7 +16810,7 @@ import {
16816
16810
  color as color28,
16817
16811
  configureChildEnvGitIdentity as configureChildEnvGitIdentity2,
16818
16812
  getChildEnvGitIdentity,
16819
- toErrorMessage as toErrorMessage15
16813
+ toErrorMessage as toErrorMessage14
16820
16814
  } from "@wrongstack/core/utils";
16821
16815
  function looksLikeEmail(s) {
16822
16816
  return /^[^\s@]+@[^\s@]+$/.test(s);
@@ -16825,7 +16819,7 @@ async function patchGlobalConfig2(globalConfigPath, mutate) {
16825
16819
  let raw = "{}";
16826
16820
  let fileExists2 = true;
16827
16821
  try {
16828
- raw = await fs11.readFile(globalConfigPath, "utf8");
16822
+ raw = await fs10.readFile(globalConfigPath, "utf8");
16829
16823
  } catch (err) {
16830
16824
  if (err.code !== "ENOENT") throw err;
16831
16825
  fileExists2 = false;
@@ -16951,7 +16945,7 @@ function buildGitIdCommand(opts) {
16951
16945
  message: `${color28.red("Unknown subcommand")} "${sub}". Try ${color28.dim("/gitid")}, ${color28.dim("/gitid set <name...> <email>")}, or ${color28.dim("/gitid help")}.`
16952
16946
  };
16953
16947
  } catch (err) {
16954
- return { message: `${color28.red("gitid error")}: ${toErrorMessage15(err)}` };
16948
+ return { message: `${color28.red("gitid error")}: ${toErrorMessage14(err)}` };
16955
16949
  }
16956
16950
  }
16957
16951
  };
@@ -17282,7 +17276,7 @@ function buildHelpCommand(opts) {
17282
17276
  }
17283
17277
 
17284
17278
  // src/slash-commands/init.ts
17285
- import * as fs12 from "node:fs/promises";
17279
+ import * as fs11 from "node:fs/promises";
17286
17280
  import * as path22 from "node:path";
17287
17281
  import { color as color30 } from "@wrongstack/core/utils";
17288
17282
  function buildInitCommand(opts) {
@@ -17297,19 +17291,19 @@ function buildInitCommand(opts) {
17297
17291
  const isFirstInit = !await fileExists(file);
17298
17292
  const detected = await detectProjectFacts(root);
17299
17293
  const body = renderAgentsTemplate(detected);
17300
- await fs12.mkdir(dir, { recursive: true });
17294
+ await fs11.mkdir(dir, { recursive: true });
17301
17295
  let backedUp = false;
17302
17296
  if (!isFirstInit) {
17303
17297
  try {
17304
- await fs12.copyFile(file, `${file}.bak`);
17298
+ await fs11.copyFile(file, `${file}.bak`);
17305
17299
  backedUp = true;
17306
17300
  } catch {
17307
17301
  }
17308
17302
  }
17309
- await fs12.writeFile(file, body, "utf8");
17303
+ await fs11.writeFile(file, body, "utf8");
17310
17304
  let nodePkg = false;
17311
17305
  try {
17312
- await fs12.access(path22.join(root, "package.json"));
17306
+ await fs11.access(path22.join(root, "package.json"));
17313
17307
  nodePkg = true;
17314
17308
  } catch {
17315
17309
  }
@@ -17347,7 +17341,7 @@ function buildInitCommand(opts) {
17347
17341
  }
17348
17342
  async function fileExists(filePath) {
17349
17343
  try {
17350
- await fs12.access(filePath);
17344
+ await fs11.access(filePath);
17351
17345
  return true;
17352
17346
  } catch {
17353
17347
  return false;
@@ -17466,6 +17460,7 @@ import {
17466
17460
  updateTask,
17467
17461
  updateTaskAssignment
17468
17462
  } from "@wrongstack/kanban";
17463
+ import { preflightManagedTransition } from "@wrongstack/kanban/manager/lifecycle";
17469
17464
  import { TaskGraphStore } from "@wrongstack/sdd";
17470
17465
 
17471
17466
  // src/slash-commands/kanban-agent-helpers.ts
@@ -18237,9 +18232,9 @@ async function handleTaskSubcommand(opts, projectRoot, args, showHelp) {
18237
18232
  try {
18238
18233
  const result = await transitionTask(projectRoot, boardId, taskId, {
18239
18234
  to,
18240
- actor: "kanban-slash",
18241
- action: `Moved to ${resolvedColumnId} via /kanban task move`,
18242
- comment: moveNote ? `${moveNote} (move \u2192 ${resolvedColumnId})` : `/kanban task move ${resolvedColumnId} (was ${taskId} on board ${boardId})`,
18235
+ actor: "kanban-slash:move",
18236
+ action: moveNote ? `${moveNote} (move \u2192 ${resolvedColumnId})` : `Moved to ${resolvedColumnId} via /kanban task move`,
18237
+ comment: moveNote ? `${moveNote} (move \u2192 ${resolvedColumnId})` : `Moved to ${resolvedColumnId} via /kanban task move (board=${boardId}, task=${taskId})`,
18243
18238
  // Reviewers require a non-empty attachment URL to advance into review.
18244
18239
  // Forward the caller's `--attachment`; if missing, the move must fail at
18245
18240
  // `validateReviewEvidence` so the audit ledger never records a fabricated
@@ -18273,7 +18268,7 @@ async function handleTaskSubcommand(opts, projectRoot, args, showHelp) {
18273
18268
  )
18274
18269
  };
18275
18270
  }
18276
- const { attachment, note, positional, warnings } = parseTaskEvidenceFlags(rest.slice(1));
18271
+ const { attachment, note, tickChecks, positional, warnings } = parseTaskEvidenceFlags(rest.slice(1));
18277
18272
  if (positional.length > 0) {
18278
18273
  return {
18279
18274
  message: color32.red(
@@ -18302,73 +18297,36 @@ async function handleTaskSubcommand(opts, projectRoot, args, showHelp) {
18302
18297
  )
18303
18298
  };
18304
18299
  }
18305
- const preflightIssues = [];
18306
- const needsRunningEvidence = path32.includes("running");
18307
- const needsReviewEvidence = path32.includes("review");
18308
- const needsDoneEvidence = path32.includes("done");
18309
18300
  const currentTask = board.tasks.find((t) => t.id === taskId);
18310
18301
  if (!currentTask) {
18311
18302
  return { message: color32.red("Task not found") };
18312
18303
  }
18313
- if (needsRunningEvidence) {
18314
- const assignment = currentTask.assignment;
18315
- const hasLease = assignment?.status === "running" && [
18316
- assignment.leaseId,
18317
- assignment.claimedAt,
18318
- assignment.heartbeatAt,
18319
- assignment.leaseExpiresAt
18320
- ].every((value) => typeof value === "string" && value.trim().length > 0);
18321
- if (!hasLease) {
18322
- preflightIssues.push(
18323
- "The /kanban task done path needs the card to already be Running with lease metadata; move it into Running first via /kanban task assign or /kanban task dispatch."
18324
- );
18325
- }
18326
- }
18327
- if (needsReviewEvidence && !attachment) {
18328
- preflightIssues.push(
18329
- 'Review evidence requires --attachment <url>; re-run `/kanban task done <boardId> <taskId> --attachment https://example.test/review --note "..."`.'
18330
- );
18331
- } else if (needsReviewEvidence && !currentTask.assignment?.lastResult) {
18332
- preflightIssues.push(
18333
- "Review evidence requires the card to carry an assignment.lastResult; dispatch the worker through the agentic supervisor so it records implementation output."
18334
- );
18304
+ const preflightIssues = [];
18305
+ if (!note || !note.trim()) {
18306
+ return {
18307
+ message: color32.red(
18308
+ `Refusing /kanban task ${currentStage ?? "unknown"} \u2192 done without a reviewer note. Re-run with --note "<what proves the work is ready>".`
18309
+ )
18310
+ };
18335
18311
  }
18336
- if (needsDoneEvidence) {
18337
- if (!attachment) {
18338
- preflightIssues.push(
18339
- 'Done requires --attachment <url>; re-run with --attachment https://example.test/review --note "verified".'
18340
- );
18341
- }
18342
- const criteria = currentTask.successCriteria ?? [];
18343
- if (criteria.length === 0 || criteria.some((check) => check.status !== "passed")) {
18344
- preflightIssues.push(
18345
- "Done requires every acceptance criterion to be explicitly passed; update them on the card before re-running."
18346
- );
18347
- }
18348
- if (currentTask.atomic && currentTask.verificationReport?.verdict !== "passed") {
18349
- preflightIssues.push(
18350
- "Atomic tasks require a passed verification report; run `kanban.verify_completion` on the task before `/kanban task done`."
18351
- );
18352
- }
18353
- if (currentTask.atomic && currentTask.childTaskIds && currentTask.childTaskIds.length > 0) {
18354
- const childTasks = board.tasks.filter(
18355
- (entry) => currentTask.childTaskIds.includes(entry.id)
18356
- );
18357
- const missingChildren = currentTask.childTaskIds.filter(
18358
- (childId) => !childTasks.some((entry) => entry.id === childId)
18359
- );
18360
- if (missingChildren.length > 0) {
18361
- preflightIssues.push(
18362
- `Atomic parent references unresolved children (${missingChildren.join(", ")}); resolve them via the kanban tool before retrying.`
18363
- );
18364
- }
18365
- const incompleteChildren = childTasks.filter((child) => child.status !== "completed");
18366
- if (incompleteChildren.length > 0) {
18367
- const ids = incompleteChildren.map((child) => child.id).join(", ");
18368
- preflightIssues.push(
18369
- `Atomic parent's children must be completed before the parent can advance to Done (pending: ${ids}).`
18370
- );
18371
- }
18312
+ const noteText = note.trim();
18313
+ const sharedAttachment = attachment ? {
18314
+ url: attachment,
18315
+ type: "url",
18316
+ title: "Reviewer evidence (kanban-slash:done)"
18317
+ } : void 0;
18318
+ for (const to of path32) {
18319
+ const transitionInput = {
18320
+ to,
18321
+ actor: "kanban-slash:done",
18322
+ action: `${noteText} (${to})`,
18323
+ comment: `${noteText} (${to})`,
18324
+ ...sharedAttachment ? { attachment: sharedAttachment } : {},
18325
+ ...tickChecks ? { tickChecks } : {}
18326
+ };
18327
+ const issues = preflightManagedTransition(board, currentTask, transitionInput);
18328
+ for (const issue of issues) {
18329
+ preflightIssues.push(issue.message);
18372
18330
  }
18373
18331
  }
18374
18332
  if (preflightIssues.length > 0) {
@@ -18383,16 +18341,17 @@ async function handleTaskSubcommand(opts, projectRoot, args, showHelp) {
18383
18341
  for (const to of path32) {
18384
18342
  await transitionTask(projectRoot, boardId, taskId, {
18385
18343
  to,
18386
- actor: "kanban-slash",
18387
- action: note ?? `Marked done via /kanban task done (${to})`,
18388
- comment: note ?? `Marked done via /kanban task done (${to})`,
18344
+ actor: "kanban-slash:done",
18345
+ action: noteText ? `${noteText} (${to})` : "",
18346
+ comment: noteText ? `${noteText} (${to})` : "",
18389
18347
  ...attachment ? {
18390
18348
  attachment: {
18391
18349
  url: attachment,
18392
18350
  type: "url",
18393
- title: "Reviewer evidence (kanban-slash)"
18351
+ title: "Reviewer evidence (kanban-slash:done)"
18394
18352
  }
18395
- } : {}
18353
+ } : {},
18354
+ ...tickChecks.length > 0 ? { tickChecks } : {}
18396
18355
  });
18397
18356
  }
18398
18357
  return { message: color32.green("\u2705 Task marked completed.") };
@@ -18815,14 +18774,17 @@ function resolveColumnReference(board, requested) {
18815
18774
  function parseTaskEvidenceFlags(tokens) {
18816
18775
  let attachment;
18817
18776
  let note;
18777
+ const tickChecks = [];
18818
18778
  const positional = [];
18819
18779
  const warnings = [];
18820
18780
  const ATTACHMENT_KEYS = /* @__PURE__ */ new Set(["--attachment", "--evidence", "--link"]);
18821
18781
  const NOTE_KEYS = /* @__PURE__ */ new Set(["--note", "--comment", "--action"]);
18782
+ const TICK_CHECK_KEYS = /* @__PURE__ */ new Set(["--tick-check", "--tick-checks"]);
18783
+ const VALID_TICK_STATUSES = /* @__PURE__ */ new Set(["passed", "failed", "skipped"]);
18822
18784
  for (let i = 0; i < tokens.length; i++) {
18823
18785
  const token = tokens[i];
18824
18786
  const eq = token.indexOf("=");
18825
- const inline = eq > 0 && (ATTACHMENT_KEYS.has(token.slice(0, eq)) || NOTE_KEYS.has(token.slice(0, eq)));
18787
+ const inline = eq > 0 && (ATTACHMENT_KEYS.has(token.slice(0, eq)) || NOTE_KEYS.has(token.slice(0, eq)) || TICK_CHECK_KEYS.has(token.slice(0, eq)));
18826
18788
  const key = inline ? token.slice(0, eq) : token;
18827
18789
  if (ATTACHMENT_KEYS.has(key)) {
18828
18790
  const value = inline ? token.slice(eq + 1) : tokens[i + 1];
@@ -18840,6 +18802,32 @@ function parseTaskEvidenceFlags(tokens) {
18840
18802
  attachment = value;
18841
18803
  continue;
18842
18804
  }
18805
+ if (TICK_CHECK_KEYS.has(key)) {
18806
+ const raw = inline ? token.slice(eq + 1) : tokens[i + 1];
18807
+ if (!raw?.trim()) {
18808
+ warnings.push(`${key} expects <checkId>=<status> but none was provided`);
18809
+ i = inline ? i : i + 1;
18810
+ continue;
18811
+ }
18812
+ if (!inline && raw.startsWith("-")) {
18813
+ warnings.push(`${key} expects <checkId>=<status> but none was provided`);
18814
+ i++;
18815
+ continue;
18816
+ }
18817
+ const sep2 = raw.lastIndexOf("=");
18818
+ const checkId = sep2 >= 0 ? raw.slice(0, sep2).trim() : "";
18819
+ const status = sep2 >= 0 ? raw.slice(sep2 + 1).trim() : "";
18820
+ if (!checkId || !status || !VALID_TICK_STATUSES.has(status)) {
18821
+ warnings.push(
18822
+ `${key} expects <checkId>=<status> where status is passed|failed|skipped (got "${raw}")`
18823
+ );
18824
+ i = inline ? i : i + 1;
18825
+ continue;
18826
+ }
18827
+ tickChecks.push({ checkId, checkStatus: status });
18828
+ i = inline ? i : i + 1;
18829
+ continue;
18830
+ }
18843
18831
  if (NOTE_KEYS.has(key)) {
18844
18832
  const inlineValue = inline ? token.slice(eq + 1) : void 0;
18845
18833
  if (inlineValue !== void 0) {
@@ -18867,7 +18855,7 @@ function parseTaskEvidenceFlags(tokens) {
18867
18855
  }
18868
18856
  positional.push(token);
18869
18857
  }
18870
- return { attachment, note, positional, warnings };
18858
+ return { attachment, note, tickChecks, positional, warnings };
18871
18859
  }
18872
18860
 
18873
18861
  // src/slash-commands/mailbox.ts
@@ -19394,8 +19382,8 @@ function buildMailboxDemoCommand(opts) {
19394
19382
  }
19395
19383
 
19396
19384
  // src/slash-commands/mailbox-serve.ts
19397
- import { spawn as spawn6 } from "node:child_process";
19398
- import * as fs13 from "node:fs/promises";
19385
+ import { spawn as spawn5 } from "node:child_process";
19386
+ import * as fs12 from "node:fs/promises";
19399
19387
  import * as os2 from "node:os";
19400
19388
  import * as path23 from "node:path";
19401
19389
  import { resolveProjectDir as resolveProjectDir5 } from "@wrongstack/core/coordination";
@@ -19457,7 +19445,7 @@ function buildMailboxServeCommand(opts) {
19457
19445
  spawnArgs = ["mailbox", "serve", ...flags];
19458
19446
  if (isWin) shim = buildWin32CmdShimInvocation(wstackCmd, spawnArgs);
19459
19447
  }
19460
- const child = spawn6(shim?.command ?? wstackCmd, shim?.args ?? spawnArgs, {
19448
+ const child = spawn5(shim?.command ?? wstackCmd, shim?.args ?? spawnArgs, {
19461
19449
  cwd,
19462
19450
  // POSIX-only: own process group so the bridge outlives the REPL.
19463
19451
  // On win32 `detached` opens a visible console window (project
@@ -19470,7 +19458,7 @@ function buildMailboxServeCommand(opts) {
19470
19458
  });
19471
19459
  child.unref();
19472
19460
  try {
19473
- await fs13.writeFile(pidFile, String(child.pid ?? ""), { mode: 384 });
19461
+ await fs12.writeFile(pidFile, String(child.pid ?? ""), { mode: 384 });
19474
19462
  } catch {
19475
19463
  }
19476
19464
  const head = [];
@@ -19737,11 +19725,11 @@ function errorMessage(err) {
19737
19725
  }
19738
19726
 
19739
19727
  // src/slash-commands/memory.ts
19740
- import { toErrorMessage as toErrorMessage18 } from "@wrongstack/core/utils";
19728
+ import { toErrorMessage as toErrorMessage17 } from "@wrongstack/core/utils";
19741
19729
  import { getSageSurface as getSageSurface2 } from "@wrongstack/sage";
19742
19730
 
19743
19731
  // src/slash-commands/memory-compact.ts
19744
- import { toErrorMessage as toErrorMessage16 } from "@wrongstack/core/utils";
19732
+ import { toErrorMessage as toErrorMessage15 } from "@wrongstack/core/utils";
19745
19733
  import { getSageSurface } from "@wrongstack/sage";
19746
19734
  var COMPACT_SYSTEM_PROMPT = `You are a memory curator. Your task is to review, deduplicate, and improve a set of long-term memory entries.
19747
19735
 
@@ -19854,7 +19842,7 @@ async function runCompact(opts) {
19854
19842
  responseText = response.content.filter((b) => b.type === "text").map((b) => b.text).join("").trim();
19855
19843
  } catch (err) {
19856
19844
  return {
19857
- message: `LLM call failed: ${toErrorMessage16(err)}`
19845
+ message: `LLM call failed: ${toErrorMessage15(err)}`
19858
19846
  };
19859
19847
  }
19860
19848
  if (!responseText) {
@@ -19870,7 +19858,7 @@ ${responseText.slice(0, 500)}` };
19870
19858
  parsed = JSON.parse(jsonMatch[0]);
19871
19859
  } catch (err) {
19872
19860
  return {
19873
- message: `Failed to parse LLM response: ${toErrorMessage16(err)}
19861
+ message: `Failed to parse LLM response: ${toErrorMessage15(err)}
19874
19862
 
19875
19863
  Raw response:
19876
19864
  ${responseText.slice(0, 500)}`
@@ -19943,7 +19931,7 @@ ${responseText.slice(0, 500)}`
19943
19931
  }
19944
19932
  }
19945
19933
  } catch (err) {
19946
- errors.push(`${op.action} failed for ${op.targets.join(", ")}: ${toErrorMessage16(err)}`);
19934
+ errors.push(`${op.action} failed for ${op.targets.join(", ")}: ${toErrorMessage15(err)}`);
19947
19935
  }
19948
19936
  }
19949
19937
  const lines = ["## Memory Compact \u2014 Complete"];
@@ -20349,7 +20337,7 @@ function formatSageShow(stats, memories) {
20349
20337
  }
20350
20338
 
20351
20339
  // src/slash-commands/memory-triage.ts
20352
- import { toErrorMessage as toErrorMessage17 } from "@wrongstack/core/utils";
20340
+ import { toErrorMessage as toErrorMessage16 } from "@wrongstack/core/utils";
20353
20341
  import {
20354
20342
  fileTriageProposals,
20355
20343
  formatTriageReport,
@@ -20461,7 +20449,7 @@ Usage: /memory triage [--dry-run|--apply] [--limit N] [--max-phase3 N] [--max-ph
20461
20449
  verbose: false
20462
20450
  });
20463
20451
  } catch (err) {
20464
- return { message: `Triage failed: ${toErrorMessage17(err)}` };
20452
+ return { message: `Triage failed: ${toErrorMessage16(err)}` };
20465
20453
  }
20466
20454
  if (!dryRun) {
20467
20455
  const applyReport = await applyDispatch(Sage, report);
@@ -20489,7 +20477,11 @@ async function loadActiveMemories(Sage, limit) {
20489
20477
  const page = await Sage.listSagePage({
20490
20478
  statuses: ["active", "stale"],
20491
20479
  limit: pageSize,
20492
- cursor
20480
+ cursor,
20481
+ // Admin surface: the user running this command owns every session in the
20482
+ // project, so it opts out of the session filter the agent-facing tools
20483
+ // rely on. Without this, session-scoped memories vanish from the listing.
20484
+ includeAllSessions: true
20493
20485
  });
20494
20486
  all.push(...page.memories);
20495
20487
  if (limit && all.length >= limit) break;
@@ -20518,7 +20510,7 @@ async function applyDispatch(Sage, report) {
20518
20510
  autoOk++;
20519
20511
  } catch (err) {
20520
20512
  autoFail++;
20521
- lines.push(` \u2717 Failed to update ${action.memoryId}: ${toErrorMessage17(err)}`);
20513
+ lines.push(` \u2717 Failed to update ${action.memoryId}: ${toErrorMessage16(err)}`);
20522
20514
  }
20523
20515
  }
20524
20516
  lines.push(`**Auto-apply:** ${autoOk} succeeded, ${autoFail} failed`);
@@ -20533,7 +20525,7 @@ async function applyDispatch(Sage, report) {
20533
20525
  } catch (err) {
20534
20526
  mergeFail++;
20535
20527
  lines.push(
20536
- ` \u2717 Failed to merge ${merge.supersededId} \u2192 ${merge.keeperId}: ${toErrorMessage17(err)}`
20528
+ ` \u2717 Failed to merge ${merge.supersededId} \u2192 ${merge.keeperId}: ${toErrorMessage16(err)}`
20537
20529
  );
20538
20530
  }
20539
20531
  }
@@ -20619,7 +20611,7 @@ function buildMemoryCommand(opts) {
20619
20611
  message: `Remembered \`${memory.id}\` [${memory.kind}] ${memory.text}${tags}`
20620
20612
  };
20621
20613
  } catch (err) {
20622
- return { message: `Could not remember: ${toErrorMessage18(err)}` };
20614
+ return { message: `Could not remember: ${toErrorMessage17(err)}` };
20623
20615
  }
20624
20616
  }
20625
20617
  case "update":
@@ -20657,7 +20649,7 @@ function buildMemoryCommand(opts) {
20657
20649
  message: `Updated \`${memory.id}\` [${memory.kind}|${memory.status}] ${memory.text}`
20658
20650
  };
20659
20651
  } catch (err) {
20660
- return { message: `Could not update: ${toErrorMessage18(err)}` };
20652
+ return { message: `Could not update: ${toErrorMessage17(err)}` };
20661
20653
  }
20662
20654
  }
20663
20655
  case "delete":
@@ -20672,7 +20664,7 @@ function buildMemoryCommand(opts) {
20672
20664
  await Sage.deleteSage(id, reason, { force: true });
20673
20665
  return { message: `Deleted \`${id}\`.` };
20674
20666
  } catch (err) {
20675
- return { message: `Could not delete: ${toErrorMessage18(err)}` };
20667
+ return { message: `Could not delete: ${toErrorMessage17(err)}` };
20676
20668
  }
20677
20669
  }
20678
20670
  case "forget":
@@ -20856,7 +20848,11 @@ function buildMemoryCommand(opts) {
20856
20848
  statuses: resolvedStatus ? [resolvedStatus] : ["active"],
20857
20849
  kind: kindVal,
20858
20850
  query: query || void 0,
20859
- limit
20851
+ limit,
20852
+ // Admin surface: the user running this command owns every session in the
20853
+ // project, so it opts out of the session filter the agent-facing tools
20854
+ // rely on. Without this, session-scoped memories vanish from the listing.
20855
+ includeAllSessions: true
20860
20856
  });
20861
20857
  if (page.memories.length === 0) {
20862
20858
  return { message: "No memories matched the gather criteria." };
@@ -20920,7 +20916,7 @@ function buildMemoryCommand(opts) {
20920
20916
  }
20921
20917
  return { message: lines.join("\n") };
20922
20918
  } catch (err) {
20923
- return { message: `gather failed: ${toErrorMessage18(err)}` };
20919
+ return { message: `gather failed: ${toErrorMessage17(err)}` };
20924
20920
  }
20925
20921
  }
20926
20922
  case "verify": {
@@ -21015,7 +21011,7 @@ function buildMemoryCommand(opts) {
21015
21011
  File size reduced. Audit-logged as \`memory.log_compacted\`.`
21016
21012
  };
21017
21013
  } catch (err) {
21018
- return { message: `Compaction failed: ${toErrorMessage18(err)}` };
21014
+ return { message: `Compaction failed: ${toErrorMessage17(err)}` };
21019
21015
  }
21020
21016
  }
21021
21017
  case "stats": {
@@ -21243,7 +21239,7 @@ async function runAudienceMemory(store, rest) {
21243
21239
  message: `Remembered \`${memory.id}\` for ${formatAudienceSelector(memory.audience)}: ${memory.text}`
21244
21240
  };
21245
21241
  } catch (err) {
21246
- return { message: `Could not remember: ${toErrorMessage18(err)}` };
21242
+ return { message: `Could not remember: ${toErrorMessage17(err)}` };
21247
21243
  }
21248
21244
  }
21249
21245
  if (sub === "clear") {
@@ -21255,7 +21251,7 @@ async function runAudienceMemory(store, rest) {
21255
21251
  message: `Cleared audience scope from \`${id}\` \u2014 it is now general project memory.`
21256
21252
  };
21257
21253
  } catch (err) {
21258
- return { message: `Could not clear audience: ${toErrorMessage18(err)}` };
21254
+ return { message: `Could not clear audience: ${toErrorMessage17(err)}` };
21259
21255
  }
21260
21256
  }
21261
21257
  if (sub === "search" || sub === "find") {
@@ -21723,7 +21719,7 @@ ${targetMode.description}`
21723
21719
  }
21724
21720
 
21725
21721
  // src/slash-commands/modelcaps.ts
21726
- import * as fs14 from "node:fs/promises";
21722
+ import * as fs13 from "node:fs/promises";
21727
21723
  import { hasProviderCredential } from "@wrongstack/core/models";
21728
21724
  import { color as color36 } from "@wrongstack/core/utils";
21729
21725
  function fmtTokens(n) {
@@ -21796,7 +21792,7 @@ function buildModelCapsCommand(opts) {
21796
21792
  }
21797
21793
  let providers;
21798
21794
  try {
21799
- const raw = await fs14.readFile(cachePath, "utf8");
21795
+ const raw = await fs13.readFile(cachePath, "utf8");
21800
21796
  const parsed = JSON.parse(raw);
21801
21797
  const payload = parsed.payload ?? parsed;
21802
21798
  providers = Object.entries(payload).map(([id, p]) => ({
@@ -21873,19 +21869,19 @@ function buildModelCapsCommand(opts) {
21873
21869
  }
21874
21870
 
21875
21871
  // src/slash-commands/models.ts
21876
- import * as fs15 from "node:fs/promises";
21872
+ import * as fs14 from "node:fs/promises";
21877
21873
  import { decryptConfigSecrets as decryptConfigSecrets3, encryptConfigSecrets as encryptConfigSecrets3, noOpVault as noOpVault4 } from "@wrongstack/core/security";
21878
21874
  import {
21879
21875
  ConfigError as ConfigError4,
21880
21876
  ToolValidationError as ToolValidationError4
21881
21877
  } from "@wrongstack/core/types";
21882
- import { atomicWrite as atomicWrite7, color as color37, toErrorMessage as toErrorMessage19 } from "@wrongstack/core/utils";
21878
+ import { atomicWrite as atomicWrite7, color as color37, toErrorMessage as toErrorMessage18 } from "@wrongstack/core/utils";
21883
21879
  async function patchProfileConfig(mutate, profileConfigPath) {
21884
21880
  const targetPath = profileConfigPath;
21885
21881
  let raw = "{}";
21886
21882
  let fileExists2 = true;
21887
21883
  try {
21888
- raw = await fs15.readFile(targetPath, "utf8");
21884
+ raw = await fs14.readFile(targetPath, "utf8");
21889
21885
  } catch (err) {
21890
21886
  if (err.code !== "ENOENT") throw err;
21891
21887
  fileExists2 = false;
@@ -22111,7 +22107,7 @@ function buildModelsCommand(opts) {
22111
22107
  };
22112
22108
  } catch (err) {
22113
22109
  return {
22114
- message: `${color37.red("models error")}: ${toErrorMessage19(err)}`
22110
+ message: `${color37.red("models error")}: ${toErrorMessage18(err)}`
22115
22111
  };
22116
22112
  }
22117
22113
  }
@@ -22983,7 +22979,7 @@ function buildPruneCommand(opts) {
22983
22979
 
22984
22980
  // src/slash-commands/refiner.ts
22985
22981
  import { noOpVault as noOpVault5 } from "@wrongstack/core/security";
22986
- import { color as color42, toErrorMessage as toErrorMessage20 } from "@wrongstack/core/utils";
22982
+ import { color as color42, toErrorMessage as toErrorMessage19 } from "@wrongstack/core/utils";
22987
22983
  function buildRefinerCommand(opts) {
22988
22984
  const help = [
22989
22985
  "Usage:",
@@ -23083,7 +23079,7 @@ function buildRefinerCommand(opts) {
23083
23079
  };
23084
23080
  } catch (err) {
23085
23081
  return {
23086
- message: `${color42.red("refiner error")}: ${toErrorMessage20(err)}`
23082
+ message: `${color42.red("refiner error")}: ${toErrorMessage19(err)}`
23087
23083
  };
23088
23084
  }
23089
23085
  }
@@ -23105,7 +23101,7 @@ function buildRefinerCommand(opts) {
23105
23101
  };
23106
23102
  } catch (err) {
23107
23103
  return {
23108
- message: `${color42.red("refiner error")}: ${toErrorMessage20(err)}`
23104
+ message: `${color42.red("refiner error")}: ${toErrorMessage19(err)}`
23109
23105
  };
23110
23106
  }
23111
23107
  }
@@ -24288,7 +24284,7 @@ ${sddHelp()}`
24288
24284
 
24289
24285
  // src/slash-commands/session.ts
24290
24286
  import { SessionRecovery } from "@wrongstack/core/storage";
24291
- import { color as color43, isPidAlive, toErrorMessage as toErrorMessage21 } from "@wrongstack/core/utils";
24287
+ import { color as color43, isPidAlive, toErrorMessage as toErrorMessage20 } from "@wrongstack/core/utils";
24292
24288
  function statusIcon2(status) {
24293
24289
  switch (status) {
24294
24290
  case "active":
@@ -24410,7 +24406,7 @@ function buildLoadCommand(opts) {
24410
24406
  message: name ? color43.green(`Renamed ${targetId} \u2192 "${name}"`) : color43.green(`Cleared name on ${targetId} (title: "${summary.title}")`)
24411
24407
  };
24412
24408
  } catch (err) {
24413
- return { message: color43.red(`Rename failed: ${toErrorMessage21(err)}`) };
24409
+ return { message: color43.red(`Rename failed: ${toErrorMessage20(err)}`) };
24414
24410
  }
24415
24411
  }
24416
24412
  if (first === "delete") {
@@ -24441,7 +24437,7 @@ function buildLoadCommand(opts) {
24441
24437
  await opts.sessionStore.delete(targetId);
24442
24438
  return { message: color43.green(`Deleted session ${targetId}`) };
24443
24439
  } catch (err) {
24444
- return { message: color43.red(`Delete failed: ${toErrorMessage21(err)}`) };
24440
+ return { message: color43.red(`Delete failed: ${toErrorMessage20(err)}`) };
24445
24441
  }
24446
24442
  }
24447
24443
  const showIncomplete = parts.includes("--incomplete") || parts.includes("-i");
@@ -24775,13 +24771,13 @@ async function killSession(sessionId, confirm) {
24775
24771
  };
24776
24772
  } catch (err) {
24777
24773
  return {
24778
- message: color43.red(`Failed to kill session: ${toErrorMessage21(err)}`)
24774
+ message: color43.red(`Failed to kill session: ${toErrorMessage20(err)}`)
24779
24775
  };
24780
24776
  }
24781
24777
  }
24782
24778
 
24783
24779
  // src/slash-commands/setmodel.ts
24784
- import * as fs16 from "node:fs/promises";
24780
+ import * as fs15 from "node:fs/promises";
24785
24781
  import { fallbackProfileChain, parseModelRef as parseModelRef3 } from "@wrongstack/core/agent";
24786
24782
  import { AGENT_CATALOG as AGENT_CATALOG2, AGENTS_BY_PHASE as AGENTS_BY_PHASE3 } from "@wrongstack/core/agent-catalog";
24787
24783
  import {
@@ -24795,7 +24791,7 @@ import { decryptConfigSecrets as decryptConfigSecrets4, encryptConfigSecrets as
24795
24791
  import {
24796
24792
  ConfigError as ConfigError5
24797
24793
  } from "@wrongstack/core/types";
24798
- import { atomicWrite as atomicWrite9, color as color44, expectDefined as expectDefined8, toErrorMessage as toErrorMessage22 } from "@wrongstack/core/utils";
24794
+ import { atomicWrite as atomicWrite9, color as color44, expectDefined as expectDefined8, toErrorMessage as toErrorMessage21 } from "@wrongstack/core/utils";
24799
24795
  import { catalogProviderIdFor } from "@wrongstack/providers";
24800
24796
  async function resolveCatalogModelIds(registry, config, providerIds) {
24801
24797
  const out = /* @__PURE__ */ new Map();
@@ -24893,7 +24889,7 @@ async function patchProfileConfig2(mutate, profileConfigPath) {
24893
24889
  let raw = "{}";
24894
24890
  let fileExists2 = true;
24895
24891
  try {
24896
- raw = await fs16.readFile(targetPath, "utf8");
24892
+ raw = await fs15.readFile(targetPath, "utf8");
24897
24893
  } catch (err) {
24898
24894
  if (err.code !== "ENOENT") throw err;
24899
24895
  fileExists2 = false;
@@ -25369,7 +25365,7 @@ function buildSetModelCommand(opts) {
25369
25365
  };
25370
25366
  } catch (err) {
25371
25367
  return {
25372
- message: `${color44.red("setmodel error")}: ${toErrorMessage22(err)}`
25368
+ message: `${color44.red("setmodel error")}: ${toErrorMessage21(err)}`
25373
25369
  };
25374
25370
  }
25375
25371
  }
@@ -25380,7 +25376,7 @@ function buildSetModelCommand(opts) {
25380
25376
  import { execFile as execFile3 } from "node:child_process";
25381
25377
  import { access as access4 } from "node:fs/promises";
25382
25378
  import * as path25 from "node:path";
25383
- import { color as color45, toErrorMessage as toErrorMessage23 } from "@wrongstack/core/utils";
25379
+ import { color as color45, toErrorMessage as toErrorMessage22 } from "@wrongstack/core/utils";
25384
25380
  import { parseNextSteps } from "@wrongstack/tools/next-steps";
25385
25381
  function readGitStatus(projectRoot, includeBranch) {
25386
25382
  const args = ["status", "--short"];
@@ -25505,7 +25501,7 @@ function buildSuggestCommand(opts) {
25505
25501
  suggestCache = { suggestions, at: Date.now() };
25506
25502
  return { message: formatSuggestions(suggestions) };
25507
25503
  } catch (err) {
25508
- const msg = `Suggestion generation failed: ${toErrorMessage23(err)}`;
25504
+ const msg = `Suggestion generation failed: ${toErrorMessage22(err)}`;
25509
25505
  opts.renderer.writeWarning(msg);
25510
25506
  return { message: msg };
25511
25507
  }
@@ -25517,7 +25513,7 @@ function parseSuggestions(raw) {
25517
25513
  if (/^none\b/i.test(trimmed) || /no (?:pending actions|further steps)/i.test(trimmed)) {
25518
25514
  return [];
25519
25515
  }
25520
- const { texts } = parseNextSteps(raw, false, false);
25516
+ const { texts } = parseNextSteps(raw, false);
25521
25517
  if (texts.length > 0) return texts;
25522
25518
  return raw.split("\n").map((l) => l.trim()).filter((l) => l.length > 10 && !l.startsWith("#") && !l.startsWith("```")).slice(0, 5);
25523
25519
  }
@@ -25728,22 +25724,58 @@ function presetHelpLines(perLine = 4) {
25728
25724
  }
25729
25725
  return lines;
25730
25726
  }
25727
+ function computeWindow(total, selected, rows) {
25728
+ const chromeRows = 5;
25729
+ const markerRows = 2;
25730
+ const minVisible = 3;
25731
+ if (total <= 0) return { start: 0, end: 0, hasAbove: false, hasBelow: false };
25732
+ const available = Math.max(1, rows - chromeRows - markerRows);
25733
+ const visible = Math.max(minVisible, Math.min(total, Math.floor(available)));
25734
+ const safeSelected = selected >= 0 && selected < total ? selected : 0;
25735
+ let start;
25736
+ if (safeSelected < visible) {
25737
+ start = 0;
25738
+ } else {
25739
+ const halfWindow = Math.floor(visible / 2);
25740
+ start = safeSelected - halfWindow;
25741
+ start = Math.max(0, Math.min(total - visible, start));
25742
+ }
25743
+ const end = Math.min(total, start + visible);
25744
+ return { start, end, hasAbove: start > 0, hasBelow: end < total };
25745
+ }
25746
+ function truncateDesc(desc, columns, active2) {
25747
+ const markWidth = active2 ? 9 : 0;
25748
+ const budget = Math.max(0, columns - 26 - markWidth);
25749
+ if (desc.length <= budget) return desc;
25750
+ if (budget <= 1) return "\u2026";
25751
+ return `${desc.slice(0, budget - 1)}\u2026`;
25752
+ }
25731
25753
  async function runThemePicker(reader, activeId) {
25732
25754
  let cursor = THEME_OPTIONS.findIndex((p) => p.id === activeId);
25733
25755
  if (cursor < 0) cursor = 0;
25734
25756
  const render = (currentCursor) => {
25757
+ const rows = process.stdout.rows ?? 24;
25758
+ const columns = process.stdout.columns ?? 80;
25759
+ const { start, end, hasAbove, hasBelow } = computeWindow(
25760
+ THEME_OPTIONS.length,
25761
+ currentCursor,
25762
+ rows
25763
+ );
25735
25764
  const lines = [];
25736
- lines.push(`
25737
- ${color46.bold(color46.amber("WrongStack") + color46.dim(" \u2014 TUI Theme Selection"))}
25738
- `);
25739
- lines.push(color46.dim(" \u2191\u2193 navigate Enter select q quit\n"));
25740
25765
  lines.push("");
25741
- for (const [i, p] of THEME_OPTIONS.entries()) {
25766
+ lines.push(`${color46.bold(color46.amber("WrongStack") + color46.dim(" \u2014 TUI Theme Selection"))}`);
25767
+ lines.push(color46.dim(" \u2191\u2193 navigate Enter select q quit"));
25768
+ lines.push("");
25769
+ if (hasAbove) lines.push(color46.dim(` \u2026 ${start} more above`));
25770
+ for (let i = start; i < end; i++) {
25771
+ const p = THEME_OPTIONS[i];
25742
25772
  const mark = p.id === activeId ? color46.green(" [active]") : "";
25743
25773
  const prefix = i === currentCursor ? color46.bold("\u276F ") : " ";
25744
25774
  const name = i === currentCursor ? color46.bold(p.name) : p.name;
25745
- lines.push(` ${prefix}${name.padEnd(21)} ${color46.dim(p.desc)}${mark}`);
25775
+ const desc = truncateDesc(p.desc, columns, p.id === activeId);
25776
+ lines.push(` ${prefix}${name.padEnd(21)} ${color46.dim(desc)}${mark}`);
25746
25777
  }
25778
+ if (hasBelow) lines.push(color46.dim(` \u2026 ${THEME_OPTIONS.length - end} more below`));
25747
25779
  lines.push("");
25748
25780
  return lines.join("\n");
25749
25781
  };
@@ -26280,11 +26312,18 @@ function buildMouseCommand(_opts) {
26280
26312
  " /mouse Show current mouse-mode status",
26281
26313
  " /mouse on Enable full mouse mode",
26282
26314
  " /mouse off Disable scrollbar drag and clickable UI",
26283
- " /mouse toggle Flip the current state",
26315
+ " /mouse native Hand the mouse back to the terminal (select + copy)",
26316
+ " /mouse toggle Flip between on and off",
26317
+ "",
26318
+ "In both on and off the wheel scrolls virtualized chat history in-app. Full",
26319
+ "mouse mode also makes the scrollbar drag-able and status-bar chips /",
26320
+ "confirm buttons clickable.",
26321
+ "",
26322
+ "Native mode releases mouse tracking entirely, so the terminal does its own",
26323
+ "click-drag text selection and copy again. The cost is the wheel: it scrolls",
26324
+ "the terminal, not the transcript. PgUp/PgDn and Ctrl+U/D still page through",
26325
+ "history. Use /mouse on or /mouse off to take the mouse back.",
26284
26326
  "",
26285
- "The wheel always scrolls virtualized chat history in-app. Full mouse mode",
26286
- "also makes the scrollbar drag-able and status-bar chips / confirm buttons",
26287
- "clickable. Shift+wheel, PgUp/PgDn, and Ctrl+U/D page through history.",
26288
26327
  "The setting persists."
26289
26328
  ].join("\n"),
26290
26329
  async run(args) {
@@ -26293,10 +26332,11 @@ function buildMouseCommand(_opts) {
26293
26332
  if (!arg || arg === "status") intent = "query";
26294
26333
  else if (arg === "on" || arg === "enable" || arg === "true" || arg === "1") intent = "on";
26295
26334
  else if (arg === "off" || arg === "disable" || arg === "false" || arg === "0") intent = "off";
26335
+ else if (arg === "native" || arg === "none" || arg === "terminal") intent = "native";
26296
26336
  else if (arg === "toggle") intent = "toggle";
26297
26337
  else {
26298
26338
  return {
26299
- message: `Unknown argument: ${arg}. Use /mouse on, /mouse off, or /mouse toggle.`
26339
+ message: `Unknown argument: ${arg}. Use /mouse on, /mouse off, /mouse native, or /mouse toggle.`
26300
26340
  };
26301
26341
  }
26302
26342
  return { metadata: { mouseToggle: intent } };
@@ -26305,8 +26345,8 @@ function buildMouseCommand(_opts) {
26305
26345
  }
26306
26346
 
26307
26347
  // src/slash-commands/project.ts
26308
- import { spawn as spawn7 } from "node:child_process";
26309
- import * as fs17 from "node:fs/promises";
26348
+ import { spawn as spawn6 } from "node:child_process";
26349
+ import * as fs16 from "node:fs/promises";
26310
26350
  import { createRequire } from "node:module";
26311
26351
  import * as path26 from "node:path";
26312
26352
  import {
@@ -26520,11 +26560,11 @@ async function listProjectsCommand(opts, ctx) {
26520
26560
  async function addProjectCommand(opts, ctx, targetPath, displayName) {
26521
26561
  const resolved = path26.resolve(ctx?.projectRoot ?? ctx?.cwd ?? process.cwd(), targetPath);
26522
26562
  try {
26523
- await fs17.access(resolved);
26563
+ await fs16.access(resolved);
26524
26564
  } catch {
26525
26565
  return { message: color48.red(`Directory not found: ${resolved}`) };
26526
26566
  }
26527
- const stat5 = await fs17.stat(resolved);
26567
+ const stat5 = await fs16.stat(resolved);
26528
26568
  if (!stat5.isDirectory()) {
26529
26569
  return { message: color48.red(`Not a directory: ${resolved}`) };
26530
26570
  }
@@ -26590,11 +26630,11 @@ async function removeProjectCommand(opts, _ctx, slugOrName) {
26590
26630
  async function switchProjectCommand(opts, ctx, target, displayName) {
26591
26631
  const resolved = path26.resolve(ctx?.projectRoot ?? ctx?.cwd ?? process.cwd(), target);
26592
26632
  try {
26593
- await fs17.access(resolved);
26633
+ await fs16.access(resolved);
26594
26634
  } catch {
26595
26635
  return { message: color48.red(`Directory not found: ${resolved}`) };
26596
26636
  }
26597
- const stat5 = await fs17.stat(resolved);
26637
+ const stat5 = await fs16.stat(resolved);
26598
26638
  if (!stat5.isDirectory()) {
26599
26639
  return { message: color48.red(`Not a directory: ${resolved}`) };
26600
26640
  }
@@ -26604,7 +26644,7 @@ async function switchProjectCommand(opts, ctx, target, displayName) {
26604
26644
  const pkgPath = req.resolve("@wrongstack/cli/package.json");
26605
26645
  const pkgDir = path26.dirname(pkgPath);
26606
26646
  cliPath = path26.join(pkgDir, "dist", "index.js");
26607
- await fs17.access(cliPath);
26647
+ await fs16.access(cliPath);
26608
26648
  } catch {
26609
26649
  cliPath = process.argv[1] ?? "";
26610
26650
  if (!cliPath) {
@@ -26630,7 +26670,7 @@ async function switchProjectCommand(opts, ctx, target, displayName) {
26630
26670
  const canSwitch = await confirmProjectSwitch(opts, targetName);
26631
26671
  if (!canSwitch) return { message: "" };
26632
26672
  const nodeExe = process.execPath;
26633
- const child = spawn7(nodeExe, [cliPath, "--no-interactive"], {
26673
+ const child = spawn6(nodeExe, [cliPath, "--no-interactive"], {
26634
26674
  cwd: resolved,
26635
26675
  stdio: "inherit",
26636
26676
  detached: false
@@ -26749,7 +26789,7 @@ async function spawnInProject(opts, _ctx, root, projectName) {
26749
26789
  const pkgPath = req.resolve("@wrongstack/cli/package.json");
26750
26790
  const pkgDir = path26.dirname(pkgPath);
26751
26791
  cliPath = path26.join(pkgDir, "dist", "index.js");
26752
- await fs17.access(cliPath);
26792
+ await fs16.access(cliPath);
26753
26793
  } catch {
26754
26794
  cliPath = process.argv[1] ?? "";
26755
26795
  if (!cliPath) {
@@ -26772,7 +26812,7 @@ async function spawnInProject(opts, _ctx, root, projectName) {
26772
26812
  }
26773
26813
  await saveManifest(manifest, opts.paths?.globalConfig);
26774
26814
  const nodeExe = process.execPath;
26775
- const child = spawn7(nodeExe, [cliPath, "--no-interactive"], {
26815
+ const child = spawn6(nodeExe, [cliPath, "--no-interactive"], {
26776
26816
  cwd: root,
26777
26817
  stdio: "inherit",
26778
26818
  detached: false
@@ -26804,7 +26844,7 @@ async function handleNewSession(_opts, _ctx) {
26804
26844
  const pkgPath = req.resolve("@wrongstack/cli/package.json");
26805
26845
  const pkgDir = path26.dirname(pkgPath);
26806
26846
  cliPath = path26.join(pkgDir, "dist", "index.js");
26807
- await fs17.access(cliPath);
26847
+ await fs16.access(cliPath);
26808
26848
  } catch {
26809
26849
  cliPath = process.argv[1] ?? "";
26810
26850
  if (!cliPath) {
@@ -26814,7 +26854,7 @@ async function handleNewSession(_opts, _ctx) {
26814
26854
  }
26815
26855
  }
26816
26856
  const nodeExe = process.execPath;
26817
- const child = spawn7(nodeExe, [cliPath, "--no-interactive"], {
26857
+ const child = spawn6(nodeExe, [cliPath, "--no-interactive"], {
26818
26858
  cwd: process.cwd(),
26819
26859
  stdio: "inherit",
26820
26860
  detached: false
@@ -26867,13 +26907,13 @@ async function handlePrevSessions(opts, _ctx) {
26867
26907
  }
26868
26908
 
26869
26909
  // src/slash-commands/review.ts
26870
- import { spawn as spawn8 } from "node:child_process";
26910
+ import { spawn as spawn7 } from "node:child_process";
26871
26911
  import * as fsp3 from "node:fs/promises";
26872
26912
  import * as path27 from "node:path";
26873
26913
  import { emitReviewIfChanged } from "@wrongstack/core/plugin";
26874
26914
  async function runGit2(args, cwd) {
26875
26915
  return new Promise((resolve8) => {
26876
- const child = spawn8("git", args, {
26916
+ const child = spawn7("git", args, {
26877
26917
  cwd,
26878
26918
  stdio: ["ignore", "pipe", "pipe"],
26879
26919
  signal: AbortSignal.timeout(1e4),
@@ -26967,7 +27007,9 @@ function buildReviewCommand(opts) {
26967
27007
  maxFiles: limit,
26968
27008
  autoFix: "off",
26969
27009
  cascadeOn: "off",
26970
- maxCascadeDepth: 0
27010
+ maxCascadeDepth: 0,
27011
+ fallbackModels: [],
27012
+ fallbackProfile: void 0
26971
27013
  },
26972
27014
  cwd,
26973
27015
  files: filesWithContent
@@ -27070,7 +27112,7 @@ function buildSecurityCommand(opts) {
27070
27112
  // src/slash-commands/settings.ts
27071
27113
  import { noOpVault as noOpVault9 } from "@wrongstack/core/security";
27072
27114
  import { resolveFleetChatVerbosity as resolveFleetChatVerbosity2 } from "@wrongstack/core/types";
27073
- import { color as color49, toErrorMessage as toErrorMessage24 } from "@wrongstack/core/utils";
27115
+ import { color as color49, toErrorMessage as toErrorMessage23 } from "@wrongstack/core/utils";
27074
27116
  import { getProcessRegistry } from "@wrongstack/tools";
27075
27117
 
27076
27118
  // src/utils/delay-format.ts
@@ -28003,7 +28045,7 @@ function buildSettingsCommand(opts) {
28003
28045
  };
28004
28046
  } catch (err) {
28005
28047
  return {
28006
- message: `${color49.red("Settings error")}: ${toErrorMessage24(err)}`
28048
+ message: `${color49.red("Settings error")}: ${toErrorMessage23(err)}`
28007
28049
  };
28008
28050
  }
28009
28051
  }
@@ -28304,7 +28346,7 @@ function parseFlags2(args) {
28304
28346
  }
28305
28347
 
28306
28348
  // src/slash-commands/spawn-agents.ts
28307
- import { toErrorMessage as toErrorMessage25 } from "@wrongstack/core/utils";
28349
+ import { toErrorMessage as toErrorMessage24 } from "@wrongstack/core/utils";
28308
28350
  function buildSpawnCommand(opts) {
28309
28351
  return {
28310
28352
  name: "spawn",
@@ -28341,7 +28383,7 @@ function buildSpawnCommand(opts) {
28341
28383
  const summary = Object.keys(parsed).length > 0 ? await opts.onSpawn(description, parsed) : await opts.onSpawn(description);
28342
28384
  return { message: summary };
28343
28385
  } catch (err) {
28344
- return { message: `Spawn failed: ${toErrorMessage25(err)}` };
28386
+ return { message: `Spawn failed: ${toErrorMessage24(err)}` };
28345
28387
  }
28346
28388
  }
28347
28389
  };
@@ -29010,21 +29052,21 @@ ${formatTaskProgress(file.tasks)}`;
29010
29052
  }
29011
29053
 
29012
29054
  // src/slash-commands/techstack.ts
29013
- import * as fs18 from "node:fs/promises";
29055
+ import * as fs17 from "node:fs/promises";
29014
29056
  import * as path28 from "node:path";
29015
- import { color as color52, toErrorMessage as toErrorMessage26 } from "@wrongstack/core/utils";
29057
+ import { color as color52, toErrorMessage as toErrorMessage25 } from "@wrongstack/core/utils";
29016
29058
  async function discoverPackageFiles(projectRoot) {
29017
29059
  const files = [];
29018
29060
  const rootPkg = path28.join(projectRoot, "package.json");
29019
29061
  try {
29020
- await fs18.access(rootPkg);
29062
+ await fs17.access(rootPkg);
29021
29063
  files.push(rootPkg);
29022
29064
  } catch {
29023
29065
  }
29024
29066
  const workspaceFile = path28.join(projectRoot, "pnpm-workspace.yaml");
29025
29067
  try {
29026
- await fs18.access(workspaceFile);
29027
- const content = await fs18.readFile(workspaceFile, "utf8");
29068
+ await fs17.access(workspaceFile);
29069
+ const content = await fs17.readFile(workspaceFile, "utf8");
29028
29070
  const globMatch = /packages?:\s*\[([^\]]+)\]/s.exec(content);
29029
29071
  const rawGlobs = globMatch?.[1];
29030
29072
  if (!rawGlobs) return files;
@@ -29033,12 +29075,12 @@ async function discoverPackageFiles(projectRoot) {
29033
29075
  const dirPrefix = g.replace(/\/?\*$/, "").replace(/\/\*$/, "");
29034
29076
  const dir = path28.join(projectRoot, dirPrefix);
29035
29077
  try {
29036
- const entries = await fs18.readdir(dir, { withFileTypes: true });
29078
+ const entries = await fs17.readdir(dir, { withFileTypes: true });
29037
29079
  for (const e of entries) {
29038
29080
  if (!e.isDirectory()) continue;
29039
29081
  const subPkg = path28.join(dir, e.name, "package.json");
29040
29082
  try {
29041
- await fs18.access(subPkg);
29083
+ await fs17.access(subPkg);
29042
29084
  files.push(subPkg);
29043
29085
  } catch {
29044
29086
  }
@@ -29220,7 +29262,7 @@ function buildTechStackCommand(opts) {
29220
29262
  message: `TechStack remediation finished: ${applied} applied, ${failed} failed, ${skipped} skipped.`
29221
29263
  };
29222
29264
  } catch (err) {
29223
- const msg = `TechStack remediation failed: ${toErrorMessage26(err)}`;
29265
+ const msg = `TechStack remediation failed: ${toErrorMessage25(err)}`;
29224
29266
  opts.renderer.writeWarning(msg);
29225
29267
  return { message: msg };
29226
29268
  } finally {
@@ -29239,7 +29281,7 @@ function buildTechStackCommand(opts) {
29239
29281
  message: `TechStack inventory complete: ${snapshot.workspaces.length} workspaces, ${snapshot.dependencies.length} dependencies (fingerprint: ${snapshot.fingerprint})`
29240
29282
  };
29241
29283
  } catch (err) {
29242
- const msg = `TechStack inventory failed: ${toErrorMessage26(err)}`;
29284
+ const msg = `TechStack inventory failed: ${toErrorMessage25(err)}`;
29243
29285
  opts.renderer.writeWarning(msg);
29244
29286
  return { message: msg };
29245
29287
  }
@@ -29254,7 +29296,7 @@ function buildTechStackCommand(opts) {
29254
29296
  );
29255
29297
  }
29256
29298
  } catch (err) {
29257
- discoveryNote = color52.red(`Could not scan for package files: ${toErrorMessage26(err)}`);
29299
+ discoveryNote = color52.red(`Could not scan for package files: ${toErrorMessage25(err)}`);
29258
29300
  }
29259
29301
  const task = buildTechStackTask({
29260
29302
  projectRoot: opts.projectRoot,
@@ -29294,7 +29336,7 @@ function buildTechStackCommand(opts) {
29294
29336
  });
29295
29337
  return { message: summary };
29296
29338
  } catch (err) {
29297
- const msg = `Tech stack scan failed: ${toErrorMessage26(err)}`;
29339
+ const msg = `Tech stack scan failed: ${toErrorMessage25(err)}`;
29298
29340
  opts.renderer.writeWarning(msg);
29299
29341
  return { message: msg };
29300
29342
  }
@@ -29303,7 +29345,7 @@ function buildTechStackCommand(opts) {
29303
29345
  }
29304
29346
 
29305
29347
  // src/slash-commands/telegram-settings.ts
29306
- import { color as color54, toErrorMessage as toErrorMessage27 } from "@wrongstack/core/utils";
29348
+ import { color as color54, toErrorMessage as toErrorMessage26 } from "@wrongstack/core/utils";
29307
29349
 
29308
29350
  // src/slash-commands/telegram-setup.ts
29309
29351
  import { color as color53 } from "@wrongstack/core/utils";
@@ -29801,7 +29843,7 @@ function buildTelegramSettingsCommand(opts) {
29801
29843
  };
29802
29844
  } catch (err) {
29803
29845
  return {
29804
- message: `${color54.red("Settings error")}: ${toErrorMessage27(err)}`
29846
+ message: `${color54.red("Settings error")}: ${toErrorMessage26(err)}`
29805
29847
  };
29806
29848
  }
29807
29849
  }
@@ -29955,7 +29997,7 @@ import {
29955
29997
  normalizeToolDescriptionMode,
29956
29998
  normalizeToolResultRenderMode,
29957
29999
  setToolResultRenderMode,
29958
- toErrorMessage as toErrorMessage28
30000
+ toErrorMessage as toErrorMessage27
29959
30001
  } from "@wrongstack/core/utils";
29960
30002
  function fit(text, width) {
29961
30003
  if (text.length <= width) return text.padEnd(width);
@@ -30190,7 +30232,7 @@ function buildToolCommand(opts) {
30190
30232
  try {
30191
30233
  return { message: await cmdEnableAll() };
30192
30234
  } catch (err) {
30193
- return { message: `${color55.red("Error")}: ${toErrorMessage28(err)}` };
30235
+ return { message: `${color55.red("Error")}: ${toErrorMessage27(err)}` };
30194
30236
  }
30195
30237
  }
30196
30238
  const name = parts[0] ?? "";
@@ -30204,7 +30246,7 @@ function buildToolCommand(opts) {
30204
30246
  for (const t of targets) results.push(await cmdDisable(t));
30205
30247
  return { message: results.join("\n") };
30206
30248
  } catch (err) {
30207
- return { message: `${color55.red("Error")}: ${toErrorMessage28(err)}` };
30249
+ return { message: `${color55.red("Error")}: ${toErrorMessage27(err)}` };
30208
30250
  }
30209
30251
  }
30210
30252
  if (sub === "enable") {
@@ -30216,7 +30258,7 @@ function buildToolCommand(opts) {
30216
30258
  for (const t of targets) results.push(await cmdEnable(t));
30217
30259
  return { message: results.join("\n") };
30218
30260
  } catch (err) {
30219
- return { message: `${color55.red("Error")}: ${toErrorMessage28(err)}` };
30261
+ return { message: `${color55.red("Error")}: ${toErrorMessage27(err)}` };
30220
30262
  }
30221
30263
  }
30222
30264
  const action = parts[1]?.toLowerCase();
@@ -30229,7 +30271,7 @@ function buildToolCommand(opts) {
30229
30271
  try {
30230
30272
  return { message: action === "disable" ? await cmdDisable(name) : await cmdEnable(name) };
30231
30273
  } catch (err) {
30232
- return { message: `${color55.red("Error")}: ${toErrorMessage28(err)}` };
30274
+ return { message: `${color55.red("Error")}: ${toErrorMessage27(err)}` };
30233
30275
  }
30234
30276
  }
30235
30277
  if (!opts.toolRegistry.get(name) && !opts.toolRegistry.isDisabled(name)) {
@@ -30269,7 +30311,7 @@ function buildToolCommand(opts) {
30269
30311
  };
30270
30312
  } catch (err) {
30271
30313
  return {
30272
- message: `${color55.red("Could not save tool setting")}: ${toErrorMessage28(err)}`
30314
+ message: `${color55.red("Could not save tool setting")}: ${toErrorMessage27(err)}`
30273
30315
  };
30274
30316
  }
30275
30317
  }
@@ -30289,7 +30331,7 @@ function buildToolCommand(opts) {
30289
30331
  };
30290
30332
  } catch (err) {
30291
30333
  return {
30292
- message: `${color55.red("Could not save tool setting")}: ${toErrorMessage28(err)}`
30334
+ message: `${color55.red("Could not save tool setting")}: ${toErrorMessage27(err)}`
30293
30335
  };
30294
30336
  }
30295
30337
  }
@@ -30350,7 +30392,7 @@ ${lines.join("\n")}${extra}
30350
30392
  }
30351
30393
 
30352
30394
  // src/slash-commands/tuneup.ts
30353
- import * as fs19 from "node:fs/promises";
30395
+ import * as fs18 from "node:fs/promises";
30354
30396
  import * as os3 from "node:os";
30355
30397
  import * as path29 from "node:path";
30356
30398
  import { atomicWrite as atomicWrite10, color as color57 } from "@wrongstack/core/utils";
@@ -30960,7 +31002,7 @@ async function gatherMemoryFiles(opts) {
30960
31002
  const out = [];
30961
31003
  for (const c of candidates) {
30962
31004
  try {
30963
- const content = await fs19.readFile(c.file, "utf8");
31005
+ const content = await fs18.readFile(c.file, "utf8");
30964
31006
  out.push({ label: c.label, path: c.file, content, committed: c.committed });
30965
31007
  } catch {
30966
31008
  }
@@ -30978,7 +31020,7 @@ async function gatherTrust(opts) {
30978
31020
  const file = opts.paths?.projectTrust;
30979
31021
  if (!file) return void 0;
30980
31022
  try {
30981
- const raw = await fs19.readFile(file, "utf8");
31023
+ const raw = await fs18.readFile(file, "utf8");
30982
31024
  const parsed = JSON.parse(raw);
30983
31025
  if (parsed && typeof parsed === "object") return parsed;
30984
31026
  } catch {
@@ -30989,7 +31031,7 @@ async function gatherConfigIssues(opts) {
30989
31031
  if (!opts.paths) return 0;
30990
31032
  const file = activeProfileConfigPath(opts.paths, opts.configStore.get());
30991
31033
  try {
30992
- const raw = await fs19.readFile(file, "utf8");
31034
+ const raw = await fs18.readFile(file, "utf8");
30993
31035
  const parsed = JSON.parse(raw);
30994
31036
  return diagnoseConfig(parsed).findings.length;
30995
31037
  } catch {
@@ -31007,14 +31049,14 @@ async function gatherSessionBytes(opts) {
31007
31049
  }
31008
31050
  async function dirSize(dir) {
31009
31051
  let total = 0;
31010
- const entries = await fs19.readdir(dir, { withFileTypes: true });
31052
+ const entries = await fs18.readdir(dir, { withFileTypes: true });
31011
31053
  for (const e of entries) {
31012
31054
  const full = path29.join(dir, e.name);
31013
31055
  if (e.isDirectory()) {
31014
31056
  total += await dirSize(full);
31015
31057
  } else if (e.isFile()) {
31016
31058
  try {
31017
- total += (await fs19.stat(full)).size;
31059
+ total += (await fs18.stat(full)).size;
31018
31060
  } catch {
31019
31061
  }
31020
31062
  }
@@ -31027,7 +31069,7 @@ async function applyActions(actions, opts) {
31027
31069
  const file = activeProfileConfigPath(opts.paths, opts.configStore.get());
31028
31070
  let raw = "{}";
31029
31071
  try {
31030
- raw = await fs19.readFile(file, "utf8");
31072
+ raw = await fs18.readFile(file, "utf8");
31031
31073
  } catch {
31032
31074
  }
31033
31075
  let parsed;
@@ -31183,9 +31225,9 @@ function summaryLine(findings, fixable, handoffs, power) {
31183
31225
  }
31184
31226
 
31185
31227
  // src/slash-commands/working-dir.ts
31186
- import * as fs20 from "node:fs/promises";
31228
+ import * as fs19 from "node:fs/promises";
31187
31229
  import * as path30 from "node:path";
31188
- import { color as color58, toErrorMessage as toErrorMessage29 } from "@wrongstack/core/utils";
31230
+ import { color as color58, toErrorMessage as toErrorMessage28 } from "@wrongstack/core/utils";
31189
31231
  function buildWorkingDirCommand(_opts) {
31190
31232
  return {
31191
31233
  name: "working_dir",
@@ -31230,7 +31272,7 @@ function buildWorkingDirCommand(_opts) {
31230
31272
  };
31231
31273
  }
31232
31274
  try {
31233
- const stat5 = await fs20.stat(resolved);
31275
+ const stat5 = await fs19.stat(resolved);
31234
31276
  if (!stat5.isDirectory()) {
31235
31277
  return { message: color58.red(`Not a directory: ${resolved}`) };
31236
31278
  }
@@ -31242,7 +31284,7 @@ function buildWorkingDirCommand(_opts) {
31242
31284
  ctx.setWorkingDir(resolved);
31243
31285
  } catch (err) {
31244
31286
  return {
31245
- message: color58.red(toErrorMessage29(err))
31287
+ message: color58.red(toErrorMessage28(err))
31246
31288
  };
31247
31289
  }
31248
31290
  const prevRel = path30.relative(ctx.projectRoot, previous) || ".";
@@ -31585,12 +31627,14 @@ async function runInteractive(cliCtx) {
31585
31627
  });
31586
31628
  const stdinInteractive = process.stdin.isTTY;
31587
31629
  const hookRunnerRef = { current: null };
31630
+ const switchProviderAndModelRef = { current: null };
31588
31631
  registerCliManagementTools({
31589
31632
  toolRegistry,
31590
31633
  configStore,
31591
31634
  profileConfigPath,
31592
31635
  stdinInteractive,
31593
- getHookRunner: () => hookRunnerRef.current
31636
+ getHookRunner: () => hookRunnerRef.current,
31637
+ getSwitchProviderAndModel: () => switchProviderAndModelRef.current
31594
31638
  });
31595
31639
  const { metricsSink, healthRegistry, metricsStatus } = (() => {
31596
31640
  const ms = setupMetrics({
@@ -31835,6 +31879,7 @@ async function runInteractive(cliCtx) {
31835
31879
  buildProviderForIdRuntime: buildProviderForId,
31836
31880
  statusTracker
31837
31881
  });
31882
+ switchProviderAndModelRef.current = switchProviderAndModel;
31838
31883
  await adoptResumedProvider({
31839
31884
  resumedProvider: sessResult.resumedProvider,
31840
31885
  resumedModel: sessResult.resumedModel,
@@ -32223,7 +32268,7 @@ async function runInteractive(cliCtx) {
32223
32268
  onEvent: evOn
32224
32269
  });
32225
32270
  const savedProviderCfg = config.providers?.[config.provider];
32226
- const { execute } = await import("./execution-QYFWDD3Y.js");
32271
+ const { execute } = await import("./execution-4IG5XKOL.js");
32227
32272
  const stopHeapWatchdog = startSharedHeapWatchdog({
32228
32273
  collectStats: () => {
32229
32274
  const hqQueue = hqPublisherRef.current?.getQueueStats();
@@ -32461,4 +32506,4 @@ export {
32461
32506
  CLI_VERSION,
32462
32507
  runInteractive
32463
32508
  };
32464
- //# sourceMappingURL=cli-main-6YE423OH.js.map
32509
+ //# sourceMappingURL=cli-main-3PUWFKSL.js.map