@wrongstack/cli 0.319.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/data/providers.json +22 -15
  2. package/dist/{acp-5ANIAOZC.js → acp-3LARESEO.js} +113 -10
  3. package/dist/acp-hq-telemetry.d.ts +44 -0
  4. package/dist/{audit-ZPCLCC3C.js → audit-46YK5DSC.js} +1 -2
  5. package/dist/{auth-KF5TAD7V.js → auth-KIBJZZIE.js} +5 -6
  6. package/dist/auth-menu/add-provider.d.ts +7 -0
  7. package/dist/auth-menu/panel-service.d.ts +2 -20
  8. package/dist/{auto-discover-providers-MHFLDSD3.js → auto-discover-providers-VQU3IZMR.js} +1 -2
  9. package/dist/{bench-XYG56AMO.js → bench-YBU6BVQP.js} +175 -35
  10. package/dist/boot/brain-decision-log.d.ts +22 -2
  11. package/dist/{boot-auto-thin-BZ675EVT.js → boot-auto-thin-MANHOYHE.js} +1 -2
  12. package/dist/{chronicle-6EPPMUC5.js → chronicle-UTFETHP6.js} +1 -2
  13. package/dist/{chunk-VWCZL4OH.js → chunk-4HV5RKZH.js} +5 -5
  14. package/dist/{chunk-42JD25KU.js → chunk-5IA5337I.js} +3 -3
  15. package/dist/{chunk-7JBKXVMK.js → chunk-C2E24IXZ.js} +44 -32
  16. package/dist/{chunk-7CECQDNH.js → chunk-D3K4NYQL.js} +1 -1
  17. package/dist/{chunk-XPX432BZ.js → chunk-DR2OXU46.js} +50 -39
  18. package/dist/{chunk-4JRIWVJ4.js → chunk-ERX4BLKP.js} +1 -1
  19. package/dist/chunk-ETYHZPXP.js +52 -0
  20. package/dist/{chunk-TYO2OVAD.js → chunk-EWKESL4L.js} +8 -4
  21. package/dist/{chunk-QAC263FZ.js → chunk-FPIWTJ2G.js} +2 -3
  22. package/dist/{chunk-7YLN7YUA.js → chunk-IMWXXF4J.js} +61 -9
  23. package/dist/{chunk-G7337TTK.js → chunk-IS2PPBQV.js} +1 -1
  24. package/dist/{chunk-G3IMKQRH.js → chunk-JHPXJRRI.js} +1 -1
  25. package/dist/{chunk-XHIEA6LG.js → chunk-MNQQ4ZNF.js} +26 -22
  26. package/dist/{chunk-P2OKBDCH.js → chunk-MXEJEYT7.js} +53 -14
  27. package/dist/{chunk-PCBJSXYV.js → chunk-O4A3HHKD.js} +2 -2
  28. package/dist/{chunk-XYKYXFEE.js → chunk-TE3Q32JP.js} +10 -4
  29. package/dist/{chunk-H7GABTGS.js → chunk-TEBMCYZN.js} +69 -30
  30. package/dist/{chunk-E4I2TF5S.js → chunk-TNK6237M.js} +2 -2
  31. package/dist/{chunk-SYIBTG3X.js → chunk-VOTTENR5.js} +3 -5
  32. package/dist/chunk-WHOIR577.js +1 -0
  33. package/dist/{chunk-2ZNBRZ4W.js → chunk-WQZW3RDP.js} +2 -2
  34. package/dist/{chunk-GGGUZSAU.js → chunk-Z7A5MXKJ.js} +18 -12
  35. package/dist/{chunk-F5GA2QW2.js → chunk-ZSZ3EYWH.js} +2 -2
  36. package/dist/{cli-context-LH4QP4W2.js → cli-context-CYMKNOK3.js} +58 -307
  37. package/dist/{cli-main-72XUFUCL.js → cli-main-TTIVR4DI.js} +925 -329
  38. package/dist/{diag-doctor-LFCCBPMD.js → diag-doctor-7LYUYU35.js} +4 -6
  39. package/dist/execute-deps.d.ts +5 -1
  40. package/dist/{execution-DKJDNPYF.js → execution-3Y55IWBK.js} +512 -469
  41. package/dist/{export-ROG3DKTZ.js → export-VVRIOWFV.js} +1 -2
  42. package/dist/{governance-JSGHHA2R.js → governance-RYSHV675.js} +1 -2
  43. package/dist/{hq-3GWBFLON.js → hq-IG3YRGCO.js} +2 -3
  44. package/dist/hq-command-controller.d.ts +37 -7
  45. package/dist/hq-server/routes.d.ts +1 -1
  46. package/dist/hq-server/ws.d.ts +1 -1
  47. package/dist/{hq-server-OARPUSQJ.js → hq-server-OILU3NPI.js} +2 -3
  48. package/dist/{hq-ttl-KUO3AU7X.js → hq-ttl-VJR65OBJ.js} +1 -2
  49. package/dist/{hq-tunnel-LO55RCZE.js → hq-tunnel-NIJ5EP2Y.js} +1 -2
  50. package/dist/index.js +5 -6
  51. package/dist/{init-4JQSG66Q.js → init-DRMMFG2G.js} +1 -2
  52. package/dist/{kanban-run-mirror-EKVNGXWW.js → kanban-run-mirror-22HQ5FNG.js} +1 -2
  53. package/dist/live-settings-input.d.ts +2 -0
  54. package/dist/{mailbox-serve-VKQIRCCB.js → mailbox-serve-VUCWZ2SJ.js} +2 -3
  55. package/dist/{mcp-AQKSASHD.js → mcp-HOMLC4WE.js} +1 -2
  56. package/dist/{modeldiag-5FRMT6FQ.js → modeldiag-FMJT37SN.js} +2 -3
  57. package/dist/{per-subcommand-help-6VCIKDUW.js → per-subcommand-help-BWBHYVJO.js} +2 -3
  58. package/dist/{permissions-2PWBL4YU.js → permissions-CFDLXETM.js} +1 -2
  59. package/dist/{plugin-usage-CYUORYM6.js → plugin-usage-HFBI3TFT.js} +2 -3
  60. package/dist/{plugins-RV3OBBND.js → plugins-PZ2VZL7V.js} +4 -5
  61. package/dist/{project-BLQ3ALVL.js → project-AOQI5XTK.js} +1 -2
  62. package/dist/{project-manifest-YFTJ3D5N.js → project-manifest-7NSFVBM3.js} +2 -3
  63. package/dist/{project-picker-R5TYAE3Q.js → project-picker-SVBXMPKX.js} +3 -4
  64. package/dist/{projects-5J727S4L.js → projects-L6C6XLDY.js} +1 -2
  65. package/dist/provider-config-utils.d.ts +1 -1
  66. package/dist/{providers-models-OKKQZIWU.js → providers-models-YVMVYWRS.js} +3 -4
  67. package/dist/{proxy-wiring-EQB5X5YH.js → proxy-wiring-MGRSKZZB.js} +3 -4
  68. package/dist/{quick-XLYLZX4B.js → quick-CNB4Z3HS.js} +1 -2
  69. package/dist/{replay-RZXZKP2U.js → replay-JJ2NOWD6.js} +1 -2
  70. package/dist/{replay-FJ2JBXUA.js → replay-Z3FTJEMM.js} +1 -2
  71. package/dist/{rewind-2FFNOOKS.js → rewind-JA3ZLCNM.js} +1 -2
  72. package/dist/{sdd-runtime-FLKCSTYV.js → sdd-runtime-PTOSPYI4.js} +2 -3
  73. package/dist/services/sdd-runtime.d.ts +1 -1
  74. package/dist/services/statusline-config.d.ts +43 -13
  75. package/dist/{sessions-config-KAMEBVOX.js → sessions-config-UL45XKX7.js} +2 -3
  76. package/dist/{sessions-doctor-EXHAZSSE.js → sessions-doctor-QUL37U32.js} +1 -2
  77. package/dist/short-circuit-flags-6PSP56L7.js +10 -0
  78. package/dist/{simpleui-dist-JKNRCRRK.js → simpleui-dist-CXSIDAXZ.js} +1 -2
  79. package/dist/slash-commands/command-context.d.ts +10 -0
  80. package/dist/slash-commands/sdd.d.ts +1 -1
  81. package/dist/slash-commands/statusline.d.ts +1 -1
  82. package/dist/subcommands/handlers/bench-run-config.d.ts +18 -0
  83. package/dist/subcommands/handlers/bench.d.ts +8 -7
  84. package/dist/subcommands-HZQKA4G2.js +9 -0
  85. package/dist/{tools-skills-Q4P27URS.js → tools-skills-GH24UCBY.js} +1 -2
  86. package/dist/{update-K45CS6SS.js → update-5DPB4YD4.js} +1 -2
  87. package/dist/{update-check-PKSMSMD6.js → update-check-BS3DHTSI.js} +1 -2
  88. package/dist/version-help-MYKF724O.js +10 -0
  89. package/dist/webui-server/client-registration.d.ts +9 -1
  90. package/dist/{webui-server-SY4EQCKD.js → webui-server-T6AMOXJJ.js} +54 -13
  91. package/dist/wiring/brain-and-orchestration.d.ts +2 -0
  92. package/dist/wiring/cli-execute-builder.d.ts +4 -0
  93. package/dist/wiring/cli-slash-commands-setup.d.ts +1 -0
  94. package/dist/wiring/command-host-state.d.ts +50 -5
  95. package/dist/wiring/external-plugins.d.ts +9 -0
  96. package/dist/wiring/provider-runtime-setup.d.ts +2 -0
  97. package/dist/wiring/runtime-controller-deps.d.ts +3 -0
  98. package/dist/wiring/vector-memory-setup.d.ts +12 -0
  99. package/dist/wiring/wrongtrace-gate.d.ts +2 -2
  100. package/dist/wiring/wrongtrace-hooks.d.ts +1 -1
  101. package/dist/wiring/wrongtrace-prompt-contributor.d.ts +5 -2
  102. package/dist/{wrongtrace-gate-counters-P5BCBXQN.js → wrongtrace-gate-counters-7C2EAAZL.js} +2 -3
  103. package/dist/{wrongtrace-telemetry-FNLANZ5I.js → wrongtrace-telemetry-3ASFKOZO.js} +2 -3
  104. package/package.json +28 -28
  105. package/dist/chunk-7OCVIDC7.js +0 -11
  106. package/dist/chunk-ALE5KHCA.js +0 -1
  107. package/dist/chunk-OZDE3OWD.js +0 -52
  108. package/dist/launch-hints.d.ts +0 -49
  109. package/dist/short-circuit-flags-U6CJAF6J.js +0 -11
  110. package/dist/subcommands-J4JMWC5W.js +0 -10
  111. package/dist/version-help-WMPSEL4U.js +0 -11
  112. package/dist/webui-server/privileged-actions.d.ts +0 -14
  113. package/dist/wiring/cli-heap-watchdog.d.ts +0 -34
