commandmate 0.44.1 → 0.44.3

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 (604) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +169 -169
  3. package/.next/app-path-routes-manifest.json +35 -35
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/prerender-manifest.json +3 -3
  6. package/.next/react-loadable-manifest.json +0 -6
  7. package/.next/required-server-files.json +1 -1
  8. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  9. package/.next/server/app/api/agents/update/route.js +1 -1
  10. package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/agents/versions/route.js +1 -1
  12. package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/app/release-notes/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/app/update/route.js +2 -2
  15. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/auth/login/route.js +1 -1
  18. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/capabilities/route.js +1 -1
  22. package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/daily-summary/route.js +1 -1
  24. package/.next/server/app/api/daily-summary/route.js.nft.json +1 -1
  25. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/daily-summary/status/route.js +1 -1
  27. package/.next/server/app/api/daily-summary/status/route.js.nft.json +1 -1
  28. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  30. package/.next/server/app/api/external-apps/[id]/route.js +1 -1
  31. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/external-apps/route.js +1 -1
  33. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/hooks/agent-event/route.js +2 -2
  37. package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
  38. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/hooks/claude-done/route.js +2 -2
  40. package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
  41. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  42. package/.next/server/app/api/hooks/permission-request/route.js +1 -1
  43. package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
  44. package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
  45. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  46. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  47. package/.next/server/app/api/push/escalation/route.js +1 -1
  48. package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
  49. package/.next/server/app/api/push/subscriptions/route.js +2 -2
  50. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  51. package/.next/server/app/api/push/vapid/route.js +1 -1
  52. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  53. package/.next/server/app/api/relays/[relayId]/cancel/route.js +1 -1
  54. package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
  55. package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/relays/route.js +1 -1
  57. package/.next/server/app/api/relays/route.js.nft.json +1 -1
  58. package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
  60. package/.next/server/app/api/repositories/[id]/route.js +1 -1
  61. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  63. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
  64. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  65. package/.next/server/app/api/repositories/clone/route.js +1 -1
  66. package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
  67. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  68. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/repositories/restore/route.js +1 -1
  70. package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
  71. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  72. package/.next/server/app/api/repositories/route.js +1 -1
  73. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  74. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  75. package/.next/server/app/api/repositories/scan/route.js +1 -1
  76. package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
  77. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  78. package/.next/server/app/api/repositories/sync/route.js +1 -1
  79. package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
  80. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  81. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  82. package/.next/server/app/api/settings/default-agents/route.js +1 -1
  83. package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
  84. package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
  85. package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
  86. package/.next/server/app/api/sidebar/group-order/route.js +1 -1
  87. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  88. package/.next/server/app/api/skills/[id]/route.js +1 -1
  89. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  90. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  91. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  93. package/.next/server/app/api/skills/route.js +1 -1
  94. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  96. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  97. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  98. package/.next/server/app/api/templates/[id]/route.js +2 -2
  99. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  100. package/.next/server/app/api/templates/route.js +2 -2
  101. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  103. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  104. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  105. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  106. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  107. package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
  108. package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
  109. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  110. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
  111. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
  112. package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
  113. package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
  114. package/.next/server/app/api/worktrees/[id]/cli-tool/route.js +1 -1
  115. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  116. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +3 -3
  117. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js.nft.json +1 -1
  118. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  120. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  121. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  122. package/.next/server/app/api/worktrees/[id]/direct-input/route.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/direct-input/route.js.nft.json +1 -1
  124. package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  127. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +2 -2
  128. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js.nft.json +1 -1
  129. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  130. package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  132. package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js +1 -1
  133. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js +1 -1
  135. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  136. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  137. package/.next/server/app/api/worktrees/[id]/git/checkout/route.js +1 -1
  138. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  139. package/.next/server/app/api/worktrees/[id]/git/commit/route.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  141. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  142. package/.next/server/app/api/worktrees/[id]/git/fetch/route.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/git/pull/route.js +1 -1
  146. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/git/push/route.js +1 -1
  148. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  149. package/.next/server/app/api/worktrees/[id]/git/reset/route.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  151. package/.next/server/app/api/worktrees/[id]/git/revert/route.js +1 -1
  152. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  153. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  154. package/.next/server/app/api/worktrees/[id]/git/stage/route.js +1 -1
  155. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  157. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  158. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js +1 -1
  159. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js +1 -1
  161. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  162. package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js +1 -1
  163. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  164. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  165. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  166. package/.next/server/app/api/worktrees/[id]/git/unstage/route.js +1 -1
  167. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  168. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/instances/notes/route.js +1 -1
  170. package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
  171. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
  173. package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
  174. package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
  175. package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
  176. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  177. package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
  178. package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
  179. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  180. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  181. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  182. package/.next/server/app/api/worktrees/[id]/marp-render/route.js +1 -1
  183. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  184. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js +1 -1
  185. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  186. package/.next/server/app/api/worktrees/[id]/memos/route.js +1 -1
  187. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  188. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  189. package/.next/server/app/api/worktrees/[id]/opencode/diff/route.js +1 -1
  190. package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
  191. package/.next/server/app/api/worktrees/[id]/opencode/session/route.js +1 -2
  192. package/.next/server/app/api/worktrees/[id]/opencode/session/route.js.nft.json +1 -1
  193. package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
  194. package/.next/server/app/api/worktrees/[id]/opencode/share/route.js +1 -2
  195. package/.next/server/app/api/worktrees/[id]/opencode/share/route.js.nft.json +1 -1
  196. package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
  197. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  198. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
  199. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  200. package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
  201. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
  202. package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
  203. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  204. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  205. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  206. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  207. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +2 -2
  208. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js.nft.json +1 -1
  209. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  210. package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +2 -2
  211. package/.next/server/app/api/worktrees/[id]/schedules/active/route.js.nft.json +1 -1
  212. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  213. package/.next/server/app/api/worktrees/[id]/schedules/route.js +3 -3
  214. package/.next/server/app/api/worktrees/[id]/schedules/route.js.nft.json +1 -1
  215. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  216. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  217. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
  218. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  219. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  220. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +3 -3
  221. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
  222. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  223. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  224. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js +1 -1
  225. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  226. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  227. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  228. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  229. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route.js +1 -1
  230. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  231. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  232. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
  233. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  234. package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
  235. package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
  236. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  237. package/.next/server/app/api/worktrees/[id]/tasks/route.js +1 -1
  238. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  239. package/.next/server/app/api/worktrees/[id]/terminal/route.js +2 -2
  240. package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
  241. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  242. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  243. package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
  244. package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
  245. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  246. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js +1 -1
  247. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  248. package/.next/server/app/api/worktrees/[id]/todos/route.js +1 -1
  249. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  250. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  251. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  252. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  253. package/.next/server/app/api/worktrees/[id]/verify/config/route.js +1 -1
  254. package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
  255. package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -1
  256. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  257. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js +1 -1
  258. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
  259. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  260. package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
  261. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  262. package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
  263. package/.next/server/app/api/worktrees/route.js +1 -1
  264. package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
  265. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  266. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  267. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  268. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  269. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  270. package/.next/server/app/page_client-reference-manifest.js +1 -1
  271. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  272. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  273. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  274. package/.next/server/app/sessions/page.js +1 -1
  275. package/.next/server/app/sessions/page.js.nft.json +1 -1
  276. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  277. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  278. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  279. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  280. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  281. package/.next/server/app/worktrees/[id]/page.js +11 -11
  282. package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
  283. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  284. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  285. package/.next/server/app-paths-manifest.json +35 -35
  286. package/.next/server/chunks/1191.js +2 -2
  287. package/.next/server/chunks/1210.js +1 -1
  288. package/.next/server/chunks/1559.js +2 -0
  289. package/.next/server/chunks/1789.js +1 -0
  290. package/.next/server/chunks/2119.js +1 -1
  291. package/.next/server/chunks/2404.js +1 -1
  292. package/.next/server/chunks/2445.js +1 -1
  293. package/.next/server/chunks/2460.js +1 -0
  294. package/.next/server/chunks/2710.js +1 -1
  295. package/.next/server/chunks/2908.js +1 -0
  296. package/.next/server/chunks/2980.js +1 -1
  297. package/.next/server/chunks/3241.js +1 -1
  298. package/.next/server/chunks/3480.js +1 -1
  299. package/.next/server/chunks/3718.js +1 -1
  300. package/.next/server/chunks/4207.js +2 -2
  301. package/.next/server/chunks/450.js +1 -1
  302. package/.next/server/chunks/4672.js +5 -0
  303. package/.next/server/chunks/{9353.js → 4718.js} +2 -2
  304. package/.next/server/chunks/4837.js +14 -0
  305. package/.next/server/chunks/5048.js +1 -1
  306. package/.next/server/chunks/5209.js +1 -0
  307. package/.next/server/chunks/5595.js +1 -0
  308. package/.next/server/chunks/5625.js +25 -0
  309. package/.next/server/chunks/5845.js +1 -0
  310. package/.next/server/chunks/611.js +1 -1
  311. package/.next/server/chunks/6130.js +1 -1
  312. package/.next/server/chunks/6401.js +1 -1
  313. package/.next/server/chunks/6781.js +1 -1
  314. package/.next/server/chunks/6793.js +3 -3
  315. package/.next/server/chunks/7491.js +2 -2
  316. package/.next/server/chunks/7905.js +1 -1
  317. package/.next/server/chunks/850.js +1 -0
  318. package/.next/server/chunks/8543.js +1 -1
  319. package/.next/server/chunks/8728.js +3 -3
  320. package/.next/server/chunks/8791.js +1 -1
  321. package/.next/server/chunks/8800.js +1 -1
  322. package/.next/server/chunks/8918.js +7 -7
  323. package/.next/server/chunks/9130.js +1 -5
  324. package/.next/server/chunks/9390.js +2 -3
  325. package/.next/server/chunks/9584.js +1 -1
  326. package/.next/server/chunks/9627.js +6 -6
  327. package/.next/server/chunks/9731.js +3 -3
  328. package/.next/server/middleware-manifest.json +5 -5
  329. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  330. package/.next/server/pages/500.html +1 -1
  331. package/.next/server/server-reference-manifest.json +1 -1
  332. package/.next/static/chunks/{1642-fb2e176aaadbd137.js → 1642-767aed8e7c61ef7f.js} +1 -1
  333. package/.next/static/chunks/{2407-f1f258d4a1d92620.js → 2407-06d35bb1aa02de80.js} +1 -1
  334. package/.next/static/chunks/{2619-04bc32f026a0d946.js → 2619-a305ad4810f1393a.js} +1 -1
  335. package/.next/static/chunks/4727-5d695d71e3fdf97b.js +1 -0
  336. package/.next/static/chunks/{8165-3853772f6ae1299b.js → 8165-3525fb42f1b4976e.js} +1 -1
  337. package/.next/static/chunks/app/{layout-da66300cc20244ed.js → layout-0d1750b833f5cc3e.js} +1 -1
  338. package/.next/static/chunks/app/sessions/page-2af68c63211c751f.js +1 -0
  339. package/.next/static/chunks/app/worktrees/[id]/page-e36898c3a80e7302.js +1 -0
  340. package/.next/static/chunks/app/worktrees/[id]/terminal/{page-373ea37b16d930c7.js → page-c601f3b3ece6557e.js} +1 -1
  341. package/.next/static/css/057f64a65726c439.css +1 -0
  342. package/.next/trace +13 -13
  343. package/dist/cli/commands/ask.d.ts.map +1 -1
  344. package/dist/cli/commands/ask.js +120 -119
  345. package/dist/cli/commands/attach.d.ts +94 -0
  346. package/dist/cli/commands/attach.d.ts.map +1 -1
  347. package/dist/cli/commands/attach.js +145 -7
  348. package/dist/cli/commands/auto-yes.js +1 -1
  349. package/dist/cli/commands/capture.d.ts.map +1 -1
  350. package/dist/cli/commands/capture.js +10 -13
  351. package/dist/cli/commands/command-target.d.ts +23 -0
  352. package/dist/cli/commands/command-target.d.ts.map +1 -0
  353. package/dist/cli/commands/command-target.js +25 -0
  354. package/dist/cli/commands/instances.d.ts.map +1 -1
  355. package/dist/cli/commands/instances.js +41 -2
  356. package/dist/cli/commands/message-dispatch.d.ts +36 -0
  357. package/dist/cli/commands/message-dispatch.d.ts.map +1 -0
  358. package/dist/cli/commands/message-dispatch.js +63 -0
  359. package/dist/cli/commands/reply.d.ts.map +1 -1
  360. package/dist/cli/commands/reply.js +2 -5
  361. package/dist/cli/commands/respond.d.ts.map +1 -1
  362. package/dist/cli/commands/respond.js +3 -6
  363. package/dist/cli/commands/send.d.ts.map +1 -1
  364. package/dist/cli/commands/send.js +149 -146
  365. package/dist/cli/commands/wait.d.ts.map +1 -1
  366. package/dist/cli/commands/wait.js +608 -416
  367. package/dist/cli/types/api-responses.d.ts +174 -27
  368. package/dist/cli/types/api-responses.d.ts.map +1 -1
  369. package/dist/cli/types/api-responses.js +4 -2
  370. package/dist/cli/utils/api-client.d.ts +25 -5
  371. package/dist/cli/utils/api-client.d.ts.map +1 -1
  372. package/dist/cli/utils/api-client.js +87 -55
  373. package/dist/cli/utils/server-url.d.ts +1 -0
  374. package/dist/cli/utils/server-url.d.ts.map +1 -1
  375. package/dist/cli/utils/server-url.js +7 -0
  376. package/dist/config/uat-isolation.d.ts +140 -0
  377. package/dist/config/uat-isolation.d.ts.map +1 -0
  378. package/dist/config/uat-isolation.js +246 -0
  379. package/dist/lib/global-state.d.ts +12 -0
  380. package/dist/lib/global-state.d.ts.map +1 -0
  381. package/dist/lib/global-state.js +16 -0
  382. package/dist/lib/polling/auto-yes-suppression-reason.d.ts +33 -0
  383. package/dist/lib/polling/auto-yes-suppression-reason.d.ts.map +1 -0
  384. package/dist/lib/polling/auto-yes-suppression-reason.js +2 -0
  385. package/dist/lib/session/prompt-view.d.ts +228 -0
  386. package/dist/lib/session/prompt-view.d.ts.map +1 -0
  387. package/dist/lib/session/prompt-view.js +290 -0
  388. package/dist/lib/session/status-evidence-type.d.ts +16 -0
  389. package/dist/lib/session/status-evidence-type.d.ts.map +1 -0
  390. package/dist/lib/session/status-evidence-type.js +2 -0
  391. package/dist/lib/tmux/legacy-session-alias.d.ts.map +1 -1
  392. package/dist/lib/tmux/legacy-session-alias.js +2 -1
  393. package/dist/server/locales/en/worktree.json +3 -1
  394. package/dist/server/locales/ja/worktree.json +3 -1
  395. package/dist/server/server.js +5 -3
  396. package/dist/server/src/cli/types/api-responses.js +4 -2
  397. package/dist/server/src/config/cli-tool-timing-config.js +1 -6
  398. package/dist/server/src/config/uat-isolation.js +246 -0
  399. package/dist/server/src/lib/assistant-response-saver.js +62 -3
  400. package/dist/server/src/lib/auto-yes-lifecycle.js +139 -0
  401. package/dist/server/src/lib/auto-yes-poller.js +465 -160
  402. package/dist/server/src/lib/auto-yes-state.js +2 -2
  403. package/dist/server/src/lib/cli-tools/antigravity.js +39 -80
  404. package/dist/server/src/lib/cli-tools/base.js +151 -0
  405. package/dist/server/src/lib/cli-tools/codex.js +44 -80
  406. package/dist/server/src/lib/cli-tools/command-code.js +24 -56
  407. package/dist/server/src/lib/cli-tools/copilot.js +25 -67
  408. package/dist/server/src/lib/cli-tools/direct-input.js +8 -0
  409. package/dist/server/src/lib/cli-tools/gemini.js +23 -73
  410. package/dist/server/src/lib/cli-tools/opencode-pane-width.js +53 -0
  411. package/dist/server/src/lib/cli-tools/opencode-v2.js +9 -7
  412. package/dist/server/src/lib/cli-tools/opencode.js +21 -85
  413. package/dist/server/src/lib/cli-tools/submit-verified-sender.js +127 -4
  414. package/dist/server/src/lib/cli-tools/vibe-local.js +21 -66
  415. package/dist/server/src/lib/detection/cli-patterns.js +374 -3047
  416. package/dist/server/src/lib/detection/idle-evidence-observation.js +2 -2
  417. package/dist/server/src/lib/detection/prompt-detect-multiple-choice.js +7 -32
  418. package/dist/server/src/lib/detection/prompt-detector.js +2 -35
  419. package/dist/server/src/lib/detection/selection-shape-patterns.js +69 -0
  420. package/dist/server/src/lib/detection/selection-shape.js +32 -520
  421. package/dist/server/src/lib/detection/shared/pasted-text.js +41 -0
  422. package/dist/server/src/lib/detection/shared/shell-pane-command.js +16 -0
  423. package/dist/server/src/lib/detection/shared/strip-box-drawing.js +25 -0
  424. package/dist/server/src/lib/detection/status-detector.js +1 -1
  425. package/dist/server/src/lib/detection/tools/antigravity/detect.js +12 -60
  426. package/dist/server/src/lib/detection/tools/antigravity/dialog.js +2 -15
  427. package/dist/server/src/lib/detection/tools/antigravity/live-region.js +39 -0
  428. package/dist/server/src/lib/detection/tools/antigravity/patterns.js +286 -0
  429. package/dist/server/src/lib/detection/tools/claude/detect.js +11 -17
  430. package/dist/server/src/lib/detection/tools/claude/live-region.js +26 -0
  431. package/dist/server/src/lib/detection/tools/claude/patterns.js +264 -4
  432. package/dist/server/src/lib/detection/tools/claude/prompt.js +2 -10
  433. package/dist/server/src/lib/detection/tools/codex/cli-patterns.js +1 -1
  434. package/dist/server/src/lib/detection/tools/codex/detect.js +71 -130
  435. package/dist/server/src/lib/detection/tools/codex/live-region.js +104 -0
  436. package/dist/server/src/lib/detection/tools/codex/patterns.js +855 -0
  437. package/dist/server/src/lib/detection/tools/codex/prompt.js +2 -10
  438. package/dist/server/src/lib/detection/tools/command-code/detect.js +19 -50
  439. package/dist/server/src/lib/detection/tools/command-code/dialog.js +2 -18
  440. package/dist/server/src/lib/detection/tools/command-code/live-region.js +36 -0
  441. package/dist/server/src/lib/detection/tools/command-code/patterns.js +234 -0
  442. package/dist/server/src/lib/detection/tools/command-code/selection-shape.js +461 -0
  443. package/dist/server/src/lib/detection/tools/context-above.js +20 -0
  444. package/dist/server/src/lib/detection/tools/copilot/detect.js +13 -35
  445. package/dist/server/src/lib/detection/tools/copilot/live-region.js +52 -0
  446. package/dist/server/src/lib/detection/tools/copilot/patterns.js +640 -0
  447. package/dist/server/src/lib/detection/tools/copilot/prompt.js +2 -10
  448. package/dist/server/src/lib/detection/tools/frame.js +36 -2
  449. package/dist/server/src/lib/detection/tools/gemini/patterns.js +29 -0
  450. package/dist/server/src/lib/detection/tools/live-region-specs.js +31 -0
  451. package/dist/server/src/lib/detection/tools/live-region.js +204 -0
  452. package/dist/server/src/lib/detection/tools/opencode/detect.js +11 -49
  453. package/dist/server/src/lib/detection/tools/opencode/live-region.js +24 -0
  454. package/dist/server/src/lib/detection/tools/opencode/patterns.js +508 -0
  455. package/dist/server/src/lib/detection/tools/opencode-gutter-live-region.js +72 -0
  456. package/dist/server/src/lib/detection/tools/opencode-v2/detect.js +10 -42
  457. package/dist/server/src/lib/detection/tools/opencode-v2/live-region.js +24 -0
  458. package/dist/server/src/lib/detection/tools/opencode-v2/patterns.js +63 -0
  459. package/dist/server/src/lib/detection/tools/run-detection.js +31 -50
  460. package/dist/server/src/lib/detection/tools/verdicts.js +59 -0
  461. package/dist/server/src/lib/detection/tools/vibe-local/patterns.js +20 -0
  462. package/dist/server/src/lib/detection/truncate-raw-content.js +38 -0
  463. package/dist/server/src/lib/detection/turn-abandoned.js +66 -0
  464. package/dist/server/src/lib/detection/unclassified-frame-tracker.js +2 -2
  465. package/dist/server/src/lib/global-state.js +16 -0
  466. package/dist/server/src/lib/hooks/agent-session-telemetry.js +4 -6
  467. package/dist/server/src/lib/hooks/permission-decision-state.js +2 -2
  468. package/dist/server/src/lib/hooks/sources/antigravity/history.js +11 -76
  469. package/dist/server/src/lib/hooks/sources/antigravity/hooks-config.js +63 -1
  470. package/dist/server/src/lib/hooks/sources/antigravity/source.js +16 -0
  471. package/dist/server/src/lib/hooks/sources/antigravity/transcript.js +3 -12
  472. package/dist/server/src/lib/hooks/sources/claude/history.js +17 -156
  473. package/dist/server/src/lib/hooks/sources/claude/queued-notice.js +53 -0
  474. package/dist/server/src/lib/hooks/sources/claude/source.js +33 -3
  475. package/dist/server/src/lib/hooks/sources/claude/transcript.js +3 -13
  476. package/dist/server/src/lib/hooks/sources/codex/history.js +11 -74
  477. package/dist/server/src/lib/hooks/sources/codex/hooks-config.js +147 -11
  478. package/dist/server/src/lib/hooks/sources/codex/relay-install.js +64 -21
  479. package/dist/server/src/lib/hooks/sources/codex/transcript.js +5 -15
  480. package/dist/server/src/lib/hooks/sources/command-code/history.js +20 -121
  481. package/dist/server/src/lib/hooks/sources/command-code/transcript.js +3 -13
  482. package/dist/server/src/lib/hooks/sources/copilot/hook-settings.js +161 -31
  483. package/dist/server/src/lib/hooks/sources/define-source.js +40 -55
  484. package/dist/server/src/lib/hooks/sources/event-mapper.js +2 -1
  485. package/dist/server/src/lib/hooks/sources/opencode/diff.js +3 -4
  486. package/dist/server/src/lib/hooks/sources/opencode/history.js +2 -1
  487. package/dist/server/src/lib/hooks/sources/opencode/launch-settings.js +2 -1
  488. package/dist/server/src/lib/hooks/sources/opencode/payloads.js +2 -1
  489. package/dist/server/src/lib/hooks/sources/opencode/ports.js +2 -1
  490. package/dist/server/src/lib/hooks/sources/opencode/subscription.js +4 -3
  491. package/dist/server/src/lib/hooks/sources/opencode/transcript.js +3 -16
  492. package/dist/server/src/lib/hooks/sources/opencode-v2/history.js +2 -1
  493. package/dist/server/src/lib/hooks/sources/opencode-v2/mappers.js +5 -4
  494. package/dist/server/src/lib/hooks/sources/opencode-v2/ports.js +2 -1
  495. package/dist/server/src/lib/hooks/sources/opencode-v2/subscription.js +3 -7
  496. package/dist/server/src/lib/hooks/sources/opencode-v2/usage.js +2 -1
  497. package/dist/server/src/lib/hooks/sources/pending-decisions.js +2 -1
  498. package/dist/server/src/lib/hooks/sources/registry.js +3 -2
  499. package/dist/server/src/lib/hooks/sources/transcript-history.js +262 -0
  500. package/dist/server/src/lib/hooks/sources/turn-body.js +31 -0
  501. package/dist/server/src/lib/hooks/tool-input-normalization-state.js +2 -2
  502. package/dist/server/src/lib/polling/antigravity-permission-receipts.js +2 -2
  503. package/dist/server/src/lib/polling/auto-yes-dialog-gate.js +16 -4
  504. package/dist/server/src/lib/polling/auto-yes-enter-fallback-state.js +142 -0
  505. package/dist/server/src/lib/polling/auto-yes-enter-fallback.js +187 -0
  506. package/dist/server/src/lib/polling/auto-yes-resolver.js +9 -3
  507. package/dist/server/src/lib/polling/auto-yes-suppression-reason.js +2 -0
  508. package/dist/server/src/lib/polling/auto-yes-suppression-state.js +2 -2
  509. package/dist/server/src/lib/polling/pending-scraped-response.js +190 -0
  510. package/dist/server/src/lib/polling/prompt-dedup-state.js +2 -2
  511. package/dist/server/src/lib/polling/prompt-dedup.js +2 -2
  512. package/dist/server/src/lib/polling/response-checker-dialog-gate.js +95 -0
  513. package/dist/server/src/lib/polling/response-checker-extraction-result.js +50 -0
  514. package/dist/server/src/lib/polling/response-checker-extraction-steps.js +670 -0
  515. package/dist/server/src/lib/polling/response-checker.js +666 -1162
  516. package/dist/server/src/lib/polling/response-dedup.js +3 -4
  517. package/dist/server/src/lib/polling/response-poller-constants.js +17 -0
  518. package/dist/server/src/lib/polling/response-poller-core.js +54 -20
  519. package/dist/server/src/lib/polling/startup-screen.js +142 -0
  520. package/dist/server/src/lib/polling/structured-history-gate.js +3 -2
  521. package/dist/server/src/lib/prompt-answer-semantic.js +178 -0
  522. package/dist/server/src/lib/prompt-answer-sender.js +6 -5
  523. package/dist/server/src/lib/push/failure-episode-state.js +2 -2
  524. package/dist/server/src/lib/push/notification-dedup.js +3 -4
  525. package/dist/server/src/lib/push/prompt-card-state.js +2 -2
  526. package/dist/server/src/lib/push/waiting-push-notifier.js +3 -4
  527. package/dist/server/src/lib/realtime/publisher-registry.js +3 -2
  528. package/dist/server/src/lib/realtime/terminal-broadcast.js +38 -2
  529. package/dist/server/src/lib/realtime/terminal-session-ownership.js +45 -0
  530. package/dist/server/src/lib/relay/relay-delivery.js +6 -2
  531. package/dist/server/src/lib/relay/relay-readiness.js +38 -1
  532. package/dist/server/src/lib/relay/relay-triggers.js +9 -0
  533. package/dist/server/src/lib/resource-cleanup.js +6 -4
  534. package/dist/server/src/lib/response-cleaner.js +24 -1
  535. package/dist/server/src/lib/response-extractor.js +16 -0
  536. package/dist/server/src/lib/schedule-manager.js +8 -10
  537. package/dist/server/src/lib/session/agent-event-ask-user-question.js +168 -0
  538. package/dist/server/src/lib/session/agent-event-awaiting-instruction.js +104 -0
  539. package/dist/server/src/lib/session/agent-event-dedup.js +539 -0
  540. package/dist/server/src/lib/session/agent-event-model.js +562 -0
  541. package/dist/server/src/lib/session/agent-event-record.js +10 -0
  542. package/dist/server/src/lib/session/agent-event-state.js +106 -1854
  543. package/dist/server/src/lib/session/agent-event-structured-state.js +109 -0
  544. package/dist/server/src/lib/session/agent-event-turn.js +811 -0
  545. package/dist/server/src/lib/session/agent-session-lifecycle.js +11 -2
  546. package/dist/server/src/lib/session/chat-turn-progress.js +322 -0
  547. package/dist/server/src/lib/session/claude-executor.js +45 -5
  548. package/dist/server/src/lib/session/claude-session.js +21 -65
  549. package/dist/server/src/lib/session/cli-session.js +17 -0
  550. package/dist/server/src/lib/session/current-output-builder.js +454 -1103
  551. package/dist/server/src/lib/session/current-output-history-writers.js +255 -0
  552. package/dist/server/src/lib/session/current-output-types.js +9 -0
  553. package/dist/server/src/lib/session/detection-divergence.js +55 -0
  554. package/dist/server/src/lib/session/global-session-constants.js +2 -13
  555. package/dist/server/src/lib/session/hook-turn-hold.js +102 -0
  556. package/dist/server/src/lib/session/layer-disagreement.js +2 -2
  557. package/dist/server/src/lib/session/opencode-session-store.js +2 -1
  558. package/dist/server/src/lib/session/prompt-view.js +290 -0
  559. package/dist/server/src/lib/session/prompt-waiting-composition.js +35 -0
  560. package/dist/server/src/lib/session/provisional-turn.js +3 -1
  561. package/dist/server/src/lib/session/send-user-message.js +1 -1
  562. package/dist/server/src/lib/session/session-starting-state.js +4 -6
  563. package/dist/server/src/lib/session/status-evidence-type.js +2 -0
  564. package/dist/server/src/lib/session/status-evidence.js +2 -2
  565. package/dist/server/src/lib/session/structured-status-merge.js +335 -0
  566. package/dist/server/src/lib/session/waiting-episode-state.js +3 -4
  567. package/dist/server/src/lib/session/waiting-kind.js +3 -0
  568. package/dist/server/src/lib/session-cleanup.js +6 -8
  569. package/dist/server/src/lib/skills/install-plan.js +2 -1
  570. package/dist/server/src/lib/skills/snapshot-store.js +2 -2
  571. package/dist/server/src/lib/skills/uninstall-plan.js +2 -2
  572. package/dist/server/src/lib/timer-manager.js +6 -8
  573. package/dist/server/src/lib/tmux/geometry-delegation.js +3 -4
  574. package/dist/server/src/lib/tmux/legacy-session-alias.js +2 -1
  575. package/dist/server/src/lib/tmux/session-hooks.js +2 -1
  576. package/dist/server/src/lib/tmux/session-status-options.js +3 -3
  577. package/dist/server/src/lib/tmux/tmux-capture-cache.js +3 -2
  578. package/dist/server/src/lib/tmux/tmux.js +33 -59
  579. package/dist/server/src/lib/tui-accumulator.js +2 -2
  580. package/dist/server/src/lib/version-checker.js +6 -6
  581. package/dist/server/src/lib/ws-server.js +47 -11
  582. package/docs/en/user-guide/webapp-guide.md +27 -3
  583. package/package.json +1 -1
  584. package/release-notes/0.44.2.json +33 -0
  585. package/release-notes/0.44.3.json +82 -0
  586. package/scripts/hooks/cmate-agent-event.sh +18 -0
  587. package/.next/server/chunks/1068.js +0 -1
  588. package/.next/server/chunks/434.js +0 -1
  589. package/.next/server/chunks/5775.js +0 -1
  590. package/.next/server/chunks/6474.js +0 -14
  591. package/.next/server/chunks/650.js +0 -1
  592. package/.next/server/chunks/6661.js +0 -1
  593. package/.next/server/chunks/8583.js +0 -1
  594. package/.next/server/chunks/964.js +0 -1
  595. package/.next/server/chunks/967.js +0 -1
  596. package/.next/server/chunks/9882.js +0 -25
  597. package/.next/static/chunks/591-308072f285c34787.js +0 -1
  598. package/.next/static/chunks/app/sessions/page-049e06335187aa91.js +0 -1
  599. package/.next/static/chunks/app/worktrees/[id]/page-040c5f0f585e6812.js +0 -1
  600. package/.next/static/css/38070d879efa1371.css +0 -1
  601. package/dist/server/src/lib/cli-tools/index.js +0 -41
  602. package/dist/server/src/lib/polling/global-session-poller.js +0 -140
  603. /package/.next/static/{57lOiz8zSEHdw97XIm0af → tWwHQzmvc-rv9KKUtDWfQ}/_buildManifest.js +0 -0
  604. /package/.next/static/{57lOiz8zSEHdw97XIm0af → tWwHQzmvc-rv9KKUtDWfQ}/_ssgManifest.js +0 -0
