terramend 0.2.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 (406) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +145 -0
  3. package/dist/agents/claude.d.ts +73 -0
  4. package/dist/agents/claudePretoolGate.d.ts +99 -0
  5. package/dist/agents/gateServer.d.ts +7 -0
  6. package/dist/agents/index.d.ts +6 -0
  7. package/dist/agents/nativeFsDenies.d.ts +28 -0
  8. package/dist/agents/opencode.d.ts +231 -0
  9. package/dist/agents/opencodePlugin.d.ts +85 -0
  10. package/dist/agents/opencodeShared.d.ts +40 -0
  11. package/dist/agents/postRun.d.ts +132 -0
  12. package/dist/agents/reviewer.d.ts +38 -0
  13. package/dist/agents/sessionLabeler.d.ts +97 -0
  14. package/dist/agents/shared.d.ts +189 -0
  15. package/dist/agents/subagentModels.d.ts +19 -0
  16. package/dist/agents/subagentToolGates.d.ts +55 -0
  17. package/dist/cli.mjs +197426 -0
  18. package/dist/external.d.ts +227 -0
  19. package/dist/index.d.ts +6 -0
  20. package/dist/index.js +196783 -0
  21. package/dist/internal/index.d.ts +18 -0
  22. package/dist/internal.js +1714 -0
  23. package/dist/lifecycle.d.ts +2 -0
  24. package/dist/main.d.ts +8 -0
  25. package/dist/mcp/arkConfig.d.ts +1 -0
  26. package/dist/mcp/checkSuite.d.ts +25 -0
  27. package/dist/mcp/checkout.d.ts +77 -0
  28. package/dist/mcp/comment.d.ts +119 -0
  29. package/dist/mcp/commitInfo.d.ts +9 -0
  30. package/dist/mcp/crosswalk.d.ts +105 -0
  31. package/dist/mcp/dependencies.d.ts +8 -0
  32. package/dist/mcp/geminiSanitizer.d.ts +28 -0
  33. package/dist/mcp/git.d.ts +46 -0
  34. package/dist/mcp/guardrails.d.ts +104 -0
  35. package/dist/mcp/issue.d.ts +18 -0
  36. package/dist/mcp/issueComments.d.ts +9 -0
  37. package/dist/mcp/issueEvents.d.ts +9 -0
  38. package/dist/mcp/issueInfo.d.ts +9 -0
  39. package/dist/mcp/labels.d.ts +12 -0
  40. package/dist/mcp/localContext.d.ts +19 -0
  41. package/dist/mcp/moduleExtraction.d.ts +71 -0
  42. package/dist/mcp/moduleTests.d.ts +104 -0
  43. package/dist/mcp/modules.d.ts +179 -0
  44. package/dist/mcp/output.d.ts +12 -0
  45. package/dist/mcp/pathSafety.d.ts +14 -0
  46. package/dist/mcp/policy.d.ts +48 -0
  47. package/dist/mcp/pr.d.ts +49 -0
  48. package/dist/mcp/prInfo.d.ts +9 -0
  49. package/dist/mcp/providerSchema.d.ts +50 -0
  50. package/dist/mcp/review.d.ts +199 -0
  51. package/dist/mcp/reviewComments.d.ts +178 -0
  52. package/dist/mcp/roots.d.ts +58 -0
  53. package/dist/mcp/scope.d.ts +15 -0
  54. package/dist/mcp/selectMode.d.ts +18 -0
  55. package/dist/mcp/server.d.ts +48 -0
  56. package/dist/mcp/shared.d.ts +47 -0
  57. package/dist/mcp/shell.d.ts +37 -0
  58. package/dist/mcp/staleFix.d.ts +51 -0
  59. package/dist/mcp/terraform/cost.d.ts +55 -0
  60. package/dist/mcp/terraform/currency.d.ts +94 -0
  61. package/dist/mcp/terraform/decisions.d.ts +178 -0
  62. package/dist/mcp/terraform/findings.d.ts +75 -0
  63. package/dist/mcp/terraform/plan.d.ts +157 -0
  64. package/dist/mcp/terraform/scanners.d.ts +131 -0
  65. package/dist/mcp/terraform/tools.d.ts +63 -0
  66. package/dist/mcp/terraform/types.d.ts +172 -0
  67. package/dist/mcp/terraform.d.ts +22 -0
  68. package/dist/mcp/terratest.d.ts +83 -0
  69. package/dist/mcp/upload.d.ts +6 -0
  70. package/dist/models.d.ts +171 -0
  71. package/dist/modes.d.ts +26 -0
  72. package/dist/prep/index.d.ts +7 -0
  73. package/dist/prep/installNodeDependencies.d.ts +2 -0
  74. package/dist/prep/installPythonDependencies.d.ts +2 -0
  75. package/dist/prep/types.d.ts +31 -0
  76. package/dist/reviewQuality.d.ts +64 -0
  77. package/dist/skills/terraform-best-practices/SKILL.md +369 -0
  78. package/dist/toolState.d.ts +135 -0
  79. package/dist/utils/activity.d.ts +40 -0
  80. package/dist/utils/agent.d.ts +20 -0
  81. package/dist/utils/agentHangReport.d.ts +38 -0
  82. package/dist/utils/apiFetch.d.ts +19 -0
  83. package/dist/utils/apiKeys.d.ts +41 -0
  84. package/dist/utils/apiUrl.d.ts +20 -0
  85. package/dist/utils/assets.d.ts +8 -0
  86. package/dist/utils/billingErrors.d.ts +85 -0
  87. package/dist/utils/body.d.ts +34 -0
  88. package/dist/utils/buildTerramendFooter.d.ts +25 -0
  89. package/dist/utils/byokFallback.d.ts +85 -0
  90. package/dist/utils/claudeSubscription.d.ts +30 -0
  91. package/dist/utils/cli.d.ts +10 -0
  92. package/dist/utils/codexHome.d.ts +29 -0
  93. package/dist/utils/codexOAuth.d.ts +60 -0
  94. package/dist/utils/diffCoverage.d.ts +63 -0
  95. package/dist/utils/errorReport.d.ts +17 -0
  96. package/dist/utils/exitHandler.d.ts +8 -0
  97. package/dist/utils/fixDoubleEscapedString.d.ts +1 -0
  98. package/dist/utils/gitAuth.d.ts +84 -0
  99. package/dist/utils/gitAuthServer.d.ts +24 -0
  100. package/dist/utils/github.d.ts +78 -0
  101. package/dist/utils/globals.d.ts +3 -0
  102. package/dist/utils/install.d.ts +60 -0
  103. package/dist/utils/instructions.d.ts +48 -0
  104. package/dist/utils/leapingComment.d.ts +11 -0
  105. package/dist/utils/learnings.d.ts +62 -0
  106. package/dist/utils/learningsTruncate.d.ts +25 -0
  107. package/dist/utils/lifecycle.d.ts +57 -0
  108. package/dist/utils/log.d.ts +111 -0
  109. package/dist/utils/normalizeEnv.d.ts +30 -0
  110. package/dist/utils/openCodeModels.d.ts +11 -0
  111. package/dist/utils/overrides.d.ts +40 -0
  112. package/dist/utils/packageManager.d.ts +49 -0
  113. package/dist/utils/patchWorkflowRunFields.d.ts +29 -0
  114. package/dist/utils/payload.d.ts +105 -0
  115. package/dist/utils/prSummary.d.ts +61 -0
  116. package/dist/utils/progressComment.d.ts +146 -0
  117. package/dist/utils/providerErrors.d.ts +31 -0
  118. package/dist/utils/rangeDiff.d.ts +51 -0
  119. package/dist/utils/remediationCommand.d.ts +55 -0
  120. package/dist/utils/retry.d.ts +13 -0
  121. package/dist/utils/reviewCleanup.d.ts +14 -0
  122. package/dist/utils/run.d.ts +9 -0
  123. package/dist/utils/runContext.d.ts +60 -0
  124. package/dist/utils/runContextData.d.ts +23 -0
  125. package/dist/utils/runErrorRenderer.d.ts +64 -0
  126. package/dist/utils/runLifecycle.d.ts +86 -0
  127. package/dist/utils/runStartupLog.d.ts +15 -0
  128. package/dist/utils/secrets.d.ts +22 -0
  129. package/dist/utils/setup.d.ts +90 -0
  130. package/dist/utils/shell.d.ts +32 -0
  131. package/dist/utils/skills.d.ts +10 -0
  132. package/dist/utils/subprocess.d.ts +80 -0
  133. package/dist/utils/terraformMcp.d.ts +42 -0
  134. package/dist/utils/time.d.ts +15 -0
  135. package/dist/utils/timer.d.ts +23 -0
  136. package/dist/utils/todoTracking.d.ts +16 -0
  137. package/dist/utils/token.d.ts +39 -0
  138. package/dist/utils/version.d.ts +2 -0
  139. package/dist/utils/versioning.d.ts +7 -0
  140. package/dist/utils/vertex.d.ts +16 -0
  141. package/dist/utils/workflow.d.ts +13 -0
  142. package/package.json +119 -0
  143. package/src/agents/claude.test.ts +1016 -0
  144. package/src/agents/claude.ts +1246 -0
  145. package/src/agents/claudePretoolGate.test.ts +28 -0
  146. package/src/agents/claudePretoolGate.ts +173 -0
  147. package/src/agents/gateServer.test.ts +204 -0
  148. package/src/agents/gateServer.ts +124 -0
  149. package/src/agents/index.ts +10 -0
  150. package/src/agents/nativeFsDenies.ts +82 -0
  151. package/src/agents/opencode.test.ts +1440 -0
  152. package/src/agents/opencode.ts +1312 -0
  153. package/src/agents/opencodePlugin.ts +222 -0
  154. package/src/agents/opencodeShared.test.ts +34 -0
  155. package/src/agents/opencodeShared.ts +121 -0
  156. package/src/agents/postRun.test.ts +549 -0
  157. package/src/agents/postRun.ts +535 -0
  158. package/src/agents/reviewer.ts +104 -0
  159. package/src/agents/sessionLabeler.test.ts +247 -0
  160. package/src/agents/sessionLabeler.ts +178 -0
  161. package/src/agents/shared.test.ts +76 -0
  162. package/src/agents/shared.ts +292 -0
  163. package/src/agents/subagentModels.test.ts +113 -0
  164. package/src/agents/subagentModels.ts +40 -0
  165. package/src/agents/subagentRegistration.test.ts +41 -0
  166. package/src/agents/subagentToolGates.ts +114 -0
  167. package/src/cli.test.ts +129 -0
  168. package/src/cli.ts +105 -0
  169. package/src/commands/gha.test.ts +192 -0
  170. package/src/commands/gha.ts +188 -0
  171. package/src/commands/mcp.ts +122 -0
  172. package/src/config.ts +1 -0
  173. package/src/entry.ts +7 -0
  174. package/src/entryPost.stdlibOnly.test.ts +109 -0
  175. package/src/entryPost.ts +99 -0
  176. package/src/external.test.ts +16 -0
  177. package/src/external.ts +302 -0
  178. package/src/index.ts +11 -0
  179. package/src/internal/index.ts +71 -0
  180. package/src/lifecycle.ts +2 -0
  181. package/src/main.test.ts +873 -0
  182. package/src/main.ts +712 -0
  183. package/src/mcp/__fixtures__/terramend-scratch-pr-49-review-3485940013.json +110 -0
  184. package/src/mcp/__fixtures__/terramend-scratch-pr-64-review-3531000326.json +14 -0
  185. package/src/mcp/__fixtures__/terramend-test-repo-pr-1.diff.json +67 -0
  186. package/src/mcp/__snapshots__/checkout.test.ts.snap +109 -0
  187. package/src/mcp/__snapshots__/reviewComments.test.ts.snap +71 -0
  188. package/src/mcp/arkConfig.ts +7 -0
  189. package/src/mcp/checkSuite.test.ts +245 -0
  190. package/src/mcp/checkSuite.ts +255 -0
  191. package/src/mcp/checkout.test.ts +752 -0
  192. package/src/mcp/checkout.ts +886 -0
  193. package/src/mcp/comment.test.ts +772 -0
  194. package/src/mcp/comment.ts +582 -0
  195. package/src/mcp/commitInfo.test.ts +127 -0
  196. package/src/mcp/commitInfo.ts +61 -0
  197. package/src/mcp/crosswalk.test.ts +106 -0
  198. package/src/mcp/crosswalk.ts +339 -0
  199. package/src/mcp/dependencies.test.ts +309 -0
  200. package/src/mcp/dependencies.ts +189 -0
  201. package/src/mcp/geminiSanitizer.test.ts +287 -0
  202. package/src/mcp/geminiSanitizer.ts +207 -0
  203. package/src/mcp/git.test.ts +1083 -0
  204. package/src/mcp/git.ts +890 -0
  205. package/src/mcp/guardrails.test.ts +705 -0
  206. package/src/mcp/guardrails.ts +465 -0
  207. package/src/mcp/issue.test.ts +113 -0
  208. package/src/mcp/issue.ts +73 -0
  209. package/src/mcp/issueComments.test.ts +69 -0
  210. package/src/mcp/issueComments.ts +48 -0
  211. package/src/mcp/issueEvents.test.ts +134 -0
  212. package/src/mcp/issueEvents.ts +100 -0
  213. package/src/mcp/issueInfo.test.ts +104 -0
  214. package/src/mcp/issueInfo.ts +72 -0
  215. package/src/mcp/labels.test.ts +52 -0
  216. package/src/mcp/labels.ts +34 -0
  217. package/src/mcp/localContext.ts +28 -0
  218. package/src/mcp/localServer.test.ts +75 -0
  219. package/src/mcp/localServer.ts +131 -0
  220. package/src/mcp/moduleExtraction.test.ts +261 -0
  221. package/src/mcp/moduleExtraction.ts +313 -0
  222. package/src/mcp/moduleTests.test.ts +269 -0
  223. package/src/mcp/moduleTests.ts +421 -0
  224. package/src/mcp/modules.test.ts +640 -0
  225. package/src/mcp/modules.ts +696 -0
  226. package/src/mcp/output.test.ts +96 -0
  227. package/src/mcp/output.ts +70 -0
  228. package/src/mcp/pathSafety.test.ts +44 -0
  229. package/src/mcp/pathSafety.ts +28 -0
  230. package/src/mcp/policy.test.ts +282 -0
  231. package/src/mcp/policy.ts +199 -0
  232. package/src/mcp/pr.test.ts +387 -0
  233. package/src/mcp/pr.ts +194 -0
  234. package/src/mcp/prInfo.test.ts +96 -0
  235. package/src/mcp/prInfo.ts +91 -0
  236. package/src/mcp/providerSchema.test.ts +85 -0
  237. package/src/mcp/providerSchema.ts +175 -0
  238. package/src/mcp/review.test.ts +936 -0
  239. package/src/mcp/review.ts +923 -0
  240. package/src/mcp/reviewComments.test.ts +549 -0
  241. package/src/mcp/reviewComments.ts +896 -0
  242. package/src/mcp/roots.test.ts +175 -0
  243. package/src/mcp/roots.ts +217 -0
  244. package/src/mcp/scope.test.ts +59 -0
  245. package/src/mcp/scope.ts +65 -0
  246. package/src/mcp/security.test.ts +720 -0
  247. package/src/mcp/selectMode.test.ts +210 -0
  248. package/src/mcp/selectMode.ts +181 -0
  249. package/src/mcp/server.test.ts +292 -0
  250. package/src/mcp/server.ts +403 -0
  251. package/src/mcp/shared.ts +100 -0
  252. package/src/mcp/shell.test.ts +520 -0
  253. package/src/mcp/shell.ts +505 -0
  254. package/src/mcp/staleFix.test.ts +237 -0
  255. package/src/mcp/staleFix.ts +277 -0
  256. package/src/mcp/terraform/cost.ts +163 -0
  257. package/src/mcp/terraform/currency.test.ts +338 -0
  258. package/src/mcp/terraform/currency.ts +336 -0
  259. package/src/mcp/terraform/decisions.ts +527 -0
  260. package/src/mcp/terraform/findings.ts +333 -0
  261. package/src/mcp/terraform/plan.ts +348 -0
  262. package/src/mcp/terraform/scanners.ts +809 -0
  263. package/src/mcp/terraform/tools.test.ts +1071 -0
  264. package/src/mcp/terraform/tools.ts +908 -0
  265. package/src/mcp/terraform/types.ts +305 -0
  266. package/src/mcp/terraform.test.ts +1957 -0
  267. package/src/mcp/terraform.ts +23 -0
  268. package/src/mcp/terratest.test.ts +105 -0
  269. package/src/mcp/terratest.ts +196 -0
  270. package/src/mcp/toolFiltering.test.ts +85 -0
  271. package/src/mcp/upload.test.ts +180 -0
  272. package/src/mcp/upload.ts +112 -0
  273. package/src/models.test.ts +300 -0
  274. package/src/models.ts +708 -0
  275. package/src/modes.test.ts +107 -0
  276. package/src/modes.ts +880 -0
  277. package/src/prep/index.ts +43 -0
  278. package/src/prep/installNodeDependencies.test.ts +298 -0
  279. package/src/prep/installNodeDependencies.ts +196 -0
  280. package/src/prep/installPythonDependencies.test.ts +268 -0
  281. package/src/prep/installPythonDependencies.ts +199 -0
  282. package/src/prep/types.ts +38 -0
  283. package/src/reviewQuality.test.ts +63 -0
  284. package/src/reviewQuality.ts +134 -0
  285. package/src/runCli.test.ts +214 -0
  286. package/src/runCli.ts +282 -0
  287. package/src/skills/terraform-best-practices/SKILL.md +369 -0
  288. package/src/toolState.test.ts +45 -0
  289. package/src/toolState.ts +252 -0
  290. package/src/utils/activity.test.ts +188 -0
  291. package/src/utils/activity.ts +210 -0
  292. package/src/utils/agent.test.ts +251 -0
  293. package/src/utils/agent.ts +139 -0
  294. package/src/utils/agentHangReport.test.ts +203 -0
  295. package/src/utils/agentHangReport.ts +170 -0
  296. package/src/utils/apiFetch.test.ts +115 -0
  297. package/src/utils/apiFetch.ts +62 -0
  298. package/src/utils/apiKeys.test.ts +344 -0
  299. package/src/utils/apiKeys.ts +206 -0
  300. package/src/utils/apiUrl.test.ts +30 -0
  301. package/src/utils/apiUrl.ts +59 -0
  302. package/src/utils/assets.test.ts +153 -0
  303. package/src/utils/assets.ts +107 -0
  304. package/src/utils/billingErrors.test.ts +121 -0
  305. package/src/utils/billingErrors.ts +189 -0
  306. package/src/utils/body.test.ts +217 -0
  307. package/src/utils/body.ts +168 -0
  308. package/src/utils/buildTerramendFooter.test.ts +38 -0
  309. package/src/utils/buildTerramendFooter.ts +82 -0
  310. package/src/utils/byokFallback.test.ts +205 -0
  311. package/src/utils/byokFallback.ts +128 -0
  312. package/src/utils/claudeSubscription.test.ts +179 -0
  313. package/src/utils/claudeSubscription.ts +93 -0
  314. package/src/utils/cli.ts +31 -0
  315. package/src/utils/codexHome.test.ts +190 -0
  316. package/src/utils/codexHome.ts +191 -0
  317. package/src/utils/codexOAuth.ts +147 -0
  318. package/src/utils/codexRefreshDetect.test.ts +85 -0
  319. package/src/utils/codexRefreshDetect.ts +35 -0
  320. package/src/utils/diffCoverage.test.ts +468 -0
  321. package/src/utils/diffCoverage.ts +404 -0
  322. package/src/utils/errorReport.test.ts +135 -0
  323. package/src/utils/errorReport.ts +83 -0
  324. package/src/utils/exitHandler.ts +35 -0
  325. package/src/utils/fixDoubleEscapedString.ts +9 -0
  326. package/src/utils/ghaCore.ts +13 -0
  327. package/src/utils/gitAuth.test.ts +322 -0
  328. package/src/utils/gitAuth.ts +263 -0
  329. package/src/utils/gitAuthServer.test.ts +260 -0
  330. package/src/utils/gitAuthServer.ts +182 -0
  331. package/src/utils/github.test.ts +615 -0
  332. package/src/utils/github.ts +538 -0
  333. package/src/utils/globals.ts +9 -0
  334. package/src/utils/humanEditCapture.test.ts +100 -0
  335. package/src/utils/humanEditCapture.ts +193 -0
  336. package/src/utils/install.test.ts +768 -0
  337. package/src/utils/install.ts +492 -0
  338. package/src/utils/instructions.test.ts +240 -0
  339. package/src/utils/instructions.ts +543 -0
  340. package/src/utils/leapingComment.test.ts +51 -0
  341. package/src/utils/leapingComment.ts +18 -0
  342. package/src/utils/learnings.test.ts +87 -0
  343. package/src/utils/learnings.ts +138 -0
  344. package/src/utils/learningsTocRender.test.ts +116 -0
  345. package/src/utils/learningsTruncate.test.ts +39 -0
  346. package/src/utils/learningsTruncate.ts +42 -0
  347. package/src/utils/lifecycle.test.ts +195 -0
  348. package/src/utils/lifecycle.ts +198 -0
  349. package/src/utils/log.test.ts +402 -0
  350. package/src/utils/log.ts +432 -0
  351. package/src/utils/normalizeEnv.test.ts +91 -0
  352. package/src/utils/normalizeEnv.ts +106 -0
  353. package/src/utils/openCodeModels.ts +82 -0
  354. package/src/utils/overrides.test.ts +89 -0
  355. package/src/utils/overrides.ts +98 -0
  356. package/src/utils/packageManager.test.ts +321 -0
  357. package/src/utils/packageManager.ts +257 -0
  358. package/src/utils/patchWorkflowRunFields.test.ts +92 -0
  359. package/src/utils/patchWorkflowRunFields.ts +150 -0
  360. package/src/utils/payload.test.ts +497 -0
  361. package/src/utils/payload.ts +371 -0
  362. package/src/utils/postApiFetch.ts +51 -0
  363. package/src/utils/prSummary.test.ts +224 -0
  364. package/src/utils/prSummary.ts +147 -0
  365. package/src/utils/progressComment.ts +261 -0
  366. package/src/utils/providerErrors.test.ts +315 -0
  367. package/src/utils/providerErrors.ts +172 -0
  368. package/src/utils/rangeDiff.test.ts +236 -0
  369. package/src/utils/rangeDiff.ts +182 -0
  370. package/src/utils/remediationCommand.test.ts +163 -0
  371. package/src/utils/remediationCommand.ts +119 -0
  372. package/src/utils/retry.test.ts +153 -0
  373. package/src/utils/retry.ts +58 -0
  374. package/src/utils/reviewCleanup.ts +106 -0
  375. package/src/utils/run.ts +99 -0
  376. package/src/utils/runContext.ts +145 -0
  377. package/src/utils/runContextData.ts +58 -0
  378. package/src/utils/runErrorRenderer.test.ts +95 -0
  379. package/src/utils/runErrorRenderer.ts +259 -0
  380. package/src/utils/runFixture.ts +76 -0
  381. package/src/utils/runLifecycle.ts +237 -0
  382. package/src/utils/runStartupLog.ts +60 -0
  383. package/src/utils/secrets.test.ts +103 -0
  384. package/src/utils/secrets.ts +177 -0
  385. package/src/utils/setup.test.ts +509 -0
  386. package/src/utils/setup.ts +352 -0
  387. package/src/utils/shell.ts +103 -0
  388. package/src/utils/skills.test.ts +46 -0
  389. package/src/utils/skills.ts +67 -0
  390. package/src/utils/subprocess.test.ts +170 -0
  391. package/src/utils/subprocess.ts +438 -0
  392. package/src/utils/terraformMcp.test.ts +63 -0
  393. package/src/utils/terraformMcp.ts +83 -0
  394. package/src/utils/time.test.ts +105 -0
  395. package/src/utils/time.ts +59 -0
  396. package/src/utils/timer.test.ts +91 -0
  397. package/src/utils/timer.ts +72 -0
  398. package/src/utils/todoTracking.test.ts +223 -0
  399. package/src/utils/todoTracking.ts +167 -0
  400. package/src/utils/token.test.ts +239 -0
  401. package/src/utils/token.ts +186 -0
  402. package/src/utils/version.ts +10 -0
  403. package/src/utils/versioning.test.ts +34 -0
  404. package/src/utils/versioning.ts +44 -0
  405. package/src/utils/vertex.ts +85 -0
  406. package/src/utils/workflow.ts +25 -0
