auditor-lambda 0.3.12 → 0.3.14

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 (61) hide show
  1. package/README.md +20 -24
  2. package/audit-code-wrapper-lib.mjs +52 -53
  3. package/dist/cli.js +43 -6
  4. package/dist/coverage.js +3 -1
  5. package/dist/extractors/disposition.js +8 -1
  6. package/dist/extractors/graph.d.ts +3 -1
  7. package/dist/extractors/graph.js +1147 -67
  8. package/dist/extractors/graphManifestEdges.d.ts +14 -0
  9. package/dist/extractors/graphManifestEdges.js +1158 -0
  10. package/dist/extractors/graphPathUtils.d.ts +5 -0
  11. package/dist/extractors/graphPathUtils.js +75 -0
  12. package/dist/extractors/pathPatterns.d.ts +1 -0
  13. package/dist/extractors/pathPatterns.js +3 -0
  14. package/dist/io/artifacts.d.ts +10 -1
  15. package/dist/io/artifacts.js +23 -3
  16. package/dist/orchestrator/internalExecutors.d.ts +4 -0
  17. package/dist/orchestrator/internalExecutors.js +35 -6
  18. package/dist/orchestrator/reviewPackets.js +1003 -31
  19. package/dist/orchestrator/syntaxResolutionExecutor.js +34 -0
  20. package/dist/types/externalAnalyzer.d.ts +9 -0
  21. package/dist/types/graph.d.ts +3 -0
  22. package/dist/types/reviewPlanning.d.ts +39 -0
  23. package/docs/contracts.md +215 -0
  24. package/docs/development.md +210 -0
  25. package/docs/handoff.md +204 -0
  26. package/docs/history.md +40 -0
  27. package/docs/operator-guide.md +189 -0
  28. package/docs/product.md +185 -0
  29. package/docs/release.md +131 -0
  30. package/package.json +1 -1
  31. package/schemas/audit_plan_metrics.schema.json +347 -0
  32. package/schemas/external_analyzer_results.schema.json +35 -0
  33. package/schemas/graph_bundle.schema.json +47 -2
  34. package/schemas/review_packets.schema.json +160 -0
  35. package/skills/audit-code/SKILL.md +7 -3
  36. package/skills/audit-code/audit-code.prompt.md +4 -1
  37. package/docs/agent-integrations.md +0 -317
  38. package/docs/agent-roles.md +0 -69
  39. package/docs/architecture.md +0 -90
  40. package/docs/artifacts.md +0 -36
  41. package/docs/bootstrap-install.md +0 -139
  42. package/docs/contract.md +0 -54
  43. package/docs/dispatch-implementation-plan.md +0 -302
  44. package/docs/field-trial-bug-report.md +0 -237
  45. package/docs/github-copilot.md +0 -66
  46. package/docs/model-selection.md +0 -97
  47. package/docs/next-steps.md +0 -202
  48. package/docs/packaging.md +0 -120
  49. package/docs/pipeline.md +0 -152
  50. package/docs/product-direction.md +0 -154
  51. package/docs/production-launch-bar.md +0 -92
  52. package/docs/production-readiness.md +0 -58
  53. package/docs/releasing.md +0 -145
  54. package/docs/remediation-baseline.md +0 -75
  55. package/docs/repo-layout.md +0 -30
  56. package/docs/run-flow.md +0 -56
  57. package/docs/session-config.md +0 -319
  58. package/docs/supervisor.md +0 -100
  59. package/docs/usage.md +0 -215
  60. package/docs/windows-setup.md +0 -146
  61. package/docs/workflow-refactor-brief.md +0 -124
package/README.md CHANGED
@@ -30,7 +30,7 @@ npm install -g auditor-lambda
30
30
 
31
31
  That makes `audit-code` available on `PATH`. During package install, the package
32
32
  also writes user-level command/skill assets for hosts we can seed safely, including
33
- the Claude command file and Codex skill bundle.
33
+ the Claude command file and global Codex skill bundle.
34
34
 
35
35
  After that, invoke `/audit-code` in a supported host. The prompt self-bootstraps
36
36
  the current repository by running:
@@ -51,7 +51,7 @@ audit-code install
51
51
 
