auditor-lambda 0.3.40 → 0.5.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 (193) hide show
  1. package/audit-code-wrapper-lib.mjs +20 -2
  2. package/dist/cli/args.d.ts +59 -0
  3. package/dist/cli/args.js +244 -0
  4. package/dist/cli/dispatch.d.ts +80 -0
  5. package/dist/cli/dispatch.js +532 -0
  6. package/dist/cli/prompts.d.ts +37 -0
  7. package/dist/cli/prompts.js +225 -0
  8. package/dist/cli/steps.d.ts +29 -0
  9. package/dist/cli/steps.js +30 -0
  10. package/dist/cli/waveManifest.d.ts +40 -0
  11. package/dist/cli/waveManifest.js +41 -0
  12. package/dist/cli/workerResult.d.ts +18 -0
  13. package/dist/cli/workerResult.js +42 -0
  14. package/dist/cli.d.ts +2 -22
  15. package/dist/cli.js +442 -975
  16. package/dist/extractors/analyzers/css.d.ts +2 -0
  17. package/dist/extractors/analyzers/css.js +101 -0
  18. package/dist/extractors/analyzers/html.d.ts +2 -0
  19. package/dist/extractors/analyzers/html.js +92 -0
  20. package/dist/extractors/analyzers/merge.d.ts +14 -0
  21. package/dist/extractors/analyzers/merge.js +85 -0
  22. package/dist/extractors/analyzers/python.d.ts +2 -0
  23. package/dist/extractors/analyzers/python.js +104 -0
  24. package/dist/extractors/analyzers/registry.d.ts +33 -0
  25. package/dist/extractors/analyzers/registry.js +100 -0
  26. package/dist/extractors/analyzers/resourceUrl.d.ts +7 -0
  27. package/dist/extractors/analyzers/resourceUrl.js +25 -0
  28. package/dist/extractors/analyzers/sql.d.ts +2 -0
  29. package/dist/extractors/analyzers/sql.js +19 -0
  30. package/dist/extractors/analyzers/treeSitter.d.ts +34 -0
  31. package/dist/extractors/analyzers/treeSitter.js +111 -0
  32. package/dist/extractors/analyzers/types.d.ts +53 -0
  33. package/dist/extractors/analyzers/typescript.d.ts +2 -0
  34. package/dist/extractors/analyzers/typescript.js +257 -0
  35. package/dist/extractors/browserExtension.d.ts +1 -3
  36. package/dist/extractors/browserExtension.js +2 -2
  37. package/dist/extractors/designAssessment.d.ts +1 -3
  38. package/dist/extractors/disposition.d.ts +2 -1
  39. package/dist/extractors/disposition.js +11 -1
  40. package/dist/extractors/flows.d.ts +1 -3
  41. package/dist/extractors/flows.js +2 -2
  42. package/dist/extractors/graph.d.ts +2 -2
  43. package/dist/extractors/graph.js +171 -327
  44. package/dist/extractors/graphManifestEdges.d.ts +1 -1
  45. package/dist/extractors/graphPathUtils.d.ts +1 -1
  46. package/dist/extractors/graphPythonImports.d.ts +18 -0
  47. package/dist/extractors/graphPythonImports.js +362 -0
  48. package/dist/extractors/pathPatterns.d.ts +6 -0
  49. package/dist/extractors/pathPatterns.js +8 -0
  50. package/dist/extractors/risk.d.ts +1 -2
  51. package/dist/extractors/surfaces.d.ts +1 -3
  52. package/dist/extractors/surfaces.js +2 -2
  53. package/dist/io/artifacts.d.ts +12 -5
  54. package/dist/io/artifacts.js +13 -1
  55. package/dist/io/runArtifacts.js +1 -1
  56. package/dist/mcp/server.js +1 -1
  57. package/dist/orchestrator/advance.d.ts +21 -0
  58. package/dist/orchestrator/advance.js +69 -7
  59. package/dist/orchestrator/auditTaskUtils.d.ts +4 -0
  60. package/dist/orchestrator/auditTaskUtils.js +27 -0
  61. package/dist/orchestrator/dependencyMap.js +27 -0
  62. package/dist/orchestrator/edgeReasoning.d.ts +39 -0
  63. package/dist/orchestrator/edgeReasoning.js +125 -0
  64. package/dist/orchestrator/executors.js +11 -1
  65. package/dist/orchestrator/fileAnchors.d.ts +1 -1
  66. package/dist/orchestrator/fileIntegrity.d.ts +7 -0
  67. package/dist/orchestrator/fileIntegrity.js +41 -0
  68. package/dist/orchestrator/flowCoverage.d.ts +1 -1
  69. package/dist/orchestrator/flowPlanning.d.ts +1 -1
  70. package/dist/orchestrator/flowRequeue.d.ts +1 -1
  71. package/dist/orchestrator/graphEnrichmentExecutor.d.ts +29 -0
  72. package/dist/orchestrator/graphEnrichmentExecutor.js +196 -0
  73. package/dist/orchestrator/internalExecutors.d.ts +13 -2
  74. package/dist/orchestrator/internalExecutors.js +112 -16
  75. package/dist/orchestrator/localCommands.js +6 -25
  76. package/dist/orchestrator/nextStep.d.ts +2 -1
  77. package/dist/orchestrator/nextStep.js +3 -1
  78. package/dist/orchestrator/planning.d.ts +1 -1
  79. package/dist/orchestrator/requeueCommand.d.ts +1 -1
  80. package/dist/orchestrator/reviewPackets.d.ts +37 -4
  81. package/dist/orchestrator/reviewPackets.js +113 -158
  82. package/dist/orchestrator/runtimeValidation.d.ts +1 -1
  83. package/dist/orchestrator/runtimeValidation.js +4 -31
  84. package/dist/orchestrator/scope.d.ts +62 -0
  85. package/dist/orchestrator/scope.js +227 -0
  86. package/dist/orchestrator/state.js +2 -0
  87. package/dist/orchestrator/taskBuilder.d.ts +1 -1
  88. package/dist/orchestrator/taskBuilder.js +1 -12
  89. package/dist/orchestrator/unionFind.d.ts +7 -0
  90. package/dist/orchestrator/unionFind.js +32 -0
  91. package/dist/orchestrator/unitBuilder.d.ts +2 -2
  92. package/dist/orchestrator/unitBuilder.js +4 -18
  93. package/dist/prompts/renderWorkerPrompt.js +18 -1
  94. package/dist/providers/claudeCodeProvider.d.ts +4 -4
  95. package/dist/providers/claudeCodeProvider.js +9 -3
  96. package/dist/providers/constants.d.ts +1 -1
  97. package/dist/providers/constants.js +1 -1
  98. package/dist/providers/index.d.ts +1 -2
  99. package/dist/providers/index.js +5 -4
  100. package/dist/providers/localSubprocessProvider.d.ts +2 -2
  101. package/dist/providers/localSubprocessProvider.js +1 -1
  102. package/dist/providers/opencodeProvider.d.ts +4 -4
  103. package/dist/providers/opencodeProvider.js +7 -2
  104. package/dist/providers/spawnLoggedCommand.d.ts +3 -1
  105. package/dist/providers/spawnLoggedCommand.js +21 -0
  106. package/dist/providers/subprocessTemplateProvider.d.ts +4 -4
  107. package/dist/providers/subprocessTemplateProvider.js +8 -3
  108. package/dist/providers/vscodeTaskProvider.d.ts +3 -4
  109. package/dist/providers/vscodeTaskProvider.js +2 -2
  110. package/dist/quota/discoveredLimits.js +1 -1
  111. package/dist/quota/hostLimits.d.ts +1 -2
  112. package/dist/quota/hostLimits.js +4 -46
  113. package/dist/quota/index.d.ts +18 -15
  114. package/dist/quota/index.js +4 -9
  115. package/dist/quota/scheduler.d.ts +1 -3
  116. package/dist/quota/scheduler.js +1 -2
  117. package/dist/reporting/synthesis.d.ts +37 -3
  118. package/dist/reporting/synthesis.js +97 -16
  119. package/dist/reporting/synthesisNarrativePrompt.d.ts +7 -0
  120. package/dist/reporting/synthesisNarrativePrompt.js +60 -0
  121. package/dist/reporting/workBlocks.d.ts +2 -11
  122. package/dist/supervisor/operatorHandoff.js +1 -1
  123. package/dist/supervisor/runLedger.d.ts +1 -1
  124. package/dist/supervisor/runLedger.js +2 -2
  125. package/dist/supervisor/sessionConfig.d.ts +8 -1
  126. package/dist/supervisor/sessionConfig.js +22 -3
  127. package/dist/types/analyzerCapability.d.ts +16 -0
  128. package/dist/types/auditScope.d.ts +43 -0
  129. package/dist/types/auditScope.js +14 -0
  130. package/dist/types/reviewPlanning.d.ts +1 -1
  131. package/dist/types/synthesisNarrative.d.ts +7 -0
  132. package/dist/types/synthesisNarrative.js +5 -0
  133. package/dist/types/workerSession.d.ts +6 -0
  134. package/dist/types.d.ts +2 -19
  135. package/dist/validation/artifacts.d.ts +1 -1
  136. package/dist/validation/artifacts.js +10 -1
  137. package/dist/validation/auditResults.d.ts +1 -1
  138. package/dist/validation/auditResults.js +1 -1
  139. package/dist/validation/sessionConfig.d.ts +2 -3
  140. package/dist/validation/sessionConfig.js +25 -3
  141. package/package.json +7 -3
  142. package/schemas/analyzer_capability.schema.json +47 -0
  143. package/schemas/audit_findings.schema.json +141 -0
  144. package/schemas/finding.schema.json +2 -1
  145. package/schemas/graph_bundle.schema.json +5 -0
  146. package/schemas/scope.schema.json +46 -0
  147. package/scripts/postinstall.mjs +0 -1
  148. package/dist/io/json.d.ts +0 -10
  149. package/dist/io/json.js +0 -142
  150. package/dist/providers/types.d.ts +0 -33
  151. package/dist/quota/compositeQuotaSource.d.ts +0 -7
  152. package/dist/quota/compositeQuotaSource.js +0 -20
  153. package/dist/quota/errorParsers/claudeCodeErrorParser.d.ts +0 -6
  154. package/dist/quota/errorParsers/claudeCodeErrorParser.js +0 -39
  155. package/dist/quota/errorParsers/genericErrorParser.d.ts +0 -9
  156. package/dist/quota/errorParsers/genericErrorParser.js +0 -7
  157. package/dist/quota/errorParsers/index.d.ts +0 -5
  158. package/dist/quota/errorParsers/index.js +0 -12
  159. package/dist/quota/errorParsing.d.ts +0 -7
  160. package/dist/quota/errorParsing.js +0 -69
  161. package/dist/quota/fileLock.d.ts +0 -6
  162. package/dist/quota/fileLock.js +0 -64
  163. package/dist/quota/learnedQuotaSource.d.ts +0 -7
  164. package/dist/quota/learnedQuotaSource.js +0 -25
  165. package/dist/quota/limits.d.ts +0 -16
  166. package/dist/quota/limits.js +0 -77
  167. package/dist/quota/quotaSource.d.ts +0 -12
  168. package/dist/quota/slidingWindow.d.ts +0 -4
  169. package/dist/quota/slidingWindow.js +0 -28
  170. package/dist/quota/state.d.ts +0 -15
  171. package/dist/quota/state.js +0 -148
  172. package/dist/quota/types.d.ts +0 -67
  173. package/dist/quota/types.js +0 -1
  174. package/dist/reporting/rootCause.d.ts +0 -10
  175. package/dist/reporting/rootCause.js +0 -146
  176. package/dist/types/disposition.d.ts +0 -9
  177. package/dist/types/disposition.js +0 -1
  178. package/dist/types/flows.d.ts +0 -17
  179. package/dist/types/flows.js +0 -1
  180. package/dist/types/graph.d.ts +0 -22
  181. package/dist/types/graph.js +0 -1
  182. package/dist/types/risk.d.ts +0 -9
  183. package/dist/types/risk.js +0 -1
  184. package/dist/types/runLedger.d.ts +0 -17
  185. package/dist/types/runLedger.js +0 -6
  186. package/dist/types/sessionConfig.d.ts +0 -79
  187. package/dist/types/sessionConfig.js +0 -15
  188. package/dist/types/surfaces.d.ts +0 -15
  189. package/dist/types/surfaces.js +0 -1
  190. package/dist/validation/basic.d.ts +0 -13
  191. package/dist/validation/basic.js +0 -46
  192. /package/dist/{providers → extractors/analyzers}/types.js +0 -0
  193. /package/dist/{quota/quotaSource.js → types/analyzerCapability.js} +0 -0
