commandmate 0.42.1 → 0.43.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 (435) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +144 -144
  3. package/.next/app-path-routes-manifest.json +23 -23
  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/agents/update/route_client-reference-manifest.js +1 -1
  9. package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
  10. package/.next/server/app/api/app/release-notes/route_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  12. package/.next/server/app/api/app/update-check/route.js +1 -1
  13. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/capabilities/route.js +1 -1
  18. package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/daily-summary/route.js +1 -1
  20. package/.next/server/app/api/daily-summary/route.js.nft.json +1 -1
  21. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  22. package/.next/server/app/api/daily-summary/status/route.js +1 -1
  23. package/.next/server/app/api/daily-summary/status/route.js.nft.json +1 -1
  24. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  25. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  27. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  28. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  30. package/.next/server/app/api/hooks/agent-event/route.js +103 -1
  31. package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
  32. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/hooks/claude-done/route.js +2 -2
  34. package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
  35. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/hooks/permission-request/route.js +1 -1
  37. package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
  38. package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  40. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  41. package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
  42. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  43. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  44. package/.next/server/app/api/relays/[relayId]/cancel/route.js +1 -1
  45. package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
  46. package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
  47. package/.next/server/app/api/relays/route.js +1 -1
  48. package/.next/server/app/api/relays/route.js.nft.json +1 -1
  49. package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
  50. package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
  51. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  52. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  53. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
  54. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  55. package/.next/server/app/api/repositories/clone/route.js +1 -1
  56. package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
  57. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  58. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/repositories/restore/route.js +1 -1
  60. package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
  61. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/repositories/route.js +1 -1
  63. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  64. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  65. package/.next/server/app/api/repositories/scan/route.js +1 -1
  66. package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
  67. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  68. package/.next/server/app/api/repositories/sync/route.js +1 -1
  69. package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
  70. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  71. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  72. package/.next/server/app/api/settings/default-agents/route.js +1 -1
  73. package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
  74. package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
  75. package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
  76. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/skills/[id]/route.js +1 -1
  78. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  79. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  80. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  81. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  82. package/.next/server/app/api/skills/route.js +1 -1
  83. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  84. package/.next/server/app/api/slash-commands/route.js +1 -1
  85. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  86. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  87. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  88. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  90. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  91. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  93. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  94. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
  96. package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
  97. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  98. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
  99. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
  100. package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
  101. package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  103. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +3 -1
  104. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js.nft.json +1 -1
  105. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  106. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  107. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  108. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  109. package/.next/server/app/api/worktrees/[id]/direct-input/route.js +1 -1
  110. package/.next/server/app/api/worktrees/[id]/direct-input/route.js.nft.json +1 -1
  111. package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
  112. package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
  113. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
  114. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  115. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +3 -1
  116. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js.nft.json +1 -1
  117. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  118. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  120. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  121. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  122. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  124. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  127. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  129. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  130. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  132. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  133. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  135. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  136. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  137. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  138. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  139. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  141. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  142. package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
  145. package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
  146. package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
  148. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  149. package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
  151. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  152. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  153. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  154. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  155. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  157. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  158. package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
  159. package/.next/server/app/api/worktrees/[id]/opencode/session/route.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/opencode/session/route.js.nft.json +1 -1
  161. package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
  162. package/.next/server/app/api/worktrees/[id]/opencode/share/route.js +1 -1
  163. package/.next/server/app/api/worktrees/[id]/opencode/share/route.js.nft.json +1 -1
  164. package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
  165. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  166. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
  167. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  168. package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
  170. package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
  171. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/route.js +1 -103
  173. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  174. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  175. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +3 -1
  176. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js.nft.json +1 -1
  177. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  178. package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +3 -1
  179. package/.next/server/app/api/worktrees/[id]/schedules/active/route.js.nft.json +1 -1
  180. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  181. package/.next/server/app/api/worktrees/[id]/schedules/route.js +3 -1
  182. package/.next/server/app/api/worktrees/[id]/schedules/route.js.nft.json +1 -1
  183. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  184. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  185. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -103
  186. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  187. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  188. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +104 -2
  189. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
  190. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  191. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  192. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  193. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  194. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  195. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  196. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  197. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  198. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
  199. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js.nft.json +1 -1
  200. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  201. package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
  202. package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
  203. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  204. package/.next/server/app/api/worktrees/[id]/tasks/route.js +1 -1
  205. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  206. package/.next/server/app/api/worktrees/[id]/terminal/route.js +1 -1
  207. package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
  208. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  209. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  210. package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
  211. package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
  212. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  213. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  214. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  215. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  216. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  217. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  218. package/.next/server/app/api/worktrees/[id]/verify/config/route.js +1 -1
  219. package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
  220. package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -1
  221. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  222. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js +1 -1
  223. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
  224. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  225. package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
  226. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  227. package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
  228. package/.next/server/app/api/worktrees/route.js +1 -1
  229. package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
  230. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  231. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  232. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  233. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  234. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  235. package/.next/server/app/page_client-reference-manifest.js +1 -1
  236. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  237. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  238. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  239. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  240. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  241. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  242. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  243. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  244. package/.next/server/app/worktrees/[id]/page.js +9 -9
  245. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  246. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  247. package/.next/server/app-paths-manifest.json +23 -23
  248. package/.next/server/chunks/1068.js +1 -1
  249. package/.next/server/chunks/1210.js +1 -1
  250. package/.next/server/chunks/1501.js +4 -4
  251. package/.next/server/chunks/1990.js +1 -1
  252. package/.next/server/chunks/2119.js +1 -1
  253. package/.next/server/chunks/22.js +1 -1
  254. package/.next/server/chunks/2328.js +1 -1
  255. package/.next/server/chunks/2404.js +4 -3
  256. package/.next/server/chunks/2445.js +1 -1
  257. package/.next/server/chunks/252.js +1 -1
  258. package/.next/server/chunks/2816.js +1 -1
  259. package/.next/server/chunks/3543.js +1 -1
  260. package/.next/server/chunks/3730.js +1 -1
  261. package/.next/server/chunks/3945.js +1 -1
  262. package/.next/server/chunks/4207.js +3 -3
  263. package/.next/server/chunks/434.js +1 -1
  264. package/.next/server/chunks/5064.js +1 -1
  265. package/.next/server/chunks/5571.js +1 -1
  266. package/.next/server/chunks/5742.js +1 -1
  267. package/.next/server/chunks/5775.js +1 -1
  268. package/.next/server/chunks/611.js +1 -1
  269. package/.next/server/chunks/6130.js +1 -1
  270. package/.next/server/chunks/6285.js +1 -1
  271. package/.next/server/chunks/6491.js +103 -0
  272. package/.next/server/chunks/6661.js +1 -1
  273. package/.next/server/chunks/6781.js +1 -1
  274. package/.next/server/chunks/6793.js +1 -1
  275. package/.next/server/chunks/7491.js +3 -0
  276. package/.next/server/chunks/7685.js +1 -1
  277. package/.next/server/chunks/7905.js +1 -1
  278. package/.next/server/chunks/8581.js +2 -2
  279. package/.next/server/chunks/8583.js +1 -1
  280. package/.next/server/chunks/8673.js +6 -6
  281. package/.next/server/chunks/8728.js +2 -2
  282. package/.next/server/chunks/8791.js +1 -1
  283. package/.next/server/chunks/8800.js +4 -3
  284. package/.next/server/chunks/8918.js +5 -5
  285. package/.next/server/chunks/9130.js +3 -3
  286. package/.next/server/chunks/{8052.js → 9353.js} +4 -2
  287. package/.next/server/chunks/9390.js +3 -0
  288. package/.next/server/chunks/9627.js +4 -4
  289. package/.next/server/chunks/964.js +1 -1
  290. package/.next/server/chunks/967.js +1 -0
  291. package/.next/server/chunks/9731.js +3 -3
  292. package/.next/server/chunks/9882.js +3 -3
  293. package/.next/server/middleware-manifest.json +5 -5
  294. package/.next/server/pages/500.html +1 -1
  295. package/.next/server/server-reference-manifest.json +1 -1
  296. package/.next/static/chunks/{1642-fb2e176aaadbd137.js → 1642-767aed8e7c61ef7f.js} +1 -1
  297. package/.next/static/chunks/{2407-21fbf12d753b8d4d.js → 2407-940df9b11fadafc6.js} +1 -1
  298. package/.next/static/chunks/{2619-04bc32f026a0d946.js → 2619-a305ad4810f1393a.js} +1 -1
  299. package/.next/static/chunks/5449-6cb80bab2bd06b79.js +1 -0
  300. package/.next/static/chunks/7705-1f58d4c03d991fcf.js +1 -0
  301. package/.next/static/chunks/8165-3525fb42f1b4976e.js +1 -0
  302. package/.next/static/chunks/app/{layout-8ff4c7c08ef1f621.js → layout-057c850cd0df978e.js} +1 -1
  303. package/.next/static/chunks/app/review/page-ff9efae3f86eb840.js +1 -0
  304. package/.next/static/chunks/app/skills/[skillId]/page-74aac15286504ef4.js +1 -0
  305. package/.next/static/chunks/app/skills/page-182e16168b2fc098.js +1 -0
  306. package/.next/static/chunks/app/worktrees/[id]/page-eab0bf7564d3f9e2.js +1 -0
  307. package/.next/static/chunks/app/worktrees/[id]/terminal/{page-373ea37b16d930c7.js → page-c601f3b3ece6557e.js} +1 -1
  308. package/.next/trace +13 -13
  309. package/README.md +3 -3
  310. package/dist/cli/commands/ask.d.ts.map +1 -1
  311. package/dist/cli/commands/ask.js +23 -149
  312. package/dist/cli/commands/reply.d.ts +40 -0
  313. package/dist/cli/commands/reply.d.ts.map +1 -0
  314. package/dist/cli/commands/reply.js +133 -0
  315. package/dist/cli/commands/verify.d.ts.map +1 -1
  316. package/dist/cli/commands/verify.js +9 -0
  317. package/dist/cli/commands/wait.d.ts +5 -0
  318. package/dist/cli/commands/wait.d.ts.map +1 -1
  319. package/dist/cli/commands/wait.js +10 -1
  320. package/dist/cli/docs/agent-operations.d.ts +2 -2
  321. package/dist/cli/docs/agent-operations.d.ts.map +1 -1
  322. package/dist/cli/docs/agent-operations.js +13 -0
  323. package/dist/cli/program.d.ts.map +1 -1
  324. package/dist/cli/program.js +4 -0
  325. package/dist/cli/types/index.d.ts +2 -0
  326. package/dist/cli/types/index.d.ts.map +1 -1
  327. package/dist/cli/utils/reply-ledger.d.ts +95 -0
  328. package/dist/cli/utils/reply-ledger.d.ts.map +1 -0
  329. package/dist/cli/utils/reply-ledger.js +187 -0
  330. package/dist/lib/cli-tools/copilot-executable.d.ts +9 -0
  331. package/dist/lib/cli-tools/copilot-executable.d.ts.map +1 -1
  332. package/dist/lib/cli-tools/copilot-executable.js +21 -5
  333. package/dist/lib/cli-tools/opencode-executable.d.ts +103 -0
  334. package/dist/lib/cli-tools/opencode-executable.d.ts.map +1 -0
  335. package/dist/lib/cli-tools/opencode-executable.js +179 -0
  336. package/dist/lib/cli-tools/types.d.ts +1 -1
  337. package/dist/lib/cli-tools/types.d.ts.map +1 -1
  338. package/dist/lib/cli-tools/types.js +5 -1
  339. package/dist/lib/detection/tools/verified-against.d.ts +15 -0
  340. package/dist/lib/detection/tools/verified-against.d.ts.map +1 -1
  341. package/dist/lib/detection/tools/verified-against.js +17 -1
  342. package/dist/lib/detection/version-probes.d.ts.map +1 -1
  343. package/dist/lib/detection/version-probes.js +14 -1
  344. package/dist/lib/session/tmux-session-surface.d.ts.map +1 -1
  345. package/dist/lib/session/tmux-session-surface.js +1 -1
  346. package/dist/server/locales/en/worktree.json +44 -14
  347. package/dist/server/locales/ja/worktree.json +44 -14
  348. package/dist/server/server.js +23 -0
  349. package/dist/server/src/config/cli-tool-timing-config.js +19 -1
  350. package/dist/server/src/config/detection-evidence-config.js +3 -0
  351. package/dist/server/src/config/schedule-config.js +55 -1
  352. package/dist/server/src/lib/auto-yes-poller.js +47 -4
  353. package/dist/server/src/lib/cli-tools/agent-mode-spec.js +54 -2
  354. package/dist/server/src/lib/cli-tools/base.js +6 -2
  355. package/dist/server/src/lib/cli-tools/command-code.js +55 -1
  356. package/dist/server/src/lib/cli-tools/composer-spec.js +10 -0
  357. package/dist/server/src/lib/cli-tools/copilot-executable.js +21 -5
  358. package/dist/server/src/lib/cli-tools/graceful-exit.js +15 -1
  359. package/dist/server/src/lib/cli-tools/index.js +3 -1
  360. package/dist/server/src/lib/cli-tools/install-hints.js +9 -3
  361. package/dist/server/src/lib/cli-tools/liveness-spec.js +19 -0
  362. package/dist/server/src/lib/cli-tools/manager.js +2 -0
  363. package/dist/server/src/lib/cli-tools/opencode-executable.js +179 -0
  364. package/dist/server/src/lib/cli-tools/opencode-v2.js +369 -0
  365. package/dist/server/src/lib/cli-tools/opencode.js +29 -5
  366. package/dist/server/src/lib/cli-tools/types.js +5 -1
  367. package/dist/server/src/lib/cmate-cli-tool-parser.js +65 -7
  368. package/dist/server/src/lib/cmate-parser.js +12 -0
  369. package/dist/server/src/lib/cmate-validator.js +13 -1
  370. package/dist/server/src/lib/db/worktree-db.js +1 -1
  371. package/dist/server/src/lib/detection/cli-patterns.js +78 -2
  372. package/dist/server/src/lib/detection/model-info-extractor.js +79 -7
  373. package/dist/server/src/lib/detection/status-detector.js +10 -1
  374. package/dist/server/src/lib/detection/tools/codex/cli-patterns.js +2 -1
  375. package/dist/server/src/lib/detection/tools/opencode-v2/detect.js +253 -0
  376. package/dist/server/src/lib/detection/tools/opencode-v2/dialog-title.js +48 -0
  377. package/dist/server/src/lib/detection/tools/registry.js +2 -0
  378. package/dist/server/src/lib/detection/tools/run-detection.js +9 -0
  379. package/dist/server/src/lib/detection/tools/verified-against.js +17 -1
  380. package/dist/server/src/lib/detection/upstream-faults.js +8 -0
  381. package/dist/server/src/lib/detection/version-probes.js +14 -1
  382. package/dist/server/src/lib/hooks/agent-session-telemetry.js +36 -1
  383. package/dist/server/src/lib/hooks/sources/opencode/log-diagnosis.js +105 -0
  384. package/dist/server/src/lib/hooks/sources/opencode/source.js +7 -1
  385. package/dist/server/src/lib/hooks/sources/opencode-v2/client.js +422 -0
  386. package/dist/server/src/lib/hooks/sources/opencode-v2/decision-labels.js +24 -0
  387. package/dist/server/src/lib/hooks/sources/opencode-v2/history.js +421 -0
  388. package/dist/server/src/lib/hooks/sources/opencode-v2/ingest.js +271 -0
  389. package/dist/server/src/lib/hooks/sources/opencode-v2/mappers.js +165 -0
  390. package/dist/server/src/lib/hooks/sources/opencode-v2/payloads.js +351 -0
  391. package/dist/server/src/lib/hooks/sources/opencode-v2/ports.js +230 -0
  392. package/dist/server/src/lib/hooks/sources/opencode-v2/reattach.js +149 -0
  393. package/dist/server/src/lib/hooks/sources/opencode-v2/runtime.js +180 -0
  394. package/dist/server/src/lib/hooks/sources/opencode-v2/secrets.js +182 -0
  395. package/dist/server/src/lib/hooks/sources/opencode-v2/source.js +295 -0
  396. package/dist/server/src/lib/hooks/sources/opencode-v2/subscription.js +455 -0
  397. package/dist/server/src/lib/hooks/sources/opencode-v2/tool-id.js +18 -0
  398. package/dist/server/src/lib/hooks/sources/opencode-v2/usage.js +214 -0
  399. package/dist/server/src/lib/hooks/sources/registry.js +2 -0
  400. package/dist/server/src/lib/hooks/structured-decision-response.js +14 -5
  401. package/dist/server/src/lib/job-executor.js +2 -1
  402. package/dist/server/src/lib/polling/auto-yes-dialog-gate.js +15 -1
  403. package/dist/server/src/lib/polling/structured-history-gate.js +19 -5
  404. package/dist/server/src/lib/relay/relay-delivery.js +4 -1
  405. package/dist/server/src/lib/session/agent-event-state.js +24 -0
  406. package/dist/server/src/lib/session/claude-executor.js +184 -10
  407. package/dist/server/src/lib/session/current-output-builder.js +27 -3
  408. package/dist/server/src/lib/session/send-user-message.js +4 -0
  409. package/dist/server/src/lib/session/structured-prompt.js +54 -0
  410. package/dist/server/src/lib/session/tmux-session-surface.js +1 -1
  411. package/dist/server/src/lib/skills/compatibility-matrix.js +65 -0
  412. package/dist/server/src/lib/tmux/tmux.js +48 -2
  413. package/dist/server/src/lib/verification/env-clean-gate.js +228 -9
  414. package/dist/server/src/lib/verification/env-snapshot.js +65 -1
  415. package/dist/server/src/types/cli-tool-contracts.js +10 -2
  416. package/dist/types/cli-tool-contracts.d.ts +16 -5
  417. package/dist/types/cli-tool-contracts.d.ts.map +1 -1
  418. package/dist/types/cli-tool-contracts.js +10 -2
  419. package/package.json +2 -1
  420. package/release-notes/0.42.2.json +20 -0
  421. package/release-notes/0.43.0.json +130 -0
  422. package/scripts/hooks/cmate-agent-event.sh +14 -0
  423. package/scripts/opencode-v2/launch.sh +226 -0
  424. package/.next/server/chunks/4443.js +0 -3
  425. package/.next/server/chunks/5164.js +0 -1
  426. package/.next/server/chunks/650.js +0 -1
  427. package/.next/static/chunks/5449-550bd273dccc3ae4.js +0 -1
  428. package/.next/static/chunks/7705-2a2936551b0cf9a3.js +0 -1
  429. package/.next/static/chunks/8165-934ee7ff3b4ddfd4.js +0 -1
  430. package/.next/static/chunks/app/review/page-30616daa1dc595c2.js +0 -1
  431. package/.next/static/chunks/app/skills/[skillId]/page-ab7e432b69fccb3b.js +0 -1
  432. package/.next/static/chunks/app/skills/page-56b4fa11223e0cbd.js +0 -1
  433. package/.next/static/chunks/app/worktrees/[id]/page-3c946bd2875391fd.js +0 -1
  434. /package/.next/static/{3M_S0B7dhEDdVE2XSJz1Y → BVkBYdceLRvMROqQIqeBx}/_buildManifest.js +0 -0
  435. /package/.next/static/{3M_S0B7dhEDdVE2XSJz1Y → BVkBYdceLRvMROqQIqeBx}/_ssgManifest.js +0 -0