52
52
  That bootstraps repo-local `/audit-code` surfaces for the hosts we can automate today, including:
53
53
 
54
- - Codex skill bundle, `AGENTS.md` guidance, and MCP setup notes
54
+ - Codex `AGENTS.md` fallback guidance for the global skill surface
55
55
  - Claude Desktop local MCP bundle artifacts and project template guidance
56
56
  - OpenCode command, skill, and `opencode.json` surfaces
57
57
  - VS Code prompt, custom agent, Copilot instructions, and `.vscode/mcp.json`
@@ -190,20 +190,25 @@ Optional backend config:
190
190
  - use `provider: "auto"` only when you want best-effort routing across installed backends
191
191
  - treat explicit provider bridges as compatibility fallback, not as the intended owner of semantic review
192
192
 
193
- ## Implementation Next Steps
193
+ ## Current Development Focus
194
194
 
195
195
  The next implementation work is tracked in:
196
196
 
197
- - `docs/next-steps.md`
197
+ - `docs/product.md`
198
+ - `docs/development.md`
199
+ - `docs/handoff.md`
198
200
 
199
201
  The short version is:
200
202
 
201
203
  - keep the packet dispatch workflow verified in real host environments
202
- - benchmark `/audit-code` packet counts and warning counts against nontrivial external repositories
203
- - prove the generated Codex, Claude Desktop, OpenCode, VS Code, and Antigravity guidance in real host flows
204
+ - make graph-informed packetization observable before adding more ecosystem-specific parsers
205
+ - consolidate graph extraction and exercise generic ownership hints for analyzer-supplied module roots
206
+ - add deterministic Python import, package, and test/source graph support as a core language path
207
+ - use semantic/NLP-style affinity only as low-authority context unless deterministic graph evidence supports it
208
+ - keep generated Codex, Claude Desktop, OpenCode, VS Code, and Antigravity guidance aligned with real host behavior
204
209
  - tighten the repo-local MCP-first bootstrap where host smoke tests expose friction
205
210
  - polish provider-assisted continuation and failure guidance
206
- - finish publish and release hardening for packaged installs
211
+ - keep schema contracts and examples easy for workers and host integrations to validate
207
212
 
208
213
  ## Build And Test
209
214
 
@@ -214,24 +219,15 @@ npm run release:patch
214
219
  npm run release:patch:publish
