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,452 @@
1
+ /**
2
+ * Logging utilities that work well in both local and GitHub Actions environments
3
+ */
4
+
5
+ import { AsyncLocalStorage } from "node:async_hooks";
6
+ import * as core from "@actions/core";
7
+ import { table } from "table";
8
+ import { type AgentUsage, formatCostUsd } from "#app/agents/shared";
9
+ import { isGitHubActions, isInsideDocker } from "#app/utils/globals";
10
+ import { redactSecrets } from "#app/utils/redact";
11
+
12
+ // --- log prefix via AsyncLocalStorage ---
13
+
14
+ type LogContext = { prefix: string };
15
+
16
+ const logContext = new AsyncLocalStorage<LogContext>();
17
+
18
+ const MAGENTA = "\x1b[35m";
19
+ const RESET = "\x1b[0m";
20
+
21
+ /** run `fn` with every log line prefixed by `prefix` (e.g. "[task-label]") in magenta */
22
+ export function withLogPrefix<T>(prefix: string, fn: () => Promise<T>): Promise<T> {
23
+ return logContext.run({ prefix }, fn);
24
+ }
25
+
26
+ function prefixLines(message: string): string {
27
+ const ctx = logContext.getStore();
28
+ if (!ctx) return message;
29
+ const colored = `${MAGENTA}${ctx.prefix}${RESET} `;
30
+ return message
31
+ .split("\n")
32
+ .map((line) => `${colored}${line}`)
33
+ .join("\n");
34
+ }
35
+
36
+ /** plain-text prefix (no ANSI) for GitHub Actions group names */
37
+ function prefixPlain(name: string): string {
38
+ const ctx = logContext.getStore();
39
+ if (!ctx) return name;
40
+ return `${ctx.prefix} ${name}`;
41
+ }
42
+
43
+ // --- log sink ----------------------------------------------------------------
44
+
45
+ type LogSink = "actions" | "stderr";
46
+
47
+ let sink: LogSink = "actions";
48
+
49
+ /**
50
+ * Route ALL log output to stderr instead of `@actions/core` (which writes to
51
+ * stdout). Required before starting a stdio MCP server: stdout is the JSON-RPC
52
+ * channel there, and a single stray diagnostic line corrupts the framing.
53
+ * The GitHub Action path never calls this — its sink stays `@actions/core`.
54
+ */
55
+ export function setLogSink(next: LogSink): void {
56
+ sink = next;
57
+ }
58
+
59
+ /**
60
+ * info-level line via the active sink.
61
+ *
62
+ * Scrub secret-shaped substrings here, at the single sink primitive, so redaction
63
+ * is truly sink-independent. `formatArgs` already redacts the `info`/`success`/`debug`
64
+ * lines, but `box`/`table`/`separator`/`group` build their content directly and reach
65
+ * the sink through this function without passing through `formatArgs` — without this
66
+ * pass a secret printed via `log.box(...)` would leak in cleartext on stderr/local.
67
+ * `redactSecrets` is idempotent and allocation-light on the no-secret path, so the
68
+ * double-pass on the already-redacted lines is cheap.
69
+ */
70
+ function emitInfo(line: string): void {
71
+ const safe = redactSecrets(line);
72
+ if (sink === "stderr") {
73
+ process.stderr.write(`${safe}\n`);
74
+ return;
75
+ }
76
+ core.info(safe);
77
+ }
78
+
79
+ const isRunnerDebugEnabled = () => core.isDebug();
80
+
81
+ const isLocalDebugEnabled = () =>
82
+ process.env.LOG_LEVEL === "debug" || process.env.ACTIONS_STEP_DEBUG === "true";
83
+
84
+ const isDebugEnabled = () => isLocalDebugEnabled() || isRunnerDebugEnabled();
85
+
86
+ /** timestamp prefix for debug mode — empty string when debug is off */
87
+ function ts(): string {
88
+ return isDebugEnabled() ? `[${new Date().toISOString()}] ` : "";
89
+ }
90
+
91
+ /**
92
+ * Format arguments into a single string for logging.
93
+ *
94
+ * The joined line is passed through {@link redactSecrets} so secret-shaped
95
+ * substrings are scrubbed regardless of the active sink — `core.setSecret` only masks
96
+ * on the GitHub `actions` sink, leaving stderr (every stdio MCP server) and local dev
97
+ * unmasked.
98
+ */
99
+ function formatArgs(args: unknown[]): string {
100
+ const joined = args
101
+ .map((arg) => {
102
+ if (typeof arg === "string") return arg;
103
+ if (arg instanceof Error) return `${arg.message}\n${arg.stack}`;
104
+ return JSON.stringify(arg);
105
+ })
106
+ .join(" ");
107
+ return redactSecrets(joined);
108
+ }
109
+
110
+ /**
111
+ * Start a collapsed group (GitHub Actions) or regular group (local)
112
+ */
113
+ function startGroup(name: string): void {
114
+ const prefixed = prefixPlain(name);
115
+ if (sink === "stderr") {
116
+ emitInfo(`▼ ${prefixed}`);
117
+ return;
118
+ }
119
+ if (isGitHubActions) {
120
+ core.startGroup(prefixed);
121
+ } else {
122
+ console.group(prefixed);
123
+ }
124
+ }
125
+
126
+ /**
127
+ * End a collapsed group
128
+ */
129
+ function endGroup(): void {
130
+ if (sink === "stderr") return;
131
+ if (isGitHubActions) {
132
+ core.endGroup();
133
+ } else {
134
+ console.groupEnd();
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Run a callback within a collapsed group
140
+ */
141
+ function group(name: string, fn: () => void): void {
142
+ startGroup(name);
143
+ fn();
144
+ endGroup();
145
+ }
146
+
147
+ /**
148
+ * Print a formatted box with text (for console output)
149
+ */
150
+ function boxString(
151
+ text: string,
152
+ options?: {
153
+ title?: string;
154
+ maxWidth?: number;
155
+ indent?: string;
156
+ padding?: number;
157
+ },
158
+ ): string {
159
+ const { title, maxWidth = 80, indent = "", padding = 1 } = options || {};
160
+
161
+ const lines = text.trim().split("\n");
162
+ const wrappedLines: string[] = [];
163
+
164
+ for (const line of lines) {
165
+ if (line.length <= maxWidth - padding * 2) {
166
+ wrappedLines.push(line);
167
+ } else {
168
+ const words = line.split(" ");
169
+ let currentLine = "";
170
+
171
+ for (const word of words) {
172
+ const testLine = currentLine ? `${currentLine} ${word}` : word;
173
+ if (testLine.length <= maxWidth - padding * 2) {
174
+ currentLine = testLine;
175
+ } else {
176
+ if (currentLine) {
177
+ wrappedLines.push(currentLine);
178
+ currentLine = "";
179
+ }
180
+ // wrap long words by breaking them into chunks
181
+ const maxLineLength = maxWidth - padding * 2;
182
+ let remainingWord = word;
183
+ while (remainingWord.length > maxLineLength) {
184
+ wrappedLines.push(remainingWord.substring(0, maxLineLength));
185
+ remainingWord = remainingWord.substring(maxLineLength);
186
+ }
187
+ currentLine = remainingWord;
188
+ }
189
+ }
190
+
191
+ if (currentLine) {
192
+ wrappedLines.push(currentLine);
193
+ }
194
+ }
195
+ }
196
+
197
+ const maxLineLength = Math.max(...wrappedLines.map((line) => line.length));
198
+ const contentBoxWidth = maxLineLength + padding * 2;
199
+
200
+ // ensure box width is at least as wide as the title line when title exists
201
+ const titleLineLength = title ? ` ${title} `.length : 0;
202
+ const boxWidth = Math.max(contentBoxWidth, titleLineLength);
203
+
204
+ let result = "";
205
+
206
+ if (title) {
207
+ const titleLine = ` ${title} `;
208
+ const titlePadding = Math.max(0, boxWidth - titleLine.length);
209
+ result += `${indent}┌${titleLine}${"─".repeat(titlePadding)}┐\n`;
210
+ }
211
+
212
+ if (!title) {
213
+ result += `${indent}┌${"─".repeat(boxWidth)}┐\n`;
214
+ }
215
+
216
+ for (const line of wrappedLines) {
217
+ const paddedLine = line.padEnd(maxLineLength);
218
+ result += `${indent}│${" ".repeat(padding)}${paddedLine}${" ".repeat(padding)}│\n`;
219
+ }
220
+
221
+ result += `${indent}└${"─".repeat(boxWidth)}┘`;
222
+
223
+ return result;
224
+ }
225
+
226
+ /**
227
+ * Print a formatted box with text
228
+ */
229
+ function box(
230
+ text: string,
231
+ options?: {
232
+ title?: string;
233
+ maxWidth?: number;
234
+ },
235
+ ): void {
236
+ const boxContent = boxString(text, options);
237
+ emitInfo(prefixLines(boxContent));
238
+ }
239
+
240
+ /**
241
+ * Overwrite the job summary with the given text.
242
+ * Skips if:
243
+ * - Not in GitHub Actions
244
+ * - Running inside Docker (CI tests inherit host env vars but can't access host paths)
245
+ * - GITHUB_STEP_SUMMARY not set
246
+ */
247
+ export async function writeSummary(text: string): Promise<void> {
248
+ if (!isGitHubActions) return;
249
+
250
+ // CI tests run in Docker with GITHUB_ACTIONS=true inherited from host,
251
+ // but the GITHUB_STEP_SUMMARY path points to a host filesystem location
252
+ // that doesn't exist inside the container
253
+ if (isInsideDocker) return;
254
+
255
+ if (!process.env.GITHUB_STEP_SUMMARY) return;
256
+
257
+ // LLM02: the job summary includes raw agent output — scrub secrets before it
258
+ // lands in the durable GitHub Actions step summary. Idempotent + no-op on clean text.
259
+ await core.summary.addRaw(redactSecrets(text)).write({ overwrite: true });
260
+ }
261
+
262
+ /**
263
+ * Print a formatted table using the table package
264
+ */
265
+ function printTable(
266
+ rows: Array<Array<{ data: string; header?: boolean } | string>>,
267
+ options?: {
268
+ title?: string;
269
+ },
270
+ ): void {
271
+ const { title } = options || {};
272
+
273
+ // Convert rows to string arrays for the table package
274
+ const tableData = rows.map((row) =>
275
+ row.map((cell) => {
276
+ if (typeof cell === "string") {
277
+ return cell;
278
+ }
279
+ return cell.data;
280
+ }),
281
+ );
282
+
283
+ const formatted = table(tableData);
284
+
285
+ if (title) {
286
+ emitInfo(prefixLines(`\n${title}`));
287
+ }
288
+ emitInfo(prefixLines(`\n${formatted}\n`));
289
+ }
290
+
291
+ /**
292
+ * Print a separator line
293
+ */
294
+ function separator(length: number = 50): void {
295
+ const separatorText = "─".repeat(length);
296
+ emitInfo(prefixLines(separatorText));
297
+ }
298
+
299
+ /**
300
+ * Main logging utility object - import this once and access all utilities
301
+ */
302
+ export const log = {
303
+ /** Print info message */
304
+ info: (...args: unknown[]): void => {
305
+ emitInfo(prefixLines(`${ts()}${formatArgs(args)}`));
306
+ },
307
+
308
+ /** Print a warning message. Use only for warnings that should be displayed in the job summary. */
309
+ warning: (...args: unknown[]): void => {
310
+ if (sink === "stderr") {
311
+ emitInfo(prefixLines(`${ts()}warning: ${formatArgs(args)}`));
312
+ return;
313
+ }
314
+ core.warning(prefixLines(`${ts()}${formatArgs(args)}`));
315
+ },
316
+
317
+ /** Print an error message. Use only for errors that should be displayed in the job summary. */
318
+ error: (...args: unknown[]): void => {
319
+ if (sink === "stderr") {
320
+ emitInfo(prefixLines(`${ts()}error: ${formatArgs(args)}`));
321
+ return;
322
+ }
323
+ core.error(prefixLines(`${ts()}${formatArgs(args)}`));
324
+ },
325
+
326
+ /** Print success message */
327
+ success: (...args: unknown[]): void => {
328
+ emitInfo(prefixLines(`${ts()}» ${formatArgs(args)}`));
329
+ },
330
+
331
+ /** Print debug message (only when debug mode is enabled) */
332
+ debug: (...args: unknown[]): void => {
333
+ if (sink === "actions" && isRunnerDebugEnabled()) {
334
+ core.debug(prefixLines(formatArgs(args)));
335
+ return;
336
+ }
337
+ if (isLocalDebugEnabled()) {
338
+ emitInfo(prefixLines(`${ts()}[DEBUG] ${formatArgs(args)}`));
339
+ }
340
+ },
341
+
342
+ /** Print a formatted box with text */
343
+ box,
344
+
345
+ /** Print a formatted table using the table package */
346
+ table: printTable,
347
+
348
+ /** Print a separator line */
349
+ separator,
350
+
351
+ /** Start a collapsed group (GitHub Actions) or regular group (local) */
352
+ startGroup,
353
+
354
+ /** End a collapsed group */
355
+ endGroup,
356
+
357
+ /** Run a callback within a collapsed group */
358
+ group,
359
+
360
+ /** Log tool call information to console with formatted output */
361
+ toolCall: ({ toolName, input }: { toolName: string; input: unknown }): void => {
362
+ const inputFormatted = formatJsonValue(input);
363
+ const output = inputFormatted !== "{}" ? `» ${toolName}(${inputFormatted})` : `» ${toolName}()`;
364
+
365
+ log.info(output.trimEnd());
366
+ },
367
+ };
368
+
369
+ /**
370
+ * Format a value as JSON, using compact format for simple values and pretty-printed for complex ones
371
+ */
372
+ export function formatJsonValue(value: unknown): string {
373
+ const compact = JSON.stringify(value);
374
+ return compact.length > 80 || compact.includes("\n") ? JSON.stringify(value, null, 2) : compact;
375
+ }
376
+
377
+ /**
378
+ * Format a multi-line string with proper indentation for tool call output
379
+ * First line has the label, subsequent lines are indented 4 spaces
380
+ */
381
+ export function formatIndentedField(label: string, content: string): string {
382
+ if (!content.includes("\n")) {
383
+ return ` ${label}: ${content}\n`;
384
+ }
385
+
386
+ const lines = content.split("\n");
387
+ let formatted = ` ${label}: ${lines[0]}\n`;
388
+ for (let i = 1; i < lines.length; i++) {
389
+ formatted += ` ${lines[i]}\n`;
390
+ }
391
+ return formatted;
392
+ }
393
+
394
+ /**
395
+ * format aggregated usage data as a markdown table for the GitHub step summary.
396
+ *
397
+ * columns mirror the per-run stdout token table emitted by `logTokenTable`
398
+ * (Input / Cache Read / Cache Write / Output / Total / Cost ($)) so the job
399
+ * summary and the in-run logs can be compared row-for-row.
400
+ *
401
+ * notes:
402
+ * - `AgentUsage.inputTokens` is the sum of non-cached input + cache read
403
+ * + cache write (set that way by both agent harnesses' `buildUsage`),
404
+ * so the non-cached Input column is recovered by subtracting cache fields.
405
+ * - `costUsd` is sourced from models.dev (OpenCode) or `total_cost_usd`
406
+ * (Claude CLI). absent rows show `—` so per-agent coverage is obvious.
407
+ */
408
+ export function formatUsageSummary(entries: AgentUsage[]): string {
409
+ if (entries.length === 0) return "";
410
+
411
+ const header = "| Agent | Input | Cache Read | Cache Write | Output | Total | Cost ($) |";
412
+ const separatorRow = "| --- | ---: | ---: | ---: | ---: | ---: | ---: |";
413
+ const fmt = (n: number) => n.toLocaleString("en-US");
414
+
415
+ const nonCachedInput = (e: AgentUsage): number =>
416
+ Math.max(0, e.inputTokens - (e.cacheReadTokens ?? 0) - (e.cacheWriteTokens ?? 0));
417
+ const totalFor = (e: AgentUsage): number =>
418
+ nonCachedInput(e) + (e.cacheReadTokens ?? 0) + (e.cacheWriteTokens ?? 0) + e.outputTokens;
419
+ const costCell = (e: AgentUsage): string =>
420
+ typeof e.costUsd === "number" && e.costUsd > 0 ? formatCostUsd(e.costUsd) : "—";
421
+
422
+ const rows = entries.map(
423
+ (e) =>
424
+ `| ${e.agent} | ${fmt(nonCachedInput(e))} | ${fmt(e.cacheReadTokens ?? 0)} | ${fmt(e.cacheWriteTokens ?? 0)} | ${fmt(e.outputTokens)} | ${fmt(totalFor(e))} | ${costCell(e)} |`,
425
+ );
426
+
427
+ const totalsRows: string[] = [];
428
+ if (entries.length > 1) {
429
+ const totalInput = entries.reduce((sum, e) => sum + nonCachedInput(e), 0);
430
+ const totalOutput = entries.reduce((sum, e) => sum + e.outputTokens, 0);
431
+ const totalCacheRead = entries.reduce((sum, e) => sum + (e.cacheReadTokens ?? 0), 0);
432
+ const totalCacheWrite = entries.reduce((sum, e) => sum + (e.cacheWriteTokens ?? 0), 0);
433
+ const grandTotal = totalInput + totalCacheRead + totalCacheWrite + totalOutput;
434
+ const totalCostUsd = entries.reduce((sum, e) => sum + (e.costUsd ?? 0), 0);
435
+ const totalCostCell = totalCostUsd > 0 ? `**${formatCostUsd(totalCostUsd)}**` : "—";
436
+ totalsRows.push(
437
+ `| **Total** | **${fmt(totalInput)}** | **${fmt(totalCacheRead)}** | **${fmt(totalCacheWrite)}** | **${fmt(totalOutput)}** | **${fmt(grandTotal)}** | ${totalCostCell} |`,
438
+ );
439
+ }
440
+
441
+ return [
442
+ "<details>",
443
+ "<summary>Usage</summary>",
444
+ "",
445
+ header,
446
+ separatorRow,
447
+ ...rows,
448
+ ...totalsRows,
449
+ "",
450
+ "</details>",
451
+ ].join("\n");
452
+ }
@@ -0,0 +1,105 @@
1
+ import type { Agent } from "#app/agents/index";
2
+ import { resolveAgent, resolveModelWithGating } from "#app/utils/agent";
3
+ import { validateAgentApiKey } from "#app/utils/apiKeys";
4
+ import { installCodexAuth } from "#app/utils/codexHome";
5
+ import {
6
+ captureAuthorizedModels,
7
+ captureBaselineModels,
8
+ getAuthorizedModels,
9
+ } from "#app/utils/openCodeModels";
10
+ import { applyManagedProxy, applyModelEnv, type ProxyMint } from "#app/utils/proxyModel";
11
+ import type { AccountPlan } from "#app/utils/runContext";
12
+
13
+ /**
14
+ * The single owner of the model decision. "Which model runs, on which harness,
15
+ * with what auth" used to be smeared across main.ts and four utils; the two
16
+ * entry points here are the whole story:
17
+ *
18
+ * 1. {@link captureModelAuthority} — the ordered BYOK-authority capture
19
+ * (baseline → Codex auth.json → authorized set), returned as an explicit
20
+ * value instead of hidden module state the caller must remember to
21
+ * sequence correctly.
22
+ * 2. {@link resolveRunModel} — BYOK gate → managed-proxy overlay → env
23
+ * patch → api-key validation, returning the routed model + harness.
24
+ *
25
+ * The building blocks stay where they are (catalog in models.ts, gate in
26
+ * agent.ts, proxy overlay in proxyModel.ts); this module owns their
27
+ * composition and ordering.
28
+ */
29
+
30
+ /**
31
+ * Capture the BYOK model authority in the one order that is correct:
32
+ * the BASELINE set (what OpenCode can route from the runner's pre-existing
33
+ * env alone) must be snapshotted BEFORE Codex auth.json is materialized, and
34
+ * the AUTHORIZED set after — their diff is the Codex credential's
35
+ * contribution, logged by the capture. Returns the authorized set, the
36
+ * authoritative input for {@link resolveRunModel}.
37
+ */
38
+ export function captureModelAuthority(opencodeCliPath: string): Set<string> {
39
+ captureBaselineModels(opencodeCliPath);
40
+ installCodexAuth();
41
+ captureAuthorizedModels(opencodeCliPath);
42
+ return getAuthorizedModels();
43
+ }
44
+
45
+ export interface RoutedRunModel {
46
+ /** the effective model that will run (post-fallback); undefined → auto-select */
47
+ model: string | undefined;
48
+ /** the slug to surface in footers/logs */
49
+ effectiveSlug: string | undefined;
50
+ /** the harness resolved for the effective model */
51
+ agent: Agent;
52
+ /** set only when the free safety-net fallback engaged */
53
+ fallback?: { from: string; to: string };
54
+ /** operator warnings for the caller to log */
55
+ warnings: string[];
56
+ }
57
+
58
+ /**
59
+ * Resolve the model + auth for this run in one call: the BYOK gate (resolve
60
+ * slug → pick harness → free-fallback decision), the managed EU Bedrock proxy
61
+ * overlay (a no-op unless PAYG with no BYO key), the env patch the routing
62
+ * needs, and the api-key validation the gate asks for. Throws the actionable
63
+ * authorized-model list on an unavailable model, a `BillingError` when the
64
+ * managed path needs a payment method, and the missing-key error when
65
+ * validation fails — all before any agent runs.
66
+ */
67
+ export async function resolveRunModel(input: {
68
+ slug: string | undefined;
69
+ plan: AccountPlan;
70
+ credential: string;
71
+ authorized: Set<string>;
72
+ repo: { owner: string; name: string };
73
+ mint?: ProxyMint;
74
+ }): Promise<RoutedRunModel> {
75
+ const routed = await applyManagedProxy({
76
+ gate: resolveModelWithGating({ slug: input.slug, authorized: input.authorized }),
77
+ plan: input.plan,
78
+ credential: input.credential,
79
+ resolveAgent,
80
+ ...(input.slug ? { slug: input.slug } : {}),
81
+ ...(input.mint ? { mint: input.mint } : {}),
82
+ });
83
+
84
+ if (routed.envToApply) {
85
+ applyModelEnv(routed.envToApply);
86
+ }
87
+
88
+ if (routed.validate) {
89
+ validateAgentApiKey({
90
+ agent: routed.agent,
91
+ model: routed.model ?? routed.effectiveSlug,
92
+ authorized: input.authorized,
93
+ owner: input.repo.owner,
94
+ name: input.repo.name,
95
+ });
96
+ }
97
+
98
+ return {
99
+ model: routed.model,
100
+ effectiveSlug: routed.effectiveSlug,
101
+ agent: routed.agent,
102
+ warnings: routed.warnings,
103
+ ...(routed.fallback ? { fallback: routed.fallback } : {}),
104
+ };
105
+ }
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Org-private cross-repo module fetch (the HepCare shape).
3
+ *
4
+ * Referencing a private module from another repo in your org works today
5
+ * (`git::https://github.com/acme/tf-modules.git//aws/s3?ref=…`), but FETCHING it
6
+ * at `terraform init` does not: the action's own git is locked down (ASKPASS,
7
+ * `credential.helper=`) and the job token is single-repo, so terraform's child
8
+ * `git clone` of the module repo has no credential. This module supplies a
9
+ * scoped one — a PAT / GitHub App token / fine-grained token the operator passes
10
+ * as `module_fetch_token`.
11
+ *
12
+ * Mechanism: Git's `GIT_CONFIG_COUNT` / `GIT_CONFIG_KEY_n` / `GIT_CONFIG_VALUE_n`
13
+ * env injection (Git ≥ 2.31). We add an `http.https://<host>/.extraheader`
14
+ * carrying a Basic auth header (the same pattern actions/checkout uses), scoped
15
+ * to the terraform subprocess only — no global/file config is mutated and the
16
+ * token never lands on disk.
17
+ *
18
+ * SSH / deploy-key sources (`git::ssh://…` / `git::git@host:…`) are a separate
19
+ * transport: `module_fetch_ssh_key` supplies a private key, which — unlike the
20
+ * token — MUST exist as a file for `ssh -i`. We write it 0600 into the run's
21
+ * tmpdir (wiped at run end), never the home dir or a committed path, and point a
22
+ * scoped `GIT_SSH_COMMAND` at it. Both credentials can apply in one run (HTTPS
23
+ * token for `git::https`, SSH key for `git::ssh`); they're independent env.
24
+ */
25
+ import { chmodSync, writeFileSync } from "node:fs";
26
+ import { join } from "node:path";
27
+
28
+ /** the `x-access-token:<token>` Basic header value Git sends per request. */
29
+ function basicAuthHeader(token: string): string {
30
+ const encoded = Buffer.from(`x-access-token:${token}`).toString("base64");
31
+ return `Authorization: Basic ${encoded}`;
32
+ }
33
+
34
+ /**
35
+ * Build the `GIT_CONFIG_*` env that authorises `git clone` of a private module
36
+ * over HTTPS for each host. Pure (token + hosts in, env out) so it is unit-
37
+ * testable without a real git. Empty/whitespace hosts are dropped; hosts are
38
+ * de-duplicated case-insensitively. Returns an empty object only when no usable
39
+ * host remains (the caller treats that as "no module-fetch credential").
40
+ */
41
+ export function buildModuleFetchGitEnv(token: string, hosts: string[]): Record<string, string> {
42
+ const seen = new Set<string>();
43
+ const uniqueHosts: string[] = [];
44
+ for (const h of hosts) {
45
+ const host = h.trim().toLowerCase();
46
+ if (!host || seen.has(host)) continue;
47
+ seen.add(host);
48
+ uniqueHosts.push(host);
49
+ }
50
+ if (uniqueHosts.length === 0) return {};
51
+
52
+ const header = basicAuthHeader(token);
53
+ const env: Record<string, string> = { GIT_CONFIG_COUNT: String(uniqueHosts.length) };
54
+ uniqueHosts.forEach((host, i) => {
55
+ env[`GIT_CONFIG_KEY_${i}`] = `http.https://${host}/.extraheader`;
56
+ env[`GIT_CONFIG_VALUE_${i}`] = header;
57
+ });
58
+ return env;
59
+ }
60
+
61
+ /**
62
+ * The hosts a module-fetch credential should authorise: always github.com, plus
63
+ * the GitHub host the run executes against (a GitHub Enterprise Server instance
64
+ * via `GITHUB_SERVER_URL`) when it differs. Reads the env; pure given it.
65
+ */
66
+ export function moduleFetchHosts(serverUrl = process.env.GITHUB_SERVER_URL): string[] {
67
+ const hosts = ["github.com"];
68
+ if (serverUrl) {
69
+ try {
70
+ const host = new URL(serverUrl).hostname;
71
+ // de-dupe case-insensitively: on github.com-hosted runs GITHUB_SERVER_URL
72
+ // is https://github.com, so the seeded host would otherwise repeat.
73
+ if (host && !hosts.some((h) => h.toLowerCase() === host.toLowerCase())) hosts.push(host);
74
+ } catch {
75
+ /* malformed GITHUB_SERVER_URL — fall back to github.com only */
76
+ }
77
+ }
78
+ return hosts;
79
+ }
80
+
81
+ function defaultWriteKey(path: string, contents: string): void {
82
+ // mode on writeFileSync is honoured on POSIX (the GitHub Actions runner); the
83
+ // explicit chmod is belt-and-suspenders for an existing-file overwrite + Windows
84
+ // local dev (where ssh applies its own perms model).
85
+ writeFileSync(path, contents, { mode: 0o600 });
86
+ try {
87
+ chmodSync(path, 0o600);
88
+ } catch {
89
+ /* best-effort — ssh still refuses a world-readable key on POSIX */
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Build the SSH env for fetching a private `git::ssh://…` module. The key MUST be
95
+ * a file for `ssh -i`, so it is written 0600 into `keyDir` (the run's tmpdir,
96
+ * wiped at run end) — never the home dir, never committed. `IdentitiesOnly=yes`
97
+ * stops ssh falling back to an agent or other keys; `StrictHostKeyChecking=accept-new`
98
+ * trusts the host on first use rather than the interactive prompt that would hang a
99
+ * headless run. Pure given an injected writer (so it is unit-testable without fs).
100
+ * Returns `{}` for a blank key.
101
+ */
102
+ export function buildModuleFetchSshEnv(
103
+ sshKey: string,
104
+ keyDir: string,
105
+ writeKey: (path: string, contents: string) => void = defaultWriteKey,
106
+ ): Record<string, string> {
107
+ const key = sshKey.trim();
108
+ if (!key) return {};
109
+ const keyPath = join(keyDir, "module_fetch_key");
110
+ // ssh rejects a key without a trailing newline.
111
+ writeKey(keyPath, key.endsWith("\n") ? key : `${key}\n`);
112
+ const sshPath = keyPath.replace(/\\/g, "/"); // GIT_SSH_COMMAND is shell-parsed
113
+ return {
114
+ GIT_SSH_COMMAND: `ssh -i "${sshPath}" -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new`,
115
+ };
116
+ }
117
+
118
+ /**
119
+ * Resolve the module-fetch git env for a run, or undefined when neither a
120
+ * `module_fetch_token` (HTTPS) nor a `module_fetch_ssh_key` (SSH) was supplied
121
+ * (the common case — public/registry/local modules need no credential). The result
122
+ * is merged into the env of the `terraform init`/`plan` invocations so private
123
+ * cross-repo modules resolve. SSH activates only when `opts.sshKeyDir` is given (a
124
+ * writable scratch dir for the ephemeral key — the run's tmpdir at the real sites).
125
+ */
126
+ export function resolveModuleFetchEnv(
127
+ payload: { moduleFetchToken?: string | undefined; moduleFetchSshKey?: string | undefined },
128
+ opts: { sshKeyDir?: string; writeKey?: (path: string, contents: string) => void } = {},
129
+ ): Record<string, string> | undefined {
130
+ const env: Record<string, string> = {};
131
+ const token = payload.moduleFetchToken?.trim();
132
+ if (token) Object.assign(env, buildModuleFetchGitEnv(token, moduleFetchHosts()));
133
+ const sshKey = payload.moduleFetchSshKey?.trim();
134
+ if (sshKey && opts.sshKeyDir) {
135
+ Object.assign(env, buildModuleFetchSshEnv(sshKey, opts.sshKeyDir, opts.writeKey));
136
+ }
137
+ return Object.keys(env).length > 0 ? env : undefined;
138
+ }