@@ -1,24 +1,27 @@
1
1
  import {
2
2
  CLI_VERSION
3
3
  } from "./chunk-XJXDOF63.js";
4
- import "./chunk-7OCVIDC7.js";
5
4
 
6
5
  // src/subcommands/handlers/bench.ts
7
6
  import * as fs from "node:fs/promises";
8
7
  import { createRequire } from "node:module";
9
- import * as path from "node:path";
8
+ import * as path2 from "node:path";
10
9
  import {
11
10
  collectCellPredictions,
11
+ compareReports,
12
12
  computeToolManifestHash,
13
+ createCoreSuite,
13
14
  createLocalManifestSuite,
14
15
  createPolyglotSuite,
16
+ createSmokeSuite,
15
17
  createSwebenchSuite,
16
18
  gradeLocalManifest,
17
19
  gradePolyglot,
18
20
  gradeSwebench,
19
- loadBenchConfig,
21
+ loadBenchConfig as loadBenchConfig2,
20
22
  mineTranscript,
21
- readSummary,
23
+ readRunDir,
24
+ renderComparisonMarkdown,
22
25
  renderMarkdownReport,
23
26
  reportHeaderLine,
24
27
  runBenchmark,
@@ -26,6 +29,68 @@ import {
26
29
  writePredictionsJsonl
27
30
  } from "@wrongstack/bench";
28
31
  import { color, toErrorMessage } from "@wrongstack/core/utils";
32
+
33
+ // src/subcommands/handlers/bench-run-config.ts
34
+ import * as path from "node:path";
35
+ import {
36
+ configFromCells,
37
+ loadBenchConfig,
38
+ parseCellList,
39
+ CORE_CONFIG_DEFAULTS,
40
+ SMOKE_CONFIG_DEFAULTS
41
+ } from "@wrongstack/bench";
42
+ var DEFAULT_BENCH_MODELS_FILE = "bench.config.json";
43
+ async function resolveBenchRunConfig(input) {
44
+ const suiteDefaults = input.suiteId === "core" ? CORE_CONFIG_DEFAULTS : input.suiteId === "smoke" ? SMOKE_CONFIG_DEFAULTS : void 0;
45
+ const cellSpec = stringFlag(input.flags, "cell") ?? stringFlag(input.flags, "cells");
46
+ if (cellSpec) {
47
+ return configFromCells(parseCellList(cellSpec), suiteDefaults);
48
+ }
49
+ const providerFlag = stringFlag(input.flags, "provider");
50
+ const modelFlag = stringFlag(input.flags, "model");
51
+ if (providerFlag && modelFlag) {
52
+ return configFromCells(
53
+ [{ label: `${providerFlag}/${modelFlag}`, provider: providerFlag, model: modelFlag }],
54
+ suiteDefaults
55
+ );
56
+ }
57
+ const modelsFlag = stringFlag(input.flags, "models");
58
+ const modelsPath = modelsFlag ?? DEFAULT_BENCH_MODELS_FILE;
59
+ const resolvedModels = path.resolve(input.cwd, modelsPath);
60
+ const customModelsFile = modelsFlag !== void 0 && modelsFlag !== DEFAULT_BENCH_MODELS_FILE;
61
+ try {
62
+ return await loadBenchConfig(resolvedModels);
63
+ } catch (err) {
64
+ if (customModelsFile || !isMissingConfigError(err)) throw err;
65
+ }
66
+ const savedProvider = input.savedProvider;
67
+ const savedModel = input.savedModel;
68
+ if (savedProvider && savedModel) {
69
+ return configFromCells(
70
+ [
71
+ {
72
+ label: `${savedProvider}/${savedModel}`,
73
+ provider: savedProvider,
74
+ model: savedModel
75
+ }
76
+ ],
77
+ suiteDefaults
78
+ );
79
+ }
80
+ throw new Error(
81
+ "No model cells. Pass --cell provider/model[,provider/model], --provider + --model, or --models <config.json>"
82
+ );
83
+ }
84
+ function stringFlag(flags, name) {
85
+ const value = flags?.[name];
86
+ return typeof value === "string" && value.length > 0 ? value : void 0;
87
+ }
88
+ function isMissingConfigError(err) {
89
+ const message = err instanceof Error ? err.message : String(err);
90
+ return /ENOENT|no such file or directory/i.test(message);
91
+ }
92
+
93
+ // src/subcommands/handlers/bench.ts
29
94
  var benchCmd = async (args, deps) => {
30
95
  const sub = args[0];
31
96
  const rest = args.slice(1);
@@ -34,6 +99,8 @@ var benchCmd = async (args, deps) => {
34
99
  return benchRun(rest, deps);
35
100
  case "report":
36
101
  return benchReport(rest, deps);
102
+ case "compare":
103
+ return benchCompare(rest, deps);
37
104
  case "list":
38
105
  return benchList(rest, deps);
39
106
  case "mine":
@@ -48,16 +115,20 @@ function printUsage(deps) {
48
115
  [
49
116
  color.bold("wstack bench") + " \u2014 model-independent agentic benchmarks",
50
117
  "",
51
- " run Run a suite across a model matrix and write a report",
52
- " mine Copy a real session transcript and draft trace-eval cases",
53
- " report Re-render report.md from a finished run directory",
54
- " list Show available suites and configured model cells",
118
+ " run Run a suite across a model matrix and write a report",
119
+ " compare Diff two finished run directories (fingerprint-aware)",
120
+ " mine Copy a real session transcript and draft trace-eval cases",
121
+ " report Re-render report.md from a finished run directory",
122
+ " list Show available suites and configured model cells",
55
123
  "",
56
124
  color.dim("Examples:"),
125
+ color.dim(" wstack bench run --cell anthropic/claude-sonnet-4-6,openai/gpt-5.4"),
126
+ color.dim(" wstack bench run --suite smoke --cell zai-coding-plan/glm-5.3-flash"),
57
127
  color.dim(
58
128
  " wstack bench run --suite polyglot --polyglot-dir ./polyglot --models bench.config.json --limit 5"
59
129
  ),
60
130
  color.dim(" wstack bench run --suite local --suite-dir ./evals --models bench.config.json"),
131
+ color.dim(" wstack bench compare ./bench-results/<baseline> ./bench-results/<candidate>"),
61
132
  color.dim(" wstack bench mine --transcript ./session.jsonl --out ./evals"),
62
133
  color.dim(" wstack bench report ./bench-results/2026-06-14T10-00-00"),
63
134
  ""
@@ -76,7 +147,7 @@ async function resolveWstackEntry() {
76
147
  try {
77
148
  const req = createRequire(import.meta.url);
78
149
  const pkgPath = req.resolve("@wrongstack/cli/package.json");
79
- const entry = path.join(path.dirname(pkgPath), "dist", "index.js");
150
+ const entry = path2.join(path2.dirname(pkgPath), "dist", "index.js");
80
151
  await fs.access(entry);
81
152
  return entry;
82
153
  } catch {
@@ -84,14 +155,19 @@ async function resolveWstackEntry() {
84
155
  }
85
156
  }
86
157
  async function benchRun(_args, deps) {
87
- const suiteId = flagStr(deps, "suite") ?? "polyglot";
88
- const modelsPath = flagStr(deps, "models") ?? "bench.config.json";
158
+ const suiteId = flagStr(deps, "suite") ?? "core";
89
159
  const limitRaw = flagStr(deps, "limit");
90
160
  const limit = limitRaw ? Math.max(1, Number.parseInt(limitRaw, 10)) : void 0;
91
161
  const outBase = flagStr(deps, "out") ?? "bench-results";
92
162
  let config;
93
163
  try {
94
- config = await loadBenchConfig(path.resolve(deps.cwd, modelsPath));
164
+ config = await resolveBenchRunConfig({
165
+ suiteId,
166
+ cwd: deps.cwd,
167
+ flags: deps.flags,
168
+ savedProvider: deps.config?.provider,
169
+ savedModel: deps.config?.model
170
+ });
95
171
  } catch (err) {
96
172
  deps.renderer.writeError(toErrorMessage(err));
97
173
  return 1;
@@ -101,13 +177,28 @@ async function benchRun(_args, deps) {
101
177
  const c = Number.parseInt(concurrencyRaw, 10);
102
178
  if (c > 0) config.concurrency = c;
103
179
  }
180
+ const repeatsRaw = flagStr(deps, "repeats");
181
+ if (repeatsRaw) {
182
+ const r = Number.parseInt(repeatsRaw, 10);
183
+ if (!Number.isFinite(r) || r <= 0) {
184
+ deps.renderer.writeError("--repeats must be a positive integer.");
185
+ return 1;
186
+ }
187
+ config.repeats = r;
188
+ }
104
189
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
105
- const outDir = path.resolve(deps.cwd, outBase, stamp);
106
- const predictionsDir = path.join(outDir, "predictions");
190
+ const outDir = path2.resolve(deps.cwd, outBase, stamp);
191
+ const predictionsDir = path2.join(outDir, "predictions");
107
192
  let suite;
108
193
  let grade;
109
194
  let isSwebench = false;
110
- if (suiteId === "polyglot") {
195
+ if (suiteId === "core") {
196
+ suite = createCoreSuite();
197
+ grade = (a) => gradeLocalManifest(a);
198
+ } else if (suiteId === "smoke") {
199
+ suite = createSmokeSuite();
200
+ grade = (a) => gradeLocalManifest(a);
201
+ } else if (suiteId === "polyglot") {
111
202
  const polyglotDir = flagStr(deps, "polyglot-dir");
112
203
  if (!polyglotDir) {
113
204
  deps.renderer.writeError("--polyglot-dir <path> is required for the polyglot suite.");
@@ -115,14 +206,14 @@ async function benchRun(_args, deps) {
115
206
  }
116
207
  const languagesRaw = flagStr(deps, "languages");
117
208
  const languages = languagesRaw ? languagesRaw.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
118
- suite = createPolyglotSuite({ polyglotDir: path.resolve(deps.cwd, polyglotDir), languages });
209
+ suite = createPolyglotSuite({ polyglotDir: path2.resolve(deps.cwd, polyglotDir), languages });
119
210
  grade = (a) => gradePolyglot(a);
120
211
  } else if (suiteId === "swebench") {
121
212
  isSwebench = true;
122
213
  const datasetDir = flagStr(deps, "dataset-dir");
123
214
  const docker = flagBool(deps, "docker");
124
215
  suite = createSwebenchSuite({
125
- datasetDir: datasetDir ? path.resolve(deps.cwd, datasetDir) : void 0,
216
+ datasetDir: datasetDir ? path2.resolve(deps.cwd, datasetDir) : void 0,
126
217
  docker
127
218
  });
128
219
  grade = (a) => gradeSwebench({ ...a, predictionsDir });
@@ -135,12 +226,14 @@ async function benchRun(_args, deps) {
135
226
  );
136
227
  return 1;
137
228
  }
138
- const manifestFile = manifestRaw ? path.resolve(deps.cwd, manifestRaw) : void 0;
139
- const suiteDir = suiteDirRaw ? path.resolve(deps.cwd, suiteDirRaw) : path.dirname(manifestFile);
229
+ const manifestFile = manifestRaw ? path2.resolve(deps.cwd, manifestRaw) : void 0;
230
+ const suiteDir = suiteDirRaw ? path2.resolve(deps.cwd, suiteDirRaw) : path2.dirname(manifestFile);
140
231
  suite = createLocalManifestSuite({ suiteDir, manifestFile });
141
232
  grade = (a) => gradeLocalManifest(a);
142
233
  } else {
143
- deps.renderer.writeError(`unknown suite "${suiteId}" (expected: polyglot | swebench | local)`);
234
+ deps.renderer.writeError(
235
+ `unknown suite "${suiteId}" (expected: core | smoke | local | polyglot | swebench)`
236
+ );
144
237
  return 1;
145
238
  }
146
239
  const tools = deps.toolRegistry?.list() ?? [];
@@ -148,6 +241,9 @@ async function benchRun(_args, deps) {
148
241
  const toolManifestHash = computeToolManifestHash(tools);
149
242
  const wstackEntry = await resolveWstackEntry();
150
243
  deps.renderer.writeInfo(`Running ${suiteId} across ${config.cells.length} model(s)\u2026`);
244
+ await fs.mkdir(outDir, { recursive: true });
245
+ const partialPath = path2.join(outDir, "results.jsonl");
246
+ await fs.writeFile(partialPath, "", "utf8");
151
247
  let report;
152
248
  try {
153
249
  report = await runBenchmark({
@@ -160,7 +256,10 @@ async function benchRun(_args, deps) {
160
256
  nodeBin: process.execPath,
161
257
  wstackEntry,
162
258
  limit,
163
- onProgress: (msg) => deps.renderer.write(color.dim(msg) + "\n")
259
+ hostHomeDir: deps.paths?.globalRoot,
260
+ keepSandbox: flagBool(deps, "keep-sandbox"),
261
+ onProgress: (msg) => deps.renderer.write(color.dim(msg) + "\n"),
262
+ onResult: (result) => fs.appendFile(partialPath, JSON.stringify(result) + "\n", "utf8")
164
263
  });
165
264
  } catch (err) {
166
265
  deps.renderer.writeError(toErrorMessage(err));
@@ -168,7 +267,7 @@ async function benchRun(_args, deps) {
168
267
  }
169
268
  await writeJsonArtifacts(outDir, report);
170
269
  const md = renderMarkdownReport(report);
171
- await fs.writeFile(path.join(outDir, "report.md"), md, "utf8");
270
+ await fs.writeFile(path2.join(outDir, "report.md"), md, "utf8");
172
271
  deps.renderer.write("\n" + md + "\n");
173
272
  if (isSwebench) {
174
273
  for (const cell of config.cells) {
@@ -181,7 +280,14 @@ async function benchRun(_args, deps) {
181
280
  "Grade with the official SWE-bench harness: python -m swebench.harness.run_evaluation --predictions_path <file> --run_id <id>"
182
281
  );
183
282
  }
184
- deps.renderer.writeInfo(`Report written to ${path.join(outDir, "report.md")}`);
283
+ deps.renderer.writeInfo(`Report written to ${path2.join(outDir, "report.md")}`);
284
+ const spawned = report.results.filter((row) => row.run.status !== "crashed").length;
285
+ if (report.results.length > 0 && spawned === 0) {
286
+ deps.renderer.writeError(
287
+ "Every run crashed before producing a result \u2014 check the provider/model ids and credentials. See the Failures section of the report."
288
+ );
289
+ return 1;
290
+ }
185
291
  return 0;
186
292
  }
187
293
  async function benchReport(args, deps) {
@@ -190,19 +296,47 @@ async function benchReport(args, deps) {
190
296
  deps.renderer.writeError("Usage: wstack bench report <run-directory>");
191
297
  return 1;
192
298
  }
193
- const outDir = path.resolve(deps.cwd, dir);
194
- let summary;
299
+ const outDir = path2.resolve(deps.cwd, dir);
300
+ let report;
195
301
  try {
196
- summary = await readSummary(outDir);
302
+ report = await readRunDir(outDir);
197
303
  } catch (err) {
198
- deps.renderer.writeError(`cannot read summary.json in ${outDir}: ${toErrorMessage(err)}`);
304
+ deps.renderer.writeError(`cannot read run artifacts in ${outDir}: ${toErrorMessage(err)}`);
199
305
  return 1;
200
306
  }
201
- const md = renderMarkdownReport(summary);
202
- await fs.writeFile(path.join(outDir, "report.md"), md, "utf8");
307
+ const md = renderMarkdownReport(report);
308
+ await fs.writeFile(path2.join(outDir, "report.md"), md, "utf8");
203
309
  deps.renderer.write("\n" + md + "\n");
204
310
  return 0;
205
311
  }
312
+ async function benchCompare(args, deps) {
313
+ const dirs = args.filter((a) => !a.startsWith("-"));
314
+ const baselineRaw = dirs[0];
315
+ const candidateRaw = dirs[1];
316
+ if (!baselineRaw || !candidateRaw) {
317
+ deps.renderer.writeError("Usage: wstack bench compare <baseline-dir> <candidate-dir>");
318
+ return 1;
319
+ }
320
+ const baselineDir = path2.resolve(deps.cwd, baselineRaw);
321
+ const candidateDir = path2.resolve(deps.cwd, candidateRaw);
322
+ let comparisonMd;
323
+ try {
324
+ const baseline = await readRunDir(baselineDir);
325
+ const candidate = await readRunDir(candidateDir);
326
+ const comparison = compareReports(baseline, candidate);
327
+ comparisonMd = renderComparisonMarkdown(comparison);
328
+ } catch (err) {
329
+ deps.renderer.writeError(`cannot compare runs: ${toErrorMessage(err)}`);
330
+ return 1;
331
+ }
332
+ const outRaw = flagStr(deps, "out");
333
+ const outFile = outRaw ? path2.resolve(deps.cwd, outRaw) : path2.join(candidateDir, "compare.md");
334
+ await fs.mkdir(path2.dirname(outFile), { recursive: true });
335
+ await fs.writeFile(outFile, comparisonMd, "utf8");
336
+ deps.renderer.write("\n" + comparisonMd + "\n");
337
+ deps.renderer.writeInfo(`Comparison written to ${outFile}`);
338
+ return 0;
339
+ }
206
340
  async function benchMine(args, deps) {
207
341
  const transcriptRaw = flagStr(deps, "transcript") ?? args.find((arg) => !arg.startsWith("-"));
208
342
  if (!transcriptRaw) {
@@ -214,8 +348,8 @@ async function benchMine(args, deps) {
214
348
  const outRaw = flagStr(deps, "out") ?? "evals";
215
349
  try {
216
350
  const mined = await mineTranscript({
217
- transcriptPath: path.resolve(deps.cwd, transcriptRaw),
218
- outDir: path.resolve(deps.cwd, outRaw)
351
+ transcriptPath: path2.resolve(deps.cwd, transcriptRaw),
352
+ outDir: path2.resolve(deps.cwd, outRaw)
219
353
  });
220
354
  deps.renderer.writeInfo(
221
355
  `Mined ${mined.candidates.length} edit attempt(s) from ${mined.sessionId}.`
@@ -234,18 +368,24 @@ async function benchMine(args, deps) {
234
368
  async function benchList(_args, deps) {
235
369
  deps.renderer.write(color.bold("Suites\n"));
236
370
  deps.renderer.write(
237
- " polyglot " + color.dim("Aider polyglot (edit accuracy) \u2014 Phase 1, Docker-free\n")
371
+ " core " + color.dim("Bundled 6-task agent-edit eval (hidden tests) \u2014 default for `bench run`\n")
238
372
  );
239
373
  deps.renderer.write(
240
- " swebench " + color.dim("SWE-bench Verified (end-to-end) \u2014 Phase 2, Docker-gated\n")
374
+ " smoke " + color.dim("3 trivial file edits \u2014 harness wiring only, not a quality score\n")
241
375
  );
242
376
  deps.renderer.write(
243
377
  " local " + color.dim("Project-defined manifest tasks with command/file graders\n")
244
378
  );
379
+ deps.renderer.write(
380
+ " polyglot " + color.dim("Aider polyglot (edit accuracy) \u2014 Docker-free, needs --polyglot-dir\n")
381
+ );
382
+ deps.renderer.write(
383
+ " swebench " + color.dim("SWE-bench Verified (end-to-end) \u2014 Docker-gated\n")
384
+ );
245
385
  const modelsPath = flagStr(deps, "models");
246
386
  if (modelsPath) {
247
387
  try {
248
- const config = await loadBenchConfig(path.resolve(deps.cwd, modelsPath));
388
+ const config = await loadBenchConfig2(path2.resolve(deps.cwd, modelsPath));
249
389
  deps.renderer.write("\n" + color.bold("Model cells\n"));
250
390
  for (const cell of config.cells) {
251
391
  deps.renderer.write(
@@ -274,4 +414,4 @@ async function benchList(_args, deps) {
274
414
  export {
275
415
  benchCmd
276
416
  };
277
- //# sourceMappingURL=bench-XYG56AMO.js.map
417
+ //# sourceMappingURL=bench-YBU6BVQP.js.map
@@ -12,16 +12,29 @@
12
12
  * The host wires this up once at boot and retains a reference to `brainLog`
13
13
  * (and indirectly `pushBrainLog`) for the duration of the session.
14
14
  */
15
+ import { type BrainTierStats } from '@wrongstack/core/coordination';
15
16
  type BrainDecisionKind = 'answered' | 'ask_human' | 'denied' | 'intervention' | 'council_warn';
16
17
  export interface BrainDecisionEntry {
17
18
  at: number;
18
19
  kind: BrainDecisionKind;
19
20
  question: string;
20
21
  outcome: string;
22
+ /**
23
+ * Which tier resolved the decision, as carried on the event.
24
+ *
25
+ * `/brain stats` groups the ring buffer by this field. It used to read a
26
+ * `tier` that nothing here ever wrote, so every decision counted as
27
+ * `unattributed` and the deterministic/model-backed split was permanently
28
+ * 0/0 — the whole provenance chain (`markDecisionTier` → the WeakMap →
29
+ * the `tier` field on `brain.decision_*`) terminated one step short of its
30
+ * only surface. Typed as a plain string: the CLI does not need to import
31
+ * the core union to bucket a label.
32
+ */
33
+ tier?: string | undefined;
21
34
  }
22
35
  /**
23
- * Subscribe to the four brain.* decision events and maintain a rolling
24
- * 20-entry ring buffer. Caller retains the returned `brainLog` array; the
36
+ * Subscribe to the brain.* decision events and maintain a rolling 20-entry
37
+ * ring buffer PLUS a session-lifetime per-tier tally. Caller retains the returned `brainLog` array; the
25
38
  * returned `pushBrainLog` lets external code (e.g. slash-command handlers)
26
39
  * append additional entries that should appear in /brain status.
27
40
  *
@@ -35,6 +48,13 @@ export interface BrainDecisionEntry {
35
48
  export declare function subscribeBrainDecisionLog(events: any): {
36
49
  brainLog: BrainDecisionEntry[];
37
50
  pushBrainLog: (entry: BrainDecisionEntry) => void;
51
+ /**
52
+ * Per-tier tally over the WHOLE session, not just the 20 entries the ring
53
+ * still holds. `/brain stats` is a "how often does the Brain burn a
54
+ * provider call" question, and a 20-decision window answers it for the
55
+ * last minute of a session that has been running for hours.
56
+ */
57
+ getTierStats: () => BrainTierStats;
38
58
  dispose: () => void;
39
59
  };
40
60
  export {};
@@ -4,7 +4,6 @@ import {
4
4
  import {
5
5
  activeProfileConfigPath
6
6
  } from "./chunk-YMXXOOFN.js";
7
- import "./chunk-7OCVIDC7.js";
8
7
 
9
8
  // src/boot/boot-auto-thin.ts
10
9
  import {
@@ -99,4 +98,4 @@ async function runBootAutoThin(deps) {
99
98
  export {
100
99
  runBootAutoThin
101
100
  };
102
- //# sourceMappingURL=boot-auto-thin-BZ675EVT.js.map
101
+ //# sourceMappingURL=boot-auto-thin-MANHOYHE.js.map
@@ -1,4 +1,3 @@
1
- import "./chunk-7OCVIDC7.js";
2
1
 
3
2
  // src/subcommands/handlers/chronicle.ts
4
3
  import { statSync } from "node:fs";
@@ -274,4 +273,4 @@ function tryStat(file) {
274
273
  export {
275
274
  chronicleCmd
276
275
  };
277
- //# sourceMappingURL=chronicle-6EPPMUC5.js.map
276
+ //# sourceMappingURL=chronicle-UTFETHP6.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  helpCmd,
3
3
  versionCmd
4
- } from "./chunk-QAC263FZ.js";
4
+ } from "./chunk-FPIWTJ2G.js";
5
5
  import {
6
6
  parseArgs
7
- } from "./chunk-GGGUZSAU.js";
7
+ } from "./chunk-Z7A5MXKJ.js";
8
8
 
9
9
  // src/boot/short-circuit-flags.ts
10
10
  async function handleHelpVersionShortCircuit(argv) {
@@ -22,11 +22,11 @@ async function handleHelpVersionShortCircuit(argv) {
22
22
  }
23
23
  if (earlyFlags["help"] === true) {
24
24
  if (positional.length > 0) {
25
- const { subcommandNames } = await import("./subcommands-J4JMWC5W.js");
25
+ const { subcommandNames } = await import("./subcommands-HZQKA4G2.js");
26
26
  if (subcommandNames.includes(positional[0])) {
27
27
  const first = positional[0];
28
28
  const deep = positional[1];
29
- const { renderDeepHelp, renderFocusedHelp } = await import("./per-subcommand-help-6VCIKDUW.js");
29
+ const { renderDeepHelp, renderFocusedHelp } = await import("./per-subcommand-help-BWBHYVJO.js");
30
30
  if (deep && renderDeepHelp(`${first}:${deep}`, stubRenderer)) {
31
31
  return 0;
32
32
  }
@@ -43,4 +43,4 @@ async function handleHelpVersionShortCircuit(argv) {
43
43
  export {
44
44
  handleHelpVersionShortCircuit
45
45
  };
46
- //# sourceMappingURL=chunk-VWCZL4OH.js.map
46
+ //# sourceMappingURL=chunk-4HV5RKZH.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  patchConfig
3
- } from "./chunk-TYO2OVAD.js";
3
+ } from "./chunk-EWKESL4L.js";
4
4
  import {
5
5
  PLUGIN_AUDIT_ENTRIES,
6
6
  loadExternalPlugins
7
- } from "./chunk-H7GABTGS.js";
7
+ } from "./chunk-TEBMCYZN.js";
8
8
 
9
9
  // src/wiring/plugins.ts
10
10
  import { join } from "node:path";
@@ -261,4 +261,4 @@ export {
261
261
  BUILTIN_PLUGIN_FACTORIES,
262
262
  setupPlugins
263
263
  };
264
- //# sourceMappingURL=chunk-42JD25KU.js.map
264
+ //# sourceMappingURL=chunk-5IA5337I.js.map