auditor-lambda 0.8.0 → 0.9.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/audit-code-wrapper-lib.mjs +149 -129
- package/dist/adapters/normalizeExternal.js +6 -3
- package/dist/cli/args.d.ts +0 -1
- package/dist/cli/args.js +0 -6
- package/dist/cli/dispatch.js +3 -2
- package/dist/cli/lineIndex.js +4 -1
- package/dist/cli/mergeAndIngestCommand.d.ts +1 -0
- package/dist/cli/mergeAndIngestCommand.js +219 -0
- package/dist/cli/nextStepCommand.js +5 -1
- package/dist/cli/runToCompletion.d.ts +9 -0
- package/dist/cli/runToCompletion.js +655 -480
- package/dist/cli/statusCommand.d.ts +1 -0
- package/dist/cli/statusCommand.js +113 -0
- package/dist/cli/submitPacketCommand.d.ts +1 -0
- package/dist/cli/submitPacketCommand.js +155 -0
- package/dist/cli/workerResult.d.ts +1 -1
- package/dist/cli/workerRunCommand.d.ts +1 -0
- package/dist/cli/workerRunCommand.js +88 -0
- package/dist/cli.js +14 -563
- package/dist/extractors/analyzers/sql.js +4 -1
- package/dist/extractors/analyzers/treeSitter.js +29 -15
- package/dist/extractors/analyzers/typescript.js +10 -8
- package/dist/extractors/designAssessment.js +43 -24
- package/dist/extractors/graph.js +139 -73
- package/dist/extractors/pathPatterns.js +17 -5
- package/dist/io/runArtifactTypes.d.ts +18 -0
- package/dist/io/runArtifactTypes.js +1 -0
- package/dist/io/runArtifacts.d.ts +2 -18
- package/dist/io/runArtifacts.js +14 -3
- package/dist/mcp/server.js +9 -0
- package/dist/orchestrator/advance.js +37 -22
- package/dist/orchestrator/artifactFreshness.js +2 -2
- package/dist/orchestrator/autoFixExecutor.d.ts +1 -1
- package/dist/orchestrator/autoFixExecutor.js +16 -8
- package/dist/orchestrator/dependencyMap.d.ts +1 -1
- package/dist/orchestrator/dependencyMap.js +7 -1
- package/dist/orchestrator/fileAnchors.js +14 -3
- package/dist/orchestrator/flowCoverage.js +1 -0
- package/dist/orchestrator/flowRequeue.js +4 -1
- package/dist/orchestrator/{internalExecutors.d.ts → ingestionExecutors.d.ts} +0 -6
- package/dist/orchestrator/ingestionExecutors.js +237 -0
- package/dist/orchestrator/intakeExecutors.d.ts +3 -0
- package/dist/orchestrator/intakeExecutors.js +25 -0
- package/dist/orchestrator/planningExecutors.d.ts +4 -0
- package/dist/orchestrator/planningExecutors.js +95 -0
- package/dist/orchestrator/runtimeCommand.js +7 -15
- package/dist/orchestrator/selectiveDeepening/conflict.d.ts +8 -0
- package/dist/orchestrator/selectiveDeepening/conflict.js +71 -0
- package/dist/orchestrator/selectiveDeepening/findingFollowup.d.ts +10 -0
- package/dist/orchestrator/selectiveDeepening/findingFollowup.js +52 -0
- package/dist/orchestrator/selectiveDeepening/highRiskClean.d.ts +7 -0
- package/dist/orchestrator/selectiveDeepening/highRiskClean.js +44 -0
- package/dist/orchestrator/selectiveDeepening/index.d.ts +18 -0
- package/dist/orchestrator/selectiveDeepening/index.js +128 -0
- package/dist/orchestrator/selectiveDeepening/lensVerification.d.ts +12 -0
- package/dist/orchestrator/selectiveDeepening/lensVerification.js +242 -0
- package/dist/orchestrator/selectiveDeepening/runtimeValidation.d.ts +13 -0
- package/dist/orchestrator/selectiveDeepening/runtimeValidation.js +57 -0
- package/dist/orchestrator/selectiveDeepening/shared.d.ts +45 -0
- package/dist/orchestrator/selectiveDeepening/shared.js +128 -0
- package/dist/orchestrator/selectiveDeepening/stewardFollowup.d.ts +6 -0
- package/dist/orchestrator/selectiveDeepening/stewardFollowup.js +72 -0
- package/dist/orchestrator/selectiveDeepening.d.ts +2 -20
- package/dist/orchestrator/selectiveDeepening.js +6 -760
- package/dist/orchestrator/staleness.js +3 -3
- package/dist/orchestrator/structureExecutors.d.ts +5 -0
- package/dist/orchestrator/structureExecutors.js +94 -0
- package/dist/orchestrator/taskBuilder.d.ts +2 -2
- package/dist/orchestrator/taskBuilder.js +101 -82
- package/dist/providers/index.d.ts +7 -0
- package/dist/providers/index.js +14 -95
- package/dist/quota/discoveredLimits.d.ts +1 -0
- package/dist/quota/discoveredLimits.js +7 -1
- package/dist/quota/index.d.ts +0 -2
- package/dist/quota/index.js +1 -2
- package/dist/reporting/workBlocks.js +7 -4
- package/dist/types/reviewPlanning.d.ts +23 -16
- package/dist/validation/auditResults.js +97 -95
- package/dist/validation/sessionConfig.d.ts +2 -2
- package/dist/validation/sessionConfig.js +14 -7
- package/package.json +3 -2
- package/schemas/audit_findings.schema.json +3 -3
- package/schemas/critical_flows.schema.json +3 -2
- package/schemas/dispatch_quota.schema.json +1 -1
- package/schemas/graph_bundle.schema.json +1 -1
- package/schemas/review_packets.schema.json +1 -1
- package/schemas/step_contract.schema.json +80 -0
- package/scripts/postinstall.mjs +19 -2
- package/skills/audit-code/opencode-command-template.txt +3 -3
- package/dist/orchestrator/internalExecutors.js +0 -424
- package/dist/providers/localSubprocessProvider.d.ts +0 -9
- package/dist/providers/localSubprocessProvider.js +0 -18
- package/dist/providers/subprocessTemplateProvider.d.ts +0 -8
- package/dist/providers/subprocessTemplateProvider.js +0 -59
- package/dist/providers/vscodeTaskProvider.d.ts +0 -7
- package/dist/providers/vscodeTaskProvider.js +0 -14
- package/dist/quota/probe.d.ts +0 -10
- package/dist/quota/probe.js +0 -18
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function cmdStatus(argv: string[]): Promise<void>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { isFileMissingError, readJsonFile } from "@audit-tools/shared";
|
|
4
|
+
import { loadRunLedger } from "../supervisor/runLedger.js";
|
|
5
|
+
import { getArtifactsDir } from "./args.js";
|
|
6
|
+
export async function cmdStatus(argv) {
|
|
7
|
+
const artifactsDir = getArtifactsDir(argv);
|
|
8
|
+
const auditStatePath = join(artifactsDir, "audit_state.json");
|
|
9
|
+
// 1. Read audit_state.json
|
|
10
|
+
let auditState = null;
|
|
11
|
+
try {
|
|
12
|
+
auditState = await readJsonFile(auditStatePath);
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
if (!isFileMissingError(error)) {
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (!auditState) {
|
|
20
|
+
console.error("No audit_state.json found; no active audit in this artifacts directory.");
|
|
21
|
+
process.exitCode = 1;
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
// Build obligations summary: count by state
|
|
25
|
+
const obligationStates = {
|
|
26
|
+
missing: 0,
|
|
27
|
+
present: 0,
|
|
28
|
+
stale: 0,
|
|
29
|
+
blocked: 0,
|
|
30
|
+
satisfied: 0,
|
|
31
|
+
};
|
|
32
|
+
for (const obligation of auditState.obligations ?? []) {
|
|
33
|
+
const state = obligation.state;
|
|
34
|
+
if (state in obligationStates) {
|
|
35
|
+
obligationStates[state]++;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// 2. Read run ledger for last N entries
|
|
39
|
+
const ledger = await loadRunLedger(artifactsDir);
|
|
40
|
+
const RECENT_RUN_LIMIT = 5;
|
|
41
|
+
const recentRuns = ledger.runs
|
|
42
|
+
.slice(-RECENT_RUN_LIMIT)
|
|
43
|
+
.reverse()
|
|
44
|
+
.map((entry) => ({
|
|
45
|
+
run_id: entry.run_id,
|
|
46
|
+
obligation_id: entry.obligation_id,
|
|
47
|
+
status: entry.status,
|
|
48
|
+
started_at: entry.started_at,
|
|
49
|
+
}));
|
|
50
|
+
// 3. Find the most recent run directory and read pending-audit-tasks.json
|
|
51
|
+
let pendingTasksSummary = null;
|
|
52
|
+
const runsDir = join(artifactsDir, "runs");
|
|
53
|
+
let runDirs = [];
|
|
54
|
+
try {
|
|
55
|
+
const entries = await readdir(runsDir, { withFileTypes: true });
|
|
56
|
+
runDirs = entries
|
|
57
|
+
.filter((e) => e.isDirectory())
|
|
58
|
+
.map((e) => e.name)
|
|
59
|
+
.sort()
|
|
60
|
+
.reverse();
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// runs directory may not exist yet
|
|
64
|
+
}
|
|
65
|
+
for (const runDirName of runDirs) {
|
|
66
|
+
const runDir = join(runsDir, runDirName);
|
|
67
|
+
const tasksPath = join(runDir, "pending-audit-tasks.json");
|
|
68
|
+
let tasks = null;
|
|
69
|
+
try {
|
|
70
|
+
tasks = await readJsonFile(tasksPath);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
continue; // no pending-audit-tasks.json in this run dir — try previous
|
|
74
|
+
}
|
|
75
|
+
if (!Array.isArray(tasks))
|
|
76
|
+
continue;
|
|
77
|
+
// Count remaining: tasks without status "complete"
|
|
78
|
+
const total = tasks.length;
|
|
79
|
+
const remaining = tasks.filter((t) => t.status !== "complete").length;
|
|
80
|
+
pendingTasksSummary = {
|
|
81
|
+
run_id: runDirName,
|
|
82
|
+
total,
|
|
83
|
+
remaining,
|
|
84
|
+
};
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
// 4. Surface failed-tasks.json from the most recent run that has one
|
|
88
|
+
let failedTasks = null;
|
|
89
|
+
for (const runDirName of runDirs) {
|
|
90
|
+
const failedTasksPath = join(runsDir, runDirName, "failed-tasks.json");
|
|
91
|
+
try {
|
|
92
|
+
const raw = await readJsonFile(failedTasksPath);
|
|
93
|
+
if (Array.isArray(raw) && raw.length > 0) {
|
|
94
|
+
failedTasks = raw;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// Not present in this run dir — keep looking
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
console.log(JSON.stringify({
|
|
103
|
+
artifacts_dir: artifactsDir,
|
|
104
|
+
status: auditState.status,
|
|
105
|
+
last_obligation: auditState.last_obligation ?? null,
|
|
106
|
+
last_executor: auditState.last_executor ?? null,
|
|
107
|
+
blockers: auditState.blockers ?? [],
|
|
108
|
+
obligations_summary: obligationStates,
|
|
109
|
+
recent_runs: recentRuns,
|
|
110
|
+
pending_tasks: pendingTasksSummary,
|
|
111
|
+
failed_tasks: failedTasks,
|
|
112
|
+
}, null, 2));
|
|
113
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function cmdSubmitPacket(argv: string[]): Promise<void>;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { readJsonFile, writeJsonFile } from "@audit-tools/shared";
|
|
4
|
+
import { validateAuditResults, formatAuditResultIssues } from "../validation/auditResults.js";
|
|
5
|
+
import { DISPATCH_RESULT_MAP_FILENAME, resolveRunScopedArg, loadDispatchResultMap, entriesByTaskId, } from "./dispatch.js";
|
|
6
|
+
import { fromBase64Url, getArtifactsDir, getFlag, readStdinText } from "./args.js";
|
|
7
|
+
export async function cmdSubmitPacket(argv) {
|
|
8
|
+
const runId = resolveRunScopedArg(argv, "--run-id", "--run-id-b64");
|
|
9
|
+
const packetId = resolveRunScopedArg(argv, "--packet-id", "--packet-id-b64");
|
|
10
|
+
const artifactsDirB64 = getFlag(argv, "--artifacts-dir-b64");
|
|
11
|
+
const artifactsDir = artifactsDirB64
|
|
12
|
+
? resolve(fromBase64Url(artifactsDirB64))
|
|
13
|
+
: getArtifactsDir(argv);
|
|
14
|
+
if (!runId || !packetId) {
|
|
15
|
+
throw new Error("submit-packet requires --run-id and --packet-id (or --run-id-b64/--packet-id-b64)");
|
|
16
|
+
}
|
|
17
|
+
const runDir = join(artifactsDir, "runs", runId);
|
|
18
|
+
const tasksPath = join(runDir, "pending-audit-tasks.json");
|
|
19
|
+
const resultMap = await loadDispatchResultMap(runDir);
|
|
20
|
+
if (!resultMap) {
|
|
21
|
+
throw new Error(`No ${DISPATCH_RESULT_MAP_FILENAME} found for run ${runId}; run prepare-dispatch first.`);
|
|
22
|
+
}
|
|
23
|
+
let packetEntries = resultMap.entries.filter((entry) => entry.packet_id === packetId);
|
|
24
|
+
let resolvedPacketId = packetId;
|
|
25
|
+
if (packetEntries.length === 0) {
|
|
26
|
+
const trimmed = packetId.trim();
|
|
27
|
+
packetEntries = resultMap.entries.filter((entry) => entry.packet_id.trim().toLowerCase() === trimmed.toLowerCase());
|
|
28
|
+
if (packetEntries.length > 0) {
|
|
29
|
+
resolvedPacketId = packetEntries[0].packet_id;
|
|
30
|
+
process.stderr.write(`[submit-packet] Resolved packet_id '${packetId}' → '${resolvedPacketId}' (case/whitespace normalization)\n`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (packetEntries.length === 0) {
|
|
34
|
+
const knownIds = [...new Set(resultMap.entries.map((e) => e.packet_id))];
|
|
35
|
+
throw new Error(`Unknown packet_id '${packetId}' for run ${runId}.\n` +
|
|
36
|
+
`Valid packet IDs: ${knownIds.join(", ")}`);
|
|
37
|
+
}
|
|
38
|
+
if (entriesByTaskId(packetEntries).size !== packetEntries.length) {
|
|
39
|
+
throw new Error(`Dispatch result map has duplicate task entries for packet '${resolvedPacketId}'.`);
|
|
40
|
+
}
|
|
41
|
+
const allTasks = await readJsonFile(tasksPath);
|
|
42
|
+
const taskById = new Map(allTasks.map((task) => [task.task_id, task]));
|
|
43
|
+
const packetTasks = packetEntries.map((entry) => taskById.get(entry.task_id));
|
|
44
|
+
const missingTask = packetEntries.find((entry, index) => !packetTasks[index]);
|
|
45
|
+
if (missingTask) {
|
|
46
|
+
throw new Error(`Dispatch result map references unknown task '${missingTask.task_id}'.`);
|
|
47
|
+
}
|
|
48
|
+
const tasks = packetTasks;
|
|
49
|
+
const expectedTaskIds = new Set(tasks.map((task) => task.task_id));
|
|
50
|
+
const lineIndex = Object.fromEntries(tasks.flatMap((task) => Object.entries(task.file_line_counts ?? {})));
|
|
51
|
+
const encodedResults = getFlag(argv, "--results-b64");
|
|
52
|
+
const raw = encodedResults ? fromBase64Url(encodedResults) : await readStdinText();
|
|
53
|
+
if (raw.trim().length === 0) {
|
|
54
|
+
throw new Error("submit-packet requires an AuditResult[] JSON payload on stdin or --results-b64.");
|
|
55
|
+
}
|
|
56
|
+
let payload;
|
|
57
|
+
try {
|
|
58
|
+
payload = JSON.parse(raw);
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw new Error(`Invalid submit-packet JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
62
|
+
}
|
|
63
|
+
const resultErrors = [];
|
|
64
|
+
const issues = validateAuditResults(payload, tasks, { lineIndex });
|
|
65
|
+
const validationErrors = issues.filter((issue) => issue.severity === "error");
|
|
66
|
+
const validationWarnings = issues.filter((issue) => issue.severity === "warning");
|
|
67
|
+
if (validationWarnings.length > 0) {
|
|
68
|
+
process.stderr.write(`audit-results validation: ${validationWarnings.length} warning(s):\n` +
|
|
69
|
+
formatAuditResultIssues(validationWarnings) +
|
|
70
|
+
"\n");
|
|
71
|
+
}
|
|
72
|
+
if (validationErrors.length > 0) {
|
|
73
|
+
resultErrors.push(formatAuditResultIssues(validationErrors));
|
|
74
|
+
}
|
|
75
|
+
if (Array.isArray(payload)) {
|
|
76
|
+
const seen = new Set();
|
|
77
|
+
for (const [index, result] of payload.entries()) {
|
|
78
|
+
if (!result || typeof result !== "object" || Array.isArray(result)) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const taskId = result.task_id;
|
|
82
|
+
if (typeof taskId !== "string" || taskId.trim().length === 0) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (seen.has(taskId)) {
|
|
86
|
+
resultErrors.push(`Duplicate audit result for assigned task '${taskId}'.`);
|
|
87
|
+
}
|
|
88
|
+
seen.add(taskId);
|
|
89
|
+
if (!expectedTaskIds.has(taskId)) {
|
|
90
|
+
resultErrors.push(`Result at index ${index} uses task_id '${taskId}', which is not assigned to packet '${resolvedPacketId}'.`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
for (const task of tasks) {
|
|
94
|
+
if (!seen.has(task.task_id)) {
|
|
95
|
+
resultErrors.push(`Missing audit result for assigned task '${task.task_id}'.`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (resultErrors.length > 0) {
|
|
100
|
+
throw new Error(`submit-packet rejected ${resolvedPacketId}:\n${resultErrors.join("\n")}`);
|
|
101
|
+
}
|
|
102
|
+
// Check for duplicate findings against already-submitted results in this run
|
|
103
|
+
const existingFindingKeys = new Set();
|
|
104
|
+
const otherEntries = resultMap.entries.filter((e) => e.packet_id !== resolvedPacketId);
|
|
105
|
+
for (const other of otherEntries) {
|
|
106
|
+
try {
|
|
107
|
+
const existing = JSON.parse(await readFile(other.result_path, "utf8"));
|
|
108
|
+
if (existing?.findings) {
|
|
109
|
+
for (const f of existing.findings) {
|
|
110
|
+
const key = [
|
|
111
|
+
(f.lens ?? "").trim().toLowerCase(),
|
|
112
|
+
(f.category ?? "").trim().toLowerCase(),
|
|
113
|
+
(f.title ?? "").trim().toLowerCase(),
|
|
114
|
+
f.affected_files?.[0]?.path ?? "",
|
|
115
|
+
].join("|");
|
|
116
|
+
existingFindingKeys.add(key);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch { /* file doesn't exist yet or invalid — skip */ }
|
|
121
|
+
}
|
|
122
|
+
let dupCount = 0;
|
|
123
|
+
for (const result of payload) {
|
|
124
|
+
for (const f of result.findings ?? []) {
|
|
125
|
+
const key = [
|
|
126
|
+
(f.lens ?? "").trim().toLowerCase(),
|
|
127
|
+
(f.category ?? "").trim().toLowerCase(),
|
|
128
|
+
(f.title ?? "").trim().toLowerCase(),
|
|
129
|
+
f.affected_files?.[0]?.path ?? "",
|
|
130
|
+
].join("|");
|
|
131
|
+
if (existingFindingKeys.has(key)) {
|
|
132
|
+
dupCount++;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (dupCount > 0) {
|
|
137
|
+
process.stderr.write(`[submit-packet] Warning: ${dupCount} finding(s) appear to duplicate findings from other packets in this run.\n`);
|
|
138
|
+
}
|
|
139
|
+
const entryByTaskId = entriesByTaskId(packetEntries);
|
|
140
|
+
for (const result of payload) {
|
|
141
|
+
const entry = entryByTaskId.get(result.task_id);
|
|
142
|
+
if (!entry) {
|
|
143
|
+
throw new Error(`Internal error: no result path for accepted task '${result.task_id}'.`);
|
|
144
|
+
}
|
|
145
|
+
await writeJsonFile(entry.result_path, result);
|
|
146
|
+
}
|
|
147
|
+
const findingCount = payload.reduce((sum, result) => sum + result.findings.length, 0);
|
|
148
|
+
console.log(JSON.stringify({
|
|
149
|
+
run_id: runId,
|
|
150
|
+
packet_id: resolvedPacketId,
|
|
151
|
+
accepted_count: payload.length,
|
|
152
|
+
finding_count: findingCount,
|
|
153
|
+
...(dupCount > 0 ? { duplicate_warning_count: dupCount } : {}),
|
|
154
|
+
}, null, 2));
|
|
155
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { WorkerResult } from "../types/workerResult.js";
|
|
2
|
-
import type { RunPaths } from "../io/
|
|
2
|
+
import type { RunPaths } from "../io/runArtifactTypes.js";
|
|
3
3
|
export declare const WORKER_RESULT_CONTRACT_VERSION = "audit-code-worker-result/v1alpha1";
|
|
4
4
|
export declare function buildWorkerResult(params: {
|
|
5
5
|
runId: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function cmdWorkerRun(argv: string[]): Promise<void>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { readJsonFile, writeJsonFile } from "@audit-tools/shared";
|
|
2
|
+
import { validateAuditResults, formatAuditResultIssues } from "../validation/auditResults.js";
|
|
3
|
+
import { runAuditStep } from "./auditStep.js";
|
|
4
|
+
import { buildLineIndexForPaths } from "./lineIndex.js";
|
|
5
|
+
import { WORKER_RESULT_CONTRACT_VERSION, formatAuditResultValidationError } from "./workerResult.js";
|
|
6
|
+
import { getFlag, looksLikeCliFlag } from "./args.js";
|
|
7
|
+
export async function cmdWorkerRun(argv) {
|
|
8
|
+
const taskPath = getFlag(argv, "--task");
|
|
9
|
+
if (!taskPath) {
|
|
10
|
+
throw new Error("worker-run requires --task <path>");
|
|
11
|
+
}
|
|
12
|
+
const task = await readJsonFile(taskPath);
|
|
13
|
+
let workerResult;
|
|
14
|
+
try {
|
|
15
|
+
if (looksLikeCliFlag(task.audit_results_path)) {
|
|
16
|
+
throw new Error(`task.audit_results_path resolved to '${task.audit_results_path}', which looks like a CLI flag instead of a file path.`);
|
|
17
|
+
}
|
|
18
|
+
if (task.preferred_executor === "agent" && !task.audit_results_path) {
|
|
19
|
+
throw new Error("agent worker-run requires audit_results_path so provider-assisted review can be ingested.");
|
|
20
|
+
}
|
|
21
|
+
if (task.preferred_executor === "agent" && task.audit_results_path) {
|
|
22
|
+
const pendingTasks = task.pending_audit_tasks_path
|
|
23
|
+
? await readJsonFile(task.pending_audit_tasks_path)
|
|
24
|
+
: [];
|
|
25
|
+
const auditResults = await readJsonFile(task.audit_results_path);
|
|
26
|
+
const pendingTaskIds = new Set(pendingTasks.map((item) => item.task_id));
|
|
27
|
+
const matchedResultCount = auditResults.filter((result) => pendingTaskIds.has(result.task_id)).length;
|
|
28
|
+
if (pendingTasks.length > 0 && matchedResultCount === 0) {
|
|
29
|
+
throw new Error("Provider-assisted review did not emit any audit results for the pending audit tasks.");
|
|
30
|
+
}
|
|
31
|
+
const issues = validateAuditResults(auditResults, pendingTasks, {
|
|
32
|
+
lineIndex: await buildLineIndexForPaths(task.repo_root, pendingTasks.flatMap((item) => item.file_paths)),
|
|
33
|
+
});
|
|
34
|
+
const errors = issues.filter((issue) => issue.severity === "error");
|
|
35
|
+
const warnings = issues.filter((issue) => issue.severity === "warning");
|
|
36
|
+
if (warnings.length > 0) {
|
|
37
|
+
process.stderr.write(`audit-results validation: ${warnings.length} warning(s):\n` +
|
|
38
|
+
formatAuditResultIssues(warnings) +
|
|
39
|
+
"\n");
|
|
40
|
+
}
|
|
41
|
+
if (errors.length > 0) {
|
|
42
|
+
throw new Error(formatAuditResultValidationError(errors));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const preferredExecutor = task.preferred_executor === "agent"
|
|
46
|
+
? "result_ingestion_executor"
|
|
47
|
+
: task.preferred_executor;
|
|
48
|
+
const result = await runAuditStep({
|
|
49
|
+
root: task.repo_root,
|
|
50
|
+
artifactsDir: task.artifacts_dir,
|
|
51
|
+
preferredExecutor,
|
|
52
|
+
auditResultsPath: task.audit_results_path,
|
|
53
|
+
runtimeUpdatesPath: task.runtime_updates_path,
|
|
54
|
+
externalAnalyzerPath: task.external_analyzer_results_path,
|
|
55
|
+
});
|
|
56
|
+
workerResult = {
|
|
57
|
+
contract_version: WORKER_RESULT_CONTRACT_VERSION,
|
|
58
|
+
run_id: task.run_id,
|
|
59
|
+
obligation_id: task.obligation_id,
|
|
60
|
+
status: result.progress_made ? "completed" : "no_progress",
|
|
61
|
+
progress_made: result.progress_made,
|
|
62
|
+
selected_executor: result.selected_executor,
|
|
63
|
+
artifacts_written: result.artifacts_written,
|
|
64
|
+
summary: result.progress_summary,
|
|
65
|
+
next_likely_step: result.next_likely_step,
|
|
66
|
+
errors: [],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
workerResult = {
|
|
71
|
+
contract_version: WORKER_RESULT_CONTRACT_VERSION,
|
|
72
|
+
run_id: task.run_id,
|
|
73
|
+
obligation_id: task.obligation_id,
|
|
74
|
+
status: "failed",
|
|
75
|
+
progress_made: false,
|
|
76
|
+
selected_executor: task.preferred_executor,
|
|
77
|
+
artifacts_written: [],
|
|
78
|
+
summary: `Worker failed for executor ${task.preferred_executor}: ${error instanceof Error ? error.message : String(error)}`,
|
|
79
|
+
next_likely_step: task.obligation_id,
|
|
80
|
+
errors: [error instanceof Error ? error.message : String(error)],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
await writeJsonFile(task.result_path, workerResult);
|
|
84
|
+
console.log(JSON.stringify(workerResult, null, 2));
|
|
85
|
+
if (workerResult.status === "failed") {
|
|
86
|
+
process.exitCode = 1;
|
|
87
|
+
}
|
|
88
|
+
}
|