auditor-lambda 0.6.8 → 0.6.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 (34) hide show
  1. package/dist/cli/auditStep.d.ts +63 -0
  2. package/dist/cli/auditStep.js +133 -0
  3. package/dist/cli/envelope.d.ts +47 -0
  4. package/dist/cli/envelope.js +64 -0
  5. package/dist/cli/lineIndex.d.ts +4 -0
  6. package/dist/cli/lineIndex.js +44 -0
  7. package/dist/cli/reviewRun.d.ts +29 -0
  8. package/dist/cli/reviewRun.js +143 -0
  9. package/dist/cli.js +7 -358
  10. package/dist/extractors/fileInventory.js +1 -1452
  11. package/dist/extractors/graph.js +5 -825
  12. package/dist/extractors/graphPathUtils.d.ts +12 -0
  13. package/dist/extractors/graphPathUtils.js +58 -0
  14. package/dist/extractors/graphRoutes.d.ts +12 -0
  15. package/dist/extractors/graphRoutes.js +435 -0
  16. package/dist/extractors/graphSuites.d.ts +4 -0
  17. package/dist/extractors/graphSuites.js +246 -0
  18. package/dist/extractors/graphTestSources.d.ts +2 -0
  19. package/dist/extractors/graphTestSources.js +102 -0
  20. package/dist/extractors/languageMap.generated.d.ts +1 -0
  21. package/dist/extractors/languageMap.generated.js +1455 -0
  22. package/dist/providers/claudeCodeProvider.d.ts +1 -1
  23. package/dist/providers/claudeCodeProvider.js +3 -2
  24. package/dist/providers/localSubprocessProvider.d.ts +1 -1
  25. package/dist/providers/localSubprocessProvider.js +3 -3
  26. package/dist/providers/opencodeProvider.js +6 -22
  27. package/dist/providers/subprocessTemplateProvider.js +22 -9
  28. package/dist/quota/index.d.ts +2 -2
  29. package/dist/quota/index.js +5 -2
  30. package/package.json +5 -4
  31. package/dist/providers/spawnLoggedCommand.d.ts +0 -12
  32. package/dist/providers/spawnLoggedCommand.js +0 -186
  33. package/dist/quota/scheduler.d.ts +0 -20
  34. package/dist/quota/scheduler.js +0 -151
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
- import { mkdir, readFile, readdir, rename, rm, unlink, writeFile } from "node:fs/promises";
1
+ import { mkdir, readFile, readdir, rm, unlink, writeFile } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
- import { basename, dirname, join, resolve } from "node:path";
3
+ import { dirname, join, resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { buildRepoManifest } from "./extractors/fileInventory.js";
6
6
  import { buildFileDisposition } from "./extractors/disposition.js";
@@ -11,7 +11,7 @@ import { buildFlowCoverage } from "./orchestrator/flowCoverage.js";
11
11
  import { buildRuntimeValidationTasks, } from "./orchestrator/runtimeValidation.js";
12
12
  import { initializeCoverageFromPlan } from "./orchestrator/planning.js";
13
13
  import { loadArtifactBundle, writeCoreArtifacts, promoteFinalAuditReport, AUDIT_REPORT_FILENAME, } from "./io/artifacts.js";
14
- import { isFileMissingError, readJsonFile, writeJsonFile, prefixValidationIssues, RunLogger } from "@audit-tools/shared";
14
+ import { isFileMissingError, readJsonFile, writeJsonFile, prefixValidationIssues } from "@audit-tools/shared";
15
15
  import { buildQuotaSource } from "@audit-tools/shared/quota/compositeQuotaSource";
16
16
  import { validateArtifactBundle } from "./validation/artifacts.js";
17
17
  import { validateAuditResults, formatAuditResultIssues, } from "./validation/auditResults.js";
@@ -45,247 +45,17 @@ import { writeCurrentStep, } from "./cli/steps.js";
45
45
  import { WORKER_RESULT_CONTRACT_VERSION, buildWorkerResult, persistWorkerRunArtifacts, isWorkerResult, buildWorkerFailureBlocker, formatAuditResultValidationError, } from "./cli/workerResult.js";
46
46
  import { DISPATCH_RESULT_MAP_FILENAME, ACTIVE_DISPATCH_FILENAME, resolveRunScopedArg, loadDispatchResultMap, entriesByTaskId, buildPendingAuditTasks, prepareDispatchArtifacts, } from "./cli/dispatch.js";
47
47
  import { readWaveManifest, writeWaveManifest, removeWaveManifest, buildWaveSlotEntry, } from "./cli/waveManifest.js";
48
+ import { buildLineIndex, buildLineIndexForPaths, addFileLineCountHints, } from "./cli/lineIndex.js";
49
+ import { emitEnvelope, buildBlockedAuditState, buildManualReviewBlocker, shouldRunInlineExecutor, } from "./cli/envelope.js";
50
+ import { writeHandoffOnly, ensureSemanticReviewRun, } from "./cli/reviewRun.js";
51
+ import { runAuditStep, ingestBatchAuditResults, } from "./cli/auditStep.js";
48
52
  const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
49
- const ADVANCE_AUDIT_CONTRACT_VERSION = "audit-code/v1alpha1";
50
53
  const SAMPLE_REPO_FILES = [
51
54
  { path: "src/api/auth.ts", size_bytes: 1240, hash: "abc123" },
52
55
  { path: "src/lib/session.ts", size_bytes: 980, hash: "def456" },
53
56
  { path: "infra/deploy.yml", size_bytes: 420, hash: "ghi789" },
54
57
  { path: "docs/notes.md", size_bytes: 300, hash: "doc111" },
55
58
  ];
56
- function buildEnvelope(params) {
57
- return {
58
- contract_version: ADVANCE_AUDIT_CONTRACT_VERSION,
59
- audit_state: params.audit_state,
60
- selected_obligation: params.selected_obligation,
61
- selected_executor: params.selected_executor,
62
- progress_made: params.progress_made,
63
- artifacts_written: params.artifacts_written,
64
- progress_summary: params.progress_summary,
65
- next_likely_step: params.next_likely_step,
66
- handoff: params.handoff,
67
- };
68
- }
69
- async function emitEnvelope(params) {
70
- const handoff = buildAuditCodeHandoff({
71
- root: params.root,
72
- artifactsDir: params.artifactsDir,
73
- state: params.audit_state,
74
- bundle: params.bundle,
75
- providerName: params.providerName,
76
- progressSummary: params.progress_summary,
77
- isConfigError: params.isConfigError,
78
- activeReviewRun: params.activeReviewRun,
79
- });
80
- await writeAuditCodeHandoffArtifacts(handoff);
81
- console.log(JSON.stringify(buildEnvelope({
82
- audit_state: params.audit_state,
83
- selected_obligation: params.selected_obligation,
84
- selected_executor: params.selected_executor,
85
- progress_made: params.progress_made,
86
- artifacts_written: params.artifacts_written,
87
- progress_summary: params.progress_summary,
88
- next_likely_step: params.next_likely_step,
89
- handoff,
90
- }), null, 2));
91
- }
92
- function buildManualReviewBlocker(providerName) {
93
- return providerName === LOCAL_SUBPROCESS_PROVIDER_NAME
94
- ? "Ready for LLM semantic review. If the host exposes a callable subagent tool, prepare dispatch and fan out packets. " +
95
- "If not, use single-task fallback: review only the first pending task, write one AuditResult to the run audit-results path, execute worker_command, then stop."
96
- : "Audit blocked: waiting for manual audit results or interactive provider configuration.";
97
- }
98
- function shouldRunInlineExecutor(selectedExecutor) {
99
- return selectedExecutor !== null && selectedExecutor !== "agent";
100
- }
101
- function buildBlockedAuditState(params) {
102
- return {
103
- ...params.state,
104
- status: "blocked",
105
- last_executor: params.executor ?? params.state.last_executor,
106
- last_obligation: params.obligationId ?? params.state.last_obligation,
107
- blockers: [...new Set([...(params.state.blockers ?? []), params.blocker])],
108
- obligations: params.state.obligations.map((item) => item.id === params.obligationId
109
- ? {
110
- ...item,
111
- state: "blocked",
112
- reason: params.blocker,
113
- }
114
- : item),
115
- };
116
- }
117
- async function buildLineIndex(root, repoManifest) {
118
- const entries = [];
119
- const batchSize = 25;
120
- for (let i = 0; i < repoManifest.files.length; i += batchSize) {
121
- const batch = repoManifest.files.slice(i, i + batchSize);
122
- const results = await Promise.all(batch.map(async (file) => {
123
- try {
124
- return [
125
- file.path,
126
- await countLines(resolve(root, file.path)),
127
- ];
128
- }
129
- catch {
130
- return [file.path, 0];
131
- }
132
- }));
133
- entries.push(...results);
134
- }
135
- return Object.fromEntries(entries);
136
- }
137
- async function buildLineIndexForPaths(root, paths) {
138
- const uniquePaths = [...new Set(paths)].sort();
139
- const entries = await Promise.all(uniquePaths.map(async (path) => {
140
- try {
141
- return [path, await countLines(resolve(root, path))];
142
- }
143
- catch {
144
- return [path, 0];
145
- }
146
- }));
147
- return Object.fromEntries(entries);
148
- }
149
- async function addFileLineCountHints(root, tasks) {
150
- const lineIndex = await buildLineIndexForPaths(root, tasks.flatMap((task) => task.file_paths));
151
- return tasks.map((task) => ({
152
- ...task,
153
- file_line_counts: Object.fromEntries(task.file_paths.map((path) => [path, lineIndex[path] ?? 0])),
154
- }));
155
- }
156
- function activeReviewRunFromTask(artifactsDir, task) {
157
- if (task.preferred_executor !== "agent" || !task.audit_results_path) {
158
- return null;
159
- }
160
- const paths = getRunPaths(artifactsDir, task.run_id);
161
- return {
162
- run_id: task.run_id,
163
- task_path: paths.taskPath,
164
- prompt_path: paths.promptPath,
165
- pending_audit_tasks_path: task.pending_audit_tasks_path,
166
- audit_results_path: task.audit_results_path,
167
- worker_command: task.worker_command,
168
- };
169
- }
170
- async function loadCurrentActiveReviewRun(artifactsDir) {
171
- try {
172
- const task = await readJsonFile(join(artifactsDir, "dispatch", "current-task.json"));
173
- return activeReviewRunFromTask(artifactsDir, task);
174
- }
175
- catch (error) {
176
- if (isFileMissingError(error)) {
177
- return null;
178
- }
179
- throw error;
180
- }
181
- }
182
- async function writeHandoffOnly(params) {
183
- const handoff = buildAuditCodeHandoff({
184
- root: params.root,
185
- artifactsDir: params.artifactsDir,
186
- state: params.audit_state,
187
- bundle: params.bundle,
188
- providerName: params.providerName,
189
- progressSummary: params.progress_summary,
190
- isConfigError: params.isConfigError,
191
- activeReviewRun: params.activeReviewRun,
192
- });
193
- await writeAuditCodeHandoffArtifacts(handoff);
194
- }
195
- async function ensureSemanticReviewRun(params) {
196
- const existingRun = await loadCurrentActiveReviewRun(params.artifactsDir);
197
- if (existingRun) {
198
- const blockedState = params.bundle.audit_state?.status === "blocked"
199
- ? params.bundle.audit_state
200
- : buildBlockedAuditState({
201
- state: params.state,
202
- obligationId: params.obligationId,
203
- executor: "agent",
204
- blocker: buildManualReviewBlocker(LOCAL_SUBPROCESS_PROVIDER_NAME),
205
- });
206
- const blockedBundle = { ...params.bundle, audit_state: blockedState };
207
- await writeCoreArtifacts(params.artifactsDir, blockedBundle);
208
- await writeHandoffOnly({
209
- root: params.root,
210
- artifactsDir: params.artifactsDir,
211
- bundle: blockedBundle,
212
- audit_state: blockedState,
213
- progress_summary: buildManualReviewBlocker(LOCAL_SUBPROCESS_PROVIDER_NAME),
214
- providerName: LOCAL_SUBPROCESS_PROVIDER_NAME,
215
- activeReviewRun: existingRun,
216
- });
217
- return {
218
- state: blockedState,
219
- bundle: blockedBundle,
220
- activeReviewRun: existingRun,
221
- };
222
- }
223
- const blockedState = buildBlockedAuditState({
224
- state: params.state,
225
- obligationId: params.obligationId,
226
- executor: "agent",
227
- blocker: buildManualReviewBlocker(LOCAL_SUBPROCESS_PROVIDER_NAME),
228
- });
229
- await writeCoreArtifacts(params.artifactsDir, {
230
- ...params.bundle,
231
- audit_state: blockedState,
232
- });
233
- const runId = buildRunId(params.obligationId, 1);
234
- const paths = getRunPaths(params.artifactsDir, runId);
235
- const pendingTasks = await addFileLineCountHints(params.root, buildPendingAuditTasks(params.bundle));
236
- const pendingTasksPath = join(paths.runDir, "pending-audit-tasks.json");
237
- const auditResultsPath = join(paths.runDir, "audit-results.json");
238
- const taskReadPaths = new Set();
239
- for (const pt of pendingTasks) {
240
- for (const fp of pt.file_paths)
241
- taskReadPaths.add(fp);
242
- }
243
- const task = {
244
- contract_version: "audit-code-worker/v1alpha1",
245
- run_id: runId,
246
- repo_root: params.root,
247
- artifacts_dir: params.artifactsDir,
248
- obligation_id: params.obligationId,
249
- preferred_executor: "agent",
250
- result_path: paths.resultPath,
251
- worker_command: [
252
- process.execPath,
253
- params.selfCliPath,
254
- "worker-run",
255
- "--task",
256
- paths.taskPath,
257
- ],
258
- audit_results_path: auditResultsPath,
259
- pending_audit_tasks_path: pendingTasksPath,
260
- timeout_ms: params.timeoutMs,
261
- max_retries: 0,
262
- access: {
263
- read_paths: [...taskReadPaths],
264
- write_paths: [auditResultsPath, paths.resultPath],
265
- },
266
- };
267
- const prompt = renderWorkerPrompt(task);
268
- await writeWorkerTaskFiles(task, prompt, paths, params.artifactsDir, pendingTasks);
269
- await writeJsonFile(pendingTasksPath, pendingTasks);
270
- const activeReviewRun = activeReviewRunFromTask(params.artifactsDir, task);
271
- if (!activeReviewRun) {
272
- throw new Error("Internal error: failed to materialize active review run.");
273
- }
274
- const blockedBundle = {
275
- ...params.bundle,
276
- audit_state: blockedState,
277
- };
278
- await writeHandoffOnly({
279
- root: params.root,
280
- artifactsDir: params.artifactsDir,
281
- bundle: blockedBundle,
282
- audit_state: blockedState,
283
- progress_summary: buildManualReviewBlocker(LOCAL_SUBPROCESS_PROVIDER_NAME),
284
- providerName: LOCAL_SUBPROCESS_PROVIDER_NAME,
285
- activeReviewRun,
286
- });
287
- return { state: blockedState, bundle: blockedBundle, activeReviewRun };
288
- }
289
59
  export const cliTestUtils = {
290
60
  defaults: DIRECT_CLI_DEFAULTS,
291
61
  getFlag,
@@ -303,127 +73,6 @@ export const cliTestUtils = {
303
73
  countLines,
304
74
  warnIfNotGitRepo,
305
75
  };
306
- async function maybeArchiveLegacyPendingResults(auditResultsPath) {
307
- if (!auditResultsPath || basename(auditResultsPath) !== "worker_results_pending.json") {
308
- return undefined;
309
- }
310
- const archivedPath = join(dirname(auditResultsPath), `worker_results_submitted_${new Date().toISOString().replace(/[:.]/g, "-")}.json`);
311
- try {
312
- await rename(auditResultsPath, archivedPath);
313
- return archivedPath;
314
- }
315
- catch (error) {
316
- process.stderr.write(`[audit-results cleanup] failed to archive ${auditResultsPath}: ${error instanceof Error ? error.message : String(error)}\n`);
317
- return undefined;
318
- }
319
- }
320
- async function runAuditStep(options) {
321
- const bundle = await loadArtifactBundle(options.artifactsDir);
322
- const runLogger = new RunLogger(join(options.artifactsDir, "run.log.jsonl"), {
323
- enabled: options.runLog ?? true,
324
- });
325
- const lineIndex = bundle.repo_manifest
326
- ? await buildLineIndex(options.root, bundle.repo_manifest)
327
- : undefined;
328
- const sizeIndex = bundle.repo_manifest
329
- ? sizeIndexFromManifest(bundle.repo_manifest)
330
- : undefined;
331
- if (looksLikeCliFlag(options.auditResultsPath)) {
332
- throw new Error(`Invalid audit results path '${options.auditResultsPath}'. This looks like a CLI flag rather than a file path.`);
333
- }
334
- const auditResults = options.auditResultsPath
335
- ? await readJsonFile(options.auditResultsPath)
336
- : undefined;
337
- if (auditResults !== undefined) {
338
- const issues = validateAuditResults(auditResults, bundle.audit_tasks ?? [], {
339
- lineIndex,
340
- });
341
- const errors = issues.filter((issue) => issue.severity === "error");
342
- const warnings = issues.filter((issue) => issue.severity === "warning");
343
- if (warnings.length > 0) {
344
- process.stderr.write(`audit-results validation: ${warnings.length} warning(s):\n` +
345
- formatAuditResultIssues(warnings) +
346
- "\n");
347
- }
348
- if (errors.length > 0) {
349
- throw new Error(formatAuditResultValidationError(errors));
350
- }
351
- }
352
- const runtimeValidationUpdates = options.runtimeUpdatesPath
353
- ? await readJsonFile(options.runtimeUpdatesPath)
354
- : undefined;
355
- const externalAnalyzerResults = options.externalAnalyzerPath
356
- ? await readJsonFile(options.externalAnalyzerPath)
357
- : undefined;
358
- const narrativeResults = options.narrativeResultsPath
359
- ? await readJsonFile(options.narrativeResultsPath)
360
- : undefined;
361
- const edgeReasoningResults = options.edgeReasoningResultsPath
362
- ? await readJsonFile(options.edgeReasoningResultsPath)
363
- : undefined;
364
- const result = await advanceAudit(bundle, {
365
- root: options.root,
366
- lineIndex,
367
- sizeIndex,
368
- auditResults: auditResults,
369
- runtimeValidationUpdates,
370
- externalAnalyzerResults,
371
- narrativeResults,
372
- edgeReasoningResults,
373
- analyzers: options.analyzers,
374
- graphLlmEdgeReasoning: options.graphLlmEdgeReasoning,
375
- since: options.since,
376
- preferredExecutor: options.preferredExecutor,
377
- opentoken: options.opentoken,
378
- runLogger,
379
- });
380
- await writeCoreArtifacts(options.artifactsDir, result.updated_bundle);
381
- const archivedPendingResults = await maybeArchiveLegacyPendingResults(options.auditResultsPath);
382
- if (archivedPendingResults) {
383
- result.progress_summary +=
384
- ` Archived legacy staging file to ${archivedPendingResults}.`;
385
- }
386
- return result;
387
- }
388
- async function ingestBatchAuditResults(options) {
389
- const batchFiles = await listBatchResultFiles(options.batchDir);
390
- const artifactsWritten = new Set();
391
- const progressSummaries = [];
392
- let lastStep = null;
393
- let anyProgress = false;
394
- for (const batchFile of batchFiles) {
395
- const step = await runAuditStep({
396
- root: options.root,
397
- artifactsDir: options.artifactsDir,
398
- preferredExecutor: "result_ingestion_executor",
399
- auditResultsPath: batchFile,
400
- });
401
- lastStep = step;
402
- anyProgress ||= step.progress_made;
403
- for (const artifact of step.artifacts_written) {
404
- artifactsWritten.add(artifact);
405
- }
406
- progressSummaries.push(`${basename(batchFile)}: ${step.progress_summary}`);
407
- }
408
- const bundle = lastStep?.updated_bundle ??
409
- (await loadArtifactBundle(options.artifactsDir));
410
- const state = deriveAuditState(bundle);
411
- const decision = decideNextStep(bundle);
412
- return {
413
- batchFiles,
414
- bundle,
415
- audit_state: state,
416
- selected_obligation: lastStep?.selected_obligation ?? decision.selected_obligation,
417
- selected_executor: lastStep?.selected_executor ?? "result_ingestion_executor",
418
- progress_made: anyProgress,
419
- artifacts_written: Array.from(artifactsWritten),
420
- progress_summary: `Imported ${batchFiles.length} batch result file${batchFiles.length === 1 ? "" : "s"} from ${options.batchDir}.` +
421
- (progressSummaries.length > 0
422
- ? `\n${progressSummaries.join("\n")}`
423
- : ""),
424
- next_likely_step: state.status === "complete" ? null : decision.selected_obligation,
425
- };
426
- }
427
76
  async function persistConfigErrorHandoff(params) {
428
77
  const bundle = await loadArtifactBundle(params.artifactsDir);
429
78
  const blockedState = buildBlockedAuditState({