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,86 @@
1
+ /**
2
+ * Sink-independent secret redaction for log output.
3
+ *
4
+ * `core.setSecret()` only masks on the GitHub `actions` log sink. Every stdio MCP
5
+ * server runs with `setLogSink("stderr")` (stdout is the JSON-RPC channel there) and
6
+ * local dev prints to the console — neither is masked. So a stray `log.debug(env)`,
7
+ * an error that stringifies a request, or any line that merely contains a bearer would
8
+ * print it in cleartext on those sinks. This scrubs secret-shaped substrings from an
9
+ * already-formatted log line BEFORE it reaches any sink, so redaction no longer depends
10
+ * on which sink is active (it complements `core.setSecret`, it doesn't replace it).
11
+ *
12
+ * Two layers, applied in order:
13
+ * 1. Registered literals — exact values handed to {@link registerSecret} (e.g. the
14
+ * minted managed-proxy token). Caught even when their shape is unusual.
15
+ * 2. Shape patterns — known token formats (`tmnd_`/`tmpx_` org + proxy tokens, the
16
+ * GitHub `ghp_`/`gho_`/`ghu_`/`ghs_`/`ghr_` family + fine-grained PATs, Anthropic
17
+ * keys, AWS access-key ids, `Bearer …` headers) plus any JSON property whose NAME
18
+ * matches the sensitive-env patterns (reuses {@link isSensitiveEnvName}, so an
19
+ * `{"GITHUB_TOKEN":"…"}` env dump is masked by key even if the value shape is novel).
20
+ */
21
+
22
+ import { TOKEN_PREFIX } from "#app/brand";
23
+ import { isSensitiveEnvName } from "#app/utils/secrets";
24
+
25
+ const REDACTED = "***";
26
+
27
+ // Literal secret values to scrub on sight — the sink-independent companion to
28
+ // core.setSecret, seeded by mint/auth code that already registers with @actions/core.
29
+ const registeredSecrets = new Set<string>();
30
+
31
+ /**
32
+ * Register a literal secret value for sink-independent log redaction. Safe to call with
33
+ * any string; values under 8 chars are ignored so we never scrub a common substring.
34
+ * Complements `core.setSecret` (call both) — this one also masks on stderr/local sinks.
35
+ */
36
+ export function registerSecret(value: string | undefined | null): void {
37
+ if (typeof value === "string" && value.length >= 8) registeredSecrets.add(value);
38
+ }
39
+
40
+ /** Test-only: clear the literal registry between cases. */
41
+ export function _resetRegisteredSecrets(): void {
42
+ registeredSecrets.clear();
43
+ }
44
+
45
+ // Token-shaped secrets: a recognizable scheme prefix (kept, so the line still reads)
46
+ // followed by secret material (masked). The trailing class spans the base64url/JWT
47
+ // alphabet so dotted `tmpx_` proxy tokens are consumed whole. Anthropic `sk-ant-` is
48
+ // included; the generic OpenAI `sk-` is deliberately NOT (too collision-prone with
49
+ // ordinary `sk-…` slugs, and this engine routes Anthropic/Bedrock anyway).
50
+ const TOKEN_SHAPES = new RegExp(
51
+ `\\b(${TOKEN_PREFIX}|tmpx_|gh[pousr]_|github_pat_|sk-ant-)[A-Za-z0-9._-]{12,}`,
52
+ "g",
53
+ );
54
+
55
+ // AWS access-key id (AKIA/ASIA + 16 upper-alnum) — a distinctive fixed shape.
56
+ const AWS_ACCESS_KEY = /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g;
57
+
58
+ // `Authorization: Bearer <token>` / bare `bearer <token>` — mask the credential, keep
59
+ // the scheme word. Catches JWTs and any bearer that the prefix patterns don't.
60
+ const BEARER = /\b(bearer\s+)[A-Za-z0-9._-]{8,}/gi;
61
+
62
+ // A JSON string property `"NAME":"VALUE"`; VALUE is masked only when NAME matches the
63
+ // sensitive-env patterns. Tolerates escaped quotes inside the value.
64
+ const JSON_STRING_PROP = /"([A-Za-z_][A-Za-z0-9_]*)"\s*:\s*"(?:[^"\\]|\\.)*"/g;
65
+
66
+ /**
67
+ * Redact secret-shaped substrings from an already-formatted log line. Idempotent,
68
+ * allocation-light on the common (no-secret) path, and never throws.
69
+ */
70
+ export function redactSecrets(text: string): string {
71
+ if (!text) return text;
72
+ let out = text;
73
+
74
+ for (const secret of registeredSecrets) {
75
+ if (out.includes(secret)) out = out.split(secret).join(REDACTED);
76
+ }
77
+
78
+ out = out.replace(JSON_STRING_PROP, (full, key: string) =>
79
+ isSensitiveEnvName(key) ? `"${key}":"${REDACTED}"` : full,
80
+ );
81
+ out = out.replace(BEARER, (_m, scheme: string) => `${scheme}${REDACTED}`);
82
+ out = out.replace(TOKEN_SHAPES, (_m, scheme: string) => `${scheme}${REDACTED}`);
83
+ out = out.replace(AWS_ACCESS_KEY, REDACTED);
84
+
85
+ return out;
86
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Private Terraform registry credential pass-through (the refactor `b.4` shape).
3
+ *
4
+ * Adopting a third-party module from a PRIVATE registry — HCP Terraform
5
+ * (`app.terraform.io`), Terraform Enterprise, or an org's own registry — needs
6
+ * Terraform/OpenTofu to authenticate to that registry's host when it resolves the
7
+ * module during `init`. The CLI reads a per-host bearer token from the env var
8
+ * `TF_TOKEN_<host>` (its documented convention; equivalent to a `credentials {}`
9
+ * block in the CLI config). The action runs scan/init under a restricted env that
10
+ * strips every `*_TOKEN` so a scanner can't exfiltrate a secret — which also strips
11
+ * any registry token. So an operator-supplied `registry_token` is re-admitted to the
12
+ * terraform subprocess ONLY, per-host and ephemerally, by this module — never written
13
+ * to disk, never a CLI-config file, never the action's own git.
14
+ *
15
+ * Host → env-var encoding follows Terraform's rule: lower-case the host, encode each
16
+ * `.` as `_` and each `-` as `__` (a literal `-` is invalid in an env var name).
17
+ * e.g. `app.terraform.io` → `TF_TOKEN_app_terraform_io`;
18
+ * `private.example-registry.io` → `TF_TOKEN_private_example__registry_io`.
19
+ *
20
+ * This is the registry-protocol counterpart of moduleFetch.ts (which handles the
21
+ * `git::` transport); `resolveModuleCredentialEnv` below merges the two so the
22
+ * scan/verify/plan/equivalence paths treat both credentials identically.
23
+ */
24
+ import { resolveModuleFetchEnv } from "#app/utils/moduleFetch";
25
+
26
+ /** the HCP Terraform / private-registry host a `registry_token` defaults to. */
27
+ export const DEFAULT_REGISTRY_HOST = "app.terraform.io";
28
+
29
+ /**
30
+ * The `TF_TOKEN_<host>` env-var NAME for a registry host, per Terraform's encoding:
31
+ * lower-cased, each `.` → `_`, each `-` → `__`. The two replacements operate on
32
+ * disjoint characters, so order is immaterial. Pure.
33
+ */
34
+ export function registryTokenEnvName(host: string): string {
35
+ const encoded = host.trim().toLowerCase().replace(/-/g, "__").replace(/\./g, "_");
36
+ return `TF_TOKEN_${encoded}`;
37
+ }
38
+
39
+ /**
40
+ * Parse the `registry_host` input (newline/comma-separated) into the hosts a
41
+ * registry token authorises. Blank/whitespace entries are dropped and hosts are
42
+ * de-duplicated case-insensitively. Falls back to the HCP host when none is given —
43
+ * the overwhelmingly common private-registry target — so supplying just a token works.
44
+ */
45
+ export function registryHosts(raw?: string | undefined): string[] {
46
+ const seen = new Set<string>();
47
+ const hosts: string[] = [];
48
+ for (const part of (raw ?? "").split(/[\n,]/)) {
49
+ const host = part.trim().toLowerCase();
50
+ if (!host || seen.has(host)) continue;
51
+ seen.add(host);
52
+ hosts.push(host);
53
+ }
54
+ return hosts.length > 0 ? hosts : [DEFAULT_REGISTRY_HOST];
55
+ }
56
+
57
+ /**
58
+ * Build the `TF_TOKEN_<host>=<token>` env that authorises `terraform init` to fetch
59
+ * a private-registry module for each host. Pure (token + hosts in, env out) so it is
60
+ * unit-testable without a real terraform. The token only ever lands in a VALUE, never
61
+ * a key. Returns `{}` for a blank token or no usable host.
62
+ */
63
+ export function buildRegistryTokenEnv(token: string, hosts: string[]): Record<string, string> {
64
+ const t = token.trim();
65
+ if (!t) return {};
66
+ const env: Record<string, string> = {};
67
+ for (const host of hosts) {
68
+ if (!host.trim()) continue;
69
+ env[registryTokenEnvName(host)] = t;
70
+ }
71
+ return env;
72
+ }
73
+
74
+ /**
75
+ * Resolve the registry-token env for a run, or undefined when no `registry_token`
76
+ * was supplied (the common public-registry/local case). Mirrors
77
+ * `resolveModuleFetchEnv` so the scan/verify/plan/refactor paths treat both
78
+ * credentials identically. The token authorises the hosts named in `registryHost`
79
+ * (default: the HCP host).
80
+ */
81
+ export function resolveRegistryTokenEnv(payload: {
82
+ registryToken?: string | undefined;
83
+ registryHost?: string | undefined;
84
+ }): Record<string, string> | undefined {
85
+ const token = payload.registryToken?.trim();
86
+ if (!token) return undefined;
87
+ const env = buildRegistryTokenEnv(token, registryHosts(payload.registryHost));
88
+ return Object.keys(env).length > 0 ? env : undefined;
89
+ }
90
+
91
+ /**
92
+ * The full extra-env a terraform subprocess needs to FETCH private modules: the
93
+ * git-transport credential for cross-repo `git::` modules (moduleFetch.ts) merged
94
+ * with the registry-protocol token for private-registry modules (this file). The two
95
+ * key namespaces (`GIT_CONFIG_*` / `GIT_SSH_COMMAND` vs `TF_TOKEN_*`) never collide.
96
+ * Both are scoped to the subprocess and never persisted. Returns undefined when
97
+ * neither is configured (the common public/local-module case). This is the single
98
+ * resolver the scan / verify / plan / equivalence-check paths call so they treat both
99
+ * credentials alike.
100
+ */
101
+ export function resolveModuleCredentialEnv(
102
+ payload: {
103
+ moduleFetchToken?: string | undefined;
104
+ moduleFetchSshKey?: string | undefined;
105
+ registryToken?: string | undefined;
106
+ registryHost?: string | undefined;
107
+ },
108
+ opts: { sshKeyDir?: string; writeKey?: (path: string, contents: string) => void } = {},
109
+ ): Record<string, string> | undefined {
110
+ const env = {
111
+ ...resolveModuleFetchEnv(payload, opts),
112
+ ...resolveRegistryTokenEnv(payload),
113
+ };
114
+ return Object.keys(env).length > 0 ? env : undefined;
115
+ }
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Comment-command interface. A developer can scope a remediation run from
3
+ * a PR/issue comment that mentions the bot:
4
+ *
5
+ * @infraweaver fix #3a9f1c2 → fix exactly one concern (by id or short id)
6
+ * @infraweaver fix all high-severity → fix every concern at/above a severity
7
+ * @infraweaver fix all → fix everything (still bounded by max_prs)
8
+ * @infraweaver fix main.tf → fix one file's group
9
+ *
10
+ * Propose, then let me steer — when a non-trivial finding has several
11
+ * genuinely distinct valid fixes, Remediate proposes 2–3 labelled strategies in
12
+ * a comment instead of guessing, and the reviewer picks one by replying:
13
+ *
14
+ * @infraweaver fix #3a9f1c2 with strategy B → apply strategy B to that concern
15
+ * @infraweaver strategy 2 → pick strategy 2 (concern from the thread)
16
+ *
17
+ * The parsing is pure + deterministic so the scoping doesn't depend on the
18
+ * model's reading of the comment. The Remediate mode applies the parsed scope
19
+ * (which group(s) to act on, and which strategy) instead of the default
20
+ * "highest-severity group, agent's-choice fix".
21
+ */
22
+
23
+ import { COMMENT_COMMAND } from "#app/brand";
24
+
25
+ export type RemediationCommand =
26
+ | { kind: "concern"; concernRef: string; strategy?: string }
27
+ | { kind: "severity"; severity: Severity }
28
+ | { kind: "file"; file: string }
29
+ // bulk remediation — sweep ONE scanner rule across every file it fires in
30
+ // (one coherent PR via by-rule grouping). e.g. `@infraweaver fix rule CKV_AWS_23`.
31
+ | { kind: "rule"; ruleId: string }
32
+ // a bare strategy pick (e.g. an in-thread reply to a proposal); the
33
+ // concern is resolved from the comment thread the run was triggered on.
34
+ | { kind: "strategy"; strategy: string }
35
+ | { kind: "all" };
36
+
37
+ const SEVERITIES = ["critical", "high", "medium", "low", "info"] as const;
38
+ type Severity = (typeof SEVERITIES)[number];
39
+
40
+ /** the bot handles a mention can use (with or without the `[bot]` suffix). */
41
+ const MENTION = new RegExp(`${COMMENT_COMMAND}(?:\\[bot\\])?\\b`, "i");
42
+
43
+ /**
44
+ * the canonical phrasing the proposal comment must tell reviewers to reply
45
+ * with. Lives next to the parser that accepts it so the proposal template (in
46
+ * the Remediate prompt) and the parser can never drift apart. `<concern-id>` and
47
+ * `<A|B|C>` are placeholders the agent fills with the real id and the offered
48
+ * strategy labels.
49
+ */
50
+ export const STRATEGY_REPLY_HINT = `${COMMENT_COMMAND} fix #<concern-id> with strategy <A|B|C>`;
51
+
52
+ // a strategy label is a single letter (A–Z, normalised to upper) or digit (1–9),
53
+ // introduced by `strategy` / `option` / `approach`. The single-char + `\b` bound
54
+ // keeps it off prose ("a good strategy overall" has no single-char boundary).
55
+ const STRATEGY = /\b(?:strategy|option|approach)\s+#?([A-Za-z]|[1-9])\b/i;
56
+
57
+ function parseStrategyToken(text: string): string | undefined {
58
+ // the capture is a single required char, so guarding `?.[1]` is equivalent to
59
+ // the old `m[1]!` but carries the non-null in the type rather than an assertion.
60
+ const tok = text.match(STRATEGY)?.[1];
61
+ if (!tok) return undefined;
62
+ return /[A-Za-z]/.test(tok) ? tok.toUpperCase() : tok;
63
+ }
64
+
65
+ /**
66
+ * Parse a `@infraweaver fix …` command out of a comment body. Returns null when
67
+ * the body isn't a recognised fix command (the run then falls back to its
68
+ * default scope). Tolerant of surrounding prose — it scans for the mention then
69
+ * the `fix` verb and its argument.
70
+ */
71
+ export function parseRemediationCommand(
72
+ body: string | undefined,
73
+ ): RemediationCommand | null {
74
+ if (!body) return null;
75
+ if (!MENTION.test(body)) return null;
76
+
77
+ // everything after the mention; we keep original case for the file/concern-ref
78
+ // capture (the lower-casing happens per match).
79
+ const afterMention = body.slice(body.search(MENTION));
80
+ const isSeverity = (s: string): s is Severity =>
81
+ (SEVERITIES as readonly string[]).includes(s);
82
+
83
+ // bulk — `fix rule <rule-id>` / `fix all rule <rule-id>`. Checked FIRST and
84
+ // gated on the explicit `rule` keyword so a scanner rule id (`CKV_AWS_23`,
85
+ // `terraform_required_version`, `trivy:AVD-AWS-0088`) is never confused with a
86
+ // severity word, a filename, or a hex concern id. Rule ids are case-significant
87
+ // — kept verbatim. The fix sweeps that ONE rule across every file it fires in.
88
+ const ruleId = afterMention.match(
89
+ /\bfix\s+(?:all\s+)?rule\s+([A-Za-z][A-Za-z0-9_.:-]+)\b/i,
90
+ )?.[1];
91
+ if (ruleId) return { kind: "rule", ruleId };
92
+
93
+ // `fix all <sev>[-severity]` / `fix all` — but a NON-severity word after "all"
94
+ // (prose like "fix all the bugs") is NOT the command: fall through rather than
95
+ // silently treating it as "fix everything".
96
+ const all = afterMention.match(
97
+ /\bfix\s+all\b(?:\s+([a-z]+)(?:\s*-?\s*severity)?)?/i,
98
+ );
99
+ if (all) {
100
+ const trailing = all[1]?.toLowerCase();
101
+ if (!trailing) return { kind: "all" };
102
+ if (isSeverity(trailing)) return { kind: "severity", severity: trailing };
103
+ // a non-severity word followed "all" → prose, not a command. fall through.
104
+ }
105
+
106
+ // `fix <sev>-severity` (without "all")
107
+ const sev = afterMention
108
+ .match(/\bfix\s+([a-z]+)\s*-?\s*severity\b/i)?.[1]
109
+ ?.toLowerCase();
110
+ if (sev && isSeverity(sev)) return { kind: "severity", severity: sev };
111
+
112
+ // `fix <path>.tf` / `fix <path>.tfvars` — a specific file's group. Checked
113
+ // BEFORE the concern-id form so an all-hex filename stem (e.g. `deadbeef.tf`)
114
+ // isn't mis-read as a concern id.
115
+ const file = afterMention.match(/\bfix\s+([^\s#]+\.tf(?:vars)?)\b/i)?.[1];
116
+ if (file) return { kind: "file", file };
117
+
118
+ // `fix #<id>` or `fix <id>` — a concern id is hex (content hash, 6–40 chars).
119
+ // carries an optional strategy label when the comment selects one.
120
+ const concernRef = afterMention
121
+ .match(/\bfix\s+#?([0-9a-f]{6,40})\b/i)?.[1]
122
+ ?.toLowerCase();
123
+ if (concernRef) {
124
+ const strategy = parseStrategyToken(afterMention);
125
+ return strategy
126
+ ? { kind: "concern", concernRef, strategy }
127
+ : { kind: "concern", concernRef };
128
+ }
129
+
130
+ // a strategy pick with no `fix` verb (e.g. an in-thread reply). If the
131
+ // reviewer still named a `#<id>`, keep it as a scoped concern; otherwise the
132
+ // concern is resolved from the thread the comment lives on.
133
+ const strategy = parseStrategyToken(afterMention);
134
+ if (strategy) {
135
+ const concernRef = afterMention
136
+ .match(/#([0-9a-f]{6,40})\b/i)?.[1]
137
+ ?.toLowerCase();
138
+ return concernRef
139
+ ? { kind: "concern", concernRef, strategy }
140
+ : { kind: "strategy", strategy };
141
+ }
142
+
143
+ return null;
144
+ }
@@ -0,0 +1,180 @@
1
+ import { setTimeout as sleep } from "node:timers/promises";
2
+ import { log } from "#app/utils/cli";
3
+
4
+ /** Default upper bound on a honored server Retry-After hint (ms). A hostile or
5
+ * buggy `Retry-After` could otherwise stall a run for its full value (GitHub
6
+ * secondary-rate-limit responses have carried multi-minute hints); 20s matches
7
+ * octokit's throttling-plugin ceiling. */
8
+ export const DEFAULT_RETRY_AFTER_CAP_MS = 20_000;
9
+
10
+ export type RetryOptions = {
11
+ maxAttempts?: number;
12
+ delayMs?: number;
13
+ /**
14
+ * explicit delay schedule — one entry per retry (length N ⇒ N+1 attempts).
15
+ * when set, overrides `maxAttempts` and `delayMs`. e.g. `[1_000, 3_000]`
16
+ * means up to 3 attempts, sleeping 1s before retry 2 and 3s before retry 3.
17
+ */
18
+ delaysMs?: readonly number[];
19
+ shouldRetry?: (error: unknown) => boolean;
20
+ /** cap (ms) on a honored server Retry-After / rate-limit-reset hint. default
21
+ * {@link DEFAULT_RETRY_AFTER_CAP_MS}. The fixed backoff is never capped —
22
+ * this only bounds how long a *server-suggested* delay can extend it. */
23
+ retryAfterCapMs?: number;
24
+ label?: string;
25
+ };
26
+
27
+ /** A numeric HTTP status carried on an error (some clients set `.status`/`.statusCode`). */
28
+ function statusOf(error: unknown): number | undefined {
29
+ if (typeof error !== "object" || error === null) return undefined;
30
+ const e = error as { status?: unknown; statusCode?: unknown };
31
+ if (typeof e.status === "number") return e.status;
32
+ if (typeof e.statusCode === "number") return e.statusCode;
33
+ return undefined;
34
+ }
35
+
36
+ /**
37
+ * A broad transient predicate for octokit/GitHub calls: an HTTP 5xx (an upstream
38
+ * blip) OR a network-class error. Distinct from a deterministic 4xx (404/401/403/
39
+ * 422), which fails fast. Pass as `shouldRetry` for idempotent GitHub reads/
40
+ * dispatches whose client carries no 5xx retry of its own (mirrors pullfrog's
41
+ * `isTransientOctokitError`). see #999/#997.
42
+ */
43
+ export function isTransientServerError(error: unknown): boolean {
44
+ const status = statusOf(error);
45
+ if (status !== undefined) return status >= 500;
46
+ if (!(error instanceof Error)) return false;
47
+ return (
48
+ error.name === "AbortError" ||
49
+ error.message.includes("fetch failed") ||
50
+ error.message.includes("ECONNRESET") ||
51
+ error.message.includes("ETIMEDOUT")
52
+ );
53
+ }
54
+
55
+ /** Response headers hung off a thrown HTTP error (octokit sets `error.response.headers`). */
56
+ function errorResponseHeaders(error: unknown): Record<string, unknown> | undefined {
57
+ if (typeof error !== "object" || error === null) return undefined;
58
+ const response = (error as { response?: unknown }).response;
59
+ if (typeof response !== "object" || response === null) return undefined;
60
+ const headers = (response as { headers?: unknown }).headers;
61
+ if (typeof headers !== "object" || headers === null) return undefined;
62
+ return headers as Record<string, unknown>;
63
+ }
64
+
65
+ /**
66
+ * A server-suggested retry delay in ms, resolved from (in order):
67
+ * 1. an explicit `retryAfterMs` property a caller stashed on the error (e.g.
68
+ * {@link parseRetryAfter} off a `Response`);
69
+ * 2. the `retry-after` response header (RFC-9110 delta-seconds / HTTP-date) —
70
+ * an explicit backoff directive whenever present (covers secondary rate
71
+ * limits, which carry it with `x-ratelimit-remaining > 0`);
72
+ * 3. `x-ratelimit-reset` (epoch seconds) but ONLY when `x-ratelimit-remaining`
73
+ * is `"0"` — GitHub returns the reset header on ~every response (~1h ahead),
74
+ * so honoring it unconditionally would balloon EVERY retried error (even a
75
+ * permissions 403) to the cap. Gating on real exhaustion matches octokit's
76
+ * throttling plugin.
77
+ * Returns `undefined` when no applicable hint is present/parseable.
78
+ */
79
+ function retryAfterMsOf(error: unknown): number | undefined {
80
+ if (typeof error !== "object" || error === null) return undefined;
81
+ const r = (error as { retryAfterMs?: unknown }).retryAfterMs;
82
+ if (typeof r === "number" && Number.isFinite(r) && r >= 0) return r;
83
+
84
+ const headers = errorResponseHeaders(error);
85
+ if (!headers) return undefined;
86
+ const retryAfter = headers["retry-after"];
87
+ if (typeof retryAfter === "string" && retryAfter.trim() !== "") {
88
+ const parsed = parseRetryAfter(retryAfter);
89
+ if (parsed !== undefined) return parsed;
90
+ }
91
+ if (headers["x-ratelimit-remaining"] === "0") {
92
+ const reset = headers["x-ratelimit-reset"];
93
+ if (typeof reset === "string" && reset.trim() !== "") {
94
+ const resetEpoch = Number(reset);
95
+ if (Number.isFinite(resetEpoch)) return Math.max(0, resetEpoch * 1000 - Date.now());
96
+ }
97
+ }
98
+ return undefined;
99
+ }
100
+
101
+ /**
102
+ * Parse an HTTP `Retry-After` header value into milliseconds. Accepts the two
103
+ * RFC-9110 forms — delta-seconds (`"120"`) and an HTTP-date (`"Wed, 21 Oct 2026
104
+ * 07:28:00 GMT"`) — and returns `undefined` for anything else. Callers that hold
105
+ * the `Response` attach the result as `retryAfterMs` on the thrown error so
106
+ * {@link retry} can floor its backoff to it.
107
+ */
108
+ export function parseRetryAfter(
109
+ value: string | null | undefined,
110
+ ): number | undefined {
111
+ if (!value) return undefined;
112
+ const trimmed = value.trim();
113
+ if (/^\d+$/.test(trimmed)) return Number(trimmed) * 1000;
114
+ const at = Date.parse(trimmed);
115
+ if (!Number.isNaN(at)) return Math.max(0, at - Date.now());
116
+ return undefined;
117
+ }
118
+
119
+ // Statuses worth retrying: rate-limit (429) + transient server errors (502/503/504).
120
+ const RETRYABLE_STATUSES = new Set([429, 502, 503, 504]);
121
+
122
+ const defaultShouldRetry = (error: unknown): boolean => {
123
+ const status = statusOf(error);
124
+ if (status !== undefined && RETRYABLE_STATUSES.has(status)) return true;
125
+ if (!(error instanceof Error)) return false;
126
+ return (
127
+ error.name === "AbortError" ||
128
+ error.message.includes("fetch failed") ||
129
+ error.message.includes("ECONNRESET") ||
130
+ error.message.includes("ETIMEDOUT") ||
131
+ /\b(429|502|503|504)\b/.test(error.message)
132
+ );
133
+ };
134
+
135
+ export async function retry<T>(
136
+ fn: () => Promise<T>,
137
+ options: RetryOptions = {},
138
+ ): Promise<T> {
139
+ const shouldRetry = options.shouldRetry ?? defaultShouldRetry;
140
+ const label = options.label ?? "operation";
141
+ const delays = options.delaysMs
142
+ ? Array.from(options.delaysMs)
143
+ : Array.from(
144
+ { length: (options.maxAttempts ?? 3) - 1 },
145
+ (_, i) => (options.delayMs ?? 1000) * (i + 1),
146
+ );
147
+ const maxAttempts = delays.length + 1;
148
+
149
+ let lastError: unknown;
150
+
151
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
152
+ try {
153
+ return await fn();
154
+ } catch (error) {
155
+ lastError = error;
156
+
157
+ if (attempt === maxAttempts || !shouldRetry(error)) {
158
+ throw error;
159
+ }
160
+
161
+ const scheduled = delays[attempt - 1] ?? options.delayMs ?? 1000;
162
+ const serverDelay = retryAfterMsOf(error);
163
+ // cap the server hint first, then floor at the fixed delay — so a hint
164
+ // never shortens below `scheduled`, and an overlong one can't hang the
165
+ // run. the fixed backoff itself is never capped.
166
+ const cap = options.retryAfterCapMs ?? DEFAULT_RETRY_AFTER_CAP_MS;
167
+ const base =
168
+ serverDelay !== undefined
169
+ ? Math.max(scheduled, Math.min(cap, serverDelay))
170
+ : scheduled;
171
+ const delay = Math.round(base + Math.random() * base * 0.5);
172
+ log.info(
173
+ `» ${label} failed (attempt ${attempt}/${maxAttempts}), retrying in ${delay}ms...`,
174
+ );
175
+ await sleep(delay);
176
+ }
177
+ }
178
+
179
+ throw lastError;
180
+ }
@@ -0,0 +1,116 @@
1
+ import { PRODUCT_SLUG } from "#app/brand";
2
+ import type { WriteablePayload } from "#app/external";
3
+ import { reportReviewNodeId } from "#app/mcp/review";
4
+ import type { ToolContext } from "#app/mcp/server";
5
+ import { log } from "#app/utils/cli";
6
+
7
+ const RE_REVIEW_PREAMBLE =
8
+ "Incrementally re-review the new commits on this pull request. Use the IncrementalReview mode.";
9
+
10
+ /**
11
+ * post-agent review lifecycle: runs after the agent exits (success or timeout).
12
+ *
13
+ * normally the agent handles new commits inline: create_pull_request_review
14
+ * detects HEAD movement and tells the agent to pull and review the delta.
15
+ * this dispatch is a safety net for cases where the agent couldn't handle
16
+ * it (timeout, error, etc).
17
+ *
18
+ * ordering matters: reportReviewNodeId marks this run "done" FIRST so push
19
+ * webhooks stop being suppressed by dedup. the HEAD check runs SECOND to
20
+ * catch any pushes that were suppressed while this run was in-flight.
21
+ */
22
+ export async function postReviewCleanup(ctx: ToolContext): Promise<void> {
23
+ const review = ctx.toolState.review;
24
+ if (!review) return;
25
+ delete ctx.toolState.review;
26
+
27
+ // mark review as submitted — unlocks webhook dedup for new pushes
28
+ await bestEffort(
29
+ () => reportReviewNodeId(ctx, { nodeId: review.nodeId }),
30
+ "reportReviewNodeId",
31
+ );
32
+
33
+ // dispatch follow-up if PR HEAD moved past the reviewed commit
34
+ if (review.reviewedSha) {
35
+ await bestEffort(
36
+ () => dispatchFollowUpReReview(ctx, review.reviewedSha!),
37
+ "follow-up re-review dispatch",
38
+ );
39
+ }
40
+ }
41
+
42
+ async function bestEffort(
43
+ fn: () => Promise<unknown>,
44
+ label: string,
45
+ ): Promise<void> {
46
+ try {
47
+ await fn();
48
+ } catch (error) {
49
+ log.debug(`${label} failed: ${error}`);
50
+ }
51
+ }
52
+
53
+ async function dispatchFollowUpReReview(
54
+ ctx: ToolContext,
55
+ reviewedSha: string,
56
+ ): Promise<void> {
57
+ const issueNumber = ctx.payload.event.issue_number;
58
+ if (!issueNumber) return;
59
+
60
+ const pr = await ctx.octokit.rest.pulls.get({
61
+ owner: ctx.repo.owner,
62
+ repo: ctx.repo.name,
63
+ pull_number: issueNumber,
64
+ });
65
+
66
+ if (pr.data.head.sha === reviewedSha) return;
67
+ if (pr.data.state !== "open") return;
68
+ if (pr.data.draft) return;
69
+
70
+ log.info(
71
+ `safety net: pr HEAD moved from ${reviewedSha.slice(0, 7)} to ${pr.data.head.sha.slice(0, 7)} ` +
72
+ `and agent did not review inline — dispatching follow-up re-review`,
73
+ );
74
+
75
+ const event: WriteablePayload["event"] = {
76
+ trigger: "pull_request_synchronize",
77
+ issue_number: issueNumber,
78
+ is_pr: true,
79
+ title: pr.data.title,
80
+ body: null,
81
+ branch: pr.data.head.ref,
82
+ before_sha: reviewedSha,
83
+ silent: true,
84
+ };
85
+ if (ctx.payload.event.authorPermission) {
86
+ event.authorPermission = ctx.payload.event.authorPermission;
87
+ }
88
+
89
+ const payload: WriteablePayload = {
90
+ "~infraweaver": true,
91
+ version: ctx.payload.version,
92
+ model: ctx.payload.model,
93
+ prompt: "",
94
+ eventInstructions: RE_REVIEW_PREAMBLE,
95
+ event,
96
+ };
97
+
98
+ await ctx.octokit.rest.actions.createWorkflowDispatch({
99
+ owner: ctx.repo.owner,
100
+ repo: ctx.repo.name,
101
+ workflow_id: getCurrentWorkflowFilename(),
102
+ ref: pr.data.base.repo.default_branch,
103
+ inputs: { prompt: JSON.stringify(payload) },
104
+ });
105
+ }
106
+
107
+ /**
108
+ * derive the running workflow's filename from `GITHUB_WORKFLOW_REF`, which has the form
109
+ * `<owner>/<repo>/.github/workflows/<filename>@<ref>` (e.g. `.../infraweaver.yaml@refs/heads/main`).
110
+ * falls back to `infraweaver.yml` if the env var is missing or malformed (shouldn't happen in CI).
111
+ */
112
+ function getCurrentWorkflowFilename(): string {
113
+ const ref = process.env.GITHUB_WORKFLOW_REF ?? "";
114
+ const match = ref.match(/\/([^/]+)@/);
115
+ return match?.[1] ?? `${PRODUCT_SLUG}.yml`;
116
+ }