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,317 @@
1
+ /**
2
+ * Registry module intelligence — look up a PUBLISHED module's interface and
3
+ * search the public registry for modules to reuse.
4
+ *
5
+ * Complements `./currency.ts` (which answers "is a newer VERSION available?"):
6
+ * this answers "what does this module EXPECT and EXPOSE?" (root inputs/outputs)
7
+ * and "what published modules exist for this need?". It exists so the agent can
8
+ * wire a `module {}` block against a real, published interface — an organisation's
9
+ * own published modules included — instead of guessing variable names.
10
+ *
11
+ * Read-only, public default registry only (private/TFE hosts are rejected, same
12
+ * scope as the currency check), and degrades green on every failure.
13
+ */
14
+
15
+ import {
16
+ DEFAULT_REGISTRY_BASE_URL,
17
+ fetchRegistryJson,
18
+ isRecord,
19
+ type LookupStatus,
20
+ } from "#app/mcp/terraform/currency";
21
+
22
+ const SEARCH_LIMIT_DEFAULT = 10;
23
+ const SEARCH_LIMIT_MAX = 25;
24
+
25
+ function asString(value: unknown): string | null {
26
+ return typeof value === "string" ? value : null;
27
+ }
28
+
29
+ function asNumber(value: unknown): number | null {
30
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
31
+ }
32
+
33
+ // --- module detail (interface lookup) ---------------------------------------
34
+
35
+ export interface ModuleInput {
36
+ name: string;
37
+ type: string | null;
38
+ description: string | null;
39
+ default: string | null;
40
+ required: boolean;
41
+ }
42
+
43
+ export interface ModuleOutput {
44
+ name: string;
45
+ description: string | null;
46
+ }
47
+
48
+ export interface ModuleDetail {
49
+ source: string;
50
+ version: string | null;
51
+ description: string | null;
52
+ verified: boolean;
53
+ downloads: number | null;
54
+ published_at: string | null;
55
+ provider_dependencies: string[];
56
+ inputs: ModuleInput[];
57
+ outputs: ModuleOutput[];
58
+ }
59
+
60
+ function parseInputs(root: unknown): ModuleInput[] {
61
+ if (!isRecord(root) || !Array.isArray(root.inputs)) return [];
62
+ const out: ModuleInput[] = [];
63
+ for (const raw of root.inputs) {
64
+ if (!isRecord(raw) || typeof raw.name !== "string") continue;
65
+ const fallback = asString(raw.default);
66
+ out.push({
67
+ name: raw.name,
68
+ type: asString(raw.type),
69
+ description: asString(raw.description),
70
+ default: fallback,
71
+ // the registry sometimes carries an explicit `required` boolean; when it
72
+ // doesn't, a variable with no default is required.
73
+ required: typeof raw.required === "boolean" ? raw.required : fallback === null,
74
+ });
75
+ }
76
+ return out;
77
+ }
78
+
79
+ function parseOutputs(root: unknown): ModuleOutput[] {
80
+ if (!isRecord(root) || !Array.isArray(root.outputs)) return [];
81
+ const out: ModuleOutput[] = [];
82
+ for (const raw of root.outputs) {
83
+ if (!isRecord(raw) || typeof raw.name !== "string") continue;
84
+ out.push({ name: raw.name, description: asString(raw.description) });
85
+ }
86
+ return out;
87
+ }
88
+
89
+ function parseProviderDependencies(root: unknown): string[] {
90
+ if (!isRecord(root) || !Array.isArray(root.provider_dependencies)) return [];
91
+ const out: string[] = [];
92
+ for (const raw of root.provider_dependencies) {
93
+ if (!isRecord(raw)) continue;
94
+ const name = asString(raw.name);
95
+ if (name === null) continue;
96
+ const namespace = asString(raw.namespace);
97
+ out.push(namespace ? `${namespace}/${name}` : name);
98
+ }
99
+ return out;
100
+ }
101
+
102
+ function parseModuleDetail(body: unknown): ModuleDetail | null {
103
+ if (!isRecord(body)) return null;
104
+ const source = asString(body.source) ?? asString(body.id);
105
+ if (source === null) return null;
106
+ const root = body.root;
107
+ return {
108
+ source,
109
+ version: asString(body.version),
110
+ description: asString(body.description),
111
+ verified: body.verified === true,
112
+ downloads: asNumber(body.downloads),
113
+ published_at: asString(body.published_at),
114
+ provider_dependencies: parseProviderDependencies(root),
115
+ inputs: parseInputs(root),
116
+ outputs: parseOutputs(root),
117
+ };
118
+ }
119
+
120
+ // --- registry resolution (public vs private host) ---------------------------
121
+
122
+ /** the default public registry host — a bare `namespace/name/provider` (or a
123
+ * `registry.terraform.io/`-prefixed source) resolves here with no auth. */
124
+ export const PUBLIC_REGISTRY_HOST = "registry.terraform.io";
125
+
126
+ /** a module lookup's outcome: the shared `LookupStatus` plus two private-registry
127
+ * policy outcomes the tool surfaces with their own message. */
128
+ export type ModuleLookupStatus = LookupStatus | "host_not_allowed" | "auth_required";
129
+
130
+ /**
131
+ * Split a module source into its optional registry `host` and the
132
+ * `namespace/name/provider` path. A host-prefixed source
133
+ * (`app.terraform.io/acme/vpc/aws`) targets a PRIVATE registry; a bare
134
+ * `namespace/name/provider` targets the public default registry (host === null).
135
+ * `path` is null when the source isn't a valid module address (the detected host,
136
+ * if any, is still returned for the caller's error message).
137
+ */
138
+ export function splitModuleAddress(source: string): { host: string | null; path: string | null } {
139
+ const segments = source.split("/").filter(Boolean);
140
+ const first = segments[0];
141
+ const host = first?.includes(".") ? first.toLowerCase() : null;
142
+ if (segments.length === 4 && host !== null) {
143
+ return { host, path: segments.slice(1).join("/") };
144
+ }
145
+ if (segments.length === 3) return { host: null, path: segments.join("/") };
146
+ return { host, path: null };
147
+ }
148
+
149
+ export interface PrivateRegistryAuth {
150
+ /** the host(s) `token` authorises — a private source's host must be one of them.
151
+ * This is the security boundary: the agent names the source, but we only ever
152
+ * send the token to a host the operator allow-listed via `registry_host`. */
153
+ allowedHosts: string[];
154
+ /** the bearer token, or undefined when the run supplied no `registry_token`. */
155
+ token: string | undefined;
156
+ }
157
+
158
+ /** discovered `modules.v1` API base per private host (a run hits the same registry
159
+ * repeatedly). Successful resolutions only — a transient failure must not poison
160
+ * the run. Cleared between tests via `_clearModuleDiscoveryCache`. */
161
+ const discoveryCache = new Map<string, string>();
162
+
163
+ /** test seam: drop the per-host discovery cache. */
164
+ export function _clearModuleDiscoveryCache(): void {
165
+ discoveryCache.clear();
166
+ }
167
+
168
+ /**
169
+ * Resolve a private registry's module API base via the standard service-discovery
170
+ * document (`GET https://<host>/.well-known/terraform.json` → its `modules.v1`
171
+ * entry). This is how Terraform itself finds the API, so it works for HCP Terraform,
172
+ * Terraform Enterprise, and any protocol-compliant registry regardless of the path
173
+ * they mount it at. Returns null when discovery fails or the host advertises no
174
+ * module API.
175
+ */
176
+ async function discoverModulesV1Base(host: string, token: string): Promise<string | null> {
177
+ const cached = discoveryCache.get(host);
178
+ if (cached !== undefined) return cached;
179
+ const { status, body } = await fetchRegistryJson(`https://${host}/.well-known/terraform.json`, {
180
+ Authorization: `Bearer ${token}`,
181
+ });
182
+ if (status !== "ok" || !isRecord(body) || typeof body["modules.v1"] !== "string") return null;
183
+ const modulesPath = body["modules.v1"].replace(/\/$/, "");
184
+ const base = modulesPath.startsWith("http") ? modulesPath : `https://${host}${modulesPath}`;
185
+ discoveryCache.set(host, base);
186
+ return base;
187
+ }
188
+
189
+ /** fetch + parse a module's detail from an already-resolved API base
190
+ * (`…/v1/modules` for the public registry, the discovered `modules.v1` for a
191
+ * private one). `token`, when present, authenticates the private call. */
192
+ async function fetchModuleDetailFrom(
193
+ base: string,
194
+ path: string,
195
+ opts: { version?: string | undefined; token?: string | undefined },
196
+ ): Promise<{ status: LookupStatus; module: ModuleDetail | null }> {
197
+ const suffix = opts.version ? `/${encodeURIComponent(opts.version)}` : "";
198
+ const headers = opts.token ? { Authorization: `Bearer ${opts.token}` } : undefined;
199
+ const { status, body } = await fetchRegistryJson(`${base}/${path}${suffix}`, headers);
200
+ if (status !== "ok") return { status, module: null };
201
+ const module = parseModuleDetail(body);
202
+ if (module === null) return { status: "error", module: null };
203
+ return { status: "ok", module };
204
+ }
205
+
206
+ /**
207
+ * Look up a published module's interface. A bare `namespace/name/provider` hits
208
+ * the public default registry (no auth). A host-prefixed `host/namespace/name/
209
+ * provider` targets a PRIVATE registry (HCP Terraform / Terraform Enterprise / any
210
+ * protocol-compliant registry): the host must be in `auth.allowedHosts` AND a token
211
+ * supplied, then the API base is resolved via service discovery and the detail
212
+ * fetched with `Authorization: Bearer …`. Pass `version` to pin the lookup; omit it
213
+ * for the latest.
214
+ */
215
+ export async function fetchModuleDetail(
216
+ source: string,
217
+ opts: {
218
+ version?: string | undefined;
219
+ auth?: PrivateRegistryAuth | undefined;
220
+ /** public-base override (tests). */
221
+ baseUrl?: string;
222
+ } = {},
223
+ ): Promise<{ status: ModuleLookupStatus; module: ModuleDetail | null }> {
224
+ const { host, path } = splitModuleAddress(source);
225
+ if (path === null) return { status: "unsupported_source", module: null };
226
+
227
+ // public default registry — no auth.
228
+ if (host === null || host === PUBLIC_REGISTRY_HOST) {
229
+ const base = `${opts.baseUrl ?? DEFAULT_REGISTRY_BASE_URL}/v1/modules`;
230
+ return fetchModuleDetailFrom(base, path, { version: opts.version });
231
+ }
232
+
233
+ // private registry — the host must be operator-authorised AND a token supplied.
234
+ if (!opts.auth?.allowedHosts.includes(host)) {
235
+ return { status: "host_not_allowed", module: null };
236
+ }
237
+ if (!opts.auth.token) return { status: "auth_required", module: null };
238
+ const modulesBase = await discoverModulesV1Base(host, opts.auth.token);
239
+ if (modulesBase === null) return { status: "error", module: null };
240
+ return fetchModuleDetailFrom(modulesBase, path, {
241
+ version: opts.version,
242
+ token: opts.auth.token,
243
+ });
244
+ }
245
+
246
+ // --- module search (discovery) ----------------------------------------------
247
+
248
+ export interface ModuleSearchResult {
249
+ address: string;
250
+ version: string | null;
251
+ description: string | null;
252
+ downloads: number | null;
253
+ verified: boolean;
254
+ }
255
+
256
+ export interface ModuleSearchQuery {
257
+ query: string;
258
+ namespace?: string | undefined;
259
+ provider?: string | undefined;
260
+ verified?: boolean | undefined;
261
+ limit?: number | undefined;
262
+ }
263
+
264
+ /** build the `namespace/name/provider` address callers feed back into
265
+ * fetchModuleDetail, falling back to the raw (version-suffixed) id. */
266
+ function searchResultAddress(raw: Record<string, unknown>): string | null {
267
+ const namespace = asString(raw.namespace);
268
+ const name = asString(raw.name);
269
+ const provider = asString(raw.provider);
270
+ if (namespace && name && provider) return `${namespace}/${name}/${provider}`;
271
+ return asString(raw.id);
272
+ }
273
+
274
+ function parseSearchResults(body: unknown): ModuleSearchResult[] | null {
275
+ if (!isRecord(body) || !Array.isArray(body.modules)) return null;
276
+ const out: ModuleSearchResult[] = [];
277
+ for (const raw of body.modules) {
278
+ if (!isRecord(raw)) continue;
279
+ const address = searchResultAddress(raw);
280
+ if (address === null) continue;
281
+ out.push({
282
+ address,
283
+ version: asString(raw.version),
284
+ description: asString(raw.description),
285
+ downloads: asNumber(raw.downloads),
286
+ verified: raw.verified === true,
287
+ });
288
+ }
289
+ return out;
290
+ }
291
+
292
+ /**
293
+ * GET /v1/modules/search — discover published modules (the organisation's own
294
+ * namespace included) to REUSE instead of writing raw resources. Public default
295
+ * registry only. `limit` is clamped to a small range to keep the result tight.
296
+ */
297
+ export async function searchRegistryModules(
298
+ params: ModuleSearchQuery,
299
+ opts: { baseUrl?: string } = {},
300
+ ): Promise<{ status: LookupStatus; modules: ModuleSearchResult[]; limit: number }> {
301
+ const base = opts.baseUrl ?? DEFAULT_REGISTRY_BASE_URL;
302
+ const limit = Math.min(
303
+ Math.max(1, Math.trunc(params.limit ?? SEARCH_LIMIT_DEFAULT)),
304
+ SEARCH_LIMIT_MAX,
305
+ );
306
+ const url = new URL(`${base}/v1/modules/search`);
307
+ url.searchParams.set("q", params.query);
308
+ url.searchParams.set("limit", String(limit));
309
+ if (params.namespace) url.searchParams.set("namespace", params.namespace);
310
+ if (params.provider) url.searchParams.set("provider", params.provider);
311
+ if (params.verified) url.searchParams.set("verified", "true");
312
+ const { status, body } = await fetchRegistryJson(url.toString());
313
+ if (status !== "ok") return { status, modules: [], limit };
314
+ const modules = parseSearchResults(body);
315
+ if (modules === null) return { status: "error", modules: [], limit };
316
+ return { status: "ok", modules, limit };
317
+ }
@@ -0,0 +1,99 @@
1
+ import { classifyRefusal } from "#app/mcp/terraform/decisions";
2
+ import {
3
+ applyNoisePenalty,
4
+ EMPTY_NOISE_PROFILE,
5
+ explainNoiseAdjustment,
6
+ type NoiseAdjustment,
7
+ type NoiseProfile,
8
+ noiseAdjustmentFor,
9
+ } from "#app/mcp/terraform/noiseProfile";
10
+ import { type Concern, cvssScoreForSeverity } from "#app/mcp/terraform/types";
11
+
12
+ const EXPOSURE_SIGNAL =
13
+ /(0\.0\.0\.0\/0|::\/0|\bpublic(ly)?\b|\binternet\b|\bingress\b|\bunrestricted\b|world[-\s]?readable|\banonymous\b|\bexposed?\b)/i;
14
+
15
+ export interface RiskFactors {
16
+ severity: number;
17
+ exposure: number;
18
+ fixability: number;
19
+ /** G7: the fleet-noise down-rank applied, as a NEGATIVE contribution. Present
20
+ * only when one applied, so a reader can always reconstruct the score from
21
+ * its parts and see that nothing was adjusted invisibly. */
22
+ noise?: number;
23
+ }
24
+
25
+ export interface RiskScore {
26
+ score: number;
27
+ factors: RiskFactors;
28
+ /** the dismissal history behind `factors.noise`, when there is one. */
29
+ noise?: NoiseAdjustment;
30
+ }
31
+
32
+ /**
33
+ * Score a concern for SURFACING order.
34
+ *
35
+ * `profile` is the org's fleet-wide dismissal record (G7). It can only ever
36
+ * lower a score, is bounded and floored, and never applies to critical/high —
37
+ * see `noiseProfile.ts` for why a ranking model in an evidence product is
38
+ * allowed to reorder and nothing else. Defaults to empty, so every existing
39
+ * caller keeps the exact scores it had.
40
+ */
41
+ export function scoreConcern(concern: Concern, profile: NoiseProfile = EMPTY_NOISE_PROFILE): RiskScore {
42
+ const severity = cvssScoreForSeverity(concern.severity);
43
+ const exposed = EXPOSURE_SIGNAL.test(`${concern.rule_id} ${concern.evidence}`);
44
+ const exposure = concern.category === "security" && exposed ? 1.5 : 0;
45
+ const fixability = classifyRefusal(concern).refuse ? 0 : 0.5;
46
+ const raw = severity + exposure + fixability;
47
+ const base = Math.min(10, Math.round(raw * 10) / 10);
48
+
49
+ const adjustment = noiseAdjustmentFor(concern, profile);
50
+ if (!adjustment) return { score: base, factors: { severity, exposure, fixability } };
51
+ const score = applyNoisePenalty(base, adjustment);
52
+ return {
53
+ score,
54
+ // report the penalty ACTUALLY applied (the floor may have absorbed part of
55
+ // it), so `severity + exposure + fixability + noise` reconstructs `score`.
56
+ factors: { severity, exposure, fixability, noise: Math.round((score - base) * 10) / 10 },
57
+ noise: adjustment,
58
+ };
59
+ }
60
+
61
+ export function riskScore(concern: Concern, profile: NoiseProfile = EMPTY_NOISE_PROFILE): number {
62
+ return scoreConcern(concern, profile).score;
63
+ }
64
+
65
+ export interface RankedConcern {
66
+ concern_id: string;
67
+ rule_id: string;
68
+ severity: Concern["severity"];
69
+ category: Concern["category"];
70
+ location: Concern["location"];
71
+ risk_score: number;
72
+ risk_factors: RiskFactors;
73
+ /** G7: why this was ranked lower, in the org's own words. Present only when a
74
+ * down-rank applied — an unexplained demotion is indistinguishable from a bug. */
75
+ noise_reason?: string;
76
+ }
77
+
78
+ export function topRisks(
79
+ concerns: Concern[],
80
+ n = 5,
81
+ profile: NoiseProfile = EMPTY_NOISE_PROFILE,
82
+ ): RankedConcern[] {
83
+ return concerns
84
+ .map((c) => ({ concern: c, risk: scoreConcern(c, profile) }))
85
+ .sort((a, b) => b.risk.score - a.risk.score || a.concern.id.localeCompare(b.concern.id))
86
+ .slice(0, n)
87
+ .map(({ concern, risk }) => ({
88
+ concern_id: concern.id,
89
+ rule_id: concern.rule_id,
90
+ severity: concern.severity,
91
+ category: concern.category,
92
+ location: concern.location,
93
+ risk_score: risk.score,
94
+ risk_factors: risk.factors,
95
+ // conditional spread, not `noise_reason: undefined` —
96
+ // `exactOptionalPropertyTypes` treats an explicit undefined as a value.
97
+ ...(risk.noise ? { noise_reason: explainNoiseAdjustment(risk.noise) } : {}),
98
+ }));
99
+ }
@@ -0,0 +1,242 @@
1
+ import type { ProvenFixPattern } from "#app/mcp/terraform/fixMemory";
2
+ import type { IdleFloorReport } from "#app/mcp/terraform/idleFloor";
3
+ import type { NoiseProfile } from "#app/mcp/terraform/noiseProfile";
4
+ import type { DriftEvidenceStatement } from "#app/mcp/terraform/planDrift";
5
+ import {
6
+ buildUpgradeStatement,
7
+ type ProvenTransform,
8
+ type TransformMatch,
9
+ type UpgradeEvidenceStatement,
10
+ type UpgradeIntent,
11
+ } from "#app/mcp/terraform/transformPacks";
12
+ import type { Concern } from "#app/mcp/terraform/types";
13
+
14
+ /**
15
+ * The terraform tool-to-tool session: the explicit, typed channel the terraform
16
+ * MCP tools use to hand results to one another (and to end-of-run reporting)
17
+ * across separate, agent-mediated invocations.
18
+ *
19
+ * This used to be ~11 loose fields on the 69-field `ToolState` god-bag, where
20
+ * the coupling was invisible in every signature and the ordering was silently
21
+ * load-bearing. Naming the channel makes the contract greppable and testable:
22
+ *
23
+ * - `terraform_scan` / `terraform_assess` / `read_findings` POPULATE the
24
+ * baseline (`baselineConcernIds` / `baselineConcernKeys` /
25
+ * `baselineFmtDriftFiles`) and the acted-on set (`lastScanConcerns`).
26
+ * - `terraform_plan` POPULATES `plannedDestroy` + the confidence signals
27
+ * (`lastBlastTier`, `lastIdempotent`); `infracost_diff` populates
28
+ * `lastCostDirection`; `terraform_emit_sarif` sets `emittedSarifPath`;
29
+ * the refactor equivalence check sets `refactorEquivalence` and
30
+ * `terraform_emit_evidence` sets `refactorProposedUnproven`.
31
+ * - `terraform_verify_remediation` CONSUMES the baseline + confidence signals;
32
+ * `terraform_validate` consumes `baselineFmtDriftFiles`; the push guardrails
33
+ * consume `plannedDestroy` / `refactorEquivalence`; end-of-run reporting
34
+ * (`runLifecycle`, `cloudReport`) consumes `lastScanConcerns` /
35
+ * `emittedSarifPath` / the refactor markers.
36
+ *
37
+ * Every field is still LITERAL (records a thing that happened) and every
38
+ * consumer degrades gracefully when its producer didn't run this session
39
+ * (`undefined`), so the ordering is documented here rather than assumed.
40
+ * Reach it through {@link scanSessionOf} so a partially-constructed `ToolState`
41
+ * (chiefly in tests) lazily gets a session rather than throwing.
42
+ */
43
+ export interface ScanSession {
44
+ // full pre-fix scan id set (the deduped union of every scanner's concern ids,
45
+ // unfiltered by severity), captured by terraform_scan. read by
46
+ // terraform_verify_remediation to compute regressions = current −
47
+ // baseline (concern ids the fix INTRODUCED). undefined until the first scan.
48
+ baselineConcernIds?: string[];
49
+ // enterprise-integrity — the LINE-INDEPENDENT keys (concernKeyOf) of the
50
+ // same full pre-fix baseline. terraform_verify_remediation diffs on these, not
51
+ // raw ids, so a fix that SHIFTS lines (almost every fix) can't make an unfixed
52
+ // concern look resolved nor a pre-existing one look like a regression. Set
53
+ // alongside baselineConcernIds by terraform_scan / read_findings.
54
+ baselineConcernKeys?: string[];
55
+ // files that already failed `terraform fmt -check` at the pre-fix baseline
56
+ // scan (before any edit). read by terraform_validate so PRE-EXISTING style
57
+ // drift the run didn't introduce never gates `passed` — a scoped remediation
58
+ // must not reformat unrelated lines just to clear drift the file already had.
59
+ // Set alongside baselineConcernIds by terraform_scan / read_findings;
60
+ // undefined until the first scan (validate then falls back to gating on all
61
+ // drift, preserving pre-change behaviour outside the remediation flow).
62
+ baselineFmtDriftFiles?: string[];
63
+ // the most recent terraform_scan's reported concern set (post scope/severity
64
+ // filtering — what the run acted on). read at end-of-run by
65
+ // finalizeSuccessRun to emit the SARIF artifact + findings-count output, and
66
+ // by cloudReport to build the dashboard report. undefined until a scan ran;
67
+ // [] means the scan came back clean.
68
+ lastScanConcerns?: Concern[];
69
+ // destructive resources the most recent terraform_plan reported, partitioned
70
+ // into stateful (data-bearing, high-risk) and ephemeral. set by
71
+ // terraform_plan; read by the destroy-block guardrail (mcp/guardrails.ts) at
72
+ // push time so a fix that would delete/replace a datastore is blocked on the
73
+ // plan's evidence rather than the agent's self-report.
74
+ plannedDestroy?: {
75
+ stateful: { address: string; action: string; type: string }[];
76
+ ephemeral: { address: string; action: string; type: string }[];
77
+ };
78
+ // verification signals the confidence label aggregates, each recorded
79
+ // by the tool that produced it: terraform_plan sets blastTier + idempotent
80
+ // (undefined when no plan ran), infracost_diff sets costDirection. read by
81
+ // terraform_verify_remediation's computeConfidence so the PR's confidence is
82
+ // computed from real evidence, not the agent's word.
83
+ lastBlastTier?: "low" | "medium" | "high";
84
+ lastIdempotent?: boolean;
85
+ lastCostDirection?: "increase" | "decrease" | "no-change" | "unknown";
86
+ // the credential-free idle-floor report from terraform_emit_cost (§5.19). set
87
+ // by that tool; read by the evidence builder so the signed bundle carries the
88
+ // SAME numbers the cost.md artifact shows, computed once.
89
+ lastIdleFloor?: IdleFloorReport | undefined;
90
+ // the drift statement from the most recent detect_plan_drift (TC-2.1). set by
91
+ // that tool; read by terraform_emit_evidence so drift — including the
92
+ // `forgotten` blind-spot list and every coverage gap — enters the SIGNED
93
+ // bundle instead of dying as a run verdict. undefined until drift ran.
94
+ lastDrift?: DriftEvidenceStatement | undefined;
95
+ // absolute path of a SARIF file the agent wrote via terraform_emit_sarif.
96
+ // set by that tool on a successful write. read by finalizeSuccessRun's
97
+ // findings-output step so the end-of-run safety-net emit does NOT clobber an
98
+ // agent-emitted report (which may use a lower threshold / custom path) — it
99
+ // points findings-sarif-path at this file instead of rewriting.
100
+ emittedSarifPath?: string;
101
+ // the most recent terraform_equivalence_check verdict (the keys-free refactor
102
+ // EQUIVALENCE proof). set by that tool; read by the assertRefactorEquivalence
103
+ // push guardrail (mcp/guardrails.ts) so a refactor whose equivalence couldn't
104
+ // be proven — most dangerously, an UNCOVERED `moved {}` block, which would
105
+ // silently destroy/recreate live resources — is hard-blocked at push time on
106
+ // the proof's evidence, never the agent's self-report. undefined until the
107
+ // equivalence check runs, so it only ever gates an actual refactor flow.
108
+ refactorEquivalence?: {
109
+ equivalent: boolean;
110
+ // the keys-free sub-results, recorded so terraform_emit_evidence can render
111
+ // the equivalence statement with the proof that backs each claim (§8).
112
+ resource_set_equivalent: boolean;
113
+ arg_names_equivalent: boolean;
114
+ moves_exhaustive: boolean;
115
+ moves_detected: number;
116
+ validate_passed: boolean;
117
+ fmt_clean: boolean;
118
+ uncovered_moves: { from: string; to: string }[];
119
+ reasons: string[];
120
+ };
121
+ // set by terraform_emit_evidence when it records a b.4 third-party-module
122
+ // adoption shipped WITHOUT a plan (the `proposed — unproven` marker). read by
123
+ // the Cloud report (cloudReport.ts) so the dashboard shows that unmissable
124
+ // marker rather than implying a proof. An actual equivalence proof
125
+ // (refactorEquivalence) always takes precedence over this flag.
126
+ refactorProposedUnproven?: boolean;
127
+ // §5.12 proven-fix memory — the library of proven-fix patterns loaded at run
128
+ // start (local `.infraweaver.fix-memory.json` ∪ the org's Cloud library), read by
129
+ // the terraform_fix_memory tool to offer the fixer a proven prior for the
130
+ // finding-types in the current scan. undefined until loaded; [] = none known.
131
+ fixMemoryLibrary?: ProvenFixPattern[];
132
+ // G7 the org's fleet-wide dismissal record, coerced at run start from the Cloud
133
+ // run-context. Read by `terraform_scan` to DOWN-RANK finding types this org has
134
+ // repeatedly waived. Surfacing only — it can never suppress a finding, change a
135
+ // severity or verdict, or touch the signed evidence (see `noiseProfile`).
136
+ // undefined until loaded; an empty map = nothing learned.
137
+ noiseProfile?: NoiseProfile;
138
+ // §5.12 — patterns CAPTURED this run: each is a finding-type that went ✗→✓ via
139
+ // terraform_verify_remediation (only on a clean proof — verified, a real
140
+ // regression baseline, no regressions). read at end-of-run by cloudReport, which
141
+ // reports them to the org library (the fleet store). Accumulated across verify
142
+ // calls; deduped on use. (The committed local `.infraweaver.fix-memory.json` is
143
+ // produced out-of-band — it's a READ source here, not written during a run.)
144
+ provenFixCaptures?: ProvenFixPattern[];
145
+ // TC-2.2 — the org's fleet-wide record of which provider-upgrade transforms
146
+ // have already planned cleanly elsewhere, coerced at run start from the Cloud
147
+ // run-context. Read by terraform_provider_upgrade to annotate a transform with
148
+ // its fleet reuse. Counters only: no repo names, no configuration.
149
+ provenTransformLibrary?: ProvenTransform[];
150
+ // TC-2.2 — what terraform_provider_upgrade matched this run. Kept so the
151
+ // end-of-run capture can report the transforms the plan actually proved,
152
+ // rather than every transform the pack knows about.
153
+ transformMatches?: TransformMatch[];
154
+ // TC-2.2 — the detected upgrade, bound at evidence time to the plan that
155
+ // followed it. undefined unless terraform_provider_upgrade ran and a pack
156
+ // applied, so a run that never touched a provider major emits no upgrade block.
157
+ upgradeIntent?: UpgradeIntent;
158
+ // TC-2.2 — the aggregate plan counts, recorded by terraform_plan. The session
159
+ // already carries blast tier, idempotency and the destroy classification; only
160
+ // the raw add/change/destroy totals were missing, and the upgrade evidence
161
+ // statement needs them to state what the plan actually showed.
162
+ lastPlanTotals?: {
163
+ to_add: number;
164
+ to_change: number;
165
+ to_destroy: number;
166
+ destructive: number;
167
+ };
168
+ // TC-2.2 — was the upgrade ALREADY detected when this plan ran? Set by
169
+ // terraform_plan from whether `upgradeIntent` existed at that moment.
170
+ //
171
+ // Without it, a run that planned for some other reason and only later called
172
+ // terraform_provider_upgrade would emit a `plan-proven` verdict off a plan
173
+ // produced BEFORE the upgrade was even considered — a signed claim that a
174
+ // migration planned cleanly, backed by a plan of the pre-migration config.
175
+ // The ordering is the whole proof, so it is recorded rather than assumed.
176
+ planFollowedUpgradeDetection?: boolean;
177
+ }
178
+
179
+ /**
180
+ * The TC-2.2 upgrade statement for this session, or undefined when no provider
181
+ * pack applied.
182
+ *
183
+ * Deliberately computed in ONE place. Two consumers need it — the signed
184
+ * evidence bundle and the fleet report — and if each assembled the plan facts
185
+ * itself they could disagree, which would mean telling an org that a transform
186
+ * planned cleanly while the signed artefact for that same run said otherwise.
187
+ */
188
+ export function upgradeStatementOf(
189
+ session: ScanSession,
190
+ ): UpgradeEvidenceStatement | undefined {
191
+ // Only a plan that ran AFTER the upgrade was detected can back it. A plan from
192
+ // earlier in the run describes the pre-migration configuration, so it is
193
+ // discarded here and the statement degrades to `no-plan` — visibly unproven,
194
+ // which is the honest outcome, rather than silently proven by the wrong plan.
195
+ const totals = session.planFollowedUpgradeDetection
196
+ ? session.lastPlanTotals
197
+ : undefined;
198
+ return buildUpgradeStatement(
199
+ session.upgradeIntent,
200
+ totals
201
+ ? {
202
+ ...totals,
203
+ stateful_destructive: session.plannedDestroy?.stateful.length ?? 0,
204
+ // A plan whose idempotency was never recorded is treated as unstable
205
+ // rather than stable — the conservative direction for a proof.
206
+ idempotent: session.lastIdempotent ?? false,
207
+ }
208
+ : undefined,
209
+ );
210
+ }
211
+
212
+ /** A fresh, empty terraform session. */
213
+ export function createScanSession(): ScanSession {
214
+ return {};
215
+ }
216
+
217
+ /**
218
+ * The single entry point to the terraform session on a `ToolState`. Lazily
219
+ * initializes it, so a partially-constructed `ToolState` (chiefly test fixtures
220
+ * that cast `{}`) still reads and writes safely rather than dereferencing
221
+ * `undefined`. In production `initToolState` seeds it, so this only ever
222
+ * lazy-creates for such fixtures.
223
+ */
224
+ export function scanSessionOf(toolState: {
225
+ scanSession?: ScanSession;
226
+ }): ScanSession {
227
+ toolState.scanSession ??= {};
228
+ return toolState.scanSession;
229
+ }
230
+
231
+ /**
232
+ * true once terraform_scan / read_findings captured a pre-fix baseline this
233
+ * session. terraform_verify_remediation key-maps requested ids against the
234
+ * baseline when this holds, and reports regressions on that basis; otherwise it
235
+ * falls back to raw-id matching and marks regressions as unchecked.
236
+ */
237
+ export function hasBaseline(session: ScanSession): boolean {
238
+ return (
239
+ session.baselineConcernKeys !== undefined ||
240
+ session.baselineConcernIds !== undefined
241
+ );
242
+ }