auditor-lambda 0.2.6 → 0.2.8

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.
Files changed (58) hide show
  1. package/README.md +23 -7
  2. package/audit-code-wrapper-lib.mjs +1605 -330
  3. package/dist/cli.js +78 -16
  4. package/dist/coverage.d.ts +2 -2
  5. package/dist/coverage.js +5 -5
  6. package/dist/extractors/disposition.js +10 -1
  7. package/dist/extractors/flows.js +7 -1
  8. package/dist/extractors/pathPatterns.d.ts +3 -0
  9. package/dist/extractors/pathPatterns.js +15 -0
  10. package/dist/extractors/risk.js +7 -1
  11. package/dist/io/artifacts.d.ts +6 -6
  12. package/dist/io/artifacts.js +14 -17
  13. package/dist/io/json.d.ts +2 -0
  14. package/dist/io/json.js +15 -0
  15. package/dist/io/runArtifacts.d.ts +1 -0
  16. package/dist/io/runArtifacts.js +18 -4
  17. package/dist/mcp/server.d.ts +1 -0
  18. package/dist/mcp/server.js +579 -0
  19. package/dist/orchestrator/advance.js +9 -2
  20. package/dist/orchestrator/dependencyMap.js +9 -13
  21. package/dist/orchestrator/executors.js +7 -2
  22. package/dist/orchestrator/flowRequeue.js +1 -1
  23. package/dist/orchestrator/internalExecutors.d.ts +2 -1
  24. package/dist/orchestrator/internalExecutors.js +120 -63
  25. package/dist/orchestrator/requeue.js +9 -4
  26. package/dist/orchestrator/resultIngestion.js +5 -6
  27. package/dist/orchestrator/runtimeValidation.d.ts +7 -2
  28. package/dist/orchestrator/runtimeValidation.js +61 -49
  29. package/dist/orchestrator/runtimeValidationUpdate.js +2 -4
  30. package/dist/orchestrator/state.js +18 -13
  31. package/dist/orchestrator/trivialAudit.js +8 -5
  32. package/dist/prompts/renderWorkerPrompt.js +3 -2
  33. package/dist/reporting/mergeFindings.js +0 -11
  34. package/dist/reporting/synthesis.d.ts +25 -22
  35. package/dist/reporting/synthesis.js +92 -59
  36. package/dist/reporting/workBlocks.d.ts +12 -3
  37. package/dist/reporting/workBlocks.js +124 -70
  38. package/dist/types/flows.d.ts +2 -0
  39. package/dist/types/runtimeValidation.d.ts +2 -1
  40. package/dist/types.d.ts +4 -7
  41. package/dist/validation/auditResults.js +64 -99
  42. package/docs/agent-integrations.md +38 -29
  43. package/docs/artifacts.md +16 -56
  44. package/docs/bootstrap-install.md +60 -30
  45. package/docs/contract.md +22 -205
  46. package/docs/next-steps.md +59 -44
  47. package/docs/packaging.md +13 -3
  48. package/docs/production-launch-bar.md +2 -2
  49. package/docs/production-readiness.md +9 -5
  50. package/docs/releasing.md +81 -0
  51. package/package.json +4 -1
  52. package/schemas/audit_result.schema.json +4 -6
  53. package/schemas/runtime_validation_report.schema.json +1 -1
  54. package/skills/audit-code/SKILL.md +11 -2
  55. package/skills/audit-code/audit-code.prompt.md +5 -8
  56. package/schemas/merged_findings.schema.json +0 -19
  57. package/schemas/root_cause_clusters.schema.json +0 -28
  58. package/schemas/synthesis_report.schema.json +0 -61
package/dist/cli.js CHANGED
@@ -7,14 +7,14 @@ import { buildCriticalFlowManifest } from "./extractors/flows.js";
7
7
  import { buildSurfaceManifest } from "./extractors/surfaces.js";
8
8
  import { buildUnitManifest } from "./orchestrator/unitBuilder.js";
9
9
  import { buildFlowCoverage } from "./orchestrator/flowCoverage.js";
10
- import { buildRuntimeValidationTasks, buildPlaceholderRuntimeValidationReport, } from "./orchestrator/runtimeValidation.js";
10
+ import { buildRuntimeValidationTasks, } from "./orchestrator/runtimeValidation.js";
11
11
  import { initializeCoverageFromPlan } from "./orchestrator/planning.js";
