@wrongstack/cli 1.0.17 → 1.0.24

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 (125) hide show
  1. package/dist/{acp-INCNOH42.js → acp-AJWSKWE5.js} +18 -7
  2. package/dist/arg-parser.d.ts +1 -0
  3. package/dist/{auth-YXK3EDUL.js → auth-GRBZ7Y3D.js} +61 -15
  4. package/dist/auth-menu/direct.d.ts +1 -0
  5. package/dist/auth-menu/local.d.ts +2 -0
  6. package/dist/auth-menu/oauth-menu.d.ts +3 -1
  7. package/dist/auth-menu/panel-service.d.ts +20 -0
  8. package/dist/{bench-YBU6BVQP.js → bench-N5K7Z5O3.js} +2 -2
  9. package/dist/boot/config-backup-recovery.d.ts +2 -1
  10. package/dist/boot/dispatch-webui.d.ts +11 -0
  11. package/dist/boot/short-circuit-desktop.d.ts +1 -0
  12. package/dist/boot/tui-project-picker-callback.d.ts +1 -1
  13. package/dist/boot/tui-settings-adapter.d.ts +15 -2
  14. package/dist/{boot-auto-thin-MANHOYHE.js → boot-auto-thin-6Q56FY3F.js} +3 -2
  15. package/dist/{chunk-6WRKAACA.js → chunk-2BKFWIER.js} +4 -2
  16. package/dist/{chunk-JY52HWL6.js → chunk-2EBVTYJR.js} +2 -2
  17. package/dist/chunk-3OCUS3VN.js +46 -0
  18. package/dist/chunk-424ORSE7.js +56 -0
  19. package/dist/{chunk-KEPABQYT.js → chunk-5SEYGOCH.js} +8 -82
  20. package/dist/chunk-BBHWW6LR.js +549 -0
  21. package/dist/{chunk-CJTBLTS4.js → chunk-BLD5DSVA.js} +4 -3
  22. package/dist/{chunk-K5PAL6KR.js → chunk-DRM7PSW7.js} +75 -29
  23. package/dist/{chunk-XJ7K67PP.js → chunk-JF2MULWF.js} +17 -10
  24. package/dist/{chunk-SIS37L3W.js → chunk-L2RVEQWO.js} +211 -193
  25. package/dist/{chunk-RDHFXOJM.js → chunk-LFMVHT3R.js} +106 -57
  26. package/dist/chunk-LUMETJFO.js +171 -0
  27. package/dist/{chunk-C3Z4N6A6.js → chunk-MHEBWVXL.js} +6 -2
  28. package/dist/{chunk-VGER3HYZ.js → chunk-PGKJ2OQP.js} +5 -5
  29. package/dist/{chunk-672UXYL3.js → chunk-QBBF7GIK.js} +2 -2
  30. package/dist/{chunk-DE7BZDNK.js → chunk-QFPQXKCG.js} +11 -3
  31. package/dist/chunk-R4QGL6GB.js +10 -0
  32. package/dist/chunk-S4FFHDJG.js +93 -0
  33. package/dist/chunk-SFBFYIOW.js +271 -0
  34. package/dist/{chunk-JX6KL7OF.js → chunk-SKPDE62W.js} +4 -3
  35. package/dist/{chunk-RMQNCHGO.js → chunk-U46QR4WR.js} +5 -9
  36. package/dist/{chunk-B4JLSXZB.js → chunk-WSTVGC2C.js} +73 -45
  37. package/dist/chunk-YBUCXXYZ.js +36 -0
  38. package/dist/{chunk-2VMJ3E5Z.js → chunk-YTEOAWOJ.js} +6 -2
  39. package/dist/{chunk-GPPRNAKW.js → chunk-ZMX5HRLI.js} +2 -2
  40. package/dist/{chunk-YLQEGYV4.js → chunk-ZZRSG7VK.js} +14 -4
  41. package/dist/{cli-context-4PTWEK52.js → cli-context-34Q5IJRA.js} +121 -89
  42. package/dist/cli-entry-point.d.ts +2 -0
  43. package/dist/{cli-main-DQ2GBY7M.js → cli-main-AELJDBGU.js} +1471 -1293
  44. package/dist/config-doctor.d.ts +10 -2
  45. package/dist/{config-transfer-2YF3CRTN.js → config-transfer-RUWLDCNK.js} +34 -13
  46. package/dist/{diag-doctor-ANPRUYFM.js → diag-doctor-WIFJH3XH.js} +2 -2
  47. package/dist/execute-deps.d.ts +2 -1
  48. package/dist/{execution-A6WJLSOC.js → execution-PYC5FCS4.js} +303 -256
  49. package/dist/{hq-NU75W3SE.js → hq-JTUTFI4L.js} +274 -258
  50. package/dist/hq-command-controller.d.ts +1 -1
  51. package/dist/hq-server/project-root.d.ts +35 -1
  52. package/dist/{hq-server-M2JWVW4D.js → hq-server-PC7GZMPT.js} +2 -2
  53. package/dist/{hq-service-L5INQFM4.js → hq-service-NW56MUP2.js} +11 -4
  54. package/dist/index.d.ts +1 -1
  55. package/dist/index.js +17 -12
  56. package/dist/kanban-supervisor-67ECABTD.js +7 -0
  57. package/dist/live-settings-input.d.ts +7 -0
  58. package/dist/{mailbox-serve-3GFOK2I7.js → mailbox-serve-WDOCH6KR.js} +3 -3
  59. package/dist/{mcp-DC5WSBOO.js → mcp-LBS45HWZ.js} +4 -4
  60. package/dist/modeldiag-36OGAL5C.js +828 -0
  61. package/dist/{per-subcommand-help-DHTYU524.js → per-subcommand-help-XE77MTGJ.js} +3 -3
  62. package/dist/permission-prompt-mirror.d.ts +1 -1
  63. package/dist/permission-prompt.d.ts +2 -2
  64. package/dist/plugin-config.d.ts +12 -0
  65. package/dist/plugin-management-types.d.ts +31 -0
  66. package/dist/plugin-management.d.ts +2 -30
  67. package/dist/plugin-package-install.d.ts +3 -0
  68. package/dist/{plugin-usage-M6KET4OZ.js → plugin-usage-S5LVGMBW.js} +6 -5
  69. package/dist/{plugins-WJLW6ULV.js → plugins-RHBIVLI7.js} +4 -3
  70. package/dist/provider-config-utils.d.ts +1 -6
  71. package/dist/{providers-models-LFNZ5WI7.js → providers-models-2CFG46RD.js} +41 -31
  72. package/dist/release-asset-download.d.ts +3 -0
  73. package/dist/services/dispatch-classifier.d.ts +39 -5
  74. package/dist/{sessions-config-UL45XKX7.js → sessions-config-IQUH2GXT.js} +13 -5
  75. package/dist/settings-menu.d.ts +2 -0
  76. package/dist/short-circuit-flags-SDT53OML.js +10 -0
  77. package/dist/{simpleui-dist-CXSIDAXZ.js → simpleui-dist-7BQISSEP.js} +7 -3
  78. package/dist/skill-suggest-L2EVWB6R.js +290 -0
  79. package/dist/slash-commands/effort.d.ts +1 -1
  80. package/dist/slash-commands/fallback.d.ts +1 -1
  81. package/dist/slash-commands/gitid.d.ts +1 -1
  82. package/dist/slash-commands/jev.d.ts +4 -0
  83. package/dist/slash-commands/openai-quota.d.ts +15 -0
  84. package/dist/slash-commands/sdd-task-mutations.d.ts +4 -0
  85. package/dist/slash-commands/settings-keys.d.ts +2 -0
  86. package/dist/slash-commands/settings-reset.d.ts +6 -0
  87. package/dist/standalone-update-MW47J3AK.js +164 -0
  88. package/dist/standalone-update.d.ts +19 -0
  89. package/dist/subcommands/handlers/hq-alerts.d.ts +3 -0
  90. package/dist/subcommands/handlers/hq-audit.d.ts +46 -0
  91. package/dist/subcommands/handlers/hq-data-dir.d.ts +13 -0
  92. package/dist/subcommands/handlers/skill-suggest.d.ts +21 -0
  93. package/dist/subcommands/handlers/typesafe-brain-replay.d.ts +26 -0
  94. package/dist/subcommands/handlers/typesafe-judgment-check.d.ts +3 -0
  95. package/dist/subcommands/handlers/typesafe-topic-replay.d.ts +19 -0
  96. package/dist/subcommands/handlers/typesafe-triage-replay.d.ts +18 -0
  97. package/dist/subcommands/handlers/typesafe.d.ts +23 -0
  98. package/dist/{subcommands-ERDDIJ3L.js → subcommands-ZTSIN7LG.js} +2 -2
  99. package/dist/typesafe-HVEVPA6R.js +316 -0
  100. package/dist/typesafe-brain-replay-C5276FVR.js +222 -0
  101. package/dist/typesafe-judgment-check-GGYYV5UF.js +29 -0
  102. package/dist/typesafe-topic-replay-4W73BOLV.js +218 -0
  103. package/dist/typesafe-triage-replay-FGAW7QM7.js +215 -0
  104. package/dist/{update-5DPB4YD4.js → update-7XIOEXTD.js} +4 -3
  105. package/dist/{update-check-BS3DHTSI.js → update-check-2POMBHFB.js} +3 -2
  106. package/dist/update-check.d.ts +1 -1
  107. package/dist/version-help-WZ623NWM.js +10 -0
  108. package/dist/version.d.ts +3 -2
  109. package/dist/webui-client-observability.d.ts +7 -0
  110. package/dist/{webui-server-MRPGTTKL.js → webui-server-L2SICPTB.js} +158 -94
  111. package/dist/webui-server-options.d.ts +11 -0
  112. package/dist/webui-server.d.ts +15 -1
  113. package/dist/wiring/domain-glossary.d.ts +5 -4
  114. package/dist/wiring/plugins.d.ts +1 -1
  115. package/dist/wiring/provider-persisters.d.ts +24 -0
  116. package/dist/wiring/provider-runtime.d.ts +9 -1
  117. package/dist/wiring/runtime-dispatch-state.d.ts +3 -1
  118. package/package.json +28 -28
  119. package/dist/chunk-DR2OXU46.js +0 -174
  120. package/dist/chunk-JACOMTIH.js +0 -275
  121. package/dist/chunk-M4W3QLQW.js +0 -54
  122. package/dist/chunk-XJXDOF63.js +0 -28
  123. package/dist/modeldiag-CJSFHZ3J.js +0 -1356
  124. package/dist/short-circuit-flags-SJQBJ33I.js +0 -10
  125. package/dist/version-help-WXI42PZ3.js +0 -10
