auditor-lambda 0.2.8 → 0.2.10

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 (104) hide show
  1. package/README.md +6 -0
  2. package/audit-code-wrapper-lib.mjs +1 -1
  3. package/dist/adapters/eslint.js +9 -5
  4. package/dist/cli.d.ts +42 -1
  5. package/dist/cli.js +234 -63
  6. package/dist/extractors/bucketing.d.ts +4 -0
  7. package/dist/extractors/bucketing.js +6 -2
  8. package/dist/extractors/disposition.d.ts +4 -0
  9. package/dist/extractors/disposition.js +6 -2
  10. package/dist/extractors/fileInventory.js +24 -28
  11. package/dist/extractors/flows.d.ts +5 -0
  12. package/dist/extractors/flows.js +18 -38
  13. package/dist/extractors/pathPatterns.d.ts +10 -3
  14. package/dist/extractors/pathPatterns.js +109 -61
  15. package/dist/extractors/surfaces.d.ts +4 -0
  16. package/dist/extractors/surfaces.js +11 -11
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.js +2 -1
  19. package/dist/io/artifacts.d.ts +55 -40
  20. package/dist/io/artifacts.js +73 -110
  21. package/dist/io/json.js +52 -21
  22. package/dist/io/runArtifacts.d.ts +1 -1
  23. package/dist/io/runArtifacts.js +26 -3
  24. package/dist/orchestrator/advance.js +83 -62
  25. package/dist/orchestrator/autoFixExecutor.js +32 -15
  26. package/dist/orchestrator/flowCoverage.js +11 -5
  27. package/dist/orchestrator/flowPlanning.d.ts +7 -2
  28. package/dist/orchestrator/flowPlanning.js +46 -21
  29. package/dist/orchestrator/flowRequeue.js +28 -8
  30. package/dist/orchestrator/internalExecutors.js +12 -8
  31. package/dist/orchestrator/localCommands.d.ts +14 -0
  32. package/dist/orchestrator/localCommands.js +124 -0
  33. package/dist/orchestrator/planning.js +25 -3
  34. package/dist/orchestrator/requeue.js +11 -1
  35. package/dist/orchestrator/syntaxResolutionExecutor.js +60 -59
  36. package/dist/orchestrator/taskBuilder.d.ts +4 -2
  37. package/dist/orchestrator/taskBuilder.js +153 -52
  38. package/dist/orchestrator/unitBuilder.d.ts +3 -1
  39. package/dist/orchestrator/unitBuilder.js +24 -16
  40. package/dist/prompts/renderWorkerPrompt.d.ts +1 -1
  41. package/dist/prompts/renderWorkerPrompt.js +16 -8
  42. package/dist/providers/claudeCodeProvider.d.ts +4 -1
  43. package/dist/providers/claudeCodeProvider.js +8 -5
  44. package/dist/providers/localSubprocessProvider.d.ts +4 -0
  45. package/dist/providers/localSubprocessProvider.js +7 -2
  46. package/dist/providers/spawnLoggedCommand.d.ts +9 -1
  47. package/dist/providers/spawnLoggedCommand.js +77 -29
  48. package/dist/reporting/synthesis.d.ts +2 -0
  49. package/dist/reporting/synthesis.js +12 -9
  50. package/dist/supervisor/operatorHandoff.d.ts +1 -1
  51. package/dist/supervisor/operatorHandoff.js +56 -18
  52. package/dist/supervisor/runLedger.d.ts +1 -1
  53. package/dist/supervisor/runLedger.js +112 -5
  54. package/dist/supervisor/sessionConfig.js +10 -10
  55. package/dist/types/externalAnalyzer.d.ts +3 -0
  56. package/dist/types/flowCoverage.d.ts +5 -1
  57. package/dist/types/flowCoverage.js +5 -1
  58. package/dist/types/flows.d.ts +5 -1
  59. package/dist/types/flows.js +1 -1
  60. package/dist/types/runLedger.d.ts +5 -1
  61. package/dist/types/runLedger.js +6 -1
  62. package/dist/types/runtimeValidation.d.ts +12 -3
  63. package/dist/types/runtimeValidation.js +16 -1
  64. package/dist/types/sessionConfig.d.ts +15 -2
  65. package/dist/types/sessionConfig.js +15 -1
  66. package/dist/types/surfaces.d.ts +4 -1
  67. package/dist/types/surfaces.js +1 -1
  68. package/dist/types/workerSession.d.ts +9 -0
  69. package/dist/types/workerSession.js +5 -1
  70. package/dist/validation/artifacts.d.ts +1 -1
  71. package/dist/validation/artifacts.js +33 -20
  72. package/dist/validation/auditResults.d.ts +2 -2
  73. package/dist/validation/auditResults.js +7 -15
  74. package/dist/validation/basic.d.ts +9 -1
  75. package/dist/validation/basic.js +40 -3
  76. package/dist/validation/sessionConfig.d.ts +4 -2
  77. package/dist/validation/sessionConfig.js +62 -15
  78. package/docs/agent-integrations.md +31 -11
  79. package/docs/next-steps.md +21 -4
  80. package/docs/packaging.md +14 -0
  81. package/docs/product-direction.md +22 -0
  82. package/docs/production-launch-bar.md +2 -0
  83. package/docs/releasing.md +17 -0
  84. package/docs/remediation-baseline.md +75 -0
  85. package/docs/run-flow.md +23 -11
  86. package/docs/session-config.md +53 -6
  87. package/docs/supervisor.md +7 -0
  88. package/docs/workflow-refactor-brief.md +177 -0
  89. package/package.json +1 -1
  90. package/schemas/audit-code-v1alpha1.schema.json +1 -0
  91. package/schemas/audit_result.schema.json +4 -1
  92. package/schemas/audit_task.schema.json +3 -1
  93. package/schemas/coverage_matrix.schema.json +3 -3
  94. package/schemas/critical_flows.schema.json +6 -2
  95. package/schemas/file_disposition.schema.json +2 -2
  96. package/schemas/finding.schema.json +9 -4
  97. package/schemas/flow_coverage.schema.json +2 -2
  98. package/schemas/repo_manifest.schema.json +4 -4
  99. package/schemas/risk_register.schema.json +2 -2
  100. package/schemas/runtime_validation_report.schema.json +2 -2
  101. package/schemas/runtime_validation_tasks.schema.json +8 -2
  102. package/schemas/surface_manifest.schema.json +6 -3
  103. package/schemas/unit_manifest.schema.json +3 -2
  104. package/skills/audit-code/SKILL.md +5 -0
