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.
Files changed (524) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +244 -0
  3. package/dist/agents/claude.d.ts +113 -0
  4. package/dist/agents/claudePretoolGate.d.ts +137 -0
  5. package/dist/agents/dispatchMetrics.d.ts +77 -0
  6. package/dist/agents/gateServer.d.ts +7 -0
  7. package/dist/agents/index.d.ts +6 -0
  8. package/dist/agents/nativeFsDenies.d.ts +46 -0
  9. package/dist/agents/opencode.d.ts +284 -0
  10. package/dist/agents/opencodePlugin.d.ts +96 -0
  11. package/dist/agents/opencodeShared.d.ts +40 -0
  12. package/dist/agents/postRun.d.ts +126 -0
  13. package/dist/agents/reviewer.d.ts +41 -0
  14. package/dist/agents/sessionLabeler.d.ts +97 -0
  15. package/dist/agents/shared.d.ts +246 -0
  16. package/dist/agents/subagentModels.d.ts +19 -0
  17. package/dist/agents/tokenQuota.d.ts +118 -0
  18. package/dist/agents/writeGateSource.d.ts +22 -0
  19. package/dist/agents/writePolicy.d.ts +79 -0
  20. package/dist/brand.d.ts +67 -0
  21. package/dist/cli.mjs +247846 -0
  22. package/dist/external.d.ts +227 -0
  23. package/dist/i18n/scaffolding.d.ts +59 -0
  24. package/dist/index.d.ts +6 -0
  25. package/dist/index.js +247061 -0
  26. package/dist/internal/index.d.ts +18 -0
  27. package/dist/internal.js +2398 -0
  28. package/dist/lifecycle.d.ts +2 -0
  29. package/dist/main.d.ts +8 -0
  30. package/dist/mcp/arkConfig.d.ts +1 -0
  31. package/dist/mcp/assess.d.ts +157 -0
  32. package/dist/mcp/capabilityContext.d.ts +71 -0
  33. package/dist/mcp/changeSummary.d.ts +52 -0
  34. package/dist/mcp/checkSuite.d.ts +27 -0
  35. package/dist/mcp/checkout.d.ts +92 -0
  36. package/dist/mcp/comment.d.ts +127 -0
  37. package/dist/mcp/commitInfo.d.ts +11 -0
  38. package/dist/mcp/crosswalk.d.ts +178 -0
  39. package/dist/mcp/crosswalkDigest.d.ts +1 -0
  40. package/dist/mcp/cyberEssentials.d.ts +24 -0
  41. package/dist/mcp/dashboard.d.ts +125 -0
  42. package/dist/mcp/dependencies.d.ts +12 -0
  43. package/dist/mcp/frameworks.d.ts +74 -0
  44. package/dist/mcp/geminiSanitizer.d.ts +28 -0
  45. package/dist/mcp/git.d.ts +60 -0
  46. package/dist/mcp/guardrails.d.ts +222 -0
  47. package/dist/mcp/issue.d.ts +20 -0
  48. package/dist/mcp/issueComments.d.ts +11 -0
  49. package/dist/mcp/issueEvents.d.ts +11 -0
  50. package/dist/mcp/issueInfo.d.ts +11 -0
  51. package/dist/mcp/labels.d.ts +14 -0
  52. package/dist/mcp/localContext.d.ts +26 -0
  53. package/dist/mcp/moduleExtraction.d.ts +79 -0
  54. package/dist/mcp/moduleTests.d.ts +106 -0
  55. package/dist/mcp/modules.d.ts +198 -0
  56. package/dist/mcp/output.d.ts +16 -0
  57. package/dist/mcp/pathSafety.d.ts +14 -0
  58. package/dist/mcp/policy.d.ts +50 -0
  59. package/dist/mcp/pr.d.ts +64 -0
  60. package/dist/mcp/prInfo.d.ts +11 -0
  61. package/dist/mcp/providerSchema.d.ts +52 -0
  62. package/dist/mcp/review.d.ts +212 -0
  63. package/dist/mcp/reviewComments.d.ts +245 -0
  64. package/dist/mcp/roots.d.ts +60 -0
  65. package/dist/mcp/scope.d.ts +26 -0
  66. package/dist/mcp/selectMode.d.ts +20 -0
  67. package/dist/mcp/server.d.ts +61 -0
  68. package/dist/mcp/shared.d.ts +62 -0
  69. package/dist/mcp/shell.d.ts +58 -0
  70. package/dist/mcp/staleFix.d.ts +138 -0
  71. package/dist/mcp/terraform/azurePrices.d.ts +8 -0
  72. package/dist/mcp/terraform/baseline.d.ts +57 -0
  73. package/dist/mcp/terraform/concernResult.d.ts +38 -0
  74. package/dist/mcp/terraform/cost.d.ts +55 -0
  75. package/dist/mcp/terraform/cspm.d.ts +80 -0
  76. package/dist/mcp/terraform/currency.d.ts +110 -0
  77. package/dist/mcp/terraform/decisions.d.ts +178 -0
  78. package/dist/mcp/terraform/eidas.d.ts +100 -0
  79. package/dist/mcp/terraform/evidence.d.ts +343 -0
  80. package/dist/mcp/terraform/findings.d.ts +76 -0
  81. package/dist/mcp/terraform/fixMemory.d.ts +81 -0
  82. package/dist/mcp/terraform/governance.d.ts +56 -0
  83. package/dist/mcp/terraform/hcl.d.ts +115 -0
  84. package/dist/mcp/terraform/iacLanguages.d.ts +120 -0
  85. package/dist/mcp/terraform/idleFloor.d.ts +78 -0
  86. package/dist/mcp/terraform/keyless.d.ts +68 -0
  87. package/dist/mcp/terraform/moduleDocs.d.ts +56 -0
  88. package/dist/mcp/terraform/nativeRules.d.ts +38 -0
  89. package/dist/mcp/terraform/nativeScan.d.ts +11 -0
  90. package/dist/mcp/terraform/noiseProfile.d.ts +100 -0
  91. package/dist/mcp/terraform/normalization.d.ts +52 -0
  92. package/dist/mcp/terraform/oscal.d.ts +103 -0
  93. package/dist/mcp/terraform/packs/azurerm-3-4.d.ts +2 -0
  94. package/dist/mcp/terraform/packs/cloudflare-4-5.d.ts +2 -0
  95. package/dist/mcp/terraform/paths.d.ts +28 -0
  96. package/dist/mcp/terraform/plan.d.ts +157 -0
  97. package/dist/mcp/terraform/planDrift.d.ts +199 -0
  98. package/dist/mcp/terraform/policyAuthor.d.ts +191 -0
  99. package/dist/mcp/terraform/prowlerOcsf.d.ts +136 -0
  100. package/dist/mcp/terraform/refactor.d.ts +183 -0
  101. package/dist/mcp/terraform/registry.d.ts +108 -0
  102. package/dist/mcp/terraform/risk.d.ts +41 -0
  103. package/dist/mcp/terraform/scanSession.d.ts +116 -0
  104. package/dist/mcp/terraform/scannerCache.d.ts +15 -0
  105. package/dist/mcp/terraform/scannerEgress.d.ts +72 -0
  106. package/dist/mcp/terraform/scannerJson.d.ts +13 -0
  107. package/dist/mcp/terraform/scanners.d.ts +205 -0
  108. package/dist/mcp/terraform/signing.d.ts +61 -0
  109. package/dist/mcp/terraform/stateLocking.d.ts +18 -0
  110. package/dist/mcp/terraform/subprocess.d.ts +43 -0
  111. package/dist/mcp/terraform/suppressions.d.ts +90 -0
  112. package/dist/mcp/terraform/taxonomy.d.ts +39 -0
  113. package/dist/mcp/terraform/tfquery.d.ts +47 -0
  114. package/dist/mcp/terraform/toolchainIntegrity.d.ts +82 -0
  115. package/dist/mcp/terraform/tools/authorPolicy.d.ts +59 -0
  116. package/dist/mcp/terraform/tools/detectPlanDrift.d.ts +20 -0
  117. package/dist/mcp/terraform/tools/emitCost.d.ts +11 -0
  118. package/dist/mcp/terraform/tools/emitSarif.d.ts +14 -0
  119. package/dist/mcp/terraform/tools/fixMemory.d.ts +19 -0
  120. package/dist/mcp/terraform/tools/infracostDiff.d.ts +22 -0
  121. package/dist/mcp/terraform/tools/ingestExternalFindings.d.ts +21 -0
  122. package/dist/mcp/terraform/tools/moduleLookup.d.ts +14 -0
  123. package/dist/mcp/terraform/tools/moduleSearch.d.ts +23 -0
  124. package/dist/mcp/terraform/tools/plan.d.ts +59 -0
  125. package/dist/mcp/terraform/tools/providerUpgrade.d.ts +55 -0
  126. package/dist/mcp/terraform/tools/readFindings.d.ts +17 -0
  127. package/dist/mcp/terraform/tools/scan.d.ts +114 -0
  128. package/dist/mcp/terraform/tools/validate.d.ts +31 -0
  129. package/dist/mcp/terraform/tools/verifyRemediation.d.ts +31 -0
  130. package/dist/mcp/terraform/tools/versionCurrency.d.ts +5 -0
  131. package/dist/mcp/terraform/tools.d.ts +16 -0
  132. package/dist/mcp/terraform/transformPacks.d.ts +267 -0
  133. package/dist/mcp/terraform/types.d.ts +226 -0
  134. package/dist/mcp/terraform/verification.d.ts +81 -0
  135. package/dist/mcp/terraform/vex.d.ts +115 -0
  136. package/dist/mcp/terraform/writeOnly.d.ts +67 -0
  137. package/dist/mcp/terraform.d.ts +51 -0
  138. package/dist/mcp/terratest.d.ts +85 -0
  139. package/dist/mcp/untrustedContent.d.ts +76 -0
  140. package/dist/mcp/upload.d.ts +8 -0
  141. package/dist/models.d.ts +181 -0
  142. package/dist/modes/address-reviews.d.ts +2 -0
  143. package/dist/modes/assess.d.ts +2 -0
  144. package/dist/modes/build.d.ts +2 -0
  145. package/dist/modes/compliance-audit.d.ts +2 -0
  146. package/dist/modes/cost-optimization.d.ts +2 -0
  147. package/dist/modes/drift-detect.d.ts +2 -0
  148. package/dist/modes/fix.d.ts +2 -0
  149. package/dist/modes/incremental-review.d.ts +2 -0
  150. package/dist/modes/index.d.ts +24 -0
  151. package/dist/modes/modernize-deprecated.d.ts +2 -0
  152. package/dist/modes/plan.d.ts +2 -0
  153. package/dist/modes/policy-gate.d.ts +2 -0
  154. package/dist/modes/prFormats.d.ts +3 -0
  155. package/dist/modes/refactor.d.ts +2 -0
  156. package/dist/modes/refresh-remediation.d.ts +2 -0
  157. package/dist/modes/remediate-and-refactor.d.ts +2 -0
  158. package/dist/modes/remediate.d.ts +2 -0
  159. package/dist/modes/resolve-conflicts.d.ts +2 -0
  160. package/dist/modes/review.d.ts +2 -0
  161. package/dist/modes/summarize-pr.d.ts +2 -0
  162. package/dist/modes/task.d.ts +2 -0
  163. package/dist/modes/terraform-code-review.d.ts +2 -0
  164. package/dist/modes/types.d.ts +9 -0
  165. package/dist/modes/update-dependencies.d.ts +2 -0
  166. package/dist/prep/index.d.ts +7 -0
  167. package/dist/prep/installNodeDependencies.d.ts +2 -0
  168. package/dist/prep/installPythonDependencies.d.ts +2 -0
  169. package/dist/prep/types.d.ts +31 -0
  170. package/dist/reviewQuality.d.ts +107 -0
  171. package/dist/skills/terraform-best-practices/SKILL.md +379 -0
  172. package/dist/toolState.d.ts +123 -0
  173. package/dist/utils/activity.d.ts +40 -0
  174. package/dist/utils/agent.d.ts +47 -0
  175. package/dist/utils/agentHangReport.d.ts +38 -0
  176. package/dist/utils/annotations.d.ts +17 -0
  177. package/dist/utils/apiFetch.d.ts +11 -0
  178. package/dist/utils/apiKeys.d.ts +48 -0
  179. package/dist/utils/apiUrl.d.ts +28 -0
  180. package/dist/utils/assets.d.ts +8 -0
  181. package/dist/utils/baseRefConfig.d.ts +121 -0
  182. package/dist/utils/billingErrors.d.ts +85 -0
  183. package/dist/utils/body.d.ts +34 -0
  184. package/dist/utils/buildInfraweaverFooter.d.ts +29 -0
  185. package/dist/utils/byokFallback.d.ts +85 -0
  186. package/dist/utils/changeImpact.d.ts +101 -0
  187. package/dist/utils/claudeSubscription.d.ts +30 -0
  188. package/dist/utils/cli.d.ts +10 -0
  189. package/dist/utils/cloudClient.d.ts +33 -0
  190. package/dist/utils/cloudFetchCore.d.ts +42 -0
  191. package/dist/utils/cloudReport.d.ts +114 -0
  192. package/dist/utils/codexHome.d.ts +29 -0
  193. package/dist/utils/codexOAuth.d.ts +60 -0
  194. package/dist/utils/diffCoverage.d.ts +63 -0
  195. package/dist/utils/env.d.ts +46 -0
  196. package/dist/utils/errorReport.d.ts +17 -0
  197. package/dist/utils/exitHandler.d.ts +8 -0
  198. package/dist/utils/fixDoubleEscapedString.d.ts +1 -0
  199. package/dist/utils/gitAuth.d.ts +84 -0
  200. package/dist/utils/gitAuthServer.d.ts +24 -0
  201. package/dist/utils/github.d.ts +104 -0
  202. package/dist/utils/globals.d.ts +3 -0
  203. package/dist/utils/infraweaverConfig.d.ts +56 -0
  204. package/dist/utils/install.d.ts +37 -0
  205. package/dist/utils/instructions.d.ts +48 -0
  206. package/dist/utils/keylessOidc.d.ts +28 -0
  207. package/dist/utils/leapingComment.d.ts +11 -0
  208. package/dist/utils/learnings.d.ts +62 -0
  209. package/dist/utils/learningsTruncate.d.ts +25 -0
  210. package/dist/utils/lifecycle.d.ts +57 -0
  211. package/dist/utils/log.d.ts +111 -0
  212. package/dist/utils/modelResolver.d.ts +63 -0
  213. package/dist/utils/moduleFetch.d.ts +39 -0
  214. package/dist/utils/normalizeEnv.d.ts +30 -0
  215. package/dist/utils/openCodeModels.d.ts +11 -0
  216. package/dist/utils/openaiCompatible.d.ts +26 -0
  217. package/dist/utils/opentofuMcp.d.ts +50 -0
  218. package/dist/utils/overrides.d.ts +40 -0
  219. package/dist/utils/packageManager.d.ts +49 -0
  220. package/dist/utils/patchWorkflowRunFields.d.ts +29 -0
  221. package/dist/utils/payload.d.ts +249 -0
  222. package/dist/utils/prSummary.d.ts +61 -0
  223. package/dist/utils/presets.d.ts +36 -0
  224. package/dist/utils/progressComment.d.ts +146 -0
  225. package/dist/utils/providerErrors.d.ts +31 -0
  226. package/dist/utils/proxyModel.d.ts +76 -0
  227. package/dist/utils/rangeDiff.d.ts +51 -0
  228. package/dist/utils/redact.d.ts +33 -0
  229. package/dist/utils/registryAuth.d.ts +52 -0
  230. package/dist/utils/remediationCommand.d.ts +58 -0
  231. package/dist/utils/retry.d.ts +38 -0
  232. package/dist/utils/reviewCleanup.d.ts +14 -0
  233. package/dist/utils/run.d.ts +9 -0
  234. package/dist/utils/runContext.d.ts +112 -0
  235. package/dist/utils/runContextData.d.ts +42 -0
  236. package/dist/utils/runErrorRenderer.d.ts +64 -0
  237. package/dist/utils/runLifecycle.d.ts +89 -0
  238. package/dist/utils/runStartupLog.d.ts +15 -0
  239. package/dist/utils/secrets.d.ts +34 -0
  240. package/dist/utils/setup.d.ts +90 -0
  241. package/dist/utils/shell.d.ts +44 -0
  242. package/dist/utils/skills.d.ts +10 -0
  243. package/dist/utils/subprocess.d.ts +81 -0
  244. package/dist/utils/terraformMcp.d.ts +46 -0
  245. package/dist/utils/time.d.ts +15 -0
  246. package/dist/utils/timer.d.ts +23 -0
  247. package/dist/utils/todoTracking.d.ts +16 -0
  248. package/dist/utils/token.d.ts +52 -0
  249. package/dist/utils/toolLicensing.d.ts +56 -0
  250. package/dist/utils/toolSelection.d.ts +73 -0
  251. package/dist/utils/toon.d.ts +16 -0
  252. package/dist/utils/version.d.ts +2 -0
  253. package/dist/utils/versioning.d.ts +7 -0
  254. package/dist/utils/vertex.d.ts +16 -0
  255. package/dist/utils/workflow.d.ts +13 -0
  256. package/package.json +132 -0
  257. package/src/agents/claude.ts +1588 -0
  258. package/src/agents/claudePretoolGate.ts +286 -0
  259. package/src/agents/dispatchMetrics.ts +162 -0
  260. package/src/agents/gateServer.ts +178 -0
  261. package/src/agents/index.ts +10 -0
  262. package/src/agents/nativeFsDenies.ts +164 -0
  263. package/src/agents/opencode.ts +1600 -0
  264. package/src/agents/opencodePlugin.ts +304 -0
  265. package/src/agents/opencodeShared.ts +134 -0
  266. package/src/agents/postRun.ts +615 -0
  267. package/src/agents/reviewer.ts +134 -0
  268. package/src/agents/sessionLabeler.ts +185 -0
  269. package/src/agents/shared.ts +377 -0
  270. package/src/agents/subagentModels.ts +40 -0
  271. package/src/agents/tokenQuota.ts +203 -0
  272. package/src/agents/writeGateSource.ts +148 -0
  273. package/src/agents/writePolicy.ts +132 -0
  274. package/src/brand.ts +84 -0
  275. package/src/cli.ts +117 -0
  276. package/src/commands/gha.ts +188 -0
  277. package/src/commands/mcp.ts +126 -0
  278. package/src/commands/verifyEvidence.ts +100 -0
  279. package/src/entry.ts +7 -0
  280. package/src/entryPost.ts +109 -0
  281. package/src/external.ts +308 -0
  282. package/src/i18n/scaffolding.ts +191 -0
  283. package/src/index.ts +7 -0
  284. package/src/internal/index.ts +74 -0
  285. package/src/lifecycle.ts +2 -0
  286. package/src/main.ts +815 -0
  287. package/src/mcp/__fixtures__/infraweaver-scratch-pr-49-review-3485940013.json +110 -0
  288. package/src/mcp/__fixtures__/infraweaver-scratch-pr-64-review-3531000326.json +14 -0
  289. package/src/mcp/__fixtures__/infraweaver-test-repo-pr-1.diff.json +67 -0
  290. package/src/mcp/__snapshots__/checkout.test.ts.snap +109 -0
  291. package/src/mcp/__snapshots__/reviewComments.test.ts.snap +71 -0
  292. package/src/mcp/arkConfig.ts +7 -0
  293. package/src/mcp/assess.ts +723 -0
  294. package/src/mcp/capabilityContext.ts +80 -0
  295. package/src/mcp/changeSummary.ts +145 -0
  296. package/src/mcp/checkSuite.ts +261 -0
  297. package/src/mcp/checkout.ts +1015 -0
  298. package/src/mcp/comment.ts +683 -0
  299. package/src/mcp/commitInfo.ts +57 -0
  300. package/src/mcp/crosswalk.ts +1253 -0
  301. package/src/mcp/crosswalkDigest.ts +5 -0
  302. package/src/mcp/cyberEssentials.ts +60 -0
  303. package/src/mcp/dashboard.ts +232 -0
  304. package/src/mcp/dependencies.ts +190 -0
  305. package/src/mcp/frameworks.ts +236 -0
  306. package/src/mcp/geminiSanitizer.ts +212 -0
  307. package/src/mcp/git.ts +1116 -0
  308. package/src/mcp/guardrails.ts +771 -0
  309. package/src/mcp/issue.ts +74 -0
  310. package/src/mcp/issueComments.ts +48 -0
  311. package/src/mcp/issueEvents.ts +100 -0
  312. package/src/mcp/issueInfo.ts +72 -0
  313. package/src/mcp/labels.ts +35 -0
  314. package/src/mcp/localContext.ts +65 -0
  315. package/src/mcp/localServer.ts +217 -0
  316. package/src/mcp/moduleExtraction.ts +368 -0
  317. package/src/mcp/moduleTests.ts +421 -0
  318. package/src/mcp/modules.ts +752 -0
  319. package/src/mcp/output.ts +71 -0
  320. package/src/mcp/pathSafety.ts +28 -0
  321. package/src/mcp/policy.ts +226 -0
  322. package/src/mcp/pr.ts +238 -0
  323. package/src/mcp/prInfo.ts +91 -0
  324. package/src/mcp/providerSchema.ts +175 -0
  325. package/src/mcp/review.ts +1081 -0
  326. package/src/mcp/reviewComments.ts +1137 -0
  327. package/src/mcp/roots.ts +217 -0
  328. package/src/mcp/scope.ts +82 -0
  329. package/src/mcp/selectMode.ts +207 -0
  330. package/src/mcp/server.ts +498 -0
  331. package/src/mcp/shared.ts +120 -0
  332. package/src/mcp/shell.ts +631 -0
  333. package/src/mcp/staleFix.ts +557 -0
  334. package/src/mcp/terraform/__snapshots__/moduleDocs.test.ts.snap +40 -0
  335. package/src/mcp/terraform/azurePrices.ts +38 -0
  336. package/src/mcp/terraform/baseline.ts +172 -0
  337. package/src/mcp/terraform/concernResult.ts +111 -0
  338. package/src/mcp/terraform/cost.ts +175 -0
  339. package/src/mcp/terraform/cspm.ts +326 -0
  340. package/src/mcp/terraform/currency.ts +354 -0
  341. package/src/mcp/terraform/decisions.ts +590 -0
  342. package/src/mcp/terraform/eidas.ts +134 -0
  343. package/src/mcp/terraform/evidence.ts +771 -0
  344. package/src/mcp/terraform/findings.ts +383 -0
  345. package/src/mcp/terraform/fixMemory.ts +253 -0
  346. package/src/mcp/terraform/governance.ts +231 -0
  347. package/src/mcp/terraform/hcl.ts +273 -0
  348. package/src/mcp/terraform/iacLanguages.ts +431 -0
  349. package/src/mcp/terraform/idleFloor.ts +304 -0
  350. package/src/mcp/terraform/keyless.ts +123 -0
  351. package/src/mcp/terraform/moduleDocs.ts +303 -0
  352. package/src/mcp/terraform/nativeRules.ts +152 -0
  353. package/src/mcp/terraform/nativeScan.ts +67 -0
  354. package/src/mcp/terraform/noiseProfile.ts +183 -0
  355. package/src/mcp/terraform/normalization.ts +265 -0
  356. package/src/mcp/terraform/oscal.ts +283 -0
  357. package/src/mcp/terraform/packs/azurerm-3-4.ts +382 -0
  358. package/src/mcp/terraform/packs/cloudflare-4-5.ts +114 -0
  359. package/src/mcp/terraform/paths.ts +59 -0
  360. package/src/mcp/terraform/plan.ts +377 -0
  361. package/src/mcp/terraform/planDrift.ts +520 -0
  362. package/src/mcp/terraform/policyAuthor.ts +886 -0
  363. package/src/mcp/terraform/prowlerOcsf.ts +380 -0
  364. package/src/mcp/terraform/refactor.ts +879 -0
  365. package/src/mcp/terraform/registry.ts +317 -0
  366. package/src/mcp/terraform/risk.ts +99 -0
  367. package/src/mcp/terraform/scanSession.ts +242 -0
  368. package/src/mcp/terraform/scannerCache.ts +86 -0
  369. package/src/mcp/terraform/scannerEgress.ts +141 -0
  370. package/src/mcp/terraform/scannerJson.ts +22 -0
  371. package/src/mcp/terraform/scanners.ts +1134 -0
  372. package/src/mcp/terraform/signing.ts +151 -0
  373. package/src/mcp/terraform/stateLocking.ts +106 -0
  374. package/src/mcp/terraform/subprocess.ts +102 -0
  375. package/src/mcp/terraform/suppressions.ts +551 -0
  376. package/src/mcp/terraform/taxonomy.ts +0 -0
  377. package/src/mcp/terraform/tfquery.ts +159 -0
  378. package/src/mcp/terraform/toolchainIntegrity.ts +151 -0
  379. package/src/mcp/terraform/tools/authorPolicy.ts +185 -0
  380. package/src/mcp/terraform/tools/detectPlanDrift.ts +279 -0
  381. package/src/mcp/terraform/tools/emitCost.ts +130 -0
  382. package/src/mcp/terraform/tools/emitSarif.ts +108 -0
  383. package/src/mcp/terraform/tools/fixMemory.ts +82 -0
  384. package/src/mcp/terraform/tools/infracostDiff.ts +110 -0
  385. package/src/mcp/terraform/tools/ingestExternalFindings.ts +259 -0
  386. package/src/mcp/terraform/tools/moduleLookup.ts +86 -0
  387. package/src/mcp/terraform/tools/moduleSearch.ts +46 -0
  388. package/src/mcp/terraform/tools/plan.ts +384 -0
  389. package/src/mcp/terraform/tools/providerUpgrade.ts +217 -0
  390. package/src/mcp/terraform/tools/readFindings.ts +138 -0
  391. package/src/mcp/terraform/tools/scan.ts +303 -0
  392. package/src/mcp/terraform/tools/validate.ts +160 -0
  393. package/src/mcp/terraform/tools/verifyRemediation.ts +190 -0
  394. package/src/mcp/terraform/tools/versionCurrency.ts +64 -0
  395. package/src/mcp/terraform/tools.ts +62 -0
  396. package/src/mcp/terraform/transformPacks.ts +594 -0
  397. package/src/mcp/terraform/types.ts +382 -0
  398. package/src/mcp/terraform/verification.ts +150 -0
  399. package/src/mcp/terraform/vex.ts +367 -0
  400. package/src/mcp/terraform/writeOnly.ts +252 -0
  401. package/src/mcp/terraform.ts +52 -0
  402. package/src/mcp/terratest.ts +215 -0
  403. package/src/mcp/untrustedContent.ts +126 -0
  404. package/src/mcp/upload.ts +123 -0
  405. package/src/models.ts +753 -0
  406. package/src/modes/address-reviews.ts +35 -0
  407. package/src/modes/assess.ts +27 -0
  408. package/src/modes/build.ts +86 -0
  409. package/src/modes/compliance-audit.ts +25 -0
  410. package/src/modes/cost-optimization.ts +36 -0
  411. package/src/modes/drift-detect.ts +31 -0
  412. package/src/modes/fix.ts +29 -0
  413. package/src/modes/incremental-review.ts +103 -0
  414. package/src/modes/index.ts +94 -0
  415. package/src/modes/modernize-deprecated.ts +36 -0
  416. package/src/modes/plan.ts +21 -0
  417. package/src/modes/policy-gate.ts +27 -0
  418. package/src/modes/prFormats.ts +325 -0
  419. package/src/modes/refactor.ts +74 -0
  420. package/src/modes/refresh-remediation.ts +40 -0
  421. package/src/modes/remediate-and-refactor.ts +42 -0
  422. package/src/modes/remediate.ts +78 -0
  423. package/src/modes/resolve-conflicts.ts +32 -0
  424. package/src/modes/review.ts +135 -0
  425. package/src/modes/summarize-pr.ts +42 -0
  426. package/src/modes/task.ts +26 -0
  427. package/src/modes/terraform-code-review.ts +68 -0
  428. package/src/modes/types.ts +17 -0
  429. package/src/modes/update-dependencies.ts +44 -0
  430. package/src/prep/index.ts +96 -0
  431. package/src/prep/installNodeDependencies.ts +251 -0
  432. package/src/prep/installPythonDependencies.ts +235 -0
  433. package/src/prep/types.ts +38 -0
  434. package/src/reviewQuality.ts +237 -0
  435. package/src/runCli.ts +335 -0
  436. package/src/skills/terraform-best-practices/SKILL.md +379 -0
  437. package/src/toolState.ts +241 -0
  438. package/src/utils/activity.ts +210 -0
  439. package/src/utils/agent.ts +245 -0
  440. package/src/utils/agentHangReport.ts +180 -0
  441. package/src/utils/annotations.ts +56 -0
  442. package/src/utils/apiFetch.ts +19 -0
  443. package/src/utils/apiKeys.ts +305 -0
  444. package/src/utils/apiUrl.ts +42 -0
  445. package/src/utils/assets.ts +123 -0
  446. package/src/utils/baseRefConfig.ts +254 -0
  447. package/src/utils/billingErrors.ts +210 -0
  448. package/src/utils/body.ts +168 -0
  449. package/src/utils/buildInfraweaverFooter.ts +104 -0
  450. package/src/utils/byokFallback.ts +137 -0
  451. package/src/utils/changeImpact.ts +330 -0
  452. package/src/utils/claudeSubscription.ts +93 -0
  453. package/src/utils/cli.ts +36 -0
  454. package/src/utils/cloudClient.ts +57 -0
  455. package/src/utils/cloudFetchCore.ts +139 -0
  456. package/src/utils/cloudReport.ts +316 -0
  457. package/src/utils/codexHome.ts +204 -0
  458. package/src/utils/codexOAuth.ts +154 -0
  459. package/src/utils/codexRefreshDetect.ts +36 -0
  460. package/src/utils/diffCoverage.ts +404 -0
  461. package/src/utils/env.ts +84 -0
  462. package/src/utils/errorReport.ts +94 -0
  463. package/src/utils/exitHandler.ts +35 -0
  464. package/src/utils/fixDoubleEscapedString.ts +9 -0
  465. package/src/utils/ghaCore.ts +13 -0
  466. package/src/utils/gitAuth.ts +268 -0
  467. package/src/utils/gitAuthServer.ts +186 -0
  468. package/src/utils/github.ts +676 -0
  469. package/src/utils/globals.ts +9 -0
  470. package/src/utils/humanEditCapture.ts +198 -0
  471. package/src/utils/infraweaverConfig.ts +202 -0
  472. package/src/utils/install.ts +279 -0
  473. package/src/utils/instructions.ts +640 -0
  474. package/src/utils/keylessOidc.ts +47 -0
  475. package/src/utils/leapingComment.ts +20 -0
  476. package/src/utils/learnings.ts +145 -0
  477. package/src/utils/learningsTruncate.ts +42 -0
  478. package/src/utils/lifecycle.ts +198 -0
  479. package/src/utils/log.ts +452 -0
  480. package/src/utils/modelResolver.ts +105 -0
  481. package/src/utils/moduleFetch.ts +138 -0
  482. package/src/utils/normalizeEnv.ts +106 -0
  483. package/src/utils/openCodeModels.ts +86 -0
  484. package/src/utils/openaiCompatible.ts +52 -0
  485. package/src/utils/opentofuMcp.ts +61 -0
  486. package/src/utils/overrides.ts +100 -0
  487. package/src/utils/packageManager.ts +257 -0
  488. package/src/utils/patchWorkflowRunFields.ts +173 -0
  489. package/src/utils/payload.ts +1206 -0
  490. package/src/utils/prSummary.ts +148 -0
  491. package/src/utils/presets.ts +105 -0
  492. package/src/utils/progressComment.ts +266 -0
  493. package/src/utils/providerErrors.ts +189 -0
  494. package/src/utils/proxyModel.ts +239 -0
  495. package/src/utils/rangeDiff.ts +182 -0
  496. package/src/utils/redact.ts +86 -0
  497. package/src/utils/registryAuth.ts +115 -0
  498. package/src/utils/remediationCommand.ts +144 -0
  499. package/src/utils/retry.ts +180 -0
  500. package/src/utils/reviewCleanup.ts +116 -0
  501. package/src/utils/run.ts +100 -0
  502. package/src/utils/runContext.ts +276 -0
  503. package/src/utils/runContextData.ts +121 -0
  504. package/src/utils/runErrorRenderer.ts +282 -0
  505. package/src/utils/runFixture.ts +91 -0
  506. package/src/utils/runLifecycle.ts +360 -0
  507. package/src/utils/runStartupLog.ts +67 -0
  508. package/src/utils/secrets.ts +208 -0
  509. package/src/utils/setup.ts +368 -0
  510. package/src/utils/shell.ts +132 -0
  511. package/src/utils/skills.ts +67 -0
  512. package/src/utils/subprocess.ts +474 -0
  513. package/src/utils/terraformMcp.ts +99 -0
  514. package/src/utils/time.ts +59 -0
  515. package/src/utils/timer.ts +72 -0
  516. package/src/utils/todoTracking.ts +168 -0
  517. package/src/utils/token.ts +294 -0
  518. package/src/utils/toolLicensing.ts +152 -0
  519. package/src/utils/toolSelection.ts +239 -0
  520. package/src/utils/toon.ts +76 -0
  521. package/src/utils/version.ts +10 -0
  522. package/src/utils/versioning.ts +44 -0
  523. package/src/utils/vertex.ts +94 -0
  524. 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
+ }