commandmate 0.45.1 → 0.46.1

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 (388) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +319 -315
  3. package/.next/app-path-routes-manifest.json +15 -15
  4. package/.next/build-manifest.json +5 -5
  5. package/.next/prerender-manifest.json +3 -3
  6. package/.next/react-loadable-manifest.json +4 -4
  7. package/.next/required-server-files.json +1 -1
  8. package/.next/server/app/_not-found/page.js +1 -1
  9. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  10. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/agents/update/route_client-reference-manifest.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_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  18. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/capabilities/route.js +1 -1
  20. package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  22. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  24. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  25. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  27. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  28. package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
  29. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  30. package/.next/server/app/api/hooks/claude-done/route.js +9 -9
  31. package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
  32. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
  34. package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  37. package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
  38. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  40. package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
  41. package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
  42. package/.next/server/app/api/relays/route.js.nft.json +1 -1
  43. package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
  44. package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
  45. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  46. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  47. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
  48. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  49. package/.next/server/app/api/repositories/clone/route.js +1 -1
  50. package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
  51. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  52. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  53. package/.next/server/app/api/repositories/restore/route.js +1 -1
  54. package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
  55. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/repositories/route.js +1 -1
  57. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  58. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/repositories/scan/route.js +1 -1
  60. package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
  61. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/repositories/sync/route.js +1 -1
  63. package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
  64. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  65. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  66. package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
  67. package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
  68. package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  70. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  71. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  72. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  73. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  74. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  75. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  76. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  78. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  79. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  80. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  81. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  82. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  83. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  84. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  85. package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
  86. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  87. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
  88. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
  89. package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
  90. package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
  91. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +3 -3
  93. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  94. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  95. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  96. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  97. package/.next/server/app/api/worktrees/[id]/direct-input/route.js +1 -1
  98. package/.next/server/app/api/worktrees/[id]/direct-input/route.js.nft.json +1 -1
  99. package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
  100. package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
  101. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +3 -3
  103. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  104. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  105. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  106. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  107. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  108. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  109. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  110. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  111. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  112. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  113. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  114. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  115. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  116. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  117. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  118. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  120. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  121. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  122. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  124. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  127. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
  129. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
  130. package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
  132. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  133. package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
  135. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  136. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  137. package/.next/server/app/api/worktrees/[id]/logs/route.js +9 -9
  138. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  139. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  141. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  142. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
  146. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
  148. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  149. package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
  151. package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
  152. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  153. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  154. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  155. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +3 -3
  157. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  158. package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +3 -3
  159. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/schedules/route.js +3 -3
  161. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  162. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  163. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
  164. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  165. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  166. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
  167. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  168. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  170. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  171. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  173. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  174. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  175. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  176. package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
  177. package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
  178. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  179. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  180. package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
  181. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  182. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  183. package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
  184. package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
  185. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  186. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  187. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  188. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  189. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  190. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  191. package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
  192. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  193. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
  194. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  195. package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
  196. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  197. package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
  198. package/.next/server/app/api/worktrees/route.js +1 -1
  199. package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
  200. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  201. package/.next/server/app/login/page.js +1 -1
  202. package/.next/server/app/login/page.js.nft.json +1 -1
  203. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  204. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  205. package/.next/server/app/more/page.js +1 -1
  206. package/.next/server/app/more/page.js.nft.json +1 -1
  207. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  208. package/.next/server/app/offline/page.js +1 -1
  209. package/.next/server/app/offline/page.js.nft.json +1 -1
  210. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  211. package/.next/server/app/page.js +1 -1
  212. package/.next/server/app/page.js.nft.json +1 -1
  213. package/.next/server/app/page_client-reference-manifest.js +1 -1
  214. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  215. package/.next/server/app/repositories/page.js +2 -2
  216. package/.next/server/app/repositories/page.js.nft.json +1 -1
  217. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  218. package/.next/server/app/review/page.js +1 -1
  219. package/.next/server/app/review/page.js.nft.json +1 -1
  220. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  221. package/.next/server/app/sessions/page.js +1 -1
  222. package/.next/server/app/sessions/page.js.nft.json +1 -1
  223. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  224. package/.next/server/app/skills/[skillId]/page.js +1 -1
  225. package/.next/server/app/skills/[skillId]/page.js.nft.json +1 -1
  226. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  227. package/.next/server/app/skills/installed/page.js +1 -1
  228. package/.next/server/app/skills/installed/page.js.nft.json +1 -1
  229. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  230. package/.next/server/app/skills/page.js +1 -1
  231. package/.next/server/app/skills/page.js.nft.json +1 -1
  232. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  233. package/.next/server/app/worktrees/[id]/files/[...path]/page.js +1 -1
  234. package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +1 -1
  235. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  236. package/.next/server/app/worktrees/[id]/page.js +12 -9
  237. package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
  238. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  239. package/.next/server/app/worktrees/[id]/terminal/page.js +1 -1
  240. package/.next/server/app/worktrees/[id]/terminal/page.js.nft.json +1 -1
  241. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  242. package/.next/server/app-paths-manifest.json +15 -15
  243. package/.next/server/chunks/1341.js +1 -1
  244. package/.next/server/chunks/1501.js +2 -2
  245. package/.next/server/chunks/1559.js +1 -1
  246. package/.next/server/chunks/2119.js +1 -1
  247. package/.next/server/chunks/2283.js +15 -13
  248. package/.next/server/chunks/2404.js +4 -4
  249. package/.next/server/chunks/2445.js +1 -1
  250. package/.next/server/chunks/2460.js +1 -1
  251. package/.next/server/chunks/2560.js +1 -1
  252. package/.next/server/chunks/2908.js +1 -1
  253. package/.next/server/chunks/2984.js +25 -0
  254. package/.next/server/chunks/3543.js +1 -1
  255. package/.next/server/chunks/3945.js +1 -1
  256. package/.next/server/chunks/4072.js +15 -0
  257. package/.next/server/chunks/4207.js +1 -1
  258. package/.next/server/chunks/4718.js +3 -3
  259. package/.next/server/chunks/4837.js +3 -3
  260. package/.next/server/chunks/5209.js +1 -1
  261. package/.next/server/chunks/5292.js +2 -2
  262. package/.next/server/chunks/5845.js +1 -1
  263. package/.next/server/chunks/6130.js +1 -1
  264. package/.next/server/chunks/6345.js +1 -0
  265. package/.next/server/chunks/6401.js +1 -1
  266. package/.next/server/chunks/6722.js +1 -0
  267. package/.next/server/chunks/8098.js +1 -1
  268. package/.next/server/chunks/8356.js +1 -1
  269. package/.next/server/chunks/8581.js +25 -29
  270. package/.next/server/chunks/8728.js +2 -2
  271. package/.next/server/chunks/8791.js +1 -1
  272. package/.next/server/chunks/8800.js +4 -4
  273. package/.next/server/chunks/8918.js +5 -5
  274. package/.next/server/chunks/9390.js +1 -1
  275. package/.next/server/chunks/9627.js +2 -1
  276. package/.next/server/chunks/9731.js +1 -1
  277. package/.next/server/middleware-build-manifest.js +1 -1
  278. package/.next/server/middleware-manifest.json +5 -5
  279. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  280. package/.next/server/pages/500.html +1 -1
  281. package/.next/server/pages/_error.js +2 -2
  282. package/.next/server/server-reference-manifest.json +1 -1
  283. package/.next/static/chunks/{2407-86890b00eeecf391.js → 2407-9703c569370b8a9d.js} +1 -1
  284. package/.next/static/chunks/{2619-a305ad4810f1393a.js → 2619-04bc32f026a0d946.js} +1 -1
  285. package/.next/static/chunks/2717.1583400c272dc1d9.js +1 -0
  286. package/.next/static/chunks/2770-db80aedf6384d594.js +1 -0
  287. package/.next/static/chunks/2863-6a07ec82fb52f4dd.js +1 -0
  288. package/.next/static/chunks/3201-c01f1feed69020e6.js +1 -0
  289. package/.next/static/chunks/4768-ad6f82f034f21eae.js +1 -0
  290. package/.next/static/chunks/5371-0dc947683e46e78c.js +1 -0
  291. package/.next/static/chunks/5794-4eee51ff1e878aa6.js +1 -0
  292. package/.next/static/chunks/5927-54315d21f323e204.js +1 -0
  293. package/.next/static/chunks/602-25e45a2422d2a3ea.js +1 -0
  294. package/.next/static/chunks/6606-02ddc006686a6b7d.js +1 -0
  295. package/.next/static/chunks/6654-f3534f35f16644bc.js +1 -0
  296. package/.next/static/chunks/7730-011e137be64403ae.js +1 -0
  297. package/.next/static/chunks/8165-263172c17ae8e8c3.js +1 -0
  298. package/.next/static/chunks/{8407-9a72e6f07c5d5458.js → 8407-155f84e5ba05f1d5.js} +1 -1
  299. package/.next/static/chunks/8606-cf6bdbff44a764cf.js +1 -0
  300. package/.next/static/chunks/934-a37509667baa86ee.js +1 -0
  301. package/.next/static/chunks/9465-e5a351baa941f31b.js +1 -0
  302. package/.next/static/chunks/app/layout-3e357690446cd2da.js +1 -0
  303. package/.next/static/chunks/app/repositories/page-71f5a5ac29b0370d.js +1 -0
  304. package/.next/static/chunks/app/review/page-e2fd4a590646a2d8.js +1 -0
  305. package/.next/static/chunks/app/sessions/page-9859ed61e93e6890.js +1 -0
  306. package/.next/static/chunks/app/skills/[skillId]/page-52ba58712faf3378.js +1 -0
  307. package/.next/static/chunks/app/worktrees/[id]/page-effbf0796881dd5a.js +1 -0
  308. package/.next/static/chunks/app/worktrees/[id]/terminal/{page-c601f3b3ece6557e.js → page-373ea37b16d930c7.js} +1 -1
  309. package/.next/static/chunks/{webpack-ee3ccbe378c4aa06.js → webpack-468b7b33030234b3.js} +1 -1
  310. package/.next/static/css/743f79ff19ab91e9.css +1 -0
  311. package/.next/trace +13 -13
  312. package/dist/cli/commands/wait.d.ts.map +1 -1
  313. package/dist/cli/commands/wait.js +6 -1
  314. package/dist/cli/types/api-responses.d.ts +8 -6
  315. package/dist/cli/types/api-responses.d.ts.map +1 -1
  316. package/dist/lib/polling/auto-yes-suppression-reason.d.ts +13 -1
  317. package/dist/lib/polling/auto-yes-suppression-reason.d.ts.map +1 -1
  318. package/dist/lib/polling/auto-yes-suppression-reason.js +3 -0
  319. package/dist/server/locales/en/worktree.json +46 -16
  320. package/dist/server/locales/ja/worktree.json +46 -16
  321. package/dist/server/src/config/activity-bar-config.js +56 -9
  322. package/dist/server/src/lib/assistant-response-saver.js +13 -0
  323. package/dist/server/src/lib/auto-yes-poller.js +252 -54
  324. package/dist/server/src/lib/conversation-logger.js +14 -2
  325. package/dist/server/src/lib/db/chat-db.js +2 -1
  326. package/dist/server/src/lib/history/user-turn-recorder.js +14 -0
  327. package/dist/server/src/lib/hooks/sources/antigravity/history.js +28 -0
  328. package/dist/server/src/lib/hooks/sources/claude/history.js +7 -0
  329. package/dist/server/src/lib/hooks/sources/codex/history.js +7 -0
  330. package/dist/server/src/lib/hooks/sources/command-code/history.js +7 -0
  331. package/dist/server/src/lib/hooks/sources/transcript-history.js +34 -0
  332. package/dist/server/src/lib/log-manager.js +7 -2
  333. package/dist/server/src/lib/polling/auto-yes-enter-fallback-state.js +22 -3
  334. package/dist/server/src/lib/polling/auto-yes-poller-state.js +234 -0
  335. package/dist/server/src/lib/polling/auto-yes-suppression-reason.js +3 -0
  336. package/dist/server/src/lib/polling/pending-scraped-response.js +119 -3
  337. package/dist/server/src/lib/polling/poller-owner.js +110 -0
  338. package/dist/server/src/lib/polling/prompt-dedup-state.js +26 -7
  339. package/dist/server/src/lib/polling/prompt-dedup.js +50 -22
  340. package/dist/server/src/lib/polling/response-checker.js +212 -36
  341. package/dist/server/src/lib/polling/response-dedup.js +112 -20
  342. package/dist/server/src/lib/polling/response-poller-core.js +178 -38
  343. package/dist/server/src/lib/polling/structured-history-gate.js +20 -1
  344. package/dist/server/src/lib/prompt-answer-sender.js +59 -12
  345. package/dist/server/src/lib/realtime/terminal-broadcast.js +14 -0
  346. package/dist/server/src/lib/session/chat-turn-progress.js +57 -6
  347. package/dist/server/src/lib/session/current-output-builder.js +19 -0
  348. package/dist/server/src/lib/session/next-action-helper.js +2 -15
  349. package/dist/server/src/lib/session/worktree-session-reconcile.js +83 -10
  350. package/dist/server/src/lib/timer-manager.js +7 -0
  351. package/dist/server/src/lib/tmux/tmux.js +24 -2
  352. package/dist/server/src/lib/verification/env-clean-gate.js +41 -0
  353. package/dist/server/src/lib/verification/gate-runner.js +17 -11
  354. package/dist/server/src/lib/verification/scope-gate.js +169 -3
  355. package/dist/server/src/types/sidebar.js +1 -0
  356. package/docs/en/architecture.md +26 -14
  357. package/docs/en/user-guide/webapp-guide.md +31 -18
  358. package/package.json +1 -1
  359. package/release-notes/0.46.0.json +110 -0
  360. package/release-notes/0.46.1.json +40 -0
  361. package/.next/server/chunks/1674.js +0 -15
  362. package/.next/server/chunks/5625.js +0 -25
  363. package/.next/server/chunks/6927.js +0 -1
  364. package/.next/server/chunks/9355.js +0 -1
  365. package/.next/static/chunks/1642-0f1bf8fb8161e10a.js +0 -1
  366. package/.next/static/chunks/2770-827a64760bab8a3a.js +0 -1
  367. package/.next/static/chunks/3922.0bc2e4e168d2b522.js +0 -1
  368. package/.next/static/chunks/4727-4c69d1aa4118cc09.js +0 -1
  369. package/.next/static/chunks/4768-fc0aa1d0891cac08.js +0 -1
  370. package/.next/static/chunks/5371-af1c2b68e983da61.js +0 -1
  371. package/.next/static/chunks/5521-c358c31f60e5e689.js +0 -1
  372. package/.next/static/chunks/6192-a67df090838b9aad.js +0 -1
  373. package/.next/static/chunks/6322-f1b30ed0ee43518f.js +0 -1
  374. package/.next/static/chunks/6654-ac431270fac1a283.js +0 -1
  375. package/.next/static/chunks/8165-3525fb42f1b4976e.js +0 -1
  376. package/.next/static/chunks/8318-01e7d1e5ad0a15a3.js +0 -1
  377. package/.next/static/chunks/8606-79c36d4c204bbd38.js +0 -1
  378. package/.next/static/chunks/9619-6c17a271f7f98fbb.js +0 -1
  379. package/.next/static/chunks/998-2eb5883186abd0bd.js +0 -1
  380. package/.next/static/chunks/app/layout-eaa6365f8f942e88.js +0 -1
  381. package/.next/static/chunks/app/repositories/page-6f7511f4ac8449e2.js +0 -1
  382. package/.next/static/chunks/app/review/page-95f749caae382f46.js +0 -1
  383. package/.next/static/chunks/app/sessions/page-ebfed2c80e916fb8.js +0 -1
  384. package/.next/static/chunks/app/skills/[skillId]/page-e4b14031f946c007.js +0 -1
  385. package/.next/static/chunks/app/worktrees/[id]/page-3372b78fde232b1f.js +0 -1
  386. package/.next/static/css/6faeb04a0b6819d4.css +0 -1
  387. /package/.next/static/{vYIpFRCU_Mt0wtG8F_3-6 → QxDf7lm-JJkWoj-TyWiSB}/_buildManifest.js +0 -0
  388. /package/.next/static/{vYIpFRCU_Mt0wtG8F_3-6 → QxDf7lm-JJkWoj-TyWiSB}/_ssgManifest.js +0 -0
