@wrongstack/cli 0.305.0 → 0.306.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.
- package/dist/{auth-K7CYVVKH.js → auth-GVPYLJPS.js} +7 -7
- package/dist/boot/short-circuit-flags.d.ts +7 -1
- package/dist/boot/system-prompt-menu.d.ts +151 -0
- package/dist/chimera-cascade-evidence.d.ts +102 -0
- package/dist/chimera-review-task.d.ts +7 -0
- package/dist/{chunk-C5NXM2SI.js → chunk-5JW3XCRA.js} +7 -3
- package/dist/{chunk-FJVCVZIV.js → chunk-WC3DK6BI.js} +5 -5
- package/dist/{cli-main-W3T56YCY.js → cli-main-DHNFGP3Z.js} +278 -197
- package/dist/diag-doctor-WTBHPOMB.js +329 -0
- package/dist/{execution-YMBD7YWC.js → execution-TTE7R5UY.js} +313 -53
- package/dist/execution-chimera-cascade.d.ts +7 -1
- package/dist/{hq-5G6D5YIU.js → hq-ZK6PGN3W.js} +95 -6
- package/dist/index.js +759 -546
- package/dist/{modeldiag-SIVUOX2Y.js → modeldiag-6VS5KDP5.js} +4 -4
- package/dist/subcommands/handlers/daemon-inventory.d.ts +41 -0
- package/dist/wiring/management-tools.d.ts +8 -1
- package/package.json +24 -23
- package/dist/diag-doctor-ZF5BF2MK.js +0 -169
|
@@ -37,23 +37,24 @@ import {
|
|
|
37
37
|
writeWebuiSessionChildReady
|
|
38
38
|
} from "./chunk-3JPTNADJ.js";
|
|
39
39
|
import {
|
|
40
|
-
|
|
41
|
-
} from "./chunk-
|
|
42
|
-
import {
|
|
43
|
-
activeProfileConfigPath
|
|
44
|
-
} from "./chunk-YMXXOOFN.js";
|
|
40
|
+
CLI_VERSION
|
|
41
|
+
} from "./chunk-XJXDOF63.js";
|
|
45
42
|
import {
|
|
46
43
|
terminalLink,
|
|
47
44
|
terminalText
|
|
48
45
|
} from "./chunk-KE7E7DPX.js";
|
|
49
46
|
import {
|
|
50
|
-
|
|
51
|
-
} from "./chunk-
|
|
47
|
+
resolveActiveApiKey
|
|
48
|
+
} from "./chunk-SZ42FYPT.js";
|
|
49
|
+
import {
|
|
50
|
+
activeProfileConfigPath
|
|
51
|
+
} from "./chunk-YMXXOOFN.js";
|
|
52
52
|
import "./chunk-7OCVIDC7.js";
|
|
53
53
|
|
|
54
54
|
// src/execution.ts
|
|
55
55
|
import * as path13 from "node:path";
|
|
56
56
|
import { effectiveFallbackChain as effectiveFallbackChain2, setQueuedMessagesSnapshot as setQueuedMessagesSnapshot2 } from "@wrongstack/core/agent";
|
|
57
|
+
import { updateReviewReportEvidence } from "@wrongstack/core/plugin";
|
|
57
58
|
import { attachTodosCheckpoint as attachTodosCheckpoint2 } from "@wrongstack/core/storage";
|
|
58
59
|
import { normalizeTokenSavingTier as normalizeTokenSavingTier2 } from "@wrongstack/core/types";
|
|
59
60
|
import { mergeCustomModelDefs } from "@wrongstack/core/utils";
|
|
@@ -1873,24 +1874,9 @@ function createSettingsAdapter(ctx) {
|
|
|
1873
1874
|
// src/boot/tui-theme-adapter.ts
|
|
1874
1875
|
import * as fs4 from "node:fs/promises";
|
|
1875
1876
|
import * as path9 from "node:path";
|
|
1877
|
+
import { THEME_PRESET_IDS } from "@wrongstack/core/types";
|
|
1876
1878
|
import { atomicWrite as atomicWrite2 } from "@wrongstack/core/utils";
|
|
1877
|
-
var VALID_PRESETS =
|
|
1878
|
-
"catppuccin",
|
|
1879
|
-
"tokyo-night",
|
|
1880
|
-
"nord",
|
|
1881
|
-
"cyberpunk",
|
|
1882
|
-
"dracula",
|
|
1883
|
-
"gruvbox-dark",
|
|
1884
|
-
"solarized-dark",
|
|
1885
|
-
"one-dark",
|
|
1886
|
-
"monokai",
|
|
1887
|
-
"rose-pine",
|
|
1888
|
-
"kanagawa",
|
|
1889
|
-
"ayu-dark",
|
|
1890
|
-
"everforest",
|
|
1891
|
-
"night-owl",
|
|
1892
|
-
"synthwave"
|
|
1893
|
-
]);
|
|
1879
|
+
var VALID_PRESETS = new Set(THEME_PRESET_IDS);
|
|
1894
1880
|
function createThemeAdapter({ configStore, wpaths }) {
|
|
1895
1881
|
return {
|
|
1896
1882
|
getThemePreset: () => {
|
|
@@ -2761,6 +2747,128 @@ import * as fsp from "node:fs/promises";
|
|
|
2761
2747
|
import * as path10 from "node:path";
|
|
2762
2748
|
import { emitReviewIfChanged } from "@wrongstack/core/plugin";
|
|
2763
2749
|
|
|
2750
|
+
// src/chimera-cascade-evidence.ts
|
|
2751
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
2752
|
+
var JSON_BLOCK_RE = /```json\s*([\s\S]*?)```/gi;
|
|
2753
|
+
function extractCascadeEvidence(text) {
|
|
2754
|
+
if (!text) return null;
|
|
2755
|
+
for (const match of text.matchAll(JSON_BLOCK_RE)) {
|
|
2756
|
+
const body = match[1]?.trim();
|
|
2757
|
+
if (!body) continue;
|
|
2758
|
+
let parsed;
|
|
2759
|
+
try {
|
|
2760
|
+
parsed = JSON.parse(body);
|
|
2761
|
+
} catch {
|
|
2762
|
+
continue;
|
|
2763
|
+
}
|
|
2764
|
+
const evidence = parseEvidenceObject(parsed);
|
|
2765
|
+
if (evidence) return evidence;
|
|
2766
|
+
}
|
|
2767
|
+
return null;
|
|
2768
|
+
}
|
|
2769
|
+
function parseEvidenceObject(parsed) {
|
|
2770
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
2771
|
+
const root = parsed;
|
|
2772
|
+
const raw = root.verification_evidence;
|
|
2773
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
2774
|
+
const checks = raw;
|
|
2775
|
+
const out = {};
|
|
2776
|
+
let found = false;
|
|
2777
|
+
for (const key of ["typecheck", "lint", "tests"]) {
|
|
2778
|
+
const check = parseSingleCheck(checks[key]);
|
|
2779
|
+
if (check) {
|
|
2780
|
+
out[key] = check;
|
|
2781
|
+
found = true;
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
return found ? out : null;
|
|
2785
|
+
}
|
|
2786
|
+
function parseSingleCheck(raw) {
|
|
2787
|
+
if (typeof raw !== "object" || raw === null) return void 0;
|
|
2788
|
+
const check = raw;
|
|
2789
|
+
const command = check.command;
|
|
2790
|
+
const exitCode = check.exitCode;
|
|
2791
|
+
if (typeof command !== "string" || command.trim().length === 0) return void 0;
|
|
2792
|
+
if (typeof exitCode !== "number" || !Number.isInteger(exitCode) || exitCode < 0 || exitCode > 255) {
|
|
2793
|
+
return void 0;
|
|
2794
|
+
}
|
|
2795
|
+
const output = typeof check.output === "string" ? truncateOutput(check.output) : void 0;
|
|
2796
|
+
return { command: command.trim(), exitCode, output };
|
|
2797
|
+
}
|
|
2798
|
+
var MAX_EVIDENCE_OUTPUT_CHARS = 2e3;
|
|
2799
|
+
function truncateOutput(output) {
|
|
2800
|
+
return output.length > MAX_EVIDENCE_OUTPUT_CHARS ? `${output.slice(0, MAX_EVIDENCE_OUTPUT_CHARS)}
|
|
2801
|
+
\u2026 (truncated)` : output;
|
|
2802
|
+
}
|
|
2803
|
+
var SAFE_EXECUTABLES = /* @__PURE__ */ new Set([
|
|
2804
|
+
"pnpm",
|
|
2805
|
+
"npm",
|
|
2806
|
+
"yarn",
|
|
2807
|
+
"npx",
|
|
2808
|
+
"bun",
|
|
2809
|
+
"node",
|
|
2810
|
+
"tsc",
|
|
2811
|
+
"biome",
|
|
2812
|
+
"eslint",
|
|
2813
|
+
"vitest",
|
|
2814
|
+
"jest"
|
|
2815
|
+
]);
|
|
2816
|
+
var CASCADE_EVIDENCE_COMMAND_TIMEOUT_MS = 12e4;
|
|
2817
|
+
var CASCADE_EVIDENCE_UNSAFE_EXIT = 126;
|
|
2818
|
+
var CASCADE_EVIDENCE_RUN_ERROR_EXIT = 127;
|
|
2819
|
+
function isSafeCascadeCommand(command) {
|
|
2820
|
+
if (!command || command.length > 500) return false;
|
|
2821
|
+
const tokens = command.trim().split(/\s+/);
|
|
2822
|
+
if (tokens.length === 0) return false;
|
|
2823
|
+
if (!SAFE_EXECUTABLES.has(tokens[0])) return false;
|
|
2824
|
+
return tokens.every((token) => /^[A-Za-z0-9@/._:=~+*?\[\]-]+$/.test(token));
|
|
2825
|
+
}
|
|
2826
|
+
var runCascadeVerificationCommand = (command, cwd, timeoutMs) => {
|
|
2827
|
+
if (!isSafeCascadeCommand(command)) {
|
|
2828
|
+
return Promise.resolve({ exitCode: CASCADE_EVIDENCE_UNSAFE_EXIT });
|
|
2829
|
+
}
|
|
2830
|
+
const tokens = command.trim().split(/\s+/);
|
|
2831
|
+
const executable = tokens[0];
|
|
2832
|
+
const args = tokens.slice(1);
|
|
2833
|
+
return new Promise((resolve3) => {
|
|
2834
|
+
let child;
|
|
2835
|
+
try {
|
|
2836
|
+
child = spawn2(executable, args, {
|
|
2837
|
+
cwd,
|
|
2838
|
+
stdio: "ignore",
|
|
2839
|
+
windowsHide: true,
|
|
2840
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
2841
|
+
});
|
|
2842
|
+
} catch {
|
|
2843
|
+
resolve3({ exitCode: CASCADE_EVIDENCE_RUN_ERROR_EXIT });
|
|
2844
|
+
return;
|
|
2845
|
+
}
|
|
2846
|
+
child.on("error", () => resolve3({ exitCode: CASCADE_EVIDENCE_RUN_ERROR_EXIT }));
|
|
2847
|
+
child.on("close", (code) => resolve3({ exitCode: code ?? CASCADE_EVIDENCE_RUN_ERROR_EXIT }));
|
|
2848
|
+
});
|
|
2849
|
+
};
|
|
2850
|
+
async function verifyCascadeEvidence(evidence, cwd, runCommand = runCascadeVerificationCommand, timeoutMs = CASCADE_EVIDENCE_COMMAND_TIMEOUT_MS) {
|
|
2851
|
+
if (!evidence) return { status: "missing", checks: [] };
|
|
2852
|
+
if (!evidence.typecheck) return { status: "failed", checks: [] };
|
|
2853
|
+
const checks = [];
|
|
2854
|
+
for (const name of ["typecheck", "lint", "tests"]) {
|
|
2855
|
+
const claimed = evidence[name];
|
|
2856
|
+
if (!claimed) continue;
|
|
2857
|
+
const actual = await runCommand(claimed.command, cwd, timeoutMs);
|
|
2858
|
+
const ok = claimed.exitCode === 0 && actual.exitCode === claimed.exitCode;
|
|
2859
|
+
checks.push({
|
|
2860
|
+
name,
|
|
2861
|
+
command: claimed.command,
|
|
2862
|
+
claimedExitCode: claimed.exitCode,
|
|
2863
|
+
actualExitCode: actual.exitCode,
|
|
2864
|
+
ok
|
|
2865
|
+
});
|
|
2866
|
+
}
|
|
2867
|
+
if (checks.length === 0) return { status: "missing", checks };
|
|
2868
|
+
const status = checks.every((c) => c.ok) ? "verified" : "failed";
|
|
2869
|
+
return { status, checks };
|
|
2870
|
+
}
|
|
2871
|
+
|
|
2764
2872
|
// src/chimera-review-task.ts
|
|
2765
2873
|
import { parseReviewSeverity } from "@wrongstack/core/plugin";
|
|
2766
2874
|
function truncateAtCodePointBoundary(text, maxCodeUnits) {
|
|
@@ -2861,6 +2969,34 @@ function buildChimeraReviewTaskDescription(p) {
|
|
|
2861
2969
|
lines.push("structured review report.");
|
|
2862
2970
|
return lines.join("\n");
|
|
2863
2971
|
}
|
|
2972
|
+
var CASCADE_EVIDENCE_INSTRUCTIONS = [
|
|
2973
|
+
`After fixing, run the project's REAL verification commands on the code you changed`,
|
|
2974
|
+
`(typecheck, lint, and the tests covering the fixed code) and return a machine-evidence`,
|
|
2975
|
+
`block as the LAST section of your response. The block MUST be a fenced JSON block`,
|
|
2976
|
+
`(exactly \`\`\`json ... \`\`\`) with this shape:`,
|
|
2977
|
+
``,
|
|
2978
|
+
"```json",
|
|
2979
|
+
"{",
|
|
2980
|
+
' "verification_evidence": {',
|
|
2981
|
+
' "typecheck": { "command": "pnpm typecheck", "exitCode": 0 },',
|
|
2982
|
+
' "lint": { "command": "pnpm lint", "exitCode": 0 },',
|
|
2983
|
+
' "tests": { "command": "pnpm test --filter affected", "exitCode": 0 }',
|
|
2984
|
+
" }",
|
|
2985
|
+
"}",
|
|
2986
|
+
"```",
|
|
2987
|
+
``,
|
|
2988
|
+
`Rules:`,
|
|
2989
|
+
`- \`command\` must be the EXACT command you ran (plain executable + args, no shell`,
|
|
2990
|
+
` chaining like \`&&\`/\`;\`/\`|\`, no redirection, no shell expansion). These commands are`,
|
|
2991
|
+
` re-run verbatim by the orchestrator to verify your work.`,
|
|
2992
|
+
`- \`exitCode\` is the real process exit code you observed: 0 = passed, non-zero = failed.`,
|
|
2993
|
+
` Never invent or omit an exit code. If a command cannot be run, omit that key entirely`,
|
|
2994
|
+
` and explain why in your report text \u2014 an omitted key is honest, a fabricated 0 is not.`,
|
|
2995
|
+
`- If your fix does not pass a command, report the true non-zero exit code; the`,
|
|
2996
|
+
` orchestrator will treat the fix as unverified and keep the finding open.`,
|
|
2997
|
+
`- At least \`typecheck\` must be present; include \`lint\` and \`tests\` when the project`,
|
|
2998
|
+
` has them.`
|
|
2999
|
+
].join("\n");
|
|
2864
3000
|
function buildChimeraCascadeTaskDescription(agentKind, p) {
|
|
2865
3001
|
const fileList = p.bundle.files.map((f) => `- ${f.path}`).join("\n");
|
|
2866
3002
|
const reportSlice = truncateAtCodePointBoundary(p.reviewText, 12e3);
|
|
@@ -2881,8 +3017,9 @@ function buildChimeraCascadeTaskDescription(agentKind, p) {
|
|
|
2881
3017
|
`Investigate the security findings above. Read the flagged files, confirm or refute`,
|
|
2882
3018
|
`each finding, and **apply fixes** for confirmed vulnerabilities using the edit tool.`,
|
|
2883
3019
|
`Use severity (Critical/High/Medium), file:line citations, and remediation steps.`,
|
|
2884
|
-
`
|
|
2885
|
-
|
|
3020
|
+
`If a finding is a false positive, say so and do not modify the file.`,
|
|
3021
|
+
``,
|
|
3022
|
+
CASCADE_EVIDENCE_INSTRUCTIONS
|
|
2886
3023
|
].join("\n");
|
|
2887
3024
|
}
|
|
2888
3025
|
return [
|
|
@@ -2899,9 +3036,10 @@ function buildChimeraCascadeTaskDescription(agentKind, p) {
|
|
|
2899
3036
|
``,
|
|
2900
3037
|
`Hunt for the bugs flagged above. Read the affected files, trace each finding to its`,
|
|
2901
3038
|
`root cause, and **apply minimal fixes** for confirmed bugs using the edit tool.`,
|
|
2902
|
-
`Use severity (Critical/High/Medium), file:line citations.
|
|
2903
|
-
`
|
|
2904
|
-
|
|
3039
|
+
`Use severity (Critical/High/Medium), file:line citations. If a finding is a false`,
|
|
3040
|
+
`positive, say so and do not modify the file.`,
|
|
3041
|
+
``,
|
|
3042
|
+
CASCADE_EVIDENCE_INSTRUCTIONS
|
|
2905
3043
|
].join("\n");
|
|
2906
3044
|
}
|
|
2907
3045
|
|
|
@@ -3018,7 +3156,9 @@ function installChimeraCascadeHandler({
|
|
|
3018
3156
|
session,
|
|
3019
3157
|
getPendingWork,
|
|
3020
3158
|
trackWork,
|
|
3021
|
-
buildLadder
|
|
3159
|
+
buildLadder,
|
|
3160
|
+
verifyEvidence = verifyCascadeEvidence,
|
|
3161
|
+
persistEvidence
|
|
3022
3162
|
}) {
|
|
3023
3163
|
events.onPattern("chimera.cascade_needed", (_event, payload) => {
|
|
3024
3164
|
const p = payload;
|
|
@@ -3031,6 +3171,7 @@ function installChimeraCascadeHandler({
|
|
|
3031
3171
|
await previousWork;
|
|
3032
3172
|
} catch {
|
|
3033
3173
|
}
|
|
3174
|
+
const agentEvidence = [];
|
|
3034
3175
|
for (const agentKind of p.agents) {
|
|
3035
3176
|
try {
|
|
3036
3177
|
const taskDesc = buildChimeraCascadeTaskDescription(agentKind, p);
|
|
@@ -3074,6 +3215,10 @@ function installChimeraCascadeHandler({
|
|
|
3074
3215
|
const result = outcome.result;
|
|
3075
3216
|
if (result?.status === "success") {
|
|
3076
3217
|
const resultText = typeof result.result === "string" ? result.result : JSON.stringify(result.result);
|
|
3218
|
+
const claimed = extractCascadeEvidence(resultText);
|
|
3219
|
+
if (claimed) {
|
|
3220
|
+
agentEvidence.push({ agentKind, evidence: claimed });
|
|
3221
|
+
}
|
|
3077
3222
|
await session.append({
|
|
3078
3223
|
type: "llm_response",
|
|
3079
3224
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -3104,7 +3249,21 @@ function installChimeraCascadeHandler({
|
|
|
3104
3249
|
});
|
|
3105
3250
|
}
|
|
3106
3251
|
}
|
|
3107
|
-
|
|
3252
|
+
const accumulatedEvidence = {};
|
|
3253
|
+
for (const { evidence } of agentEvidence) {
|
|
3254
|
+
for (const name of ["typecheck", "lint", "tests"]) {
|
|
3255
|
+
if (evidence[name]) accumulatedEvidence[name] = evidence[name];
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3258
|
+
await maybeReReviewCascade({
|
|
3259
|
+
events,
|
|
3260
|
+
session,
|
|
3261
|
+
bundle: p.bundle,
|
|
3262
|
+
reportId: p.reportId,
|
|
3263
|
+
claimedEvidence: accumulatedEvidence,
|
|
3264
|
+
verifyEvidence,
|
|
3265
|
+
persistEvidence
|
|
3266
|
+
});
|
|
3108
3267
|
})();
|
|
3109
3268
|
trackWork(pendingWork);
|
|
3110
3269
|
});
|
|
@@ -3112,16 +3271,71 @@ function installChimeraCascadeHandler({
|
|
|
3112
3271
|
async function maybeReReviewCascade({
|
|
3113
3272
|
events,
|
|
3114
3273
|
session,
|
|
3115
|
-
bundle
|
|
3274
|
+
bundle,
|
|
3275
|
+
reportId,
|
|
3276
|
+
claimedEvidence,
|
|
3277
|
+
verifyEvidence,
|
|
3278
|
+
persistEvidence
|
|
3116
3279
|
}) {
|
|
3117
3280
|
const maxDepth = bundle.maxCascadeDepth ?? 0;
|
|
3118
3281
|
const currentDepth = bundle.cascadeDepth ?? 0;
|
|
3282
|
+
const hasClaimedEvidence = Object.keys(claimedEvidence).length > 0;
|
|
3283
|
+
const verification = hasClaimedEvidence ? await verifyEvidence(
|
|
3284
|
+
claimedEvidence,
|
|
3285
|
+
bundle.cwd,
|
|
3286
|
+
void 0,
|
|
3287
|
+
CASCADE_EVIDENCE_COMMAND_TIMEOUT_MS
|
|
3288
|
+
) : { status: "missing", checks: [] };
|
|
3289
|
+
const evidenceBundle = {
|
|
3290
|
+
...bundle,
|
|
3291
|
+
evidenceStatus: verification.status,
|
|
3292
|
+
evidenceChecks: verification.checks
|
|
3293
|
+
};
|
|
3294
|
+
if (reportId && persistEvidence) {
|
|
3295
|
+
try {
|
|
3296
|
+
await persistEvidence(reportId, verification.status, verification.checks);
|
|
3297
|
+
} catch (error) {
|
|
3298
|
+
await session.append({
|
|
3299
|
+
type: "error",
|
|
3300
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3301
|
+
message: `Chimera cascade evidence persistence failed: ${errorText2(error)}`,
|
|
3302
|
+
phase: "agent"
|
|
3303
|
+
});
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
3306
|
+
await session.append({
|
|
3307
|
+
type: "llm_response",
|
|
3308
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3309
|
+
content: [
|
|
3310
|
+
{
|
|
3311
|
+
type: "text",
|
|
3312
|
+
text: renderEvidenceSummary(verification.status, verification.checks)
|
|
3313
|
+
}
|
|
3314
|
+
],
|
|
3315
|
+
stopReason: "end_turn",
|
|
3316
|
+
usage: { input: 0, output: 0 }
|
|
3317
|
+
});
|
|
3318
|
+
if (verification.status !== "verified") {
|
|
3319
|
+
await session.append({
|
|
3320
|
+
type: "llm_response",
|
|
3321
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3322
|
+
content: [
|
|
3323
|
+
{
|
|
3324
|
+
type: "text",
|
|
3325
|
+
text: `\u{1F982} Chimera cascade evidence ${verification.status} \u2014 fix not confirmed, skipping re-review. Findings remain open.`
|
|
3326
|
+
}
|
|
3327
|
+
],
|
|
3328
|
+
stopReason: "end_turn",
|
|
3329
|
+
usage: { input: 0, output: 0 }
|
|
3330
|
+
});
|
|
3331
|
+
return;
|
|
3332
|
+
}
|
|
3119
3333
|
if (maxDepth > 0 && currentDepth < maxDepth) {
|
|
3120
3334
|
try {
|
|
3121
3335
|
const reReadFiles = [];
|
|
3122
|
-
for (const f of
|
|
3336
|
+
for (const f of evidenceBundle.files) {
|
|
3123
3337
|
try {
|
|
3124
|
-
const absPath = path10.join(
|
|
3338
|
+
const absPath = path10.join(evidenceBundle.cwd, f.path);
|
|
3125
3339
|
const content = await fsp.readFile(absPath, "utf8");
|
|
3126
3340
|
reReadFiles.push({ path: f.path, status: "modified", content });
|
|
3127
3341
|
} catch {
|
|
@@ -3129,7 +3343,7 @@ async function maybeReReviewCascade({
|
|
|
3129
3343
|
}
|
|
3130
3344
|
if (reReadFiles.length > 0) {
|
|
3131
3345
|
const reReviewBundle = {
|
|
3132
|
-
...
|
|
3346
|
+
...evidenceBundle,
|
|
3133
3347
|
files: reReadFiles,
|
|
3134
3348
|
cascadeDepth: currentDepth + 1
|
|
3135
3349
|
};
|
|
@@ -3187,18 +3401,28 @@ async function maybeReReviewCascade({
|
|
|
3187
3401
|
});
|
|
3188
3402
|
}
|
|
3189
3403
|
}
|
|
3404
|
+
function renderEvidenceSummary(status, checks) {
|
|
3405
|
+
if (status === "missing") return "no machine evidence supplied";
|
|
3406
|
+
const summary = checks.map((check) => `${check.name}:${check.ok ? "pass" : "fail"}(${check.actualExitCode})`).join(", ");
|
|
3407
|
+
return `${status}${summary ? ` \u2014 ${summary}` : ""}`;
|
|
3408
|
+
}
|
|
3409
|
+
function errorText2(error) {
|
|
3410
|
+
return error instanceof Error ? error.message : String(error);
|
|
3411
|
+
}
|
|
3190
3412
|
|
|
3191
3413
|
// src/execution-chimera-review.ts
|
|
3192
3414
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
3193
3415
|
import path11 from "node:path";
|
|
3194
|
-
import { effectiveFallbackChain } from "@wrongstack/core/agent";
|
|
3416
|
+
import { effectiveFallbackChain, fallbackProfileChain as fallbackProfileChain2 } from "@wrongstack/core/agent";
|
|
3195
3417
|
import {
|
|
3196
3418
|
CHIMERA_REVIEW_PROMPT,
|
|
3419
|
+
classifyChimeraReviewSource,
|
|
3197
3420
|
integrateFindings,
|
|
3198
3421
|
maybeCompactReviewStores,
|
|
3199
3422
|
parseChimeraReviewReport,
|
|
3200
3423
|
persistReviewReport,
|
|
3201
|
-
recordCompletedReview
|
|
3424
|
+
recordCompletedReview,
|
|
3425
|
+
verifyFindingsAgainstDisk
|
|
3202
3426
|
} from "@wrongstack/core/plugin";
|
|
3203
3427
|
function normalizeFileKeyForCitation(raw, cwd) {
|
|
3204
3428
|
const forward = raw.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
@@ -3282,7 +3506,13 @@ function installChimeraReviewHandler({
|
|
|
3282
3506
|
const rawModel = p.reviewFallbackModels ? p.config.model?.trim() || void 0 : tModel;
|
|
3283
3507
|
const baseProvider = rawProvider || tProvider || config.provider;
|
|
3284
3508
|
const baseModel = rawModel || tModel || config.model;
|
|
3285
|
-
const
|
|
3509
|
+
const configFallbacks = [...p.config.fallbackModels ?? []];
|
|
3510
|
+
if (p.config.fallbackProfile) {
|
|
3511
|
+
configFallbacks.push(...fallbackProfileChain2(config, p.config.fallbackProfile));
|
|
3512
|
+
}
|
|
3513
|
+
const baseFallbacks = p.reviewFallbackModels ? [...p.reviewFallbackModels] : resolveReviewerFallbackModels(
|
|
3514
|
+
configFallbacks.length > 0 ? configFallbacks : void 0
|
|
3515
|
+
);
|
|
3286
3516
|
const assigned = assignReviewerModels(
|
|
3287
3517
|
baseProvider,
|
|
3288
3518
|
baseModel,
|
|
@@ -3383,18 +3613,34 @@ function installChimeraReviewHandler({
|
|
|
3383
3613
|
}
|
|
3384
3614
|
const reviewText = typeof result.result === "string" ? result.result.trim() : JSON.stringify(result.result);
|
|
3385
3615
|
const reportId = randomUUID3();
|
|
3616
|
+
const reviewSource = classifyChimeraReviewSource(p);
|
|
3617
|
+
const winningAttempt = outcome.wonAt ? ladder[outcome.wonAt - 1] : void 0;
|
|
3618
|
+
const parsedReport = parseChimeraReviewReport(reviewText, {
|
|
3619
|
+
sessionId: reviewSessionId,
|
|
3620
|
+
agentId: p.fileProvenance?.find((entry) => entry.agentId)?.agentId ?? "chimera-review",
|
|
3621
|
+
reviewerModel: winningAttempt ? attemptLabel(winningAttempt) : void 0,
|
|
3622
|
+
reviewType: reviewSource,
|
|
3623
|
+
reportId
|
|
3624
|
+
});
|
|
3625
|
+
const verifiedFindings = await verifyFindingsAgainstDisk(parsedReport.findings, {
|
|
3626
|
+
cwd: p.cwd
|
|
3627
|
+
});
|
|
3628
|
+
const verifiedParsedReport = {
|
|
3629
|
+
...parsedReport,
|
|
3630
|
+
findings: verifiedFindings
|
|
3631
|
+
};
|
|
3386
3632
|
await persistAndEmitCompletion({
|
|
3387
3633
|
bundle: p,
|
|
3388
3634
|
reviewText,
|
|
3389
3635
|
status: "success",
|
|
3390
3636
|
cwd: p.cwd,
|
|
3391
3637
|
sessionId: reviewSessionId,
|
|
3392
|
-
reportId
|
|
3638
|
+
reportId,
|
|
3639
|
+
parsedReport: verifiedParsedReport
|
|
3393
3640
|
});
|
|
3394
3641
|
if (reviewText) {
|
|
3395
3642
|
const reviewHasFindings = !isChimeraAllClearReview(reviewText);
|
|
3396
|
-
const
|
|
3397
|
-
const citedFindings = parsedReview.findings.filter((finding) => finding.location);
|
|
3643
|
+
const citedFindings = verifiedFindings.filter((finding) => finding.location);
|
|
3398
3644
|
const citedPaths = new Set(
|
|
3399
3645
|
p.files.map((file) => normalizeFileKeyForCitation(file.path, p.cwd))
|
|
3400
3646
|
);
|
|
@@ -3406,14 +3652,28 @@ function installChimeraReviewHandler({
|
|
|
3406
3652
|
if (bucket) bucket.push(normalized);
|
|
3407
3653
|
else changedBasenameIndex.set(basename7, [normalized]);
|
|
3408
3654
|
}
|
|
3409
|
-
const
|
|
3655
|
+
const inScopeCited = citedFindings.filter((finding) => {
|
|
3410
3656
|
const citedKey = normalizeFileKeyForCitation(finding.location.file, p.cwd);
|
|
3411
|
-
if (citedPaths.has(citedKey)) return
|
|
3657
|
+
if (citedPaths.has(citedKey)) return true;
|
|
3412
3658
|
const basename7 = path11.basename(finding.location.file).toLowerCase();
|
|
3413
3659
|
const bucket = changedBasenameIndex.get(basename7);
|
|
3414
|
-
return
|
|
3660
|
+
return !!(bucket && bucket.length === 1);
|
|
3415
3661
|
});
|
|
3416
|
-
const
|
|
3662
|
+
const droppedCitations = citedFindings.filter(
|
|
3663
|
+
(finding) => !inScopeCited.includes(finding)
|
|
3664
|
+
);
|
|
3665
|
+
const actionableFindings = inScopeCited.filter(
|
|
3666
|
+
(finding) => finding.verification?.status === "verified"
|
|
3667
|
+
);
|
|
3668
|
+
const unverifiedInScope = inScopeCited.filter(
|
|
3669
|
+
(finding) => finding.verification?.status === "unverified"
|
|
3670
|
+
);
|
|
3671
|
+
const failedVerificationCount = inScopeCited.filter(
|
|
3672
|
+
(finding) => finding.verification?.status === "failed"
|
|
3673
|
+
).length;
|
|
3674
|
+
const effectiveHasFindings = reviewHasFindings && actionableFindings.length > 0;
|
|
3675
|
+
const verifiedCount = actionableFindings.length;
|
|
3676
|
+
const unverifiedCount = unverifiedInScope.length;
|
|
3417
3677
|
const hallucinationNote = droppedCitations.length > 0 ? `
|
|
3418
3678
|
|
|
3419
3679
|
\u26A0\uFE0F Citation validation: ${droppedCitations.length} finding(s) cite files outside the changed-file set and should be verified before acting.` : "";
|
|
@@ -3456,7 +3716,7 @@ ${reviewBody}`;
|
|
|
3456
3716
|
reviewLength: reviewText.length,
|
|
3457
3717
|
messageId: reviewMailMessageId
|
|
3458
3718
|
});
|
|
3459
|
-
if (!
|
|
3719
|
+
if (!reviewHasFindings) {
|
|
3460
3720
|
try {
|
|
3461
3721
|
await mailbox.ack({
|
|
3462
3722
|
messageId: reviewMailMessageId,
|
|
@@ -3500,11 +3760,8 @@ ${reviewBody}`;
|
|
|
3500
3760
|
phase: "agent"
|
|
3501
3761
|
});
|
|
3502
3762
|
}
|
|
3503
|
-
const findingCount =
|
|
3504
|
-
|
|
3505
|
-
parsedReview.findings.length - droppedCitations.length
|
|
3506
|
-
);
|
|
3507
|
-
const message = effectiveHasFindings ? `\u{1F982} Chimera report ready \u2014 ${findingCount || "unparsed"} potential finding(s) across ${p.files.length} file(s). No follow-up started; open the mailbox and explicitly ask the leader to act if wanted.` : `\u{1F982} Chimera report ready \u2014 ${p.files.length} file(s) checked, no actionable findings. No follow-up started.`;
|
|
3763
|
+
const findingCount = actionableFindings.length;
|
|
3764
|
+
const message = effectiveHasFindings ? `\u{1F982} Chimera report ready \u2014 ${findingCount || "unparsed"} potential finding(s) (${verifiedCount} verified against disk, ${unverifiedCount} unverified, ${failedVerificationCount} failed) across ${p.files.length} file(s). No follow-up started; open the mailbox and explicitly ask the leader to act if wanted.` : `\u{1F982} Chimera report ready \u2014 ${p.files.length} file(s) checked, no actionable findings. No follow-up started.`;
|
|
3508
3765
|
events.emitCustom("chimera.report_available", {
|
|
3509
3766
|
reportId,
|
|
3510
3767
|
sessionId: reviewSessionId,
|
|
@@ -3726,7 +3983,7 @@ function parseSuggestionsFromOutput(finalText, todos) {
|
|
|
3726
3983
|
setAutoSuggestions([]);
|
|
3727
3984
|
return null;
|
|
3728
3985
|
}
|
|
3729
|
-
const { texts, autoTexts } = parseNextSteps(finalText
|
|
3986
|
+
const { texts, autoTexts } = parseNextSteps(finalText);
|
|
3730
3987
|
if (autoTexts.length > 0) {
|
|
3731
3988
|
setAutoSuggestions(autoTexts);
|
|
3732
3989
|
}
|
|
@@ -4924,6 +5181,9 @@ async function execute(deps) {
|
|
|
4924
5181
|
session: { provider: config.provider, model: config.model }
|
|
4925
5182
|
}),
|
|
4926
5183
|
getPendingWork: () => chimeraWork.pending(),
|
|
5184
|
+
persistEvidence: async (reportId, status, checks) => {
|
|
5185
|
+
await updateReviewReportEvidence(reportId, wpaths.projectDir, status, checks);
|
|
5186
|
+
},
|
|
4927
5187
|
trackWork: (work) => {
|
|
4928
5188
|
chimeraWork.track(work);
|
|
4929
5189
|
}
|
|
@@ -5362,4 +5622,4 @@ export {
|
|
|
5362
5622
|
execute,
|
|
5363
5623
|
resolveReviewerFallbackModels
|
|
5364
5624
|
};
|
|
5365
|
-
//# sourceMappingURL=execution-
|
|
5625
|
+
//# sourceMappingURL=execution-TTE7R5UY.js.map
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { CascadeEvidenceCheckResult, CascadeEvidenceStatus } from '@wrongstack/core/plugin';
|
|
2
|
+
import { verifyCascadeEvidence } from './chimera-cascade-evidence.js';
|
|
1
3
|
import type { ReviewerAttempt } from './chimera-reviewer-policy.js';
|
|
2
4
|
import type { ExecuteDeps } from './execute-deps.js';
|
|
3
5
|
type Director = NonNullable<ExecuteDeps['fleet']['director']>;
|
|
@@ -14,7 +16,11 @@ export type InstallChimeraCascadeHandlerOptions = {
|
|
|
14
16
|
* holds the live config. Omit to keep the single unpinned spawn.
|
|
15
17
|
*/
|
|
16
18
|
buildLadder?: (() => ReviewerAttempt[]) | undefined;
|
|
19
|
+
/** Test seam; production defaults to the real safe command verifier. */
|
|
20
|
+
verifyEvidence?: typeof verifyCascadeEvidence | undefined;
|
|
21
|
+
/** Persist every evidence verdict on the source report, even when re-review stops. */
|
|
22
|
+
persistEvidence?: ((reportId: string, status: CascadeEvidenceStatus, checks: CascadeEvidenceCheckResult[]) => Promise<void>) | undefined;
|
|
17
23
|
};
|
|
18
|
-
export declare function installChimeraCascadeHandler({ events, director, session, getPendingWork, trackWork, buildLadder, }: InstallChimeraCascadeHandlerOptions): void;
|
|
24
|
+
export declare function installChimeraCascadeHandler({ events, director, session, getPendingWork, trackWork, buildLadder, verifyEvidence, persistEvidence, }: InstallChimeraCascadeHandlerOptions): void;
|
|
19
25
|
export {};
|
|
20
26
|
//# sourceMappingURL=execution-chimera-cascade.d.ts.map
|