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,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trust boundary for the repo-committed `.infraweaver.yml` on a PULL-REQUEST run.
|
|
3
|
+
*
|
|
4
|
+
* THE PROBLEM. `.infraweaver.yml` is read from the checked-out ref, which on a PR
|
|
5
|
+
* run is the PR's own head. Most of the run's shape is already out of reach —
|
|
6
|
+
* `push`, `shell`, `allow_replace` and the `*_instructions` are deliberately not
|
|
7
|
+
* file-readable, because "the run's shape belongs to the workflow that
|
|
8
|
+
* dispatches it" ([[infraweaverConfig]]). But several keys that ARE file-readable
|
|
9
|
+
* decide how strictly the run judges the code, and a PR that edits them is
|
|
10
|
+
* editing the gates that judge that same PR:
|
|
11
|
+
*
|
|
12
|
+
* allowed_paths / protected_paths → what the fix loop may write
|
|
13
|
+
* required_controls → which controls must be clean to pass
|
|
14
|
+
* severity_threshold → what counts as reportable at all
|
|
15
|
+
* autonomy_threshold → what escalates to a human
|
|
16
|
+
* tools_enabled → which scanners run
|
|
17
|
+
* scan_scope / iac_languages → how much of the tree is looked at
|
|
18
|
+
* suppressions → which findings are silenced outright
|
|
19
|
+
*
|
|
20
|
+
* None of these is an arbitrary-code-execution hole, and GitHub already defangs
|
|
21
|
+
* the fork case (read-only token, no secrets on `pull_request`). A workflow
|
|
22
|
+
* input also always wins over the file. But "the workflow author remembered to
|
|
23
|
+
* pin it" is not a control, and a same-repo PR silencing the finding that would
|
|
24
|
+
* have blocked it is a plausible, quiet failure.
|
|
25
|
+
*
|
|
26
|
+
* THE RULE. On a PR-triggered run these come from the BASE ref — the reviewed
|
|
27
|
+
* state of the branch being merged into. Everything else (prose language,
|
|
28
|
+
* grouping, the advisory module catalogue) still comes from the head, because
|
|
29
|
+
* none of it can weaken a verdict.
|
|
30
|
+
*
|
|
31
|
+
* This is the same principle as the shipped two-person SoD on waivers (§5.3): a
|
|
32
|
+
* suppression takes effect once someone other than its author has accepted it —
|
|
33
|
+
* here, by merging it. A PR that adds a waiver still SEES the finding it waives;
|
|
34
|
+
* the waiver applies from the next run on the merged base.
|
|
35
|
+
*
|
|
36
|
+
* HONEST DEGRADE. When the base ref can't be read (a shallow clone with no
|
|
37
|
+
* `origin/<base>`, a non-PR run, no git at all), the head value is used and the
|
|
38
|
+
* fact is stated for the run summary. Failing the run would turn a hardening
|
|
39
|
+
* measure into an outage on every shallow-checkout workflow; silently preferring
|
|
40
|
+
* the head with no record would be the dishonesty this codebase avoids
|
|
41
|
+
* everywhere else. So: use it, and say so.
|
|
42
|
+
*
|
|
43
|
+
* DIRECTION IS NOT INSPECTED. A PR that *tightens* a gate also defers to the
|
|
44
|
+
* base value — not because tightening is dangerous, but because "which value
|
|
45
|
+
* applies" must not depend on a per-key notion of stricter/looser that we would
|
|
46
|
+
* have to get right for every key forever. The new value takes effect on merge,
|
|
47
|
+
* which is when the reviewed state actually changes.
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
import { CONFIG_FILE } from "#app/brand";
|
|
51
|
+
// the sync, restricted-env, timeout-bounded runner every other git shell-out
|
|
52
|
+
// uses (`resolveBaseRef` in mcp/terraform/paths.ts does the same) — a config
|
|
53
|
+
// read must not inherit the ambient env any more than a scanner does.
|
|
54
|
+
import { run } from "#app/mcp/terraform/subprocess";
|
|
55
|
+
import { log } from "#app/utils/cli";
|
|
56
|
+
import {
|
|
57
|
+
type InfraweaverConfigKey,
|
|
58
|
+
type InfraweaverFileValues,
|
|
59
|
+
INFRAWEAVER_CONFIG_FILENAMES,
|
|
60
|
+
parseInfraweaverConfig,
|
|
61
|
+
} from "#app/utils/infraweaverConfig";
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The file-readable keys that can weaken a verdict. Deliberately enumerated
|
|
65
|
+
* rather than derived by exclusion, and paired with
|
|
66
|
+
* {@link PRESENTATIONAL_CONFIG_KEYS} so that every key in
|
|
67
|
+
* `INFRAWEAVER_CONFIG_KEYS` is classified exactly once — `baseRefConfig.test.ts`
|
|
68
|
+
* asserts that partition, so a key added later cannot silently default to
|
|
69
|
+
* "PR-controllable".
|
|
70
|
+
*/
|
|
71
|
+
export const GATE_RELEVANT_CONFIG_KEYS = [
|
|
72
|
+
"allowed_paths",
|
|
73
|
+
"protected_paths",
|
|
74
|
+
"required_controls",
|
|
75
|
+
"severity_threshold",
|
|
76
|
+
"autonomy_threshold",
|
|
77
|
+
"tools_enabled",
|
|
78
|
+
"scan_scope",
|
|
79
|
+
"iac_languages",
|
|
80
|
+
] as const satisfies readonly InfraweaverConfigKey[];
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Keys a PR may set from its own head: none can hide a finding, relax a
|
|
84
|
+
* guardrail, or shrink what is scanned. `language` is prose only; `grouping` is
|
|
85
|
+
* presentation; `module_catalogue` is an advisory list the fixer may prefer
|
|
86
|
+
* from, never a gate.
|
|
87
|
+
*/
|
|
88
|
+
export const PRESENTATIONAL_CONFIG_KEYS = [
|
|
89
|
+
"language",
|
|
90
|
+
"grouping",
|
|
91
|
+
"module_catalogue",
|
|
92
|
+
] as const satisfies readonly InfraweaverConfigKey[];
|
|
93
|
+
|
|
94
|
+
const GATE_KEY_SET: ReadonlySet<string> = new Set<string>(
|
|
95
|
+
GATE_RELEVANT_CONFIG_KEYS,
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
/** What the base ref had to say about `.infraweaver.*`. */
|
|
99
|
+
export type BaseConfigSource =
|
|
100
|
+
/** the base ref itself could not be resolved (shallow clone, no git, non-PR). */
|
|
101
|
+
| { kind: "unavailable" }
|
|
102
|
+
/** the base ref resolved and carries NO config file — so no file-level policy. */
|
|
103
|
+
| { kind: "absent"; ref: string }
|
|
104
|
+
| { kind: "file"; ref: string; raw: string; format: "yaml" | "json" };
|
|
105
|
+
|
|
106
|
+
/** `git show <ref>:<path>`, or null when the ref/path pair doesn't resolve. */
|
|
107
|
+
function showAtRef(cwd: string, ref: string, path: string): string | null {
|
|
108
|
+
const r = run("git", ["show", `${ref}:${path}`], cwd);
|
|
109
|
+
return r.status === 0 ? r.stdout : null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Candidate git refs for the PR's base, most-specific first. */
|
|
113
|
+
function baseRefCandidates(baseRef: string): string[] {
|
|
114
|
+
return [`origin/${baseRef}`, `refs/remotes/origin/${baseRef}`, baseRef];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// One `git show` per (cwd, baseRef) per process. Both the scalar-key resolver
|
|
118
|
+
// and the suppression-policy loader ask the same question, and the answer
|
|
119
|
+
// cannot change mid-run.
|
|
120
|
+
const cache = new Map<string, BaseConfigSource>();
|
|
121
|
+
|
|
122
|
+
/** Drop the base-ref read cache — tests only. */
|
|
123
|
+
export function resetBaseConfigCache(): void {
|
|
124
|
+
cache.clear();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Read `.infraweaver.*` as it exists on the PR's base ref.
|
|
129
|
+
*
|
|
130
|
+
* The `absent` / `unavailable` distinction is load-bearing: "the base has no
|
|
131
|
+
* config" legitimately means *no file-level policy applies*, so a PR that ADDS
|
|
132
|
+
* one is correctly ignored. "We could not look" must never be read that way, or
|
|
133
|
+
* a shallow clone would silently drop a real policy.
|
|
134
|
+
*/
|
|
135
|
+
export function readConfigAtBaseRef(
|
|
136
|
+
cwdOrUndefined: string | undefined,
|
|
137
|
+
baseRef: string | undefined,
|
|
138
|
+
): BaseConfigSource {
|
|
139
|
+
if (!baseRef) return { kind: "unavailable" };
|
|
140
|
+
const cwd = cwdOrUndefined ?? process.cwd();
|
|
141
|
+
const key = `${cwd}::${baseRef}`;
|
|
142
|
+
const hit = cache.get(key);
|
|
143
|
+
if (hit) return hit;
|
|
144
|
+
|
|
145
|
+
let result: BaseConfigSource = { kind: "unavailable" };
|
|
146
|
+
for (const ref of baseRefCandidates(baseRef)) {
|
|
147
|
+
// Prove the ref resolves before concluding anything from a missing file.
|
|
148
|
+
if (
|
|
149
|
+
run("git", ["rev-parse", "--verify", "--quiet", `${ref}^{commit}`], cwd)
|
|
150
|
+
.status !== 0
|
|
151
|
+
) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
result = { kind: "absent", ref };
|
|
155
|
+
for (const name of INFRAWEAVER_CONFIG_FILENAMES) {
|
|
156
|
+
const raw = showAtRef(cwd, ref, name);
|
|
157
|
+
if (raw === null) continue;
|
|
158
|
+
result = {
|
|
159
|
+
kind: "file",
|
|
160
|
+
ref,
|
|
161
|
+
raw,
|
|
162
|
+
format: name.endsWith(".json") ? "json" : "yaml",
|
|
163
|
+
};
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
cache.set(key, result);
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface BaseRefConfigResult {
|
|
173
|
+
/** the config to use, gate keys taken from the base ref where available. */
|
|
174
|
+
values: InfraweaverFileValues;
|
|
175
|
+
/** human-readable notes for the run log: what was overridden, or why not. */
|
|
176
|
+
notes: string[];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Layer the base ref's gate-relevant keys over the head's config. `headValues`
|
|
181
|
+
* is what `loadInfraweaverConfig` already read from the checked-out tree; on a
|
|
182
|
+
* non-PR run (or when the base can't be resolved) it comes back unchanged.
|
|
183
|
+
*/
|
|
184
|
+
export function resolveConfigAcrossRefs(args: {
|
|
185
|
+
cwd: string | undefined;
|
|
186
|
+
headValues: InfraweaverFileValues;
|
|
187
|
+
/** the PR's base branch — `GITHUB_BASE_REF`; empty/undefined on a non-PR run. */
|
|
188
|
+
baseRef: string | undefined;
|
|
189
|
+
/** injectable for tests; defaults to the real git read. */
|
|
190
|
+
readBase?: (
|
|
191
|
+
cwd: string | undefined,
|
|
192
|
+
baseRef: string | undefined,
|
|
193
|
+
) => BaseConfigSource;
|
|
194
|
+
}): BaseRefConfigResult {
|
|
195
|
+
const { cwd, headValues, baseRef } = args;
|
|
196
|
+
const notes: string[] = [];
|
|
197
|
+
if (!baseRef) return { values: headValues, notes };
|
|
198
|
+
|
|
199
|
+
const source = (args.readBase ?? readConfigAtBaseRef)(cwd, baseRef);
|
|
200
|
+
const headGateKeys = Object.keys(headValues).filter((k) =>
|
|
201
|
+
GATE_KEY_SET.has(k),
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
if (source.kind === "unavailable") {
|
|
205
|
+
// Only worth a note when the head actually sets a gate key — otherwise
|
|
206
|
+
// there was nothing the base could have overridden.
|
|
207
|
+
if (headGateKeys.length > 0) {
|
|
208
|
+
notes.push(
|
|
209
|
+
`could not read the base ref (${baseRef}) to resolve gate-relevant config — using this ` +
|
|
210
|
+
`ref's values for [${headGateKeys.join(", ")}]. A shallow clone causes this; ` +
|
|
211
|
+
"`fetch-depth: 0` (or fetching the base branch) restores the check.",
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
return { values: headValues, notes };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const baseValues =
|
|
218
|
+
source.kind === "file"
|
|
219
|
+
? parseInfraweaverConfig(source.raw, source.format).values
|
|
220
|
+
: {};
|
|
221
|
+
const values: InfraweaverFileValues = { ...headValues };
|
|
222
|
+
const changed: string[] = [];
|
|
223
|
+
for (const key of GATE_RELEVANT_CONFIG_KEYS) {
|
|
224
|
+
if (headValues[key] === baseValues[key]) continue;
|
|
225
|
+
changed.push(key);
|
|
226
|
+
const base = baseValues[key];
|
|
227
|
+
if (base === undefined) delete values[key];
|
|
228
|
+
else values[key] = base;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (changed.length > 0) {
|
|
232
|
+
notes.push(
|
|
233
|
+
`gate-relevant config differs from the base ref (${source.ref}); using the BASE value for ` +
|
|
234
|
+
`[${changed.join(", ")}] so this change cannot relax the gates reviewing it. ` +
|
|
235
|
+
"It takes effect once merged.",
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
return { values, notes };
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* `resolveConfigAcrossRefs` + logging, for the one call site in `resolvePayload`.
|
|
243
|
+
* Notes are warnings, not info: a divergence belongs in the run summary rather
|
|
244
|
+
* than buried in debug output.
|
|
245
|
+
*/
|
|
246
|
+
export function applyBaseRefConfigPolicy(args: {
|
|
247
|
+
cwd: string | undefined;
|
|
248
|
+
headValues: InfraweaverFileValues;
|
|
249
|
+
baseRef: string | undefined;
|
|
250
|
+
}): InfraweaverFileValues {
|
|
251
|
+
const { values, notes } = resolveConfigAcrossRefs(args);
|
|
252
|
+
for (const n of notes) log.warning(`» ${CONFIG_FILE}: ${n}`);
|
|
253
|
+
return values;
|
|
254
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Billing-error classification + user-facing copy for `/api/proxy-token`
|
|
3
|
+
* failures and OpenRouter mid-run exhaustion. Two error classes (Billing vs.
|
|
4
|
+
* Transient) keep the framing honest: a card decline is *not* the same UX as
|
|
5
|
+
* a 503 from the proxy service. Both originate in `utils/proxy.ts` (mint
|
|
6
|
+
* failures) and `utils/runErrorRenderer.ts` (mid-run keylimit reclassify).
|
|
7
|
+
*
|
|
8
|
+
* Renderers return markdown bodies that are written into both the GitHub
|
|
9
|
+
* Actions job summary and the PR progress comment.
|
|
10
|
+
*
|
|
11
|
+
* Lives outside `main.ts` so adding a new error `code` branch is a one-file
|
|
12
|
+
* edit that does not retrigger the full LLM CI matrix (`action/main.ts` is
|
|
13
|
+
* in `action/test/coverage.ts::ALWAYS_RUN_ALL`).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { PRIMARY_DOMAIN, PRODUCT_NAME, STATUS_URL } from "#app/brand";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Billing-layer error surfaced from `/api/proxy-token` as a 402. User-actionable
|
|
20
|
+
* — distinct from TransientError (503 / transient sync issue) so the job
|
|
21
|
+
* summary + PR comment can use affirmative "you need to do X" copy rather than
|
|
22
|
+
* the ambiguous "billing error" label that makes transient outages look like
|
|
23
|
+
* the user's fault.
|
|
24
|
+
*
|
|
25
|
+
* `code` is a server-side discriminator: `router_requires_card` (no card + no
|
|
26
|
+
* wallet balance on Router), or null for unclassified. `declineCode` is
|
|
27
|
+
* Stripe's more specific sub-reason on `card_declined` (e.g.
|
|
28
|
+
* `insufficient_funds`, `lost_card`). `needsReauthentication` is the 3DS case
|
|
29
|
+
* broken out for convenience.
|
|
30
|
+
*/
|
|
31
|
+
export class BillingError extends Error {
|
|
32
|
+
code: string | null;
|
|
33
|
+
declineCode: string | null;
|
|
34
|
+
needsReauthentication: boolean;
|
|
35
|
+
|
|
36
|
+
constructor(
|
|
37
|
+
message: string,
|
|
38
|
+
opts: {
|
|
39
|
+
code?: string | null;
|
|
40
|
+
declineCode?: string | null;
|
|
41
|
+
needsReauthentication?: boolean;
|
|
42
|
+
} = {},
|
|
43
|
+
) {
|
|
44
|
+
super(message);
|
|
45
|
+
this.name = "BillingError";
|
|
46
|
+
this.code = opts.code ?? null;
|
|
47
|
+
this.declineCode = opts.declineCode ?? null;
|
|
48
|
+
this.needsReauthentication = opts.needsReauthentication ?? false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Transient service failures from `/api/proxy-token` (503: partial OpenRouter
|
|
54
|
+
* usage sync, DB flake, in-flight payment intent). Not the user's fault — the
|
|
55
|
+
* summary uses "temporarily unavailable" framing, and the non-zero exit lets
|
|
56
|
+
* GH Actions apply whatever retry policy the workflow has configured.
|
|
57
|
+
*/
|
|
58
|
+
export class TransientError extends Error {
|
|
59
|
+
constructor(message: string) {
|
|
60
|
+
super(message);
|
|
61
|
+
this.name = "TransientError";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Deep link into the right console section for the failing account. Anchors
|
|
67
|
+
* are defined in `app/console/[owner]/page.tsx` (`#billing`, `#model-access`).
|
|
68
|
+
* `owner` is the GitHub login of the repo's account — i.e. the org or user
|
|
69
|
+
* that pays for this repo's runs, which is the right scope for billing.
|
|
70
|
+
*/
|
|
71
|
+
function billingConsoleUrl(
|
|
72
|
+
owner: string,
|
|
73
|
+
anchor: "billing" | "model-access",
|
|
74
|
+
): string {
|
|
75
|
+
return `https://infraweaver.dev/console/${encodeURIComponent(owner)}#${anchor}`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Render a BillingError as user-facing markdown (shared between GH job summary
|
|
80
|
+
* and the PR progress comment). Goals:
|
|
81
|
+
*
|
|
82
|
+
* - quiet, not alarmist — bold first line instead of an `### ❌` H3, since
|
|
83
|
+
* the comment already has Infraweaver branding in the footer
|
|
84
|
+
* - actionable — every branch ends in a single CTA deep-linked to the
|
|
85
|
+
* correct section of the owner's console
|
|
86
|
+
* - honest — say what actually went wrong (card declined vs. balance
|
|
87
|
+
* empty vs. 3DS required), don't lump them under "billing error"
|
|
88
|
+
*
|
|
89
|
+
* Branches:
|
|
90
|
+
* - `router_requires_card`: user is on Router mode with no card AND no
|
|
91
|
+
* wallet balance (signup credit exhausted or not granted). Frame as
|
|
92
|
+
* "add a card to continue", link to `#model-access` where the Add
|
|
93
|
+
* Card flow lives.
|
|
94
|
+
* - `router_balance_exhausted`: user has a card on file but auto-reload is
|
|
95
|
+
* disabled and they've spent past their $5 overdraft buffer. Frame as
|
|
96
|
+
* "balance ran out" and surface both remediation paths (top up, or flip
|
|
97
|
+
* on auto-reload).
|
|
98
|
+
* - `router_keylimit_exhausted`: OpenRouter rejected mid-run because the
|
|
99
|
+
* per-run key budget was exhausted while the agent was working. The
|
|
100
|
+
* wallet is now negative; same remediation as `router_balance_exhausted`
|
|
101
|
+
* but framed for the after-the-fact case ("this run was cut short").
|
|
102
|
+
* - `needsReauthentication`: issuer requires 3DS on every off-session
|
|
103
|
+
* charge. Re-adding the card won't help — the only escape is a manual
|
|
104
|
+
* top-up where 3DS runs interactively in Stripe Checkout.
|
|
105
|
+
* - `declineCode` set: Stripe declined a real charge. Show the sub-code
|
|
106
|
+
* so support can act on it; tell the user we'll retry on next dispatch.
|
|
107
|
+
* - default: balance hit zero with no in-flight charge (auto-reload off
|
|
108
|
+
* or amount below threshold). Direct them to top up or enable auto-reload.
|
|
109
|
+
*/
|
|
110
|
+
export function formatBillingErrorSummary(
|
|
111
|
+
error: BillingError,
|
|
112
|
+
owner: string,
|
|
113
|
+
): string {
|
|
114
|
+
if (error.code === "router_requires_card") {
|
|
115
|
+
return [
|
|
116
|
+
`**Add a card to start using ${PRODUCT_NAME} Router.**`,
|
|
117
|
+
"",
|
|
118
|
+
"Router proxies OpenRouter at raw cost — no platform markup. Add a card and we'll auto-reload your wallet so runs keep flowing.",
|
|
119
|
+
"",
|
|
120
|
+
`[Add a card →](${billingConsoleUrl(owner, "model-access")})`,
|
|
121
|
+
].join("\n");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (error.code === "router_balance_exhausted") {
|
|
125
|
+
return [
|
|
126
|
+
`**Your ${PRODUCT_NAME} Router balance is exhausted.**`,
|
|
127
|
+
"",
|
|
128
|
+
"You have a card on file but auto-reload is disabled, so runs paused once your balance went past the overdraft buffer.",
|
|
129
|
+
"",
|
|
130
|
+
`[Top up balance →](${billingConsoleUrl(owner, "billing")}) · [Enable auto-reload →](${billingConsoleUrl(owner, "model-access")})`,
|
|
131
|
+
].join("\n");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (error.code === "router_keylimit_exhausted") {
|
|
135
|
+
return [
|
|
136
|
+
`**This run was cut short — your ${PRODUCT_NAME} Router balance ran out mid-run.**`,
|
|
137
|
+
"",
|
|
138
|
+
"OpenRouter stopped the agent because the per-run budget was exhausted. Your wallet is now negative; top up or enable auto-reload to keep runs flowing.",
|
|
139
|
+
"",
|
|
140
|
+
`[Top up balance →](${billingConsoleUrl(owner, "billing")}) · [Enable auto-reload →](${billingConsoleUrl(owner, "model-access")})`,
|
|
141
|
+
].join("\n");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (error.code === "router_requires_upgrade") {
|
|
145
|
+
return [
|
|
146
|
+
"**This managed model needs a higher plan.**",
|
|
147
|
+
"",
|
|
148
|
+
"Managed models run through our AWS Bedrock proxy (UK & EU): **Claude Opus 4.8** and **Claude Sonnet 5** run on OSS + Team, and **Claude Fable 5** is on Enterprise. Upgrade to run this model, or pick one your plan includes.",
|
|
149
|
+
"",
|
|
150
|
+
`[Upgrade your plan →](${billingConsoleUrl(owner, "billing")})`,
|
|
151
|
+
].join("\n");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (error.code === "router_monthly_limit") {
|
|
155
|
+
return [
|
|
156
|
+
`**${PRODUCT_NAME} Router hit its monthly spend limit.**`,
|
|
157
|
+
"",
|
|
158
|
+
"Auto-reloads are paused for the rest of this UTC month. Ask your admin to raise the cap, or wait for it to reset at 00:00 UTC on the 1st.",
|
|
159
|
+
"",
|
|
160
|
+
`[Adjust limit →](${billingConsoleUrl(owner, "model-access")})`,
|
|
161
|
+
].join("\n");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (error.needsReauthentication) {
|
|
165
|
+
const code = error.declineCode ?? "authentication_required";
|
|
166
|
+
return [
|
|
167
|
+
`**Your card issuer requires 3D Secure on every charge** (\`${code}\`).`,
|
|
168
|
+
"",
|
|
169
|
+
`${PRODUCT_NAME} can't complete a 3DS challenge from inside a workflow. Top up your Router balance once in Stripe Checkout — subsequent runs draw from the prepaid balance without re-triggering 3DS.`,
|
|
170
|
+
"",
|
|
171
|
+
`[Top up balance →](${billingConsoleUrl(owner, "billing")})`,
|
|
172
|
+
].join("\n");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (error.declineCode) {
|
|
176
|
+
return [
|
|
177
|
+
`**Your card was declined** (\`${error.declineCode}\`).`,
|
|
178
|
+
"",
|
|
179
|
+
`Update your payment method and ${PRODUCT_NAME} will retry on the next run.`,
|
|
180
|
+
"",
|
|
181
|
+
`[Update payment method →](${billingConsoleUrl(owner, "billing")})`,
|
|
182
|
+
].join("\n");
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return [
|
|
186
|
+
`**Your ${PRODUCT_NAME} balance is empty.**`,
|
|
187
|
+
"",
|
|
188
|
+
"Top up your balance or enable auto-reload to keep runs flowing.",
|
|
189
|
+
"",
|
|
190
|
+
`[Manage billing →](${billingConsoleUrl(owner, "billing")})`,
|
|
191
|
+
].join("\n");
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Render a TransientError as user-facing markdown. Distinct framing from
|
|
196
|
+
* BillingError so the user doesn't read an alarm and assume their card
|
|
197
|
+
* failed — this branch is "our fault, retry shortly", not theirs.
|
|
198
|
+
*/
|
|
199
|
+
export function formatTransientErrorSummary(
|
|
200
|
+
error: TransientError,
|
|
201
|
+
owner: string,
|
|
202
|
+
): string {
|
|
203
|
+
return [
|
|
204
|
+
`**${PRODUCT_NAME} billing is temporarily unavailable.**`,
|
|
205
|
+
"",
|
|
206
|
+
error.message,
|
|
207
|
+
"",
|
|
208
|
+
`Usually transient — the next dispatch should succeed. If it persists, check [status.${PRIMARY_DOMAIN}](${STATUS_URL}) or [your console](${billingConsoleUrl(owner, "billing")}).`,
|
|
209
|
+
].join("\n");
|
|
210
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import TurndownService from "turndown";
|
|
2
|
+
import type { PayloadEvent } from "#app/external";
|
|
3
|
+
import { downloadAssetsInMarkdown } from "#app/utils/assets";
|
|
4
|
+
import type { OctokitWithPlugins } from "#app/utils/github";
|
|
5
|
+
import type { RunContextData } from "#app/utils/runContextData";
|
|
6
|
+
|
|
7
|
+
const turndown = new TurndownService();
|
|
8
|
+
|
|
9
|
+
function hasImages(body: string | null | undefined): boolean {
|
|
10
|
+
if (!body) return false;
|
|
11
|
+
return body.includes("<img") || body.includes("![");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ResolveBodyContext {
|
|
15
|
+
event: PayloadEvent;
|
|
16
|
+
octokit: OctokitWithPlugins;
|
|
17
|
+
repo: RunContextData["repo"];
|
|
18
|
+
tmpdir: string;
|
|
19
|
+
githubToken: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* resolves the body of an event by fetching body_html and converting to markdown.
|
|
24
|
+
* only fetches body_html if the body contains images (to avoid unnecessary API calls).
|
|
25
|
+
* this ensures agents receive markdown with working signed image URLs instead of
|
|
26
|
+
* broken user-attachments URLs.
|
|
27
|
+
*/
|
|
28
|
+
export async function resolveBody(ctx: ResolveBodyContext): Promise<string | null> {
|
|
29
|
+
const body = ctx.event.body;
|
|
30
|
+
const bodyHtml = hasImages(body) ? await fetchBodyHtml(ctx) : undefined;
|
|
31
|
+
return resolveBodyAssets({
|
|
32
|
+
body,
|
|
33
|
+
bodyHtml,
|
|
34
|
+
tmpdir: ctx.tmpdir,
|
|
35
|
+
githubToken: ctx.githubToken,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface ResolveBodyAssetsContext {
|
|
40
|
+
body: string | null | undefined;
|
|
41
|
+
bodyHtml: string | null | undefined;
|
|
42
|
+
tmpdir: string;
|
|
43
|
+
githubToken: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* downloads github-hosted image assets in a body to disk and rewrites the urls to local
|
|
48
|
+
* paths so the agent can read them. when the body has images and a rendered `bodyHtml`
|
|
49
|
+
* is supplied, the html is turndowned first: github only exposes attachments as signed,
|
|
50
|
+
* self-authenticating `*.githubusercontent.com` urls through body_html — the raw
|
|
51
|
+
* `github.com/user-attachments/...` urls in unrendered markdown 404 for the installation
|
|
52
|
+
* token. callers that fetch a body should request it with the `application/vnd.github.full+json`
|
|
53
|
+
* media type and pass `body_html` here.
|
|
54
|
+
*/
|
|
55
|
+
export async function resolveBodyAssets(ctx: ResolveBodyAssetsContext): Promise<string | null> {
|
|
56
|
+
let body = ctx.body ?? null;
|
|
57
|
+
if (body && hasImages(body) && ctx.bodyHtml) {
|
|
58
|
+
body = turndown.turndown(ctx.bodyHtml);
|
|
59
|
+
}
|
|
60
|
+
if (!body) return ctx.body ?? null;
|
|
61
|
+
return downloadAssetsInMarkdown(body, ctx.tmpdir, ctx.githubToken);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function fetchBodyHtml(ctx: ResolveBodyContext): Promise<string | undefined> {
|
|
65
|
+
const event = ctx.event;
|
|
66
|
+
const headers = { accept: "application/vnd.github.full+json" };
|
|
67
|
+
const owner = ctx.repo.owner;
|
|
68
|
+
const repo = ctx.repo.name;
|
|
69
|
+
|
|
70
|
+
switch (event.trigger) {
|
|
71
|
+
case "issue_comment_created":
|
|
72
|
+
if (!event.comment_id) return;
|
|
73
|
+
return (
|
|
74
|
+
await ctx.octokit.rest.issues.getComment({
|
|
75
|
+
owner,
|
|
76
|
+
repo,
|
|
77
|
+
comment_id: event.comment_id,
|
|
78
|
+
headers,
|
|
79
|
+
})
|
|
80
|
+
).data.body_html;
|
|
81
|
+
|
|
82
|
+
case "issues_opened":
|
|
83
|
+
case "issues_assigned":
|
|
84
|
+
case "issues_labeled":
|
|
85
|
+
if (!event.issue_number) return;
|
|
86
|
+
return (
|
|
87
|
+
await ctx.octokit.rest.issues.get({
|
|
88
|
+
owner,
|
|
89
|
+
repo,
|
|
90
|
+
issue_number: event.issue_number,
|
|
91
|
+
headers,
|
|
92
|
+
})
|
|
93
|
+
).data.body_html;
|
|
94
|
+
|
|
95
|
+
case "pull_request_opened":
|
|
96
|
+
case "pull_request_ready_for_review":
|
|
97
|
+
case "pull_request_synchronize":
|
|
98
|
+
case "pull_request_review_requested":
|
|
99
|
+
// PRs are also issues - use issues.get which returns body_html
|
|
100
|
+
if (!event.issue_number) return;
|
|
101
|
+
return (
|
|
102
|
+
await ctx.octokit.rest.issues.get({
|
|
103
|
+
owner,
|
|
104
|
+
repo,
|
|
105
|
+
issue_number: event.issue_number,
|
|
106
|
+
headers,
|
|
107
|
+
})
|
|
108
|
+
).data.body_html;
|
|
109
|
+
|
|
110
|
+
case "pull_request_review_submitted":
|
|
111
|
+
if (!event.issue_number || !event.review_id) return;
|
|
112
|
+
return (
|
|
113
|
+
await ctx.octokit.rest.pulls.getReview({
|
|
114
|
+
owner,
|
|
115
|
+
repo,
|
|
116
|
+
pull_number: event.issue_number,
|
|
117
|
+
review_id: event.review_id,
|
|
118
|
+
headers,
|
|
119
|
+
})
|
|
120
|
+
).data.body_html;
|
|
121
|
+
|
|
122
|
+
case "pull_request_review_comment_created":
|
|
123
|
+
if (!event.comment_id) return;
|
|
124
|
+
return (
|
|
125
|
+
await ctx.octokit.rest.pulls.getReviewComment({
|
|
126
|
+
owner,
|
|
127
|
+
repo,
|
|
128
|
+
comment_id: event.comment_id,
|
|
129
|
+
headers,
|
|
130
|
+
})
|
|
131
|
+
).data.body_html;
|
|
132
|
+
|
|
133
|
+
case "check_suite_completed":
|
|
134
|
+
// body is the PR body
|
|
135
|
+
if (!event.issue_number) return;
|
|
136
|
+
return (
|
|
137
|
+
await ctx.octokit.rest.issues.get({
|
|
138
|
+
owner,
|
|
139
|
+
repo,
|
|
140
|
+
issue_number: event.issue_number,
|
|
141
|
+
headers,
|
|
142
|
+
})
|
|
143
|
+
).data.body_html;
|
|
144
|
+
|
|
145
|
+
case "implement_plan":
|
|
146
|
+
// body is the plan content from an issue comment
|
|
147
|
+
if (!event.plan_comment_id) return;
|
|
148
|
+
return (
|
|
149
|
+
await ctx.octokit.rest.issues.getComment({
|
|
150
|
+
owner,
|
|
151
|
+
repo,
|
|
152
|
+
comment_id: event.plan_comment_id,
|
|
153
|
+
headers,
|
|
154
|
+
})
|
|
155
|
+
).data.body_html;
|
|
156
|
+
|
|
157
|
+
// triggers without a body field that needs resolution
|
|
158
|
+
case "workflow_dispatch":
|
|
159
|
+
case "fix_review":
|
|
160
|
+
case "unknown":
|
|
161
|
+
return undefined;
|
|
162
|
+
|
|
163
|
+
default:
|
|
164
|
+
// exhaustiveness check - TypeScript will error if a trigger is missing
|
|
165
|
+
event satisfies never;
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
}
|