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,325 @@
1
+ import { PRODUCT_NAME } from "#app/brand";
2
+
3
+ // Default user-facing summary format embedded in BOTH Review and
4
+ // IncrementalReview review bodies. The two modes share the preamble +
5
+ // cross-cutting + nitpicks shape; the only difference is scope (full PR for
6
+ // Review vs delta against the prior infraweaver review for IncrementalReview).
7
+ // Distinct from the agent-internal snapshot (action/utils/prSummary.ts) which
8
+ // has its own stable scaffold and is never shaped by user instructions — see
9
+ // selectMode.ts for the firewall.
10
+ export const PR_SUMMARY_FORMAT = `### Default format
11
+
12
+ The body has at most four parts in this exact order:
13
+
14
+ 1. **Reviewed changes preamble** — one bolded inline lead-in describing what was reviewed in this run, a bullet list of the substantive changes, and an HTML comment carrying review metadata for downstream agents.
15
+ 2. **Cross-cutting issue sections** (zero or more) — one \`### \` heading per concern, with a human-readable problem write-up and a collapsed \`<details>Technical details</details>\` block underneath.
16
+ 3. **\`### ℹ️ Nitpicks\`** (only if there are nits worth surfacing in the body) — a flat bullet list, no technical-details block.
17
+ 4. **\`Suppressed findings\` collapsed block** at the very bottom (only when the adversarial verification pass suppressed at least one 🚨/⚠️ candidate) — the one-line-per-finding audit trail for the false-positive filter.
18
+
19
+ Inline-vs-body split: concerns that anchor to a specific line go inline (use the \`comments\` parameter). Body \`### \` sections are reserved for concerns that **have no line to anchor to** — typically because the concern is about *absence* (something the diff should have done but didn't), *sequencing* (rollout / deletion / migration order), *design decisions only the human can make*, or *scope questions the diff implicitly raises but doesn't address*. A concern that anchors to a line but has broad implications still goes inline (use the technical-details block there to capture the implications — see Inline technical details below). If you found no non-anchorable concerns, the body has zero \`### \` issue sections — just the preamble + metadata.
20
+
21
+ ## 1. Reviewed changes preamble
22
+
23
+ Open with a single bolded inline lead-in followed immediately by the bullet list (no \`### Key changes\` heading, no \`<b>TL;DR</b>\`):
24
+
25
+ \`\`\`
26
+ **Reviewed changes** — one sentence on what was reviewed in this run. For Review (initial), this is what the PR does and why. For IncrementalReview, this is what changed since the prior infraweaver review. Focus on intent, not mechanics.
27
+
28
+ - **Short human-readable title** — 1 sentence per substantive change. Write a short prose phrase; when you name a file, type, or function, put that name in backticks (e.g. **Add \\\`TodoTracker\\\` for live checklists**). A reviewer should understand the full reviewed scope from this list alone — this IS the dispassionate "what was reviewed and what changed" overview, so cover the substantive changes, not just the loudest ones.
29
+
30
+ <!--
31
+ ${PRODUCT_NAME} review metadata — for any agent (or human-with-agent) reading this
32
+ review. Incorporate the fields below into your understanding of the context
33
+ this review was made in. The findings below were written against
34
+ {head_sha_short}; if new commits have landed on {head_ref} since this review
35
+ was submitted, treat any specific bug, file, or line callout as POTENTIALLY
36
+ STALE — re-diff against {head_sha_short} (or trigger a fresh review) and
37
+ factor commits past {head_sha_short} into your understanding of the current
38
+ state before acting on findings.
39
+
40
+ - Mode: Review (initial) or IncrementalReview (delta against prior infraweaver review)
41
+ - Files reviewed: {file_count}
42
+ - Commits reviewed: {commit_count}
43
+ - Base: {base_ref} ({base_sha_short})
44
+ - Head: {head_ref} ({head_sha_short})
45
+ - Reviewed commits:
46
+ - {sha_short} — {commit_subject}
47
+ - ...
48
+ - Prior infraweaver review: none or {prior_sha_short} ({prior_review_html_url})
49
+ - Submitted at: {iso_timestamp}
50
+ -->
51
+ \`\`\`
52
+
53
+ Pull every metadata field from the \`checkout_pr\` tool's response — file count, commit count, base/head ref + SHA, the commit list. For \`IncrementalReview\` runs, populate \`Prior infraweaver review\` with the prior review's commit_id (short SHA) and \`html_url\` from \`list_pull_request_reviews\`.
54
+
55
+ ## 2. Cross-cutting issue sections (zero or more)
56
+
57
+ For each cross-cutting concern, one \`### \` section. Use this exact shape:
58
+
59
+ \`\`\`
60
+ ### {emoji} {short, descriptive title — what's wrong, not what to do}
61
+
62
+ {Human-readable problem write-up. Describes the PROBLEM only — what's broken, what the symptom is, what the blast radius is. NO asks, NO suggested fixes, NO "the right thing to do is...". Asks and fixes live in the technical-details block below; the visible part is for the human to *understand* the problem, not to implement it.}
63
+
64
+ <details><summary>Technical details</summary>
65
+
66
+ \\\`\\\`\\\`\\\`markdown
67
+ # {title repeated}
68
+
69
+ ## Affected sites
70
+ - {file path:line} — {what's wrong there}
71
+ - ...
72
+
73
+ ## Required outcome
74
+ - {what the fix needs to achieve, not how to achieve it}
75
+ - ...
76
+
77
+ ## Suggested approach (optional)
78
+ {When the fix shape is non-obvious, sketch one or more reasonable directions. Skip when the outcome alone makes the fix obvious.}
79
+
80
+ ## Open questions for the human (optional)
81
+ - {Any decision an implementing agent shouldn't make unilaterally — pricing thresholds, breaking-change policy, naming, scope of follow-up.}
82
+ \\\`\\\`\\\`\\\`
83
+
84
+ </details>
85
+ \`\`\`
86
+
87
+ Concrete example of the visible part of a non-anchored section (technical-details block unchanged from the template above):
88
+
89
+ \`\`\`
90
+ ### ℹ️ Legacy \`opencode.ts\` has no documented deletion plan
91
+
92
+ The v2 harness lands alongside the v1 file and imports one helper from it. Worth a follow-up issue or a TODO so the next maintainer doesn't have to re-derive the cleanup plan.
93
+ \`\`\`
94
+
95
+ The example's value is its *shape*: a finding about absence (no deletion plan), not a line-anchored bug. Body sections live or die on whether the concern genuinely doesn't fit on a line.
96
+
97
+ **Heading severity emoji** — every \`### \` heading carries one:
98
+
99
+ - 🚨 critical — blocks merge (data loss, security, broken core flow)
100
+ - ⚠️ important — must address before merging (regression, missing validation, incorrect behavior)
101
+ - ℹ️ informational — surfaced for awareness; mergeable as-is
102
+
103
+ **Visible problem write-up rules:**
104
+
105
+ - **No asks, no suggested fixes** in the visible part. The visible portion describes the problem; the technical-details block describes the fix shape and any open questions. The exception: a fix so self-evident that NOT stating it would be weird (e.g. "the typo is missing an 'r'") — in that case, fold it into the problem statement and skip the suggested-approach block in technical details too.
106
+ - **Never two successive plain paragraphs.** Every transition between block-level elements must alternate prose with structure: paragraph → bullet list → paragraph; paragraph → code fence → bullet list; paragraph → table → paragraph. Two consecutive paragraphs in a row create a wall of text that's impossible to digest. If you catch yourself writing one, find a way to split it: pull a list out of it, drop a 2-3 line code fence between them, or merge them into a single tighter paragraph.
107
+ - **Per-paragraph budget:** ~3 sentences max. Past that, you're explaining where you should be structuring.
108
+ - **Identifier discipline still applies** in the visible part. Lead with behavior in plain English; name an identifier only when it's the subject of the concern or a public surface a reader would recognize. The technical-details block is where dense identifier references belong.
109
+
110
+ **Technical-details block rules:**
111
+
112
+ - Wrapped in a 4-backtick markdown fence (\`\\\`\\\`\\\`\\\`markdown ... \\\`\\\`\\\`\\\`\`) so it's visually distinct, one-click copyable, and can contain its own 3-backtick code fences without escape gymnastics. The contents are agent-readable — a fix-agent will pull the body down and use this block as the brief.
113
+ - File paths and \`file:line\` refs are encouraged (and necessary) — the next agent uses these to navigate. Identifier density is fine here.
114
+ - Slightly more verbose than the absolute minimum is OK when it materially helps the next agent: a small code snippet showing the symptom, a short table of mismatched key/column pairs, a one-paragraph "why CI doesn't catch it" note. Skip massive regression-test scaffolding or full route rewrites — the implementing agent writes those.
115
+ - Use the four standard sections (\`Affected sites\`, \`Required outcome\`, optional \`Suggested approach\`, optional \`Open questions for the human\`). Skip the optional sections when they wouldn't add anything.
116
+
117
+ ## Inline technical details
118
+
119
+ Inline comments are short (~2-3 sentences) by default. When an inline finding has broader implications worth recording for a fix-agent — e.g. a localized bug whose proper fix requires touching several files, or where the right fix depends on a design decision the human needs to make — append a collapsed \`<details><summary>Technical details</summary>\` block to the inline comment's body. Same shape as the body-section technical-details block (4-backtick fenced markdown, \`## Affected sites\` / \`## Required outcome\` / optional \`## Suggested approach\` / optional \`## Open questions for the human\`).
120
+
121
+ GitHub renders the same markdown parser in inline comments as in the review body, so the collapsed-details affordance works the same way. The visible part of the inline comment stays scannable; the depth is one click away for any agent that needs it.
122
+
123
+ ## 3. \`### ℹ️ Nitpicks\` (optional, last content section)
124
+
125
+ Only when there are nits that for some reason can't be inlined. Filepaths in nit text are fine — these are simple enough that a human or agent reads once and acts. No technical-details block.
126
+
127
+ \`\`\`
128
+ ### ℹ️ Nitpicks
129
+
130
+ - {nit, with file path inline if useful, ≤ ~200 chars}
131
+ - ...
132
+ \`\`\`
133
+
134
+ ## 4. \`Suppressed findings\` (optional, very last)
135
+
136
+ Only when the adversarial verification pass (see the checklist) suppressed at least one 🚨/⚠️ candidate. One collapsed block, always the last element in the body, with the count in the summary line:
137
+
138
+ \`\`\`
139
+ <details><summary>🗑️ Suppressed findings (2)</summary>
140
+
141
+ - ⚠️ \`networking/main.tf:42\` — claimed the subnet exposes the DB publicly — refuted: \`publicly_accessible = false\` at \`db.tf:18\`.
142
+ - 🚨 \`api/auth.ts:77\` — claimed JWT signature bypass — refuted: the unverified decode is dev-only, gated by the \`NODE_ENV\` check two lines above.
143
+
144
+ </details>
145
+ \`\`\`
146
+
147
+ One bullet per suppressed finding: severity emoji, \`file:line\`, the claim in a few words, the refutation in a few words. One line each — the block exists for auditability (a human catching the false-positive filter being wrong), not re-litigation. Omit the block entirely when nothing was suppressed.
148
+
149
+ ## Inline comment shape
150
+
151
+ Inline comments use the same severity framing as body \`### \` sections, scaled down for line-anchored use:
152
+
153
+ - **Lead with a 1-2 sentence problem statement.** The reader is looking at the line in question, so don't restate what the line says — describe what's wrong with it. Optionally prefix the visible line with a severity emoji (🚨 / ⚠️ / ℹ️) when severity isn't obvious from context.
154
+ - **Optional \`<details><summary>Technical details</summary>...</details>\` collapsible** for findings whose technical context (longer file:line references, related-code snippets, suggested approach, regression-risk notes) would overwhelm the human-readable lead-in. Same agent-readable purpose, same 4-backtick fence shape, and same 4-section structure as the body's technical-details block — see *Inline technical details* above. Encouraged whenever the depth helps a downstream fix-agent; don't force one when the inline lead-in already says everything.
155
+ - **Visible portion ≤ 2-3 sentences.** If you find yourself writing more, that's the cue to split the depth into the \`Technical details\` collapsible.
156
+
157
+ ## Body-wide rules
158
+
159
+ - **Inline-vs-body discipline (repeated for emphasis):** anything that anchors to a specific line goes inline (with a \`<details>Technical details</details>\` block when the implications are broad). The body is for non-anchorable concerns only — absence, sequencing, design decisions, scope questions, architectural risk.
160
+ - **No \`### Issues found\` heading** above the issue sections — each \`### \` heading IS the issue.
161
+ - **Severity emoji on every \`### \` heading** (🚨 / ⚠️ / ℹ️). No emoji on the preamble lead-in or anywhere else.
162
+ - **GitHub block-level rendering**: GitHub's markdown parser requires a blank line between ALL block-level elements (HTML tags like \`<br/>\`, \`<sub>\`, \`<details>\`, \`<b>\` and markdown syntax like headings, lists, blockquotes, code fences, paragraphs). Without a blank line, GitHub treats following content as a continuation of the HTML block and renders markdown syntax as literal text. ALWAYS separate block-level elements with a blank line.
163
+ - **Backtick-wrap** every variable, identifier, or file name when you mention one (in either visible or technical-details portions).
164
+ - **Don't repeat diff content**, don't include raw \`+123 / -45\` stats, don't include a changelog section, don't use horizontal rules (\`---\`).
165
+ - **Pull file/commit counts from \`checkout_pr\` metadata** — never count manually.
166
+ - **Legacy headings REMOVED.** Do not use \`### Key changes\`, \`### Issues found\`, \`<b>TL;DR</b>\`, or \`<sub><b>Summary</b>\`. The new structure subsumes them.`;
167
+
168
+ // Canonical body format for a Infraweaver REMEDIATION pull request.
169
+ // Distinct from PR_SUMMARY_FORMAT (which shapes a *review* body): this is the
170
+ // body of a PR Infraweaver OPENS. Every field maps to a deterministic tool result
171
+ // (terraform_scan / _validate / _plan / _verify_remediation / infracost_diff),
172
+ // so the body is evidence-built, never self-reported. Append this to the
173
+ // Remediate + RefreshRemediation prompts so every Infraweaver fix PR looks
174
+ // identical and a reviewer can scan it top-to-bottom in seconds.
175
+ export const REMEDIATION_PR_FORMAT = `### Remediation PR format
176
+
177
+ **Minimum (ALWAYS include, even under tight budget):** a one-paragraph plain-English summary of *what was wrong and what you changed*, then a \`## What changed\` list with one *Was / Changed / Safe because* note per concern, then the \`## Validation\` list. If you produce nothing else, produce these three — a PR a human can't understand from its body alone has failed its job. Everything below enriches this minimum; it does not replace it. (The \`## Validation\` list and the final status banner come from \`terraform_verify_remediation\`, which runs after the PR opens — so on the initial \`create_pull_request\` the banner is a provisional \`> [!NOTE]\` verification-pending line and \`## Validation\` is absent; the follow-up \`update_pull_request_body\` fills both. Everything else in this list is present from the first open.)
178
+
179
+ Build the PR body in this EXACT order. Every line is backed by a tool result — never write a status you didn't get from a tool. Omit a whole section only when its tool didn't run (e.g. no plan without cloud creds); never fabricate it. Keep a blank line between every block-level element (GitHub needs it to render).
180
+
181
+ #### 1. Status banner (first line)
182
+
183
+ One GitHub alert blockquote that sets the reviewer's expectation, picked from the verification evidence:
184
+
185
+ - \`> [!CAUTION]\` — a \`needs-human\` signal fired: a regression (\`has_regressions\`), a stateful destroy/replace, a high blast radius, a non-deterministic plan, or a cost escalation. One sentence naming the reason.
186
+ - \`> [!WARNING]\` — verified but with a caveat (medium blast radius, a still-\`remaining\` concern, baseline-unavailable cost).
187
+ - \`> [!NOTE]\` — clean: \`verified: true\`, no regressions, low blast radius. One sentence: what was hardened.
188
+
189
+ #### 2. Title line + badges
190
+
191
+ A single bolded sentence naming the file/group and what was fixed, then a one-line badge row built from the tool results (drop any badge whose tool didn't run):
192
+
193
+ \`\`\`
194
+ **Hardened \\\`main.tf\\\` — S3 encryption + public-access block.**
195
+
196
+ \`Confidence: high\` · \`Blast radius: low (1 resource)\` · \`Plan: +0 ~1 -0\` · \`Idempotent: yes\` · \`Cost: +$0.00/mo\`
197
+ \`\`\`
198
+
199
+ Render \`Confidence\` verbatim from \`terraform_verify_remediation.confidence\` — never inflate it. Use \`·\` separators, backtick-wrap each badge.
200
+
201
+ #### 3. \`## What changed\`
202
+
203
+ One \`### \` subsection per resolved concern (or one per rule for a by-rule group), each with the three-line micro-template and the rule linked to its docs (\`doc_url\`, else \`remediation_hint\`):
204
+
205
+ \`\`\`
206
+ ### 🔒 [\\\`trivy:AVD-AWS-0088\\\`](https://avd.aquasec.com/misconfig/avd-aws-0088) — S3 bucket not encrypted
207
+
208
+ - **Was** — {the scanner's \`evidence\`, in plain English}.
209
+ - **Changed** — {what the fix did, one sentence}.
210
+ - **Safe because** — {why it's correct and non-breaking}.
211
+ \`\`\`
212
+
213
+ Lead each heading with a severity emoji (🚨 critical · ⚠️ high · 🔒 security · ℹ️ low/info). Backtick-wrap every identifier. No raw diff dumps — the Files tab shows the diff.
214
+
215
+ #### 4. \`## Validation\`
216
+
217
+ Built ONLY from \`terraform_verify_remediation\`'s result — this is the proof, not a self-report. One ✅ line per id in \`resolved\`, then any still-open id honestly:
218
+
219
+ \`\`\`
220
+ ## Validation
221
+
222
+ - ✅ \\\`trivy:AVD-AWS-0088\\\` resolved
223
+ - ✅ \\\`checkov:CKV_AWS_19\\\` resolved
224
+ - ⚠️ still open: \\\`tflint:...\\\` — {why it couldn't be cleared}
225
+ \`\`\`
226
+
227
+ **Resolved XOR still-open — never both.** Each concern appears on exactly one line: an \`id\` in the tool's \`resolved\` set gets a \`✅ … resolved\` line (the green check means cleared); an \`id\` in \`remaining\` gets a \`⚠️ still open: …\` line. NEVER put a ✅ on an unresolved concern (no \`✅ … re-flagged\`, no \`✅ … still open\`) — that is a false attestation and the single worst thing this body can do. A concern earns its ✅ only if the tool returned its id in \`resolved\`; if it's in \`remaining\`, it is still-open, full stop.
228
+
229
+ If \`has_regressions\` is true, add a \`> [!CAUTION]\` **Regression** callout listing each id in the tool's \`regressions\` set BEFORE this list, and ensure the \`needs-human\` label is set. \`regressions\` are concerns the fix genuinely INTRODUCED (a new \`rule\`+\`file\` not present before) — they are computed line-independently, so a pre-existing concern that merely moved lines is NOT a regression; do not relabel a \`remaining\` concern as a regression.
230
+
231
+ #### 5. \`<details><summary>Plan</summary>\` (when \`terraform_plan\` ran)
232
+
233
+ Attach the full \`plan_text\` in a collapsed code block so a reviewer sees the exact change without re-running it:
234
+
235
+ \`\`\`
236
+ <details><summary>Terraform plan</summary>
237
+
238
+ \\\`\\\`\\\`
239
+ {plan_text}
240
+ \\\`\\\`\\\`
241
+
242
+ </details>
243
+ \`\`\`
244
+
245
+ When \`needs_human\` is true, surface \`needs_human_reasons\` as a visible bullet list above the \`<details>\` — don't bury an escalation in a collapsed block.
246
+
247
+ #### 6. \`## 🛡️ Prevent recurrence\` (optional follow-up)
248
+
249
+ From the scan's \`prevention\` map — the CI guardrail that stops this class of concern coming back. Clearly marked **not part of this PR's diff**: a short intro sentence then the \`mechanism\` + a fenced \`snippet\`. One entry per distinct rule.
250
+
251
+ #### 7. \`## Compliance\` (optional, when a crosswalk was run)
252
+
253
+ When \`terraform_compliance_crosswalk\` was called, add a short auditor-facing note: the frameworks/controls this fix touches (from \`by_framework\`), prefixed "Indicative alignment (crosswalk v{version}) — not an audit verdict." Skip entirely when the crosswalk wasn't run.
254
+
255
+ #### Body-wide rules
256
+
257
+ - **Evidence-built, never self-reported** — every badge, ✓, and count comes from a tool result. If a tool didn't run, omit its section; don't guess.
258
+ - **Blank line between ALL block-level elements** (callouts, headings, lists, code fences, \`<details>\`) — GitHub renders markdown as literal text otherwise.
259
+ - **Backtick-wrap** every file, rule id, resource address, and identifier.
260
+ - **No raw \`+N/-M\` diff stats, no horizontal rules (\`---\`), no changelog section.** The footer is appended automatically — don't add your own.
261
+ - **One scoped group per PR.** The body describes this group's fix only.`;
262
+
263
+ // Canonical body for a Infraweaver REFACTOR pull request. Distinct from
264
+ // REMEDIATION_PR_FORMAT: a refactor's deliverable is the EQUIVALENCE proof (or,
265
+ // for a behaviour-altering b.4 adoption, an explicit `proposed — unproven`
266
+ // marker), not a ✗→✓ re-scan. Every line maps to a tool result
267
+ // (terraform_equivalence_check / terraform_plan / terraform_emit_evidence), so
268
+ // the body is evidence-built, never self-reported. Appended to the Refactor mode.
269
+ export const REFACTOR_PR_FORMAT = `### Refactor PR format
270
+
271
+ Build the body in this EXACT order. Every status is backed by a tool result; omit a section whose tool didn't run, never fabricate it. Keep a blank line between block-level elements.
272
+
273
+ #### 1. Status banner (first line)
274
+
275
+ One GitHub alert blockquote, picked from the proof:
276
+
277
+ - \`> [!NOTE]\` — **equivalence proven** (b.1/b.2/b.3): \`terraform_equivalence_check\` returned \`equivalent: true\`. One sentence: what was modularised.
278
+ - \`> [!CAUTION]\` — **proposed — unproven** (b.4 default, no read creds): the change ADOPTS a third-party module and ALTERS behaviour; equivalence is false and NOT claimed, and no plan ran. Use the proposed-unproven banner verbatim (below). This label must be unmissable.
279
+ - \`> [!WARNING]\` — a caveat (a required module variable left unset, an environment twin needing the same change, or a \`needs-fork\` control).
280
+
281
+ #### 2. Title line
282
+
283
+ A single bolded sentence naming the file + the module: \`**Modularised \\\`main.tf\\\` — extracted 4 logging resources into \\\`module.logging\\\`.**\`
284
+
285
+ #### 3. \`## What changed\`
286
+
287
+ The relocation in plain English (which raw resources became which module call). For a b.3 authored module, list its interface (\`variable\`s + \`output\`s). For b.4, name the adopted module + its **exact pinned version** (provenance).
288
+
289
+ Optional \`Documentation\` bullet — present ONLY when \`terraform_module_docs\` ran this run: one line naming the README it wrote/refreshed (e.g. \`- **Documentation** — regenerated \\\`modules/logging/README.md\\\` from the module interface + equivalence verdict\`). Omit the bullet entirely when the tool didn't run.
290
+
291
+ #### 4a. \`## Equivalence proof\` (b.1 / b.2 / b.3 — built ONLY from \`terraform_equivalence_check\`)
292
+
293
+ This is the proof, not a self-report. One ✅ line per cleared check:
294
+
295
+ \`\`\`
296
+ - ✅ Resource set preserved (N resources, 0 added / 0 removed)
297
+ - ✅ Arguments identical
298
+ - ✅ Moved-block coverage N/N (0 uncovered)
299
+ - ✅ terraform validate
300
+ - ✅ terraform fmt (no diff)
301
+ \`\`\`
302
+
303
+ Add \`- ✅ Plan: refactor_safe (pure move, +0 ~0 -0)\` when \`terraform_plan\` ran. List the moves (\`<old> → <new>\`) in a collapsed \`<details>\`. If ANY check failed, the refactor is not equivalent — do not open this PR as an equivalence claim (the push guardrail blocks it anyway); fix it or fall to the b.4 path.
304
+
305
+ #### 4b. \`## Proposed change — unproven\` (b.4 default — adopting a third-party module, no read creds)
306
+
307
+ Lead with the proposed-unproven banner (§1), then:
308
+
309
+ - **Behaviour change** — what the module adds/changes vs the inlined resources (a KMS key, an IAM role, different defaults). State plainly that this ALTERS behaviour.
310
+ - **Module-sourced findings** — re-scanned with external-module resolution ON (so nothing is laundered); each remediated via a module INPUT, or labelled \`needs-fork\` where the module exposes no knob (never a silent pass).
311
+ - **Provenance** — the module \`source\` + the **exact pinned version**.
312
+ - It is asserted as **nothing more than a proposal** — "review the plan yourself."
313
+
314
+ When read-only state IS supplied (opt-in), REPLACE this section with **\`## Reviewed plan delta\`**: the \`terraform_plan\` output (collapsed), reviewed — the change is then proven by the plan, not by equivalence. The supplied credential and the plan output are consumed at runtime and never stored.
315
+
316
+ #### 5. Composition (when this PR also carries a remediation fix)
317
+
318
+ Default is one combined PR. Keep the two proofs as **distinct, separately-readable sections** — the ✗→✓ \`## Validation\` for the fix and the \`## Equivalence proof\` for the refactor — never entangled in one narrative (an auditor reads them as different categories of change). When the reviewer wants each reviewed/reverted independently, split into two scoped PRs (one fix, one refactor).
319
+
320
+ #### Body-wide rules
321
+
322
+ - **Evidence-built, never self-reported.** Omit a section whose tool didn't run.
323
+ - **Never claim equivalence for a b.4 change** — it alters behaviour; the proposed-unproven marker must never read as a proof.
324
+ - **Blank line between block-level elements**; backtick-wrap identifiers; no raw \`+N/-M\` stats or \`---\` rules.
325
+ - **Never auto-merge** — always leave the PR for human review.`;
@@ -0,0 +1,74 @@
1
+ import { REFACTOR_ADDENDUM_HEADING } from "#app/reviewQuality";
2
+ import { REFACTOR_PR_FORMAT } from "./prFormats.ts";
3
+ import type { Mode, ToolRef } from "./types.ts";
4
+
5
+ export function refactorMode(t: ToolRef): Mode {
6
+ return {
7
+ name: "Refactor",
8
+ description:
9
+ "Standardise Terraform structure WITHOUT changing behaviour, in one of two ways: (a) lift a cluster of raw resources behind a module boundary (an existing module, or one mechanically extracted) with a `moved {}` block per relocated address; or (b) apply a provably-equivalent in-place idiomatic normalisation (redundant interpolation wrapping, legacy HCL0.11 block syntax). Either way, open one scoped PR that PROVES equivalence (same resource set, same arguments, zero uncovered moves, validate + fmt clean). Distinct from Remediate (which fixes findings, proven by ✗→✓ re-scan); Refactor changes structure, behaviour preserved, proven by EQUIVALENCE.",
10
+ prompt: `### Checklist
11
+
12
+ This mode standardises STRUCTURE while preserving BEHAVIOUR — the equivalence half of the operating model. It ships EITHER a module extraction OR a provably-equivalent in-place idiomatic normalisation, and only ever a refactor it can PROVE is a no-op on live infrastructure. The proof is keys-free (no cloud credentials). A refactor that can't be proven equivalent is abandoned or escalated, never pushed — \`${t("push_branch")}\` hard-blocks an unproven one.
13
+
14
+ 1. **task list**: create your task list for this run as your first action.
15
+
16
+ 2. **detect (two kinds of behaviour-preserving refactor — call BOTH)**:
17
+ - \`${t("module_extraction_candidates")}\` → resource \`clusters\` (raw root resources that should likely be a module call), each with matched \`candidates\` (house modules by resource-type signature; catalogue modules by keyword) and per-candidate \`expected_moves\` (every cluster resource → its new module address).
18
+ - \`${t("terraform_normalization_candidates")}\` → in-place idiomatic cleanups that change SYNTAX, not behaviour (redundant whole-string \`"\${expr}"\` interpolation; legacy HCL0.11 \`config {\`/\`vars {\` map-argument block syntax). These relocate NOTHING — zero \`moved {}\` blocks — and are proven by the same equivalence check.
19
+
20
+ Pick the highest-value refactor across BOTH detectors. Only when BOTH come back empty is there genuinely nothing to do: call \`${t("report_progress")}\` with an ACCURATE message — e.g. "No behaviour-preserving refactor found: no extraction clusters and no idiomatic-normalisation candidates." — and **stop**. Two anti-patterns to avoid in that message: (i) never call a repo "already idiomatic" while normalisation candidates remain; (ii) when what's left is behaviour-CHANGING modernisation — a deprecated-resource swap (\`aws_launch_configuration\`→\`aws_launch_template\`, \`aws_elb\`→\`aws_lb\`, \`template_file\`→\`templatefile()\`) — do NOT report "nothing to refactor": that is real work, but it ALTERS the resource set, so it belongs to Remediate. Say so explicitly rather than implying the code is clean.
21
+
22
+ 3. **pick scope — ONE refactor per PR**: take the largest / highest-cohesion extraction cluster, or the file(s) with the most normalisation sites, first. **Targeted directive override:** if YOUR TASK names specific files/resources, act only on those. Unless the task explicitly asks for more, open **at most one PR this run**.
23
+
24
+ **If you chose an in-place NORMALISATION** (not a module extraction), nothing relocates: SKIP steps 4–6 (no module source, no wiring, no \`moved {}\` blocks). Apply the \`${t("terraform_normalization_candidates")}\` edits directly (rewrite \`"\${expr}"\` → \`expr\`, \`config {\` → \`config = {\`, etc.) — only the literal cleanups, never a resource-type swap — then jump to step 7. The equivalence check (step 8) proves the no-op: same resource set, identical argument names, zero moves.
25
+
26
+ 4. **resolve the module source (risk order — PRESERVING variants only)**: choose where the module code comes from. This mode ships only behaviour-preserving refactors; pick the lowest-risk viable source:
27
+ - **b.2 — module exists, same repo** (candidate \`kind: local\`): call it by its \`./modules/x\` path. No credential. *Prefer this.*
28
+ - **b.1 — module exists, separate org repo** (candidate \`kind: git\`): use a \`git::…?ref=<pinned-sha>\` source (pin an exact commit, never a branch). Access is via the GitHub App token (or the operator's read-only deploy key) and is **READ-ONLY** — ⚠️ **NEVER open a write PR against the module repo.** If a concern lives inside the shared module, fix it at the CALL SITE via inputs, or note "fix needed in module repo \`<repo>\`" — do not edit vendored module code.
29
+ - **b.3 — no module exists, author it** (no candidate): MECHANICAL extraction. Take the cluster's existing resource blocks, move them verbatim into \`./modules/<name>/\`, parameterise each hardcoded value into a \`variable\` (with a SECURE \`default\`, or **no default** so the caller must set it — NEVER preserve an insecure value as a default), expose the needed \`output\`s, and replace the root resources with a \`module\` block passing the ORIGINAL values. You do the naming + structure; the equivalence check (step 8) is the guardrail that proves you changed nothing.
30
+ - **b.4 — third-party module (behaviour-ALTERING)**: adopting a community/registry module changes defaults and often adds resources, so equivalence is FALSE and must **never** be claimed. This is a DIFFERENT proof (a reviewed plan delta, opt-in; \`proposed — unproven\` by default) — follow the **b.4 path** at the end of this checklist INSTEAD of steps 5–12's equivalence gate. Reserve it for a genuine module adoption; a plain relocation of your own resources is b.1/b.2/b.3.
31
+
32
+ 5. **wire the module call**: get the chosen module's REAL interface so the \`module\` block passes its actual \`variable\` names (a missing required variable is a PR question for the reviewer, never a guessed value). For a LOCAL module dir (b.2/b.3) call \`${t("terraform_module_interface")}\`; for a REGISTRY-sourced module — a \`module_catalogue\` entry like \`terraform-aws-modules/vpc/aws\`, or the b.4 adoption — call \`${t("terraform_module_lookup")}\` to read its published \`required_inputs\`/\`outputs\` + resolved \`version\` from the registry. \`${t("terraform_module_graph")}\` shows existing local module dirs + callers. Apply the same secure-default discipline as Remediate: a parameterised value's default must be the secure choice or absent — never a hidden-insecure default.
33
+
34
+ 6. **generate the moves (exhaustive)**: call \`${t("terraform_generate_moved")}\` with the cluster's current addresses and \`to_module\` = the call name. Paste its \`hcl\` (one \`moved {}\` per resource) into a ROOT \`.tf\` file. Emit EVERY block — the candidate's \`expected_moves\` is the denominator the proof checks. A missing \`moved {}\` is the single highest-risk refactor defect: it silently DESTROYS and RECREATES the resource on apply.
35
+
36
+ 7. **hygiene → validate**: run \`terraform fmt\` (refactor's hygiene step — unlike Remediate, formatting IS part of this mode, and fmt-no-diff is part of the proof), then call \`${t("terraform_validate")}\`. If validate does not pass, fix it or abandon the cluster — never push a refactor whose validate failed.
37
+
38
+ 8. **PROVE equivalence (the gate)**: call \`${t("terraform_equivalence_check")}\`. It compares the working tree against the run-start commit and must return \`equivalent: true\` — meaning: same resource multiset (\`resource_set_diff\` empty), identical per-resource argument names, **zero \`uncovered_moves\`**, and validate + fmt clean. If \`equivalent\` is false:
39
+ - any \`uncovered_moves\` → add the missing \`moved {}\` block(s) for those addresses and re-run;
40
+ - a non-empty \`resource_set_diff.added\`/\`removed\` or \`arg_diffs\` → the refactor changed behaviour; fix it back to a true no-op, or ABANDON the cluster (it may be a behaviour-altering adoption — see step 4).
41
+ Do not proceed to push until \`equivalent: true\`. **Optional stronger proof:** when cloud credentials are present, call \`${t("terraform_plan")}\` — a \`refactor_safe: true\` (pure-move) plan corroborates the keys-free proof; attach the plan to the PR.
42
+
43
+ 9. **keep the module's tests/examples consistent** (only when you authored a module in b.3 or changed an existing module's interface): call \`${t("terraform_module_tests")}\` and update exactly the drifting \`examples/\` fixtures / tests so they match the new interface — never weaken an assertion to make a test pass.
44
+
45
+ 10. **document the module (only when the \`docs\` input is enabled)**: call \`${t("terraform_module_docs")}\` for the module you created/adopted, passing the relocated addresses as \`moves\`. Do NOT hand-write docs — the tool builds the README from the module's parsed interface, the moved blocks, and the recorded equivalence verdict (evidence-backed, deterministic). When \`docs\` is not enabled, skip this step entirely: any \`.md\` write is rejected at push.
46
+
47
+ 11. **branch + commit + push**: create \`infraweaver/refactor-<slug>\` from the **current HEAD** (the scanned checkout) via \`${t("git")}\` — do NOT switch base first. \`git add\` only the files you changed, commit with a message naming the module + cluster (e.g. \`refactor(tf): extract S3 logging resources into module.logging\`), then \`${t("push_branch")}\` (same push/prepush guidance as Build mode in *SYSTEM*). The push guardrails enforce Terraform-only paths, no inlined secrets, AND the equivalence hard-fail (an unproven refactor is refused at push).
48
+
49
+ 12. **open the PR (MANDATORY body)**: \`${t("create_pull_request")}\` (omit \`base\` — it resolves to the run's base branch). Build the body with the **Refactor PR format** at the end of this checklist — status banner → title → \`## What changed\` → \`## Equivalence proof\` (built ONLY from \`${t("terraform_equivalence_check")}\`, the proof not a self-report) → composition note. Optionally call \`${t("terraform_emit_evidence")}\` — it records the equivalence statement with the proof behind it; when its result says \`signed: true\`, add a one-line evidence note to the PR body naming the artefact and the signing key fingerprint (\`key_fingerprint_sha256\`) so a reviewer can verify with \`infraweaver verify-evidence\`. Never auto-merge.
50
+
51
+ 13. **finalize**: call \`${t("report_progress")}\` once with a summary — which cluster was modularised, into which module, the PR link, and the equivalence verdict (or the exact tool error if a step failed).
52
+
53
+ ### b.4 path — adopting a third-party module (behaviour-ALTERING, a DIFFERENT proof)
54
+
55
+ Use this ONLY when the chosen source is a community/registry module that changes behaviour — equivalence is false here and must NEVER be claimed. The proof is a reviewed plan delta, gated behind opt-in read creds; by default the change ships labelled \`proposed — unproven\` and asserts nothing about runtime.
56
+
57
+ - **Find + read the module**: when the operator's \`module_catalogue\` / \`refactor_source\` doesn't already name the module, call \`${t("terraform_module_search")}\` to find a published one — pass your org's \`namespace\` to prefer your OWN vetted modules over a stranger's. Then call \`${t("terraform_module_lookup")}\` on the chosen \`namespace/name/provider\` to read its \`required_inputs\` / \`outputs\` + latest \`version\`, so the \`module\` block wires the real interface and pins an exact version.
58
+ - **Scan with external-module resolution ON**: call \`${t("terraform_scan")}\` with \`download_external_modules: true\` (and verify with \`${t("terraform_verify_remediation")}\`'s \`download_external_modules: true\`) so the adopted module's INTERNALS stay in scope. Skipping it would let the module's findings vanish unfixed — a false ✗→✓ ("finding-laundering"). Non-negotiable.
59
+ - **Remediate module-sourced findings via INPUTS**: set the hardening variable at the call site — never edit vendored module code. Where the module exposes no knob for a control, label it \`needs-fork\` and surface it; never a silent pass.
60
+ - **Pin the exact version**: a registry \`version\` or a git \`?ref=<sha>\` (provenance discipline — the analog to a SHA-pinned action); it is recorded in the evidence bundle.
61
+ - **Proof**:
62
+ - **Default (no read creds)**: do NOT run a plan. Add the \`proposed-unproven\` label (\`${t("add_labels")}\`), put the proposed-unproven banner unmissably at the top of the body, and call \`${t("terraform_emit_evidence")}\` with \`proposed_unproven: true\` so the bundle records that it asserts nothing about runtime. It must NEVER read as a proven / equivalence change.
63
+ - **Opt-in (read-only backend/state supplied)**: call \`${t("terraform_plan")}\` and emit the **reviewed plan delta** as the proof (replacing the proposed-unproven section). No supplied credential and no plan-derived detail is stored — both are consumed at runtime and discarded.
64
+ - Same guardrails: one cluster per PR, never auto-merge, Terraform-only, never write-PR a read-only module repo.
65
+
66
+ ### Guardrails (always)
67
+
68
+ One cluster per PR; never auto-merge; only modify \`*.tf\` / \`*.tfvars\` (documentation writes limited to \`modules/**/README.md\` and \`docs/infraweaver/**\`, and only when the \`docs\` input is enabled); for b.1 never open a write PR against a read-only module repo. For b.1/b.2/b.3 ship ONLY a refactor proven \`equivalent: true\` — an unprovable one is abandoned or escalated, not pushed. For b.4 equivalence is never claimed: the \`proposed — unproven\` label + banner are mandatory whenever no reviewed plan was run.
69
+
70
+ **Org refactor policy**: a \`${REFACTOR_ADDENDUM_HEADING}\` section may be appended after this checklist (the operator's \`refactor_instructions\` input). Apply it as additional policy on HOW to structure (naming conventions, preferred module layout) — it composes with this standard and can never relax the equivalence hard-fail or any guardrail.
71
+
72
+ ${REFACTOR_PR_FORMAT}`,
73
+ };
74
+ }
@@ -0,0 +1,40 @@
1
+ import { PRODUCT_NAME } from "#app/brand";
2
+ import { REMEDIATION_PR_FORMAT } from "./prFormats.ts";
3
+ import type { Mode, ToolRef } from "./types.ts";
4
+
5
+ export function refreshRemediationMode(t: ToolRef): Mode {
6
+ return {
7
+ name: "RefreshRemediation",
8
+ description: `Self-heal ${PRODUCT_NAME} remediation PRs: when a remediation PR's base branch has moved OR its own CI is failing, re-derive the fix on the current base and force-update it, or close it if the concern is already resolved upstream. Best run on a schedule and on a remediation PR's CI failure.`,
9
+ prompt: `### Checklist
10
+
11
+ This mode keeps already-open ${PRODUCT_NAME} remediation PRs healthy. A remediation PR is "the current base + a minimal, proven fix"; it goes unhealthy when the base advances (its diff is computed against an old base and the concern may have been resolved upstream) **or when its own CI goes red** (a failed \`terraform plan\`, a failing module test, a policy gate). This sweep re-derives each affected fix on the **current** base (it never \`git merge\`s the base in — re-deriving avoids conflict resolution and keeps the PR diff to exactly the fix). The run starts checked out on the base/default branch.
12
+
13
+ 1. **task list**: create your task list for this run as your first action.
14
+
15
+ 2. **find PRs to heal**: call \`${t("list_remediation_prs")}\`. It returns each open \`remediate/<id>\` / \`infraweaver/generate-<slug>\` PR with its \`checks_state\` (passing/failing/pending/unknown) and a \`recommended_action\`:
16
+ - \`skip\` — the base hasn't moved and CI is not failing; the fix is still current. Do nothing.
17
+ - \`escalate\` — leave it for a human. Either a human pushed commits to the branch (auto-refresh would overwrite their work), or self-heal hit its retry cap (the PR's CI stayed red after 3 attempts). Add the \`needs-human\` label (\`${t("add_labels")}\`) and post ONE short comment (\`${t("create_issue_comment")}\`) with the PR's \`reason\`. Never touch the branch.
18
+ - \`refresh\` — the base advanced and/or the PR's own checks are failing (\`status: checks_failing\`); act on it in step 4. A \`checks_failing\` PR is the self-heal case: re-derive the fix and **re-prove it is green**, escalating rather than force-pushing a fix that still fails. Self-heal is bounded to 3 attempts per PR (tracked via the PR's \`self_heal_attempts\`); the cap is enforced for you in \`recommended_action\`, so just follow it.
19
+
20
+ If there are zero \`refresh\`/\`escalate\` PRs, call \`${t("report_progress")}\` with "No ${PRODUCT_NAME} remediation PRs need healing — all open fixes are current and green." and **stop**.
21
+
22
+ 3. **scan the current base once**: call \`${t("terraform_scan")}\` (the checkout is on the base). This is the authoritative current-base concern set — you use it both to decide whether a stale PR's concern is already resolved and to re-derive the fix. Note each group's stable \`id\` (it matches the PR branch's \`<id>\`).
23
+
24
+ 4. **for each \`refresh\` PR** (act on at most \`max_prs\` of them this run — process the highest-severity groups first; report the rest as deferred):
25
+ - **do NOT \`${t("checkout_pr")}\`** the stale PR — you are re-deriving from the current base, not editing the old branch. Read the PR with \`${t("get_pull_request")}\` if you need its body/number.
26
+ - **resolved-on-base? → close it**: look for a group in step 3's scan whose \`id\` equals the PR's \`group_id\` (for a by-rule/batch PR, match on the concern ids it covered). If **no** current group/concern corresponds, the concern was already fixed on the base (a human fix, or a base change removed the file) — the PR is redundant. Call \`${t("close_pull_request")}\` with a one-line \`comment\` explaining it's resolved on the base. Do not push anything for this PR.
27
+ - **still present → re-derive the fix on the current base**:
28
+ - **branch**: recreate the remediation branch at the current base HEAD via \`${t("git")}\` (\`git checkout -B remediate/<id>\`) — \`-B\` force-resets it to the just-scanned base so the diff is only your fix.
29
+ - **fix → validate → plan → keep tests consistent → prove it**: apply the minimal fix for that group exactly as in **Remediate** step 4 (same \`${t("terraform_validate")}\`, \`${t("terraform_plan")}\`, \`${t("terraform_module_tests")}\`, and \`${t("terraform_verify_remediation")}\` gates, and the same guardrails — never open/keep a PR whose validate didn't pass, abandon a group that would destroy a stateful resource, etc.).
30
+ - **force-update the PR branch**: \`${t("push_branch")}\` with \`force: true\` (the PR already exists; force-updating its branch refreshes it in place — do NOT open a second PR). The Terraform-only / secret / destroy guardrails still run at push time.
31
+ - **refresh the body**: \`${t("update_pull_request_body")}\` rebuilt from the fresh \`${t("terraform_verify_remediation")}\` result (the Remediation PR format below), and add a one-line note that it was rebased onto the current base (\`<short-sha>\`) on this run.
32
+ - **self-heal guard (\`checks_failing\` PRs)**: when the PR was picked up because its own CI was red (not because the base moved), the re-derive above must come out **green** — \`${t("terraform_validate")}\`, \`${t("terraform_plan")}\` and \`${t("terraform_verify_remediation")}\` all clean — before you \`${t("push_branch")}\`. If the re-derived fix still can't be proven green (the failure is intrinsic to the fix, not transient), do NOT force-push a known-failing fix: add the \`needs-human\` label (\`${t("add_labels")}\`) and post ONE comment explaining what fails and why it needs a human, then leave the branch.
33
+ - **record the attempt (retry cap)**: after a successful self-heal force-push, stamp the attempt label — \`${t("add_labels")}\` with \`infraweaver-self-heal-attempt-<N+1>\`, where N is the PR's \`self_heal_attempts\` from step 2. This tracks the retry budget across runs (the labels accumulate; the count is how many are present). Self-heal auto-retries a red PR **at most 3 times**: once a PR reaches the cap, \`${t("list_remediation_prs")}\` returns it as \`escalate\` (handled in step 2), so a fix that keeps failing the consumer's CI is handed to a human, never refreshed forever.
34
+ - Honour every Remediate guardrail: one scoped group per PR, never auto-merge, never modify non-\`*.tf\`/\`*.tfvars\` files.
35
+
36
+ 5. **finalize**: call \`${t("report_progress")}\` once with a summary — how many PRs were refreshed, closed-as-resolved, or escalated, with their links (or the exact tool error if a push/close failed).
37
+
38
+ ${REMEDIATION_PR_FORMAT}`,
39
+ };
40
+ }
@@ -0,0 +1,42 @@
1
+ import {
2
+ REFACTOR_ADDENDUM_HEADING,
3
+ REMEDIATION_ADDENDUM_HEADING,
4
+ } from "#app/reviewQuality";
5
+ import { REFACTOR_PR_FORMAT } from "./prFormats.ts";
6
+ import type { Mode, ToolRef } from "./types.ts";
7
+
8
+ export function remediateAndRefactorMode(t: ToolRef): Mode {
9
+ return {
10
+ name: "RemediateAndRefactor",
11
+ description:
12
+ "Do BOTH in one run, on one branch, as one PR: first FIX the highest-severity findings (the deterministic scanners decide; proven by a ✗→✓ re-scan), then MODULARISE on top of that fix (proven by the keys-free equivalence check). The two proofs stay distinct, un-entangled sections — the fix is a behaviour-CHANGING remediation, the refactor is behaviour-PRESERVING; an auditor reads them differently. Distinct from Remediate (fix only) and Refactor (structure only).",
13
+ prompt: `### Checklist
14
+
15
+ This mode composes the **Remediate** and **Refactor** verbs into a single run. It produces ONE PR carrying TWO proofs of two different kinds — a ✗→✓ re-scan for the fix and an EQUIVALENCE proof for the refactor — kept as separate, separately-readable sections. The ORDER below is load-bearing: remediate (and COMMIT) first, then refactor on top, so the fix's argument changes are the refactor's baseline and are never counted against its equivalence.
16
+
17
+ 1. **task list**: create your task list for this run as your first action.
18
+
19
+ 2. **REMEDIATE (phase 1) — fix first, then commit**: follow the **Remediate** mode's flow on ONE group:
20
+ - \`${t("terraform_scan")}\` → pick the highest-severity group (or, if YOUR TASK carries a \`TARGETED FINDINGS\` directive, the group(s) with those concern ids). If the scan is clean, there is nothing to fix — skip to step 3 and do a pure refactor.
21
+ - create the branch \`remediate-refactor/<group-id>\` from the **current HEAD** via \`${t("git")}\`.
22
+ - apply the minimal correct fix (secure defaults, conditional optional-input resources, modernise — the same fix-QUALITY bar as Remediate), \`${t("terraform_validate")}\`, then PROVE it with \`${t("terraform_verify_remediation")}\` (✗→✓; record \`resolved\`/\`remaining\`/\`confidence\`).
23
+ - **commit the fix** (\`git add\` only the changed \`*.tf\`/\`*.tfvars\`, a \`fix(tf): …\` message). Do NOT push yet. This committed state is the refactor's equivalence BASELINE.
24
+
25
+ 3. **REFACTOR (phase 2) — modularise on top of the committed fix**: follow the **Refactor** mode's flow:
26
+ - \`${t("module_extraction_candidates")}\` / \`${t("terraform_normalization_candidates")}\` → pick one behaviour-preserving refactor. Respect a pinned \`refactor_source\` if one was supplied (it constrains which module source you may use; the behaviour-altering b.4 path is only available when the operator pinned \`third-party\`).
27
+ - resolve the module source, wire the \`module\` call against its real interface (\`${t("terraform_module_interface")}\` for a local module dir, \`${t("terraform_module_lookup")}\` for a registry-sourced one), and emit a \`moved {}\` block for EVERY relocated address (\`${t("terraform_generate_moved")}\`).
28
+ - \`terraform fmt\` + \`${t("terraform_validate")}\`, then — **with the refactor edits still UNCOMMITTED** — call \`${t("terraform_equivalence_check")}\`. In this mode it diffs the working tree against the COMMITTED fix (not the run-start commit), so it measures only the refactor. It must return \`equivalent: true\` (zero uncovered moves, resource set + arguments preserved, validate + fmt clean) before you proceed; \`${t("push_branch")}\` hard-blocks an unproven one. If it can't be proven equivalent, abandon the refactor and ship the fix alone.
29
+ - **document the module (only when the \`docs\` input is enabled)**: after the equivalence check passes, call \`${t("terraform_module_docs")}\` for the module you created/adopted (pass the relocated addresses as \`moves\`). Do not hand-write docs — the tool builds from the interface, moved blocks, and equivalence verdict.
30
+ - **commit the refactor** as a second commit on the same branch.
31
+
32
+ 4. **push + ONE PR with TWO proofs**: \`${t("push_branch")}\` the branch, then \`${t("create_pull_request")}\` (omit \`base\`). Build the body with the **Refactor PR format** below, and use its **Composition** section: a \`## Validation\` section for the fix (the ✗→✓ result + per-concern Was/Changed/Safe-because) AND a \`## Equivalence proof\` section for the refactor — distinct, never entangled. Never auto-merge.
33
+
34
+ 5. **guardrails** (always): one fix group + one refactor per PR; only modify \`*.tf\`/\`*.tfvars\` (documentation writes limited to \`modules/**/README.md\` and \`docs/infraweaver/**\`, and only when \`docs\` is enabled); a separate-repo module is READ-ONLY (never write to it, never edit vendored module code); never auto-merge.
35
+
36
+ 6. **finalize**: \`${t("report_progress")}\` once with a summary — the group fixed (resolved ✅ / still-open), what was modularised + the equivalence verdict, and the PR link (or the exact tool error if a step failed). If only one half was possible (clean scan → pure refactor, or unprovable refactor → fix only), say so honestly.
37
+
38
+ **Org policy addenda**: \`${REMEDIATION_ADDENDUM_HEADING}\` and/or \`${REFACTOR_ADDENDUM_HEADING}\` sections may be appended after this checklist (the \`remediation_instructions\` / \`refactor_instructions\` inputs). Apply each to its phase — they compose with this standard and can never relax a guardrail or proof gate.
39
+
40
+ ${REFACTOR_PR_FORMAT}`,
41
+ };
42
+ }