auditor-lambda 0.7.0 → 0.9.0

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 (125) hide show
  1. package/README.md +0 -21
  2. package/audit-code-wrapper-lib.mjs +149 -129
  3. package/dist/adapters/normalizeExternal.js +6 -3
  4. package/dist/cli/args.d.ts +0 -1
  5. package/dist/cli/args.js +0 -6
  6. package/dist/cli/auditStep.js +7 -1
  7. package/dist/cli/dispatch.js +3 -2
  8. package/dist/cli/lineIndex.js +4 -1
  9. package/dist/cli/mergeAndIngestCommand.d.ts +1 -0
  10. package/dist/cli/mergeAndIngestCommand.js +219 -0
  11. package/dist/cli/nextStepCommand.js +5 -1
  12. package/dist/cli/runToCompletion.d.ts +9 -0
  13. package/dist/cli/runToCompletion.js +655 -480
  14. package/dist/cli/statusCommand.d.ts +1 -0
  15. package/dist/cli/statusCommand.js +113 -0
  16. package/dist/cli/submitPacketCommand.d.ts +1 -0
  17. package/dist/cli/submitPacketCommand.js +155 -0
  18. package/dist/cli/workerResult.d.ts +1 -1
  19. package/dist/cli/workerRunCommand.d.ts +1 -0
  20. package/dist/cli/workerRunCommand.js +88 -0
  21. package/dist/cli.d.ts +0 -1
  22. package/dist/cli.js +14 -565
  23. package/dist/extractors/analyzers/sql.js +4 -1
  24. package/dist/extractors/analyzers/treeSitter.js +29 -15
  25. package/dist/extractors/analyzers/typescript.js +10 -8
  26. package/dist/extractors/designAssessment.js +43 -24
  27. package/dist/extractors/graph.js +151 -75
  28. package/dist/extractors/pathPatterns.js +17 -5
  29. package/dist/io/artifacts.d.ts +3 -1
  30. package/dist/io/artifacts.js +18 -2
  31. package/dist/io/runArtifactTypes.d.ts +18 -0
  32. package/dist/io/runArtifactTypes.js +1 -0
  33. package/dist/io/runArtifacts.d.ts +2 -18
  34. package/dist/io/runArtifacts.js +14 -3
  35. package/dist/mcp/server.js +9 -0
  36. package/dist/orchestrator/advance.js +38 -22
  37. package/dist/orchestrator/artifactFreshness.js +14 -4
  38. package/dist/orchestrator/autoFixExecutor.d.ts +2 -2
  39. package/dist/orchestrator/autoFixExecutor.js +26 -8
  40. package/dist/orchestrator/dependencyMap.d.ts +1 -1
  41. package/dist/orchestrator/dependencyMap.js +7 -1
  42. package/dist/orchestrator/executorResult.d.ts +12 -0
  43. package/dist/orchestrator/executorResult.js +1 -0
  44. package/dist/orchestrator/fileAnchors.js +14 -3
  45. package/dist/orchestrator/fileIntegrity.d.ts +1 -0
  46. package/dist/orchestrator/fileIntegrity.js +12 -3
  47. package/dist/orchestrator/flowCoverage.js +1 -0
  48. package/dist/orchestrator/flowRequeue.js +4 -1
  49. package/dist/orchestrator/graphEnrichmentExecutor.d.ts +1 -1
  50. package/dist/orchestrator/graphEnrichmentExecutor.js +3 -1
  51. package/dist/orchestrator/ingestionExecutors.d.ts +11 -0
  52. package/dist/orchestrator/ingestionExecutors.js +237 -0
  53. package/dist/orchestrator/intakeExecutors.d.ts +3 -0
  54. package/dist/orchestrator/intakeExecutors.js +25 -0
  55. package/dist/orchestrator/planningExecutors.d.ts +4 -0
  56. package/dist/orchestrator/planningExecutors.js +95 -0
  57. package/dist/orchestrator/reviewPacketGraph.d.ts +31 -0
  58. package/dist/orchestrator/reviewPacketGraph.js +691 -0
  59. package/dist/orchestrator/reviewPackets.d.ts +2 -15
  60. package/dist/orchestrator/reviewPackets.js +3 -685
  61. package/dist/orchestrator/runtimeCommand.d.ts +11 -0
  62. package/dist/orchestrator/runtimeCommand.js +71 -0
  63. package/dist/orchestrator/scope.js +1 -1
  64. package/dist/orchestrator/selectiveDeepening/conflict.d.ts +8 -0
  65. package/dist/orchestrator/selectiveDeepening/conflict.js +71 -0
  66. package/dist/orchestrator/selectiveDeepening/findingFollowup.d.ts +10 -0
  67. package/dist/orchestrator/selectiveDeepening/findingFollowup.js +52 -0
  68. package/dist/orchestrator/selectiveDeepening/highRiskClean.d.ts +7 -0
  69. package/dist/orchestrator/selectiveDeepening/highRiskClean.js +44 -0
  70. package/dist/orchestrator/selectiveDeepening/index.d.ts +18 -0
  71. package/dist/orchestrator/selectiveDeepening/index.js +128 -0
  72. package/dist/orchestrator/selectiveDeepening/lensVerification.d.ts +12 -0
  73. package/dist/orchestrator/selectiveDeepening/lensVerification.js +242 -0
  74. package/dist/orchestrator/selectiveDeepening/runtimeValidation.d.ts +13 -0
  75. package/dist/orchestrator/selectiveDeepening/runtimeValidation.js +57 -0
  76. package/dist/orchestrator/selectiveDeepening/shared.d.ts +45 -0
  77. package/dist/orchestrator/selectiveDeepening/shared.js +128 -0
  78. package/dist/orchestrator/selectiveDeepening/stewardFollowup.d.ts +6 -0
  79. package/dist/orchestrator/selectiveDeepening/stewardFollowup.js +72 -0
  80. package/dist/orchestrator/selectiveDeepening.d.ts +2 -20
  81. package/dist/orchestrator/selectiveDeepening.js +6 -760
  82. package/dist/orchestrator/staleness.js +3 -3
  83. package/dist/orchestrator/structureExecutors.d.ts +5 -0
  84. package/dist/orchestrator/structureExecutors.js +94 -0
  85. package/dist/orchestrator/syntaxResolutionExecutor.d.ts +1 -1
  86. package/dist/orchestrator/synthesisExecutors.d.ts +12 -0
  87. package/dist/orchestrator/synthesisExecutors.js +90 -0
  88. package/dist/orchestrator/taskBuilder.d.ts +2 -2
  89. package/dist/orchestrator/taskBuilder.js +101 -82
  90. package/dist/providers/index.d.ts +7 -0
  91. package/dist/providers/index.js +14 -95
  92. package/dist/quota/discoveredLimits.d.ts +1 -0
  93. package/dist/quota/discoveredLimits.js +7 -1
  94. package/dist/quota/index.d.ts +0 -2
  95. package/dist/quota/index.js +1 -2
  96. package/dist/reporting/workBlocks.js +7 -4
  97. package/dist/types/reviewPlanning.d.ts +23 -16
  98. package/dist/validation/auditResults.js +97 -95
  99. package/dist/validation/sessionConfig.d.ts +2 -2
  100. package/dist/validation/sessionConfig.js +14 -7
  101. package/docs/development.md +35 -139
  102. package/docs/history.md +26 -0
  103. package/docs/product.md +41 -108
  104. package/package.json +3 -2
  105. package/schemas/audit_findings.schema.json +6 -5
  106. package/schemas/critical_flows.schema.json +3 -2
  107. package/schemas/dispatch_quota.schema.json +3 -1
  108. package/schemas/external_analyzer_results.schema.json +2 -2
  109. package/schemas/graph_bundle.schema.json +1 -1
  110. package/schemas/repo_manifest.schema.json +1 -1
  111. package/schemas/review_packets.schema.json +1 -1
  112. package/schemas/step_contract.schema.json +80 -0
  113. package/scripts/postinstall.mjs +19 -2
  114. package/skills/audit-code/opencode-command-template.txt +3 -3
  115. package/dist/orchestrator/internalExecutors.d.ts +0 -34
  116. package/dist/orchestrator/internalExecutors.js +0 -581
  117. package/dist/providers/localSubprocessProvider.d.ts +0 -9
  118. package/dist/providers/localSubprocessProvider.js +0 -18
  119. package/dist/providers/subprocessTemplateProvider.d.ts +0 -8
  120. package/dist/providers/subprocessTemplateProvider.js +0 -59
  121. package/dist/providers/vscodeTaskProvider.d.ts +0 -7
  122. package/dist/providers/vscodeTaskProvider.js +0 -14
  123. package/dist/quota/probe.d.ts +0 -10
  124. package/dist/quota/probe.js +0 -18
  125. package/docs/handoff.md +0 -204
