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,557 @@
|
|
|
1
|
+
import { type } from "arktype";
|
|
2
|
+
import { PRODUCT_NAME, PRODUCT_SLUG } from "#app/brand";
|
|
3
|
+
import type { GitHubToolContext } from "#app/mcp/capabilityContext";
|
|
4
|
+
import { addFooter } from "#app/mcp/comment";
|
|
5
|
+
import { assertTargetInScope } from "#app/mcp/scope";
|
|
6
|
+
import { execute, tool, toolOk } from "#app/mcp/shared";
|
|
7
|
+
import { log } from "#app/utils/cli";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Stale-fix self-healing. A Infraweaver remediation PR is "base + a minimal,
|
|
11
|
+
* proven fix". When the base branch advances after the PR is opened, the PR goes
|
|
12
|
+
* stale: its diff is computed against an old base, the concern may already be
|
|
13
|
+
* resolved upstream (a human fixed it, or the base changed the file), or the
|
|
14
|
+
* branch simply needs re-deriving on the new base. A scheduled `RefreshRemediation`
|
|
15
|
+
* run sweeps the open remediation PRs and, per PR, either re-derives the fix on
|
|
16
|
+
* the current base and force-updates it, closes it as already-resolved, or leaves
|
|
17
|
+
* it for a human when someone has added their own commits.
|
|
18
|
+
*
|
|
19
|
+
* This file is the GitHub-orchestration seam: a pure classifier (`assessStaleFix`)
|
|
20
|
+
* that decides what to do from git facts, the read tool that surfaces the open
|
|
21
|
+
* remediation PRs with their staleness, and the focused write tool that closes a
|
|
22
|
+
* now-redundant PR. The actual re-derive/validate/verify loop is driven by the
|
|
23
|
+
* mode prompt using the existing scan/validate/verify/push tools — no git merge
|
|
24
|
+
* is performed (re-deriving on the fresh base avoids conflict resolution entirely
|
|
25
|
+
* and keeps the PR diff to exactly the fix).
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
// the branch-name conventions Infraweaver opens PRs under: `remediate/<group-id>`
|
|
29
|
+
// (incl. `remediate/batch-<hash>`) for a fix and `infraweaver/generate-<slug>` for
|
|
30
|
+
// a generation. The naming is the primary "this is Infraweaver's PR" signal.
|
|
31
|
+
const REMEDIATION_BRANCH = /^(?:remediate\/|infraweaver\/generate-)/;
|
|
32
|
+
|
|
33
|
+
/** true when `branch` is a Infraweaver remediation/generation branch. */
|
|
34
|
+
export function isRemediationBranch(branch: string): boolean {
|
|
35
|
+
return REMEDIATION_BRANCH.test(branch);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** the `<group-id>` of a `remediate/<group-id>` branch (the scan group id that
|
|
39
|
+
* keys the fix), or null for a generation branch / non-remediation branch. */
|
|
40
|
+
export function groupIdFromBranch(branch: string): string | null {
|
|
41
|
+
return branch.match(/^remediate\/(.+)$/)?.[1] ?? null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** core matcher: a NON-EMPTY identity string (a GitHub login or a git author
|
|
45
|
+
* name) that belongs to a bot — Infraweaver's own, or any `[bot]` account. */
|
|
46
|
+
function matchesBotIdentity(identity: string): boolean {
|
|
47
|
+
const normalized = identity.replace(/\[bot\]$/i, "").toLowerCase();
|
|
48
|
+
return (
|
|
49
|
+
normalized === PRODUCT_SLUG ||
|
|
50
|
+
normalized === `${PRODUCT_SLUG}dev` ||
|
|
51
|
+
/\[bot\]$/i.test(identity)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** a git author email belonging to a bot noreply account, e.g.
|
|
56
|
+
* `infraweaver[bot]@users.noreply.github.com`. */
|
|
57
|
+
function isBotEmail(email: string): boolean {
|
|
58
|
+
return /\[bot\]@/i.test(email);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** true when a commit-author LOGIN is Infraweaver's bot (so a commit by it is NOT
|
|
62
|
+
* a human edit). A null/absent login is treated as non-human here for backward
|
|
63
|
+
* compatibility of this login-only helper — but prefer {@link isBotCommit}, which
|
|
64
|
+
* resolves an absent login via the commit's git identity rather than assuming
|
|
65
|
+
* bot (the assumption that caused a human commit with an unlinked email to be
|
|
66
|
+
* force-overwritten). */
|
|
67
|
+
export function isBotActor(login: string | null | undefined): boolean {
|
|
68
|
+
if (!login) return true;
|
|
69
|
+
return matchesBotIdentity(login);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** the authorship slice of a compareCommits entry that {@link isBotCommit} reads. */
|
|
73
|
+
export interface CommitAuthorship {
|
|
74
|
+
/** the GitHub user GitHub resolved from the commit's author email, or null when
|
|
75
|
+
* the email isn't linked to any account — true for Infraweaver's own `[bot]`
|
|
76
|
+
* noreply email AND for a human committing under an unverified email. */
|
|
77
|
+
author?: { login?: string | null } | null;
|
|
78
|
+
/** the raw git author identity from the commit object, present even when the
|
|
79
|
+
* GitHub `author` account above is null. */
|
|
80
|
+
commit?: {
|
|
81
|
+
author?: { name?: string | null; email?: string | null } | null;
|
|
82
|
+
} | null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Decide whether a remediation-branch commit is Infraweaver's own (a bot commit,
|
|
87
|
+
* safe to force-overwrite on refresh) or a human/third-party edit (must be
|
|
88
|
+
* preserved — escalate instead of refresh).
|
|
89
|
+
*
|
|
90
|
+
* A resolved GitHub `author.login` is authoritative: a positive bot match is a
|
|
91
|
+
* bot, a real login is a human. When the login is ABSENT — which happens both for
|
|
92
|
+
* Infraweaver's own commits (its `infraweaver[bot]` noreply email doesn't map to a
|
|
93
|
+
* GitHub account) and for a human committing under an unverified email — fall
|
|
94
|
+
* back to the commit's git identity: only a recognised bot name/email
|
|
95
|
+
* (`infraweaver[bot]`, any `[bot]`) counts as a bot; ANY other identity is treated
|
|
96
|
+
* as a human edit. This is the conservative direction on purpose — a missed bot
|
|
97
|
+
* commit costs one skipped auto-refresh, whereas a missed human commit is a
|
|
98
|
+
* force-push that destroys their work.
|
|
99
|
+
*/
|
|
100
|
+
export function isBotCommit(commit: CommitAuthorship): boolean {
|
|
101
|
+
const login = commit.author?.login;
|
|
102
|
+
if (login) return isBotActor(login);
|
|
103
|
+
const name = commit.commit?.author?.name ?? "";
|
|
104
|
+
const email = commit.commit?.author?.email ?? "";
|
|
105
|
+
return matchesBotIdentity(name) || isBotEmail(email);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export type StaleFixStatus =
|
|
109
|
+
| "current"
|
|
110
|
+
| "stale"
|
|
111
|
+
| "human_touched"
|
|
112
|
+
| "checks_failing";
|
|
113
|
+
export type StaleFixAction = "skip" | "refresh" | "escalate";
|
|
114
|
+
|
|
115
|
+
/** the latest CI conclusion on a remediation PR's head, used to self-heal a PR
|
|
116
|
+
* whose own checks are red (a failed `terraform plan`, a failing module test, a
|
|
117
|
+
* policy gate) even when its base hasn't moved. `unknown` = no checks reported or
|
|
118
|
+
* the read failed (treated as "no signal" — never manufactures a refresh). */
|
|
119
|
+
export type ChecksState = "passing" | "failing" | "pending" | "unknown";
|
|
120
|
+
|
|
121
|
+
/** check-run conclusions that count as a hard CI failure for self-heal purposes.
|
|
122
|
+
* `neutral`/`skipped`/`stale`/`cancelled`/`success` are NOT failures. */
|
|
123
|
+
const FAILING_CONCLUSIONS = new Set([
|
|
124
|
+
"failure",
|
|
125
|
+
"timed_out",
|
|
126
|
+
"action_required",
|
|
127
|
+
]);
|
|
128
|
+
|
|
129
|
+
export interface StaleFixAssessment {
|
|
130
|
+
status: StaleFixStatus;
|
|
131
|
+
action: StaleFixAction;
|
|
132
|
+
reason: string;
|
|
133
|
+
/** a likely zombie: stale (base advanced), untouched by humans, and open past
|
|
134
|
+
* the staleness age threshold — surface it so the sweep prioritizes closing it
|
|
135
|
+
* once the concern is confirmed resolved. Advisory; the action stays `refresh`. */
|
|
136
|
+
zombie: boolean;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** age (in days, PR open duration) past which a stale, untouched remediation PR
|
|
140
|
+
* is flagged as a likely zombie for prioritized cleanup. */
|
|
141
|
+
export const DEFAULT_STALE_AFTER_DAYS = 30;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* How many times the sweep will auto re-derive a remediation PR to clear a FAILING
|
|
145
|
+
* CI check before it gives up and escalates to a human. Self-heal is on by default,
|
|
146
|
+
* but a fix the engine proves green locally yet that keeps failing the consumer's
|
|
147
|
+
* CI (a cloud-credentialled `terraform plan`, a flaky integration test) must not
|
|
148
|
+
* loop forever — past the cap the PR is labelled needs-human and left alone. Only
|
|
149
|
+
* the checks-failing path is capped; a genuine base move is always a fresh refresh.
|
|
150
|
+
*/
|
|
151
|
+
export const DEFAULT_SELF_HEAL_MAX_ATTEMPTS = 3;
|
|
152
|
+
|
|
153
|
+
/** the per-attempt label the sweep stamps on a PR each time it self-heals a red
|
|
154
|
+
* CI, so the retry budget survives across stateless runs. Accumulating (add-only):
|
|
155
|
+
* the attempt count is how many are present. */
|
|
156
|
+
const SELF_HEAL_ATTEMPT_LABEL = /^infraweaver-self-heal-attempt-\d+$/;
|
|
157
|
+
|
|
158
|
+
/** count of self-heal attempts already recorded on a PR, from its accumulated
|
|
159
|
+
* `infraweaver-self-heal-attempt-N` labels. */
|
|
160
|
+
export function selfHealAttempts(labels: string[]): number {
|
|
161
|
+
return labels.filter((l) => SELF_HEAL_ATTEMPT_LABEL.test(l)).length;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** the label to stamp when recording the next self-heal attempt (1-based). */
|
|
165
|
+
export function nextSelfHealLabel(attempts: number): string {
|
|
166
|
+
return `infraweaver-self-heal-attempt-${attempts + 1}`;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Decide what a refresh sweep should do with one open remediation PR, from git +
|
|
171
|
+
* CI facts alone. Pure.
|
|
172
|
+
* - a branch carrying NON-bot commits is `human_touched` → `escalate` (never
|
|
173
|
+
* force-overwrite a human's work; leave it for review).
|
|
174
|
+
* - a branch whose base has NOT advanced AND whose checks are not failing is
|
|
175
|
+
* `current` → `skip` (the fix is still derived against the live base).
|
|
176
|
+
* - a branch whose own CI is red (and base unchanged) is `checks_failing` →
|
|
177
|
+
* `refresh`: re-derive the fix on the current base and re-prove it (the
|
|
178
|
+
* self-heal case — a failed plan/test/policy on Infraweaver's own PR). Two guards
|
|
179
|
+
* stop this looping forever: (1) if it is ALREADY labelled needs-human and the
|
|
180
|
+
* base hasn't moved, re-deriving would only reproduce the same failing fix, so
|
|
181
|
+
* `skip`; (2) once `selfHealAttempts` reaches `maxSelfHealAttempts` (default 3)
|
|
182
|
+
* the sweep gives up and `escalate`s instead of re-deriving again.
|
|
183
|
+
* - otherwise the base moved → `stale` → `refresh`: re-derive the fix on the
|
|
184
|
+
* current base, then close it if the concern is already resolved or update it.
|
|
185
|
+
*
|
|
186
|
+
* `ageDays` (PR open duration) is advisory: a stale, untouched PR open past
|
|
187
|
+
* `staleAfterDays` is additionally flagged `zombie` so the sweep can prioritize
|
|
188
|
+
* clearing the long-rotting ones. It never changes the action — a fix is only
|
|
189
|
+
* ever closed once a re-scan confirms its concern is actually resolved.
|
|
190
|
+
*/
|
|
191
|
+
export function assessStaleFix(input: {
|
|
192
|
+
baseBehindBy: number;
|
|
193
|
+
hasNonBotCommits: boolean;
|
|
194
|
+
/** the PR's CI is red (a failed plan/test/policy) — triggers a self-heal. */
|
|
195
|
+
checksFailing?: boolean;
|
|
196
|
+
/** the PR already carries `needs-human` — used as the self-heal loop guard. */
|
|
197
|
+
alreadyEscalated?: boolean;
|
|
198
|
+
/** self-heal attempts already recorded on this PR (from its attempt labels). */
|
|
199
|
+
selfHealAttempts?: number;
|
|
200
|
+
/** the retry ceiling for self-heal (default {@link DEFAULT_SELF_HEAL_MAX_ATTEMPTS}). */
|
|
201
|
+
maxSelfHealAttempts?: number;
|
|
202
|
+
ageDays?: number;
|
|
203
|
+
staleAfterDays?: number;
|
|
204
|
+
}): StaleFixAssessment {
|
|
205
|
+
if (input.hasNonBotCommits) {
|
|
206
|
+
return {
|
|
207
|
+
status: "human_touched",
|
|
208
|
+
action: "escalate",
|
|
209
|
+
reason: `the PR branch has commit(s) not authored by ${PRODUCT_SLUG} — auto-refresh would overwrite a human's work; label it needs-human and leave it for review`,
|
|
210
|
+
zombie: false,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
const baseMoved = input.baseBehindBy > 0;
|
|
214
|
+
const checksFailing = input.checksFailing === true;
|
|
215
|
+
|
|
216
|
+
if (!baseMoved && !checksFailing) {
|
|
217
|
+
return {
|
|
218
|
+
status: "current",
|
|
219
|
+
action: "skip",
|
|
220
|
+
reason:
|
|
221
|
+
"the base has not advanced since the PR was opened — the fix is still current",
|
|
222
|
+
zombie: false,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// self-heal loop guard: a still-failing PR we already escalated, with an
|
|
227
|
+
// unchanged base, would only re-derive the same failing fix — leave it.
|
|
228
|
+
if (!baseMoved && checksFailing && input.alreadyEscalated) {
|
|
229
|
+
return {
|
|
230
|
+
status: "checks_failing",
|
|
231
|
+
action: "skip",
|
|
232
|
+
reason:
|
|
233
|
+
"the PR's checks are failing but it is already labelled needs-human and the base has not moved — left for a human to avoid a refresh loop",
|
|
234
|
+
zombie: false,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// checks-failing only (base unchanged): self-heal — re-derive + re-prove. Bounded
|
|
239
|
+
// by the retry cap so a fix the engine proves green locally but that keeps failing
|
|
240
|
+
// the consumer's CI can't loop forever.
|
|
241
|
+
if (!baseMoved && checksFailing) {
|
|
242
|
+
const attempts = input.selfHealAttempts ?? 0;
|
|
243
|
+
const max = input.maxSelfHealAttempts ?? DEFAULT_SELF_HEAL_MAX_ATTEMPTS;
|
|
244
|
+
if (attempts >= max) {
|
|
245
|
+
return {
|
|
246
|
+
status: "checks_failing",
|
|
247
|
+
action: "escalate",
|
|
248
|
+
reason: `self-heal exhausted its retry budget (${attempts}/${max} attempts) without clearing CI — escalate to needs-human and STOP; no further auto-retry on this PR`,
|
|
249
|
+
zombie: false,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
status: "checks_failing",
|
|
254
|
+
action: "refresh",
|
|
255
|
+
reason:
|
|
256
|
+
`the PR's checks are failing while the base is unchanged — self-heal attempt ${attempts + 1} of ${max}: ` +
|
|
257
|
+
"re-derive the fix on the current base and re-prove it (✗→✓), then stamp the attempt label. " +
|
|
258
|
+
"If the re-derived fix still can't be proven green, escalate to needs-human instead of force-pushing a known-failing fix.",
|
|
259
|
+
zombie: false,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// base moved (the original staleness case; checks may also be red).
|
|
264
|
+
const threshold = input.staleAfterDays ?? DEFAULT_STALE_AFTER_DAYS;
|
|
265
|
+
const ageDays = input.ageDays;
|
|
266
|
+
const zombie = ageDays !== undefined && ageDays >= threshold;
|
|
267
|
+
const ageNote =
|
|
268
|
+
zombie && ageDays !== undefined
|
|
269
|
+
? ` It has been open ${Math.floor(ageDays)} day(s) (≥ ${threshold}) with no human commits — a likely zombie; prioritize closing it once the concern is confirmed resolved.`
|
|
270
|
+
: "";
|
|
271
|
+
return {
|
|
272
|
+
status: "stale",
|
|
273
|
+
action: "refresh",
|
|
274
|
+
reason:
|
|
275
|
+
`the base advanced ${input.baseBehindBy} commit(s) since the PR was opened — re-scan on the current base, ` +
|
|
276
|
+
"then close the PR if the concern is already resolved or re-derive + force-update the fix otherwise." +
|
|
277
|
+
(checksFailing
|
|
278
|
+
? " Its checks are also failing — re-prove the fix is green before force-updating."
|
|
279
|
+
: "") +
|
|
280
|
+
ageNote,
|
|
281
|
+
zombie,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** Minimal shape of `octokit.rest.checks.listForRef` — typed as optional so a
|
|
286
|
+
* mock/older client without the Checks API degrades to `unknown` rather than
|
|
287
|
+
* throwing. */
|
|
288
|
+
type ChecksListForRef = (args: {
|
|
289
|
+
owner: string;
|
|
290
|
+
repo: string;
|
|
291
|
+
ref: string;
|
|
292
|
+
per_page?: number;
|
|
293
|
+
}) => Promise<{
|
|
294
|
+
data: { check_runs?: Array<{ status?: string; conclusion?: string | null }> };
|
|
295
|
+
}>;
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Best-effort read of the latest CI conclusion on a PR head SHA via the Checks
|
|
299
|
+
* API, for self-healing a remediation PR whose own checks are red. A missing
|
|
300
|
+
* `sha`, an absent Checks API, or any read error returns `unknown` — a failed
|
|
301
|
+
* read must never manufacture a refresh.
|
|
302
|
+
*/
|
|
303
|
+
async function readChecksState(
|
|
304
|
+
ctx: GitHubToolContext,
|
|
305
|
+
owner: string,
|
|
306
|
+
repo: string,
|
|
307
|
+
sha: string | undefined,
|
|
308
|
+
): Promise<ChecksState> {
|
|
309
|
+
const listForRef = (
|
|
310
|
+
ctx.octokit.rest.checks as { listForRef?: ChecksListForRef } | undefined
|
|
311
|
+
)?.listForRef;
|
|
312
|
+
if (!sha || !listForRef) return "unknown";
|
|
313
|
+
try {
|
|
314
|
+
const res = await listForRef({ owner, repo, ref: sha, per_page: 100 });
|
|
315
|
+
const runs = res.data?.check_runs ?? [];
|
|
316
|
+
if (runs.length === 0) return "unknown";
|
|
317
|
+
if (runs.some((c) => c.status !== "completed")) return "pending";
|
|
318
|
+
if (runs.some((c) => FAILING_CONCLUSIONS.has(c.conclusion ?? "")))
|
|
319
|
+
return "failing";
|
|
320
|
+
return "passing";
|
|
321
|
+
} catch (e) {
|
|
322
|
+
log.info(
|
|
323
|
+
`» checks read skipped for ${sha.slice(0, 7)}: ${e instanceof Error ? e.message : e}`,
|
|
324
|
+
);
|
|
325
|
+
return "unknown";
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
interface AssessedRemediationPr {
|
|
330
|
+
number: number;
|
|
331
|
+
url: string;
|
|
332
|
+
title: string;
|
|
333
|
+
branch: string;
|
|
334
|
+
base: string;
|
|
335
|
+
group_id: string | null;
|
|
336
|
+
base_behind_by: number;
|
|
337
|
+
head_ahead_by: number;
|
|
338
|
+
has_non_bot_commits: boolean;
|
|
339
|
+
commit_authors: string[];
|
|
340
|
+
labels: string[];
|
|
341
|
+
checks_state: ChecksState;
|
|
342
|
+
/** self-heal attempts already recorded (from the accumulated attempt labels). The
|
|
343
|
+
* sweep stops auto-retrying a red PR once this hits the cap (default 3). */
|
|
344
|
+
self_heal_attempts: number;
|
|
345
|
+
age_days: number;
|
|
346
|
+
status: StaleFixStatus;
|
|
347
|
+
recommended_action: StaleFixAction;
|
|
348
|
+
zombie: boolean;
|
|
349
|
+
reason: string;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export const ListRemediationPrsParams = type({
|
|
353
|
+
"limit?": type.number.describe(
|
|
354
|
+
"max open remediation PRs to assess (default 30). Each is one compare-commits API call.",
|
|
355
|
+
),
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
export function ListRemediationPrsTool(ctx: GitHubToolContext) {
|
|
359
|
+
return tool({
|
|
360
|
+
name: "list_remediation_prs",
|
|
361
|
+
description:
|
|
362
|
+
`List the repo's OPEN ${PRODUCT_NAME} remediation/generation PRs (branches \`remediate/<id>\` or ` +
|
|
363
|
+
"`infraweaver/generate-<slug>`) with their staleness, so a refresh sweep knows which to act on. For each " +
|
|
364
|
+
"PR it compares the head branch against its base and returns `base_behind_by` (how many commits the " +
|
|
365
|
+
"base advanced since the PR was opened), `head_ahead_by`, `has_non_bot_commits` (a human pushed to the " +
|
|
366
|
+
"branch), the `group_id`, labels, and a `recommended_action`: `skip` (still current), `refresh` (base " +
|
|
367
|
+
"moved — re-derive the fix on the current base, then close-if-resolved or force-update), or `escalate` " +
|
|
368
|
+
"(human-touched — label needs-human, don't overwrite). It also returns `age_days` and a `zombie` flag " +
|
|
369
|
+
"(stale + no human commits + open ≥ 30 days) so you can prioritize clearing long-rotting PRs. It also " +
|
|
370
|
+
"reports each PR's `checks_state` (passing/failing/pending/unknown): a PR whose OWN CI is failing (a red " +
|
|
371
|
+
"`terraform plan`, a failing module test, a policy gate) is recommended for `refresh` even when its base " +
|
|
372
|
+
"hasn't moved — self-heal — unless it's already labelled needs-human (then it's left for a human to avoid " +
|
|
373
|
+
"a loop). Self-heal is bounded: each PR carries `self_heal_attempts` (counted from its " +
|
|
374
|
+
"`infraweaver-self-heal-attempt-N` labels) and after the cap (3) a still-red PR is recommended for `escalate`, " +
|
|
375
|
+
"not `refresh`, so it can't loop forever. Read-only. Use it as the first step of RefreshRemediation.",
|
|
376
|
+
parameters: ListRemediationPrsParams,
|
|
377
|
+
execute: execute(async ({ limit }) => {
|
|
378
|
+
const cap = limit ?? 30;
|
|
379
|
+
const owner = ctx.repo.owner;
|
|
380
|
+
const repo = ctx.repo.name;
|
|
381
|
+
|
|
382
|
+
const open = await ctx.octokit.paginate(ctx.octokit.rest.pulls.list, {
|
|
383
|
+
owner,
|
|
384
|
+
repo,
|
|
385
|
+
state: "open",
|
|
386
|
+
per_page: 100,
|
|
387
|
+
});
|
|
388
|
+
const remediation = open
|
|
389
|
+
.filter((pr) => isRemediationBranch(pr.head.ref))
|
|
390
|
+
.slice(0, cap);
|
|
391
|
+
|
|
392
|
+
const prs: AssessedRemediationPr[] = [];
|
|
393
|
+
const errors: { number: number; error: string }[] = [];
|
|
394
|
+
for (const pr of remediation) {
|
|
395
|
+
try {
|
|
396
|
+
// base..head: ahead_by = the PR's own commits, behind_by = commits on
|
|
397
|
+
// the base the PR lacks (how far the base moved since the fork point).
|
|
398
|
+
const cmp = await ctx.octokit.rest.repos.compareCommits({
|
|
399
|
+
owner,
|
|
400
|
+
repo,
|
|
401
|
+
base: pr.base.ref,
|
|
402
|
+
head: pr.head.ref,
|
|
403
|
+
});
|
|
404
|
+
const commitAuthors = [
|
|
405
|
+
...new Set(
|
|
406
|
+
(cmp.data.commits ?? [])
|
|
407
|
+
.map((c) => c.author?.login ?? c.commit.author?.name ?? null)
|
|
408
|
+
.filter((a): a is string => a !== null),
|
|
409
|
+
),
|
|
410
|
+
];
|
|
411
|
+
// resolve each commit via login when present, else its git identity —
|
|
412
|
+
// a human commit whose email isn't linked to a GitHub account (null
|
|
413
|
+
// login) must NOT be mistaken for Infraweaver's bot and force-overwritten.
|
|
414
|
+
const hasNonBotCommits = (cmp.data.commits ?? []).some(
|
|
415
|
+
(c) => !isBotCommit(c),
|
|
416
|
+
);
|
|
417
|
+
const labels = pr.labels
|
|
418
|
+
.map((l) => (typeof l === "string" ? l : l.name))
|
|
419
|
+
.filter(Boolean);
|
|
420
|
+
const checksState = await readChecksState(
|
|
421
|
+
ctx,
|
|
422
|
+
owner,
|
|
423
|
+
repo,
|
|
424
|
+
pr.head.sha,
|
|
425
|
+
);
|
|
426
|
+
const attempts = selfHealAttempts(labels);
|
|
427
|
+
const createdMs = new Date(pr.created_at).getTime();
|
|
428
|
+
const ageDays = Number.isFinite(createdMs)
|
|
429
|
+
? (Date.now() - createdMs) / 86_400_000
|
|
430
|
+
: 0;
|
|
431
|
+
const assessment = assessStaleFix({
|
|
432
|
+
baseBehindBy: cmp.data.behind_by,
|
|
433
|
+
hasNonBotCommits,
|
|
434
|
+
checksFailing: checksState === "failing",
|
|
435
|
+
alreadyEscalated: labels.includes("needs-human"),
|
|
436
|
+
selfHealAttempts: attempts,
|
|
437
|
+
ageDays,
|
|
438
|
+
});
|
|
439
|
+
prs.push({
|
|
440
|
+
number: pr.number,
|
|
441
|
+
url: pr.html_url,
|
|
442
|
+
title: pr.title,
|
|
443
|
+
branch: pr.head.ref,
|
|
444
|
+
base: pr.base.ref,
|
|
445
|
+
group_id: groupIdFromBranch(pr.head.ref),
|
|
446
|
+
base_behind_by: cmp.data.behind_by,
|
|
447
|
+
head_ahead_by: cmp.data.ahead_by,
|
|
448
|
+
has_non_bot_commits: hasNonBotCommits,
|
|
449
|
+
commit_authors: commitAuthors,
|
|
450
|
+
labels,
|
|
451
|
+
checks_state: checksState,
|
|
452
|
+
self_heal_attempts: attempts,
|
|
453
|
+
age_days: Math.round(ageDays),
|
|
454
|
+
status: assessment.status,
|
|
455
|
+
recommended_action: assessment.action,
|
|
456
|
+
zombie: assessment.zombie,
|
|
457
|
+
reason: assessment.reason,
|
|
458
|
+
});
|
|
459
|
+
} catch (e) {
|
|
460
|
+
errors.push({
|
|
461
|
+
number: pr.number,
|
|
462
|
+
error: e instanceof Error ? e.message : String(e),
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const counts = {
|
|
468
|
+
refresh: prs.filter((p) => p.recommended_action === "refresh").length,
|
|
469
|
+
skip: prs.filter((p) => p.recommended_action === "skip").length,
|
|
470
|
+
escalate: prs.filter((p) => p.recommended_action === "escalate").length,
|
|
471
|
+
checks_failing: prs.filter((p) => p.checks_state === "failing").length,
|
|
472
|
+
zombie: prs.filter((p) => p.zombie).length,
|
|
473
|
+
};
|
|
474
|
+
log.info(
|
|
475
|
+
`» list_remediation_prs: ${prs.length} open remediation PR(s) — ` +
|
|
476
|
+
`${counts.refresh} refresh, ${counts.skip} skip, ${counts.escalate} escalate` +
|
|
477
|
+
(counts.checks_failing
|
|
478
|
+
? `, ${counts.checks_failing} checks-failing`
|
|
479
|
+
: "") +
|
|
480
|
+
(counts.zombie ? `, ${counts.zombie} zombie` : "") +
|
|
481
|
+
(errors.length ? ` (${errors.length} errored)` : ""),
|
|
482
|
+
);
|
|
483
|
+
return toolOk({
|
|
484
|
+
count: prs.length,
|
|
485
|
+
action_counts: counts,
|
|
486
|
+
pull_requests: prs,
|
|
487
|
+
...(errors.length ? { errors } : {}),
|
|
488
|
+
note:
|
|
489
|
+
prs.length === 0
|
|
490
|
+
? `No open ${PRODUCT_NAME} remediation PRs to refresh.`
|
|
491
|
+
: "Act on the `refresh` PRs (re-derive on the current base, then close-if-resolved or force-update — a `checks_failing` PR is refreshed to self-heal its red CI: re-prove the fix is green, else escalate to needs-human); `escalate` PRs get a needs-human label and are left for a human; `skip` PRs are already current.",
|
|
492
|
+
});
|
|
493
|
+
}),
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
export const ClosePullRequest = type({
|
|
498
|
+
pull_number: type.number.describe(
|
|
499
|
+
"the pull request number to close (not merge).",
|
|
500
|
+
),
|
|
501
|
+
"comment?": type.string.describe(
|
|
502
|
+
"an optional comment explaining why it's being closed — posted before closing (e.g. 'concern already resolved on the base; this fix is now redundant').",
|
|
503
|
+
),
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
export function ClosePullRequestTool(ctx: GitHubToolContext) {
|
|
507
|
+
return tool({
|
|
508
|
+
mutates: true,
|
|
509
|
+
name: "close_pull_request",
|
|
510
|
+
description:
|
|
511
|
+
`Close (NOT merge) a pull request. Use: a ${PRODUCT_NAME} remediation PR whose concern is already ` +
|
|
512
|
+
"resolved on the current base — the fix is redundant, so close it (optionally with an explanatory " +
|
|
513
|
+
"comment) instead of leaving a stale PR open. Blocked under `push: disabled`, and bound to the run's " +
|
|
514
|
+
"scope (a comment-triggered run can only close the PR it was triggered on or one it opened; a " +
|
|
515
|
+
"standalone scheduled sweep may close any). Never merges — closing is reversible.",
|
|
516
|
+
parameters: ClosePullRequest,
|
|
517
|
+
execute: execute(async ({ pull_number, comment }) => {
|
|
518
|
+
// permission gate: closing a PR is a repo write — block it under read-only.
|
|
519
|
+
if (ctx.payload.push === "disabled") {
|
|
520
|
+
throw new Error(
|
|
521
|
+
"Closing a pull request is disabled. This repository is configured for read-only access (push: disabled).",
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
// scope gate: same binding as comment/label/PR-body writes (mcp/scope.ts).
|
|
525
|
+
assertTargetInScope(ctx, pull_number, "close");
|
|
526
|
+
|
|
527
|
+
const owner = ctx.repo.owner;
|
|
528
|
+
const repo = ctx.repo.name;
|
|
529
|
+
|
|
530
|
+
if (comment) {
|
|
531
|
+
await ctx.octokit.rest.issues.createComment({
|
|
532
|
+
owner,
|
|
533
|
+
repo,
|
|
534
|
+
issue_number: pull_number,
|
|
535
|
+
body: addFooter(ctx, comment),
|
|
536
|
+
});
|
|
537
|
+
log.info(`» commented before closing PR #${pull_number}`);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
const result = await ctx.octokit.rest.pulls.update({
|
|
541
|
+
owner,
|
|
542
|
+
repo,
|
|
543
|
+
pull_number,
|
|
544
|
+
state: "closed",
|
|
545
|
+
});
|
|
546
|
+
ctx.toolState.wasUpdated = true;
|
|
547
|
+
log.info(`» closed pull request #${result.data.number}`);
|
|
548
|
+
|
|
549
|
+
return {
|
|
550
|
+
success: true,
|
|
551
|
+
number: result.data.number,
|
|
552
|
+
state: result.data.state,
|
|
553
|
+
url: result.data.html_url,
|
|
554
|
+
};
|
|
555
|
+
}),
|
|
556
|
+
});
|
|
557
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`buildModuleReadme > is deterministic — identical inputs produce byte-identical output (snapshot) 1`] = `
|
|
4
|
+
"# \`logging\` module
|
|
5
|
+
|
|
6
|
+
Evidence-backed documentation generated by Infraweaver from the module's parsed interface and the refactor's recorded proof. Descriptions are quoted verbatim from the HCL (empty when the HCL has none).
|
|
7
|
+
|
|
8
|
+
## Interface
|
|
9
|
+
|
|
10
|
+
### Inputs
|
|
11
|
+
|
|
12
|
+
| Name | Type | Required | Description |
|
|
13
|
+
| ---- | ---- | :------: | ----------- |
|
|
14
|
+
| \`bucket_name\` | \`string\` | **yes** | Name of the log bucket |
|
|
15
|
+
| \`retention_days\` | \`number\` | no | |
|
|
16
|
+
|
|
17
|
+
### Outputs
|
|
18
|
+
|
|
19
|
+
| Name | Description |
|
|
20
|
+
| ---- | ----------- |
|
|
21
|
+
| \`bucket_arn\` | ARN of the created bucket |
|
|
22
|
+
|
|
23
|
+
## Refactor provenance
|
|
24
|
+
|
|
25
|
+
Verdict: \`equivalence-proven\`
|
|
26
|
+
|
|
27
|
+
The relocation was **proven behaviour-preserving** by \`terraform_equivalence_check\`: same resource set, identical arguments, every relocated address covered by a \`moved {}\` block, validate + fmt clean.
|
|
28
|
+
|
|
29
|
+
Relocated addresses:
|
|
30
|
+
|
|
31
|
+
- \`aws_s3_bucket.logs\` → \`module.logging.aws_s3_bucket.logs\`
|
|
32
|
+
|
|
33
|
+
<!--
|
|
34
|
+
generated-by: infraweaver
|
|
35
|
+
infraweaver-version: 0.3.0
|
|
36
|
+
git-head: abc1234def5678
|
|
37
|
+
diagram: placeholder — link a Infragram-rendered architecture diagram of this module here
|
|
38
|
+
-->
|
|
39
|
+
"
|
|
40
|
+
`;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Generated by `pnpm run gen:azure-prices` — do not edit by hand.
|
|
2
|
+
// Public list prices from the unauthenticated Azure Retail Prices API
|
|
3
|
+
// (https://prices.azure.com), pinned so scan-time is offline with zero egress.
|
|
4
|
+
// Every entry is a FIXED hourly charge that accrues at zero traffic — the
|
|
5
|
+
// deterministic "idle floor". Usage-metered lines are deliberately not here.
|
|
6
|
+
|
|
7
|
+
/** Region these list prices were captured for. */
|
|
8
|
+
export const AZURE_PRICE_REGION = "westeurope";
|
|
9
|
+
/** Currency of every price below. */
|
|
10
|
+
export const AZURE_PRICE_CURRENCY = "EUR";
|
|
11
|
+
/** ISO date the snapshot was captured — surfaced in cost.md so staleness is visible. */
|
|
12
|
+
export const AZURE_PRICE_FETCHED_AT = "2026-07-25";
|
|
13
|
+
|
|
14
|
+
/** meter key → list price per HOUR. */
|
|
15
|
+
export const AZURE_HOURLY_PRICES: Record<string, number> = {
|
|
16
|
+
"app-service-p0v3": 0.0781,
|
|
17
|
+
"app-service-p1v3": 0.1562,
|
|
18
|
+
"app-service-p2v3": 0.3124,
|
|
19
|
+
"app-service-p3v3": 0.6248,
|
|
20
|
+
"bastion-basic": 0.1667,
|
|
21
|
+
"bastion-premium": 0.3949,
|
|
22
|
+
"bastion-standard": 0.2545,
|
|
23
|
+
"firewall-basic": 0.3466,
|
|
24
|
+
"firewall-premium": 1.5358,
|
|
25
|
+
"firewall-standard": 1.097,
|
|
26
|
+
"redis-c0": 0.0241,
|
|
27
|
+
"redis-c1": 0.0606,
|
|
28
|
+
"redis-c2": 0.0983,
|
|
29
|
+
"redis-c3": 0.1975,
|
|
30
|
+
"redis-p1": 0.2431,
|
|
31
|
+
"redis-p2": 0.4871,
|
|
32
|
+
"redis-p3": 0.9732,
|
|
33
|
+
"vpn-gateway-vpngw1": 0.1667,
|
|
34
|
+
"vpn-gateway-vpngw2": 0.43,
|
|
35
|
+
"vpn-gateway-vpngw3": 1.097,
|
|
36
|
+
"vpn-gateway-vpngw4": 1.8429,
|
|
37
|
+
"vpn-gateway-vpngw5": 3.2032,
|
|
38
|
+
};
|