@@ -9,13 +9,17 @@ exports.stopPolling = stopPolling;
9
9
  exports.stopAllPolling = stopAllPolling;
10
10
  exports.getActivePollers = getActivePollers;
11
11
  exports.migrateResponsePollerWorktreeIds = migrateResponsePollerWorktreeIds;
12
- const async_hooks_1 = require("async_hooks");
13
12
  const logger_1 = require("../../lib/logger");
14
13
  const tui_accumulator_1 = require("../tui-accumulator");
15
14
  const prompt_dedup_1 = require("./prompt-dedup");
16
15
  const response_dedup_1 = require("./response-dedup");
17
16
  const prompt_dedup_state_1 = require("./prompt-dedup-state");
18
17
  const response_checker_1 = require("./response-checker");
18
+ // Issue #3663: the migration's own entry points into the held-scrape store,
19
+ // imported from the store itself rather than through `./response-checker`'s
20
+ // re-export (suites that replace the checker by path keep working unchanged).
21
+ const pending_scraped_response_1 = require("./pending-scraped-response");
22
+ const poller_owner_1 = require("./poller-owner");
19
23
  const terminal_broadcast_1 = require("../../lib/realtime/terminal-broadcast");
20
24
  const terminal_session_ownership_1 = require("../../lib/realtime/terminal-session-ownership");
