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,377 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import type { RunTokenQuota } from "#app/agents/tokenQuota";
|
|
4
|
+
import type { AgentId } from "#app/external";
|
|
5
|
+
import type { ToolState } from "#app/toolState";
|
|
6
|
+
import { log } from "#app/utils/cli";
|
|
7
|
+
import type { ResolvedInstructions } from "#app/utils/instructions";
|
|
8
|
+
import type { ResolvedPayload } from "#app/utils/payload";
|
|
9
|
+
import type { TodoTracker } from "#app/utils/todoTracking";
|
|
10
|
+
|
|
11
|
+
// maximum number of stderr lines to keep in the rolling buffer during agent execution
|
|
12
|
+
export const MAX_STDERR_LINES = 20;
|
|
13
|
+
|
|
14
|
+
// ── post-run retry loop ────────────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* how many times the post-run loop may resume the agent to fix a dirty tree
|
|
18
|
+
* or a failing stop hook before giving up.
|
|
19
|
+
*/
|
|
20
|
+
export const MAX_POST_RUN_RETRIES = 3;
|
|
21
|
+
|
|
22
|
+
export function getGitStatus(): string {
|
|
23
|
+
try {
|
|
24
|
+
return execFileSync("git", ["status", "--porcelain"], {
|
|
25
|
+
encoding: "utf-8",
|
|
26
|
+
timeout: 10_000,
|
|
27
|
+
}).trim();
|
|
28
|
+
} catch (err) {
|
|
29
|
+
// a git failure (timeout on a huge repo, index lock held by a stray
|
|
30
|
+
// agent-spawned process) is otherwise indistinguishable from a clean tree,
|
|
31
|
+
// silently disabling the dirty-tree gate — surface it so a lost-work run
|
|
32
|
+
// can be diagnosed.
|
|
33
|
+
log.warning(
|
|
34
|
+
`git status failed — dirty-tree gate skipped for this check: ${err instanceof Error ? err.message : String(err)}`,
|
|
35
|
+
);
|
|
36
|
+
return "";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function buildCommitPrompt(status: string): string {
|
|
41
|
+
return [
|
|
42
|
+
`UNCOMMITTED CHANGES — the working tree is dirty. push all changes to a pull request (new or existing). \`git status\` must be clean before you finish.`,
|
|
43
|
+
"",
|
|
44
|
+
"```",
|
|
45
|
+
status,
|
|
46
|
+
"```",
|
|
47
|
+
].join("\n");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface StopHookFailure {
|
|
51
|
+
exitCode: number;
|
|
52
|
+
output: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface SummaryStale {
|
|
56
|
+
/** absolute path to the seeded snapshot file the agent was meant to edit. */
|
|
57
|
+
filePath: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface PostRunIssues {
|
|
61
|
+
stopHook?: StopHookFailure;
|
|
62
|
+
dirtyTree?: string;
|
|
63
|
+
/** populated when the rolling PR summary file is byte-identical to its
|
|
64
|
+
* seed, i.e. the agent never touched it. soft gate — nudges once via a
|
|
65
|
+
* resume turn but never fails the run, parallel to dirtyTree semantics. */
|
|
66
|
+
summaryStale?: SummaryStale;
|
|
67
|
+
/**
|
|
68
|
+
* populated when the agent selected a review mode but the post-run check
|
|
69
|
+
* over toolState shows neither a `create_pull_request_review` submission
|
|
70
|
+
* nor a final `report_progress` write happened. derived inline from
|
|
71
|
+
* `toolState.selectedMode` + `toolState.review` + `toolState.finalSummaryWritten`
|
|
72
|
+
* via {@link getUnsubmittedReview} — no parallel toolState flag is stored.
|
|
73
|
+
* carries the mode name so the resume prompt can reference it. handled like
|
|
74
|
+
* `stopHook`: nudge via resume, hard-fail if still unsatisfied after
|
|
75
|
+
* `MAX_POST_RUN_RETRIES`.
|
|
76
|
+
*/
|
|
77
|
+
unsubmittedReview?: "Review" | "IncrementalReview" | "TerraformCodeReview";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function hasPostRunIssues(issues: PostRunIssues): boolean {
|
|
81
|
+
return (
|
|
82
|
+
issues.stopHook !== undefined ||
|
|
83
|
+
issues.dirtyTree !== undefined ||
|
|
84
|
+
issues.summaryStale !== undefined ||
|
|
85
|
+
issues.unsubmittedReview !== undefined
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* token/cost usage data from a single agent run.
|
|
91
|
+
*
|
|
92
|
+
* NOTE on semantics: `inputTokens` here is the *total* billable input for the
|
|
93
|
+
* run — non-cached input + cache read + cache write — matching the per-agent
|
|
94
|
+
* SDK conventions. This is what gets persisted to `WorkflowRun.inputTokens`.
|
|
95
|
+
*
|
|
96
|
+
* The stdout token table and markdown step summary display a different "Input"
|
|
97
|
+
* column that shows only the non-cached portion (derivable as
|
|
98
|
+
* `inputTokens - cacheReadTokens - cacheWriteTokens`) so humans can see the
|
|
99
|
+
* cache hit ratio at a glance. Dashboards that query `WorkflowRun.inputTokens`
|
|
100
|
+
* directly are seeing the full total, not the log column.
|
|
101
|
+
*/
|
|
102
|
+
export interface AgentUsage {
|
|
103
|
+
agent: string;
|
|
104
|
+
/** full billable input: non-cached + cache read + cache write */
|
|
105
|
+
inputTokens: number;
|
|
106
|
+
outputTokens: number;
|
|
107
|
+
cacheReadTokens?: number | undefined;
|
|
108
|
+
cacheWriteTokens?: number | undefined;
|
|
109
|
+
costUsd?: number | undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface AgentToolUseEvent {
|
|
113
|
+
toolName: string;
|
|
114
|
+
input: unknown;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Result returned by agent execution
|
|
119
|
+
*/
|
|
120
|
+
export interface AgentResult {
|
|
121
|
+
success: boolean;
|
|
122
|
+
output?: string | undefined;
|
|
123
|
+
error?: string | undefined;
|
|
124
|
+
metadata?: Record<string, unknown>;
|
|
125
|
+
usage?: AgentUsage | undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Env var that carries the per-run MCP bearer token to BOTH agent harnesses,
|
|
130
|
+
* which reference it from their MCP client config so the on-disk/in-config form
|
|
131
|
+
* holds only a placeholder, never the raw token:
|
|
132
|
+
* - Claude Code expands `${INFRAWEAVER_MCP_TOKEN}` in .mcp.json headers.
|
|
133
|
+
* - opencode expands `{env:INFRAWEAVER_MCP_TOKEN}` in remote-MCP headers.
|
|
134
|
+
* The `_TOKEN` suffix also makes filterEnv() strip it from the MCP shell
|
|
135
|
+
* sandbox. Set only on the agent/server spawn env (never process.env), so a
|
|
136
|
+
* co-located dependency-install subprocess never inherits it. See
|
|
137
|
+
* ToolContext.mcpServerToken and gateServer.ts for the same pattern.
|
|
138
|
+
*/
|
|
139
|
+
export const MCP_SERVER_TOKEN_ENV = "INFRAWEAVER_MCP_TOKEN";
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Context passed to agent.run() and threaded through the post-run loop.
|
|
143
|
+
*
|
|
144
|
+
* design rule: this is the single object that flows through the harness and
|
|
145
|
+
* downstream utilities by reference. derived predicates (e.g.
|
|
146
|
+
* `getUnsubmittedReview`), tmpfile paths, and seed bytes live on
|
|
147
|
+
* `toolState` — read them at the call site, do not duplicate them onto this
|
|
148
|
+
* interface. utilities that need run state should accept `ctx` whole, not
|
|
149
|
+
* destructure a narrow subset.
|
|
150
|
+
*/
|
|
151
|
+
export interface AgentRunContext {
|
|
152
|
+
payload: ResolvedPayload;
|
|
153
|
+
resolvedModel?: string | undefined;
|
|
154
|
+
mcpServerUrl: string;
|
|
155
|
+
/** per-run bearer token the agent's MCP client presents to mcpServerUrl. See
|
|
156
|
+
* ToolContext.mcpServerToken — delivered to the client config out-of-band so
|
|
157
|
+
* it never lands in a readable file. */
|
|
158
|
+
mcpServerToken: string;
|
|
159
|
+
tmpdir: string;
|
|
160
|
+
/** harness-owned secret paths that agent filesystem tools must never read. */
|
|
161
|
+
secretDenyPaths?: string[] | undefined;
|
|
162
|
+
/**
|
|
163
|
+
* canonical bare names of the state-mutating MCP tools subagents must not
|
|
164
|
+
* call, derived from each tool's `mutates` flag (`subagentDeniedToolNames`).
|
|
165
|
+
* Embedded into the claude/opencode subagent gate sources written at startup.
|
|
166
|
+
*/
|
|
167
|
+
subagentDeniedTools: readonly string[];
|
|
168
|
+
instructions: ResolvedInstructions;
|
|
169
|
+
todoTracker?: TodoTracker | undefined;
|
|
170
|
+
/**
|
|
171
|
+
* user-configured stop hook script. runs after the agent finishes each
|
|
172
|
+
* attempt; non-zero exit resumes the agent with the hook output as
|
|
173
|
+
* guidance. null when the repo has no stop hook configured.
|
|
174
|
+
*/
|
|
175
|
+
stopScript?: string | null | undefined;
|
|
176
|
+
/**
|
|
177
|
+
* mutable per-run state shared with the MCP server (by reference). post-run
|
|
178
|
+
* gates read fresh values from it after each agent attempt — `summaryFilePath`,
|
|
179
|
+
* `summarySeed`, `selectedMode`, `review`, `finalSummaryWritten`,
|
|
180
|
+
* `hadProgressComment` are all consulted by `collectPostRunIssues`. see
|
|
181
|
+
* `action/toolState.ts` for the literal-state design rule.
|
|
182
|
+
*/
|
|
183
|
+
toolState: ToolState;
|
|
184
|
+
/**
|
|
185
|
+
* called synchronously when the agent subprocess is killed for inner
|
|
186
|
+
* activity timeout. lets main.ts tear down shared resources (MCP HTTP
|
|
187
|
+
* server) so lingering SSE reconnects don't keep the outer timer alive.
|
|
188
|
+
*/
|
|
189
|
+
onActivityTimeout?: (() => void) | undefined;
|
|
190
|
+
onToolUse?: ((event: AgentToolUseEvent) => void) | undefined;
|
|
191
|
+
/**
|
|
192
|
+
* Per-run token ceiling (OWASP LLM10). Harnesses report their running total
|
|
193
|
+
* to `observe()` as usage arrives and must stop the run when it returns true
|
|
194
|
+
* — the activity watchdogs bound idleness, and a runaway loop is never idle.
|
|
195
|
+
* Absent for call sites with nothing to bound (subagents, tests); use
|
|
196
|
+
* `unlimitedTokenQuota()` rather than a null check when one is required.
|
|
197
|
+
*/
|
|
198
|
+
tokenQuota?: RunTokenQuota | undefined;
|
|
199
|
+
/**
|
|
200
|
+
* Infraweaver API JWT scoped to this run. agents only need this when they
|
|
201
|
+
* have to write state back to Infraweaver mid-run (today: opencode.ts uses
|
|
202
|
+
* it to seed the post-hook's writeback envelope for Codex auth refresh).
|
|
203
|
+
* empty string when the run wasn't context-resolved (e.g. local dry-runs).
|
|
204
|
+
*/
|
|
205
|
+
apiToken: string;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export interface Agent {
|
|
209
|
+
name: AgentId;
|
|
210
|
+
install: (token?: string) => Promise<string>;
|
|
211
|
+
run: (ctx: AgentRunContext) => Promise<AgentResult>;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export const agent = (input: Agent): Agent => {
|
|
215
|
+
return {
|
|
216
|
+
...input,
|
|
217
|
+
run: async (ctx: AgentRunContext): Promise<AgentResult> => {
|
|
218
|
+
log.debug(`» payload: ${JSON.stringify(ctx.payload, null, 2)}`);
|
|
219
|
+
return input.run(ctx);
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
/** format a USD cost to 4 decimal places, always showing the leading zero */
|
|
225
|
+
export function formatCostUsd(costUsd: number): string {
|
|
226
|
+
return costUsd.toFixed(4);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Redirect the sub-agent's HOME / XDG config into the run tmpdir so it never
|
|
231
|
+
* reads or writes the runner's real home. Both harnesses build this identically
|
|
232
|
+
* (then `mkdir` under `XDG_CONFIG_HOME` for their provider config).
|
|
233
|
+
*/
|
|
234
|
+
export function agentHomeEnv(tmpdir: string): {
|
|
235
|
+
HOME: string;
|
|
236
|
+
XDG_CONFIG_HOME: string;
|
|
237
|
+
} {
|
|
238
|
+
return { HOME: tmpdir, XDG_CONFIG_HOME: join(tmpdir, ".config") };
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* The base spawn env every harness starts from: the process env, the tmpdir
|
|
243
|
+
* HOME/XDG redirect, and `PWD` pinned to the repo dir.
|
|
244
|
+
*
|
|
245
|
+
* PWD is load-bearing: opencode (≥1.14) resolves the session `directory` from
|
|
246
|
+
* `process.env.PWD`, and claude-code (2.1.x) registers `PWD` as a "session"
|
|
247
|
+
* additional working dir when it differs from `process.cwd()` — so inheriting
|
|
248
|
+
* the harness's own PWD via `...process.env` would add the wrong dir to the
|
|
249
|
+
* agent's allowed working set under `pnpm runtest`/`dev:run`. Providers spread
|
|
250
|
+
* this and layer their own keys (config content, credentials) on top.
|
|
251
|
+
*/
|
|
252
|
+
export function baseAgentEnv(
|
|
253
|
+
homeEnv: { HOME: string; XDG_CONFIG_HOME: string },
|
|
254
|
+
repoDir: string,
|
|
255
|
+
): NodeJS.ProcessEnv {
|
|
256
|
+
return { ...process.env, ...homeEnv, PWD: repoDir };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Normalize a run's raw token/cost components into an {@link AgentUsage}, or
|
|
261
|
+
* `undefined` when the run produced nothing billable. The single home for the
|
|
262
|
+
* convention both harnesses previously re-implemented in their `buildUsage`:
|
|
263
|
+
* - total `inputTokens` = non-cached input + cache read + cache write
|
|
264
|
+
* - a zero cache / cost field collapses to `undefined` (symmetry with
|
|
265
|
+
* {@link mergeAgentUsage})
|
|
266
|
+
* - all-zero input/output/cost → `undefined` (no empty usage rows)
|
|
267
|
+
*/
|
|
268
|
+
export function buildAgentUsage(parts: {
|
|
269
|
+
agent: string;
|
|
270
|
+
/** non-cached input tokens sent this run. */
|
|
271
|
+
input: number;
|
|
272
|
+
output: number;
|
|
273
|
+
cacheRead: number;
|
|
274
|
+
cacheWrite: number;
|
|
275
|
+
costUsd: number;
|
|
276
|
+
}): AgentUsage | undefined {
|
|
277
|
+
const inputTokens = parts.input + parts.cacheRead + parts.cacheWrite;
|
|
278
|
+
if (inputTokens <= 0 && parts.output <= 0 && parts.costUsd <= 0)
|
|
279
|
+
return undefined;
|
|
280
|
+
return {
|
|
281
|
+
agent: parts.agent,
|
|
282
|
+
inputTokens,
|
|
283
|
+
outputTokens: parts.output,
|
|
284
|
+
cacheReadTokens: parts.cacheRead > 0 ? parts.cacheRead : undefined,
|
|
285
|
+
cacheWriteTokens: parts.cacheWrite > 0 ? parts.cacheWrite : undefined,
|
|
286
|
+
costUsd: parts.costUsd > 0 ? parts.costUsd : undefined,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* merge two AgentUsage snapshots into one running total.
|
|
292
|
+
*
|
|
293
|
+
* both agent harnesses invoke their runner multiple times per `run()` when the
|
|
294
|
+
* post-run retry loop kicks in (MAX_POST_RUN_RETRIES). each invocation
|
|
295
|
+
* produces its own AgentUsage; we sum them so downstream callers (usage
|
|
296
|
+
* summary, WorkflowRun persistence) see the whole session — not just the
|
|
297
|
+
* final retry's slice.
|
|
298
|
+
*
|
|
299
|
+
* returns `undefined` when both sides are empty so callers can short-circuit
|
|
300
|
+
* without a special case. zero-valued cache / cost fields are dropped to
|
|
301
|
+
* `undefined` for symmetry with each harness's `buildUsage`.
|
|
302
|
+
*/
|
|
303
|
+
export function mergeAgentUsage(
|
|
304
|
+
a: AgentUsage | undefined,
|
|
305
|
+
b: AgentUsage | undefined,
|
|
306
|
+
): AgentUsage | undefined {
|
|
307
|
+
// always return a fresh object — callers treat AgentUsage as immutable, and
|
|
308
|
+
// returning `a` / `b` directly would leak that invariant to future callers
|
|
309
|
+
if (!a && !b) return undefined;
|
|
310
|
+
if (!a) return { ...(b as AgentUsage) };
|
|
311
|
+
if (!b) return { ...a };
|
|
312
|
+
const cacheRead = (a.cacheReadTokens ?? 0) + (b.cacheReadTokens ?? 0);
|
|
313
|
+
const cacheWrite = (a.cacheWriteTokens ?? 0) + (b.cacheWriteTokens ?? 0);
|
|
314
|
+
const cost = (a.costUsd ?? 0) + (b.costUsd ?? 0);
|
|
315
|
+
return {
|
|
316
|
+
agent: a.agent,
|
|
317
|
+
inputTokens: a.inputTokens + b.inputTokens,
|
|
318
|
+
outputTokens: a.outputTokens + b.outputTokens,
|
|
319
|
+
cacheReadTokens: cacheRead > 0 ? cacheRead : undefined,
|
|
320
|
+
cacheWriteTokens: cacheWrite > 0 ? cacheWrite : undefined,
|
|
321
|
+
costUsd: cost > 0 ? cost : undefined,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* unified per-run token table used by every agent harness.
|
|
327
|
+
*
|
|
328
|
+
* columns are kept stable across agents and models so downstream log parsers
|
|
329
|
+
* (scripts/token-usage.ts, cost dashboards) only have to understand one format:
|
|
330
|
+
*
|
|
331
|
+
* Input non-cached input tokens sent this run
|
|
332
|
+
* Cache Read input tokens served from prompt cache (Anthropic, etc.)
|
|
333
|
+
* Cache Write input tokens written to prompt cache this run
|
|
334
|
+
* Output assistant output tokens
|
|
335
|
+
* Total sum of the four columns — the real billable quantity
|
|
336
|
+
* Cost ($) USD cost reported by the provider (only rendered when known)
|
|
337
|
+
*
|
|
338
|
+
* models that don't report prompt caching leave Cache Read / Write at 0.
|
|
339
|
+
* OpenCode emits per-step `part.cost` sourced from models.dev (works across
|
|
340
|
+
* Anthropic, OpenAI, Google, xAI, DeepSeek, Moonshot, OpenRouter, etc.);
|
|
341
|
+
* Claude CLI emits `total_cost_usd` on its final `result` event. pass the
|
|
342
|
+
* accumulated value via `costUsd` to render the Cost column.
|
|
343
|
+
*/
|
|
344
|
+
export function logTokenTable(t: {
|
|
345
|
+
input: number;
|
|
346
|
+
cacheRead: number;
|
|
347
|
+
cacheWrite: number;
|
|
348
|
+
output: number;
|
|
349
|
+
costUsd?: number | undefined;
|
|
350
|
+
}): void {
|
|
351
|
+
const total = t.input + t.cacheRead + t.cacheWrite + t.output;
|
|
352
|
+
// narrow costUsd to a concrete number so the render path doesn't need a cast
|
|
353
|
+
const costUsd =
|
|
354
|
+
typeof t.costUsd === "number" && t.costUsd > 0 ? t.costUsd : undefined;
|
|
355
|
+
|
|
356
|
+
const headerRow: Array<{ data: string; header: true }> = [
|
|
357
|
+
{ data: "Input", header: true },
|
|
358
|
+
{ data: "Cache Read", header: true },
|
|
359
|
+
{ data: "Cache Write", header: true },
|
|
360
|
+
{ data: "Output", header: true },
|
|
361
|
+
{ data: "Total", header: true },
|
|
362
|
+
];
|
|
363
|
+
const dataRow: string[] = [
|
|
364
|
+
String(t.input),
|
|
365
|
+
String(t.cacheRead),
|
|
366
|
+
String(t.cacheWrite),
|
|
367
|
+
String(t.output),
|
|
368
|
+
String(total),
|
|
369
|
+
];
|
|
370
|
+
|
|
371
|
+
if (costUsd !== undefined) {
|
|
372
|
+
headerRow.push({ data: "Cost ($)", header: true });
|
|
373
|
+
dataRow.push(formatCostUsd(costUsd));
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
log.table([headerRow, dataRow]);
|
|
377
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { modelAliases } from "#app/models";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Derive a cheaper subagent model override from the orchestrator's resolved
|
|
5
|
+
* model spec.
|
|
6
|
+
*
|
|
7
|
+
* This is a pure registry lookup: every alias in `action/models.ts` declares
|
|
8
|
+
* its own `subagentModel` (alias key in the same provider). At runtime we
|
|
9
|
+
* reverse-lookup the orchestrator's resolved slug to find the alias that
|
|
10
|
+
* produced it, follow the `subagentModel` pointer, and return the target
|
|
11
|
+
* alias's resolve / openRouterResolve depending on which route the
|
|
12
|
+
* orchestrator was using.
|
|
13
|
+
*
|
|
14
|
+
* Returns `{ reviewer: undefined }` when the orchestrator's alias has no
|
|
15
|
+
* `subagentModel` (e.g. it's already at a sufficiently cheap tier, or its
|
|
16
|
+
* provider doesn't have a clean cheaper-but-capable sibling). See models.ts
|
|
17
|
+
* for the wiring + per-provider rationale.
|
|
18
|
+
*/
|
|
19
|
+
export function deriveSubagentModels(orchestratorSpec: string | undefined): {
|
|
20
|
+
reviewer: string | undefined;
|
|
21
|
+
} {
|
|
22
|
+
if (!orchestratorSpec) return { reviewer: undefined };
|
|
23
|
+
|
|
24
|
+
// Reverse-lookup. The same resolve string appears in only one alias
|
|
25
|
+
// (within its provider), so first match wins. We track which field
|
|
26
|
+
// matched (resolve vs openRouterResolve) so we can pick the same field
|
|
27
|
+
// off the subagent target — keeping the orchestrator's route consistent.
|
|
28
|
+
for (const source of modelAliases) {
|
|
29
|
+
const matchedDirect = source.resolve === orchestratorSpec;
|
|
30
|
+
const matchedOR = source.openRouterResolve === orchestratorSpec;
|
|
31
|
+
if (!matchedDirect && !matchedOR) continue;
|
|
32
|
+
if (!source.subagentModel) return { reviewer: undefined };
|
|
33
|
+
const target = modelAliases.find((a) => a.slug === source.subagentModel);
|
|
34
|
+
if (!target) return { reviewer: undefined };
|
|
35
|
+
const reviewer = matchedOR ? target.openRouterResolve : target.resolve;
|
|
36
|
+
return { reviewer };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return { reviewer: undefined };
|
|
40
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-run token quota (OWASP **LLM10**, unbounded consumption).
|
|
3
|
+
*
|
|
4
|
+
* WHAT WAS ACTUALLY UNBOUNDED. The engine already bounds a run in *time* — an
|
|
5
|
+
* outer process-output timer, an inner event-silence watchdog, one agent per
|
|
6
|
+
* run — and Infraweaver Cloud already bounds *spend* per run and per tenant. What
|
|
7
|
+
* neither bounds is **tokens inside a single, continuously-progressing run**: an
|
|
8
|
+
* agent that keeps emitting tokens never trips an activity watchdog, because it
|
|
9
|
+
* is not idle. A hostile repository can steer a remediation loop into exactly
|
|
10
|
+
* that shape (a fix that re-breaks its own check, a file that always re-scans
|
|
11
|
+
* dirty), and on a **self-hosted** run there is no Cloud meter watching. Time
|
|
12
|
+
* says nothing about consumption; this module is the missing bound.
|
|
13
|
+
*
|
|
14
|
+
* FAIL-CLOSED, NOT TRUNCATED. When the quota is reached the run STOPS and says
|
|
15
|
+
* so. It does not quietly finish with whatever it had — a truncated compliance
|
|
16
|
+
* run that reports as complete is worse than no run, because the output looks
|
|
17
|
+
* like an assessment and is not one. {@link RunTokenQuota.gap} is the sentence
|
|
18
|
+
* that goes to the operator, phrased as a coverage gap rather than a crash.
|
|
19
|
+
*
|
|
20
|
+
* WHY MONOTONIC-BY-SOURCE. The harnesses do not report deltas. Claude Code
|
|
21
|
+
* accumulates per-message usage and then *replaces* the running total with the
|
|
22
|
+
* authoritative figure from the terminal `result` event; opencode sums per-turn
|
|
23
|
+
* and retries produce a fresh accumulator. Feeding either straight into a `+=`
|
|
24
|
+
* would double-count. So callers report a running TOTAL under a stable source
|
|
25
|
+
* key and the quota charges only the increase — correct whether the harness
|
|
26
|
+
* accumulates, replaces, or restarts, and never decreasing.
|
|
27
|
+
*
|
|
28
|
+
* INPUT-ONLY, NEVER `.infraweaver.yml`. This is a safety limit, so it is settable
|
|
29
|
+
* from the workflow input alone. A quota a pull request could raise in the run
|
|
30
|
+
* that reviews it would not be a quota — the A.1 lesson, applied at birth (the
|
|
31
|
+
* same call TC-0.2 made for `tools_network`).
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Thrown (as an abort reason) when a run reaches its token ceiling.
|
|
36
|
+
*
|
|
37
|
+
* A distinct class because the retry paths must be able to tell this apart
|
|
38
|
+
* from a transient provider failure: retrying a run that was stopped for
|
|
39
|
+
* spending too much is precisely the wrong response, and would double the
|
|
40
|
+
* consumption the quota exists to bound.
|
|
41
|
+
*/
|
|
42
|
+
export class TokenQuotaExceededError extends Error {
|
|
43
|
+
readonly code = "TOKEN_QUOTA_EXCEEDED";
|
|
44
|
+
constructor(message: string) {
|
|
45
|
+
super(message);
|
|
46
|
+
this.name = "TokenQuotaExceededError";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** True when an unknown error is (or wraps) a token-quota abort. */
|
|
51
|
+
export function isTokenQuotaError(err: unknown): boolean {
|
|
52
|
+
return err instanceof TokenQuotaExceededError;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Default ceiling on billable tokens for one run.
|
|
57
|
+
*
|
|
58
|
+
* Sized to bound a runaway, not to ration real work: a heavy Review over a
|
|
59
|
+
* large repository lands in the low millions once cache reads are counted, so
|
|
60
|
+
* this sits roughly an order of magnitude above the worst legitimate run we
|
|
61
|
+
* expect. A limit tuned close to normal usage would turn a control into an
|
|
62
|
+
* outage, which is how safety limits get switched off for good.
|
|
63
|
+
*/
|
|
64
|
+
export const DEFAULT_RUN_TOKEN_QUOTA = 10_000_000;
|
|
65
|
+
|
|
66
|
+
/** The workflow input that overrides {@link DEFAULT_RUN_TOKEN_QUOTA}. */
|
|
67
|
+
export const RUN_TOKEN_QUOTA_INPUT = "max_run_tokens";
|
|
68
|
+
|
|
69
|
+
/** The four token components a run is charged for. Cache reads are cheap per
|
|
70
|
+
* token but they are still work performed on the model's behalf, and a
|
|
71
|
+
* runaway loop is visible mostly in cache reads — excluding them would leave
|
|
72
|
+
* the loudest signal of the very failure this bounds outside the count. */
|
|
73
|
+
export interface TokenComponents {
|
|
74
|
+
input?: number | undefined;
|
|
75
|
+
output?: number | undefined;
|
|
76
|
+
cacheRead?: number | undefined;
|
|
77
|
+
cacheWrite?: number | undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Sum the components that count against the quota. Negative and non-finite
|
|
81
|
+
* values are dropped rather than trusted — the numbers come from a provider
|
|
82
|
+
* response, which is not ours. */
|
|
83
|
+
export function billableTokens(t: TokenComponents): number {
|
|
84
|
+
let total = 0;
|
|
85
|
+
for (const v of [t.input, t.output, t.cacheRead, t.cacheWrite]) {
|
|
86
|
+
if (typeof v === "number" && Number.isFinite(v) && v > 0) total += v;
|
|
87
|
+
}
|
|
88
|
+
return Math.floor(total);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface RunTokenQuota {
|
|
92
|
+
/** The ceiling, in billable tokens. */
|
|
93
|
+
readonly limit: number;
|
|
94
|
+
/** Billable tokens charged so far across every source. */
|
|
95
|
+
used(): number;
|
|
96
|
+
/**
|
|
97
|
+
* Report a source's running TOTAL (not a delta) and return whether the quota
|
|
98
|
+
* is exhausted as of this observation. `source` must be stable for the life
|
|
99
|
+
* of one accumulator — an attempt id, not a message id.
|
|
100
|
+
*/
|
|
101
|
+
observe(source: string, total: TokenComponents | number): boolean;
|
|
102
|
+
/** True once {@link used} has reached the limit. Latches: a quota cannot
|
|
103
|
+
* un-exhaust, so a late-arriving smaller figure can't reopen a stopped run. */
|
|
104
|
+
exhausted(): boolean;
|
|
105
|
+
/** The operator-facing sentence. Stable text — the error renderer and the
|
|
106
|
+
* tests both key on it. */
|
|
107
|
+
gap(): string;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* A quota that never trips. Returned when the operator sets the input to `0`,
|
|
112
|
+
* and used by call sites that have no quota to enforce (subagent harnesses,
|
|
113
|
+
* tests) so they need no null checks.
|
|
114
|
+
*/
|
|
115
|
+
export function unlimitedTokenQuota(): RunTokenQuota {
|
|
116
|
+
let used = 0;
|
|
117
|
+
const seen = new Map<string, number>();
|
|
118
|
+
return {
|
|
119
|
+
limit: 0,
|
|
120
|
+
used: () => used,
|
|
121
|
+
observe(source, total) {
|
|
122
|
+
const t =
|
|
123
|
+
typeof total === "number"
|
|
124
|
+
? Math.max(0, Math.floor(total))
|
|
125
|
+
: billableTokens(total);
|
|
126
|
+
const prev = seen.get(source) ?? 0;
|
|
127
|
+
if (t > prev) {
|
|
128
|
+
used += t - prev;
|
|
129
|
+
seen.set(source, t);
|
|
130
|
+
}
|
|
131
|
+
return false;
|
|
132
|
+
},
|
|
133
|
+
exhausted: () => false,
|
|
134
|
+
gap: () => "",
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Create a per-run token quota.
|
|
140
|
+
*
|
|
141
|
+
* `limit <= 0` yields {@link unlimitedTokenQuota} — the explicit opt-out, which
|
|
142
|
+
* an operator has to ask for. There is no accidental path to unlimited.
|
|
143
|
+
*/
|
|
144
|
+
export function createTokenQuota(limit: number): RunTokenQuota {
|
|
145
|
+
if (!Number.isFinite(limit) || limit <= 0) return unlimitedTokenQuota();
|
|
146
|
+
const ceiling = Math.floor(limit);
|
|
147
|
+
let used = 0;
|
|
148
|
+
let latched = false;
|
|
149
|
+
const seen = new Map<string, number>();
|
|
150
|
+
return {
|
|
151
|
+
limit: ceiling,
|
|
152
|
+
used: () => used,
|
|
153
|
+
observe(source, total) {
|
|
154
|
+
const t =
|
|
155
|
+
typeof total === "number"
|
|
156
|
+
? Math.max(0, Math.floor(total))
|
|
157
|
+
: billableTokens(total);
|
|
158
|
+
const prev = seen.get(source) ?? 0;
|
|
159
|
+
if (t > prev) {
|
|
160
|
+
used += t - prev;
|
|
161
|
+
seen.set(source, t);
|
|
162
|
+
}
|
|
163
|
+
if (used >= ceiling) latched = true;
|
|
164
|
+
return latched;
|
|
165
|
+
},
|
|
166
|
+
exhausted: () => latched,
|
|
167
|
+
gap: () =>
|
|
168
|
+
`run token quota exhausted: ${used.toLocaleString("en-GB")} of ${ceiling.toLocaleString("en-GB")} ` +
|
|
169
|
+
"billable tokens consumed, so the run was stopped before it finished. Its results are INCOMPLETE " +
|
|
170
|
+
"and must not be read as a clean assessment — a finding that would have been raised after this " +
|
|
171
|
+
`point was never looked for. Raise \`${RUN_TOKEN_QUOTA_INPUT}\` if the run legitimately needs more ` +
|
|
172
|
+
`budget, or set \`${RUN_TOKEN_QUOTA_INPUT}: 0\` to remove the bound entirely. A run that reaches ` +
|
|
173
|
+
"this limit without finishing is more often a remediation loop that cannot converge (a fix that " +
|
|
174
|
+
"re-breaks its own check) than a genuinely large repository.",
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Parse the `max_run_tokens` input. A non-negative integer; `0` means unlimited.
|
|
180
|
+
* Anything unparseable returns undefined so the caller applies the default —
|
|
181
|
+
* a typo'd limit must not silently become "no limit".
|
|
182
|
+
*
|
|
183
|
+
* Deliberately stricter than the other numeric input parsers, which use a bare
|
|
184
|
+
* `parseInt`. `parseInt("1e6")` is `1` and `parseInt("5.5")` is `5`: for
|
|
185
|
+
* `max_prs` a prefix-parse is merely surprising, but here it would turn a
|
|
186
|
+
* plausible-looking limit into a one-token quota that aborts every run at the
|
|
187
|
+
* first message. Underscore separators are accepted because a limit of
|
|
188
|
+
* `10_000_000` is far easier to read — and to get right — than `10000000`.
|
|
189
|
+
*/
|
|
190
|
+
export function parseRunTokenQuota(
|
|
191
|
+
raw: string | undefined,
|
|
192
|
+
): number | undefined {
|
|
193
|
+
if (raw === undefined) return undefined;
|
|
194
|
+
const trimmed = raw.trim().replace(/_/g, "");
|
|
195
|
+
if (!/^\d+$/.test(trimmed)) return undefined;
|
|
196
|
+
const n = Number.parseInt(trimmed, 10);
|
|
197
|
+
return Number.isSafeInteger(n) ? n : undefined;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Resolve the effective limit from the parsed input, applying the default. */
|
|
201
|
+
export function resolveRunTokenQuota(parsed: number | undefined): number {
|
|
202
|
+
return parsed === undefined ? DEFAULT_RUN_TOKEN_QUOTA : parsed;
|
|
203
|
+
}
|