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 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, and ingest them with audit-code --results <file> or audit-code --batch-results <dir>. 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
+ ? "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
- const sessionConfig = await loadSessionConfig(artifactsDir);
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
- const sessionConfig = await loadSessionConfig(artifactsDir);
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 slotStatus = "no_progress";
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
- slotStatus = stepResult.progress_made ? "completed" : "no_progress";
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: "agent",
843
- status: slotStatus,
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 writeJsonFile(paths.resultPath, workerResult);
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 writeJsonFile(paths.resultPath, workerResult);
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[]): Promise<void>;
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>;
@@ -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
- await writeJsonFile(join(artifactsDir, "dispatch", "current-task.json"), task);
61
- await writeFile(join(artifactsDir, "dispatch", "current-prompt.md"), prompt, "utf8");
62
- await writeJsonFile(join(artifactsDir, "dispatch", "current-tasks.json"), currentTasks ?? []);
63
- await writeFile(join(artifactsDir, "dispatch", "audit-result.schema.json"), await readFile(auditResultSchemaPath, "utf8"), "utf8");
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
- "current-task.json",
68
- "current-prompt.md",
69
- "current-tasks.json",
70
- "audit-result.schema.json",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auditor-lambda",
3
- "version": "0.2.11",
3
+ "version": "0.2.12",
4
4
  "private": false,
5
5
  "description": "Portable hybrid code-auditing framework for arbitrary repositories.",
6
6
  "type": "module",
@@ -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
  },