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.
- package/README.md +173 -0
- package/audit-code-wrapper-lib.mjs +905 -0
- package/audit-code.mjs +13 -0
- package/dist/adapters/coverageSummary.d.ts +8 -0
- package/dist/adapters/coverageSummary.js +13 -0
- package/dist/adapters/eslint.d.ts +13 -0
- package/dist/adapters/eslint.js +21 -0
- package/dist/adapters/normalizeExternal.d.ts +12 -0
- package/dist/adapters/normalizeExternal.js +19 -0
- package/dist/adapters/npmAudit.d.ts +15 -0
- package/dist/adapters/npmAudit.js +12 -0
- package/dist/adapters/semgrep.d.ts +22 -0
- package/dist/adapters/semgrep.js +14 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +724 -0
- package/dist/coverage.d.ts +11 -0
- package/dist/coverage.js +102 -0
- package/dist/extractors/bucketing.d.ts +7 -0
- package/dist/extractors/bucketing.js +72 -0
- package/dist/extractors/disposition.d.ts +4 -0
- package/dist/extractors/disposition.js +41 -0
- package/dist/extractors/fileInventory.d.ts +7 -0
- package/dist/extractors/fileInventory.js +44 -0
- package/dist/extractors/flows.d.ts +5 -0
- package/dist/extractors/flows.js +125 -0
- package/dist/extractors/fsIntake.d.ts +8 -0
- package/dist/extractors/fsIntake.js +66 -0
- package/dist/extractors/graph.d.ts +4 -0
- package/dist/extractors/graph.js +46 -0
- package/dist/extractors/ignore.d.ts +1 -0
- package/dist/extractors/ignore.js +17 -0
- package/dist/extractors/risk.d.ts +5 -0
- package/dist/extractors/risk.js +45 -0
- package/dist/extractors/surfaces.d.ts +4 -0
- package/dist/extractors/surfaces.js +40 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/io/artifacts.d.ts +38 -0
- package/dist/io/artifacts.js +100 -0
- package/dist/io/json.d.ts +8 -0
- package/dist/io/json.js +96 -0
- package/dist/io/runArtifacts.d.ts +14 -0
- package/dist/io/runArtifacts.js +37 -0
- package/dist/orchestrator/advance.d.ts +24 -0
- package/dist/orchestrator/advance.js +104 -0
- package/dist/orchestrator/artifactMetadata.d.ts +4 -0
- package/dist/orchestrator/artifactMetadata.js +111 -0
- package/dist/orchestrator/autoFixExecutor.d.ts +3 -0
- package/dist/orchestrator/autoFixExecutor.js +63 -0
- package/dist/orchestrator/chunking.d.ts +5 -0
- package/dist/orchestrator/chunking.js +13 -0
- package/dist/orchestrator/dependencyMap.d.ts +1 -0
- package/dist/orchestrator/dependencyMap.js +82 -0
- package/dist/orchestrator/executors.d.ts +6 -0
- package/dist/orchestrator/executors.js +52 -0
- package/dist/orchestrator/flowCoverage.d.ts +4 -0
- package/dist/orchestrator/flowCoverage.js +44 -0
- package/dist/orchestrator/flowPlanning.d.ts +3 -0
- package/dist/orchestrator/flowPlanning.js +42 -0
- package/dist/orchestrator/flowRequeue.d.ts +5 -0
- package/dist/orchestrator/flowRequeue.js +58 -0
- package/dist/orchestrator/internalExecutors.d.ts +16 -0
- package/dist/orchestrator/internalExecutors.js +212 -0
- package/dist/orchestrator/nextStep.d.ts +9 -0
- package/dist/orchestrator/nextStep.js +44 -0
- package/dist/orchestrator/planning.d.ts +4 -0
- package/dist/orchestrator/planning.js +62 -0
- package/dist/orchestrator/requeue.d.ts +3 -0
- package/dist/orchestrator/requeue.js +25 -0
- package/dist/orchestrator/requeueCommand.d.ts +10 -0
- package/dist/orchestrator/requeueCommand.js +27 -0
- package/dist/orchestrator/resultIngestion.d.ts +2 -0
- package/dist/orchestrator/resultIngestion.js +13 -0
- package/dist/orchestrator/runtimeValidation.d.ts +7 -0
- package/dist/orchestrator/runtimeValidation.js +103 -0
- package/dist/orchestrator/runtimeValidationUpdate.d.ts +2 -0
- package/dist/orchestrator/runtimeValidationUpdate.js +52 -0
- package/dist/orchestrator/staleness.d.ts +2 -0
- package/dist/orchestrator/staleness.js +83 -0
- package/dist/orchestrator/state.d.ts +3 -0
- package/dist/orchestrator/state.js +85 -0
- package/dist/orchestrator/syntaxResolutionExecutor.d.ts +3 -0
- package/dist/orchestrator/syntaxResolutionExecutor.js +99 -0
- package/dist/orchestrator/taskBuilder.d.ts +12 -0
- package/dist/orchestrator/taskBuilder.js +154 -0
- package/dist/orchestrator/unitBuilder.d.ts +3 -0
- package/dist/orchestrator/unitBuilder.js +145 -0
- package/dist/orchestrator.d.ts +6 -0
- package/dist/orchestrator.js +33 -0
- package/dist/prompts/renderWorkerPrompt.d.ts +2 -0
- package/dist/prompts/renderWorkerPrompt.js +19 -0
- package/dist/providers/claudeCodeProvider.d.ts +8 -0
- package/dist/providers/claudeCodeProvider.js +20 -0
- package/dist/providers/index.d.ts +7 -0
- package/dist/providers/index.js +77 -0
- package/dist/providers/localSubprocessProvider.d.ts +5 -0
- package/dist/providers/localSubprocessProvider.js +13 -0
- package/dist/providers/opencodeProvider.d.ts +8 -0
- package/dist/providers/opencodeProvider.js +15 -0
- package/dist/providers/spawnLoggedCommand.d.ts +2 -0
- package/dist/providers/spawnLoggedCommand.js +48 -0
- package/dist/providers/subprocessTemplateProvider.d.ts +8 -0
- package/dist/providers/subprocessTemplateProvider.js +41 -0
- package/dist/providers/types.d.ts +22 -0
- package/dist/providers/types.js +1 -0
- package/dist/providers/vscodeTaskProvider.d.ts +8 -0
- package/dist/providers/vscodeTaskProvider.js +14 -0
- package/dist/reporting/mergeFindings.d.ts +4 -0
- package/dist/reporting/mergeFindings.js +136 -0
- package/dist/reporting/rootCause.d.ts +11 -0
- package/dist/reporting/rootCause.js +69 -0
- package/dist/reporting/synthesis.d.ts +21 -0
- package/dist/reporting/synthesis.js +55 -0
- package/dist/supervisor/operatorHandoff.d.ts +37 -0
- package/dist/supervisor/operatorHandoff.js +144 -0
- package/dist/supervisor/runLedger.d.ts +3 -0
- package/dist/supervisor/runLedger.js +17 -0
- package/dist/supervisor/sessionConfig.d.ts +4 -0
- package/dist/supervisor/sessionConfig.js +26 -0
- package/dist/types/artifactMetadata.d.ts +8 -0
- package/dist/types/artifactMetadata.js +1 -0
- package/dist/types/auditState.d.ts +14 -0
- package/dist/types/auditState.js +1 -0
- package/dist/types/disposition.d.ts +9 -0
- package/dist/types/disposition.js +1 -0
- package/dist/types/externalAnalyzer.d.ts +16 -0
- package/dist/types/externalAnalyzer.js +1 -0
- package/dist/types/flowCoverage.d.ts +11 -0
- package/dist/types/flowCoverage.js +1 -0
- package/dist/types/flows.d.ts +11 -0
- package/dist/types/flows.js +1 -0
- package/dist/types/graph.d.ts +18 -0
- package/dist/types/graph.js +1 -0
- package/dist/types/risk.d.ts +9 -0
- package/dist/types/risk.js +1 -0
- package/dist/types/runLedger.d.ts +13 -0
- package/dist/types/runLedger.js +1 -0
- package/dist/types/runtimeValidation.d.ts +22 -0
- package/dist/types/runtimeValidation.js +1 -0
- package/dist/types/sessionConfig.d.ts +27 -0
- package/dist/types/sessionConfig.js +1 -0
- package/dist/types/surfaces.d.ts +11 -0
- package/dist/types/surfaces.js +1 -0
- package/dist/types/workerResult.d.ts +13 -0
- package/dist/types/workerResult.js +1 -0
- package/dist/types/workerSession.d.ts +13 -0
- package/dist/types/workerSession.js +1 -0
- package/dist/types.d.ts +104 -0
- package/dist/types.js +1 -0
- package/dist/validation/artifacts.d.ts +3 -0
- package/dist/validation/artifacts.js +191 -0
- package/dist/validation/basic.d.ts +5 -0
- package/dist/validation/basic.js +9 -0
- package/dist/validation/sessionConfig.d.ts +6 -0
- package/dist/validation/sessionConfig.js +139 -0
- package/docs/agent-integrations.md +237 -0
- package/docs/agent-roles.md +69 -0
- package/docs/architecture.md +90 -0
- package/docs/artifacts.md +69 -0
- package/docs/bootstrap-install.md +79 -0
- package/docs/contract.md +140 -0
- package/docs/github-copilot.md +50 -0
- package/docs/model-selection.md +86 -0
- package/docs/next-steps.md +161 -0
- package/docs/packaging.md +88 -0
- package/docs/pipeline.md +152 -0
- package/docs/product-direction.md +111 -0
- package/docs/production-launch-bar.md +83 -0
- package/docs/production-readiness.md +52 -0
- package/docs/repo-layout.md +30 -0
- package/docs/run-flow.md +49 -0
- package/docs/session-config.md +232 -0
- package/docs/supervisor.md +83 -0
- package/docs/usage.md +172 -0
- package/docs/windows-setup.md +146 -0
- package/package.json +56 -0
- package/schemas/audit-code-v1alpha1.schema.json +191 -0
- package/schemas/audit_result.schema.json +48 -0
- package/schemas/audit_state.schema.json +36 -0
- package/schemas/audit_task.schema.json +49 -0
- package/schemas/blind_spot_register.schema.json +40 -0
- package/schemas/coverage_matrix.schema.json +50 -0
- package/schemas/critical_flows.schema.json +38 -0
- package/schemas/external_analyzer_results.schema.json +31 -0
- package/schemas/file_disposition.schema.json +33 -0
- package/schemas/finding.schema.json +62 -0
- package/schemas/flow_coverage.schema.json +44 -0
- package/schemas/graph_bundle.schema.json +55 -0
- package/schemas/merged_findings.schema.json +14 -0
- package/schemas/repo_manifest.schema.json +37 -0
- package/schemas/risk_register.schema.json +30 -0
- package/schemas/root_cause_clusters.schema.json +31 -0
- package/schemas/runtime_validation_report.schema.json +34 -0
- package/schemas/runtime_validation_tasks.schema.json +36 -0
- package/schemas/surface_manifest.schema.json +32 -0
- package/schemas/synthesis_report.schema.json +61 -0
- package/schemas/unit_manifest.schema.json +36 -0
- package/skills/audit-code/SKILL.md +54 -0
- package/skills/audit-code/audit-code.prompt.md +66 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { isAuditExcludedStatus } from "./disposition.js";
|
|
2
|
+
function methodsForPath(path) {
|
|
3
|
+
const normalized = path.toLowerCase();
|
|
4
|
+
if (normalized.includes("api") || normalized.includes("route")) {
|
|
5
|
+
return ["GET", "POST"];
|
|
6
|
+
}
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
export function buildSurfaceManifest(repoManifest, disposition) {
|
|
10
|
+
const surfaces = [];
|
|
11
|
+
const dispositionMap = new Map(disposition?.files.map((item) => [item.path, item.status]) ?? []);
|
|
12
|
+
for (const file of repoManifest.files) {
|
|
13
|
+
const status = dispositionMap.get(file.path);
|
|
14
|
+
if (status && isAuditExcludedStatus(status)) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const normalized = file.path.toLowerCase();
|
|
18
|
+
if (normalized.includes("api/") ||
|
|
19
|
+
normalized.includes("route") ||
|
|
20
|
+
normalized.includes("controller") ||
|
|
21
|
+
normalized.includes("worker") ||
|
|
22
|
+
normalized.includes("job") ||
|
|
23
|
+
normalized.includes("command") ||
|
|
24
|
+
normalized.includes("cli")) {
|
|
25
|
+
surfaces.push({
|
|
26
|
+
id: `surface:${file.path}`,
|
|
27
|
+
kind: normalized.includes("worker") || normalized.includes("job")
|
|
28
|
+
? "background"
|
|
29
|
+
: "interface",
|
|
30
|
+
entrypoint: file.path,
|
|
31
|
+
exposure: normalized.includes("api") || normalized.includes("route")
|
|
32
|
+
? "network"
|
|
33
|
+
: "local",
|
|
34
|
+
methods: methodsForPath(file.path),
|
|
35
|
+
notes: ["Heuristic surface detection."],
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return { surfaces };
|
|
40
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./cli.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./cli.js";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { AuditResult, AuditTask, CoverageMatrix, RepoManifest, UnitManifest } from "../types.js";
|
|
2
|
+
import type { AuditState } from "../types/auditState.js";
|
|
3
|
+
import type { ArtifactMetadataManifest } from "../types/artifactMetadata.js";
|
|
4
|
+
import type { FileDisposition } from "../types/disposition.js";
|
|
5
|
+
import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
|
|
6
|
+
import type { FlowCoverageManifest } from "../types/flowCoverage.js";
|
|
7
|
+
import type { CriticalFlowManifest } from "../types/flows.js";
|
|
8
|
+
import type { GraphBundle } from "../types/graph.js";
|
|
9
|
+
import type { RiskRegister } from "../types/risk.js";
|
|
10
|
+
import type { RuntimeValidationReport, RuntimeValidationTaskManifest } from "../types/runtimeValidation.js";
|
|
11
|
+
import type { SurfaceManifest } from "../types/surfaces.js";
|
|
12
|
+
export interface ArtifactBundle {
|
|
13
|
+
repo_manifest?: RepoManifest;
|
|
14
|
+
file_disposition?: FileDisposition;
|
|
15
|
+
auto_fixes_applied?: unknown;
|
|
16
|
+
unit_manifest?: UnitManifest;
|
|
17
|
+
graph_bundle?: GraphBundle;
|
|
18
|
+
surface_manifest?: SurfaceManifest;
|
|
19
|
+
critical_flows?: CriticalFlowManifest;
|
|
20
|
+
flow_coverage?: FlowCoverageManifest;
|
|
21
|
+
risk_register?: RiskRegister;
|
|
22
|
+
coverage_matrix?: CoverageMatrix;
|
|
23
|
+
runtime_validation_tasks?: RuntimeValidationTaskManifest;
|
|
24
|
+
runtime_validation_report?: RuntimeValidationReport;
|
|
25
|
+
external_analyzer_results?: ExternalAnalyzerResults;
|
|
26
|
+
audit_results?: AuditResult[];
|
|
27
|
+
audit_tasks?: AuditTask[];
|
|
28
|
+
requeue_tasks?: AuditTask[];
|
|
29
|
+
merged_findings?: unknown;
|
|
30
|
+
root_cause_clusters?: unknown;
|
|
31
|
+
synthesis_report?: unknown;
|
|
32
|
+
audit_state?: AuditState;
|
|
33
|
+
artifact_metadata?: ArtifactMetadataManifest;
|
|
34
|
+
}
|
|
35
|
+
export declare const ARTIFACT_FILE_TO_BUNDLE_KEY: Record<string, keyof ArtifactBundle>;
|
|
36
|
+
export declare function getArtifactValue(bundle: ArtifactBundle, artifactName: string): unknown;
|
|
37
|
+
export declare function loadArtifactBundle(root: string): Promise<ArtifactBundle>;
|
|
38
|
+
export declare function writeCoreArtifacts(root: string, bundle: ArtifactBundle): Promise<void>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { writeJsonFile, readOptionalJsonFile, readOptionalNdjsonFile, writeNdjsonFile, } from "./json.js";
|
|
2
|
+
export const ARTIFACT_FILE_TO_BUNDLE_KEY = {
|
|
3
|
+
"repo_manifest.json": "repo_manifest",
|
|
4
|
+
"file_disposition.json": "file_disposition",
|
|
5
|
+
"auto_fixes_applied.json": "auto_fixes_applied",
|
|
6
|
+
"unit_manifest.json": "unit_manifest",
|
|
7
|
+
"graph_bundle.json": "graph_bundle",
|
|
8
|
+
"surface_manifest.json": "surface_manifest",
|
|
9
|
+
"critical_flows.json": "critical_flows",
|
|
10
|
+
"flow_coverage.json": "flow_coverage",
|
|
11
|
+
"risk_register.json": "risk_register",
|
|
12
|
+
"coverage_matrix.json": "coverage_matrix",
|
|
13
|
+
"runtime_validation_tasks.json": "runtime_validation_tasks",
|
|
14
|
+
"runtime_validation_report.json": "runtime_validation_report",
|
|
15
|
+
"external_analyzer_results.json": "external_analyzer_results",
|
|
16
|
+
"audit_results.jsonl": "audit_results",
|
|
17
|
+
"audit_tasks.json": "audit_tasks",
|
|
18
|
+
"requeue_tasks.json": "requeue_tasks",
|
|
19
|
+
"merged_findings.json": "merged_findings",
|
|
20
|
+
"root_cause_clusters.json": "root_cause_clusters",
|
|
21
|
+
"synthesis_report.json": "synthesis_report",
|
|
22
|
+
"audit_state.json": "audit_state",
|
|
23
|
+
"artifact_metadata.json": "artifact_metadata",
|
|
24
|
+
};
|
|
25
|
+
export function getArtifactValue(bundle, artifactName) {
|
|
26
|
+
const key = ARTIFACT_FILE_TO_BUNDLE_KEY[artifactName];
|
|
27
|
+
return key ? bundle[key] : undefined;
|
|
28
|
+
}
|
|
29
|
+
export async function loadArtifactBundle(root) {
|
|
30
|
+
const bundle = {};
|
|
31
|
+
bundle.repo_manifest = await readOptionalJsonFile(`${root}/repo_manifest.json`);
|
|
32
|
+
bundle.file_disposition = await readOptionalJsonFile(`${root}/file_disposition.json`);
|
|
33
|
+
bundle.auto_fixes_applied = await readOptionalJsonFile(`${root}/auto_fixes_applied.json`);
|
|
34
|
+
bundle.unit_manifest = await readOptionalJsonFile(`${root}/unit_manifest.json`);
|
|
35
|
+
bundle.graph_bundle = await readOptionalJsonFile(`${root}/graph_bundle.json`);
|
|
36
|
+
bundle.surface_manifest = await readOptionalJsonFile(`${root}/surface_manifest.json`);
|
|
37
|
+
bundle.critical_flows = await readOptionalJsonFile(`${root}/critical_flows.json`);
|
|
38
|
+
bundle.flow_coverage = await readOptionalJsonFile(`${root}/flow_coverage.json`);
|
|
39
|
+
bundle.risk_register = await readOptionalJsonFile(`${root}/risk_register.json`);
|
|
40
|
+
bundle.coverage_matrix = await readOptionalJsonFile(`${root}/coverage_matrix.json`);
|
|
41
|
+
bundle.runtime_validation_tasks =
|
|
42
|
+
await readOptionalJsonFile(`${root}/runtime_validation_tasks.json`);
|
|
43
|
+
bundle.runtime_validation_report =
|
|
44
|
+
await readOptionalJsonFile(`${root}/runtime_validation_report.json`);
|
|
45
|
+
bundle.external_analyzer_results =
|
|
46
|
+
await readOptionalJsonFile(`${root}/external_analyzer_results.json`);
|
|
47
|
+
bundle.audit_results = await readOptionalNdjsonFile(`${root}/audit_results.jsonl`);
|
|
48
|
+
bundle.audit_tasks = await readOptionalJsonFile(`${root}/audit_tasks.json`);
|
|
49
|
+
bundle.requeue_tasks = await readOptionalJsonFile(`${root}/requeue_tasks.json`);
|
|
50
|
+
bundle.merged_findings = await readOptionalJsonFile(`${root}/merged_findings.json`);
|
|
51
|
+
bundle.root_cause_clusters = await readOptionalJsonFile(`${root}/root_cause_clusters.json`);
|
|
52
|
+
bundle.synthesis_report = await readOptionalJsonFile(`${root}/synthesis_report.json`);
|
|
53
|
+
bundle.audit_state = await readOptionalJsonFile(`${root}/audit_state.json`);
|
|
54
|
+
bundle.artifact_metadata = await readOptionalJsonFile(`${root}/artifact_metadata.json`);
|
|
55
|
+
return bundle;
|
|
56
|
+
}
|
|
57
|
+
export async function writeCoreArtifacts(root, bundle) {
|
|
58
|
+
if (bundle.repo_manifest)
|
|
59
|
+
await writeJsonFile(`${root}/repo_manifest.json`, bundle.repo_manifest);
|
|
60
|
+
if (bundle.file_disposition)
|
|
61
|
+
await writeJsonFile(`${root}/file_disposition.json`, bundle.file_disposition);
|
|
62
|
+
if (bundle.auto_fixes_applied)
|
|
63
|
+
await writeJsonFile(`${root}/auto_fixes_applied.json`, bundle.auto_fixes_applied);
|
|
64
|
+
if (bundle.unit_manifest)
|
|
65
|
+
await writeJsonFile(`${root}/unit_manifest.json`, bundle.unit_manifest);
|
|
66
|
+
if (bundle.graph_bundle)
|
|
67
|
+
await writeJsonFile(`${root}/graph_bundle.json`, bundle.graph_bundle);
|
|
68
|
+
if (bundle.surface_manifest)
|
|
69
|
+
await writeJsonFile(`${root}/surface_manifest.json`, bundle.surface_manifest);
|
|
70
|
+
if (bundle.critical_flows)
|
|
71
|
+
await writeJsonFile(`${root}/critical_flows.json`, bundle.critical_flows);
|
|
72
|
+
if (bundle.flow_coverage)
|
|
73
|
+
await writeJsonFile(`${root}/flow_coverage.json`, bundle.flow_coverage);
|
|
74
|
+
if (bundle.risk_register)
|
|
75
|
+
await writeJsonFile(`${root}/risk_register.json`, bundle.risk_register);
|
|
76
|
+
if (bundle.coverage_matrix)
|
|
77
|
+
await writeJsonFile(`${root}/coverage_matrix.json`, bundle.coverage_matrix);
|
|
78
|
+
if (bundle.runtime_validation_tasks)
|
|
79
|
+
await writeJsonFile(`${root}/runtime_validation_tasks.json`, bundle.runtime_validation_tasks);
|
|
80
|
+
if (bundle.runtime_validation_report)
|
|
81
|
+
await writeJsonFile(`${root}/runtime_validation_report.json`, bundle.runtime_validation_report);
|
|
82
|
+
if (bundle.external_analyzer_results)
|
|
83
|
+
await writeJsonFile(`${root}/external_analyzer_results.json`, bundle.external_analyzer_results);
|
|
84
|
+
if (bundle.audit_results)
|
|
85
|
+
await writeNdjsonFile(`${root}/audit_results.jsonl`, bundle.audit_results);
|
|
86
|
+
if (bundle.audit_tasks)
|
|
87
|
+
await writeJsonFile(`${root}/audit_tasks.json`, bundle.audit_tasks);
|
|
88
|
+
if (bundle.requeue_tasks)
|
|
89
|
+
await writeJsonFile(`${root}/requeue_tasks.json`, bundle.requeue_tasks);
|
|
90
|
+
if (bundle.merged_findings)
|
|
91
|
+
await writeJsonFile(`${root}/merged_findings.json`, bundle.merged_findings);
|
|
92
|
+
if (bundle.root_cause_clusters)
|
|
93
|
+
await writeJsonFile(`${root}/root_cause_clusters.json`, bundle.root_cause_clusters);
|
|
94
|
+
if (bundle.synthesis_report)
|
|
95
|
+
await writeJsonFile(`${root}/synthesis_report.json`, bundle.synthesis_report);
|
|
96
|
+
if (bundle.audit_state)
|
|
97
|
+
await writeJsonFile(`${root}/audit_state.json`, bundle.audit_state);
|
|
98
|
+
if (bundle.artifact_metadata)
|
|
99
|
+
await writeJsonFile(`${root}/artifact_metadata.json`, bundle.artifact_metadata);
|
|
100
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function isFileMissingError(error: unknown): boolean;
|
|
2
|
+
export declare function readJsonFile<T>(path: string): Promise<T>;
|
|
3
|
+
export declare function writeJsonFile(path: string, value: unknown): Promise<void>;
|
|
4
|
+
export declare function appendNdjsonFile(path: string, value: unknown): Promise<void>;
|
|
5
|
+
export declare function readNdjsonFile<T>(path: string): Promise<T[]>;
|
|
6
|
+
export declare function readOptionalJsonFile<T>(path: string): Promise<T | undefined>;
|
|
7
|
+
export declare function readOptionalNdjsonFile<T>(path: string): Promise<T[] | undefined>;
|
|
8
|
+
export declare function writeNdjsonFile(path: string, values: unknown[]): Promise<void>;
|
package/dist/io/json.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile, appendFile } from "node:fs/promises";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
function errorMessage(error) {
|
|
4
|
+
return error instanceof Error ? error.message : String(error);
|
|
5
|
+
}
|
|
6
|
+
export function isFileMissingError(error) {
|
|
7
|
+
return (typeof error === "object" &&
|
|
8
|
+
error !== null &&
|
|
9
|
+
"code" in error &&
|
|
10
|
+
error.code === "ENOENT");
|
|
11
|
+
}
|
|
12
|
+
export async function readJsonFile(path) {
|
|
13
|
+
let content;
|
|
14
|
+
try {
|
|
15
|
+
content = await readFile(path, "utf8");
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (isFileMissingError(error)) {
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`Failed to read ${path}: ${errorMessage(error)}`);
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(content);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
throw new Error(`Invalid JSON in ${path}: ${errorMessage(error)}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export async function writeJsonFile(path, value) {
|
|
31
|
+
await mkdir(dirname(path), { recursive: true });
|
|
32
|
+
await writeFile(path, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
33
|
+
}
|
|
34
|
+
export async function appendNdjsonFile(path, value) {
|
|
35
|
+
await mkdir(dirname(path), { recursive: true });
|
|
36
|
+
await appendFile(path, JSON.stringify(value) + "\n", "utf8");
|
|
37
|
+
}
|
|
38
|
+
export async function readNdjsonFile(path) {
|
|
39
|
+
try {
|
|
40
|
+
const content = await readFile(path, "utf8");
|
|
41
|
+
if (content.trim().length === 0) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
return content
|
|
45
|
+
.trim()
|
|
46
|
+
.split(/\r?\n/)
|
|
47
|
+
.filter(Boolean)
|
|
48
|
+
.map((line, index) => {
|
|
49
|
+
try {
|
|
50
|
+
return JSON.parse(line);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
throw new Error(`Invalid NDJSON in ${path} at line ${index + 1}: ${errorMessage(error)}`);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (isFileMissingError(error)) {
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
if (error instanceof Error && error.message.includes(path)) {
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`Failed to read ${path}: ${errorMessage(error)}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export async function readOptionalJsonFile(path) {
|
|
68
|
+
try {
|
|
69
|
+
return await readJsonFile(path);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (isFileMissingError(error)) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export async function readOptionalNdjsonFile(path) {
|
|
79
|
+
try {
|
|
80
|
+
return await readNdjsonFile(path);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (isFileMissingError(error)) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export async function writeNdjsonFile(path, values) {
|
|
90
|
+
await mkdir(dirname(path), { recursive: true });
|
|
91
|
+
if (values.length === 0) {
|
|
92
|
+
await writeFile(path, "", "utf8");
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
await writeFile(path, values.map((v) => JSON.stringify(v)).join("\n") + "\n", "utf8");
|
|
96
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { WorkerTask } from "../types/workerSession.js";
|
|
2
|
+
export interface RunPaths {
|
|
3
|
+
runDir: string;
|
|
4
|
+
taskPath: string;
|
|
5
|
+
promptPath: string;
|
|
6
|
+
resultPath: string;
|
|
7
|
+
stdoutPath: string;
|
|
8
|
+
stderrPath: string;
|
|
9
|
+
statusPath: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function buildRunId(obligationId: string | null, index: number): string;
|
|
12
|
+
export declare function getRunPaths(artifactsDir: string, runId: string): RunPaths;
|
|
13
|
+
export declare function ensureSupervisorDirs(artifactsDir: string): Promise<void>;
|
|
14
|
+
export declare function writeWorkerTaskFiles(task: WorkerTask, prompt: string, paths: RunPaths, artifactsDir: string): Promise<void>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { writeJsonFile } from "./json.js";
|
|
4
|
+
export function buildRunId(obligationId, index) {
|
|
5
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
6
|
+
const obligation = obligationId ?? "terminal";
|
|
7
|
+
return `${timestamp}_${obligation}_${String(index).padStart(3, "0")}`;
|
|
8
|
+
}
|
|
9
|
+
export function getRunPaths(artifactsDir, runId) {
|
|
10
|
+
const runDir = join(artifactsDir, "runs", runId);
|
|
11
|
+
return {
|
|
12
|
+
runDir,
|
|
13
|
+
taskPath: join(runDir, "task.json"),
|
|
14
|
+
promptPath: join(runDir, "prompt.md"),
|
|
15
|
+
resultPath: join(runDir, "result.json"),
|
|
16
|
+
stdoutPath: join(runDir, "stdout.log"),
|
|
17
|
+
stderrPath: join(runDir, "stderr.log"),
|
|
18
|
+
statusPath: join(runDir, "status.json"),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export async function ensureSupervisorDirs(artifactsDir) {
|
|
22
|
+
await mkdir(join(artifactsDir, "dispatch"), { recursive: true });
|
|
23
|
+
await mkdir(join(artifactsDir, "worker-results"), { recursive: true });
|
|
24
|
+
await mkdir(join(artifactsDir, "worker-logs"), { recursive: true });
|
|
25
|
+
await mkdir(join(artifactsDir, "runs"), { recursive: true });
|
|
26
|
+
}
|
|
27
|
+
export async function writeWorkerTaskFiles(task, prompt, paths, artifactsDir) {
|
|
28
|
+
await mkdir(paths.runDir, { recursive: true });
|
|
29
|
+
await writeJsonFile(paths.taskPath, task);
|
|
30
|
+
await writeFile(paths.promptPath, prompt, "utf8");
|
|
31
|
+
await writeJsonFile(paths.statusPath, {
|
|
32
|
+
run_id: task.run_id,
|
|
33
|
+
status: "dispatched",
|
|
34
|
+
});
|
|
35
|
+
await writeJsonFile(join(artifactsDir, "dispatch", "current-task.json"), task);
|
|
36
|
+
await writeFile(join(artifactsDir, "dispatch", "current-prompt.md"), prompt, "utf8");
|
|
37
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ArtifactBundle } from "../io/artifacts.js";
|
|
2
|
+
import type { AuditState } from "../types/auditState.js";
|
|
3
|
+
import type { AuditResult } from "../types.js";
|
|
4
|
+
import type { RuntimeValidationReport } from "../types/runtimeValidation.js";
|
|
5
|
+
import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
|
|
6
|
+
export interface AdvanceAuditOptions {
|
|
7
|
+
root?: string;
|
|
8
|
+
lineIndex?: Record<string, number>;
|
|
9
|
+
auditResults?: AuditResult[];
|
|
10
|
+
runtimeValidationUpdates?: RuntimeValidationReport;
|
|
11
|
+
externalAnalyzerResults?: ExternalAnalyzerResults;
|
|
12
|
+
preferredExecutor?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface AdvanceAuditResult {
|
|
15
|
+
audit_state: AuditState;
|
|
16
|
+
selected_obligation: string | null;
|
|
17
|
+
selected_executor: string | null;
|
|
18
|
+
progress_made: boolean;
|
|
19
|
+
artifacts_written: string[];
|
|
20
|
+
progress_summary: string;
|
|
21
|
+
next_likely_step: string | null;
|
|
22
|
+
updated_bundle: ArtifactBundle;
|
|
23
|
+
}
|
|
24
|
+
export declare function advanceAudit(bundle: ArtifactBundle, options?: AdvanceAuditOptions): Promise<AdvanceAuditResult>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { decideNextStep } from "./nextStep.js";
|
|
2
|
+
import { deriveAuditState } from "./state.js";
|
|
3
|
+
import { computeArtifactMetadata } from "./artifactMetadata.js";
|
|
4
|
+
import { runIntakeExecutor, runStructureExecutor, runPlanningExecutor, runResultIngestionExecutor, runRuntimeValidationUpdateExecutor, runSynthesisExecutor, runExternalAnalyzerImportExecutor, } from "./internalExecutors.js";
|
|
5
|
+
import { runAutoFixExecutor } from "./autoFixExecutor.js";
|
|
6
|
+
import { runSyntaxResolutionExecutor } from "./syntaxResolutionExecutor.js";
|
|
7
|
+
export async function advanceAudit(bundle, options = {}) {
|
|
8
|
+
const decision = decideNextStep(bundle);
|
|
9
|
+
const forcedExecutor = options.preferredExecutor ?? null;
|
|
10
|
+
const selectedExecutor = forcedExecutor ?? decision.selected_executor;
|
|
11
|
+
const selectedObligation = forcedExecutor
|
|
12
|
+
? `forced:${forcedExecutor}`
|
|
13
|
+
: decision.selected_obligation;
|
|
14
|
+
if (!selectedExecutor) {
|
|
15
|
+
const state = deriveAuditState(bundle);
|
|
16
|
+
state.last_executor = selectedExecutor ?? undefined;
|
|
17
|
+
state.last_obligation = selectedObligation ?? undefined;
|
|
18
|
+
return {
|
|
19
|
+
audit_state: state,
|
|
20
|
+
selected_obligation: selectedObligation,
|
|
21
|
+
selected_executor: selectedExecutor,
|
|
22
|
+
progress_made: false,
|
|
23
|
+
artifacts_written: ["audit_state.json"],
|
|
24
|
+
progress_summary: decision.reason,
|
|
25
|
+
next_likely_step: null,
|
|
26
|
+
updated_bundle: { ...bundle, audit_state: state },
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
let run;
|
|
30
|
+
switch (selectedExecutor) {
|
|
31
|
+
case "intake_executor":
|
|
32
|
+
if (!options.root)
|
|
33
|
+
throw new Error("advanceAudit intake_executor requires root");
|
|
34
|
+
run = await runIntakeExecutor(bundle, options.root);
|
|
35
|
+
break;
|
|
36
|
+
case "structure_executor":
|
|
37
|
+
run = runStructureExecutor(bundle);
|
|
38
|
+
break;
|
|
39
|
+
case "planning_executor":
|
|
40
|
+
run = runPlanningExecutor(bundle, options.lineIndex ?? {});
|
|
41
|
+
break;
|
|
42
|
+
case "result_ingestion_executor":
|
|
43
|
+
run = runResultIngestionExecutor(bundle, options.auditResults ?? bundle.audit_results ?? []);
|
|
44
|
+
break;
|
|
45
|
+
case "synthesis_executor":
|
|
46
|
+
run = runSynthesisExecutor(bundle, options.auditResults);
|
|
47
|
+
break;
|
|
48
|
+
case "runtime_validation_update_executor":
|
|
49
|
+
if (!options.runtimeValidationUpdates)
|
|
50
|
+
throw new Error("advanceAudit runtime_validation_update_executor requires runtimeValidationUpdates");
|
|
51
|
+
run = runRuntimeValidationUpdateExecutor(bundle, options.runtimeValidationUpdates);
|
|
52
|
+
break;
|
|
53
|
+
case "external_analyzer_import_executor":
|
|
54
|
+
if (!options.externalAnalyzerResults)
|
|
55
|
+
throw new Error("advanceAudit external_analyzer_import_executor requires externalAnalyzerResults");
|
|
56
|
+
run = runExternalAnalyzerImportExecutor(bundle, options.externalAnalyzerResults);
|
|
57
|
+
break;
|
|
58
|
+
case "auto_fix_executor":
|
|
59
|
+
if (!options.root)
|
|
60
|
+
throw new Error("advanceAudit auto_fix_executor requires root");
|
|
61
|
+
run = runAutoFixExecutor(bundle, options.root);
|
|
62
|
+
break;
|
|
63
|
+
case "syntax_resolution_executor":
|
|
64
|
+
if (!options.root)
|
|
65
|
+
throw new Error("advanceAudit syntax_resolution_executor requires root");
|
|
66
|
+
run = runSyntaxResolutionExecutor(bundle, options.root);
|
|
67
|
+
break;
|
|
68
|
+
default:
|
|
69
|
+
const state = deriveAuditState(bundle);
|
|
70
|
+
state.last_executor = selectedExecutor;
|
|
71
|
+
state.last_obligation = selectedObligation ?? undefined;
|
|
72
|
+
return {
|
|
73
|
+
audit_state: state,
|
|
74
|
+
selected_obligation: selectedObligation,
|
|
75
|
+
selected_executor: selectedExecutor,
|
|
76
|
+
progress_made: false,
|
|
77
|
+
artifacts_written: ["audit_state.json"],
|
|
78
|
+
progress_summary: `Executor ${selectedExecutor} is selected but not yet dispatched through advance-audit.`,
|
|
79
|
+
next_likely_step: selectedObligation,
|
|
80
|
+
updated_bundle: { ...bundle, audit_state: state },
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const metadata = computeArtifactMetadata(run.updated, bundle.artifact_metadata);
|
|
84
|
+
const metadataBundle = { ...run.updated, artifact_metadata: metadata };
|
|
85
|
+
const updatedState = deriveAuditState(metadataBundle);
|
|
86
|
+
updatedState.last_executor = selectedExecutor;
|
|
87
|
+
updatedState.last_obligation = selectedObligation ?? undefined;
|
|
88
|
+
const finalizedBundle = { ...metadataBundle, audit_state: updatedState };
|
|
89
|
+
const followupDecision = decideNextStep(finalizedBundle);
|
|
90
|
+
return {
|
|
91
|
+
audit_state: updatedState,
|
|
92
|
+
selected_obligation: selectedObligation,
|
|
93
|
+
selected_executor: selectedExecutor,
|
|
94
|
+
progress_made: true,
|
|
95
|
+
artifacts_written: [
|
|
96
|
+
...run.artifacts_written,
|
|
97
|
+
"artifact_metadata.json",
|
|
98
|
+
"audit_state.json",
|
|
99
|
+
],
|
|
100
|
+
progress_summary: run.progress_summary,
|
|
101
|
+
next_likely_step: followupDecision.selected_obligation,
|
|
102
|
+
updated_bundle: finalizedBundle,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ArtifactMetadataManifest } from "../types/artifactMetadata.js";
|
|
2
|
+
import type { ArtifactBundle } from "../io/artifacts.js";
|
|
3
|
+
export declare function present(bundle: ArtifactBundle, artifactName: string): boolean;
|
|
4
|
+
export declare function computeArtifactMetadata(bundle: ArtifactBundle, previous?: ArtifactMetadataManifest): ArtifactMetadataManifest;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { ARTIFACT_DEPENDENCY_MAP } from "./dependencyMap.js";
|
|
3
|
+
import { getArtifactValue } from "../io/artifacts.js";
|
|
4
|
+
function stableStringify(value) {
|
|
5
|
+
if (value === undefined) {
|
|
6
|
+
return "null";
|
|
7
|
+
}
|
|
8
|
+
if (value === null || typeof value !== "object") {
|
|
9
|
+
return JSON.stringify(value);
|
|
10
|
+
}
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
return `[${value.map((item) => stableStringify(item ?? null)).join(",")}]`;
|
|
13
|
+
}
|
|
14
|
+
const entries = Object.entries(value)
|
|
15
|
+
.filter(([, item]) => item !== undefined)
|
|
16
|
+
.sort(([a], [b]) => a.localeCompare(b));
|
|
17
|
+
return `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`).join(",")}}`;
|
|
18
|
+
}
|
|
19
|
+
function hashValue(value) {
|
|
20
|
+
return createHash("sha256").update(stableStringify(value)).digest("hex");
|
|
21
|
+
}
|
|
22
|
+
function normalizeForMetadataHash(artifactName, value) {
|
|
23
|
+
if (artifactName === "repo_manifest.json" &&
|
|
24
|
+
value &&
|
|
25
|
+
typeof value === "object" &&
|
|
26
|
+
!Array.isArray(value)) {
|
|
27
|
+
const record = value;
|
|
28
|
+
const { generated_at: _generatedAt, ...rest } = record;
|
|
29
|
+
return rest;
|
|
30
|
+
}
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
function buildReverseDependencyMap() {
|
|
34
|
+
const reverse = {};
|
|
35
|
+
for (const [upstream, downstreamList] of Object.entries(ARTIFACT_DEPENDENCY_MAP)) {
|
|
36
|
+
reverse[upstream] ??= [];
|
|
37
|
+
for (const downstream of downstreamList) {
|
|
38
|
+
reverse[downstream] ??= [];
|
|
39
|
+
reverse[downstream].push(upstream);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return reverse;
|
|
43
|
+
}
|
|
44
|
+
const REVERSE_DEPENDENCY_MAP = buildReverseDependencyMap();
|
|
45
|
+
function computeDependencyFirstOrder(artifactNames) {
|
|
46
|
+
const target = new Set(artifactNames);
|
|
47
|
+
const ordered = [];
|
|
48
|
+
const temporary = new Set();
|
|
49
|
+
const permanent = new Set();
|
|
50
|
+
const visit = (artifactName) => {
|
|
51
|
+
if (permanent.has(artifactName))
|
|
52
|
+
return;
|
|
53
|
+
if (temporary.has(artifactName))
|
|
54
|
+
return;
|
|
55
|
+
temporary.add(artifactName);
|
|
56
|
+
const dependencies = (REVERSE_DEPENDENCY_MAP[artifactName] ?? [])
|
|
57
|
+
.filter((dependencyName) => target.has(dependencyName))
|
|
58
|
+
.sort();
|
|
59
|
+
for (const dependencyName of dependencies) {
|
|
60
|
+
visit(dependencyName);
|
|
61
|
+
}
|
|
62
|
+
temporary.delete(artifactName);
|
|
63
|
+
permanent.add(artifactName);
|
|
64
|
+
ordered.push(artifactName);
|
|
65
|
+
};
|
|
66
|
+
for (const artifactName of Array.from(target).sort()) {
|
|
67
|
+
visit(artifactName);
|
|
68
|
+
}
|
|
69
|
+
return ordered;
|
|
70
|
+
}
|
|
71
|
+
export function present(bundle, artifactName) {
|
|
72
|
+
const value = getArtifactValue(bundle, artifactName);
|
|
73
|
+
return value !== undefined && value !== null;
|
|
74
|
+
}
|
|
75
|
+
export function computeArtifactMetadata(bundle, previous) {
|
|
76
|
+
const artifacts = {};
|
|
77
|
+
const presentArtifacts = Object.keys(REVERSE_DEPENDENCY_MAP).filter((artifactName) => artifactName !== "artifact_metadata.json" &&
|
|
78
|
+
present(bundle, artifactName));
|
|
79
|
+
const orderedArtifacts = computeDependencyFirstOrder(presentArtifacts);
|
|
80
|
+
for (const artifactName of orderedArtifacts) {
|
|
81
|
+
if (artifactName === "artifact_metadata.json")
|
|
82
|
+
continue;
|
|
83
|
+
const value = getArtifactValue(bundle, artifactName);
|
|
84
|
+
if (value === undefined || value === null)
|
|
85
|
+
continue;
|
|
86
|
+
const contentHash = hashValue(normalizeForMetadataHash(artifactName, value));
|
|
87
|
+
const previousEntry = previous?.artifacts[artifactName];
|
|
88
|
+
const dependencyRevisions = Object.fromEntries((REVERSE_DEPENDENCY_MAP[artifactName] ?? [])
|
|
89
|
+
.filter((dependencyName) => dependencyName !== "artifact_metadata.json")
|
|
90
|
+
.sort()
|
|
91
|
+
.map((dependencyName) => [
|
|
92
|
+
dependencyName,
|
|
93
|
+
artifacts[dependencyName]?.revision ??
|
|
94
|
+
previous?.artifacts[dependencyName]?.revision ??
|
|
95
|
+
0,
|
|
96
|
+
]));
|
|
97
|
+
const sameContent = previousEntry?.content_hash === contentHash;
|
|
98
|
+
const sameDependencies = previousEntry &&
|
|
99
|
+
stableStringify(previousEntry.dependency_revisions) ===
|
|
100
|
+
stableStringify(dependencyRevisions);
|
|
101
|
+
const revision = sameContent && sameDependencies
|
|
102
|
+
? previousEntry.revision
|
|
103
|
+
: (previousEntry?.revision ?? 0) + 1;
|
|
104
|
+
artifacts[artifactName] = {
|
|
105
|
+
revision,
|
|
106
|
+
content_hash: contentHash,
|
|
107
|
+
dependency_revisions: dependencyRevisions,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return { artifacts };
|
|
111
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { isAuditExcludedStatus } from "../extractors/disposition.js";
|
|
3
|
+
function tryRunConfiguredFormatter(root, command) {
|
|
4
|
+
try {
|
|
5
|
+
execSync(command, { cwd: root, stdio: "ignore", windowsHide: true });
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
catch (e) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function runAutoFixExecutor(bundle, root) {
|
|
13
|
+
if (!bundle.file_disposition) {
|
|
14
|
+
throw new Error("Cannot run auto fix executor without file_disposition");
|
|
15
|
+
}
|
|
16
|
+
const extensions = new Set();
|
|
17
|
+
for (const file of bundle.file_disposition.files) {
|
|
18
|
+
if (!isAuditExcludedStatus(file.status)) {
|
|
19
|
+
const match = file.path.match(/\.([^.]+)$/);
|
|
20
|
+
if (match) {
|
|
21
|
+
extensions.add(match[1].toLowerCase());
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const executedTools = [];
|
|
26
|
+
// TS / JS
|
|
27
|
+
if (extensions.has("ts") ||
|
|
28
|
+
extensions.has("js") ||
|
|
29
|
+
extensions.has("tsx") ||
|
|
30
|
+
extensions.has("jsx")) {
|
|
31
|
+
if (tryRunConfiguredFormatter(root, "npx prettier --write ."))
|
|
32
|
+
executedTools.push("prettier");
|
|
33
|
+
if (tryRunConfiguredFormatter(root, "npx eslint --fix ."))
|
|
34
|
+
executedTools.push("eslint");
|
|
35
|
+
}
|
|
36
|
+
// Python
|
|
37
|
+
if (extensions.has("py")) {
|
|
38
|
+
if (tryRunConfiguredFormatter(root, "black .") ||
|
|
39
|
+
tryRunConfiguredFormatter(root, "python -m black .")) {
|
|
40
|
+
executedTools.push("black");
|
|
41
|
+
}
|
|
42
|
+
if (tryRunConfiguredFormatter(root, "autopep8 --in-place --recursive .")) {
|
|
43
|
+
executedTools.push("autopep8");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Go
|
|
47
|
+
if (extensions.has("go")) {
|
|
48
|
+
if (tryRunConfiguredFormatter(root, "gofmt -w ."))
|
|
49
|
+
executedTools.push("gofmt");
|
|
50
|
+
}
|
|
51
|
+
const resultsArtifact = {
|
|
52
|
+
executed_tools: executedTools,
|
|
53
|
+
timestamp: new Date().toISOString(),
|
|
54
|
+
};
|
|
55
|
+
return {
|
|
56
|
+
updated: {
|
|
57
|
+
...bundle,
|
|
58
|
+
auto_fixes_applied: resultsArtifact,
|
|
59
|
+
},
|
|
60
|
+
artifacts_written: ["auto_fixes_applied.json"],
|
|
61
|
+
progress_summary: `Phase 1 Deterministic Auto-Fix complete. Formatters executed: ${executedTools.length > 0 ? executedTools.join(", ") : "None"}.`,
|
|
62
|
+
};
|
|
63
|
+
}
|