auditor-lambda 0.1.0 → 0.2.1
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/README.md +2 -1
- package/audit-code-wrapper-lib.mjs +458 -380
- package/dist/cli.js +258 -11
- package/dist/coverage.d.ts +0 -1
- package/dist/coverage.js +3 -34
- package/dist/extractors/fileInventory.js +2 -0
- package/dist/io/artifacts.js +2 -1
- package/dist/orchestrator/advance.js +70 -52
- package/dist/orchestrator/flowCoverage.js +2 -1
- package/dist/orchestrator/flowPlanning.d.ts +1 -1
- package/dist/orchestrator/flowPlanning.js +21 -28
- package/dist/orchestrator/internalExecutors.js +0 -1
- package/dist/orchestrator/taskBuilder.d.ts +7 -2
- package/dist/orchestrator/taskBuilder.js +55 -47
- package/dist/prompts/renderWorkerPrompt.js +32 -0
- package/dist/providers/claudeCodeProvider.js +6 -0
- package/dist/providers/index.js +5 -2
- package/dist/providers/opencodeProvider.js +6 -1
- package/dist/providers/types.d.ts +1 -0
- package/dist/reporting/mergeFindings.js +0 -7
- package/dist/reporting/rootCause.d.ts +0 -1
- package/dist/reporting/rootCause.js +0 -6
- package/dist/reporting/synthesis.js +18 -0
- package/dist/supervisor/runLedger.js +6 -2
- package/dist/types/sessionConfig.d.ts +8 -0
- package/dist/types/workerSession.d.ts +2 -0
- package/dist/types.d.ts +1 -2
- package/dist/validation/auditResults.d.ts +11 -0
- package/dist/validation/auditResults.js +118 -0
- package/dist/validation/sessionConfig.js +15 -1
- package/docs/agent-integrations.md +61 -56
- package/docs/agent-roles.md +69 -69
- package/docs/architecture.md +90 -90
- package/docs/artifacts.md +69 -69
- package/docs/bootstrap-install.md +1 -1
- package/docs/model-selection.md +86 -86
- package/docs/next-steps.md +11 -9
- package/docs/packaging.md +3 -3
- package/docs/pipeline.md +152 -152
- package/docs/production-readiness.md +6 -5
- package/docs/repo-layout.md +18 -18
- package/docs/run-flow.md +5 -5
- package/docs/session-config.md +216 -210
- package/docs/supervisor.md +70 -70
- package/docs/windows-setup.md +139 -139
- package/package.json +56 -56
- package/schemas/audit-code-v1alpha1.schema.json +76 -76
- package/schemas/audit_result.schema.json +48 -48
- package/schemas/audit_task.schema.json +49 -49
- package/schemas/coverage_matrix.schema.json +0 -15
- package/schemas/file_disposition.schema.json +33 -33
- package/schemas/finding.schema.json +58 -62
- package/schemas/flow_coverage.schema.json +44 -44
- package/schemas/root_cause_clusters.schema.json +0 -4
- package/schemas/runtime_validation_report.schema.json +34 -34
- package/schemas/synthesis_report.schema.json +61 -61
- package/skills/audit-code/SKILL.md +37 -37
- package/skills/audit-code/audit-code.prompt.md +56 -54
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mkdir } from "node:fs/promises";
|
|
2
2
|
import { createReadStream } from "node:fs";
|
|
3
|
-
import { resolve } from "node:path";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
4
|
import { buildRepoManifest } from "./extractors/fileInventory.js";
|
|
5
5
|
import { buildFileDisposition } from "./extractors/disposition.js";
|
|
6
6
|
import { buildCriticalFlowManifest } from "./extractors/flows.js";
|
|
@@ -12,6 +12,7 @@ import { initializeCoverageFromPlan } from "./orchestrator/planning.js";
|
|
|
12
12
|
import { loadArtifactBundle, writeCoreArtifacts, } from "./io/artifacts.js";
|
|
13
13
|
import { readJsonFile, writeJsonFile } from "./io/json.js";
|
|
14
14
|
import { validateArtifactBundle } from "./validation/artifacts.js";
|
|
15
|
+
import { validateAuditResults, formatAuditResultIssues, } from "./validation/auditResults.js";
|
|
15
16
|
import { validateConfiguredProviderEnvironment, validateSessionConfig, } from "./validation/sessionConfig.js";
|
|
16
17
|
import { buildSynthesisReport } from "./reporting/synthesis.js";
|
|
17
18
|
import { deriveAuditState } from "./orchestrator/state.js";
|
|
@@ -47,8 +48,41 @@ function getRootDir(argv) {
|
|
|
47
48
|
return resolve(getFlag(argv, "--root", "."));
|
|
48
49
|
}
|
|
49
50
|
function getMaxRuns(argv) {
|
|
50
|
-
const raw = Number(getFlag(argv, "--max-runs", "
|
|
51
|
-
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) :
|
|
51
|
+
const raw = Number(getFlag(argv, "--max-runs", "1000"));
|
|
52
|
+
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 1000;
|
|
53
|
+
}
|
|
54
|
+
function getAgentBatchSize(argv, sessionConfig) {
|
|
55
|
+
const fromArg = getFlag(argv, "--agent-batch-size");
|
|
56
|
+
if (fromArg !== undefined) {
|
|
57
|
+
const parsed = Number(fromArg);
|
|
58
|
+
if (Number.isFinite(parsed) && parsed > 0)
|
|
59
|
+
return Math.floor(parsed);
|
|
60
|
+
}
|
|
61
|
+
if (typeof sessionConfig.agent_task_batch_size === "number" &&
|
|
62
|
+
sessionConfig.agent_task_batch_size > 0) {
|
|
63
|
+
return Math.floor(sessionConfig.agent_task_batch_size);
|
|
64
|
+
}
|
|
65
|
+
return 1;
|
|
66
|
+
}
|
|
67
|
+
function getParallelWorkers(argv, sessionConfig) {
|
|
68
|
+
const fromArg = getFlag(argv, "--parallel");
|
|
69
|
+
if (fromArg !== undefined) {
|
|
70
|
+
const parsed = Number(fromArg);
|
|
71
|
+
if (Number.isFinite(parsed) && parsed > 0)
|
|
72
|
+
return Math.floor(parsed);
|
|
73
|
+
}
|
|
74
|
+
if (typeof sessionConfig.parallel_workers === "number" &&
|
|
75
|
+
sessionConfig.parallel_workers > 0) {
|
|
76
|
+
return Math.floor(sessionConfig.parallel_workers);
|
|
77
|
+
}
|
|
78
|
+
return 1;
|
|
79
|
+
}
|
|
80
|
+
function chunkArray(arr, size) {
|
|
81
|
+
const chunks = [];
|
|
82
|
+
for (let i = 0; i < arr.length; i += size) {
|
|
83
|
+
chunks.push(arr.slice(i, i + size));
|
|
84
|
+
}
|
|
85
|
+
return chunks;
|
|
52
86
|
}
|
|
53
87
|
function getUiMode(argv, fallback = "headless") {
|
|
54
88
|
const raw = getFlag(argv, "--ui");
|
|
@@ -160,6 +194,25 @@ async function buildLineIndex(root, repoManifest) {
|
|
|
160
194
|
}
|
|
161
195
|
return Object.fromEntries(entries);
|
|
162
196
|
}
|
|
197
|
+
function resolveModelForTasks(tasks, sessionConfig) {
|
|
198
|
+
if (!sessionConfig.model_tiers)
|
|
199
|
+
return undefined;
|
|
200
|
+
const tiers = [
|
|
201
|
+
"capable",
|
|
202
|
+
"balanced",
|
|
203
|
+
"fast",
|
|
204
|
+
];
|
|
205
|
+
for (const tier of tiers) {
|
|
206
|
+
if (tasks.some((t) => t.model_hint === tier)) {
|
|
207
|
+
return sessionConfig.model_tiers[tier];
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
function buildPendingAuditTasks(bundle) {
|
|
213
|
+
const completedTaskIds = new Set((bundle.audit_results ?? []).map((result) => result.task_id));
|
|
214
|
+
return (bundle.audit_tasks ?? []).filter((task) => !completedTaskIds.has(task.task_id));
|
|
215
|
+
}
|
|
163
216
|
async function runAuditStep(options) {
|
|
164
217
|
const bundle = await loadArtifactBundle(options.artifactsDir);
|
|
165
218
|
const auditResults = options.auditResultsPath
|
|
@@ -282,6 +335,8 @@ async function cmdRunToCompletion(argv) {
|
|
|
282
335
|
const provider = createFreshSessionProvider(getFlag(argv, "--provider"), sessionConfig);
|
|
283
336
|
const uiMode = getUiMode(argv, sessionConfig.ui_mode ?? "headless");
|
|
284
337
|
const maxRuns = getMaxRuns(argv);
|
|
338
|
+
const agentBatchSize = getAgentBatchSize(argv, sessionConfig);
|
|
339
|
+
const parallelWorkers = getParallelWorkers(argv, sessionConfig);
|
|
285
340
|
const timeoutMs = sessionConfig.timeout_ms ?? 30 * 60 * 1000;
|
|
286
341
|
const selfCliPath = resolve(process.argv[1] ?? "");
|
|
287
342
|
await mkdir(artifactsDir, { recursive: true });
|
|
@@ -328,6 +383,32 @@ async function cmdRunToCompletion(argv) {
|
|
|
328
383
|
...bundle,
|
|
329
384
|
audit_state: blockedState,
|
|
330
385
|
});
|
|
386
|
+
const blockRunId = buildRunId(obligationId, runCount + 1);
|
|
387
|
+
const blockPaths = getRunPaths(artifactsDir, blockRunId);
|
|
388
|
+
const blockPendingTasks = buildPendingAuditTasks(bundle).slice(0, agentBatchSize);
|
|
389
|
+
const blockPendingTasksPath = join(blockPaths.runDir, "pending-audit-tasks.json");
|
|
390
|
+
const blockAuditResultsPath = join(blockPaths.runDir, "audit-results.json");
|
|
391
|
+
const blockTask = {
|
|
392
|
+
contract_version: "audit-code-worker/v1alpha1",
|
|
393
|
+
run_id: blockRunId,
|
|
394
|
+
repo_root: root,
|
|
395
|
+
artifacts_dir: artifactsDir,
|
|
396
|
+
obligation_id: obligationId,
|
|
397
|
+
preferred_executor: preferredExecutor,
|
|
398
|
+
result_path: blockPaths.resultPath,
|
|
399
|
+
worker_command: [
|
|
400
|
+
process.execPath,
|
|
401
|
+
selfCliPath,
|
|
402
|
+
"worker-run",
|
|
403
|
+
"--task",
|
|
404
|
+
blockPaths.taskPath,
|
|
405
|
+
],
|
|
406
|
+
audit_results_path: blockAuditResultsPath,
|
|
407
|
+
pending_audit_tasks_path: blockPendingTasksPath,
|
|
408
|
+
};
|
|
409
|
+
const blockPrompt = renderWorkerPrompt(blockTask);
|
|
410
|
+
await writeWorkerTaskFiles(blockTask, blockPrompt, blockPaths, artifactsDir);
|
|
411
|
+
await writeJsonFile(blockPendingTasksPath, blockPendingTasks);
|
|
331
412
|
await emitEnvelope({
|
|
332
413
|
root,
|
|
333
414
|
artifactsDir,
|
|
@@ -369,9 +450,143 @@ async function cmdRunToCompletion(argv) {
|
|
|
369
450
|
});
|
|
370
451
|
return;
|
|
371
452
|
}
|
|
453
|
+
if (preferredExecutor === "agent" && parallelWorkers > 1) {
|
|
454
|
+
const allPendingTasks = buildPendingAuditTasks(bundle);
|
|
455
|
+
const taskGroups = chunkArray(allPendingTasks.slice(0, parallelWorkers * agentBatchSize), agentBatchSize);
|
|
456
|
+
const workerSlots = [];
|
|
457
|
+
for (const group of taskGroups) {
|
|
458
|
+
runCount += 1;
|
|
459
|
+
const slotRunId = buildRunId(obligationId, runCount);
|
|
460
|
+
const slotPaths = getRunPaths(artifactsDir, slotRunId);
|
|
461
|
+
const slotAuditResultsPath = join(slotPaths.runDir, "audit-results.json");
|
|
462
|
+
const slotPendingTasksPath = join(slotPaths.runDir, "pending-audit-tasks.json");
|
|
463
|
+
const slotTask = {
|
|
464
|
+
contract_version: "audit-code-worker/v1alpha1",
|
|
465
|
+
run_id: slotRunId,
|
|
466
|
+
repo_root: root,
|
|
467
|
+
artifacts_dir: artifactsDir,
|
|
468
|
+
obligation_id: obligationId,
|
|
469
|
+
preferred_executor: "agent",
|
|
470
|
+
result_path: slotPaths.resultPath,
|
|
471
|
+
worker_command: [
|
|
472
|
+
process.execPath,
|
|
473
|
+
selfCliPath,
|
|
474
|
+
"worker-run",
|
|
475
|
+
"--task",
|
|
476
|
+
slotPaths.taskPath,
|
|
477
|
+
],
|
|
478
|
+
audit_results_path: slotAuditResultsPath,
|
|
479
|
+
pending_audit_tasks_path: slotPendingTasksPath,
|
|
480
|
+
skip_worker_command: true,
|
|
481
|
+
};
|
|
482
|
+
const slotPrompt = renderWorkerPrompt(slotTask);
|
|
483
|
+
await writeWorkerTaskFiles(slotTask, slotPrompt, slotPaths, artifactsDir);
|
|
484
|
+
await writeJsonFile(slotPendingTasksPath, group);
|
|
485
|
+
workerSlots.push({
|
|
486
|
+
runId: slotRunId,
|
|
487
|
+
paths: slotPaths,
|
|
488
|
+
auditResultsPath: slotAuditResultsPath,
|
|
489
|
+
pendingTasksPath: slotPendingTasksPath,
|
|
490
|
+
group,
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
const parallelStartedAt = new Date().toISOString();
|
|
494
|
+
await Promise.allSettled(workerSlots.map((slot) => provider.launch({
|
|
495
|
+
repoRoot: root,
|
|
496
|
+
runId: slot.runId,
|
|
497
|
+
obligationId,
|
|
498
|
+
promptPath: slot.paths.promptPath,
|
|
499
|
+
taskPath: slot.paths.taskPath,
|
|
500
|
+
resultPath: slot.paths.resultPath,
|
|
501
|
+
stdoutPath: slot.paths.stdoutPath,
|
|
502
|
+
stderrPath: slot.paths.stderrPath,
|
|
503
|
+
uiMode,
|
|
504
|
+
timeoutMs,
|
|
505
|
+
model: resolveModelForTasks(slot.group, sessionConfig),
|
|
506
|
+
})));
|
|
507
|
+
let batchProgress = false;
|
|
508
|
+
for (const slot of workerSlots) {
|
|
509
|
+
const parallelEndedAt = new Date().toISOString();
|
|
510
|
+
let slotStatus = "no_progress";
|
|
511
|
+
try {
|
|
512
|
+
const auditResults = await readJsonFile(slot.auditResultsPath);
|
|
513
|
+
const pendingTaskIds = new Set(slot.group.map((t) => t.task_id));
|
|
514
|
+
const matchedCount = auditResults.filter((r) => pendingTaskIds.has(r.task_id)).length;
|
|
515
|
+
if (slot.group.length > 0 && matchedCount === 0) {
|
|
516
|
+
throw new Error("Worker did not emit any audit results for the assigned tasks.");
|
|
517
|
+
}
|
|
518
|
+
const issues = validateAuditResults(auditResults, slot.group);
|
|
519
|
+
const errors = issues.filter((issue) => issue.severity === "error");
|
|
520
|
+
const warnings = issues.filter((issue) => issue.severity === "warning");
|
|
521
|
+
if (warnings.length > 0) {
|
|
522
|
+
process.stderr.write(`audit-results validation: ${warnings.length} warning(s) for ${slot.runId}:\n` +
|
|
523
|
+
formatAuditResultIssues(warnings) +
|
|
524
|
+
"\n");
|
|
525
|
+
}
|
|
526
|
+
if (errors.length > 0) {
|
|
527
|
+
throw new Error(`audit-results validation failed with ${errors.length} error(s):\n` +
|
|
528
|
+
formatAuditResultIssues(errors));
|
|
529
|
+
}
|
|
530
|
+
const stepResult = await runAuditStep({
|
|
531
|
+
root,
|
|
532
|
+
artifactsDir,
|
|
533
|
+
preferredExecutor: "result_ingestion_executor",
|
|
534
|
+
auditResultsPath: slot.auditResultsPath,
|
|
535
|
+
});
|
|
536
|
+
slotStatus = stepResult.progress_made ? "completed" : "no_progress";
|
|
537
|
+
batchProgress ||= stepResult.progress_made;
|
|
538
|
+
if (stepResult.progress_made)
|
|
539
|
+
anyProgress = true;
|
|
540
|
+
for (const a of stepResult.artifacts_written)
|
|
541
|
+
artifactsWritten.add(a);
|
|
542
|
+
}
|
|
543
|
+
catch {
|
|
544
|
+
slotStatus = "failed";
|
|
545
|
+
}
|
|
546
|
+
await appendRunLedgerEntry(artifactsDir, {
|
|
547
|
+
run_id: slot.runId,
|
|
548
|
+
provider: provider.name,
|
|
549
|
+
obligation_id: obligationId,
|
|
550
|
+
selected_executor: "agent",
|
|
551
|
+
status: slotStatus,
|
|
552
|
+
started_at: parallelStartedAt,
|
|
553
|
+
ended_at: parallelEndedAt,
|
|
554
|
+
result_path: slot.paths.resultPath,
|
|
555
|
+
});
|
|
556
|
+
artifactsWritten.add("run-ledger.json");
|
|
557
|
+
}
|
|
558
|
+
if (!batchProgress) {
|
|
559
|
+
const bundleAfter = await loadArtifactBundle(artifactsDir);
|
|
560
|
+
const state = bundleAfter.audit_state ?? deriveAuditState(bundleAfter);
|
|
561
|
+
await emitEnvelope({
|
|
562
|
+
root,
|
|
563
|
+
artifactsDir,
|
|
564
|
+
bundle: bundleAfter,
|
|
565
|
+
audit_state: state,
|
|
566
|
+
selected_obligation: obligationId,
|
|
567
|
+
selected_executor: "agent",
|
|
568
|
+
progress_made: anyProgress,
|
|
569
|
+
artifacts_written: Array.from(artifactsWritten),
|
|
570
|
+
progress_summary: "Parallel worker batch made no progress.",
|
|
571
|
+
next_likely_step: obligationId,
|
|
572
|
+
providerName: provider.name,
|
|
573
|
+
});
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
continue;
|
|
577
|
+
}
|
|
372
578
|
runCount += 1;
|
|
373
579
|
const runId = buildRunId(obligationId, runCount);
|
|
374
580
|
const paths = getRunPaths(artifactsDir, runId);
|
|
581
|
+
const pendingAuditTasks = preferredExecutor === "agent"
|
|
582
|
+
? buildPendingAuditTasks(bundle).slice(0, agentBatchSize)
|
|
583
|
+
: undefined;
|
|
584
|
+
const pendingAuditTasksPath = preferredExecutor === "agent"
|
|
585
|
+
? join(paths.runDir, "pending-audit-tasks.json")
|
|
586
|
+
: undefined;
|
|
587
|
+
const providerAuditResultsPath = preferredExecutor === "agent"
|
|
588
|
+
? join(paths.runDir, "audit-results.json")
|
|
589
|
+
: auditResultsPath;
|
|
375
590
|
const task = {
|
|
376
591
|
contract_version: "audit-code-worker/v1alpha1",
|
|
377
592
|
run_id: runId,
|
|
@@ -387,12 +602,16 @@ async function cmdRunToCompletion(argv) {
|
|
|
387
602
|
"--task",
|
|
388
603
|
paths.taskPath,
|
|
389
604
|
],
|
|
390
|
-
audit_results_path:
|
|
605
|
+
audit_results_path: providerAuditResultsPath,
|
|
606
|
+
pending_audit_tasks_path: pendingAuditTasksPath,
|
|
391
607
|
runtime_updates_path: runtimeUpdatesPath,
|
|
392
608
|
external_analyzer_results_path: externalAnalyzerPath,
|
|
393
609
|
};
|
|
394
610
|
const prompt = renderWorkerPrompt(task);
|
|
395
611
|
await writeWorkerTaskFiles(task, prompt, paths, artifactsDir);
|
|
612
|
+
if (pendingAuditTasksPath && pendingAuditTasks) {
|
|
613
|
+
await writeJsonFile(pendingAuditTasksPath, pendingAuditTasks);
|
|
614
|
+
}
|
|
396
615
|
const startedAt = new Date().toISOString();
|
|
397
616
|
let workerResult;
|
|
398
617
|
try {
|
|
@@ -407,6 +626,9 @@ async function cmdRunToCompletion(argv) {
|
|
|
407
626
|
stderrPath: paths.stderrPath,
|
|
408
627
|
uiMode,
|
|
409
628
|
timeoutMs,
|
|
629
|
+
model: pendingAuditTasks
|
|
630
|
+
? resolveModelForTasks(pendingAuditTasks, sessionConfig)
|
|
631
|
+
: undefined,
|
|
410
632
|
});
|
|
411
633
|
const candidate = await readJsonFile(paths.resultPath);
|
|
412
634
|
workerResult = isWorkerResult(candidate)
|
|
@@ -459,7 +681,7 @@ async function cmdRunToCompletion(argv) {
|
|
|
459
681
|
artifactsWritten.add("run-ledger.json");
|
|
460
682
|
if (externalAnalyzerPath)
|
|
461
683
|
pendingExternalAnalyzerPath = undefined;
|
|
462
|
-
if (
|
|
684
|
+
if (providerAuditResultsPath)
|
|
463
685
|
pendingAuditResultsPath = undefined;
|
|
464
686
|
if (runtimeUpdatesPath)
|
|
465
687
|
pendingRuntimeUpdatesPath = undefined;
|
|
@@ -509,10 +731,39 @@ async function cmdWorkerRun(argv) {
|
|
|
509
731
|
const task = await readJsonFile(taskPath);
|
|
510
732
|
let workerResult;
|
|
511
733
|
try {
|
|
734
|
+
if (task.preferred_executor === "agent" && !task.audit_results_path) {
|
|
735
|
+
throw new Error("agent worker-run requires audit_results_path so provider-assisted review can be ingested.");
|
|
736
|
+
}
|
|
737
|
+
if (task.preferred_executor === "agent" && task.audit_results_path) {
|
|
738
|
+
const pendingTasks = task.pending_audit_tasks_path
|
|
739
|
+
? await readJsonFile(task.pending_audit_tasks_path)
|
|
740
|
+
: [];
|
|
741
|
+
const auditResults = await readJsonFile(task.audit_results_path);
|
|
742
|
+
const pendingTaskIds = new Set(pendingTasks.map((item) => item.task_id));
|
|
743
|
+
const matchedResultCount = auditResults.filter((result) => pendingTaskIds.has(result.task_id)).length;
|
|
744
|
+
if (pendingTasks.length > 0 && matchedResultCount === 0) {
|
|
745
|
+
throw new Error("Provider-assisted review did not emit any audit results for the pending audit tasks.");
|
|
746
|
+
}
|
|
747
|
+
const issues = validateAuditResults(auditResults, pendingTasks);
|
|
748
|
+
const errors = issues.filter((issue) => issue.severity === "error");
|
|
749
|
+
const warnings = issues.filter((issue) => issue.severity === "warning");
|
|
750
|
+
if (warnings.length > 0) {
|
|
751
|
+
process.stderr.write(`audit-results validation: ${warnings.length} warning(s):\n` +
|
|
752
|
+
formatAuditResultIssues(warnings) +
|
|
753
|
+
"\n");
|
|
754
|
+
}
|
|
755
|
+
if (errors.length > 0) {
|
|
756
|
+
throw new Error(`audit-results validation failed with ${errors.length} error(s):\n` +
|
|
757
|
+
formatAuditResultIssues(errors));
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
const preferredExecutor = task.preferred_executor === "agent"
|
|
761
|
+
? "result_ingestion_executor"
|
|
762
|
+
: task.preferred_executor;
|
|
512
763
|
const result = await runAuditStep({
|
|
513
764
|
root: task.repo_root,
|
|
514
765
|
artifactsDir: task.artifacts_dir,
|
|
515
|
-
preferredExecutor
|
|
766
|
+
preferredExecutor,
|
|
516
767
|
auditResultsPath: task.audit_results_path,
|
|
517
768
|
runtimeUpdatesPath: task.runtime_updates_path,
|
|
518
769
|
externalAnalyzerPath: task.external_analyzer_results_path,
|
|
@@ -630,11 +881,7 @@ async function cmdValidate(argv) {
|
|
|
630
881
|
const providerIssues = rawSessionConfig === undefined || sessionConfigIssues.length > 0
|
|
631
882
|
? []
|
|
632
883
|
: prefixValidationIssues("session_config", validateConfiguredProviderEnvironment(rawSessionConfig));
|
|
633
|
-
const issues = [
|
|
634
|
-
...artifactIssues,
|
|
635
|
-
...sessionConfigIssues,
|
|
636
|
-
...providerIssues,
|
|
637
|
-
];
|
|
884
|
+
const issues = [...artifactIssues, ...sessionConfigIssues, ...providerIssues];
|
|
638
885
|
const resolvedProvider = rawSessionConfig === undefined
|
|
639
886
|
? "local-subprocess"
|
|
640
887
|
: sessionConfigIssues.length > 0
|
package/dist/coverage.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { CoverageFileRecord, CoverageMatrix, Lens, ReviewedLineRange } from "./types.js";
|
|
2
|
-
export declare function mergeRanges(ranges: ReviewedLineRange[]): ReviewedLineRange[];
|
|
3
2
|
export declare function createCoverageMatrix(paths: string[]): CoverageMatrix;
|
|
4
3
|
export declare function markExcludedPath(matrix: CoverageMatrix, path: string, classificationStatus: string): void;
|
|
5
4
|
export declare function applyUnitCoverage(matrix: CoverageMatrix, path: string, unitId: string, requiredLenses: Lens[]): void;
|
package/dist/coverage.js
CHANGED
|
@@ -1,29 +1,3 @@
|
|
|
1
|
-
function sortRanges(ranges) {
|
|
2
|
-
return [...ranges].sort((a, b) => {
|
|
3
|
-
if (a.path !== b.path)
|
|
4
|
-
return a.path.localeCompare(b.path);
|
|
5
|
-
if (a.start !== b.start)
|
|
6
|
-
return a.start - b.start;
|
|
7
|
-
return a.end - b.end;
|
|
8
|
-
});
|
|
9
|
-
}
|
|
10
|
-
export function mergeRanges(ranges) {
|
|
11
|
-
const sorted = sortRanges(ranges);
|
|
12
|
-
const merged = [];
|
|
13
|
-
for (const range of sorted) {
|
|
14
|
-
const last = merged[merged.length - 1];
|
|
15
|
-
if (!last || last.path !== range.path || range.start > last.end + 1) {
|
|
16
|
-
merged.push({ ...range });
|
|
17
|
-
continue;
|
|
18
|
-
}
|
|
19
|
-
last.end = Math.max(last.end, range.end);
|
|
20
|
-
last.pass_id = `${last.pass_id},${range.pass_id}`;
|
|
21
|
-
last.agent_role = [last.agent_role, range.agent_role]
|
|
22
|
-
.filter(Boolean)
|
|
23
|
-
.join(",");
|
|
24
|
-
}
|
|
25
|
-
return merged;
|
|
26
|
-
}
|
|
27
1
|
export function createCoverageMatrix(paths) {
|
|
28
2
|
return {
|
|
29
3
|
files: paths.map((path) => ({
|
|
@@ -33,7 +7,6 @@ export function createCoverageMatrix(paths) {
|
|
|
33
7
|
audit_status: "pending",
|
|
34
8
|
required_lenses: [],
|
|
35
9
|
completed_lenses: [],
|
|
36
|
-
reviewed_line_ranges: [],
|
|
37
10
|
})),
|
|
38
11
|
};
|
|
39
12
|
}
|
|
@@ -45,7 +18,6 @@ export function markExcludedPath(matrix, path, classificationStatus) {
|
|
|
45
18
|
record.audit_status = "excluded";
|
|
46
19
|
record.required_lenses = [];
|
|
47
20
|
record.completed_lenses = [];
|
|
48
|
-
record.reviewed_line_ranges = [];
|
|
49
21
|
record.unit_ids = [];
|
|
50
22
|
}
|
|
51
23
|
export function applyUnitCoverage(matrix, path, unitId, requiredLenses) {
|
|
@@ -65,21 +37,18 @@ export function applyReviewedRanges(matrix, reviewedRanges) {
|
|
|
65
37
|
const record = matrix.files.find((file) => file.path === range.path);
|
|
66
38
|
if (!record || record.audit_status === "excluded")
|
|
67
39
|
continue;
|
|
68
|
-
record.reviewed_line_ranges.push(range);
|
|
69
|
-
record.reviewed_line_ranges = mergeRanges(record.reviewed_line_ranges);
|
|
70
40
|
if (range.lens && !record.completed_lenses.includes(range.lens)) {
|
|
71
41
|
record.completed_lenses.push(range.lens);
|
|
72
42
|
}
|
|
73
43
|
}
|
|
74
44
|
for (const file of matrix.files) {
|
|
75
|
-
|
|
76
|
-
if (file.audit_status === "excluded") {
|
|
45
|
+
if (file.audit_status === "excluded")
|
|
77
46
|
continue;
|
|
78
|
-
|
|
47
|
+
const hasAllRequired = file.required_lenses.every((lens) => file.completed_lenses.includes(lens));
|
|
79
48
|
if (hasAllRequired && file.required_lenses.length > 0) {
|
|
80
49
|
file.audit_status = "complete";
|
|
81
50
|
}
|
|
82
|
-
else if (file.
|
|
51
|
+
else if (file.completed_lenses.length > 0) {
|
|
83
52
|
file.audit_status = "partial";
|
|
84
53
|
}
|
|
85
54
|
}
|
package/dist/io/artifacts.js
CHANGED
|
@@ -51,7 +51,8 @@ export async function loadArtifactBundle(root) {
|
|
|
51
51
|
bundle.root_cause_clusters = await readOptionalJsonFile(`${root}/root_cause_clusters.json`);
|
|
52
52
|
bundle.synthesis_report = await readOptionalJsonFile(`${root}/synthesis_report.json`);
|
|
53
53
|
bundle.audit_state = await readOptionalJsonFile(`${root}/audit_state.json`);
|
|
54
|
-
bundle.artifact_metadata =
|
|
54
|
+
bundle.artifact_metadata =
|
|
55
|
+
await readOptionalJsonFile(`${root}/artifact_metadata.json`);
|
|
55
56
|
return bundle;
|
|
56
57
|
}
|
|
57
58
|
export async function writeCoreArtifacts(root, bundle) {
|
|
@@ -27,58 +27,76 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
let run;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
30
|
+
try {
|
|
31
|
+
switch (selectedExecutor) {
|
|
32
|
+
case "intake_executor":
|
|
33
|
+
if (!options.root)
|
|
34
|
+
throw new Error("advanceAudit intake_executor requires root");
|
|
35
|
+
run = await runIntakeExecutor(bundle, options.root);
|
|
36
|
+
break;
|
|
37
|
+
case "structure_executor":
|
|
38
|
+
run = runStructureExecutor(bundle);
|
|
39
|
+
break;
|
|
40
|
+
case "planning_executor":
|
|
41
|
+
run = runPlanningExecutor(bundle, options.lineIndex ?? {});
|
|
42
|
+
break;
|
|
43
|
+
case "result_ingestion_executor":
|
|
44
|
+
run = runResultIngestionExecutor(bundle, options.auditResults ?? bundle.audit_results ?? []);
|
|
45
|
+
break;
|
|
46
|
+
case "synthesis_executor":
|
|
47
|
+
run = runSynthesisExecutor(bundle, options.auditResults);
|
|
48
|
+
break;
|
|
49
|
+
case "runtime_validation_update_executor":
|
|
50
|
+
if (!options.runtimeValidationUpdates)
|
|
51
|
+
throw new Error("advanceAudit runtime_validation_update_executor requires runtimeValidationUpdates");
|
|
52
|
+
run = runRuntimeValidationUpdateExecutor(bundle, options.runtimeValidationUpdates);
|
|
53
|
+
break;
|
|
54
|
+
case "external_analyzer_import_executor":
|
|
55
|
+
if (!options.externalAnalyzerResults)
|
|
56
|
+
throw new Error("advanceAudit external_analyzer_import_executor requires externalAnalyzerResults");
|
|
57
|
+
run = runExternalAnalyzerImportExecutor(bundle, options.externalAnalyzerResults);
|
|
58
|
+
break;
|
|
59
|
+
case "auto_fix_executor":
|
|
60
|
+
if (!options.root)
|
|
61
|
+
throw new Error("advanceAudit auto_fix_executor requires root");
|
|
62
|
+
run = runAutoFixExecutor(bundle, options.root);
|
|
63
|
+
break;
|
|
64
|
+
case "syntax_resolution_executor":
|
|
65
|
+
if (!options.root)
|
|
66
|
+
throw new Error("advanceAudit syntax_resolution_executor requires root");
|
|
67
|
+
run = runSyntaxResolutionExecutor(bundle, options.root);
|
|
68
|
+
break;
|
|
69
|
+
default: {
|
|
70
|
+
const state = deriveAuditState(bundle);
|
|
71
|
+
state.last_executor = selectedExecutor;
|
|
72
|
+
state.last_obligation = selectedObligation ?? undefined;
|
|
73
|
+
return {
|
|
74
|
+
audit_state: state,
|
|
75
|
+
selected_obligation: selectedObligation,
|
|
76
|
+
selected_executor: selectedExecutor,
|
|
77
|
+
progress_made: false,
|
|
78
|
+
artifacts_written: ["audit_state.json"],
|
|
79
|
+
progress_summary: `Executor ${selectedExecutor} is selected but not yet dispatched through advance-audit.`,
|
|
80
|
+
next_likely_step: selectedObligation,
|
|
81
|
+
updated_bundle: { ...bundle, audit_state: state },
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
const state = deriveAuditState(bundle);
|
|
88
|
+
state.last_executor = selectedExecutor;
|
|
89
|
+
state.last_obligation = selectedObligation ?? undefined;
|
|
90
|
+
return {
|
|
91
|
+
audit_state: state,
|
|
92
|
+
selected_obligation: selectedObligation,
|
|
93
|
+
selected_executor: selectedExecutor,
|
|
94
|
+
progress_made: false,
|
|
95
|
+
artifacts_written: [],
|
|
96
|
+
progress_summary: `Executor ${selectedExecutor} failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
97
|
+
next_likely_step: selectedObligation,
|
|
98
|
+
updated_bundle: { ...bundle, audit_state: state },
|
|
99
|
+
};
|
|
82
100
|
}
|
|
83
101
|
const metadata = computeArtifactMetadata(run.updated, bundle.artifact_metadata);
|
|
84
102
|
const metadataBundle = { ...run.updated, artifact_metadata: metadata };
|
|
@@ -10,11 +10,12 @@ function lensSetForFlow(concerns) {
|
|
|
10
10
|
return concerns.filter((concern) => allowed.includes(concern));
|
|
11
11
|
}
|
|
12
12
|
export function buildFlowCoverage(criticalFlows, coverageMatrix) {
|
|
13
|
+
const fileIndex = new Map(coverageMatrix.files.map((file) => [file.path, file]));
|
|
13
14
|
const flows = criticalFlows.flows.map((flow) => {
|
|
14
15
|
const required = lensSetForFlow(flow.concerns);
|
|
15
16
|
const completed = new Set();
|
|
16
17
|
for (const path of flow.paths) {
|
|
17
|
-
const record =
|
|
18
|
+
const record = fileIndex.get(path);
|
|
18
19
|
if (!record || record.audit_status === "excluded") {
|
|
19
20
|
continue;
|
|
20
21
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { AuditTask } from "../types.js";
|
|
2
2
|
import type { CriticalFlowManifest } from "../types/flows.js";
|
|
3
|
-
export declare function buildFlowAwareTaskAugmentations(existingTasks: AuditTask[], criticalFlows: CriticalFlowManifest,
|
|
3
|
+
export declare function buildFlowAwareTaskAugmentations(existingTasks: AuditTask[], criticalFlows: CriticalFlowManifest, _lineIndex: Record<string, number>): AuditTask[];
|