@@ -0,0 +1,122 @@
1
+ import { existsSync, statSync } from "node:fs";
2
+ import { isAbsolute, resolve } from "node:path";
3
+ import arg from "arg";
4
+ import { startLocalMcpServer } from "#app/mcp/localServer";
5
+ import { setLogSink } from "#app/utils/log";
6
+
7
+ const SEVERITIES = ["critical", "high", "medium", "low", "info"] as const;
8
+ type SeverityFlag = (typeof SEVERITIES)[number];
9
+
10
+ const SCAN_SCOPES = ["full", "diff"] as const;
11
+ type ScanScopeFlag = (typeof SCAN_SCOPES)[number];
12
+
13
+ function isSeverity(value: string): value is SeverityFlag {
14
+ return (SEVERITIES as readonly string[]).includes(value);
15
+ }
16
+
17
+ function isScanScope(value: string): value is ScanScopeFlag {
18
+ return (SCAN_SCOPES as readonly string[]).includes(value);
19
+ }
20
+
21
+ interface McpCliParams {
22
+ args: string[];
23
+ prog: string;
24
+ showHelp?: boolean;
25
+ }
26
+
27
+ function printMcpUsage(params: { stream: typeof console.log; prog: string }): void {
28
+ params.stream(`usage: ${params.prog} mcp [options]\n`);
29
+ params.stream("start the local MCP server (stdio) exposing terramend's read-only");
30
+ params.stream("terraform tools — scan, validate, verify, plan, version currency,");
31
+ params.stream("modules, provider schema, roots — to MCP clients like Claude Code,");
32
+ params.stream("Cursor, or Windsurf. example registration:");
33
+ params.stream(" claude mcp add terramend -- npx -y terramend mcp");
34
+ params.stream("");
35
+ params.stream("options:");
36
+ params.stream(" --cwd <dir> workspace to operate on (default: current dir)");
37
+ params.stream(` --severity-threshold <sev> minimum severity (${SEVERITIES.join("|")})`);
38
+ params.stream(" --scan-scope <scope> full (default) or diff (vs base branch)");
39
+ params.stream(" --module-catalogue <list> approved modules to prefer (comma/newline-sep)");
40
+ params.stream(" -h, --help show help");
41
+ }
42
+
43
+ function parseMcpArgs(args: string[]) {
44
+ return arg(
45
+ {
46
+ "--help": Boolean,
47
+ "--cwd": String,
48
+ "--severity-threshold": String,
49
+ "--scan-scope": String,
50
+ "--module-catalogue": String,
51
+ "-h": "--help",
52
+ },
53
+ { argv: args },
54
+ );
55
+ }
56
+
57
+ export async function runMcpCli(params: McpCliParams): Promise<void> {
58
+ if (params.showHelp) {
59
+ printMcpUsage({ stream: console.log, prog: params.prog });
60
+ return;
61
+ }
62
+
63
+ let parsed: ReturnType<typeof parseMcpArgs>;
64
+ try {
65
+ parsed = parseMcpArgs(params.args);
66
+ } catch (error) {
67
+ const message = error instanceof Error ? error.message : String(error);
68
+ console.error(`${message}\n`);
69
+ printMcpUsage({ stream: console.error, prog: params.prog });
70
+ process.exit(1);
71
+ }
72
+
73
+ if (parsed["--help"]) {
74
+ printMcpUsage({ stream: console.log, prog: params.prog });
75
+ return;
76
+ }
77
+
78
+ if (parsed._.length > 0) {
79
+ console.error(`unexpected positional arguments for mcp: ${parsed._.join(" ")}\n`);
80
+ printMcpUsage({ stream: console.error, prog: params.prog });
81
+ process.exit(1);
82
+ }
83
+
84
+ const rawCwd = parsed["--cwd"];
85
+ let cwd = process.cwd();
86
+ if (rawCwd) {
87
+ cwd = isAbsolute(rawCwd) ? rawCwd : resolve(process.cwd(), rawCwd);
88
+ }
89
+ if (!existsSync(cwd) || !statSync(cwd).isDirectory()) {
90
+ console.error(`--cwd is not a directory: ${cwd}`);
91
+ process.exit(1);
92
+ }
93
+
94
+ const severityRaw = parsed["--severity-threshold"];
95
+ if (severityRaw !== undefined && !isSeverity(severityRaw)) {
96
+ console.error(
97
+ `invalid --severity-threshold: ${severityRaw} (expected ${SEVERITIES.join("|")})`,
98
+ );
99
+ process.exit(1);
100
+ }
101
+ const scopeRaw = parsed["--scan-scope"];
102
+ if (scopeRaw !== undefined && !isScanScope(scopeRaw)) {
103
+ console.error(`invalid --scan-scope: ${scopeRaw} (expected ${SCAN_SCOPES.join("|")})`);
104
+ process.exit(1);
105
+ }
106
+
107
+ // stdout is the JSON-RPC channel from here on — every diagnostic goes to stderr.
108
+ setLogSink("stderr");
109
+
110
+ const server = await startLocalMcpServer({
111
+ cwd,
112
+ severityThreshold: severityRaw,
113
+ scanScope: scopeRaw,
114
+ moduleCatalogue: parsed["--module-catalogue"],
115
+ });
116
+
117
+ const shutdown = (): void => {
118
+ void server.stop().finally(() => process.exit(0));
119
+ };
120
+ process.on("SIGINT", shutdown);
121
+ process.on("SIGTERM", shutdown);
122
+ }
package/src/config.ts ADDED
@@ -0,0 +1 @@
1
+ // action-level constants shared across the action runtime
package/src/entry.ts ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { runTerramendCli } from "#app/runCli";
4
+
5
+ runTerramendCli({
6
+ cliArgs: ["gha"],
7
+ });
@@ -0,0 +1,109 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { describe, expect, it } from "vitest";
4
+
5
+ // The GHA `post:` hook runs `node action/entryPost.ts` directly against the
6
+ // rsynced action checkout, which deliberately excludes `node_modules`. Any
7
+ // non-relative / non-`node:` import in entryPost.ts (or in its transitive
8
+ // imports) crashes the post-step with `ERR_MODULE_NOT_FOUND` AFTER the agent
9
+ // already exited 0, flipping the workflow to `failure`. see #834.
10
+ //
11
+ // This test parses the static-import graph rooted at entryPost.ts and refuses
12
+ // any specifier that isn't one of:
13
+ // - node:* (stdlib)
14
+ // - ./* or ../* (relative)
15
+ // - #app/* or #package.json (local subpath imports — resolve to ./src/* and
16
+ // ./package.json via the package.json `imports` map, which ships in the
17
+ // action checkout; no `node_modules` needed)
18
+ //
19
+ // Any other specifier (`@actions/core`, `terramend`, `zod`, etc.) means the
20
+ // post-hook will need a `node_modules` tree the rsync drops.
21
+
22
+ const ENTRY_FILE = resolve(import.meta.dirname, "entryPost.ts");
23
+ // `#app/*` maps to `./src/*` (see package.json imports); entryPost.ts lives in src/.
24
+ const SRC_ROOT = import.meta.dirname;
25
+
26
+ const IMPORT_RE = /^\s*(?:import|export)(?:\s+(?:type\s+)?[\s\S]*?)?\s+from\s+["']([^"']+)["']/gm;
27
+ const SIDE_EFFECT_RE = /^\s*import\s+["']([^"']+)["']/gm;
28
+ // `import.meta.glob` and friends are not used in entryPost.ts; the simple
29
+ // regex above is sufficient here. expand if a transitive dep starts using
30
+ // dynamic imports for stdlib-only logic.
31
+
32
+ function extractImports(filePath: string): string[] {
33
+ const source = readFileSync(filePath, "utf8");
34
+ const specs: string[] = [];
35
+ for (const re of [IMPORT_RE, SIDE_EFFECT_RE]) {
36
+ re.lastIndex = 0;
37
+ for (const m of source.matchAll(re)) specs.push(m[1]!);
38
+ }
39
+ return specs;
40
+ }
41
+
42
+ function isAllowed(spec: string): boolean {
43
+ return (
44
+ spec.startsWith("node:") ||
45
+ spec.startsWith("./") ||
46
+ spec.startsWith("../") ||
47
+ spec.startsWith("#app/") ||
48
+ spec === "#package.json"
49
+ );
50
+ }
51
+
52
+ type WalkResult = {
53
+ visited: Set<string>;
54
+ violations: { file: string; spec: string }[];
55
+ };
56
+
57
+ function walk(start: string): WalkResult {
58
+ const visited = new Set<string>();
59
+ const violations: WalkResult["violations"] = [];
60
+ const queue: string[] = [start];
61
+
62
+ while (queue.length > 0) {
63
+ const file = queue.shift()!;
64
+ if (visited.has(file)) continue;
65
+ visited.add(file);
66
+
67
+ for (const spec of extractImports(file)) {
68
+ if (!isAllowed(spec)) {
69
+ violations.push({ file, spec });
70
+ continue;
71
+ }
72
+ if (spec.startsWith("node:") || spec === "#package.json") continue;
73
+ const resolved = spec.startsWith("#app/")
74
+ ? resolve(SRC_ROOT, spec.slice("#app/".length))
75
+ : resolve(dirname(file), spec);
76
+ const candidate = resolved.endsWith(".ts") ? resolved : `${resolved}.ts`;
77
+ try {
78
+ readFileSync(candidate, "utf8");
79
+ queue.push(candidate);
80
+ } catch {
81
+ // non-.ts (e.g. JSON `with { type: "json" }`) — already classified
82
+ // as relative-allowed above. nothing further to walk.
83
+ }
84
+ }
85
+ }
86
+ return { visited, violations };
87
+ }
88
+
89
+ describe("entryPost.ts stdlib-only invariant (#834)", () => {
90
+ it("only imports node: builtins and relative siblings (no node_modules deps)", () => {
91
+ const result = walk(ENTRY_FILE);
92
+ expect(result.violations, JSON.stringify(result.violations, null, 2)).toEqual([]);
93
+ });
94
+
95
+ it("walks the full transitive graph (entryPost + 3 utils)", () => {
96
+ const result = walk(ENTRY_FILE);
97
+ expect(result.visited.size).toBeGreaterThanOrEqual(4);
98
+ });
99
+
100
+ it("matches the modules entryPost actually imports today", () => {
101
+ const direct = extractImports(ENTRY_FILE).sort();
102
+ expect(direct).toEqual([
103
+ "#app/utils/codexRefreshDetect",
104
+ "#app/utils/ghaCore",
105
+ "#app/utils/postApiFetch",
106
+ "node:fs",
107
+ ]);
108
+ });
109
+ });
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+ //
3
+ // GitHub Actions `post:` entry point. Runs after the main step regardless of
4
+ // exit status (cancellation, timeout, unhandled error) — that's the contract
5
+ // we need for credential persistence: if OpenCode refreshed the Codex
6
+ // auth.json during the run, the refreshed token must land back in Terramend
7
+ // even when the main step died unexpectedly.
8
+ //
9
+ // THIS IS WHY `CODEX_AUTH_JSON` HAS TO LIVE IN TERRAMEND'S OWN SECRET STORE,
10
+ // NOT IN GITHUB ACTIONS SECRETS. The refresh chain rotates on every use; this
11
+ // hook PUTs the rotated chain back to Terramend Postgres so the next run starts
12
+ // from a fresh token. GH Actions secrets are read-only at runtime — there is
13
+ // no API to write them back from inside a job — so a token stashed there
14
+ // silently goes stale on the first refresh and the next run fails. See
15
+ // wiki/codex-auth.md.
16
+ //
17
+ // Today's only job: detect a Codex auth refresh by diffing the on-disk
18
+ // auth.json against the original refresh token (saved to GH Actions state
19
+ // by src/agents/opencode.ts), convert OpenCode's auth shape
20
+ // back to Codex CLI shape, and PUT it to /api/runtime/secret.
21
+ //
22
+ // Silent no-op when the main step didn't materialize Codex auth (no state
23
+ // saved). Best-effort: failures are logged but never throw — the workflow
24
+ // is already done, and a missed refresh write-back means the user re-runs
25
+ // `terramend auth codex` next time the chain breaks.
26
+ //
27
+ // Imports here MUST stay stdlib-only — GHA runs this file directly from the
28
+ // checked-out action repo, which has no node_modules for sha-pinned consumers.
29
+
30
+ import { existsSync, readFileSync } from "node:fs";
31
+ import { detectCodexRefresh } from "#app/utils/codexRefreshDetect";
32
+ import * as core from "#app/utils/ghaCore";
33
+ import { postApiFetch } from "#app/utils/postApiFetch";
34
+
35
+ async function main(): Promise<void> {
36
+ const raw = core.getState("codex_writeback");
37
+ if (!raw) {
38
+ core.info("codex post-hook: no writeback state — skipping");
39
+ return;
40
+ }
41
+
42
+ let state: { apiToken: string; authPath: string; originalRefresh: string };
43
+ try {
44
+ state = JSON.parse(raw) as typeof state;
45
+ } catch (err) {
46
+ core.warning(`codex post-hook: malformed writeback state — ${err}`);
47
+ return;
48
+ }
49
+ if (!state.apiToken || !state.authPath || !state.originalRefresh) {
50
+ core.warning("codex post-hook: incomplete writeback state — skipping");
51
+ return;
52
+ }
53
+
54
+ if (!existsSync(state.authPath)) {
55
+ core.info(`codex post-hook: ${state.authPath} not found — nothing to write back`);
56
+ return;
57
+ }
58
+
59
+ let authFileContent: string;
60
+ try {
61
+ authFileContent = readFileSync(state.authPath, "utf8");
62
+ } catch (err) {
63
+ core.warning(`codex post-hook: cannot read ${state.authPath} — ${err}`);
64
+ return;
65
+ }
66
+
67
+ const refreshedCodexJson = detectCodexRefresh({
68
+ authFileContent,
69
+ originalRefresh: state.originalRefresh,
70
+ });
71
+ if (!refreshedCodexJson) {
72
+ core.info("codex post-hook: refresh chain unchanged — no writeback needed");
73
+ return;
74
+ }
75
+
76
+ try {
77
+ const response = await postApiFetch({
78
+ path: "/api/runtime/secret",
79
+ method: "PUT",
80
+ headers: {
81
+ authorization: `Bearer ${state.apiToken}`,
82
+ "content-type": "application/json",
83
+ },
84
+ body: JSON.stringify({ name: "CODEX_AUTH_JSON", value: refreshedCodexJson }),
85
+ });
86
+ if (!response.ok) {
87
+ const body = await response.text().catch(() => "");
88
+ core.warning(`codex post-hook: writeback returned ${response.status}: ${body}`);
89
+ return;
90
+ }
91
+ core.info("codex post-hook: refreshed CODEX_AUTH_JSON persisted to Terramend");
92
+ } catch (err) {
93
+ core.warning(`codex post-hook: writeback failed — ${err}`);
94
+ }
95
+ }
96
+
97
+ main().catch((err) => {
98
+ core.warning(`codex post-hook: unexpected error — ${err}`);
99
+ });
@@ -0,0 +1,16 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { formatMcpToolRef, terramendMcpName } from "#app/external";
3
+
4
+ describe("formatMcpToolRef", () => {
5
+ it("formats claude tool refs with the mcp__ prefix", () => {
6
+ expect(formatMcpToolRef("claude", "select_mode")).toBe("mcp__terramend__select_mode");
7
+ });
8
+
9
+ it("formats opencode tool refs with the server-name prefix", () => {
10
+ expect(formatMcpToolRef("opencode", "select_mode")).toBe("terramend_select_mode");
11
+ });
12
+
13
+ it("uses the shared mcp server name constant", () => {
14
+ expect(formatMcpToolRef("claude", "push_branch")).toBe(`mcp__${terramendMcpName}__push_branch`);
15
+ });
16
+ });
@@ -0,0 +1,302 @@
1
+ /**
2
+ * ⚠️ LIMITED IMPORTS - this file is imported by Next.js and must avoid pulling in backend code.
3
+ * All shared constants, types, and data used by both the Next.js app and the action runtime live here.
4
+ * Other files in action/ re-export from this file for backward compatibility.
5
+ */
6
+
7
+ import type { PullRequest } from "@octokit/webhooks-types";
8
+
9
+ // mcp name constant
10
+ export const terramendMcpName = "terramend";
11
+
12
+ /** @see {@link file://./agents/shared.ts} Agent interface that uses this type */
13
+ export type AgentId = "claude" | "opencode";
14
+
15
+ /**
16
+ * format a tool name the way each agent's MCP client presents it to the model.
17
+ * claude code: mcp__terramend__select_mode
18
+ * opencode: terramend_select_mode
19
+ */
20
+ export function formatMcpToolRef(agentId: AgentId, toolName: string): string {
21
+ switch (agentId) {
22
+ case "claude":
23
+ return `mcp__${terramendMcpName}__${toolName}`;
24
+ case "opencode":
25
+ return `${terramendMcpName}_${toolName}`;
26
+ default:
27
+ return agentId satisfies never;
28
+ }
29
+ }
30
+
31
+ // model alias registry lives in models.ts — re-exported here for shared access
32
+ export type { ModelAlias, ModelProvider, ProviderConfig } from "#app/models";
33
+ export {
34
+ DEFAULT_PROXY_MODEL,
35
+ getAutoSelectHintModel,
36
+ getModelEnvVars,
37
+ getModelManagedCredentials,
38
+ getModelProvider,
39
+ getProviderDisplayName,
40
+ modelAliases,
41
+ parseModel,
42
+ providers,
43
+ resolveCliModel,
44
+ resolveDisplayAlias,
45
+ resolveModelSlug,
46
+ resolveOpenRouterModel,
47
+ } from "#app/models";
48
+
49
+ // tool permission types shared with server dispatch
50
+ export type ToolPermission = "disabled" | "enabled";
51
+ export type ShellPermission = "disabled" | "restricted" | "enabled";
52
+ export type PushPermission = "disabled" | "restricted" | "enabled";
53
+
54
+ // workflow yml permissions for GITHUB_TOKEN
55
+ export type WorkflowPermissionValue = "read" | "write" | "none";
56
+ export type WorkflowIdTokenPermissionValue = "write" | "none";
57
+
58
+ export interface WorkflowPermissions {
59
+ actions?: WorkflowPermissionValue;
60
+ attestations?: WorkflowPermissionValue;
61
+ checks?: WorkflowPermissionValue;
62
+ contents?: WorkflowPermissionValue;
63
+ deployments?: WorkflowPermissionValue;
64
+ discussions?: WorkflowPermissionValue;
65
+ "id-token"?: WorkflowIdTokenPermissionValue;
66
+ issues?: WorkflowPermissionValue;
67
+ models?: WorkflowPermissionValue;
68
+ packages?: WorkflowPermissionValue;
69
+ pages?: WorkflowPermissionValue;
70
+ "pull-requests"?: WorkflowPermissionValue;
71
+ "repository-projects"?: WorkflowPermissionValue;
72
+ "security-events"?: WorkflowPermissionValue;
73
+ statuses?: WorkflowPermissionValue;
74
+ }
75
+
76
+ // permission level for the author who triggered the event
77
+ // matches GitHub's permission levels: admin > write > maintain > triage > read > none
78
+ export type AuthorPermission = "admin" | "maintain" | "write" | "triage" | "read" | "none";
79
+
80
+ // base interface for common payload event fields
81
+ interface BasePayloadEvent {
82
+ issue_number?: number;
83
+ is_pr?: boolean;
84
+ branch?: string;
85
+ /** title of the issue/PR (or contextual title for comments) */
86
+ title?: string;
87
+ /** primary content for this trigger (issue body, PR body, comment body, review body, etc.) */
88
+ body?: string | null;
89
+ comment_id?: number;
90
+ review_id?: number;
91
+ review_state?: string;
92
+ /** GraphQL review-thread context (shape owned by the backend producer; not read in-action) */
93
+ thread?: unknown;
94
+ pull_request?: PullRequest;
95
+ check_suite?: {
96
+ id: number;
97
+ head_sha: string;
98
+ head_branch: string | null;
99
+ status: string | null;
100
+ conclusion: string | null;
101
+ url: string;
102
+ };
103
+ comment_ids?: number[] | "all";
104
+ /** permission level of the user who triggered this event */
105
+ authorPermission?: AuthorPermission;
106
+ /** when true, runs silently without progress comments (e.g., auto-labeling) */
107
+ silent?: boolean;
108
+ [key: string]: unknown;
109
+ }
110
+
111
+ interface PullRequestOpenedEvent extends BasePayloadEvent {
112
+ trigger: "pull_request_opened";
113
+ issue_number: number;
114
+ is_pr: true;
115
+ title: string;
116
+ body: string | null;
117
+ branch: string;
118
+ }
119
+
120
+ interface PullRequestReadyForReviewEvent extends BasePayloadEvent {
121
+ trigger: "pull_request_ready_for_review";
122
+ issue_number: number;
123
+ is_pr: true;
124
+ title: string;
125
+ body: string | null;
126
+ branch: string;
127
+ }
128
+
129
+ interface PullRequestReviewRequestedEvent extends BasePayloadEvent {
130
+ trigger: "pull_request_review_requested";
131
+ issue_number: number;
132
+ is_pr: true;
133
+ title: string;
134
+ body: string | null;
135
+ branch: string;
136
+ }
137
+
138
+ interface PullRequestReviewSubmittedEvent extends BasePayloadEvent {
139
+ trigger: "pull_request_review_submitted";
140
+ issue_number: number;
141
+ is_pr: true;
142
+ review_id: number;
143
+ /** review body is the primary content */
144
+ body: string | null;
145
+ review_state: string;
146
+ branch: string;
147
+ }
148
+
149
+ interface PullRequestReviewCommentCreatedEvent extends BasePayloadEvent {
150
+ trigger: "pull_request_review_comment_created";
151
+ issue_number: number;
152
+ is_pr: true;
153
+ title: string;
154
+ comment_id: number;
155
+ /** comment body is the primary content (null if already in prompt) */
156
+ body: string | null;
157
+ thread?: unknown;
158
+ branch: string;
159
+ }
160
+
161
+ interface IssuesOpenedEvent extends BasePayloadEvent {
162
+ trigger: "issues_opened";
163
+ issue_number: number;
164
+ title: string;
165
+ body: string | null;
166
+ }
167
+
168
+ interface IssuesAssignedEvent extends BasePayloadEvent {
169
+ trigger: "issues_assigned";
170
+ issue_number: number;
171
+ title: string;
172
+ body: string | null;
173
+ }
174
+
175
+ interface IssuesLabeledEvent extends BasePayloadEvent {
176
+ trigger: "issues_labeled";
177
+ issue_number: number;
178
+ title: string;
179
+ body: string | null;
180
+ }
181
+
182
+ interface IssueCommentCreatedEvent extends BasePayloadEvent {
183
+ trigger: "issue_comment_created";
184
+ comment_id: number;
185
+ /** distinguishes this from PR review comments (which use pull_request_review_comment_created) */
186
+ comment_type: "issue";
187
+ /** comment body is the primary content (null if already in prompt) */
188
+ body: string | null;
189
+ issue_number: number;
190
+ // PR-specific fields (only present when is_pr is true)
191
+ is_pr?: true;
192
+ branch?: string;
193
+ title?: string;
194
+ }
195
+
196
+ interface CheckSuiteCompletedEvent extends BasePayloadEvent {
197
+ trigger: "check_suite_completed";
198
+ issue_number: number;
199
+ is_pr: true;
200
+ title: string;
201
+ body: string | null;
202
+ pull_request: PullRequest;
203
+ branch: string;
204
+ check_suite: {
205
+ id: number;
206
+ head_sha: string;
207
+ head_branch: string | null;
208
+ status: string | null;
209
+ conclusion: string | null;
210
+ url: string;
211
+ };
212
+ }
213
+
214
+ interface WorkflowDispatchEvent extends BasePayloadEvent {
215
+ trigger: "workflow_dispatch";
216
+ }
217
+
218
+ interface FixReviewEvent extends BasePayloadEvent {
219
+ trigger: "fix_review";
220
+ issue_number: number;
221
+ is_pr: true;
222
+ review_id: number;
223
+ /** when true, only address comments the triggerer approved with 👍 (vs all comments) */
224
+ approved_only?: boolean | undefined;
225
+ }
226
+
227
+ interface ImplementPlanEvent extends BasePayloadEvent {
228
+ trigger: "implement_plan";
229
+ issue_number: number;
230
+ plan_comment_id: number;
231
+ /** plan content is the primary content (null if already in prompt) */
232
+ body: string | null;
233
+ }
234
+
235
+ interface PullRequestSynchronizeEvent extends BasePayloadEvent {
236
+ trigger: "pull_request_synchronize";
237
+ issue_number: number;
238
+ is_pr: true;
239
+ title: string;
240
+ body: string | null;
241
+ branch: string;
242
+ /** SHA before the push -- used to compute incremental range-diff between PR versions */
243
+ before_sha: string;
244
+ }
245
+
246
+ interface UnknownEvent extends BasePayloadEvent {
247
+ trigger: "unknown";
248
+ }
249
+
250
+ // discriminated union for payload event based on trigger
251
+ // note: all events use issue_number for consistency (PRs are issues in GitHub's API)
252
+ export type PayloadEvent =
253
+ | PullRequestOpenedEvent
254
+ | PullRequestReadyForReviewEvent
255
+ | PullRequestSynchronizeEvent
256
+ | PullRequestReviewRequestedEvent
257
+ | PullRequestReviewSubmittedEvent
258
+ | PullRequestReviewCommentCreatedEvent
259
+ | IssuesOpenedEvent
260
+ | IssuesAssignedEvent
261
+ | IssuesLabeledEvent
262
+ | IssueCommentCreatedEvent
263
+ | CheckSuiteCompletedEvent
264
+ | WorkflowDispatchEvent
265
+ | FixReviewEvent
266
+ | ImplementPlanEvent
267
+ | UnknownEvent;
268
+
269
+ // writeable payload type for building payloads
270
+ export interface WriteablePayload {
271
+ "~terramend": true;
272
+ /** semantic version of the payload to ensure compatibility */
273
+ version: string;
274
+ /** provider/model slug (e.g. "anthropic/claude-opus") */
275
+ model?: string | undefined;
276
+ /** the user's actual request (body if @terramend tagged) */
277
+ prompt: string;
278
+ /** github username of the human who triggered this workflow run */
279
+ triggerer?: string | undefined;
280
+ /** event-level instructions for this trigger type (flag-expanded server-side) */
281
+ eventInstructions?: string | undefined;
282
+ /**
283
+ * system-injected note about prior superseded runs (e.g. when the
284
+ * triggering @terramend comment is edited). rendered alongside the user's
285
+ * prompt rather than via eventInstructions so it survives user-prompt
286
+ * precedence.
287
+ */
288
+ previousRunsNote?: string | undefined;
289
+ /** event data from webhook payload - discriminated union based on trigger field */
290
+ event: PayloadEvent;
291
+ /** timeout for agent run (e.g., "10m", "1h30m") - defaults to "1h" */
292
+ timeout?: string | undefined;
293
+ /** working directory for the agent */
294
+ cwd?: string | undefined;
295
+ /** pre-created progress comment (ID + type) for updating status */
296
+ progressComment?: { id: string; type: "issue" | "review" } | undefined;
297
+ /** when true, seed the PR summary tmpfile + persist edits at run end */
298
+ generateSummary?: boolean | undefined;
299
+ }
300
+
301
+ // immutable payload type for agent execution
302
+ export type Payload = Readonly<WriteablePayload>;
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Library entry point for npm package
3
+ * This exports the main function for programmatic usage
4
+ */
5
+
6
+ export type { Agent, AgentResult, AgentRunContext } from "#app/agents/shared";
7
+ export {
8
+ type Inputs as ExecutionInputs,
9
+ type MainResult,
10
+ main,
11
+ } from "#app/main";