12
- import { loadArtifactBundle, writeCoreArtifacts, cleanupIntermediateArtifacts, } from "./io/artifacts.js";
12
+ import { loadArtifactBundle, writeCoreArtifacts, promoteFinalAuditReport, } from "./io/artifacts.js";
13
13
  import { readJsonFile, writeJsonFile } from "./io/json.js";
14
14
  import { validateArtifactBundle } from "./validation/artifacts.js";
15
15
  import { validateAuditResults, formatAuditResultIssues, } from "./validation/auditResults.js";
16
16
  import { validateConfiguredProviderEnvironment, validateSessionConfig, } from "./validation/sessionConfig.js";
17
- import { buildSynthesisReport } from "./reporting/synthesis.js";
17
+ import { buildAuditReportModel, renderAuditReportMarkdown, } from "./reporting/synthesis.js";
18
18
  import { deriveAuditState } from "./orchestrator/state.js";
19
19
  import { advanceAudit } from "./orchestrator/advance.js";
20
20
  import { decideNextStep } from "./orchestrator/nextStep.js";
@@ -22,9 +22,10 @@ import { createFreshSessionProvider, resolveFreshSessionProviderName, } from "./
22
22
  import { appendRunLedgerEntry } from "./supervisor/runLedger.js";
23
23
  import { buildAuditCodeHandoff, writeAuditCodeHandoffArtifacts, } from "./supervisor/operatorHandoff.js";
24
24
  import { getSessionConfigPath, loadSessionConfig, readSessionConfigFile, } from "./supervisor/sessionConfig.js";
25
- import { buildRunId, ensureSupervisorDirs, getRunPaths, writeWorkerTaskFiles, } from "./io/runArtifacts.js";
25
+ import { clearDispatchFiles, buildRunId, ensureSupervisorDirs, getRunPaths, writeWorkerTaskFiles, } from "./io/runArtifacts.js";
26
26
  import { renderWorkerPrompt } from "./prompts/renderWorkerPrompt.js";
27
27
  import { LOCAL_SUBPROCESS_PROVIDER_NAME } from "./providers/constants.js";
28
+ import { runAuditCodeMcpServer } from "./mcp/server.js";
28
29
  const ADVANCE_AUDIT_CONTRACT_VERSION = "audit-code/v1alpha1";
29
30
  const WORKER_RESULT_CONTRACT_VERSION = "audit-code-worker-result/v1alpha1";
30
31
  const DEFAULT_MAX_RUNS = 1000;
@@ -401,18 +402,35 @@ export async function runSample() {
401
402
  pass_id: "pass:security",
402
403
  lens: "security",
403
404
  agent_role: "security-auditor",
404
- reviewed_ranges: [
405
- { path: "src/api/auth.ts", start: 1, end: 100, line_count: 100 },
406
- ],
405
+ file_coverage: [{ path: "src/api/auth.ts", total_lines: 100 }],
407
406
  findings: [],
408
407
  notes: ["Sample result ingestion path."],
409
408
  requires_followup: false,
410
409
  },
411
410
  ];
412
411
  const flowCoverage = buildFlowCoverage(criticalFlows, coverage);
413
- const runtimeValidationTasks = buildRuntimeValidationTasks(unitManifest, criticalFlows, flowCoverage);
414
- const runtimeValidationReport = buildPlaceholderRuntimeValidationReport(runtimeValidationTasks);
415
- const synthesisReport = buildSynthesisReport(sampleResults, runtimeValidationReport);
412
+ const runtimeValidationTasks = buildRuntimeValidationTasks({
413
+ unitManifest,
414
+ criticalFlows,
415
+ flowCoverage,
416
+ command: ["npm", "test"],
417
+ });
418
+ const runtimeValidationReport = {
419
+ results: runtimeValidationTasks.tasks.map((task) => ({
420
+ task_id: task.id,
421
+ status: "confirmed",
422
+ summary: "Sample runtime validation completed.",
423
+ evidence: [],
424
+ notes: [],
425
+ })),
426
+ };
427
+ const auditReport = renderAuditReportMarkdown(buildAuditReportModel({
428
+ results: sampleResults,
429
+ unitManifest,
430
+ criticalFlows,
431
+ coverageMatrix: coverage,
432
+ runtimeValidationReport,
433
+ }));
416
434
  const auditState = deriveAuditState({
417
435
  repo_manifest: repoManifest,
418
436
  file_disposition: disposition,
@@ -424,7 +442,7 @@ export async function runSample() {
424
442
  runtime_validation_tasks: runtimeValidationTasks,
425
443
  runtime_validation_report: runtimeValidationReport,
426
444
  audit_results: sampleResults,
427
- synthesis_report: synthesisReport,
445
+ audit_report: auditReport,
428
446
  });
429
447
  const artifactsDir = getArtifactsDir(process.argv);
430
448
  await mkdir(artifactsDir, { recursive: true });
@@ -439,7 +457,7 @@ export async function runSample() {
439
457
  runtime_validation_tasks: runtimeValidationTasks,
440
458
  runtime_validation_report: runtimeValidationReport,
441
459
  audit_results: sampleResults,
442
- synthesis_report: synthesisReport,
460
+ audit_report: auditReport,
443
461
  audit_state: auditState,
444
462
  });
