terramend 0.2.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 (406) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +145 -0
  3. package/dist/agents/claude.d.ts +73 -0
  4. package/dist/agents/claudePretoolGate.d.ts +99 -0
  5. package/dist/agents/gateServer.d.ts +7 -0
  6. package/dist/agents/index.d.ts +6 -0
  7. package/dist/agents/nativeFsDenies.d.ts +28 -0
  8. package/dist/agents/opencode.d.ts +231 -0
  9. package/dist/agents/opencodePlugin.d.ts +85 -0
  10. package/dist/agents/opencodeShared.d.ts +40 -0
  11. package/dist/agents/postRun.d.ts +132 -0
  12. package/dist/agents/reviewer.d.ts +38 -0
  13. package/dist/agents/sessionLabeler.d.ts +97 -0
  14. package/dist/agents/shared.d.ts +189 -0
  15. package/dist/agents/subagentModels.d.ts +19 -0
  16. package/dist/agents/subagentToolGates.d.ts +55 -0
  17. package/dist/cli.mjs +197426 -0
  18. package/dist/external.d.ts +227 -0
  19. package/dist/index.d.ts +6 -0
  20. package/dist/index.js +196783 -0
  21. package/dist/internal/index.d.ts +18 -0
  22. package/dist/internal.js +1714 -0
  23. package/dist/lifecycle.d.ts +2 -0
  24. package/dist/main.d.ts +8 -0
  25. package/dist/mcp/arkConfig.d.ts +1 -0
  26. package/dist/mcp/checkSuite.d.ts +25 -0
  27. package/dist/mcp/checkout.d.ts +77 -0
  28. package/dist/mcp/comment.d.ts +119 -0
  29. package/dist/mcp/commitInfo.d.ts +9 -0
  30. package/dist/mcp/crosswalk.d.ts +105 -0
  31. package/dist/mcp/dependencies.d.ts +8 -0
  32. package/dist/mcp/geminiSanitizer.d.ts +28 -0
  33. package/dist/mcp/git.d.ts +46 -0
  34. package/dist/mcp/guardrails.d.ts +104 -0
  35. package/dist/mcp/issue.d.ts +18 -0
  36. package/dist/mcp/issueComments.d.ts +9 -0
  37. package/dist/mcp/issueEvents.d.ts +9 -0
  38. package/dist/mcp/issueInfo.d.ts +9 -0
  39. package/dist/mcp/labels.d.ts +12 -0
  40. package/dist/mcp/localContext.d.ts +19 -0
  41. package/dist/mcp/moduleExtraction.d.ts +71 -0
  42. package/dist/mcp/moduleTests.d.ts +104 -0
  43. package/dist/mcp/modules.d.ts +179 -0
  44. package/dist/mcp/output.d.ts +12 -0
  45. package/dist/mcp/pathSafety.d.ts +14 -0
  46. package/dist/mcp/policy.d.ts +48 -0
  47. package/dist/mcp/pr.d.ts +49 -0
  48. package/dist/mcp/prInfo.d.ts +9 -0
  49. package/dist/mcp/providerSchema.d.ts +50 -0
  50. package/dist/mcp/review.d.ts +199 -0
  51. package/dist/mcp/reviewComments.d.ts +178 -0
  52. package/dist/mcp/roots.d.ts +58 -0
  53. package/dist/mcp/scope.d.ts +15 -0
  54. package/dist/mcp/selectMode.d.ts +18 -0
  55. package/dist/mcp/server.d.ts +48 -0
  56. package/dist/mcp/shared.d.ts +47 -0
  57. package/dist/mcp/shell.d.ts +37 -0
  58. package/dist/mcp/staleFix.d.ts +51 -0
  59. package/dist/mcp/terraform/cost.d.ts +55 -0
  60. package/dist/mcp/terraform/currency.d.ts +94 -0
  61. package/dist/mcp/terraform/decisions.d.ts +178 -0
  62. package/dist/mcp/terraform/findings.d.ts +75 -0
  63. package/dist/mcp/terraform/plan.d.ts +157 -0
  64. package/dist/mcp/terraform/scanners.d.ts +131 -0
  65. package/dist/mcp/terraform/tools.d.ts +63 -0
  66. package/dist/mcp/terraform/types.d.ts +172 -0
  67. package/dist/mcp/terraform.d.ts +22 -0
  68. package/dist/mcp/terratest.d.ts +83 -0
  69. package/dist/mcp/upload.d.ts +6 -0
  70. package/dist/models.d.ts +171 -0
  71. package/dist/modes.d.ts +26 -0
  72. package/dist/prep/index.d.ts +7 -0
  73. package/dist/prep/installNodeDependencies.d.ts +2 -0
  74. package/dist/prep/installPythonDependencies.d.ts +2 -0
  75. package/dist/prep/types.d.ts +31 -0
  76. package/dist/reviewQuality.d.ts +64 -0
  77. package/dist/skills/terraform-best-practices/SKILL.md +369 -0
  78. package/dist/toolState.d.ts +135 -0
  79. package/dist/utils/activity.d.ts +40 -0
  80. package/dist/utils/agent.d.ts +20 -0
  81. package/dist/utils/agentHangReport.d.ts +38 -0
  82. package/dist/utils/apiFetch.d.ts +19 -0
  83. package/dist/utils/apiKeys.d.ts +41 -0
  84. package/dist/utils/apiUrl.d.ts +20 -0
  85. package/dist/utils/assets.d.ts +8 -0
  86. package/dist/utils/billingErrors.d.ts +85 -0
  87. package/dist/utils/body.d.ts +34 -0
  88. package/dist/utils/buildTerramendFooter.d.ts +25 -0
  89. package/dist/utils/byokFallback.d.ts +85 -0
  90. package/dist/utils/claudeSubscription.d.ts +30 -0
  91. package/dist/utils/cli.d.ts +10 -0
  92. package/dist/utils/codexHome.d.ts +29 -0
  93. package/dist/utils/codexOAuth.d.ts +60 -0
  94. package/dist/utils/diffCoverage.d.ts +63 -0
  95. package/dist/utils/errorReport.d.ts +17 -0
  96. package/dist/utils/exitHandler.d.ts +8 -0
  97. package/dist/utils/fixDoubleEscapedString.d.ts +1 -0
  98. package/dist/utils/gitAuth.d.ts +84 -0
  99. package/dist/utils/gitAuthServer.d.ts +24 -0
  100. package/dist/utils/github.d.ts +78 -0
  101. package/dist/utils/globals.d.ts +3 -0
  102. package/dist/utils/install.d.ts +60 -0
  103. package/dist/utils/instructions.d.ts +48 -0
  104. package/dist/utils/leapingComment.d.ts +11 -0
  105. package/dist/utils/learnings.d.ts +62 -0
  106. package/dist/utils/learningsTruncate.d.ts +25 -0
  107. package/dist/utils/lifecycle.d.ts +57 -0
  108. package/dist/utils/log.d.ts +111 -0
  109. package/dist/utils/normalizeEnv.d.ts +30 -0
  110. package/dist/utils/openCodeModels.d.ts +11 -0
  111. package/dist/utils/overrides.d.ts +40 -0
  112. package/dist/utils/packageManager.d.ts +49 -0
  113. package/dist/utils/patchWorkflowRunFields.d.ts +29 -0
  114. package/dist/utils/payload.d.ts +105 -0
  115. package/dist/utils/prSummary.d.ts +61 -0
  116. package/dist/utils/progressComment.d.ts +146 -0
  117. package/dist/utils/providerErrors.d.ts +31 -0
  118. package/dist/utils/rangeDiff.d.ts +51 -0
  119. package/dist/utils/remediationCommand.d.ts +55 -0
  120. package/dist/utils/retry.d.ts +13 -0
  121. package/dist/utils/reviewCleanup.d.ts +14 -0
  122. package/dist/utils/run.d.ts +9 -0
  123. package/dist/utils/runContext.d.ts +60 -0
  124. package/dist/utils/runContextData.d.ts +23 -0
  125. package/dist/utils/runErrorRenderer.d.ts +64 -0
  126. package/dist/utils/runLifecycle.d.ts +86 -0
  127. package/dist/utils/runStartupLog.d.ts +15 -0
  128. package/dist/utils/secrets.d.ts +22 -0
  129. package/dist/utils/setup.d.ts +90 -0
  130. package/dist/utils/shell.d.ts +32 -0
  131. package/dist/utils/skills.d.ts +10 -0
  132. package/dist/utils/subprocess.d.ts +80 -0
  133. package/dist/utils/terraformMcp.d.ts +42 -0
  134. package/dist/utils/time.d.ts +15 -0
  135. package/dist/utils/timer.d.ts +23 -0
  136. package/dist/utils/todoTracking.d.ts +16 -0
  137. package/dist/utils/token.d.ts +39 -0
  138. package/dist/utils/version.d.ts +2 -0
  139. package/dist/utils/versioning.d.ts +7 -0
  140. package/dist/utils/vertex.d.ts +16 -0
  141. package/dist/utils/workflow.d.ts +13 -0
  142. package/package.json +119 -0
  143. package/src/agents/claude.test.ts +1016 -0
  144. package/src/agents/claude.ts +1246 -0
  145. package/src/agents/claudePretoolGate.test.ts +28 -0
  146. package/src/agents/claudePretoolGate.ts +173 -0
  147. package/src/agents/gateServer.test.ts +204 -0
  148. package/src/agents/gateServer.ts +124 -0
  149. package/src/agents/index.ts +10 -0
  150. package/src/agents/nativeFsDenies.ts +82 -0
  151. package/src/agents/opencode.test.ts +1440 -0
  152. package/src/agents/opencode.ts +1312 -0
  153. package/src/agents/opencodePlugin.ts +222 -0
  154. package/src/agents/opencodeShared.test.ts +34 -0
  155. package/src/agents/opencodeShared.ts +121 -0
  156. package/src/agents/postRun.test.ts +549 -0
  157. package/src/agents/postRun.ts +535 -0
  158. package/src/agents/reviewer.ts +104 -0
  159. package/src/agents/sessionLabeler.test.ts +247 -0
  160. package/src/agents/sessionLabeler.ts +178 -0
  161. package/src/agents/shared.test.ts +76 -0
  162. package/src/agents/shared.ts +292 -0
  163. package/src/agents/subagentModels.test.ts +113 -0
  164. package/src/agents/subagentModels.ts +40 -0
  165. package/src/agents/subagentRegistration.test.ts +41 -0
  166. package/src/agents/subagentToolGates.ts +114 -0
  167. package/src/cli.test.ts +129 -0
  168. package/src/cli.ts +105 -0
  169. package/src/commands/gha.test.ts +192 -0
  170. package/src/commands/gha.ts +188 -0
  171. package/src/commands/mcp.ts +122 -0
  172. package/src/config.ts +1 -0
  173. package/src/entry.ts +7 -0
  174. package/src/entryPost.stdlibOnly.test.ts +109 -0
  175. package/src/entryPost.ts +99 -0
  176. package/src/external.test.ts +16 -0
  177. package/src/external.ts +302 -0
  178. package/src/index.ts +11 -0
  179. package/src/internal/index.ts +71 -0
  180. package/src/lifecycle.ts +2 -0
  181. package/src/main.test.ts +873 -0
  182. package/src/main.ts +712 -0
  183. package/src/mcp/__fixtures__/terramend-scratch-pr-49-review-3485940013.json +110 -0
  184. package/src/mcp/__fixtures__/terramend-scratch-pr-64-review-3531000326.json +14 -0
  185. package/src/mcp/__fixtures__/terramend-test-repo-pr-1.diff.json +67 -0
  186. package/src/mcp/__snapshots__/checkout.test.ts.snap +109 -0
  187. package/src/mcp/__snapshots__/reviewComments.test.ts.snap +71 -0
  188. package/src/mcp/arkConfig.ts +7 -0
  189. package/src/mcp/checkSuite.test.ts +245 -0
  190. package/src/mcp/checkSuite.ts +255 -0
  191. package/src/mcp/checkout.test.ts +752 -0
  192. package/src/mcp/checkout.ts +886 -0
  193. package/src/mcp/comment.test.ts +772 -0
  194. package/src/mcp/comment.ts +582 -0
  195. package/src/mcp/commitInfo.test.ts +127 -0
  196. package/src/mcp/commitInfo.ts +61 -0
  197. package/src/mcp/crosswalk.test.ts +106 -0
  198. package/src/mcp/crosswalk.ts +339 -0
  199. package/src/mcp/dependencies.test.ts +309 -0
  200. package/src/mcp/dependencies.ts +189 -0
  201. package/src/mcp/geminiSanitizer.test.ts +287 -0
  202. package/src/mcp/geminiSanitizer.ts +207 -0
  203. package/src/mcp/git.test.ts +1083 -0
  204. package/src/mcp/git.ts +890 -0
  205. package/src/mcp/guardrails.test.ts +705 -0
  206. package/src/mcp/guardrails.ts +465 -0
  207. package/src/mcp/issue.test.ts +113 -0
  208. package/src/mcp/issue.ts +73 -0
  209. package/src/mcp/issueComments.test.ts +69 -0
  210. package/src/mcp/issueComments.ts +48 -0
  211. package/src/mcp/issueEvents.test.ts +134 -0
  212. package/src/mcp/issueEvents.ts +100 -0
  213. package/src/mcp/issueInfo.test.ts +104 -0
  214. package/src/mcp/issueInfo.ts +72 -0
  215. package/src/mcp/labels.test.ts +52 -0
  216. package/src/mcp/labels.ts +34 -0
  217. package/src/mcp/localContext.ts +28 -0
  218. package/src/mcp/localServer.test.ts +75 -0
  219. package/src/mcp/localServer.ts +131 -0
  220. package/src/mcp/moduleExtraction.test.ts +261 -0
  221. package/src/mcp/moduleExtraction.ts +313 -0
  222. package/src/mcp/moduleTests.test.ts +269 -0
  223. package/src/mcp/moduleTests.ts +421 -0
  224. package/src/mcp/modules.test.ts +640 -0
  225. package/src/mcp/modules.ts +696 -0
  226. package/src/mcp/output.test.ts +96 -0
  227. package/src/mcp/output.ts +70 -0
  228. package/src/mcp/pathSafety.test.ts +44 -0
  229. package/src/mcp/pathSafety.ts +28 -0
  230. package/src/mcp/policy.test.ts +282 -0
  231. package/src/mcp/policy.ts +199 -0
  232. package/src/mcp/pr.test.ts +387 -0
  233. package/src/mcp/pr.ts +194 -0
  234. package/src/mcp/prInfo.test.ts +96 -0
  235. package/src/mcp/prInfo.ts +91 -0
  236. package/src/mcp/providerSchema.test.ts +85 -0
  237. package/src/mcp/providerSchema.ts +175 -0
  238. package/src/mcp/review.test.ts +936 -0
  239. package/src/mcp/review.ts +923 -0
  240. package/src/mcp/reviewComments.test.ts +549 -0
  241. package/src/mcp/reviewComments.ts +896 -0
  242. package/src/mcp/roots.test.ts +175 -0
  243. package/src/mcp/roots.ts +217 -0
  244. package/src/mcp/scope.test.ts +59 -0
  245. package/src/mcp/scope.ts +65 -0
  246. package/src/mcp/security.test.ts +720 -0
  247. package/src/mcp/selectMode.test.ts +210 -0
  248. package/src/mcp/selectMode.ts +181 -0
  249. package/src/mcp/server.test.ts +292 -0
  250. package/src/mcp/server.ts +403 -0
  251. package/src/mcp/shared.ts +100 -0
  252. package/src/mcp/shell.test.ts +520 -0
  253. package/src/mcp/shell.ts +505 -0
  254. package/src/mcp/staleFix.test.ts +237 -0
  255. package/src/mcp/staleFix.ts +277 -0
  256. package/src/mcp/terraform/cost.ts +163 -0
  257. package/src/mcp/terraform/currency.test.ts +338 -0
  258. package/src/mcp/terraform/currency.ts +336 -0
  259. package/src/mcp/terraform/decisions.ts +527 -0
  260. package/src/mcp/terraform/findings.ts +333 -0
  261. package/src/mcp/terraform/plan.ts +348 -0
  262. package/src/mcp/terraform/scanners.ts +809 -0
  263. package/src/mcp/terraform/tools.test.ts +1071 -0
  264. package/src/mcp/terraform/tools.ts +908 -0
  265. package/src/mcp/terraform/types.ts +305 -0
  266. package/src/mcp/terraform.test.ts +1957 -0
  267. package/src/mcp/terraform.ts +23 -0
  268. package/src/mcp/terratest.test.ts +105 -0
  269. package/src/mcp/terratest.ts +196 -0
  270. package/src/mcp/toolFiltering.test.ts +85 -0
  271. package/src/mcp/upload.test.ts +180 -0
  272. package/src/mcp/upload.ts +112 -0
  273. package/src/models.test.ts +300 -0
  274. package/src/models.ts +708 -0
  275. package/src/modes.test.ts +107 -0
  276. package/src/modes.ts +880 -0
  277. package/src/prep/index.ts +43 -0
  278. package/src/prep/installNodeDependencies.test.ts +298 -0
  279. package/src/prep/installNodeDependencies.ts +196 -0
  280. package/src/prep/installPythonDependencies.test.ts +268 -0
  281. package/src/prep/installPythonDependencies.ts +199 -0
  282. package/src/prep/types.ts +38 -0
  283. package/src/reviewQuality.test.ts +63 -0
  284. package/src/reviewQuality.ts +134 -0
  285. package/src/runCli.test.ts +214 -0
  286. package/src/runCli.ts +282 -0
  287. package/src/skills/terraform-best-practices/SKILL.md +369 -0
  288. package/src/toolState.test.ts +45 -0
  289. package/src/toolState.ts +252 -0
  290. package/src/utils/activity.test.ts +188 -0
  291. package/src/utils/activity.ts +210 -0
  292. package/src/utils/agent.test.ts +251 -0
  293. package/src/utils/agent.ts +139 -0
  294. package/src/utils/agentHangReport.test.ts +203 -0
  295. package/src/utils/agentHangReport.ts +170 -0
  296. package/src/utils/apiFetch.test.ts +115 -0
  297. package/src/utils/apiFetch.ts +62 -0
  298. package/src/utils/apiKeys.test.ts +344 -0
  299. package/src/utils/apiKeys.ts +206 -0
  300. package/src/utils/apiUrl.test.ts +30 -0
  301. package/src/utils/apiUrl.ts +59 -0
  302. package/src/utils/assets.test.ts +153 -0
  303. package/src/utils/assets.ts +107 -0
  304. package/src/utils/billingErrors.test.ts +121 -0
  305. package/src/utils/billingErrors.ts +189 -0
  306. package/src/utils/body.test.ts +217 -0
  307. package/src/utils/body.ts +168 -0
  308. package/src/utils/buildTerramendFooter.test.ts +38 -0
  309. package/src/utils/buildTerramendFooter.ts +82 -0
  310. package/src/utils/byokFallback.test.ts +205 -0
  311. package/src/utils/byokFallback.ts +128 -0
  312. package/src/utils/claudeSubscription.test.ts +179 -0
  313. package/src/utils/claudeSubscription.ts +93 -0
  314. package/src/utils/cli.ts +31 -0
  315. package/src/utils/codexHome.test.ts +190 -0
  316. package/src/utils/codexHome.ts +191 -0
  317. package/src/utils/codexOAuth.ts +147 -0
  318. package/src/utils/codexRefreshDetect.test.ts +85 -0
  319. package/src/utils/codexRefreshDetect.ts +35 -0
  320. package/src/utils/diffCoverage.test.ts +468 -0
  321. package/src/utils/diffCoverage.ts +404 -0
  322. package/src/utils/errorReport.test.ts +135 -0
  323. package/src/utils/errorReport.ts +83 -0
  324. package/src/utils/exitHandler.ts +35 -0
  325. package/src/utils/fixDoubleEscapedString.ts +9 -0
  326. package/src/utils/ghaCore.ts +13 -0
  327. package/src/utils/gitAuth.test.ts +322 -0
  328. package/src/utils/gitAuth.ts +263 -0
  329. package/src/utils/gitAuthServer.test.ts +260 -0
  330. package/src/utils/gitAuthServer.ts +182 -0
  331. package/src/utils/github.test.ts +615 -0
  332. package/src/utils/github.ts +538 -0
  333. package/src/utils/globals.ts +9 -0
  334. package/src/utils/humanEditCapture.test.ts +100 -0
  335. package/src/utils/humanEditCapture.ts +193 -0
  336. package/src/utils/install.test.ts +768 -0
  337. package/src/utils/install.ts +492 -0
  338. package/src/utils/instructions.test.ts +240 -0
  339. package/src/utils/instructions.ts +543 -0
  340. package/src/utils/leapingComment.test.ts +51 -0
  341. package/src/utils/leapingComment.ts +18 -0
  342. package/src/utils/learnings.test.ts +87 -0
  343. package/src/utils/learnings.ts +138 -0
  344. package/src/utils/learningsTocRender.test.ts +116 -0
  345. package/src/utils/learningsTruncate.test.ts +39 -0
  346. package/src/utils/learningsTruncate.ts +42 -0
  347. package/src/utils/lifecycle.test.ts +195 -0
  348. package/src/utils/lifecycle.ts +198 -0
  349. package/src/utils/log.test.ts +402 -0
  350. package/src/utils/log.ts +432 -0
  351. package/src/utils/normalizeEnv.test.ts +91 -0
  352. package/src/utils/normalizeEnv.ts +106 -0
  353. package/src/utils/openCodeModels.ts +82 -0
  354. package/src/utils/overrides.test.ts +89 -0
  355. package/src/utils/overrides.ts +98 -0
  356. package/src/utils/packageManager.test.ts +321 -0
  357. package/src/utils/packageManager.ts +257 -0
  358. package/src/utils/patchWorkflowRunFields.test.ts +92 -0
  359. package/src/utils/patchWorkflowRunFields.ts +150 -0
  360. package/src/utils/payload.test.ts +497 -0
  361. package/src/utils/payload.ts +371 -0
  362. package/src/utils/postApiFetch.ts +51 -0
  363. package/src/utils/prSummary.test.ts +224 -0
  364. package/src/utils/prSummary.ts +147 -0
  365. package/src/utils/progressComment.ts +261 -0
  366. package/src/utils/providerErrors.test.ts +315 -0
  367. package/src/utils/providerErrors.ts +172 -0
  368. package/src/utils/rangeDiff.test.ts +236 -0
  369. package/src/utils/rangeDiff.ts +182 -0
  370. package/src/utils/remediationCommand.test.ts +163 -0
  371. package/src/utils/remediationCommand.ts +119 -0
  372. package/src/utils/retry.test.ts +153 -0
  373. package/src/utils/retry.ts +58 -0
  374. package/src/utils/reviewCleanup.ts +106 -0
  375. package/src/utils/run.ts +99 -0
  376. package/src/utils/runContext.ts +145 -0
  377. package/src/utils/runContextData.ts +58 -0
  378. package/src/utils/runErrorRenderer.test.ts +95 -0
  379. package/src/utils/runErrorRenderer.ts +259 -0
  380. package/src/utils/runFixture.ts +76 -0
  381. package/src/utils/runLifecycle.ts +237 -0
  382. package/src/utils/runStartupLog.ts +60 -0
  383. package/src/utils/secrets.test.ts +103 -0
  384. package/src/utils/secrets.ts +177 -0
  385. package/src/utils/setup.test.ts +509 -0
  386. package/src/utils/setup.ts +352 -0
  387. package/src/utils/shell.ts +103 -0
  388. package/src/utils/skills.test.ts +46 -0
  389. package/src/utils/skills.ts +67 -0
  390. package/src/utils/subprocess.test.ts +170 -0
  391. package/src/utils/subprocess.ts +438 -0
  392. package/src/utils/terraformMcp.test.ts +63 -0
  393. package/src/utils/terraformMcp.ts +83 -0
  394. package/src/utils/time.test.ts +105 -0
  395. package/src/utils/time.ts +59 -0
  396. package/src/utils/timer.test.ts +91 -0
  397. package/src/utils/timer.ts +72 -0
  398. package/src/utils/todoTracking.test.ts +223 -0
  399. package/src/utils/todoTracking.ts +167 -0
  400. package/src/utils/token.test.ts +239 -0
  401. package/src/utils/token.ts +186 -0
  402. package/src/utils/version.ts +10 -0
  403. package/src/utils/versioning.test.ts +34 -0
  404. package/src/utils/versioning.ts +44 -0
  405. package/src/utils/vertex.ts +85 -0
  406. package/src/utils/workflow.ts +25 -0