@@ -1,129 +1,92 @@
1
1
  import { cp, rm, unlink } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
- import { writeJsonFile, readOptionalJsonFile, readOptionalNdjsonFile, readOptionalTextFile, writeNdjsonFile, writeTextFile, } from "./json.js";
4
- export const ARTIFACT_FILE_TO_BUNDLE_KEY = {
5
- "repo_manifest.json": "repo_manifest",
6
- "file_disposition.json": "file_disposition",
7
- "auto_fixes_applied.json": "auto_fixes_applied",
8
- "unit_manifest.json": "unit_manifest",
9
- "graph_bundle.json": "graph_bundle",
10
- "surface_manifest.json": "surface_manifest",
11
- "critical_flows.json": "critical_flows",
12
- "flow_coverage.json": "flow_coverage",
13
- "risk_register.json": "risk_register",
14
- "coverage_matrix.json": "coverage_matrix",
15
- "runtime_validation_tasks.json": "runtime_validation_tasks",
16
- "runtime_validation_report.json": "runtime_validation_report",
17
- "external_analyzer_results.json": "external_analyzer_results",
18
- "audit_results.jsonl": "audit_results",
19
- "audit_tasks.json": "audit_tasks",
20
- "requeue_tasks.json": "requeue_tasks",
21
- "audit-report.md": "audit_report",
22
- "audit_state.json": "audit_state",
23
- "artifact_metadata.json": "artifact_metadata",
3
+ import { isFileMissingError, readOptionalJsonFile, readOptionalNdjsonFile, readOptionalTextFile, writeJsonFile, writeNdjsonFile, writeTextFile, } from "./json.js";
4
+ function jsonArtifact(fileName, phase) {
5
+ return {
6
+ fileName,
7
+ phase,
8
+ read: (path) => readOptionalJsonFile(path),
9
+ write: (path, value) => writeJsonFile(path, value),
10
+ };
11
+ }
12
+ function ndjsonArtifact(fileName, phase) {
13
+ return {
14
+ fileName,
15
+ phase,
16
+ read: (path) => readOptionalNdjsonFile(path),
17
+ write: (path, value) => writeNdjsonFile(path, value),
18
+ };
19
+ }
20
+ function textArtifact(fileName, phase) {
21
+ return {
22
+ fileName,
23
+ phase,
24
+ read: (path) => readOptionalTextFile(path),
25
+ write: (path, value) => writeTextFile(path, value),
26
+ };
27
+ }
28
+ export const ARTIFACT_DEFINITIONS = {
29
+ repo_manifest: jsonArtifact("repo_manifest.json", "intake"),
30
+ file_disposition: jsonArtifact("file_disposition.json", "intake"),
31
+ auto_fixes_applied: jsonArtifact("auto_fixes_applied.json", "intake"),
32
+ unit_manifest: jsonArtifact("unit_manifest.json", "analysis"),
33
+ graph_bundle: jsonArtifact("graph_bundle.json", "analysis"),
34
+ surface_manifest: jsonArtifact("surface_manifest.json", "analysis"),
35
+ critical_flows: jsonArtifact("critical_flows.json", "analysis"),
36
+ flow_coverage: jsonArtifact("flow_coverage.json", "analysis"),
37
+ risk_register: jsonArtifact("risk_register.json", "analysis"),
38
+ coverage_matrix: jsonArtifact("coverage_matrix.json", "execution"),
39
+ runtime_validation_tasks: jsonArtifact("runtime_validation_tasks.json", "execution"),
40
+ runtime_validation_report: jsonArtifact("runtime_validation_report.json", "execution"),
41
+ external_analyzer_results: jsonArtifact("external_analyzer_results.json", "execution"),
42
+ audit_results: ndjsonArtifact("audit_results.jsonl", "execution"),
43
+ audit_tasks: jsonArtifact("audit_tasks.json", "execution"),
44
+ requeue_tasks: jsonArtifact("requeue_tasks.json", "execution"),
45
+ audit_report: textArtifact("audit-report.md", "reporting"),
46
+ audit_state: jsonArtifact("audit_state.json", "supervisor"),
47
+ artifact_metadata: jsonArtifact("artifact_metadata.json", "supervisor"),
24
48
  };
25
- const _bundleKeyCoverage = true;
49
+ const ARTIFACT_ENTRIES = Object.entries(ARTIFACT_DEFINITIONS);
50
+ export const ARTIFACT_FILE_TO_BUNDLE_KEY = Object.fromEntries(ARTIFACT_ENTRIES.map(([key, definition]) => [definition.fileName, key]));
26
51
  export function getArtifactValue(bundle, artifactName) {
27
- const map = ARTIFACT_FILE_TO_BUNDLE_KEY;
28
- const key = map[artifactName];
52
+ const key = ARTIFACT_FILE_TO_BUNDLE_KEY[artifactName];
29
53
  return key ? bundle[key] : undefined;
30
54
  }
31
55
  export async function loadArtifactBundle(root) {
32
56
  const bundle = {};
33
- bundle.repo_manifest = await readOptionalJsonFile(`${root}/repo_manifest.json`);
34
- bundle.file_disposition = await readOptionalJsonFile(`${root}/file_disposition.json`);
35
- bundle.auto_fixes_applied = await readOptionalJsonFile(`${root}/auto_fixes_applied.json`);
36
- bundle.unit_manifest = await readOptionalJsonFile(`${root}/unit_manifest.json`);
37
- bundle.graph_bundle = await readOptionalJsonFile(`${root}/graph_bundle.json`);
38
- bundle.surface_manifest = await readOptionalJsonFile(`${root}/surface_manifest.json`);
39
- bundle.critical_flows = await readOptionalJsonFile(`${root}/critical_flows.json`);
40
- bundle.flow_coverage = await readOptionalJsonFile(`${root}/flow_coverage.json`);
41
- bundle.risk_register = await readOptionalJsonFile(`${root}/risk_register.json`);
42
- bundle.coverage_matrix = await readOptionalJsonFile(`${root}/coverage_matrix.json`);
43
- bundle.runtime_validation_tasks =
44
- await readOptionalJsonFile(`${root}/runtime_validation_tasks.json`);
45
- bundle.runtime_validation_report =
46
- await readOptionalJsonFile(`${root}/runtime_validation_report.json`);
47
- bundle.external_analyzer_results =
48
- await readOptionalJsonFile(`${root}/external_analyzer_results.json`);
49
- bundle.audit_results = await readOptionalNdjsonFile(`${root}/audit_results.jsonl`);
50
- bundle.audit_tasks = await readOptionalJsonFile(`${root}/audit_tasks.json`);
51
- bundle.requeue_tasks = await readOptionalJsonFile(`${root}/requeue_tasks.json`);
52
- bundle.audit_report = await readOptionalTextFile(`${root}/audit-report.md`);
53
- bundle.audit_state = await readOptionalJsonFile(`${root}/audit_state.json`);
54
- bundle.artifact_metadata = await readOptionalJsonFile(`${root}/artifact_metadata.json`);
57
+ const bundleRecord = bundle;
58
+ for (const entry of ARTIFACT_ENTRIES) {
59
+ const [key, definition] = entry;
60
+ const value = await definition.read(join(root, definition.fileName));
61
+ if (value !== undefined) {
62
+ bundleRecord[key] = value;
63
+ }
64
+ }
55
65
  return bundle;
56
66
  }
57
67
  export async function writeCoreArtifacts(root, bundle) {
58
- if (bundle.repo_manifest)
59
- await writeJsonFile(`${root}/repo_manifest.json`, bundle.repo_manifest);
60
- if (bundle.file_disposition)
61
- await writeJsonFile(`${root}/file_disposition.json`, bundle.file_disposition);
62
- if (bundle.auto_fixes_applied)
63
- await writeJsonFile(`${root}/auto_fixes_applied.json`, bundle.auto_fixes_applied);
64
- if (bundle.unit_manifest)
65
- await writeJsonFile(`${root}/unit_manifest.json`, bundle.unit_manifest);
66
- if (bundle.graph_bundle)
67
- await writeJsonFile(`${root}/graph_bundle.json`, bundle.graph_bundle);
68
- if (bundle.surface_manifest)
69
- await writeJsonFile(`${root}/surface_manifest.json`, bundle.surface_manifest);
70
- if (bundle.critical_flows)
71
- await writeJsonFile(`${root}/critical_flows.json`, bundle.critical_flows);
72
- if (bundle.flow_coverage)
73
- await writeJsonFile(`${root}/flow_coverage.json`, bundle.flow_coverage);
74
- if (bundle.risk_register)
75
- await writeJsonFile(`${root}/risk_register.json`, bundle.risk_register);
76
- if (bundle.coverage_matrix)
77
- await writeJsonFile(`${root}/coverage_matrix.json`, bundle.coverage_matrix);
78
- if (bundle.runtime_validation_tasks)
79
- await writeJsonFile(`${root}/runtime_validation_tasks.json`, bundle.runtime_validation_tasks);
80
- if (bundle.runtime_validation_report)
81
- await writeJsonFile(`${root}/runtime_validation_report.json`, bundle.runtime_validation_report);
82
- if (bundle.external_analyzer_results)
83
- await writeJsonFile(`${root}/external_analyzer_results.json`, bundle.external_analyzer_results);
84
- if (bundle.audit_results)
85
- await writeNdjsonFile(`${root}/audit_results.jsonl`, bundle.audit_results);
86
- if (bundle.audit_tasks)
87
- await writeJsonFile(`${root}/audit_tasks.json`, bundle.audit_tasks);
88
- if (bundle.requeue_tasks)
89
- await writeJsonFile(`${root}/requeue_tasks.json`, bundle.requeue_tasks);
90
- if (bundle.audit_report !== undefined)
91
- await writeTextFile(`${root}/audit-report.md`, bundle.audit_report);
92
- if (bundle.audit_state)
93
- await writeJsonFile(`${root}/audit_state.json`, bundle.audit_state);
94
- if (bundle.artifact_metadata)
95
- await writeJsonFile(`${root}/artifact_metadata.json`, bundle.artifact_metadata);
68
+ const bundleRecord = bundle;
69
+ for (const entry of ARTIFACT_ENTRIES) {
70
+ const [key, definition] = entry;
71
+ const value = bundleRecord[key];
72
+ if (value !== undefined) {
73
+ await definition.write(join(root, definition.fileName), value);
74
+ }
75
+ }
96
76
  }
97
- const INTERMEDIATE_ARTIFACTS = [
98
- "repo_manifest.json",
99
- "file_disposition.json",
100
- "auto_fixes_applied.json",
101
- "unit_manifest.json",
102
- "graph_bundle.json",
103
- "surface_manifest.json",
104
- "critical_flows.json",
105
- "flow_coverage.json",
106
- "risk_register.json",
107
- "coverage_matrix.json",
108
- "runtime_validation_tasks.json",
109
- "runtime_validation_report.json",
110
- "external_analyzer_results.json",
111
- "audit_results.jsonl",
112
- "audit_tasks.json",
113
- "requeue_tasks.json",
114
- "artifact_metadata.json",
115
- "audit_state.json",
116
- "audit-report.md",
117
- ];
118
77
  export async function cleanupIntermediateArtifacts(root) {
119
78
  const deleted = [];
120
- for (const name of INTERMEDIATE_ARTIFACTS) {
79
+ for (const [, definition] of ARTIFACT_ENTRIES) {
80
+ const path = join(root, definition.fileName);
121
81
  try {
122
- await unlink(join(root, name));
123
- deleted.push(name);
82
+ await unlink(path);
83
+ deleted.push(definition.fileName);
124
84
  }
125
- catch {
126
- // file absent — nothing to delete
85
+ catch (error) {
86
+ if (isFileMissingError(error)) {
87
+ continue;
88
+ }
89
+ throw error;
127
90
  }
128
91
  }
129
92
  return deleted;
package/dist/io/json.js CHANGED
@@ -3,6 +3,17 @@ import { dirname } from "node:path";
3
3
  function errorMessage(error) {
4
4
  return error instanceof Error ? error.message : String(error);
5
5
  }
6
+ function ioError(action, path, error) {
7
+ return new Error(`Failed to ${action} ${path}: ${errorMessage(error)}`);
8
+ }
9
+ async function ensureParentDirectory(path) {
10
+ try {
11
+ await mkdir(dirname(path), { recursive: true });
12
+ }
13
+ catch (error) {
14
+ throw ioError("prepare parent directory", path, error);
15
+ }
16
+ }
6
17
  export function isFileMissingError(error) {
7
18
  return (typeof error === "object" &&
8
19
  error !== null &&
@@ -28,31 +39,41 @@ export async function readJsonFile(path) {
28
39
  }
29
40
  }
30
41
  export async function writeJsonFile(path, value) {
31
- await mkdir(dirname(path), { recursive: true });
32
- await writeFile(path, JSON.stringify(value, null, 2) + "\n", "utf8");
42
+ await ensureParentDirectory(path);
43
+ try {
44
+ await writeFile(path, JSON.stringify(value, null, 2) + "\n", "utf8");
45
+ }
46
+ catch (error) {
47
+ throw ioError("write", path, error);
48
+ }
33
49
  }
34
50
  export async function appendNdjsonFile(path, value) {
35
- await mkdir(dirname(path), { recursive: true });
36
- await appendFile(path, JSON.stringify(value) + "\n", "utf8");
51
+ await ensureParentDirectory(path);
52
+ try {
53
+ await appendFile(path, JSON.stringify(value) + "\n", "utf8");
54
+ }
55
+ catch (error) {
56
+ throw ioError("append", path, error);
57
+ }
37
58
  }
38
59
  export async function readNdjsonFile(path) {
39
60
  try {
40
61
  const content = await readFile(path, "utf8");
41
- if (content.trim().length === 0) {
42
- return [];
43
- }
44
- return content
45
- .trim()
46
- .split(/\r?\n/)
47
- .filter(Boolean)
48
- .map((line, index) => {
62
+ const values = [];
63
+ let sawContent = false;
64
+ for (const [index, line] of content.split(/\r?\n/).entries()) {
65
+ if (line.trim().length === 0) {
66
+ continue;
67
+ }
68
+ sawContent = true;
49
69
  try {
50
- return JSON.parse(line);
70
+ values.push(JSON.parse(line));
51
71
  }
52
72
  catch (error) {
53
73
  throw new Error(`Invalid NDJSON in ${path} at line ${index + 1}: ${errorMessage(error)}`);
54
74
  }
55
- });
75
+ }
76
+ return sawContent ? values : [];
56
77
  }
57
78
  catch (error) {
58
79
  if (isFileMissingError(error)) {
@@ -87,12 +108,17 @@ export async function readOptionalNdjsonFile(path) {
87
108
  }
88
109
  }
89
110
  export async function writeNdjsonFile(path, values) {
90
- await mkdir(dirname(path), { recursive: true });
91
- if (values.length === 0) {
92
- await writeFile(path, "", "utf8");
93
- return;
111
+ await ensureParentDirectory(path);
112
+ try {
113
+ if (values.length === 0) {
114
+ await writeFile(path, "", "utf8");
115
+ return;
116
+ }
117
+ await writeFile(path, values.map((v) => JSON.stringify(v)).join("\n") + "\n", "utf8");
118
+ }
119
+ catch (error) {
120
+ throw ioError("write", path, error);
94
121
  }
95
- await writeFile(path, values.map((v) => JSON.stringify(v)).join("\n") + "\n", "utf8");
96
122
  }
97
123
  export async function readOptionalTextFile(path) {
98
124
  try {
@@ -106,6 +132,11 @@ export async function readOptionalTextFile(path) {
106
132
  }
107
133
  }
108
134
  export async function writeTextFile(path, value) {
109
- await mkdir(dirname(path), { recursive: true });
110
- await writeFile(path, value, "utf8");
135
+ await ensureParentDirectory(path);
136
+ try {
137
+ await writeFile(path, value, "utf8");
138
+ }
139
+ catch (error) {
140
+ throw ioError("write", path, error);
141
+ }
111
142
  }
@@ -9,7 +9,7 @@ export interface RunPaths {
9
9
  stderrPath: string;
10
10
  statusPath: string;
11
11
  }
12
- export declare function buildRunId(obligationId: string | null, index: number): string;
12
+ export declare function buildRunId(obligationId: string | null, index: number, now?: Date): string;
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>;
@@ -5,9 +5,32 @@ 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
- export function buildRunId(obligationId, index) {
9
- const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
10
- const obligation = (obligationId ?? "terminal").replace(/[^a-zA-Z0-9_-]/g, "-");
8
+ function pad(value, size = 2) {
9
+ return String(value).padStart(size, "0");
10
+ }
11
+ function formatRunTimestamp(value) {
12
+ return [
13
+ pad(value.getUTCFullYear(), 4),
14
+ pad(value.getUTCMonth() + 1),
15
+ pad(value.getUTCDate()),
16
+ "T",
17
+ pad(value.getUTCHours()),
18
+ pad(value.getUTCMinutes()),
19
+ pad(value.getUTCSeconds()),
20
+ pad(value.getUTCMilliseconds(), 3),
21
+ "Z",
22
+ ].join("");
23
+ }
24
+ function normalizeRunIdSegment(value) {
25
+ const normalized = (value ?? "terminal")
26
+ .trim()
27
+ .replace(/[^a-zA-Z0-9_-]+/g, "-")
28
+ .replace(/^-+|-+$/g, "");
29
+ return normalized.length > 0 ? normalized : "terminal";
30
+ }
31
+ export function buildRunId(obligationId, index, now = new Date()) {
32
+ const timestamp = formatRunTimestamp(now);
33
+ const obligation = normalizeRunIdSegment(obligationId);
11
34
  return `${timestamp}_${obligation}_${String(index).padStart(3, "0")}`;
12
35
  }
13
36
  export function getRunPaths(artifactsDir, runId) {
@@ -4,6 +4,19 @@ import { computeArtifactMetadata } from "./artifactMetadata.js";
4
4
  import { runIntakeExecutor, runStructureExecutor, runPlanningExecutor, runResultIngestionExecutor, runRuntimeValidationExecutor, runRuntimeValidationUpdateExecutor, runSynthesisExecutor, runExternalAnalyzerImportExecutor, } from "./internalExecutors.js";
5
5
  import { runAutoFixExecutor } from "./autoFixExecutor.js";
6
6
  import { runSyntaxResolutionExecutor } from "./syntaxResolutionExecutor.js";
7
+ function cloneState(state) {
8
+ return {
9
+ ...state,
10
+ blockers: [...(state.blockers ?? [])],
11
+ obligations: state.obligations.map((obligation) => ({ ...obligation })),
12
+ };
13
+ }
14
+ function formatExecutorFailure(selectedExecutor, selectedObligation, error) {
15
+ const detail = error instanceof Error ? error.message : String(error ?? "unknown error");
16
+ return new Error(`advanceAudit ${selectedExecutor} failed while resolving ${selectedObligation ?? "the current obligation"}: ${detail}`, {
17
+ cause: error instanceof Error ? error : undefined,
18
+ });
19
+ }
7
20
  export async function advanceAudit(bundle, options = {}) {
8
21
  const decision = decideNextStep(bundle);
9
22
  const forcedExecutor = options.preferredExecutor ?? null;
@@ -12,9 +25,12 @@ export async function advanceAudit(bundle, options = {}) {
12
25
  ? `forced:${forcedExecutor}`
13
26
  : decision.selected_obligation;
14
27
  if (!selectedExecutor) {
15
- const state = deriveAuditState(bundle);
16
- // Do not overwrite last_executor when no executor was selected — preserve prior value
17
- state.last_obligation = selectedObligation ?? undefined;
28
+ const state = cloneState(decision.state);
29
+ state.last_executor = bundle.audit_state?.last_executor ?? state.last_executor;
30
+ state.last_obligation =
31
+ selectedObligation ??
32
+ bundle.audit_state?.last_obligation ??
33
+ state.last_obligation;
18
34
  return {
19
35
  audit_state: state,
20
36
  selected_obligation: selectedObligation,
@@ -27,65 +43,70 @@ export async function advanceAudit(bundle, options = {}) {
27
43
  };
28
44
  }
29
45
  let run;
30
- switch (selectedExecutor) {
31
- case "intake_executor":
32
- if (!options.root)
33
- throw new Error("advanceAudit intake_executor requires root");
34
- run = await runIntakeExecutor(bundle, options.root);
35
- break;
36
- case "structure_executor":
37
- run = runStructureExecutor(bundle);
38
- break;
39
- case "planning_executor":
40
- if (!options.root)
41
- throw new Error("advanceAudit planning_executor requires root");
42
- run = await runPlanningExecutor(bundle, options.root, options.lineIndex ?? {});
43
- break;
44
- case "result_ingestion_executor":
45
- run = runResultIngestionExecutor(bundle, options.auditResults ?? bundle.audit_results ?? []);
46
- break;
47
- case "runtime_validation_executor":
48
- if (!options.root)
49
- throw new Error("advanceAudit runtime_validation_executor requires root");
50
- run = await runRuntimeValidationExecutor(bundle, options.root);
51
- break;
52
- case "synthesis_executor":
53
- run = runSynthesisExecutor(bundle, options.auditResults);
54
- break;
55
- case "runtime_validation_update_executor":
56
- if (!options.runtimeValidationUpdates)
57
- throw new Error("advanceAudit runtime_validation_update_executor requires runtimeValidationUpdates");
58
- run = runRuntimeValidationUpdateExecutor(bundle, options.runtimeValidationUpdates);
59
- break;
60
- case "external_analyzer_import_executor":
61
- if (!options.externalAnalyzerResults)
62
- throw new Error("advanceAudit external_analyzer_import_executor requires externalAnalyzerResults");
63
- run = runExternalAnalyzerImportExecutor(bundle, options.externalAnalyzerResults);
64
- break;
65
- case "auto_fix_executor":
66
- if (!options.root)
67
- throw new Error("advanceAudit auto_fix_executor requires root");
68
- run = runAutoFixExecutor(bundle, options.root);
69
- break;
70
- case "syntax_resolution_executor":
71
- if (!options.root)
72
- throw new Error("advanceAudit syntax_resolution_executor requires root");
73
- run = runSyntaxResolutionExecutor(bundle, options.root);
74
- break;
75
- default:
76
- const state = deriveAuditState(bundle);
77
- state.last_executor = selectedExecutor;
78
- state.last_obligation = selectedObligation ?? undefined;
79
- return {
80
- audit_state: state,
81
- selected_obligation: selectedObligation,
82
- selected_executor: selectedExecutor,
83
- progress_made: false,
84
- artifacts_written: ["audit_state.json"],
85
- progress_summary: `Executor ${selectedExecutor} is selected but not yet dispatched through advance-audit.`,
86
- next_likely_step: selectedObligation,
87
- updated_bundle: { ...bundle, audit_state: state },
88
- };
46
+ try {
47
+ switch (selectedExecutor) {
48
+ case "intake_executor":
49
+ if (!options.root)
50
+ throw new Error("advanceAudit intake_executor requires root");
51
+ run = await runIntakeExecutor(bundle, options.root);
52
+ break;
53
+ case "structure_executor":
54
+ run = runStructureExecutor(bundle);
55
+ break;
56
+ case "planning_executor":
57
+ if (!options.root)
58
+ throw new Error("advanceAudit planning_executor requires root");
59
+ run = await runPlanningExecutor(bundle, options.root, options.lineIndex ?? {});
60
+ break;
61
+ case "result_ingestion_executor":
62
+ run = runResultIngestionExecutor(bundle, options.auditResults ?? bundle.audit_results ?? []);
63
+ break;
64
+ case "runtime_validation_executor":
65
+ if (!options.root)
66
+ throw new Error("advanceAudit runtime_validation_executor requires root");
67
+ run = await runRuntimeValidationExecutor(bundle, options.root);
68
+ break;
69
+ case "synthesis_executor":
70
+ run = runSynthesisExecutor(bundle, options.auditResults);
71
+ break;
72
+ case "runtime_validation_update_executor":
73
+ if (!options.runtimeValidationUpdates)
74
+ throw new Error("advanceAudit runtime_validation_update_executor requires runtimeValidationUpdates");
75
+ run = runRuntimeValidationUpdateExecutor(bundle, options.runtimeValidationUpdates);
76
+ break;
77
+ case "external_analyzer_import_executor":
78
+ if (!options.externalAnalyzerResults)
79
+ throw new Error("advanceAudit external_analyzer_import_executor requires externalAnalyzerResults");
80
+ run = runExternalAnalyzerImportExecutor(bundle, options.externalAnalyzerResults);
81
+ break;
82
+ case "auto_fix_executor":
83
+ if (!options.root)
84
+ throw new Error("advanceAudit auto_fix_executor requires root");
85
+ run = runAutoFixExecutor(bundle, options.root);
86
+ break;
87
+ case "syntax_resolution_executor":
88
+ if (!options.root)
89
+ throw new Error("advanceAudit syntax_resolution_executor requires root");
90
+ run = runSyntaxResolutionExecutor(bundle, options.root);
91
+ break;
92
+ default:
93
+ const state = deriveAuditState(bundle);
94
+ state.last_executor = selectedExecutor;
95
+ state.last_obligation = selectedObligation ?? undefined;
96
+ return {
97
+ audit_state: state,
98
+ selected_obligation: selectedObligation,
99
+ selected_executor: selectedExecutor,
100
+ progress_made: false,
101
+ artifacts_written: ["audit_state.json"],
102
+ progress_summary: `Executor ${selectedExecutor} is selected but not yet dispatched through advance-audit.`,
103
+ next_likely_step: selectedObligation,
104
+ updated_bundle: { ...bundle, audit_state: state },
105
+ };
106
+ }
107
+ }
108
+ catch (error) {
109
+ throw formatExecutorFailure(selectedExecutor, selectedObligation, error);
89
110
  }
90
111
  const metadata = computeArtifactMetadata(run.updated, bundle.artifact_metadata);
91
112
  const metadataBundle = { ...run.updated, artifact_metadata: metadata };
@@ -1,13 +1,9 @@
1
- import { execSync } from "node:child_process";
1
+ import { join } from "node:path";
2
2
  import { isAuditExcludedStatus } from "../extractors/disposition.js";
3
- function tryRunConfiguredFormatter(root, command) {
4
- try {
5
- execSync(command, { cwd: root, stdio: "ignore", windowsHide: true });
6
- return true;
7
- }
8
- catch (e) {
9
- return false;
10
- }
3
+ import { resolveNodeTool, runFirstAvailableCommand, } from "./localCommands.js";
4
+ function tryRunConfiguredFormatter(root, candidates) {
5
+ const result = runFirstAvailableCommand(root, candidates);
6
+ return result !== null && !result.error && result.exitCode === 0;
11
7
  }
12
8
  export function runAutoFixExecutor(bundle, root) {
13
9
  if (!bundle.file_disposition) {
@@ -28,24 +24,45 @@ export function runAutoFixExecutor(bundle, root) {
28
24
  extensions.has("js") ||
29
25
  extensions.has("tsx") ||
30
26
  extensions.has("jsx")) {
31
- if (tryRunConfiguredFormatter(root, "npx prettier --write ."))
27
+ if (tryRunConfiguredFormatter(root, [
28
+ ...resolveNodeTool(root, join("node_modules", "prettier", "bin", "prettier.cjs"), ["--write", "."], "prettier --write ."),
29
+ { command: "prettier", args: ["--write", "."], display: "prettier --write ." },
30
+ ]))
32
31
  executedTools.push("prettier");
33
- if (tryRunConfiguredFormatter(root, "npx eslint --fix ."))
32
+ if (tryRunConfiguredFormatter(root, [
33
+ ...resolveNodeTool(root, join("node_modules", "eslint", "bin", "eslint.js"), ["--fix", "."], "eslint --fix ."),
34
+ { command: "eslint", args: ["--fix", "."], display: "eslint --fix ." },
35
+ ]))
34
36
  executedTools.push("eslint");
35
37
  }
36
38
  // Python
37
39
  if (extensions.has("py")) {
38
- if (tryRunConfiguredFormatter(root, "black .") ||
39
- tryRunConfiguredFormatter(root, "python -m black .")) {
40
+ if (tryRunConfiguredFormatter(root, [
41
+ { command: "black", args: ["."], display: "black ." },
42
+ { command: "python", args: ["-m", "black", "."], display: "python -m black ." },
43
+ ])) {
40
44
  executedTools.push("black");
41
45
  }
42
- if (tryRunConfiguredFormatter(root, "autopep8 --in-place --recursive .")) {
46
+ if (tryRunConfiguredFormatter(root, [
47
+ {
48
+ command: "autopep8",
49
+ args: ["--in-place", "--recursive", "."],
50
+ display: "autopep8 --in-place --recursive .",
51
+ },
52
+ {
53
+ command: "python",
54
+ args: ["-m", "autopep8", "--in-place", "--recursive", "."],
55
+ display: "python -m autopep8 --in-place --recursive .",
56
+ },
57
+ ])) {
43
58
  executedTools.push("autopep8");
44
59
  }
45
60
  }
46
61
  // Go
47
62
  if (extensions.has("go")) {
48
- if (tryRunConfiguredFormatter(root, "gofmt -w ."))
63
+ if (tryRunConfiguredFormatter(root, [
64
+ { command: "gofmt", args: ["-w", "."], display: "gofmt -w ." },
65
+ ]))
49
66
  executedTools.push("gofmt");
50
67
  }
51
68
  const resultsArtifact = {
@@ -10,11 +10,17 @@ function lensSetForFlow(concerns) {
10
10
  return concerns.filter((concern) => allowed.includes(concern));
11
11
  }
12
12
  export function buildFlowCoverage(criticalFlows, coverageMatrix) {
13
+ const coverageByPath = new Map(coverageMatrix.files.map((file) => [file.path, file]));
13
14
  const flows = criticalFlows.flows.map((flow) => {
14
- const required = lensSetForFlow(flow.concerns);
15
+ const flowPaths = Array.isArray(flow.paths)
16
+ ? flow.paths.filter((path) => typeof path === "string")
17
+ : [];
18
+ const required = lensSetForFlow(Array.isArray(flow.concerns)
19
+ ? flow.concerns.filter((concern) => typeof concern === "string")
20
+ : []);
15
21
  const completed = new Set();
16
- for (const path of flow.paths) {
17
- const record = coverageMatrix.files.find((file) => file.path === path);
22
+ for (const path of flowPaths) {
23
+ const record = coverageByPath.get(path);
18
24
  if (!record || record.audit_status === "excluded") {
19
25
  continue;
20
26
  }
@@ -33,11 +39,11 @@ export function buildFlowCoverage(criticalFlows, coverageMatrix) {
33
39
  : "pending";
34
40
  return {
35
41
  flow_id: flow.id,
36
- paths: flow.paths,
42
+ paths: flowPaths,
37
43
  required_lenses: required,
38
44
  completed_lenses,
39
45
  status,
40
- notes: [`Derived from ${flow.paths.length} path(s).`],
46
+ notes: [`Derived from ${flowPaths.length} path(s).`],
41
47
  };
42
48
  });
43
49
  return { flows };
@@ -1,3 +1,8 @@
1
- import type { AuditTask } from "../types.js";
1
+ import type { Lens } from "../types.js";
2
2
  import type { CriticalFlowManifest } from "../types/flows.js";
3
- export declare function buildFlowAwareTaskAugmentations(existingTasks: AuditTask[], criticalFlows: CriticalFlowManifest, _lineIndex: Record<string, number>): AuditTask[];
3
+ export interface FlowReviewBlock {
4
+ flow_id: string;
5
+ lens: Lens;
6
+ file_paths: string[];
7
+ }
8
+ export declare function claimFlowReviewBlocks(criticalFlows: CriticalFlowManifest, pendingByLens: Map<Lens, Set<string>>, assigned: Set<string>): FlowReviewBlock[];