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,210 @@
1
+ import { performance } from "node:perf_hooks";
2
+
3
+ function isMonitorDebugEnabled(): boolean {
4
+ return (
5
+ process.env.ACTIONS_STEP_DEBUG === "true" ||
6
+ process.env.RUNNER_DEBUG === "1" ||
7
+ process.env.LOG_LEVEL === "debug"
8
+ );
9
+ }
10
+
11
+ /**
12
+ * generic `spawn()` idle default for ordinary short-lived subprocesses (prep
13
+ * probes, package-manager invocations, dependency installs). these should be
14
+ * producing output steadily, so a comparatively tight budget catches a wedged
15
+ * command promptly. the long-silent-tool tolerance the agent harnesses need
16
+ * lives in AGENT_ACTIVITY_TIMEOUT_MS, applied explicitly at those sites.
17
+ */
18
+ export const DEFAULT_ACTIVITY_TIMEOUT_MS = 300_000;
19
+
20
+ /**
21
+ * flat idle budget for the agent activity watchdog (the outer process-output
22
+ * monitor, the v1 harness spawns, and the v2 inner event-silence watchdog).
23
+ * sized to exceed the worst-case legitimate silent tool window (issue #760:
24
+ * `checkout_pr` git fetch+deepen on a large monorepo, ~4-5min) with generous
25
+ * headroom, so no single in-flight tool call can be mistaken for a stall. a
26
+ * timeout this generous needs no suspend/resume bracketing — the cost of a
27
+ * genuinely hung run is only GitHub Actions minutes, not tokens.
28
+ */
29
+ export const AGENT_ACTIVITY_TIMEOUT_MS = 900_000;
30
+ export const DEFAULT_ACTIVITY_CHECK_INTERVAL_MS = 5_000;
31
+
32
+ /**
33
+ * chunks whose every non-empty line matches one of these patterns do not
34
+ * count as agent activity. mcp-proxy SSE reconnects and provider-error
35
+ * retries happen on their own schedule and were keeping the outer activity
36
+ * timer alive long after the agent subprocess had been killed for inactivity,
37
+ * producing multi-hour zombie runs.
38
+ *
39
+ * both patterns anchor to the start of the (optionally debug-timestamped)
40
+ * log line so they don't accidentally match agent output that happens to
41
+ * mention "[mcp-proxy]" or "provider error detected" in analysis text.
42
+ */
43
+ const DEBUG_TS_PREFIX = /^(?:\[\d{4}-\d{2}-\d{2}T[^\]]+\]\s+)?/.source;
44
+ // our own internal monitors (this file's bypass + subprocess.ts's spawn
45
+ // activity timer) emit high-frequency diagnostic logs when debug logging is
46
+ // enabled. in the past those lines reached the wrapped process.stdout.write,
47
+ // missed the noise check, and marked activity every interval — which in
48
+ // debug-enabled runs kept the outer timer alive after the agent subprocess
49
+ // was already dead, re-creating the #12 zombie-run bug. the `(?:spawn|process)
50
+ // activity ` patterns below explicitly filter our own diagnostic lines in both
51
+ // local-debug (`[DEBUG] …`) and GH-runner-debug (`::debug::…`) formats.
52
+ export const ACTIVITY_NOISE_PATTERNS: readonly RegExp[] = [
53
+ new RegExp(`${DEBUG_TS_PREFIX}\\[mcp-proxy\\]`),
54
+ new RegExp(`${DEBUG_TS_PREFIX}» provider error detected`),
55
+ new RegExp(`${DEBUG_TS_PREFIX}\\[DEBUG\\]\\s+(?:spawn|process) activity `),
56
+ /^::debug::(?:spawn|process) activity /,
57
+ ];
58
+
59
+ export function isActivityNoise(chunk: string | Uint8Array): boolean {
60
+ const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
61
+ if (!text.trim()) return true;
62
+ return text.split("\n").every((line) => {
63
+ const trimmed = line.trim();
64
+ if (!trimmed) return true;
65
+ return ACTIVITY_NOISE_PATTERNS.some((pattern) => pattern.test(trimmed));
66
+ });
67
+ }
68
+
69
+ type ActivityTimeoutContext = {
70
+ timeoutMs: number;
71
+ checkIntervalMs: number;
72
+ };
73
+
74
+ export type ActivityTimeout = {
75
+ promise: Promise<never>;
76
+ stop: () => void;
77
+ /** force the timeout to reject immediately with a custom reason */
78
+ forceReject: (reason: string) => void;
79
+ };
80
+
81
+ type OutputMonitorContext = {
82
+ timeoutMs: number;
83
+ checkIntervalMs: number;
84
+ onTimeout: (idleMs: number) => void;
85
+ };
86
+
87
+ type OutputMonitor = {
88
+ stop: () => void;
89
+ };
90
+
91
+ type WriteCallback = (error?: Error | null) => void;
92
+ type WriteFunction = {
93
+ (chunk: string | Uint8Array, cb?: WriteCallback): boolean;
94
+ (chunk: string | Uint8Array, encoding?: BufferEncoding, cb?: WriteCallback): boolean;
95
+ };
96
+
97
+ // module-level activity tracking - allows agents to mark activity on any event
98
+ let _lastActivity = performance.now();
99
+
100
+ /**
101
+ * mark activity to reset the no-output timeout.
102
+ * call this whenever the agent emits any event, even if it isn't logged to stdout.
103
+ */
104
+ export function markActivity(): void {
105
+ _lastActivity = performance.now();
106
+ }
107
+
108
+ /** get the time since last activity in milliseconds. */
109
+ export function getIdleMs(): number {
110
+ return Math.round(performance.now() - _lastActivity);
111
+ }
112
+
113
+ function wrapWrite(original: WriteFunction, onActivity: () => void): WriteFunction {
114
+ const wrapped: WriteFunction = (
115
+ chunk: string | Uint8Array,
116
+ encodingOrCb?: BufferEncoding | WriteCallback,
117
+ cb?: WriteCallback,
118
+ ): boolean => {
119
+ if (!isActivityNoise(chunk)) {
120
+ onActivity();
121
+ }
122
+ if (typeof encodingOrCb === "function") {
123
+ return original(chunk, encodingOrCb);
124
+ }
125
+ return original(chunk, encodingOrCb, cb);
126
+ };
127
+ return wrapped;
128
+ }
129
+
130
+ function startProcessOutputMonitor(ctx: OutputMonitorContext): OutputMonitor {
131
+ let timedOut = false;
132
+
133
+ const originalStdoutWrite: WriteFunction = process.stdout.write.bind(process.stdout);
134
+ const originalStderrWrite: WriteFunction = process.stderr.write.bind(process.stderr);
135
+
136
+ // stdout/stderr writes also mark activity
137
+ process.stdout.write = wrapWrite(originalStdoutWrite, markActivity);
138
+ process.stderr.write = wrapWrite(originalStderrWrite, markActivity);
139
+
140
+ // route the monitor's own diagnostics through the captured original write
141
+ // instead of log.debug — otherwise those lines feed back through the
142
+ // wrapped process.stdout.write, miss isActivityNoise, and call
143
+ // markActivity() themselves. in debug mode the periodic check below would
144
+ // then reset the timer every interval and the timeout would never fire,
145
+ // re-creating the exact zombie-run bug #12 was meant to kill.
146
+ const debugBypass = (msg: string): void => {
147
+ if (!isMonitorDebugEnabled()) return;
148
+ originalStdoutWrite(`[${new Date().toISOString()}] [DEBUG] ${msg}\n`);
149
+ };
150
+
151
+ debugBypass(`process activity monitor started: timeout=${ctx.timeoutMs}ms`);
152
+
153
+ const intervalId = setInterval(() => {
154
+ const idleMs = getIdleMs();
155
+ debugBypass(`process activity check: idle=${idleMs}ms / ${ctx.timeoutMs}ms`);
156
+ if (timedOut || idleMs <= ctx.timeoutMs) return;
157
+ timedOut = true;
158
+ ctx.onTimeout(idleMs);
159
+ }, ctx.checkIntervalMs);
160
+
161
+ function stop(): void {
162
+ clearInterval(intervalId);
163
+ process.stdout.write = originalStdoutWrite;
164
+ process.stderr.write = originalStderrWrite;
165
+ }
166
+
167
+ return { stop };
168
+ }
169
+
170
+ export function createProcessOutputActivityTimeout(ctx: ActivityTimeoutContext): ActivityTimeout {
171
+ markActivity(); // reset baseline
172
+
173
+ let rejectFn: ((error: Error) => void) | null = null;
174
+ const promise = new Promise<never>((_, reject) => {
175
+ rejectFn = reject;
176
+ });
177
+
178
+ let monitor: OutputMonitor | null = null;
179
+ monitor = startProcessOutputMonitor({
180
+ timeoutMs: ctx.timeoutMs,
181
+ checkIntervalMs: ctx.checkIntervalMs,
182
+ onTimeout: (idleMs) => {
183
+ if (!rejectFn) return;
184
+ const idleSec = Math.round(idleMs / 1000);
185
+ if (monitor) {
186
+ monitor.stop();
187
+ }
188
+ const reject = rejectFn;
189
+ rejectFn = null;
190
+ reject(new Error(`activity timeout: no output for ${idleSec}s`));
191
+ },
192
+ });
193
+
194
+ return {
195
+ promise,
196
+ // stop() also disarms forceReject so a late safety-net fire can't reject
197
+ // the promise after the run has already succeeded.
198
+ stop: () => {
199
+ monitor?.stop();
200
+ rejectFn = null;
201
+ },
202
+ forceReject: (reason: string) => {
203
+ if (!rejectFn) return;
204
+ monitor?.stop();
205
+ const reject = rejectFn;
206
+ rejectFn = null;
207
+ reject(new Error(reason));
208
+ },
209
+ };
210
+ }
@@ -0,0 +1,245 @@
1
+ import type { Agent } from "#app/agents/index";
2
+ import { agents } from "#app/agents/index";
3
+ import { DOCS_URL } from "#app/brand";
4
+ import {
5
+ BEDROCK_MODEL_ID_ENV,
6
+ getModelProvider,
7
+ isBedrockAnthropicId,
8
+ isVertexAnthropicId,
9
+ OPENAI_COMPATIBLE_MODEL_ID_ENV,
10
+ resolveCliModel,
11
+ resolveDisplayAlias,
12
+ VERTEX_MODEL_ID_ENV,
13
+ } from "#app/models";
14
+ import {
15
+ buildUnavailableModelError,
16
+ hasProviderKeyForModel,
17
+ selectFallbackModelIfNeeded,
18
+ } from "#app/utils/byokFallback";
19
+ import { log } from "#app/utils/cli";
20
+ import {
21
+ OPENAI_COMPATIBLE_BASE_URL_ENV,
22
+ isOpenAiCompatibleRoute,
23
+ } from "#app/utils/openaiCompatible";
24
+ import { VERTEX_SERVICE_ACCOUNT_JSON_ENV } from "#app/utils/vertex";
25
+ import { hasEnvVar } from "#app/utils/env";
26
+
27
+ function hasClaudeCodeAuth(): boolean {
28
+ return hasEnvVar("CLAUDE_CODE_OAUTH_TOKEN") || hasEnvVar("ANTHROPIC_API_KEY");
29
+ }
30
+
31
+ function hasBedrockAuth(): boolean {
32
+ return (
33
+ hasEnvVar("AWS_BEARER_TOKEN_BEDROCK") ||
34
+ (hasEnvVar("AWS_ACCESS_KEY_ID") && hasEnvVar("AWS_SECRET_ACCESS_KEY"))
35
+ );
36
+ }
37
+
38
+ function hasVertexAuth(): boolean {
39
+ return hasEnvVar(VERTEX_SERVICE_ACCOUNT_JSON_ENV);
40
+ }
41
+
42
+ /**
43
+ * resolve a single slug to its CLI-ready model string. routing aliases
44
+ * (e.g. `bedrock/byok`) defer to their backing env var instead of the
45
+ * sentinel stored in `resolve`. shared between INFRAWEAVER_MODEL override
46
+ * and repo-config slug resolution so both paths get the same routing
47
+ * semantics — without this helper, `INFRAWEAVER_MODEL=bedrock/byok` would
48
+ * leak the literal sentinel string `"bedrock"` downstream.
49
+ */
50
+ function resolveSlug(slug: string): string | undefined {
51
+ const alias = resolveDisplayAlias(slug);
52
+ if (alias?.routing === "bedrock") {
53
+ const bedrockId = process.env[BEDROCK_MODEL_ID_ENV]?.trim();
54
+ if (!bedrockId) {
55
+ throw new Error(
56
+ `${BEDROCK_MODEL_ID_ENV} env var is required when the model is set to "${slug}". ` +
57
+ `set it to an AWS Bedrock model ID from the Bedrock console. ` +
58
+ `see ${DOCS_URL}/bedrock for setup.`,
59
+ );
60
+ }
61
+ return bedrockId;
62
+ }
63
+ if (alias?.routing === "vertex") {
64
+ const vertexId = process.env[VERTEX_MODEL_ID_ENV]?.trim();
65
+ if (!vertexId) {
66
+ throw new Error(
67
+ `${VERTEX_MODEL_ID_ENV} env var is required when the model is set to "${slug}". ` +
68
+ `set it to a Google Vertex AI model ID from Model Garden. ` +
69
+ `see ${DOCS_URL}/vertex for setup.`,
70
+ );
71
+ }
72
+ return vertexId;
73
+ }
74
+ if (alias?.routing === "openai-compatible") {
75
+ const modelId = process.env[OPENAI_COMPATIBLE_MODEL_ID_ENV]?.trim();
76
+ if (!modelId) {
77
+ throw new Error(
78
+ `${OPENAI_COMPATIBLE_MODEL_ID_ENV} env var is required when the model is set to "${slug}". ` +
79
+ `set it to the model id your endpoint serves (and ${OPENAI_COMPATIBLE_BASE_URL_ENV} to the endpoint URL). ` +
80
+ `see ${DOCS_URL}/openai-compatible for setup.`,
81
+ );
82
+ }
83
+ return modelId;
84
+ }
85
+ return resolveCliModel(slug);
86
+ }
87
+
88
+ /**
89
+ * resolve the effective model for this run.
90
+ *
91
+ * priority:
92
+ * 1. INFRAWEAVER_MODEL env var — resolved through the alias registry first,
93
+ * so values like "anthropic/claude-opus" become "anthropic/claude-opus-4-7".
94
+ * raw specifiers (e.g. "anthropic/claude-opus-4-6") pass through unchanged.
95
+ * always wins — bypasses Bedrock routing entirely. to test a different
96
+ * Bedrock model, change `BEDROCK_MODEL_ID`, not `INFRAWEAVER_MODEL`.
97
+ * 2. slug from repo config / payload → alias registry. routing slugs
98
+ * (e.g. `bedrock/byok`) defer to a separate env var (`BEDROCK_MODEL_ID`).
99
+ * 3. undefined — agent will auto-select.
100
+ */
101
+ export function resolveModel(ctx: {
102
+ slug?: string | undefined;
103
+ }): string | undefined {
104
+ const envModel = process.env.INFRAWEAVER_MODEL?.trim();
105
+ if (envModel) {
106
+ return resolveSlug(envModel) ?? envModel;
107
+ }
108
+
109
+ if (ctx.slug) {
110
+ const resolved = resolveSlug(ctx.slug);
111
+ if (resolved) {
112
+ return resolved;
113
+ }
114
+ log.warning(`» unknown model slug "${ctx.slug}" — agent will auto-select`);
115
+ }
116
+
117
+ return undefined;
118
+ }
119
+
120
+ export function resolveAgent(ctx: { model?: string | undefined }): Agent {
121
+ // 1. explicit env var override (escape hatch)
122
+ const envAgent = process.env.INFRAWEAVER_AGENT?.trim();
123
+ if (envAgent) {
124
+ if (envAgent in agents) {
125
+ return agents[envAgent as keyof typeof agents];
126
+ }
127
+ log.warning(
128
+ `» unknown INFRAWEAVER_AGENT="${envAgent}" — falling through to auto-select`,
129
+ );
130
+ }
131
+
132
+ // 2. Bedrock routing: when BEDROCK_MODEL_ID is the resolved model, route
133
+ // Anthropic IDs through claude-code (which supports Bedrock natively
134
+ // once CLAUDE_CODE_USE_BEDROCK=1) and everything else through opencode's
135
+ // `amazon-bedrock` provider.
136
+ if (
137
+ ctx.model &&
138
+ hasBedrockAuth() &&
139
+ process.env[BEDROCK_MODEL_ID_ENV]?.trim() === ctx.model
140
+ ) {
141
+ return isBedrockAnthropicId(ctx.model) ? agents.claude : agents.opencode;
142
+ }
143
+
144
+ // 3. Vertex routing: same shape as Bedrock, but Anthropic Vertex IDs are
145
+ // anchored `claude-*` IDs and non-Anthropic models use opencode's
146
+ // `google-vertex` provider.
147
+ if (
148
+ ctx.model &&
149
+ hasVertexAuth() &&
150
+ process.env[VERTEX_MODEL_ID_ENV]?.trim() === ctx.model
151
+ ) {
152
+ return isVertexAnthropicId(ctx.model) ? agents.claude : agents.opencode;
153
+ }
154
+
155
+ // 3b. OpenAI-compatible BYOK endpoint: always opencode (the custom-provider
156
+ // block speaks the OpenAI wire format; claude-code is never involved).
157
+ // Checked before the Anthropic branch so an endpoint whose model id starts
158
+ // with "anthropic/" can't be mis-routed to claude-code.
159
+ if (ctx.model && isOpenAiCompatibleRoute(ctx.model)) {
160
+ return agents.opencode;
161
+ }
162
+
163
+ // 4. if model is Anthropic and Claude Code credentials are available, use Claude Code
164
+ if (ctx.model) {
165
+ try {
166
+ const provider = getModelProvider(ctx.model);
167
+ if (provider === "anthropic" && hasClaudeCodeAuth()) {
168
+ return agents.claude;
169
+ }
170
+ } catch {
171
+ // invalid model format — fall through
172
+ }
173
+ }
174
+
175
+ // 5. default: OpenCode (universal, supports all providers)
176
+ return agents.opencode;
177
+ }
178
+
179
+ /**
180
+ * The single BYOK model gate: resolve the slug, pick the harness, and run the
181
+ * fallback decision in one place. Throws the actionable authorized-model list
182
+ * on the `unavailable` decision (key present but model unroutable — fail loudly,
183
+ * never silently downgrade).
184
+ */
185
+ export interface ModelGateResult {
186
+ /** the effective model that will run (post-fallback); undefined → auto-select */
187
+ model: string | undefined;
188
+ /** the slug to surface in footers/logs */
189
+ effectiveSlug: string | undefined;
190
+ /** the harness resolved for the effective model */
191
+ agent: Agent;
192
+ /** set only when the free safety-net fallback engaged */
193
+ fallback?: { from: string; to: string };
194
+ /** operator warnings to log at the orchestration layer */
195
+ warnings: string[];
196
+ /** whether the caller should still run `validateAgentApiKey` */
197
+ validate: boolean;
198
+ }
199
+
200
+ export function resolveModelWithGating(input: {
201
+ slug?: string | undefined;
202
+ authorized: Set<string>;
203
+ }): ModelGateResult {
204
+ const initialModel = resolveModel({ slug: input.slug });
205
+ const initialAgent = resolveAgent({ model: initialModel });
206
+
207
+ const decision = selectFallbackModelIfNeeded({
208
+ resolvedModel: initialModel,
209
+ authorized: input.authorized,
210
+ providerKeyPresent: initialModel
211
+ ? hasProviderKeyForModel(initialModel)
212
+ : false,
213
+ agentName: initialAgent.name,
214
+ });
215
+
216
+ if (decision.kind === "unavailable") {
217
+ throw new Error(
218
+ buildUnavailableModelError({
219
+ model: decision.model,
220
+ authorized: input.authorized,
221
+ }),
222
+ );
223
+ }
224
+
225
+ if (decision.kind === "fallback") {
226
+ return {
227
+ model: decision.to,
228
+ effectiveSlug: decision.to,
229
+ agent: resolveAgent({ model: decision.to }),
230
+ fallback: { from: decision.from, to: decision.to },
231
+ warnings: [
232
+ `» fell back from ${decision.from} to ${decision.to} — no provider key present in runner env. add a provider key in repo secrets to use ${decision.from} instead.`,
233
+ ],
234
+ validate: false,
235
+ };
236
+ }
237
+
238
+ return {
239
+ model: initialModel,
240
+ effectiveSlug: input.slug,
241
+ agent: initialAgent,
242
+ warnings: [],
243
+ validate: true,
244
+ };
245
+ }
@@ -0,0 +1,180 @@
1
+ import { PRODUCT_NAME } from "#app/brand";
2
+
3
+ const MAX_STDERR_BYTES = 3000;
4
+
5
+ /**
6
+ * mutable per-run handle the agent harness writes to as a run progresses.
7
+ * the action's outer try/catch in `main.ts` reads this off `toolState` when
8
+ * the activity-timeout watchdog wins the race against the harness's own
9
+ * catch — the bare timer reject reason ("activity timeout: no output for
10
+ * 302s") tells the user nothing actionable, but `recentStderr` +
11
+ * `lastProviderError` together usually point straight at the upstream cause.
12
+ *
13
+ * `recentStderr` is shared by reference with the harness's bounded ring
14
+ * buffer, so the diagnostic always reflects the latest captured tail.
15
+ */
16
+ export type AgentDiagnostic = {
17
+ /** display label for the agent, e.g. "Infraweaver". used in the headline. */
18
+ label: string;
19
+ /** shared reference to the harness's bounded stderr ring buffer. */
20
+ recentStderr: string[];
21
+ /** most-recent provider-error label from `detectProviderError`, if any. */
22
+ lastProviderError: string | undefined;
23
+ /** count of stdout events successfully parsed before the failure. */
24
+ eventCount: number;
25
+ };
26
+
27
+ /**
28
+ * Build a user-facing markdown body for an agent hang or failure.
29
+ *
30
+ * Rendered into both the PR progress comment and the GitHub Actions job
31
+ * summary. Returns `null` when no diagnostic is available, which signals to
32
+ * the caller to fall back to its bare-error rendering.
33
+ *
34
+ * `errorMessage` is the underlying timer / spawn reject string (e.g.
35
+ * `activity timeout: no output for 301s`). The idle seconds are parsed out
36
+ * of it for the hang explanation — total runtime would overstate the stall
37
+ * for runs that streamed for a long time before going quiet.
38
+ */
39
+ export function formatAgentHangBody(input: {
40
+ diagnostic: AgentDiagnostic | undefined;
41
+ isHang: boolean;
42
+ errorMessage: string;
43
+ }): string | null {
44
+ if (!input.diagnostic) return null;
45
+
46
+ // billing exhaustion (CreditsError / FreeUsageLimitError / spending cap /
47
+ // Insufficient balance) is mis-classified as transient by upstream harnesses
48
+ // and the run only ends when the activity-timeout watchdog fires (see #778).
49
+ // when we recognise the billing label, replace the generic "stalled — auth
50
+ // error" headline with a billing-specific CTA that names the actual remedy.
51
+ if (input.diagnostic.lastProviderError === "provider billing exhausted") {
52
+ return formatBillingExhaustedBody(input.diagnostic);
53
+ }
54
+
55
+ const verb = input.isHang ? "stalled" : "failed";
56
+ const cause = input.diagnostic.lastProviderError
57
+ ? ` — likely cause: \`${input.diagnostic.lastProviderError}\``
58
+ : "";
59
+ const headline = `**${input.diagnostic.label} ${verb}**${cause}`;
60
+
61
+ const explanation = formatExplanation({
62
+ isHang: input.isHang,
63
+ errorMessage: input.errorMessage,
64
+ });
65
+ const parts = [
66
+ headline,
67
+ "",
68
+ `${explanation} ${formatEventsPart(input.diagnostic)}`,
69
+ ];
70
+
71
+ const tail = renderStderrTail(input.diagnostic.recentStderr);
72
+ if (tail) {
73
+ // pick a fence longer than any backtick run in the body so a stderr line
74
+ // containing ``` (provider error JSON occasionally embeds it) can't
75
+ // terminate the fence early and corrupt the rest of the markdown.
76
+ const fence = pickFence(tail);
77
+ parts.push(
78
+ "",
79
+ "<details><summary>Recent agent stderr</summary>",
80
+ "",
81
+ fence,
82
+ tail,
83
+ fence,
84
+ "",
85
+ "</details>",
86
+ );
87
+ }
88
+
89
+ return parts.join("\n");
90
+ }
91
+
92
+ function formatExplanation(input: {
93
+ isHang: boolean;
94
+ errorMessage: string;
95
+ }): string {
96
+ if (!input.isHang)
97
+ return `The agent exited unexpectedly: ${input.errorMessage}`;
98
+ const idleSec = parseIdleSec(input.errorMessage);
99
+ if (idleSec === undefined) {
100
+ return "The agent stopped emitting events and was killed by the activity-timeout watchdog.";
101
+ }
102
+ return `The agent stopped emitting events for ${idleSec}s and was killed by the activity-timeout watchdog.`;
103
+ }
104
+
105
+ function parseIdleSec(message: string): number | undefined {
106
+ const match = /no output for (\d+)s/.exec(message);
107
+ return match ? Number(match[1]) : undefined;
108
+ }
109
+
110
+ function formatEventsPart(diagnostic: AgentDiagnostic): string {
111
+ if (diagnostic.eventCount > 0) {
112
+ return `${diagnostic.eventCount} events were processed before the failure.`;
113
+ }
114
+ // when the provider-error label already names the cause in the headline,
115
+ // the reachability nudge below contradicts it (e.g. an immediate 401 also
116
+ // produces zero events but isn't a reachability problem). suppress it.
117
+ if (diagnostic.lastProviderError)
118
+ return "No events were emitted before the failure.";
119
+ return "No events were emitted — check whether the model provider is reachable.";
120
+ }
121
+
122
+ function renderStderrTail(lines: readonly string[]): string {
123
+ if (lines.length === 0) return "";
124
+ const joined = lines.join("\n");
125
+ if (joined.length <= MAX_STDERR_BYTES) return joined;
126
+ return `... (older lines truncated)\n${joined.slice(-MAX_STDERR_BYTES)}`;
127
+ }
128
+
129
+ function pickFence(content: string): string {
130
+ let max = 0;
131
+ for (const match of content.matchAll(/`+/g)) {
132
+ if (match[0].length > max) max = match[0].length;
133
+ }
134
+ return "`".repeat(Math.max(3, max + 1));
135
+ }
136
+
137
+ /**
138
+ * Pull a billing URL out of the captured stderr if the provider helpfully
139
+ * embedded one (OpenCode Zen does — Anthropic and Gemini do not). Restricted
140
+ * to known billing/console hosts so a stray URL elsewhere in the buffer
141
+ * can't masquerade as the remedy link.
142
+ */
143
+ function extractBillingUrl(lines: readonly string[]): string | undefined {
144
+ const urlPattern =
145
+ /https:\/\/(?:opencode\.ai\/[^\s"]*billing[^\s"]*|console\.anthropic\.com[^\s"]*|console\.cloud\.google\.com[^\s"]*billing[^\s"]*)/i;
146
+ for (let i = lines.length - 1; i >= 0; i--) {
147
+ const m = urlPattern.exec(lines[i] ?? "");
148
+ if (m) return m[0];
149
+ }
150
+ return undefined;
151
+ }
152
+
153
+ function formatBillingExhaustedBody(diagnostic: AgentDiagnostic): string {
154
+ const headline = `**${diagnostic.label} stopped** — your model provider returned a billing-exhausted response.`;
155
+
156
+ const billingUrl = extractBillingUrl(diagnostic.recentStderr);
157
+ const cta = billingUrl
158
+ ? `Top up your provider balance, then re-run: [${billingUrl}](${billingUrl})`
159
+ : "Top up your model-provider balance (or rotate to a key with remaining credits) and re-run.";
160
+ const explanation = `The agent kept retrying the request because the provider marked the failure as transient. ${PRODUCT_NAME}'s activity-timeout watchdog ended the run after no further events were emitted.`;
161
+
162
+ const parts = [headline, "", explanation, "", cta];
163
+
164
+ const tail = renderStderrTail(diagnostic.recentStderr);
165
+ if (tail) {
166
+ const fence = pickFence(tail);
167
+ parts.push(
168
+ "",
169
+ "<details><summary>Recent agent stderr</summary>",
170
+ "",
171
+ fence,
172
+ tail,
173
+ fence,
174
+ "",
175
+ "</details>",
176
+ );
177
+ }
178
+
179
+ return parts.join("\n");
180
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * GitHub PR inline annotations (2d).
3
+ *
4
+ * Turns the active scan concerns into GitHub Actions annotation descriptors so
5
+ * they show up inline on the PR's "Files changed" view and in the check summary.
6
+ * A NEW high/critical finding (the gate set) is an `error` annotation; everything
7
+ * else active is a `warning`. The list is capped (GitHub only renders the first
8
+ * handful per level, and a flood of annotations is noise) — the SARIF upload +
9
+ * the dashboard carry the full set.
10
+ *
11
+ * Pure: returns descriptors; the caller emits them via `@actions/core`.
12
+ */
13
+ import { PRODUCT_NAME } from "#app/brand";
14
+ import type { Concern } from "#app/mcp/terraform/types";
15
+ import { redactSecrets } from "#app/utils/redact";
16
+
17
+ /** Max annotations emitted per run (GitHub throttles display well below this). */
18
+ export const MAX_ANNOTATIONS = 50;
19
+
20
+ export interface FindingAnnotation {
21
+ level: "error" | "warning";
22
+ message: string;
23
+ title: string;
24
+ file: string;
25
+ startLine: number;
26
+ }
27
+
28
+ /**
29
+ * Build annotation descriptors for the active concerns. `gatingIds` is the set of
30
+ * concern ids that fail the gate (new high/critical) — those become `error`s,
31
+ * sorted first so they survive the cap. Concerns with no file location are skipped
32
+ * (an annotation needs a file to anchor to).
33
+ */
34
+ export function buildFindingAnnotations(
35
+ active: Concern[],
36
+ gatingIds: ReadonlySet<string>,
37
+ max: number = MAX_ANNOTATIONS,
38
+ ): FindingAnnotation[] {
39
+ const anchored = active.filter((c) => c.location.file && c.location.file !== "-");
40
+ // Gate-failing findings first so they're never dropped by the cap.
41
+ const ordered = [...anchored].sort((a, b) => {
42
+ const ga = gatingIds.has(a.id) ? 0 : 1;
43
+ const gb = gatingIds.has(b.id) ? 0 : 1;
44
+ return ga - gb;
45
+ });
46
+ return ordered.slice(0, max).map((c) => ({
47
+ level: gatingIds.has(c.id) ? "error" : "warning",
48
+ // LLM02: redact repo-derived evidence before it renders as a durable PR annotation.
49
+ message: redactSecrets(
50
+ c.remediation_hint ? `${c.evidence} — ${c.remediation_hint}` : c.evidence,
51
+ ),
52
+ title: `${PRODUCT_NAME}: ${c.rule_id}`,
53
+ file: c.location.file,
54
+ startLine: c.location.line ?? 1,
55
+ }));
56
+ }