@@ -31,6 +31,7 @@ const api_client_1 = require("../utils/api-client");
31
31
  const command_helpers_1 = require("../utils/command-helpers");
32
32
  const verify_runner_1 = require("../utils/verify-runner");
33
33
  const agent_target_options_1 = require("../config/agent-target-options");
34
+ const prompt_view_1 = require("../../lib/session/prompt-view");
34
35
  const instances_1 = require("./instances");
35
36
  /** [IA3-02] Polling interval 5 seconds (matches tmux-capture-cache TTL=2s) */
36
37
  const POLL_INTERVAL_MS = 5000;
@@ -53,7 +54,24 @@ const SELECTION_LIST_PROMPT_TYPE = 'selection_list';
53
54
  * among them) keeps working and simply meets a kind it does not recognise,
54
55
  * whereas a new exit code reads as an infrastructure error to all of them.
55
56
  */
56
- const UNCLASSIFIED_PROMPT_TYPE = 'unclassified';
57
+ //
58
+ // Issue #3184: the value comes from `lib/session/prompt-view` rather than a copy
59
+ // here — that module has no imports, so the CLI build compiles it.
60
+ const UNCLASSIFIED_PROMPT_TYPE = prompt_view_1.UNCLASSIFIED_PROMPT_VIEW_TYPE;
61
+ /**
62
+ * How the prompt reported on exit 10 is answered (Issue #3184): `screen` = the
63
+ * option number or y/n typed at the pane (`respond`), `api` = a decision
64
+ * delivered over the agent's own API (`respond <id> <number>`, no keys sent),
65
+ * `terminal` = nothing to offer, a human answers at the pane. Read off the
66
+ * shared view so `wait` and the browser cannot reach different conclusions.
67
+ */
68
+ function waitAnswerVia(view) {
69
+ if (view?.kind === 'screen-choices')
70
+ return 'screen';
71
+ if (view?.kind === 'api-choices')
72
+ return 'api';
73
+ return 'terminal';
74
+ }
57
75
  /**
58
76
  * Why `wait` decided the agent was done, printed on the completion line
59
77
  * (Issue #1839).
@@ -200,6 +218,8 @@ function describePaneObstruction(data) {
200
218
  const SUPPRESSION_FRESH_MS = 60_000;
201
219
  /** The suppression currently blocking this session, or null. */