@@ -0,0 +1,55 @@
1
+ import { type RunResult } from "#app/mcp/terraform/types";
2
+ export interface CostBreakdown {
3
+ /** total estimated monthly cost, or null when no resources are priced. */
4
+ totalMonthlyCost: number | null;
5
+ currency: string;
6
+ }
7
+ /**
8
+ * Parse `infracost breakdown --format json`. The top-level `totalMonthlyCost`
9
+ * is a decimal string (absent / null when a project has no priced resources);
10
+ * `currency` defaults to USD. A missing/unparseable cost becomes null so the
11
+ * caller reports "unpriced" rather than a misleading $0.00.
12
+ */
13
+ export declare function parseInfracostBreakdown(stdout: string): CostBreakdown;
14
+ export interface ResourceCost {
15
+ name: string;
16
+ monthlyCost: number;
17
+ }
18
+ /**
19
+ * Parse the per-resource monthly costs from `infracost breakdown --format json`
20
+ * (`projects[].breakdown.resources[]`), so a cost increase can be attributed to
21
+ * the specific resources that drove it instead of just a total. Skips unpriced
22
+ * (null/zero) resources; returns them sorted most-expensive first. Pure.
23
+ */
24
+ export declare function parseInfracostResources(stdout: string): ResourceCost[];
25
+ export interface CostDelta {
26
+ currency: string;
27
+ baselineMonthly: number | null;
28
+ currentMonthly: number | null;
29
+ /** current − baseline, rounded to cents; null when either side is unknown. */
30
+ deltaMonthly: number | null;
31
+ direction: "increase" | "decrease" | "no-change" | "unknown";
32
+ }
33
+ /** Pure cost-delta computation: current (post-fix) vs the base-branch baseline. */
34
+ export declare function computeCostDelta(baseline: CostBreakdown | null, current: CostBreakdown): CostDelta;
35
+ export interface CostEscalation {
36
+ /** true when the monthly increase meets/exceeds the operator's threshold. */
37
+ escalate: boolean;
38
+ reason?: string;
39
+ }
40
+ /**
41
+ * §4.16-next — decide whether a cost increase is large enough to escalate the PR
42
+ * to human review (`needs-human`). Compares the monthly delta against the
43
+ * operator's `cost_increase_block_usd` threshold. No threshold set, an unknown
44
+ * delta, or a decrease/no-change ⇒ no escalation. Pure + deterministic so the
45
+ * decision is auditable, not a model judgement.
46
+ */
47
+ export declare function classifyCostEscalation(deltaMonthly: number | null, thresholdUsd: number | undefined): CostEscalation;
48
+ export declare function runInfracostBreakdown(scanCwd: string, key: string): RunResult;
49
+ /**
50
+ * Cost of the base-branch version of the same Terraform, computed in a detached
51
+ * git worktree so the current (fixed) checkout is never disturbed. Best-effort:
52
+ * any failure (no base ref, worktree add fails, infracost errors) returns null
53
+ * and the caller falls back to reporting current cost only.
54
+ */
55
+ export declare function infracostBaseline(cwd: string, key: string, tmpdir: string): CostBreakdown | null;
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Version currency (§P1 provider currency / M3 module upgrades).
3
+ *
4
+ * Answers one question the scanners can't: "is a NEWER version available?"
5
+ * tflint checks that versions are *pinned*; nothing we run checks that they're
6
+ * *current*. This module compares the workspace's pinned provider requirements
7
+ * and registry-module pins against the Terraform Registry's published versions.
8
+ *
9
+ * Deliberately NOT a scanner source: results are advisory intelligence the
10
+ * Remediate mode turns into `chore(deps)` upgrade PRs, not `Concern`s — the
11
+ * finding baseline stays scanner-owned (see docs/workplan/04-implementation-plan.md).
12
+ *
13
+ * Degrades green everywhere: a per-source lookup failure is reported on that
14
+ * row (`lookup: "error" | "not_found" | "unsupported_source"`), and only a
15
+ * fully-unreachable registry (every lookup failed) becomes a tool-level skip.
16
+ */
17
+ export declare const DEFAULT_REGISTRY_BASE_URL = "https://registry.terraform.io";
18
+ /**
19
+ * Convert ONE Terraform version constraint string (comma-separated comparators,
20
+ * AND semantics) into an npm semver range, or null when any comparator is
21
+ * unparseable. `~>` is Terraform's pessimistic operator: the RIGHTMOST given
22
+ * component may float (`~> 5.0` → `>=5.0.0 <6.0.0`, `~> 5.1.2` → `>=5.1.2 <5.2.0`,
23
+ * `~> 5` → `>=5.0.0 <6.0.0`). `!=` comparators have no single-range npm
24
+ * equivalent and are skipped — acceptable here because the result only ranks
25
+ * candidate versions, it never selects what gets installed.
26
+ */
27
+ export declare function terraformConstraintToRange(constraint: string): string | null;
28
+ export interface CurrencyVerdict {
29
+ /** newest stable version the registry publishes (null: nothing published). */
30
+ latest: string | null;
31
+ /** newest published version the written constraint admits (null: no
32
+ * constraint, unparseable constraint, or nothing satisfies). */
33
+ newestSatisfying: string | null;
34
+ /** true when the registry has a stable version the constraint does NOT admit
35
+ * — i.e. an upgrade PR is available. Always false without a constraint. */
36
+ outdated: boolean;
37
+ /** how many MAJORs the constraint's best version trails the latest by —
38
+ * >0 signals an interface-risk upgrade that must be `needs-human`. */
39
+ majorsBehind: number;
40
+ }
41
+ export declare function classifyCurrency(params: {
42
+ constraint: string | null;
43
+ available: string[];
44
+ }): CurrencyVerdict;
45
+ export type LookupStatus = "ok" | "not_found" | "error" | "unsupported_source";
46
+ /** GET /v1/providers/{namespace}/{type}/versions — provider release list. */
47
+ export declare function fetchProviderVersions(source: string, opts?: {
48
+ baseUrl?: string;
49
+ }): Promise<{
50
+ status: LookupStatus;
51
+ versions: string[];
52
+ }>;
53
+ /** GET /v1/modules/{namespace}/{name}/{provider}/versions — registry-module
54
+ * release list (the response nests per-module records; the first is the
55
+ * requested module, the rest are dependency records we don't want). */
56
+ export declare function fetchModuleVersions(sourceBase: string, opts?: {
57
+ baseUrl?: string;
58
+ }): Promise<{
59
+ status: LookupStatus;
60
+ versions: string[];
61
+ }>;
62
+ export interface ProviderCurrencyRow {
63
+ name: string;
64
+ source: string;
65
+ constraint: string | null;
66
+ latest: string | null;
67
+ newest_satisfying: string | null;
68
+ outdated: boolean;
69
+ majors_behind: number;
70
+ lookup: LookupStatus;
71
+ }
72
+ export interface ModuleCurrencyRow {
73
+ name: string;
74
+ source: string;
75
+ version: string | null;
76
+ latest: string | null;
77
+ newest_satisfying: string | null;
78
+ outdated: boolean;
79
+ /** registry module with no `version` attribute — pin it (to `latest`). */
80
+ unpinned: boolean;
81
+ lookup: LookupStatus;
82
+ declared_in: string;
83
+ }
84
+ export interface CurrencyReport {
85
+ providers: ProviderCurrencyRow[];
86
+ modules: ModuleCurrencyRow[];
87
+ outdated_count: number;
88
+ unpinned_count: number;
89
+ lookups_attempted: number;
90
+ lookups_failed: number;
91
+ }
92
+ export declare function checkVersionCurrency(cwd: string, opts?: {
93
+ baseUrl?: string;
94
+ }): Promise<CurrencyReport>;
@@ -0,0 +1,178 @@
1
+ import type { CostDelta } from "#app/mcp/terraform/cost";
2
+ import { type Autonomy, type BlastTier, type Concern, type ConcernGroup, type Severity } from "#app/mcp/terraform/types";
3
+ /** group concerns by file into scoped units, sorted by max severity. */
4
+ export declare function groupConcerns(concerns: Concern[]): ConcernGroup[];
5
+ /**
6
+ * §3.11 — group concerns by RULE across files instead of by file. When a single
7
+ * rule fires in many files ("add `tags` to every resource", "enable encryption
8
+ * on every bucket"), fixing it as ONE coherent change is far better than N
9
+ * near-identical per-file PRs. Each group covers one `rule_id` and lists every
10
+ * `file` it spans; the branch key (`remediate/<id>`) is rule-derived and stable.
11
+ * Opt-in (scan `group_by: "rule"`) — by-file stays the default because it keeps
12
+ * each PR's blast radius smaller; by-rule suits sweeping, low-risk rules.
13
+ */
14
+ export declare function groupConcernsByRule(concerns: Concern[]): ConcernGroup[];
15
+ /**
16
+ * §3.9 — annotate each group with an autonomy decision. Works for BOTH grouping
17
+ * modes: it resolves a group's concerns by `concern_ids` membership (not by
18
+ * `file`, which is just a label for by-rule groups), so the severity/category
19
+ * policy applies identically. Blast radius isn't known until terraform_plan
20
+ * runs, so it can only escalate a group later (the plan tool + prompt apply the
21
+ * `high`-blast override); at scan time autonomy is severity/category-driven.
22
+ */
23
+ export declare function annotateGroups(groups: ConcernGroup[], all: Concern[], threshold: Severity): ConcernGroup[];
24
+ export interface BatchPlan {
25
+ /** group ids safe to combine into ONE low-risk PR (`remediate/batch-<hash>`). */
26
+ batchable: string[];
27
+ /** group ids that must each get their own PR (security / higher severity /
28
+ * needs-human / large blast). */
29
+ isolated: string[];
30
+ /** deterministic branch name for the batch (stable for the same member set). */
31
+ batch_branch: string | null;
32
+ }
33
+ /**
34
+ * §3.10 — split annotated groups into a single low-risk BATCH (merged into one
35
+ * easy-to-review PR) and the riskier groups that each stay ISOLATED in their own
36
+ * PR (so they can be reviewed/reverted independently). The batch branch name
37
+ * hashes the sorted member ids, so re-runs over the same set reuse the branch
38
+ * (idempotent). Returns `batch_branch: null` when fewer than two groups are
39
+ * batchable (one group is just a normal single-group PR, not a batch).
40
+ */
41
+ export declare function planBatches(groups: ConcernGroup[]): BatchPlan;
42
+ /**
43
+ * Resolve the canonical documentation URL for a concern's rule, for the PR's
44
+ * per-finding explanation. Prefers the scanner's own `remediation_hint` when it
45
+ * is already a URL (checkov guideline, tflint rule link, trivy reference).
46
+ * Otherwise derives the well-known page deterministically: a trivy `AVD-*` rule
47
+ * maps to its Aqua Vulnerability Database page. Returns null when no canonical
48
+ * URL is known (the agent then explains from `evidence` alone).
49
+ */
50
+ export declare function ruleDocUrl(concern: Pick<Concern, "rule_id" | "remediation_hint">): string | null;
51
+ /** distinct rule→doc-url map for a group, for the PR body's per-finding links. */
52
+ export declare function docUrlsForGroup(g: ConcernGroup, all: Concern[]): Record<string, string>;
53
+ export interface AutonomyDecision {
54
+ autonomy: Autonomy;
55
+ /** human-readable reasons a group was escalated (empty for `auto`). */
56
+ reasons: string[];
57
+ }
58
+ /**
59
+ * Decide whether a group of concerns can be auto-fixed and opened as a normal
60
+ * PR (`auto`), or must be flagged for human review (`needs-human`). Trivial
61
+ * findings (style/correctness, deprecated args, missing tags, formatting) open
62
+ * as normal; high-severity SECURITY findings escalate by default, as does a
63
+ * `high` blast radius regardless of finding severity (§2.6 overrides upward).
64
+ *
65
+ * `threshold` is the minimum severity at which a *security* concern escalates
66
+ * (default `high`, so critical/high security → human; medium/low → auto). The
67
+ * decision is deterministic and computed from the `Concern` model's existing
68
+ * `severity` + `category` — no model self-assessment.
69
+ */
70
+ export declare function classifyAutonomy(concerns: Pick<Concern, "severity" | "category">[], threshold?: Severity, blastTier?: BlastTier): AutonomyDecision;
71
+ export interface SuggestionDecision {
72
+ /** true ⇒ post a GitHub one-click `suggestion` instead of opening a full PR. */
73
+ suggest: boolean;
74
+ reason: string;
75
+ }
76
+ /**
77
+ * §5.18 — decide whether a fix is small/low-risk enough to post as a GitHub
78
+ * one-click **suggested change** (a ` ```suggestion ` block on the existing PR)
79
+ * rather than opening a whole `remediate/*` branch + PR. Much lower friction for
80
+ * trivial fixes. Only when ALL hold: there IS an existing PR context (a comment
81
+ * trigger on a PR); the group is `low`/`info` severity; the fix is a single hunk
82
+ * in a single file; and the blast radius (when known) is `low`. Anything bigger
83
+ * keeps full-PR mode.
84
+ */
85
+ export declare function shouldSuggestInline(opts: {
86
+ hasPrContext: boolean;
87
+ severity: Severity;
88
+ fileCount: number;
89
+ hunkCount: number;
90
+ blastTier?: BlastTier | undefined;
91
+ }): SuggestionDecision;
92
+ export type Confidence = "high" | "medium" | "low";
93
+ export interface ConfidenceSignals {
94
+ /** §1.1 — every targeted concern id was cleared by the re-scan. */
95
+ verified: boolean;
96
+ /** §1.4 — count of NEW concern ids the fix introduced (0 is good). */
97
+ regressionCount: number;
98
+ /** §1.3 — second plan matched the first. undefined when plan didn't run. */
99
+ idempotent?: boolean | undefined;
100
+ /** §2.6 — blast tier. undefined when plan didn't run. */
101
+ blastTier?: BlastTier | undefined;
102
+ /** §4.16 — cost direction. undefined when infracost didn't run. */
103
+ costDirection?: CostDelta["direction"] | undefined;
104
+ }
105
+ export interface ConfidenceResult {
106
+ level: Confidence;
107
+ reasons: string[];
108
+ }
109
+ /**
110
+ * Derive a fix's confidence DETERMINISTICALLY from the verification evidence
111
+ * already gathered — never a model self-assessment, which keeps it honest.
112
+ *
113
+ * - A fix that didn't verify (§1.1) or introduced a regression (§1.4) is `low`:
114
+ * the proof failed, full stop.
115
+ * - Otherwise it starts `high` and is capped to `medium` by any weaker signal:
116
+ * a non-deterministic plan (§1.3 `idempotent: false`), a `high` blast radius
117
+ * (§2.6), a cost increase (§4.16), or a signal that was *skipped* (plan /
118
+ * infracost didn't run, so we have less proof — `high` requires the full
119
+ * stack). A skipped signal lowers confidence but does not, by itself, make a
120
+ * verified, regression-free fix `low`.
121
+ */
122
+ export declare function computeConfidence(signals: ConfidenceSignals): ConfidenceResult;
123
+ export interface RefusalDecision {
124
+ /** true ⇒ this concern needs a human decision; prefer a structured non-fix
125
+ * (an issue) over guessing a fix that could break the stack. */
126
+ refuse: boolean;
127
+ reason?: string;
128
+ }
129
+ /**
130
+ * §29 — advisory check: would auto-fixing this concern require a judgement only
131
+ * a human can make? If so, the Remediate flow should post a STRUCTURED refusal
132
+ * (an issue describing the concern, why it won't auto-fix, and what a human
133
+ * should do) rather than guess a fix that could break the stack. Deterministic
134
+ * and conservative — it only flags the well-known human-decision classes.
135
+ */
136
+ export declare function classifyRefusal(concern: Pick<Concern, "rule_id" | "evidence">): RefusalDecision;
137
+ /**
138
+ * §29 — format a structured non-fix for a concern Terramend won't auto-fix. The
139
+ * output is a Markdown issue body: what's wrong, why it isn't auto-fixed, and
140
+ * the concrete next step for a human. Pure (string in → string out).
141
+ */
142
+ export declare function buildRefusalReport(input: {
143
+ concern: Pick<Concern, "rule_id" | "evidence" | "location">;
144
+ whyNoAutoFix: string;
145
+ humanAction: string;
146
+ }): string;
147
+ export interface PreventiveControl {
148
+ /** the mechanism that stops this class of concern recurring. */
149
+ mechanism: string;
150
+ /** a copy-pasteable config/CI snippet. */
151
+ snippet: string;
152
+ note: string;
153
+ }
154
+ /**
155
+ * §21 — alongside the patch, suggest the guardrail that stops the concern
156
+ * RECURRING: a CI gate keyed on the producing scanner. Deterministic by source
157
+ * (the scanner is the right enforcement point), parameterised by the rule id.
158
+ * Returns null for sources with no natural preventive gate.
159
+ */
160
+ export declare function preventiveControlFor(concern: Pick<Concern, "source" | "rule_id">): PreventiveControl | null;
161
+ export interface LocationCluster {
162
+ file: string;
163
+ line: number | null;
164
+ /** the concern ids at this exact location (likely the same underlying defect). */
165
+ concern_ids: string[];
166
+ /** the distinct scanners that flagged this location. */
167
+ sources: string[];
168
+ }
169
+ /**
170
+ * §30 — surface concerns that DIFFERENT scanners flagged at the same `file:line`
171
+ * — almost always the same underlying defect (trivy ∩ checkov overlap heavily on
172
+ * e.g. S3 encryption). Reported so the agent writes ONE canonical fix + ONE
173
+ * explanation for the cluster rather than treating each as separate work. This
174
+ * is purely advisory: it NEVER removes a concern from the verification set (a
175
+ * missing id must still provably clear), so it can't drop a real finding. Only
176
+ * clusters spanning more than one scanner are returned.
177
+ */
178
+ export declare function clusterByLocation(concerns: Concern[]): LocationCluster[];
@@ -0,0 +1,75 @@
1
+ import { type Concern } from "#app/mcp/terraform/types";
2
+ /**
3
+ * Map a reviewer `findings.json` body into Concern[]. Drops `human_only`
4
+ * findings (out of scope — not auto-remediable). Paths are normalized to
5
+ * repo-relative POSIX (same as the scanners) so ids and grouping stay portable.
6
+ */
7
+ export declare function parseReviewerFindings(json: string, cwd?: string): Concern[];
8
+ interface SarifLocation {
9
+ physicalLocation?: {
10
+ artifactLocation?: {
11
+ uri?: string;
12
+ };
13
+ region?: {
14
+ startLine?: number;
15
+ };
16
+ };
17
+ }
18
+ interface SarifResult {
19
+ ruleId?: string;
20
+ level?: string;
21
+ message?: {
22
+ text?: string;
23
+ };
24
+ locations?: SarifLocation[];
25
+ properties?: {
26
+ "security-severity"?: string;
27
+ };
28
+ }
29
+ interface SarifRule {
30
+ id?: string;
31
+ helpUri?: string;
32
+ shortDescription?: {
33
+ text?: string;
34
+ };
35
+ }
36
+ interface SarifRun {
37
+ tool?: {
38
+ driver?: {
39
+ name?: string;
40
+ rules?: SarifRule[];
41
+ };
42
+ };
43
+ results?: SarifResult[];
44
+ }
45
+ interface SarifReport {
46
+ version?: string;
47
+ $schema?: string;
48
+ runs?: SarifRun[];
49
+ }
50
+ /** true when a parsed JSON object looks like a SARIF report (the standard
51
+ * scanner-output format) rather than a terraform-reviewer findings.json. */
52
+ export declare function isSarif(parsed: unknown): boolean;
53
+ /**
54
+ * Parse a SARIF 2.1.0 report (the standard scanner-output format Trivy /
55
+ * Checkov / tflint all emit) into Concern[]. The driver name picks the source so
56
+ * a finding from a scanner Terramend re-runs reproduces the SAME content id
57
+ * (✗→✓ verifiable); other tools collapse to `reviewer`. Rule docs come from the
58
+ * matching `tool.driver.rules[].helpUri`. Non-Terraform files are dropped.
59
+ */
60
+ export declare function parseSarifFindings(json: string, cwd?: string): Concern[];
61
+ /** dispatch a findings file to the right parser: SARIF (standard scanner
62
+ * output) or a terraform-reviewer findings.json. */
63
+ export declare function parseFindingsFile(json: string, cwd?: string): Concern[];
64
+ /**
65
+ * Emit a set of concerns as a SARIF 2.1.0 report for GitHub code-scanning (the
66
+ * inverse of `parseSarifFindings` — close the loop so a Terramend scan can
67
+ * populate the repo's Security tab via `github/codeql-action/upload-sarif`). One
68
+ * `run` with the `terramend` driver, a deduped `rules` array (each rule's
69
+ * `helpUri` from `ruleDocUrl`), and one `result` per concern carrying its
70
+ * `level`, `security-severity`, message, and `file:line`. Pure + deterministic
71
+ * (rules sorted, stable partialFingerprints from the content id) so re-emitting
72
+ * an unchanged scan yields a byte-identical report.
73
+ */
74
+ export declare function buildSarifReport(concerns: Concern[]): SarifReport;
75
+ export {};
@@ -0,0 +1,157 @@
1
+ import type { BlastTier } from "#app/mcp/terraform/types";
2
+ export interface PlanSummary {
3
+ /** resources to add / change / destroy, from the plan's change_summary. */
4
+ add: number;
5
+ change: number;
6
+ destroy: number;
7
+ /** every resource with a real action (create/update/delete/replace) — the set
8
+ * that powers blast-radius (§2.6) and plan-stability (§1.3). */
9
+ changed: {
10
+ address: string;
11
+ action: string;
12
+ }[];
13
+ /** resources that would be deleted or replaced — the destructive set. */
14
+ destructive: {
15
+ address: string;
16
+ action: string;
17
+ }[];
18
+ hasDestroyOrReplace: boolean;
19
+ /** state-only moves (`moved {}` blocks / refactors): the new address and the
20
+ * address it came from. Moves don't mutate live infrastructure, so they are
21
+ * NOT in `changed` — they power the M2 modularization gate (`isPureMovePlan`). */
22
+ moved: {
23
+ address: string;
24
+ previousAddress: string | null;
25
+ }[];
26
+ }
27
+ export declare function parseTerraformPlanJson(stdout: string): PlanSummary;
28
+ /**
29
+ * §M2 modularization gate — true when the plan is PURELY state moves: at least
30
+ * one `moved` entry and zero create/update/delete/replace. That proves a
31
+ * resources→module refactor preserved every resource address (via `moved {}`
32
+ * blocks) and is a no-op on live infrastructure — the condition under which a
33
+ * modularization PR may proceed without human escalation.
34
+ */
35
+ export declare function isPureMovePlan(plan: {
36
+ add: number;
37
+ change: number;
38
+ destroy: number;
39
+ changed: {
40
+ address: string;
41
+ }[];
42
+ moved: {
43
+ address: string;
44
+ }[];
45
+ }): boolean;
46
+ /**
47
+ * Resource types that hold data/state — destroying or replacing one of these
48
+ * means data loss, not just recreation. A remediation that would delete or
49
+ * replace one is hard-blocked at push time unless the operator opts in via the
50
+ * `allow_replace` input. Not exhaustive: it covers the common managed
51
+ * datastores across AWS / Azure / GCP; extend as new ones come up.
52
+ */
53
+ export declare const STATEFUL_RESOURCE_TYPES: ReadonlySet<string>;
54
+ /**
55
+ * Extract the Terraform resource TYPE from a plan address, stripping any
56
+ * `module.<name>.` prefixes and an instance index/key suffix:
57
+ * `module.db.aws_db_instance.main` -> `aws_db_instance`
58
+ * `aws_s3_bucket.data["prod"]` -> `aws_s3_bucket`
59
+ * `module.a.module.b.google_storage_bucket.x[0]` -> `google_storage_bucket`
60
+ * Returns "" when the address has no parseable `type.name` pair.
61
+ */
62
+ export declare function resourceTypeOf(address: string): string;
63
+ export interface DestroyClassification {
64
+ /** destroy/replace of a data-bearing type — high-risk, blocked by default. */
65
+ stateful: {
66
+ address: string;
67
+ action: string;
68
+ type: string;
69
+ }[];
70
+ /** destroy/replace of a recreatable type — recorded, not blocked. */
71
+ ephemeral: {
72
+ address: string;
73
+ action: string;
74
+ type: string;
75
+ }[];
76
+ }
77
+ /** partition a plan's destructive set into stateful (blocked) vs ephemeral. */
78
+ export declare function classifyDestructive(destructive: {
79
+ address: string;
80
+ action: string;
81
+ }[]): DestroyClassification;
82
+ export interface BlastRadius {
83
+ tier: BlastTier;
84
+ /** count of resources the plan would create/update/delete/replace. */
85
+ resourceCount: number;
86
+ /** distinct module addresses touched (root resources count as `root`). */
87
+ modules: string[];
88
+ }
89
+ /**
90
+ * Extract the module address from a resource address: the `module.X[.module.Y]`
91
+ * call path, or `root` for a top-level resource. Strips instance index/key from
92
+ * EVERY segment — a `count`/`for_each` MODULE carries its key on the module
93
+ * segment (`module.net[0]`), so all instances of one module collapse to one
94
+ * address (else a single-module fix would look cross-module). Removing keys
95
+ * first also tolerates a `.` inside a `for_each` string key.
96
+ * `aws_s3_bucket.b` -> `root`
97
+ * `module.db.aws_db_instance.main` -> `module.db`
98
+ * `module.net[0].aws_vpc.main` -> `module.net`
99
+ * `module.a.module.b.google_x.y[0]` -> `module.a.module.b`
100
+ */
101
+ export declare function moduleAddressOf(address: string): string;
102
+ /**
103
+ * Score how much a fix touches, to route large changes through stricter review:
104
+ * 1–2 resources = `low`, 3–10 = `medium`, more than 10 OR spanning more than one
105
+ * module = `high`. A `high` blast radius should force human-in-the-loop
106
+ * regardless of finding severity (feeds §3.9). 0 changes is `low` (nothing to do).
107
+ */
108
+ export declare function computeBlastRadius(changed: {
109
+ address: string;
110
+ }[]): BlastRadius;
111
+ export interface StabilityResult {
112
+ /** true when a second plan produced the identical change set. */
113
+ stable: boolean;
114
+ reason?: string;
115
+ }
116
+ /**
117
+ * Compare two consecutive plans for stability. Terramend never `apply`s (it only
118
+ * opens PRs), so a true "no perpetual diff after apply" cannot be proven here —
119
+ * but a fix whose plan is non-deterministic (e.g. `timestamp()`, `uuid()`, an
120
+ * unkeyed `random_*`, or a data source that varies run-to-run) yields a DIFFERENT
121
+ * plan on the second run, and that is a real perpetual-diff smell we can catch
122
+ * without applying. Stable ⇒ the two plans matched; unstable ⇒ report it.
123
+ */
124
+ export declare function comparePlanStability(first: PlanSummary, second: PlanSummary): StabilityResult;
125
+ export interface RootPlan {
126
+ /** display label for the root ("." for the top-level root). */
127
+ dir: string;
128
+ summary: PlanSummary;
129
+ stable: boolean;
130
+ }
131
+ export interface AggregatedPlan {
132
+ add: number;
133
+ change: number;
134
+ destroy: number;
135
+ changed: {
136
+ address: string;
137
+ action: string;
138
+ }[];
139
+ destructive: {
140
+ address: string;
141
+ action: string;
142
+ }[];
143
+ hasDestroyOrReplace: boolean;
144
+ idempotent: boolean;
145
+ moved: {
146
+ address: string;
147
+ previousAddress: string | null;
148
+ }[];
149
+ }
150
+ /**
151
+ * Aggregate per-root plan results into one view: SUM the add/change/destroy
152
+ * counts, UNION the changed + destructive sets (so blast-radius and the
153
+ * destroy-block see every root's effect), and treat the whole run as
154
+ * non-idempotent if ANY root's plan was unstable. Pure. Single-root input passes
155
+ * straight through (identical to the pre-multi-root behaviour).
156
+ */
157
+ export declare function aggregatePlans(roots: RootPlan[]): AggregatedPlan;