215
220
  ```
216
221
 
217
- For GitHub Actions publication and npm Trusted Publishing setup, see `docs/releasing.md`.
222
+ For GitHub Actions publication and npm Trusted Publishing setup, see `docs/release.md`.
218
223
 
219
224
  ## Key Docs
220
225
 
221
- - `docs/product-direction.md`
222
- - `docs/workflow-refactor-brief.md`
223
- - `docs/remediation-baseline.md`
224
- - `docs/releasing.md`
225
- - `docs/production-readiness.md`
226
- - `docs/production-launch-bar.md`
227
- - `docs/next-steps.md`
226
+ - `docs/product.md`
227
+ - `docs/operator-guide.md`
228
+ - `docs/contracts.md`
229
+ - `docs/release.md`
230
+ - `docs/development.md`
231
+ - `docs/handoff.md`
232
+ - `docs/history.md`
228
233
  - `skills/audit-code/SKILL.md`
229
- - `docs/bootstrap-install.md`
230
- - `docs/agent-integrations.md`
231
- - `docs/github-copilot.md`
232
- - `docs/contract.md`
233
- - `docs/model-selection.md`
234
- - `docs/packaging.md`
235
- - `docs/session-config.md`
236
- - `docs/supervisor.md`
237
- - `docs/windows-setup.md`
@@ -398,6 +398,23 @@ async function writeGeneratedMarkdown(targetPath, content) {
398
398
  };
399
399
  }
400
400
 
401
+ async function removeGeneratedMarkdownIfMatches(targetPath, expectedContent) {
402
+ const existing = await readTextIfExists(targetPath);
403
+ if (existing === null) {
404
+ return null;
405
+ }
406
+
407
+ if (normalizeNewlines(existing) !== normalizeNewlines(expectedContent)) {
408
+ return null;
409
+ }
410
+
411
+ await unlink(targetPath);
412
+ return {
413
+ path: targetPath,
414
+ mode: 'removed',
415
+ };
416
+ }
417
+
401
418
  async function writeGeneratedJson(targetPath, value) {
402
419
  const existed = await fileExists(targetPath);
403
420
  await mkdir(dirname(targetPath), { recursive: true });
@@ -628,7 +645,7 @@ function renderClaudeDesktopProjectTemplate() {
628
645
  '',
629
646
  '- `.audit-code/install/audit-code.import.md`',
630
647
  '- `.audit-code/install/GETTING-STARTED.md`',
631
- '- `docs/agent-integrations.md` when you want host-specific operator context',
648
+ '- `docs/operator-guide.md` when you want host-specific operator context',
632
649
  '',
633
650
  'Starter prompt:',
634
651
  '',
@@ -1021,22 +1038,20 @@ const INSTALL_HOST_DEFINITIONS = {
1021
1038
  host: 'codex',
1022
1039
  label: 'Codex',
1023
1040
  support_level: 'supported',
1024
- setup_kind: 'skills+mcp+instructions',
1041
+ setup_kind: 'global-skill+instructions',
1025
1042
  summary:
1026
- 'Use the generated Codex skill bundle, AGENTS instructions, and shared MCP launcher so Codex can drive the backend through native tools instead of raw shell commands.',
1027
- primary_path_key: 'codexSkillPath',
1043
+ 'Use the global Codex skill installed by npm plus AGENTS fallback instructions for this repository. Repo-local Codex skill bundles are intentionally not generated.',
1044
+ primary_path_key: 'agentsInstructionsPath',
1028
1045
  supporting_path_keys: [
1029
- 'agentsInstructionsPath',
1030
- 'codexMcpSetupPath',
1031
- 'codexAutomationRecipePath',
1046
+ 'installedPromptPath',
1047
+ 'mcpLauncherPath',
1032
1048
  ],
1033
1049
  steps: [
1034
1050
  'Open this repository in Codex.',
1035
- 'Ensure Codex can access the repo-local auditor MCP server using the generated setup guide.',
1036
- 'Ask Codex to use the auditor MCP tools to start or continue `/audit-code`.',
1051
+ 'Use the global `/audit-code` skill installed by `npm install -g auditor-lambda`.',
1052
+ 'If the global skill is unavailable, follow the AGENTS fallback instructions that point at the repo-local prompt asset.',
1037
1053
  ],
1038
1054
  profile: {
1039
- writeCodex: true,
1040
1055
  writeAgents: true,
1041
1056
  },
1042
1057
  },
@@ -1685,43 +1700,14 @@ async function verifyInstalledBootstrap(argv) {
1685
1700
 
1686
1701
  switch (hostKey) {
1687
1702
  case 'codex':
1688
- await collectVerifyCheck(checks, 'codex_skill', async () => {
1689
- const content = await readFile(assetPaths.codexSkillPath, 'utf8');
1690
- if (!content.includes('# audit-code skill')) {
1691
- throw new Error(`Codex skill file is missing the expected heading: ${assetPaths.codexSkillPath}`);
1692
- }
1693
- const sourceSkill = (await readFile(skillAssetPath, 'utf8')).replace(/\r\n/g, '\n');
1694
- if (content.replace(/\r\n/g, '\n') !== sourceSkill) {
1695
- throw new Error(
1696
- `Codex skill is out of sync with the source skill. Run "audit-code install --host codex" or "audit-code install".`,
1697
- );
1703
+ await collectVerifyCheck(checks, 'codex_global_surface', async () => {
1704
+ const content = await readFile(assetPaths.agentsInstructionsPath, 'utf8');
1705
+ if (!content.includes('/audit-code')) {
1706
+ throw new Error(`AGENTS instructions do not reference /audit-code: ${assetPaths.agentsInstructionsPath}`);
1698
1707
  }
1699
1708
  return {
1700
- summary: 'Codex skill bundle is present and matches the source skill.',
1701
- path: assetPaths.codexSkillPath,
1702
- };
1703
- });
1704
- await collectVerifyCheck(checks, 'codex_prompt', async () => {
1705
- const content = await readFile(assetPaths.codexPromptPath, 'utf8');
1706
- const sourcePrompt = await readFile(promptAssetPath, 'utf8');
1707
- if (content !== sourcePrompt) {
1708
- throw new Error(
1709
- `Codex prompt is out of sync with the source prompt. Run "audit-code install --host codex" or "audit-code install".`,
1710
- );
1711
- }
1712
- return {
1713
- summary: 'Codex prompt bundle is present and matches the source prompt.',
1714
- path: assetPaths.codexPromptPath,
1715
- };
1716
- });
1717
- await collectVerifyCheck(checks, 'codex_mcp_setup', async () => {
1718
- const content = await readFile(assetPaths.codexMcpSetupPath, 'utf8');
1719
- if (!content.includes(MCP_LAUNCHER_FILENAME)) {
1720
- throw new Error(`Codex MCP setup guide does not reference ${MCP_LAUNCHER_FILENAME}.`);
1721
- }
1722
- return {
1723
- summary: 'Codex MCP setup guide references the shared launcher.',
1724
- path: assetPaths.codexMcpSetupPath,
1709
+ summary: 'Codex uses the global skill surface with AGENTS fallback instructions.',
1710
+ path: assetPaths.agentsInstructionsPath,
1725
1711
  };
1726
1712
  });
1727
1713
  break;
@@ -1989,6 +1975,10 @@ async function detectBootstrapRefreshReason(root, host) {
1989
1975
  (installManifest.hosts ?? []).map((entry) => entry.host),
1990
1976
  );
1991
1977
 
1978
+ if (hostCatalog.has('codex') && (assetPaths.codexSkillPath || assetPaths.codexPromptPath)) {
1979
+ return 'legacy_repo_local_codex_skill';
1980
+ }
1981
+
1992
1982
  for (const hostKey of getInstallHostKeys(host)) {
1993
1983
  if (!hostCatalog.has(hostKey)) {
1994
1984
  return `missing_host_surface:${hostKey}`;
@@ -2029,14 +2019,6 @@ async function detectBootstrapRefreshReason(root, host) {
2029
2019
  for (const hostKey of getInstallHostKeys(host)) {
2030
2020
  switch (hostKey) {
2031
2021
  case 'codex': {
2032
- const codexSkill = await readTextIfExists(assetPaths.codexSkillPath);
2033
- if (codexSkill?.replace(/\r\n/g, '\n') !== sourceSkill) {
2034
- return 'stale_host_asset:codex:skill';
2035
- }
2036
- const codexPrompt = await readTextIfExists(assetPaths.codexPromptPath);
2037
- if (codexPrompt !== sourcePrompt) {
2038
- return 'stale_host_asset:codex:prompt';
2039
- }
2040
2022
  break;
2041
2023
  }
2042
2024
  case 'opencode': {
@@ -2240,6 +2222,23 @@ async function installBootstrap(argv, options = {}) {
2240
2222
  );
2241
2223
  }
2242
2224
 
2225
+ if (!profile.writeCodex) {
2226
+ const legacyCodexSkillRemoval = await removeGeneratedMarkdownIfMatches(
2227
+ join(root, '.codex', 'skills', 'audit-code', 'SKILL.md'),
2228
+ skillSource,
2229
+ );
2230
+ if (legacyCodexSkillRemoval) {
2231
+ results.push(legacyCodexSkillRemoval);
2232
+ }
2233
+ const legacyCodexPromptRemoval = await removeGeneratedMarkdownIfMatches(
2234
+ join(root, '.codex', 'skills', 'audit-code', 'audit-code.prompt.md'),
2235
+ promptSource,
2236
+ );
2237
+ if (legacyCodexPromptRemoval) {
2238
+ results.push(legacyCodexPromptRemoval);
2239
+ }
2240
+ }
2241
+
2243
2242
  if (profile.writeCodex) {
2244
2243
  results.push(
2245
2244
  await writeGeneratedMarkdown(
package/dist/cli.js CHANGED
@@ -792,7 +792,7 @@ async function cmdRunToCompletion(argv) {
792
792
  });
793
793
  const blockRunId = buildRunId(obligationId, runCount + 1);
794
794
  const blockPaths = getRunPaths(artifactsDir, blockRunId);
795
- const blockPendingTasks = await addFileLineCountHints(root, buildPendingAuditTasks(bundle).slice(0, agentBatchSize));
795
+ const blockPendingTasks = await addFileLineCountHints(root, buildPendingAuditTasks(bundle));
796
796
  const blockPendingTasksPath = join(blockPaths.runDir, "pending-audit-tasks.json");
797
797
  const blockAuditResultsPath = join(blockPaths.runDir, "audit-results.json");
798
798
  const blockTask = {
@@ -1193,7 +1193,7 @@ async function cmdRunToCompletion(argv) {
1193
1193
  continue;
1194
1194
  }
1195
1195
  const pendingAuditTasks = preferredExecutor === "agent"
1196
- ? await addFileLineCountHints(root, buildPendingAuditTasks(bundle).slice(0, agentBatchSize))
1196
+ ? await addFileLineCountHints(root, buildPendingAuditTasks(bundle))
1197
1197
  : undefined;
1198
1198
  const pendingAuditTasksPath = preferredExecutor === "agent"
1199
1199
  ? join(paths.runDir, "pending-audit-tasks.json")
@@ -1559,6 +1559,42 @@ function renderAnchorPreview(summary, anchorPath) {
1559
1559
  "",
1560
1560
  ];
1561
1561
  }
1562
+ function formatPacketConfidence(value) {
1563
+ return typeof value === "number" && Number.isFinite(value)
1564
+ ? value.toFixed(2)
1565
+ : "n/a";
1566
+ }
1567
+ function renderPacketGraphContext(packet) {
1568
+ const hasContext = (packet.entrypoints?.length ?? 0) > 0 ||
1569
+ (packet.key_edges?.length ?? 0) > 0 ||
1570
+ (packet.boundary_files?.length ?? 0) > 0 ||
1571
+ packet.quality !== undefined;
1572
+ if (!hasContext) {
1573
+ return [];
1574
+ }
1575
+ const lines = ["## Packet graph context"];
1576
+ if (packet.entrypoints?.length) {
1577
+ lines.push("Entrypoints:");
1578
+ lines.push(...packet.entrypoints.map((entrypoint) => `- ${entrypoint}`));
1579
+ }
1580
+ if (packet.key_edges?.length) {
1581
+ lines.push("Key internal edges:");
1582
+ lines.push(...packet.key_edges.map((edge) => {
1583
+ const kind = edge.kind ? ` [${edge.kind}]` : "";
1584
+ const reason = edge.reason ? ` - ${edge.reason}` : "";
1585
+ return `- ${edge.from} -> ${edge.to}${kind} confidence=${formatPacketConfidence(edge.confidence)}${reason}`;
1586
+ }));
1587
+ }
1588
+ if (packet.boundary_files?.length) {
1589
+ lines.push("Boundary files to check only when evidence crosses the packet:");
1590
+ lines.push(...packet.boundary_files.map((path) => `- ${path}`));
1591
+ }
1592
+ if (packet.quality) {
1593
+ lines.push(`Quality: cohesion=${packet.quality.cohesion_score}, internal_edges=${packet.quality.internal_edge_count}, boundary_edges=${packet.quality.boundary_edge_count}, unexplained_files=${packet.quality.unexplained_file_count}`);
1594
+ }
1595
+ lines.push("");
1596
+ return lines;
1597
+ }
1562
1598
  async function cmdPrepareDispatch(argv) {
1563
1599
  const runId = getFlag(argv, "--run-id");
1564
1600
  if (!runId)
@@ -1738,6 +1774,7 @@ async function cmdPrepareDispatch(argv) {
1738
1774
  : "Use your Read tool. Paths are repo-relative from the current working directory.",
1739
1775
  fileList,
1740
1776
  "",
1777
+ ...renderPacketGraphContext(packet),
1741
1778
  ...largeFileSection,
1742
1779
  "## Tasks",
1743
1780
  ...taskSections,
@@ -1961,13 +1998,12 @@ async function cmdMergeAndIngest(argv) {
1961
1998
  const passing = [];
1962
1999
  const failing = [];
1963
2000
  const seenTaskIds = new Set();
2001
+ let spuriousFileCount = 0;
1964
2002
  for (const filename of files) {
1965
2003
  const filePath = resolve(join(taskResultsDir, filename));
1966
2004
  if (!expectedPaths.has(filePath)) {
1967
- failing.push({
1968
- task_id: filename,
1969
- errors: ["Unexpected task result file; only backend-assigned result paths may be ingested."],
1970
- });
2005
+ spuriousFileCount++;
2006
+ process.stderr.write(`[merge-and-ingest] Warning: ignoring unexpected file in task-results/: ${filename}\n`);
1971
2007
  }
1972
2008
  }
1973
2009
  for (const task of allTasks) {
@@ -2054,6 +2090,7 @@ async function cmdMergeAndIngest(argv) {
2054
2090
  status: workerResult.status,
2055
2091
  accepted_count: passing.length,
2056
2092
  rejected_count: 0,
2093
+ spurious_file_count: spuriousFileCount,
2057
2094
  finding_count: findingCount,
2058
2095
  audit_results_path: auditResultsPath,
2059
2096
  selected_executor: workerResult.selected_executor,
package/dist/coverage.js CHANGED
@@ -37,7 +37,9 @@ export function applyFileCoverage(matrix, fileCoverage) {
37
37
  const record = matrix.files.find((file) => file.path === coverage.path);
38
38
  if (!record || record.audit_status === "excluded")
39
39
  continue;
40
- if (coverage.lens && !record.completed_lenses.includes(coverage.lens)) {
40
+ if (coverage.lens &&
41
+ record.required_lenses.includes(coverage.lens) &&
42
+ !record.completed_lenses.includes(coverage.lens)) {
41
43
  record.completed_lenses.push(coverage.lens);
42
44
  }
43
45
  }
@@ -1,4 +1,4 @@
1
- import { isNodeModulesOrGit, isBuildOutput, isVendorPath, isBinaryArtifact, isLicensePath, isLockfilePath, isLogPath, isDocPath, isAuditArtifactPath, isGeneratedInstallArtifactPath, isExamplesOrFixturesPath, normalizeExtractorPath, } from "./pathPatterns.js";
1
+ import { isNodeModulesOrGit, isBuildOutput, isVendorPath, isBinaryArtifact, isLicensePath, isLockfilePath, isLogPath, isDocPath, isAuditArtifactPath, isGeneratedTestArtifactPath, isGeneratedInstallArtifactPath, isExamplesOrFixturesPath, normalizeExtractorPath, } from "./pathPatterns.js";
2
2
  function inferDisposition(path) {
3
3
  const normalized = normalizeExtractorPath(path);
4
4
  if (isNodeModulesOrGit(normalized)) {
@@ -33,6 +33,13 @@ function inferDisposition(path) {
33
33
  reason: "Generated audit artifact.",
34
34
  };
35
35
  }
36
+ if (isGeneratedTestArtifactPath(normalized)) {
37
+ return {
38
+ path,
39
+ status: "generated",
40
+ reason: "Generated test artifact.",
41
+ };
42
+ }
36
43
  if (isDocPath(normalized)) {
37
44
  return { path, status: "doc_only", reason: "Documentation artifact." };
38
45
  }
@@ -1,8 +1,10 @@
1
1
  import type { RepoManifest } from "../types.js";
2
2
  import type { FileDisposition } from "../types/disposition.js";
3
+ import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
3
4
  import type { GraphBundle } from "../types/graph.js";
4
5
  export interface BuildGraphBundleOptions {
5
6
  fileContents?: Record<string, string>;
7
+ externalAnalyzerResults?: ExternalAnalyzerResults;
6
8
  }
7
- export declare function buildGraphBundleFromFs(repoManifest: RepoManifest, root: string, disposition?: FileDisposition): Promise<GraphBundle>;
9
+ export declare function buildGraphBundleFromFs(repoManifest: RepoManifest, root: string, disposition?: FileDisposition, options?: Pick<BuildGraphBundleOptions, "externalAnalyzerResults">): Promise<GraphBundle>;
8
10
  export declare function buildGraphBundle(repoManifest: RepoManifest, disposition?: FileDisposition, options?: BuildGraphBundleOptions): GraphBundle;