commandmate 0.22.1 → 0.23.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 (484) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +86 -86
  3. package/.next/app-path-routes-manifest.json +17 -17
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/prerender-manifest.json +9 -9
  6. package/.next/required-server-files.json +1 -1
  7. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  8. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  9. package/.next/server/app/api/app/update-check/route.js +1 -1
  10. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/assistant/conversation/route.js +1 -1
  12. package/.next/server/app/api/assistant/conversation/route.js.nft.json +1 -1
  13. package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/assistant/current-output/route.js +1 -1
  15. package/.next/server/app/api/assistant/current-output/route.js.nft.json +1 -1
  16. package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/assistant/messages/route.js +1 -1
  18. package/.next/server/app/api/assistant/messages/route.js.nft.json +1 -1
  19. package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/assistant/session/route.js +1 -1
  21. package/.next/server/app/api/assistant/session/route.js.nft.json +1 -1
  22. package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/assistant/start/route.js +1 -1
  24. package/.next/server/app/api/assistant/start/route.js.nft.json +1 -1
  25. package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/assistant/terminal/route.js +3 -3
  27. package/.next/server/app/api/assistant/terminal/route.js.nft.json +1 -1
  28. package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/assistant/tools/route.js +1 -1
  30. package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
  31. package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/daily-summary/route.js +1 -1
  36. package/.next/server/app/api/daily-summary/route.js.nft.json +1 -1
  37. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  38. package/.next/server/app/api/daily-summary/status/route.js +1 -1
  39. package/.next/server/app/api/daily-summary/status/route.js.nft.json +1 -1
  40. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  41. package/.next/server/app/api/external-apps/[id]/health/route.js +1 -1
  42. package/.next/server/app/api/external-apps/[id]/health/route.js.nft.json +1 -1
  43. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  44. package/.next/server/app/api/external-apps/[id]/route.js +1 -1
  45. package/.next/server/app/api/external-apps/[id]/route.js.nft.json +1 -1
  46. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  47. package/.next/server/app/api/external-apps/route.js +1 -1
  48. package/.next/server/app/api/external-apps/route.js.nft.json +1 -1
  49. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  50. package/.next/server/app/api/fs/browse/route.js +1 -1
  51. package/.next/server/app/api/fs/browse/route.js.nft.json +1 -1
  52. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  53. package/.next/server/app/api/fs/recent-paths/route.js +1 -1
  54. package/.next/server/app/api/fs/recent-paths/route.js.nft.json +1 -1
  55. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/hooks/agent-event/route.js +1 -1
  57. package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
  58. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/hooks/claude-done/route.js +1 -1
  60. package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
  61. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/hooks/permission-request/route.js +1 -1
  63. package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
  64. package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
  65. package/.next/server/app/api/metrics/vibe/route.js +1 -1
  66. package/.next/server/app/api/metrics/vibe/route.js.nft.json +1 -1
  67. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  68. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/push/subscriptions/route.js +1 -1
  70. package/.next/server/app/api/push/subscriptions/route.js.nft.json +1 -1
  71. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  72. package/.next/server/app/api/push/vapid/route.js +1 -1
  73. package/.next/server/app/api/push/vapid/route.js.nft.json +1 -1
  74. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  75. package/.next/server/app/api/repositories/[id]/route.js +1 -1
  76. package/.next/server/app/api/repositories/[id]/route.js.nft.json +1 -1
  77. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  78. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route.js +1 -1
  79. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route.js.nft.json +1 -1
  80. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  81. package/.next/server/app/api/repositories/[id]/todos/route.js +1 -1
  82. package/.next/server/app/api/repositories/[id]/todos/route.js.nft.json +1 -1
  83. package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
  84. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  85. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
  86. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  87. package/.next/server/app/api/repositories/clone/route.js +1 -1
  88. package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
  89. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  90. package/.next/server/app/api/repositories/excluded/route.js +1 -1
  91. package/.next/server/app/api/repositories/excluded/route.js.nft.json +1 -1
  92. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  93. package/.next/server/app/api/repositories/restore/route.js +1 -1
  94. package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
  95. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  96. package/.next/server/app/api/repositories/route.js +1 -1
  97. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  98. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  99. package/.next/server/app/api/repositories/scan/route.js +1 -1
  100. package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
  101. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/repositories/sync/route.js +1 -1
  103. package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
  104. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  105. package/.next/server/app/api/repositories/validate-path/route.js +1 -1
  106. package/.next/server/app/api/repositories/validate-path/route.js.nft.json +1 -1
  107. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  108. package/.next/server/app/api/sidebar/group-order/route.js +1 -1
  109. package/.next/server/app/api/sidebar/group-order/route.js.nft.json +1 -1
  110. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  111. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  112. package/.next/server/app/api/skills/installations/route.js +1 -1
  113. package/.next/server/app/api/skills/installations/route.js.nft.json +1 -1
  114. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  115. package/.next/server/app/api/skills/operations/route.js +1 -1
  116. package/.next/server/app/api/skills/operations/route.js.nft.json +1 -1
  117. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  118. package/.next/server/app/api/skills/reindex/route.js +1 -1
  119. package/.next/server/app/api/skills/reindex/route.js.nft.json +1 -1
  120. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  121. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  122. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  123. package/.next/server/app/api/tasks/[taskId]/cancel/route.js +1 -4
  124. package/.next/server/app/api/tasks/[taskId]/cancel/route.js.nft.json +1 -1
  125. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  126. package/.next/server/app/api/tasks/[taskId]/route.js +1 -4
  127. package/.next/server/app/api/tasks/[taskId]/route.js.nft.json +1 -1
  128. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  129. package/.next/server/app/api/templates/[id]/route.js +1 -1
  130. package/.next/server/app/api/templates/[id]/route.js.nft.json +1 -1
  131. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  132. package/.next/server/app/api/templates/route.js +1 -1
  133. package/.next/server/app/api/templates/route.js.nft.json +1 -1
  134. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  135. package/.next/server/app/api/todos/route.js +1 -1
  136. package/.next/server/app/api/todos/route.js.nft.json +1 -1
  137. package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
  138. package/.next/server/app/api/verification/runs/[runId]/route.js +1 -1
  139. package/.next/server/app/api/verification/runs/[runId]/route.js.nft.json +1 -1
  140. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  141. package/.next/server/app/api/verification/runs/route.js +1 -1
  142. package/.next/server/app/api/verification/runs/route.js.nft.json +1 -1
  143. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  146. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
  148. package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
  149. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/cli-tool/route.js +1 -1
  151. package/.next/server/app/api/worktrees/[id]/cli-tool/route.js.nft.json +1 -1
  152. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  153. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +2 -2
  154. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js.nft.json +1 -1
  155. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  157. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  158. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  159. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js.nft.json +1 -1
  161. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  162. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +2 -2
  163. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js.nft.json +1 -1
  164. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  165. package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js +1 -1
  166. package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js.nft.json +1 -1
  167. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  168. package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js.nft.json +1 -1
  170. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  171. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js.nft.json +1 -1
  173. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  174. package/.next/server/app/api/worktrees/[id]/git/branches/route.js +1 -1
  175. package/.next/server/app/api/worktrees/[id]/git/branches/route.js.nft.json +1 -1
  176. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  177. package/.next/server/app/api/worktrees/[id]/git/checkout/route.js +1 -1
  178. package/.next/server/app/api/worktrees/[id]/git/checkout/route.js.nft.json +1 -1
  179. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  180. package/.next/server/app/api/worktrees/[id]/git/commit/route.js +1 -1
  181. package/.next/server/app/api/worktrees/[id]/git/commit/route.js.nft.json +1 -1
  182. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  183. package/.next/server/app/api/worktrees/[id]/git/diff/route.js +1 -1
  184. package/.next/server/app/api/worktrees/[id]/git/diff/route.js.nft.json +1 -1
  185. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  186. package/.next/server/app/api/worktrees/[id]/git/fetch/route.js +1 -1
  187. package/.next/server/app/api/worktrees/[id]/git/fetch/route.js.nft.json +1 -1
  188. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  189. package/.next/server/app/api/worktrees/[id]/git/log/route.js +1 -1
  190. package/.next/server/app/api/worktrees/[id]/git/log/route.js.nft.json +1 -1
  191. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  192. package/.next/server/app/api/worktrees/[id]/git/pull/route.js +1 -1
  193. package/.next/server/app/api/worktrees/[id]/git/pull/route.js.nft.json +1 -1
  194. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  195. package/.next/server/app/api/worktrees/[id]/git/push/route.js +1 -1
  196. package/.next/server/app/api/worktrees/[id]/git/push/route.js.nft.json +1 -1
  197. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  198. package/.next/server/app/api/worktrees/[id]/git/reset/route.js +1 -1
  199. package/.next/server/app/api/worktrees/[id]/git/reset/route.js.nft.json +1 -1
  200. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  201. package/.next/server/app/api/worktrees/[id]/git/revert/route.js +1 -1
  202. package/.next/server/app/api/worktrees/[id]/git/revert/route.js.nft.json +1 -1
  203. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  204. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js +1 -1
  205. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js.nft.json +1 -1
  206. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  207. package/.next/server/app/api/worktrees/[id]/git/stage/route.js +1 -1
  208. package/.next/server/app/api/worktrees/[id]/git/stage/route.js.nft.json +1 -1
  209. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  210. package/.next/server/app/api/worktrees/[id]/git/staged/route.js +1 -1
  211. package/.next/server/app/api/worktrees/[id]/git/staged/route.js.nft.json +1 -1
  212. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  213. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js +1 -1
  214. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js.nft.json +1 -1
  215. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  216. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js +1 -1
  217. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js.nft.json +1 -1
  218. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  219. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js +1 -1
  220. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js.nft.json +1 -1
  221. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  222. package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js +1 -1
  223. package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js.nft.json +1 -1
  224. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  225. package/.next/server/app/api/worktrees/[id]/git/stash/route.js +1 -1
  226. package/.next/server/app/api/worktrees/[id]/git/stash/route.js.nft.json +1 -1
  227. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  228. package/.next/server/app/api/worktrees/[id]/git/status/route.js +1 -1
  229. package/.next/server/app/api/worktrees/[id]/git/status/route.js.nft.json +1 -1
  230. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  231. package/.next/server/app/api/worktrees/[id]/git/unstage/route.js +1 -1
  232. package/.next/server/app/api/worktrees/[id]/git/unstage/route.js.nft.json +1 -1
  233. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  234. package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js +1 -1
  235. package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js.nft.json +1 -1
  236. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  237. package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
  238. package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
  239. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  240. package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
  241. package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
  242. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  243. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js +1 -1
  244. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js.nft.json +1 -1
  245. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  246. package/.next/server/app/api/worktrees/[id]/logs/route.js +1 -1
  247. package/.next/server/app/api/worktrees/[id]/logs/route.js.nft.json +1 -1
  248. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  249. package/.next/server/app/api/worktrees/[id]/marp-render/route.js +3 -3
  250. package/.next/server/app/api/worktrees/[id]/marp-render/route.js.nft.json +1 -1
  251. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  252. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js +1 -1
  253. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js.nft.json +1 -1
  254. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  255. package/.next/server/app/api/worktrees/[id]/memos/route.js +1 -1
  256. package/.next/server/app/api/worktrees/[id]/memos/route.js.nft.json +1 -1
  257. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  258. package/.next/server/app/api/worktrees/[id]/messages/route.js +1 -1
  259. package/.next/server/app/api/worktrees/[id]/messages/route.js.nft.json +1 -1
  260. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  261. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  262. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
  263. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  264. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
  265. package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
  266. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  267. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  268. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  269. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  270. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +2 -2
  271. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js.nft.json +1 -1
  272. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  273. package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +1 -1
  274. package/.next/server/app/api/worktrees/[id]/schedules/active/route.js.nft.json +1 -1
  275. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  276. package/.next/server/app/api/worktrees/[id]/schedules/route.js +3 -3
  277. package/.next/server/app/api/worktrees/[id]/schedules/route.js.nft.json +1 -1
  278. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  279. package/.next/server/app/api/worktrees/[id]/search/route.js +1 -1
  280. package/.next/server/app/api/worktrees/[id]/search/route.js.nft.json +1 -1
  281. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  282. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
  283. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  284. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  285. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +1 -1
  286. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
  287. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  288. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route.js +1 -1
  289. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route.js.nft.json +1 -1
  290. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  291. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js +1 -1
  292. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js.nft.json +1 -1
  293. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  294. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.js +1 -1
  295. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.js.nft.json +1 -1
  296. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  297. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.js +1 -1
  298. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.js.nft.json +1 -1
  299. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  300. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route.js +1 -1
  301. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route.js.nft.json +1 -1
  302. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  303. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route.js +1 -1
  304. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route.js.nft.json +1 -1
  305. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  306. package/.next/server/app/api/worktrees/[id]/skills/route.js +1 -1
  307. package/.next/server/app/api/worktrees/[id]/skills/route.js.nft.json +1 -1
  308. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  309. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
  310. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js.nft.json +1 -1
  311. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  312. package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
  313. package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
  314. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  315. package/.next/server/app/api/worktrees/[id]/start-polling/route.js +1 -1
  316. package/.next/server/app/api/worktrees/[id]/start-polling/route.js.nft.json +1 -1
  317. package/.next/server/app/api/worktrees/[id]/start-polling/route_client-reference-manifest.js +1 -1
  318. package/.next/server/app/api/worktrees/[id]/tasks/route.js +2 -2
  319. package/.next/server/app/api/worktrees/[id]/tasks/route.js.nft.json +1 -1
  320. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  321. package/.next/server/app/api/worktrees/[id]/terminal/route.js +1 -1
  322. package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
  323. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  324. package/.next/server/app/api/worktrees/[id]/timers/history/route.js +1 -1
  325. package/.next/server/app/api/worktrees/[id]/timers/history/route.js.nft.json +1 -1
  326. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  327. package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
  328. package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
  329. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  330. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js +1 -1
  331. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js.nft.json +1 -1
  332. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  333. package/.next/server/app/api/worktrees/[id]/todos/route.js +1 -1
  334. package/.next/server/app/api/worktrees/[id]/todos/route.js.nft.json +1 -1
  335. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  336. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js +1 -1
  337. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js.nft.json +1 -1
  338. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  339. package/.next/server/app/api/worktrees/[id]/tree/route.js +1 -1
  340. package/.next/server/app/api/worktrees/[id]/tree/route.js.nft.json +1 -1
  341. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  342. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route.js +1 -1
  343. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route.js.nft.json +1 -1
  344. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  345. package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -4
  346. package/.next/server/app/api/worktrees/[id]/verify/route.js.nft.json +1 -1
  347. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  348. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route.js +1 -1
  349. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route.js.nft.json +1 -1
  350. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  351. package/.next/server/app/api/worktrees/[id]/verify/runs/route.js +1 -1
  352. package/.next/server/app/api/worktrees/[id]/verify/runs/route.js.nft.json +1 -1
  353. package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
  354. package/.next/server/app/api/worktrees/[id]/viewed/route.js +1 -1
  355. package/.next/server/app/api/worktrees/[id]/viewed/route.js.nft.json +1 -1
  356. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  357. package/.next/server/app/api/worktrees/route.js +1 -1
  358. package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
  359. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  360. package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  361. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  362. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  363. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  364. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  365. package/.next/server/app/page_client-reference-manifest.js +1 -1
  366. package/.next/server/app/proxy/[...path]/route.js +1 -1
  367. package/.next/server/app/proxy/[...path]/route.js.nft.json +1 -1
  368. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  369. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  370. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  371. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  372. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  373. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  374. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  375. package/.next/server/app/worktrees/[id]/files/[...path]/page.js +1 -1
  376. package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +1 -1
  377. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  378. package/.next/server/app/worktrees/[id]/page.js +2 -2
  379. package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
  380. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  381. package/.next/server/app/worktrees/[id]/terminal/page.js +1 -1
  382. package/.next/server/app/worktrees/[id]/terminal/page.js.nft.json +1 -1
  383. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  384. package/.next/server/app-paths-manifest.json +17 -17
  385. package/.next/server/chunks/1029.js +1 -1
  386. package/.next/server/chunks/1068.js +1 -1
  387. package/.next/server/chunks/2119.js +1 -1
  388. package/.next/server/chunks/2404.js +1 -1
  389. package/.next/server/chunks/2445.js +1 -1
  390. package/.next/server/chunks/2546.js +1 -1
  391. package/.next/server/chunks/3241.js +1 -0
  392. package/.next/server/chunks/3417.js +1 -1
  393. package/.next/server/chunks/406.js +10 -6
  394. package/.next/server/chunks/4444.js +1 -1
  395. package/.next/server/chunks/5959.js +4 -5
  396. package/.next/server/chunks/5998.js +1 -12
  397. package/.next/server/chunks/6130.js +1 -1
  398. package/.next/server/chunks/6274.js +3 -3
  399. package/.next/server/chunks/6401.js +1 -1
  400. package/.next/server/chunks/6781.js +1 -0
  401. package/.next/server/chunks/7458.js +6 -0
  402. package/.next/server/chunks/{3753.js → 7970.js} +57 -32
  403. package/.next/server/chunks/8536.js +1 -1
  404. package/.next/server/chunks/8807.js +180 -127
  405. package/.next/server/chunks/9058.js +1 -1
  406. package/.next/server/chunks/9067.js +1 -1
  407. package/.next/server/chunks/9360.js +1 -1
  408. package/.next/server/chunks/9687.js +2 -2
  409. package/.next/server/middleware-manifest.json +5 -5
  410. package/.next/server/pages/500.html +1 -1
  411. package/.next/server/server-reference-manifest.json +1 -1
  412. package/.next/server/src/middleware.js.map +1 -1
  413. package/.next/static/chunks/{6488-63dacfbab082ca8d.js → 6488-95ba9d24a76f0cc5.js} +1 -1
  414. package/.next/static/chunks/app/worktrees/[id]/{page-c1be93f2595d0803.js → page-966a451ae7b0903a.js} +1 -1
  415. package/.next/trace +12 -12
  416. package/dist/cli/docs/agent-operations.d.ts +1 -1
  417. package/dist/cli/docs/agent-operations.d.ts.map +1 -1
  418. package/dist/cli/docs/agent-operations.js +5 -1
  419. package/dist/cli/utils/api-client.d.ts.map +1 -1
  420. package/dist/cli/utils/api-client.js +9 -2
  421. package/dist/cli/utils/server-url.d.ts +23 -0
  422. package/dist/cli/utils/server-url.d.ts.map +1 -1
  423. package/dist/cli/utils/server-url.js +33 -0
  424. package/dist/server/src/config/log-config.js +10 -1
  425. package/dist/server/src/config/safe-directory.js +103 -0
  426. package/dist/server/src/config/system-directories.js +74 -9
  427. package/dist/server/src/lib/cli-tools/antigravity.js +19 -2
  428. package/dist/server/src/lib/cli-tools/codex.js +95 -1
  429. package/dist/server/src/lib/cli-tools/copilot.js +30 -1
  430. package/dist/server/src/lib/cli-tools/gemini.js +28 -2
  431. package/dist/server/src/lib/cli-tools/opencode.js +51 -2
  432. package/dist/server/src/lib/git/git-default-branch.js +59 -0
  433. package/dist/server/src/lib/hooks/agent-event-service.js +205 -0
  434. package/dist/server/src/lib/hooks/agent-event-types.js +7 -86
  435. package/dist/server/src/lib/hooks/hook-settings-generator.js +26 -11
  436. package/dist/server/src/lib/hooks/permission-decision-service.js +269 -0
  437. package/dist/server/src/lib/hooks/sources/abstain.js +78 -0
  438. package/dist/server/src/lib/hooks/sources/antigravity/hooks-config.js +372 -0
  439. package/dist/server/src/lib/hooks/sources/antigravity/source.js +225 -0
  440. package/dist/server/src/lib/hooks/sources/antigravity/tool-id.js +16 -0
  441. package/dist/server/src/lib/hooks/sources/claude/source.js +143 -0
  442. package/dist/server/src/lib/hooks/sources/claude/tool-id.js +18 -0
  443. package/dist/server/src/lib/hooks/sources/codex/hooks-config.js +465 -0
  444. package/dist/server/src/lib/hooks/sources/codex/source.js +138 -0
  445. package/dist/server/src/lib/hooks/sources/codex/tool-id.js +15 -0
  446. package/dist/server/src/lib/hooks/sources/copilot/hook-settings.js +473 -0
  447. package/dist/server/src/lib/hooks/sources/copilot/source.js +210 -0
  448. package/dist/server/src/lib/hooks/sources/copilot/tool-id.js +15 -0
  449. package/dist/server/src/lib/hooks/sources/define-source.js +169 -0
  450. package/dist/server/src/lib/hooks/sources/event-mapper.js +157 -0
  451. package/dist/server/src/lib/hooks/sources/gemini/event-vocabulary.js +102 -0
  452. package/dist/server/src/lib/hooks/sources/gemini/settings-generator.js +315 -0
  453. package/dist/server/src/lib/hooks/sources/gemini/shared-config-tree.js +103 -0
  454. package/dist/server/src/lib/hooks/sources/gemini/source.js +151 -0
  455. package/dist/server/src/lib/hooks/sources/gemini/tool-id.js +17 -0
  456. package/dist/server/src/lib/hooks/sources/hook-event-vocabulary.js +111 -0
  457. package/dist/server/src/lib/hooks/sources/index.js +62 -0
  458. package/dist/server/src/lib/hooks/sources/legacy-relay.js +84 -0
  459. package/dist/server/src/lib/hooks/sources/opencode/client.js +299 -0
  460. package/dist/server/src/lib/hooks/sources/opencode/ingest.js +261 -0
  461. package/dist/server/src/lib/hooks/sources/opencode/mappers.js +154 -0
  462. package/dist/server/src/lib/hooks/sources/opencode/payloads.js +189 -0
  463. package/dist/server/src/lib/hooks/sources/opencode/ports.js +295 -0
  464. package/dist/server/src/lib/hooks/sources/opencode/runtime.js +159 -0
  465. package/dist/server/src/lib/hooks/sources/opencode/source.js +250 -0
  466. package/dist/server/src/lib/hooks/sources/opencode/subscription.js +422 -0
  467. package/dist/server/src/lib/hooks/sources/opencode/tool-id.js +14 -0
  468. package/dist/server/src/lib/hooks/sources/opencode/turn-gate.js +193 -0
  469. package/dist/server/src/lib/hooks/sources/pending-decisions.js +127 -0
  470. package/dist/server/src/lib/hooks/sources/registry.js +111 -0
  471. package/dist/server/src/lib/hooks/sources/types.js +46 -0
  472. package/dist/server/src/lib/session/agent-session-lifecycle.js +82 -0
  473. package/dist/server/src/lib/session/claude-session.js +10 -3
  474. package/dist/server/src/lib/tasks/contract-message.js +175 -0
  475. package/dist/server/src/lib/verification/env-clean-gate.js +320 -0
  476. package/dist/server/src/lib/verification/env-snapshot.js +474 -0
  477. package/dist/server/src/lib/verification/gate-runner.js +802 -0
  478. package/dist/server/src/lib/verification/scope-gate.js +402 -0
  479. package/dist/server/src/lib/verification/verify-config.js +281 -0
  480. package/package.json +1 -1
  481. package/scripts/hooks/cmate-agent-event.sh +73 -3
  482. package/.next/server/chunks/8856.js +0 -4
  483. /package/.next/static/{d4vh4O18WEhXs4WbdShIs → wH6K6QNPHSdATFkVoIcy3}/_buildManifest.js +0 -0
  484. /package/.next/static/{d4vh4O18WEhXs4WbdShIs → wH6K6QNPHSdATFkVoIcy3}/_ssgManifest.js +0 -0