@@ -0,0 +1,290 @@
1
+
2
+ // src/subcommands/handlers/skill-suggest.ts
3
+ import * as fs from "node:fs/promises";
4
+ import * as path from "node:path";
5
+ import {
6
+ buildSuggesterFromConfig,
7
+ parseEvalJsonl,
8
+ scoreSuggestions,
9
+ sweepThresholds,
10
+ unknownGoldLabels
11
+ } from "@wrongstack/core/skills";
12
+ import { estimateTypeSafeCostUsd } from "@wrongstack/core/typesafe";
13
+ import { color } from "@wrongstack/core/utils";
14
+ var SWEEP_STEPS = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6];
15
+ var EVAL_WORKERS = 4;
16
+ var USAGE = [
17
+ "Usage:",
18
+ ' wstack skill-suggest "<request>" preview one request',
19
+ " wstack skill-suggest --eval <file.jsonl> score a labeled set",
20
+ " wstack skill-suggest --eval <file.jsonl> --sweep \u2026and sweep thresholds",
21
+ "",
22
+ "Eval file: one JSON object per line.",
23
+ ' {"text": "cut a release branch for 1.2.0", "gold": "git-flow"}',
24
+ ' {"text": "explain what a monad is"} // nothing covers it',
25
+ "",
26
+ "Both modes send request text to the configured TypeSafe/OpenRouter route.",
27
+ "Configure its key with `wstack typesafe login` and verify with `wstack typesafe test`."
28
+ ].join("\n");
29
+ var skillSuggestCmd = async (args, deps) => {
30
+ const write = (line) => deps.renderer.write(`${line}
31
+ `);
32
+ const flags = deps.flags ?? {};
33
+ const evalFile = typeof flags["eval"] === "string" ? flags["eval"] : void 0;
34
+ const sweep = flags["sweep"] === true || flags["sweep"] === "true";
35
+ const positional = args.filter((a) => !a.startsWith("-"));
36
+ if (flags["help"] === true || flags["h"] === true) {
37
+ write(USAGE);
38
+ return 0;
39
+ }
40
+ if (!evalFile && positional.length === 0) {
41
+ write(USAGE);
42
+ return 1;
43
+ }
44
+ const built = buildSuggesterFromConfig({
45
+ config: deps.config,
46
+ skillLoader: deps.skillLoader
47
+ });
48
+ if ("error" in built) {
49
+ write(color.red(`skill-suggest: ${built.error}`));
50
+ return 1;
51
+ }
52
+ const { suggester } = built;
53
+ if (evalFile) {
54
+ return runEval({
55
+ file: path.resolve(deps.cwd, evalFile),
56
+ sweep,
57
+ suggester,
58
+ rosterNames: (await deps.skillLoader?.list())?.map((s) => s.name) ?? [],
59
+ write
60
+ });
61
+ }
62
+ const request = positional.join(" ").trim();
63
+ if (!request) {
64
+ write(color.red("skill-suggest: give a request to preview, or --eval <file>"));
65
+ return 1;
66
+ }
67
+ return runPreview({ request, suggester, write, config: deps.config });
68
+ };
69
+ async function runPreview(input) {
70
+ const { write } = input;
71
+ const gateThreshold = input.config.skills?.suggest?.gateThreshold ?? 0.3;
72
+ const fitsThreshold = input.config.skills?.suggest?.fitsThreshold ?? 0.3;
73
+ const started = Date.now();
74
+ const trace = await input.suggester.explain(input.request);
75
+ const elapsed = Date.now() - started;
76
+ write("");
77
+ write(color.dim(` "${truncate(input.request, 72)}"`));
78
+ write("");
79
+ if (trace.stop === "error") {
80
+ write(color.red(" the suggester failed \u2014 no answer to show"));
81
+ write(color.dim(" check the API key, the endpoint, and network reachability"));
82
+ return 1;
83
+ }
84
+ if (trace.stop === "roster-too-small") {
85
+ write(color.yellow(" roster has fewer than 2 visible skills \u2014 nothing to choose between"));
86
+ return 0;
87
+ }
88
+ write(
89
+ ` ${label("gate")} ${bar(trace.gate)} ${pct(trace.gate)} ${verdictWord(trace.gate >= gateThreshold, gateThreshold)}`
90
+ );
91
+ for (const [key, value] of Object.entries(trace.gateValues)) {
92
+ const inverted = key === "prose_suffices";
93
+ write(
94
+ color.dim(` ${key.padEnd(34)} ${pct(value)}${inverted ? " (counts inverted)" : ""}`)
95
+ );
96
+ }
97
+ write("");
98
+ if (trace.ranked.length > 0) {
99
+ write(` ${label("pass 1 \u2014 ranked")}`);
100
+ for (const entry of trace.ranked.slice(0, 5)) {
101
+ const shortlisted = trace.shortlist.includes(entry.name);
102
+ const line = ` ${pct(entry.probability).padStart(4)} ${entry.name}`;
103
+ write(shortlisted ? line : color.dim(line));
104
+ }
105
+ write("");
106
+ }
107
+ if (trace.shortlist.length > 0 && Object.keys(trace.fits).length > 0) {
108
+ write(` ${label("pass 2 \u2014 fits")}`);
109
+ for (const name of trace.shortlist) {
110
+ const value = trace.fits[name];
111
+ const marker = name === trace.winner ? color.cyan(" \u2190 choice") : "";
112
+ write(` ${(value === void 0 ? "\u2014" : pct(value)).padStart(4)} ${name}${marker}`);
113
+ }
114
+ write("");
115
+ }
116
+ const suggestion = trace.suggestion;
117
+ if (suggestion) {
118
+ write(` ${color.green("suggests")} ${suggestion.name}`);
119
+ } else {
120
+ write(
121
+ ` ${color.yellow("suggests nothing")} ${color.dim(`(${stopReason(trace, gateThreshold, fitsThreshold)})`)}`
122
+ );
123
+ }
124
+ write(
125
+ color.dim(
126
+ ` ${trace.requests} request(s), ${elapsed}ms, ${trace.inputTokens} input tokens (~$${estimateTypeSafeCostUsd(trace.inputTokens).toFixed(6)})` + (trace.models.length > 0 ? ` \xB7 answered by ${trace.models.join(", ")}` : "")
127
+ )
128
+ );
129
+ write("");
130
+ return 0;
131
+ }
132
+ function stopReason(trace, gateThreshold, fitsThreshold) {
133
+ switch (trace.stop) {
134
+ case "gate":
135
+ return `gate ${pct(trace.gate)} below ${pct(gateThreshold)}`;
136
+ case "fits": {
137
+ const best = Math.max(...Object.values(trace.fits), 0);
138
+ return `best fit ${pct(best)} below ${pct(fitsThreshold)}`;
139
+ }
140
+ case "wide-failed":
141
+ case "rerank-failed":
142
+ return "the model returned no usable answer for that pass";
143
+ default:
144
+ return trace.stop;
145
+ }
146
+ }
147
+ async function runEval(input) {
148
+ const { write } = input;
149
+ let source;
150
+ try {
151
+ source = await fs.readFile(input.file, "utf8");
152
+ } catch {
153
+ write(color.red(`skill-suggest: cannot read ${input.file}`));
154
+ return 1;
155
+ }
156
+ const { requests, errors } = parseEvalJsonl(source);
157
+ for (const error of errors) {
158
+ write(color.yellow(` line ${error.line}: ${error.reason}`));
159
+ }
160
+ if (requests.length === 0) {
161
+ write(color.red("skill-suggest: no usable cases in that file"));
162
+ return 1;
163
+ }
164
+ const unknown = unknownGoldLabels(requests, input.rosterNames);
165
+ if (unknown.length > 0) {
166
+ write(color.yellow(` gold labels not in this roster: ${unknown.join(", ")}`));
167
+ write(color.yellow(" those cases can never be scored correct \u2014 fix or remove them"));
168
+ write("");
169
+ }
170
+ const covered = requests.filter((r) => r.gold).length;
171
+ write(
172
+ color.dim(
173
+ ` ${requests.length} cases (${covered} covered, ${requests.length - covered} uncovered) \u2192 up to ${requests.length * 2} TypeSafe requests`
174
+ )
175
+ );
176
+ write("");
177
+ const traces = await mapWithConcurrency(requests, EVAL_WORKERS, async (request) => ({
178
+ request,
179
+ // A sweep has to know what pass 2 WOULD have said below the configured
180
+ // gate, and a trace that stopped at the gate cannot answer that.
181
+ trace: await input.suggester.explain(request.text, void 0, { alwaysRerank: input.sweep })
182
+ }));
183
+ const inputTokens = traces.reduce((sum, row) => sum + row.trace.inputTokens, 0);
184
+ const models = [...new Set(traces.flatMap((row) => row.trace.models))];
185
+ write(
186
+ color.dim(
187
+ ` spent ${inputTokens} input tokens (~$${estimateTypeSafeCostUsd(inputTokens).toFixed(4)})` + (models.length > 0 ? ` \xB7 answered by ${models.join(", ")}` : "")
188
+ )
189
+ );
190
+ if (models.length > 1) {
191
+ write(
192
+ color.yellow(
193
+ " Two model versions answered this run \u2014 the alias moved mid-run; re-run before trusting the sweep."
194
+ )
195
+ );
196
+ }
197
+ write("");
198
+ const failed = traces.filter((row) => row.trace.stop === "error").length;
199
+ if (failed > 0) {
200
+ write(color.yellow(` ${failed} case(s) failed outright and count as "suggested nothing"`));
201
+ write("");
202
+ }
203
+ const byText = new Map(traces.map((row) => [row.request.text, row.trace]));
204
+ const { score, cases } = scoreSuggestions(
205
+ requests,
206
+ (request) => byText.get(request.text)?.suggestion?.name
207
+ );
208
+ writeScore(write, score);
209
+ const misses = cases.filter((c) => c.outcome === "wrong" || c.outcome === "needless");
210
+ if (misses.length > 0) {
211
+ write("");
212
+ write(` ${label("worst cases")}`);
213
+ for (const miss of misses.slice(0, 10)) {
214
+ const wanted = miss.request.gold ?? "(nothing)";
215
+ write(color.dim(` "${truncate(miss.request.text, 52)}"`));
216
+ write(` wanted ${wanted}, got ${color.red(miss.suggested ?? "(nothing)")}`);
217
+ }
218
+ if (misses.length > 10) write(color.dim(` \u2026and ${misses.length - 10} more`));
219
+ }
220
+ if (input.sweep) {
221
+ write("");
222
+ write(` ${label("threshold sweep")}`);
223
+ write(
224
+ color.dim(" gate fits correct wrong missed needless (of covered / uncovered)")
225
+ );
226
+ const rows = sweepThresholds(traces, SWEEP_STEPS, SWEEP_STEPS);
227
+ for (const row of rows) {
228
+ const s = row.score;
229
+ write(
230
+ ` ${row.gateThreshold.toFixed(1)} ${row.fitsThreshold.toFixed(1)} ${pct(s.correct).padStart(6)} ${pct(s.wrongSuggestion).padStart(6)} ${pct(s.missed).padStart(6)} ${pct(s.needless).padStart(8)}`
231
+ );
232
+ }
233
+ write("");
234
+ write(
235
+ color.dim(
236
+ " These score the SUGGESTER against your labels, not what the agent then loads."
237
+ )
238
+ );
239
+ write(
240
+ color.dim(
241
+ " Raising gate cuts needless suggestions and adds misses. Pick the one that costs you more."
242
+ )
243
+ );
244
+ }
245
+ write("");
246
+ return 0;
247
+ }
248
+ function writeScore(write, score) {
249
+ write(` ${label("covered")} ${color.dim(`(${score.covered} cases)`)}`);
250
+ write(` correct ${pct(score.correct)}`);
251
+ write(` wrong suggestion ${pct(score.wrongSuggestion)}`);
252
+ write(` suggested nothing ${pct(score.missed)}`);
253
+ write(` ${label("uncovered")} ${color.dim(`(${score.uncovered} cases)`)}`);
254
+ write(` needless ${pct(score.needless)}`);
255
+ }
256
+ async function mapWithConcurrency(items, limit, fn) {
257
+ const results = new Array(items.length);
258
+ let cursor = 0;
259
+ const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {
260
+ for (; ; ) {
261
+ const index = cursor++;
262
+ const item = items[index];
263
+ if (item === void 0) return;
264
+ results[index] = await fn(item);
265
+ }
266
+ });
267
+ await Promise.all(workers);
268
+ return results;
269
+ }
270
+ function pct(value) {
271
+ return `${(value * 100).toFixed(0)}%`;
272
+ }
273
+ function bar(value) {
274
+ const filled = Math.round(value * 10);
275
+ return color.dim(`[${"#".repeat(filled)}${".".repeat(10 - filled)}]`);
276
+ }
277
+ function label(text) {
278
+ return color.bold(text);
279
+ }
280
+ function verdictWord(passed, threshold) {
281
+ return passed ? color.green(`\u2265 ${pct(threshold)} \u2014 continue`) : color.yellow(`< ${pct(threshold)} \u2014 stop here`);
282
+ }
283
+ function truncate(text, max) {
284
+ const flat = text.replace(/\s+/g, " ").trim();
285
+ return flat.length <= max ? flat : `${flat.slice(0, max - 1)}\u2026`;
286
+ }
287
+ export {
288
+ skillSuggestCmd
289
+ };
290
+ //# sourceMappingURL=skill-suggest-L2EVWB6R.js.map
@@ -1,6 +1,6 @@
1
1
  import { type ReasoningEffort, type SlashCommand } from '@wrongstack/core/types';
