auditor-lambda 0.1.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 (199) hide show
  1. package/README.md +173 -0
  2. package/audit-code-wrapper-lib.mjs +905 -0
  3. package/audit-code.mjs +13 -0
  4. package/dist/adapters/coverageSummary.d.ts +8 -0
  5. package/dist/adapters/coverageSummary.js +13 -0
  6. package/dist/adapters/eslint.d.ts +13 -0
  7. package/dist/adapters/eslint.js +21 -0
  8. package/dist/adapters/normalizeExternal.d.ts +12 -0
  9. package/dist/adapters/normalizeExternal.js +19 -0
  10. package/dist/adapters/npmAudit.d.ts +15 -0
  11. package/dist/adapters/npmAudit.js +12 -0
  12. package/dist/adapters/semgrep.d.ts +22 -0
  13. package/dist/adapters/semgrep.js +14 -0
  14. package/dist/cli.d.ts +1 -0
  15. package/dist/cli.js +724 -0
  16. package/dist/coverage.d.ts +11 -0
  17. package/dist/coverage.js +102 -0
  18. package/dist/extractors/bucketing.d.ts +7 -0
  19. package/dist/extractors/bucketing.js +72 -0
  20. package/dist/extractors/disposition.d.ts +4 -0
  21. package/dist/extractors/disposition.js +41 -0
  22. package/dist/extractors/fileInventory.d.ts +7 -0
  23. package/dist/extractors/fileInventory.js +44 -0
  24. package/dist/extractors/flows.d.ts +5 -0
  25. package/dist/extractors/flows.js +125 -0
  26. package/dist/extractors/fsIntake.d.ts +8 -0
  27. package/dist/extractors/fsIntake.js +66 -0
  28. package/dist/extractors/graph.d.ts +4 -0
  29. package/dist/extractors/graph.js +46 -0
  30. package/dist/extractors/ignore.d.ts +1 -0
  31. package/dist/extractors/ignore.js +17 -0
  32. package/dist/extractors/risk.d.ts +5 -0
  33. package/dist/extractors/risk.js +45 -0
  34. package/dist/extractors/surfaces.d.ts +4 -0
  35. package/dist/extractors/surfaces.js +40 -0
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.js +1 -0
  38. package/dist/io/artifacts.d.ts +38 -0
  39. package/dist/io/artifacts.js +100 -0
  40. package/dist/io/json.d.ts +8 -0
  41. package/dist/io/json.js +96 -0
  42. package/dist/io/runArtifacts.d.ts +14 -0
  43. package/dist/io/runArtifacts.js +37 -0
  44. package/dist/orchestrator/advance.d.ts +24 -0
  45. package/dist/orchestrator/advance.js +104 -0
  46. package/dist/orchestrator/artifactMetadata.d.ts +4 -0
  47. package/dist/orchestrator/artifactMetadata.js +111 -0
  48. package/dist/orchestrator/autoFixExecutor.d.ts +3 -0
  49. package/dist/orchestrator/autoFixExecutor.js +63 -0
  50. package/dist/orchestrator/chunking.d.ts +5 -0
  51. package/dist/orchestrator/chunking.js +13 -0
  52. package/dist/orchestrator/dependencyMap.d.ts +1 -0
  53. package/dist/orchestrator/dependencyMap.js +82 -0
  54. package/dist/orchestrator/executors.d.ts +6 -0
  55. package/dist/orchestrator/executors.js +52 -0
  56. package/dist/orchestrator/flowCoverage.d.ts +4 -0
  57. package/dist/orchestrator/flowCoverage.js +44 -0
  58. package/dist/orchestrator/flowPlanning.d.ts +3 -0
  59. package/dist/orchestrator/flowPlanning.js +42 -0
  60. package/dist/orchestrator/flowRequeue.d.ts +5 -0
  61. package/dist/orchestrator/flowRequeue.js +58 -0
  62. package/dist/orchestrator/internalExecutors.d.ts +16 -0
  63. package/dist/orchestrator/internalExecutors.js +212 -0
  64. package/dist/orchestrator/nextStep.d.ts +9 -0
  65. package/dist/orchestrator/nextStep.js +44 -0
  66. package/dist/orchestrator/planning.d.ts +4 -0
  67. package/dist/orchestrator/planning.js +62 -0
  68. package/dist/orchestrator/requeue.d.ts +3 -0
  69. package/dist/orchestrator/requeue.js +25 -0
  70. package/dist/orchestrator/requeueCommand.d.ts +10 -0
  71. package/dist/orchestrator/requeueCommand.js +27 -0
  72. package/dist/orchestrator/resultIngestion.d.ts +2 -0
  73. package/dist/orchestrator/resultIngestion.js +13 -0
  74. package/dist/orchestrator/runtimeValidation.d.ts +7 -0
  75. package/dist/orchestrator/runtimeValidation.js +103 -0
  76. package/dist/orchestrator/runtimeValidationUpdate.d.ts +2 -0
  77. package/dist/orchestrator/runtimeValidationUpdate.js +52 -0
  78. package/dist/orchestrator/staleness.d.ts +2 -0
  79. package/dist/orchestrator/staleness.js +83 -0
  80. package/dist/orchestrator/state.d.ts +3 -0
  81. package/dist/orchestrator/state.js +85 -0
  82. package/dist/orchestrator/syntaxResolutionExecutor.d.ts +3 -0
  83. package/dist/orchestrator/syntaxResolutionExecutor.js +99 -0
  84. package/dist/orchestrator/taskBuilder.d.ts +12 -0
  85. package/dist/orchestrator/taskBuilder.js +154 -0
  86. package/dist/orchestrator/unitBuilder.d.ts +3 -0
  87. package/dist/orchestrator/unitBuilder.js +145 -0
  88. package/dist/orchestrator.d.ts +6 -0
  89. package/dist/orchestrator.js +33 -0
  90. package/dist/prompts/renderWorkerPrompt.d.ts +2 -0
  91. package/dist/prompts/renderWorkerPrompt.js +19 -0
  92. package/dist/providers/claudeCodeProvider.d.ts +8 -0
  93. package/dist/providers/claudeCodeProvider.js +20 -0
  94. package/dist/providers/index.d.ts +7 -0
  95. package/dist/providers/index.js +77 -0
  96. package/dist/providers/localSubprocessProvider.d.ts +5 -0
  97. package/dist/providers/localSubprocessProvider.js +13 -0
  98. package/dist/providers/opencodeProvider.d.ts +8 -0
  99. package/dist/providers/opencodeProvider.js +15 -0
  100. package/dist/providers/spawnLoggedCommand.d.ts +2 -0
  101. package/dist/providers/spawnLoggedCommand.js +48 -0
  102. package/dist/providers/subprocessTemplateProvider.d.ts +8 -0
  103. package/dist/providers/subprocessTemplateProvider.js +41 -0
  104. package/dist/providers/types.d.ts +22 -0
  105. package/dist/providers/types.js +1 -0
  106. package/dist/providers/vscodeTaskProvider.d.ts +8 -0
  107. package/dist/providers/vscodeTaskProvider.js +14 -0
  108. package/dist/reporting/mergeFindings.d.ts +4 -0
  109. package/dist/reporting/mergeFindings.js +136 -0
  110. package/dist/reporting/rootCause.d.ts +11 -0
  111. package/dist/reporting/rootCause.js +69 -0
  112. package/dist/reporting/synthesis.d.ts +21 -0
  113. package/dist/reporting/synthesis.js +55 -0
  114. package/dist/supervisor/operatorHandoff.d.ts +37 -0
  115. package/dist/supervisor/operatorHandoff.js +144 -0
  116. package/dist/supervisor/runLedger.d.ts +3 -0
  117. package/dist/supervisor/runLedger.js +17 -0
  118. package/dist/supervisor/sessionConfig.d.ts +4 -0
  119. package/dist/supervisor/sessionConfig.js +26 -0
  120. package/dist/types/artifactMetadata.d.ts +8 -0
  121. package/dist/types/artifactMetadata.js +1 -0
  122. package/dist/types/auditState.d.ts +14 -0
  123. package/dist/types/auditState.js +1 -0
  124. package/dist/types/disposition.d.ts +9 -0
  125. package/dist/types/disposition.js +1 -0
  126. package/dist/types/externalAnalyzer.d.ts +16 -0
  127. package/dist/types/externalAnalyzer.js +1 -0
  128. package/dist/types/flowCoverage.d.ts +11 -0
  129. package/dist/types/flowCoverage.js +1 -0
  130. package/dist/types/flows.d.ts +11 -0
  131. package/dist/types/flows.js +1 -0
  132. package/dist/types/graph.d.ts +18 -0
  133. package/dist/types/graph.js +1 -0
  134. package/dist/types/risk.d.ts +9 -0
  135. package/dist/types/risk.js +1 -0
  136. package/dist/types/runLedger.d.ts +13 -0
  137. package/dist/types/runLedger.js +1 -0
  138. package/dist/types/runtimeValidation.d.ts +22 -0
  139. package/dist/types/runtimeValidation.js +1 -0
  140. package/dist/types/sessionConfig.d.ts +27 -0
  141. package/dist/types/sessionConfig.js +1 -0
  142. package/dist/types/surfaces.d.ts +11 -0
  143. package/dist/types/surfaces.js +1 -0
  144. package/dist/types/workerResult.d.ts +13 -0
  145. package/dist/types/workerResult.js +1 -0
  146. package/dist/types/workerSession.d.ts +13 -0
  147. package/dist/types/workerSession.js +1 -0
  148. package/dist/types.d.ts +104 -0
  149. package/dist/types.js +1 -0
  150. package/dist/validation/artifacts.d.ts +3 -0
  151. package/dist/validation/artifacts.js +191 -0
  152. package/dist/validation/basic.d.ts +5 -0
  153. package/dist/validation/basic.js +9 -0
  154. package/dist/validation/sessionConfig.d.ts +6 -0
  155. package/dist/validation/sessionConfig.js +139 -0
  156. package/docs/agent-integrations.md +237 -0
  157. package/docs/agent-roles.md +69 -0
  158. package/docs/architecture.md +90 -0
  159. package/docs/artifacts.md +69 -0
  160. package/docs/bootstrap-install.md +79 -0
  161. package/docs/contract.md +140 -0
  162. package/docs/github-copilot.md +50 -0
  163. package/docs/model-selection.md +86 -0
  164. package/docs/next-steps.md +161 -0
  165. package/docs/packaging.md +88 -0
  166. package/docs/pipeline.md +152 -0
  167. package/docs/product-direction.md +111 -0
  168. package/docs/production-launch-bar.md +83 -0
  169. package/docs/production-readiness.md +52 -0
  170. package/docs/repo-layout.md +30 -0
  171. package/docs/run-flow.md +49 -0
  172. package/docs/session-config.md +232 -0
  173. package/docs/supervisor.md +83 -0
  174. package/docs/usage.md +172 -0
  175. package/docs/windows-setup.md +146 -0
  176. package/package.json +56 -0
  177. package/schemas/audit-code-v1alpha1.schema.json +191 -0
  178. package/schemas/audit_result.schema.json +48 -0
  179. package/schemas/audit_state.schema.json +36 -0
  180. package/schemas/audit_task.schema.json +49 -0
  181. package/schemas/blind_spot_register.schema.json +40 -0
  182. package/schemas/coverage_matrix.schema.json +50 -0
  183. package/schemas/critical_flows.schema.json +38 -0
  184. package/schemas/external_analyzer_results.schema.json +31 -0
  185. package/schemas/file_disposition.schema.json +33 -0
  186. package/schemas/finding.schema.json +62 -0
  187. package/schemas/flow_coverage.schema.json +44 -0
  188. package/schemas/graph_bundle.schema.json +55 -0
  189. package/schemas/merged_findings.schema.json +14 -0
  190. package/schemas/repo_manifest.schema.json +37 -0
  191. package/schemas/risk_register.schema.json +30 -0
  192. package/schemas/root_cause_clusters.schema.json +31 -0
  193. package/schemas/runtime_validation_report.schema.json +34 -0
  194. package/schemas/runtime_validation_tasks.schema.json +36 -0
  195. package/schemas/surface_manifest.schema.json +32 -0
  196. package/schemas/synthesis_report.schema.json +61 -0
  197. package/schemas/unit_manifest.schema.json +36 -0
  198. package/skills/audit-code/SKILL.md +54 -0
  199. package/skills/audit-code/audit-code.prompt.md +66 -0