@@ -0,0 +1,250 @@
1
+ "use strict";
2
+ /**
3
+ * opencode as an {@link AgentEventSource} — the first pull implementation
4
+ * (Issue #1763, Epic #1720 Phase 4-5).
5
+ *
6
+ * Five tools push into `POST /api/hooks/agent-event`; this one is subscribed
7
+ * to. #1758 established that the difference is real and not cosmetic, and
8
+ * #1759 built the interface so it could be expressed without a special case.
9
+ * What is here is that expression: `definePullEventSource`, the measured
10
+ * values, and nothing shaped like `if (tool === 'opencode')` anywhere above it.
11
+ *
12
+ * ## Why each declared value is what it is
13
+ *
14
+ * - **`noDecision: 'blocks'`** — measured, and the single most consequential
15
+ * line in the file. An approval left unanswered for **10 minutes 19 seconds**
16
+ * was still pending, with no timeout event and no fall-through (#1758 §5.5.3).
17
+ * The TUI dialog and the REST request are not two stages, they are the same
18
+ * pending object seen twice, so "abstaining costs a dialog" — true on Claude,
19
+ * codex and copilot — is false here: abstaining costs the session. Callers
20
+ * read this through `describeAbstain()` and owe the operator a visible signal.
21
+ * - **`configScope: 'none'`** — nothing is written anywhere. No settings file,
22
+ * no hooks entry, no change to `~/.config/opencode/opencode.jsonc`. The whole
23
+ * integration is a `--port` argument and a subscription.
24
+ * - **`decisionTimeoutSeconds: null`** — the honest encoding of "waits forever".
25
+ * Not zero, which would read as "answer instantly or lose the chance", and not
26
+ * a large number, which would read as a deadline that exists.
27
+ * - **`supportedEvents`** — seven words, but two of them mean less than their
28
+ * name suggests. `session_end` fires only for an explicit
29
+ * `DELETE /session/:id`; the TUI's `/exit` emits nothing at all, so process
30
+ * death stays tmux's question (§5.6.4). And `notification` is a bundle of
31
+ * three unrelated events with no `idle_prompt` member — opencode never reports
32
+ * "the agent is sitting at the composer".
33
+ *
34
+ * ## What is deliberately not done
35
+ *
36
+ * `GET /session` is never called to enumerate "this instance's sessions". It
37
+ * returns sessions belonging to *other processes* that share the same `HOME`
38
+ * and project directory, because a session belongs to `opencode.db` rather than
39
+ * to a server (§5.6.3). Instance identity is (worktree, tool, instance) and the
40
+ * port, exactly as it is for every other tool.
41
+ *
42
+ * @module lib/hooks/sources/opencode/source
43
+ */
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.opencodeAgentEventSource = void 0;
46
+ exports.toOpencodePermissionReply = toOpencodePermissionReply;
47
+ exports.prepareOpencodeLaunch = prepareOpencodeLaunch;
48
+ const agent_event_types_1 = require("../../../../lib/hooks/agent-event-types");
49
+ const hook_settings_generator_1 = require("../../../../lib/hooks/hook-settings-generator");
50
+ const logger_1 = require("../../../../lib/logger");
51
+ const define_source_1 = require("../define-source");
52
+ const client_1 = require("./client");
53
+ const mappers_1 = require("./mappers");
54
+ const payloads_1 = require("./payloads");
55
+ const ports_1 = require("./ports");
56
+ const subscription_1 = require("./subscription");
57
+ const tool_id_1 = require("./tool-id");
58
+ const logger = (0, logger_1.createLogger)('lib/hooks/sources/opencode/source');
59
+ /**
60
+ * The `AGENT_EVENT_TYPES` members opencode can produce.
61
+ *
62
+ * All seven, but see the module comment for what two of them actually mean.
63
+ * Spelled from the shared constant so a new word added to the vocabulary is a
64
+ * compile-time decision here rather than a silent omission.
65
+ */
66
+ const OPENCODE_SUPPORTED_EVENTS = agent_event_types_1.AGENT_EVENT_TYPES;
67
+ /**
68
+ * Map a verdict onto opencode's three-valued reply, or null when it has none.
69
+ *
70
+ * `abstain` is null and that is the point: there is no wire value for "no
71
+ * opinion", because there is no request to answer — the reply is a fresh POST
72
+ * that simply does not happen. What that costs is {@link
73
+ * AgentEventSource.noDecision}, not something this function can express.
74
+ */
75
+ function toOpencodePermissionReply(verdict) {
76
+ switch (verdict.kind) {
77
+ case 'allowOnce':
78
+ return 'once';
79
+ case 'allowAlways':
80
+ return 'always';
81
+ case 'deny':
82
+ return 'reject';
83
+ case 'answer':
84
+ case 'abstain':
85
+ return null;
86
+ }
87
+ }
88
+ /**
89
+ * Send a verdict over its own connection (C2).
90
+ *
91
+ * The caller — `answerPendingDecision` — does not know this is an HTTP call
92
+ * rather than a response body, and must not.
93
+ */
94
+ async function decideOpencode(target, decision, verdict) {
95
+ const instanceId = target.instanceId ?? target.cliToolId;
96
+ if (verdict.kind === 'abstain') {
97
+ // Nothing is sent, and on this tool that is an action rather than the
98
+ // absence of one: the agent waits with no timeout. Logged here as well as
99
+ // at the receiver, because this is the layer that knows the decision was
100
+ // addressed to a source whose silence blocks.
101
+ logger.warn('opencode-verdict-abstained', {
102
+ worktreeId: target.worktreeId,
103
+ instanceId,
104
+ decisionId: decision.id,
105
+ consequence: 'the agent waits indefinitely; nothing else will unblock it',
106
+ });
107
+ return;
108
+ }
109
+ const port = (0, ports_1.getAssignedOpencodePort)(target);
110
+ if (port === null) {
111
+ logger.warn('opencode-verdict-undeliverable-no-port', {
112
+ worktreeId: target.worktreeId,
113
+ instanceId,
114
+ decisionId: decision.id,
115
+ });
116
+ return;
117
+ }
118
+ if (decision.kind === 'question') {
119
+ if (verdict.kind !== 'answer') {
120
+ // An approval verdict cannot answer a question — and unlike Claude, where
121
+ // allowing the `AskUserQuestion` permission still leaves the picker up,
122
+ // there is nothing here that would make it harmless.
123
+ logger.info('opencode-question-not-answerable', {
124
+ worktreeId: target.worktreeId,
125
+ instanceId,
126
+ decisionId: decision.id,
127
+ verdict: verdict.kind,
128
+ });
129
+ return;
130
+ }
131
+ const delivered = await (0, client_1.replyOpencodeQuestion)(port, decision.id, verdict.answers);
132
+ logger.info('opencode-question-replied', {
133
+ worktreeId: target.worktreeId,
134
+ instanceId,
135
+ decisionId: decision.id,
136
+ delivered,
137
+ });
138
+ return;
139
+ }
140
+ const reply = toOpencodePermissionReply(verdict);
141
+ if (reply === null)
142
+ return;
143
+ const delivered = await (0, client_1.replyOpencodePermission)(port, decision.id, reply, verdict.kind === 'deny' ? verdict.message : undefined);
144
+ logger.info('opencode-permission-replied', {
145
+ worktreeId: target.worktreeId,
146
+ instanceId,
147
+ decisionId: decision.id,
148
+ reply,
149
+ delivered,
150
+ });
151
+ }
152
+ /** Re-read what is waiting on a human (C7). */
153
+ async function listOpencodePending(target) {
154
+ const port = (0, ports_1.getAssignedOpencodePort)(target);
155
+ if (port === null)
156
+ return [];
157
+ const askedAt = Date.now();
158
+ const [permissions, questions] = await Promise.all([
159
+ (0, client_1.fetchOpencodePendingPermissions)(port),
160
+ (0, client_1.fetchOpencodePendingQuestions)(port),
161
+ ]);
162
+ const pending = [];
163
+ for (const entry of permissions) {
164
+ const decision = (0, payloads_1.toOpencodePendingPermission)(entry, askedAt);
165
+ if (decision)
166
+ pending.push(decision);
167
+ }
168
+ for (const entry of questions) {
169
+ const decision = (0, payloads_1.toOpencodePendingQuestion)(entry, askedAt);
170
+ if (decision)
171
+ pending.push(decision);
172
+ }
173
+ return pending;
174
+ }
175
+ /**
176
+ * Ask whether the conversation is working (C7).
177
+ *
178
+ * Note what `busy` includes: a session blocked on an approval reads `busy`
179
+ * (#1758 §5.3.1), because from the server's point of view the turn has not
180
+ * ended. This answers "is the turn over", never "is a human needed".
181
+ */
182
+ async function probeOpencodeActivity(target) {
183
+ const port = (0, ports_1.getAssignedOpencodePort)(target);
184
+ if (port === null)
185
+ return null;
186
+ return (0, client_1.fetchOpencodeActivity)(port);
187
+ }
188
+ /**
189
+ * The command that starts opencode for one instance (S3 / S4 / S5).
190
+ *
191
+ * The whole of the launch change #1763 makes. #1758 §5.1.2 measured that the
192
+ * plain TUI serves the same API `opencode serve` does when given `--port`, so
193
+ * there is no second process to start, no pid to track and no orphan to reap —
194
+ * the server's lifetime is the pane's.
195
+ *
196
+ * Falls back to the bare executable — the pre-#1763 command, byte for byte —
197
+ * whenever there is no port to pass: `CM_AGENT_HOOKS_INJECT=0`, an exhausted
198
+ * range, or a caller that did not allocate one. A session that starts without
199
+ * structured events is the status quo; a session that fails to start is not.
200
+ *
201
+ * `--hostname` is passed explicitly even though `127.0.0.1` is the default,
202
+ * because the default is the security property: the server is unauthenticated,
203
+ * and `--mdns` (never passed) would move it to `0.0.0.0` (#1758 §5.8.3).
204
+ */
205
+ function prepareOpencodeLaunch(target, executablePath) {
206
+ if (!(0, hook_settings_generator_1.isHookInjectionEnabled)()) {
207
+ return { command: executablePath, settingsPath: null };
208
+ }
209
+ const port = (0, ports_1.getAssignedOpencodePort)(target);
210
+ if (port === null) {
211
+ return { command: executablePath, settingsPath: null };
212
+ }
213
+ return {
214
+ command: `${(0, hook_settings_generator_1.shellQuote)(executablePath)} --port ${port} --hostname ${client_1.OPENCODE_SERVER_HOST}`,
215
+ // Nothing is written to disk. `configScope: 'none'` says the same thing to
216
+ // a caller that asks the capabilities instead of the plan.
217
+ settingsPath: null,
218
+ };
219
+ }
220
+ /**
221
+ * opencode as an event source.
222
+ *
223
+ * Registered in `../registry`. Nothing outside this directory imports it by
224
+ * name; callers ask the registry for the tool they are holding.
225
+ */
226
+ exports.opencodeAgentEventSource = (0, define_source_1.definePullEventSource)({
227
+ cliToolId: tool_id_1.OPENCODE_CLI_TOOL_ID,
228
+ // #1758 §5.5.3. Not a default, not an assumption — a stopwatch.
229
+ noDecision: { kind: 'blocks' },
230
+ capabilities: {
231
+ supportedEvents: OPENCODE_SUPPORTED_EVENTS,
232
+ configScope: 'none',
233
+ decisionTimeoutSeconds: null,
234
+ },
235
+ // C4. Predicates, not a name table: see ./mappers.
236
+ mappers: mappers_1.OPENCODE_MAPPERS,
237
+ // The envelope names the event in `type`; `hook_event_name` does not exist.
238
+ nativeEventNameFields: ['type'],
239
+ // Flat lookup cannot reach `properties.sessionID`; the rules fill it in.
240
+ conversationIdFields: [],
241
+ parsePermissionRequest: payloads_1.parseOpencodePermissionRequest,
242
+ parseQuestion: payloads_1.parseOpencodeQuestion,
243
+ // Self-reference resolves at call time, which is after this const is bound.
244
+ subscribe: (target, onEvent) => (0, subscription_1.openOpencodeSubscription)(target, onEvent, (raw) => exports.opencodeAgentEventSource.normalizeEvent(raw)),
245
+ decide: decideOpencode,
246
+ listPending: listOpencodePending,
247
+ probeActivity: probeOpencodeActivity,
248
+ liveness: (target) => (0, subscription_1.getOpencodeLiveness)(target),
249
+ prepareLaunch: prepareOpencodeLaunch,
250
+ });
@@ -0,0 +1,422 @@
1
+ "use strict";
2
+ /**
3
+ * Holding the SSE connection to one opencode instance (Issue #1763, constraint
4
+ * C1).
5
+ *
6
+ * Every other tool CommandMate supports pushes: the agent runs a hook, the hook
7
+ * POSTs, and there is nothing to keep alive. opencode is subscribed to, so this
8
+ * module owns the states a push transport does not have — connected, lost,
9
+ * reconnecting — and the failure modes that come with them.
10
+ *
11
+ * ## What it has to get right
12
+ *
13
+ * - **Reconnect, and re-read what was missed.** Durable replay does not work on
14
+ * 1.18.3: `GET /api/session/:id/event?after=<seq>` returns zero bytes (#1758
15
+ * §5.2.2). So a reconnect cannot ask "what did I miss"; it re-reads *state*
16
+ * instead, from `GET /permission` and `GET /question`, which is what makes a
17
+ * dropped approval recoverable rather than lost forever. A missed
18
+ * `session.idle` is not recoverable and is not pretended to be — `wait` falls
19
+ * back to the scraper, which is the pre-#1763 behaviour.
20
+ * - **Not report a turn twice.** See `./turn-gate`.
21
+ * - **Not throw on an unknown frame.** `server.heartbeat` arrives every ten
22
+ * seconds and is not in the server's own OpenAPI `Event` union (#1758 D5), so
23
+ * a strict reader would fail six times a minute on a healthy connection. It is
24
+ * counted, not raised.
25
+ * - **Know when the connection is dead.** The heartbeat is the signal: 60 of
26
+ * them over ten minutes, gaps of 10.00-10.03 s (§5.7.1). Silence past
27
+ * {@link OPENCODE_HEARTBEAT_TIMEOUT_MS} means the stream is gone even if the
28
+ * socket has not noticed.
29
+ *
30
+ * ## Held on `globalThis`
31
+ *
32
+ * Not decoration (Issue #1736). Under `next dev` every route handler is bundled
33
+ * separately, so a module-scoped map of live subscriptions would be one map per
34
+ * bundle: the launcher would open a stream the receiver cannot see, closing a
35
+ * session would leave a stream running against a dead pane, and starting the
36
+ * same instance twice would open two streams that both deliver every event.
37
+ * None of that produces an error.
38
+ *
39
+ * @module lib/hooks/sources/opencode/subscription
40
+ */
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.OPENCODE_RECONNECT_BACKOFF_MS = exports.OPENCODE_HEARTBEAT_TIMEOUT_MS = void 0;
43
+ exports.isOpencodeSubscribed = isOpencodeSubscribed;
44
+ exports.getOpencodeLiveness = getOpencodeLiveness;
45
+ exports.openOpencodeSubscription = openOpencodeSubscription;
46
+ exports.closeOpencodeSubscription = closeOpencodeSubscription;
47
+ exports.resetOpencodeSubscriptions = resetOpencodeSubscriptions;
48
+ const logger_1 = require("../../../../lib/logger");
49
+ const auto_yes_state_1 = require("../../../../lib/auto-yes-state");
50
+ const event_mapper_1 = require("../event-mapper");
51
+ const client_1 = require("./client");
52
+ const mappers_1 = require("./mappers");
53
+ const payloads_1 = require("./payloads");
54
+ const ports_1 = require("./ports");
55
+ const turn_gate_1 = require("./turn-gate");
56
+ const logger = (0, logger_1.createLogger)('lib/hooks/sources/opencode/subscription');
57
+ /**
58
+ * How long a connection may be silent before it counts as dead.
59
+ *
60
+ * The heartbeat is a metronome at 10 s (#1758 §5.7.1), so three missed beats is
61
+ * unambiguous while leaving room for a stalled event loop. Shorter would churn
62
+ * connections on a busy server; longer would leave `liveness` claiming `live`
63
+ * for a stream that stopped.
64
+ */
65
+ exports.OPENCODE_HEARTBEAT_TIMEOUT_MS = 30_000;
66
+ /** Reconnect backoff, in ms. The last value repeats. */
67
+ exports.OPENCODE_RECONNECT_BACKOFF_MS = [
68
+ 1_000, 2_000, 4_000, 8_000, 15_000, 30_000,
69
+ ];
70
+ /** Cap on remembered decision ids, so a long session cannot grow the set. */
71
+ const MAX_SEEN_DECISIONS = 256;
72
+ const subscriptions = (globalThis.__opencodeSubscriptions ??= new Map());
73
+ function keyOf(target) {
74
+ return (0, auto_yes_state_1.buildCompositeKey)(target.worktreeId, target.cliToolId, target.instanceId);
75
+ }
76
+ /** Whether a stream is currently held for this instance. */
77
+ function isOpencodeSubscribed(target) {
78
+ return subscriptions.has(keyOf(target));
79
+ }
80
+ /**
81
+ * How the connection to this instance is doing (C6).
82
+ *
83
+ * `unknown` for an instance with no subscription, which is the honest answer:
84
+ * a session started before this feature, or launched with structured events off,
85
+ * is indistinguishable from one whose stream has not been opened.
86
+ */
87
+ function getOpencodeLiveness(target) {
88
+ return subscriptions.get(keyOf(target))?.liveness ?? { state: 'unknown' };
89
+ }
90
+ /** A subscription handle for an instance that has no server to subscribe to. */
91
+ function inertSubscription() {
92
+ return { close: async () => { }, liveness: { state: 'unknown' } };
93
+ }
94
+ /**
95
+ * Open — or re-use — the event stream for one instance.
96
+ *
97
+ * Resolves as soon as the stream loop is running, not when the first frame
98
+ * arrives: the caller is a `startSession` that must not be held up by a server
99
+ * that is still booting, and the loop's own reconnect handles a port that is
100
+ * not listening yet.
101
+ *
102
+ * Never throws. A source that cannot reach its agent degrades to the scraper,
103
+ * and this call sits on the session-start path.
104
+ *
105
+ * @param target - The instance to watch
106
+ * @param onEvent - Receives normalised events, gated by {@link TurnGate}
107
+ * @param normalize - The source's own `normalizeEvent`, passed in rather than
108
+ * imported so this module does not depend on the module that depends on it
109
+ * @param port - Overrides the recorded assignment. For tests
110
+ */
111
+ async function openOpencodeSubscription(target, onEvent, normalize, port) {
112
+ const key = keyOf(target);
113
+ const existing = subscriptions.get(key);
114
+ if (existing)
115
+ return handleFor(existing);
116
+ const resolvedPort = port ?? (0, ports_1.getAssignedOpencodePort)(target);
117
+ if (resolvedPort === null) {
118
+ // No port was assigned: structured events are off, allocation failed, or
119
+ // this pane predates the feature. All three mean "the scraper is in charge",
120
+ // which is exactly what an inert subscription expresses.
121
+ logger.info('opencode-subscription-skipped-no-port', {
122
+ worktreeId: target.worktreeId,
123
+ instanceId: target.instanceId ?? target.cliToolId,
124
+ });
125
+ return inertSubscription();
126
+ }
127
+ const state = {
128
+ key,
129
+ target,
130
+ port: resolvedPort,
131
+ onEvent,
132
+ normalize,
133
+ gate: (0, turn_gate_1.createTurnGate)(),
134
+ seenDecisions: new Set(),
135
+ streamController: new AbortController(),
136
+ liveness: { state: 'unknown' },
137
+ closed: false,
138
+ watchdog: null,
139
+ };
140
+ subscriptions.set(key, state);
141
+ logger.info('opencode-subscription-opened', {
142
+ worktreeId: target.worktreeId,
143
+ instanceId: target.instanceId ?? target.cliToolId,
144
+ port: resolvedPort,
145
+ });
146
+ // Deliberately not awaited: the loop runs for the life of the session.
147
+ void runStream(state);
148
+ return handleFor(state);
149
+ }
150
+ /** The handle the caller holds. `liveness` reads through to the live state. */
151
+ function handleFor(state) {
152
+ return {
153
+ close: async () => {
154
+ await closeOpencodeSubscription(state.target);
155
+ },
156
+ get liveness() {
157
+ return state.liveness;
158
+ },
159
+ };
160
+ }
161
+ /** Stop watching an instance. Idempotent. */
162
+ async function closeOpencodeSubscription(target) {
163
+ const key = keyOf(target);
164
+ const state = subscriptions.get(key);
165
+ if (!state)
166
+ return;
167
+ state.closed = true;
168
+ clearWatchdog(state);
169
+ state.streamController.abort();
170
+ subscriptions.delete(key);
171
+ logger.info('opencode-subscription-closed', {
172
+ worktreeId: target.worktreeId,
173
+ instanceId: target.instanceId ?? target.cliToolId,
174
+ port: state.port,
175
+ });
176
+ }
177
+ /** Close every subscription without waiting. Test seam. */
178
+ function resetOpencodeSubscriptions() {
179
+ for (const state of subscriptions.values()) {
180
+ state.closed = true;
181
+ clearWatchdog(state);
182
+ state.streamController.abort();
183
+ }
184
+ subscriptions.clear();
185
+ }
186
+ function clearWatchdog(state) {
187
+ if (state.watchdog !== null) {
188
+ clearTimeout(state.watchdog);
189
+ state.watchdog = null;
190
+ }
191
+ }
192
+ /**
193
+ * Restart the silence timer.
194
+ *
195
+ * `unref` so a held connection never keeps a CLI process alive; the server has
196
+ * its own reasons to stay up and does not need this timer to supply one.
197
+ */
198
+ function armWatchdog(state) {
199
+ clearWatchdog(state);
200
+ const timer = setTimeout(() => {
201
+ if (state.closed)
202
+ return;
203
+ logger.warn('opencode-subscription-heartbeat-lost', {
204
+ worktreeId: state.target.worktreeId,
205
+ instanceId: state.target.instanceId ?? state.target.cliToolId,
206
+ port: state.port,
207
+ afterMs: exports.OPENCODE_HEARTBEAT_TIMEOUT_MS,
208
+ });
209
+ // Force the read to end; the loop treats it as a dropped connection.
210
+ state.streamController.abort();
211
+ }, exports.OPENCODE_HEARTBEAT_TIMEOUT_MS);
212
+ timer.unref?.();
213
+ state.watchdog = timer;
214
+ }
215
+ /** Sleep, unless the subscription is torn down first. */
216
+ function delay(ms, signal) {
217
+ return new Promise((resolve) => {
218
+ const timer = setTimeout(resolve, ms);
219
+ timer.unref?.();
220
+ signal.addEventListener('abort', () => {
221
+ clearTimeout(timer);
222
+ resolve();
223
+ }, { once: true });
224
+ });
225
+ }
226
+ function backoffFor(attempt) {
227
+ const index = Math.min(attempt, exports.OPENCODE_RECONNECT_BACKOFF_MS.length - 1);
228
+ return exports.OPENCODE_RECONNECT_BACKOFF_MS[index];
229
+ }
230
+ /**
231
+ * The connection loop.
232
+ *
233
+ * Runs until `close()`. Every ending — a clean EOF, an aborted read, a refused
234
+ * connection — is the same thing to this function: reconnect after a backoff,
235
+ * having first re-read the state that could not be replayed.
236
+ */
237
+ async function runStream(state) {
238
+ let attempt = 0;
239
+ while (!state.closed) {
240
+ state.streamController = new AbortController();
241
+ // A reconnect is a new arming window: whatever was mid-turn when the
242
+ // connection dropped, its `session.status(busy)` was on the old stream, and
243
+ // an idle that arrives without one must not resolve a `wait`.
244
+ state.gate.reset();
245
+ let reason = 'stream-ended';
246
+ try {
247
+ await resyncPending(state);
248
+ armWatchdog(state);
249
+ for await (const frame of (0, client_1.readOpencodeEventStream)(state.port, state.streamController.signal)) {
250
+ attempt = 0;
251
+ armWatchdog(state);
252
+ handleFrame(state, frame);
253
+ }
254
+ }
255
+ catch (error) {
256
+ reason = error instanceof Error ? error.message : String(error);
257
+ }
258
+ finally {
259
+ clearWatchdog(state);
260
+ }
261
+ if (state.closed)
262
+ break;
263
+ state.liveness = { state: 'lost', since: Date.now(), reason };
264
+ logger.warn('opencode-subscription-disconnected', {
265
+ worktreeId: state.target.worktreeId,
266
+ instanceId: state.target.instanceId ?? state.target.cliToolId,
267
+ port: state.port,
268
+ reason,
269
+ attempt,
270
+ });
271
+ await delay(backoffFor(attempt), state.streamController.signal);
272
+ attempt += 1;
273
+ }
274
+ }
275
+ /**
276
+ * Re-read what is waiting on a human and announce anything not seen yet (C7).
277
+ *
278
+ * The only recovery opencode offers. An approval raised while CommandMate was
279
+ * disconnected is still pending on the server, so re-reading it restores both
280
+ * the "a human is blocked" state and Auto-Yes's chance to adjudicate it — which
281
+ * matters more here than anywhere else, because an unanswered opencode approval
282
+ * waits forever (#1758 §5.5.3).
283
+ */
284
+ async function resyncPending(state) {
285
+ const now = Date.now();
286
+ const [permissions, questions] = await Promise.all([
287
+ (0, client_1.fetchOpencodePendingPermissions)(state.port),
288
+ (0, client_1.fetchOpencodePendingQuestions)(state.port),
289
+ ]);
290
+ const replay = (entries, type) => {
291
+ for (const entry of entries) {
292
+ const id = (0, event_mapper_1.readStringField)(entry, 'id');
293
+ if (!id || state.seenDecisions.has(id))
294
+ continue;
295
+ // Rebuilt into the envelope the live path uses, so one mapper and one
296
+ // parser cover both arrival routes.
297
+ deliver(state, { id: `resync_${id}`, type, properties: entry }, now);
298
+ }
299
+ };
300
+ replay(permissions, 'permission.asked');
301
+ replay(questions, 'question.asked');
302
+ }
303
+ /** Process one frame off the stream. */
304
+ function handleFrame(state, frame) {
305
+ const type = (0, event_mapper_1.readStringField)(frame, 'type');
306
+ if (type === 'server.heartbeat' || type === 'server.connected') {
307
+ state.liveness = { state: 'live', lastHeartbeatAt: Date.now() };
308
+ // Still normalised below so the unknown-event tally counts it: the tally is
309
+ // the diagnostic for "this tool sends words we have none for", and a
310
+ // keepalive silently excluded from it would make the count look healthier
311
+ // than the vocabulary is.
312
+ }
313
+ deliver(state, frame, Date.now());
314
+ }
315
+ /**
316
+ * Normalise one frame and hand it on, if the gate allows.
317
+ *
318
+ * @param frame - `{ id, type, properties }`, live or rebuilt from a re-sync
319
+ * @param receivedAt - Epoch ms
320
+ */
321
+ function deliver(state, frame, receivedAt) {
322
+ const type = (0, event_mapper_1.readStringField)(frame, 'type');
323
+ // Recorded before the mapping, and for every status: `permission.asked` names
324
+ // no tool, only a `callID`, and the frame that does name it is the `pending`
325
+ // one — which maps to nothing at all. Reading it only from mapped events
326
+ // would leave every approval anonymous (see ./payloads).
327
+ if (type === 'message.part.updated') {
328
+ const callId = (0, mappers_1.partCallId)(frame);
329
+ const toolName = (0, mappers_1.partToolName)(frame);
330
+ if (callId && toolName)
331
+ (0, payloads_1.rememberOpencodeToolCall)(callId, toolName);
332
+ }
333
+ const observation = state.gate.observe(type, frame);
334
+ if (observation.kind === 'failed') {
335
+ logger.warn('opencode-session-error', {
336
+ worktreeId: state.target.worktreeId,
337
+ instanceId: state.target.instanceId ?? state.target.cliToolId,
338
+ sessionId: observation.sessionId,
339
+ errorName: observation.errorName,
340
+ });
341
+ }
342
+ let normalized = null;
343
+ try {
344
+ normalized = state.normalize({ payload: frame, receivedAt });
345
+ }
346
+ catch (error) {
347
+ // The interface forbids this, and a source that broke the rule must still
348
+ // not take the connection down with it.
349
+ logger.error('opencode-normalize-threw', {
350
+ type,
351
+ error: error instanceof Error ? error.message : String(error),
352
+ });
353
+ return;
354
+ }
355
+ if (!normalized)
356
+ return;
357
+ const suppressedBecause = gateVerdict(normalized.event, observation);
358
+ if (suppressedBecause !== null) {
359
+ logger.info('opencode-repeat-suppressed', {
360
+ worktreeId: state.target.worktreeId,
361
+ instanceId: state.target.instanceId ?? state.target.cliToolId,
362
+ sessionId: normalized.conversationId,
363
+ event: normalized.event,
364
+ reason: suppressedBecause,
365
+ });
366
+ return;
367
+ }
368
+ rememberDecisionId(state, frame);
369
+ try {
370
+ state.onEvent(normalized);
371
+ }
372
+ catch (error) {
373
+ logger.error('opencode-event-handler-failed', {
374
+ type,
375
+ error: error instanceof Error ? error.message : String(error),
376
+ });
377
+ }
378
+ }
379
+ /**
380
+ * Whether the gate refuses to let this event through, and why.
381
+ *
382
+ * Both words opencode repeats are gated, and both would be wrong in the same
383
+ * direction — the status layer reads only the newest event, so a repeat of
384
+ * either overwrites the truth:
385
+ *
386
+ * - a second `stop` resolves a `wait` for work that is not over;
387
+ * - a trailing `user_prompt_submit` — which opencode emits *after*
388
+ * `session.idle` — leaves a finished turn reading `running` for the next
389
+ * thirty minutes.
390
+ *
391
+ * Everything else passes: repeats of `pre_tool_use` and `post_tool_use` are
392
+ * idempotent in the state machine they feed, and the receiver's own dedup
393
+ * window collapses them anyway.
394
+ *
395
+ * @returns The suppression reason, or null when the event may be delivered
396
+ */
397
+ function gateVerdict(event, observation) {
398
+ if (event === 'stop' && observation.kind !== 'completed') {
399
+ return observation.kind === 'suppressed' ? observation.reason : 'not-a-turn-end';
400
+ }
401
+ if (event === 'user_prompt_submit' && observation.kind !== 'announced') {
402
+ return observation.kind === 'suppressed' ? observation.reason : 'not-a-new-prompt';
403
+ }
404
+ return null;
405
+ }
406
+ /** Note an approval / question id so a later re-sync does not repeat it. */
407
+ function rememberDecisionId(state, frame) {
408
+ const type = (0, event_mapper_1.readStringField)(frame, 'type');
409
+ if (type !== 'permission.asked' && type !== 'question.asked')
410
+ return;
411
+ const properties = (0, event_mapper_1.isPlainObject)(frame.properties) ? frame.properties : {};
412
+ const id = (0, event_mapper_1.readStringField)(properties, 'id');
413
+ if (!id)
414
+ return;
415
+ state.seenDecisions.add(id);
416
+ while (state.seenDecisions.size > MAX_SEEN_DECISIONS) {
417
+ const oldest = state.seenDecisions.values().next();
418
+ if (oldest.done)
419
+ break;
420
+ state.seenDecisions.delete(oldest.value);
421
+ }
422
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ /**
3
+ * opencode's {@link CLIToolType}, on its own so the id can be imported without
4
+ * pulling in the source (Issue #1763).
5
+ *
6
+ * Same shape as `../claude/tool-id`: the registry, the launcher and the tests
7
+ * all need the literal, and only the registry needs the implementation.
8
+ *
9
+ * @module lib/hooks/sources/opencode/tool-id
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.OPENCODE_CLI_TOOL_ID = void 0;
13
+ /** The tool id every opencode module keys off. */
14
+ exports.OPENCODE_CLI_TOOL_ID = 'opencode';