2
- import type { SlashCommandContext } from './command-context.js';
3
2
  import type { WstackPaths } from '@wrongstack/core/utils';
3
+ import type { SlashCommandContext } from './command-context.js';
4
4
  /**
5
5
  * `/effort` — view or set the SESSION-WIDE reasoning effort applied to the
6
6
  * active leader model. This is the quick, discoverable front-end for
@@ -1,4 +1,4 @@
1
- import { type SlashCommand } from '@wrongstack/core/types';
1
+ import type { SlashCommand } from '@wrongstack/core/types';
2
2
  import type { SlashCommandContext } from './command-context.js';
3
3
  /**
4
4
  * `/fallback` — view or change the cross-provider fallback chain that the
@@ -1,4 +1,4 @@
1
- import { type SlashCommand } from '@wrongstack/core/types';
1
+ import type { SlashCommand } from '@wrongstack/core/types';
2
2
  import type { SlashCommandContext } from './command-context.js';
3
3
  /**
4
4
  * `/gitid` — view or change the commit identity (author/committer name +
@@ -0,0 +1,4 @@
1
+ import type { SlashCommand } from '@wrongstack/core/types';
2
+ import type { SlashCommandContext } from './command-context.js';
3
+ export declare function buildJevCommand(opts: SlashCommandContext): SlashCommand;
4
+ //# sourceMappingURL=jev.d.ts.map
@@ -28,4 +28,19 @@ import type { SlashCommand } from '@wrongstack/core/types';
28
28
  */
