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,72 @@
1
+ import { performance } from "node:perf_hooks";
2
+ import { log } from "#app/utils/cli";
3
+
4
+ export class Timer {
5
+ private initialTimestamp: number;
6
+ private lastCheckpointTimestamp: number | null = null;
7
+
8
+ constructor() {
9
+ this.initialTimestamp = performance.now();
10
+ }
11
+
12
+ checkpoint(name: string): void {
13
+ const now = performance.now();
14
+ const duration = this.lastCheckpointTimestamp
15
+ ? now - this.lastCheckpointTimestamp
16
+ : now - this.initialTimestamp;
17
+
18
+ log.debug(`» ${name}: ${duration}ms`);
19
+ this.lastCheckpointTimestamp = now;
20
+ }
21
+ }
22
+
23
+ const THINKING_THRESHOLD = 3000; // ms
24
+
25
+ /**
26
+ * Measures wall-clock gap between the last tool_result and the next tool_call,
27
+ * surfacing it as a "thought for Xs" log when over `THINKING_THRESHOLD`.
28
+ *
29
+ * Use one instance per logical session (orchestrator, each subagent) — sharing
30
+ * a single timer across sessions conflates cross-session interleaving as
31
+ * thinking time. The optional `formatLine` lets the caller prefix output with
32
+ * a session label so attribution is visible in the merged log stream.
33
+ */
34
+ export class ThinkingTimer {
35
+ private readonly durationFormatter = new Intl.NumberFormat("en-US", {
36
+ style: "unit",
37
+ unit: "second",
38
+ unitDisplay: "long",
39
+ minimumFractionDigits: 0,
40
+ maximumFractionDigits: 1,
41
+ });
42
+
43
+ private lastToolResultTimestamp: number | null = null;
44
+ private readonly formatLine: (line: string) => string;
45
+
46
+ // node's native TS strip-only mode does not support parameter properties,
47
+ // so the formatter is declared as a field and assigned in the body.
48
+ constructor(formatLine: (line: string) => string = (l) => l) {
49
+ this.formatLine = formatLine;
50
+ }
51
+
52
+ markToolResult(): void {
53
+ this.lastToolResultTimestamp = performance.now();
54
+ log.debug(
55
+ this.formatLine(`» thinking timer: markToolResult at ${this.lastToolResultTimestamp}`),
56
+ );
57
+ }
58
+
59
+ markToolCall(): void {
60
+ const now = performance.now();
61
+ log.debug(
62
+ this.formatLine(
63
+ `» thinking timer: markToolCall at ${now}, lastToolResult=${this.lastToolResultTimestamp}`,
64
+ ),
65
+ );
66
+ if (this.lastToolResultTimestamp === null) return;
67
+ const elapsed = now - this.lastToolResultTimestamp;
68
+ if (elapsed < THINKING_THRESHOLD) return;
69
+ const seconds = elapsed / 1000;
70
+ log.info(this.formatLine(`» thought for ${this.durationFormatter.format(seconds)}`));
71
+ }
72
+ }
@@ -0,0 +1,168 @@
1
+ import { UPLOADS_URL } from "#app/brand";
2
+ import { log } from "#app/utils/log";
3
+
4
+ type TodoItem = {
5
+ id: string;
6
+ content: string;
7
+ status: "pending" | "in_progress" | "completed" | "cancelled";
8
+ };
9
+
10
+ function isValidTodoStatus(value: string): value is TodoItem["status"] {
11
+ return (
12
+ value === "pending" || value === "in_progress" || value === "completed" || value === "cancelled"
13
+ );
14
+ }
15
+
16
+ function parseTodowriteInput(input: unknown): { todos: unknown[]; merge: boolean } | undefined {
17
+ if (!input || typeof input !== "object" || !("todos" in input)) return undefined;
18
+ if (!Array.isArray(input.todos)) return undefined;
19
+ const merge = "merge" in input && input.merge === true;
20
+ return { todos: input.todos, merge };
21
+ }
22
+
23
+ function parseTodoItem(entry: unknown, index: number): TodoItem | undefined {
24
+ if (!entry || typeof entry !== "object") return undefined;
25
+ if (!("content" in entry) || typeof entry.content !== "string") return undefined;
26
+ const id = "id" in entry && typeof entry.id === "string" ? entry.id : String(index);
27
+ const status =
28
+ "status" in entry && typeof entry.status === "string" && isValidTodoStatus(entry.status)
29
+ ? entry.status
30
+ : "pending";
31
+ return { id, content: entry.content, status };
32
+ }
33
+
34
+ function renderTodoMarkdown(todos: TodoItem[]): string {
35
+ return todos
36
+ .map((todo) => {
37
+ switch (todo.status) {
38
+ case "completed":
39
+ return `- [x] ${todo.content}`;
40
+ case "cancelled":
41
+ return `- ~~${todo.content}~~`;
42
+ case "in_progress":
43
+ return `- [ ] <img src="${UPLOADS_URL}/Progress%20Indicator.gif" width="11" style="visibility: visible; max-width: 100%;" /> ${todo.content}`;
44
+ case "pending":
45
+ return `- [ ] ${todo.content}`;
46
+ default:
47
+ todo.status satisfies never;
48
+ return `- [ ] ${todo.content}`;
49
+ }
50
+ })
51
+ .join("\n");
52
+ }
53
+
54
+ export type TodoTracker = {
55
+ update: (input: unknown) => void;
56
+ flush: () => Promise<void>;
57
+ cancel: () => void;
58
+ /** resolves when any in-flight onUpdate call completes */
59
+ settled: () => Promise<void>;
60
+ /** mark in-progress items as completed (for final snapshot before review/progress post) */
61
+ completeInProgress: () => void;
62
+ renderCollapsible: (options?: { completeInProgress?: boolean }) => string;
63
+ readonly enabled: boolean;
64
+ /** true after the tracker has successfully called onUpdate at least once */
65
+ readonly hasPublished: boolean;
66
+ };
67
+
68
+ const DEBOUNCE_MS = 2000;
69
+
70
+ export function createTodoTracker(onUpdate: (body: string) => Promise<void>): TodoTracker {
71
+ const state = new Map<string, TodoItem>();
72
+ let enabled = true;
73
+ let hasPublished = false;
74
+ let debounceTimer: ReturnType<typeof setTimeout> | null = null;
75
+ let inflightPromise: Promise<void> = Promise.resolve();
76
+
77
+ function scheduleUpdate() {
78
+ if (!enabled) return;
79
+ if (debounceTimer) clearTimeout(debounceTimer);
80
+ debounceTimer = setTimeout(() => {
81
+ debounceTimer = null;
82
+ if (!enabled || state.size === 0) return;
83
+ const markdown = renderTodoMarkdown(Array.from(state.values()));
84
+ inflightPromise = inflightPromise
85
+ .then(async () => {
86
+ if (!enabled) return;
87
+ await onUpdate(markdown);
88
+ hasPublished = true;
89
+ })
90
+ .catch((err) => {
91
+ log.debug(`todo progress update failed: ${err}`);
92
+ });
93
+ }, DEBOUNCE_MS);
94
+ }
95
+
96
+ return {
97
+ update(input: unknown) {
98
+ if (!enabled) return;
99
+ const parsed = parseTodowriteInput(input);
100
+ if (!parsed) return;
101
+ if (!parsed.merge) state.clear();
102
+ for (const [index, entry] of parsed.todos.entries()) {
103
+ const item = parseTodoItem(entry, index);
104
+ if (item) state.set(item.id, item);
105
+ }
106
+ log.debug(`» todowrite: ${state.size} items tracked`);
107
+ scheduleUpdate();
108
+ },
109
+
110
+ async flush() {
111
+ if (debounceTimer) {
112
+ clearTimeout(debounceTimer);
113
+ debounceTimer = null;
114
+ }
115
+ if (!enabled || state.size === 0) return;
116
+ const markdown = renderTodoMarkdown(Array.from(state.values()));
117
+ inflightPromise = inflightPromise
118
+ .then(async () => {
119
+ if (!enabled) return;
120
+ await onUpdate(markdown);
121
+ hasPublished = true;
122
+ })
123
+ .catch((err) => {
124
+ log.debug(`todo progress flush failed: ${err}`);
125
+ });
126
+ await inflightPromise;
127
+ },
128
+
129
+ cancel() {
130
+ enabled = false;
131
+ if (debounceTimer) {
132
+ clearTimeout(debounceTimer);
133
+ debounceTimer = null;
134
+ }
135
+ },
136
+
137
+ async settled() {
138
+ await inflightPromise;
139
+ },
140
+
141
+ completeInProgress() {
142
+ for (const item of state.values()) {
143
+ if (item.status === "in_progress") item.status = "completed";
144
+ }
145
+ },
146
+
147
+ renderCollapsible(options?: { completeInProgress?: boolean }): string {
148
+ if (state.size === 0) return "";
149
+ const shouldCompleteInProgress = options?.completeInProgress === true;
150
+ const todos = Array.from(state.values()).map((item) =>
151
+ shouldCompleteInProgress && item.status === "in_progress"
152
+ ? { ...item, status: "completed" as const }
153
+ : item,
154
+ );
155
+ const completed = todos.filter((t) => t.status === "completed").length;
156
+ const markdown = renderTodoMarkdown(todos);
157
+ return `<details>\n<summary>Task list (${completed}/${todos.length} completed)</summary>\n\n${markdown}\n\n</details>`;
158
+ },
159
+
160
+ get enabled() {
161
+ return enabled;
162
+ },
163
+
164
+ get hasPublished() {
165
+ return hasPublished;
166
+ },
167
+ };
168
+ }
@@ -0,0 +1,294 @@
1
+ import assert from "node:assert/strict";
2
+ import * as core from "@actions/core";
3
+ import type { PushPermission } from "#app/external";
4
+ import { log } from "#app/utils/cli";
5
+ import { onExitSignal } from "#app/utils/exitHandler";
6
+ import {
7
+ acquireNewToken,
8
+ type OidcCreds,
9
+ readOidcCreds,
10
+ } from "#app/utils/github";
11
+ import { isGitHubActions } from "#app/utils/globals";
12
+ import { stashKeylessOidcCreds } from "#app/utils/keylessOidc";
13
+
14
+ // re-export for `infraweaver gha token` subcommand
15
+ export {
16
+ acquireNewToken as acquireInstallationToken,
17
+ revokeGitHubInstallationToken as revokeInstallationToken,
18
+ };
19
+
20
+ // store MCP token in memory for getGitHubInstallationToken()
21
+ let mcpTokenValue: string | undefined;
22
+
23
+ // single-flight refresher for the MCP installation token, installed by
24
+ // resolveTokens when OIDC re-minting is possible. createOctokit calls it on a
25
+ // 401 to swap in a fresh token mid-run (pullfrog #891). undefined off-CI, on the
26
+ // external-GH_TOKEN path, or once tokens are disposed.
27
+ let refreshMcpTokenFn: ((stale: string) => Promise<string>) | undefined;
28
+
29
+ /** The live MCP-token refresher (see {@link refreshMcpTokenFn}), or undefined
30
+ * when re-minting isn't possible. Passed into `createOctokit` as `refreshAuth`. */
31
+ export function getMcpTokenRefresh():
32
+ | ((stale: string) => Promise<string>)
33
+ | undefined {
34
+ return refreshMcpTokenFn;
35
+ }
36
+
37
+ /**
38
+ * get the job-scoped token from action input.
39
+ * this token has permissions defined by the workflow's permissions block.
40
+ *
41
+ * fallback order:
42
+ * 1. INPUT_TOKEN (from workflow `with: token:`)
43
+ * 2. GH_TOKEN (external token override)
44
+ * 3. GITHUB_TOKEN (pre-acquired in tests or from GHA env)
45
+ */
46
+ export function getJobToken(): string {
47
+ const inputToken = core.getInput("token");
48
+ if (inputToken) {
49
+ return inputToken;
50
+ }
51
+
52
+ // fallback for test environment and local dev
53
+ const fallbackToken = process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
54
+ if (fallbackToken) {
55
+ return fallbackToken;
56
+ }
57
+
58
+ throw new Error("token input is required");
59
+ }
60
+
61
+ export type TokenRef = {
62
+ /** Read live via the getter below: after a mid-run re-mint (`refreshGitToken`
63
+ * recovers an auth-class push 401 with a fresh token, revoking the old one),
64
+ * this reflects the CURRENT git token. Push-class tools (push_branch,
65
+ * push_tags, delete_branch, git_fetch) that read it per call therefore never
66
+ * reuse a stale/revoked snapshot. Mirrors the `getMcpTokenRefresh` /
67
+ * `githubInstallationToken` live-getter pattern (pullfrog #891/#964). */
68
+ gitToken: string;
69
+ mcpToken: string;
70
+ /** single-flight re-mint of the git token, threaded into pushWithRetry so an
71
+ * auth-class push 401 can recover with a fresh token (pullfrog #972). undefined
72
+ * when re-minting isn't possible (off-CI or external GH_TOKEN). */
73
+ refreshGitToken?: (stale: string) => Promise<string>;
74
+ [Symbol.asyncDispose]: () => Promise<void>;
75
+ };
76
+
77
+ type ResolveTokensParams = {
78
+ push: PushPermission;
79
+ };
80
+
81
+ /**
82
+ * resolve tokens for the action run.
83
+ *
84
+ * creates two separate tokens:
85
+ * - gitToken: contents permission based on `push` setting (assumed exfiltratable)
86
+ * - push: enabled → contents:write (can push)
87
+ * - push: disabled → contents:read (read-only)
88
+ * - mcpToken: full installation token - used for GitHub API calls in MCP tools (not exfiltratable)
89
+ *
90
+ * security-conscious users can pass their own token via GH_TOKEN env var or inputs.token.
91
+ */
92
+ export async function resolveTokens(
93
+ params: ResolveTokensParams,
94
+ ): Promise<TokenRef> {
95
+ assert(!mcpTokenValue, "tokens are already resolved");
96
+
97
+ const externalToken = process.env.GH_TOKEN;
98
+
99
+ // external token takes precedence - use for both git and MCP
100
+ if (externalToken) {
101
+ mcpTokenValue = externalToken;
102
+
103
+ if (isGitHubActions) {
104
+ core.setSecret(externalToken);
105
+ }
106
+
107
+ log.info("» using external GH_TOKEN for both git and MCP");
108
+
109
+ return {
110
+ gitToken: externalToken,
111
+ mcpToken: externalToken,
112
+ async [Symbol.asyncDispose]() {
113
+ mcpTokenValue = undefined;
114
+ // GH_TOKEN isn't acquired here, so it's not revoked here either
115
+ },
116
+ };
117
+ }
118
+
119
+ // create git token based on push permission (assumed exfiltratable)
120
+ // disabled = read-only, restricted/enabled = write (MCP tools enforce branch restrictions)
121
+ // workflows permission is write-only in the API, so only requested when pushing is allowed
122
+ const gitPermissions =
123
+ params.push === "disabled"
124
+ ? { contents: "read" as const }
125
+ : { contents: "write" as const, workflows: "write" as const };
126
+ let currentGitToken = await acquireNewToken({ permissions: gitPermissions });
127
+ if (isGitHubActions) {
128
+ core.setSecret(currentGitToken);
129
+ }
130
+ log.info(
131
+ `» acquired git token (${Object.entries(gitPermissions)
132
+ .map((e) => e.join(":"))
133
+ .join(", ")})`,
134
+ );
135
+
136
+ // MCP token scoped to only what MCP tools actually need.
137
+ // not exfiltratable (only accessible via MCP tools), but scoped as defense-in-depth
138
+ // so even a compromised tool context can't touch secrets, admin, etc.
139
+ const mcpPermissions = {
140
+ contents: "write",
141
+ pull_requests: "write",
142
+ issues: "write",
143
+ checks: "read",
144
+ actions: "read",
145
+ } as const;
146
+ let currentMcpToken = await acquireNewToken({ permissions: mcpPermissions });
147
+ if (isGitHubActions) {
148
+ core.setSecret(currentMcpToken);
149
+ }
150
+ log.info(
151
+ `» acquired scoped MCP token (${Object.entries(mcpPermissions)
152
+ .map((e) => e.join(":"))
153
+ .join(", ")})`,
154
+ );
155
+
156
+ mcpTokenValue = currentMcpToken;
157
+
158
+ // Stash the OIDC creds NOW — resolveTokens runs before main.ts scrubs the
159
+ // ACTIONS_ID_TOKEN_REQUEST_* env vars (in every shell mode), so without this the
160
+ // refreshers below couldn't re-mint mid-run. undefined off-CI (local GitHub-App
161
+ // path) → no refresher, which is fine: re-mint is a CI replication-lag cure.
162
+ const oidc: OidcCreds | undefined = readOidcCreds();
163
+ // Feed the same snapshot to keyless (Sigstore) evidence signing, which runs
164
+ // later in the agent loop after these env vars are scrubbed. No-op off-CI.
165
+ stashKeylessOidcCreds(oidc);
166
+
167
+ // Single-flight re-minters (pullfrog #891/#972). Each coalesces concurrent
168
+ // callers on the same stale token: a caller holding an already-superseded token
169
+ // gets the current one without minting, and only the first caller of a given
170
+ // stale token triggers acquireNewToken. The memo clears in `finally` so a
171
+ // transient mint failure doesn't permanently poison the run.
172
+ let gitRefreshPromise: Promise<string> | undefined;
173
+ const refreshGitToken = oidc
174
+ ? (stale: string): Promise<string> => {
175
+ assert(mcpTokenValue, "tokens already disposed");
176
+ if (stale !== currentGitToken) return Promise.resolve(currentGitToken);
177
+ gitRefreshPromise ??= acquireNewToken({
178
+ permissions: gitPermissions,
179
+ oidc,
180
+ })
181
+ .then((fresh) => {
182
+ if (isGitHubActions) core.setSecret(fresh);
183
+ const superseded = currentGitToken;
184
+ currentGitToken = fresh;
185
+ void revokeGitHubInstallationToken(superseded);
186
+ log.warning(
187
+ "» GitHub rejected the git token; re-acquired a fresh installation token",
188
+ );
189
+ return fresh;
190
+ })
191
+ .finally(() => {
192
+ gitRefreshPromise = undefined;
193
+ });
194
+ return gitRefreshPromise;
195
+ }
196
+ : undefined;
197
+
198
+ let mcpRefreshPromise: Promise<string> | undefined;
199
+ refreshMcpTokenFn = oidc
200
+ ? (stale: string): Promise<string> => {
201
+ assert(mcpTokenValue, "tokens already disposed");
202
+ if (stale !== currentMcpToken) return Promise.resolve(currentMcpToken);
203
+ mcpRefreshPromise ??= acquireNewToken({
204
+ permissions: mcpPermissions,
205
+ oidc,
206
+ })
207
+ .then((fresh) => {
208
+ if (isGitHubActions) core.setSecret(fresh);
209
+ const superseded = currentMcpToken;
210
+ currentMcpToken = fresh;
211
+ mcpTokenValue = fresh;
212
+ void revokeGitHubInstallationToken(superseded);
213
+ log.warning(
214
+ "» GitHub rejected the MCP token; re-acquired a fresh installation token",
215
+ );
216
+ return fresh;
217
+ })
218
+ .finally(() => {
219
+ mcpRefreshPromise = undefined;
220
+ });
221
+ return mcpRefreshPromise;
222
+ }
223
+ : undefined;
224
+
225
+ let disposingRef: PromiseWithResolvers<void> | undefined;
226
+
227
+ const dispose = async () => {
228
+ if (disposingRef) {
229
+ // this can happen if the signal arrives when disposing tokens
230
+ // we make sure to wait for the current dispose to complete
231
+ return disposingRef.promise;
232
+ }
233
+ disposingRef = Promise.withResolvers();
234
+ try {
235
+ mcpTokenValue = undefined;
236
+ refreshMcpTokenFn = undefined;
237
+ // revoke the freshest tokens (a re-mint already revoked any superseded one)
238
+ await Promise.all([
239
+ revokeGitHubInstallationToken(currentGitToken),
240
+ revokeGitHubInstallationToken(currentMcpToken),
241
+ ]);
242
+ } finally {
243
+ removeSignalHandler();
244
+ disposingRef.resolve();
245
+ disposingRef = undefined;
246
+ }
247
+ };
248
+
249
+ const removeSignalHandler = onExitSignal(dispose);
250
+
251
+ return {
252
+ // live getter (not a captured value): a mid-run re-mint advances
253
+ // `currentGitToken` and revokes the prior one, so any consumer that reads
254
+ // `tokenRef.gitToken` per call always sees the fresh token. see #964.
255
+ get gitToken() {
256
+ return currentGitToken;
257
+ },
258
+ mcpToken: currentMcpToken,
259
+ ...(refreshGitToken ? { refreshGitToken } : {}),
260
+ [Symbol.asyncDispose]: dispose,
261
+ };
262
+ }
263
+
264
+ /**
265
+ * get the MCP token from memory.
266
+ * this is the token used for GitHub API calls in MCP tools.
267
+ */
268
+ export function getGitHubInstallationToken(): string {
269
+ assert(mcpTokenValue, "tokens not set. call resolveTokens first.");
270
+ return mcpTokenValue;
271
+ }
272
+
273
+ export async function revokeGitHubInstallationToken(
274
+ token: string,
275
+ ): Promise<void> {
276
+ const apiUrl = process.env.GITHUB_API_URL || "https://api.github.com";
277
+
278
+ try {
279
+ await fetch(`${apiUrl}/installation/token`, {
280
+ method: "DELETE",
281
+ headers: {
282
+ Accept: "application/vnd.github+json",
283
+ Authorization: `Bearer ${token}`,
284
+ "X-GitHub-Api-Version": "2022-11-28",
285
+ },
286
+ signal: AbortSignal.timeout(10_000),
287
+ });
288
+ log.debug("» installation token revoked");
289
+ } catch (error) {
290
+ log.info(
291
+ `Failed to revoke installation token: ${error instanceof Error ? error.message : String(error)}`,
292
+ );
293
+ }
294
+ }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Tool-licence classification (dependency posture; the "non-permissive-tool
3
+ * confirmation gate").
4
+ *
5
+ * Infraweaver ORCHESTRATES external tools — it never bundles or redistributes
6
+ * their binaries ("be an orchestrator, not a redistributor"). This module
7
+ * makes the licence of every selectable tool explicit so the engine can DEFAULT
8
+ * to the permissively-licensed tools and treat a non-permissive one (tflint's
9
+ * embedded BUSL Terraform fork, HashiCorp's terraform-mcp-server) as an
10
+ * *informed, named opt-in* rather than something whose output is consumed
11
+ * silently. Pure data + pure predicates — the gate that consumes it lives in
12
+ * [[toolSelection]].
13
+ */
14
+
15
+ /** every external tool the engine can be configured to run. */
16
+ export type ToolId =
17
+ | "terraform"
18
+ | "tflint"
19
+ | "trivy"
20
+ | "checkov"
21
+ | "infracost"
22
+ | "gitleaks"
23
+ | "conftest"
24
+ | "terratest"
25
+ | "terraform_mcp"
26
+ | "opentofu_mcp";
27
+
28
+ /**
29
+ * Coarse licence family the gate reasons about:
30
+ * - `permissive` — MIT / Apache-2.0 / BSD / ISC: default-enabled.
31
+ * - `copyleft` — MPL / (L)GPL / AGPL: gated (explicit opt-in).
32
+ * - `source-available` — BUSL / SSPL / Elastic: gated (explicit opt-in).
33
+ */
34
+ export type LicenseClass = "permissive" | "copyleft" | "source-available";
35
+
36
+ export interface ToolLicense {
37
+ id: ToolId;
38
+ /** display name for logs / PR notes. */
39
+ name: string;
40
+ /** human-facing SPDX-ish identifier (shown, never parsed). */
41
+ license: string;
42
+ class: LicenseClass;
43
+ /**
44
+ * The core Terraform CLI is the SUBSTRATE the engine cannot run without and
45
+ * which the operator installs themselves — invoking it is never
46
+ * redistribution. It is licence-classified for honesty (Terraform moved to
47
+ * BUSL-1.1 at v1.6) but EXEMPT from the opt-in gate, so a Terraform fixer
48
+ * always has Terraform.
49
+ */
50
+ required?: boolean;
51
+ }
52
+
53
+ /**
54
+ * The single source of truth for what each tool is licensed under. Verified
55
+ * against the "third-party dependency posture" note (June 2026). Keep in sync
56
+ * when a tool's licence changes (e.g. a vendor relicensing event).
57
+ */
58
+ export const TOOL_LICENSES: Readonly<Record<ToolId, ToolLicense>> = {
59
+ terraform: {
60
+ id: "terraform",
61
+ name: "Terraform CLI",
62
+ license: "BUSL-1.1",
63
+ class: "source-available",
64
+ required: true,
65
+ },
66
+ // tflint is MPL-2.0, but it embeds a BUSL Terraform fork — flagged as the
67
+ // canonical "never bundle/redistribute; invoke as an external process" case.
68
+ tflint: {
69
+ id: "tflint",
70
+ name: "TFLint",
71
+ license: "MPL-2.0",
72
+ class: "copyleft",
73
+ },
74
+ trivy: {
75
+ id: "trivy",
76
+ name: "Trivy",
77
+ license: "Apache-2.0",
78
+ class: "permissive",
79
+ },
80
+ checkov: {
81
+ id: "checkov",
82
+ name: "Checkov",
83
+ license: "Apache-2.0",
84
+ class: "permissive",
85
+ },
86
+ infracost: {
87
+ id: "infracost",
88
+ name: "Infracost CLI",
89
+ license: "Apache-2.0",
90
+ class: "permissive",
91
+ },
92
+ gitleaks: {
93
+ id: "gitleaks",
94
+ name: "gitleaks",
95
+ license: "MIT",
96
+ class: "permissive",
97
+ },
98
+ conftest: {
99
+ id: "conftest",
100
+ name: "Conftest (OPA)",
101
+ license: "Apache-2.0",
102
+ class: "permissive",
103
+ },
104
+ terratest: {
105
+ id: "terratest",
106
+ name: "Terratest",
107
+ license: "Apache-2.0",
108
+ class: "permissive",
109
+ },
110
+ // HashiCorp's terraform-mcp-server, run as a Docker image — a redistribution-
111
+ // sensitive HashiCorp surface, so it is gated like tflint.
112
+ terraform_mcp: {
113
+ id: "terraform_mcp",
114
+ name: "terraform-mcp-server",
115
+ license: "MPL-2.0",
116
+ class: "copyleft",
117
+ },
118
+ // The OpenTofu project's registry MCP server — the permissively-preferred
119
+ // sibling to terraform-mcp-server (OpenTofu is the MPL fork; Terraform is BUSL).
120
+ // MPL-2.0 → gated as an explicit opt-in, same class as terraform_mcp. Reached
121
+ // as OpenTofu's own hosted endpoint (public registry data, no credentials), so
122
+ // there's no binary to redistribute — but kept behind the opt-in gate for
123
+ // parity and because it's an external network surface the operator chooses.
124
+ opentofu_mcp: {
125
+ id: "opentofu_mcp",
126
+ name: "opentofu-mcp-server",
127
+ license: "MPL-2.0",
128
+ class: "copyleft",
129
+ },
130
+ } as const;
131
+
132
+ export const ALL_TOOL_IDS = Object.keys(TOOL_LICENSES) as ToolId[];
133
+
134
+ /** a permissively-licensed tool can be enabled by default; anything else needs
135
+ * an explicit, licence-named opt-in. */
136
+ export function isPermissive(c: LicenseClass): boolean {
137
+ return c === "permissive";
138
+ }
139
+
140
+ /**
141
+ * A tool whose output must NOT be consumed without an explicit, licence-named
142
+ * opt-in: non-permissive AND not the required substrate. This is the predicate
143
+ * the confirmation gate is built on.
144
+ */
145
+ export function isLicenseGated(id: ToolId): boolean {
146
+ const t = TOOL_LICENSES[id];
147
+ return !t.required && !isPermissive(t.class);
148
+ }
149
+
150
+ /** every tool currently behind the licence gate (for docs / reporting). */
151
+ export const LICENSE_GATED_TOOLS: ToolId[] =
152
+ ALL_TOOL_IDS.filter(isLicenseGated);