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,279 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { type } from "arktype";
4
+ import { PRODUCT_NAME } from "#app/brand";
5
+ import type { LocalToolContext } from "#app/mcp/localContext";
6
+ import { walkTfFiles } from "#app/mcp/modules";
7
+ import { resolveWithinCwd } from "#app/mcp/pathSafety";
8
+ import { execute, tool, toolOk } from "#app/mcp/shared";
9
+ import { buildConcernResult } from "#app/mcp/terraform/concernResult";
10
+ import { indexTfResources } from "#app/mcp/terraform/cspm";
11
+ import { docUrlsForGroup, ruleDocUrl } from "#app/mcp/terraform/decisions";
12
+ import { findActionTriggers } from "#app/mcp/terraform/governance";
13
+ import {
14
+ buildDriftStatement,
15
+ classifyForgotten,
16
+ detectDrift,
17
+ driftToConcerns,
18
+ filterProviderNoise,
19
+ isSupportedPlanFormat,
20
+ PlanDocument,
21
+ summarizeActionInvocations,
22
+ } from "#app/mcp/terraform/planDrift";
23
+ import { scanSessionOf } from "#app/mcp/terraform/scanSession";
24
+ import {
25
+ SEVERITY_RANK,
26
+ type Severity,
27
+ skipResult,
28
+ } from "#app/mcp/terraform/types";
29
+ import { log } from "#app/utils/cli";
30
+
31
+ export const DetectPlanDriftParams = type({
32
+ "path?": type.string.describe(
33
+ "path to a `terraform show -json` plan artifact. Defaults to $INFRAWEAVER_PLAN_JSON_PATH, then ./plan.json.",
34
+ ),
35
+ "severity_threshold?": type(
36
+ "'critical' | 'high' | 'medium' | 'low' | 'info'",
37
+ ).describe(
38
+ "minimum severity to report (default: the run's configured threshold, else low).",
39
+ ),
40
+ "noise_fields?": type("string[]").describe(
41
+ "extra attribute names to treat as provider-computed noise, in addition to the built-in " +
42
+ "per-provider defaults (aws tags_all, google effective_labels/terraform_labels). An update whose " +
43
+ "ENTIRE diff is noise fields is excluded from drift and listed under `noise_filtered` instead.",
44
+ ),
45
+ "noise_filter?": type("boolean").describe(
46
+ "set false to disable the provider-noise filter entirely and report every mutating change as drift " +
47
+ "(default true).",
48
+ ),
49
+ });
50
+
51
+ /** Read every `.tf` file under `cwd` into `{ file, hcl }` pairs for the resource index. */
52
+ function readTfFiles(cwd: string): { file: string; hcl: string }[] {
53
+ const out: { file: string; hcl: string }[] = [];
54
+ for (const file of walkTfFiles(cwd)) {
55
+ try {
56
+ out.push({ file, hcl: readFileSync(join(cwd, file), "utf8") });
57
+ } catch {
58
+ // unreadable file — skip
59
+ }
60
+ }
61
+ return out;
62
+ }
63
+
64
+ export function DetectPlanDriftTool(ctx: LocalToolContext) {
65
+ return tool({
66
+ name: "detect_plan_drift",
67
+ description:
68
+ "Detect infrastructure DRIFT from a `terraform show -json` plan artifact WITHOUT holding cloud " +
69
+ "credentials — the customer's CI runs `terraform plan` (where the creds live) and writes the plan out " +
70
+ "as JSON; this reads that artifact. The sovereign, zero-credential companion to running terraform_plan " +
71
+ "against live state. On a run whose CODE is unchanged (a scheduled drift workflow), every mutating " +
72
+ "`resource_changes[]` entry is drift: a resource updated/deleted/replaced/recreated to reconcile live " +
73
+ "state with code. Each drifted resource becomes a `reviewer`-source concern at its file:line (returning " +
74
+ "the SAME { concerns, groups, summary } shape as terraform_scan); as drift it is not-code-verifiable by " +
75
+ `the ✗→✓ re-scan (reconciling needs live cloud access — a human decision; ${PRODUCT_NAME} never applies). ` +
76
+ "Drift whose address isn't in code is returned under `unlocated`. DETECTION ONLY — never edits, applies, " +
77
+ "or opens a PR. Returns `found: false` (never an error) when no plan artifact is present.",
78
+ parameters: DetectPlanDriftParams,
79
+ execute: execute(
80
+ async ({ path, severity_threshold, noise_fields, noise_filter }) => {
81
+ const cwd = ctx.payload.cwd ?? process.cwd();
82
+ // SECURITY: confine the agent-supplied `path` to the workspace; the env-var
83
+ // fallback is operator-controlled, so it stays unconfined.
84
+ const planPath = path
85
+ ? resolveWithinCwd(cwd, path)
86
+ : process.env.INFRAWEAVER_PLAN_JSON_PATH || join(cwd, "plan.json");
87
+ let raw: string;
88
+ try {
89
+ raw = readFileSync(planPath, "utf8");
90
+ } catch {
91
+ return skipResult(
92
+ "plan_artifact_not_found",
93
+ `no plan artifact at ${planPath} (write one with \`terraform show -json plan.out > plan.json\`, ` +
94
+ `or set the path arg / $INFRAWEAVER_PLAN_JSON_PATH)`,
95
+ {
96
+ key: "found",
97
+ reasonKey: "reason",
98
+ extra: { concerns: [], groups: [], unlocated: [] },
99
+ },
100
+ );
101
+ }
102
+
103
+ let parsed: unknown;
104
+ try {
105
+ parsed = JSON.parse(raw || "{}");
106
+ } catch {
107
+ return skipResult(
108
+ "plan_artifact_parse_error",
109
+ `could not parse JSON at ${planPath}`,
110
+ {
111
+ key: "found",
112
+ reasonKey: "reason",
113
+ extra: { concerns: [], groups: [], unlocated: [] },
114
+ },
115
+ );
116
+ }
117
+ const document = PlanDocument(parsed);
118
+ if (document instanceof type.errors) {
119
+ return skipResult(
120
+ "plan_artifact_invalid",
121
+ `plan artifact at ${planPath} is not a terraform show -json document: ${document.summary}`,
122
+ {
123
+ key: "found",
124
+ reasonKey: "reason",
125
+ extra: { concerns: [], groups: [], unlocated: [] },
126
+ },
127
+ );
128
+ }
129
+
130
+ // Forward-compat: an unknown MAJOR schema means we may be reading a
131
+ // document we do not understand, so say so rather than report a
132
+ // confident 'no drift' derived from keys that may have moved.
133
+ const formatSupported = isSupportedPlanFormat(document.format_version);
134
+ // Provider-noise filter: an update whose ENTIRE diff is provider-computed
135
+ // bookkeeping (aws tags_all, …) is not an operator touching infra. Kept
136
+ // auditable — filtered items are returned, never silently dropped.
137
+ const { kept: drift, filtered: noiseFiltered } =
138
+ noise_filter === false
139
+ ? { kept: detectDrift(document), filtered: [] }
140
+ : filterProviderNoise(detectDrift(document), noise_fields ?? []);
141
+ // State-only removals: the cloud object survives but leaves management, so
142
+ // every later drift scan is blind to it. Reported as a coverage gap — and
143
+ // a STATEFUL forget (a database leaving management) escalates to
144
+ // needs-human: after it, a data-bearing object exists with no destroy
145
+ // protection, no drift visibility, and nothing in code saying so.
146
+ const forgotten = classifyForgotten(document);
147
+ const statefulForgotten = forgotten.filter((f) => f.stateful);
148
+ const tfFiles = readTfFiles(cwd);
149
+ const index = indexTfResources(tfFiles);
150
+ const byAddress = new Map(index.map((e) => [e.address, e]));
151
+ const { concerns: driftConcerns, unlocated } = driftToConcerns(
152
+ drift,
153
+ (address) => {
154
+ const e = byAddress.get(address);
155
+ return e ? { file: e.file, line: e.line } : null;
156
+ },
157
+ );
158
+ // Runtime↔static correlation (TC-2.1 ∘ TC-3.2): `action_invocations` is
159
+ // the plan saying "THIS apply invokes provider actions" — the runtime
160
+ // counterpart of the static `imperative-action-trigger` finding. Each
161
+ // invocation is marked with whether a lifecycle trigger in the repo's HCL
162
+ // declares it, so an invocation NOT declared in code stands out.
163
+ const declaredActionRefs = new Set(
164
+ tfFiles.flatMap(({ hcl }) =>
165
+ findActionTriggers(hcl).flatMap((t) => t.actions),
166
+ ),
167
+ );
168
+ const actionInvocations = summarizeActionInvocations(document).map(
169
+ (inv) => ({
170
+ ...inv,
171
+ declared_in_code: declaredActionRefs.has(inv.address),
172
+ }),
173
+ );
174
+
175
+ const configured = ctx.payload.severityThreshold as
176
+ | Severity
177
+ | undefined;
178
+ const threshold: Severity = severity_threshold ?? configured ?? "low";
179
+ const minRank = SEVERITY_RANK[threshold];
180
+ const autonomyThreshold =
181
+ (ctx.payload.autonomyThreshold as Severity | undefined) ?? "high";
182
+
183
+ const {
184
+ active,
185
+ suppressed,
186
+ groups,
187
+ batchPlan,
188
+ bySeverity: by_severity,
189
+ } = buildConcernResult(ctx, driftConcerns, {
190
+ cwd,
191
+ minRank,
192
+ grouping: "file",
193
+ autonomyThreshold,
194
+ // drift is a narrow concern source — join any prior scan baseline so a
195
+ // later ✗→✓ verify doesn't read the whole workspace as regressions.
196
+ baselineMode: "merge",
197
+ });
198
+
199
+ log.info(
200
+ `» detect_plan_drift: ${active.length} drifted resource(s) ≥ ${threshold} from ${planPath}` +
201
+ (noiseFiltered.length
202
+ ? `, ${noiseFiltered.length} noise-filtered`
203
+ : "") +
204
+ (unlocated.length ? `, ${unlocated.length} unlocated` : "") +
205
+ (statefulForgotten.length
206
+ ? `, ${statefulForgotten.length} STATEFUL forget(s)`
207
+ : "") +
208
+ (suppressed.length ? ` (${suppressed.length} suppressed)` : ""),
209
+ );
210
+
211
+ const coverageGap = formatSupported
212
+ ? undefined
213
+ : `plan artifact declares format_version ${document.format_version} — this parser reads 1.x; ` +
214
+ "results may be incomplete";
215
+
216
+ // Record the drift statement for terraform_emit_evidence: drift (with the
217
+ // forgotten blind-spot list and any coverage gap) enters the SIGNED
218
+ // bundle instead of dying as a run verdict. The statement is built from
219
+ // the UNTHRESHOLDED drift set — evidence must not shrink with a
220
+ // reporting preference.
221
+ scanSessionOf(ctx.toolState).lastDrift = buildDriftStatement({
222
+ sourceFile: planPath,
223
+ kept: drift,
224
+ filtered: noiseFiltered,
225
+ forgotten,
226
+ unlocated: unlocated.length,
227
+ coverageGaps: coverageGap ? [coverageGap] : [],
228
+ });
229
+
230
+ const needsHumanReasons = statefulForgotten.map(
231
+ (f) =>
232
+ `plan forgets STATEFUL resource ${f.address} (${f.type}) — after this apply it keeps existing ` +
233
+ "with no destroy protection and no drift visibility; confirm the removal is intentional",
234
+ );
235
+
236
+ return toolOk({
237
+ found: true,
238
+ source_file: planPath,
239
+ drift: active.length > 0,
240
+ summary: {
241
+ drifted: active.length,
242
+ suppressed: suppressed.length,
243
+ noise_filtered: noiseFiltered.length,
244
+ unlocated: unlocated.length,
245
+ groups: groups.length,
246
+ by_severity,
247
+ },
248
+ groups: groups.map((g) => ({
249
+ ...g,
250
+ doc_urls: docUrlsForGroup(g, active),
251
+ })),
252
+ batch_plan: batchPlan,
253
+ concerns: active.map((c) => ({ ...c, doc_url: ruleDocUrl(c) })),
254
+ // A resource that drifted but isn't in code (e.g. deleted from the config but
255
+ // still in state) — surfaced honestly, not hidden.
256
+ unlocated,
257
+ // Drift excluded as provider-computed bookkeeping (aws tags_all, …) —
258
+ // listed field-by-field so the filtering is auditable, never silent.
259
+ noise_filtered: noiseFiltered,
260
+ // Resources the plan would drop from state while the real object keeps
261
+ // existing. NOT drift and NOT a destroy — but after this, drift detection
262
+ // can no longer see them, so the gap is stated rather than assumed away.
263
+ // Each entry carries `stateful`; a stateful forget escalates below.
264
+ forgotten,
265
+ // Provider actions THIS plan will invoke (TF 1.15 `action_invocations`) —
266
+ // the runtime counterpart of the static `imperative-action-trigger`
267
+ // finding; `declared_in_code: false` means the plan invokes an action no
268
+ // lifecycle trigger in the repo declares.
269
+ action_invocations: actionInvocations,
270
+ // Deterministic escalation (mirrors terraform_plan's needs_human): a
271
+ // stateful resource leaving management is a human decision, not a verdict.
272
+ needs_human: needsHumanReasons.length > 0,
273
+ needs_human_reasons: needsHumanReasons,
274
+ ...(coverageGap ? { coverage_gap: coverageGap } : {}),
275
+ });
276
+ },
277
+ ),
278
+ });
279
+ }
@@ -0,0 +1,130 @@
1
+ import { readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { type } from "arktype";
4
+ import { COST_FILE, PRODUCT_NAME } from "#app/brand";
5
+ import { COST_OPTIMIZATION_MODE } from "#app/mcp/guardrails";
6
+ import type { LocalToolContext } from "#app/mcp/localContext";
7
+ import { walkTfFiles } from "#app/mcp/modules";
8
+ import { resolveWithinCwd } from "#app/mcp/pathSafety";
9
+ import { execute, tool, toolOk } from "#app/mcp/shared";
10
+ import { indexTfResources } from "#app/mcp/terraform/cspm";
11
+ import {
12
+ detectIdleFloor,
13
+ IDLE_FLOOR_DOES_NOT_ASSERT,
14
+ renderCostMarkdown,
15
+ } from "#app/mcp/terraform/idleFloor";
16
+ import { scanSessionOf } from "#app/mcp/terraform/scanSession";
17
+ import { skipResult } from "#app/mcp/terraform/types";
18
+ import { log } from "#app/utils/cli";
19
+ import packageJson from "#package.json" with { type: "json" };
20
+
21
+ /** No `output_path`: the artifact name is FIXED. The guardrail carve-out that
22
+ * lets this file be pushed is the single literal `cost.md` (see
23
+ * `COST_ALLOWED_PATHS`), so an agent-chosen path could either be rejected at
24
+ * push time or — worse, for a path like `main.tf` that IS allow-listed —
25
+ * overwrite Terraform source with markdown. Fixing the name makes the tool's
26
+ * write surface exactly the surface the guardrail permits. */
27
+ export const TerraformEmitCostParams = type({});
28
+
29
+ /** Read every `.tf` file under `cwd` into `{ file, hcl }` pairs for the resource index. */
30
+ function readTfFiles(cwd: string): { file: string; hcl: string }[] {
31
+ const out: { file: string; hcl: string }[] = [];
32
+ for (const file of walkTfFiles(cwd)) {
33
+ try {
34
+ out.push({ file, hcl: readFileSync(join(cwd, file), "utf8") });
35
+ } catch {
36
+ // unreadable file — skip
37
+ }
38
+ }
39
+ return out;
40
+ }
41
+
42
+ export function TerraformEmitCostTool(ctx: LocalToolContext) {
43
+ return tool({
44
+ name: "terraform_emit_cost",
45
+ description:
46
+ "Compute the credential-free IDLE FLOOR — what this configuration bills at ZERO traffic — and write " +
47
+ `it as a \`${COST_FILE}\` artifact for the PR. Needs NO cloud credentials, NO pricing API key and makes ` +
48
+ "NO network call: prices come from a bundled snapshot of public Azure list prices, so it works offline " +
49
+ "in the free tier. Reports only the DETERMINISTIC portion of cost (reserved compute, provisioned " +
50
+ "gateways, provisioned cache) — never a monthly total, because usage-dependent lines (data processed, " +
51
+ "requests, egress) are not derivable from Terraform and quoting them would be a guess; a resource whose " +
52
+ "tier it cannot identify is listed as unpriced rather than estimated. Use it to justify a " +
53
+ "CostOptimization fix: the floor is the part a right-sizing PR actually removes. CostOptimization mode " +
54
+ "only (that is the one mode whose push allows the artifact). Azure resource types today; returns " +
55
+ "`found: false` (never an error) when nothing is priced.",
56
+ parameters: TerraformEmitCostParams,
57
+ // writes a file that lands in the PR diff — mutating for subagent purposes.
58
+ mutates: true,
59
+ execute: execute(async () => {
60
+ // Mode gate, mirroring terraform_module_docs: the push guardrail only
61
+ // allow-lists `cost.md` for CostOptimization, so writing it under any other
62
+ // guarded mode would hard-block that run's push. Skip, never throw.
63
+ const mode = ctx.toolState.selectedMode;
64
+ if (mode !== COST_OPTIMIZATION_MODE) {
65
+ return skipResult(
66
+ "cost_mode_only",
67
+ `the cost artifact is written by the ${COST_OPTIMIZATION_MODE} mode only (this run is ${mode ?? "unset"}) — its push allow-list is the one that permits ${COST_FILE}`,
68
+ { key: "found", reasonKey: "reason", extra: { items: [], monthly_floor: 0 } },
69
+ );
70
+ }
71
+
72
+ const cwd = ctx.payload.cwd ?? process.cwd();
73
+ const target = resolveWithinCwd(cwd, COST_FILE);
74
+ const session = scanSessionOf(ctx.toolState);
75
+
76
+ const report = detectIdleFloor(indexTfResources(readTfFiles(cwd)));
77
+ if (report.items.length === 0) {
78
+ // Clear any earlier report: a re-run after a fix that removed the last
79
+ // priced resource must not leave the evidence bundle asserting the OLD
80
+ // floor while cost.md was never rewritten.
81
+ session.lastIdleFloor = undefined;
82
+ return skipResult(
83
+ "no_priced_resources",
84
+ "no resources from the idle-floor catalog were priced in this configuration",
85
+ {
86
+ key: "found",
87
+ reasonKey: "reason",
88
+ extra: { items: [], monthly_floor: 0, unpriced: report.unpriced },
89
+ },
90
+ );
91
+ }
92
+
93
+ const markdown = renderCostMarkdown(report, packageJson.version);
94
+ try {
95
+ writeFileSync(target, markdown, "utf8");
96
+ } catch (e) {
97
+ return skipResult(
98
+ "cost_write_failed",
99
+ `could not write the cost artifact to ${target}: ${e instanceof Error ? e.message : String(e)}`,
100
+ { key: "found", reasonKey: "reason", extra: { items: [], monthly_floor: 0 } },
101
+ );
102
+ }
103
+
104
+ // Hand the report to the session so the evidence bundle can carry the same
105
+ // numbers without recomputing them (one source, one set of bytes signed).
106
+ session.lastIdleFloor = report;
107
+
108
+ log.info(
109
+ `» terraform_emit_cost: ${report.currency} ${report.monthly_floor.toFixed(2)}/mo idle floor ` +
110
+ `across ${report.items.length} resource(s) → ${target}` +
111
+ (report.unpriced.length ? ` (${report.unpriced.length} unpriced)` : ""),
112
+ );
113
+ return toolOk({
114
+ found: true,
115
+ output_path: target,
116
+ currency: report.currency,
117
+ monthly_floor: report.monthly_floor,
118
+ priced_at: report.priced_at,
119
+ region: report.region,
120
+ items: report.items,
121
+ // Catalogued resources whose tier wasn't identifiable — the floor is a
122
+ // lower bound by exactly these, and saying so is the point.
123
+ unpriced: report.unpriced,
124
+ note:
125
+ `Idle floor only — ${IDLE_FLOOR_DOES_NOT_ASSERT} ` +
126
+ `${PRODUCT_NAME} holds no cloud credentials and made no pricing call.`,
127
+ });
128
+ }),
129
+ });
130
+ }
@@ -0,0 +1,108 @@
1
+ import { writeFileSync } from "node:fs";
2
+ import { type } from "arktype";
3
+ import { SARIF_FILE } from "#app/brand";
4
+ import type { LocalToolContext } from "#app/mcp/localContext";
5
+ import { resolveWithinCwd } from "#app/mcp/pathSafety";
6
+ import { execute, tool, toolOk } from "#app/mcp/shared";
7
+ import { buildSarifReport } from "#app/mcp/terraform/findings";
8
+ import {
9
+ checkovFrameworksFor,
10
+ detectIacLanguages,
11
+ inLanguageScope,
12
+ resolveLanguageScope,
13
+ } from "#app/mcp/terraform/iacLanguages";
14
+ import { scanSessionOf } from "#app/mcp/terraform/scanSession";
15
+ import { runScanners } from "#app/mcp/terraform/scanners";
16
+ import { suppressConcerns } from "#app/mcp/terraform/suppressions";
17
+ import {
18
+ dedupe,
19
+ SEVERITY_RANK,
20
+ type Severity,
21
+ skipResult,
22
+ sortConcerns,
23
+ } from "#app/mcp/terraform/types";
24
+ import { log } from "#app/utils/cli";
25
+ import { resolveModuleCredentialEnv } from "#app/utils/registryAuth";
26
+ import { resolveToolSelection } from "#app/utils/toolSelection";
27
+
28
+ export const TerraformEmitSarifParams = type({
29
+ "output_path?": type.string.describe(
30
+ `where to write the SARIF file (default: ./${SARIF_FILE} in the workspace). Upload it with github/codeql-action/upload-sarif to populate the repo's Security tab.`,
31
+ ),
32
+ "severity_threshold?": type(
33
+ "'critical' | 'high' | 'medium' | 'low' | 'info'",
34
+ ).describe(
35
+ "minimum severity to include (default: the run's configured threshold, else low).",
36
+ ),
37
+ });
38
+
39
+ export function TerraformEmitSarifTool(ctx: LocalToolContext) {
40
+ return tool({
41
+ name: "terraform_emit_sarif",
42
+ description:
43
+ "Emit the current best-practice scan as a SARIF 2.1.0 file for GitHub code-scanning. Re-runs " +
44
+ `the scanners and writes a SARIF report (default \`${SARIF_FILE}\`) that a later workflow step uploads ` +
45
+ "with `github/codeql-action/upload-sarif`, surfacing every concern in the repo's Security tab with the " +
46
+ "right severity + doc link. This is the EMIT side (the inverse of `read_findings`' SARIF INGEST) — use " +
47
+ "it when the goal is to REPORT findings to code-scanning rather than open a remediation PR. Degrades " +
48
+ "green: writes an empty-result report when the tree is clean.",
49
+ parameters: TerraformEmitSarifParams,
50
+ execute: execute(async ({ output_path, severity_threshold }) => {
51
+ const cwd = ctx.payload.cwd ?? process.cwd();
52
+ const configured = ctx.payload.severityThreshold as Severity | undefined;
53
+ const threshold: Severity = severity_threshold ?? configured ?? "low";
54
+ const minRank = SEVERITY_RANK[threshold];
55
+ // Mirror the Assess pillar's multi-language scope so the Security tab reflects
56
+ // exactly what the assessment reports — Terraform plus every other IaC language
57
+ // the scanners parse (scoped by `iac_languages`), not Terraform alone.
58
+ const languageScope = resolveLanguageScope(ctx.payload.iacLanguages, detectIacLanguages(cwd));
59
+ // same selection + module-fetch credential as terraform_scan, so the
60
+ // SARIF report mirrors exactly what a scan reports (no extra gated tools).
61
+ const outcomes = runScanners(cwd, {
62
+ selection: resolveToolSelection(ctx.payload),
63
+ terraformEnv: resolveModuleCredentialEnv(ctx.payload, {
64
+ sshKeyDir: ctx.tmpdir,
65
+ }),
66
+ checkovFrameworks: checkovFrameworksFor(languageScope.scanned),
67
+ toolsNetwork: ctx.payload.toolsNetwork,
68
+ });
69
+ const inScope = inLanguageScope(languageScope);
70
+ const concerns = suppressConcerns(
71
+ sortConcerns(dedupe(outcomes.flatMap((o) => o.concerns)))
72
+ .filter(inScope)
73
+ .filter((c) => SEVERITY_RANK[c.severity] >= minRank),
74
+ cwd,
75
+ );
76
+ const suppressedCount = concerns.filter((c) => c.suppression).length;
77
+ const report = buildSarifReport(concerns);
78
+ // SECURITY: confine the agent-supplied output_path to the workspace so it
79
+ // can't be used to clobber arbitrary files on the runner (the action
80
+ // process runs outside the shell sandbox). Computed BEFORE the try so an
81
+ // escape attempt surfaces as a clear error, not a "write failed" skip.
82
+ const target = resolveWithinCwd(cwd, output_path ?? SARIF_FILE);
83
+ try {
84
+ writeFileSync(target, `${JSON.stringify(report, null, 2)}\n`, "utf8");
85
+ } catch (e) {
86
+ return skipResult(
87
+ "sarif_write_failed",
88
+ `could not write SARIF to ${target}: ${e instanceof Error ? e.message : String(e)}`,
89
+ );
90
+ }
91
+ // record the agent-emitted path so the end-of-run findings-output safety
92
+ // net (finalizeSuccessRun) defers to this file instead of rewriting it.
93
+ scanSessionOf(ctx.toolState).emittedSarifPath = target;
94
+ log.info(
95
+ `» terraform_emit_sarif: ${concerns.length} result(s)` +
96
+ (suppressedCount ? ` (${suppressedCount} suppressed)` : "") +
97
+ ` → ${target}`,
98
+ );
99
+ return toolOk({
100
+ sarif_path: target,
101
+ result_count: concerns.length,
102
+ suppressed_count: suppressedCount,
103
+ rule_count: report.runs?.[0]?.tool?.driver?.rules?.length ?? 0,
104
+ note: "Upload with github/codeql-action/upload-sarif to populate the repo's Security tab.",
105
+ });
106
+ }),
107
+ });
108
+ }
@@ -0,0 +1,82 @@
1
+ import { type } from "arktype";
2
+ import type { LocalToolContext } from "#app/mcp/localContext";
3
+ import { execute, tool, toolOk } from "#app/mcp/shared";
4
+ import {
5
+ loadFixMemory,
6
+ matchPatternsForConcerns,
7
+ type ProvenFixPattern,
8
+ } from "#app/mcp/terraform/fixMemory";
9
+ import { scanSessionOf } from "#app/mcp/terraform/scanSession";
10
+
11
+ export const TerraformFixMemoryParams = type({});
12
+
13
+ /**
14
+ * The effective library for this run: the one loaded at run start
15
+ * (`session.fixMemoryLibrary` — the org's Cloud library ∪ any committed local
16
+ * file), or, on the local stdio MCP server where there is no run-start hook, a
17
+ * lazy read of the committed `.infraweaver.fix-memory.json`. Cached back onto the
18
+ * session so the file is read at most once.
19
+ */
20
+ function effectiveLibrary(ctx: LocalToolContext): ProvenFixPattern[] {
21
+ const session = scanSessionOf(ctx.toolState);
22
+ if (session.fixMemoryLibrary === undefined) {
23
+ session.fixMemoryLibrary = loadFixMemory(ctx.payload.cwd);
24
+ }
25
+ return session.fixMemoryLibrary;
26
+ }
27
+
28
+ export function runFixMemory(ctx: LocalToolContext) {
29
+ if (!ctx.payload.fixMemory) {
30
+ return toolOk({
31
+ enabled: false,
32
+ patterns: [],
33
+ note: 'Proven-fix memory is off. Enable it with the `fix_memory: "true"` input.',
34
+ });
35
+ }
36
+
37
+ const session = scanSessionOf(ctx.toolState);
38
+ if (session.lastScanConcerns === undefined) {
39
+ return toolOk({
40
+ enabled: true,
41
+ patterns: [],
42
+ note: "No scan this run yet — run terraform_scan first, then call this to see proven priors for its findings.",
43
+ });
44
+ }
45
+
46
+ const matched = matchPatternsForConcerns(
47
+ effectiveLibrary(ctx),
48
+ session.lastScanConcerns,
49
+ );
50
+ return toolOk({
51
+ enabled: true,
52
+ patterns: matched.map((p) => ({
53
+ finding_type: p.finding_type,
54
+ title: p.title,
55
+ canonical_class: p.canonical_class ?? undefined,
56
+ remediation_hint: p.remediation_hint ?? undefined,
57
+ before_example: p.before_example ?? undefined,
58
+ times_proven: p.times_proven ?? undefined,
59
+ repos_count: p.repos_count ?? undefined,
60
+ last_proven: p.last_proven ?? undefined,
61
+ })),
62
+ note:
63
+ matched.length > 0
64
+ ? "Each pattern is a PROVEN starting point for that finding-type from a prior ✗→✓. Adapt it to THIS repo's resources — you MUST still run terraform_verify_remediation to prove ✗→✓ here. Never apply a pattern blind."
65
+ : "No proven-fix pattern matches this scan's finding-types yet.",
66
+ });
67
+ }
68
+
69
+ export function TerraformFixMemoryTool(ctx: LocalToolContext) {
70
+ return tool({
71
+ name: "terraform_fix_memory",
72
+ description:
73
+ "Reusable proven-fix memory: returns proven-fix patterns for the finding-types in the CURRENT " +
74
+ "scan — each a transformation that already passed a ✗→✓ proof on this repo or elsewhere in the " +
75
+ "fleet. Call it in the fix step to start from a known-good approach instead of rediscovering it. " +
76
+ "A pattern is a PRIOR, not a patch: adapt it to this repo's own resources and ALWAYS re-prove with " +
77
+ "terraform_verify_remediation — a pattern is never blind-applied, and the ✗→✓ proof is still required " +
78
+ "per target. Returns an empty list (never an error) when nothing matches or memory is off.",
79
+ parameters: TerraformFixMemoryParams,
80
+ execute: execute(() => Promise.resolve(runFixMemory(ctx))),
81
+ });
82
+ }