auditor-lambda 0.2.6 → 0.2.9

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 +29 -7
  2. package/audit-code-wrapper-lib.mjs +1605 -330
  3. package/dist/adapters/eslint.js +9 -5
  4. package/dist/cli.d.ts +42 -1
  5. package/dist/cli.js +192 -80
  6. package/dist/coverage.d.ts +2 -2
  7. package/dist/coverage.js +5 -5
  8. package/dist/extractors/bucketing.d.ts +4 -0
  9. package/dist/extractors/bucketing.js +6 -2
  10. package/dist/extractors/disposition.d.ts +4 -0
  11. package/dist/extractors/disposition.js +15 -2
  12. package/dist/extractors/fileInventory.js +24 -28
  13. package/dist/extractors/flows.d.ts +5 -0
  14. package/dist/extractors/flows.js +25 -39
  15. package/dist/extractors/pathPatterns.d.ts +13 -3
  16. package/dist/extractors/pathPatterns.js +116 -53
  17. package/dist/extractors/risk.js +7 -1
  18. package/dist/extractors/surfaces.d.ts +4 -0
  19. package/dist/extractors/surfaces.js +11 -11
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +2 -1
  22. package/dist/io/artifacts.d.ts +59 -44
  23. package/dist/io/artifacts.js +80 -120
  24. package/dist/io/json.d.ts +2 -0
  25. package/dist/io/json.js +65 -19
  26. package/dist/io/runArtifacts.d.ts +2 -1
  27. package/dist/io/runArtifacts.js +44 -7
  28. package/dist/mcp/server.d.ts +1 -0
  29. package/dist/mcp/server.js +579 -0
  30. package/dist/orchestrator/advance.js +84 -56
  31. package/dist/orchestrator/dependencyMap.js +9 -13
  32. package/dist/orchestrator/executors.js +7 -2
  33. package/dist/orchestrator/flowCoverage.js +11 -5
  34. package/dist/orchestrator/flowPlanning.d.ts +7 -2
  35. package/dist/orchestrator/flowPlanning.js +46 -21
  36. package/dist/orchestrator/flowRequeue.js +29 -9
  37. package/dist/orchestrator/internalExecutors.d.ts +2 -1
  38. package/dist/orchestrator/internalExecutors.js +130 -69
  39. package/dist/orchestrator/planning.js +25 -3
  40. package/dist/orchestrator/requeue.js +20 -5
  41. package/dist/orchestrator/resultIngestion.js +5 -6
  42. package/dist/orchestrator/runtimeValidation.d.ts +7 -2
  43. package/dist/orchestrator/runtimeValidation.js +61 -49
  44. package/dist/orchestrator/runtimeValidationUpdate.js +2 -4
  45. package/dist/orchestrator/state.js +18 -13
  46. package/dist/orchestrator/taskBuilder.d.ts +4 -2
  47. package/dist/orchestrator/taskBuilder.js +153 -52
  48. package/dist/orchestrator/trivialAudit.js +8 -5
  49. package/dist/orchestrator/unitBuilder.d.ts +3 -1
  50. package/dist/orchestrator/unitBuilder.js +24 -16
  51. package/dist/prompts/renderWorkerPrompt.d.ts +1 -1
  52. package/dist/prompts/renderWorkerPrompt.js +19 -10
  53. package/dist/providers/claudeCodeProvider.d.ts +4 -1
  54. package/dist/providers/claudeCodeProvider.js +8 -5
  55. package/dist/providers/localSubprocessProvider.d.ts +4 -0
  56. package/dist/providers/localSubprocessProvider.js +7 -2
  57. package/dist/providers/spawnLoggedCommand.d.ts +9 -1
  58. package/dist/providers/spawnLoggedCommand.js +77 -29
  59. package/dist/reporting/mergeFindings.js +0 -11
  60. package/dist/reporting/synthesis.d.ts +26 -21
  61. package/dist/reporting/synthesis.js +97 -61
  62. package/dist/reporting/workBlocks.d.ts +12 -3
  63. package/dist/reporting/workBlocks.js +124 -70
  64. package/dist/supervisor/operatorHandoff.js +48 -18
  65. package/dist/supervisor/runLedger.d.ts +1 -1
  66. package/dist/supervisor/runLedger.js +112 -5
  67. package/dist/supervisor/sessionConfig.js +10 -10
  68. package/dist/types/externalAnalyzer.d.ts +3 -0
  69. package/dist/types/flowCoverage.d.ts +5 -1
  70. package/dist/types/flowCoverage.js +5 -1
  71. package/dist/types/flows.d.ts +6 -0
  72. package/dist/types/flows.js +1 -1
  73. package/dist/types/runLedger.d.ts +5 -1
  74. package/dist/types/runLedger.js +6 -1
  75. package/dist/types/runtimeValidation.d.ts +13 -3
  76. package/dist/types/runtimeValidation.js +16 -1
  77. package/dist/types/sessionConfig.d.ts +15 -2
  78. package/dist/types/sessionConfig.js +15 -1
  79. package/dist/types/surfaces.d.ts +4 -1
  80. package/dist/types/surfaces.js +1 -1
  81. package/dist/types/workerSession.d.ts +9 -0
  82. package/dist/types/workerSession.js +5 -1
  83. package/dist/types.d.ts +4 -7
  84. package/dist/validation/artifacts.d.ts +1 -1
  85. package/dist/validation/artifacts.js +33 -20
  86. package/dist/validation/auditResults.d.ts +2 -2
  87. package/dist/validation/auditResults.js +71 -114
  88. package/dist/validation/basic.d.ts +9 -1
  89. package/dist/validation/basic.js +40 -3
  90. package/dist/validation/sessionConfig.d.ts +4 -2
  91. package/dist/validation/sessionConfig.js +62 -15
  92. package/docs/agent-integrations.md +67 -38
  93. package/docs/artifacts.md +16 -56
  94. package/docs/bootstrap-install.md +60 -30
  95. package/docs/contract.md +22 -205
  96. package/docs/next-steps.md +76 -44
  97. package/docs/packaging.md +27 -3
  98. package/docs/product-direction.md +22 -0
  99. package/docs/production-launch-bar.md +4 -2
  100. package/docs/production-readiness.md +9 -5
  101. package/docs/releasing.md +98 -0
  102. package/docs/remediation-baseline.md +75 -0
  103. package/docs/run-flow.md +23 -11
  104. package/docs/session-config.md +50 -5
  105. package/docs/supervisor.md +7 -0
  106. package/docs/workflow-refactor-brief.md +177 -0
  107. package/package.json +4 -1
  108. package/schemas/audit_result.schema.json +8 -7
  109. package/schemas/audit_task.schema.json +3 -1
  110. package/schemas/coverage_matrix.schema.json +3 -3
  111. package/schemas/critical_flows.schema.json +6 -2
  112. package/schemas/file_disposition.schema.json +2 -2
  113. package/schemas/finding.schema.json +9 -4
  114. package/schemas/flow_coverage.schema.json +2 -2
  115. package/schemas/repo_manifest.schema.json +4 -4
  116. package/schemas/risk_register.schema.json +2 -2
  117. package/schemas/runtime_validation_report.schema.json +3 -3
  118. package/schemas/runtime_validation_tasks.schema.json +8 -2
  119. package/schemas/surface_manifest.schema.json +6 -3
  120. package/schemas/unit_manifest.schema.json +3 -2
  121. package/skills/audit-code/SKILL.md +16 -2
  122. package/skills/audit-code/audit-code.prompt.md +5 -8
  123. package/schemas/merged_findings.schema.json +0 -19
  124. package/schemas/root_cause_clusters.schema.json +0 -28
  125. package/schemas/synthesis_report.schema.json +0 -61
