infraweaver 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/LICENSE +661 -0
- package/README.md +244 -0
- package/dist/agents/claude.d.ts +113 -0
- package/dist/agents/claudePretoolGate.d.ts +137 -0
- package/dist/agents/dispatchMetrics.d.ts +77 -0
- package/dist/agents/gateServer.d.ts +7 -0
- package/dist/agents/index.d.ts +6 -0
- package/dist/agents/nativeFsDenies.d.ts +46 -0
- package/dist/agents/opencode.d.ts +284 -0
- package/dist/agents/opencodePlugin.d.ts +96 -0
- package/dist/agents/opencodeShared.d.ts +40 -0
- package/dist/agents/postRun.d.ts +126 -0
- package/dist/agents/reviewer.d.ts +41 -0
- package/dist/agents/sessionLabeler.d.ts +97 -0
- package/dist/agents/shared.d.ts +246 -0
- package/dist/agents/subagentModels.d.ts +19 -0
- package/dist/agents/tokenQuota.d.ts +118 -0
- package/dist/agents/writeGateSource.d.ts +22 -0
- package/dist/agents/writePolicy.d.ts +79 -0
- package/dist/brand.d.ts +67 -0
- package/dist/cli.mjs +247846 -0
- package/dist/external.d.ts +227 -0
- package/dist/i18n/scaffolding.d.ts +59 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +247061 -0
- package/dist/internal/index.d.ts +18 -0
- package/dist/internal.js +2398 -0
- package/dist/lifecycle.d.ts +2 -0
- package/dist/main.d.ts +8 -0
- package/dist/mcp/arkConfig.d.ts +1 -0
- package/dist/mcp/assess.d.ts +157 -0
- package/dist/mcp/capabilityContext.d.ts +71 -0
- package/dist/mcp/changeSummary.d.ts +52 -0
- package/dist/mcp/checkSuite.d.ts +27 -0
- package/dist/mcp/checkout.d.ts +92 -0
- package/dist/mcp/comment.d.ts +127 -0
- package/dist/mcp/commitInfo.d.ts +11 -0
- package/dist/mcp/crosswalk.d.ts +178 -0
- package/dist/mcp/crosswalkDigest.d.ts +1 -0
- package/dist/mcp/cyberEssentials.d.ts +24 -0
- package/dist/mcp/dashboard.d.ts +125 -0
- package/dist/mcp/dependencies.d.ts +12 -0
- package/dist/mcp/frameworks.d.ts +74 -0
- package/dist/mcp/geminiSanitizer.d.ts +28 -0
- package/dist/mcp/git.d.ts +60 -0
- package/dist/mcp/guardrails.d.ts +222 -0
- package/dist/mcp/issue.d.ts +20 -0
- package/dist/mcp/issueComments.d.ts +11 -0
- package/dist/mcp/issueEvents.d.ts +11 -0
- package/dist/mcp/issueInfo.d.ts +11 -0
- package/dist/mcp/labels.d.ts +14 -0
- package/dist/mcp/localContext.d.ts +26 -0
- package/dist/mcp/moduleExtraction.d.ts +79 -0
- package/dist/mcp/moduleTests.d.ts +106 -0
- package/dist/mcp/modules.d.ts +198 -0
- package/dist/mcp/output.d.ts +16 -0
- package/dist/mcp/pathSafety.d.ts +14 -0
- package/dist/mcp/policy.d.ts +50 -0
- package/dist/mcp/pr.d.ts +64 -0
- package/dist/mcp/prInfo.d.ts +11 -0
- package/dist/mcp/providerSchema.d.ts +52 -0
- package/dist/mcp/review.d.ts +212 -0
- package/dist/mcp/reviewComments.d.ts +245 -0
- package/dist/mcp/roots.d.ts +60 -0
- package/dist/mcp/scope.d.ts +26 -0
- package/dist/mcp/selectMode.d.ts +20 -0
- package/dist/mcp/server.d.ts +61 -0
- package/dist/mcp/shared.d.ts +62 -0
- package/dist/mcp/shell.d.ts +58 -0
- package/dist/mcp/staleFix.d.ts +138 -0
- package/dist/mcp/terraform/azurePrices.d.ts +8 -0
- package/dist/mcp/terraform/baseline.d.ts +57 -0
- package/dist/mcp/terraform/concernResult.d.ts +38 -0
- package/dist/mcp/terraform/cost.d.ts +55 -0
- package/dist/mcp/terraform/cspm.d.ts +80 -0
- package/dist/mcp/terraform/currency.d.ts +110 -0
- package/dist/mcp/terraform/decisions.d.ts +178 -0
- package/dist/mcp/terraform/eidas.d.ts +100 -0
- package/dist/mcp/terraform/evidence.d.ts +343 -0
- package/dist/mcp/terraform/findings.d.ts +76 -0
- package/dist/mcp/terraform/fixMemory.d.ts +81 -0
- package/dist/mcp/terraform/governance.d.ts +56 -0
- package/dist/mcp/terraform/hcl.d.ts +115 -0
- package/dist/mcp/terraform/iacLanguages.d.ts +120 -0
- package/dist/mcp/terraform/idleFloor.d.ts +78 -0
- package/dist/mcp/terraform/keyless.d.ts +68 -0
- package/dist/mcp/terraform/moduleDocs.d.ts +56 -0
- package/dist/mcp/terraform/nativeRules.d.ts +38 -0
- package/dist/mcp/terraform/nativeScan.d.ts +11 -0
- package/dist/mcp/terraform/noiseProfile.d.ts +100 -0
- package/dist/mcp/terraform/normalization.d.ts +52 -0
- package/dist/mcp/terraform/oscal.d.ts +103 -0
- package/dist/mcp/terraform/packs/azurerm-3-4.d.ts +2 -0
- package/dist/mcp/terraform/packs/cloudflare-4-5.d.ts +2 -0
- package/dist/mcp/terraform/paths.d.ts +28 -0
- package/dist/mcp/terraform/plan.d.ts +157 -0
- package/dist/mcp/terraform/planDrift.d.ts +199 -0
- package/dist/mcp/terraform/policyAuthor.d.ts +191 -0
- package/dist/mcp/terraform/prowlerOcsf.d.ts +136 -0
- package/dist/mcp/terraform/refactor.d.ts +183 -0
- package/dist/mcp/terraform/registry.d.ts +108 -0
- package/dist/mcp/terraform/risk.d.ts +41 -0
- package/dist/mcp/terraform/scanSession.d.ts +116 -0
- package/dist/mcp/terraform/scannerCache.d.ts +15 -0
- package/dist/mcp/terraform/scannerEgress.d.ts +72 -0
- package/dist/mcp/terraform/scannerJson.d.ts +13 -0
- package/dist/mcp/terraform/scanners.d.ts +205 -0
- package/dist/mcp/terraform/signing.d.ts +61 -0
- package/dist/mcp/terraform/stateLocking.d.ts +18 -0
- package/dist/mcp/terraform/subprocess.d.ts +43 -0
- package/dist/mcp/terraform/suppressions.d.ts +90 -0
- package/dist/mcp/terraform/taxonomy.d.ts +39 -0
- package/dist/mcp/terraform/tfquery.d.ts +47 -0
- package/dist/mcp/terraform/toolchainIntegrity.d.ts +82 -0
- package/dist/mcp/terraform/tools/authorPolicy.d.ts +59 -0
- package/dist/mcp/terraform/tools/detectPlanDrift.d.ts +20 -0
- package/dist/mcp/terraform/tools/emitCost.d.ts +11 -0
- package/dist/mcp/terraform/tools/emitSarif.d.ts +14 -0
- package/dist/mcp/terraform/tools/fixMemory.d.ts +19 -0
- package/dist/mcp/terraform/tools/infracostDiff.d.ts +22 -0
- package/dist/mcp/terraform/tools/ingestExternalFindings.d.ts +21 -0
- package/dist/mcp/terraform/tools/moduleLookup.d.ts +14 -0
- package/dist/mcp/terraform/tools/moduleSearch.d.ts +23 -0
- package/dist/mcp/terraform/tools/plan.d.ts +59 -0
- package/dist/mcp/terraform/tools/providerUpgrade.d.ts +55 -0
- package/dist/mcp/terraform/tools/readFindings.d.ts +17 -0
- package/dist/mcp/terraform/tools/scan.d.ts +114 -0
- package/dist/mcp/terraform/tools/validate.d.ts +31 -0
- package/dist/mcp/terraform/tools/verifyRemediation.d.ts +31 -0
- package/dist/mcp/terraform/tools/versionCurrency.d.ts +5 -0
- package/dist/mcp/terraform/tools.d.ts +16 -0
- package/dist/mcp/terraform/transformPacks.d.ts +267 -0
- package/dist/mcp/terraform/types.d.ts +226 -0
- package/dist/mcp/terraform/verification.d.ts +81 -0
- package/dist/mcp/terraform/vex.d.ts +115 -0
- package/dist/mcp/terraform/writeOnly.d.ts +67 -0
- package/dist/mcp/terraform.d.ts +51 -0
- package/dist/mcp/terratest.d.ts +85 -0
- package/dist/mcp/untrustedContent.d.ts +76 -0
- package/dist/mcp/upload.d.ts +8 -0
- package/dist/models.d.ts +181 -0
- package/dist/modes/address-reviews.d.ts +2 -0
- package/dist/modes/assess.d.ts +2 -0
- package/dist/modes/build.d.ts +2 -0
- package/dist/modes/compliance-audit.d.ts +2 -0
- package/dist/modes/cost-optimization.d.ts +2 -0
- package/dist/modes/drift-detect.d.ts +2 -0
- package/dist/modes/fix.d.ts +2 -0
- package/dist/modes/incremental-review.d.ts +2 -0
- package/dist/modes/index.d.ts +24 -0
- package/dist/modes/modernize-deprecated.d.ts +2 -0
- package/dist/modes/plan.d.ts +2 -0
- package/dist/modes/policy-gate.d.ts +2 -0
- package/dist/modes/prFormats.d.ts +3 -0
- package/dist/modes/refactor.d.ts +2 -0
- package/dist/modes/refresh-remediation.d.ts +2 -0
- package/dist/modes/remediate-and-refactor.d.ts +2 -0
- package/dist/modes/remediate.d.ts +2 -0
- package/dist/modes/resolve-conflicts.d.ts +2 -0
- package/dist/modes/review.d.ts +2 -0
- package/dist/modes/summarize-pr.d.ts +2 -0
- package/dist/modes/task.d.ts +2 -0
- package/dist/modes/terraform-code-review.d.ts +2 -0
- package/dist/modes/types.d.ts +9 -0
- package/dist/modes/update-dependencies.d.ts +2 -0
- package/dist/prep/index.d.ts +7 -0
- package/dist/prep/installNodeDependencies.d.ts +2 -0
- package/dist/prep/installPythonDependencies.d.ts +2 -0
- package/dist/prep/types.d.ts +31 -0
- package/dist/reviewQuality.d.ts +107 -0
- package/dist/skills/terraform-best-practices/SKILL.md +379 -0
- package/dist/toolState.d.ts +123 -0
- package/dist/utils/activity.d.ts +40 -0
- package/dist/utils/agent.d.ts +47 -0
- package/dist/utils/agentHangReport.d.ts +38 -0
- package/dist/utils/annotations.d.ts +17 -0
- package/dist/utils/apiFetch.d.ts +11 -0
- package/dist/utils/apiKeys.d.ts +48 -0
- package/dist/utils/apiUrl.d.ts +28 -0
- package/dist/utils/assets.d.ts +8 -0
- package/dist/utils/baseRefConfig.d.ts +121 -0
- package/dist/utils/billingErrors.d.ts +85 -0
- package/dist/utils/body.d.ts +34 -0
- package/dist/utils/buildInfraweaverFooter.d.ts +29 -0
- package/dist/utils/byokFallback.d.ts +85 -0
- package/dist/utils/changeImpact.d.ts +101 -0
- package/dist/utils/claudeSubscription.d.ts +30 -0
- package/dist/utils/cli.d.ts +10 -0
- package/dist/utils/cloudClient.d.ts +33 -0
- package/dist/utils/cloudFetchCore.d.ts +42 -0
- package/dist/utils/cloudReport.d.ts +114 -0
- package/dist/utils/codexHome.d.ts +29 -0
- package/dist/utils/codexOAuth.d.ts +60 -0
- package/dist/utils/diffCoverage.d.ts +63 -0
- package/dist/utils/env.d.ts +46 -0
- package/dist/utils/errorReport.d.ts +17 -0
- package/dist/utils/exitHandler.d.ts +8 -0
- package/dist/utils/fixDoubleEscapedString.d.ts +1 -0
- package/dist/utils/gitAuth.d.ts +84 -0
- package/dist/utils/gitAuthServer.d.ts +24 -0
- package/dist/utils/github.d.ts +104 -0
- package/dist/utils/globals.d.ts +3 -0
- package/dist/utils/infraweaverConfig.d.ts +56 -0
- package/dist/utils/install.d.ts +37 -0
- package/dist/utils/instructions.d.ts +48 -0
- package/dist/utils/keylessOidc.d.ts +28 -0
- package/dist/utils/leapingComment.d.ts +11 -0
- package/dist/utils/learnings.d.ts +62 -0
- package/dist/utils/learningsTruncate.d.ts +25 -0
- package/dist/utils/lifecycle.d.ts +57 -0
- package/dist/utils/log.d.ts +111 -0
- package/dist/utils/modelResolver.d.ts +63 -0
- package/dist/utils/moduleFetch.d.ts +39 -0
- package/dist/utils/normalizeEnv.d.ts +30 -0
- package/dist/utils/openCodeModels.d.ts +11 -0
- package/dist/utils/openaiCompatible.d.ts +26 -0
- package/dist/utils/opentofuMcp.d.ts +50 -0
- package/dist/utils/overrides.d.ts +40 -0
- package/dist/utils/packageManager.d.ts +49 -0
- package/dist/utils/patchWorkflowRunFields.d.ts +29 -0
- package/dist/utils/payload.d.ts +249 -0
- package/dist/utils/prSummary.d.ts +61 -0
- package/dist/utils/presets.d.ts +36 -0
- package/dist/utils/progressComment.d.ts +146 -0
- package/dist/utils/providerErrors.d.ts +31 -0
- package/dist/utils/proxyModel.d.ts +76 -0
- package/dist/utils/rangeDiff.d.ts +51 -0
- package/dist/utils/redact.d.ts +33 -0
- package/dist/utils/registryAuth.d.ts +52 -0
- package/dist/utils/remediationCommand.d.ts +58 -0
- package/dist/utils/retry.d.ts +38 -0
- package/dist/utils/reviewCleanup.d.ts +14 -0
- package/dist/utils/run.d.ts +9 -0
- package/dist/utils/runContext.d.ts +112 -0
- package/dist/utils/runContextData.d.ts +42 -0
- package/dist/utils/runErrorRenderer.d.ts +64 -0
- package/dist/utils/runLifecycle.d.ts +89 -0
- package/dist/utils/runStartupLog.d.ts +15 -0
- package/dist/utils/secrets.d.ts +34 -0
- package/dist/utils/setup.d.ts +90 -0
- package/dist/utils/shell.d.ts +44 -0
- package/dist/utils/skills.d.ts +10 -0
- package/dist/utils/subprocess.d.ts +81 -0
- package/dist/utils/terraformMcp.d.ts +46 -0
- package/dist/utils/time.d.ts +15 -0
- package/dist/utils/timer.d.ts +23 -0
- package/dist/utils/todoTracking.d.ts +16 -0
- package/dist/utils/token.d.ts +52 -0
- package/dist/utils/toolLicensing.d.ts +56 -0
- package/dist/utils/toolSelection.d.ts +73 -0
- package/dist/utils/toon.d.ts +16 -0
- package/dist/utils/version.d.ts +2 -0
- package/dist/utils/versioning.d.ts +7 -0
- package/dist/utils/vertex.d.ts +16 -0
- package/dist/utils/workflow.d.ts +13 -0
- package/package.json +132 -0
- package/src/agents/claude.ts +1588 -0
- package/src/agents/claudePretoolGate.ts +286 -0
- package/src/agents/dispatchMetrics.ts +162 -0
- package/src/agents/gateServer.ts +178 -0
- package/src/agents/index.ts +10 -0
- package/src/agents/nativeFsDenies.ts +164 -0
- package/src/agents/opencode.ts +1600 -0
- package/src/agents/opencodePlugin.ts +304 -0
- package/src/agents/opencodeShared.ts +134 -0
- package/src/agents/postRun.ts +615 -0
- package/src/agents/reviewer.ts +134 -0
- package/src/agents/sessionLabeler.ts +185 -0
- package/src/agents/shared.ts +377 -0
- package/src/agents/subagentModels.ts +40 -0
- package/src/agents/tokenQuota.ts +203 -0
- package/src/agents/writeGateSource.ts +148 -0
- package/src/agents/writePolicy.ts +132 -0
- package/src/brand.ts +84 -0
- package/src/cli.ts +117 -0
- package/src/commands/gha.ts +188 -0
- package/src/commands/mcp.ts +126 -0
- package/src/commands/verifyEvidence.ts +100 -0
- package/src/entry.ts +7 -0
- package/src/entryPost.ts +109 -0
- package/src/external.ts +308 -0
- package/src/i18n/scaffolding.ts +191 -0
- package/src/index.ts +7 -0
- package/src/internal/index.ts +74 -0
- package/src/lifecycle.ts +2 -0
- package/src/main.ts +815 -0
- package/src/mcp/__fixtures__/infraweaver-scratch-pr-49-review-3485940013.json +110 -0
- package/src/mcp/__fixtures__/infraweaver-scratch-pr-64-review-3531000326.json +14 -0
- package/src/mcp/__fixtures__/infraweaver-test-repo-pr-1.diff.json +67 -0
- package/src/mcp/__snapshots__/checkout.test.ts.snap +109 -0
- package/src/mcp/__snapshots__/reviewComments.test.ts.snap +71 -0
- package/src/mcp/arkConfig.ts +7 -0
- package/src/mcp/assess.ts +723 -0
- package/src/mcp/capabilityContext.ts +80 -0
- package/src/mcp/changeSummary.ts +145 -0
- package/src/mcp/checkSuite.ts +261 -0
- package/src/mcp/checkout.ts +1015 -0
- package/src/mcp/comment.ts +683 -0
- package/src/mcp/commitInfo.ts +57 -0
- package/src/mcp/crosswalk.ts +1253 -0
- package/src/mcp/crosswalkDigest.ts +5 -0
- package/src/mcp/cyberEssentials.ts +60 -0
- package/src/mcp/dashboard.ts +232 -0
- package/src/mcp/dependencies.ts +190 -0
- package/src/mcp/frameworks.ts +236 -0
- package/src/mcp/geminiSanitizer.ts +212 -0
- package/src/mcp/git.ts +1116 -0
- package/src/mcp/guardrails.ts +771 -0
- package/src/mcp/issue.ts +74 -0
- package/src/mcp/issueComments.ts +48 -0
- package/src/mcp/issueEvents.ts +100 -0
- package/src/mcp/issueInfo.ts +72 -0
- package/src/mcp/labels.ts +35 -0
- package/src/mcp/localContext.ts +65 -0
- package/src/mcp/localServer.ts +217 -0
- package/src/mcp/moduleExtraction.ts +368 -0
- package/src/mcp/moduleTests.ts +421 -0
- package/src/mcp/modules.ts +752 -0
- package/src/mcp/output.ts +71 -0
- package/src/mcp/pathSafety.ts +28 -0
- package/src/mcp/policy.ts +226 -0
- package/src/mcp/pr.ts +238 -0
- package/src/mcp/prInfo.ts +91 -0
- package/src/mcp/providerSchema.ts +175 -0
- package/src/mcp/review.ts +1081 -0
- package/src/mcp/reviewComments.ts +1137 -0
- package/src/mcp/roots.ts +217 -0
- package/src/mcp/scope.ts +82 -0
- package/src/mcp/selectMode.ts +207 -0
- package/src/mcp/server.ts +498 -0
- package/src/mcp/shared.ts +120 -0
- package/src/mcp/shell.ts +631 -0
- package/src/mcp/staleFix.ts +557 -0
- package/src/mcp/terraform/__snapshots__/moduleDocs.test.ts.snap +40 -0
- package/src/mcp/terraform/azurePrices.ts +38 -0
- package/src/mcp/terraform/baseline.ts +172 -0
- package/src/mcp/terraform/concernResult.ts +111 -0
- package/src/mcp/terraform/cost.ts +175 -0
- package/src/mcp/terraform/cspm.ts +326 -0
- package/src/mcp/terraform/currency.ts +354 -0
- package/src/mcp/terraform/decisions.ts +590 -0
- package/src/mcp/terraform/eidas.ts +134 -0
- package/src/mcp/terraform/evidence.ts +771 -0
- package/src/mcp/terraform/findings.ts +383 -0
- package/src/mcp/terraform/fixMemory.ts +253 -0
- package/src/mcp/terraform/governance.ts +231 -0
- package/src/mcp/terraform/hcl.ts +273 -0
- package/src/mcp/terraform/iacLanguages.ts +431 -0
- package/src/mcp/terraform/idleFloor.ts +304 -0
- package/src/mcp/terraform/keyless.ts +123 -0
- package/src/mcp/terraform/moduleDocs.ts +303 -0
- package/src/mcp/terraform/nativeRules.ts +152 -0
- package/src/mcp/terraform/nativeScan.ts +67 -0
- package/src/mcp/terraform/noiseProfile.ts +183 -0
- package/src/mcp/terraform/normalization.ts +265 -0
- package/src/mcp/terraform/oscal.ts +283 -0
- package/src/mcp/terraform/packs/azurerm-3-4.ts +382 -0
- package/src/mcp/terraform/packs/cloudflare-4-5.ts +114 -0
- package/src/mcp/terraform/paths.ts +59 -0
- package/src/mcp/terraform/plan.ts +377 -0
- package/src/mcp/terraform/planDrift.ts +520 -0
- package/src/mcp/terraform/policyAuthor.ts +886 -0
- package/src/mcp/terraform/prowlerOcsf.ts +380 -0
- package/src/mcp/terraform/refactor.ts +879 -0
- package/src/mcp/terraform/registry.ts +317 -0
- package/src/mcp/terraform/risk.ts +99 -0
- package/src/mcp/terraform/scanSession.ts +242 -0
- package/src/mcp/terraform/scannerCache.ts +86 -0
- package/src/mcp/terraform/scannerEgress.ts +141 -0
- package/src/mcp/terraform/scannerJson.ts +22 -0
- package/src/mcp/terraform/scanners.ts +1134 -0
- package/src/mcp/terraform/signing.ts +151 -0
- package/src/mcp/terraform/stateLocking.ts +106 -0
- package/src/mcp/terraform/subprocess.ts +102 -0
- package/src/mcp/terraform/suppressions.ts +551 -0
- package/src/mcp/terraform/taxonomy.ts +0 -0
- package/src/mcp/terraform/tfquery.ts +159 -0
- package/src/mcp/terraform/toolchainIntegrity.ts +151 -0
- package/src/mcp/terraform/tools/authorPolicy.ts +185 -0
- package/src/mcp/terraform/tools/detectPlanDrift.ts +279 -0
- package/src/mcp/terraform/tools/emitCost.ts +130 -0
- package/src/mcp/terraform/tools/emitSarif.ts +108 -0
- package/src/mcp/terraform/tools/fixMemory.ts +82 -0
- package/src/mcp/terraform/tools/infracostDiff.ts +110 -0
- package/src/mcp/terraform/tools/ingestExternalFindings.ts +259 -0
- package/src/mcp/terraform/tools/moduleLookup.ts +86 -0
- package/src/mcp/terraform/tools/moduleSearch.ts +46 -0
- package/src/mcp/terraform/tools/plan.ts +384 -0
- package/src/mcp/terraform/tools/providerUpgrade.ts +217 -0
- package/src/mcp/terraform/tools/readFindings.ts +138 -0
- package/src/mcp/terraform/tools/scan.ts +303 -0
- package/src/mcp/terraform/tools/validate.ts +160 -0
- package/src/mcp/terraform/tools/verifyRemediation.ts +190 -0
- package/src/mcp/terraform/tools/versionCurrency.ts +64 -0
- package/src/mcp/terraform/tools.ts +62 -0
- package/src/mcp/terraform/transformPacks.ts +594 -0
- package/src/mcp/terraform/types.ts +382 -0
- package/src/mcp/terraform/verification.ts +150 -0
- package/src/mcp/terraform/vex.ts +367 -0
- package/src/mcp/terraform/writeOnly.ts +252 -0
- package/src/mcp/terraform.ts +52 -0
- package/src/mcp/terratest.ts +215 -0
- package/src/mcp/untrustedContent.ts +126 -0
- package/src/mcp/upload.ts +123 -0
- package/src/models.ts +753 -0
- package/src/modes/address-reviews.ts +35 -0
- package/src/modes/assess.ts +27 -0
- package/src/modes/build.ts +86 -0
- package/src/modes/compliance-audit.ts +25 -0
- package/src/modes/cost-optimization.ts +36 -0
- package/src/modes/drift-detect.ts +31 -0
- package/src/modes/fix.ts +29 -0
- package/src/modes/incremental-review.ts +103 -0
- package/src/modes/index.ts +94 -0
- package/src/modes/modernize-deprecated.ts +36 -0
- package/src/modes/plan.ts +21 -0
- package/src/modes/policy-gate.ts +27 -0
- package/src/modes/prFormats.ts +325 -0
- package/src/modes/refactor.ts +74 -0
- package/src/modes/refresh-remediation.ts +40 -0
- package/src/modes/remediate-and-refactor.ts +42 -0
- package/src/modes/remediate.ts +78 -0
- package/src/modes/resolve-conflicts.ts +32 -0
- package/src/modes/review.ts +135 -0
- package/src/modes/summarize-pr.ts +42 -0
- package/src/modes/task.ts +26 -0
- package/src/modes/terraform-code-review.ts +68 -0
- package/src/modes/types.ts +17 -0
- package/src/modes/update-dependencies.ts +44 -0
- package/src/prep/index.ts +96 -0
- package/src/prep/installNodeDependencies.ts +251 -0
- package/src/prep/installPythonDependencies.ts +235 -0
- package/src/prep/types.ts +38 -0
- package/src/reviewQuality.ts +237 -0
- package/src/runCli.ts +335 -0
- package/src/skills/terraform-best-practices/SKILL.md +379 -0
- package/src/toolState.ts +241 -0
- package/src/utils/activity.ts +210 -0
- package/src/utils/agent.ts +245 -0
- package/src/utils/agentHangReport.ts +180 -0
- package/src/utils/annotations.ts +56 -0
- package/src/utils/apiFetch.ts +19 -0
- package/src/utils/apiKeys.ts +305 -0
- package/src/utils/apiUrl.ts +42 -0
- package/src/utils/assets.ts +123 -0
- package/src/utils/baseRefConfig.ts +254 -0
- package/src/utils/billingErrors.ts +210 -0
- package/src/utils/body.ts +168 -0
- package/src/utils/buildInfraweaverFooter.ts +104 -0
- package/src/utils/byokFallback.ts +137 -0
- package/src/utils/changeImpact.ts +330 -0
- package/src/utils/claudeSubscription.ts +93 -0
- package/src/utils/cli.ts +36 -0
- package/src/utils/cloudClient.ts +57 -0
- package/src/utils/cloudFetchCore.ts +139 -0
- package/src/utils/cloudReport.ts +316 -0
- package/src/utils/codexHome.ts +204 -0
- package/src/utils/codexOAuth.ts +154 -0
- package/src/utils/codexRefreshDetect.ts +36 -0
- package/src/utils/diffCoverage.ts +404 -0
- package/src/utils/env.ts +84 -0
- package/src/utils/errorReport.ts +94 -0
- package/src/utils/exitHandler.ts +35 -0
- package/src/utils/fixDoubleEscapedString.ts +9 -0
- package/src/utils/ghaCore.ts +13 -0
- package/src/utils/gitAuth.ts +268 -0
- package/src/utils/gitAuthServer.ts +186 -0
- package/src/utils/github.ts +676 -0
- package/src/utils/globals.ts +9 -0
- package/src/utils/humanEditCapture.ts +198 -0
- package/src/utils/infraweaverConfig.ts +202 -0
- package/src/utils/install.ts +279 -0
- package/src/utils/instructions.ts +640 -0
- package/src/utils/keylessOidc.ts +47 -0
- package/src/utils/leapingComment.ts +20 -0
- package/src/utils/learnings.ts +145 -0
- package/src/utils/learningsTruncate.ts +42 -0
- package/src/utils/lifecycle.ts +198 -0
- package/src/utils/log.ts +452 -0
- package/src/utils/modelResolver.ts +105 -0
- package/src/utils/moduleFetch.ts +138 -0
- package/src/utils/normalizeEnv.ts +106 -0
- package/src/utils/openCodeModels.ts +86 -0
- package/src/utils/openaiCompatible.ts +52 -0
- package/src/utils/opentofuMcp.ts +61 -0
- package/src/utils/overrides.ts +100 -0
- package/src/utils/packageManager.ts +257 -0
- package/src/utils/patchWorkflowRunFields.ts +173 -0
- package/src/utils/payload.ts +1206 -0
- package/src/utils/prSummary.ts +148 -0
- package/src/utils/presets.ts +105 -0
- package/src/utils/progressComment.ts +266 -0
- package/src/utils/providerErrors.ts +189 -0
- package/src/utils/proxyModel.ts +239 -0
- package/src/utils/rangeDiff.ts +182 -0
- package/src/utils/redact.ts +86 -0
- package/src/utils/registryAuth.ts +115 -0
- package/src/utils/remediationCommand.ts +144 -0
- package/src/utils/retry.ts +180 -0
- package/src/utils/reviewCleanup.ts +116 -0
- package/src/utils/run.ts +100 -0
- package/src/utils/runContext.ts +276 -0
- package/src/utils/runContextData.ts +121 -0
- package/src/utils/runErrorRenderer.ts +282 -0
- package/src/utils/runFixture.ts +91 -0
- package/src/utils/runLifecycle.ts +360 -0
- package/src/utils/runStartupLog.ts +67 -0
- package/src/utils/secrets.ts +208 -0
- package/src/utils/setup.ts +368 -0
- package/src/utils/shell.ts +132 -0
- package/src/utils/skills.ts +67 -0
- package/src/utils/subprocess.ts +474 -0
- package/src/utils/terraformMcp.ts +99 -0
- package/src/utils/time.ts +59 -0
- package/src/utils/timer.ts +72 -0
- package/src/utils/todoTracking.ts +168 -0
- package/src/utils/token.ts +294 -0
- package/src/utils/toolLicensing.ts +152 -0
- package/src/utils/toolSelection.ts +239 -0
- package/src/utils/toon.ts +76 -0
- package/src/utils/version.ts +10 -0
- package/src/utils/versioning.ts +44 -0
- package/src/utils/vertex.ts +94 -0
- package/src/utils/workflow.ts +25 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* G7 — the noise-reduction learning loop.
|
|
3
|
+
*
|
|
4
|
+
* WHAT IT LEARNS FROM. Every time an org waives a rule it records a decision: a
|
|
5
|
+
* `rule`, a human `reason`, and (since the two-person gate) who proposed and who
|
|
6
|
+
* ratified it. When the SAME rule has been waived independently across several
|
|
7
|
+
* repos in a fleet, that is no longer a per-repo judgement — it is the org
|
|
8
|
+
* telling us, in writing and with reasons, that this finding type is noise for
|
|
9
|
+
* them. This module turns that record into a **surfacing** signal.
|
|
10
|
+
*
|
|
11
|
+
* WHAT IT IS NOT. Not suppression, and the distinction is the whole design:
|
|
12
|
+
*
|
|
13
|
+
* - A down-ranked finding is still **reported**, still **gates CI**, still
|
|
14
|
+
* appears in the **signed evidence** with an unchanged verdict. Only its
|
|
15
|
+
* position in "the top N that matter" moves.
|
|
16
|
+
* - The concern's `severity`, `category`, band and assessability are never
|
|
17
|
+
* touched. Nothing derived from a scanner's judgement is rewritten.
|
|
18
|
+
* - It applies to nothing at `critical` or `high`. A repeatedly-waived
|
|
19
|
+
* critical is a governance problem that should get LOUDER, not quieter, and
|
|
20
|
+
* an attacker who can get a rule waived across a fleet must not thereby be
|
|
21
|
+
* able to bury it.
|
|
22
|
+
*
|
|
23
|
+
* A ranking model that could hide a finding would be a liability in an evidence
|
|
24
|
+
* product; one that can only reorder the low-severity tail is a genuine
|
|
25
|
+
* ergonomic win with no honesty cost.
|
|
26
|
+
*
|
|
27
|
+
* WHY A THRESHOLD. One waiver is a decision, not a pattern — a single repo
|
|
28
|
+
* silencing a rule says nothing about the fleet. The signal needs
|
|
29
|
+
* {@link MIN_DISMISSAL_REPOS} *distinct repos*, counted per repo rather than
|
|
30
|
+
* per policy so that one repo with five overlapping path-scoped waivers cannot
|
|
31
|
+
* masquerade as five repos agreeing.
|
|
32
|
+
*
|
|
33
|
+
* ALWAYS REASON-LOGGED. An adjustment carries the repo count and the actual
|
|
34
|
+
* human reasons, and the scan output surfaces them next to the finding. A
|
|
35
|
+
* ranking that quietly demotes things is indistinguishable from a bug; one that
|
|
36
|
+
* says "ranked lower: 4 repos waived this — 'managed by the platform team'" is
|
|
37
|
+
* reviewable, and can be argued with.
|
|
38
|
+
*
|
|
39
|
+
* Pure. The profile arrives from Cloud over run-context as an untrusted blob
|
|
40
|
+
* (same shape and trust posture as §5.12's proven-fix library) and is coerced
|
|
41
|
+
* here before anything reads it.
|
|
42
|
+
*/
|
|
43
|
+
import type { Concern, Severity } from "#app/mcp/terraform/types";
|
|
44
|
+
|
|
45
|
+
/** Distinct repos that must have waived a rule before it is treated as fleet
|
|
46
|
+
* noise rather than one team's decision. */
|
|
47
|
+
export const MIN_DISMISSAL_REPOS = 3;
|
|
48
|
+
|
|
49
|
+
/** Severities a noise adjustment may never touch. A finding this loud stays
|
|
50
|
+
* where it is no matter how often it has been waived — see the module note. */
|
|
51
|
+
const PROTECTED_SEVERITIES: ReadonlySet<Severity> = new Set<Severity>(["critical", "high"]);
|
|
52
|
+
|
|
53
|
+
/** The largest amount a score may be reduced, and the floor it may not cross.
|
|
54
|
+
* Bounded so a down-rank reorders the tail rather than deleting a finding from
|
|
55
|
+
* practical view: a heavily-waived medium still outranks an untouched info. */
|
|
56
|
+
export const MAX_NOISE_PENALTY = 1.5;
|
|
57
|
+
export const NOISE_SCORE_FLOOR = 1;
|
|
58
|
+
|
|
59
|
+
/** How many distinct reasons to carry into the report. Enough to show the
|
|
60
|
+
* pattern; not so many that the finding's own text is buried. */
|
|
61
|
+
const MAX_REASONS_SURFACED = 3;
|
|
62
|
+
|
|
63
|
+
/** One rule's dismissal history across an org's fleet. */
|
|
64
|
+
export interface NoiseEntry {
|
|
65
|
+
/** the waived rule id, exactly as the org recorded it. */
|
|
66
|
+
rule: string;
|
|
67
|
+
/** DISTINCT repos that have waived it — never a raw policy count. */
|
|
68
|
+
repos: number;
|
|
69
|
+
/** the human reasons given, deduped, in the order Cloud returned them. */
|
|
70
|
+
reasons: string[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** The org's fleet-wide dismissal record, keyed by rule id. */
|
|
74
|
+
export type NoiseProfile = ReadonlyMap<string, NoiseEntry>;
|
|
75
|
+
|
|
76
|
+
export const EMPTY_NOISE_PROFILE: NoiseProfile = new Map();
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Coerce the untrusted run-context blob into a {@link NoiseProfile}.
|
|
80
|
+
*
|
|
81
|
+
* Every field is validated and anything malformed is dropped rather than
|
|
82
|
+
* defaulted: this data reorders a security report, so a blob that is not
|
|
83
|
+
* recognisably a dismissal record must produce NO adjustment instead of a
|
|
84
|
+
* plausible-looking one. Mirrors `fixMemory.coerceLibrary`.
|
|
85
|
+
*/
|
|
86
|
+
export function coerceNoiseProfile(raw: unknown): NoiseProfile {
|
|
87
|
+
if (!Array.isArray(raw)) return EMPTY_NOISE_PROFILE;
|
|
88
|
+
const out = new Map<string, NoiseEntry>();
|
|
89
|
+
for (const item of raw) {
|
|
90
|
+
if (typeof item !== "object" || item === null) continue;
|
|
91
|
+
const entry = item as Record<string, unknown>;
|
|
92
|
+
const rule = typeof entry.rule === "string" ? entry.rule.trim() : "";
|
|
93
|
+
if (!rule) continue;
|
|
94
|
+
// `repos` must be a real count. A non-integer, a negative, or a missing
|
|
95
|
+
// value means we cannot tell how many teams agreed — so we don't guess.
|
|
96
|
+
const repos = entry.repos;
|
|
97
|
+
if (typeof repos !== "number" || !Number.isInteger(repos) || repos < 1) continue;
|
|
98
|
+
const reasons = Array.isArray(entry.reasons)
|
|
99
|
+
? [
|
|
100
|
+
...new Set(
|
|
101
|
+
entry.reasons
|
|
102
|
+
.filter((r): r is string => typeof r === "string")
|
|
103
|
+
.map((r) => r.trim())
|
|
104
|
+
.filter(Boolean),
|
|
105
|
+
),
|
|
106
|
+
]
|
|
107
|
+
: [];
|
|
108
|
+
// last write wins on a duplicate rule — Cloud aggregates, so a duplicate is
|
|
109
|
+
// a serialisation artefact, not two different histories.
|
|
110
|
+
out.set(rule, { rule, repos, reasons });
|
|
111
|
+
}
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** A ranking adjustment, with the evidence for it. Never produced silently. */
|
|
116
|
+
export interface NoiseAdjustment {
|
|
117
|
+
/** how much the risk score was reduced (positive, ≤ {@link MAX_NOISE_PENALTY}). */
|
|
118
|
+
penalty: number;
|
|
119
|
+
/** distinct repos in the org that waived this rule. */
|
|
120
|
+
repos: number;
|
|
121
|
+
/** the human reasons they gave, truncated to {@link MAX_REASONS_SURFACED}. */
|
|
122
|
+
reasons: string[];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* The penalty for a rule with `repos` distinct dismissals.
|
|
127
|
+
*
|
|
128
|
+
* Logarithmic, not linear: the difference between three teams and four is
|
|
129
|
+
* meaningful, the difference between twenty and thirty is not, and a linear
|
|
130
|
+
* ramp would let a large fleet drive any rule to the floor. Saturates at
|
|
131
|
+
* {@link MAX_NOISE_PENALTY}.
|
|
132
|
+
*/
|
|
133
|
+
function penaltyFor(repos: number): number {
|
|
134
|
+
const over = repos - MIN_DISMISSAL_REPOS + 1;
|
|
135
|
+
const raw = MAX_NOISE_PENALTY * (Math.log2(over + 1) / Math.log2(9));
|
|
136
|
+
return Math.min(MAX_NOISE_PENALTY, Math.round(raw * 10) / 10);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The adjustment for one concern, or null when none applies.
|
|
141
|
+
*
|
|
142
|
+
* Returns null — rather than a zero penalty — when the rule is unknown, below
|
|
143
|
+
* the threshold, or protected by severity, so a caller cannot accidentally
|
|
144
|
+
* report "adjusted by 0" as if a judgement had been made.
|
|
145
|
+
*/
|
|
146
|
+
export function noiseAdjustmentFor(
|
|
147
|
+
concern: Pick<Concern, "rule_id" | "severity">,
|
|
148
|
+
profile: NoiseProfile,
|
|
149
|
+
): NoiseAdjustment | null {
|
|
150
|
+
if (PROTECTED_SEVERITIES.has(concern.severity)) return null;
|
|
151
|
+
const entry = profile.get(concern.rule_id);
|
|
152
|
+
if (!entry || entry.repos < MIN_DISMISSAL_REPOS) return null;
|
|
153
|
+
return {
|
|
154
|
+
penalty: penaltyFor(entry.repos),
|
|
155
|
+
repos: entry.repos,
|
|
156
|
+
reasons: entry.reasons.slice(0, MAX_REASONS_SURFACED),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Apply an adjustment to a risk score, clamped to {@link NOISE_SCORE_FLOOR}.
|
|
162
|
+
*
|
|
163
|
+
* The floor is what keeps this a re-ordering rather than a disappearance: a
|
|
164
|
+
* finding can be pushed down the list but never to zero, because zero reads as
|
|
165
|
+
* "nothing here" and something is definitely here.
|
|
166
|
+
*/
|
|
167
|
+
export function applyNoisePenalty(score: number, adjustment: NoiseAdjustment | null): number {
|
|
168
|
+
if (!adjustment) return score;
|
|
169
|
+
const adjusted = Math.max(NOISE_SCORE_FLOOR, score - adjustment.penalty);
|
|
170
|
+
return Math.round(adjusted * 10) / 10;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** One line explaining an adjustment, for the report. Deliberately states the
|
|
174
|
+
* bound as well as the reason — a reader must not infer that we hid anything. */
|
|
175
|
+
export function explainNoiseAdjustment(adjustment: NoiseAdjustment): string {
|
|
176
|
+
const reasons = adjustment.reasons.length
|
|
177
|
+
? ` — ${adjustment.reasons.map((r) => `"${r}"`).join("; ")}`
|
|
178
|
+
: "";
|
|
179
|
+
return (
|
|
180
|
+
`ranked lower: ${adjustment.repos} repos in this org have waived this rule${reasons}. ` +
|
|
181
|
+
"Still reported and still gating — only its position in the ranking changed."
|
|
182
|
+
);
|
|
183
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Idiomatic-normalisation DETECTION — the Refactor verb's companion to
|
|
3
|
+
* moduleExtraction.ts. Module extraction lifts raw resources behind a boundary;
|
|
4
|
+
* this finds the OTHER provably-equivalent refactor: in-place idiomatic cleanup of
|
|
5
|
+
* legacy HCL that changes STRUCTURE/SYNTAX but not behaviour, so a repo that is
|
|
6
|
+
* already modular but stylistically dated still has a real refactor to ship.
|
|
7
|
+
*
|
|
8
|
+
* Every kind here is a no-op the keys-free equivalence check proves: the resource
|
|
9
|
+
* set and per-resource argument NAMES are untouched, addresses don't move (zero
|
|
10
|
+
* `moved {}` needed), and `terraform validate` + `fmt` stay clean. That is the hard
|
|
11
|
+
* boundary — anything that changes a resource TYPE or the managed-resource set
|
|
12
|
+
* (e.g. `aws_launch_configuration`→`aws_launch_template`, `aws_elb`→`aws_lb`) is
|
|
13
|
+
* behaviour-ALTERING modernisation and belongs to Remediate, NOT here; the
|
|
14
|
+
* equivalence check would reject it as a resource-set diff anyway.
|
|
15
|
+
*
|
|
16
|
+
* Pure parsing over files already on disk — no subprocess, no network — mirroring
|
|
17
|
+
* moduleExtraction.ts.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { readFileSync } from "node:fs";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { type } from "arktype";
|
|
23
|
+
import type { LocalToolContext } from "#app/mcp/localContext";
|
|
24
|
+
import { walkTfFiles } from "#app/mcp/modules";
|
|
25
|
+
import { execute, tool, toolOk } from "#app/mcp/shared";
|
|
26
|
+
import { log } from "#app/utils/cli";
|
|
27
|
+
|
|
28
|
+
export type NormalizationKind = "redundant_interpolation" | "legacy_block_assignment";
|
|
29
|
+
|
|
30
|
+
export interface NormalizationSite {
|
|
31
|
+
kind: NormalizationKind;
|
|
32
|
+
/** 1-based line of the offending snippet. */
|
|
33
|
+
line: number;
|
|
34
|
+
/** the snippet as written. */
|
|
35
|
+
before: string;
|
|
36
|
+
/** the idiomatic, behaviour-identical rewrite (advisory — the agent writes the edit). */
|
|
37
|
+
after: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// --- redundant whole-string interpolation (pure) -----------------------------
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Find the index of the closing `}` matching the `{` at `openBrace`, string-aware
|
|
44
|
+
* (a `}` inside a nested string literal doesn't close it) and nesting-aware.
|
|
45
|
+
* Mutually recursive with {@link stringLiteralEnd} so `${file("x{}y")}` matches.
|
|
46
|
+
*/
|
|
47
|
+
function interpolationEnd(hcl: string, openBrace: number): number {
|
|
48
|
+
let depth = 0;
|
|
49
|
+
for (let i = openBrace; i < hcl.length; i++) {
|
|
50
|
+
const ch = hcl[i];
|
|
51
|
+
if (ch === '"') {
|
|
52
|
+
i = stringLiteralEnd(hcl, i);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (ch === "{") depth++;
|
|
56
|
+
else if (ch === "}") {
|
|
57
|
+
depth--;
|
|
58
|
+
if (depth === 0) return i;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return hcl.length - 1;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The index of the closing quote of the string literal opening at `openQuote`,
|
|
66
|
+
* escape-aware and interpolation-aware (a `"` inside a `${ … }` is part of the
|
|
67
|
+
* interpolation, not the string's end — `"${coalesce(var.a, "x")}"`).
|
|
68
|
+
*/
|
|
69
|
+
function stringLiteralEnd(hcl: string, openQuote: number): number {
|
|
70
|
+
for (let i = openQuote + 1; i < hcl.length; i++) {
|
|
71
|
+
const ch = hcl[i];
|
|
72
|
+
if (ch === "\\") {
|
|
73
|
+
i++;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (ch === '"') return i;
|
|
77
|
+
if ((ch === "$" || ch === "%") && hcl[i + 1] === "{") {
|
|
78
|
+
i = interpolationEnd(hcl, i + 1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return hcl.length - 1;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** 1-based line number of `index` in `hcl`. */
|
|
85
|
+
function lineOf(hcl: string, index: number): number {
|
|
86
|
+
let line = 1;
|
|
87
|
+
for (let i = 0; i < index && i < hcl.length; i++) if (hcl[i] === "\n") line++;
|
|
88
|
+
return line;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Find every string literal that is EXACTLY one full-span interpolation
|
|
93
|
+
* (`"${ expr }"`), where dropping the wrapper to a bare `expr` is a behaviour-
|
|
94
|
+
* identical HCL2 rewrite (the canonical 0.11→0.12 cleanup). Skips comments and
|
|
95
|
+
* heredocs, and naturally excludes `"$${literal}"` (an escaped, non-interpolated
|
|
96
|
+
* `${`) and partial templates like `"${a}-${b}"` (where the quotes are load-bearing).
|
|
97
|
+
*/
|
|
98
|
+
export function findRedundantInterpolations(hcl: string): NormalizationSite[] {
|
|
99
|
+
const out: NormalizationSite[] = [];
|
|
100
|
+
for (let i = 0; i < hcl.length; i++) {
|
|
101
|
+
const ch = hcl[i];
|
|
102
|
+
// skip line comments
|
|
103
|
+
if (ch === "#" || (ch === "/" && hcl[i + 1] === "/")) {
|
|
104
|
+
const nl = hcl.indexOf("\n", i);
|
|
105
|
+
if (nl === -1) break;
|
|
106
|
+
i = nl;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
// skip block comments
|
|
110
|
+
if (ch === "/" && hcl[i + 1] === "*") {
|
|
111
|
+
const close = hcl.indexOf("*/", i + 2);
|
|
112
|
+
i = close === -1 ? hcl.length : close + 1;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
// skip heredocs (their bodies are templates we don't normalise)
|
|
116
|
+
if (ch === "<" && hcl[i + 1] === "<") {
|
|
117
|
+
const m = /^<<[-~]?([A-Za-z_][A-Za-z0-9_]*)/.exec(hcl.slice(i, i + 80));
|
|
118
|
+
if (m) {
|
|
119
|
+
const openNl = hcl.indexOf("\n", i);
|
|
120
|
+
if (openNl === -1) break;
|
|
121
|
+
const cm = new RegExp(`\\n[ \\t]*${m[1]}[ \\t]*(?=\\n|$)`).exec(hcl.slice(openNl));
|
|
122
|
+
i = cm ? openNl + cm.index + cm[0].length - 1 : hcl.length;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (ch !== '"') continue;
|
|
127
|
+
const end = stringLiteralEnd(hcl, i);
|
|
128
|
+
// full-span single interpolation: opens `${`, and its matching `}` is the last
|
|
129
|
+
// inner char (immediately before the closing quote).
|
|
130
|
+
if (hcl[i + 1] === "$" && hcl[i + 2] === "{") {
|
|
131
|
+
const close = interpolationEnd(hcl, i + 2);
|
|
132
|
+
if (close === end - 1) {
|
|
133
|
+
const expr = hcl.slice(i + 3, close).trim();
|
|
134
|
+
if (expr) {
|
|
135
|
+
out.push({
|
|
136
|
+
kind: "redundant_interpolation",
|
|
137
|
+
line: lineOf(hcl, i),
|
|
138
|
+
before: hcl.slice(i, end + 1),
|
|
139
|
+
after: expr,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
i = end;
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// --- legacy HCL0.11 map-argument block syntax (pure) --------------------------
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* HCL0.11 assigned a map/object argument with a bare block — `config { … }` — where
|
|
153
|
+
* HCL2 requires `config = { … }`. The argument is the same name and the same data,
|
|
154
|
+
* so the conversion is behaviour-preserving (and `terraform validate` rejects the
|
|
155
|
+
* old form on modern Terraform). Limited to the well-known offenders so the
|
|
156
|
+
* line-level match can't mistake a genuine nested block for a map argument.
|
|
157
|
+
*/
|
|
158
|
+
const LEGACY_BLOCK_ARGS: ReadonlySet<string> = new Set(["config", "vars"]);
|
|
159
|
+
|
|
160
|
+
export function findLegacyBlockAssignments(hcl: string): NormalizationSite[] {
|
|
161
|
+
const out: NormalizationSite[] = [];
|
|
162
|
+
const lines = hcl.split("\n");
|
|
163
|
+
for (let n = 0; n < lines.length; n++) {
|
|
164
|
+
const m = /^(\s*)([A-Za-z_][A-Za-z0-9_]*)\s*\{\s*$/.exec(lines[n] ?? "");
|
|
165
|
+
if (m && LEGACY_BLOCK_ARGS.has(m[2] ?? "")) {
|
|
166
|
+
out.push({
|
|
167
|
+
kind: "legacy_block_assignment",
|
|
168
|
+
line: n + 1,
|
|
169
|
+
before: `${m[2]} {`,
|
|
170
|
+
after: `${m[2]} = {`,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return out;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** every normalisation site in one file, in line order. */
|
|
178
|
+
export function scanNormalizations(hcl: string): NormalizationSite[] {
|
|
179
|
+
return [...findRedundantInterpolations(hcl), ...findLegacyBlockAssignments(hcl)].sort(
|
|
180
|
+
(a, b) => a.line - b.line,
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// --- workspace scan (I/O composition) ----------------------------------------
|
|
185
|
+
|
|
186
|
+
export interface NormalizationFile {
|
|
187
|
+
file: string;
|
|
188
|
+
count: number;
|
|
189
|
+
kind_counts: Record<NormalizationKind, number>;
|
|
190
|
+
/** a capped sample of the actual sites, for the agent to anchor its edits. */
|
|
191
|
+
sites: NormalizationSite[];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** files shown in the result, and sites shown per file — caps so a legacy-heavy
|
|
195
|
+
* repo reports a digestible summary, not a thousand-line dump. */
|
|
196
|
+
const MAX_FILES = 30;
|
|
197
|
+
const MAX_SITES_PER_FILE = 12;
|
|
198
|
+
|
|
199
|
+
export function findNormalizationCandidates(cwd: string): NormalizationFile[] {
|
|
200
|
+
const out: NormalizationFile[] = [];
|
|
201
|
+
for (const rel of walkTfFiles(cwd)) {
|
|
202
|
+
let text: string;
|
|
203
|
+
try {
|
|
204
|
+
text = readFileSync(join(cwd, rel), "utf8");
|
|
205
|
+
} catch {
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
const sites = scanNormalizations(text);
|
|
209
|
+
if (sites.length === 0) continue;
|
|
210
|
+
const kindCounts: Record<NormalizationKind, number> = {
|
|
211
|
+
redundant_interpolation: 0,
|
|
212
|
+
legacy_block_assignment: 0,
|
|
213
|
+
};
|
|
214
|
+
for (const s of sites) kindCounts[s.kind]++;
|
|
215
|
+
out.push({
|
|
216
|
+
file: rel.replace(/\\/g, "/"),
|
|
217
|
+
count: sites.length,
|
|
218
|
+
kind_counts: kindCounts,
|
|
219
|
+
sites: sites.slice(0, MAX_SITES_PER_FILE),
|
|
220
|
+
});
|
|
221
|
+
if (out.length >= MAX_FILES) break;
|
|
222
|
+
}
|
|
223
|
+
return out;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// --- the tool ----------------------------------------------------------------
|
|
227
|
+
|
|
228
|
+
export const NormalizationCandidatesParams = type({});
|
|
229
|
+
|
|
230
|
+
export function NormalizationCandidatesTool(ctx: LocalToolContext) {
|
|
231
|
+
return tool({
|
|
232
|
+
name: "terraform_normalization_candidates",
|
|
233
|
+
description:
|
|
234
|
+
"Find BEHAVIOUR-PRESERVING idiomatic-normalisation opportunities in the Terraform tree — the Refactor " +
|
|
235
|
+
"companion to module_extraction_candidates for code that is already modular but stylistically dated. " +
|
|
236
|
+
"Detects (1) redundant whole-string interpolation wrapping — a quoted string that is exactly one " +
|
|
237
|
+
"interpolation, unwrapped to the bare expression (the canonical HCL 0.11→0.12 cleanup) — and (2) legacy " +
|
|
238
|
+
"HCL0.11 map-argument block syntax (`config {`/`vars {` → `config = {`). Both " +
|
|
239
|
+
"leave the managed-resource set and every resource's argument NAMES identical, so they need ZERO " +
|
|
240
|
+
"`moved {}` blocks and are proven a no-op by terraform_equivalence_check (resource set + args unchanged, " +
|
|
241
|
+
"validate + fmt clean). This is the path when there are no extraction clusters worth a module but the " +
|
|
242
|
+
"code is plainly non-idiomatic. HARD BOUNDARY: it never includes behaviour-CHANGING modernisation — a " +
|
|
243
|
+
"resource-type swap (`aws_launch_configuration`→`aws_launch_template`, `aws_elb`→`aws_lb`) alters the " +
|
|
244
|
+
"resource set and is Remediate's job, not a refactor. Returns per-file `count`, `kind_counts`, and a " +
|
|
245
|
+
"capped `sites` sample (each with `line`, `before`, `after`).",
|
|
246
|
+
parameters: NormalizationCandidatesParams,
|
|
247
|
+
execute: execute(async () => {
|
|
248
|
+
const cwd = ctx.payload.cwd ?? process.cwd();
|
|
249
|
+
const files = findNormalizationCandidates(cwd);
|
|
250
|
+
const total = files.reduce((n, f) => n + f.count, 0);
|
|
251
|
+
log.info(
|
|
252
|
+
`» terraform_normalization_candidates: ${total} site(s) across ${files.length} file(s)`,
|
|
253
|
+
);
|
|
254
|
+
return toolOk({
|
|
255
|
+
file_count: files.length,
|
|
256
|
+
total,
|
|
257
|
+
files,
|
|
258
|
+
note:
|
|
259
|
+
total === 0
|
|
260
|
+
? "no idiomatic-normalisation opportunities found (redundant interpolation / legacy block syntax)"
|
|
261
|
+
: "apply these in-place edits (they keep the resource set + argument names identical), then PROVE the no-op with terraform_equivalence_check (zero moves expected) — never include a resource-type swap, that ALTERS behaviour and is Remediate's job",
|
|
262
|
+
});
|
|
263
|
+
}),
|
|
264
|
+
});
|
|
265
|
+
}
|