@@ -0,0 +1,351 @@
1
+ "use strict";
2
+ /**
3
+ * Reading OpenCode V2's approvals and questions (Issue #2945, Epic #2370
4
+ * Phase 2).
5
+ *
6
+ * The v2 counterpart of `../opencode/payloads`: both shapes are parsed into
7
+ * the vocabulary the tool-independent layers already speak
8
+ * ({@link PermissionRequestPayload}, {@link AskUserQuestionSpec},
9
+ * {@link PendingDecision}), so the adjudicator, `agent-event-state`, the
10
+ * `/respond` route and `commandmate respond` need no v2 branch.
11
+ *
12
+ * ## Approvals (`permission.asked`, `Permission.Request`)
13
+ *
14
+ * Measured on 2.0.18 (#2370 Phase 0): `{id: "per_…", sessionID, action,
15
+ * resources, save, metadata: {files: [{file, patch, status, additions,
16
+ * deletions}]}, source}`. Unlike v1 the approval names what it is for — the
17
+ * `action` (`edit`, `shell`, …) — so there is no tool-call correlation table
18
+ * here. And it carries the diff, which is what the approval card shows
19
+ * ({@link describeOpencodeV2Permission}).
20
+ *
21
+ * ## Questions (`form.created`, `Form.Info`)
22
+ *
23
+ * `form.created` carries the form under `data.form` (measured on 2.0.18); the
24
+ * list endpoints answer it bare. Either way it is
25
+ * `{id: "frm_…", sessionID, title, metadata: {kind: "question"}, fields:
26
+ * [{key, title, description, type, options: [{value, label, description}],
27
+ * custom}]}`. One field is one question. A field is representable as a
28
+ * question with choices when it offers options (`string` with `options`,
29
+ * `multiselect`) or is a `boolean` (two synthesised choices); a form with any
30
+ * other visible field (a bare number, a free-text string, an external link) is
31
+ * not parsed, and the human answers it in the TUI. A form with several fields
32
+ * is parsed field by field, but `resolveStructuredQuestionAnswer` refuses a
33
+ * multi-question answer, so only a one-field form is answerable from a surface
34
+ * — the same bound v1's multi-question calls have.
35
+ *
36
+ * The answer goes back as `{answer: {<key>: <value>}}`, and the value is the
37
+ * option's `value`, not its label: {@link buildOpencodeV2FormAnswer} maps the
38
+ * labels a verdict carries back through the same form the question was read
39
+ * from.
40
+ *
41
+ * @module lib/hooks/sources/opencode-v2/payloads
42
+ */
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.unwrapOpencodeV2Payload = unwrapOpencodeV2Payload;
45
+ exports.parseOpencodeV2PermissionRequest = parseOpencodeV2PermissionRequest;
46
+ exports.toOpencodeV2PendingPermission = toOpencodeV2PendingPermission;
47
+ exports.readOpencodeV2PermissionSubject = readOpencodeV2PermissionSubject;
48
+ exports.stripOpencodeV2PatchHeaders = stripOpencodeV2PatchHeaders;
49
+ exports.describeOpencodeV2Permission = describeOpencodeV2Permission;
50
+ exports.parseOpencodeV2Form = parseOpencodeV2Form;
51
+ exports.toOpencodeV2PendingQuestion = toOpencodeV2PendingQuestion;
52
+ exports.buildOpencodeV2FormAnswer = buildOpencodeV2FormAnswer;
53
+ const ask_user_question_payload_1 = require("../../../../lib/hooks/ask-user-question-payload");
54
+ const event_mapper_1 = require("../event-mapper");
55
+ /**
56
+ * The object an approval or a question lives in.
57
+ *
58
+ * Two callers hand this module two shapes: the SSE frame `{id, type, data}`,
59
+ * and the bare object the list endpoints return. Unwrapping here lets the
60
+ * list path reuse the live path's parsing.
61
+ */
62
+ function unwrapOpencodeV2Payload(payload) {
63
+ if (typeof payload.type === 'string' && (0, event_mapper_1.isPlainObject)(payload.data)) {
64
+ // `form.created` nests the form one level further — `data.form` (measured
65
+ // on 2.0.18); `permission.asked` does not.
66
+ return (0, event_mapper_1.isPlainObject)(payload.data.form) ? payload.data.form : payload.data;
67
+ }
68
+ return payload;
69
+ }
70
+ function readStringArray(value) {
71
+ return Array.isArray(value) ? value.filter((item) => typeof item === 'string') : [];
72
+ }
73
+ // =============================================================================
74
+ // Approvals
75
+ // =============================================================================
76
+ /**
77
+ * Read a `permission.asked` frame, or an entry of `GET /api/permission/request`.
78
+ *
79
+ * @returns What the adjudicator judges, or null when this is not an approval
80
+ * the server can address (no `per_…` id or no session) — which every caller
81
+ * treats as "leave it for the human"
82
+ */
83
+ function parseOpencodeV2PermissionRequest(payload) {
84
+ const data = unwrapOpencodeV2Payload(payload);
85
+ const permissionId = (0, event_mapper_1.readStringField)(data, 'id');
86
+ const sessionId = (0, event_mapper_1.readStringField)(data, 'sessionID');
87
+ // Both are in the reply URL: `/api/session/{sessionID}/permission/{id}/reply`.
88
+ if (!permissionId || !sessionId)
89
+ return null;
90
+ // A form shares nothing with an approval but the envelope; never judge one.
91
+ if (Array.isArray(data.fields))
92
+ return null;
93
+ const action = (0, event_mapper_1.readStringField)(data, 'action');
94
+ const metadata = (0, event_mapper_1.isPlainObject)(data.metadata) ? data.metadata : {};
95
+ return {
96
+ // The approval names its own kind (`edit`, `shell`, …); v1 had to borrow
97
+ // the tool name from a separate frame.
98
+ toolName: action ?? 'permission',
99
+ // `metadata` verbatim — a `shell` approval's command, an `edit`'s files and
100
+ // patches — plus what is being asked for. What the deny patterns see.
101
+ toolInput: {
102
+ action,
103
+ resources: readStringArray(data.resources),
104
+ ...metadata,
105
+ },
106
+ promptId: permissionId,
107
+ sessionId,
108
+ permissionMode: null,
109
+ // `save` is the rule `Always allow` would store. Recorded, never judged.
110
+ permissionSuggestions: Array.isArray(data.save) ? data.save : null,
111
+ };
112
+ }
113
+ /** Turn an approval into a {@link PendingDecision}. */
114
+ function toOpencodeV2PendingPermission(payload, askedAt) {
115
+ const parsed = parseOpencodeV2PermissionRequest(payload);
116
+ if (!parsed || !parsed.promptId)
117
+ return null;
118
+ return {
119
+ kind: 'permission',
120
+ id: parsed.promptId,
121
+ conversationId: parsed.sessionId,
122
+ subject: { kind: 'permission', toolName: parsed.toolName, toolInput: parsed.toolInput },
123
+ raw: payload,
124
+ askedAt,
125
+ };
126
+ }
127
+ /**
128
+ * What an approval is about, for the approval card (Issue #2945 D1).
129
+ *
130
+ * `toolName` is the action and `patterns` is `save` — the rule `Always allow`
131
+ * would store, which is what the card shows beside that button (the same slot
132
+ * v1 fills from `patterns`, #2031). Null when the payload is not an approval.
133
+ */
134
+ function readOpencodeV2PermissionSubject(payload) {
135
+ const parsed = parseOpencodeV2PermissionRequest(payload);
136
+ if (!parsed)
137
+ return null;
138
+ return {
139
+ toolName: parsed.toolName,
140
+ patterns: readStringArray(parsed.permissionSuggestions),
141
+ };
142
+ }
143
+ /**
144
+ * Lines of a unified diff that carry no change: the `Index:` / `====` banner
145
+ * and the `---` / `+++` file headers the card already names.
146
+ */
147
+ const PATCH_HEADER_LINE = /^(Index: |={3,}$|--- |\+\+\+ )/;
148
+ /** A patch with its file headers removed, trailing newline trimmed. */
149
+ function stripOpencodeV2PatchHeaders(patch) {
150
+ return patch
151
+ .split('\n')
152
+ .filter((line) => !PATCH_HEADER_LINE.test(line))
153
+ .join('\n')
154
+ .replace(/\n+$/, '');
155
+ }
156
+ /**
157
+ * The approval card's text: what is asked for, then the diff (Issue #2945 D1).
158
+ *
159
+ * ```
160
+ * edit hello.txt
161
+ * @@ -0,0 +1,1 @@
162
+ * +hi
163
+ * ```
164
+ *
165
+ * The first line is the action and its resources; then, per file in
166
+ * `metadata.files`, the file name (when there is more than one) and its patch
167
+ * without the header lines. A `shell` approval, which carries a command rather
168
+ * than files, reads `shell <command>`. Unbounded here — the caller cuts it to
169
+ * the record's message bound, and a cut diff is still the head of the diff.
170
+ *
171
+ * @returns The text, or null when the payload is not an approval
172
+ */
173
+ function describeOpencodeV2Permission(payload) {
174
+ const parsed = parseOpencodeV2PermissionRequest(payload);
175
+ if (!parsed)
176
+ return null;
177
+ const input = parsed.toolInput;
178
+ const subject = typeof input.command === 'string' && input.command !== ''
179
+ ? input.command
180
+ : readStringArray(input.resources).join(', ');
181
+ const lines = [subject === '' ? parsed.toolName : `${parsed.toolName} ${subject}`];
182
+ const files = Array.isArray(input.files) ? input.files.filter(event_mapper_1.isPlainObject) : [];
183
+ for (const file of files) {
184
+ const patch = typeof file.patch === 'string' ? stripOpencodeV2PatchHeaders(file.patch) : '';
185
+ if (patch === '')
186
+ continue;
187
+ if (files.length > 1 && typeof file.file === 'string')
188
+ lines.push(file.file);
189
+ lines.push(patch);
190
+ }
191
+ return lines.join('\n');
192
+ }
193
+ /**
194
+ * The two choices a `boolean` field is offered as. Untranslated for the reason
195
+ * the approval verdicts are: the label is also what `commandmate respond`
196
+ * accepts, and a locale-dependent word would make the same command work on one
197
+ * machine and not another.
198
+ */
199
+ const BOOLEAN_FIELD_CHOICES = [
200
+ // eslint-disable-next-line no-restricted-syntax -- CLI answer vocabulary, not display text
201
+ { label: 'Yes', description: null, value: true },
202
+ // eslint-disable-next-line no-restricted-syntax -- CLI answer vocabulary, not display text
203
+ { label: 'No', description: null, value: false },
204
+ ];
205
+ /** The label as `parseAskUserQuestionToolInput` keeps it, for matching back. */
206
+ function normalizeLabel(label) {
207
+ return label.trim().slice(0, ask_user_question_payload_1.MAX_ASK_USER_QUESTION_LABEL_LENGTH);
208
+ }
209
+ function readFieldChoices(options) {
210
+ if (!Array.isArray(options) || options.length === 0)
211
+ return null;
212
+ const choices = [];
213
+ for (const option of options) {
214
+ if (!(0, event_mapper_1.isPlainObject)(option))
215
+ return null;
216
+ const value = (0, event_mapper_1.readStringField)(option, 'value');
217
+ const label = (0, event_mapper_1.readStringField)(option, 'label') ?? value;
218
+ if (value === null || label === null)
219
+ return null;
220
+ choices.push({ label, description: (0, event_mapper_1.readStringField)(option, 'description'), value });
221
+ }
222
+ return choices;
223
+ }
224
+ /**
225
+ * The form's visible fields as questions, or null when one of them cannot be
226
+ * offered as a choice (see the module comment).
227
+ */
228
+ function readFormQuestionFields(form) {
229
+ if (!Array.isArray(form.fields))
230
+ return null;
231
+ const formTitle = (0, event_mapper_1.readStringField)(form, 'title');
232
+ const fields = [];
233
+ for (const raw of form.fields) {
234
+ if (!(0, event_mapper_1.isPlainObject)(raw))
235
+ return null;
236
+ if (raw.hidden === true)
237
+ continue;
238
+ const key = (0, event_mapper_1.readStringField)(raw, 'key');
239
+ if (key === null)
240
+ return null;
241
+ const type = (0, event_mapper_1.readStringField)(raw, 'type');
242
+ const choices = type === 'boolean' ? [...BOOLEAN_FIELD_CHOICES] : type === 'string' || type === 'multiselect'
243
+ ? readFieldChoices(raw.options)
244
+ : null;
245
+ if (choices === null)
246
+ return null;
247
+ // Measured on 2.0.18: the question tool puts the question in `description`
248
+ // (`Which colour do you like?`) and a heading in `title` (`Favourite colour`).
249
+ const question = (0, event_mapper_1.readStringField)(raw, 'description') ?? (0, event_mapper_1.readStringField)(raw, 'title') ?? formTitle;
250
+ if (question === null)
251
+ return null;
252
+ fields.push({
253
+ key,
254
+ question,
255
+ header: (0, event_mapper_1.readStringField)(raw, 'title') ?? formTitle,
256
+ multiSelect: type === 'multiselect',
257
+ custom: raw.custom === true && type !== 'boolean',
258
+ choices,
259
+ });
260
+ }
261
+ return fields.length > 0 ? fields : null;
262
+ }
263
+ /**
264
+ * Read a form (`form.created` data, or an entry of `GET …/form`) as a question.
265
+ *
266
+ * @returns The spec — `promptId` is the `frm_…` id — or null when the form is
267
+ * not one a surface can offer choices for
268
+ */
269
+ function parseOpencodeV2Form(payload) {
270
+ const form = unwrapOpencodeV2Payload(payload);
271
+ const formId = (0, event_mapper_1.readStringField)(form, 'id');
272
+ if (!formId)
273
+ return null;
274
+ const fields = readFormQuestionFields(form);
275
+ if (fields === null)
276
+ return null;
277
+ const questions = (0, ask_user_question_payload_1.parseAskUserQuestionToolInput)({
278
+ questions: fields.map((field) => ({
279
+ question: field.question,
280
+ header: field.header,
281
+ multiSelect: field.multiSelect,
282
+ options: field.choices.map((choice) => ({
283
+ label: choice.label,
284
+ ...(choice.description ? { description: choice.description } : {}),
285
+ })),
286
+ })),
287
+ });
288
+ if (questions === null)
289
+ return null;
290
+ // Issue #2951: a field that takes a typed answer says so, so the surfaces
291
+ // can offer an input for it. `questions` is `fields` one-to-one.
292
+ const withCustom = questions.map((entry, index) => fields[index]?.custom ? { ...entry, custom: true } : entry);
293
+ return { questions: withCustom, promptId: formId };
294
+ }
295
+ /** Turn a form into a {@link PendingDecision}; `raw` keeps the form for the reply. */
296
+ function toOpencodeV2PendingQuestion(payload, askedAt) {
297
+ const form = unwrapOpencodeV2Payload(payload);
298
+ const spec = parseOpencodeV2Form(form);
299
+ if (!spec || !spec.promptId)
300
+ return null;
301
+ return {
302
+ kind: 'question',
303
+ id: spec.promptId,
304
+ conversationId: (0, event_mapper_1.readStringField)(form, 'sessionID'),
305
+ subject: { kind: 'question', spec },
306
+ raw: form,
307
+ askedAt,
308
+ };
309
+ }
310
+ /**
311
+ * The `answer` object a form reply carries, built from a verdict's `answers`
312
+ * (one array per question, in field order).
313
+ *
314
+ * Each entry is matched to the field's choices by label (then by value), and
315
+ * the choice's `value` is sent — `true` / `false` for a boolean. An entry that
316
+ * matches no choice is sent as typed only where the field accepts free text
317
+ * (`custom: true`); anywhere else the whole answer is refused, because the
318
+ * server would refuse it (`FormInvalidAnswerError`) and a partial answer is not
319
+ * the operator's.
320
+ *
321
+ * @returns The object, or null when the answer does not fit the form
322
+ */
323
+ function buildOpencodeV2FormAnswer(form, answers) {
324
+ const fields = readFormQuestionFields(unwrapOpencodeV2Payload(form));
325
+ if (fields === null || answers.length !== fields.length)
326
+ return null;
327
+ const answer = {};
328
+ for (const [index, field] of fields.entries()) {
329
+ const values = [];
330
+ for (const given of answers[index]) {
331
+ const wanted = normalizeLabel(given);
332
+ const choice = field.choices.find((candidate) => normalizeLabel(candidate.label) === wanted) ??
333
+ field.choices.find((candidate) => candidate.value === given);
334
+ if (choice)
335
+ values.push(choice.value);
336
+ else if (field.custom && given.trim() !== '')
337
+ values.push(given.trim());
338
+ else
339
+ return null;
340
+ }
341
+ if (field.multiSelect) {
342
+ answer[field.key] = values.map(String);
343
+ }
344
+ else {
345
+ if (values.length !== 1)
346
+ return null;
347
+ answer[field.key] = values[0];
348
+ }
349
+ }
350
+ return answer;
351
+ }
@@ -0,0 +1,230 @@
1
+ "use strict";
2
+ /**
3
+ * Per-instance port assignment for OpenCode V2 servers (Issue #2934, D4).
4
+ *
5
+ * The same idea as v1's `../opencode/ports` — a deterministic starting point per
6
+ * instance, the first free port from there, an in-memory map for the running
7
+ * process and a file so a restarted CommandMate can find a server that outlived
8
+ * it — but its own range and its own file, so v1 is not touched:
9
+ *
10
+ * - range {@link OPENCODE_V2_PORT_RANGE} (4300–4399) does not overlap v1's
11
+ * `OPENCODE_PORT_RANGE` (4200–4299). A v1 and a v2 instance of the same
12
+ * worktree therefore can never be handed the same port, whatever their
13
+ * hashes say;
14
+ * - the file is `ports.json` inside the OpenCode V2 state directory
15
+ * (`~/.commandmate/opencode-v2/`), next to the password files.
16
+ *
17
+ * The bind probe is v1's {@link isPortFree}, imported rather than copied: it is
18
+ * a pure question about the machine ("can something bind here on every
19
+ * address?") and has nothing v1-specific in it.
20
+ *
21
+ * @module lib/hooks/sources/opencode-v2/ports
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.OPENCODE_V2_PORT_FILE_NAME = exports.OPENCODE_V2_PORT_RANGE = void 0;
25
+ exports.getOpencodeV2PortFilePath = getOpencodeV2PortFilePath;
26
+ exports.readPersistedOpencodeV2Ports = readPersistedOpencodeV2Ports;
27
+ exports.getAssignedOpencodeV2Port = getAssignedOpencodeV2Port;
28
+ exports.rememberOpencodeV2Port = rememberOpencodeV2Port;
29
+ exports.forgetOpencodeV2Port = forgetOpencodeV2Port;
30
+ exports.forgetOpencodeV2PortByKey = forgetOpencodeV2PortByKey;
31
+ exports.deriveOpencodeV2PortStart = deriveOpencodeV2PortStart;
32
+ exports.opencodeV2PortCandidates = opencodeV2PortCandidates;
33
+ exports.allocateOpencodeV2Port = allocateOpencodeV2Port;
34
+ exports.recoverOpencodeV2Port = recoverOpencodeV2Port;
35
+ exports.resetOpencodeV2PortAssignments = resetOpencodeV2PortAssignments;
36
+ const fs_1 = require("fs");
37
+ const path_1 = require("path");
38
+ const logger_1 = require("../../../../lib/logger");
39
+ const ports_1 = require("../opencode/ports");
40
+ const secrets_1 = require("./secrets");
41
+ const logger = (0, logger_1.createLogger)('lib/hooks/sources/opencode-v2/ports');
42
+ /** Ports OpenCode V2 servers are started on. Disjoint from v1's 4200–4299. */
43
+ exports.OPENCODE_V2_PORT_RANGE = { min: 4300, max: 4399 };
44
+ const PORT_SPAN = exports.OPENCODE_V2_PORT_RANGE.max - exports.OPENCODE_V2_PORT_RANGE.min + 1;
45
+ /** File name of the persisted assignments inside the state directory. */
46
+ exports.OPENCODE_V2_PORT_FILE_NAME = 'ports.json';
47
+ const assignments = (globalThis.__opencodeV2PortAssignments ??= new Map());
48
+ /** Absolute path of the persisted assignments. */
49
+ function getOpencodeV2PortFilePath() {
50
+ return (0, path_1.join)((0, secrets_1.getOpencodeV2StateDir)(), exports.OPENCODE_V2_PORT_FILE_NAME);
51
+ }
52
+ function isAssignment(value) {
53
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
54
+ return false;
55
+ const record = value;
56
+ return (typeof record.port === 'number' &&
57
+ Number.isInteger(record.port) &&
58
+ record.port >= exports.OPENCODE_V2_PORT_RANGE.min &&
59
+ record.port <= exports.OPENCODE_V2_PORT_RANGE.max &&
60
+ typeof record.worktreePath === 'string');
61
+ }
62
+ /** Every persisted assignment, keyed by composite key. Unreadable → empty. */
63
+ function readPersistedOpencodeV2Ports() {
64
+ try {
65
+ const parsed = JSON.parse((0, fs_1.readFileSync)(getOpencodeV2PortFilePath(), 'utf8'));
66
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
67
+ return {};
68
+ const result = {};
69
+ for (const [key, value] of Object.entries(parsed)) {
70
+ if (isAssignment(value)) {
71
+ result[key] = {
72
+ port: value.port,
73
+ worktreePath: value.worktreePath,
74
+ updatedAt: typeof value.updatedAt === 'number' ? value.updatedAt : 0,
75
+ };
76
+ }
77
+ }
78
+ return result;
79
+ }
80
+ catch {
81
+ return {};
82
+ }
83
+ }
84
+ function writePersistedOpencodeV2Ports(all) {
85
+ const path = getOpencodeV2PortFilePath();
86
+ try {
87
+ if (Object.keys(all).length === 0) {
88
+ (0, fs_1.rmSync)(path, { force: true });
89
+ return;
90
+ }
91
+ (0, secrets_1.ensureOpencodeV2StateDir)();
92
+ (0, fs_1.writeFileSync)(path, `${JSON.stringify(all, null, 2)}\n`, { mode: 0o600 });
93
+ }
94
+ catch (error) {
95
+ logger.warn('opencode-v2-port-file-write-failed', {
96
+ path,
97
+ error: error instanceof Error ? error.message : String(error),
98
+ });
99
+ }
100
+ }
101
+ /** The port this process assigned to the instance, or null. */
102
+ function getAssignedOpencodeV2Port(target) {
103
+ return assignments.get((0, secrets_1.opencodeV2KeyOf)(target))?.port ?? null;
104
+ }
105
+ /** Record an assignment in memory and on disk. */
106
+ function rememberOpencodeV2Port(target, port, worktreePath, at = Date.now()) {
107
+ const key = (0, secrets_1.opencodeV2KeyOf)(target);
108
+ const assignment = { port, worktreePath, updatedAt: at };
109
+ assignments.set(key, assignment);
110
+ const all = readPersistedOpencodeV2Ports();
111
+ all[key] = assignment;
112
+ writePersistedOpencodeV2Ports(all);
113
+ }
114
+ /** Drop an assignment from memory and from disk. */
115
+ function forgetOpencodeV2Port(target) {
116
+ forgetOpencodeV2PortByKey((0, secrets_1.opencodeV2KeyOf)(target));
117
+ }
118
+ /** {@link forgetOpencodeV2Port} by composite key (the startup sweep's form). */
119
+ function forgetOpencodeV2PortByKey(key) {
120
+ assignments.delete(key);
121
+ const all = readPersistedOpencodeV2Ports();
122
+ if (key in all) {
123
+ delete all[key];
124
+ writePersistedOpencodeV2Ports(all);
125
+ }
126
+ }
127
+ /**
128
+ * First port tried for a key: FNV-1a of the key, folded into the range.
129
+ *
130
+ * The same hash v1 uses, over a different range, so instances spread out
131
+ * instead of all contending for the range's first port.
132
+ */
133
+ function deriveOpencodeV2PortStart(key) {
134
+ let hash = 0x811c9dc5;
135
+ for (let index = 0; index < key.length; index += 1) {
136
+ hash ^= key.charCodeAt(index);
137
+ hash = Math.imul(hash, 0x01000193) >>> 0;
138
+ }
139
+ return exports.OPENCODE_V2_PORT_RANGE.min + (hash % PORT_SPAN);
140
+ }
141
+ /** Every port in the range, starting at the instance's own start and wrapping. */
142
+ function opencodeV2PortCandidates(target) {
143
+ const start = deriveOpencodeV2PortStart((0, secrets_1.opencodeV2KeyOf)(target));
144
+ const candidates = [];
145
+ for (let offset = 0; offset < PORT_SPAN; offset += 1) {
146
+ candidates.push(exports.OPENCODE_V2_PORT_RANGE.min + ((start - exports.OPENCODE_V2_PORT_RANGE.min + offset) % PORT_SPAN));
147
+ }
148
+ return candidates;
149
+ }
150
+ /**
151
+ * Assign a free port to the instance.
152
+ *
153
+ * Unlike v1 this is not optional: an OpenCode V2 pane without its own server
154
+ * would fall back to the user's shared background service, which CommandMate
155
+ * must not drive. So hook injection being off does not skip the allocation.
156
+ * An already-held assignment is reused; a persisted one is preferred when its
157
+ * port is free again.
158
+ *
159
+ * @returns The port, or null when the whole range is taken
160
+ */
161
+ async function allocateOpencodeV2Port(target, worktreePath, probe = ports_1.isPortFree) {
162
+ const existing = getAssignedOpencodeV2Port(target);
163
+ if (existing !== null && (await probe(existing)))
164
+ return existing;
165
+ const key = (0, secrets_1.opencodeV2KeyOf)(target);
166
+ const preferred = readPersistedOpencodeV2Ports()[key]?.port;
167
+ const candidates = opencodeV2PortCandidates(target);
168
+ const ordered = preferred !== undefined ? [preferred, ...candidates.filter((p) => p !== preferred)] : candidates;
169
+ for (const port of ordered) {
170
+ if (await probe(port)) {
171
+ rememberOpencodeV2Port(target, port, worktreePath);
172
+ logger.info('opencode-v2-port-allocated', {
173
+ worktreeId: target.worktreeId,
174
+ instanceId: target.instanceId ?? target.cliToolId,
175
+ port,
176
+ });
177
+ return port;
178
+ }
179
+ }
180
+ logger.warn('opencode-v2-port-exhausted', {
181
+ worktreeId: target.worktreeId,
182
+ instanceId: target.instanceId ?? target.cliToolId,
183
+ range: `${exports.OPENCODE_V2_PORT_RANGE.min}-${exports.OPENCODE_V2_PORT_RANGE.max}`,
184
+ });
185
+ return null;
186
+ }
187
+ /**
188
+ * Re-adopt a persisted assignment after a CommandMate restart.
189
+ *
190
+ * Adopted only when it was recorded for the same worktree path and `verify`
191
+ * says the server on it is this instance's (it accepts the instance's
192
+ * password). A port someone else took since is not re-adopted.
193
+ *
194
+ * @returns The recovered port, or null
195
+ */
196
+ async function recoverOpencodeV2Port(target, worktreePath, verify) {
197
+ const existing = getAssignedOpencodeV2Port(target);
198
+ if (existing !== null)
199
+ return existing;
200
+ const key = (0, secrets_1.opencodeV2KeyOf)(target);
201
+ const persisted = readPersistedOpencodeV2Ports()[key];
202
+ if (!persisted)
203
+ return null;
204
+ if (persisted.worktreePath !== worktreePath) {
205
+ logger.info('opencode-v2-port-recovery-path-mismatch', {
206
+ worktreeId: target.worktreeId,
207
+ instanceId: target.instanceId ?? target.cliToolId,
208
+ });
209
+ return null;
210
+ }
211
+ if (!(await verify(persisted.port))) {
212
+ logger.info('opencode-v2-port-recovery-unverified', {
213
+ worktreeId: target.worktreeId,
214
+ instanceId: target.instanceId ?? target.cliToolId,
215
+ port: persisted.port,
216
+ });
217
+ return null;
218
+ }
219
+ assignments.set(key, persisted);
220
+ logger.info('opencode-v2-port-recovered', {
221
+ worktreeId: target.worktreeId,
222
+ instanceId: target.instanceId ?? target.cliToolId,
223
+ port: persisted.port,
224
+ });
225
+ return persisted.port;
226
+ }
227
+ /** Forget every in-memory assignment. For tests. */
228
+ function resetOpencodeV2PortAssignments() {
229
+ assignments.clear();
230
+ }