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,114 @@
1
+ import type { TransformEntry, TransformPack } from "#app/mcp/terraform/transformPacks";
2
+
3
+ /**
4
+ * cloudflare 4.x → 5.0.
5
+ *
6
+ * This pack is deliberately THIN, and the reason is the interesting part:
7
+ * Cloudflare ships its own migration tool. `tf-migrate` rewrites the HCL,
8
+ * generates the `moved {}` blocks and updates cross-file references, and the
9
+ * provider carries state upgraders from v5.19 onward. Re-implementing forty
10
+ * resource renames here would produce a worse version of something the vendor
11
+ * maintains — the same "integrate upward, don't compete" call the product makes
12
+ * everywhere else.
13
+ *
14
+ * So what this pack contributes is the thing `tf-migrate` deliberately does not:
15
+ * a verdict on whether the change is safe to ship unattended. It names the
16
+ * renames whose state moves automatically (fine) and, separately, the handful
17
+ * the vendor's own guide marks **Manual** — those have no `MoveState` handler,
18
+ * so they need `terraform state rm` + `terraform import` and must never be
19
+ * applied by an agent on its own.
20
+ */
21
+
22
+ const SOURCE =
23
+ "https://github.com/cloudflare/terraform-provider-cloudflare/blob/main/docs/guides/version-5-migration.md";
24
+
25
+ /** Renames the provider can carry across automatically (`moved {}` blocks, or a
26
+ * built-in `MoveState` handler on v5.19+). State survives; no replacement. */
27
+ const AUTO_RENAMES: [from: string, to: string][] = [
28
+ ["cloudflare_record", "cloudflare_dns_record"],
29
+ ["cloudflare_tunnel", "cloudflare_zero_trust_tunnel_cloudflared"],
30
+ ["cloudflare_access_application", "cloudflare_zero_trust_access_application"],
31
+ ["cloudflare_teams_rule", "cloudflare_zero_trust_gateway_policy"],
32
+ ];
33
+
34
+ /** Renames where the resource also SPLIT, so a `moved {}` block carries only
35
+ * part of what the v4 resource managed. The remainder has to be created fresh,
36
+ * and saying only "renamed" would leave it silently unmanaged. */
37
+ const SPLIT_RENAMES: [from: string, to: string, alsoNeeded: string, what: string][] = [
38
+ [
39
+ "cloudflare_argo",
40
+ "cloudflare_argo_smart_routing",
41
+ "cloudflare_argo_tiered_caching",
42
+ "tiered caching",
43
+ ],
44
+ ];
45
+
46
+ /** Marked **Manual** in Cloudflare's rename table: no automatic state move.
47
+ * Applying the config edit alone destroys and recreates the resource. */
48
+ const MANUAL_RENAMES: [from: string, to: string][] = [
49
+ ["cloudflare_access_custom_page", "cloudflare_zero_trust_access_custom_page"],
50
+ ["cloudflare_access_keys_configuration", "cloudflare_zero_trust_access_key_configuration"],
51
+ ["cloudflare_device_policy_certificates", "cloudflare_zero_trust_device_certificates"],
52
+ ["cloudflare_gre_tunnel", "cloudflare_magic_wan_gre_tunnel"],
53
+ ];
54
+
55
+ const ENTRIES: TransformEntry[] = [
56
+ {
57
+ id: "cloudflare.4-5.use-tf-migrate",
58
+ kind: "provider_setting",
59
+ resource_type: null,
60
+ from: "manual v4 → v5 rewrite",
61
+ to: "tf-migrate",
62
+ state_move: "auto",
63
+ forces_replacement: false,
64
+ note: "Cloudflare maintains `tf-migrate` (github.com/cloudflare/tf-migrate) for this upgrade: it rewrites resource types, transforms attributes, generates `moved {}` blocks and fixes cross-file references. Run it first and review its diff — do not hand-migrate what it already handles. Terraform 1.8+ is needed for `moved {}`, and provider v5.19+ ships the automatic state upgraders.",
65
+ },
66
+ ...AUTO_RENAMES.map(
67
+ ([from, to]): TransformEntry => ({
68
+ id: `cloudflare.4-5.resource.${from}`,
69
+ kind: "resource_renamed",
70
+ resource_type: from,
71
+ from,
72
+ to,
73
+ state_move: "moved_block",
74
+ forces_replacement: false,
75
+ note: `Renamed in v5: \`${from}\` → \`${to}\`. Author a \`moved {}\` block (or let \`tf-migrate\` generate it) so state follows the rename instead of the resource being destroyed and recreated.`,
76
+ }),
77
+ ),
78
+ ...SPLIT_RENAMES.map(
79
+ ([from, to, alsoNeeded, what]): TransformEntry => ({
80
+ id: `cloudflare.4-5.resource.${from}`,
81
+ kind: "resource_renamed",
82
+ resource_type: from,
83
+ from,
84
+ to,
85
+ state_move: "moved_block",
86
+ forces_replacement: false,
87
+ value_change: `⚠️ v4's \`${from}\` managed TWO things; v5 splits them. \`${to}\` inherits the state via \`moved {}\`, but ${what} does NOT come with it — it needs a fresh \`${alsoNeeded}\` resource. Rename alone and ${what} silently stops being managed by Terraform, with no plan diff to warn you.`,
88
+ note: `Renamed AND split in v5: \`${from}\` → \`${to}\` + \`${alsoNeeded}\`. Author the \`moved {}\` block for the first and create the second.`,
89
+ }),
90
+ ),
91
+ ...MANUAL_RENAMES.map(
92
+ ([from, to]): TransformEntry => ({
93
+ id: `cloudflare.4-5.resource.${from}`,
94
+ kind: "resource_renamed",
95
+ resource_type: from,
96
+ from,
97
+ to,
98
+ state_move: "manual_import",
99
+ forces_replacement: true,
100
+ note: `\`${from}\` → \`${to}\` is marked **Manual** in Cloudflare's own rename table: there is no automatic state move, so a \`moved {}\` block will not help. This needs \`terraform state rm\` + \`terraform import\` performed by a human.`,
101
+ }),
102
+ ),
103
+ ];
104
+
105
+ export const CLOUDFLARE_4_TO_5: TransformPack = {
106
+ provider: "cloudflare",
107
+ from_major: 4,
108
+ to_major: 5,
109
+ version: "2026.07",
110
+ source: SOURCE,
111
+ exhaustive: false,
112
+ official_tool: "tf-migrate — https://github.com/cloudflare/tf-migrate",
113
+ entries: ENTRIES,
114
+ };
@@ -0,0 +1,59 @@
1
+ import { join } from "node:path";
2
+ import { discoverTerraformRoots } from "#app/mcp/roots";
3
+ import { run } from "#app/mcp/terraform/subprocess";
4
+
5
+ /**
6
+ * Normalize a scanner-reported path to a repo-relative POSIX path. Each scanner
7
+ * reports the file differently — tflint gives `main.tf` (relative), trivy a
8
+ * scan-dir-relative `Target`, terraform an absolute path (`/repo/main.tf` or
9
+ * `D:\repo\main.tf`), checkov a leading-slash path (`/main.tf`). Left
10
+ * unnormalized, these leak into `location.file` AND the
11
+ * content-derived `concernId`, making the id (and the `remediate/<id>` branch)
12
+ * machine-dependent and breaking the ✗→✓ re-scan id match across environments.
13
+ * So normalize BEFORE building any Concern.
14
+ */
15
+ export function toRepoRelative(raw: string | undefined, cwd: string): string {
16
+ if (!raw) return "(unknown)";
17
+ const posix = raw.replace(/\\/g, "/");
18
+ const cwdPosix = cwd.replace(/\\/g, "/").replace(/\/+$/, "");
19
+ let rel = posix;
20
+ if (cwdPosix && posix.toLowerCase().startsWith(`${cwdPosix.toLowerCase()}/`)) {
21
+ rel = posix.slice(cwdPosix.length + 1);
22
+ }
23
+ // strip any leading "./" or "/" (checkov reports paths relative to its -d root
24
+ // with a leading separator).
25
+ rel = rel.replace(/^(?:\.\/|\/)+/, "");
26
+ return rel || "(unknown)";
27
+ }
28
+
29
+ export interface ResolvedRoot {
30
+ /** absolute dir the per-root command (init/plan/validate) runs in. */
31
+ absDir: string;
32
+ /** that root's path relative to the scan `cwd` ("" when the root IS cwd) —
33
+ * prepended to per-root concern files so they stay cwd-relative. */
34
+ relDir: string;
35
+ }
36
+
37
+ /**
38
+ * The Terraform root modules to operate on under `cwd`. A repo can hold several
39
+ * roots (hepcare: `terraform/` + `terraform/core/`); `terraform validate` /
40
+ * `plan` are per-root, so they must run in EACH. Falls back to `cwd` itself as a
41
+ * single root when none is detected — so a normal single-root repo behaves
42
+ * exactly as before (no rebasing, one iteration).
43
+ */
44
+ export function resolveRoots(cwd: string): ResolvedRoot[] {
45
+ const discovered = discoverTerraformRoots(cwd);
46
+ if (discovered.length === 0) return [{ absDir: cwd, relDir: "" }];
47
+ return discovered.map((r) => ({ absDir: r.dir ? join(cwd, r.dir) : cwd, relDir: r.dir }));
48
+ }
49
+
50
+ /** the repo's base ref for diff-scope, or null when one can't be determined. */
51
+ export function resolveBaseRef(cwd: string): string | null {
52
+ const head = run("git", ["rev-parse", "--abbrev-ref", "origin/HEAD"], cwd);
53
+ if (head.status === 0 && head.stdout.trim()) return head.stdout.trim();
54
+ for (const ref of ["origin/main", "origin/master"]) {
55
+ const verify = run("git", ["rev-parse", "--verify", "--quiet", ref], cwd);
56
+ if (verify.status === 0 && verify.stdout.trim()) return ref;
57
+ }
58
+ return null;
59
+ }
@@ -0,0 +1,377 @@
1
+ import type { BlastTier } from "#app/mcp/terraform/types";
2
+
3
+ // --- terraform plan (the safety gate) -------------------------------------
4
+
5
+ export interface PlanSummary {
6
+ /** resources to add / change / destroy, from the plan's change_summary. */
7
+ add: number;
8
+ change: number;
9
+ destroy: number;
10
+ /** every resource with a real action (create/update/delete/replace) — the set
11
+ * that powers blast-radius and plan-stability. */
12
+ changed: { address: string; action: string }[];
13
+ /** resources that would be deleted or replaced — the destructive set. */
14
+ destructive: { address: string; action: string }[];
15
+ hasDestroyOrReplace: boolean;
16
+ /** state-only moves (`moved {}` blocks / refactors): the new address and the
17
+ * address it came from. Moves don't mutate live infrastructure, so they are
18
+ * NOT in `changed` — they power the modularization gate (`isPureMovePlan`). */
19
+ moved: { address: string; previousAddress: string | null }[];
20
+ }
21
+
22
+ /**
23
+ * Parse `terraform plan -json` (newline-delimited JSON). `change_summary` gives
24
+ * the add/change/destroy totals; each `planned_change` with a real action is
25
+ * collected into `changed`, and the delete/replace subset into `destructive`
26
+ * (the high-risk set a reviewer must scrutinise). Non-mutating actions are
27
+ * ignored, as are non-JSON / non-plan lines, so a noisy stream (provider logs,
28
+ * diagnostics) parses cleanly.
29
+ *
30
+ * NB on the action enum: terraform's machine-readable UI (the `-json` stream)
31
+ * spells no-op as `"noop"` — NOT `"no-op"` — and also emits `"move"` / `"import"`
32
+ * / `"forget"` for state-only operations that don't mutate live infrastructure.
33
+ * None of those should count toward `changed` (they'd inflate the blast
34
+ * radius). We skip them explicitly; `"no-op"` is tolerated too in case a wrapper
35
+ * or older format hyphenates it. See
36
+ * https://developer.hashicorp.com/terraform/internals/machine-readable-ui.
37
+ */
38
+ const NON_MUTATING_PLAN_ACTIONS: ReadonlySet<string> = new Set([
39
+ "noop",
40
+ "no-op",
41
+ "read",
42
+ "move",
43
+ "import",
44
+ "forget",
45
+ ]);
46
+
47
+ export function parseTerraformPlanJson(stdout: string): PlanSummary {
48
+ let add = 0;
49
+ let change = 0;
50
+ let destroy = 0;
51
+ const changed: { address: string; action: string }[] = [];
52
+ const destructive: { address: string; action: string }[] = [];
53
+ const moved: { address: string; previousAddress: string | null }[] = [];
54
+ for (const line of stdout.split("\n")) {
55
+ const trimmed = line.trim();
56
+ if (!trimmed.startsWith("{")) continue;
57
+ let msg: {
58
+ type?: string;
59
+ changes?: { add?: number; change?: number; remove?: number };
60
+ change?: {
61
+ action?: string;
62
+ resource?: { addr?: string; resource?: string };
63
+ previous_resource?: { addr?: string; resource?: string };
64
+ };
65
+ };
66
+ try {
67
+ msg = JSON.parse(trimmed);
68
+ } catch {
69
+ continue;
70
+ }
71
+ if (msg.type === "change_summary" && msg.changes) {
72
+ add = Number(msg.changes.add) || 0;
73
+ change = Number(msg.changes.change) || 0;
74
+ destroy = Number(msg.changes.remove) || 0;
75
+ } else if (msg.type === "planned_change" && msg.change) {
76
+ const action = String(msg.change.action ?? "");
77
+ // moves are state-only (no infra mutation) but are tracked separately —
78
+ // they prove a modularization refactor is a no-op (`isPureMovePlan`).
79
+ if (action === "move") {
80
+ const address =
81
+ msg.change.resource?.addr ||
82
+ msg.change.resource?.resource ||
83
+ "(unknown)";
84
+ const previousAddress =
85
+ msg.change.previous_resource?.addr ||
86
+ msg.change.previous_resource?.resource ||
87
+ null;
88
+ moved.push({ address, previousAddress });
89
+ continue;
90
+ }
91
+ if (!action || NON_MUTATING_PLAN_ACTIONS.has(action)) continue;
92
+ const address =
93
+ msg.change.resource?.addr ||
94
+ msg.change.resource?.resource ||
95
+ "(unknown)";
96
+ changed.push({ address, action });
97
+ // "delete", "replace", and the "*-then-delete" / "delete-then-*" forms.
98
+ if (action.includes("delete") || action === "replace") {
99
+ destructive.push({ address, action });
100
+ }
101
+ }
102
+ }
103
+ return {
104
+ add,
105
+ change,
106
+ destroy,
107
+ changed,
108
+ destructive,
109
+ hasDestroyOrReplace: destructive.length > 0,
110
+ moved,
111
+ };
112
+ }
113
+
114
+ /**
115
+ * modularization gate — true when the plan is PURELY state moves: at least
116
+ * one `moved` entry and zero create/update/delete/replace. That proves a
117
+ * resources→module refactor preserved every resource address (via `moved {}`
118
+ * blocks) and is a no-op on live infrastructure — the condition under which a
119
+ * modularization PR may proceed without human escalation.
120
+ */
121
+ export function isPureMovePlan(plan: {
122
+ add: number;
123
+ change: number;
124
+ destroy: number;
125
+ changed: { address: string }[];
126
+ moved: { address: string }[];
127
+ }): boolean {
128
+ return (
129
+ plan.moved.length > 0 &&
130
+ plan.changed.length === 0 &&
131
+ plan.add + plan.change + plan.destroy === 0
132
+ );
133
+ }
134
+
135
+ // --- stateful destroy/replace classification (safety gate) ------------
136
+
137
+ /**
138
+ * Resource types that hold data/state — destroying or replacing one of these
139
+ * means data loss, not just recreation. A remediation that would delete or
140
+ * replace one is hard-blocked at push time unless the operator opts in via the
141
+ * `allow_replace` input. Not exhaustive: it covers the common managed
142
+ * datastores across AWS / Azure / GCP; extend as new ones come up.
143
+ */
144
+ export const STATEFUL_RESOURCE_TYPES: ReadonlySet<string> = new Set([
145
+ // AWS
146
+ "aws_db_instance",
147
+ "aws_rds_cluster",
148
+ "aws_rds_cluster_instance",
149
+ "aws_s3_bucket",
150
+ "aws_ebs_volume",
151
+ "aws_efs_file_system",
152
+ "aws_dynamodb_table",
153
+ "aws_dynamodb_global_table",
154
+ "aws_elasticache_cluster",
155
+ "aws_elasticache_replication_group",
156
+ "aws_redshift_cluster",
157
+ "aws_docdb_cluster",
158
+ "aws_neptune_cluster",
159
+ "aws_opensearch_domain",
160
+ "aws_elasticsearch_domain",
161
+ // Azure
162
+ "azurerm_sql_database",
163
+ "azurerm_mssql_database",
164
+ "azurerm_postgresql_database",
165
+ "azurerm_postgresql_flexible_server",
166
+ "azurerm_mysql_database",
167
+ "azurerm_mysql_flexible_server",
168
+ "azurerm_cosmosdb_account",
169
+ "azurerm_cosmosdb_sql_database",
170
+ // The container is where the documents actually live, and replacing one (a
171
+ // partition-key change does exactly that) empties it. Added 2026-07-27 after
172
+ // TC-2.2's azurerm v3→v4 pack surfaced a documented breaking change that
173
+ // forces this replacement while the guard below could not see it.
174
+ "azurerm_cosmosdb_sql_container",
175
+ "azurerm_storage_account",
176
+ // Data-bearing children of a storage account: the share directory and the
177
+ // table entity hold content the account itself does not.
178
+ "azurerm_storage_share_directory",
179
+ "azurerm_storage_table_entity",
180
+ "azurerm_managed_disk",
181
+ // GCP
182
+ "google_sql_database_instance",
183
+ "google_storage_bucket",
184
+ "google_bigtable_instance",
185
+ "google_bigquery_dataset",
186
+ "google_spanner_database",
187
+ "google_redis_instance",
188
+ "google_filestore_instance",
189
+ "google_compute_disk",
190
+ ]);
191
+
192
+ /**
193
+ * Extract the Terraform resource TYPE from a plan address, stripping any
194
+ * `module.<name>.` prefixes and an instance index/key suffix:
195
+ * `module.db.aws_db_instance.main` -> `aws_db_instance`
196
+ * `aws_s3_bucket.data["prod"]` -> `aws_s3_bucket`
197
+ * `module.a.module.b.google_storage_bucket.x[0]` -> `google_storage_bucket`
198
+ * Returns "" when the address has no parseable `type.name` pair.
199
+ */
200
+ export function resourceTypeOf(address: string): string {
201
+ const withoutModules = address.replace(/^(?:module\.[^.]+\.)+/, "");
202
+ const cleaned = withoutModules.replace(/\[[^\]]*\]$/, "");
203
+ const segments = cleaned.split(".");
204
+ return segments.at(-2) ?? "";
205
+ }
206
+
207
+ export interface DestroyClassification {
208
+ /** destroy/replace of a data-bearing type — high-risk, blocked by default. */
209
+ stateful: { address: string; action: string; type: string }[];
210
+ /** destroy/replace of a recreatable type — recorded, not blocked. */
211
+ ephemeral: { address: string; action: string; type: string }[];
212
+ }
213
+
214
+ /** partition a plan's destructive set into stateful (blocked) vs ephemeral. */
215
+ export function classifyDestructive(
216
+ destructive: { address: string; action: string }[],
217
+ ): DestroyClassification {
218
+ const stateful: DestroyClassification["stateful"] = [];
219
+ const ephemeral: DestroyClassification["ephemeral"] = [];
220
+ for (const d of destructive) {
221
+ const type = resourceTypeOf(d.address);
222
+ (STATEFUL_RESOURCE_TYPES.has(type) ? stateful : ephemeral).push({
223
+ ...d,
224
+ type,
225
+ });
226
+ }
227
+ return { stateful, ephemeral };
228
+ }
229
+
230
+ // --- blast-radius scoring -------------------------------------------
231
+
232
+ export interface BlastRadius {
233
+ tier: BlastTier;
234
+ /** count of resources the plan would create/update/delete/replace. */
235
+ resourceCount: number;
236
+ /** distinct module addresses touched (root resources count as `root`). */
237
+ modules: string[];
238
+ }
239
+
240
+ /**
241
+ * Extract the module address from a resource address: the `module.X[.module.Y]`
242
+ * call path, or `root` for a top-level resource. Strips instance index/key from
243
+ * EVERY segment — a `count`/`for_each` MODULE carries its key on the module
244
+ * segment (`module.net[0]`), so all instances of one module collapse to one
245
+ * address (else a single-module fix would look cross-module). Removing keys
246
+ * first also tolerates a `.` inside a `for_each` string key.
247
+ * `aws_s3_bucket.b` -> `root`
248
+ * `module.db.aws_db_instance.main` -> `module.db`
249
+ * `module.net[0].aws_vpc.main` -> `module.net`
250
+ * `module.a.module.b.google_x.y[0]` -> `module.a.module.b`
251
+ */
252
+ export function moduleAddressOf(address: string): string {
253
+ const cleaned = address.replace(/\[[^\]]*\]/g, "");
254
+ const segments = cleaned.split(".");
255
+ // the resource is the final `type.name` pair; anything before is the module path.
256
+ return segments.length <= 2
257
+ ? "root"
258
+ : segments.slice(0, segments.length - 2).join(".");
259
+ }
260
+
261
+ /**
262
+ * Score how much a fix touches, to route large changes through stricter review:
263
+ * 1–2 resources = `low`, 3–10 = `medium`, more than 10 OR spanning more than one
264
+ * module = `high`. A `high` blast radius should force human-in-the-loop
265
+ * regardless of finding severity. 0 changes is `low` (nothing to do).
266
+ */
267
+ export function computeBlastRadius(
268
+ changed: { address: string }[],
269
+ ): BlastRadius {
270
+ const resourceCount = changed.length;
271
+ const modules = [
272
+ ...new Set(changed.map((c) => moduleAddressOf(c.address))),
273
+ ].sort();
274
+ const crossModule = modules.length > 1;
275
+ let tier: BlastTier;
276
+ if (resourceCount > 10 || crossModule) tier = "high";
277
+ else if (resourceCount >= 3) tier = "medium";
278
+ else tier = "low";
279
+ return { tier, resourceCount, modules };
280
+ }
281
+
282
+ // --- plan stability / idempotency -----------------------------------
283
+
284
+ export interface StabilityResult {
285
+ /** true when a second plan produced the identical change set. */
286
+ stable: boolean;
287
+ reason?: string;
288
+ }
289
+
290
+ /** a normalized signature of a plan's change set (summary counts + sorted
291
+ * address:action pairs) — two plans with the same signature are equivalent. */
292
+ function planSignature(s: PlanSummary): string {
293
+ const set = s.changed
294
+ .map((c) => `${c.address}:${c.action}`)
295
+ .sort()
296
+ .join(",");
297
+ return `+${s.add}~${s.change}-${s.destroy}|${set}`;
298
+ }
299
+
300
+ /**
301
+ * Compare two consecutive plans for stability. Infraweaver never `apply`s (it only
302
+ * opens PRs), so a true "no perpetual diff after apply" cannot be proven here —
303
+ * but a fix whose plan is non-deterministic (e.g. `timestamp()`, `uuid()`, an
304
+ * unkeyed `random_*`, or a data source that varies run-to-run) yields a DIFFERENT
305
+ * plan on the second run, and that is a real perpetual-diff smell we can catch
306
+ * without applying. Stable ⇒ the two plans matched; unstable ⇒ report it.
307
+ */
308
+ export function comparePlanStability(
309
+ first: PlanSummary,
310
+ second: PlanSummary,
311
+ ): StabilityResult {
312
+ if (planSignature(first) === planSignature(second)) return { stable: true };
313
+ return {
314
+ stable: false,
315
+ reason:
316
+ `the plan is not deterministic — a second \`terraform plan\` (same state, no apply) produced a ` +
317
+ `different change set (first: +${first.add} ~${first.change} -${first.destroy}; ` +
318
+ `second: +${second.add} ~${second.change} -${second.destroy}). This is a perpetual-diff smell, ` +
319
+ `usually a non-deterministic value in the config (timestamp()/uuid()/unkeyed random_*/a varying data source).`,
320
+ };
321
+ }
322
+
323
+ // --- multi-root plan aggregation -------------------------------------------
324
+
325
+ export interface RootPlan {
326
+ /** display label for the root ("." for the top-level root). */
327
+ dir: string;
328
+ summary: PlanSummary;
329
+ stable: boolean;
330
+ }
331
+
332
+ export interface AggregatedPlan {
333
+ add: number;
334
+ change: number;
335
+ destroy: number;
336
+ changed: { address: string; action: string }[];
337
+ destructive: { address: string; action: string }[];
338
+ hasDestroyOrReplace: boolean;
339
+ idempotent: boolean;
340
+ moved: { address: string; previousAddress: string | null }[];
341
+ }
342
+
343
+ /**
344
+ * Aggregate per-root plan results into one view: SUM the add/change/destroy
345
+ * counts, UNION the changed + destructive sets (so blast-radius and the
346
+ * destroy-block see every root's effect), and treat the whole run as
347
+ * non-idempotent if ANY root's plan was unstable. Pure. Single-root input passes
348
+ * straight through (identical to the pre-multi-root behaviour).
349
+ */
350
+ export function aggregatePlans(roots: RootPlan[]): AggregatedPlan {
351
+ let add = 0;
352
+ let change = 0;
353
+ let destroy = 0;
354
+ let idempotent = true;
355
+ const changed: { address: string; action: string }[] = [];
356
+ const destructive: { address: string; action: string }[] = [];
357
+ const moved: { address: string; previousAddress: string | null }[] = [];
358
+ for (const r of roots) {
359
+ add += r.summary.add;
360
+ change += r.summary.change;
361
+ destroy += r.summary.destroy;
362
+ changed.push(...r.summary.changed);
363
+ destructive.push(...r.summary.destructive);
364
+ moved.push(...r.summary.moved);
365
+ if (!r.stable) idempotent = false;
366
+ }
367
+ return {
368
+ add,
369
+ change,
370
+ destroy,
371
+ changed,
372
+ destructive,
373
+ hasDestroyOrReplace: destructive.length > 0,
374
+ idempotent,
375
+ moved,
376
+ };
377
+ }