@@ -1,12 +1,16 @@
1
1
  import { normalizeGenericExternalResults } from "./normalizeExternal.js";
2
2
  const ESLINT_SEVERITY_ERROR = 2;
3
3
  const ESLINT_SEVERITY_WARNING = 1;
4
+ const ESLINT_SEVERITY_MAP = {
5
+ [ESLINT_SEVERITY_ERROR]: "medium",
6
+ [ESLINT_SEVERITY_WARNING]: "low",
7
+ };
4
8
  function mapSeverity(value) {
5
- if (value === ESLINT_SEVERITY_ERROR)
6
- return "medium";
7
- if (value === ESLINT_SEVERITY_WARNING)
8
- return "low";
9
- return "info";
9
+ // ESLint's JSON formatter emits 2 for errors and 1 for warnings.
10
+ if (typeof value !== "number") {
11
+ return "info";
12
+ }
13
+ return ESLINT_SEVERITY_MAP[value] ?? "info";
10
14
  }
11
15
  export function normalizeEslintJson(input) {
12
16
  return normalizeGenericExternalResults("eslint", input.flatMap((file) => (file.messages ?? []).map((message, index) => ({
package/dist/cli.d.ts CHANGED
@@ -1 +1,42 @@
1
- export declare function runSample(): Promise<void>;
1
+ import type { SessionConfig } from "./types/sessionConfig.js";
2
+ type UiMode = "visible" | "headless";
3
+ declare function getFlag(argv: string[], name: string, fallback?: string): string | undefined;
4
+ declare function hasFlag(argv: string[], name: string): boolean;
5
+ declare function getArtifactsDir(argv: string[]): string;
6
+ declare function getRootDir(argv: string[]): string;
7
+ declare function getBatchResultsDir(argv: string[]): string | undefined;
8
+ declare function getMaxRuns(argv: string[]): number;
9
+ declare function getAgentBatchSize(argv: string[], sessionConfig: SessionConfig): number;
10
+ declare function getParallelWorkers(argv: string[], sessionConfig: SessionConfig): number;
11
+ declare function getTimeoutMs(argv: string[], sessionConfig: SessionConfig): number;
12
+ declare function chunkArray<T>(arr: T[], size: number): T[][];
13
+ declare function getUiMode(argv: string[], fallback?: UiMode): UiMode;
14
+ declare function countLines(path: string): Promise<number>;
15
+ declare function looksLikeCliFlag(value: string | undefined): boolean;
16
+ export declare const cliTestUtils: {
17
+ defaults: {
18
+ rootDir: string;
19
+ artifactsDir: string;
20
+ maxRuns: number;
21
+ agentBatchSize: number;
22
+ parallelWorkers: number;
23
+ timeoutMs: number;
24
+ uiMode: UiMode;
25
+ };
26
+ getFlag: typeof getFlag;
27
+ hasFlag: typeof hasFlag;
28
+ getArtifactsDir: typeof getArtifactsDir;
29
+ getRootDir: typeof getRootDir;
30
+ getBatchResultsDir: typeof getBatchResultsDir;
31
+ getMaxRuns: typeof getMaxRuns;
32
+ getAgentBatchSize: typeof getAgentBatchSize;
33
+ getParallelWorkers: typeof getParallelWorkers;
34
+ getTimeoutMs: typeof getTimeoutMs;
35
+ chunkArray: typeof chunkArray;
36
+ getUiMode: typeof getUiMode;
37
+ looksLikeCliFlag: typeof looksLikeCliFlag;
38
+ countLines: typeof countLines;
39
+ };
40
+ export declare function runSample(argv?: string[]): Promise<void>;
41
+ export declare function runCli(argv: string[]): Promise<void>;
42
+ export {};
package/dist/cli.js CHANGED
@@ -1,20 +1,22 @@
1
1
  import { access, mkdir, readdir, rename } from "node:fs/promises";
2
2
  import { createReadStream } from "node:fs";
3
3
  import { basename, dirname, join, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
4
5
  import { buildRepoManifest } from "./extractors/fileInventory.js";
5
6
  import { buildFileDisposition } from "./extractors/disposition.js";
6
7
  import { buildCriticalFlowManifest } from "./extractors/flows.js";
7
8
  import { buildSurfaceManifest } from "./extractors/surfaces.js";
8
9
  import { buildUnitManifest } from "./orchestrator/unitBuilder.js";
9
10
  import { buildFlowCoverage } from "./orchestrator/flowCoverage.js";
10
- import { buildRuntimeValidationTasks, buildPlaceholderRuntimeValidationReport, } from "./orchestrator/runtimeValidation.js";
11
+ import { buildRuntimeValidationTasks, } from "./orchestrator/runtimeValidation.js";
11
12
  import { initializeCoverageFromPlan } from "./orchestrator/planning.js";
12
- import { loadArtifactBundle, writeCoreArtifacts, cleanupIntermediateArtifacts, } from "./io/artifacts.js";
13
+ import { loadArtifactBundle, writeCoreArtifacts, promoteFinalAuditReport, } from "./io/artifacts.js";
13
14
  import { readJsonFile, writeJsonFile } from "./io/json.js";
14
15
  import { validateArtifactBundle } from "./validation/artifacts.js";
15
16
  import { validateAuditResults, formatAuditResultIssues, } from "./validation/auditResults.js";
17
+ import { prefixValidationIssues } from "./validation/basic.js";
16
18
  import { validateConfiguredProviderEnvironment, validateSessionConfig, } from "./validation/sessionConfig.js";
17
- import { buildSynthesisReport } from "./reporting/synthesis.js";
19
+ import { buildAuditReportModel, renderAuditReportMarkdown, } from "./reporting/synthesis.js";
18
20
  import { deriveAuditState } from "./orchestrator/state.js";
19
21
  import { advanceAudit } from "./orchestrator/advance.js";
20
22
  import { decideNextStep } from "./orchestrator/nextStep.js";
@@ -22,83 +24,107 @@ import { createFreshSessionProvider, resolveFreshSessionProviderName, } from "./
22
24
  import { appendRunLedgerEntry } from "./supervisor/runLedger.js";
23
25
  import { buildAuditCodeHandoff, writeAuditCodeHandoffArtifacts, } from "./supervisor/operatorHandoff.js";
24
26
  import { getSessionConfigPath, loadSessionConfig, readSessionConfigFile, } from "./supervisor/sessionConfig.js";
25
- import { buildRunId, ensureSupervisorDirs, getRunPaths, writeWorkerTaskFiles, } from "./io/runArtifacts.js";
27
+ import { clearDispatchFiles, buildRunId, ensureSupervisorDirs, getRunPaths, writeWorkerTaskFiles, } from "./io/runArtifacts.js";
26
28
  import { renderWorkerPrompt } from "./prompts/renderWorkerPrompt.js";
27
29
  import { LOCAL_SUBPROCESS_PROVIDER_NAME } from "./providers/constants.js";
30
+ import { runAuditCodeMcpServer } from "./mcp/server.js";
28
31
  const ADVANCE_AUDIT_CONTRACT_VERSION = "audit-code/v1alpha1";
29
32
  const WORKER_RESULT_CONTRACT_VERSION = "audit-code-worker-result/v1alpha1";
30
- const DEFAULT_MAX_RUNS = 1000;
31
- const DEFAULT_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
32
- const sampleFiles = [
33
+ const DIRECT_CLI_DEFAULTS = {
34
+ rootDir: ".",
35
+ artifactsDir: ".artifacts",
36
+ maxRuns: 1000,
37
+ agentBatchSize: 1,
38
+ parallelWorkers: 1,
39
+ timeoutMs: 30 * 60 * 1000, // 30 minutes
40
+ uiMode: "headless",
41
+ };
42
+ // Keep the sample-run payload explicit so the demo command is deterministic.
43
+ const SAMPLE_REPO_FILES = [
33
44
  { path: "src/api/auth.ts", size_bytes: 1240, hash: "abc123" },
34
45
  { path: "src/lib/session.ts", size_bytes: 980, hash: "def456" },
35
46
  { path: "infra/deploy.yml", size_bytes: 420, hash: "ghi789" },
36
47
  { path: "docs/notes.md", size_bytes: 300, hash: "doc111" },
37
48
  ];
49
+ function isLongFlagToken(value) {
50
+ return typeof value === "string" && value.startsWith("--");
51
+ }
52
+ // Read a long-form CLI flag while treating a following flag token as "missing".
38
53
  function getFlag(argv, name, fallback) {
39
54
  const index = argv.indexOf(name);
40
- if (index >= 0 && argv[index + 1])
41
- return argv[index + 1];
42
- return fallback;
55
+ if (index < 0)
56
+ return fallback;
57
+ const candidate = argv[index + 1];
58
+ if (!candidate || isLongFlagToken(candidate))
59
+ return fallback;
60
+ return candidate;
43
61
  }
62
+ // Boolean flags only care whether the token is present at all.
44
63
  function hasFlag(argv, name) {
45
64
  return argv.includes(name);
46
65
  }
66
+ function resolveFlagPath(argv, name, fallback) {
67
+ return resolve(getFlag(argv, name, fallback));
68
+ }
69
+ function normalizePositiveInteger(value) {
70
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
71
+ return undefined;
72
+ }
73
+ return Math.floor(value);
74
+ }
75
+ function parsePositiveIntegerFlag(argv, name) {
76
+ const raw = getFlag(argv, name);
77
+ if (raw === undefined) {
78
+ return undefined;
79
+ }
80
+ return normalizePositiveInteger(Number(raw));
81
+ }
47
82
  function getArtifactsDir(argv) {
48
- return resolve(getFlag(argv, "--artifacts-dir", ".artifacts"));
83
+ return resolveFlagPath(argv, "--artifacts-dir", DIRECT_CLI_DEFAULTS.artifactsDir);
49
84
  }
50
85
  function getRootDir(argv) {
51
- return resolve(getFlag(argv, "--root", "."));
86
+ return resolveFlagPath(argv, "--root", DIRECT_CLI_DEFAULTS.rootDir);
52
87
  }
53
88
  function getBatchResultsDir(argv) {
54
89
  const value = getFlag(argv, "--batch-results");
55
90
  return value ? resolve(value) : undefined;
56
91
  }
57
92
  function getMaxRuns(argv) {
58
- const raw = Number(getFlag(argv, "--max-runs", String(DEFAULT_MAX_RUNS)));
59
- return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : DEFAULT_MAX_RUNS;
93
+ return parsePositiveIntegerFlag(argv, "--max-runs") ?? DIRECT_CLI_DEFAULTS.maxRuns;
60
94
  }
61
95
  function getAgentBatchSize(argv, sessionConfig) {
62
- const fromArg = getFlag(argv, "--agent-batch-size");
63
- if (fromArg !== undefined) {
64
- const parsed = Number(fromArg);
65
- if (Number.isFinite(parsed) && parsed > 0)
66
- return Math.floor(parsed);
67
- }
68
- if (typeof sessionConfig.agent_task_batch_size === "number" && sessionConfig.agent_task_batch_size > 0) {
69
- return Math.floor(sessionConfig.agent_task_batch_size);
70
- }
71
- return 1;
96
+ return (parsePositiveIntegerFlag(argv, "--agent-batch-size") ??
97
+ normalizePositiveInteger(sessionConfig.agent_task_batch_size) ??
98
+ DIRECT_CLI_DEFAULTS.agentBatchSize);
72
99
  }
73
100
  function getParallelWorkers(argv, sessionConfig) {
74
- const fromArg = getFlag(argv, "--parallel");
75
- if (fromArg !== undefined) {
76
- const parsed = Number(fromArg);
77
- if (Number.isFinite(parsed) && parsed > 0)
78
- return Math.floor(parsed);
79
- }
80
- if (typeof sessionConfig.parallel_workers === "number" && sessionConfig.parallel_workers > 0) {
81
- return Math.floor(sessionConfig.parallel_workers);
82
- }
83
- return 1;
101
+ return (parsePositiveIntegerFlag(argv, "--parallel") ??
102
+ normalizePositiveInteger(sessionConfig.parallel_workers) ??
103
+ DIRECT_CLI_DEFAULTS.parallelWorkers);
84
104
  }
85
105
  function getTimeoutMs(argv, sessionConfig) {
86
- const fromArg = getFlag(argv, "--timeout");
87
- if (fromArg !== undefined) {
88
- const parsed = Number(fromArg);
89
- if (Number.isFinite(parsed) && parsed > 0)
90
- return Math.floor(parsed);
91
- }
92
- return sessionConfig.timeout_ms ?? DEFAULT_TIMEOUT_MS;
106
+ return (parsePositiveIntegerFlag(argv, "--timeout") ??
107
+ normalizePositiveInteger(sessionConfig.timeout_ms) ??
108
+ DIRECT_CLI_DEFAULTS.timeoutMs);
109
+ }
110
+ function getExplicitProvider(argv) {
111
+ return getFlag(argv, "--provider");
112
+ }
113
+ function resolveRunProviderName(argv, sessionConfig) {
114
+ return resolveFreshSessionProviderName(getExplicitProvider(argv) ?? LOCAL_SUBPROCESS_PROVIDER_NAME, sessionConfig);
93
115
  }
94
116
  function chunkArray(arr, size) {
117
+ const chunkSize = normalizePositiveInteger(size);
118
+ if (chunkSize === undefined) {
119
+ throw new Error("chunkArray size must be a positive integer.");
120
+ }
95
121
  const chunks = [];
96
- for (let i = 0; i < arr.length; i += size) {
97
- chunks.push(arr.slice(i, i + size));
122
+ for (let i = 0; i < arr.length; i += chunkSize) {
123
+ chunks.push(arr.slice(i, i + chunkSize));
98
124
  }
99
125
  return chunks;
100
126
  }
101
- function getUiMode(argv, fallback = "headless") {
127
+ function getUiMode(argv, fallback = DIRECT_CLI_DEFAULTS.uiMode) {
102
128
  const raw = getFlag(argv, "--ui");
103
129
  if (raw === "visible")
104
130
  return "visible";
@@ -143,19 +169,9 @@ async function emitEnvelope(params) {
143
169
  }
144
170
  function buildManualReviewBlocker(providerName) {
145
171
  return providerName === LOCAL_SUBPROCESS_PROVIDER_NAME
146
- ? "Automatic local-subprocess work is exhausted. Remaining audit tasks require explicit audit results or an interactive provider such as claude-code, opencode, or subprocess-template."
172
+ ? "Automatic backend steps are exhausted. Remaining semantic review now belongs to the active conversation agent. Review the dispatched files, write structured audit results, and run the generated worker command to ingest them. If you intentionally want a backend bridge instead, re-run audit-code with --provider auto, --provider claude-code, --provider opencode, --provider subprocess-template, or --provider vscode-task."
147
173
  : "Automatic work is exhausted. Remaining audit tasks require explicit audit results or an interactive provider.";
148
174
  }
149
- function prefixValidationIssues(prefix, issues) {
150
- return issues.map((issue) => ({
151
- path: issue.path.length === 0
152
- ? prefix
153
- : issue.path === prefix || issue.path.startsWith(`${prefix}.`)
154
- ? issue.path
155
- : `${prefix}.${issue.path}`,
156
- message: issue.message,
157
- }));
158
- }
159
175
  function buildBlockedAuditState(params) {
160
176
  return {
161
177
  ...params.state,
@@ -278,8 +294,24 @@ function buildWorkerFailureBlocker(workerResult) {
278
294
  : workerResult.summary;
279
295
  }
280
296
  function looksLikeCliFlag(value) {
281
- return typeof value === "string" && value.startsWith("--");
297
+ return isLongFlagToken(value);
282
298
  }
299
+ export const cliTestUtils = {
300
+ defaults: DIRECT_CLI_DEFAULTS,
301
+ getFlag,
302
+ hasFlag,
303
+ getArtifactsDir,
304
+ getRootDir,
305
+ getBatchResultsDir,
306
+ getMaxRuns,
307
+ getAgentBatchSize,
308
+ getParallelWorkers,
309
+ getTimeoutMs,
310
+ chunkArray,
311
+ getUiMode,
312
+ looksLikeCliFlag,
313
+ countLines,
314
+ };
283
315
  async function maybeArchiveLegacyPendingResults(auditResultsPath) {
284
316
  if (!auditResultsPath || basename(auditResultsPath) !== "worker_results_pending.json") {
285
317
  return undefined;
@@ -387,8 +419,8 @@ function isWorkerResult(value) {
387
419
  value.contract_version ===
388
420
  WORKER_RESULT_CONTRACT_VERSION);
389
421
  }
390
- export async function runSample() {
391
- const repoManifest = buildRepoManifest("sample-repo", sampleFiles);
422
+ export async function runSample(argv = process.argv) {
423
+ const repoManifest = buildRepoManifest("sample-repo", SAMPLE_REPO_FILES);
392
424
  const disposition = buildFileDisposition(repoManifest);
393
425
  const unitManifest = buildUnitManifest(repoManifest, disposition);
394
426
  const surfaceManifest = buildSurfaceManifest(repoManifest, disposition);
@@ -401,18 +433,35 @@ export async function runSample() {
401
433
  pass_id: "pass:security",
402
434
  lens: "security",
403
435
  agent_role: "security-auditor",
404
- reviewed_ranges: [
405
- { path: "src/api/auth.ts", start: 1, end: 100, line_count: 100 },
406
- ],
436
+ file_coverage: [{ path: "src/api/auth.ts", total_lines: 100 }],
407
437
  findings: [],
408
438
  notes: ["Sample result ingestion path."],
409
439
  requires_followup: false,
410
440
  },
411
441
  ];
412
442
  const flowCoverage = buildFlowCoverage(criticalFlows, coverage);
413
- const runtimeValidationTasks = buildRuntimeValidationTasks(unitManifest, criticalFlows, flowCoverage);
414
- const runtimeValidationReport = buildPlaceholderRuntimeValidationReport(runtimeValidationTasks);
415
- const synthesisReport = buildSynthesisReport(sampleResults, runtimeValidationReport);
443
+ const runtimeValidationTasks = buildRuntimeValidationTasks({
444
+ unitManifest,
445
+ criticalFlows,
446
+ flowCoverage,
447
+ command: ["npm", "test"],
448
+ });
449
+ const runtimeValidationReport = {
450
+ results: runtimeValidationTasks.tasks.map((task) => ({
451
+ task_id: task.id,
452
+ status: "confirmed",
453
+ summary: "Sample runtime validation completed.",
454
+ evidence: [],
455
+ notes: [],
456
+ })),
457
+ };
458
+ const auditReport = renderAuditReportMarkdown(buildAuditReportModel({
459
+ results: sampleResults,
460
+ unitManifest,
461
+ criticalFlows,
462
+ coverageMatrix: coverage,
463
+ runtimeValidationReport,
464
+ }));
416
465
  const auditState = deriveAuditState({
417
466
  repo_manifest: repoManifest,
418
467
  file_disposition: disposition,
@@ -424,9 +473,9 @@ export async function runSample() {
424
473
  runtime_validation_tasks: runtimeValidationTasks,
425
474
  runtime_validation_report: runtimeValidationReport,
426
475
  audit_results: sampleResults,
427
- synthesis_report: synthesisReport,
476
+ audit_report: auditReport,
428
477
  });
429
- const artifactsDir = getArtifactsDir(process.argv);
478
+ const artifactsDir = getArtifactsDir(argv);
430
479
  await mkdir(artifactsDir, { recursive: true });
431
480
  await writeCoreArtifacts(artifactsDir, {
432
481
  repo_manifest: repoManifest,
@@ -439,7 +488,7 @@ export async function runSample() {
439
488
  runtime_validation_tasks: runtimeValidationTasks,
440
489
  runtime_validation_report: runtimeValidationReport,
441
490
  audit_results: sampleResults,
442
- synthesis_report: synthesisReport,
491
+ audit_report: auditReport,
443
492
  audit_state: auditState,
444
493
  });
445
494
  console.log(JSON.stringify({ audit_state: auditState, artifacts_dir: artifactsDir }, null, 2));
@@ -448,7 +497,7 @@ async function cmdAdvanceAudit(argv) {
448
497
  const root = getRootDir(argv);
449
498
  const artifactsDir = getArtifactsDir(argv);
450
499
  const sessionConfig = await loadSessionConfig(artifactsDir);
451
- const providerName = resolveFreshSessionProviderName(getFlag(argv, "--provider"), sessionConfig);
500
+ const providerName = resolveRunProviderName(argv, sessionConfig);
452
501
  const batchResultsDir = getBatchResultsDir(argv);
453
502
  if (batchResultsDir && getFlag(argv, "--results")) {
454
503
  throw new Error("Use either --results <file> or --batch-results <dir>, not both.");
@@ -459,6 +508,9 @@ async function cmdAdvanceAudit(argv) {
459
508
  artifactsDir,
460
509
  batchDir: batchResultsDir,
461
510
  });
511
+ if (result.selected_executor !== "agent") {
512
+ await clearDispatchFiles(artifactsDir);
513
+ }
462
514
  await emitEnvelope({
463
515
  root,
464
516
  artifactsDir,
@@ -473,7 +525,7 @@ async function cmdAdvanceAudit(argv) {
473
525
  providerName,
474
526
  });
475
527
  if (result.audit_state.status === "complete") {
476
- await cleanupIntermediateArtifacts(artifactsDir);
528
+ await promoteFinalAuditReport({ artifactsDir, repoRoot: root });
477
529
  }
478
530
  return;
479
531
  }
@@ -487,6 +539,9 @@ async function cmdAdvanceAudit(argv) {
487
539
  runtimeUpdatesPath: getFlag(argv, "--updates"),
488
540
  externalAnalyzerPath,
489
541
  });
542
+ if (result.selected_executor !== "agent") {
543
+ await clearDispatchFiles(artifactsDir);
544
+ }
490
545
  await emitEnvelope({
491
546
  root,
492
547
  artifactsDir,
@@ -501,20 +556,21 @@ async function cmdAdvanceAudit(argv) {
501
556
  providerName,
502
557
  });
503
558
  if (result.audit_state.status === "complete") {
504
- await cleanupIntermediateArtifacts(artifactsDir);
559
+ await promoteFinalAuditReport({ artifactsDir, repoRoot: root });
505
560
  }
506
561
  }
507
562
  async function cmdRunToCompletion(argv) {
508
563
  const root = getRootDir(argv);
509
564
  const artifactsDir = getArtifactsDir(argv);
510
565
  const sessionConfig = await loadSessionConfig(artifactsDir);
511
- const provider = createFreshSessionProvider(getFlag(argv, "--provider"), sessionConfig);
566
+ const explicitProvider = getExplicitProvider(argv);
567
+ const provider = createFreshSessionProvider(explicitProvider ?? LOCAL_SUBPROCESS_PROVIDER_NAME, sessionConfig);
512
568
  const uiMode = getUiMode(argv, sessionConfig.ui_mode ?? "headless");
513
569
  const maxRuns = getMaxRuns(argv);
514
570
  const agentBatchSize = getAgentBatchSize(argv, sessionConfig);
515
571
  const parallelWorkers = getParallelWorkers(argv, sessionConfig);
516
572
  const timeoutMs = getTimeoutMs(argv, sessionConfig);
517
- const selfCliPath = resolve(process.argv[1] ?? "");
573
+ const selfCliPath = resolve(argv[1] ?? process.argv[1] ?? "");
518
574
  await mkdir(artifactsDir, { recursive: true });
519
575
  await ensureSupervisorDirs(artifactsDir);
520
576
  const batchResultsDir = getBatchResultsDir(argv);
@@ -622,6 +678,8 @@ async function cmdRunToCompletion(argv) {
622
678
  ],
623
679
  audit_results_path: blockAuditResultsPath,
624
680
  pending_audit_tasks_path: blockPendingTasksPath,
681
+ timeout_ms: timeoutMs,
682
+ max_retries: 0,
625
683
  };
626
684
  const blockPrompt = renderWorkerPrompt(blockTask);
627
685
  await writeWorkerTaskFiles(blockTask, blockPrompt, blockPaths, artifactsDir, blockPendingTasks);
@@ -646,6 +704,7 @@ async function cmdRunToCompletion(argv) {
646
704
  }
647
705
  if (!preferredExecutor) {
648
706
  const state = bundle.audit_state ?? decision.state;
707
+ await clearDispatchFiles(artifactsDir);
649
708
  await emitEnvelope({
650
709
  root,
651
710
  artifactsDir,
@@ -666,7 +725,7 @@ async function cmdRunToCompletion(argv) {
666
725
  providerName: provider.name,
667
726
  });
668
727
  if (state.status === "complete") {
669
- await cleanupIntermediateArtifacts(artifactsDir);
728
+ await promoteFinalAuditReport({ artifactsDir, repoRoot: root });
670
729
  }
671
730
  return;
672
731
  }
@@ -691,7 +750,9 @@ async function cmdRunToCompletion(argv) {
691
750
  worker_command: [process.execPath, selfCliPath, "worker-run", "--task", slotPaths.taskPath],
692
751
  audit_results_path: slotAuditResultsPath,
693
752
  pending_audit_tasks_path: slotPendingTasksPath,
694
- skip_worker_command: true,
753
+ worker_command_mode: "deferred",
754
+ timeout_ms: timeoutMs,
755
+ max_retries: 0,
695
756
  };
696
757
  const slotPrompt = renderWorkerPrompt(slotTask);
697
758
  await writeWorkerTaskFiles(slotTask, slotPrompt, slotPaths, artifactsDir, group);
@@ -863,6 +924,8 @@ async function cmdRunToCompletion(argv) {
863
924
  pending_audit_tasks_path: pendingAuditTasksPath,
864
925
  runtime_updates_path: runtimeUpdatesPath,
865
926
  external_analyzer_results_path: externalAnalyzerPath,
927
+ timeout_ms: timeoutMs,
928
+ max_retries: 0,
866
929
  };
867
930
  const prompt = renderWorkerPrompt(task);
868
931
  await writeWorkerTaskFiles(task, prompt, paths, artifactsDir, pendingAuditTasks);
@@ -989,6 +1052,9 @@ async function cmdRunToCompletion(argv) {
989
1052
  const bundle = await loadArtifactBundle(artifactsDir);
990
1053
  const decision = decideNextStep(bundle);
991
1054
  const state = bundle.audit_state ?? decision.state;
1055
+ if (state.status === "complete") {
1056
+ await clearDispatchFiles(artifactsDir);
1057
+ }
992
1058
  await emitEnvelope({
993
1059
  root,
994
1060
  artifactsDir,
@@ -1236,6 +1302,31 @@ async function cmdValidate(argv) {
1236
1302
  }, null, 2));
1237
1303
  process.exitCode = issues.length > 0 ? 1 : 0;
1238
1304
  }
1305
+ async function cmdValidateResults(argv) {
1306
+ const artifactsDir = getArtifactsDir(argv);
1307
+ const resultsPath = getFlag(argv, "--results");
1308
+ if (!resultsPath) {
1309
+ throw new Error("validate-results requires --results <file>");
1310
+ }
1311
+ const bundle = await loadArtifactBundle(artifactsDir);
1312
+ const lineIndex = bundle.repo_manifest
1313
+ ? await buildLineIndex(getRootDir(argv), bundle.repo_manifest)
1314
+ : undefined;
1315
+ const auditResults = await readJsonFile(resultsPath);
1316
+ const issues = validateAuditResults(auditResults, bundle.audit_tasks ?? [], {
1317
+ lineIndex,
1318
+ });
1319
+ const errors = issues.filter((issue) => issue.severity === "error");
1320
+ const warnings = issues.filter((issue) => issue.severity === "warning");
1321
+ console.log(JSON.stringify({
1322
+ artifacts_dir: artifactsDir,
1323
+ results_path: resolve(resultsPath),
1324
+ warning_count: warnings.length,
1325
+ error_count: errors.length,
1326
+ issues,
1327
+ }, null, 2));
1328
+ process.exitCode = errors.length > 0 ? 1 : 0;
1329
+ }
1239
1330
  async function cmdRequeue(argv) {
1240
1331
  const artifactsDir = getArtifactsDir(argv);
1241
1332
  const bundle = await loadArtifactBundle(artifactsDir);
@@ -1257,11 +1348,14 @@ async function cmdSynthesize(argv) {
1257
1348
  progress_summary: result.progress_summary,
1258
1349
  }, null, 2));
1259
1350
  }
1351
+ async function cmdMcp(argv) {
1352
+ await runAuditCodeMcpServer(argv.slice(3));
1353
+ }
1260
1354
  async function main(argv) {
1261
1355
  const command = argv[2] ?? "sample-run";
1262
1356
  switch (command) {
1263
1357
  case "sample-run":
1264
- await runSample();
1358
+ await runSample(argv);
1265
1359
  return;
1266
1360
  case "advance-audit":
1267
1361
  await cmdAdvanceAudit(argv);
@@ -1293,19 +1387,37 @@ async function main(argv) {
1293
1387
  case "validate":
1294
1388
  await cmdValidate(argv);
1295
1389
  return;
1390
+ case "validate-results":
1391
+ await cmdValidateResults(argv);
1392
+ return;
1296
1393
  case "requeue":
1297
1394
  await cmdRequeue(argv);
1298
1395
  return;
1299
1396
  case "synthesize":
1300
1397
  await cmdSynthesize(argv);
1301
1398
  return;
1399
+ case "mcp":
1400
+ await cmdMcp(argv);
1401
+ return;
1302
1402
  default:
1303
1403
  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");
1404
+ 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
1405
  process.exitCode = 1;
1306
1406
  }
1307
1407
  }
1308
- await main(process.argv).catch((error) => {
1309
- console.error(error instanceof Error ? error.message : String(error));
1310
- process.exitCode = 1;
1311
- });
1408
+ export async function runCli(argv) {
1409
+ await main(argv).catch((error) => {
1410
+ console.error(error instanceof Error ? error.message : String(error));
1411
+ process.exitCode = 1;
1412
+ });
1413
+ }
1414
+ function isDirectCliExecution(argv) {
1415
+ const entryPath = argv[1];
1416
+ if (!entryPath) {
1417
+ return false;
1418
+ }
1419
+ return resolve(entryPath) === fileURLToPath(import.meta.url);
1420
+ }
1421
+ if (isDirectCliExecution(process.argv)) {
1422
+ await runCli(process.argv);
1423
+ }
@@ -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) {
@@ -4,4 +4,8 @@ export interface BucketAssignment {
4
4
  buckets: FileBucket[];
5
5
  rationale: string[];
6
6
  }
7
+ /**
8
+ * Buckets files using the shared extractor heuristics so intake stays
9
+ * consistent across OS-specific path separators and mixed-case manifests.
10
+ */
7
11
  export declare function bucketFile(path: string): BucketAssignment;
@@ -1,12 +1,16 @@
1
- import { isNodeModulesOrGit, isTestPath, isInterfacePath, isDataLayerPath, isSecuritySensitivePath, isConcurrencyPath, isScriptPath, isDeploymentConfigPath, isDocPath, isGeneratedPath, } from "./pathPatterns.js";
1
+ import { isNodeModulesOrGit, isTestPath, isInterfacePath, isDataLayerPath, isSecuritySensitivePath, isConcurrencyPath, isScriptPath, isDeploymentConfigPath, isDocPath, isGeneratedPath, normalizeExtractorPath, } from "./pathPatterns.js";
2
2
  function addBucket(buckets, rationale, bucket, reason) {
3
3
  if (!buckets.has(bucket)) {
4
4
  buckets.add(bucket);
5
5
  rationale.push(reason);
6
6
  }
7
7
  }
8
+ /**
9
+ * Buckets files using the shared extractor heuristics so intake stays
10
+ * consistent across OS-specific path separators and mixed-case manifests.
11
+ */
8
12
  export function bucketFile(path) {
9
- const normalized = path.toLowerCase();
13
+ const normalized = normalizeExtractorPath(path);
10
14
  const buckets = new Set();
11
15
  const rationale = [];
12
16
  if (isNodeModulesOrGit(normalized)) {
@@ -1,4 +1,8 @@
1
1
  import type { RepoManifest } from "../types.js";
2
2
  import type { FileDisposition, FileDispositionStatus } from "../types/disposition.js";
3
+ /**
4
+ * Applies shared path heuristics to mark files that should be excluded or
5
+ * down-scoped before audit planning begins.
6
+ */
3
7
  export declare function buildFileDisposition(repoManifest: RepoManifest): FileDisposition;
4
8
  export declare function isAuditExcludedStatus(status: FileDispositionStatus): boolean;