445
463
  console.log(JSON.stringify({ audit_state: auditState, artifacts_dir: artifactsDir }, null, 2));
@@ -459,6 +477,9 @@ async function cmdAdvanceAudit(argv) {
459
477
  artifactsDir,
460
478
  batchDir: batchResultsDir,
461
479
  });
480
+ if (result.selected_executor !== "agent") {
481
+ await clearDispatchFiles(artifactsDir);
482
+ }
462
483
  await emitEnvelope({
463
484
  root,
464
485
  artifactsDir,
@@ -473,7 +494,7 @@ async function cmdAdvanceAudit(argv) {
473
494
  providerName,
474
495
  });
475
496
  if (result.audit_state.status === "complete") {
476
- await cleanupIntermediateArtifacts(artifactsDir);
497
+ await promoteFinalAuditReport({ artifactsDir, repoRoot: root });
477
498
  }
478
499
  return;
479
500
  }
@@ -487,6 +508,9 @@ async function cmdAdvanceAudit(argv) {
487
508
  runtimeUpdatesPath: getFlag(argv, "--updates"),
488
509
  externalAnalyzerPath,
489
510
  });
511
+ if (result.selected_executor !== "agent") {
512
+ await clearDispatchFiles(artifactsDir);
513
+ }
490
514
  await emitEnvelope({
491
515
  root,
492
516
  artifactsDir,
@@ -501,7 +525,7 @@ async function cmdAdvanceAudit(argv) {
501
525
  providerName,
502
526
  });
503
527
  if (result.audit_state.status === "complete") {
504
- await cleanupIntermediateArtifacts(artifactsDir);
528
+ await promoteFinalAuditReport({ artifactsDir, repoRoot: root });
505
529
  }
506
530
  }
507
531
  async function cmdRunToCompletion(argv) {
@@ -646,6 +670,7 @@ async function cmdRunToCompletion(argv) {
646
670
  }
647
671
  if (!preferredExecutor) {
648
672
  const state = bundle.audit_state ?? decision.state;
673
+ await clearDispatchFiles(artifactsDir);
649
674
  await emitEnvelope({
650
675
  root,
651
676
  artifactsDir,
@@ -666,7 +691,7 @@ async function cmdRunToCompletion(argv) {
666
691
  providerName: provider.name,
667
692
  });
668
693
  if (state.status === "complete") {
669
- await cleanupIntermediateArtifacts(artifactsDir);
694
+ await promoteFinalAuditReport({ artifactsDir, repoRoot: root });
670
695
  }
671
696
  return;
672
697
  }
@@ -989,6 +1014,9 @@ async function cmdRunToCompletion(argv) {
989
1014
  const bundle = await loadArtifactBundle(artifactsDir);
990
1015
  const decision = decideNextStep(bundle);
991
1016
  const state = bundle.audit_state ?? decision.state;
1017
+ if (state.status === "complete") {
1018
+ await clearDispatchFiles(artifactsDir);
1019
+ }
992
1020
  await emitEnvelope({
993
1021
  root,
994
1022
  artifactsDir,
@@ -1236,6 +1264,31 @@ async function cmdValidate(argv) {
1236
1264
  }, null, 2));
1237
1265
  process.exitCode = issues.length > 0 ? 1 : 0;
1238
1266
  }
1267
+ async function cmdValidateResults(argv) {
1268
+ const artifactsDir = getArtifactsDir(argv);
1269
+ const resultsPath = getFlag(argv, "--results");
1270
+ if (!resultsPath) {
1271
+ throw new Error("validate-results requires --results <file>");
1272
+ }
1273
+ const bundle = await loadArtifactBundle(artifactsDir);
1274
+ const lineIndex = bundle.repo_manifest
1275
+ ? await buildLineIndex(getRootDir(argv), bundle.repo_manifest)
1276
+ : undefined;
1277
+ const auditResults = await readJsonFile(resultsPath);
1278
+ const issues = validateAuditResults(auditResults, bundle.audit_tasks ?? [], {
1279
+ lineIndex,
1280
+ });
1281
+ const errors = issues.filter((issue) => issue.severity === "error");
1282
+ const warnings = issues.filter((issue) => issue.severity === "warning");
1283
+ console.log(JSON.stringify({
1284
+ artifacts_dir: artifactsDir,
1285
+ results_path: resolve(resultsPath),
1286
+ warning_count: warnings.length,
1287
+ error_count: errors.length,
1288
+ issues,
1289
+ }, null, 2));
1290
+ process.exitCode = errors.length > 0 ? 1 : 0;
1291
+ }
1239
1292
  async function cmdRequeue(argv) {
1240
1293
  const artifactsDir = getArtifactsDir(argv);
1241
1294
  const bundle = await loadArtifactBundle(artifactsDir);
@@ -1257,6 +1310,9 @@ async function cmdSynthesize(argv) {
1257
1310
  progress_summary: result.progress_summary,
1258
1311
  }, null, 2));
1259
1312
  }