202
220
  function activeSuppression(data, now) {
221
+ // No `autoYes` at all (a session that is not running, Issue #3300) reads as
222
+ // "nothing was withheld", the same as a null record.
203
223
  const suppression = data.autoYes?.lastSuppression;
204
224
  if (!suppression)
205
225
  return null;
@@ -278,6 +298,33 @@ function formatSuppressionNotice(suppression, ageSeconds) {
278
298
  const cause = suppressionCause(suppression.reason);
279
299
  return ` auto-yes suppressed this prompt ${cause}: ${parts.join(' ')} (${ageSeconds}s ago)`;
280
300
  }
301
+ /**
302
+ * One stderr line saying Auto-Yes pressed Enter on THIS prompt (Issue #3397), or
303
+ * null when the record is absent or about another screen.
304
+ *
305
+ * The prompt is one CommandMate could not read (the window offers direct input
306
+ * for it). `sent` — Auto-Yes confirmed whatever was selected; `no-effect` — the
307
+ * same screen outlived the Enter, no second one was sent, and it is a human's
308
+ * again. An outcome this CLI does not know is named verbatim (#1843's rule).
309
+ * `currentPrompt` is the server's judgement that the record is about the
310
+ * `promptData` of the same response, so an Enter sent to an earlier screen is
311
+ * never reported against this one.
312
+ */
313
+ function formatEnterFallbackNotice(data, now) {
314
+ const record = data.autoYes?.lastEnterFallback;
315
+ if (!record || record.currentPrompt !== true)
316
+ return null;
317
+ const detail = `refusal=${record.refusalReason} promptType=${record.promptType}`;
318
+ const ago = `(${Math.max(0, Math.round((now - record.at) / 1000))}s ago)`;
319
+ if (record.outcome === 'sent') {
320
+ return ` auto-yes sent Enter to this prompt (CommandMate could not read it): ${detail} ${ago}`;
321
+ }
322
+ if (record.outcome === 'no-effect') {
323
+ return ` auto-yes sent Enter to this prompt, but the same screen is still up (no-effect); ` +
324
+ `answer it in the terminal: ${detail} ${ago}`;
325
+ }
326
+ return ` auto-yes Enter record for this prompt: outcome=${record.outcome} ${detail} ${ago}`;
327
+ }
281
328
  /**
282
329
  * Whether this server publishes a real turn record (Issue #1930).
283
330
  *
@@ -660,6 +707,508 @@ function nextPollWithinDeadlines(options, startTime, lastActivityTime, now) {
660
707
  }
661
708
  return true;
662
709
  }
710
+ /**
711
+ * The exit-10 payload for a prompt the detection layer parsed. `suppressed` is
712
+ * {@link activeSuppression}'s reading of the same poll.
713
+ */
714
+ function buildPromptOutput(worktreeId, data, promptData, suppressed) {
715
+ // Issue #1898: the degraded `unclassified` payload carries no `options`
716
+ // — by construction, because nothing parsed the screen — but for a
717
+ // source whose approvals are answered by decision id it does carry
718
+ // `decisionOptions`, which ARE answerable (`respond <id> 1`). Reporting
719
+ // an empty list there told the caller a dialog was open and gave it
720
+ // nothing to do about it, which is the whole of #1898-3 seen from the
721
+ // pipeline's side.
722
+ //
723
+ // Issue #3184: and a QUESTION answered by decision id (OpenCode V2,
724
+ // #2100) carries neither — its choices are `askUserQuestion.labels`,
725
+ // numbered by position. The panel offered them as buttons while this
726
+ // reported `[]`. Which of these applies is the shared view's call
727
+ // (`readPromptView`), not a third reading of the raw fields here.
728
+ const promptView = (0, prompt_view_1.readPromptView)(data);
729
+ const promptOptions = promptData.options?.length
730
+ ? promptData.options
731
+ : promptData.decisionOptions?.length
732
+ ? promptData.decisionOptions
733
+ : promptView?.apiTarget === 'question'
734
+ ? promptView.choices.map((choice) => ({
735
+ number: Number(choice.answer),
736
+ label: choice.label,
737
+ }))
738
+ : [];
739
+ const promptOutput = {
740
+ worktreeId,
741
+ cliToolId: data.cliToolId || 'claude',
742
+ type: promptData.type || 'unknown',
743
+ question: promptData.question || '',
744
+ options: promptOptions,
745
+ status: promptData.status || 'pending',
746
+ answerVia: waitAnswerVia(promptView),
747
+ ...(promptData.approvalTarget !== undefined && {
748
+ approvalTarget: promptData.approvalTarget,
749
+ }),
750
+ ...(suppressed && {
751
+ autoYesSuppression: {
752
+ reason: suppressed.suppression.reason,
753
+ mode: suppressed.suppression.mode,
754
+ promptType: suppressed.suppression.promptType,
755
+ ...(suppressed.suppression.pattern !== undefined && {
756
+ pattern: suppressed.suppression.pattern,
757
+ }),
758
+ ageSeconds: suppressed.ageSeconds,
759
+ },
760
+ }),
761
+ };
762
+ return promptOutput;
763
+ }
764
+ /** The exit-10 payload for an arrow-key selection list (Issue #1628). */
765
+ function buildSelectionListOutput(worktreeId, data) {
766
+ return {
767
+ worktreeId,
768
+ cliToolId: data.cliToolId || 'claude',
769
+ type: SELECTION_LIST_PROMPT_TYPE,
770
+ question: data.sessionStatusReason ?? SELECTION_LIST_PROMPT_TYPE,
771
+ options: [],
772
+ status: 'pending',
773
+ };
774
+ }
775
+ /**
776
+ * What `wait` says about a frame that stayed unclassified for the whole dwell
777
+ * (Issue #1708): the stderr line, and the `question` of its exit-10 payload.
778
+ */
779
+ function describeUnclassifiedFrame(worktreeId, data, dwellMs) {
780
+ const dwellSeconds = Math.round(dwellMs / 1000);
781
+ return (`Unclassified interactive frame on ${worktreeId} for ${dwellSeconds}s ` +
782
+ `(status=${data.sessionStatus ?? 'unknown'}/${data.sessionStatusReason ?? 'unknown'}). ` +
783
+ `The detection layer could not parse it; inspect the raw pane with ` +
784
+ `\`commandmate capture ${worktreeId} --pane\`.` +
785
+ // Issue #2095: the sidebar is exactly this frame's reason, and the
786
+ // one recovery is a keystroke in the pane. Riding the message keeps
787
+ // the exit-code table (10, `type: unclassified`) unchanged for every
788
+ // caller that already branches on it.
789
+ describePaneObstruction(data));
790
+ }
791
+ /** The exit-10 payload for a persistently unclassified frame (Issue #1708). */
792
+ function buildUnclassifiedOutput(worktreeId, data, question) {
793
+ return {
794
+ worktreeId,
795
+ cliToolId: data.cliToolId || 'claude',
796
+ type: UNCLASSIFIED_PROMPT_TYPE,
797
+ question,
798
+ options: [],
799
+ status: 'pending',
800
+ answerVia: 'terminal',
801
+ };
802
+ }
803
+ /** The stderr line for a session this wait never saw running (Issue #1628). */
804
+ function describeNotStarted(worktreeId, data, options) {
805
+ return (`Not started: ${worktreeId} has no running ${data.cliToolId ?? 'agent'} session` +
806
+ `${options.instance ? ` for instance ${options.instance}` : ''}` +
807
+ // Issue #1884: name the stage that chose the agent above. `wait` has
808
+ // no --agent to correct a mis-resolution with, so "no running claude
809
+ // session for instance opencode" was the entire evidence an operator
810
+ // got for a live agent reported as absent. `worktree-default` here
811
+ // means the instance is neither in the roster nor named after a
812
+ // tool; `client-fallback`, that the server is too old to resolve.
813
+ `${data.resolvedBy ? ` (resolvedBy=${data.resolvedBy})` : ''}.`);
814
+ }
815
+ /** The outcome that ends the wait with `result`. */
816
+ function exitWith(result) {
817
+ return { kind: 'exit', result };
818
+ }
819
+ /**
820
+ * Stage: `--timeout` and `--stall-timeout`, asked at the top of every poll,
821
+ * before its request. Exit 124.
822
+ */
823
+ function deadlineStage(poll, state) {
824
+ const { worktreeId, options, startTime } = poll;
825
+ // Check timeout
826
+ if (options.timeout) {
827
+ const elapsed = (Date.now() - startTime) / 1000;
828
+ if (elapsed >= options.timeout) {
829
+ console.error(`Timeout: ${worktreeId} exceeded ${options.timeout}s`);
830
+ return exitWith({ exitCode: types_1.WaitExitCode.TIMEOUT });
831
+ }
832
+ }
833
+ // Check stall-timeout
834
+ if (options.stallTimeout) {
835
+ const stallElapsed = (Date.now() - state.lastActivityTime) / 1000;
836
+ if (stallElapsed >= options.stallTimeout) {
837
+ console.error(`Stall timeout: ${worktreeId} no output for ${options.stallTimeout}s`);
838
+ return exitWith({ exitCode: types_1.WaitExitCode.TIMEOUT });
839
+ }
840
+ }
841
+ return { kind: 'next' };
842
+ }
843
+ /**
844
+ * Stage: a prompt the detection layer parsed. Exit 10, unless it is held for a
845
+ * human (`--on-prompt human`) or for the target's Auto-Yes (Issue #2463).
846
+ */
847
+ function promptStage(poll, state, data) {
848
+ const { worktreeId, options, startTime, autoYesGraceSeconds, autoYesGraceMs } = poll;
849
+ // Prompt detected
850
+ if (data.isPromptWaiting && data.promptData) {
851
+ // Issue #1699: report a policy suppression on both exits — the human one
852
+ // keeps polling and would otherwise say nothing about why nobody
853
+ // answered, and the agent one is read by pipelines that never see stderr.
854
+ const suppressed = activeSuppression(data, Date.now());
855
+ // [DR1-03] Prompt detection exit code
856
+ if (options.onPrompt === 'human') {
857
+ // Block and continue polling - user handles prompt manually
858
+ console.error(`Prompt detected on ${worktreeId}. Waiting for human response...`);
859
+ if (suppressed) {
860
+ console.error(formatSuppressionNotice(suppressed.suppression, suppressed.ageSeconds));
861
+ }
862
+ // Issue #3397: and whether Auto-Yes already pressed Enter on it.
863
+ const enterNotice = formatEnterFallbackNotice(data, Date.now());
864
+ if (enterNotice)
865
+ console.error(enterNotice);
866
+ return { kind: 'wait' };
867
+ }
868
+ // Issue #2463: the one case `decidePromptPush()` stays quiet about —
869
+ // Auto-Yes is on and has not withheld this answer — is a prompt Auto-Yes
870
+ // is about to answer, and exit 10 there hands a delegation back to a
871
+ // human for a dialog nobody had to see. Hold it for the grace window; a
872
+ // poll that shows no prompt ends the hold below and completion is judged
873
+ // as usual. A withheld answer (`suppressed`) and Auto-Yes being off are
874
+ // the gate's other two branches and still exit 10 at once.
875
+ if (!suppressed && data.autoYes?.enabled === true && autoYesGraceMs > 0) {
876
+ const now = Date.now();
877
+ if (state.autoYesAnsweringSince === null) {
878
+ state.autoYesAnsweringSince = now;
879
+ // stderr only: stdout is the exit-10 payload and nothing else.
880
+ console.error("Prompt detected; the target's Auto-Yes is answering, waiting up to " +
881
+ `${autoYesGraceSeconds}s… (${worktreeId})`);
882
+ }
883
+ const heldMs = now - state.autoYesAnsweringSince;
884
+ if (heldMs < autoYesGraceMs &&
885
+ nextPollWithinDeadlines(options, startTime, state.lastActivityTime, now)) {
886
+ return { kind: 'wait' };
887
+ }
888
+ console.error(heldMs < autoYesGraceMs
889
+ ? `Note: the prompt on ${worktreeId} is still open after ${Math.round(heldMs / 1000)}s ` +
890
+ 'under Auto-Yes, and the next poll would pass --timeout/--stall-timeout; reporting it now.'
891
+ : `Note: the target's Auto-Yes did not answer the prompt on ${worktreeId} within ` +
892
+ `${autoYesGraceSeconds}s; reporting it.`);
893
+ }
894
+ else if (state.autoYesAnsweringSince !== null && !suppressed) {
895
+ console.error(`Note: Auto-Yes is no longer enabled on ${worktreeId}; reporting the prompt.`);
896
+ }
897
+ // Default (agent mode): output prompt info and exit 10
898
+ const promptOutput = buildPromptOutput(worktreeId, data, data.promptData, suppressed);
899
+ if (suppressed) {
900
+ console.error(formatSuppressionNotice(suppressed.suppression, suppressed.ageSeconds));
901
+ }
902
+ // Issue #3397: stderr only, like the notice above; the exit-10 payload is unchanged.
903
+ const enterNotice = formatEnterFallbackNotice(data, Date.now());
904
+ if (enterNotice)
905
+ console.error(enterNotice);
906
+ return exitWith({ exitCode: types_1.WaitExitCode.PROMPT_DETECTED, output: promptOutput });
907
+ }
908
+ return { kind: 'next' };
909
+ }
910
+ /** Stage: an arrow-key selection list (Issue #1628). Exit 10, or held under `--on-prompt human`. */
911
+ function selectionListStage(poll, data) {
912
+ const { worktreeId, options } = poll;
913
+ // Issue #1628: an arrow-key menu is the agent blocked on a human just as much
914
+ // as a numbered prompt is, but it is published with isPromptWaiting=false so
915
+ // the UI can render NavigationButtons instead of PromptPanel. Treat it as a
916
+ // prompt here — otherwise `wait` polls a stopped agent until --timeout.
917
+ if (data.isSelectionListActive) {
918
+ if (options.onPrompt === 'human') {
919
+ console.error(`Selection list active on ${worktreeId} (${data.sessionStatusReason ?? 'selection_list'}). ` +
920
+ 'Waiting for human response...');
921
+ // Issue #1699: the poller parses frames status-detector publishes as
922
+ // selection lists, so a policy can be the reason this one is stuck too.
923
+ const suppressed = activeSuppression(data, Date.now());
924
+ if (suppressed) {
925
+ console.error(formatSuppressionNotice(suppressed.suppression, suppressed.ageSeconds));
926
+ }
927
+ return { kind: 'wait' };
928
+ }
929
+ return exitWith({
930
+ exitCode: types_1.WaitExitCode.PROMPT_DETECTED,
931
+ output: buildSelectionListOutput(worktreeId, data),
932
+ });
933
+ }
934
+ return { kind: 'next' };
935
+ }
936
+ /**
937
+ * Stage: an interactive frame nothing could parse, once it has stayed up for the
938
+ * whole dwell (Issue #1708). Exit 10, or held under `--on-prompt human`.
939
+ */
940
+ function unclassifiedStage(poll, state, data) {
941
+ const { worktreeId, options } = poll;
942
+ // Issue #1708: the frame is interactive but nothing could parse it. The
943
+ // detection layer is the single entry point every downstream safeguard
944
+ // hangs off, so a frame that slips past it disables Auto-Yes, the exit-10
945
+ // handoff and the contract's autoYes policy all at once — and `wait` used
946
+ // to burn its whole --timeout without ever mentioning it. Treat a
947
+ // PERSISTENT unclassified frame as a stop reason of its own.
948
+ //
949
+ // The dwell deliberately spans ALL THREE states that raise this flag, and
950
+ // the completion check below is suppressed while it is up. That is the
951
+ // whole point, and it is worth spelling out because the obvious reading is
952
+ // the wrong one. The server's definition (`isUnclassifiedFrame` in
953
+ // `src/lib/session/status-evidence.ts`, restated there by Issue #2011):
954
+ //
955
+ // isUnclassifiedActive =
956
+ // running && (default | unknown_frame | no_recent_output)
957
+ //
958
+ // `no_recent_output` is there because a static unrecognised overlay
959
+ // DEGRADES into it — once the Auto-Yes poller stamps
960
+ // lastServerResponseTimestamp, a frame that stopped changing flips from
961
+ // `running`/`default` after STALE_OUTPUT_THRESHOLD_MS (5s). `unknown_frame`
962
+ // is the same floor for a tool that opts out of the generic composer check
963
+ // (copilot, opencode), and says "this tool's own rules looked and read
964
+ // nothing". Both arrive about twelve times faster than this dwell. Letting
965
+ // the completion check claim one turned a stalled worker into `Completed`,
966
+ // which is worse than the timeout Issue #1708 complained about: exit 124
967
+ // stops a pipeline, exit 0 lets it merge. Measured before this guard: two
968
+ // unclassified polls followed by the degraded state returned SUCCESS.
969
+ //
970
+ // What is deliberately NOT in the set is `ready`/`input_prompt` with
971
+ // `statusEvidence: 'none'` — the agent back at its composer on a frame no
972
+ // tool-specific idle rule could vouch for. That frame WAS classified; what
973
+ // is missing is positive proof, which is a different question and §4 D1's
974
+ // to answer. Issue #1927 folded the two together and every idle Claude pane
975
+ // stopped completing (#2011). Whether `wait` should hold for evidence as
976
+ // well as classification is open, and any answer belongs in the same place
977
+ // as the rollout that produces the evidence — not here.
978
+ if (data.isUnclassifiedActive === true) {
979
+ if (state.unclassifiedSince === null)
980
+ state.unclassifiedSince = Date.now();
981
+ const dwellMs = Date.now() - state.unclassifiedSince;
982
+ if (dwellMs >= UNCLASSIFIED_DWELL_MS) {
983
+ const question = describeUnclassifiedFrame(worktreeId, data, dwellMs);
984
+ if (options.onPrompt === 'human') {
985
+ console.error(question);
986
+ console.error('Waiting for human response...');
987
+ return { kind: 'wait' };
988
+ }
989
+ console.error(question);
990
+ return exitWith({
991
+ exitCode: types_1.WaitExitCode.PROMPT_DETECTED,
992
+ output: buildUnclassifiedOutput(worktreeId, data, question),
993
+ });
994
+ }
995
+ }
996
+ else {
997
+ state.unclassifiedSince = null;
998
+ }
999
+ return { kind: 'next' };
1000
+ }
1001
+ /**
1002
+ * Stage: the session is not running (Path A). Exit 21 when this wait never saw
1003
+ * it alive (Issue #1628), exit 0 when it went away after it had been seen.
1004
+ */
1005
+ function notRunningStage(poll, state, data, selfResumeSuffix) {
1006
+ const { worktreeId, options } = poll;
1007
+ // Completion check [DR1-04]:
1008
+ // Path A: the tmux session went away after we had seen it alive — the agent
1009
+ // finished and its session was stopped.
1010
+ // Path B: agent completed task (sessionStatus === 'ready', input prompt detected)
1011
+ // Both indicate "no more work in progress" from wait command's perspective.
1012
+ // (This stage handles Path A only; Path B is checked in `readyStage`.)
1013
+ //
1014
+ // Issue #1628 narrowed Path A: a session that was NEVER seen running is
1015
+ // "nothing to wait for" (NOT_STARTED), not a completion. See `everRunning`.
1016
+ if (!data.isRunning && !state.everRunning) {
1017
+ console.error(describeNotStarted(worktreeId, data, options));
1018
+ return exitWith({ exitCode: types_1.VerifyExitCode.NOT_STARTED });
1019
+ }
1020
+ if (!data.isRunning) {
1021
+ console.error(`Completed: ${worktreeId} (basis=${COMPLETION_BASIS.SESSION_GONE}${selfResumeSuffix()})`);
1022
+ return exitWith({ exitCode: types_1.WaitExitCode.SUCCESS });
1023
+ }
1024
+ return { kind: 'next' };
1025
+ }
1026
+ /**
1027
+ * Stage of a `ready` frame: an upstream fault on the frame, under
1028
+ * `--fail-on-upstream-fault` (Issue #1839). Exit 11.
1029
+ */
1030
+ function upstreamFaultStage(poll, data) {
1031
+ const { worktreeId, options } = poll;
1032
+ // Issue #1839: the agent is back at its composer with an upstream
1033
+ // failure on the frame. Checked BEFORE the turn-boundary gate below,
1034
+ // because it is the answer to the question that gate can only ask: the
1035
+ // turn did not end, and this is why. Without it the same session runs
1036
+ // to --timeout and reports 124, which says nothing about the cause.
1037
+ const fault = data.upstreamFault ?? null;
1038
+ if (options.failOnUpstreamFault && fault) {
1039
+ console.error(`Upstream fault on ${worktreeId}: id=${fault.id} — the agent is back at its ` +
1040
+ 'composer with an upstream API failure on screen, so this turn did not run. ' +
1041
+ `Matched: ${JSON.stringify(fault.matchedText)}`);
1042
+ if (fault.id === 'context-limit') {
1043
+ // A retry into the same session hits the same wall (Issue #3011).
1044
+ console.error('The session\'s conversation is over the model\'s context limit. Start a fresh ' +
1045
+ `session and send again: commandmate instances ${worktreeId} kill ` +
1046
+ `${options.instance ?? '<instance>'}`);
1047
+ }
1048
+ return exitWith({
1049
+ exitCode: types_1.WaitExitCode.UPSTREAM_FAULT,
1050
+ upstreamFault: { id: fault.id, matchedText: fault.matchedText },
1051
+ });
1052
+ }
1053
+ return { kind: 'next' };
1054
+ }
1055
+ /**
1056
+ * Stage of a `ready` frame: the agent has not reported the end of the turn this
1057
+ * wait adopted (Issue #1839). Held.
1058
+ */
1059
+ function unsettledTurnStage(poll, state, data) {
1060
+ const { worktreeId } = poll;
1061
+ // Issue #1839: `ready` off the terminal frame is the agent's composer,
1062
+ // not the agent's verdict. Measured 2026-08-20 against a stub upstream
1063
+ // answering 529: Claude returns to the composer ~3 s after the send
1064
+ // having executed nothing, and never sends `Stop`. When this instance's
1065
+ // hooks ARE reporting — the only case in which `turnStartedAt` is
1066
+ // non-null — that missing `Stop` is the difference between "finished"
1067
+ // and "never ran", and it is the only signal that carries it.
1068
+ if (!turnSettled(data, state.turnStartedAt)) {
1069
+ console.error(`Waiting: ${worktreeId} is back at its composer, but its agent has not reported ` +
1070
+ `the end of this turn (turnStartedAt=${state.turnStartedAt}, ` +
1071
+ `lastStopEventAt=${data.lastStopEventAt ?? 'none'}, ${describeTurnClose(data)}). ` +
1072
+ 'Not reporting completion; inspect with ' +
1073
+ `\`commandmate capture ${worktreeId} --json\`.`);
1074
+ return { kind: 'wait' };
1075
+ }
1076
+ return { kind: 'next' };
1077
+ }
1078
+ /**
1079
+ * Stage of a `ready` frame: the turn ended on a `stop` that said the agent will
1080
+ * resume by itself (Issue #2614). Held, up to {@link SELF_RESUME_HOLD_MS}.
1081
+ */
1082
+ function selfResumeHoldStage(poll, state, data, selfResumeStopAt) {
1083
+ const { worktreeId } = poll;
1084
+ // Issue #2614: the turn did end — the agent said so — but it also said
1085
+ // that work of its own is still running in the background (a `schedule`
1086
+ // timer, a backgrounded command), and that work wakes it with nobody
1087
+ // typing anything. Measured 2026-09-17 on antigravity 1.2.4: four such
1088
+ // stops ~58 s before each self-wake, and the first one was reported as
1089
+ // `Completed (basis=hook_stop)` and verified five minutes before the
1090
+ // work was done. So this `stop` is held until it is no longer the newest
1091
+ // word (see `selfResumeStopAt` above), or until the bound.
1092
+ //
1093
+ // The bound is measured from whichever is further along: the `stop`
1094
+ // itself (server clock — a negative age is skew, and the max discards
1095
+ // it) or this wait's first sight of it. A session that said so hours ago
1096
+ // and never woke is not held again.
1097
+ if (selfResumeStopAt !== null) {
1098
+ const now = Date.now();
1099
+ if (state.selfResumeHold === null)
1100
+ state.selfResumeHold = { stopAt: selfResumeStopAt, since: now };
1101
+ const heldMs = now - state.selfResumeHold.since;
1102
+ const elapsedMs = Math.max(heldMs, now - selfResumeStopAt);
1103
+ if (elapsedMs < exports.SELF_RESUME_HOLD_MS) {
1104
+ state.selfResumeHeld = true;
1105
+ console.error(`Waiting: ${worktreeId} ended its turn with background work still running ` +
1106
+ `(stoppedAt=${new Date(selfResumeStopAt).toISOString()}, ` +
1107
+ `lastEventDetail=${exports.SELF_RESUME_PENDING_DETAIL}, ${describeTurnClose(data)}); ` +
1108
+ 'it resumes by itself when that work finishes. Not reporting completion ' +
1109
+ `(held ${Math.round(heldMs / 1000)}s, at most ${exports.SELF_RESUME_HOLD_MS / 1000}s ` +
1110
+ 'after the stop).');
1111
+ return { kind: 'wait' };
1112
+ }
1113
+ console.error(`Note: ${worktreeId} said at its stop ${Math.round(elapsedMs / 1000)}s ` +
1114
+ 'ago that background work was still running, and has not resumed since; ' +
1115
+ 'completing on that stop.');
1116
+ }
1117
+ return { kind: 'next' };
1118
+ }
1119
+ /**
1120
+ * Stage of a `ready` frame: the chat ledger shows a prompt the agent has not
1121
+ * reported the end of (Issue #1975). Held, up to {@link PENDING_PROMPT_HOLD_MS}.
1122
+ * `next` carries whether the newest prompt was answered, which
1123
+ * {@link completionStage} needs for its basis.
1124
+ */
1125
+ async function promptLedgerStage(poll, state, data) {
1126
+ const { client, worktreeId, options, startTime } = poll;
1127
+ // Issue #1975: the same frame, one question further back. #1839's gate
1128
+ // above can only fire once a turn has been ADOPTED, and `send` leaves a
1129
+ // window ~1s wide in which nothing has been: the newest structured event
1130
+ // is still the previous turn's `stop`, so `adoptTurnStart` takes nothing,
1131
+ // `turnSettled` reads null as "settled", and the composer the agent has
1132
+ // not touched yet is read as the composer it came back to. Measured
1133
+ // 2026-08-22 against copilot 1.0.80 on an isolated server: 3 of 5
1134
+ // send-then-wait runs came back in ~0.3s with `basis=scraper_ready` and
1135
+ // no artefact on disk.
1136
+ //
1137
+ // So ask the ledger instead of the clock: has this instance been handed
1138
+ // a prompt that the agent has not reported the end of? See
1139
+ // {@link outstandingPrompt} for why that comparison is the one that
1140
+ // separates "not started" from "finished", and
1141
+ // {@link reportsTurnBoundaries} for why a tool that posts no hooks never
1142
+ // reaches it.
1143
+ let answeredNewestPrompt = false;
1144
+ if (state.turnStartedAt === null && state.promptLedgerReadable && reportsTurnBoundaries(data)) {
1145
+ const ledger = await readNewestPromptAt(client, worktreeId, options, data);
1146
+ // One notice, then stop asking: a ledger that failed once will fail
1147
+ // every poll, and the point of degrading is to stop paying for it.
1148
+ state.promptLedgerReadable = ledger.readable;
1149
+ if (ledger.readable && ledger.submittedAt !== null) {
1150
+ if (outstandingPrompt(data, ledger.submittedAt)) {
1151
+ const heldMs = Date.now() - startTime;
1152
+ if (heldMs < PENDING_PROMPT_HOLD_MS) {
1153
+ console.error(`Waiting: ${worktreeId} is at its composer, but the newest prompt sent to it ` +
1154
+ `has no reported end (sentAt=${new Date(ledger.submittedAt).toISOString()}, ` +
1155
+ `lastStopEventAt=${data.lastStopEventAt ?? 'none'}, ${describeTurnClose(data)}). ` +
1156
+ 'Not reporting completion: the agent has not started this turn yet.');
1157
+ return { kind: 'wait' };
1158
+ }
1159
+ console.error(`Note: ${worktreeId} has been at its composer for ` +
1160
+ `${Math.round(heldMs / 1000)}s with the newest prompt still unreported by its ` +
1161
+ 'agent. Its hooks are not answering; completing on the frame alone.');
1162
+ }
1163
+ else {
1164
+ answeredNewestPrompt = true;
1165
+ }
1166
+ }
1167
+ }
1168
+ return { kind: 'next', answeredNewestPrompt };
1169
+ }
1170
+ /** Last stage of a `ready` frame: the completion line with its basis. Exit 0. */
1171
+ function completionStage(poll, state, answeredNewestPrompt, selfResumeSuffix) {
1172
+ const { worktreeId } = poll;
1173
+ // `hook_stop` on both branches that have one, and they are the same
1174
+ // statement made from two records: the agent reported the end of the
1175
+ // turn this wait is about. `scraper_ready` keeps its documented meaning
1176
+ // — "the screen said so and nothing corroborated it" — which is now
1177
+ // exactly the set of cases that reach it.
1178
+ const basis = state.turnStartedAt !== null || answeredNewestPrompt
1179
+ ? COMPLETION_BASIS.HOOK_STOP
1180
+ : COMPLETION_BASIS.SCRAPER_READY;
1181
+ console.error(`Completed: ${worktreeId} (basis=${basis}${selfResumeSuffix()})`);
1182
+ return exitWith({ exitCode: types_1.WaitExitCode.SUCCESS });
1183
+ }
1184
+ /**
1185
+ * Stage: the agent is back at its composer on a frame that was understood. Asks
1186
+ * the stages of a `ready` frame in order; the first that applies decides.
1187
+ */
1188
+ async function readyStage(poll, state, data, selfResumeStopAt, selfResumeSuffix) {
1189
+ // Issue #1708 narrowed Path B: `ready` is only a completion when the frame
1190
+ // was actually understood. A structured `hook_stop` over an unreadable
1191
+ // pane is the degraded form of an overlay nobody could parse (see the note
1192
+ // above), and reporting it as `Completed` is how a stalled worker gets
1193
+ // merged. Path A is untouched — a session that went away really is
1194
+ // finished, and carries no flag anyway.
1195
+ if (data.sessionStatus === 'ready' && data.isUnclassifiedActive !== true) {
1196
+ const faultOutcome = upstreamFaultStage(poll, data);
1197
+ if (faultOutcome.kind !== 'next')
1198
+ return faultOutcome;
1199
+ const turnOutcome = unsettledTurnStage(poll, state, data);
1200
+ if (turnOutcome.kind !== 'next')
1201
+ return turnOutcome;
1202
+ const holdOutcome = selfResumeHoldStage(poll, state, data, selfResumeStopAt);
1203
+ if (holdOutcome.kind !== 'next')
1204
+ return holdOutcome;
1205
+ const ledgerOutcome = await promptLedgerStage(poll, state, data);
1206
+ if (ledgerOutcome.kind !== 'next')
1207
+ return ledgerOutcome;
1208
+ return completionStage(poll, state, ledgerOutcome.answeredNewestPrompt, selfResumeSuffix);
1209
+ }
1210
+ return { kind: 'next' };
1211
+ }
663
1212
  /**
664
1213
  * Poll a single worktree until completion, prompt, or timeout.
665
1214
  *
@@ -676,81 +1225,36 @@ function nextPollWithinDeadlines(options, startTime, lastActivityTime, now) {
676
1225
  */
677
1226
  async function pollWorktree(client, worktreeId, options) {
678
1227
  const startTime = Date.now();
679
- let lastActivityTime = Date.now();
680
- let lastContent = '';
681
- /**
682
- * Issue #1628: whether this wait ever saw the session alive. `!isRunning` on the
683
- * FIRST poll is "there is nothing here to wait for", not "the agent finished" —
684
- * reporting SUCCESS for it is how a wait on a worktree whose agent never started
685
- * (wrong tool, wrong instance, session never created) came back `Completed` in
686
- * milliseconds and handed a `passed` verdict to whatever ran next.
687
- */
688
- let everRunning = false;
689
- /**
690
- * Epoch ms of the first poll in the current unbroken run of
691
- * `isUnclassifiedActive === true`, or null when the last poll cleared it
692
- * (Issue #1708).
693
- */
694
- let unclassifiedSince = null;
695
- /**
696
- * Epoch ms of the `user_prompt_submit` / `pre_tool_use` / `post_tool_use` this
697
- * wait adopted as "the turn I am waiting on", or null when the agent has
698
- * reported none (Issue #1839). See {@link adoptTurnStart}.
699
- */
700
- let turnStartedAt = null;
701
- /**
702
- * Whether the chat ledger is still worth asking (Issue #1975). Cleared by the
703
- * first read that fails, after which this wait judges completion from the
704
- * frame alone — the pre-#1975 behaviour — rather than re-reporting the same
705
- * unreachable endpoint on every poll.
706
- */
707
- let promptLedgerReadable = true;
708
- /**
709
- * Epoch ms of the first poll in the current unbroken run of an agent-mode
710
- * prompt the target's Auto-Yes is expected to answer, or null (Issue #2463).
711
- * Cleared by the first poll that shows no prompt, so every prompt Auto-Yes
712
- * answers gets a window of its own.
713
- */
714
- let autoYesAnsweringSince = null;
1228
+ const state = {
1229
+ lastActivityTime: Date.now(),
1230
+ lastContent: '',
1231
+ everRunning: false,
1232
+ unclassifiedSince: null,
1233
+ turnStartedAt: null,
1234
+ promptLedgerReadable: true,
1235
+ autoYesAnsweringSince: null,
1236
+ selfResumeHold: null,
1237
+ selfResumeHeldMs: 0,
1238
+ selfResumeHeld: false,
1239
+ };
715
1240
  const autoYesGraceSeconds = options.autoYesGrace ?? AUTO_YES_GRACE_DEFAULT_SECONDS;
716
1241
  const autoYesGraceMs = autoYesGraceSeconds * 1000;
717
- /**
718
- * The self-resume hold in progress: the `stop` it is about, and when this wait
719
- * first held on it (CLI clock). Null when none is (Issue #2614).
720
- */
721
- let selfResumeHold = null;
722
- /** Milliseconds spent in self-resume holds that have already ended (Issue #2614). */
723
- let selfResumeHeldMs = 0;
724
- /** Whether any poll of this wait was held for a self-resume (Issue #2614). */
725
- let selfResumeHeld = false;
1242
+ const poll = { client, worktreeId, options, startTime, autoYesGraceSeconds, autoYesGraceMs };
726
1243
  /**
727
1244
  * What the completion line adds when this wait held for a self-resume, or ''
728
1245
  * (Issue #2614). `basis=` keeps its word: the verdict is still the agent's own
729
1246
  * `Stop`, the hold only decided which one.
730
1247
  */
731
1248
  const selfResumeSuffix = () => {
732
- if (!selfResumeHeld)
1249
+ if (!state.selfResumeHeld)
733
1250
  return '';
734
- const total = selfResumeHeldMs + (selfResumeHold ? Date.now() - selfResumeHold.since : 0);
1251
+ const total = state.selfResumeHeldMs + (state.selfResumeHold ? Date.now() - state.selfResumeHold.since : 0);
735
1252
  return `, heldForSelfResume=${Math.round(total / 1000)}s`;
736
1253
  };
737
1254
  while (true) {
738
- // Check timeout
739
- if (options.timeout) {
740
- const elapsed = (Date.now() - startTime) / 1000;
741
- if (elapsed >= options.timeout) {
742
- console.error(`Timeout: ${worktreeId} exceeded ${options.timeout}s`);
743
- return { exitCode: types_1.WaitExitCode.TIMEOUT };
744
- }
745
- }
746
- // Check stall-timeout
747
- if (options.stallTimeout) {
748
- const stallElapsed = (Date.now() - lastActivityTime) / 1000;
749
- if (stallElapsed >= options.stallTimeout) {
750
- console.error(`Stall timeout: ${worktreeId} no output for ${options.stallTimeout}s`);
751
- return { exitCode: types_1.WaitExitCode.TIMEOUT };
752
- }
753
- }
1255
+ const deadlineOutcome = deadlineStage(poll, state);
1256
+ if (deadlineOutcome.kind === 'exit')
1257
+ return deadlineOutcome.result;
754
1258
  try {
755
1259
  // Issue #868: scope polling to a specific agent instance when provided.
756
1260
  const path = options.instance
@@ -758,12 +1262,12 @@ async function pollWorktree(client, worktreeId, options) {
758
1262
  : `/api/worktrees/${worktreeId}/current-output`;
759
1263
  const data = await client.get(path);
760
1264
  // Track content changes for stall detection
761
- if (data.content !== lastContent) {
762
- lastContent = data.content;
763
- lastActivityTime = Date.now();
1265
+ if (data.content !== state.lastContent) {
1266
+ state.lastContent = data.content;
1267
+ state.lastActivityTime = Date.now();
764
1268
  }
765
1269
  if (data.isRunning) {
766
- everRunning = true;
1270
+ state.everRunning = true;
767
1271
  }
768
1272
  // Issue #3179: the agent is still launching. Work in progress, so keep
769
1273
  // polling: no prompt or selection list is read off the launch's frame,
@@ -772,377 +1276,65 @@ async function pollWorktree(client, worktreeId, options) {
772
1276
  // launch that then fails leaves no session, which is NOT_STARTED, not a
773
1277
  // completion. The server bounds the launch, so this cannot hold forever.
774
1278
  if (typeof data.startingSince === 'number') {
775
- unclassifiedSince = null;
1279
+ state.unclassifiedSince = null;
776
1280
  await sleep(POLL_INTERVAL_MS);
777
1281
  continue;
778
1282
  }
779
1283
  // Issue #1839: done before any exit path so the turn is adopted even on a
780
1284
  // poll that ends in a prompt — the same turn is still open when the human
781
1285
  // answers and `--on-prompt human` resumes polling.
782
- turnStartedAt = adoptTurnStart(data, startTime, turnStartedAt);
1286
+ state.turnStartedAt = adoptTurnStart(data, startTime, state.turnStartedAt);
783
1287
  // Issue #2614: a self-resume hold is about one `stop`, and ends the first
784
1288
  // time that `stop` is no longer the newest word — the agent woke (a
785
1289
  // turn-opening event) or stopped again. Checked on every poll, ahead of
786
1290
  // every exit, because the wake usually lands on a `running` frame that
787
1291
  // never reaches the hold itself.
788
1292
  const selfResumeStopAt = pendingSelfResumeStop(data);
789
- if (selfResumeHold !== null && selfResumeHold.stopAt !== selfResumeStopAt) {
790
- const heldMs = Date.now() - selfResumeHold.since;
791
- selfResumeHeldMs += heldMs;
792
- selfResumeHold = null;
1293
+ if (state.selfResumeHold !== null && state.selfResumeHold.stopAt !== selfResumeStopAt) {
1294
+ const heldMs = Date.now() - state.selfResumeHold.since;
1295
+ state.selfResumeHeldMs += heldMs;
1296
+ state.selfResumeHold = null;
793
1297
  console.error(`Note: ${worktreeId} has moved past the stop it said it would resume from ` +
794
1298
  `(held ${Math.round(heldMs / 1000)}s); judging its current state.`);
795
1299
  }
796
- // Prompt detected
797
- if (data.isPromptWaiting && data.promptData) {
798
- // Issue #1699: report a policy suppression on both exits — the human one
799
- // keeps polling and would otherwise say nothing about why nobody
800
- // answered, and the agent one is read by pipelines that never see stderr.
801
- const suppressed = activeSuppression(data, Date.now());
802
- // [DR1-03] Prompt detection exit code
803
- if (options.onPrompt === 'human') {
804
- // Block and continue polling - user handles prompt manually
805
- console.error(`Prompt detected on ${worktreeId}. Waiting for human response...`);
806
- if (suppressed) {
807
- console.error(formatSuppressionNotice(suppressed.suppression, suppressed.ageSeconds));
808
- }
809
- await sleep(POLL_INTERVAL_MS);
810
- continue;
811
- }
812
- // Issue #2463: the one case `decidePromptPush()` stays quiet about —
813
- // Auto-Yes is on and has not withheld this answer — is a prompt Auto-Yes
814
- // is about to answer, and exit 10 there hands a delegation back to a
815
- // human for a dialog nobody had to see. Hold it for the grace window; a
816
- // poll that shows no prompt ends the hold below and completion is judged
817
- // as usual. A withheld answer (`suppressed`) and Auto-Yes being off are
818
- // the gate's other two branches and still exit 10 at once.
819
- if (!suppressed && data.autoYes?.enabled === true && autoYesGraceMs > 0) {
820
- const now = Date.now();
821
- if (autoYesAnsweringSince === null) {
822
- autoYesAnsweringSince = now;
823
- // stderr only: stdout is the exit-10 payload and nothing else.
824
- console.error("Prompt detected; the target's Auto-Yes is answering, waiting up to " +
825
- `${autoYesGraceSeconds}s… (${worktreeId})`);
826
- }
827
- const heldMs = now - autoYesAnsweringSince;
828
- if (heldMs < autoYesGraceMs &&
829
- nextPollWithinDeadlines(options, startTime, lastActivityTime, now)) {
830
- await sleep(POLL_INTERVAL_MS);
831
- continue;
832
- }
833
- console.error(heldMs < autoYesGraceMs
834
- ? `Note: the prompt on ${worktreeId} is still open after ${Math.round(heldMs / 1000)}s ` +
835
- 'under Auto-Yes, and the next poll would pass --timeout/--stall-timeout; reporting it now.'
836
- : `Note: the target's Auto-Yes did not answer the prompt on ${worktreeId} within ` +
837
- `${autoYesGraceSeconds}s; reporting it.`);
838
- }
839
- else if (autoYesAnsweringSince !== null && !suppressed) {
840
- console.error(`Note: Auto-Yes is no longer enabled on ${worktreeId}; reporting the prompt.`);
841
- }
842
- // Default (agent mode): output prompt info and exit 10
843
- //
844
- // Issue #1898: the degraded `unclassified` payload carries no `options`
845
- // — by construction, because nothing parsed the screen — but for a
846
- // source whose approvals are answered by decision id it does carry
847
- // `decisionOptions`, which ARE answerable (`respond <id> 1`). Reporting
848
- // an empty list there told the caller a dialog was open and gave it
849
- // nothing to do about it, which is the whole of #1898-3 seen from the
850
- // pipeline's side.
851
- const promptOptions = data.promptData.options?.length
852
- ? data.promptData.options
853
- : (data.promptData.decisionOptions ?? []);
854
- const promptOutput = {
855
- worktreeId,
856
- cliToolId: data.cliToolId || 'claude',
857
- type: data.promptData.type || 'unknown',
858
- question: data.promptData.question || '',
859
- options: promptOptions,
860
- status: data.promptData.status || 'pending',
861
- ...(data.promptData.approvalTarget !== undefined && {
862
- approvalTarget: data.promptData.approvalTarget,
863
- }),
864
- ...(suppressed && {
865
- autoYesSuppression: {
866
- reason: suppressed.suppression.reason,
867
- mode: suppressed.suppression.mode,
868
- promptType: suppressed.suppression.promptType,
869
- ...(suppressed.suppression.pattern !== undefined && {
870
- pattern: suppressed.suppression.pattern,
871
- }),
872
- ageSeconds: suppressed.ageSeconds,
873
- },
874
- }),
875
- };
876
- if (suppressed) {
877
- console.error(formatSuppressionNotice(suppressed.suppression, suppressed.ageSeconds));
878
- }
879
- return { exitCode: types_1.WaitExitCode.PROMPT_DETECTED, output: promptOutput };
1300
+ const promptOutcome = promptStage(poll, state, data);
1301
+ if (promptOutcome.kind === 'exit')
1302
+ return promptOutcome.result;
1303
+ if (promptOutcome.kind === 'wait') {
1304
+ await sleep(POLL_INTERVAL_MS);
1305
+ continue;
880
1306
  }
881
1307
  // Issue #2463: the prompt the hold was waiting on has gone. Who answered it
882
1308
  // is not on the wire — Auto-Yes, or a human at the pane — so the line says
883
1309
  // only that it cleared; what the agent does next is for the checks below.
884
- if (autoYesAnsweringSince !== null) {
1310
+ if (state.autoYesAnsweringSince !== null) {
885
1311
  console.error(`Prompt on ${worktreeId} cleared after ` +
886
- `${Math.round((Date.now() - autoYesAnsweringSince) / 1000)}s; judging completion as usual.`);
887
- autoYesAnsweringSince = null;
888
- }
889
- // Issue #1628: an arrow-key menu is the agent blocked on a human just as much
890
- // as a numbered prompt is, but it is published with isPromptWaiting=false so
891
- // the UI can render NavigationButtons instead of PromptPanel. Treat it as a
892
- // prompt here — otherwise `wait` polls a stopped agent until --timeout.
893
- if (data.isSelectionListActive) {
894
- if (options.onPrompt === 'human') {
895
- console.error(`Selection list active on ${worktreeId} (${data.sessionStatusReason ?? 'selection_list'}). ` +
896
- 'Waiting for human response...');
897
- // Issue #1699: the poller parses frames status-detector publishes as
898
- // selection lists, so a policy can be the reason this one is stuck too.
899
- const suppressed = activeSuppression(data, Date.now());
900
- if (suppressed) {
901
- console.error(formatSuppressionNotice(suppressed.suppression, suppressed.ageSeconds));
902
- }
903
- await sleep(POLL_INTERVAL_MS);
904
- continue;
905
- }
906
- return {
907
- exitCode: types_1.WaitExitCode.PROMPT_DETECTED,
908
- output: {
909
- worktreeId,
910
- cliToolId: data.cliToolId || 'claude',
911
- type: SELECTION_LIST_PROMPT_TYPE,
912
- question: data.sessionStatusReason ?? SELECTION_LIST_PROMPT_TYPE,
913
- options: [],
914
- status: 'pending',
915
- },
916
- };
917
- }
918
- // Issue #1708: the frame is interactive but nothing could parse it. The
919
- // detection layer is the single entry point every downstream safeguard
920
- // hangs off, so a frame that slips past it disables Auto-Yes, the exit-10
921
- // handoff and the contract's autoYes policy all at once — and `wait` used
922
- // to burn its whole --timeout without ever mentioning it. Treat a
923
- // PERSISTENT unclassified frame as a stop reason of its own.
924
- //
925
- // The dwell deliberately spans ALL THREE states that raise this flag, and
926
- // the completion check below is suppressed while it is up. That is the
927
- // whole point, and it is worth spelling out because the obvious reading is
928
- // the wrong one. The server's definition (`isUnclassifiedFrame` in
929
- // `src/lib/session/status-evidence.ts`, restated there by Issue #2011):
930
- //
931
- // isUnclassifiedActive =
932
- // running && (default | unknown_frame | no_recent_output)
933
- //
934
- // `no_recent_output` is there because a static unrecognised overlay
935
- // DEGRADES into it — once the Auto-Yes poller stamps
936
- // lastServerResponseTimestamp, a frame that stopped changing flips from
937
- // `running`/`default` after STALE_OUTPUT_THRESHOLD_MS (5s). `unknown_frame`
938
- // is the same floor for a tool that opts out of the generic composer check
939
- // (copilot, opencode), and says "this tool's own rules looked and read
940
- // nothing". Both arrive about twelve times faster than this dwell. Letting
941
- // the completion check claim one turned a stalled worker into `Completed`,
942
- // which is worse than the timeout Issue #1708 complained about: exit 124
943
- // stops a pipeline, exit 0 lets it merge. Measured before this guard: two
944
- // unclassified polls followed by the degraded state returned SUCCESS.
945
- //
946
- // What is deliberately NOT in the set is `ready`/`input_prompt` with
947
- // `statusEvidence: 'none'` — the agent back at its composer on a frame no
948
- // tool-specific idle rule could vouch for. That frame WAS classified; what
949
- // is missing is positive proof, which is a different question and §4 D1's
950
- // to answer. Issue #1927 folded the two together and every idle Claude pane
951
- // stopped completing (#2011). Whether `wait` should hold for evidence as
952
- // well as classification is open, and any answer belongs in the same place
953
- // as the rollout that produces the evidence — not here.
954
- if (data.isUnclassifiedActive === true) {
955
- if (unclassifiedSince === null)
956
- unclassifiedSince = Date.now();
957
- const dwellMs = Date.now() - unclassifiedSince;
958
- if (dwellMs >= UNCLASSIFIED_DWELL_MS) {
959
- const dwellSeconds = Math.round(dwellMs / 1000);
960
- const question = `Unclassified interactive frame on ${worktreeId} for ${dwellSeconds}s ` +
961
- `(status=${data.sessionStatus ?? 'unknown'}/${data.sessionStatusReason ?? 'unknown'}). ` +
962
- `The detection layer could not parse it; inspect the raw pane with ` +
963
- `\`commandmate capture ${worktreeId} --pane\`.` +
964
- // Issue #2095: the sidebar is exactly this frame's reason, and the
965
- // one recovery is a keystroke in the pane. Riding the message keeps
966
- // the exit-code table (10, `type: unclassified`) unchanged for every
967
- // caller that already branches on it.
968
- describePaneObstruction(data);
969
- if (options.onPrompt === 'human') {
970
- console.error(question);
971
- console.error('Waiting for human response...');
972
- await sleep(POLL_INTERVAL_MS);
973
- continue;
974
- }
975
- console.error(question);
976
- return {
977
- exitCode: types_1.WaitExitCode.PROMPT_DETECTED,
978
- output: {
979
- worktreeId,
980
- cliToolId: data.cliToolId || 'claude',
981
- type: UNCLASSIFIED_PROMPT_TYPE,
982
- question,
983
- options: [],
984
- status: 'pending',
985
- },
986
- };
987
- }
988
- }
989
- else {
990
- unclassifiedSince = null;
1312
+ `${Math.round((Date.now() - state.autoYesAnsweringSince) / 1000)}s; judging completion as usual.`);
1313
+ state.autoYesAnsweringSince = null;
991
1314
  }
992
- // Completion check [DR1-04]:
993
- // Path A: the tmux session went away after we had seen it alive — the agent
994
- // finished and its session was stopped.
995
- // Path B: agent completed task (sessionStatus === 'ready', input prompt detected)
996
- // Both indicate "no more work in progress" from wait command's perspective.
997
- //
998
- // Issue #1628 narrowed Path A: a session that was NEVER seen running is
999
- // "nothing to wait for" (NOT_STARTED), not a completion. See `everRunning`.
1000
- if (!data.isRunning && !everRunning) {
1001
- console.error(`Not started: ${worktreeId} has no running ${data.cliToolId ?? 'agent'} session` +
1002
- `${options.instance ? ` for instance ${options.instance}` : ''}` +
1003
- // Issue #1884: name the stage that chose the agent above. `wait` has
1004
- // no --agent to correct a mis-resolution with, so "no running claude
1005
- // session for instance opencode" was the entire evidence an operator
1006
- // got for a live agent reported as absent. `worktree-default` here
1007
- // means the instance is neither in the roster nor named after a
1008
- // tool; `client-fallback`, that the server is too old to resolve.
1009
- `${data.resolvedBy ? ` (resolvedBy=${data.resolvedBy})` : ''}.`);
1010
- return { exitCode: types_1.VerifyExitCode.NOT_STARTED };
1315
+ const selectionListOutcome = selectionListStage(poll, data);
1316
+ if (selectionListOutcome.kind === 'exit')
1317
+ return selectionListOutcome.result;
1318
+ if (selectionListOutcome.kind === 'wait') {
1319
+ await sleep(POLL_INTERVAL_MS);
1320
+ continue;
1011
1321
  }
1012
- // Issue #1708 narrowed Path B: `ready` is only a completion when the frame
1013
- // was actually understood. A structured `hook_stop` over an unreadable
1014
- // pane is the degraded form of an overlay nobody could parse (see the note
1015
- // above), and reporting it as `Completed` is how a stalled worker gets
1016
- // merged. Path A is untouched — a session that went away really is
1017
- // finished, and carries no flag anyway.
1018
- if (!data.isRunning) {
1019
- console.error(`Completed: ${worktreeId} (basis=${COMPLETION_BASIS.SESSION_GONE}${selfResumeSuffix()})`);
1020
- return { exitCode: types_1.WaitExitCode.SUCCESS };
1322
+ const unclassifiedOutcome = unclassifiedStage(poll, state, data);
1323
+ if (unclassifiedOutcome.kind === 'exit')
1324
+ return unclassifiedOutcome.result;
1325
+ if (unclassifiedOutcome.kind === 'wait') {
1326
+ await sleep(POLL_INTERVAL_MS);
1327
+ continue;
1021
1328
  }
1022
- if (data.sessionStatus === 'ready' && data.isUnclassifiedActive !== true) {
1023
- // Issue #1839: the agent is back at its composer with an upstream
1024
- // failure on the frame. Checked BEFORE the turn-boundary gate below,
1025
- // because it is the answer to the question that gate can only ask: the
1026
- // turn did not end, and this is why. Without it the same session runs
1027
- // to --timeout and reports 124, which says nothing about the cause.
1028
- const fault = data.upstreamFault ?? null;
1029
- if (options.failOnUpstreamFault && fault) {
1030
- console.error(`Upstream fault on ${worktreeId}: id=${fault.id} — the agent is back at its ` +
1031
- 'composer with an upstream API failure on screen, so this turn did not run. ' +
1032
- `Matched: ${JSON.stringify(fault.matchedText)}`);
1033
- if (fault.id === 'context-limit') {
1034
- // A retry into the same session hits the same wall (Issue #3011).
1035
- console.error('The session\'s conversation is over the model\'s context limit. Start a fresh ' +
1036
- `session and send again: commandmate instances ${worktreeId} kill ` +
1037
- `${options.instance ?? '<instance>'}`);
1038
- }
1039
- return {
1040
- exitCode: types_1.WaitExitCode.UPSTREAM_FAULT,
1041
- upstreamFault: { id: fault.id, matchedText: fault.matchedText },
1042
- };
1043
- }
1044
- // Issue #1839: `ready` off the terminal frame is the agent's composer,
1045
- // not the agent's verdict. Measured 2026-08-20 against a stub upstream
1046
- // answering 529: Claude returns to the composer ~3 s after the send
1047
- // having executed nothing, and never sends `Stop`. When this instance's
1048
- // hooks ARE reporting — the only case in which `turnStartedAt` is
1049
- // non-null — that missing `Stop` is the difference between "finished"
1050
- // and "never ran", and it is the only signal that carries it.
1051
- if (!turnSettled(data, turnStartedAt)) {
1052
- console.error(`Waiting: ${worktreeId} is back at its composer, but its agent has not reported ` +
1053
- `the end of this turn (turnStartedAt=${turnStartedAt}, ` +
1054
- `lastStopEventAt=${data.lastStopEventAt ?? 'none'}, ${describeTurnClose(data)}). ` +
1055
- 'Not reporting completion; inspect with ' +
1056
- `\`commandmate capture ${worktreeId} --json\`.`);
1057
- await sleep(POLL_INTERVAL_MS);
1058
- continue;
1059
- }
1060
- // Issue #2614: the turn did end — the agent said so — but it also said
1061
- // that work of its own is still running in the background (a `schedule`
1062
- // timer, a backgrounded command), and that work wakes it with nobody
1063
- // typing anything. Measured 2026-09-17 on antigravity 1.2.4: four such
1064
- // stops ~58 s before each self-wake, and the first one was reported as
1065
- // `Completed (basis=hook_stop)` and verified five minutes before the
1066
- // work was done. So this `stop` is held until it is no longer the newest
1067
- // word (see `selfResumeStopAt` above), or until the bound.
1068
- //
1069
- // The bound is measured from whichever is further along: the `stop`
1070
- // itself (server clock — a negative age is skew, and the max discards
1071
- // it) or this wait's first sight of it. A session that said so hours ago
1072
- // and never woke is not held again.
1073
- if (selfResumeStopAt !== null) {
1074
- const now = Date.now();
1075
- if (selfResumeHold === null)
1076
- selfResumeHold = { stopAt: selfResumeStopAt, since: now };
1077
- const heldMs = now - selfResumeHold.since;
1078
- const elapsedMs = Math.max(heldMs, now - selfResumeStopAt);
1079
- if (elapsedMs < exports.SELF_RESUME_HOLD_MS) {
1080
- selfResumeHeld = true;
1081
- console.error(`Waiting: ${worktreeId} ended its turn with background work still running ` +
1082
- `(stoppedAt=${new Date(selfResumeStopAt).toISOString()}, ` +
1083
- `lastEventDetail=${exports.SELF_RESUME_PENDING_DETAIL}, ${describeTurnClose(data)}); ` +
1084
- 'it resumes by itself when that work finishes. Not reporting completion ' +
1085
- `(held ${Math.round(heldMs / 1000)}s, at most ${exports.SELF_RESUME_HOLD_MS / 1000}s ` +
1086
- 'after the stop).');
1087
- await sleep(POLL_INTERVAL_MS);
1088
- continue;
1089
- }
1090
- console.error(`Note: ${worktreeId} said at its stop ${Math.round(elapsedMs / 1000)}s ` +
1091
- 'ago that background work was still running, and has not resumed since; ' +
1092
- 'completing on that stop.');
1093
- }
1094
- // Issue #1975: the same frame, one question further back. #1839's gate
1095
- // above can only fire once a turn has been ADOPTED, and `send` leaves a
1096
- // window ~1s wide in which nothing has been: the newest structured event
1097
- // is still the previous turn's `stop`, so `adoptTurnStart` takes nothing,
1098
- // `turnSettled` reads null as "settled", and the composer the agent has
1099
- // not touched yet is read as the composer it came back to. Measured
1100
- // 2026-08-22 against copilot 1.0.80 on an isolated server: 3 of 5
1101
- // send-then-wait runs came back in ~0.3s with `basis=scraper_ready` and
1102
- // no artefact on disk.
1103
- //
1104
- // So ask the ledger instead of the clock: has this instance been handed
1105
- // a prompt that the agent has not reported the end of? See
1106
- // {@link outstandingPrompt} for why that comparison is the one that
1107
- // separates "not started" from "finished", and
1108
- // {@link reportsTurnBoundaries} for why a tool that posts no hooks never
1109
- // reaches it.
1110
- let answeredNewestPrompt = false;
1111
- if (turnStartedAt === null && promptLedgerReadable && reportsTurnBoundaries(data)) {
1112
- const ledger = await readNewestPromptAt(client, worktreeId, options, data);
1113
- // One notice, then stop asking: a ledger that failed once will fail
1114
- // every poll, and the point of degrading is to stop paying for it.
1115
- promptLedgerReadable = ledger.readable;
1116
- if (ledger.readable && ledger.submittedAt !== null) {
1117
- if (outstandingPrompt(data, ledger.submittedAt)) {
1118
- const heldMs = Date.now() - startTime;
1119
- if (heldMs < PENDING_PROMPT_HOLD_MS) {
1120
- console.error(`Waiting: ${worktreeId} is at its composer, but the newest prompt sent to it ` +
1121
- `has no reported end (sentAt=${new Date(ledger.submittedAt).toISOString()}, ` +
1122
- `lastStopEventAt=${data.lastStopEventAt ?? 'none'}, ${describeTurnClose(data)}). ` +
1123
- 'Not reporting completion: the agent has not started this turn yet.');
1124
- await sleep(POLL_INTERVAL_MS);
1125
- continue;
1126
- }
1127
- console.error(`Note: ${worktreeId} has been at its composer for ` +
1128
- `${Math.round(heldMs / 1000)}s with the newest prompt still unreported by its ` +
1129
- 'agent. Its hooks are not answering; completing on the frame alone.');
1130
- }
1131
- else {
1132
- answeredNewestPrompt = true;
1133
- }
1134
- }
1135
- }
1136
- // `hook_stop` on both branches that have one, and they are the same
1137
- // statement made from two records: the agent reported the end of the
1138
- // turn this wait is about. `scraper_ready` keeps its documented meaning
1139
- // — "the screen said so and nothing corroborated it" — which is now
1140
- // exactly the set of cases that reach it.
1141
- const basis = turnStartedAt !== null || answeredNewestPrompt
1142
- ? COMPLETION_BASIS.HOOK_STOP
1143
- : COMPLETION_BASIS.SCRAPER_READY;
1144
- console.error(`Completed: ${worktreeId} (basis=${basis}${selfResumeSuffix()})`);
1145
- return { exitCode: types_1.WaitExitCode.SUCCESS };
1329
+ const notRunningOutcome = notRunningStage(poll, state, data, selfResumeSuffix);
1330
+ if (notRunningOutcome.kind === 'exit')
1331
+ return notRunningOutcome.result;
1332
+ const readyOutcome = await readyStage(poll, state, data, selfResumeStopAt, selfResumeSuffix);
1333
+ if (readyOutcome.kind === 'exit')
1334
+ return readyOutcome.result;
1335
+ if (readyOutcome.kind === 'wait') {
1336
+ await sleep(POLL_INTERVAL_MS);
1337
+ continue;
1146
1338
  }
1147
1339
  // Progress indicator on stderr [DR1-05]
1148
1340
  console.error(`Waiting: ${worktreeId} (status=${data.sessionStatus}, running=${data.isRunning}, prompt=${data.isPromptWaiting})`);