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,85 @@
1
+ /**
2
+ * Source for the opencode plugin we drop into the per-run tmpdir at
3
+ * `<XDG_CONFIG_HOME>/opencode/plugin/terramend-events.ts`. The harness already
4
+ * redirects `XDG_CONFIG_HOME` to `ctx.tmpdir/.config` (see `opencode.ts`
5
+ * `homeEnv`), so opencode's auto-discovery scans the tmpdir, never the user's
6
+ * working tree. opencode's `Global.Path.config` resolves to
7
+ * `path.join(xdgConfig, "opencode")` and the config layer auto-discovers
8
+ * plugins from every directory in its scan list — including
9
+ * `Global.Path.config` — by globbing `{plugin,plugins}/*.{ts,js}` via
10
+ * `ConfigPlugin.load(dir)`.
11
+ *
12
+ * We MUST NOT write into the user's repo working tree. The repo is a checkout
13
+ * the agent operates on; only the agent's own tools (gated by
14
+ * `OPENCODE_PERMISSION`) may modify it. The whole reason we redirect HOME and
15
+ * XDG_CONFIG_HOME is so harness-side files (config, plugins, scratch state)
16
+ * land in the tmpdir.
17
+ *
18
+ * Why the events plugin exists: opencode's `task` tool runs subagents
19
+ * in-process and the CLI's `cli/cmd/run.ts` event loop filters
20
+ * `part.sessionID !== sessionID`, so subagent-internal `message.part.updated`
21
+ * events are silently discarded before reaching our parent NDJSON stream.
22
+ * plugins, by contrast, receive EVERY bus event via `bus.subscribeAll()`
23
+ * regardless of session.
24
+ *
25
+ * The events plugin re-emits every relevant bus event onto opencode's stdout
26
+ * as a single JSON line wrapped in a sentinel envelope. our `runOpenCode`
27
+ * parser recognises the envelope, unpacks it, and routes the inner part
28
+ * through the existing handlers with a per-session label from `SessionLabeler`
29
+ * so each subagent's tool calls / text appear inline alongside the
30
+ * orchestrator's.
31
+ *
32
+ * The subagent gate (the `tool.execute.before` hook that hard-blocks
33
+ * state-mutating MCP tool calls from a subagent session) lives in a SEPARATE
34
+ * plugin — `TERRAMEND_OPENCODE_GATE_PLUGIN_SOURCE` below — because it's the
35
+ * load-bearing security fence and must ship into the opencode harness,
36
+ * whereas this events re-emitter was only needed by the legacy CLI-parsing
37
+ * path (the active `opencode.ts` reads subagent events directly off the SDK
38
+ * event stream, so it installs ONLY the gate plugin). Deny-list source of
39
+ * truth: `src/agents/subagentToolGates.ts`.
40
+ *
41
+ * Dumb plugin / smart parent split: the events plugin emits every part for
42
+ * every session. the parent dedupes against the orchestrator's own session id
43
+ * (which it already knows from the `init` event). this keeps the plugin trivial
44
+ * and keeps the per-session attribution logic on the parent side where the
45
+ * SessionLabeler already lives.
46
+ *
47
+ * Event-name prefixing: the wrapped event-type sentinel is
48
+ * `terramend_bus_event` — picked to be unmistakably ours so a future opencode
49
+ * release that introduces a coincidentally-named event type won't collide.
50
+ */
51
+ export declare const TERRAMEND_BUS_EVENT_TYPE: "terramend_bus_event";
52
+ export declare const TERRAMEND_OPENCODE_PLUGIN_FILENAME: "terramend-events.ts";
53
+ export declare const TERRAMEND_OPENCODE_GATE_PLUGIN_FILENAME: "terramend-subagent-gate.ts";
54
+ /**
55
+ * Source written verbatim to `<XDG_CONFIG_HOME>/opencode/plugin/terramend-events.ts`.
56
+ *
57
+ * - Structural typing only (no runtime import of `@opencode-ai/plugin`):
58
+ * opencode installs that dep into the directory containing the plugin
59
+ * alongside discovery, but a) the dep isn't required for the structural
60
+ * shape we use, and b) keeping zero imports avoids any module-resolution
61
+ * coupling to opencode's plugin-loader internals across versions.
62
+ * - default export is the plugin factory (opencode's plugin loader accepts
63
+ * default exports as the server entrypoint).
64
+ * - we only forward `message.part.updated`. that's where the user-visible
65
+ * subagent activity (tool calls, text, step transitions) lives. add more
66
+ * event types here if the parent needs them.
67
+ * - JSON.stringify+single write keeps the line atomic up to PIPE_BUF (4KB on
68
+ * Linux). longer parts may interleave with concurrent stdout writers; the
69
+ * parser tolerates non-JSON lines (logs them at debug) so a torn line is a
70
+ * missed event, not a crash.
71
+ */
72
+ export declare const TERRAMEND_OPENCODE_PLUGIN_SOURCE: string;
73
+ /**
74
+ * Standalone subagent gate plugin written to
75
+ * `<XDG_CONFIG_HOME>/opencode/plugin/terramend-subagent-gate.ts`. Installed by
76
+ * the in-process `opencode.ts` harness — the gate is the load-bearing security
77
+ * fence, so it ships independently of the events re-emitter above (which the
78
+ * in-process harness doesn't need).
79
+ *
80
+ * Hard-blocks state-mutating MCP tool calls originating from a subagent
81
+ * session via `tool.execute.before`, complementing the runtime backstops from
82
+ * PR #796 (action/mcp/checkout.ts, action/mcp/git.ts). Deny-list source of
83
+ * truth: `action/agents/subagentToolGates.ts`.
84
+ */
85
+ export declare const TERRAMEND_OPENCODE_GATE_PLUGIN_SOURCE: string;
@@ -0,0 +1,40 @@
1
+ export type OpenCodeConfig = {
2
+ mcp?: Record<string, unknown>;
3
+ permission?: Record<string, unknown>;
4
+ provider?: Record<string, unknown>;
5
+ agent?: Record<string, unknown>;
6
+ experimental?: Record<string, unknown>;
7
+ model?: string;
8
+ enabled_providers?: string[];
9
+ [key: string]: unknown;
10
+ };
11
+ /**
12
+ * Build the `provider.google.models[id].options` map that pins every direct-Google
13
+ * Gemini alias to `thinkingLevel: "high"`. Sourced from the model registry so
14
+ * adding/renaming a Google alias in `action/models.ts` flows through automatically.
15
+ */
16
+ export declare function geminiHighThinkingOverrides(): Record<string, {
17
+ options: object;
18
+ }>;
19
+ /**
20
+ * Read-only `reviewfrog` subagent for lens-based review. Non-mutative +
21
+ * non-recursive — enforced by the system prompt in reviewer.ts.
22
+ *
23
+ * Per-subagent `model:` override is driven by the registry in
24
+ * `action/models.ts` via each alias's `subagentModel` field. Currently wired:
25
+ * Anthropic opus → sonnet, OpenAI gpt-pro → gpt and gpt → gpt-5.4, Google
26
+ * gemini-pro → gemini-flash. Other providers inherit (no override).
27
+ */
28
+ export declare function buildReviewerAgentConfig(orchestratorModel: string | undefined): Record<string, unknown>;
29
+ /**
30
+ * Install the opencode-ai npm tarball and return the path to the executable.
31
+ *
32
+ * The bin path differs by version: v1.4.x and earlier shipped `bin/opencode`;
33
+ * v1.14+ renames the platform-specific binary to `bin/opencode.exe` for every
34
+ * OS via the postinstall script. Callers pass the binPath that matches their
35
+ * pinned version so a v1↔v2 swap can't silently install the wrong file.
36
+ */
37
+ export declare function installOpencodeCli(params: {
38
+ binPath: string;
39
+ }): Promise<string>;
40
+ export declare function autoSelectModel(): string | undefined;
@@ -0,0 +1,132 @@
1
+ import { type AgentResult, type AgentRunContext, type AgentUsage, type PostRunIssues, type StopHookFailure } from "#app/agents/shared";
2
+ import type { ToolState } from "#app/toolState";
3
+ /**
4
+ * derive "agent picked a review mode but never produced visible output" from
5
+ * the literal facts on `toolState`. returns the selected mode when the gate
6
+ * should fire, `null` otherwise — pure read, no side effects, safe to invoke
7
+ * after every agent attempt.
8
+ *
9
+ * the gate is anchored to `hadProgressComment` so silent runs (non-issue
10
+ * events, dispatcher skipped seeding) don't fire a nudge there's no UI for.
11
+ *
12
+ * `Review` and `IncrementalReview` have different valid exits:
13
+ * - Review: only `create_pull_request_review` counts. `report_progress` is
14
+ * not a substitute — a Review run that exits with just a summary comment
15
+ * has produced nothing reviewable on the PR. matches the hard-fail
16
+ * message at `expected = "create_pull_request_review"` below.
17
+ * - IncrementalReview: `report_progress` is a legitimate "no review
18
+ * warranted" exit, so either toolState flag short-circuits.
19
+ * splitting per mode also closes the bypass where a subagent (e.g. a
20
+ * `task`-dispatched `reviewfrog` lens) calls `report_progress` and silences
21
+ * the gate even though the orchestrator never submitted a review.
22
+ */
23
+ export declare function getUnsubmittedReview(toolState: ToolState): "Review" | "IncrementalReview" | null;
24
+ /**
25
+ * run the user-configured stop hook.
26
+ *
27
+ * parallel to `executeLifecycleHook` (which soft-fails with a warning), but
28
+ * returns structured output so agent harnesses can feed the failure back into
29
+ * the session as a resume prompt.
30
+ *
31
+ * - non-zero exit → `StopHookFailure`, actionable: the output is fed to the
32
+ * agent so it can fix the underlying issue.
33
+ * - timeout / spawn error → null, treated as passed: we can't usefully ask the
34
+ * agent to fix an infrastructure problem, and retrying would risk infinite
35
+ * loops.
36
+ */
37
+ export declare function executeStopHook(script: string): Promise<StopHookFailure | null>;
38
+ export declare function buildStopHookPrompt(failure: StopHookFailure): string;
39
+ export declare function buildSummaryStalePrompt(filePath: string): string;
40
+ export declare function buildUnsubmittedReviewPrompt(mode: "Review" | "IncrementalReview"): string;
41
+ /**
42
+ * check the post-run gates: did the stop hook pass, is the working tree
43
+ * clean, and (when applicable) did the agent touch the rolling PR summary
44
+ * snapshot or produce review output? returns everything that still needs
45
+ * nudging so the caller can render a single combined resume prompt.
46
+ *
47
+ * reads run state directly off `ctx.toolState` so each invocation sees the
48
+ * latest mutations from MCP tool calls. `skipSummaryStale` lets the loop
49
+ * suppress the summary-stale check after the one-shot nudge has been
50
+ * delivered (re-firing it would burn the retry budget on a soft gate the
51
+ * agent has already decided not to act on).
52
+ */
53
+ export declare function collectPostRunIssues(ctx: AgentRunContext, options?: {
54
+ skipSummaryStale?: boolean;
55
+ }): Promise<PostRunIssues>;
56
+ export declare function buildPostRunPrompt(issues: PostRunIssues): string;
57
+ /**
58
+ * terminal-only post-run finalize: re-checks the hard-fail gates after the
59
+ * agent has exited and converts a successful result to a hard-fail when
60
+ * `stopHook` or `unsubmittedReview` is still failing. used by harnesses
61
+ * that inject follow-up turns via a mechanism other than the resume
62
+ * callback (e.g. the Claude managed Stop hook + gate server). soft gates
63
+ * (`dirtyTree`, `summaryStale`) are intentionally not re-checked here —
64
+ * they never flip a successful run to failed.
65
+ */
66
+ export declare function finalizeAgentResult<R extends AgentResult>(params: {
67
+ ctx: AgentRunContext;
68
+ result: R;
69
+ }): Promise<R>;
70
+ export declare function shouldRunReflection(mode: string | undefined): boolean;
71
+ /**
72
+ * prompt for a dedicated post-run reflection turn nudging the agent to edit
73
+ * the rolling learnings file if it discovered anything worth persisting.
74
+ *
75
+ * this exists because passive "if you learned something, write it down"
76
+ * instructions baked into mode checklists are frequently ignored — the agent
77
+ * stays focused on the task and the meta-ask falls through. delivering it
78
+ * as its own resume turn, with nothing competing for attention, raises the
79
+ * fire rate substantially.
80
+ *
81
+ * the file is the single source of truth — there is no separate MCP tool
82
+ * call. the server reads the file at end-of-run and persists any edits to
83
+ * `Repo.learnings`.
84
+ *
85
+ * the prompt copy is shaped by repo-wide audits of the actual content the
86
+ * agent has been writing (issue #619 in terramend/app). recurring failure
87
+ * modes the framing pushes back on:
88
+ * - massive multi-paragraph "bullets" that are really mini-articles
89
+ * - facts anchored to moving repo state (PR / review / commit / branch
90
+ * refs, dates, version pins, line numbers) that decay within weeks
91
+ * - sections growing into giant flat lists with no internal structure,
92
+ * forcing future runs to read kilobytes to find one fact
93
+ *
94
+ * single litmus delivered in the prompt: "would a future run on this repo
95
+ * do its work better because this bullet exists?". tool-quirk workarounds
96
+ * are explicitly allowed when the agent burned calls discovering the
97
+ * quirk this run — recording the workaround prevents next run from
98
+ * repeating the waste. tradeoff: the same quirk gets duplicated across
99
+ * repos, so when a quirk is fixed upstream in tool descriptions the
100
+ * per-repo bullets go stale and we have no batch-invalidation path.
101
+ */
102
+ export declare function buildLearningsReflectionPrompt(filePath: string): string;
103
+ /**
104
+ * shared post-run retry loop used by every agent harness.
105
+ *
106
+ * checks the post-run gates (stop hook + dirty tree), and if either is
107
+ * failing, invokes `resume` to let the agent fix and push in the same turn.
108
+ * bails at `MAX_POST_RUN_RETRIES` attempts. the `canResume` predicate is
109
+ * consulted before each retry — harnesses that can't re-enter the session
110
+ * (e.g. claude without a sessionId) return false here.
111
+ *
112
+ * an optional `reflectionPrompt` fires exactly once, after the gates first
113
+ * observe a clean state. it's a one-shot nudge (e.g. "update learnings if
114
+ * relevant"), not a gate, so it does not consume the gate-retry budget. if
115
+ * the reflection turn dirties the tree, the loop picks that up on the next
116
+ * iteration via the normal dirty-tree gate.
117
+ *
118
+ * stop hook must pass for the run to succeed; persistent hook failures are
119
+ * surfaced as `AgentResult.error`. dirty-tree-only failures preserve prior
120
+ * behavior: they're logged but don't fail the run.
121
+ */
122
+ export declare function runPostRunRetryLoop<R extends AgentResult>(params: {
123
+ ctx: AgentRunContext;
124
+ initialResult: R;
125
+ initialUsage: AgentUsage | undefined;
126
+ resume: (context: {
127
+ prompt: string;
128
+ previousResult: R;
129
+ }) => Promise<R>;
130
+ canResume?: ((result: R) => boolean) | undefined;
131
+ reflectionPrompt?: string | undefined;
132
+ }): Promise<AgentResult>;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Definition of the `reviewfrog` named subagent — the constrained
3
+ * read-only worker dispatched by Build mode self-review and the in-Terramend
4
+ * /anneal multi-lens review.
5
+ *
6
+ * The contract: non-mutative + non-recursive.
7
+ * allow: file reads, grep/glob, web search/fetch, read-only MCP queries
8
+ * deny: state-changing MCP tools, file writes, shell, nested subagent dispatch
9
+ *
10
+ * Enforcement is now belt-and-suspenders:
11
+ * 1. Machine-enforced PreToolUse gates intercept every state-mutating MCP
12
+ * tool call originating from a subagent session and refuse it before
13
+ * MCP runs. See action/agents/subagentToolGates.ts (the deny list),
14
+ * action/agents/claudePretoolGate.ts (Claude Code's PreToolUse hook),
15
+ * and action/agents/opencodePlugin.ts (opencode's tool.execute.before
16
+ * hook). Followed PR #796 which added runtime backstops inside
17
+ * checkout_pr / push_branch after a subagent-originated tool call
18
+ * clobbered an unrelated PR branch in zed-industries/cloud.
19
+ * 2. The prose system prompt below as a backup against (a) tools added
20
+ * to the MCP server without a corresponding deny-list update, and
21
+ * (b) shell/git read-vs-write distinctions the static gate can't see.
22
+ * It states the rule as a no-op-if-reverted invariant the model can
23
+ * apply to any tool, including ones added after this comment was
24
+ * written.
25
+ *
26
+ * Historical note: per-agent `disallowedTools` in claude-code is upstream-
27
+ * broken for subagent-spawned tool calls (anthropics/claude-agent-sdk-
28
+ * typescript#172, open as of Mar 2026), which is why the gate runs at
29
+ * PreToolUse rather than tool-registration time.
30
+ */
31
+ export declare const REVIEWER_AGENT_NAME = "reviewfrog";
32
+ /**
33
+ * System prompt baked into the named reviewer subagent. The orchestrator
34
+ * supplies the per-call task content (YOUR TASK, the diff, the lens) at
35
+ * dispatch time; this preamble enforces the role and constraints regardless
36
+ * of what the orchestrator sends.
37
+ */
38
+ export declare const REVIEWER_SYSTEM_PROMPT: string;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Track per-session labels so log lines from parallel subagents can be
3
+ * differentiated. The orchestrator dispatches lens subagents
4
+ * via the Task tool; each subagent runs in its own opencode/claude Session
5
+ * with its own `sessionID` (or `session_id`) tag on the NDJSON event stream.
6
+ *
7
+ * Without per-session prefixing, parallel subagent tool_use / tool_result /
8
+ * text events appear as a single interleaved stream tagged with `[Terramend]`,
9
+ * making it impossible for a human reading the logs to attribute work to a
10
+ * specific lens.
11
+ *
12
+ * The labeler is deliberately runtime-agnostic — both opencode.ts and
13
+ * claude.ts feed it the same shape. The contract is FIFO: when the orchestrator
14
+ * dispatches N task tool_use blocks in a single assistant turn (the parallel
15
+ * fan-out the multi-lens prompt requires), the i-th new sessionID is assumed
16
+ * to belong to the i-th task dispatch. This is correct as long as parallel
17
+ * dispatches are emitted in source-order and the runtimes respect that order
18
+ * when assigning child sessions; we do not depend on it for correctness of
19
+ * the read-only contract — only for log readability.
20
+ */
21
+ export interface TaskDispatchInput {
22
+ description?: string | undefined;
23
+ subagent_type?: string | undefined;
24
+ prompt?: string | undefined;
25
+ }
26
+ export declare const ORCHESTRATOR_LABEL = "orchestrator";
27
+ /**
28
+ * Extract a human-readable label from a Task tool's input. Tries (in order):
29
+ * 1. explicit `lens: <name>` marker on a line in the prompt — preferred,
30
+ * lets the orchestrator name the lens deterministically
31
+ * 2. the Task tool's `description` field — short, written by orchestrator
32
+ * per call, usually enough
33
+ * 3. the `subagent_type` — falls back to the named
34
+ * subagent identity when description is missing
35
+ * 4. generic "subagent" — last resort
36
+ */
37
+ export declare function deriveLabelFromTaskInput(input: TaskDispatchInput): string;
38
+ /**
39
+ * Stateful tracker mapping subagent activity back to human-readable labels.
40
+ *
41
+ * Two attribution channels are supported because the runtimes differ:
42
+ *
43
+ * - **OpenCode** spawns each subagent as its own opencode `Session` with
44
+ * a distinct `sessionID`. The harness records each Task dispatch into a
45
+ * pending FIFO queue; the next previously-unseen sessionID consumes the
46
+ * head of the queue and binds it to that label.
47
+ *
48
+ * - **Claude Code** runs subagents inside the orchestrator's session — they
49
+ * all share `session_id` — and instead stamps every subagent message with
50
+ * `parent_tool_use_id` pointing at the Agent tool_use id that spawned them.
51
+ * The harness binds each Agent tool_use id to its dispatched label up
52
+ * front, then `labelFor` looks the label up directly when an event arrives
53
+ * carrying that `parent_tool_use_id`.
54
+ *
55
+ * `labelFor(sessionID, parentToolUseId?)` accepts both: when
56
+ * `parentToolUseId` is set and known it short-circuits to the direct mapping;
57
+ * otherwise it falls through to the FIFO/sessionID path.
58
+ */
59
+ export declare class SessionLabeler {
60
+ private readonly labels;
61
+ private readonly labelsByToolUseId;
62
+ private readonly pendingLabels;
63
+ private fallbackCounter;
64
+ /**
65
+ * Record a Task/Agent tool dispatch.
66
+ *
67
+ * @param input Task tool input — used to derive the lens label.
68
+ * @param toolUseId Optional Agent tool_use id. When provided, future events
69
+ * carrying `parent_tool_use_id === toolUseId` resolve
70
+ * directly to this label without consuming the FIFO queue
71
+ * (Claude path). Always also pushed to the FIFO queue so
72
+ * the OpenCode path still works when toolUseId is absent.
73
+ */
74
+ recordTaskDispatch(input: TaskDispatchInput, toolUseId?: string | null): string;
75
+ /**
76
+ * Return a label for the given event.
77
+ *
78
+ * @param sessionID Session id from the event (OpenCode: per-session;
79
+ * Claude: shared across orchestrator + subagents).
80
+ * @param parentToolUseId Claude's `parent_tool_use_id` — non-null on
81
+ * subagent messages. When set and known, takes
82
+ * priority over the FIFO/sessionID path.
83
+ */
84
+ labelFor(sessionID: string | undefined | null, parentToolUseId?: string | null): string;
85
+ /** number of distinct sessions seen so far (for diagnostics) */
86
+ size(): number;
87
+ /** all (sessionID, label) pairs, oldest first */
88
+ entries(): Array<[string, string]>;
89
+ /** how many pending labels are queued waiting to bind to a new session */
90
+ pendingDispatchCount(): number;
91
+ }
92
+ /**
93
+ * Format a log message with a session label prefix in magenta. Mirrors the
94
+ * style of utils/log.ts:prefixLines() so per-session prefixes look the same
95
+ * as the dormant withLogPrefix-based ones.
96
+ */
97
+ export declare function formatWithLabel(label: string, message: string): string;
@@ -0,0 +1,189 @@
1
+ import type { AgentId } from "#app/external";
2
+ import type { ToolState } from "#app/toolState";
3
+ import type { ResolvedInstructions } from "#app/utils/instructions";
4
+ import type { ResolvedPayload } from "#app/utils/payload";
5
+ import type { TodoTracker } from "#app/utils/todoTracking";
6
+ export declare const MAX_STDERR_LINES = 20;
7
+ /**
8
+ * how many times the post-run loop may resume the agent to fix a dirty tree
9
+ * or a failing stop hook before giving up.
10
+ */
11
+ export declare const MAX_POST_RUN_RETRIES = 3;
12
+ export declare function getGitStatus(): string;
13
+ export declare function buildCommitPrompt(status: string): string;
14
+ export interface StopHookFailure {
15
+ exitCode: number;
16
+ output: string;
17
+ }
18
+ export interface SummaryStale {
19
+ /** absolute path to the seeded snapshot file the agent was meant to edit. */
20
+ filePath: string;
21
+ }
22
+ export interface PostRunIssues {
23
+ stopHook?: StopHookFailure;
24
+ dirtyTree?: string;
25
+ /** populated when the rolling PR summary file is byte-identical to its
26
+ * seed, i.e. the agent never touched it. soft gate — nudges once via a
27
+ * resume turn but never fails the run, parallel to dirtyTree semantics. */
28
+ summaryStale?: SummaryStale;
29
+ /**
30
+ * populated when the agent selected a review mode but the post-run check
31
+ * over toolState shows neither a `create_pull_request_review` submission
32
+ * nor a final `report_progress` write happened. derived inline from
33
+ * `toolState.selectedMode` + `toolState.review` + `toolState.finalSummaryWritten`
34
+ * via {@link getUnsubmittedReview} — no parallel toolState flag is stored.
35
+ * carries the mode name so the resume prompt can reference it. handled like
36
+ * `stopHook`: nudge via resume, hard-fail if still unsatisfied after
37
+ * `MAX_POST_RUN_RETRIES`.
38
+ */
39
+ unsubmittedReview?: "Review" | "IncrementalReview";
40
+ }
41
+ export declare function hasPostRunIssues(issues: PostRunIssues): boolean;
42
+ /**
43
+ * token/cost usage data from a single agent run.
44
+ *
45
+ * NOTE on semantics: `inputTokens` here is the *total* billable input for the
46
+ * run — non-cached input + cache read + cache write — matching the per-agent
47
+ * SDK conventions. This is what gets persisted to `WorkflowRun.inputTokens`.
48
+ *
49
+ * The stdout token table and markdown step summary display a different "Input"
50
+ * column that shows only the non-cached portion (derivable as
51
+ * `inputTokens - cacheReadTokens - cacheWriteTokens`) so humans can see the
52
+ * cache hit ratio at a glance. Dashboards that query `WorkflowRun.inputTokens`
53
+ * directly are seeing the full total, not the log column.
54
+ */
55
+ export interface AgentUsage {
56
+ agent: string;
57
+ /** full billable input: non-cached + cache read + cache write */
58
+ inputTokens: number;
59
+ outputTokens: number;
60
+ cacheReadTokens?: number | undefined;
61
+ cacheWriteTokens?: number | undefined;
62
+ costUsd?: number | undefined;
63
+ }
64
+ export interface AgentToolUseEvent {
65
+ toolName: string;
66
+ input: unknown;
67
+ }
68
+ /**
69
+ * Result returned by agent execution
70
+ */
71
+ export interface AgentResult {
72
+ success: boolean;
73
+ output?: string | undefined;
74
+ error?: string | undefined;
75
+ metadata?: Record<string, unknown>;
76
+ usage?: AgentUsage | undefined;
77
+ }
78
+ /**
79
+ * Env var that carries the per-run MCP bearer token to BOTH agent harnesses,
80
+ * which reference it from their MCP client config so the on-disk/in-config form
81
+ * holds only a placeholder, never the raw token:
82
+ * - Claude Code expands `${TERRAMEND_MCP_TOKEN}` in .mcp.json headers.
83
+ * - opencode expands `{env:TERRAMEND_MCP_TOKEN}` in remote-MCP headers.
84
+ * The `_TOKEN` suffix also makes filterEnv() strip it from the MCP shell
85
+ * sandbox. Set only on the agent/server spawn env (never process.env), so a
86
+ * co-located dependency-install subprocess never inherits it. See
87
+ * ToolContext.mcpServerToken and gateServer.ts for the same pattern.
88
+ */
89
+ export declare const MCP_SERVER_TOKEN_ENV = "TERRAMEND_MCP_TOKEN";
90
+ /**
91
+ * Context passed to agent.run() and threaded through the post-run loop.
92
+ *
93
+ * design rule: this is the single object that flows through the harness and
94
+ * downstream utilities by reference. derived predicates (e.g.
95
+ * `getUnsubmittedReview`), tmpfile paths, and seed bytes live on
96
+ * `toolState` — read them at the call site, do not duplicate them onto this
97
+ * interface. utilities that need run state should accept `ctx` whole, not
98
+ * destructure a narrow subset.
99
+ */
100
+ export interface AgentRunContext {
101
+ payload: ResolvedPayload;
102
+ resolvedModel?: string | undefined;
103
+ mcpServerUrl: string;
104
+ /** per-run bearer token the agent's MCP client presents to mcpServerUrl. See
105
+ * ToolContext.mcpServerToken — delivered to the client config out-of-band so
106
+ * it never lands in a readable file. */
107
+ mcpServerToken: string;
108
+ tmpdir: string;
109
+ /** harness-owned secret paths that agent filesystem tools must never read. */
110
+ secretDenyPaths?: string[] | undefined;
111
+ instructions: ResolvedInstructions;
112
+ todoTracker?: TodoTracker | undefined;
113
+ /**
114
+ * user-configured stop hook script. runs after the agent finishes each
115
+ * attempt; non-zero exit resumes the agent with the hook output as
116
+ * guidance. null when the repo has no stop hook configured.
117
+ */
118
+ stopScript?: string | null | undefined;
119
+ /**
120
+ * mutable per-run state shared with the MCP server (by reference). post-run
121
+ * gates read fresh values from it after each agent attempt — `summaryFilePath`,
122
+ * `summarySeed`, `selectedMode`, `review`, `finalSummaryWritten`,
123
+ * `hadProgressComment` are all consulted by `collectPostRunIssues`. see
124
+ * `action/toolState.ts` for the literal-state design rule.
125
+ */
126
+ toolState: ToolState;
127
+ /**
128
+ * called synchronously when the agent subprocess is killed for inner
129
+ * activity timeout. lets main.ts tear down shared resources (MCP HTTP
130
+ * server) so lingering SSE reconnects don't keep the outer timer alive.
131
+ */
132
+ onActivityTimeout?: (() => void) | undefined;
133
+ onToolUse?: ((event: AgentToolUseEvent) => void) | undefined;
134
+ /**
135
+ * Terramend API JWT scoped to this run. agents only need this when they
136
+ * have to write state back to Terramend mid-run (today: opencode.ts uses
137
+ * it to seed the post-hook's writeback envelope for Codex auth refresh).
138
+ * empty string when the run wasn't context-resolved (e.g. local dry-runs).
139
+ */
140
+ apiToken: string;
141
+ }
142
+ export interface Agent {
143
+ name: AgentId;
144
+ install: (token?: string) => Promise<string>;
145
+ run: (ctx: AgentRunContext) => Promise<AgentResult>;
146
+ }
147
+ export declare const agent: (input: Agent) => Agent;
148
+ /** format a USD cost to 4 decimal places, always showing the leading zero */
149
+ export declare function formatCostUsd(costUsd: number): string;
150
+ /**
151
+ * merge two AgentUsage snapshots into one running total.
152
+ *
153
+ * both agent harnesses invoke their runner multiple times per `run()` when the
154
+ * post-run retry loop kicks in (MAX_POST_RUN_RETRIES). each invocation
155
+ * produces its own AgentUsage; we sum them so downstream callers (usage
156
+ * summary, WorkflowRun persistence) see the whole session — not just the
157
+ * final retry's slice.
158
+ *
159
+ * returns `undefined` when both sides are empty so callers can short-circuit
160
+ * without a special case. zero-valued cache / cost fields are dropped to
161
+ * `undefined` for symmetry with each harness's `buildUsage`.
162
+ */
163
+ export declare function mergeAgentUsage(a: AgentUsage | undefined, b: AgentUsage | undefined): AgentUsage | undefined;
164
+ /**
165
+ * unified per-run token table used by every agent harness.
166
+ *
167
+ * columns are kept stable across agents and models so downstream log parsers
168
+ * (scripts/token-usage.ts, cost dashboards) only have to understand one format:
169
+ *
170
+ * Input non-cached input tokens sent this run
171
+ * Cache Read input tokens served from prompt cache (Anthropic, etc.)
172
+ * Cache Write input tokens written to prompt cache this run
173
+ * Output assistant output tokens
174
+ * Total sum of the four columns — the real billable quantity
175
+ * Cost ($) USD cost reported by the provider (only rendered when known)
176
+ *
177
+ * models that don't report prompt caching leave Cache Read / Write at 0.
178
+ * OpenCode emits per-step `part.cost` sourced from models.dev (works across
179
+ * Anthropic, OpenAI, Google, xAI, DeepSeek, Moonshot, OpenRouter, etc.);
180
+ * Claude CLI emits `total_cost_usd` on its final `result` event. pass the
181
+ * accumulated value via `costUsd` to render the Cost column.
182
+ */
183
+ export declare function logTokenTable(t: {
184
+ input: number;
185
+ cacheRead: number;
186
+ cacheWrite: number;
187
+ output: number;
188
+ costUsd?: number | undefined;
189
+ }): void;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Derive a cheaper subagent model override from the orchestrator's resolved
3
+ * model spec.
4
+ *
5
+ * This is a pure registry lookup: every alias in `action/models.ts` declares
6
+ * its own `subagentModel` (alias key in the same provider). At runtime we
7
+ * reverse-lookup the orchestrator's resolved slug to find the alias that
8
+ * produced it, follow the `subagentModel` pointer, and return the target
9
+ * alias's resolve / openRouterResolve depending on which route the
10
+ * orchestrator was using.
11
+ *
12
+ * Returns `{ reviewer: undefined }` when the orchestrator's alias has no
13
+ * `subagentModel` (e.g. it's already at a sufficiently cheap tier, or its
14
+ * provider doesn't have a clean cheaper-but-capable sibling). See models.ts
15
+ * for the wiring + per-provider rationale.
16
+ */
17
+ export declare function deriveSubagentModels(orchestratorSpec: string | undefined): {
18
+ reviewer: string | undefined;
19
+ };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Single source of truth for MCP tools subagents are forbidden from calling.
3
+ *
4
+ * Subagents share the orchestrator's in-process git working tree, `toolState`,
5
+ * progress comment, and run-scoped pr/branch context. A subagent that calls
6
+ * `checkout_pr` switches the orchestrator's HEAD; one that calls `push_branch`
7
+ * pushes whatever the orchestrator happens to have committed. The 2026-05-18
8
+ * `zed-industries/cloud` incident hit exactly this: a `reviewfrog` lens
9
+ * dispatched `checkout_pr({2582})` mid-review, the orchestrator's next push
10
+ * clobbered an unrelated engineer's branch. PR #796 added runtime backstops
11
+ * inside `checkout_pr`/`push_branch`; this list is the upstream gate that
12
+ * stops the call from ever reaching MCP when it originates from a subagent.
13
+ *
14
+ * The gate is enforced at two pre-tool hooks:
15
+ * - opencode: `tool.execute.before` (action/agents/opencodePlugin.ts)
16
+ * - claude: `PreToolUse` settings hook (action/agents/claudePretoolGate.ts)
17
+ *
18
+ * Names are stored in their canonical bare form (the FastMCP tool `name`
19
+ * field). Each runtime presents them with a different prefix:
20
+ * - claude: `mcp__terramend__<name>`
21
+ * - opencode: `terramend_<name>`
22
+ * The hooks strip those prefixes before comparing.
23
+ *
24
+ * Read-only MCP tools (`get_*`, `list_*`, `git_fetch`, `get_check_suite_logs`,
25
+ * `await_dependency_installation`, etc.) and the `git`/`shell` tools stay off
26
+ * this list — denying them would make review work impossible. The reviewer system prompt
27
+ * (`action/agents/reviewer.ts`) already forbids state-changing shell/git
28
+ * subcommands as a prose constraint; this list is the belt-and-suspenders
29
+ * machine fence for the high-stakes mutations we can identify by name alone.
30
+ *
31
+ * When adding a state-changing MCP tool to `action/mcp/server.ts`, add its
32
+ * canonical name here too. Inclusions justified inline.
33
+ */
34
+ export declare const SUBAGENT_DENIED_TOOLS: readonly ["checkout_pr", "push_branch", "push_tags", "delete_branch", "create_pull_request", "update_pull_request_body", "close_pull_request", "create_issue", "create_issue_comment", "edit_issue_comment", "reply_to_review_comment", "create_pull_request_review", "resolve_review_thread", "add_labels", "set_output", "report_progress", "select_mode", "start_dependency_installation", "kill_background", "upload_file"];
35
+ export type SubagentDeniedTool = (typeof SUBAGENT_DENIED_TOOLS)[number];
36
+ /**
37
+ * Strip the runtime-specific MCP prefix from a tool name and return the
38
+ * canonical bare name (matching FastMCP's `name:` field). Returns the input
39
+ * unchanged if it doesn't carry a known prefix — keeping comparison simple
40
+ * for native (non-MCP) tools, which never appear on the deny list anyway.
41
+ */
42
+ export declare function stripMcpPrefix(toolName: string): string;
43
+ /**
44
+ * Whether `toolName` (in any runtime's prefix style) names a tool that
45
+ * subagents must not call.
46
+ */
47
+ export declare function isSubagentDeniedTool(toolName: string): boolean;
48
+ /**
49
+ * Human-readable refusal surfaced to the model when a denied tool is gated.
50
+ * Phrased so a halfway-attentive subagent realises (a) the tool is denied to
51
+ * it specifically, (b) why (shared in-process state with the orchestrator),
52
+ * and (c) what to do instead (report findings; the orchestrator can call the
53
+ * tool directly).
54
+ */
55
+ export declare function buildSubagentDenyMessage(toolName: string): string;