29
29
  export declare function renderQuotaSnapshot(snapshot: ProviderQuotaSnapshot): string[];
30
30
  export declare function buildOpenAIQuotaCommand(): SlashCommand;
31
+ /**
32
+ * `/provider-quota` — every metered subscription this session has heard from.
33
+ *
34
+ * The narrow `/openai-quota` above stays because it answers one question
35
+ * without making the user read past other providers; this one exists because
36
+ * the reporters are no longer Codex-only. Claude Pro/Max and GitHub Copilot
37
+ * report into the same store, and a session that is signed into two metered
38
+ * plans has no other way to see which one is about to run out.
39
+ *
40
+ * The name says `provider` on purpose. A bare `/quota` would read as "what
41
+ * this project costs" — an account-wide spend view that does not exist here —
42
+ * and would occupy the name if one is ever built. What this shows is exactly
43
+ * the provider plane's readings, so that is what it is called.
44
+ */
45
+ export declare function buildProviderQuotaCommand(): SlashCommand;
31
46
  //# sourceMappingURL=openai-quota.d.ts.map
@@ -0,0 +1,4 @@
1
+ export declare function executeSddTaskMutation(cmd: string, restJoined: string): {
2
+ message: string;
3
+ };
4
+ //# sourceMappingURL=sdd-task-mutations.d.ts.map
@@ -0,0 +1,2 @@
1
+ export declare const ALL_SETTINGS_KEYS: string[];
2
+ //# sourceMappingURL=settings-keys.d.ts.map
@@ -0,0 +1,6 @@
1
+ import { persistConfigSetting } from '../settings-menu.js';
2
+ import type { SlashCommandContext } from './command-context.js';
3
+ export declare function executeSettingsReset(rest: string[], persistDeps: Parameters<typeof persistConfigSetting>[0], opts: SlashCommandContext, profileName: string): Promise<{
4
+ message: string;
5
+ }>;
6
+ //# sourceMappingURL=settings-reset.d.ts.map
@@ -0,0 +1,164 @@
1
+ import {
2
+ STANDALONE_TARGET
3
+ } from "./chunk-YBUCXXYZ.js";
4
+
5
+ // src/standalone-update.ts
6
+ import { createHash } from "node:crypto";
7
+ import * as fs from "node:fs";
8
+ import * as path from "node:path";
9
+ import { FetchError } from "@wrongstack/core/types";
10
+
11
+ // src/release-asset-download.ts
12
+ async function downloadReleaseAsset(url, timeoutMs, maxBytes) {
13
+ const res = await fetch(url, {
14
+ signal: AbortSignal.timeout(timeoutMs),
15
+ headers: { "User-Agent": "wrongstack-cli" },
16
+ redirect: "follow"
17
+ });
18
+ if (!res.ok) throw new Error(`download ${url} responded ${res.status}`);
19
+ const declared = Number(res.headers.get("content-length") ?? "0");
20
+ if (declared > maxBytes) throw new Error(`download ${url} is too large`);
21
+ if (!res.body) return Buffer.alloc(0);
22
+ const chunks = [];
23
+ let received = 0;
24
+ const reader = res.body.getReader();
25
+ try {
26
+ while (true) {
27
+ const { done, value } = await reader.read();
28
+ if (done) break;
29
+ received += value.byteLength;
30
+ if (received > maxBytes) {
31
+ await reader.cancel();
32
+ throw new Error(`download ${url} is too large`);
33
+ }
34
+ chunks.push(Buffer.from(value.buffer, value.byteOffset, value.byteLength));
35
+ }
36
+ } finally {
37
+ reader.releaseLock();
38
+ }
39
+ return Buffer.concat(chunks, received);
40
+ }
41
+
42
+ // src/standalone-update.ts
43
+ var RELEASES_REPO = "WrongStack/WrongStack";
44
+ var API_LATEST = `https://api.github.com/repos/${RELEASES_REPO}/releases/latest`;
45
+ var MAX_BINARY_BYTES = 512 * 1024 * 1024;
46
+ var MAX_CHECKSUM_BYTES = 1024 * 1024;
47
+ function standaloneAssetName(target) {
48
+ const name = `wstack-${target.replace(/^bun-/, "")}`;
49
+ return target.startsWith("bun-windows") ? `${name}.exe` : name;
50
+ }
51
+ async function fetchLatestRelease(timeoutMs, signal) {
52
+ const timeoutSignal = AbortSignal.timeout(timeoutMs);
53
+ const res = await fetch(API_LATEST, {
54
+ signal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal,
55
+ headers: { Accept: "application/vnd.github+json", "User-Agent": "wrongstack-cli" }
56
+ });
57
+ if (!res.ok) {
58
+ throw new FetchError({
59
+ message: `GitHub releases responded ${res.status}`,
60
+ status: res.status,
61
+ context: { op: "checkForUpdate", registry: "github-releases", url: API_LATEST }
62
+ });
63
+ }
64
+ const data = await res.json();
65
+ if (typeof data.tag_name !== "string") throw new Error("Latest release has no tag");
66
+ const assets = Array.isArray(data.assets) ? data.assets.filter(
67
+ (a) => typeof a?.name === "string" && typeof a?.browser_download_url === "string"
68
+ ) : [];
69
+ return { version: data.tag_name.replace(/^v/, ""), assets };
70
+ }
71
+ async function fetchLatestStandaloneVersion(timeoutMs = 3e3, signal) {
72
+ return (await fetchLatestRelease(timeoutMs, signal)).version;
73
+ }
74
+ function parseSha256Sums(text) {
75
+ const sums = /* @__PURE__ */ new Map();
76
+ for (const line of text.split(/\r?\n/)) {
77
+ const match = line.trim().match(/^([0-9a-f]{64})\s+\*?(.+)$/i);
78
+ if (match?.[1] && match[2]) {
79
+ const name = match[2].trim();
80
+ if (sums.has(name)) throw new Error(`Duplicate SHA256SUMS entry: ${name}`);
81
+ sums.set(name, match[1].toLowerCase());
82
+ }
83
+ }
84
+ return sums;
85
+ }
86
+ function replaceExecutable(target, bytes, platform = process.platform) {
87
+ const staged = `${target}.new-${process.pid}`;
88
+ fs.writeFileSync(staged, bytes, { mode: 493 });
89
+ try {
90
+ if (platform === "win32") {
91
+ const aside = `${target}.old`;
92
+ fs.rmSync(aside, { force: true });
93
+ fs.renameSync(target, aside);
94
+ try {
95
+ fs.renameSync(staged, target);
96
+ } catch (error) {
97
+ fs.renameSync(aside, target);
98
+ throw error;
99
+ }
100
+ } else {
101
+ fs.renameSync(staged, target);
102
+ }
103
+ } finally {
104
+ fs.rmSync(staged, { force: true });
105
+ }
106
+ }
107
+ async function updateStandaloneBinary(options) {
108
+ const { renderer } = options;
109
+ if (!STANDALONE_TARGET) {
110
+ renderer.write("Update failed: this executable does not record its build target.\n");
111
+ return 1;
112
+ }
113
+ const assetName = standaloneAssetName(STANDALONE_TARGET);
114
+ try {
115
+ const release = await fetchLatestRelease(15e3);
116
+ const asset = release.assets.find((a) => a.name === assetName);
117
+ const sumsAsset = release.assets.find((a) => a.name === "SHA256SUMS");
118
+ if (!asset || !sumsAsset) {
119
+ renderer.write(`Update failed: release v${release.version} has no ${assetName} build.
120
+ `);
121
+ return 1;
122
+ }
123
+ renderer.write(`Updating wrongstack from v${options.current} to v${release.version}...
124
+ `);
125
+ renderer.write(`Downloading ${assetName}
126
+ `);
127
+ const [bytes, sumsText] = await Promise.all([
128
+ downloadReleaseAsset(asset.browser_download_url, 6e5, MAX_BINARY_BYTES),
129
+ downloadReleaseAsset(sumsAsset.browser_download_url, 3e4, MAX_CHECKSUM_BYTES).then(
130
+ (b) => b.toString("utf8")
131
+ )
132
+ ]);
133
+ const expected = parseSha256Sums(sumsText).get(assetName);
134
+ const actual = createHash("sha256").update(bytes).digest("hex");
135
+ if (!expected || expected !== actual) {
136
+ renderer.write("Update failed: checksum does not match the release SHA256SUMS.\n");
137
+ return 1;
138
+ }
139
+ const executable = fs.realpathSync(process.execPath);
140
+ replaceExecutable(executable, bytes);
141
+ renderer.write(
142
+ `
143
+ Updated ${path.basename(executable)} to v${release.version}. Restart wrongstack to use it.
144
+ `
145
+ );
146
+ return 0;
147
+ } catch (err) {
148
+ const msg = err instanceof Error ? err.message : String(err);
149
+ const permission = /EACCES|EPERM/.test(msg) ? "\nThe executable is not writable by this user; rerun with the permissions it was installed with." : "";
150
+ renderer.write(`
151
+ Update failed: ${msg}${permission}
152
+ `);
153
+ return 1;
154
+ }
155
+ }
156
+ export {
157
+ RELEASES_REPO,
158
+ fetchLatestStandaloneVersion,
159
+ parseSha256Sums,
160
+ replaceExecutable,
161
+ standaloneAssetName,
162
+ updateStandaloneBinary
163
+ };
164
+ //# sourceMappingURL=standalone-update-MW47J3AK.js.map
@@ -0,0 +1,19 @@
1
+ import type { TerminalRenderer } from './renderer.js';
2
+ export declare const RELEASES_REPO = "WrongStack/WrongStack";
3
+ /** Asset name a build target publishes under (mirrors build-binaries.mjs `outputName`). */
4
+ export declare function standaloneAssetName(target: string): string;
5
+ /** Latest released version, for the update check. */
6
+ export declare function fetchLatestStandaloneVersion(timeoutMs?: number, signal?: AbortSignal): Promise<string>;
7
+ /** `<sha256> <name>` lines → map. */
8
+ export declare function parseSha256Sums(text: string): Map<string, string>;
9
+ /**
10
+ * Replace `target` with `bytes`. Staged next to the target so the final step
11
+ * is a same-filesystem rename.
12
+ */
13
+ export declare function replaceExecutable(target: string, bytes: Buffer, platform?: NodeJS.Platform): void;
14
+ /** `wstack update` for the standalone binary. Returns the process exit code. */
15
+ export declare function updateStandaloneBinary(options: {
16
+ current: string;
17
+ renderer: Pick<TerminalRenderer, 'write'>;
18
+ }): Promise<number>;
19
+ //# sourceMappingURL=standalone-update.d.ts.map
@@ -0,0 +1,3 @@
1
+ import type { SubcommandDeps } from '../contracts.js';
2
+ export declare function hqAlertsCmd(args: string[], deps: SubcommandDeps): Promise<number>;
3
+ //# sourceMappingURL=hq-alerts.d.ts.map
@@ -0,0 +1,46 @@
1
+ import type { SubcommandDeps } from '../contracts.js';
2
+ /**
3
+ * `wstack hq audit verify` — re-derive the contentHash from the current
4
+ * on-disk `auth.json` and print it so an operator can compare against a
5
+ * `contentHash` field in an audit entry. This closes the forensic
6
+ * tie-back loop without requiring the operator to write a script: copy
7
+ * the hash from the audit log, run this command, eyeball (or `diff`)
8
+ * the two values.
9
+ *
10
+ * Prints:
11
+ * - the resolved `auth.json` path (so the operator knows which file
12
+ * was hashed)
13
+ * - the SHA-256 contentHash, or `(unavailable)` if the file is
14
+ * missing/unreadable
15
+ * - the `auth-audit.jsonl` path (so the operator knows where to look
16
+ * for entries to compare against)
17
+ *
18
+ * Exit codes:
19
+ * 0 — hash computed and printed
20
+ * 1 — `auth.json` missing or unreadable (hash unavailable); the
21
+ * audit-log path is still printed so the operator can inspect
22
+ * historical entries
23
+ */
24
+ export declare function hqAuditCmd(args: string[], deps: SubcommandDeps): Promise<number>;
25
+ /**
26
+ * Re-read the persisted `auth.json` and return a conditional
27
+ * `contentHash` field for embedding in an audit entry. This closes the
28
+ * forensic tie-back loop: an operator reviewing `auth-audit.jsonl` can
29
+ * compare the `contentHash` against the current on-disk file via
30
+ * `wstack hq audit verify`.
31
+ *
32
+ * Re-reads rather than hashing the in-memory post-mutation snapshot
33
+ * because `writeHqAuthFile` re-stamps `updatedAt` on the persisted
34
+ * payload — hashing the in-memory `next` would diverge from what
35
+ * `verify` computes. Matches the pattern established by the `first-run`
36
+ * and `expired-prune` emitters in `auth-store.ts` / `hq-server.ts`.
37
+ *
38
+ * Returns `{}` (no `contentHash` key) when the file is unreadable, so
39
+ * the audit entry still records the event without a tie-back — the
40
+ * absence itself is meaningful. Conditional spread preserves
41
+ * `exactOptionalPropertyTypes`.
42
+ */
43
+ export declare function computeAuditHashField(dataDir: string, warn: (msg: string) => void): Promise<{
44
+ contentHash?: string;
45
+ }>;
46
+ //# sourceMappingURL=hq-audit.d.ts.map
@@ -0,0 +1,13 @@
1
+ import type { SubcommandDeps } from '../contracts.js';
2
+ /**
3
+ * Build a free-form actor string for the auth audit log. Combines the OS
4
+ * username (best-effort) with the hostname so an operator reviewing the
5
+ * log can see "who minted this token" without parsing environment
6
+ * variables. Never includes the token string.
7
+ *
8
+ * Shared by the `wstack hq token` create/revoke handlers and by
9
+ * `startHqServer`'s first-run bootstrap so every audit entry point
10
+ * produces the same actor shape.
11
+ */
12
+ export declare function resolveDataDir(deps: SubcommandDeps): string;
13
+ //# sourceMappingURL=hq-data-dir.d.ts.map
@@ -0,0 +1,21 @@
1
+ /**
2
+ * `wstack skill-suggest` — inspect and tune the TypeSafe skill suggester.
3
+ *
4
+ * The suggester runs inside a turn and its output is one line of system prompt,
5
+ * which makes it almost impossible to observe in place: you see the agent load
6
+ * a skill, not why. Two modes make it inspectable:
7
+ *
8
+ * wstack skill-suggest "<request>" one request, both passes, all numbers
9
+ * wstack skill-suggest --eval cases.jsonl labeled set, scored
10
+ * wstack skill-suggest --eval cases.jsonl --sweep …plus a threshold table
11
+ *
12
+ * Both work whether or not `skills.suggest.enabled` is on — previewing is how
13
+ * you decide whether to turn it on. Both need a TypeSafe API key, and both send
14
+ * request text to TypeSafe, so `--eval` prints what it is about to spend before
15
+ * it spends it.
16
+ */
17
+ import { type LabeledRequest, type ScoredCase } from '@wrongstack/core/skills';
18
+ import type { SubcommandHandler } from '../contracts.js';
19
+ export declare const skillSuggestCmd: SubcommandHandler;
20
+ export type { LabeledRequest, ScoredCase };
21
+ //# sourceMappingURL=skill-suggest.d.ts.map
@@ -0,0 +1,26 @@
1
+ /**
2
+ * `wstack typesafe replay-brain-ledger` — calibrate the Brain's System One
3
+ * tier on decisions this project already made.
4
+ *
5
+ * The Brain ledger records every decision (question, chosen option, which tier
6
+ * or council settled it) and, for interventions, whether the same signal fired
7
+ * again afterwards. It does not record the option list or the full context —
8
+ * but the BrainMonitor signals (file churn, tool-failure streak, stall, error
9
+ * storm) always ask the same steer/continue question with a context the
10
+ * question text already carries, so those requests can be rebuilt exactly.
11
+ *
12
+ * Each rebuilt request goes through `probeSystemOneBrain` (the tier's real
13
+ * questions, no thresholds), and the report compares Jev's pick with the
14
+ * recorded one: overall agreement, how much the current thresholds would
15
+ * settle and how often those settled picks agree, a threshold sweep, and how
16
+ * often Jev said `continue` on a steer the ledger shows was futile (the same
17
+ * signal re-fired).
18
+ *
19
+ * The recorded pick is a reference, not ground truth: most were made by the
20
+ * council or a policy, and the outcome record only exists for steers. The
21
+ * decision digest the live tier sees is omitted — rebuilding it from the
22
+ * ledger would leak later outcomes into earlier decisions.
23
+ */
24
+ import type { SubcommandDeps } from '../contracts.js';
25
+ export declare function replayBrainLedger(deps: SubcommandDeps, write: (line: string) => void): Promise<number>;
26
+ //# sourceMappingURL=typesafe-brain-replay.d.ts.map
@@ -0,0 +1,3 @@
1
+ import type { SubcommandDeps } from '../contracts.js';
2
+ export declare function checkJudgments(deps: SubcommandDeps, write: (line: string) => void): Promise<number>;
3
+ //# sourceMappingURL=typesafe-judgment-check.d.ts.map