auditor-lambda 0.2.11 → 0.2.12
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/cli.js +132 -19
- package/dist/extractors/disposition.js +8 -1
- package/dist/extractors/pathPatterns.d.ts +1 -0
- package/dist/extractors/pathPatterns.js +3 -0
- package/dist/io/runArtifacts.d.ts +13 -1
- package/dist/io/runArtifacts.js +53 -9
- package/dist/supervisor/operatorHandoff.d.ts +13 -0
- package/dist/supervisor/operatorHandoff.js +48 -4
- package/package.json +1 -1
- package/schemas/audit-code-v1alpha1.schema.json +47 -0
package/dist/cli.js
CHANGED
|
@@ -24,7 +24,7 @@ import { createFreshSessionProvider, resolveFreshSessionProviderName, } from "./
|
|
|
24
24
|
import { appendRunLedgerEntry } from "./supervisor/runLedger.js";
|
|
25
25
|
import { buildAuditCodeHandoff, writeAuditCodeHandoffArtifacts, } from "./supervisor/operatorHandoff.js";
|
|
26
26
|
import { getSessionConfigPath, loadSessionConfig, readSessionConfigFile, } from "./supervisor/sessionConfig.js";
|
|
27
|
-
import { clearDispatchFiles, buildRunId, ensureSupervisorDirs, getRunPaths, writeWorkerTaskFiles, } from "./io/runArtifacts.js";
|
|
27
|
+
import { clearDispatchFiles, buildRunId, ensureSupervisorDirs, getRunPaths, writeDispatchBatchFiles, writeWorkerTaskFiles, } from "./io/runArtifacts.js";
|
|
28
28
|
import { renderWorkerPrompt } from "./prompts/renderWorkerPrompt.js";
|
|
29
29
|
import { LOCAL_SUBPROCESS_PROVIDER_NAME } from "./providers/constants.js";
|
|
30
30
|
import { runAuditCodeMcpServer } from "./mcp/server.js";
|
|
@@ -154,6 +154,7 @@ async function emitEnvelope(params) {
|
|
|
154
154
|
providerName: params.providerName,
|
|
155
155
|
progressSummary: params.progress_summary,
|
|
156
156
|
isConfigError: params.isConfigError,
|
|
157
|
+
activeReviewRun: params.activeReviewRun,
|
|
157
158
|
});
|
|
158
159
|
await writeAuditCodeHandoffArtifacts(handoff);
|
|
159
160
|
console.log(JSON.stringify(buildEnvelope({
|
|
@@ -169,7 +170,7 @@ async function emitEnvelope(params) {
|
|
|
169
170
|
}
|
|
170
171
|
function buildManualReviewBlocker(providerName) {
|
|
171
172
|
return providerName === LOCAL_SUBPROCESS_PROVIDER_NAME
|
|
172
|
-
? "Automatic backend steps are exhausted. Remaining semantic review now belongs to the active conversation agent. Review the dispatched files, write structured audit results
|
|
173
|
+
? "Automatic backend steps are exhausted. Remaining semantic review now belongs to the active conversation agent. Review the dispatched files, write structured audit results to the run-scoped audit_results_path, and execute the worker_command from current-task.json exactly as written. If you intentionally want a backend bridge instead, re-run audit-code with --provider auto, --provider claude-code, --provider opencode, --provider subprocess-template, or --provider vscode-task."
|
|
173
174
|
: "Automatic work is exhausted. Remaining audit tasks require explicit audit results or an interactive provider.";
|
|
174
175
|
}
|
|
175
176
|
function shouldRunInlineExecutor(selectedExecutor) {
|
|
@@ -416,6 +417,51 @@ async function ingestBatchAuditResults(options) {
|
|
|
416
417
|
next_likely_step: state.status === "complete" ? null : decision.selected_obligation,
|
|
417
418
|
};
|
|
418
419
|
}
|
|
420
|
+
function buildWorkerResult(params) {
|
|
421
|
+
return {
|
|
422
|
+
contract_version: WORKER_RESULT_CONTRACT_VERSION,
|
|
423
|
+
run_id: params.runId,
|
|
424
|
+
obligation_id: params.obligationId,
|
|
425
|
+
status: params.status,
|
|
426
|
+
progress_made: params.progressMade,
|
|
427
|
+
selected_executor: params.selectedExecutor,
|
|
428
|
+
artifacts_written: params.artifactsWritten,
|
|
429
|
+
summary: params.summary,
|
|
430
|
+
next_likely_step: params.nextLikelyStep,
|
|
431
|
+
errors: params.errors,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
async function persistWorkerRunArtifacts(paths, workerResult, executionMode) {
|
|
435
|
+
await writeJsonFile(paths.resultPath, workerResult);
|
|
436
|
+
await writeJsonFile(paths.statusPath, {
|
|
437
|
+
run_id: workerResult.run_id,
|
|
438
|
+
status: workerResult.status,
|
|
439
|
+
execution_mode: executionMode,
|
|
440
|
+
result_path: paths.resultPath,
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
async function persistConfigErrorHandoff(params) {
|
|
444
|
+
const bundle = await loadArtifactBundle(params.artifactsDir);
|
|
445
|
+
const blockedState = buildBlockedAuditState({
|
|
446
|
+
state: bundle.audit_state ?? deriveAuditState(bundle),
|
|
447
|
+
obligationId: null,
|
|
448
|
+
executor: null,
|
|
449
|
+
blocker: params.progressSummary,
|
|
450
|
+
});
|
|
451
|
+
await writeCoreArtifacts(params.artifactsDir, {
|
|
452
|
+
...bundle,
|
|
453
|
+
audit_state: blockedState,
|
|
454
|
+
});
|
|
455
|
+
const handoff = buildAuditCodeHandoff({
|
|
456
|
+
root: params.root,
|
|
457
|
+
artifactsDir: params.artifactsDir,
|
|
458
|
+
state: blockedState,
|
|
459
|
+
bundle: { ...bundle, audit_state: blockedState },
|
|
460
|
+
progressSummary: params.progressSummary,
|
|
461
|
+
isConfigError: true,
|
|
462
|
+
});
|
|
463
|
+
await writeAuditCodeHandoffArtifacts(handoff);
|
|
464
|
+
}
|
|
419
465
|
function isWorkerResult(value) {
|
|
420
466
|
return (typeof value === "object" &&
|
|
421
467
|
value !== null &&
|
|
@@ -499,7 +545,20 @@ export async function runSample(argv = process.argv) {
|
|
|
499
545
|
async function cmdAdvanceAudit(argv) {
|
|
500
546
|
const root = getRootDir(argv);
|
|
501
547
|
const artifactsDir = getArtifactsDir(argv);
|
|
502
|
-
|
|
548
|
+
await mkdir(artifactsDir, { recursive: true });
|
|
549
|
+
await ensureSupervisorDirs(artifactsDir);
|
|
550
|
+
let sessionConfig;
|
|
551
|
+
try {
|
|
552
|
+
sessionConfig = await loadSessionConfig(artifactsDir);
|
|
553
|
+
}
|
|
554
|
+
catch (error) {
|
|
555
|
+
await persistConfigErrorHandoff({
|
|
556
|
+
root,
|
|
557
|
+
artifactsDir,
|
|
558
|
+
progressSummary: error instanceof Error ? error.message : String(error),
|
|
559
|
+
});
|
|
560
|
+
throw error;
|
|
561
|
+
}
|
|
503
562
|
const providerName = resolveRunProviderName(argv, sessionConfig);
|
|
504
563
|
const batchResultsDir = getBatchResultsDir(argv);
|
|
505
564
|
if (batchResultsDir && getFlag(argv, "--results")) {
|
|
@@ -565,7 +624,20 @@ async function cmdAdvanceAudit(argv) {
|
|
|
565
624
|
async function cmdRunToCompletion(argv) {
|
|
566
625
|
const root = getRootDir(argv);
|
|
567
626
|
const artifactsDir = getArtifactsDir(argv);
|
|
568
|
-
|
|
627
|
+
await mkdir(artifactsDir, { recursive: true });
|
|
628
|
+
await ensureSupervisorDirs(artifactsDir);
|
|
629
|
+
let sessionConfig;
|
|
630
|
+
try {
|
|
631
|
+
sessionConfig = await loadSessionConfig(artifactsDir);
|
|
632
|
+
}
|
|
633
|
+
catch (error) {
|
|
634
|
+
await persistConfigErrorHandoff({
|
|
635
|
+
root,
|
|
636
|
+
artifactsDir,
|
|
637
|
+
progressSummary: error instanceof Error ? error.message : String(error),
|
|
638
|
+
});
|
|
639
|
+
throw error;
|
|
640
|
+
}
|
|
569
641
|
const explicitProvider = getExplicitProvider(argv);
|
|
570
642
|
const provider = createFreshSessionProvider(explicitProvider ?? LOCAL_SUBPROCESS_PROVIDER_NAME, sessionConfig);
|
|
571
643
|
const uiMode = getUiMode(argv, sessionConfig.ui_mode ?? "headless");
|
|
@@ -574,8 +646,6 @@ async function cmdRunToCompletion(argv) {
|
|
|
574
646
|
const parallelWorkers = getParallelWorkers(argv, sessionConfig);
|
|
575
647
|
const timeoutMs = getTimeoutMs(argv, sessionConfig);
|
|
576
648
|
const selfCliPath = resolve(argv[1] ?? process.argv[1] ?? "");
|
|
577
|
-
await mkdir(artifactsDir, { recursive: true });
|
|
578
|
-
await ensureSupervisorDirs(artifactsDir);
|
|
579
649
|
const batchResultsDir = getBatchResultsDir(argv);
|
|
580
650
|
if (batchResultsDir && getFlag(argv, "--results")) {
|
|
581
651
|
throw new Error("Use either --results <file> or --batch-results <dir>, not both.");
|
|
@@ -702,6 +772,14 @@ async function cmdRunToCompletion(argv) {
|
|
|
702
772
|
progress_summary: blocker,
|
|
703
773
|
next_likely_step: null,
|
|
704
774
|
providerName: provider.name,
|
|
775
|
+
activeReviewRun: {
|
|
776
|
+
run_id: blockRunId,
|
|
777
|
+
task_path: blockPaths.taskPath,
|
|
778
|
+
prompt_path: blockPaths.promptPath,
|
|
779
|
+
pending_audit_tasks_path: blockPendingTasksPath,
|
|
780
|
+
audit_results_path: blockAuditResultsPath,
|
|
781
|
+
worker_command: blockTask.worker_command,
|
|
782
|
+
},
|
|
705
783
|
});
|
|
706
784
|
return;
|
|
707
785
|
}
|
|
@@ -758,10 +836,19 @@ async function cmdRunToCompletion(argv) {
|
|
|
758
836
|
max_retries: 0,
|
|
759
837
|
};
|
|
760
838
|
const slotPrompt = renderWorkerPrompt(slotTask);
|
|
761
|
-
await writeWorkerTaskFiles(slotTask, slotPrompt, slotPaths, artifactsDir, group);
|
|
839
|
+
await writeWorkerTaskFiles(slotTask, slotPrompt, slotPaths, artifactsDir, group, { updateDispatch: false });
|
|
762
840
|
await writeJsonFile(slotPendingTasksPath, group);
|
|
763
841
|
workerSlots.push({ runId: slotRunId, paths: slotPaths, auditResultsPath: slotAuditResultsPath, pendingTasksPath: slotPendingTasksPath, group });
|
|
764
842
|
}
|
|
843
|
+
await writeDispatchBatchFiles(artifactsDir, workerSlots.map((slot) => ({
|
|
844
|
+
run_id: slot.runId,
|
|
845
|
+
task_path: slot.paths.taskPath,
|
|
846
|
+
prompt_path: slot.paths.promptPath,
|
|
847
|
+
result_path: slot.paths.resultPath,
|
|
848
|
+
status_path: slot.paths.statusPath,
|
|
849
|
+
audit_results_path: slot.auditResultsPath,
|
|
850
|
+
pending_audit_tasks_path: slot.pendingTasksPath,
|
|
851
|
+
})), workerSlots.flatMap((slot) => slot.group));
|
|
765
852
|
const parallelStartedAt = new Date().toISOString();
|
|
766
853
|
const launchResults = await Promise.allSettled(workerSlots.map((slot) => provider.launch({
|
|
767
854
|
repoRoot: root,
|
|
@@ -791,7 +878,17 @@ async function cmdRunToCompletion(argv) {
|
|
|
791
878
|
const batchErrors = [];
|
|
792
879
|
for (const slot of workerSlots) {
|
|
793
880
|
const parallelEndedAt = new Date().toISOString();
|
|
794
|
-
let
|
|
881
|
+
let workerResult = buildWorkerResult({
|
|
882
|
+
runId: slot.runId,
|
|
883
|
+
obligationId,
|
|
884
|
+
status: "no_progress",
|
|
885
|
+
progressMade: false,
|
|
886
|
+
selectedExecutor: "agent",
|
|
887
|
+
artifactsWritten: [],
|
|
888
|
+
summary: "Parallel worker batch made no progress.",
|
|
889
|
+
nextLikelyStep: obligationId,
|
|
890
|
+
errors: [],
|
|
891
|
+
});
|
|
795
892
|
try {
|
|
796
893
|
const launchError = launchErrorsByRunId.get(slot.runId);
|
|
797
894
|
if (launchError) {
|
|
@@ -822,7 +919,17 @@ async function cmdRunToCompletion(argv) {
|
|
|
822
919
|
preferredExecutor: "result_ingestion_executor",
|
|
823
920
|
auditResultsPath: slot.auditResultsPath,
|
|
824
921
|
});
|
|
825
|
-
|
|
922
|
+
workerResult = buildWorkerResult({
|
|
923
|
+
runId: slot.runId,
|
|
924
|
+
obligationId,
|
|
925
|
+
status: stepResult.progress_made ? "completed" : "no_progress",
|
|
926
|
+
progressMade: stepResult.progress_made,
|
|
927
|
+
selectedExecutor: stepResult.selected_executor,
|
|
928
|
+
artifactsWritten: stepResult.artifacts_written,
|
|
929
|
+
summary: stepResult.progress_summary,
|
|
930
|
+
nextLikelyStep: stepResult.next_likely_step,
|
|
931
|
+
errors: [],
|
|
932
|
+
});
|
|
826
933
|
batchProgress ||= stepResult.progress_made;
|
|
827
934
|
if (stepResult.progress_made)
|
|
828
935
|
anyProgress = true;
|
|
@@ -830,17 +937,28 @@ async function cmdRunToCompletion(argv) {
|
|
|
830
937
|
artifactsWritten.add(a);
|
|
831
938
|
}
|
|
832
939
|
catch (error) {
|
|
833
|
-
slotStatus = "failed";
|
|
834
940
|
const message = error instanceof Error ? error.message : String(error);
|
|
835
941
|
batchErrors.push(`${slot.runId}: ${message}`);
|
|
942
|
+
workerResult = buildWorkerResult({
|
|
943
|
+
runId: slot.runId,
|
|
944
|
+
obligationId,
|
|
945
|
+
status: "failed",
|
|
946
|
+
progressMade: false,
|
|
947
|
+
selectedExecutor: "agent",
|
|
948
|
+
artifactsWritten: [],
|
|
949
|
+
summary: `Worker failed for executor agent: ${message}`,
|
|
950
|
+
nextLikelyStep: obligationId,
|
|
951
|
+
errors: [message],
|
|
952
|
+
});
|
|
836
953
|
process.stderr.write(`[agent-batch] ${slot.runId} failed: ${message}\n`);
|
|
837
954
|
}
|
|
955
|
+
await persistWorkerRunArtifacts(slot.paths, workerResult, "parallel-deferred-agent");
|
|
838
956
|
await appendRunLedgerEntry(artifactsDir, {
|
|
839
957
|
run_id: slot.runId,
|
|
840
958
|
provider: provider.name,
|
|
841
959
|
obligation_id: obligationId,
|
|
842
|
-
selected_executor:
|
|
843
|
-
status:
|
|
960
|
+
selected_executor: workerResult.selected_executor,
|
|
961
|
+
status: workerResult.status,
|
|
844
962
|
started_at: parallelStartedAt,
|
|
845
963
|
ended_at: parallelEndedAt,
|
|
846
964
|
result_path: slot.paths.resultPath,
|
|
@@ -940,12 +1058,7 @@ async function cmdRunToCompletion(argv) {
|
|
|
940
1058
|
errors: [message],
|
|
941
1059
|
};
|
|
942
1060
|
}
|
|
943
|
-
await
|
|
944
|
-
await writeJsonFile(paths.statusPath, {
|
|
945
|
-
run_id: runId,
|
|
946
|
-
status: workerResult.status,
|
|
947
|
-
execution_mode: "inline",
|
|
948
|
-
});
|
|
1061
|
+
await persistWorkerRunArtifacts(paths, workerResult, "inline");
|
|
949
1062
|
await appendRunLedgerEntry(artifactsDir, {
|
|
950
1063
|
run_id: runId,
|
|
951
1064
|
provider: provider.name,
|
|
@@ -1098,7 +1211,7 @@ async function cmdRunToCompletion(argv) {
|
|
|
1098
1211
|
next_likely_step: decision.selected_obligation,
|
|
1099
1212
|
errors: [message],
|
|
1100
1213
|
};
|
|
1101
|
-
await
|
|
1214
|
+
await persistWorkerRunArtifacts(paths, workerResult, "provider-launch");
|
|
1102
1215
|
}
|
|
1103
1216
|
await appendRunLedgerEntry(artifactsDir, {
|
|
1104
1217
|
run_id: runId,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isNodeModulesOrGit, isBuildOutput, isVendorPath, isBinaryArtifact, isLicensePath, isLockfilePath, isLogPath, isDocPath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
1
|
+
import { isNodeModulesOrGit, isBuildOutput, isVendorPath, isBinaryArtifact, isLicensePath, isLockfilePath, isLogPath, isDocPath, isGeneratedInstallArtifactPath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
2
2
|
function inferDisposition(path) {
|
|
3
3
|
const normalized = normalizeExtractorPath(path);
|
|
4
4
|
if (isNodeModulesOrGit(normalized)) {
|
|
@@ -29,6 +29,13 @@ function inferDisposition(path) {
|
|
|
29
29
|
if (isDocPath(normalized)) {
|
|
30
30
|
return { path, status: "doc_only", reason: "Documentation artifact." };
|
|
31
31
|
}
|
|
32
|
+
if (isGeneratedInstallArtifactPath(normalized)) {
|
|
33
|
+
return {
|
|
34
|
+
path,
|
|
35
|
+
status: "generated",
|
|
36
|
+
reason: "Generated install/bootstrap artifact.",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
32
39
|
return {
|
|
33
40
|
path,
|
|
34
41
|
status: "included",
|
|
@@ -13,6 +13,7 @@ export declare function isLogPath(normalized: string): boolean;
|
|
|
13
13
|
export declare function isLicensePath(normalized: string): boolean;
|
|
14
14
|
export declare function isLockfilePath(normalized: string): boolean;
|
|
15
15
|
export declare function isDocPath(normalized: string): boolean;
|
|
16
|
+
export declare function isGeneratedInstallArtifactPath(normalized: string): boolean;
|
|
16
17
|
export declare function isTestPath(normalized: string): boolean;
|
|
17
18
|
export declare function isInterfacePath(normalized: string): boolean;
|
|
18
19
|
export declare function isDataLayerPath(normalized: string): boolean;
|
|
@@ -100,6 +100,9 @@ export function isLockfilePath(normalized) {
|
|
|
100
100
|
export function isDocPath(normalized) {
|
|
101
101
|
return normalized.endsWith(".md") || hasSegment(normalized, "docs");
|
|
102
102
|
}
|
|
103
|
+
export function isGeneratedInstallArtifactPath(normalized) {
|
|
104
|
+
return normalized.startsWith(".audit-code/install/");
|
|
105
|
+
}
|
|
103
106
|
export function isTestPath(normalized) {
|
|
104
107
|
return includesAny(normalized, TEST_KEYWORDS);
|
|
105
108
|
}
|
|
@@ -9,8 +9,20 @@ export interface RunPaths {
|
|
|
9
9
|
stderrPath: string;
|
|
10
10
|
statusPath: string;
|
|
11
11
|
}
|
|
12
|
+
export interface DispatchBatchRun {
|
|
13
|
+
run_id: string;
|
|
14
|
+
task_path: string;
|
|
15
|
+
prompt_path: string;
|
|
16
|
+
result_path: string;
|
|
17
|
+
status_path: string;
|
|
18
|
+
audit_results_path?: string;
|
|
19
|
+
pending_audit_tasks_path?: string;
|
|
20
|
+
}
|
|
12
21
|
export declare function buildRunId(obligationId: string | null, index: number, now?: Date): string;
|
|
13
22
|
export declare function getRunPaths(artifactsDir: string, runId: string): RunPaths;
|
|
14
23
|
export declare function ensureSupervisorDirs(artifactsDir: string): Promise<void>;
|
|
15
|
-
export declare function writeWorkerTaskFiles(task: WorkerTask, prompt: string, paths: RunPaths, artifactsDir: string, currentTasks?: AuditTask[]
|
|
24
|
+
export declare function writeWorkerTaskFiles(task: WorkerTask, prompt: string, paths: RunPaths, artifactsDir: string, currentTasks?: AuditTask[], options?: {
|
|
25
|
+
updateDispatch?: boolean;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
export declare function writeDispatchBatchFiles(artifactsDir: string, runs: DispatchBatchRun[], currentTasks: AuditTask[]): Promise<void>;
|
|
16
28
|
export declare function clearDispatchFiles(artifactsDir: string): Promise<void>;
|
package/dist/io/runArtifacts.js
CHANGED
|
@@ -5,6 +5,10 @@ import { writeJsonFile } from "./json.js";
|
|
|
5
5
|
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
6
6
|
const packageRoot = resolve(moduleDir, "..", "..");
|
|
7
7
|
const auditResultSchemaPath = join(packageRoot, "schemas", "audit_result.schema.json");
|
|
8
|
+
const CURRENT_TASK_FILENAME = "current-task.json";
|
|
9
|
+
const CURRENT_PROMPT_FILENAME = "current-prompt.md";
|
|
10
|
+
const CURRENT_TASKS_FILENAME = "current-tasks.json";
|
|
11
|
+
const CURRENT_SCHEMA_FILENAME = "audit-result.schema.json";
|
|
8
12
|
function pad(value, size = 2) {
|
|
9
13
|
return String(value).padStart(size, "0");
|
|
10
14
|
}
|
|
@@ -49,7 +53,7 @@ export async function ensureSupervisorDirs(artifactsDir) {
|
|
|
49
53
|
await mkdir(join(artifactsDir, "dispatch"), { recursive: true });
|
|
50
54
|
await mkdir(join(artifactsDir, "runs"), { recursive: true });
|
|
51
55
|
}
|
|
52
|
-
export async function writeWorkerTaskFiles(task, prompt, paths, artifactsDir, currentTasks) {
|
|
56
|
+
export async function writeWorkerTaskFiles(task, prompt, paths, artifactsDir, currentTasks, options = {}) {
|
|
53
57
|
await mkdir(paths.runDir, { recursive: true });
|
|
54
58
|
await writeJsonFile(paths.taskPath, task);
|
|
55
59
|
await writeFile(paths.promptPath, prompt, "utf8");
|
|
@@ -57,17 +61,57 @@ export async function writeWorkerTaskFiles(task, prompt, paths, artifactsDir, cu
|
|
|
57
61
|
run_id: task.run_id,
|
|
58
62
|
status: "dispatched",
|
|
59
63
|
});
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
if (options.updateDispatch === false) {
|
|
65
|
+
await writeFile(join(artifactsDir, "dispatch", CURRENT_SCHEMA_FILENAME), await readFile(auditResultSchemaPath, "utf8"), "utf8");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
await writeJsonFile(join(artifactsDir, "dispatch", CURRENT_TASK_FILENAME), task);
|
|
69
|
+
await writeFile(join(artifactsDir, "dispatch", CURRENT_PROMPT_FILENAME), prompt, "utf8");
|
|
70
|
+
await writeJsonFile(join(artifactsDir, "dispatch", CURRENT_TASKS_FILENAME), currentTasks ?? []);
|
|
71
|
+
await writeFile(join(artifactsDir, "dispatch", CURRENT_SCHEMA_FILENAME), await readFile(auditResultSchemaPath, "utf8"), "utf8");
|
|
72
|
+
}
|
|
73
|
+
export async function writeDispatchBatchFiles(artifactsDir, runs, currentTasks) {
|
|
74
|
+
const summary = {
|
|
75
|
+
contract_version: "audit-code-dispatch/v1alpha1",
|
|
76
|
+
mode: "parallel-batch",
|
|
77
|
+
run_count: runs.length,
|
|
78
|
+
current_tasks_path: join(artifactsDir, "dispatch", CURRENT_TASKS_FILENAME),
|
|
79
|
+
runs,
|
|
80
|
+
};
|
|
81
|
+
const promptLines = [
|
|
82
|
+
"# audit-code parallel dispatch",
|
|
83
|
+
"",
|
|
84
|
+
`This batch launched ${runs.length} deferred review run(s).`,
|
|
85
|
+
"Each run keeps its own task.json, prompt.md, result.json, and status.json under .audit-artifacts/runs/<run_id>/.",
|
|
86
|
+
"Use current-tasks.json for the combined task list, then inspect the per-run files below when you need exact prompts or result paths.",
|
|
87
|
+
"",
|
|
88
|
+
"Runs:",
|
|
89
|
+
...runs.flatMap((run) => [
|
|
90
|
+
`- ${run.run_id}`,
|
|
91
|
+
` task: ${run.task_path}`,
|
|
92
|
+
` prompt: ${run.prompt_path}`,
|
|
93
|
+
` result: ${run.result_path}`,
|
|
94
|
+
` status: ${run.status_path}`,
|
|
95
|
+
...(run.audit_results_path
|
|
96
|
+
? [` audit results: ${run.audit_results_path}`]
|
|
97
|
+
: []),
|
|
98
|
+
...(run.pending_audit_tasks_path
|
|
99
|
+
? [` pending tasks: ${run.pending_audit_tasks_path}`]
|
|
100
|
+
: []),
|
|
101
|
+
]),
|
|
102
|
+
"",
|
|
103
|
+
];
|
|
104
|
+
await writeJsonFile(join(artifactsDir, "dispatch", CURRENT_TASK_FILENAME), summary);
|
|
105
|
+
await writeFile(join(artifactsDir, "dispatch", CURRENT_PROMPT_FILENAME), promptLines.join("\n"), "utf8");
|
|
106
|
+
await writeJsonFile(join(artifactsDir, "dispatch", CURRENT_TASKS_FILENAME), currentTasks);
|
|
107
|
+
await writeFile(join(artifactsDir, "dispatch", CURRENT_SCHEMA_FILENAME), await readFile(auditResultSchemaPath, "utf8"), "utf8");
|
|
64
108
|
}
|
|
65
109
|
export async function clearDispatchFiles(artifactsDir) {
|
|
66
110
|
const targets = [
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
111
|
+
CURRENT_TASK_FILENAME,
|
|
112
|
+
CURRENT_PROMPT_FILENAME,
|
|
113
|
+
CURRENT_TASKS_FILENAME,
|
|
114
|
+
CURRENT_SCHEMA_FILENAME,
|
|
71
115
|
];
|
|
72
116
|
for (const name of targets) {
|
|
73
117
|
await rm(join(artifactsDir, "dispatch", name), { force: true });
|
|
@@ -11,9 +11,20 @@ export interface AuditCodeHandoffArtifactPaths {
|
|
|
11
11
|
operator_handoff_markdown: string;
|
|
12
12
|
session_config: string;
|
|
13
13
|
run_ledger: string;
|
|
14
|
+
current_task: string | null;
|
|
15
|
+
current_prompt: string | null;
|
|
16
|
+
current_tasks: string | null;
|
|
14
17
|
audit_tasks: string | null;
|
|
15
18
|
runtime_validation_tasks: string | null;
|
|
16
19
|
}
|
|
20
|
+
export interface ActiveReviewRun {
|
|
21
|
+
run_id: string;
|
|
22
|
+
task_path: string;
|
|
23
|
+
prompt_path: string;
|
|
24
|
+
pending_audit_tasks_path?: string;
|
|
25
|
+
audit_results_path: string;
|
|
26
|
+
worker_command: string[];
|
|
27
|
+
}
|
|
17
28
|
export declare const CONFIG_ERROR_BLOCKER_PREFIX = "config-error:";
|
|
18
29
|
export interface AuditCodeHandoff {
|
|
19
30
|
status: AuditTopLevelStatus;
|
|
@@ -26,6 +37,7 @@ export interface AuditCodeHandoff {
|
|
|
26
37
|
suggested_commands: string[];
|
|
27
38
|
interactive_provider_hint: string | null;
|
|
28
39
|
artifact_paths: AuditCodeHandoffArtifactPaths;
|
|
40
|
+
active_review_run?: ActiveReviewRun;
|
|
29
41
|
}
|
|
30
42
|
export declare function buildAuditCodeHandoff(params: {
|
|
31
43
|
root: string;
|
|
@@ -35,5 +47,6 @@ export declare function buildAuditCodeHandoff(params: {
|
|
|
35
47
|
providerName?: string | null;
|
|
36
48
|
progressSummary: string;
|
|
37
49
|
isConfigError?: boolean;
|
|
50
|
+
activeReviewRun?: ActiveReviewRun;
|
|
38
51
|
}): AuditCodeHandoff;
|
|
39
52
|
export declare function writeAuditCodeHandoffArtifacts(handoff: AuditCodeHandoff): Promise<void>;
|
|
@@ -8,6 +8,9 @@ const OPERATOR_HANDOFF_JSON_FILENAME = "operator-handoff.json";
|
|
|
8
8
|
const OPERATOR_HANDOFF_MARKDOWN_FILENAME = "operator-handoff.md";
|
|
9
9
|
const SESSION_CONFIG_FILENAME = "session-config.json";
|
|
10
10
|
const RUN_LEDGER_FILENAME = "run-ledger.json";
|
|
11
|
+
const CURRENT_TASK_FILENAME = "current-task.json";
|
|
12
|
+
const CURRENT_PROMPT_FILENAME = "current-prompt.md";
|
|
13
|
+
const CURRENT_TASKS_FILENAME = "current-tasks.json";
|
|
11
14
|
const AUDIT_TASKS_FILENAME = "audit_tasks.json";
|
|
12
15
|
const RUNTIME_VALIDATION_TASKS_FILENAME = "runtime_validation_tasks.json";
|
|
13
16
|
const BLOCKED_STATUS = "blocked";
|
|
@@ -29,6 +32,12 @@ function quoteShellPath(filePath) {
|
|
|
29
32
|
// double-quote wrapping plus escaping embedded double quotes.
|
|
30
33
|
return `"${filePath.replace(/"/g, '\\"')}"`;
|
|
31
34
|
}
|
|
35
|
+
function quoteShellArg(value) {
|
|
36
|
+
return quoteShellPath(value);
|
|
37
|
+
}
|
|
38
|
+
function renderShellCommand(argv) {
|
|
39
|
+
return argv.map((item) => quoteShellArg(item)).join(" ");
|
|
40
|
+
}
|
|
32
41
|
function buildPendingObligations(state) {
|
|
33
42
|
return state.obligations
|
|
34
43
|
.filter((item) => !NON_PENDING_OBLIGATION_STATES.has(item.state))
|
|
@@ -55,10 +64,19 @@ function buildSummary(status, providerName, fallbackSummary) {
|
|
|
55
64
|
? `Automatic work can continue under ${providerName}. Re-run the same wrapper or inspect the listed artifacts if you need operator context.`
|
|
56
65
|
: "Automatic work can continue. Re-run the same wrapper or inspect the listed artifacts if you need operator context.";
|
|
57
66
|
}
|
|
58
|
-
function buildSuggestedInputs(artifactsDir, status, isConfigError) {
|
|
67
|
+
function buildSuggestedInputs(artifactsDir, status, isConfigError, activeReviewRun) {
|
|
59
68
|
if (status !== BLOCKED_STATUS || isConfigError) {
|
|
60
69
|
return [];
|
|
61
70
|
}
|
|
71
|
+
if (activeReviewRun) {
|
|
72
|
+
return [
|
|
73
|
+
{
|
|
74
|
+
flag: "--results",
|
|
75
|
+
suggested_path: activeReviewRun.audit_results_path,
|
|
76
|
+
description: "Write structured audit-review results for the currently dispatched run, then execute the exact worker command below to ingest them.",
|
|
77
|
+
},
|
|
78
|
+
];
|
|
79
|
+
}
|
|
62
80
|
const incomingDir = join(artifactsDir, INCOMING_DIRNAME);
|
|
63
81
|
return [
|
|
64
82
|
{
|
|
@@ -83,10 +101,13 @@ function buildSuggestedInputs(artifactsDir, status, isConfigError) {
|
|
|
83
101
|
},
|
|
84
102
|
];
|
|
85
103
|
}
|
|
86
|
-
function buildSuggestedCommands(suggestedInputs, status) {
|
|
104
|
+
function buildSuggestedCommands(suggestedInputs, status, activeReviewRun) {
|
|
87
105
|
if (status !== BLOCKED_STATUS) {
|
|
88
106
|
return [];
|
|
89
107
|
}
|
|
108
|
+
if (activeReviewRun) {
|
|
109
|
+
return [renderShellCommand(activeReviewRun.worker_command)];
|
|
110
|
+
}
|
|
90
111
|
return suggestedInputs.map((item) => `audit-code ${item.flag} ${quoteShellPath(item.suggested_path)}`);
|
|
91
112
|
}
|
|
92
113
|
function buildInteractiveProviderHint(status, providerName, sessionConfigPath, isConfigError) {
|
|
@@ -126,6 +147,9 @@ function renderMarkdown(handoff) {
|
|
|
126
147
|
lines.push(`- incoming dir: ${handoff.artifact_paths.incoming_dir}`);
|
|
127
148
|
lines.push(`- session config: ${handoff.artifact_paths.session_config}`);
|
|
128
149
|
lines.push(`- run ledger: ${handoff.artifact_paths.run_ledger}`);
|
|
150
|
+
lines.push(`- current task: ${handoff.artifact_paths.current_task ?? "not available"}`);
|
|
151
|
+
lines.push(`- current prompt: ${handoff.artifact_paths.current_prompt ?? "not available"}`);
|
|
152
|
+
lines.push(`- current tasks: ${handoff.artifact_paths.current_tasks ?? "not available"}`);
|
|
129
153
|
lines.push(`- audit tasks: ${handoff.artifact_paths.audit_tasks ?? "not available yet"}`);
|
|
130
154
|
lines.push(`- runtime validation tasks: ${handoff.artifact_paths.runtime_validation_tasks ?? "not available yet"}`);
|
|
131
155
|
if (handoff.suggested_inputs.length > 0) {
|
|
@@ -141,6 +165,16 @@ function renderMarkdown(handoff) {
|
|
|
141
165
|
lines.push(`- ${command}`);
|
|
142
166
|
}
|
|
143
167
|
}
|
|
168
|
+
if (handoff.active_review_run) {
|
|
169
|
+
lines.push("", "Active review run:");
|
|
170
|
+
lines.push(`- run id: ${handoff.active_review_run.run_id}`);
|
|
171
|
+
lines.push(`- task file: ${handoff.active_review_run.task_path}`);
|
|
172
|
+
lines.push(`- prompt file: ${handoff.active_review_run.prompt_path}`);
|
|
173
|
+
if (handoff.active_review_run.pending_audit_tasks_path) {
|
|
174
|
+
lines.push(`- pending tasks: ${handoff.active_review_run.pending_audit_tasks_path}`);
|
|
175
|
+
}
|
|
176
|
+
lines.push(`- audit results: ${handoff.active_review_run.audit_results_path}`);
|
|
177
|
+
}
|
|
144
178
|
if (handoff.interactive_provider_hint) {
|
|
145
179
|
lines.push("", "Interactive provider hint:");
|
|
146
180
|
lines.push(`- ${handoff.interactive_provider_hint}`);
|
|
@@ -157,6 +191,15 @@ export function buildAuditCodeHandoff(params) {
|
|
|
157
191
|
operator_handoff_markdown: join(params.artifactsDir, OPERATOR_HANDOFF_MARKDOWN_FILENAME),
|
|
158
192
|
session_config: join(params.artifactsDir, SESSION_CONFIG_FILENAME),
|
|
159
193
|
run_ledger: join(params.artifactsDir, RUN_LEDGER_FILENAME),
|
|
194
|
+
current_task: params.state.status === BLOCKED_STATUS
|
|
195
|
+
? join(params.artifactsDir, "dispatch", CURRENT_TASK_FILENAME)
|
|
196
|
+
: null,
|
|
197
|
+
current_prompt: params.state.status === BLOCKED_STATUS
|
|
198
|
+
? join(params.artifactsDir, "dispatch", CURRENT_PROMPT_FILENAME)
|
|
199
|
+
: null,
|
|
200
|
+
current_tasks: params.state.status === BLOCKED_STATUS
|
|
201
|
+
? join(params.artifactsDir, "dispatch", CURRENT_TASKS_FILENAME)
|
|
202
|
+
: null,
|
|
160
203
|
audit_tasks: params.bundle.audit_tasks
|
|
161
204
|
? join(params.artifactsDir, AUDIT_TASKS_FILENAME)
|
|
162
205
|
: null,
|
|
@@ -164,7 +207,7 @@ export function buildAuditCodeHandoff(params) {
|
|
|
164
207
|
? join(params.artifactsDir, RUNTIME_VALIDATION_TASKS_FILENAME)
|
|
165
208
|
: null,
|
|
166
209
|
};
|
|
167
|
-
const suggestedInputs = buildSuggestedInputs(params.artifactsDir, params.state.status, isConfigError);
|
|
210
|
+
const suggestedInputs = buildSuggestedInputs(params.artifactsDir, params.state.status, isConfigError, params.activeReviewRun);
|
|
168
211
|
return {
|
|
169
212
|
status: params.state.status,
|
|
170
213
|
repo_root: params.root,
|
|
@@ -173,9 +216,10 @@ export function buildAuditCodeHandoff(params) {
|
|
|
173
216
|
summary: buildSummary(params.state.status, params.providerName ?? null, params.progressSummary),
|
|
174
217
|
pending_obligations: buildPendingObligations(params.state),
|
|
175
218
|
suggested_inputs: suggestedInputs,
|
|
176
|
-
suggested_commands: buildSuggestedCommands(suggestedInputs, params.state.status),
|
|
219
|
+
suggested_commands: buildSuggestedCommands(suggestedInputs, params.state.status, params.activeReviewRun),
|
|
177
220
|
interactive_provider_hint: buildInteractiveProviderHint(params.state.status, params.providerName ?? null, artifactPaths.session_config, isConfigError),
|
|
178
221
|
artifact_paths: artifactPaths,
|
|
222
|
+
active_review_run: params.activeReviewRun,
|
|
179
223
|
};
|
|
180
224
|
}
|
|
181
225
|
export async function writeAuditCodeHandoffArtifacts(handoff) {
|
package/package.json
CHANGED
|
@@ -154,6 +154,41 @@
|
|
|
154
154
|
"interactive_provider_hint": {
|
|
155
155
|
"type": ["string", "null"]
|
|
156
156
|
},
|
|
157
|
+
"active_review_run": {
|
|
158
|
+
"type": "object",
|
|
159
|
+
"additionalProperties": false,
|
|
160
|
+
"required": [
|
|
161
|
+
"run_id",
|
|
162
|
+
"task_path",
|
|
163
|
+
"prompt_path",
|
|
164
|
+
"audit_results_path",
|
|
165
|
+
"worker_command"
|
|
166
|
+
],
|
|
167
|
+
"properties": {
|
|
168
|
+
"run_id": {
|
|
169
|
+
"type": "string"
|
|
170
|
+
},
|
|
171
|
+
"task_path": {
|
|
172
|
+
"type": "string"
|
|
173
|
+
},
|
|
174
|
+
"prompt_path": {
|
|
175
|
+
"type": "string"
|
|
176
|
+
},
|
|
177
|
+
"pending_audit_tasks_path": {
|
|
178
|
+
"type": "string"
|
|
179
|
+
},
|
|
180
|
+
"audit_results_path": {
|
|
181
|
+
"type": "string"
|
|
182
|
+
},
|
|
183
|
+
"worker_command": {
|
|
184
|
+
"type": "array",
|
|
185
|
+
"minItems": 1,
|
|
186
|
+
"items": {
|
|
187
|
+
"type": "string"
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
},
|
|
157
192
|
"artifact_paths": {
|
|
158
193
|
"type": "object",
|
|
159
194
|
"additionalProperties": false,
|
|
@@ -163,6 +198,9 @@
|
|
|
163
198
|
"operator_handoff_markdown",
|
|
164
199
|
"session_config",
|
|
165
200
|
"run_ledger",
|
|
201
|
+
"current_task",
|
|
202
|
+
"current_prompt",
|
|
203
|
+
"current_tasks",
|
|
166
204
|
"audit_tasks",
|
|
167
205
|
"runtime_validation_tasks"
|
|
168
206
|
],
|
|
@@ -182,6 +220,15 @@
|
|
|
182
220
|
"run_ledger": {
|
|
183
221
|
"type": "string"
|
|
184
222
|
},
|
|
223
|
+
"current_task": {
|
|
224
|
+
"type": ["string", "null"]
|
|
225
|
+
},
|
|
226
|
+
"current_prompt": {
|
|
227
|
+
"type": ["string", "null"]
|
|
228
|
+
},
|
|
229
|
+
"current_tasks": {
|
|
230
|
+
"type": ["string", "null"]
|
|
231
|
+
},
|
|
185
232
|
"audit_tasks": {
|
|
186
233
|
"type": ["string", "null"]
|
|
187
234
|
},
|