1313
+ async function cmdMcp(argv) {
1314
+ await runAuditCodeMcpServer(argv.slice(3));
1315
+ }
1260
1316
  async function main(argv) {
1261
1317
  const command = argv[2] ?? "sample-run";
1262
1318
  switch (command) {
@@ -1293,15 +1349,21 @@ async function main(argv) {
1293
1349
  case "validate":
1294
1350
  await cmdValidate(argv);
1295
1351
  return;
1352
+ case "validate-results":
1353
+ await cmdValidateResults(argv);
1354
+ return;
1296
1355
  case "requeue":
1297
1356
  await cmdRequeue(argv);
1298
1357
  return;
1299
1358
  case "synthesize":
1300
1359
  await cmdSynthesize(argv);
1301
1360
  return;
1361
+ case "mcp":
1362
+ await cmdMcp(argv);
1363
+ return;
1302
1364
  default:
1303
1365
  console.error(`Unknown command: ${command}`);
1304
- console.error("Available commands: sample-run, advance-audit, run-to-completion, worker-run, import-external-analyzer, intake, plan, ingest-results, explain-task, update-runtime-validation, validate, requeue, synthesize");
1366
+ console.error("Available commands: sample-run, advance-audit, run-to-completion, worker-run, import-external-analyzer, intake, plan, ingest-results, explain-task, update-runtime-validation, validate, validate-results, requeue, synthesize, mcp");
1305
1367
  process.exitCode = 1;
1306
1368
  }
1307
1369
  }
@@ -1,8 +1,8 @@
1
- import type { CoverageFileRecord, CoverageMatrix, Lens, ReviewedLineRange } from "./types.js";
1
+ import type { CoverageFileRecord, CoverageMatrix, FileCoverageRecord, Lens } from "./types.js";
2
2
  export declare function createCoverageMatrix(paths: string[]): CoverageMatrix;
3
3
  export declare function markExcludedPath(matrix: CoverageMatrix, path: string, classificationStatus: string): void;
4
4
  export declare function applyUnitCoverage(matrix: CoverageMatrix, path: string, unitId: string, requiredLenses: Lens[]): void;
5
- export declare function applyReviewedRanges(matrix: CoverageMatrix, reviewedRanges: ReviewedLineRange[]): void;
5
+ export declare function applyFileCoverage(matrix: CoverageMatrix, fileCoverage: FileCoverageRecord[]): void;
6
6
  export declare function findUncoveredFiles(matrix: CoverageMatrix): CoverageFileRecord[];
7
7
  export declare function buildRequeueTargets(matrix: CoverageMatrix): Array<{
8
8
  path: string;
package/dist/coverage.js CHANGED
@@ -32,13 +32,13 @@ export function applyUnitCoverage(matrix, path, unitId, requiredLenses) {
32
32
  ...new Set([...record.required_lenses, ...requiredLenses]),
33
33
  ];
34
34
  }
35
- export function applyReviewedRanges(matrix, reviewedRanges) {
36
- for (const range of reviewedRanges) {
37
- const record = matrix.files.find((file) => file.path === range.path);
35
+ export function applyFileCoverage(matrix, fileCoverage) {
36
+ for (const coverage of fileCoverage) {
37
+ const record = matrix.files.find((file) => file.path === coverage.path);
38
38
  if (!record || record.audit_status === "excluded")
39
39
  continue;
40
- if (range.lens && !record.completed_lenses.includes(range.lens)) {
41
- record.completed_lenses.push(range.lens);
40
+ if (coverage.lens && !record.completed_lenses.includes(coverage.lens)) {
41
+ record.completed_lenses.push(coverage.lens);
42
42
  }
43
43
  }
44
44
  for (const file of matrix.files) {
@@ -1,4 +1,4 @@
1
- import { isNodeModulesOrGit, isBuildOutput, isVendorPath, isBinaryArtifact, isDocPath, } from "./pathPatterns.js";
1
+ import { isNodeModulesOrGit, isBuildOutput, isVendorPath, isBinaryArtifact, isLicensePath, isLockfilePath, isLogPath, isDocPath, } from "./pathPatterns.js";
2
2
  function inferDisposition(path) {
3
3
  const normalized = path.toLowerCase();
4
4
  if (isNodeModulesOrGit(normalized)) {
@@ -17,6 +17,15 @@ function inferDisposition(path) {
17
17
  reason: "Non-source binary-like artifact.",
18
18
  };
19
19
  }
20
+ if (isLogPath(normalized)) {
21
+ return { path, status: "generated", reason: "Runtime log artifact." };
22
+ }
23
+ if (isLicensePath(normalized)) {
24
+ return { path, status: "doc_only", reason: "License file is not auditable code." };
25
+ }
26
+ if (isLockfilePath(normalized)) {
27
+ return { path, status: "generated", reason: "Lockfile excluded from code audit scope." };
28
+ }
20
29
  if (isDocPath(normalized)) {
21
30
  return { path, status: "doc_only", reason: "Documentation artifact." };
22
31
  }
@@ -94,6 +94,7 @@ export function buildCriticalFlowManifest(repoManifest, surfaceManifest, disposi
94
94
  entrypoints: [entry],
95
95
  paths,
96
96
  concerns: inferConcerns(paths),
97
+ confidence: paths.length > 1 ? "high" : "low",
97
98
  notes: [
98
99
  "Heuristic critical-flow inference from detected surfaces and related paths.",
99
100
  ],
@@ -108,9 +109,14 @@ export function buildCriticalFlowManifest(repoManifest, surfaceManifest, disposi
108
109
  entrypoints: [path],
109
110
  paths: relatedPaths(path, availablePaths),
110
111
  concerns: ["data_integrity", "reliability"],
112
+ confidence: "high",
111
113
  notes: ["Heuristic data-evolution flow."],
112
114
  });
113
115
  }
114
116
  }
115
- return { flows: dedupeFlows(flows) };
117
+ const deduped = dedupeFlows(flows);
118
+ return {
119
+ flows: deduped,
120
+ fallback_required: deduped.length === 0 || deduped.some((flow) => flow.confidence === "low"),
121
+ };
116
122
  }
@@ -7,6 +7,9 @@ export declare function isNodeModulesOrGit(normalized: string): boolean;
7
7
  export declare function isBuildOutput(normalized: string): boolean;
8
8
  export declare function isVendorPath(normalized: string): boolean;
9
9
  export declare function isBinaryArtifact(normalized: string): boolean;
10
+ export declare function isLogPath(normalized: string): boolean;
11
+ export declare function isLicensePath(normalized: string): boolean;
12
+ export declare function isLockfilePath(normalized: string): boolean;
10
13
  export declare function isDocPath(normalized: string): boolean;
11
14
  export declare function isTestPath(normalized: string): boolean;
12
15
  export declare function isInterfacePath(normalized: string): boolean;
@@ -21,6 +21,21 @@ export function isBinaryArtifact(normalized) {
21
21
  normalized.endsWith(".pdf") ||
22
22
  normalized.endsWith(".zip"));
23
23
  }
24
+ export function isLogPath(normalized) {
25
+ return normalized.endsWith(".log") || normalized.includes("stdout.log") || normalized.includes("stderr.log");
26
+ }
27
+ export function isLicensePath(normalized) {
28
+ const base = normalized.split(/[/\\]/).pop() ?? normalized;
29
+ return base === "license" || base.startsWith("license.");
30
+ }
31
+ export function isLockfilePath(normalized) {
32
+ return (normalized.endsWith("package-lock.json") ||
33
+ normalized.endsWith("pnpm-lock.yaml") ||
34
+ normalized.endsWith("yarn.lock") ||
35
+ normalized.endsWith("cargo.lock") ||
36
+ normalized.endsWith("composer.lock") ||
37
+ normalized.endsWith("go.sum"));
38
+ }
24
39
  export function isDocPath(normalized) {
25
40
  return normalized.endsWith(".md") || normalized.startsWith("docs/");
26
41
  }
@@ -19,6 +19,9 @@ export function buildRiskRegister(unitManifest, criticalFlows, externalAnalyzerR
19
19
  signals.push("writes_or_persistence");
20
20
  if (unit.required_lenses.includes("config_deployment"))
21
21
  signals.push("operational_surface");
22
+ if (unit.files.some((path) => /(write|save|persist|lock|cache|retry|open|sync|refresh)/i.test(path))) {
23
+ signals.push("path_level_stateful_behavior");
24
+ }
22
25
  const flowHits = unit.files.reduce((sum, path) => sum + (flowMap.get(path) ?? 0), 0);
23
26
  if (flowHits > 0) {
24
27
  signals.push("critical_flow_member");
@@ -29,7 +32,10 @@ export function buildRiskRegister(unitManifest, criticalFlows, externalAnalyzerR
29
32
  }
30
33
  return {
31
34
  unit_id: unit.unit_id,
32
- risk_score: (unit.risk_score ?? 0) + flowHits + externalHits,
35
+ risk_score: (unit.risk_score ?? 0) +
36
+ flowHits +
37
+ externalHits +
38
+ (signals.includes("path_level_stateful_behavior") ? 1 : 0),
33
39
  signals,
34
40
  notes: [
35
41
  "Initial heuristic risk scoring.",
@@ -26,9 +26,7 @@ export interface ArtifactBundle {
26
26
  audit_results?: AuditResult[];
27
27
  audit_tasks?: AuditTask[];
28
28
  requeue_tasks?: AuditTask[];
29
- merged_findings?: unknown;
30
- root_cause_clusters?: unknown;
31
- synthesis_report?: unknown;
29
+ audit_report?: string;
32
30
  audit_state?: AuditState;
33
31
  artifact_metadata?: ArtifactMetadataManifest;
34
32
  }
@@ -49,9 +47,7 @@ export declare const ARTIFACT_FILE_TO_BUNDLE_KEY: {
49
47
  readonly "audit_results.jsonl": "audit_results";
50
48
  readonly "audit_tasks.json": "audit_tasks";
51
49
  readonly "requeue_tasks.json": "requeue_tasks";
52
- readonly "merged_findings.json": "merged_findings";
53
- readonly "root_cause_clusters.json": "root_cause_clusters";
54
- readonly "synthesis_report.json": "synthesis_report";
50
+ readonly "audit-report.md": "audit_report";
55
51
  readonly "audit_state.json": "audit_state";
56
52
  readonly "artifact_metadata.json": "artifact_metadata";
57
53
  };
@@ -59,3 +55,7 @@ export declare function getArtifactValue(bundle: ArtifactBundle, artifactName: s
59
55
  export declare function loadArtifactBundle(root: string): Promise<ArtifactBundle>;
60
56
  export declare function writeCoreArtifacts(root: string, bundle: ArtifactBundle): Promise<void>;
61
57
  export declare function cleanupIntermediateArtifacts(root: string): Promise<string[]>;
58
+ export declare function promoteFinalAuditReport(params: {
59
+ artifactsDir: string;
60
+ repoRoot: string;
61
+ }): Promise<void>;
@@ -1,6 +1,6 @@
1
- import { unlink } from "node:fs/promises";
1
+ import { cp, rm, unlink } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
- import { writeJsonFile, readOptionalJsonFile, readOptionalNdjsonFile, writeNdjsonFile, } from "./json.js";
3
+ import { writeJsonFile, readOptionalJsonFile, readOptionalNdjsonFile, readOptionalTextFile, writeNdjsonFile, writeTextFile, } from "./json.js";
4
4
  export const ARTIFACT_FILE_TO_BUNDLE_KEY = {
5
5
  "repo_manifest.json": "repo_manifest",
6
6
  "file_disposition.json": "file_disposition",
@@ -18,9 +18,7 @@ export const ARTIFACT_FILE_TO_BUNDLE_KEY = {
18
18
  "audit_results.jsonl": "audit_results",
19
19
  "audit_tasks.json": "audit_tasks",
20
20
  "requeue_tasks.json": "requeue_tasks",
21
- "merged_findings.json": "merged_findings",
22
- "root_cause_clusters.json": "root_cause_clusters",
23
- "synthesis_report.json": "synthesis_report",
21
+ "audit-report.md": "audit_report",
24
22
  "audit_state.json": "audit_state",
25
23
  "artifact_metadata.json": "artifact_metadata",
26
24
  };
@@ -51,9 +49,7 @@ export async function loadArtifactBundle(root) {
51
49
  bundle.audit_results = await readOptionalNdjsonFile(`${root}/audit_results.jsonl`);
52
50
  bundle.audit_tasks = await readOptionalJsonFile(`${root}/audit_tasks.json`);
53
51
  bundle.requeue_tasks = await readOptionalJsonFile(`${root}/requeue_tasks.json`);
54
- bundle.merged_findings = await readOptionalJsonFile(`${root}/merged_findings.json`);
55
- bundle.root_cause_clusters = await readOptionalJsonFile(`${root}/root_cause_clusters.json`);
56
- bundle.synthesis_report = await readOptionalJsonFile(`${root}/synthesis_report.json`);
52
+ bundle.audit_report = await readOptionalTextFile(`${root}/audit-report.md`);
57
53
  bundle.audit_state = await readOptionalJsonFile(`${root}/audit_state.json`);
58
54
  bundle.artifact_metadata = await readOptionalJsonFile(`${root}/artifact_metadata.json`);
59
55
  return bundle;
@@ -91,20 +87,13 @@ export async function writeCoreArtifacts(root, bundle) {
91
87
  await writeJsonFile(`${root}/audit_tasks.json`, bundle.audit_tasks);
92
88
  if (bundle.requeue_tasks)
93
89
  await writeJsonFile(`${root}/requeue_tasks.json`, bundle.requeue_tasks);
94
- if (bundle.merged_findings)
95
- await writeJsonFile(`${root}/merged_findings.json`, bundle.merged_findings);
96
- if (bundle.root_cause_clusters)
97
- await writeJsonFile(`${root}/root_cause_clusters.json`, bundle.root_cause_clusters);
98
- if (bundle.synthesis_report)
99
- await writeJsonFile(`${root}/synthesis_report.json`, bundle.synthesis_report);
90
+ if (bundle.audit_report !== undefined)
91
+ await writeTextFile(`${root}/audit-report.md`, bundle.audit_report);
100
92
  if (bundle.audit_state)
101
93
  await writeJsonFile(`${root}/audit_state.json`, bundle.audit_state);
102
94
  if (bundle.artifact_metadata)
103
95
  await writeJsonFile(`${root}/artifact_metadata.json`, bundle.artifact_metadata);
104
96
  }
105
- // Intermediate files deleted after synthesis completes. The final outputs
106
- // (synthesis_report.json, merged_findings.json, root_cause_clusters.json,
107
- // audit_state.json) are retained.
108
97
  const INTERMEDIATE_ARTIFACTS = [
109
98
  "repo_manifest.json",
110
99
  "file_disposition.json",
@@ -123,6 +112,8 @@ const INTERMEDIATE_ARTIFACTS = [
123
112
  "audit_tasks.json",
124
113
  "requeue_tasks.json",
125
114
  "artifact_metadata.json",
115
+ "audit_state.json",
116
+ "audit-report.md",
126
117
  ];
127
118
  export async function cleanupIntermediateArtifacts(root) {
128
119
  const deleted = [];
@@ -137,3 +128,9 @@ export async function cleanupIntermediateArtifacts(root) {
137
128
  }
138
129
  return deleted;
139
130
  }
131
+ export async function promoteFinalAuditReport(params) {
132
+ const source = join(params.artifactsDir, "audit-report.md");
133
+ const destination = join(params.repoRoot, "audit-report.md");
134
+ await cp(source, destination, { force: true });
135
+ await rm(params.artifactsDir, { recursive: true, force: true });
136
+ }
package/dist/io/json.d.ts CHANGED
@@ -6,3 +6,5 @@ export declare function readNdjsonFile<T>(path: string): Promise<T[]>;
6
6
  export declare function readOptionalJsonFile<T>(path: string): Promise<T | undefined>;
7
7
  export declare function readOptionalNdjsonFile<T>(path: string): Promise<T[] | undefined>;
8
8
  export declare function writeNdjsonFile(path: string, values: unknown[]): Promise<void>;
9
+ export declare function readOptionalTextFile(path: string): Promise<string | undefined>;
10
+ export declare function writeTextFile(path: string, value: string): Promise<void>;
package/dist/io/json.js CHANGED
@@ -94,3 +94,18 @@ export async function writeNdjsonFile(path, values) {
94
94
  }
95
95
  await writeFile(path, values.map((v) => JSON.stringify(v)).join("\n") + "\n", "utf8");
96
96
  }
97
+ export async function readOptionalTextFile(path) {
98
+ try {
99
+ return await readFile(path, "utf8");
100
+ }
101
+ catch (error) {
102
+ if (isFileMissingError(error)) {
103
+ return undefined;
104
+ }
105
+ throw new Error(`Failed to read ${path}: ${errorMessage(error)}`);
106
+ }
107
+ }
108
+ export async function writeTextFile(path, value) {
109
+ await mkdir(dirname(path), { recursive: true });
110
+ await writeFile(path, value, "utf8");
111
+ }
@@ -13,3 +13,4 @@ export declare function buildRunId(obligationId: string | null, index: number):
13
13
  export declare function getRunPaths(artifactsDir: string, runId: string): RunPaths;
14
14
  export declare function ensureSupervisorDirs(artifactsDir: string): Promise<void>;
15
15
  export declare function writeWorkerTaskFiles(task: WorkerTask, prompt: string, paths: RunPaths, artifactsDir: string, currentTasks?: AuditTask[]): Promise<void>;
16
+ export declare function clearDispatchFiles(artifactsDir: string): Promise<void>;
@@ -1,6 +1,10 @@
1
- import { mkdir, writeFile } from "node:fs/promises";
2
- import { join } from "node:path";
1
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
2
+ import { dirname, join, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
3
4
  import { writeJsonFile } from "./json.js";
5
+ const moduleDir = dirname(fileURLToPath(import.meta.url));
6
+ const packageRoot = resolve(moduleDir, "..", "..");
7
+ const auditResultSchemaPath = join(packageRoot, "schemas", "audit_result.schema.json");
4
8
  export function buildRunId(obligationId, index) {
5
9
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
6
10
  const obligation = (obligationId ?? "terminal").replace(/[^a-zA-Z0-9_-]/g, "-");
@@ -20,8 +24,6 @@ export function getRunPaths(artifactsDir, runId) {
20
24
  }
21
25
  export async function ensureSupervisorDirs(artifactsDir) {
22
26
  await mkdir(join(artifactsDir, "dispatch"), { recursive: true });
23
- await mkdir(join(artifactsDir, "worker-results"), { recursive: true });
24
- await mkdir(join(artifactsDir, "worker-logs"), { recursive: true });
25
27
  await mkdir(join(artifactsDir, "runs"), { recursive: true });
26
28
  }
27
29
  export async function writeWorkerTaskFiles(task, prompt, paths, artifactsDir, currentTasks) {
@@ -35,4 +37,16 @@ export async function writeWorkerTaskFiles(task, prompt, paths, artifactsDir, cu
35
37
  await writeJsonFile(join(artifactsDir, "dispatch", "current-task.json"), task);
36
38
  await writeFile(join(artifactsDir, "dispatch", "current-prompt.md"), prompt, "utf8");
37
39
  await writeJsonFile(join(artifactsDir, "dispatch", "current-tasks.json"), currentTasks ?? []);
40
+ await writeFile(join(artifactsDir, "dispatch", "audit-result.schema.json"), await readFile(auditResultSchemaPath, "utf8"), "utf8");
41
+ }
42
+ export async function clearDispatchFiles(artifactsDir) {
43
+ const targets = [
44
+ "current-task.json",
45
+ "current-prompt.md",
46
+ "current-tasks.json",
47
+ "audit-result.schema.json",
48
+ ];
49
+ for (const name of targets) {
50
+ await rm(join(artifactsDir, "dispatch", name), { force: true });
51
+ }
38
52
  }
@@ -0,0 +1 @@
1
+ export declare function runAuditCodeMcpServer(argv: string[]): Promise<void>;