@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.
- package/dist/{acp-INCNOH42.js → acp-AJWSKWE5.js} +18 -7
- package/dist/arg-parser.d.ts +1 -0
- package/dist/{auth-YXK3EDUL.js → auth-GRBZ7Y3D.js} +61 -15
- package/dist/auth-menu/direct.d.ts +1 -0
- package/dist/auth-menu/local.d.ts +2 -0
- package/dist/auth-menu/oauth-menu.d.ts +3 -1
- package/dist/auth-menu/panel-service.d.ts +20 -0
- package/dist/{bench-YBU6BVQP.js → bench-N5K7Z5O3.js} +2 -2
- package/dist/boot/config-backup-recovery.d.ts +2 -1
- package/dist/boot/dispatch-webui.d.ts +11 -0
- package/dist/boot/short-circuit-desktop.d.ts +1 -0
- package/dist/boot/tui-project-picker-callback.d.ts +1 -1
- package/dist/boot/tui-settings-adapter.d.ts +15 -2
- package/dist/{boot-auto-thin-MANHOYHE.js → boot-auto-thin-6Q56FY3F.js} +3 -2
- package/dist/{chunk-6WRKAACA.js → chunk-2BKFWIER.js} +4 -2
- package/dist/{chunk-JY52HWL6.js → chunk-2EBVTYJR.js} +2 -2
- package/dist/chunk-3OCUS3VN.js +46 -0
- package/dist/chunk-424ORSE7.js +56 -0
- package/dist/{chunk-KEPABQYT.js → chunk-5SEYGOCH.js} +8 -82
- package/dist/chunk-BBHWW6LR.js +549 -0
- package/dist/{chunk-CJTBLTS4.js → chunk-BLD5DSVA.js} +4 -3
- package/dist/{chunk-K5PAL6KR.js → chunk-DRM7PSW7.js} +75 -29
- package/dist/{chunk-XJ7K67PP.js → chunk-JF2MULWF.js} +17 -10
- package/dist/{chunk-SIS37L3W.js → chunk-L2RVEQWO.js} +211 -193
- package/dist/{chunk-RDHFXOJM.js → chunk-LFMVHT3R.js} +106 -57
- package/dist/chunk-LUMETJFO.js +171 -0
- package/dist/{chunk-C3Z4N6A6.js → chunk-MHEBWVXL.js} +6 -2
- package/dist/{chunk-VGER3HYZ.js → chunk-PGKJ2OQP.js} +5 -5
- package/dist/{chunk-672UXYL3.js → chunk-QBBF7GIK.js} +2 -2
- package/dist/{chunk-DE7BZDNK.js → chunk-QFPQXKCG.js} +11 -3
- package/dist/chunk-R4QGL6GB.js +10 -0
- package/dist/chunk-S4FFHDJG.js +93 -0
- package/dist/chunk-SFBFYIOW.js +271 -0
- package/dist/{chunk-JX6KL7OF.js → chunk-SKPDE62W.js} +4 -3
- package/dist/{chunk-RMQNCHGO.js → chunk-U46QR4WR.js} +5 -9
- package/dist/{chunk-B4JLSXZB.js → chunk-WSTVGC2C.js} +73 -45
- package/dist/chunk-YBUCXXYZ.js +36 -0
- package/dist/{chunk-2VMJ3E5Z.js → chunk-YTEOAWOJ.js} +6 -2
- package/dist/{chunk-GPPRNAKW.js → chunk-ZMX5HRLI.js} +2 -2
- package/dist/{chunk-YLQEGYV4.js → chunk-ZZRSG7VK.js} +14 -4
- package/dist/{cli-context-4PTWEK52.js → cli-context-34Q5IJRA.js} +121 -89
- package/dist/cli-entry-point.d.ts +2 -0
- package/dist/{cli-main-DQ2GBY7M.js → cli-main-AELJDBGU.js} +1471 -1293
- package/dist/config-doctor.d.ts +10 -2
- package/dist/{config-transfer-2YF3CRTN.js → config-transfer-RUWLDCNK.js} +34 -13
- package/dist/{diag-doctor-ANPRUYFM.js → diag-doctor-WIFJH3XH.js} +2 -2
- package/dist/execute-deps.d.ts +2 -1
- package/dist/{execution-A6WJLSOC.js → execution-PYC5FCS4.js} +303 -256
- package/dist/{hq-NU75W3SE.js → hq-JTUTFI4L.js} +274 -258
- package/dist/hq-command-controller.d.ts +1 -1
- package/dist/hq-server/project-root.d.ts +35 -1
- package/dist/{hq-server-M2JWVW4D.js → hq-server-PC7GZMPT.js} +2 -2
- package/dist/{hq-service-L5INQFM4.js → hq-service-NW56MUP2.js} +11 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +17 -12
- package/dist/kanban-supervisor-67ECABTD.js +7 -0
- package/dist/live-settings-input.d.ts +7 -0
- package/dist/{mailbox-serve-3GFOK2I7.js → mailbox-serve-WDOCH6KR.js} +3 -3
- package/dist/{mcp-DC5WSBOO.js → mcp-LBS45HWZ.js} +4 -4
- package/dist/modeldiag-36OGAL5C.js +828 -0
- package/dist/{per-subcommand-help-DHTYU524.js → per-subcommand-help-XE77MTGJ.js} +3 -3
- package/dist/permission-prompt-mirror.d.ts +1 -1
- package/dist/permission-prompt.d.ts +2 -2
- package/dist/plugin-config.d.ts +12 -0
- package/dist/plugin-management-types.d.ts +31 -0
- package/dist/plugin-management.d.ts +2 -30
- package/dist/plugin-package-install.d.ts +3 -0
- package/dist/{plugin-usage-M6KET4OZ.js → plugin-usage-S5LVGMBW.js} +6 -5
- package/dist/{plugins-WJLW6ULV.js → plugins-RHBIVLI7.js} +4 -3
- package/dist/provider-config-utils.d.ts +1 -6
- package/dist/{providers-models-LFNZ5WI7.js → providers-models-2CFG46RD.js} +41 -31
- package/dist/release-asset-download.d.ts +3 -0
- package/dist/services/dispatch-classifier.d.ts +39 -5
- package/dist/{sessions-config-UL45XKX7.js → sessions-config-IQUH2GXT.js} +13 -5
- package/dist/settings-menu.d.ts +2 -0
- package/dist/short-circuit-flags-SDT53OML.js +10 -0
- package/dist/{simpleui-dist-CXSIDAXZ.js → simpleui-dist-7BQISSEP.js} +7 -3
- package/dist/skill-suggest-L2EVWB6R.js +290 -0
- package/dist/slash-commands/effort.d.ts +1 -1
- package/dist/slash-commands/fallback.d.ts +1 -1
- package/dist/slash-commands/gitid.d.ts +1 -1
- package/dist/slash-commands/jev.d.ts +4 -0
- package/dist/slash-commands/openai-quota.d.ts +15 -0
- package/dist/slash-commands/sdd-task-mutations.d.ts +4 -0
- package/dist/slash-commands/settings-keys.d.ts +2 -0
- package/dist/slash-commands/settings-reset.d.ts +6 -0
- package/dist/standalone-update-MW47J3AK.js +164 -0
- package/dist/standalone-update.d.ts +19 -0
- package/dist/subcommands/handlers/hq-alerts.d.ts +3 -0
- package/dist/subcommands/handlers/hq-audit.d.ts +46 -0
- package/dist/subcommands/handlers/hq-data-dir.d.ts +13 -0
- package/dist/subcommands/handlers/skill-suggest.d.ts +21 -0
- package/dist/subcommands/handlers/typesafe-brain-replay.d.ts +26 -0
- package/dist/subcommands/handlers/typesafe-judgment-check.d.ts +3 -0
- package/dist/subcommands/handlers/typesafe-topic-replay.d.ts +19 -0
- package/dist/subcommands/handlers/typesafe-triage-replay.d.ts +18 -0
- package/dist/subcommands/handlers/typesafe.d.ts +23 -0
- package/dist/{subcommands-ERDDIJ3L.js → subcommands-ZTSIN7LG.js} +2 -2
- package/dist/typesafe-HVEVPA6R.js +316 -0
- package/dist/typesafe-brain-replay-C5276FVR.js +222 -0
- package/dist/typesafe-judgment-check-GGYYV5UF.js +29 -0
- package/dist/typesafe-topic-replay-4W73BOLV.js +218 -0
- package/dist/typesafe-triage-replay-FGAW7QM7.js +215 -0
- package/dist/{update-5DPB4YD4.js → update-7XIOEXTD.js} +4 -3
- package/dist/{update-check-BS3DHTSI.js → update-check-2POMBHFB.js} +3 -2
- package/dist/update-check.d.ts +1 -1
- package/dist/version-help-WZ623NWM.js +10 -0
- package/dist/version.d.ts +3 -2
- package/dist/webui-client-observability.d.ts +7 -0
- package/dist/{webui-server-MRPGTTKL.js → webui-server-L2SICPTB.js} +158 -94
- package/dist/webui-server-options.d.ts +11 -0
- package/dist/webui-server.d.ts +15 -1
- package/dist/wiring/domain-glossary.d.ts +5 -4
- package/dist/wiring/plugins.d.ts +1 -1
- package/dist/wiring/provider-persisters.d.ts +24 -0
- package/dist/wiring/provider-runtime.d.ts +9 -1
- package/dist/wiring/runtime-dispatch-state.d.ts +3 -1
- package/package.json +28 -28
- package/dist/chunk-DR2OXU46.js +0 -174
- package/dist/chunk-JACOMTIH.js +0 -275
- package/dist/chunk-M4W3QLQW.js +0 -54
- package/dist/chunk-XJXDOF63.js +0 -28
- package/dist/modeldiag-CJSFHZ3J.js +0 -1356
- package/dist/short-circuit-flags-SJQBJ33I.js +0 -10
- package/dist/version-help-WXI42PZ3.js +0 -10
|
@@ -13,29 +13,290 @@ import {
|
|
|
13
13
|
} from "./chunk-Q7E3BPDU.js";
|
|
14
14
|
|
|
15
15
|
// src/subcommands/handlers/hq.ts
|
|
16
|
-
import * as fs from "node:fs/promises";
|
|
17
|
-
import * as path from "node:path";
|
|
18
16
|
import {
|
|
19
17
|
HQ_AUTH_FILE_VERSION,
|
|
20
18
|
HQ_CLI_DEFAULT_HOST,
|
|
21
|
-
HqAlertEngine,
|
|
22
19
|
HqInsecureExposureError,
|
|
23
|
-
hqAuthAuditPath,
|
|
24
|
-
hqAuthContentHash,
|
|
25
|
-
hqAuthFilePath,
|
|
26
20
|
isLoopbackHost,
|
|
27
21
|
logHqAuthAudit,
|
|
28
22
|
mintHqToken,
|
|
29
23
|
mutateHqAuthFile,
|
|
30
|
-
|
|
31
|
-
readHqAuthFile,
|
|
32
|
-
resolveHqDataDir
|
|
24
|
+
readHqAuthFile as readHqAuthFile2
|
|
33
25
|
} from "@wrongstack/core/hq";
|
|
34
26
|
import { expectDefined } from "@wrongstack/core/utils";
|
|
27
|
+
|
|
28
|
+
// src/subcommands/handlers/hq-alerts.ts
|
|
29
|
+
import * as fs from "node:fs/promises";
|
|
30
|
+
import * as path from "node:path";
|
|
31
|
+
import {
|
|
32
|
+
HqAlertEngine,
|
|
33
|
+
readHqAlertsConfig
|
|
34
|
+
} from "@wrongstack/core/hq";
|
|
35
|
+
|
|
36
|
+
// src/subcommands/handlers/hq-data-dir.ts
|
|
37
|
+
import { resolveHqDataDir } from "@wrongstack/core/hq";
|
|
35
38
|
function resolveDataDir(deps) {
|
|
36
39
|
const override = typeof deps.flags?.["data-dir"] === "string" ? deps.flags["data-dir"] : void 0;
|
|
37
40
|
return resolveHqDataDir(override);
|
|
38
41
|
}
|
|
42
|
+
|
|
43
|
+
// src/subcommands/handlers/hq-alerts.ts
|
|
44
|
+
async function hqAlertsCmd(args, deps) {
|
|
45
|
+
const action = args[0];
|
|
46
|
+
if (deps.flags?.["help"] === true || action === "help" || action === "--help") {
|
|
47
|
+
printAlertsHelp(deps);
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
if (action === "eval" || action === void 0) {
|
|
51
|
+
return hqAlertsEval(args.slice(1), deps);
|
|
52
|
+
}
|
|
53
|
+
deps.renderer.writeError(`Unknown hq alerts subcommand: ${action ?? "(none)"}
|
|
54
|
+
`);
|
|
55
|
+
printAlertsHelp(deps);
|
|
56
|
+
return 1;
|
|
57
|
+
}
|
|
58
|
+
async function hqAlertsEval(_args, deps) {
|
|
59
|
+
const flags = deps.flags ?? {};
|
|
60
|
+
const snapshotArg = typeof flags["snapshot"] === "string" ? flags["snapshot"] : void 0;
|
|
61
|
+
let snapshotPath;
|
|
62
|
+
try {
|
|
63
|
+
if (snapshotArg !== void 0) {
|
|
64
|
+
snapshotPath = path.resolve(snapshotArg);
|
|
65
|
+
} else {
|
|
66
|
+
const dataDir2 = resolveDataDir(deps);
|
|
67
|
+
snapshotPath = path.join(dataDir2, "snapshot.json");
|
|
68
|
+
}
|
|
69
|
+
} catch (err) {
|
|
70
|
+
deps.renderer.writeError(`Failed to resolve snapshot path: ${err.message}
|
|
71
|
+
`);
|
|
72
|
+
return 2;
|
|
73
|
+
}
|
|
74
|
+
let raw;
|
|
75
|
+
try {
|
|
76
|
+
raw = await fs.readFile(snapshotPath, "utf8");
|
|
77
|
+
} catch (err) {
|
|
78
|
+
deps.renderer.writeError(
|
|
79
|
+
`Cannot read snapshot at ${snapshotPath}: ${err.message}
|
|
80
|
+
Pass --snapshot <path> to evaluate against a specific file.
|
|
81
|
+
`
|
|
82
|
+
);
|
|
83
|
+
return 2;
|
|
84
|
+
}
|
|
85
|
+
let snapshot;
|
|
86
|
+
try {
|
|
87
|
+
snapshot = JSON.parse(raw);
|
|
88
|
+
} catch (err) {
|
|
89
|
+
deps.renderer.writeError(
|
|
90
|
+
`Snapshot at ${snapshotPath} is not valid JSON: ${err.message}
|
|
91
|
+
`
|
|
92
|
+
);
|
|
93
|
+
return 2;
|
|
94
|
+
}
|
|
95
|
+
const dataDir = resolveDataDir(deps);
|
|
96
|
+
let thresholds;
|
|
97
|
+
try {
|
|
98
|
+
const config = await readHqAlertsConfig(dataDir);
|
|
99
|
+
thresholds = config.thresholds;
|
|
100
|
+
} catch {
|
|
101
|
+
}
|
|
102
|
+
const engine = new HqAlertEngine({
|
|
103
|
+
onAlert: () => {
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
let fired;
|
|
107
|
+
try {
|
|
108
|
+
fired = engine.evaluate(snapshot, thresholds);
|
|
109
|
+
} catch (err) {
|
|
110
|
+
deps.renderer.writeError(`Alert evaluation failed: ${err.message}
|
|
111
|
+
`);
|
|
112
|
+
return 2;
|
|
113
|
+
}
|
|
114
|
+
if (fired.length === 0) {
|
|
115
|
+
deps.renderer.write(`No alert rules fired against ${snapshotPath}.
|
|
116
|
+
`);
|
|
117
|
+
if (thresholds === void 0) {
|
|
118
|
+
deps.renderer.write(
|
|
119
|
+
"(No persisted thresholds; using built-in defaults. Run `wstack hq alerts` with a populated alerts-config.json to override.)\n"
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
124
|
+
deps.renderer.write(`${fired.length} alert rule(s) fired against ${snapshotPath}:
|
|
125
|
+
`);
|
|
126
|
+
for (const alert of fired) {
|
|
127
|
+
deps.renderer.write(` [${alert.severity}] ${alert.ruleId}: ${alert.message}
|
|
128
|
+
`);
|
|
129
|
+
}
|
|
130
|
+
return 1;
|
|
131
|
+
}
|
|
132
|
+
function printAlertsHelp(deps) {
|
|
133
|
+
deps.renderer.write(`Usage: wstack hq alerts <eval>
|
|
134
|
+
`);
|
|
135
|
+
deps.renderer.write("\n");
|
|
136
|
+
deps.renderer.write(
|
|
137
|
+
` wstack hq alerts eval [--snapshot <path>] Run HqAlertEngine.evaluate() against a
|
|
138
|
+
`
|
|
139
|
+
);
|
|
140
|
+
deps.renderer.write(
|
|
141
|
+
` snapshot file (or the live <dataDir>/
|
|
142
|
+
`
|
|
143
|
+
);
|
|
144
|
+
deps.renderer.write(
|
|
145
|
+
` snapshot.json). Pure-function dry run;
|
|
146
|
+
`
|
|
147
|
+
);
|
|
148
|
+
deps.renderer.write(
|
|
149
|
+
` no server required. Exits 0 when no
|
|
150
|
+
`
|
|
151
|
+
);
|
|
152
|
+
deps.renderer.write(
|
|
153
|
+
` rules fire, 1 when rules fire, 2 on errors.
|
|
154
|
+
`
|
|
155
|
+
);
|
|
156
|
+
deps.renderer.write("\n");
|
|
157
|
+
deps.renderer.write(
|
|
158
|
+
`Persisted thresholds (<dataDir>/alerts-config.json) are loaded automatically when
|
|
159
|
+
`
|
|
160
|
+
);
|
|
161
|
+
deps.renderer.write(
|
|
162
|
+
`present; otherwise the engine's built-in defaults apply. Snoozes are NOT honored
|
|
163
|
+
`
|
|
164
|
+
);
|
|
165
|
+
deps.renderer.write(
|
|
166
|
+
`by this command \u2014 eval is a "what would fire RIGHT NOW if there were no snoozes"
|
|
167
|
+
`
|
|
168
|
+
);
|
|
169
|
+
deps.renderer.write(`probe.
|
|
170
|
+
`);
|
|
171
|
+
deps.renderer.write("\n");
|
|
172
|
+
deps.renderer.write(`Flags:
|
|
173
|
+
`);
|
|
174
|
+
deps.renderer.write(
|
|
175
|
+
` --snapshot <path> Evaluate against this snapshot file instead of the live one.
|
|
176
|
+
`
|
|
177
|
+
);
|
|
178
|
+
deps.renderer.write(
|
|
179
|
+
` --data-dir <path> Override HQ data directory (default ~/.wrongstack/hq).
|
|
180
|
+
`
|
|
181
|
+
);
|
|
182
|
+
deps.renderer.write("\n");
|
|
183
|
+
deps.renderer.write(`Run \`wstack hq --help\` for the full HQ command list.
|
|
184
|
+
`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/subcommands/handlers/hq-audit.ts
|
|
188
|
+
import * as fs2 from "node:fs/promises";
|
|
189
|
+
import {
|
|
190
|
+
hqAuthAuditPath,
|
|
191
|
+
hqAuthContentHash,
|
|
192
|
+
hqAuthFilePath,
|
|
193
|
+
readHqAuthFile
|
|
194
|
+
} from "@wrongstack/core/hq";
|
|
195
|
+
async function hqAuditCmd(args, deps) {
|
|
196
|
+
const action = args[0];
|
|
197
|
+
if (deps.flags?.["help"] === true || action === "help" || action === "--help") {
|
|
198
|
+
printAuditHelp(deps);
|
|
199
|
+
return 0;
|
|
200
|
+
}
|
|
201
|
+
if (action === "verify" || action === void 0) {
|
|
202
|
+
return hqAuditVerify(deps);
|
|
203
|
+
}
|
|
204
|
+
deps.renderer.writeError(`Unknown hq audit subcommand: ${action ?? "(none)"}
|
|
205
|
+
`);
|
|
206
|
+
printAuditHelp(deps);
|
|
207
|
+
return 1;
|
|
208
|
+
}
|
|
209
|
+
async function hqAuditVerify(deps) {
|
|
210
|
+
const dataDir = resolveDataDir(deps);
|
|
211
|
+
const authPath = hqAuthFilePath(dataDir);
|
|
212
|
+
const auditPath = hqAuthAuditPath(dataDir);
|
|
213
|
+
deps.renderer.write(`auth file: ${authPath}
|
|
214
|
+
`);
|
|
215
|
+
deps.renderer.write(`audit log: ${auditPath}
|
|
216
|
+
`);
|
|
217
|
+
const fileExists = await fileExistsQuiet(authPath);
|
|
218
|
+
if (!fileExists) {
|
|
219
|
+
deps.renderer.write(`contentHash: (unavailable \u2014 auth.json does not exist)
|
|
220
|
+
`);
|
|
221
|
+
deps.renderer.write(
|
|
222
|
+
`Compare historical entries in the audit log above against a known-good hash.
|
|
223
|
+
`
|
|
224
|
+
);
|
|
225
|
+
return 1;
|
|
226
|
+
}
|
|
227
|
+
const authFile = await readHqAuthFile(dataDir, {
|
|
228
|
+
warn: (msg) => deps.renderer.writeWarning(`${msg}
|
|
229
|
+
`)
|
|
230
|
+
});
|
|
231
|
+
const hash = hqAuthContentHash(authFile);
|
|
232
|
+
if (hash === void 0) {
|
|
233
|
+
deps.renderer.write(`contentHash: (unavailable \u2014 auth.json is unreadable or malformed)
|
|
234
|
+
`);
|
|
235
|
+
deps.renderer.write(
|
|
236
|
+
`Compare historical entries in the audit log above against a known-good hash.
|
|
237
|
+
`
|
|
238
|
+
);
|
|
239
|
+
return 1;
|
|
240
|
+
}
|
|
241
|
+
deps.renderer.write(`contentHash: ${hash}
|
|
242
|
+
`);
|
|
243
|
+
deps.renderer.write("\n");
|
|
244
|
+
deps.renderer.write(
|
|
245
|
+
`Compare this value against the 'contentHash' field of entries in the audit log.
|
|
246
|
+
`
|
|
247
|
+
);
|
|
248
|
+
deps.renderer.write(
|
|
249
|
+
`A match means the redacted projection of auth.json is identical to when that
|
|
250
|
+
`
|
|
251
|
+
);
|
|
252
|
+
deps.renderer.write(
|
|
253
|
+
`entry was emitted (secrets may differ \u2014 only the non-secret shape is hashed).
|
|
254
|
+
`
|
|
255
|
+
);
|
|
256
|
+
return 0;
|
|
257
|
+
}
|
|
258
|
+
async function fileExistsQuiet(filePath) {
|
|
259
|
+
try {
|
|
260
|
+
await fs2.access(filePath);
|
|
261
|
+
return true;
|
|
262
|
+
} catch {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
async function computeAuditHashField(dataDir, warn) {
|
|
267
|
+
const persisted = await readHqAuthFile(dataDir, { warn });
|
|
268
|
+
const hash = hqAuthContentHash(persisted);
|
|
269
|
+
return hash !== void 0 ? { contentHash: hash } : {};
|
|
270
|
+
}
|
|
271
|
+
function printAuditHelp(deps) {
|
|
272
|
+
deps.renderer.write(`Usage: wstack hq audit <verify>
|
|
273
|
+
`);
|
|
274
|
+
deps.renderer.write("\n");
|
|
275
|
+
deps.renderer.write(
|
|
276
|
+
` wstack hq audit verify Re-derive the SHA-256 contentHash from the current
|
|
277
|
+
`
|
|
278
|
+
);
|
|
279
|
+
deps.renderer.write(
|
|
280
|
+
` on-disk auth.json and print it so an operator can compare
|
|
281
|
+
`
|
|
282
|
+
);
|
|
283
|
+
deps.renderer.write(
|
|
284
|
+
` it against a contentHash field in an audit-log entry.
|
|
285
|
+
`
|
|
286
|
+
);
|
|
287
|
+
deps.renderer.write("\n");
|
|
288
|
+
deps.renderer.write(`Flags:
|
|
289
|
+
`);
|
|
290
|
+
deps.renderer.write(
|
|
291
|
+
` --data-dir <path> Override HQ data directory (default ~/.wrongstack/hq).
|
|
292
|
+
`
|
|
293
|
+
);
|
|
294
|
+
deps.renderer.write("\n");
|
|
295
|
+
deps.renderer.write(`Run \`wstack hq --help\` for the full HQ command list.
|
|
296
|
+
`);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// src/subcommands/handlers/hq.ts
|
|
39
300
|
var hqCmd = async (args, deps) => {
|
|
40
301
|
const sub = args[0];
|
|
41
302
|
if (deps.flags?.["help"] === true && (!sub || sub === "serve")) {
|
|
@@ -55,7 +316,7 @@ var hqCmd = async (args, deps) => {
|
|
|
55
316
|
return hqAlertsCmd(args.slice(1), deps);
|
|
56
317
|
}
|
|
57
318
|
if (sub === "service") {
|
|
58
|
-
const { hqServiceCmd } = await import("./hq-service-
|
|
319
|
+
const { hqServiceCmd } = await import("./hq-service-NW56MUP2.js");
|
|
59
320
|
return hqServiceCmd(args.slice(1), deps);
|
|
60
321
|
}
|
|
61
322
|
if (sub === "help" || sub === "--help") {
|
|
@@ -68,7 +329,7 @@ var hqCmd = async (args, deps) => {
|
|
|
68
329
|
return 1;
|
|
69
330
|
};
|
|
70
331
|
async function startServer(deps) {
|
|
71
|
-
const { startHqServer } = await import("./hq-server-
|
|
332
|
+
const { startHqServer } = await import("./hq-server-PC7GZMPT.js");
|
|
72
333
|
const dataDir = resolveDataDir(deps);
|
|
73
334
|
const flags = deps.flags ?? {};
|
|
74
335
|
const rawPublicUrl = typeof flags["hq-public-url"] === "string" ? flags["hq-public-url"] : process.env.WRONGSTACK_HQ_PUBLIC_URL;
|
|
@@ -286,82 +547,6 @@ async function hqTokenCmd(args, deps) {
|
|
|
286
547
|
printTokenHelp(deps);
|
|
287
548
|
return 1;
|
|
288
549
|
}
|
|
289
|
-
async function hqAuditCmd(args, deps) {
|
|
290
|
-
const action = args[0];
|
|
291
|
-
if (deps.flags?.["help"] === true || action === "help" || action === "--help") {
|
|
292
|
-
printAuditHelp(deps);
|
|
293
|
-
return 0;
|
|
294
|
-
}
|
|
295
|
-
if (action === "verify" || action === void 0) {
|
|
296
|
-
return hqAuditVerify(deps);
|
|
297
|
-
}
|
|
298
|
-
deps.renderer.writeError(`Unknown hq audit subcommand: ${action ?? "(none)"}
|
|
299
|
-
`);
|
|
300
|
-
printAuditHelp(deps);
|
|
301
|
-
return 1;
|
|
302
|
-
}
|
|
303
|
-
async function hqAuditVerify(deps) {
|
|
304
|
-
const dataDir = resolveDataDir(deps);
|
|
305
|
-
const authPath = hqAuthFilePath(dataDir);
|
|
306
|
-
const auditPath = hqAuthAuditPath(dataDir);
|
|
307
|
-
deps.renderer.write(`auth file: ${authPath}
|
|
308
|
-
`);
|
|
309
|
-
deps.renderer.write(`audit log: ${auditPath}
|
|
310
|
-
`);
|
|
311
|
-
const fileExists = await fileExistsQuiet(authPath);
|
|
312
|
-
if (!fileExists) {
|
|
313
|
-
deps.renderer.write(`contentHash: (unavailable \u2014 auth.json does not exist)
|
|
314
|
-
`);
|
|
315
|
-
deps.renderer.write(
|
|
316
|
-
`Compare historical entries in the audit log above against a known-good hash.
|
|
317
|
-
`
|
|
318
|
-
);
|
|
319
|
-
return 1;
|
|
320
|
-
}
|
|
321
|
-
const authFile = await readHqAuthFile(dataDir, {
|
|
322
|
-
warn: (msg) => deps.renderer.writeWarning(`${msg}
|
|
323
|
-
`)
|
|
324
|
-
});
|
|
325
|
-
const hash = hqAuthContentHash(authFile);
|
|
326
|
-
if (hash === void 0) {
|
|
327
|
-
deps.renderer.write(`contentHash: (unavailable \u2014 auth.json is unreadable or malformed)
|
|
328
|
-
`);
|
|
329
|
-
deps.renderer.write(
|
|
330
|
-
`Compare historical entries in the audit log above against a known-good hash.
|
|
331
|
-
`
|
|
332
|
-
);
|
|
333
|
-
return 1;
|
|
334
|
-
}
|
|
335
|
-
deps.renderer.write(`contentHash: ${hash}
|
|
336
|
-
`);
|
|
337
|
-
deps.renderer.write("\n");
|
|
338
|
-
deps.renderer.write(
|
|
339
|
-
`Compare this value against the 'contentHash' field of entries in the audit log.
|
|
340
|
-
`
|
|
341
|
-
);
|
|
342
|
-
deps.renderer.write(
|
|
343
|
-
`A match means the redacted projection of auth.json is identical to when that
|
|
344
|
-
`
|
|
345
|
-
);
|
|
346
|
-
deps.renderer.write(
|
|
347
|
-
`entry was emitted (secrets may differ \u2014 only the non-secret shape is hashed).
|
|
348
|
-
`
|
|
349
|
-
);
|
|
350
|
-
return 0;
|
|
351
|
-
}
|
|
352
|
-
async function fileExistsQuiet(filePath) {
|
|
353
|
-
try {
|
|
354
|
-
await fs.access(filePath);
|
|
355
|
-
return true;
|
|
356
|
-
} catch {
|
|
357
|
-
return false;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
async function computeAuditHashField(dataDir, warn) {
|
|
361
|
-
const persisted = await readHqAuthFile(dataDir, { warn });
|
|
362
|
-
const hash = hqAuthContentHash(persisted);
|
|
363
|
-
return hash !== void 0 ? { contentHash: hash } : {};
|
|
364
|
-
}
|
|
365
550
|
var TOKEN_CAPABILITIES = {
|
|
366
551
|
// `control.approve` is grantable but never default — see
|
|
367
552
|
// DEFAULT_TOKEN_CAPABILITIES below.
|
|
@@ -532,7 +717,7 @@ async function tokenList(args, deps) {
|
|
|
532
717
|
const scope = resolveTokenScope(args, deps);
|
|
533
718
|
const dataDir = resolveDataDir(deps);
|
|
534
719
|
const tokenField = scope === "client" ? "clientTokens" : "browserTokens";
|
|
535
|
-
const authFile = await
|
|
720
|
+
const authFile = await readHqAuthFile2(dataDir, {
|
|
536
721
|
warn: (msg) => deps.renderer.writeWarning(`${msg}
|
|
537
722
|
`)
|
|
538
723
|
});
|
|
@@ -814,177 +999,8 @@ function printTokenHelp(deps) {
|
|
|
814
999
|
deps.renderer.write(`Run \`wstack hq --help\` for the full HQ command list.
|
|
815
1000
|
`);
|
|
816
1001
|
}
|
|
817
|
-
function printAuditHelp(deps) {
|
|
818
|
-
deps.renderer.write(`Usage: wstack hq audit <verify>
|
|
819
|
-
`);
|
|
820
|
-
deps.renderer.write("\n");
|
|
821
|
-
deps.renderer.write(
|
|
822
|
-
` wstack hq audit verify Re-derive the SHA-256 contentHash from the current
|
|
823
|
-
`
|
|
824
|
-
);
|
|
825
|
-
deps.renderer.write(
|
|
826
|
-
` on-disk auth.json and print it so an operator can compare
|
|
827
|
-
`
|
|
828
|
-
);
|
|
829
|
-
deps.renderer.write(
|
|
830
|
-
` it against a contentHash field in an audit-log entry.
|
|
831
|
-
`
|
|
832
|
-
);
|
|
833
|
-
deps.renderer.write("\n");
|
|
834
|
-
deps.renderer.write(`Flags:
|
|
835
|
-
`);
|
|
836
|
-
deps.renderer.write(
|
|
837
|
-
` --data-dir <path> Override HQ data directory (default ~/.wrongstack/hq).
|
|
838
|
-
`
|
|
839
|
-
);
|
|
840
|
-
deps.renderer.write("\n");
|
|
841
|
-
deps.renderer.write(`Run \`wstack hq --help\` for the full HQ command list.
|
|
842
|
-
`);
|
|
843
|
-
}
|
|
844
|
-
async function hqAlertsCmd(args, deps) {
|
|
845
|
-
const action = args[0];
|
|
846
|
-
if (deps.flags?.["help"] === true || action === "help" || action === "--help") {
|
|
847
|
-
printAlertsHelp(deps);
|
|
848
|
-
return 0;
|
|
849
|
-
}
|
|
850
|
-
if (action === "eval" || action === void 0) {
|
|
851
|
-
return hqAlertsEval(args.slice(1), deps);
|
|
852
|
-
}
|
|
853
|
-
deps.renderer.writeError(`Unknown hq alerts subcommand: ${action ?? "(none)"}
|
|
854
|
-
`);
|
|
855
|
-
printAlertsHelp(deps);
|
|
856
|
-
return 1;
|
|
857
|
-
}
|
|
858
|
-
async function hqAlertsEval(_args, deps) {
|
|
859
|
-
const flags = deps.flags ?? {};
|
|
860
|
-
const snapshotArg = typeof flags["snapshot"] === "string" ? flags["snapshot"] : void 0;
|
|
861
|
-
let snapshotPath;
|
|
862
|
-
try {
|
|
863
|
-
if (snapshotArg !== void 0) {
|
|
864
|
-
snapshotPath = path.resolve(snapshotArg);
|
|
865
|
-
} else {
|
|
866
|
-
const dataDir2 = resolveDataDir(deps);
|
|
867
|
-
snapshotPath = path.join(dataDir2, "snapshot.json");
|
|
868
|
-
}
|
|
869
|
-
} catch (err) {
|
|
870
|
-
deps.renderer.writeError(`Failed to resolve snapshot path: ${err.message}
|
|
871
|
-
`);
|
|
872
|
-
return 2;
|
|
873
|
-
}
|
|
874
|
-
let raw;
|
|
875
|
-
try {
|
|
876
|
-
raw = await fs.readFile(snapshotPath, "utf8");
|
|
877
|
-
} catch (err) {
|
|
878
|
-
deps.renderer.writeError(
|
|
879
|
-
`Cannot read snapshot at ${snapshotPath}: ${err.message}
|
|
880
|
-
Pass --snapshot <path> to evaluate against a specific file.
|
|
881
|
-
`
|
|
882
|
-
);
|
|
883
|
-
return 2;
|
|
884
|
-
}
|
|
885
|
-
let snapshot;
|
|
886
|
-
try {
|
|
887
|
-
snapshot = JSON.parse(raw);
|
|
888
|
-
} catch (err) {
|
|
889
|
-
deps.renderer.writeError(
|
|
890
|
-
`Snapshot at ${snapshotPath} is not valid JSON: ${err.message}
|
|
891
|
-
`
|
|
892
|
-
);
|
|
893
|
-
return 2;
|
|
894
|
-
}
|
|
895
|
-
const dataDir = resolveDataDir(deps);
|
|
896
|
-
let thresholds;
|
|
897
|
-
try {
|
|
898
|
-
const config = await readHqAlertsConfig(dataDir);
|
|
899
|
-
thresholds = config.thresholds;
|
|
900
|
-
} catch {
|
|
901
|
-
}
|
|
902
|
-
const engine = new HqAlertEngine({
|
|
903
|
-
onAlert: () => {
|
|
904
|
-
}
|
|
905
|
-
});
|
|
906
|
-
let fired;
|
|
907
|
-
try {
|
|
908
|
-
fired = engine.evaluate(snapshot, thresholds);
|
|
909
|
-
} catch (err) {
|
|
910
|
-
deps.renderer.writeError(`Alert evaluation failed: ${err.message}
|
|
911
|
-
`);
|
|
912
|
-
return 2;
|
|
913
|
-
}
|
|
914
|
-
if (fired.length === 0) {
|
|
915
|
-
deps.renderer.write(`No alert rules fired against ${snapshotPath}.
|
|
916
|
-
`);
|
|
917
|
-
if (thresholds === void 0) {
|
|
918
|
-
deps.renderer.write(
|
|
919
|
-
"(No persisted thresholds; using built-in defaults. Run `wstack hq alerts` with a populated alerts-config.json to override.)\n"
|
|
920
|
-
);
|
|
921
|
-
}
|
|
922
|
-
return 0;
|
|
923
|
-
}
|
|
924
|
-
deps.renderer.write(`${fired.length} alert rule(s) fired against ${snapshotPath}:
|
|
925
|
-
`);
|
|
926
|
-
for (const alert of fired) {
|
|
927
|
-
deps.renderer.write(` [${alert.severity}] ${alert.ruleId}: ${alert.message}
|
|
928
|
-
`);
|
|
929
|
-
}
|
|
930
|
-
return 1;
|
|
931
|
-
}
|
|
932
|
-
function printAlertsHelp(deps) {
|
|
933
|
-
deps.renderer.write(`Usage: wstack hq alerts <eval>
|
|
934
|
-
`);
|
|
935
|
-
deps.renderer.write("\n");
|
|
936
|
-
deps.renderer.write(
|
|
937
|
-
` wstack hq alerts eval [--snapshot <path>] Run HqAlertEngine.evaluate() against a
|
|
938
|
-
`
|
|
939
|
-
);
|
|
940
|
-
deps.renderer.write(
|
|
941
|
-
` snapshot file (or the live <dataDir>/
|
|
942
|
-
`
|
|
943
|
-
);
|
|
944
|
-
deps.renderer.write(
|
|
945
|
-
` snapshot.json). Pure-function dry run;
|
|
946
|
-
`
|
|
947
|
-
);
|
|
948
|
-
deps.renderer.write(
|
|
949
|
-
` no server required. Exits 0 when no
|
|
950
|
-
`
|
|
951
|
-
);
|
|
952
|
-
deps.renderer.write(
|
|
953
|
-
` rules fire, 1 when rules fire, 2 on errors.
|
|
954
|
-
`
|
|
955
|
-
);
|
|
956
|
-
deps.renderer.write("\n");
|
|
957
|
-
deps.renderer.write(
|
|
958
|
-
`Persisted thresholds (<dataDir>/alerts-config.json) are loaded automatically when
|
|
959
|
-
`
|
|
960
|
-
);
|
|
961
|
-
deps.renderer.write(
|
|
962
|
-
`present; otherwise the engine's built-in defaults apply. Snoozes are NOT honored
|
|
963
|
-
`
|
|
964
|
-
);
|
|
965
|
-
deps.renderer.write(
|
|
966
|
-
`by this command \u2014 eval is a "what would fire RIGHT NOW if there were no snoozes"
|
|
967
|
-
`
|
|
968
|
-
);
|
|
969
|
-
deps.renderer.write(`probe.
|
|
970
|
-
`);
|
|
971
|
-
deps.renderer.write("\n");
|
|
972
|
-
deps.renderer.write(`Flags:
|
|
973
|
-
`);
|
|
974
|
-
deps.renderer.write(
|
|
975
|
-
` --snapshot <path> Evaluate against this snapshot file instead of the live one.
|
|
976
|
-
`
|
|
977
|
-
);
|
|
978
|
-
deps.renderer.write(
|
|
979
|
-
` --data-dir <path> Override HQ data directory (default ~/.wrongstack/hq).
|
|
980
|
-
`
|
|
981
|
-
);
|
|
982
|
-
deps.renderer.write("\n");
|
|
983
|
-
deps.renderer.write(`Run \`wstack hq --help\` for the full HQ command list.
|
|
984
|
-
`);
|
|
985
|
-
}
|
|
986
1002
|
export {
|
|
987
1003
|
hqCmd,
|
|
988
1004
|
resolveAuditActor
|
|
989
1005
|
};
|
|
990
|
-
//# sourceMappingURL=hq-
|
|
1006
|
+
//# sourceMappingURL=hq-JTUTFI4L.js.map
|
|
@@ -81,7 +81,7 @@ export interface HqCommandController {
|
|
|
81
81
|
* (`createApprovalRegistry` in `@wrongstack/core/hq`), which is the only
|
|
82
82
|
* holder of the resolver closures.
|
|
83
83
|
*/
|
|
84
|
-
resolveApproval?: ((toolUseId: string, decision: 'yes' | 'no' | 'always' | 'deny', sessionId?: string | undefined) => boolean) | undefined;
|
|
84
|
+
resolveApproval?: ((toolUseId: string, decision: 'yes' | 'no' | 'always' | 'always-exact' | 'always-command' | 'always-tool' | 'deny', sessionId?: string | undefined) => boolean) | undefined;
|
|
85
85
|
resolveUserInput?: ((requestId: string, response: UserInputResponse, sessionId?: string | undefined) => boolean) | undefined;
|
|
86
86
|
/** Apply a lifecycle transition through the project's Kanban IPC client. */
|
|
87
87
|
kanbanTransition?: ((input: {
|
|
@@ -1,5 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why this is not just `string | undefined`.
|
|
3
|
+
*
|
|
4
|
+
* Resolution walks `ProjectSessionRegistry.list()`, which probes each known
|
|
5
|
+
* project's session-catalog daemon with `callExisting` — a path that must never
|
|
6
|
+
* spawn — and turns EVERY per-project failure into an empty result: metadata not
|
|
7
|
+
* yet written, the daemon gone, the IPC connect refused, a timeout. The gateway
|
|
8
|
+
* then reported that as `404 Unknown project`, which is indistinguishable from
|
|
9
|
+
* "this project does not exist".
|
|
10
|
+
*
|
|
11
|
+
* That conflation is observable: a session lease lives 30s and is renewed every
|
|
12
|
+
* 5s, so under heavy load a live project's daemon can lapse and exit, and a
|
|
13
|
+
* perfectly real project answers 404 for a moment. The caller cannot tell a
|
|
14
|
+
* permanent negative from a blip, so it cannot know whether retrying is
|
|
15
|
+
* sensible.
|
|
16
|
+
*
|
|
17
|
+
* The on-disk project directory is the discriminator: it is created when the
|
|
18
|
+
* project first gets a daemon and it outlives that daemon (only the metadata
|
|
19
|
+
* file is removed on exit). A directory therefore means "this machine knows
|
|
20
|
+
* this project, it just is not answering right now" — transient. No directory
|
|
21
|
+
* means genuinely unknown.
|
|
22
|
+
*/
|
|
23
|
+
export type HqProjectResolution = {
|
|
24
|
+
status: 'found';
|
|
25
|
+
projectRoot: string;
|
|
26
|
+
}
|
|
27
|
+
/** No such project on this machine. A retry will not help. */
|
|
28
|
+
| {
|
|
29
|
+
status: 'unknown';
|
|
30
|
+
}
|
|
31
|
+
/** The project is known but could not be resolved right now; retry may help. */
|
|
32
|
+
| {
|
|
33
|
+
status: 'unavailable';
|
|
34
|
+
};
|
|
1
35
|
export declare function resolveHqProjectRoot(globalRoot: string, ids: {
|
|
2
36
|
sessionId?: string | undefined;
|
|
3
37
|
projectId?: string | undefined;
|
|
4
|
-
}): Promise<
|
|
38
|
+
}): Promise<HqProjectResolution>;
|
|
5
39
|
//# sourceMappingURL=project-root.d.ts.map
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
readLocalSubagentTranscript,
|
|
11
11
|
sanitizeApiError,
|
|
12
12
|
startHqServer
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-DRM7PSW7.js";
|
|
14
14
|
import "./chunk-HXJYHAR4.js";
|
|
15
15
|
import "./chunk-5EA6OTLJ.js";
|
|
16
16
|
import "./chunk-Q7E3BPDU.js";
|
|
@@ -27,4 +27,4 @@ export {
|
|
|
27
27
|
sanitizeApiError,
|
|
28
28
|
startHqServer
|
|
29
29
|
};
|
|
30
|
-
//# sourceMappingURL=hq-server-
|
|
30
|
+
//# sourceMappingURL=hq-server-PC7GZMPT.js.map
|
|
@@ -4,16 +4,17 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
detectUpdatePackageManager,
|
|
6
6
|
detectUpdatePackageName
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QFPQXKCG.js";
|
|
8
8
|
import "./chunk-U3SS4NRH.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-ZZRSG7VK.js";
|
|
10
|
+
import "./chunk-YBUCXXYZ.js";
|
|
10
11
|
|
|
11
12
|
// src/hq-service.ts
|
|
12
13
|
import { spawn } from "node:child_process";
|
|
13
14
|
import { constants as fsConstants } from "node:fs";
|
|
14
15
|
import * as fs from "node:fs/promises";
|
|
15
16
|
import * as path from "node:path";
|
|
16
|
-
import { buildChildEnv } from "@wrongstack/core/utils";
|
|
17
|
+
import { buildChildEnv, isStandaloneBinary } from "@wrongstack/core/utils";
|
|
17
18
|
var SERVICE_NAME = "wrongstack-hq.service";
|
|
18
19
|
var UPDATE_SERVICE_NAME = "wrongstack-hq-update.service";
|
|
19
20
|
var UPDATE_TIMER_NAME = "wrongstack-hq-update.timer";
|
|
@@ -314,6 +315,12 @@ async function installService(deps) {
|
|
|
314
315
|
deps.renderer.writeError("--port must be an integer between 1 and 65535.\n");
|
|
315
316
|
return 1;
|
|
316
317
|
}
|
|
318
|
+
if (isStandaloneBinary()) {
|
|
319
|
+
deps.renderer.writeError(
|
|
320
|
+
"The HQ system service installer manages an npm install. With the standalone binary, run `wstack hq` under your own service manager and update it with `wstack update`.\n"
|
|
321
|
+
);
|
|
322
|
+
return 1;
|
|
323
|
+
}
|
|
317
324
|
const requestedManager = deps.flags?.["pm"] ?? deps.flags?.["package-manager"];
|
|
318
325
|
const detectedManager = typeof requestedManager === "string" ? requestedManager : detectUpdatePackageManager();
|
|
319
326
|
if (detectedManager !== "npm" && detectedManager !== "pnpm") {
|
|
@@ -504,4 +511,4 @@ export {
|
|
|
504
511
|
hqServiceCmd,
|
|
505
512
|
renderHqServiceAssets
|
|
506
513
|
};
|
|
507
|
-
//# sourceMappingURL=hq-service-
|
|
514
|
+
//# sourceMappingURL=hq-service-NW56MUP2.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { main } from './cli-entry-main.js';
|
|
2
|
-
export { installBrokenPipeHandlers } from './cli-entry-point.js';
|
|
2
|
+
export { installBrokenPipeHandlers, runCliProcess } from './cli-entry-point.js';
|
|
3
3
|
export { CLI_VERSION } from './version.js';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|