@@ -1,4 +1,4 @@
1
- import { readJsonFile } from "../io/json.js";
1
+ import { readJsonFile } from "@audit-tools/shared";
2
2
  import { spawnLoggedCommand } from "./spawnLoggedCommand.js";
3
3
  function shellQuote(arg) {
4
4
  return JSON.stringify(arg);
@@ -25,9 +25,11 @@ function applyTemplate(template, input, task) {
25
25
  export class SubprocessTemplateProvider {
26
26
  name;
27
27
  config;
28
- constructor(config, name = "subprocess-template") {
28
+ opentoken;
29
+ constructor(config, name = "subprocess-template", opentoken = {}) {
29
30
  this.config = config;
30
31
  this.name = name;
32
+ this.opentoken = opentoken;
31
33
  }
32
34
  async launch(input) {
33
35
  const task = await readJsonFile(input.taskPath);
@@ -36,6 +38,9 @@ export class SubprocessTemplateProvider {
36
38
  }
37
39
  const rendered = this.config.command_template.map((entry) => applyTemplate(entry, input, task));
38
40
  const [command, ...args] = rendered;
39
- return await spawnLoggedCommand(command, args, input, this.config.env);
41
+ return await spawnLoggedCommand(command, args, input, this.config.env, {
42
+ opentoken: this.opentoken.enabled,
43
+ opentokenCommand: this.opentoken.command,
44
+ });
40
45
  }
41
46
  }
@@ -1,8 +1,7 @@
1
- import type { FreshSessionProvider, LaunchFreshSessionInput } from "./types.js";
2
- import type { VSCodeTaskConfig } from "../types/sessionConfig.js";
1
+ import type { FreshSessionProvider, LaunchFreshSessionInput, VSCodeTaskConfig, OpenTokenConfig } from "@audit-tools/shared";
3
2
  export declare class VSCodeTaskProvider implements FreshSessionProvider {
4
3
  name: string;
5
4
  private readonly delegate;
6
- constructor(config: VSCodeTaskConfig);
7
- launch(input: LaunchFreshSessionInput): Promise<import("./types.js").LaunchFreshSessionResult>;
5
+ constructor(config: VSCodeTaskConfig, opentoken?: OpenTokenConfig);
6
+ launch(input: LaunchFreshSessionInput): Promise<import("@audit-tools/shared").LaunchFreshSessionResult>;
8
7
  }
@@ -2,11 +2,11 @@ import { SubprocessTemplateProvider } from "./subprocessTemplateProvider.js";
2
2
  export class VSCodeTaskProvider {
3
3
  name = "vscode-task";
4
4
  delegate;
5
- constructor(config) {
5
+ constructor(config, opentoken = {}) {
6
6
  this.delegate = new SubprocessTemplateProvider({
7
7
  command_template: config.command_template,
8
8
  env: config.env,
9
- }, "vscode-task");
9
+ }, "vscode-task", opentoken);
10
10
  }
11
11
  async launch(input) {
12
12
  return await this.delegate.launch(input);
@@ -1,6 +1,6 @@
1
1
  import { mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { dirname } from "node:path";
3
- import { getQuotaStatePath } from "./state.js";
3
+ import { getQuotaStatePath } from "@audit-tools/shared";
4
4
  function getCachePath() {
5
5
  return getQuotaStatePath().replace(/quota-state\.json$/, "discovered-limits.json");
6
6
  }
@@ -1,5 +1,4 @@
1
- import type { SessionConfig } from "../types/sessionConfig.js";
2
- import type { HostConcurrencyLimit } from "./types.js";
1
+ import type { SessionConfig, HostConcurrencyLimit } from "@audit-tools/shared";
3
2
  export declare function detectHostActiveSubagentLimit(env?: NodeJS.ProcessEnv): HostConcurrencyLimit | null;
4
3
  export declare function resolveHostActiveSubagentLimit(options: {
5
4
  explicitLimit?: number | null;
@@ -1,50 +1,8 @@
1
- const CODEX_DESKTOP_ACTIVE_SUBAGENT_LIMIT = 6;
2
- function parsePositiveInteger(value) {
3
- if (typeof value === "number") {
4
- return Number.isInteger(value) && value > 0 ? value : null;
5
- }
6
- if (typeof value !== "string")
7
- return null;
8
- const trimmed = value.trim();
9
- if (!/^\d+$/.test(trimmed))
10
- return null;
11
- const parsed = Number(trimmed);
12
- return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null;
13
- }
1
+ import { detectHostActiveSubagentLimit as detectShared, resolveHostActiveSubagentLimit as resolveShared, } from "@audit-tools/shared";
2
+ const ENV_PREFIX = "AUDIT_CODE";
14
3
  export function detectHostActiveSubagentLimit(env = process.env) {
15
- const explicitEnvLimit = parsePositiveInteger(env.AUDIT_CODE_HOST_MAX_ACTIVE_SUBAGENTS ??
16
- env.CODEX_MAX_ACTIVE_SUBAGENTS);
17
- if (explicitEnvLimit !== null) {
18
- return {
19
- active_subagents: explicitEnvLimit,
20
- source: "environment",
21
- description: "Host active subagent limit from environment.",
22
- };
23
- }
24
- if (env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE === "Codex Desktop") {
25
- return {
26
- active_subagents: CODEX_DESKTOP_ACTIVE_SUBAGENT_LIMIT,
27
- source: "environment",
28
- description: "Codex Desktop active subagent limit.",
29
- };
30
- }
31
- return null;
4
+ return detectShared(ENV_PREFIX, env);
32
5
  }
33
6
  export function resolveHostActiveSubagentLimit(options) {
34
- if (options.explicitLimit !== undefined && options.explicitLimit !== null) {
35
- return {
36
- active_subagents: options.explicitLimit,
37
- source: "cli_flags",
38
- description: "Host active subagent limit reported by the conversation host.",
39
- };
40
- }
41
- const configuredLimit = parsePositiveInteger(options.sessionConfig.quota?.host_active_subagent_limit);
42
- if (configuredLimit !== null) {
43
- return {
44
- active_subagents: configuredLimit,
45
- source: "session_config",
46
- description: "Host active subagent limit from session-config quota settings.",
47
- };
48
- }
49
- return detectHostActiveSubagentLimit(options.env);
7
+ return resolveShared({ envPrefix: ENV_PREFIX, ...options });
50
8
  }
@@ -1,25 +1,28 @@
1
- export { resolveLimits, lookupKnownModel, classifyProvider } from "./limits.js";
2
- export type { LimitResolutionResult, ResolveLimitsOptions, ProviderType } from "./limits.js";
3
- export { detectHostActiveSubagentLimit, resolveHostActiveSubagentLimit, } from "./hostLimits.js";
4
- export { readQuotaState, writeQuotaState, computeMaxSafeConcurrency, recordWaveOutcome, getQuotaStatePath, decayWeight, applyDecayToEntry, computeBackoffCooldownMs, computeBackoffFailureWeight, computeRampUpConcurrency, } from "./state.js";
1
+ import type { ResolvedLimits as _ResolvedLimits, LimitConfidence as _LimitConfidence, LimitSource as _LimitSource, HostConcurrencyLimit as _HostConcurrencyLimit, QuotaUsageSnapshot as _QuotaUsageSnapshot, BackoffState as _BackoffState } from "@audit-tools/shared";
2
+ export { resolveLimits, lookupKnownModel, classifyProvider, readQuotaState, writeQuotaState, computeMaxSafeConcurrency, recordWaveOutcome, getQuotaStatePath, decayWeight, applyDecayToEntry, computeBackoffCooldownMs, computeBackoffFailureWeight, computeRampUpConcurrency, setQuotaStateDir, detectRateLimitError, computeCooldownUntil, acquireLock, releaseLock, withFileLock, FileLockTimeoutError, runSlidingWindow, LearnedQuotaSource, CompositeQuotaSource, GenericErrorParser, ClaudeCodeErrorParser, getErrorParserForProvider, } from "@audit-tools/shared";
3
+ export type { LimitResolutionResult, ResolveLimitsOptions, ProviderType, ResolvedLimits, LimitSource, LimitConfidence, HostConcurrencyLimit, HostConcurrencyLimitSource, QuotaState, QuotaStateEntry, ConcurrencyBucket, WaveSchedule, BackoffState, ObservedWaveOutcome, RateLimitDetectionResult, SlidingWindowResult, QuotaSource, QuotaUsageSnapshot, ErrorParser, } from "@audit-tools/shared";
5
4
  export { scheduleWave, buildProviderModelKey } from "./scheduler.js";
6
5
  export type { ScheduleWaveOptions } from "./scheduler.js";
7
- export { detectRateLimitError, computeCooldownUntil } from "./errorParsing.js";
8
- export { acquireLock, releaseLock, withFileLock, FileLockTimeoutError } from "./fileLock.js";
9
- export { runSlidingWindow } from "./slidingWindow.js";
10
- export type { SlidingWindowResult } from "./slidingWindow.js";
11
- export type { RateLimitDetectionResult } from "./errorParsing.js";
6
+ export { detectHostActiveSubagentLimit, resolveHostActiveSubagentLimit, } from "./hostLimits.js";
12
7
  export { probeProvider } from "./probe.js";
13
8
  export type { ProbeResult } from "./probe.js";
14
- export type { QuotaSource, QuotaUsageSnapshot } from "./quotaSource.js";
15
- export type { ErrorParser } from "./errorParsers/index.js";
16
- export { GenericErrorParser, ClaudeCodeErrorParser, getErrorParserForProvider } from "./errorParsers/index.js";
17
- export { LearnedQuotaSource } from "./learnedQuotaSource.js";
18
- export { CompositeQuotaSource } from "./compositeQuotaSource.js";
19
9
  export { lookupDiscoveredLimits, updateDiscoveredLimits, mergeDiscoveredLimits, readDiscoveredLimitsCache, writeDiscoveredLimitsCache, } from "./discoveredLimits.js";
20
10
  export type { DiscoveredRateLimits, DiscoveredLimitsCache, DiscoveredLimitsCacheEntry } from "./discoveredLimits.js";
21
11
  export { extractRateLimitHeaders } from "./headerExtraction.js";
22
12
  export type { ExtractedRateLimits } from "./headerExtraction.js";
23
13
  export type { HeaderExtractor } from "./headerExtractors/index.js";
24
14
  export { GenericHeaderExtractor, ClaudeCodeHeaderExtractor, getHeaderExtractorForProvider } from "./headerExtractors/index.js";
25
- export type { ResolvedLimits, LimitSource, LimitConfidence, HostConcurrencyLimit, HostConcurrencyLimitSource, QuotaState, QuotaStateEntry, ConcurrencyBucket, WaveSchedule, DispatchQuota, ObservedWaveOutcome, } from "./types.js";
15
+ export interface DispatchQuota {
16
+ contract_version: "audit-code-dispatch-quota/v1alpha1" | "audit-code-dispatch-quota/v1alpha2";
17
+ run_id: string;
18
+ model: string | null;
19
+ resolved_limits: _ResolvedLimits;
20
+ confidence: _LimitConfidence;
21
+ source: _LimitSource;
22
+ host_concurrency_limit: _HostConcurrencyLimit | null;
23
+ wave_size: number;
24
+ estimated_wave_tokens: number;
25
+ cooldown_until: string | null;
26
+ quota_source_snapshot?: _QuotaUsageSnapshot | null;
27
+ backoff_state?: _BackoffState | null;
28
+ }
@@ -1,14 +1,9 @@
1
- export { resolveLimits, lookupKnownModel, classifyProvider } from "./limits.js";
2
- export { detectHostActiveSubagentLimit, resolveHostActiveSubagentLimit, } from "./hostLimits.js";
3
- export { readQuotaState, writeQuotaState, computeMaxSafeConcurrency, recordWaveOutcome, getQuotaStatePath, decayWeight, applyDecayToEntry, computeBackoffCooldownMs, computeBackoffFailureWeight, computeRampUpConcurrency, } from "./state.js";
1
+ // Re-exported from @audit-tools/shared
2
+ export { resolveLimits, lookupKnownModel, classifyProvider, readQuotaState, writeQuotaState, computeMaxSafeConcurrency, recordWaveOutcome, getQuotaStatePath, decayWeight, applyDecayToEntry, computeBackoffCooldownMs, computeBackoffFailureWeight, computeRampUpConcurrency, setQuotaStateDir, detectRateLimitError, computeCooldownUntil, acquireLock, releaseLock, withFileLock, FileLockTimeoutError, runSlidingWindow, LearnedQuotaSource, CompositeQuotaSource, GenericErrorParser, ClaudeCodeErrorParser, getErrorParserForProvider, } from "@audit-tools/shared";
3
+ // Auditor-specific: local scheduler, probe, discovered limits, header extraction
4
4
  export { scheduleWave, buildProviderModelKey } from "./scheduler.js";
5
- export { detectRateLimitError, computeCooldownUntil } from "./errorParsing.js";
6
- export { acquireLock, releaseLock, withFileLock, FileLockTimeoutError } from "./fileLock.js";
7
- export { runSlidingWindow } from "./slidingWindow.js";
5
+ export { detectHostActiveSubagentLimit, resolveHostActiveSubagentLimit, } from "./hostLimits.js";
8
6
  export { probeProvider } from "./probe.js";
9
- export { GenericErrorParser, ClaudeCodeErrorParser, getErrorParserForProvider } from "./errorParsers/index.js";
10
- export { LearnedQuotaSource } from "./learnedQuotaSource.js";
11
- export { CompositeQuotaSource } from "./compositeQuotaSource.js";
12
7
  export { lookupDiscoveredLimits, updateDiscoveredLimits, mergeDiscoveredLimits, readDiscoveredLimitsCache, writeDiscoveredLimitsCache, } from "./discoveredLimits.js";
13
8
  export { extractRateLimitHeaders } from "./headerExtraction.js";
14
9
  export { GenericHeaderExtractor, ClaudeCodeHeaderExtractor, getHeaderExtractorForProvider } from "./headerExtractors/index.js";
@@ -1,6 +1,4 @@
1
- import type { ResolvedProviderName, SessionConfig } from "../types/sessionConfig.js";
2
- import type { HostConcurrencyLimit, QuotaStateEntry, WaveSchedule } from "./types.js";
3
- import type { QuotaUsageSnapshot } from "./quotaSource.js";
1
+ import type { ResolvedProviderName, SessionConfig, HostConcurrencyLimit, QuotaStateEntry, WaveSchedule, QuotaUsageSnapshot } from "@audit-tools/shared";
4
2
  import type { DiscoveredRateLimits } from "./discoveredLimits.js";
5
3
  export interface ScheduleWaveOptions {
6
4
  providerName: ResolvedProviderName;
@@ -1,5 +1,4 @@
1
- import { classifyProvider, resolveLimits } from "./limits.js";
2
- import { computeMaxSafeConcurrency, computeRampUpConcurrency } from "./state.js";
1
+ import { classifyProvider, resolveLimits, computeMaxSafeConcurrency, computeRampUpConcurrency } from "@audit-tools/shared";
3
2
  function sumTopN(sorted, n) {
4
3
  let sum = 0;
5
4
  for (let i = 0; i < Math.min(n, sorted.length); i++)
@@ -1,10 +1,26 @@
1
1
  import type { AuditResult, CoverageMatrix, Finding, UnitManifest } from "../types.js";
2
+ import type { AuditScopeManifest } from "../types/auditScope.js";
2
3
  import type { DesignAssessment } from "../types/designAssessment.js";
3
4
  import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
4
- import type { CriticalFlowManifest } from "../types/flows.js";
5
- import type { GraphBundle } from "../types/graph.js";
5
+ import type { AuditFindingsReport, CriticalFlowManifest, Finding as SharedFinding, FindingTheme, GraphBundle, SynthesisNarrative } from "@audit-tools/shared";
6
6
  import type { RuntimeValidationReport } from "../types/runtimeValidation.js";
7
7
  import { type WorkBlock } from "./workBlocks.js";
8
+ /** Contract version stamped onto the canonical `audit-findings.json`. */
9
+ export declare const AUDIT_FINDINGS_CONTRACT_VERSION = "audit-tools/audit-findings/v1";
10
+ /**
11
+ * Anything renderable as the deterministic audit report. Both `AuditReportModel`
12
+ * (no narrative) and the canonical `AuditFindingsReport` (optionally carrying
13
+ * themes/executive_summary/top_risks) satisfy this shape, so the same renderer
14
+ * produces the base report and the narrative-enriched report.
15
+ */
16
+ export interface RenderableAuditReport {
17
+ summary: AuditReportSummary;
18
+ findings: SharedFinding[];
19
+ work_blocks: WorkBlock[];
20
+ themes?: FindingTheme[];
21
+ executive_summary?: string;
22
+ top_risks?: string[];
23
+ }
8
24
  export interface AuditReportSummary {
9
25
  finding_count: number;
10
26
  work_block_count: number;
@@ -28,4 +44,22 @@ export declare function buildAuditReportModel(params: {
28
44
  externalAnalyzerResults?: ExternalAnalyzerResults;
29
45
  designAssessment?: DesignAssessment;
30
46
  }): AuditReportModel;
31
- export declare function renderAuditReportMarkdown(model: AuditReportModel): string;
47
+ /**
48
+ * Wrap the deterministic report model in the canonical `audit-findings.json`
49
+ * contract — the machine hand-off consumed by the remediator. Narrative fields
50
+ * are absent here; they are layered on later by {@link applyNarrative}.
51
+ */
52
+ export declare function buildAuditFindingsReport(model: AuditReportModel): AuditFindingsReport;
53
+ /**
54
+ * Merge an LLM synthesis narrative into the canonical findings report: keep only
55
+ * themes whose `finding_ids` reference real findings, tag each covered finding
56
+ * with its (first-claiming) `theme_id`, and attach the executive summary / top
57
+ * risks. Deterministic and idempotent — the same narrative yields the same
58
+ * report.
59
+ */
60
+ export declare function applyNarrative(report: AuditFindingsReport, narrative: SynthesisNarrative): AuditFindingsReport;
61
+ export interface RenderAuditReportOptions {
62
+ /** Scope manifest for the run; when delta, the report header reports it honestly. */
63
+ scope?: AuditScopeManifest;
64
+ }
65
+ export declare function renderAuditReportMarkdown(report: RenderableAuditReport, options?: RenderAuditReportOptions): string;
@@ -1,5 +1,8 @@
1
+ import { AUDITOR_REPORT_MARKER } from "@audit-tools/shared";
1
2
  import { buildWorkBlocks } from "./workBlocks.js";
2
3
  import { mergeFindings } from "./mergeFindings.js";
4
+ /** Contract version stamped onto the canonical `audit-findings.json`. */
5
+ export const AUDIT_FINDINGS_CONTRACT_VERSION = "audit-tools/audit-findings/v1";
3
6
  function countBy(items, selectKey) {
4
7
  const breakdown = {};
5
8
  for (const item of items) {
@@ -53,26 +56,92 @@ export function buildAuditReportModel(params) {
53
56
  work_blocks: workBlocks,
54
57
  };
55
58
  }
56
- export function renderAuditReportMarkdown(model) {
59
+ /**
60
+ * Wrap the deterministic report model in the canonical `audit-findings.json`
61
+ * contract — the machine hand-off consumed by the remediator. Narrative fields
62
+ * are absent here; they are layered on later by {@link applyNarrative}.
63
+ */
64
+ export function buildAuditFindingsReport(model) {
65
+ return {
66
+ contract_version: AUDIT_FINDINGS_CONTRACT_VERSION,
67
+ summary: { ...model.summary },
68
+ findings: model.findings,
69
+ work_blocks: model.work_blocks,
70
+ };
71
+ }
72
+ /**
73
+ * Merge an LLM synthesis narrative into the canonical findings report: keep only
74
+ * themes whose `finding_ids` reference real findings, tag each covered finding
75
+ * with its (first-claiming) `theme_id`, and attach the executive summary / top
76
+ * risks. Deterministic and idempotent — the same narrative yields the same
77
+ * report.
78
+ */
79
+ export function applyNarrative(report, narrative) {
80
+ const validFindingIds = new Set(report.findings.map((finding) => finding.id));
81
+ const themeByFinding = new Map();
82
+ const themes = [];
83
+ for (const theme of narrative.themes ?? []) {
84
+ const findingIds = [
85
+ ...new Set((theme.finding_ids ?? []).filter((id) => validFindingIds.has(id))),
86
+ ];
87
+ themes.push({
88
+ theme_id: theme.theme_id,
89
+ title: theme.title,
90
+ root_cause: theme.root_cause,
91
+ finding_ids: findingIds,
92
+ suggested_fix_pattern: theme.suggested_fix_pattern,
93
+ });
94
+ for (const id of findingIds) {
95
+ if (!themeByFinding.has(id)) {
96
+ themeByFinding.set(id, theme.theme_id);
97
+ }
98
+ }
99
+ }
100
+ const findings = report.findings.map((finding) => themeByFinding.has(finding.id)
101
+ ? { ...finding, theme_id: themeByFinding.get(finding.id) }
102
+ : finding);
103
+ return {
104
+ ...report,
105
+ findings,
106
+ themes,
107
+ executive_summary: narrative.executive_summary,
108
+ top_risks: narrative.top_risks,
109
+ };
110
+ }
111
+ export function renderAuditReportMarkdown(report, options = {}) {
57
112
  const lines = [
113
+ AUDITOR_REPORT_MARKER,
58
114
  "# Audit Report",
59
115
  "",
60
- "## Summary",
61
- "",
62
- `- Findings: ${model.summary.finding_count}`,
63
- `- Work blocks: ${model.summary.work_block_count}`,
64
- `- Severity breakdown: ${formatSeverityList(model.summary.severity_breakdown)}`,
65
- `- Fully audited files: ${model.summary.audited_file_count}`,
66
- `- Excluded non-auditable files: ${model.summary.excluded_file_count}`,
67
- "",
68
- "## Work Blocks",
69
- "",
70
116
  ];
71
- if (model.work_blocks.length === 0) {
117
+ if (report.executive_summary && report.executive_summary.trim().length > 0) {
118
+ lines.push("## Executive Summary", "", report.executive_summary.trim(), "");
119
+ }
120
+ lines.push("## Summary", "", `- Findings: ${report.summary.finding_count}`, `- Work blocks: ${report.summary.work_block_count}`, `- Severity breakdown: ${formatSeverityList(report.summary.severity_breakdown)}`, `- Fully audited files: ${report.summary.audited_file_count}`, `- Excluded non-auditable files: ${report.summary.excluded_file_count}`, "");
121
+ if (report.top_risks && report.top_risks.length > 0) {
122
+ lines.push("## Top Risks", "");
123
+ for (const risk of report.top_risks) {
124
+ lines.push(`- ${risk}`);
125
+ }
126
+ lines.push("");
127
+ }
128
+ if (report.themes && report.themes.length > 0) {
129
+ lines.push("## Themes", "");
130
+ for (const theme of report.themes) {
131
+ lines.push(`### ${theme.theme_id} — ${theme.title}`);
132
+ lines.push("");
133
+ lines.push(`- Root cause: ${theme.root_cause}`);
134
+ lines.push(`- Findings: ${theme.finding_ids.length > 0 ? theme.finding_ids.join(", ") : "none"}`);
135
+ lines.push(`- Suggested fix pattern: ${theme.suggested_fix_pattern}`);
136
+ lines.push("");
137
+ }
138
+ }
139
+ lines.push("## Work Blocks", "");
140
+ if (report.work_blocks.length === 0) {
72
141
  lines.push("No remediation work blocks were generated.", "");
73
142
  }
74
143
  else {
75
- for (const block of model.work_blocks) {
144
+ for (const block of report.work_blocks) {
76
145
  lines.push(`### ${block.id}`);
77
146
  lines.push("");
78
147
  lines.push(`- Max severity: ${block.max_severity}`);
@@ -85,16 +154,19 @@ export function renderAuditReportMarkdown(model) {
85
154
  }
86
155
  }
87
156
  lines.push("## Findings", "");
88
- if (model.findings.length === 0) {
157
+ if (report.findings.length === 0) {
89
158
  lines.push("No findings were recorded.", "");
90
159
  }
91
160
  else {
92
- for (const finding of model.findings) {
161
+ for (const finding of report.findings) {
93
162
  lines.push(`### ${finding.id} — ${finding.title}`);
94
163
  lines.push("");
95
164
  lines.push(`- Severity: ${finding.severity}`);
96
165
  lines.push(`- Confidence: ${finding.confidence}`);
97
166
  lines.push(`- Lens: ${finding.lens}`);
167
+ if (finding.theme_id) {
168
+ lines.push(`- Theme: ${finding.theme_id}`);
169
+ }
98
170
  lines.push(`- Files: ${finding.affected_files.map((file) => file.path).join(", ")}`);
99
171
  lines.push(`- Summary: ${finding.summary}`);
100
172
  if (finding.evidence && finding.evidence.length > 0) {
@@ -107,7 +179,16 @@ export function renderAuditReportMarkdown(model) {
107
179
  }
108
180
  }
109
181
  lines.push("## Scope and Coverage", "");
110
- lines.push("This report is deterministic output from the completed audit. Non-auditable files were excluded from scope before task generation.");
182
+ const scope = options.scope;
183
+ if (scope && scope.mode === "delta") {
184
+ lines.push(`**Delta audit since \`${scope.since}\`.** This run audited ${scope.seed_files.length} changed file(s) and ${scope.expanded_files.length} graph neighbour(s); all other auditable files were left out of scope (inherited from a prior audit where complete, otherwise excluded from this run). **A full audit is advised before release.**`);
185
+ if (scope.dropped_note) {
186
+ lines.push("", scope.dropped_note);
187
+ }
188
+ }
189
+ else {
190
+ lines.push("This report is deterministic output from the completed audit. Non-auditable files were excluded from scope before task generation.");
191
+ }
111
192
  lines.push("");
112
193
  return lines.join("\n");
113
194
  }
@@ -0,0 +1,7 @@
1
+ import type { AuditFindingsReport } from "@audit-tools/shared";
2
+ /**
3
+ * Prompt for the optional synthesis-narrative pass. The host groups the
4
+ * already-finalized deterministic findings into root-cause themes and writes a
5
+ * `SynthesisNarrative` JSON document — it does not re-audit or invent findings.
6
+ */
7
+ export declare function renderSynthesisNarrativePrompt(report: AuditFindingsReport): string;
@@ -0,0 +1,60 @@
1
+ const MAX_RENDERED_FINDINGS = 120;
2
+ function summarizeFinding(finding) {
3
+ const files = finding.affected_files
4
+ .map((file) => file.path)
5
+ .slice(0, 4)
6
+ .join(", ");
7
+ return `- ${finding.id} [${finding.severity}/${finding.lens}] ${finding.title} — ${finding.summary}${files ? ` (files: ${files})` : ""}`;
8
+ }
9
+ /**
10
+ * Prompt for the optional synthesis-narrative pass. The host groups the
11
+ * already-finalized deterministic findings into root-cause themes and writes a
12
+ * `SynthesisNarrative` JSON document — it does not re-audit or invent findings.
13
+ */
14
+ export function renderSynthesisNarrativePrompt(report) {
15
+ const findings = report.findings;
16
+ const rendered = findings.slice(0, MAX_RENDERED_FINDINGS).map(summarizeFinding);
17
+ const overflowNote = findings.length > MAX_RENDERED_FINDINGS
18
+ ? [` ... and ${findings.length - MAX_RENDERED_FINDINGS} more findings (see audit-findings.json).`]
19
+ : [];
20
+ return [
21
+ "# Synthesis narrative",
22
+ "",
23
+ "The deterministic audit is complete. Your job is to add an interpretive narrative on top of the finalized findings — group them into a small number of root-cause themes, write a short executive summary, and list the top risks.",
24
+ "",
25
+ "Do not re-audit the code, change severities, or invent new findings. Use only the findings below; reference them by their exact `id`.",
26
+ "",
27
+ "## Summary",
28
+ "",
29
+ `- Findings: ${report.summary.finding_count}`,
30
+ `- Work blocks: ${report.summary.work_block_count}`,
31
+ "",
32
+ "## Findings",
33
+ "",
34
+ ...(rendered.length > 0 ? rendered : ["- (no findings were recorded)"]),
35
+ ...overflowNote,
36
+ "",
37
+ "## Output format",
38
+ "",
39
+ "Write a single JSON object conforming to:",
40
+ "",
41
+ "```json",
42
+ "{",
43
+ ' "themes": [',
44
+ " {",
45
+ ' "theme_id": "T-001",',
46
+ ' "title": "short root-cause title",',
47
+ ' "root_cause": "what underlying cause ties these findings together",',
48
+ ' "finding_ids": ["<finding id>", "..."],',
49
+ ' "suggested_fix_pattern": "the shared remediation approach for this theme"',
50
+ " }",
51
+ " ],",
52
+ ' "executive_summary": "2-4 sentence overview of the audit outcome",',
53
+ ' "top_risks": ["highest-impact risk", "..."]',
54
+ "}",
55
+ "```",
56
+ "",
57
+ "Prefer a handful of substantive themes over many thin ones. Every `finding_ids` entry must be an id listed above; unknown ids are dropped. A finding may belong to at most one theme.",
58
+ "",
59
+ ].join("\n");
60
+ }
@@ -1,15 +1,6 @@
1
1
  import type { Finding, UnitManifest } from "../types.js";
2
- import type { CriticalFlowManifest } from "../types/flows.js";
3
- import type { GraphBundle } from "../types/graph.js";
4
- export interface WorkBlock {
5
- id: string;
6
- finding_ids: string[];
7
- unit_ids: string[];
8
- owned_files: string[];
9
- max_severity: Finding["severity"];
10
- rationale: string;
11
- depends_on: string[];
12
- }
2
+ import type { CriticalFlowManifest, GraphBundle, WorkBlock } from "@audit-tools/shared";
3
+ export type { WorkBlock } from "@audit-tools/shared";
13
4
  export declare function buildWorkBlocks(params: {
14
5
  findings: Finding[];
15
6
  unitManifest?: UnitManifest;
@@ -1,6 +1,6 @@
1
1
  import { mkdir, writeFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
- import { writeJsonFile } from "../io/json.js";
3
+ import { writeJsonFile } from "@audit-tools/shared";
4
4
  import { LOCAL_SUBPROCESS_PROVIDER_NAME } from "../providers/constants.js";
5
5
  export const CONFIG_ERROR_BLOCKER_PREFIX = "config-error:";
6
6
  const INCOMING_DIRNAME = "incoming";
@@ -1,3 +1,3 @@
1
- import { type RunLedger, type RunLedgerEntry } from "../types/runLedger.js";
1
+ import { type RunLedger, type RunLedgerEntry } from "@audit-tools/shared";
2
2
  export declare function loadRunLedger(artifactsDir: string): Promise<RunLedger>;
3
3
  export declare function appendRunLedgerEntry(artifactsDir: string, entry: RunLedgerEntry): Promise<void>;
@@ -1,8 +1,8 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { mkdir, open, rename, rm } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
- import { RUN_LEDGER_STATUSES, } from "../types/runLedger.js";
5
- import { isFileMissingError, readJsonFile, writeJsonFile } from "../io/json.js";
4
+ import { RUN_LEDGER_STATUSES, } from "@audit-tools/shared";
5
+ import { isFileMissingError, readJsonFile, writeJsonFile } from "@audit-tools/shared";
6
6
  const RUN_LEDGER_FILENAME = "run-ledger.json";
7
7
  const RUN_LEDGER_LOCK_FILENAME = "run-ledger.lock";
8
8
  const LOCK_RETRY_DELAY_MS = 20;
@@ -1,4 +1,11 @@
1
- import type { SessionConfig } from "../types/sessionConfig.js";
1
+ import { type AnalyzerSetting, type SessionConfig } from "@audit-tools/shared";
2
2
  export declare function getSessionConfigPath(artifactsDir: string): string;
3
3
  export declare function readSessionConfigFile(artifactsDir: string): Promise<unknown | undefined>;
4
4
  export declare function loadSessionConfig(artifactsDir: string): Promise<SessionConfig>;
5
+ /**
6
+ * Merge per-analyzer resolution decisions into `session-config.json`,
7
+ * preserving any unknown fields, validating, and persisting the result. Used by
8
+ * the conversation-first `analyzer_install` step to durably record the host's
9
+ * `{ephemeral|permanent|skip}` choices under `analyzers.<id>`.
10
+ */
11
+ export declare function persistAnalyzerSettings(artifactsDir: string, settings: Record<string, AnalyzerSetting>): Promise<SessionConfig>;
@@ -1,8 +1,6 @@
1
1
  import { join } from "node:path";
2
- import { readOptionalJsonFile } from "../io/json.js";
3
- import { formatValidationIssues, } from "../validation/basic.js";
2
+ import { isRecord, readOptionalJsonFile, writeJsonFile, formatValidationIssues, } from "@audit-tools/shared";
4
3
  import { validateSessionConfig } from "../validation/sessionConfig.js";
5
- import { writeJsonFile } from "../io/json.js";
6
4
  const SESSION_CONFIG_FILENAME = "session-config.json";
7
5
  const DEFAULT_SESSION_CONFIG = { provider: "local-subprocess" };
8
6
  export function getSessionConfigPath(artifactsDir) {
@@ -27,3 +25,24 @@ export async function loadSessionConfig(artifactsDir) {
27
25
  }
28
26
  return rawConfig;
29
27
  }
28
+ /**
29
+ * Merge per-analyzer resolution decisions into `session-config.json`,
30
+ * preserving any unknown fields, validating, and persisting the result. Used by
31
+ * the conversation-first `analyzer_install` step to durably record the host's
32
+ * `{ephemeral|permanent|skip}` choices under `analyzers.<id>`.
33
+ */
34
+ export async function persistAnalyzerSettings(artifactsDir, settings) {
35
+ const configPath = getSessionConfigPath(artifactsDir);
36
+ const raw = (await readOptionalJsonFile(configPath)) ?? {
37
+ ...DEFAULT_SESSION_CONFIG,
38
+ };
39
+ const base = isRecord(raw) ? raw : { ...DEFAULT_SESSION_CONFIG };
40
+ const current = isRecord(base.analyzers) ? base.analyzers : {};
41
+ const merged = { ...base, analyzers: { ...current, ...settings } };
42
+ const issues = validateSessionConfig(merged);
43
+ if (issues.length > 0) {
44
+ throw new Error(formatConfigValidationIssues(configPath, issues));
45
+ }
46
+ await writeJsonFile(configPath, merged);
47
+ return merged;
48
+ }
@@ -0,0 +1,16 @@
1
+ import type { AnalyzerSetting } from "@audit-tools/shared";
2
+ import type { AnalyzerResolution } from "../extractors/analyzers/types.js";
3
+ export type AnalyzerCapabilityStatus = "applied" | "omitted";
4
+ export interface AnalyzerCapabilityEntry {
5
+ id: string;
6
+ resolution: AnalyzerResolution;
7
+ setting: AnalyzerSetting;
8
+ edges_added: number;
9
+ routes_added: number;
10
+ note?: string;
11
+ }
12
+ export interface AnalyzerCapabilityRecord {
13
+ /** `applied` when ≥1 analyzer contributed edges/routes; `omitted` otherwise. */
14
+ status: AnalyzerCapabilityStatus;
15
+ analyzers: AnalyzerCapabilityEntry[];
16
+ }