@@ -0,0 +1,219 @@
1
+ import { readFile, readdir } from "node:fs/promises";
2
+ import { join, resolve } from "node:path";
3
+ import { isFileMissingError, readJsonFile, writeJsonFile } from "@audit-tools/shared";
4
+ import { validateAuditResults } from "../validation/auditResults.js";
5
+ import { runAuditStep } from "./auditStep.js";
6
+ import { DISPATCH_RESULT_MAP_FILENAME, ACTIVE_DISPATCH_FILENAME, loadDispatchResultMap, entriesByTaskId, buildPendingAuditTasks, } from "./dispatch.js";
7
+ import { addFileLineCountHints } from "./lineIndex.js";
8
+ import { isCanonicalResultFilename, getArtifactsDir, getFlag } from "./args.js";
9
+ import { buildWorkerResult } from "./workerResult.js";
10
+ export async function cmdMergeAndIngest(argv) {
11
+ const runId = getFlag(argv, "--run-id");
12
+ if (!runId)
13
+ throw new Error("merge-and-ingest requires --run-id <run_id>");
14
+ const artifactsDir = getArtifactsDir(argv);
15
+ const runDir = join(artifactsDir, "runs", runId);
16
+ const taskResultsDir = join(runDir, "task-results");
17
+ const auditResultsPath = join(runDir, "audit-results.json");
18
+ const taskPath = join(runDir, "task.json");
19
+ const tasksPath = join(runDir, "pending-audit-tasks.json");
20
+ const workerTask = await readJsonFile(taskPath);
21
+ const resultMap = await loadDispatchResultMap(runDir);
22
+ if (!resultMap) {
23
+ throw new Error(`No ${DISPATCH_RESULT_MAP_FILENAME} found for run ${runId}; run prepare-dispatch first.`);
24
+ }
25
+ let allTasks = [];
26
+ try {
27
+ allTasks = await readJsonFile(tasksPath);
28
+ }
29
+ catch { /* may not exist */ }
30
+ const entryByTaskId = entriesByTaskId(resultMap.entries);
31
+ if (entryByTaskId.size !== resultMap.entries.length) {
32
+ throw new Error(`Dispatch result map for run ${runId} contains duplicate task entries.`);
33
+ }
34
+ const expectedPaths = new Set(resultMap.entries.map((entry) => resolve(entry.result_path)));
35
+ let files;
36
+ try {
37
+ files = (await readdir(taskResultsDir)).filter(f => f.endsWith(".json")).sort();
38
+ }
39
+ catch {
40
+ files = [];
41
+ }
42
+ const passing = [];
43
+ const failing = [];
44
+ const seenTaskIds = new Set();
45
+ let spuriousFileCount = 0;
46
+ const fallbackByTaskId = new Map();
47
+ for (const filename of files) {
48
+ const filePath = resolve(join(taskResultsDir, filename));
49
+ if (expectedPaths.has(filePath))
50
+ continue;
51
+ // Not part of this round's plan. Still read it so a current task can be
52
+ // recovered by task_id (e.g. a subagent wrote a valid result under a
53
+ // non-assigned name).
54
+ try {
55
+ const raw = await readFile(filePath, "utf8");
56
+ const parsed = JSON.parse(raw);
57
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
58
+ const tid = typeof parsed.task_id === "string"
59
+ ? String(parsed.task_id) : undefined;
60
+ if (tid && !fallbackByTaskId.has(tid)) {
61
+ fallbackByTaskId.set(tid, parsed);
62
+ }
63
+ }
64
+ }
65
+ catch { /* not parseable — skip */ }
66
+ // Only genuinely stray files are "spurious". Canonical per-task result files
67
+ // (<stem>_<digest>.json) left by prior deepening rounds in the same
68
+ // task-results/ dir are legitimate and must not inflate the count or bury
69
+ // the real stray-file signal (3 -> 191 over a run before this fix).
70
+ if (!isCanonicalResultFilename(filename)) {
71
+ spuriousFileCount++;
72
+ process.stderr.write(`[merge-and-ingest] Warning: unexpected file in task-results/: ${filename}\n`);
73
+ }
74
+ }
75
+ for (const task of allTasks) {
76
+ const entry = entryByTaskId.get(task.task_id);
77
+ if (!entry) {
78
+ failing.push({
79
+ task_id: task.task_id,
80
+ errors: ["Missing dispatch result-map entry for assigned task."],
81
+ });
82
+ continue;
83
+ }
84
+ const filePath = entry.result_path;
85
+ let obj;
86
+ try {
87
+ obj = JSON.parse(await readFile(filePath, "utf8"));
88
+ }
89
+ catch (e) {
90
+ if (isFileMissingError(e)) {
91
+ const fallback = fallbackByTaskId.get(task.task_id);
92
+ if (fallback) {
93
+ process.stderr.write(`[merge-and-ingest] Recovered result for '${task.task_id}' from unexpected file (matched by task_id)\n`);
94
+ obj = fallback;
95
+ }
96
+ else {
97
+ failing.push({
98
+ task_id: task.task_id,
99
+ errors: ["Missing audit result for assigned task."],
100
+ });
101
+ continue;
102
+ }
103
+ }
104
+ else {
105
+ failing.push({ task_id: task.task_id, errors: [`Invalid JSON: ${e.message}`] });
106
+ continue;
107
+ }
108
+ }
109
+ const record = obj && typeof obj === "object" && !Array.isArray(obj)
110
+ ? obj
111
+ : undefined;
112
+ const taskId = typeof record?.task_id === "string"
113
+ ? String(record.task_id) : undefined;
114
+ const resultErrors = [];
115
+ if (taskId) {
116
+ if (seenTaskIds.has(taskId)) {
117
+ resultErrors.push(`Duplicate audit result for assigned task '${taskId}'.`);
118
+ }
119
+ else {
120
+ seenTaskIds.add(taskId);
121
+ }
122
+ if (taskId !== task.task_id) {
123
+ resultErrors.push(`Result file is assigned to '${task.task_id}' but contains task_id '${taskId}'.`);
124
+ }
125
+ }
126
+ const issues = validateAuditResults([obj], [task], { lineIndex: task.file_line_counts ?? {} });
127
+ resultErrors.push(...issues
128
+ .filter(i => i.severity === "error")
129
+ .map(i => i.message));
130
+ if (resultErrors.length === 0) {
131
+ passing.push(obj);
132
+ }
133
+ else {
134
+ failing.push({ task_id: taskId ?? task.task_id, errors: resultErrors });
135
+ }
136
+ }
137
+ await writeJsonFile(auditResultsPath, passing);
138
+ const failedTasksPath = join(runDir, "failed-tasks.json");
139
+ if (failing.length > 0) {
140
+ await writeJsonFile(failedTasksPath, failing);
141
+ }
142
+ if (passing.length === 0 && failing.length > 0) {
143
+ throw new Error(`All ${failing.length} assigned task result(s) were missing or invalid; blocked before ingestion. See ${failedTasksPath}`);
144
+ }
145
+ const findingCount = passing.reduce((sum, result) => sum + result.findings.length, 0);
146
+ let result = null;
147
+ if (passing.length > 0) {
148
+ result = await runAuditStep({
149
+ root: workerTask.repo_root,
150
+ artifactsDir,
151
+ preferredExecutor: "result_ingestion_executor",
152
+ auditResultsPath,
153
+ });
154
+ const updatedPendingTasks = await addFileLineCountHints(workerTask.repo_root, buildPendingAuditTasks(result.updated_bundle));
155
+ await writeJsonFile(tasksPath, updatedPendingTasks);
156
+ }
157
+ const activeDispatchPath = join(artifactsDir, ACTIVE_DISPATCH_FILENAME);
158
+ try {
159
+ const dispatch = await readJsonFile(activeDispatchPath);
160
+ if (dispatch.run_id === runId) {
161
+ dispatch.status = failing.length > 0 ? "active" : "merged";
162
+ await writeJsonFile(activeDispatchPath, dispatch);
163
+ }
164
+ }
165
+ catch { /* no active dispatch file — skip */ }
166
+ let retryDispatchPath = null;
167
+ if (failing.length > 0) {
168
+ const failedTaskIds = new Set(failing.map((f) => f.task_id));
169
+ const failedPacketIds = [
170
+ ...new Set(resultMap.entries
171
+ .filter((e) => failedTaskIds.has(e.task_id))
172
+ .map((e) => e.packet_id)),
173
+ ];
174
+ const retryDispatch = {
175
+ run_id: runId,
176
+ retry_packet_ids: failedPacketIds,
177
+ failed_task_count: failing.length,
178
+ accepted_task_count: passing.length,
179
+ };
180
+ retryDispatchPath = join(runDir, "retry-dispatch.json");
181
+ await writeJsonFile(retryDispatchPath, retryDispatch);
182
+ process.stderr.write(`[merge-and-ingest] ${passing.length} accepted, ${failing.length} failed. ` +
183
+ `Retry packets: ${failedPacketIds.join(", ")}\n`);
184
+ }
185
+ const status = failing.length > 0
186
+ ? "partial"
187
+ : (result?.progress_made ? "completed" : "no_progress");
188
+ const workerResult = buildWorkerResult({
189
+ runId,
190
+ obligationId: workerTask.obligation_id,
191
+ status: failing.length > 0 ? "no_progress" : (result?.progress_made ? "completed" : "no_progress"),
192
+ progressMade: result?.progress_made ?? false,
193
+ selectedExecutor: result?.selected_executor ?? null,
194
+ artifactsWritten: result?.artifacts_written ?? [],
195
+ summary: result?.progress_summary ?? `${failing.length} task(s) failed`,
196
+ nextLikelyStep: result?.next_likely_step ?? null,
197
+ errors: [],
198
+ });
199
+ await writeJsonFile(workerTask.result_path, workerResult);
200
+ console.log(JSON.stringify({
201
+ run_id: runId,
202
+ status,
203
+ accepted_count: passing.length,
204
+ rejected_count: failing.length,
205
+ spurious_file_count: spuriousFileCount,
206
+ finding_count: findingCount,
207
+ audit_results_path: auditResultsPath,
208
+ ...(retryDispatchPath ? { retry_dispatch_path: retryDispatchPath } : {}),
209
+ ...(result ? {
210
+ selected_executor: workerResult.selected_executor,
211
+ progress_made: workerResult.progress_made,
212
+ progress_summary: workerResult.summary,
213
+ next_likely_step: workerResult.next_likely_step,
214
+ } : {}),
215
+ }, null, 2));
216
+ if (failing.length > 0) {
217
+ process.exitCode = 2;
218
+ }
219
+ }
@@ -71,7 +71,11 @@ async function runDeterministicForNextStep(params) {
71
71
  if (taskFiles.size > 0) {
72
72
  const integrity = await checkFileIntegrity(params.root, bundle.repo_manifest, [...taskFiles]);
73
73
  if (!integrity.is_clean) {
74
- console.log(`File integrity check: ${integrity.changed_files.length} changed, ${integrity.missing_files.length} missing re-running intake.`);
74
+ // Route this diagnostic OFF stdout: cmdNextStep emits the step
75
+ // contract as the sole stdout payload via console.log(JSON.stringify),
76
+ // so a console.log here would corrupt the JSON-on-stdout contract.
77
+ process.stderr.write(`[audit-code] nextStep: integrity check — ${integrity.changed_files.length} changed, ` +
78
+ `${integrity.missing_files.length} missing, ${integrity.io_errors.length} io-error(s); re-running intake.\n`);
75
79
  await advanceAudit(bundle, { root: params.root, preferredExecutor: "intake_executor", opentoken: params.opentoken });
76
80
  continue;
77
81
  }
@@ -1 +1,10 @@
1
+ import type { AuditTask } from "../types.js";
2
+ import { type RunPaths } from "../io/runArtifacts.js";
3
+ export interface WorkerSlot {
4
+ runId: string;
5
+ paths: RunPaths;
6
+ auditResultsPath: string;
7
+ pendingTasksPath: string;
8
+ group: AuditTask[];
9
+ }
1
10
  export declare function cmdRunToCompletion(argv: string[]): Promise<void>;