@@ -0,0 +1,8 @@
1
+ import type { FreshSessionProvider, LaunchFreshSessionInput } from "./types.js";
2
+ import type { VSCodeTaskConfig } from "../types/sessionConfig.js";
3
+ export declare class VSCodeTaskProvider implements FreshSessionProvider {
4
+ name: string;
5
+ private readonly delegate;
6
+ constructor(config: VSCodeTaskConfig);
7
+ launch(input: LaunchFreshSessionInput): Promise<import("./types.js").LaunchFreshSessionResult>;
8
+ }
@@ -0,0 +1,14 @@
1
+ import { SubprocessTemplateProvider } from "./subprocessTemplateProvider.js";
2
+ export class VSCodeTaskProvider {
3
+ name = "vscode-task";
4
+ delegate;
5
+ constructor(config) {
6
+ this.delegate = new SubprocessTemplateProvider({
7
+ command_template: config.command_template,
8
+ env: config.env,
9
+ }, "vscode-task");
10
+ }
11
+ async launch(input) {
12
+ return await this.delegate.launch(input);
13
+ }
14
+ }
@@ -0,0 +1,4 @@
1
+ import type { AuditResult, Finding } from "../types.js";
2
+ import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
3
+ import type { RuntimeValidationReport } from "../types/runtimeValidation.js";
4
+ export declare function mergeFindings(results: AuditResult[], runtimeReport?: RuntimeValidationReport, externalAnalyzerResults?: ExternalAnalyzerResults): Finding[];
@@ -0,0 +1,136 @@
1
+ function normalizeText(value) {
2
+ return (value ?? "").trim().toLowerCase();
3
+ }
4
+ function primaryPath(finding) {
5
+ return finding.affected_files[0]?.path ?? "";
6
+ }
7
+ function findingKey(finding) {
8
+ return [
9
+ normalizeText(finding.lens),
10
+ normalizeText(finding.category),
11
+ normalizeText(finding.title),
12
+ primaryPath(finding),
13
+ String(finding.affected_files[0]?.line_start ?? ""),
14
+ String(finding.affected_files[0]?.line_end ?? ""),
15
+ ].join("|");
16
+ }
17
+ function severityRank(severity) {
18
+ switch (severity) {
19
+ case "critical":
20
+ return 5;
21
+ case "high":
22
+ return 4;
23
+ case "medium":
24
+ return 3;
25
+ case "low":
26
+ return 2;
27
+ case "info":
28
+ return 1;
29
+ }
30
+ }
31
+ function confidenceRank(confidence) {
32
+ switch (confidence) {
33
+ case "high":
34
+ return 3;
35
+ case "medium":
36
+ return 2;
37
+ case "low":
38
+ return 1;
39
+ }
40
+ }
41
+ function runtimeSummary(report) {
42
+ if (!report) {
43
+ return [];
44
+ }
45
+ return report.results.map((result) => `${result.task_id}: ${result.status} — ${result.summary}`);
46
+ }
47
+ function externalSummary(results) {
48
+ if (!results) {
49
+ return [];
50
+ }
51
+ return results.results.map((item) => `external:${results.tool}:${item.path}:${item.summary}`);
52
+ }
53
+ function mergeAffectedFiles(existing, incoming) {
54
+ const seen = new Set(existing.affected_files.map((f) => `${f.path}:${f.line_start ?? ""}:${f.line_end ?? ""}:${f.symbol ?? ""}`));
55
+ for (const file of incoming.affected_files) {
56
+ const key = `${file.path}:${file.line_start ?? ""}:${file.line_end ?? ""}:${file.symbol ?? ""}`;
57
+ if (!seen.has(key)) {
58
+ existing.affected_files.push(file);
59
+ seen.add(key);
60
+ }
61
+ }
62
+ existing.affected_files.sort((a, b) => a.path.localeCompare(b.path) || (a.line_start ?? 0) - (b.line_start ?? 0));
63
+ }
64
+ export function mergeFindings(results, runtimeReport, externalAnalyzerResults) {
65
+ const merged = new Map();
66
+ const runtimeEvidence = runtimeSummary(runtimeReport);
67
+ const analyzerEvidence = externalSummary(externalAnalyzerResults);
68
+ for (const result of results) {
69
+ for (const finding of result.findings) {
70
+ const key = findingKey(finding);
71
+ const existing = merged.get(key);
72
+ if (!existing) {
73
+ merged.set(key, {
74
+ ...finding,
75
+ affected_files: [...finding.affected_files],
76
+ evidence: [
77
+ ...new Set([
78
+ ...(finding.evidence ?? []),
79
+ ...runtimeEvidence,
80
+ ...analyzerEvidence,
81
+ ]),
82
+ ],
83
+ remediation: [...new Set(finding.remediation ?? [])],
84
+ related_findings: [
85
+ ...new Set([...(finding.related_findings ?? []), finding.id]),
86
+ ],
87
+ });
88
+ continue;
89
+ }
90
+ if (severityRank(finding.severity) > severityRank(existing.severity)) {
91
+ existing.severity = finding.severity;
92
+ }
93
+ if (confidenceRank(finding.confidence) > confidenceRank(existing.confidence)) {
94
+ existing.confidence = finding.confidence;
95
+ }
96
+ existing.systemic = Boolean(existing.systemic || finding.systemic);
97
+ existing.impact = existing.impact ?? finding.impact;
98
+ existing.likelihood = existing.likelihood ?? finding.likelihood;
99
+ existing.summary =
100
+ existing.summary.length >= finding.summary.length
101
+ ? existing.summary
102
+ : finding.summary;
103
+ mergeAffectedFiles(existing, finding);
104
+ existing.evidence = [
105
+ ...new Set([
106
+ ...(existing.evidence ?? []),
107
+ ...(finding.evidence ?? []),
108
+ ...runtimeEvidence,
109
+ ...analyzerEvidence,
110
+ ]),
111
+ ];
112
+ existing.remediation = [
113
+ ...new Set([
114
+ ...(existing.remediation ?? []),
115
+ ...(finding.remediation ?? []),
116
+ ]),
117
+ ];
118
+ existing.related_findings = [
119
+ ...new Set([
120
+ ...(existing.related_findings ?? []),
121
+ ...(finding.related_findings ?? []),
122
+ finding.id,
123
+ ]),
124
+ ];
125
+ }
126
+ }
127
+ return [...merged.values()].sort((a, b) => {
128
+ const severityDelta = severityRank(b.severity) - severityRank(a.severity);
129
+ if (severityDelta !== 0)
130
+ return severityDelta;
131
+ const confidenceDelta = confidenceRank(b.confidence) - confidenceRank(a.confidence);
132
+ if (confidenceDelta !== 0)
133
+ return confidenceDelta;
134
+ return a.title.localeCompare(b.title);
135
+ });
136
+ }
@@ -0,0 +1,11 @@
1
+ import type { Finding } from "../types.js";
2
+ import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
3
+ import type { RuntimeValidationReport } from "../types/runtimeValidation.js";
4
+ export interface RootCauseCluster {
5
+ id: string;
6
+ title: string;
7
+ summary: string;
8
+ finding_ids: string[];
9
+ recommended_actions: string[];
10
+ }
11
+ export declare function buildRootCauseClusters(findings: Finding[], runtimeReport?: RuntimeValidationReport, externalAnalyzerResults?: ExternalAnalyzerResults): RootCauseCluster[];
@@ -0,0 +1,69 @@
1
+ function severityRank(severity) {
2
+ switch (severity) {
3
+ case "critical":
4
+ return 5;
5
+ case "high":
6
+ return 4;
7
+ case "medium":
8
+ return 3;
9
+ case "low":
10
+ return 2;
11
+ case "info":
12
+ return 1;
13
+ }
14
+ }
15
+ function summarizeRuntime(report) {
16
+ if (!report) {
17
+ return "No runtime validation evidence attached.";
18
+ }
19
+ const counts = new Map();
20
+ for (const result of report.results) {
21
+ counts.set(result.status, (counts.get(result.status) ?? 0) + 1);
22
+ }
23
+ return [...counts.entries()]
24
+ .map(([status, count]) => `${status}:${count}`)
25
+ .join(", ");
26
+ }
27
+ function summarizeExternal(results) {
28
+ if (!results)
29
+ return "No external analyzer signals attached.";
30
+ return `${results.tool}:${results.results.length}`;
31
+ }
32
+ function clusterKey(finding) {
33
+ const primaryPath = finding.affected_files[0]?.path ?? "";
34
+ const pathPrefix = primaryPath.split("/").slice(0, 2).join("/");
35
+ return `${finding.lens}:${finding.category}:${pathPrefix}`;
36
+ }
37
+ function titleForCluster(key) {
38
+ const [lens, category, scope] = key.split(":");
39
+ return `${lens}/${category}${scope ? ` in ${scope}` : ""}`;
40
+ }
41
+ export function buildRootCauseClusters(findings, runtimeReport, externalAnalyzerResults) {
42
+ const groups = new Map();
43
+ for (const finding of findings) {
44
+ const key = clusterKey(finding);
45
+ const existing = groups.get(key) ?? [];
46
+ existing.push(finding);
47
+ groups.set(key, existing);
48
+ }
49
+ const runtimeSummary = summarizeRuntime(runtimeReport);
50
+ const externalSummary = summarizeExternal(externalAnalyzerResults);
51
+ return [...groups.entries()]
52
+ .map(([key, grouped], index) => {
53
+ const highestSeverity = grouped.reduce((max, finding) => Math.max(max, severityRank(finding.severity)), 1);
54
+ const systemicCount = grouped.filter((finding) => finding.systemic).length;
55
+ const uniqueRemediations = [
56
+ ...new Set(grouped.flatMap((finding) => finding.remediation ?? [])),
57
+ ].slice(0, 5);
58
+ return {
59
+ id: `cluster-${index + 1}`,
60
+ title: titleForCluster(key),
61
+ summary: `Grouped ${grouped.length} finding(s); highest severity ${highestSeverity}; systemic flags ${systemicCount}. Runtime validation status: ${runtimeSummary}. External analyzer summary: ${externalSummary}.`,
62
+ finding_ids: grouped.map((finding) => finding.id),
63
+ recommended_actions: uniqueRemediations.length > 0
64
+ ? uniqueRemediations
65
+ : [`Review systemic causes behind ${titleForCluster(key)}.`],
66
+ };
67
+ })
68
+ .sort((a, b) => a.title.localeCompare(b.title));
69
+ }
@@ -0,0 +1,21 @@
1
+ import type { AuditResult } from "../types.js";
2
+ import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
3
+ import type { RuntimeValidationReport } from "../types/runtimeValidation.js";
4
+ import { mergeFindings } from "./mergeFindings.js";
5
+ import { buildRootCauseClusters } from "./rootCause.js";
6
+ export interface SynthesisReport {
7
+ summary: {
8
+ finding_count: number;
9
+ cluster_count: number;
10
+ runtime_validation_status_breakdown: Record<string, number>;
11
+ notes: string[];
12
+ severity_breakdown: Record<string, number>;
13
+ external_analyzer_summary: {
14
+ tool_count: number;
15
+ result_count: number;
16
+ };
17
+ };
18
+ merged_findings: ReturnType<typeof mergeFindings>;
19
+ root_cause_clusters: ReturnType<typeof buildRootCauseClusters>;
20
+ }
21
+ export declare function buildSynthesisReport(results: AuditResult[], runtimeReport?: RuntimeValidationReport, externalAnalyzerResults?: ExternalAnalyzerResults): SynthesisReport;
@@ -0,0 +1,55 @@
1
+ import { mergeFindings } from "./mergeFindings.js";
2
+ import { buildRootCauseClusters } from "./rootCause.js";
3
+ function statusBreakdown(report) {
4
+ const breakdown = {};
5
+ for (const result of report?.results ?? []) {
6
+ breakdown[result.status] = (breakdown[result.status] ?? 0) + 1;
7
+ }
8
+ return breakdown;
9
+ }
10
+ function severityBreakdown(findings) {
11
+ const breakdown = {};
12
+ for (const finding of findings) {
13
+ breakdown[finding.severity] = (breakdown[finding.severity] ?? 0) + 1;
14
+ }
15
+ return breakdown;
16
+ }
17
+ function externalSummary(results) {
18
+ if (!results) {
19
+ return { tool_count: 0, result_count: 0 };
20
+ }
21
+ return {
22
+ tool_count: results.tool ? 1 : 0,
23
+ result_count: results.results.length,
24
+ };
25
+ }
26
+ export function buildSynthesisReport(results, runtimeReport, externalAnalyzerResults) {
27
+ const merged_findings = mergeFindings(results, runtimeReport, externalAnalyzerResults);
28
+ const root_cause_clusters = buildRootCauseClusters(merged_findings, runtimeReport, externalAnalyzerResults);
29
+ const runtimeBreakdown = statusBreakdown(runtimeReport);
30
+ const sevBreakdown = severityBreakdown(merged_findings);
31
+ const extSummary = externalSummary(externalAnalyzerResults);
32
+ return {
33
+ summary: {
34
+ finding_count: merged_findings.length,
35
+ cluster_count: root_cause_clusters.length,
36
+ runtime_validation_status_breakdown: runtimeBreakdown,
37
+ severity_breakdown: sevBreakdown,
38
+ external_analyzer_summary: extSummary,
39
+ notes: [
40
+ ...(Object.keys(runtimeBreakdown).length === 0
41
+ ? ["No runtime validation evidence attached."]
42
+ : [
43
+ "Runtime validation evidence has been incorporated into synthesis.",
44
+ ]),
45
+ ...(extSummary.result_count > 0
46
+ ? [
47
+ `External analyzer signals incorporated: ${extSummary.result_count} result(s) from ${externalAnalyzerResults?.tool}.`,
48
+ ]
49
+ : []),
50
+ ],
51
+ },
52
+ merged_findings,
53
+ root_cause_clusters,
54
+ };
55
+ }
@@ -0,0 +1,37 @@
1
+ import type { ArtifactBundle } from "../io/artifacts.js";
2
+ import type { AuditState, AuditTopLevelStatus } from "../types/auditState.js";
3
+ export interface AuditCodeHandoffInput {
4
+ flag: "--results" | "--updates" | "--external-analyzer-results";
5
+ suggested_path: string;
6
+ description: string;
7
+ }
8
+ export interface AuditCodeHandoffArtifactPaths {
9
+ incoming_dir: string;
10
+ operator_handoff_json: string;
11
+ operator_handoff_markdown: string;
12
+ session_config: string;
13
+ run_ledger: string;
14
+ audit_tasks: string | null;
15
+ runtime_validation_tasks: string | null;
16
+ }
17
+ export interface AuditCodeHandoff {
18
+ status: AuditTopLevelStatus;
19
+ repo_root: string;
20
+ artifacts_dir: string;
21
+ provider: string | null;
22
+ summary: string;
23
+ pending_obligations: string[];
24
+ suggested_inputs: AuditCodeHandoffInput[];
25
+ suggested_commands: string[];
26
+ interactive_provider_hint: string | null;
27
+ artifact_paths: AuditCodeHandoffArtifactPaths;
28
+ }
29
+ export declare function buildAuditCodeHandoff(params: {
30
+ root: string;
31
+ artifactsDir: string;
32
+ state: AuditState;
33
+ bundle: ArtifactBundle;
34
+ providerName?: string | null;
35
+ progressSummary: string;
36
+ }): AuditCodeHandoff;
37
+ export declare function writeAuditCodeHandoffArtifacts(handoff: AuditCodeHandoff): Promise<void>;
@@ -0,0 +1,144 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { writeJsonFile } from "../io/json.js";
4
+ function quoteShellPath(path) {
5
+ return `"${path.replace(/"/g, '\\"')}"`;
6
+ }
7
+ function buildPendingObligations(state) {
8
+ return state.obligations
9
+ .filter((item) => item.state !== "satisfied" && item.state !== "present")
10
+ .map((item) => item.id);
11
+ }
12
+ function buildSummary(status, providerName, fallbackSummary) {
13
+ if (status === "complete") {
14
+ return "No operator handoff is required. All known obligations are currently satisfied.";
15
+ }
16
+ if (status === "blocked") {
17
+ return fallbackSummary;
18
+ }
19
+ if (status === "not_started") {
20
+ return "The artifact bundle is not initialized yet. Run the wrapper from the repository root to create the initial audit artifacts.";
21
+ }
22
+ return providerName
23
+ ? `Automatic work can continue under ${providerName}. Re-run the same wrapper or inspect the listed artifacts if you need operator context.`
24
+ : "Automatic work can continue. Re-run the same wrapper or inspect the listed artifacts if you need operator context.";
25
+ }
26
+ function buildSuggestedInputs(artifactsDir, status) {
27
+ if (status !== "blocked") {
28
+ return [];
29
+ }
30
+ const incomingDir = join(artifactsDir, "incoming");
31
+ return [
32
+ {
33
+ flag: "--results",
34
+ suggested_path: join(incomingDir, "audit-results.json"),
35
+ description: "Import structured audit-review results after manual or provider-assisted review finishes.",
36
+ },
37
+ {
38
+ flag: "--updates",
39
+ suggested_path: join(incomingDir, "runtime-validation-updates.json"),
40
+ description: "Merge runtime validation evidence updates gathered outside the wrapper.",
41
+ },
42
+ {
43
+ flag: "--external-analyzer-results",
44
+ suggested_path: join(incomingDir, "external-analyzer-results.json"),
45
+ description: "Import normalized external analyzer results such as Semgrep findings.",
46
+ },
47
+ ];
48
+ }
49
+ function buildSuggestedCommands(suggestedInputs, status) {
50
+ if (status !== "blocked") {
51
+ return [];
52
+ }
53
+ return suggestedInputs.map((item) => `audit-code ${item.flag} ${quoteShellPath(item.suggested_path)}`);
54
+ }
55
+ function buildInteractiveProviderHint(status, providerName, sessionConfigPath) {
56
+ if (status !== "blocked") {
57
+ return null;
58
+ }
59
+ const providerLabel = providerName ?? "local-subprocess";
60
+ return `Current provider is ${providerLabel}. If you want the backend to continue through an interactive provider instead of importing results manually, set "provider" in ${sessionConfigPath} to "auto", "claude-code", "opencode", "subprocess-template", or "vscode-task", then run audit-code again from the repository root.`;
61
+ }
62
+ function renderMarkdown(handoff) {
63
+ const lines = [
64
+ "# audit-code operator handoff",
65
+ "",
66
+ `Status: ${handoff.status}`,
67
+ `Provider: ${handoff.provider ?? "n/a"}`,
68
+ `Repo root: ${handoff.repo_root}`,
69
+ `Artifacts dir: ${handoff.artifacts_dir}`,
70
+ "",
71
+ `Summary: ${handoff.summary}`,
72
+ "",
73
+ "Pending obligations:",
74
+ ];
75
+ if (handoff.pending_obligations.length === 0) {
76
+ lines.push("- none");
77
+ }
78
+ else {
79
+ for (const obligation of handoff.pending_obligations) {
80
+ lines.push(`- ${obligation}`);
81
+ }
82
+ }
83
+ lines.push("", "Useful artifact paths:");
84
+ lines.push(`- operator handoff json: ${handoff.artifact_paths.operator_handoff_json}`);
85
+ lines.push(`- operator handoff markdown: ${handoff.artifact_paths.operator_handoff_markdown}`);
86
+ lines.push(`- incoming dir: ${handoff.artifact_paths.incoming_dir}`);
87
+ lines.push(`- session config: ${handoff.artifact_paths.session_config}`);
88
+ lines.push(`- run ledger: ${handoff.artifact_paths.run_ledger}`);
89
+ lines.push(`- audit tasks: ${handoff.artifact_paths.audit_tasks ?? "not available yet"}`);
90
+ lines.push(`- runtime validation tasks: ${handoff.artifact_paths.runtime_validation_tasks ?? "not available yet"}`);
91
+ if (handoff.suggested_inputs.length > 0) {
92
+ lines.push("", "Suggested evidence inputs:");
93
+ for (const item of handoff.suggested_inputs) {
94
+ lines.push(`- ${item.flag} -> ${item.suggested_path}`);
95
+ lines.push(` ${item.description}`);
96
+ }
97
+ }
98
+ if (handoff.suggested_commands.length > 0) {
99
+ lines.push("", "Suggested commands:");
100
+ for (const command of handoff.suggested_commands) {
101
+ lines.push(`- ${command}`);
102
+ }
103
+ }
104
+ if (handoff.interactive_provider_hint) {
105
+ lines.push("", "Interactive provider hint:");
106
+ lines.push(`- ${handoff.interactive_provider_hint}`);
107
+ }
108
+ lines.push("");
109
+ return lines.join("\n");
110
+ }
111
+ export function buildAuditCodeHandoff(params) {
112
+ const incomingDir = join(params.artifactsDir, "incoming");
113
+ const artifactPaths = {
114
+ incoming_dir: incomingDir,
115
+ operator_handoff_json: join(params.artifactsDir, "operator-handoff.json"),
116
+ operator_handoff_markdown: join(params.artifactsDir, "operator-handoff.md"),
117
+ session_config: join(params.artifactsDir, "session-config.json"),
118
+ run_ledger: join(params.artifactsDir, "run-ledger.json"),
119
+ audit_tasks: params.bundle.audit_tasks
120
+ ? join(params.artifactsDir, "audit_tasks.json")
121
+ : null,
122
+ runtime_validation_tasks: params.bundle.runtime_validation_tasks
123
+ ? join(params.artifactsDir, "runtime_validation_tasks.json")
124
+ : null,
125
+ };
126
+ const suggestedInputs = buildSuggestedInputs(params.artifactsDir, params.state.status);
127
+ return {
128
+ status: params.state.status,
129
+ repo_root: params.root,
130
+ artifacts_dir: params.artifactsDir,
131
+ provider: params.providerName ?? null,
132
+ summary: buildSummary(params.state.status, params.providerName ?? null, params.progressSummary),
133
+ pending_obligations: buildPendingObligations(params.state),
134
+ suggested_inputs: suggestedInputs,
135
+ suggested_commands: buildSuggestedCommands(suggestedInputs, params.state.status),
136
+ interactive_provider_hint: buildInteractiveProviderHint(params.state.status, params.providerName ?? null, artifactPaths.session_config),
137
+ artifact_paths: artifactPaths,
138
+ };
139
+ }
140
+ export async function writeAuditCodeHandoffArtifacts(handoff) {
141
+ await mkdir(handoff.artifact_paths.incoming_dir, { recursive: true });
142
+ await writeJsonFile(handoff.artifact_paths.operator_handoff_json, handoff);
143
+ await writeFile(handoff.artifact_paths.operator_handoff_markdown, renderMarkdown(handoff), "utf8");
144
+ }
@@ -0,0 +1,3 @@
1
+ import type { RunLedger, RunLedgerEntry } from "../types/runLedger.js";
2
+ export declare function loadRunLedger(artifactsDir: string): Promise<RunLedger>;
3
+ export declare function appendRunLedgerEntry(artifactsDir: string, entry: RunLedgerEntry): Promise<void>;
@@ -0,0 +1,17 @@
1
+ import { readJsonFile, writeJsonFile } from "../io/json.js";
2
+ function ledgerPath(artifactsDir) {
3
+ return `${artifactsDir}/run-ledger.json`;
4
+ }
5
+ export async function loadRunLedger(artifactsDir) {
6
+ try {
7
+ return await readJsonFile(ledgerPath(artifactsDir));
8
+ }
9
+ catch {
10
+ return { runs: [] };
11
+ }
12
+ }
13
+ export async function appendRunLedgerEntry(artifactsDir, entry) {
14
+ const ledger = await loadRunLedger(artifactsDir);
15
+ ledger.runs.push(entry);
16
+ await writeJsonFile(ledgerPath(artifactsDir), ledger);
17
+ }
@@ -0,0 +1,4 @@
1
+ import type { SessionConfig } from "../types/sessionConfig.js";
2
+ export declare function getSessionConfigPath(artifactsDir: string): string;
3
+ export declare function readSessionConfigFile(artifactsDir: string): Promise<unknown | undefined>;
4
+ export declare function loadSessionConfig(artifactsDir: string): Promise<SessionConfig>;
@@ -0,0 +1,26 @@
1
+ import { readOptionalJsonFile } from "../io/json.js";
2
+ import { validateSessionConfig } from "../validation/sessionConfig.js";
3
+ export function getSessionConfigPath(artifactsDir) {
4
+ return `${artifactsDir}/session-config.json`;
5
+ }
6
+ export async function readSessionConfigFile(artifactsDir) {
7
+ return await readOptionalJsonFile(getSessionConfigPath(artifactsDir));
8
+ }
9
+ function formatValidationIssues(configPath, issues) {
10
+ const details = issues
11
+ .map((issue) => `- ${issue.path}: ${issue.message}`)
12
+ .join("\n");
13
+ return `Invalid ${configPath}:\n${details}`;
14
+ }
15
+ export async function loadSessionConfig(artifactsDir) {
16
+ const configPath = getSessionConfigPath(artifactsDir);
17
+ const rawConfig = await readOptionalJsonFile(configPath);
18
+ if (rawConfig === undefined) {
19
+ return {};
20
+ }
21
+ const issues = validateSessionConfig(rawConfig);
22
+ if (issues.length > 0) {
23
+ throw new Error(formatValidationIssues(configPath, issues));
24
+ }
25
+ return rawConfig;
26
+ }
@@ -0,0 +1,8 @@
1
+ export interface ArtifactMetadataEntry {
2
+ revision: number;
3
+ content_hash: string;
4
+ dependency_revisions: Record<string, number>;
5
+ }
6
+ export interface ArtifactMetadataManifest {
7
+ artifacts: Record<string, ArtifactMetadataEntry>;
8
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ export type AuditTopLevelStatus = "not_started" | "active" | "blocked" | "complete";
2
+ export type ObligationState = "missing" | "present" | "stale" | "blocked" | "satisfied";
3
+ export interface AuditObligation {
4
+ id: string;
5
+ state: ObligationState;
6
+ reason?: string;
7
+ }
8
+ export interface AuditState {
9
+ status: AuditTopLevelStatus;
10
+ last_executor?: string;
11
+ last_obligation?: string;
12
+ blockers?: string[];
13
+ obligations: AuditObligation[];
14
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ export type FileDispositionStatus = "included" | "excluded" | "generated" | "vendor" | "binary" | "doc_only";
2
+ export interface FileDispositionItem {
3
+ path: string;
4
+ status: FileDispositionStatus;
5
+ reason?: string;
6
+ }
7
+ export interface FileDisposition {
8
+ files: FileDispositionItem[];
9
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ export interface ExternalAnalyzerResultItem {
2
+ id: string;
3
+ category: string;
4
+ severity: string;
5
+ path: string;
6
+ line_start?: number;
7
+ line_end?: number;
8
+ summary: string;
9
+ rule?: string;
10
+ raw?: unknown;
11
+ }
12
+ export interface ExternalAnalyzerResults {
13
+ tool: string;
14
+ generated_at?: string;
15
+ results: ExternalAnalyzerResultItem[];
16
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ export interface FlowCoverageRecord {
2
+ flow_id: string;
3
+ paths: string[];
4
+ required_lenses: string[];
5
+ completed_lenses: string[];
6
+ status: string;
7
+ notes?: string[];
8
+ }
9
+ export interface FlowCoverageManifest {
10
+ flows: FlowCoverageRecord[];
11
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ export interface CriticalFlow {
2
+ id: string;
3
+ name: string;
4
+ entrypoints: string[];
5
+ paths: string[];
6
+ concerns: string[];
7
+ notes?: string[];
8
+ }
9
+ export interface CriticalFlowManifest {
10
+ flows: CriticalFlow[];
11
+ }
@@ -0,0 +1 @@
1
+ export {};