21
25
  const session_name_1 = require("../../lib/cli-tools/session-name");
@@ -58,7 +62,7 @@ const coordinator = (0, global_state_1.getOrInitGlobal)('__responsePollerCoordin
58
62
  owners: new Map(),
59
63
  running: new Map(),
60
64
  pendingRestart: new Map(),
61
- ownerStorage: new async_hooks_1.AsyncLocalStorage(),
65
+ latestOwners: new Map(),
62
66
  generationCounter: 0,
63
67
  pausedOnPrompt: new Set(),
64
68
  }));
@@ -68,6 +72,7 @@ const coordinator = (0, global_state_1.getOrInitGlobal)('__responsePollerCoordin
68
72
  // `globalThis` across HMR, and a poller started before the reload would
69
73
  // otherwise crash the first tick after it.
70
74
  coordinator.pausedOnPrompt ??= new Set();
75
+ coordinator.latestOwners ??= new Map();
71
76
  /**
72
77
  * Active pollers map: "worktreeId:instanceId" -> NodeJS.Timeout
73
78
  *
@@ -101,11 +106,17 @@ exports.pollingStartTimes = coordinator.pollingStartTimes;
101
106
  * @param instanceId - Optional agent instance ID (defaults to cliToolId)
102
107
  */
103
108
  function getPollerKey(worktreeId, cliToolId, instanceId) {
104
- return `${worktreeId}:${instanceId ?? cliToolId}`;
109
+ // Issue #3705: spelled in `./poller-owner`, so the writers that ask whether a
110
+ // tick may still act for this key name it the same way without importing here.
111
+ return (0, poller_owner_1.pollerKeyOf)(worktreeId, cliToolId, instanceId);
105
112
  }
106
113
  /** Hand `pollerKey` to a brand-new chain, retiring whichever chain held it. */
107
114
  function takeOwnership(pollerKey) {
108
- const previous = coordinator.owners.get(pollerKey);
115
+ // Issue #3705: the newest chain the key ever had, not only the one holding it
116
+ // now. A chain that was stopped (a route, a migration that displaced it) has
117
+ // left `owners`, but a tick of it may still be in flight, and it has a
118
+ // successor from this moment on.
119
+ const previous = coordinator.owners.get(pollerKey) ?? coordinator.latestOwners.get(pollerKey);
109
120
  if (previous)
110
121
  previous.superseded = true;
111
122
  const owner = {
@@ -116,6 +127,7 @@ function takeOwnership(pollerKey) {
116
127
  selfStopped: false,
117
128
  };
118
129
  coordinator.owners.set(pollerKey, owner);
130
+ coordinator.latestOwners.set(pollerKey, owner);
119
131
  return owner;
120
132
  }
121
133
  /**
@@ -171,7 +183,7 @@ function startPolling(worktreeId, cliToolId, instanceId) {
171
183
  // previous turn.
172
184
  inFlight.owner.superseded = true;
173
185
  if (Date.now() - inFlight.since < exports.STALLED_TICK_TIMEOUT) {
174
- coordinator.pendingRestart.set(pollerKey, target);
186
+ coordinator.pendingRestart.set(pollerKey, { target, behind: inFlight.owner });
175
187
  return;
176
188
  }
177
189
  logger.warn('poller:restart-past-stalled-tick', {
@@ -293,7 +305,11 @@ async function runPollTick(target, owner) {
293
305
  // Check for response
294
306
  let recorded = false;
295
307
  try {
296
- recorded = await coordinator.ownerStorage.run(owner, () => (0, response_checker_1.checkForResponse)(target.worktreeId, target.cliToolId, target.instanceId));
308
+ // The token rides through `checkForResponse()` (`./poller-owner`), so a
309
+ // `stopPolling()` raised inside a superseded tick can be told apart from
310
+ // one raised by a route, `session-cleanup` or `kill-session` (#2223), and
311
+ // the held-scrape store can turn away a tick that was retired (#3663).
312
+ recorded = await poller_owner_1.pollerOwnerStorage.run(owner, () => (0, response_checker_1.checkForResponse)(target.worktreeId, target.cliToolId, target.instanceId));
297
313
  }
298
314
  catch (error) {
299
315
  logger.error('error:', { error: error instanceof Error ? error.message : String(error) });
@@ -310,8 +326,14 @@ async function runPollTick(target, owner) {
310
326
  // Issue #2223: skipped once another chain owns the key — a superseded tick
311
327
  // would push the previous turn's screen on top of the live one, and its
312
328
  // `version` counter would make the client drop the real frame that follows.
329
+ //
330
+ // Issue #3705: and the snapshot carries the owner explicitly
331
+ // (`snapshotOwnerStorage`), because this is only where it starts. Its
332
+ // capture and the writers inside `buildCurrentOutput` resume after awaits,
333
+ // and they ask again then (`maySnapshotPublish`): a successor that took the
334
+ // key in the meantime is not overwritten by the turn that ended.
313
335
  if (!owner.superseded) {
314
- void (0, terminal_broadcast_1.broadcastTerminalSnapshot)(target.worktreeId, target.cliToolId, target.instanceId);
336
+ void poller_owner_1.snapshotOwnerStorage.run(owner, () => (0, terminal_broadcast_1.broadcastTerminalSnapshot)(target.worktreeId, target.cliToolId, target.instanceId));
315
337
  }
316
338
  // Schedule next poll ONLY after current one completes
317
339
  // Guard: only if THIS chain is still the poller for the key (Issue #2223)
@@ -326,10 +348,15 @@ async function runPollTick(target, owner) {
326
348
  // Apply a restart that arrived while this tick was in flight. Doing it here
327
349
  // rather than in startPolling() is what keeps the old and new chains from
328
350
  // polling the same pane at the same time.
351
+ //
352
+ // Issue #3705: only the restart handed to THIS tick. One queued behind a
353
+ // later chain's tick belongs to that tick: applied here, by a tick that was
354
+ // cut loose past STALLED_TICK_TIMEOUT and came back, it would stop the chain
355
+ // whose tick is still running and start the next one beside it.
329
356
  const pending = coordinator.pendingRestart.get(pollerKey);
330
- if (pending) {
357
+ if (pending && pending.behind === owner) {
331
358
  coordinator.pendingRestart.delete(pollerKey);
332
- restartChain(pollerKey, pending);
359
+ restartChain(pollerKey, pending.target);
333
360
  }
334
361
  }
335
362
  }
@@ -391,7 +418,7 @@ function stopPollingByKey(pollerKey, options = {}) {
391
418
  // (worktree gone, session not running, prompt detected, TUI reply saved).
392
419
  // Honouring that verdict would kill the chain that replaced it — the old
393
420
  // tick is describing a turn that is already over.
394
- const caller = coordinator.ownerStorage.getStore();
421
+ const caller = poller_owner_1.pollerOwnerStorage.getStore();
395
422
  if (caller && caller.pollerKey === pollerKey && (caller.superseded || caller.stopped)) {
396
423
  logger.info('poller:stale-stop-ignored', {
397
424
  pollerKey,
@@ -532,8 +559,23 @@ function splitPollerKey(pollerKey) {
532
559
  * one in-flight TUI response may be truncated at the rename boundary; the next
533
560
  * turn accumulates normally.
534
561
  *
535
- * Takes the whole batch because IDs can swap (A→B, B→A): every source key is
536
- * removed before any destination key is written.
562
+ * Takes the whole batch because IDs can swap (A→B, B→A) or chain (A→B→C):
563
+ * every source key is removed before any destination key is written. That
564
+ * includes the dedup state (Issue #3553) — of running pollers and paused chains
565
+ * alike — which is lifted off every source key in one pass and only then
566
+ * written, so a pair handled early cannot overwrite a source handled later.
567
+ *
568
+ * Issue #3663: the held scrapes (#2436) move too, by the same lift-then-place
569
+ * rule, keeping everything but their worktree ID, which becomes the new one.
570
+ * Every chain whose key changes hands is retired (`stopped`), so a tick still
571
+ * awaiting the transcript reader cannot come back and hold, drop or write
572
+ * under it: the moved chains' old owners, and a chain already running on a
573
+ * destination key that no source vacates — that one is stopped like any
574
+ * other, which writes its held scrape under the ID it carries before the moved
575
+ * one arrives. A chain that cannot be resolved has its held scrape written
576
+ * under the NEW ID: the old one is gone from the table, and a row for it fails
577
+ * the foreign key and is lost. A chain with a tick running at the moment of
578
+ * the migration does not hand its response hash on (see the dedup move below).
537
579
  *
538
580
  * @param renames - Worktree ID pairs being applied
539
581
  * @param resolveCliToolId - Maps a poller's (worktree, instance) back to its CLI
@@ -562,7 +604,7 @@ function migrateResponsePollerWorktreeIds(renames, resolveCliToolId) {
562
604
  continue;
563
605
  const cliToolId = resolveCliToolId(parts.worktreeId, parts.instanceId);
564
606
  if (!cliToolId) {
565
- abandoned.push(pollerKey);
607
+ abandoned.push({ pollerKey, newWorktreeId });
566
608
  continue;
567
609
  }
568
610
  moves.push({
@@ -576,6 +618,16 @@ function migrateResponsePollerWorktreeIds(renames, resolveCliToolId) {
576
618
  // Phase 1: stop every affected timer and lift the state off the old keys.
577
619
  // Done for the whole batch before any write so a swap cannot self-collide.
578
620
  const carried = new Map();
621
+ // Issue #3663: the moves whose chain has a tick running right now — read
622
+ // before anything below touches the coordinator. See the response hash below.
623
+ // The chain that holds the key now, not merely some tick under the key: a
624
+ // chain retired earlier leaves its `running` entry until its own tick
625
+ // returns (the epilogue removes it by owner), and the chain that replaced it
626
+ // may not have started a tick yet.
627
+ const midTick = moves.filter((move) => {
628
+ const inFlight = coordinator.running.get(move.oldKey);
629
+ return inFlight !== undefined && inFlight.owner === coordinator.owners.get(move.oldKey);
630
+ });
579
631
  for (const move of moves) {
580
632
  const timerId = exports.activePollers.get(move.oldKey);
581
633
  if (timerId)
@@ -596,33 +648,26 @@ function migrateResponsePollerWorktreeIds(renames, resolveCliToolId) {
596
648
  coordinator.pendingRestart.delete(move.oldKey);
597
649
  carried.set(move.newKey, { startedAt: exports.pollingStartTimes.get(move.oldKey) });
598
650
  exports.pollingStartTimes.delete(move.oldKey);
599
- (0, prompt_dedup_1.renamePromptHashCacheKey)(move.oldKey, move.newKey);
600
- (0, response_dedup_1.renameResponseHashCacheKey)(move.oldKey, move.newKey);
601
- // Issue #1695: the prompt hash moved on the line above, so the guard keeps
602
- // suppressing the prompt on screen under the new ID. Its tally has to move
603
- // with it, or `capture --json` reports zero skips for a session that is
604
- // still skipping. Old worktree ID comes back out of the key we just left.
605
- const movedFrom = splitPollerKey(move.oldKey);
606
- if (movedFrom) {
607
- (0, prompt_dedup_state_1.renamePromptDedupSkips)(movedFrom.worktreeId, move.newWorktreeId, move.cliToolId, move.instanceId);
608
- }
609
651
  (0, tui_accumulator_1.clearTuiAccumulator)(move.oldKey);
610
652
  }
611
- for (const pollerKey of abandoned) {
653
+ // Stop the abandoned pollers before any dedup state is written: the stop
654
+ // clears every cache under its key, and that key can be the destination of
655
+ // another move in this batch (A:x paused → B:x while B:x is abandoned).
656
+ // Stopped afterwards, it erased the state that had just arrived (#3553).
657
+ // An abandoned key is never a move source, so nothing still to be moved is
658
+ // lost here; and the paused chains are collected after it, as before, so a
659
+ // pause the stop ends is not carried.
660
+ //
661
+ // Issue #3663: its held scrape is pointed at the new ID first, so the stop
662
+ // writes it there — the old ID is no longer in the table.
663
+ for (const { pollerKey, newWorktreeId } of abandoned) {
664
+ (0, pending_scraped_response_1.retargetPendingScrapedResponse)(pollerKey, newWorktreeId);
612
665
  stopPollingByKey(pollerKey);
613
666
  logger.warn('poller:migrate-abandoned', { pollerKey });
614
667
  }
615
- // Phase 2: restart each poller under its new identity.
616
- for (const move of moves) {
617
- const startedAt = carried.get(move.newKey)?.startedAt;
618
- exports.pollingStartTimes.set(move.newKey, startedAt ?? Date.now());
619
- if (isFullScreenTui(move.cliToolId)) {
620
- (0, tui_accumulator_1.initTuiAccumulator)(move.newKey);
621
- }
622
- scheduleNextResponsePoll(move.newWorktreeId, move.cliToolId, move.instanceId);
623
- }
624
- // Issue #2230: a chain paused on a prompt has no timer, so the loop above
625
- // never sees it — but it is holding the response hash for the turn it paused
668
+ const abandonedKeys = new Set(abandoned.map(({ pollerKey }) => pollerKey));
669
+ // Issue #2230: a chain paused on a prompt has no timer, so the loops here
670
+ // never see it — but it is holding the response hash for the turn it paused
626
671
  // on, and `/respond` will resume it under the NEW ID. Move the hash and the
627
672
  // pause mark with it; the chain itself stays paused until that resume.
628
673
  const pausedMoves = [];
@@ -635,11 +680,106 @@ function migrateResponsePollerWorktreeIds(renames, resolveCliToolId) {
635
680
  continue;
636
681
  pausedMoves.push({ oldKey: pollerKey, newKey: `${newWorktreeId}:${parts.instanceId}` });
637
682
  }
683
+ // Issue #3663: every held scrape under a renamed worktree ID moves — a
684
+ // running chain's, a paused chain's, and one whose chain is already gone.
685
+ // The abandoned ones were written above and are no longer held.
686
+ const pendingMoves = [];
687
+ for (const pollerKey of (0, pending_scraped_response_1.listPendingScrapedResponseKeys)()) {
688
+ if (abandonedKeys.has(pollerKey))
689
+ continue;
690
+ const parts = splitPollerKey(pollerKey);
691
+ if (!parts)
692
+ continue;
693
+ const newWorktreeId = targets.get(parts.worktreeId);
694
+ if (!newWorktreeId)
695
+ continue;
696
+ pendingMoves.push({ oldKey: pollerKey, newKey: `${newWorktreeId}:${parts.instanceId}`, newWorktreeId });
697
+ }
698
+ // Issue #3663: a destination a chain (running or paused) moves onto, that no
699
+ // source of this batch vacates, may already be held by another chain — B:x
700
+ // running while A:x moves to B:x. That chain loses the key, so it is stopped
701
+ // here like any other stop: its held scrape is written under the ID it
702
+ // carries (the current one), its owner is retired so its in-flight tick can
703
+ // no longer hold or drop anything, and its caches are cleared before the
704
+ // moved state is written. A destination nothing is on is left alone, and so
705
+ // is every other instance of the destination worktree.
706
+ const vacated = new Set([
707
+ ...moves.map((move) => move.oldKey),
708
+ ...pausedMoves.map((move) => move.oldKey),
709
+ ...pendingMoves.map((move) => move.oldKey),
710
+ ]);
711
+ // A held scrape moved on its own (no chain, no pause) changes the key's
712
+ // owner just the same, so its destination is handled alike (#3663 review).
713
+ const occupied = new Set([
714
+ ...moves.map((move) => move.newKey),
715
+ ...pausedMoves.map((move) => move.newKey),
716
+ ...pendingMoves.map((move) => move.newKey),
717
+ ]);
718
+ for (const pollerKey of occupied) {
719
+ if (vacated.has(pollerKey) || abandonedKeys.has(pollerKey))
720
+ continue;
721
+ const held = coordinator.owners.has(pollerKey) ||
722
+ exports.activePollers.has(pollerKey) ||
723
+ coordinator.pausedOnPrompt.has(pollerKey) ||
724
+ (0, pending_scraped_response_1.hasPendingScrapedResponse)(pollerKey);
725
+ if (!held)
726
+ continue;
727
+ stopPollingByKey(pollerKey);
728
+ logger.warn('poller:migrate-displaced', { pollerKey });
729
+ }
730
+ // Issue #3553: the dedup state of the whole batch moves in one call per map
731
+ // family, each lifting every source before writing any destination. Re-keyed
732
+ // pair by pair, a swap left A with its own state and B empty.
733
+ //
734
+ // Issue #3663: except the response hash of a chain whose tick is running.
735
+ // That tick may have registered the hash of a reply it has not yet saved or
736
+ // held — it is awaiting the transcript reader, and the hold it comes back
737
+ // with is refused (its owner is retired above). Handed on, the hash would
738
+ // make the successor skip a reply nobody wrote. Dropped, the successor judges
739
+ // the screen itself and holds or saves it. The price, taken knowingly: a
740
+ // reply that tick HAD already saved may be saved once more by the successor
741
+ // — a duplicate row rather than a lost one, the trade #2436 makes. Deciding
742
+ // here, once, replaces marking the hash and taking it back later, whose
743
+ // lifetime every later move, resume and restart would have to carry.
744
+ // The prompt hash and the prompt-skip tally move as before.
745
+ // Dropped on the source key only, before the batch moves: the destination is
746
+ // left as the batch leaves it, so what another source of a many-to-one move
747
+ // brings there (a chain that saved its reply and is waiting) still stands.
748
+ for (const move of midTick)
749
+ (0, response_dedup_1.clearResponseHashCache)(move.oldKey);
750
+ (0, prompt_dedup_1.renamePromptHashCacheKeys)(moves);
751
+ (0, response_dedup_1.renameResponseHashCacheKeys)([...moves, ...pausedMoves]);
752
+ (0, pending_scraped_response_1.movePendingScrapedResponses)(pendingMoves);
753
+ // Issue #1695: the prompt hash moved above, so the guard keeps suppressing
754
+ // the prompt on screen under the new ID. Its tally has to move with it, or
755
+ // `capture --json` reports zero skips for a session that is still skipping.
756
+ // Old worktree ID comes back out of the key being left.
757
+ (0, prompt_dedup_state_1.renamePromptDedupSkipsBatch)(moves.flatMap((move) => {
758
+ const movedFrom = splitPollerKey(move.oldKey);
759
+ return movedFrom
760
+ ? [{
761
+ oldWorktreeId: movedFrom.worktreeId,
762
+ newWorktreeId: move.newWorktreeId,
763
+ cliToolId: move.cliToolId,
764
+ instanceId: move.instanceId,
765
+ }]
766
+ : [];
767
+ }));
768
+ // Phase 2: restart each poller under its new identity.
769
+ for (const move of moves) {
770
+ const startedAt = carried.get(move.newKey)?.startedAt;
771
+ exports.pollingStartTimes.set(move.newKey, startedAt ?? Date.now());
772
+ if (isFullScreenTui(move.cliToolId)) {
773
+ (0, tui_accumulator_1.initTuiAccumulator)(move.newKey);
774
+ }
775
+ scheduleNextResponsePoll(move.newWorktreeId, move.cliToolId, move.instanceId);
776
+ }
777
+ // Issue #2230: the pause marks of the chains collected above follow their
778
+ // hashes (moved with the batch). All removed before any is added, for the
779
+ // same swap reason.
638
780
  for (const move of pausedMoves)
639
781
  coordinator.pausedOnPrompt.delete(move.oldKey);
640
- for (const move of pausedMoves) {
641
- (0, response_dedup_1.renameResponseHashCacheKey)(move.oldKey, move.newKey);
782
+ for (const move of pausedMoves)
642
783
  coordinator.pausedOnPrompt.add(move.newKey);
643
- }
644
784
  return moves;
645
785
  }
@@ -84,6 +84,7 @@ const tool_id_4 = require("../../lib/hooks/sources/command-code/tool-id");
84
84
  const registry_1 = require("../../lib/hooks/sources/registry");
85
85
  const relay_triggers_1 = require("../../lib/relay/relay-triggers");
86
86
  const global_state_1 = require("../global-state");
87
+ const poller_owner_1 = require("./poller-owner");
87
88
  const logger = (0, logger_1.createLogger)('lib/polling/structured-history-gate');
88
89
  /**
89
90
  * One in-flight capture per instance (Issue #2246).
@@ -382,7 +383,25 @@ async function captureStructuredHistoryTurn(worktreeId, cliToolId, instanceId, c
382
383
  // back. So a provisional capture announces nothing at all; the relay
383
384
  // keeps waiting on the deadline it already has, and the settled capture
384
385
  // that follows announces the finished body.
385
- if (captured && completion === 'settled') {
386
+ //
387
+ // Issue #3701: a poller tick retired while it awaited the reader
388
+ // announces nothing under the key it lost, and claims nothing, so its
389
+ // successor still announces this completion. Asked by the poller key
390
+ // (`getPollerKey`'s `worktreeId:instanceId`), not `captureKey`. The
391
+ // Stop hook runs outside any tick and is never refused. Issue #3705:
392
+ // what the reader itself writes during the `await` (rows, user rows,
393
+ // the cursor, agy's follow list) is asked the same question by the
394
+ // reader, after its own last `await` (`mayReaderWrite`).
395
+ const pollerKey = (0, poller_owner_1.pollerKeyOf)(worktreeId, cliToolId, resolvedInstanceId);
396
+ if (captured && completion === 'settled' && !(0, poller_owner_1.mayActForPollerKey)(pollerKey)) {
397
+ logger.info('structured-history-completion-refused', {
398
+ worktreeId,
399
+ cliToolId,
400
+ instanceId: resolvedInstanceId,
401
+ generation: (0, poller_owner_1.currentPollerOwner)()?.generation,
402
+ });
403
+ }
404
+ else if (captured && completion === 'settled') {
386
405
  if (claimCompletionAnnouncement(captureKey, readerReport.completionKey)) {
387
406
  (0, relay_triggers_1.onRelayTurnCompleted)(worktreeId, cliToolId, resolvedInstanceId, true);
388
407
  }
@@ -7,7 +7,7 @@
7
7
  * the promptType/defaultOptionNumber fallback introduced in Bug1).
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.MultiSelectAnswerRejectedError = exports.MULTI_SELECT_NOT_COMMITTED_REASON = exports.FreeTextAtChoiceOnlyPromptError = exports.FreeTextAnswerRejectedError = exports.FREE_TEXT_AT_MENU_ROW_REASON = exports.PromptAnswerRejectedError = exports.ANSWER_MODE_KEYS_REASON = void 0;
10
+ exports.PromptAnswerAbortedError = exports.MultiSelectAnswerRejectedError = exports.MULTI_SELECT_NOT_COMMITTED_REASON = exports.FreeTextAtChoiceOnlyPromptError = exports.FreeTextAnswerRejectedError = exports.FREE_TEXT_AT_MENU_ROW_REASON = exports.PromptAnswerRejectedError = exports.ANSWER_MODE_KEYS_REASON = void 0;
11
11
  exports.sendPromptAnswer = sendPromptAnswer;
12
12
  const tmux_1 = require("./tmux/tmux");
13
13
  const frame_1 = require("../lib/detection/tools/frame");
@@ -665,7 +665,7 @@ async function recaptureAfterKeys(sessionName) {
665
665
  * @throws {MultiSelectAnswerRejectedError} whenever the question was not
666
666
  * committed; `keysSent` says whether the pane was touched.
667
667
  */
668
- async function sendCommandCodeMultiSelectAnswer(sessionName, promptData, wanted) {
668
+ async function sendCommandCodeMultiSelectAnswer(sessionName, promptData, wanted, stillCurrent) {
669
669
  const cursor = promptData.options.find((option) => option.isDefault === true);
670
670
  if (cursor === undefined) {
671
671
  throw new MultiSelectAnswerRejectedError('cursor-unknown', false, wanted);
@@ -679,12 +679,13 @@ async function sendCommandCodeMultiSelectAnswer(sessionName, promptData, wanted)
679
679
  ...current.filter((n) => !wanted.includes(n)),
680
680
  ].sort((a, b) => a - b);
681
681
  if (toggles.length > 0) {
682
- await (0, tmux_1.sendSpecialKeys)(sessionName, toggles.map(String));
682
+ await sendSpecialKeysWhileCurrent(sessionName, toggles.map(String), stillCurrent);
683
683
  }
684
684
  const keysSent = toggles.length > 0;
685
685
  // 2. Read the screen back and refuse unless it is the same question with
686
686
  // exactly the requested boxes ticked.
687
687
  const afterToggle = await recaptureAfterKeys(sessionName);
688
+ assertStillCurrent(stillCurrent, keysSent);
688
689
  if (afterToggle === null) {
689
690
  throw new MultiSelectAnswerRejectedError('recapture-failed', keysSent, wanted);
690
691
  }
@@ -711,14 +712,12 @@ async function sendCommandCodeMultiSelectAnswer(sessionName, promptData, wanted)
711
712
  if (cursorNow === undefined) {
712
713
  throw new MultiSelectAnswerRejectedError('cursor-unknown', keysSent, wanted);
713
714
  }
714
- await (0, tmux_1.sendSpecialKeys)(sessionName, [
715
- ...downKeys(verified.options.length - cursorNow.number + 1),
716
- 'Enter',
717
- ]);
715
+ await sendSpecialKeysWhileCurrent(sessionName, [...downKeys(verified.options.length - cursorNow.number + 1), 'Enter'], stillCurrent);
718
716
  // 4. The second stage. `Submit` opens the Review page and the answer is sent
719
717
  // from there; `Next` advances to the following question, which IS the
720
718
  // commit for this one (its tab turns `✔`).
721
719
  const afterConfirm = await recaptureAfterKeys(sessionName);
720
+ assertStillCurrent(stillCurrent, true);
722
721
  if (afterConfirm === null) {
723
722
  throw new MultiSelectAnswerRejectedError('recapture-failed', true, wanted);
724
723
  }
@@ -729,7 +728,7 @@ async function sendCommandCodeMultiSelectAnswer(sessionName, promptData, wanted)
729
728
  if (review.hasUnansweredWarning) {
730
729
  throw new MultiSelectAnswerRejectedError('review-unanswered', true, wanted);
731
730
  }
732
- await (0, tmux_1.sendSpecialKeys)(sessionName, ['Enter']);
731
+ await sendSpecialKeysWhileCurrent(sessionName, ['Enter'], stillCurrent);
733
732
  return;
734
733
  }
735
734
  const next = (0, dialog_1.readCommandCodeQuestionDialog)(afterConfirm);
@@ -740,6 +739,50 @@ async function sendCommandCodeMultiSelectAnswer(sessionName, promptData, wanted)
740
739
  throw new MultiSelectAnswerRejectedError('not-committed', true, wanted);
741
740
  }
742
741
  }
742
+ /**
743
+ * The caller's `stillCurrent` said no after one of the send's waits
744
+ * (Issue #3706): the keys not yet sent were not sent. Keys already typed cannot
745
+ * be taken back, so {@link keysSent} says whether the pane was touched; either
746
+ * way the answer was NOT completed and must not be recorded as one.
747
+ */
748
+ class PromptAnswerAbortedError extends Error {
749
+ keysSent;
750
+ constructor(
751
+ /** Whether any key reached the pane before the stop. */
752
+ keysSent) {
753
+ super(`Prompt answer stopped by its caller (${keysSent ? 'some keys were sent' : 'no key was sent'})`);
754
+ this.keysSent = keysSent;
755
+ this.name = 'PromptAnswerAbortedError';
756
+ }
757
+ }
758
+ exports.PromptAnswerAbortedError = PromptAnswerAbortedError;
759
+ /** Stop here when the caller's `stillCurrent` says no (Issue #3706). */
760
+ function assertStillCurrent(stillCurrent, keysSent) {
761
+ if (stillCurrent && !stillCurrent())
762
+ throw new PromptAnswerAbortedError(keysSent);
763
+ }
764
+ /**
765
+ * `sendSpecialKeys`, asking `stillCurrent` between the keys when the caller
766
+ * gave one (Issue #3706). Without it the call is exactly the old two-argument
767
+ * one, so manual answers and every other caller send as before.
768
+ */
769
+ async function sendSpecialKeysWhileCurrent(sessionName, keys, stillCurrent) {
770
+ if (!stillCurrent) {
771
+ await (0, tmux_1.sendSpecialKeys)(sessionName, keys);
772
+ return;
773
+ }
774
+ try {
775
+ await (0, tmux_1.sendSpecialKeys)(sessionName, keys, { shouldContinue: stillCurrent });
776
+ }
777
+ catch (error) {
778
+ // By name rather than `instanceof`: test doubles of `./tmux/tmux` need not
779
+ // export the class.
780
+ if (error instanceof Error && error.name === 'SpecialKeysAbortedError') {
781
+ throw new PromptAnswerAbortedError(true);
782
+ }
783
+ throw error;
784
+ }
785
+ }
743
786
  /**
744
787
  * Send an answer to a tmux session, using cursor-key navigation for
745
788
  * Claude Code / Antigravity multiple-choice prompts and text input for
@@ -750,7 +793,7 @@ async function sendCommandCodeMultiSelectAnswer(sessionName, promptData, wanted)
750
793
  * - src/lib/auto-yes-manager.ts (L340-399)
751
794
  */
752
795
  async function sendPromptAnswer(params) {
753
- const { sessionName, answer, cliToolId, promptData, fallbackPromptType, fallbackDefaultOptionNumber } = params;
796
+ const { sessionName, answer, cliToolId, promptData, fallbackPromptType, fallbackDefaultOptionNumber, stillCurrent } = params;
754
797
  // Issue #2755: Command Code's checkbox question, before every guard below.
755
798
  // Its answer is a SET (`"1,3"`), which none of them can read — `/^\d+$/` is
756
799
  // how all three ask "is this a number?", so a set would be judged as free
@@ -760,7 +803,7 @@ async function sendPromptAnswer(params) {
760
803
  // a two-stage confirm, not a digit and an Enter.
761
804
  const multiSelect = readMultiSelectRequest(params);
762
805
  if (multiSelect !== null) {
763
- await sendCommandCodeMultiSelectAnswer(sessionName, multiSelect.promptData, multiSelect.wanted);
806
+ await sendCommandCodeMultiSelectAnswer(sessionName, multiSelect.promptData, multiSelect.wanted, stillCurrent);
764
807
  (0, tmux_capture_cache_1.invalidateCache)(sessionName);
765
808
  return;
766
809
  }
@@ -781,6 +824,8 @@ async function sendPromptAnswer(params) {
781
824
  // the Enter after them confirms that row — so the cursor has to be checked
782
825
  // here too, before the branch.
783
826
  assertFreeTextCursorIsOnTheField(params);
827
+ // Issue #3706: the guard above may have read the pane; nothing is typed yet.
828
+ assertStillCurrent(stillCurrent, false);
784
829
  // Determine if this is an arrow-key-navigated multiple-choice prompt.
785
830
  // Claude Code and Antigravity (agy) both render selection menus that only
786
831
  // respond to cursor navigation + Enter, not to typed option numbers
@@ -829,7 +874,7 @@ async function sendPromptAnswer(params) {
829
874
  keys.push(...buildNavigationKeys(downToNext));
830
875
  // 4. Enter to submit
831
876
  keys.push('Enter');
832
- await (0, tmux_1.sendSpecialKeys)(sessionName, keys);
877
+ await sendSpecialKeysWhileCurrent(sessionName, keys, stillCurrent);
833
878
  }
834
879
  else {
835
880
  // Single-select: navigate and Enter to select
@@ -847,7 +892,7 @@ async function sendPromptAnswer(params) {
847
892
  const keys = (isAskUserQuestionPicker && offset === 0)
848
893
  ? ['Down', 'Up', 'Enter']
849
894
  : [...navigationKeys, 'Enter'];
850
- await (0, tmux_1.sendSpecialKeys)(sessionName, keys);
895
+ await sendSpecialKeysWhileCurrent(sessionName, keys, stillCurrent);
851
896
  }
852
897
  }
853
898
  else {
@@ -858,6 +903,8 @@ async function sendPromptAnswer(params) {
858
903
  if (!shouldSuppressEnter(params, resolvedSubmitMode, dialog)) {
859
904
  // Wait a moment for the input to be processed
860
905
  await new Promise(resolve => setTimeout(resolve, cli_tool_timing_config_1.TUI_TEXT_INPUT_WAIT_MS));
906
+ // Issue #3706: the text is typed; the Enter that submits it is not.
907
+ assertStillCurrent(stillCurrent, true);
861
908
  // Send Enter
862
909
  await (0, tmux_1.sendKeys)(sessionName, '', true);
863
910
  }
@@ -24,6 +24,7 @@ const manager_1 = require("../../lib/cli-tools/manager");
24
24
  const tmux_capture_cache_1 = require("../../lib/tmux/tmux-capture-cache");
25
25
  const global_state_1 = require("../global-state");
26
26
  const terminal_session_ownership_1 = require("./terminal-session-ownership");
27
+ const poller_owner_1 = require("../../lib/polling/poller-owner");
27
28
  const logger = (0, logger_1.createLogger)('terminal-broadcast');
28
29
  const versionCounters = (0, global_state_1.getOrInitGlobal)('__terminalSnapshotVersions', () => new Map());
29
30
  exports.INTERACTION_SNAPSHOT_RETRY_DELAYS_MS = [100, 250, 500, 750];
@@ -43,11 +44,24 @@ async function broadcastTerminalSnapshot(worktreeId, cliToolId, instanceId) {
43
44
  try {
44
45
  if (!(await isPushableSession(worktreeId, cliToolId, instanceId)))
45
46
  return;
47
+ // Issue #3705: the response poller starts this snapshot inside its tick's
48
+ // owner (`snapshotOwnerStorage`) and the question is asked again after each
49
+ // `await`: a successor that took the key meanwhile is not overwritten by
50
+ // the turn that ended, and its `version` is not spent on it. Outside a
51
+ // poller tick, always yes.
52
+ if (!(0, poller_owner_1.maySnapshotPublish)())
53
+ throw new poller_owner_1.RetiredSnapshotError();
46
54
  const db = (0, db_instance_1.getDbInstance)();
47
55
  const payload = await (0, current_output_builder_1.buildCurrentOutput)(db, worktreeId, cliToolId, instanceId);
56
+ if (!(0, poller_owner_1.maySnapshotPublish)())
57
+ throw new poller_owner_1.RetiredSnapshotError();
48
58
  emitTerminalSnapshot(worktreeId, cliToolId, payload, instanceId);
49
59
  }
50
60
  catch (error) {
61
+ if (error instanceof poller_owner_1.RetiredSnapshotError) {
62
+ logger.info('terminal-snapshot:retired', { worktreeId, cliToolId, instanceId });
63
+ return;
64
+ }
51
65
  logger.error('terminal-snapshot:failed', {
52
66
  worktreeId,
53
67
  error: error instanceof Error ? error.message : String(error),