commandmate 0.48.0 → 0.49.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 (780) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +292 -285
  3. package/.next/app-path-routes-manifest.json +35 -34
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/prerender-manifest.json +9 -9
  6. package/.next/required-server-files.json +1 -1
  7. package/.next/routes-manifest.json +8 -0
  8. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  9. package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
  10. package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/app/release-notes/route_client-reference-manifest.js +1 -1
  12. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/capabilities/route.js +1 -1
  18. package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  22. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  24. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  25. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/hooks/agent-event/route.js +2 -2
  27. package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
  28. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/hooks/claude-done/route.js +2 -2
  30. package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
  31. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/hooks/permission-request/route.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.js +1 -1
  38. package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/push/subscriptions/route.js +1 -1
  40. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  41. package/.next/server/app/api/push/vapid/route.js +1 -1
  42. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  43. package/.next/server/app/api/relays/[relayId]/cancel/route.js +1 -1
  44. package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
  45. package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
  46. package/.next/server/app/api/relays/[relayId]/route.js +1 -0
  47. package/.next/server/app/api/relays/[relayId]/route.js.nft.json +1 -0
  48. package/.next/server/app/api/relays/[relayId]/route_client-reference-manifest.js +1 -0
  49. package/.next/server/app/api/relays/route.js +1 -1
  50. package/.next/server/app/api/relays/route.js.nft.json +1 -1
  51. package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
  52. package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
  53. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  54. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  55. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
  56. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  57. package/.next/server/app/api/repositories/clone/route.js +1 -1
  58. package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
  59. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  60. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  61. package/.next/server/app/api/repositories/restore/route.js +1 -1
  62. package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
  63. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  64. package/.next/server/app/api/repositories/route.js +1 -1
  65. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  66. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  67. package/.next/server/app/api/repositories/scan/route.js +1 -1
  68. package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
  69. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  70. package/.next/server/app/api/repositories/sync/route.js +1 -1
  71. package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
  72. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  73. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  74. package/.next/server/app/api/settings/default-agents/route.js +1 -1
  75. package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
  76. package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
  78. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  79. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  80. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  81. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  82. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  83. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  84. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  85. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  86. package/.next/server/app/api/tasks/[taskId]/route.js +1 -1
  87. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  88. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  90. package/.next/server/app/api/verification/runs/[runId]/route.js +1 -1
  91. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/api/verification/runs/route.js +1 -1
  93. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  94. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  95. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  96. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  97. package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
  98. package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
  99. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  100. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
  101. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
  102. package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
  103. package/.next/server/app/api/worktrees/[id]/cli-reference/route.js +1 -1
  104. package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
  105. package/.next/server/app/api/worktrees/[id]/cli-tool/route.js +1 -1
  106. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  107. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +1 -1
  108. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  109. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  110. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  111. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  112. package/.next/server/app/api/worktrees/[id]/direct-input/route.js +1 -1
  113. package/.next/server/app/api/worktrees/[id]/direct-input/route.js.nft.json +1 -1
  114. package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
  115. package/.next/server/app/api/worktrees/[id]/env/route.js +1 -1
  116. package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
  117. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
  118. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +1 -1
  120. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  121. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  122. package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  124. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/git/branches/route.js +1 -1
  127. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/git/checkout/route.js +1 -1
  129. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  130. package/.next/server/app/api/worktrees/[id]/git/commit/route.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  132. package/.next/server/app/api/worktrees/[id]/git/diff/route.js +1 -1
  133. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/git/fetch/route.js +1 -1
  135. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  136. package/.next/server/app/api/worktrees/[id]/git/log/route.js +1 -1
  137. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  138. package/.next/server/app/api/worktrees/[id]/git/pull/route.js +1 -1
  139. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/git/push/route.js +1 -1
  141. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  142. package/.next/server/app/api/worktrees/[id]/git/reset/route.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/git/revert/route.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  146. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  148. package/.next/server/app/api/worktrees/[id]/git/stage/route.js +1 -1
  149. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/git/staged/route.js +1 -1
  151. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  152. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js +1 -1
  153. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  154. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js +1 -1
  155. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js +1 -1
  157. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  158. package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js +1 -1
  159. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/git/stash/route.js +1 -1
  161. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  162. package/.next/server/app/api/worktrees/[id]/git/status/route.js +1 -1
  163. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  164. package/.next/server/app/api/worktrees/[id]/git/unstage/route.js +1 -1
  165. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  166. package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js +1 -1
  167. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  168. package/.next/server/app/api/worktrees/[id]/instances/notes/route.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
  170. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
  171. package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
  173. package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
  174. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  175. package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
  176. package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
  177. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  178. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js +1 -1
  179. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  180. package/.next/server/app/api/worktrees/[id]/logs/route.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.js +1 -1
  189. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  190. package/.next/server/app/api/worktrees/[id]/opencode/diff/route.js +1 -1
  191. package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
  192. package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
  193. package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
  194. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  195. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
  196. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  197. package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route.js +1 -1
  198. package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route.js.nft.json +1 -1
  199. package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route_client-reference-manifest.js +1 -1
  200. package/.next/server/app/api/worktrees/[id]/resolve-target/route.js +1 -1
  201. package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
  202. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
  203. package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
  204. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  205. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  206. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  207. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  208. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +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 +1 -1
  211. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  212. package/.next/server/app/api/worktrees/[id]/schedules/route.js +1 -1
  213. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  214. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  215. package/.next/server/app/api/worktrees/[id]/send/route.js +144 -1
  216. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  217. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  218. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +3 -3
  219. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
  220. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  221. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  222. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  223. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  224. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  225. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  226. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  227. package/.next/server/app/api/worktrees/[id]/skills/route.js +1 -1
  228. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  229. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
  230. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  231. package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
  232. package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
  233. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  234. package/.next/server/app/api/worktrees/[id]/tasks/route.js +1 -1
  235. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  236. package/.next/server/app/api/worktrees/[id]/terminal/route.js +103 -1
  237. package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
  238. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  239. package/.next/server/app/api/worktrees/[id]/timers/history/route.js +1 -1
  240. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  241. package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
  242. package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
  243. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  244. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js +1 -1
  245. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  246. package/.next/server/app/api/worktrees/[id]/todos/route.js +1 -1
  247. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  248. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  249. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  250. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  251. package/.next/server/app/api/worktrees/[id]/verify/config/route.js +1 -1
  252. package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
  253. package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -1
  254. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  255. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js +1 -1
  256. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
  257. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route.js +1 -1
  258. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  259. package/.next/server/app/api/worktrees/[id]/verify/runs/route.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.js +1 -1
  262. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  263. package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
  264. package/.next/server/app/api/worktrees/route.js +1 -1
  265. package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
  266. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  267. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  268. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  269. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  270. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  271. package/.next/server/app/page_client-reference-manifest.js +1 -1
  272. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  273. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  274. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  275. package/.next/server/app/sessions/page.js +1 -1
  276. package/.next/server/app/sessions/page.js.nft.json +1 -1
  277. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  278. package/.next/server/app/skills/[skillId]/page.js +1 -1
  279. package/.next/server/app/skills/[skillId]/page.js.nft.json +1 -1
  280. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  281. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  282. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  283. package/.next/server/app/worktrees/[id]/files/[...path]/page.js +2 -2
  284. package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +1 -1
  285. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  286. package/.next/server/app/worktrees/[id]/page.js +11 -11
  287. package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
  288. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  289. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  290. package/.next/server/app-paths-manifest.json +35 -34
  291. package/.next/server/chunks/1601.js +2 -2
  292. package/.next/server/chunks/1656.js +2 -2
  293. package/.next/server/chunks/2069.js +1 -0
  294. package/.next/server/chunks/2119.js +1 -1
  295. package/.next/server/chunks/2404.js +1 -1
  296. package/.next/server/chunks/2422.js +1 -1
  297. package/.next/server/chunks/2445.js +1 -1
  298. package/.next/server/chunks/2534.js +1 -1
  299. package/.next/server/chunks/3241.js +1 -1
  300. package/.next/server/chunks/3773.js +1 -0
  301. package/.next/server/chunks/3801.js +31 -0
  302. package/.next/server/chunks/4243.js +1 -1
  303. package/.next/server/chunks/4248.js +1 -1
  304. package/.next/server/chunks/5209.js +1 -1
  305. package/.next/server/chunks/5354.js +1 -1
  306. package/.next/server/chunks/{9130.js → 5630.js} +1 -1
  307. package/.next/server/chunks/5775.js +1 -0
  308. package/.next/server/chunks/610.js +1 -0
  309. package/.next/server/chunks/6119.js +1 -1
  310. package/.next/server/chunks/6130.js +1 -1
  311. package/.next/server/chunks/6401.js +1 -1
  312. package/.next/server/chunks/6486.js +1 -1
  313. package/.next/server/chunks/6781.js +1 -1
  314. package/.next/server/chunks/6808.js +4 -0
  315. package/.next/server/chunks/7023.js +14 -0
  316. package/.next/server/chunks/7604.js +2 -2
  317. package/.next/server/chunks/7905.js +1 -1
  318. package/.next/server/chunks/8581.js +16 -16
  319. package/.next/server/chunks/8728.js +3 -3
  320. package/.next/server/chunks/8782.js +1 -1
  321. package/.next/server/chunks/8791.js +1 -1
  322. package/.next/server/chunks/8807.js +63 -53
  323. package/.next/server/chunks/8918.js +103 -1
  324. package/.next/server/chunks/9198.js +144 -0
  325. package/.next/server/chunks/9390.js +1 -1
  326. package/.next/server/chunks/9584.js +1 -1
  327. package/.next/server/chunks/9627.js +4 -4
  328. package/.next/server/chunks/9731.js +3 -3
  329. package/.next/server/middleware-manifest.json +5 -5
  330. package/.next/server/pages/500.html +1 -1
  331. package/.next/server/server-reference-manifest.json +1 -1
  332. package/.next/static/chunks/1128-914c559913546bbc.js +1 -0
  333. package/.next/static/chunks/{2407-26139a8a2f1adbe8.js → 2407-675ba6b21844dc3b.js} +1 -1
  334. package/.next/static/chunks/{2619-a305ad4810f1393a.js → 2619-04bc32f026a0d946.js} +1 -1
  335. package/.next/static/chunks/{2863-f0121af1cbbedb3b.js → 2863-7173dc305dffc4f6.js} +1 -1
  336. package/.next/static/chunks/3931-1a1abab16248f14d.js +1 -0
  337. package/.next/static/chunks/6288-6fadbba6e84393b2.js +1 -0
  338. package/.next/static/chunks/7665-e9ef6e0a85b9fa49.js +1 -0
  339. package/.next/static/chunks/{8165-c68b3dc844210e6a.js → 8165-263172c17ae8e8c3.js} +1 -1
  340. package/.next/static/chunks/8606-ce17ffa77f39608e.js +1 -0
  341. package/.next/static/chunks/app/api/agents/update/route-a4f129c451de7859.js +1 -0
  342. package/.next/static/chunks/app/api/agents/versions/route-a4f129c451de7859.js +1 -0
  343. package/.next/static/chunks/app/api/app/release-notes/route-a4f129c451de7859.js +1 -0
  344. package/.next/static/chunks/app/api/app/update/route-a4f129c451de7859.js +1 -0
  345. package/.next/static/chunks/app/api/app/update-check/route-a4f129c451de7859.js +1 -0
  346. package/.next/static/chunks/app/api/auth/login/route-a4f129c451de7859.js +1 -0
  347. package/.next/static/chunks/app/api/auth/logout/route-a4f129c451de7859.js +1 -0
  348. package/.next/static/chunks/app/api/auth/status/route-a4f129c451de7859.js +1 -0
  349. package/.next/static/chunks/app/api/capabilities/route-a4f129c451de7859.js +1 -0
  350. package/.next/static/chunks/app/api/daily-summary/route-a4f129c451de7859.js +1 -0
  351. package/.next/static/chunks/app/api/daily-summary/status/route-a4f129c451de7859.js +1 -0
  352. package/.next/static/chunks/app/api/external-apps/[id]/health/route-a4f129c451de7859.js +1 -0
  353. package/.next/static/chunks/app/api/external-apps/[id]/route-a4f129c451de7859.js +1 -0
  354. package/.next/static/chunks/app/api/external-apps/route-a4f129c451de7859.js +1 -0
  355. package/.next/static/chunks/app/api/fs/browse/route-a4f129c451de7859.js +1 -0
  356. package/.next/static/chunks/app/api/fs/recent-paths/route-a4f129c451de7859.js +1 -0
  357. package/.next/static/chunks/app/api/hooks/agent-event/route-a4f129c451de7859.js +1 -0
  358. package/.next/static/chunks/app/api/hooks/claude-done/route-a4f129c451de7859.js +1 -0
  359. package/.next/static/chunks/app/api/hooks/permission-request/route-a4f129c451de7859.js +1 -0
  360. package/.next/static/chunks/app/api/metrics/vibe/route-a4f129c451de7859.js +1 -0
  361. package/.next/static/chunks/app/api/ollama/models/route-a4f129c451de7859.js +1 -0
  362. package/.next/static/chunks/app/api/push/escalation/route-a4f129c451de7859.js +1 -0
  363. package/.next/static/chunks/app/api/push/subscriptions/route-a4f129c451de7859.js +1 -0
  364. package/.next/static/chunks/app/api/push/vapid/route-a4f129c451de7859.js +1 -0
  365. package/.next/static/chunks/app/api/relays/[relayId]/cancel/route-a4f129c451de7859.js +1 -0
  366. package/.next/static/chunks/app/api/relays/[relayId]/route-a4f129c451de7859.js +1 -0
  367. package/.next/static/chunks/app/api/relays/route-a4f129c451de7859.js +1 -0
  368. package/.next/static/chunks/app/api/remote/pair/route-a4f129c451de7859.js +1 -0
  369. package/.next/static/chunks/app/api/repositories/[id]/route-a4f129c451de7859.js +1 -0
  370. package/.next/static/chunks/app/api/repositories/clone/[jobId]/route-a4f129c451de7859.js +1 -0
  371. package/.next/static/chunks/app/api/repositories/clone/route-a4f129c451de7859.js +1 -0
  372. package/.next/static/chunks/app/api/repositories/excluded/route-a4f129c451de7859.js +1 -0
  373. package/.next/static/chunks/app/api/repositories/restore/route-a4f129c451de7859.js +1 -0
  374. package/.next/static/chunks/app/api/repositories/route-a4f129c451de7859.js +1 -0
  375. package/.next/static/chunks/app/api/repositories/scan/route-a4f129c451de7859.js +1 -0
  376. package/.next/static/chunks/app/api/repositories/sync/route-a4f129c451de7859.js +1 -0
  377. package/.next/static/chunks/app/api/repositories/validate-path/route-a4f129c451de7859.js +1 -0
  378. package/.next/static/chunks/app/api/settings/default-agents/route-a4f129c451de7859.js +1 -0
  379. package/.next/static/chunks/app/api/settings/default-surface-mode/route-a4f129c451de7859.js +1 -0
  380. package/.next/static/chunks/app/api/sidebar/group-order/route-a4f129c451de7859.js +1 -0
  381. package/.next/static/chunks/app/api/skills/[id]/route-a4f129c451de7859.js +1 -0
  382. package/.next/static/chunks/app/api/skills/installations/route-a4f129c451de7859.js +1 -0
  383. package/.next/static/chunks/app/api/skills/operations/route-a4f129c451de7859.js +1 -0
  384. package/.next/static/chunks/app/api/skills/reindex/route-a4f129c451de7859.js +1 -0
  385. package/.next/static/chunks/app/api/skills/route-a4f129c451de7859.js +1 -0
  386. package/.next/static/chunks/app/api/slash-commands/route-a4f129c451de7859.js +1 -0
  387. package/.next/static/chunks/app/api/tasks/[taskId]/cancel/route-a4f129c451de7859.js +1 -0
  388. package/.next/static/chunks/app/api/tasks/[taskId]/route-a4f129c451de7859.js +1 -0
  389. package/.next/static/chunks/app/api/templates/[id]/route-a4f129c451de7859.js +1 -0
  390. package/.next/static/chunks/app/api/templates/route-a4f129c451de7859.js +1 -0
  391. package/.next/static/chunks/app/api/verification/runs/[runId]/route-a4f129c451de7859.js +1 -0
  392. package/.next/static/chunks/app/api/verification/runs/route-a4f129c451de7859.js +1 -0
  393. package/.next/static/chunks/app/api/worktrees/[id]/auto-yes/route-a4f129c451de7859.js +1 -0
  394. package/.next/static/chunks/app/api/worktrees/[id]/capture/route-a4f129c451de7859.js +1 -0
  395. package/.next/static/chunks/app/api/worktrees/[id]/clear-composer/route-a4f129c451de7859.js +1 -0
  396. package/.next/static/chunks/app/api/worktrees/[id]/cli-reference/route-a4f129c451de7859.js +1 -0
  397. package/.next/static/chunks/app/api/worktrees/[id]/cli-tool/route-a4f129c451de7859.js +1 -0
  398. package/.next/static/chunks/app/api/worktrees/[id]/cmate/schedules/route-a4f129c451de7859.js +1 -0
  399. package/.next/static/chunks/app/api/worktrees/[id]/current-output/route-a4f129c451de7859.js +1 -0
  400. package/.next/static/chunks/app/api/worktrees/[id]/direct-input/route-a4f129c451de7859.js +1 -0
  401. package/.next/static/chunks/app/api/worktrees/[id]/env/route-a4f129c451de7859.js +1 -0
  402. package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/[logId]/route-a4f129c451de7859.js +1 -0
  403. package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/route-a4f129c451de7859.js +1 -0
  404. package/.next/static/chunks/app/api/worktrees/[id]/files/[...path]/route-a4f129c451de7859.js +1 -0
  405. package/.next/static/chunks/app/api/worktrees/[id]/git/branch/create/route-a4f129c451de7859.js +1 -0
  406. package/.next/static/chunks/app/api/worktrees/[id]/git/branch/delete/route-a4f129c451de7859.js +1 -0
  407. package/.next/static/chunks/app/api/worktrees/[id]/git/branches/route-a4f129c451de7859.js +1 -0
  408. package/.next/static/chunks/app/api/worktrees/[id]/git/checkout/route-a4f129c451de7859.js +1 -0
  409. package/.next/static/chunks/app/api/worktrees/[id]/git/commit/route-a4f129c451de7859.js +1 -0
  410. package/.next/static/chunks/app/api/worktrees/[id]/git/diff/route-a4f129c451de7859.js +1 -0
  411. package/.next/static/chunks/app/api/worktrees/[id]/git/fetch/route-a4f129c451de7859.js +1 -0
  412. package/.next/static/chunks/app/api/worktrees/[id]/git/log/route-a4f129c451de7859.js +1 -0
  413. package/.next/static/chunks/app/api/worktrees/[id]/git/pull/route-a4f129c451de7859.js +1 -0
  414. package/.next/static/chunks/app/api/worktrees/[id]/git/push/route-a4f129c451de7859.js +1 -0
  415. package/.next/static/chunks/app/api/worktrees/[id]/git/reset/route-a4f129c451de7859.js +1 -0
  416. package/.next/static/chunks/app/api/worktrees/[id]/git/revert/route-a4f129c451de7859.js +1 -0
  417. package/.next/static/chunks/app/api/worktrees/[id]/git/show/[commitHash]/route-a4f129c451de7859.js +1 -0
  418. package/.next/static/chunks/app/api/worktrees/[id]/git/stage/route-a4f129c451de7859.js +1 -0
  419. package/.next/static/chunks/app/api/worktrees/[id]/git/staged/route-a4f129c451de7859.js +1 -0
  420. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/[index]/route-a4f129c451de7859.js +1 -0
  421. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/apply/route-a4f129c451de7859.js +1 -0
  422. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/pop/route-a4f129c451de7859.js +1 -0
  423. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/push/route-a4f129c451de7859.js +1 -0
  424. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/route-a4f129c451de7859.js +1 -0
  425. package/.next/static/chunks/app/api/worktrees/[id]/git/status/route-a4f129c451de7859.js +1 -0
  426. package/.next/static/chunks/app/api/worktrees/[id]/git/unstage/route-a4f129c451de7859.js +1 -0
  427. package/.next/static/chunks/app/api/worktrees/[id]/git/working-diff/route-a4f129c451de7859.js +1 -0
  428. package/.next/static/chunks/app/api/worktrees/[id]/instances/notes/route-a4f129c451de7859.js +1 -0
  429. package/.next/static/chunks/app/api/worktrees/[id]/instances/opencode/route-a4f129c451de7859.js +1 -0
  430. package/.next/static/chunks/app/api/worktrees/[id]/interrupt/route-a4f129c451de7859.js +1 -0
  431. package/.next/static/chunks/app/api/worktrees/[id]/kill-session/route-a4f129c451de7859.js +1 -0
  432. package/.next/static/chunks/app/api/worktrees/[id]/logs/[filename]/route-a4f129c451de7859.js +1 -0
  433. package/.next/static/chunks/app/api/worktrees/[id]/logs/route-a4f129c451de7859.js +1 -0
  434. package/.next/static/chunks/app/api/worktrees/[id]/marp-render/route-a4f129c451de7859.js +1 -0
  435. package/.next/static/chunks/app/api/worktrees/[id]/memos/[memoId]/route-a4f129c451de7859.js +1 -0
  436. package/.next/static/chunks/app/api/worktrees/[id]/memos/route-a4f129c451de7859.js +1 -0
  437. package/.next/static/chunks/app/api/worktrees/[id]/messages/route-a4f129c451de7859.js +1 -0
  438. package/.next/static/chunks/app/api/worktrees/[id]/opencode/diff/route-a4f129c451de7859.js +1 -0
  439. package/.next/static/chunks/app/api/worktrees/[id]/opencode/session/route-a4f129c451de7859.js +1 -0
  440. package/.next/static/chunks/app/api/worktrees/[id]/opencode/share/route-a4f129c451de7859.js +1 -0
  441. package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/route-a4f129c451de7859.js +1 -0
  442. package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/strict/route-a4f129c451de7859.js +1 -0
  443. package/.next/static/chunks/app/api/worktrees/[id]/resolve-target/route-a4f129c451de7859.js +1 -0
  444. package/.next/static/chunks/app/api/worktrees/[id]/respond/route-a4f129c451de7859.js +1 -0
  445. package/.next/static/chunks/app/api/worktrees/[id]/route-a4f129c451de7859.js +1 -0
  446. package/.next/static/chunks/app/api/worktrees/[id]/schedules/[scheduleId]/route-a4f129c451de7859.js +1 -0
  447. package/.next/static/chunks/app/api/worktrees/[id]/schedules/active/route-a4f129c451de7859.js +1 -0
  448. package/.next/static/chunks/app/api/worktrees/[id]/schedules/route-a4f129c451de7859.js +1 -0
  449. package/.next/static/chunks/app/api/worktrees/[id]/search/route-a4f129c451de7859.js +1 -0
  450. package/.next/static/chunks/app/api/worktrees/[id]/send/route-a4f129c451de7859.js +1 -0
  451. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route-a4f129c451de7859.js +1 -0
  452. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/install/route-a4f129c451de7859.js +1 -0
  453. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/plan/route-a4f129c451de7859.js +1 -0
  454. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall/route-a4f129c451de7859.js +1 -0
  455. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route-a4f129c451de7859.js +1 -0
  456. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update/route-a4f129c451de7859.js +1 -0
  457. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update-plan/route-a4f129c451de7859.js +1 -0
  458. package/.next/static/chunks/app/api/worktrees/[id]/skills/route-a4f129c451de7859.js +1 -0
  459. package/.next/static/chunks/app/api/worktrees/[id]/slash-commands/route-a4f129c451de7859.js +1 -0
  460. package/.next/static/chunks/app/api/worktrees/[id]/special-keys/route-a4f129c451de7859.js +1 -0
  461. package/.next/static/chunks/app/api/worktrees/[id]/tasks/route-a4f129c451de7859.js +1 -0
  462. package/.next/static/chunks/app/api/worktrees/[id]/terminal/route-a4f129c451de7859.js +1 -0
  463. package/.next/static/chunks/app/api/worktrees/[id]/timers/history/route-a4f129c451de7859.js +1 -0
  464. package/.next/static/chunks/app/api/worktrees/[id]/timers/route-a4f129c451de7859.js +1 -0
  465. package/.next/static/chunks/app/api/worktrees/[id]/todos/[todoId]/route-a4f129c451de7859.js +1 -0
  466. package/.next/static/chunks/app/api/worktrees/[id]/todos/route-a4f129c451de7859.js +1 -0
  467. package/.next/static/chunks/app/api/worktrees/[id]/tree/[...path]/route-a4f129c451de7859.js +1 -0
  468. package/.next/static/chunks/app/api/worktrees/[id]/tree/route-a4f129c451de7859.js +1 -0
  469. package/.next/static/chunks/app/api/worktrees/[id]/upload/[...path]/route-a4f129c451de7859.js +1 -0
  470. package/.next/static/chunks/app/api/worktrees/[id]/verify/config/route-a4f129c451de7859.js +1 -0
  471. package/.next/static/chunks/app/api/worktrees/[id]/verify/route-a4f129c451de7859.js +1 -0
  472. package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route-a4f129c451de7859.js +1 -0
  473. package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/[runId]/route-a4f129c451de7859.js +1 -0
  474. package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/route-a4f129c451de7859.js +1 -0
  475. package/.next/static/chunks/app/api/worktrees/[id]/viewed/route-a4f129c451de7859.js +1 -0
  476. package/.next/static/chunks/app/api/worktrees/apply-default-agents/route-a4f129c451de7859.js +1 -0
  477. package/.next/static/chunks/app/api/worktrees/route-a4f129c451de7859.js +1 -0
  478. package/.next/static/chunks/app/layout-8bfac4724277b47f.js +1 -0
  479. package/.next/static/chunks/app/manifest.webmanifest/route-a4f129c451de7859.js +1 -0
  480. package/.next/static/chunks/app/proxy/[...path]/route-a4f129c451de7859.js +1 -0
  481. package/.next/static/chunks/app/sessions/page-890fd50ec9739973.js +1 -0
  482. package/.next/static/chunks/app/skills/[skillId]/{page-52ba58712faf3378.js → page-cb6e74fd9a6a571d.js} +1 -1
  483. package/.next/static/chunks/app/worktrees/[id]/files/[...path]/page-704086656fb45699.js +1 -0
  484. package/.next/static/chunks/app/worktrees/[id]/layout-a4f129c451de7859.js +1 -0
  485. package/.next/static/chunks/app/worktrees/[id]/page-f6d3ab8185d93aae.js +1 -0
  486. package/.next/static/chunks/app/worktrees/[id]/terminal/{page-c601f3b3ece6557e.js → page-373ea37b16d930c7.js} +1 -1
  487. package/.next/static/css/c1e307d05daf93b6.css +1 -0
  488. package/.next/trace +13 -13
  489. package/.next/types/app/api/relays/[relayId]/route.ts +347 -0
  490. package/.next/types/routes.d.ts +2 -1
  491. package/.next/types/validator.ts +9 -0
  492. package/dist/cli/commands/ask.d.ts.map +1 -1
  493. package/dist/cli/commands/ask.js +178 -13
  494. package/dist/cli/commands/auto-yes.d.ts.map +1 -1
  495. package/dist/cli/commands/auto-yes.js +3 -5
  496. package/dist/cli/commands/capture.d.ts.map +1 -1
  497. package/dist/cli/commands/capture.js +5 -0
  498. package/dist/cli/commands/message-dispatch.d.ts +25 -5
  499. package/dist/cli/commands/message-dispatch.d.ts.map +1 -1
  500. package/dist/cli/commands/message-dispatch.js +92 -6
  501. package/dist/cli/commands/relays.d.ts +25 -2
  502. package/dist/cli/commands/relays.d.ts.map +1 -1
  503. package/dist/cli/commands/relays.js +69 -5
  504. package/dist/cli/commands/respond.d.ts +12 -0
  505. package/dist/cli/commands/respond.d.ts.map +1 -1
  506. package/dist/cli/commands/respond.js +63 -1
  507. package/dist/cli/commands/send.d.ts.map +1 -1
  508. package/dist/cli/commands/send.js +10 -10
  509. package/dist/cli/commands/verify.d.ts.map +1 -1
  510. package/dist/cli/commands/verify.js +8 -1
  511. package/dist/cli/commands/wait-hook-stop-settle.d.ts +66 -0
  512. package/dist/cli/commands/wait-hook-stop-settle.d.ts.map +1 -0
  513. package/dist/cli/commands/wait-hook-stop-settle.js +150 -0
  514. package/dist/cli/commands/wait-instance.d.ts +21 -0
  515. package/dist/cli/commands/wait-instance.d.ts.map +1 -0
  516. package/dist/cli/commands/wait-instance.js +41 -0
  517. package/dist/cli/commands/wait-notices.d.ts +87 -0
  518. package/dist/cli/commands/wait-notices.d.ts.map +1 -0
  519. package/dist/cli/commands/wait-notices.js +301 -0
  520. package/dist/cli/commands/wait-poll-bookkeeping.d.ts +15 -0
  521. package/dist/cli/commands/wait-poll-bookkeeping.d.ts.map +1 -0
  522. package/dist/cli/commands/wait-poll-bookkeeping.js +57 -0
  523. package/dist/cli/commands/wait-poll-state.d.ts +118 -0
  524. package/dist/cli/commands/wait-poll-state.d.ts.map +1 -0
  525. package/dist/cli/commands/wait-poll-state.js +6 -0
  526. package/dist/cli/commands/wait-timing.d.ts +46 -0
  527. package/dist/cli/commands/wait-timing.d.ts.map +1 -0
  528. package/dist/cli/commands/wait-timing.js +99 -0
  529. package/dist/cli/commands/wait-turn-boundary.d.ts +284 -0
  530. package/dist/cli/commands/wait-turn-boundary.d.ts.map +1 -0
  531. package/dist/cli/commands/wait-turn-boundary.js +427 -0
  532. package/dist/cli/commands/wait-verify.d.ts +50 -0
  533. package/dist/cli/commands/wait-verify.d.ts.map +1 -0
  534. package/dist/cli/commands/wait-verify.js +124 -0
  535. package/dist/cli/commands/wait.d.ts +6 -105
  536. package/dist/cli/commands/wait.d.ts.map +1 -1
  537. package/dist/cli/commands/wait.js +207 -959
  538. package/dist/cli/config/duration-constants.d.ts +16 -13
  539. package/dist/cli/config/duration-constants.d.ts.map +1 -1
  540. package/dist/cli/config/duration-constants.js +21 -21
  541. package/dist/cli/docs/agent-operations.d.ts +2 -2
  542. package/dist/cli/docs/agent-operations.d.ts.map +1 -1
  543. package/dist/cli/docs/agent-operations.js +25 -2
  544. package/dist/cli/types/api-responses.d.ts +76 -4
  545. package/dist/cli/types/api-responses.d.ts.map +1 -1
  546. package/dist/cli/utils/api-client.d.ts +15 -1
  547. package/dist/cli/utils/api-client.d.ts.map +1 -1
  548. package/dist/cli/utils/api-client.js +7 -1
  549. package/dist/cli/utils/reply-ledger.d.ts +79 -0
  550. package/dist/cli/utils/reply-ledger.d.ts.map +1 -1
  551. package/dist/cli/utils/reply-ledger.js +141 -1
  552. package/dist/cli/utils/verify-runner.d.ts +24 -1
  553. package/dist/cli/utils/verify-runner.d.ts.map +1 -1
  554. package/dist/cli/utils/verify-runner.js +54 -1
  555. package/dist/config/auto-yes-duration.d.ts +56 -0
  556. package/dist/config/auto-yes-duration.d.ts.map +1 -0
  557. package/dist/config/auto-yes-duration.js +76 -0
  558. package/dist/lib/session/send-attempt-types.d.ts +23 -1
  559. package/dist/lib/session/send-attempt-types.d.ts.map +1 -1
  560. package/dist/lib/session/send-attempt-types.js +9 -1
  561. package/dist/server/locales/en/worktree.json +18 -3
  562. package/dist/server/locales/ja/worktree.json +18 -3
  563. package/dist/server/src/config/auto-yes-config.js +14 -19
  564. package/dist/server/src/config/auto-yes-duration.js +76 -0
  565. package/dist/server/src/lib/auto-yes-poller.js +49 -10
  566. package/dist/server/src/lib/auto-yes-state.js +9 -2
  567. package/dist/server/src/lib/cli-tools/antigravity.js +40 -7
  568. package/dist/server/src/lib/cli-tools/codex.js +60 -11
  569. package/dist/server/src/lib/cli-tools/command-code-plan-review.js +24 -2
  570. package/dist/server/src/lib/cli-tools/copilot.js +120 -30
  571. package/dist/server/src/lib/cli-tools/gemini.js +28 -9
  572. package/dist/server/src/lib/cli-tools/opencode.js +55 -13
  573. package/dist/server/src/lib/cli-tools/submit-composer-read.js +580 -0
  574. package/dist/server/src/lib/cli-tools/submit-verified-sender.js +374 -516
  575. package/dist/server/src/lib/db/migrations/index.js +2 -0
  576. package/dist/server/src/lib/db/migrations/pre-migration-backup.js +266 -0
  577. package/dist/server/src/lib/db/migrations/runner.js +37 -4
  578. package/dist/server/src/lib/db/migrations/v62-session-relays-bind.js +102 -0
  579. package/dist/server/src/lib/db/relay-bind-db.js +437 -0
  580. package/dist/server/src/lib/db/relay-db.js +59 -96
  581. package/dist/server/src/lib/detection/composer-text.js +215 -11
  582. package/dist/server/src/lib/detection/prompt-detect-multiple-choice-chrome.js +193 -0
  583. package/dist/server/src/lib/detection/prompt-detect-multiple-choice.js +8 -191
  584. package/dist/server/src/lib/detection/upstream-faults.js +56 -5
  585. package/dist/server/src/lib/hooks/sources/opencode/client.js +12 -6
  586. package/dist/server/src/lib/hooks/structured-decision-response.js +1 -1
  587. package/dist/server/src/lib/polling/auto-yes-manual-answer.js +4 -2
  588. package/dist/server/src/lib/polling/response-checker.js +15 -16
  589. package/dist/server/src/lib/prompt-answer-errors.js +288 -0
  590. package/dist/server/src/lib/prompt-answer-sender.js +264 -288
  591. package/dist/server/src/lib/push/failure-episode-state.js +4 -1
  592. package/dist/server/src/lib/realtime/terminal-broadcast.js +1 -4
  593. package/dist/server/src/lib/realtime-snippet.js +54 -0
  594. package/dist/server/src/lib/relay/relay-bind.js +294 -0
  595. package/dist/server/src/lib/relay/relay-boot.js +51 -0
  596. package/dist/server/src/lib/relay/relay-bound-reply.js +519 -0
  597. package/dist/server/src/lib/relay/relay-delivery.js +134 -220
  598. package/dist/server/src/lib/relay/relay-messages.js +39 -4
  599. package/dist/server/src/lib/relay/relay-overlap.js +92 -0
  600. package/dist/server/src/lib/relay/relay-system-line.js +3 -2
  601. package/dist/server/src/lib/relay/types.js +12 -1
  602. package/dist/server/src/lib/session/agent-session-lifecycle.js +18 -0
  603. package/dist/server/src/lib/session/claude-session.js +41 -6
  604. package/dist/server/src/lib/session/composer-clear.js +109 -4
  605. package/dist/server/src/lib/session/current-output-builder.js +23 -6
  606. package/dist/server/src/lib/session/instance-input-lock.js +664 -0
  607. package/dist/server/src/lib/session/send-attempt-state.js +19 -1
  608. package/dist/server/src/lib/session/send-attempt-types.js +9 -1
  609. package/dist/server/src/lib/session/send-user-message.js +82 -13
  610. package/dist/server/src/lib/session/waiting-episode-state-ops.js +152 -0
  611. package/dist/server/src/lib/session/waiting-episode-state-store.js +202 -0
  612. package/dist/server/src/lib/session/waiting-episode-state-types.js +6 -0
  613. package/dist/server/src/lib/session/waiting-episode-state.js +26 -339
  614. package/dist/server/src/lib/tmux/tmux.js +25 -0
  615. package/dist/server/src/lib/verification/gate-runner.js +11 -4
  616. package/docs/en/user-guide/webapp-guide.md +15 -10
  617. package/package.json +1 -1
  618. package/release-notes/0.49.0.json +45 -0
  619. package/release-notes/0.49.1.json +66 -0
  620. package/.next/server/chunks/1210.js +0 -1
  621. package/.next/server/chunks/1945.js +0 -14
  622. package/.next/server/chunks/1990.js +0 -103
  623. package/.next/server/chunks/4194.js +0 -67
  624. package/.next/server/chunks/4280.js +0 -1
  625. package/.next/server/chunks/5845.js +0 -1
  626. package/.next/server/chunks/6722.js +0 -1
  627. package/.next/server/chunks/720.js +0 -103
  628. package/.next/server/chunks/936.js +0 -1
  629. package/.next/server/chunks/9540.js +0 -1
  630. package/.next/static/chunks/2099-c3e0ab70a1b95dd3.js +0 -1
  631. package/.next/static/chunks/5371-a549a0d2c2044d41.js +0 -1
  632. package/.next/static/chunks/6288-09feba367cc2c65e.js +0 -1
  633. package/.next/static/chunks/8606-cf6bdbff44a764cf.js +0 -1
  634. package/.next/static/chunks/9079-406b84d3cc891a87.js +0 -1
  635. package/.next/static/chunks/app/api/agents/update/route-c81284a9d8b35304.js +0 -1
  636. package/.next/static/chunks/app/api/agents/versions/route-c81284a9d8b35304.js +0 -1
  637. package/.next/static/chunks/app/api/app/release-notes/route-c81284a9d8b35304.js +0 -1
  638. package/.next/static/chunks/app/api/app/update/route-c81284a9d8b35304.js +0 -1
  639. package/.next/static/chunks/app/api/app/update-check/route-c81284a9d8b35304.js +0 -1
  640. package/.next/static/chunks/app/api/auth/login/route-c81284a9d8b35304.js +0 -1
  641. package/.next/static/chunks/app/api/auth/logout/route-c81284a9d8b35304.js +0 -1
  642. package/.next/static/chunks/app/api/auth/status/route-c81284a9d8b35304.js +0 -1
  643. package/.next/static/chunks/app/api/capabilities/route-c81284a9d8b35304.js +0 -1
  644. package/.next/static/chunks/app/api/daily-summary/route-c81284a9d8b35304.js +0 -1
  645. package/.next/static/chunks/app/api/daily-summary/status/route-c81284a9d8b35304.js +0 -1
  646. package/.next/static/chunks/app/api/external-apps/[id]/health/route-c81284a9d8b35304.js +0 -1
  647. package/.next/static/chunks/app/api/external-apps/[id]/route-c81284a9d8b35304.js +0 -1
  648. package/.next/static/chunks/app/api/external-apps/route-c81284a9d8b35304.js +0 -1
  649. package/.next/static/chunks/app/api/fs/browse/route-c81284a9d8b35304.js +0 -1
  650. package/.next/static/chunks/app/api/fs/recent-paths/route-c81284a9d8b35304.js +0 -1
  651. package/.next/static/chunks/app/api/hooks/agent-event/route-c81284a9d8b35304.js +0 -1
  652. package/.next/static/chunks/app/api/hooks/claude-done/route-c81284a9d8b35304.js +0 -1
  653. package/.next/static/chunks/app/api/hooks/permission-request/route-c81284a9d8b35304.js +0 -1
  654. package/.next/static/chunks/app/api/metrics/vibe/route-c81284a9d8b35304.js +0 -1
  655. package/.next/static/chunks/app/api/ollama/models/route-c81284a9d8b35304.js +0 -1
  656. package/.next/static/chunks/app/api/push/escalation/route-c81284a9d8b35304.js +0 -1
  657. package/.next/static/chunks/app/api/push/subscriptions/route-c81284a9d8b35304.js +0 -1
  658. package/.next/static/chunks/app/api/push/vapid/route-c81284a9d8b35304.js +0 -1
  659. package/.next/static/chunks/app/api/relays/[relayId]/cancel/route-c81284a9d8b35304.js +0 -1
  660. package/.next/static/chunks/app/api/relays/route-c81284a9d8b35304.js +0 -1
  661. package/.next/static/chunks/app/api/remote/pair/route-c81284a9d8b35304.js +0 -1
  662. package/.next/static/chunks/app/api/repositories/[id]/route-c81284a9d8b35304.js +0 -1
  663. package/.next/static/chunks/app/api/repositories/clone/[jobId]/route-c81284a9d8b35304.js +0 -1
  664. package/.next/static/chunks/app/api/repositories/clone/route-c81284a9d8b35304.js +0 -1
  665. package/.next/static/chunks/app/api/repositories/excluded/route-c81284a9d8b35304.js +0 -1
  666. package/.next/static/chunks/app/api/repositories/restore/route-c81284a9d8b35304.js +0 -1
  667. package/.next/static/chunks/app/api/repositories/route-c81284a9d8b35304.js +0 -1
  668. package/.next/static/chunks/app/api/repositories/scan/route-c81284a9d8b35304.js +0 -1
  669. package/.next/static/chunks/app/api/repositories/sync/route-c81284a9d8b35304.js +0 -1
  670. package/.next/static/chunks/app/api/repositories/validate-path/route-c81284a9d8b35304.js +0 -1
  671. package/.next/static/chunks/app/api/settings/default-agents/route-c81284a9d8b35304.js +0 -1
  672. package/.next/static/chunks/app/api/settings/default-surface-mode/route-c81284a9d8b35304.js +0 -1
  673. package/.next/static/chunks/app/api/sidebar/group-order/route-c81284a9d8b35304.js +0 -1
  674. package/.next/static/chunks/app/api/skills/[id]/route-c81284a9d8b35304.js +0 -1
  675. package/.next/static/chunks/app/api/skills/installations/route-c81284a9d8b35304.js +0 -1
  676. package/.next/static/chunks/app/api/skills/operations/route-c81284a9d8b35304.js +0 -1
  677. package/.next/static/chunks/app/api/skills/reindex/route-c81284a9d8b35304.js +0 -1
  678. package/.next/static/chunks/app/api/skills/route-c81284a9d8b35304.js +0 -1
  679. package/.next/static/chunks/app/api/slash-commands/route-c81284a9d8b35304.js +0 -1
  680. package/.next/static/chunks/app/api/tasks/[taskId]/cancel/route-c81284a9d8b35304.js +0 -1
  681. package/.next/static/chunks/app/api/tasks/[taskId]/route-c81284a9d8b35304.js +0 -1
  682. package/.next/static/chunks/app/api/templates/[id]/route-c81284a9d8b35304.js +0 -1
  683. package/.next/static/chunks/app/api/templates/route-c81284a9d8b35304.js +0 -1
  684. package/.next/static/chunks/app/api/verification/runs/[runId]/route-c81284a9d8b35304.js +0 -1
  685. package/.next/static/chunks/app/api/verification/runs/route-c81284a9d8b35304.js +0 -1
  686. package/.next/static/chunks/app/api/worktrees/[id]/auto-yes/route-c81284a9d8b35304.js +0 -1
  687. package/.next/static/chunks/app/api/worktrees/[id]/capture/route-c81284a9d8b35304.js +0 -1
  688. package/.next/static/chunks/app/api/worktrees/[id]/clear-composer/route-c81284a9d8b35304.js +0 -1
  689. package/.next/static/chunks/app/api/worktrees/[id]/cli-reference/route-c81284a9d8b35304.js +0 -1
  690. package/.next/static/chunks/app/api/worktrees/[id]/cli-tool/route-c81284a9d8b35304.js +0 -1
  691. package/.next/static/chunks/app/api/worktrees/[id]/cmate/schedules/route-c81284a9d8b35304.js +0 -1
  692. package/.next/static/chunks/app/api/worktrees/[id]/current-output/route-c81284a9d8b35304.js +0 -1
  693. package/.next/static/chunks/app/api/worktrees/[id]/direct-input/route-c81284a9d8b35304.js +0 -1
  694. package/.next/static/chunks/app/api/worktrees/[id]/env/route-c81284a9d8b35304.js +0 -1
  695. package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/[logId]/route-c81284a9d8b35304.js +0 -1
  696. package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/route-c81284a9d8b35304.js +0 -1
  697. package/.next/static/chunks/app/api/worktrees/[id]/files/[...path]/route-c81284a9d8b35304.js +0 -1
  698. package/.next/static/chunks/app/api/worktrees/[id]/git/branch/create/route-c81284a9d8b35304.js +0 -1
  699. package/.next/static/chunks/app/api/worktrees/[id]/git/branch/delete/route-c81284a9d8b35304.js +0 -1
  700. package/.next/static/chunks/app/api/worktrees/[id]/git/branches/route-c81284a9d8b35304.js +0 -1
  701. package/.next/static/chunks/app/api/worktrees/[id]/git/checkout/route-c81284a9d8b35304.js +0 -1
  702. package/.next/static/chunks/app/api/worktrees/[id]/git/commit/route-c81284a9d8b35304.js +0 -1
  703. package/.next/static/chunks/app/api/worktrees/[id]/git/diff/route-c81284a9d8b35304.js +0 -1
  704. package/.next/static/chunks/app/api/worktrees/[id]/git/fetch/route-c81284a9d8b35304.js +0 -1
  705. package/.next/static/chunks/app/api/worktrees/[id]/git/log/route-c81284a9d8b35304.js +0 -1
  706. package/.next/static/chunks/app/api/worktrees/[id]/git/pull/route-c81284a9d8b35304.js +0 -1
  707. package/.next/static/chunks/app/api/worktrees/[id]/git/push/route-c81284a9d8b35304.js +0 -1
  708. package/.next/static/chunks/app/api/worktrees/[id]/git/reset/route-c81284a9d8b35304.js +0 -1
  709. package/.next/static/chunks/app/api/worktrees/[id]/git/revert/route-c81284a9d8b35304.js +0 -1
  710. package/.next/static/chunks/app/api/worktrees/[id]/git/show/[commitHash]/route-c81284a9d8b35304.js +0 -1
  711. package/.next/static/chunks/app/api/worktrees/[id]/git/stage/route-c81284a9d8b35304.js +0 -1
  712. package/.next/static/chunks/app/api/worktrees/[id]/git/staged/route-c81284a9d8b35304.js +0 -1
  713. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/[index]/route-c81284a9d8b35304.js +0 -1
  714. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/apply/route-c81284a9d8b35304.js +0 -1
  715. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/pop/route-c81284a9d8b35304.js +0 -1
  716. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/push/route-c81284a9d8b35304.js +0 -1
  717. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/route-c81284a9d8b35304.js +0 -1
  718. package/.next/static/chunks/app/api/worktrees/[id]/git/status/route-c81284a9d8b35304.js +0 -1
  719. package/.next/static/chunks/app/api/worktrees/[id]/git/unstage/route-c81284a9d8b35304.js +0 -1
  720. package/.next/static/chunks/app/api/worktrees/[id]/git/working-diff/route-c81284a9d8b35304.js +0 -1
  721. package/.next/static/chunks/app/api/worktrees/[id]/instances/notes/route-c81284a9d8b35304.js +0 -1
  722. package/.next/static/chunks/app/api/worktrees/[id]/instances/opencode/route-c81284a9d8b35304.js +0 -1
  723. package/.next/static/chunks/app/api/worktrees/[id]/interrupt/route-c81284a9d8b35304.js +0 -1
  724. package/.next/static/chunks/app/api/worktrees/[id]/kill-session/route-c81284a9d8b35304.js +0 -1
  725. package/.next/static/chunks/app/api/worktrees/[id]/logs/[filename]/route-c81284a9d8b35304.js +0 -1
  726. package/.next/static/chunks/app/api/worktrees/[id]/logs/route-c81284a9d8b35304.js +0 -1
  727. package/.next/static/chunks/app/api/worktrees/[id]/marp-render/route-c81284a9d8b35304.js +0 -1
  728. package/.next/static/chunks/app/api/worktrees/[id]/memos/[memoId]/route-c81284a9d8b35304.js +0 -1
  729. package/.next/static/chunks/app/api/worktrees/[id]/memos/route-c81284a9d8b35304.js +0 -1
  730. package/.next/static/chunks/app/api/worktrees/[id]/messages/route-c81284a9d8b35304.js +0 -1
  731. package/.next/static/chunks/app/api/worktrees/[id]/opencode/diff/route-c81284a9d8b35304.js +0 -1
  732. package/.next/static/chunks/app/api/worktrees/[id]/opencode/session/route-c81284a9d8b35304.js +0 -1
  733. package/.next/static/chunks/app/api/worktrees/[id]/opencode/share/route-c81284a9d8b35304.js +0 -1
  734. package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/route-c81284a9d8b35304.js +0 -1
  735. package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/strict/route-c81284a9d8b35304.js +0 -1
  736. package/.next/static/chunks/app/api/worktrees/[id]/resolve-target/route-c81284a9d8b35304.js +0 -1
  737. package/.next/static/chunks/app/api/worktrees/[id]/respond/route-c81284a9d8b35304.js +0 -1
  738. package/.next/static/chunks/app/api/worktrees/[id]/route-c81284a9d8b35304.js +0 -1
  739. package/.next/static/chunks/app/api/worktrees/[id]/schedules/[scheduleId]/route-c81284a9d8b35304.js +0 -1
  740. package/.next/static/chunks/app/api/worktrees/[id]/schedules/active/route-c81284a9d8b35304.js +0 -1
  741. package/.next/static/chunks/app/api/worktrees/[id]/schedules/route-c81284a9d8b35304.js +0 -1
  742. package/.next/static/chunks/app/api/worktrees/[id]/search/route-c81284a9d8b35304.js +0 -1
  743. package/.next/static/chunks/app/api/worktrees/[id]/send/route-c81284a9d8b35304.js +0 -1
  744. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route-c81284a9d8b35304.js +0 -1
  745. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/install/route-c81284a9d8b35304.js +0 -1
  746. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/plan/route-c81284a9d8b35304.js +0 -1
  747. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall/route-c81284a9d8b35304.js +0 -1
  748. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route-c81284a9d8b35304.js +0 -1
  749. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update/route-c81284a9d8b35304.js +0 -1
  750. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update-plan/route-c81284a9d8b35304.js +0 -1
  751. package/.next/static/chunks/app/api/worktrees/[id]/skills/route-c81284a9d8b35304.js +0 -1
  752. package/.next/static/chunks/app/api/worktrees/[id]/slash-commands/route-c81284a9d8b35304.js +0 -1
  753. package/.next/static/chunks/app/api/worktrees/[id]/special-keys/route-c81284a9d8b35304.js +0 -1
  754. package/.next/static/chunks/app/api/worktrees/[id]/tasks/route-c81284a9d8b35304.js +0 -1
  755. package/.next/static/chunks/app/api/worktrees/[id]/terminal/route-c81284a9d8b35304.js +0 -1
  756. package/.next/static/chunks/app/api/worktrees/[id]/timers/history/route-c81284a9d8b35304.js +0 -1
  757. package/.next/static/chunks/app/api/worktrees/[id]/timers/route-c81284a9d8b35304.js +0 -1
  758. package/.next/static/chunks/app/api/worktrees/[id]/todos/[todoId]/route-c81284a9d8b35304.js +0 -1
  759. package/.next/static/chunks/app/api/worktrees/[id]/todos/route-c81284a9d8b35304.js +0 -1
  760. package/.next/static/chunks/app/api/worktrees/[id]/tree/[...path]/route-c81284a9d8b35304.js +0 -1
  761. package/.next/static/chunks/app/api/worktrees/[id]/tree/route-c81284a9d8b35304.js +0 -1
  762. package/.next/static/chunks/app/api/worktrees/[id]/upload/[...path]/route-c81284a9d8b35304.js +0 -1
  763. package/.next/static/chunks/app/api/worktrees/[id]/verify/config/route-c81284a9d8b35304.js +0 -1
  764. package/.next/static/chunks/app/api/worktrees/[id]/verify/route-c81284a9d8b35304.js +0 -1
  765. package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route-c81284a9d8b35304.js +0 -1
  766. package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/[runId]/route-c81284a9d8b35304.js +0 -1
  767. package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/route-c81284a9d8b35304.js +0 -1
  768. package/.next/static/chunks/app/api/worktrees/[id]/viewed/route-c81284a9d8b35304.js +0 -1
  769. package/.next/static/chunks/app/api/worktrees/apply-default-agents/route-c81284a9d8b35304.js +0 -1
  770. package/.next/static/chunks/app/api/worktrees/route-c81284a9d8b35304.js +0 -1
  771. package/.next/static/chunks/app/layout-46b4cbf07520d9b6.js +0 -1
  772. package/.next/static/chunks/app/manifest.webmanifest/route-c81284a9d8b35304.js +0 -1
  773. package/.next/static/chunks/app/proxy/[...path]/route-c81284a9d8b35304.js +0 -1
  774. package/.next/static/chunks/app/sessions/page-fb241bed579c67aa.js +0 -1
  775. package/.next/static/chunks/app/worktrees/[id]/files/[...path]/page-9cf1ecc59e36a004.js +0 -1
  776. package/.next/static/chunks/app/worktrees/[id]/layout-c81284a9d8b35304.js +0 -1
  777. package/.next/static/chunks/app/worktrees/[id]/page-cbc7749a33450cc5.js +0 -1
  778. package/.next/static/css/743f79ff19ab91e9.css +0 -1
  779. /package/.next/static/{PTlAswXLq8PAe2vUJ8dVP → fqfSDqQMweROeHUzOt_m1}/_buildManifest.js +0 -0
  780. /package/.next/static/{PTlAswXLq8PAe2vUJ8dVP → fqfSDqQMweROeHUzOt_m1}/_ssgManifest.js +0 -0
@@ -79,6 +79,16 @@
79
79
  * codex, Enter now waits until the composer shows the typed body
80
80
  * ({@link confirmTypedBodyLanded}); a body that never appears THROWS before
81
81
  * Enter, as #2464 does for a paste.
82
+ *
83
+ * Issue #3945 is two sends to one instance at once. A send that withdrew its
84
+ * body, or cleared before typing, erased whatever was in the composer — another
85
+ * send's body included — and a codex placeholder carries only a count, so a
86
+ * late one could not be told from the next send's. A send now runs as the
87
+ * instance's only writer (`lib/session/instance-input-lock`), re-reads the pane
88
+ * once it owns it ({@link recheckComposerBeforeInput}),
89
+ * checks it still owns the composer before every key, watches an `unseen`
90
+ * paste a little longer before giving up, and leaves a mark for a body that
91
+ * may still arrive, which the next send waits out ({@link waitOutCarriedPaste}).
82
92
  */
83
93
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
84
94
  if (k2 === undefined) k2 = k;
@@ -114,10 +124,7 @@ var __importStar = (this && this.__importStar) || (function () {
114
124
  };
115
125
  })();
116
126
  Object.defineProperty(exports, "__esModule", { value: true });
117
- exports.LITERAL_SEND_MAX_BYTES = void 0;
118
- exports.classifySubmit = classifySubmit;
119
- exports.isSubmitted = isSubmitted;
120
- exports.classifyPasteLanded = classifyPasteLanded;
127
+ exports.LITERAL_SEND_MAX_BYTES = exports.isSubmitted = exports.classifySubmit = exports.classifyPasteLanded = exports.recheckComposerBeforeInput = void 0;
121
128
  exports.clearComposerBeforeSend = clearComposerBeforeSend;
122
129
  exports.sendMessageWithSubmitVerification = sendMessageWithSubmitVerification;
123
130
  const childProcess = __importStar(require("child_process"));
@@ -127,19 +134,19 @@ const composer_spec_1 = require("./composer-spec");
127
134
  const cli_patterns_1 = require("../detection/cli-patterns");
128
135
  const cli_tool_timing_config_1 = require("../../config/cli-tool-timing-config");
129
136
  const logger_1 = require("../../lib/logger");
137
+ const global_state_1 = require("../../lib/global-state");
130
138
  const composer_clear_1 = require("../../lib/session/composer-clear");
139
+ Object.defineProperty(exports, "recheckComposerBeforeInput", { enumerable: true, get: function () { return composer_clear_1.recheckComposerBeforeInput; } });
140
+ const instance_input_lock_1 = require("../../lib/session/instance-input-lock");
131
141
  const composer_text_1 = require("../../lib/detection/composer-text");
142
+ const submit_composer_read_1 = require("./submit-composer-read");
143
+ // Issue #3963: the composer reads moved to `submit-composer-read`; re-exported
144
+ // so every caller and test keeps importing them from here.
145
+ var submit_composer_read_2 = require("./submit-composer-read");
146
+ Object.defineProperty(exports, "classifyPasteLanded", { enumerable: true, get: function () { return submit_composer_read_2.classifyPasteLanded; } });
147
+ Object.defineProperty(exports, "classifySubmit", { enumerable: true, get: function () { return submit_composer_read_2.classifySubmit; } });
148
+ Object.defineProperty(exports, "isSubmitted", { enumerable: true, get: function () { return submit_composer_read_2.isSubmitted; } });
132
149
  const logger = (0, logger_1.createLogger)('cli-tools/submit-verified-sender');
133
- /**
134
- * Version-resilient pasted-text placeholder.
135
- *
136
- * Broader than PASTED_TEXT_PATTERN (`/\[Pasted text #\d+/`) so it still matches
137
- * when a CLI version drops the `#N` and renders `[Pasted text +46 lines]`
138
- * (Issue #1469 condition 2). Used ONLY as a positive "still in the input box"
139
- * signal — never as the sole submit gate — so applying it to every tool is safe:
140
- * a tool that never renders it simply never matches.
141
- */
142
- const PASTE_PLACEHOLDER_PATTERN = /\[Pasted text[\s#]/;
143
150
  /**
144
151
  * Largest body typed as keystrokes (`send-keys -l`); anything longer is pasted
145
152
  * (Issue #2464).
@@ -178,461 +185,24 @@ const TYPED_BODY_POLL_MS = 50;
178
185
  const DEFAULT_TYPED_BODY_ATTEMPTS = 100;
179
186
  /** Per-command timeout for `load-buffer` / `paste-buffer`, as for every other tmux call. */
180
187
  const PASTE_COMMAND_TIMEOUT_MS = 5000;
181
- /** Makes each send's tmux paste buffer name unique within this process. */
182
- let pasteBufferSeq = 0;
183
- /**
184
- * A slash-command sitting on the input line (Issue #1501).
185
- *
186
- * TUI completion popups replace a typed slash command with a highlighted menu
187
- * item (`/status` -> `/statusline`, `/review` -> `/teamwork-preview`); the
188
- * result is always another slash command. Scoping the "replaced" verdict to
189
- * `/…` text keeps idle-prompt placeholders that some TUIs paint on an empty
190
- * composer (gemini's "Type your message or @path", claude's hints, "? for
191
- * shortcuts") — none of which start with `/` — from being mistaken for a
192
- * substitution, so a genuinely-submitted message never fails spuriously.
193
- */
194
- const REPLACEMENT_COMMAND_PATTERN = /^\/[A-Za-z]/;
195
188
  /**
196
- * Prompt input-line markers across the marker-drawing TUIs.
197
- * claude/gemini/copilot: `>` or `❯`; codex: `›`; antigravity: `>`;
198
- * vibe-local: `ctx:N% ❯`. Leading whitespace is tolerated (tmux padding).
199
- *
200
- * Issue #1906 scopes this to the tools whose {@link ComposerSpec.reader} is
201
- * `input-line-marker`. opencode draws no marker at all, so applying it there was
202
- * wrong in both directions — see {@link readComposer}.
189
+ * Makes each send's tmux paste buffer name unique within this process — on
190
+ * `globalThis` (Issue #3945 review #11): tmux buffers are server-wide, and a
191
+ * module-local counter restarts at 0 in every bundle `next dev` loads this file
192
+ * into, so two sessions' sends could load into one buffer name (the second
193
+ * `load-buffer` overwriting the first before its `paste-buffer`).
203
194
  */
204
- const INPUT_LINE_MARKER = /^\s*(?:ctx:\d+%\s*)?[>❯›]/;
195
+ const pasteBufferSeq = (0, global_state_1.getOrInitGlobal)('__submitPasteBufferSeq', () => ({ last: 0 }));
205
196
  /**
206
- * Lines of pane tail to inspect for the "is the tool generating?" signal.
207
- *
208
- * Distinct from `ComposerSpec.verifyCaptureLines`, which sizes the tmux
209
- * capture: the busy marker of every tool lives in a status bar pinned to the
210
- * bottom of the pane, so it is read from a short tail even when the capture
211
- * itself is opencode's whole 200-row frame. Widening it to that frame would
212
- * match `esc interrupt` printed inside a reply.
213
- *
214
- * "The bottom" is the last row that holds anything (Issue #2464). codex,
215
- * Command Code and agy draw inline from the TOP of the 1000-row pane, so the
216
- * last twelve rows of the capture are blank padding — measured at rows 306,
217
- * 297 and 286 of 1,002 — and reading them found no composer on any send to
218
- * those three tools. See {@link withoutTrailingBlankRows}.
197
+ * Rows read for the re-check under the input lock (Issue #3945). The same
198
+ * capture `clearComposer` takes for its first read, so on a tool that clears
199
+ * before sending that read is the re-check's frame and no extra read is made.
219
200
  */
220
- const VERIFY_WINDOW_LINES = 12;
221
- /**
222
- * Read the composer out of a captured frame.
223
- *
224
- * Two readers, because the two families of TUI say "this is the input line" in
225
- * incompatible ways:
226
- *
227
- * - **marker tools** (`reader: 'input-line-marker'`) draw a `>` / `❯` / `›` at
228
- * the start of the row. Scanned bottom-up over the tail window so a status bar
229
- * below the box does not hide it.
230
- * - **opencode** draws a box with a gutter and no marker anywhere. Its buffer
231
- * rows are located structurally by {@link findOpenCodeComposerRows} (#1911's
232
- * chrome walk), and `Ask anything...` inside that box is opencode's own way of
233
- * saying the buffer is empty (#1883) rather than a row of text.
234
- *
235
- * Before this split, opencode went through the marker reader, which is wrong
236
- * both ways round. It never matched opencode's composer, so EVERY opencode send
237
- * was classified `submitted` without evidence — #1471's "the Enter was
238
- * swallowed" recovery has never once run on opencode. And when a `>` did land in
239
- * the window from somewhere else (a Markdown quote in a reply), the reader
240
- * treated that row as the input line and answered from it.
241
- *
242
- * Issue #1933 turned "which reader" from a `cliToolId === 'opencode'` test plus
243
- * a set membership test into {@link ComposerSpec.reader}, so the answer is one
244
- * declaration the tool owns rather than two tables a new tool has to be added
245
- * to. `unreadable` is the third arm, and it is the one #1906 found opencode
246
- * silently occupying: it means every send is classified `submitted` without
247
- * evidence, so it is a state to declare knowingly, never to fall into.
248
- */
249
- function readComposer(reader, lines, windowLines) {
250
- if (reader === 'opencode-box') {
251
- const rows = (0, cli_patterns_1.findOpenCodeComposerRows)(lines);
252
- if (rows === null)
253
- return { kind: 'absent' };
254
- // The placeholder is painted only while the buffer is empty, and only
255
- // inside the box — hence matched on the raw, still-guttered row (#1883).
256
- if (rows.some((row) => cli_patterns_1.OPENCODE_IDLE_COMPOSER_PATTERN.test(row)))
257
- return { kind: 'empty' };
258
- const first = rows.map(cli_patterns_1.stripOpenCodeGutter).find((row) => row.length > 0);
259
- if (first === undefined)
260
- return { kind: 'empty' };
261
- return { kind: 'text', text: first, rows };
262
- }
263
- if (reader !== 'input-line-marker')
264
- return { kind: 'absent' };
265
- const inputLine = findInputLine(windowLines);
266
- if (inputLine === null)
267
- return { kind: 'absent' };
268
- const stripped = stripInputMarker(inputLine);
269
- if (stripped.length === 0)
270
- return { kind: 'empty' };
271
- return { kind: 'text', text: stripped, rows: [inputLine] };
272
- }
273
- /**
274
- * The captured rows without the blank rows under the last drawn one
275
- * (Issue #2464).
276
- *
277
- * `capture-pane` returns every row of the pane, and a TUI that renders inline
278
- * from the top (codex, Command Code, agy) fills only the first few hundred of
279
- * the 1000 rows the session is created with. The composer is the last thing
280
- * such a TUI draws, so "the tail of the pane" has to mean "the tail of what is
281
- * drawn" — otherwise the tail window is all padding, no composer is ever found,
282
- * and every send to those tools classifies as `submitted` whatever the
283
- * composer actually holds. A bottom-anchored TUI (claude) has no trailing blank
284
- * rows, so for it this is the identity.
285
- */
286
- function withoutTrailingBlankRows(lines) {
287
- let end = lines.length;
288
- while (end > 0 && lines[end - 1].trim() === '')
289
- end--;
290
- return lines.slice(0, end);
291
- }
201
+ const RECHECK_CAPTURE_LINES = 200;
202
+ /** How often a send waiting out a carried paste mark reads the composer (Issue #3945). */
203
+ const CARRIED_MARK_POLL_MS = 200;
292
204
  /** Default bounded recovery Enters (each read back) before giving up (throwing). */
293
205
  const DEFAULT_VERIFY_ATTEMPTS = 4;
294
- /**
295
- * First non-blank line of the message, trimmed. This is what a TUI shows on the
296
- * prompt line before the body folds into a paste placeholder. NOT truncated:
297
- * the replacement check (inputMatchesBody) needs the full first line so that a
298
- * completion suffix (`/status` -> `/statusline`) is not mistaken for the body.
299
- */
300
- function firstNonBlankLine(message) {
301
- const line = message
302
- .split('\n')
303
- .map((l) => l.trim())
304
- .find((l) => l.length > 0);
305
- return line ?? '';
306
- }
307
- /**
308
- * Locate the active input line within the pane tail: the last line that begins
309
- * with a prompt marker. Scanned bottom-up so a status-bar/footer line rendered
310
- * BELOW the input box (antigravity's "? for shortcuts", vibe-local's status bar)
311
- * does not hide the real input line above it.
312
- */
313
- function findInputLine(windowLines) {
314
- for (let i = windowLines.length - 1; i >= 0; i--) {
315
- if (INPUT_LINE_MARKER.test(windowLines[i])) {
316
- return windowLines[i];
317
- }
318
- }
319
- return null;
320
- }
321
- /** Input line text with the prompt marker stripped and surrounding space trimmed. */
322
- function stripInputMarker(inputLine) {
323
- return inputLine.replace(INPUT_LINE_MARKER, '').trim();
324
- }
325
- /**
326
- * Whether the (marker-stripped, non-empty) input-line text is still our
327
- * unsent body rather than a TUI-substituted command.
328
- *
329
- * The still-unsent body appears verbatim on the input line. Line wrapping can
330
- * visually truncate it to a PREFIX of the first line, but a completion popup
331
- * always produces a DIFFERENT string — the body plus a completion suffix
332
- * (`/status` -> `/statusline`) or an unrelated command (`/review` ->
333
- * `/teamwork-preview`) — which is never a prefix of the body. So the body is
334
- * "still there" iff the input text is a prefix of (or equals) the body's first
335
- * line. This deliberately rejects `/statusline` for a `/status` body: the safe
336
- * rule is "input text that is not the body (or a prefix of it) is NOT resent".
337
- */
338
- function inputMatchesBody(strippedInput, message) {
339
- const bodyFirstLine = firstNonBlankLine(message);
340
- if (bodyFirstLine.length === 0)
341
- return false;
342
- return bodyFirstLine.startsWith(strippedInput);
343
- }
344
- /**
345
- * Collapsed-paste placeholders, as measured at the production 200x1000
346
- * geometry (Issue #2464, `tests/fixtures/long-body-2464/`):
347
- *
348
- * claude 2.1.268 `[Pasted text #86 +59 lines]` for 60 lines, `[Pasted text #87]` for one
349
- * agy 1.2.0 `[Pasted text #5 +60 lines]` for 60 lines, `[Pasted text #6 12288 chars]` for one
350
- * codex 0.154.0 `[Pasted Content 12288 chars]`
351
- * Command Code 1.53.0 `[PROBE P12k… +60L]` — the first ten characters, then the line count
352
- *
353
- * The `#N` stays optional for #1469's version drift (`[Pasted text +46 lines]`).
354
- */
355
- const PASTE_TOKEN_PATTERNS = [
356
- {
357
- pattern: /\[Pasted text(?: #\d+)?(?: \+(\d+) lines?| (\d+) chars?)?\]/g,
358
- read: (m) => m[1] !== undefined ? { lines: Number(m[1]) } : m[2] !== undefined ? { chars: Number(m[2]) } : {},
359
- },
360
- { pattern: /\[Pasted Content (\d+) chars?\]/g, read: (m) => ({ chars: Number(m[1]) }) },
361
- { pattern: /\[([^\]\n]*?)… \+(\d+)L\]/g, read: (m) => ({ head: m[1], lineTotal: Number(m[2]) }) },
362
- ];
363
- /** Every paste placeholder on a composer row, and the text left around them. */
364
- function findPasteTokens(text) {
365
- const tokens = [];
366
- let rest = text;
367
- for (const { pattern, read } of PASTE_TOKEN_PATTERNS) {
368
- for (const match of text.matchAll(pattern)) {
369
- tokens.push(read(match));
370
- rest = rest.replace(match[0], '');
371
- }
372
- }
373
- return { tokens, rest: rest.trim() };
374
- }
375
- /**
376
- * Does one placeholder account for the whole body?
377
- *
378
- * Counts below the body's mean the paste is still arriving; counts above it mean
379
- * the composer holds more than the body. The two units that differ between
380
- * tools for the same `+M lines` wording (claude: 59 for a 60-line body, agy: 60)
381
- * are both accepted — a bracketed paste arrives as one unit, so the failure this
382
- * guards against is a count that is wildly short (the 24-byte tail of #2464),
383
- * not one that is off by one line.
384
- */
385
- function comparePasteToken(token, message) {
386
- const newlines = (message.match(/\n/g) ?? []).length;
387
- if (token.head !== undefined) {
388
- const normalizedHead = token.head.replace(/\s+/g, ' ').trim();
389
- if (!message.replace(/\s+/g, ' ').startsWith(normalizedHead))
390
- return 'mismatch';
391
- }
392
- let observed;
393
- let accepted;
394
- if (token.chars !== undefined) {
395
- observed = token.chars;
396
- accepted = [[...message].length, message.length];
397
- }
398
- else if (token.lineTotal !== undefined) {
399
- observed = token.lineTotal;
400
- accepted = [newlines + 1];
401
- }
402
- else if (token.lines !== undefined) {
403
- observed = token.lines;
404
- accepted = [newlines, newlines + 1];
405
- }
406
- else {
407
- // claude's bare `[Pasted text #N]` is what it draws for a single line.
408
- return newlines === 0 ? 'landed' : 'pasting';
409
- }
410
- if (accepted.includes(observed))
411
- return 'landed';
412
- return observed < Math.min(...accepted) ? 'pasting' : 'mismatch';
413
- }
414
- /**
415
- * The composer as {@link classifySubmit} reads it (Issue #3205).
416
- *
417
- * {@link readComposer}'s marker reader takes the bottom-most `›` row of the
418
- * tail as the input line. A codex composer holding several lines draws its
419
- * continuation rows under the `›` row, and when one of them itself begins with
420
- * `›` — a body quoting a dialog's `› 1. Yes, proceed (y)` — that continuation
421
- * row was read as the input line: its text is not the body's first line, so a
422
- * body still sitting in the composer was classified `submitted` (F). Measured:
423
- * `tests/fixtures/codex-multiline-composer-3205/tc104-raw-pane.txt`.
424
- *
425
- * So for codex a composer of two or more rows is read with
426
- * `extractComposerText` — the #1890 reader `awaitTypedBody` already uses —
427
- * and its first line is the input line. Every other frame (a one-row
428
- * composer, an empty or ghost one, none at all, another tool) is read exactly
429
- * as before.
430
- *
431
- * Issue #3880 (H-2): this is also the reader before Enter
432
- * ({@link classifyPasteLanded}) and in the error text ({@link describeComposer}).
433
- * The paste check used to read the twelve-row tail with {@link readComposer}
434
- * alone, so a codex composer taller than that window (a 20-line paste, or 600
435
- * bytes wrapped in a narrow pane) put its `›` row above the window — `unseen`,
436
- * and the body that was in the composer was withdrawn and reported as not
437
- * landed — and a continuation row starting with `>` (a Markdown quote) was taken
438
- * for the input line — `mismatch`. The same frame read after Enter was
439
- * `pending`. One reader on both sides of Enter keeps the two verdicts about the
440
- * same composer.
441
- */
442
- /**
443
- * Everything a codex composer holds, for deciding that a pasted body arrived in
444
- * full (Issue #3880).
445
- *
446
- * `extractComposerText` answers for the UI: its text stops at 2,000 characters,
447
- * at 40 rows and at the composer's first blank row, so a composer that matches
448
- * it may still be missing the rest of the body — or hold something after it.
449
- * This reads the raw rows instead, from the `›` row down to the last block of
450
- * the frame (codex's model / cwd footer), so a body with blank lines, more than
451
- * 40 rows or more than 2,000 characters is compared whole, and anything typed
452
- * after the body is part of what is compared.
453
- */
454
- function codexComposerRegion(output) {
455
- const raw = output.split('\n');
456
- const box = (0, composer_text_1.findCodexInputBox)(raw);
457
- if (box === null)
458
- return null;
459
- const isBlank = (row) => (0, cli_patterns_1.stripAnsi)(row).trim() === '';
460
- let end = raw.length - 1;
461
- while (end >= 0 && isBlank(raw[end]))
462
- end--;
463
- let lastBlockStart = end;
464
- while (lastBlockStart > 0 && !isBlank(raw[lastBlockStart - 1]))
465
- lastBlockStart--;
466
- const stop = lastBlockStart > box.lastRow ? lastBlockStart - 1 : end;
467
- const rows = raw.slice(box.firstRow, stop + 1).map((row) => (0, cli_patterns_1.stripAnsi)(row));
468
- rows[0] = rows[0].replace(/^\s*\u203A ?/, '');
469
- return rows.join('\n');
470
- }
471
- function readSubmitComposer(output, cliToolId, reader, lines, windowLines) {
472
- if (cliToolId === 'codex' && reader === 'input-line-marker') {
473
- const read = (0, composer_text_1.extractComposerText)(output, cliToolId);
474
- if (read.state === 'content') {
475
- const region = codexComposerRegion(output) ?? read.text;
476
- if (read.text.includes('\n')) {
477
- return { kind: 'text', text: firstNonBlankLine(read.text), rows: read.text.split('\n'), region };
478
- }
479
- // Issue #3880 (N1): a one-row excerpt is read as before for its verdict
480
- // after Enter, but still carries the whole region — `head` with the rest of
481
- // the body under a blank row is one excerpt row and must not pass for the
482
- // whole body before Enter.
483
- const single = readComposer(reader, lines, windowLines);
484
- return single.kind === 'text' ? { ...single, region } : single;
485
- }
486
- }
487
- return readComposer(reader, lines, windowLines);
488
- }
489
- /**
490
- * Classify a captured pane into submitted / pending / replaced (Issue #1501).
491
- *
492
- * Version-independent by design — does NOT require the paste placeholder:
493
- * A. The tool is generating a response -> submitted.
494
- * B. No composer, or the composer is empty -> submitted.
495
- * C. A paste placeholder is folded in the composer -> pending (Enter eaten).
496
- * D. The body is still verbatim in the composer -> pending (resend Enter).
497
- * E. A DIFFERENT slash command is in the composer -> replaced (TUI popup
498
- * autocompleted the command; clear the line and throw, never resend Enter).
499
- * F. Any other non-empty text (idle placeholder/hint) -> submitted (unchanged
500
- * pre-#1501 permissive default, so normal sends never spuriously fail).
501
- *
502
- * C–F are scoped to the composer only, so the user-message echo that a TUI
503
- * prints into its history above the prompt never causes a false verdict.
504
- *
505
- * Issue #1906: "the composer" is read per tool by {@link readComposer} rather
506
- * than by looking for a `>` in the last twelve rows. For opencode — which draws
507
- * no marker — that read was unreachable, so every send reached F (in fact B) and
508
- * this function has never returned anything but `submitted` for it.
509
- *
510
- * Issue #2464: the tail window starts at the last drawn row, not at the last row
511
- * of the pane ({@link withoutTrailingBlankRows}), and C recognises every tool's
512
- * paste placeholder ({@link findPasteTokens}), not only claude's.
513
- *
514
- * @param output - Captured pane, ANSI intact. For opencode this must be the
515
- * whole pane; {@link ComposerSpec.verifyCaptureLines} is what asks tmux for it.
516
- * @param cliToolId - CLI tool id, for the "generating" detector
517
- * @param message - The body that was typed
518
- * @param composer - The tool's composer description (Issue #1933). Defaults to
519
- * the tool's own, so every existing three-argument caller is unchanged.
520
- */
521
- function classifySubmit(output, cliToolId, message, composerSpec = (0, composer_spec_1.resolveComposerSpec)(cliToolId)) {
522
- const clean = (0, cli_patterns_1.stripAnsi)(output);
523
- const lines = withoutTrailingBlankRows(clean.split('\n'));
524
- const windowLines = lines.slice(-VERIFY_WINDOW_LINES);
525
- const windowStr = windowLines.join('\n');
526
- // A. Actively generating a response => the message was accepted. Read from the
527
- // tail window for every tool: each one's busy marker lives in a status bar
528
- // pinned to the bottom of the pane, and widening it to opencode's whole
529
- // frame would match `esc interrupt` printed inside a reply.
530
- if ((0, cli_patterns_1.detectThinking)(cliToolId, windowStr)) {
531
- return 'submitted';
532
- }
533
- const composer = readSubmitComposer(output, cliToolId, composerSpec.reader, lines, windowLines);
534
- // B. No composer visible (scrolled off / dialog / still starting), or the
535
- // composer is empty => the message left the box => submitted.
536
- if (composer.kind !== 'text') {
537
- return 'submitted';
538
- }
539
- // C. A paste placeholder is still folded into the composer => body is there.
540
- if (composer.rows.some((row) => PASTE_PLACEHOLDER_PATTERN.test(row) || findPasteTokens(row).tokens.length > 0)) {
541
- return 'pending';
542
- }
543
- // D. The typed body is still sitting in the composer => resend Enter.
544
- if (inputMatchesBody(composer.text, message)) {
545
- return 'pending';
546
- }
547
- // E. A different slash command is in the composer => a completion popup
548
- // replaced what we typed. (Scoped to `/…` so idle-prompt placeholders that
549
- // some TUIs paint on an empty composer are never mistaken for this.)
550
- if (REPLACEMENT_COMMAND_PATTERN.test(composer.text)) {
551
- return 'replaced';
552
- }
553
- // F. Non-empty, non-command steady-state text (idle placeholder / hint) =>
554
- // submitted, preserving the pre-#1501 permissive default.
555
- return 'submitted';
556
- }
557
- /**
558
- * Backward-compatible boolean view of {@link classifySubmit}: submitted vs not.
559
- * A `replaced` verdict is NOT "submitted", so this returns false for it too.
560
- */
561
- function isSubmitted(output, cliToolId, message, composerSpec = (0, composer_spec_1.resolveComposerSpec)(cliToolId)) {
562
- return classifySubmit(output, cliToolId, message, composerSpec) === 'submitted';
563
- }
564
- /**
565
- * How much of a pasted body the composer shows, read BEFORE Enter (Issue #2464).
566
- *
567
- * The question #2464 needs answered is not "did Enter work" but "is what Enter
568
- * would submit the message we sent". Claude kept the last 24 bytes of a 12 KB
569
- * brief as ordinary composer text; every check that runs after Enter saw an
570
- * empty box and a generating model, i.e. a perfect send. So the composer is
571
- * judged here, while pressing Enter can still be withheld:
572
- *
573
- * 1. A collapsed placeholder is compared by the count the TUI prints — lines
574
- * for claude, agy and Command Code, characters for codex and agy's
575
- * single-line form ({@link comparePasteToken}).
576
- * 2. Plain text is the body only if it is the body's BEGINNING. Text that
577
- * occurs in the body but not at its start is exactly the #2464 tail, and is
578
- * a mismatch rather than "not drawn yet".
579
- * 3. Anything else — the idle placeholder, a ghost suggestion, no composer —
580
- * shows nothing of the body. `unseen`, which the caller decides about.
581
- *
582
- * Reads the composer the way {@link classifySubmit} does
583
- * ({@link readSubmitComposer}), so a history echo of an earlier message above the
584
- * composer is never mistaken for this one, and a frame both functions see holds
585
- * the same composer for both (Issue #3880). A multi-row codex composer is
586
- * compared as a whole ({@link codexComposerRegion}), whitespace removed
587
- * (wrapping and continuation indent proof): only the WHOLE body is `landed`;
588
- * the body's beginning alone is `pasting` (never enough to press Enter on), the
589
- * body plus anything else or text from inside it is `mismatch`. The whole body
590
- * is checked before placeholders, so a body that itself quotes
591
- * `[Pasted Content 600 chars]` is its own text, not codex's placeholder; a real
592
- * placeholder is only ever the composer's first row.
593
- */
594
- function classifyPasteLanded(output, cliToolId, message, composerSpec = (0, composer_spec_1.resolveComposerSpec)(cliToolId)) {
595
- const lines = withoutTrailingBlankRows((0, cli_patterns_1.stripAnsi)(output).split('\n'));
596
- const composer = readSubmitComposer(output, cliToolId, composerSpec.reader, lines, lines.slice(-VERIFY_WINDOW_LINES));
597
- if (composer.kind !== 'text')
598
- return 'unseen';
599
- if (composer.region !== undefined) {
600
- const shown = compactText(composer.region);
601
- const body = compactText(message);
602
- if (shown === body)
603
- return 'landed';
604
- const placeholder = findPasteTokens(composer.text);
605
- if (placeholder.tokens.length > 0) {
606
- // A placeholder plus anything else — on its row or under it — is not the body as sent.
607
- const below = compactText(composer.region.split('\n').slice(1).join('\n'));
608
- if (placeholder.tokens.length > 1 || placeholder.rest !== '' || below !== '')
609
- return 'mismatch';
610
- return comparePasteToken(placeholder.tokens[0], message);
611
- }
612
- if (body.startsWith(shown))
613
- return 'pasting';
614
- // The body's beginning followed by something else, the body plus more, or a
615
- // piece from inside it: the composer holds something other than the body.
616
- if (inputMatchesBody(composer.text, message) || shown.startsWith(body) || body.includes(shown)) {
617
- return 'mismatch';
618
- }
619
- return 'unseen';
620
- }
621
- // The whole body on one row is the body, even when it quotes a placeholder.
622
- if (compactText(composer.text) === compactText(message))
623
- return 'landed';
624
- const { tokens, rest } = findPasteTokens(composer.text);
625
- if (tokens.length === 0) {
626
- if (inputMatchesBody(composer.text, message))
627
- return 'landed';
628
- if (message.includes(composer.text))
629
- return 'mismatch';
630
- return 'unseen';
631
- }
632
- if (tokens.length > 1 || rest !== '')
633
- return 'mismatch';
634
- return comparePasteToken(tokens[0], message);
635
- }
636
206
  /** Run one tmux command, optionally feeding it `input` on stdin. */
637
207
  function runTmux(args, input) {
638
208
  return new Promise((resolve, reject) => {
@@ -659,12 +229,40 @@ function runTmux(args, input) {
659
229
  * per line for a TUI that did not ask for brackets. `-d` drops the buffer on
660
230
  * success; a failure drops it here, so no body is left behind in the server.
661
231
  *
662
- * @throws Error when either tmux command fails
232
+ * Issue #3945 (review-1 #2): ownership is asked again between the two commands,
233
+ * right before `paste-buffer` — the session may have been replaced while
234
+ * `load-buffer` ran. A lost ticket drops the buffer and throws before anything
235
+ * reaches the pane (`input lock lost, nothing was typed`).
236
+ *
237
+ * @throws Error when either tmux command fails, or `ticket` lost the composer
663
238
  */
664
- async function pasteBody(sessionName, message) {
665
- const bufferName = `cm-send-${process.pid}-${++pasteBufferSeq}`;
239
+ async function pasteBody(sessionName, message, ticket, cliToolId) {
240
+ pasteBufferSeq.last += 1;
241
+ const bufferName = `cm-send-${process.pid}-${pasteBufferSeq.last}`;
666
242
  try {
667
243
  await runTmux(['load-buffer', '-b', bufferName, '-'], message);
244
+ }
245
+ catch (error) {
246
+ await runTmux(['delete-buffer', '-b', bufferName]).catch(() => undefined);
247
+ const errorMessage = error instanceof Error ? error.message : String(error);
248
+ throw new Error(`Failed to paste message into tmux session: ${errorMessage}`);
249
+ }
250
+ if (!ticket.isCurrent()) {
251
+ await runTmux(['delete-buffer', '-b', bufferName]).catch(() => undefined);
252
+ assertInputOwner(ticket, cliToolId, 'paste-buffer', false);
253
+ }
254
+ // Issue #3953: the send's stamp, as the typed branch takes it — after
255
+ // `load-buffer` (up to its timeout), right before the body reaches the pane.
256
+ // Issue #3992: a refused input boundary (#3957) stops the send here, with the
257
+ // body loaded but not pasted — the buffer is dropped before the refusal goes up.
258
+ try {
259
+ (0, instance_input_lock_1.noteInputStart)();
260
+ }
261
+ catch (error) {
262
+ await runTmux(['delete-buffer', '-b', bufferName]).catch(() => undefined);
263
+ throw error;
264
+ }
265
+ try {
668
266
  await runTmux(['paste-buffer', '-p', '-r', '-d', '-b', bufferName, '-t', (0, tmux_1.exactTarget)(sessionName)]);
669
267
  }
670
268
  catch (error) {
@@ -674,9 +272,9 @@ async function pasteBody(sessionName, message) {
674
272
  }
675
273
  }
676
274
  /** The composer's first row, for an error message a person has to act on. */
677
- function describeComposer(output, cliToolId, composerSpec) {
678
- const lines = withoutTrailingBlankRows((0, cli_patterns_1.stripAnsi)(output).split('\n'));
679
- const composer = readSubmitComposer(output, cliToolId, composerSpec.reader, lines, lines.slice(-VERIFY_WINDOW_LINES));
275
+ function describeComposer(output, cliToolId, composerSpec, message) {
276
+ const lines = (0, submit_composer_read_1.withoutTrailingBlankRows)((0, cli_patterns_1.stripAnsi)(output).split('\n'));
277
+ const composer = (0, submit_composer_read_1.readSubmitComposer)(output, cliToolId, composerSpec.reader, lines, lines.slice(-submit_composer_read_1.VERIFY_WINDOW_LINES), message);
680
278
  if (composer.kind === 'absent')
681
279
  return 'no composer on screen';
682
280
  if (composer.kind === 'empty')
@@ -690,15 +288,27 @@ function describeComposer(output, cliToolId, composerSpec) {
690
288
  * Leaving it would put the fragment in front of the next message. claude and
691
289
  * codex go through the verified #1879 loop (a paste can span rows); the rest
692
290
  * get the single `C-u` the #1501 path already sends to them.
291
+ *
292
+ * @returns Whether the composer was confirmed empty afterwards (Issue #3945):
293
+ * false for a `C-u` nothing can read back, a failed clear, and a ticket that
294
+ * no longer owns the composer (no key is sent then).
693
295
  */
694
- async function withdrawUnsentBody(sessionName, cliToolId, composerSpec) {
296
+ async function withdrawUnsentBody(sessionName, cliToolId, composerSpec, ticket) {
297
+ // Issue #3945: only this send's own composer is taken back. A ticket that is
298
+ // no longer current means another writer owns the composer now, and what it
299
+ // holds is that writer's.
300
+ if (!ticket.isCurrent()) {
301
+ logger.error('paste-withdraw-skipped-not-owner', { sessionName, cliToolId, generation: ticket.generation });
302
+ return false;
303
+ }
695
304
  try {
696
305
  if (composerSpec.clearBeforeSend) {
697
- await (0, composer_clear_1.clearComposer)(sessionName, cliToolId);
698
- }
699
- else {
700
- await (0, tmux_1.clearInputLine)(sessionName);
306
+ const result = await (0, composer_clear_1.clearComposer)(sessionName, cliToolId, { beforePass: () => ticket.isCurrent() });
307
+ return result.cleared;
701
308
  }
309
+ await (0, tmux_1.clearInputLine)(sessionName);
310
+ // One `C-u` into a composer nothing here can read: sent, never confirmed.
311
+ return false;
702
312
  }
703
313
  catch (clearError) {
704
314
  logger.error('paste-withdraw-failed', {
@@ -706,7 +316,85 @@ async function withdrawUnsentBody(sessionName, cliToolId, composerSpec) {
706
316
  cliToolId,
707
317
  error: clearError instanceof Error ? clearError.message : String(clearError),
708
318
  });
319
+ return false;
320
+ }
321
+ }
322
+ /**
323
+ * Throw unless `ticket` still owns the composer (Issue #3945 stage 3). Called
324
+ * right before every key a send sends — body, paste, each Enter — so work still
325
+ * in flight after its ownership ended cannot reach the next owner's composer.
326
+ *
327
+ * @param typed - Whether any of the body may already be in the composer, which
328
+ * decides how the failure classifies (`not-sent` before the body only).
329
+ */
330
+ function assertInputOwner(ticket, cliToolId, step, typed) {
331
+ if (ticket.isCurrent())
332
+ return;
333
+ logger.error('input-lock-lost', { sessionName: ticket.sessionName, cliToolId, step, generation: ticket.generation });
334
+ if (!typed) {
335
+ throw new Error(`Session ${ticket.sessionName} was handed to another writer before ${step}; input lock lost, nothing was typed (Issue #3945).`);
336
+ }
337
+ throw new Error(`Session ${ticket.sessionName} was handed to another writer before ${step}; part of the message may be in its composer (Issue #3945).`);
338
+ }
339
+ /**
340
+ * Hold off typing while a carried paste mark is fresh (Issue #3945 stage 4).
341
+ *
342
+ * A previous send gave up on a body that may still be drawn. Until the mark
343
+ * expires, nothing of this send is typed: a placeholder of the same count as
344
+ * this body would be taken for it ({@link classifyPasteLanded} cannot tell
345
+ * them apart). What appears meanwhile is taken out at once — it is the previous
346
+ * send's, and this owner is the one left to handle it. A tool whose composer is
347
+ * not readable (no `clearBeforeSend`) only waits.
348
+ *
349
+ * @returns Whether there was a mark to wait out
350
+ */
351
+ async function waitOutCarriedPaste(sessionName, cliToolId, composer, ticket) {
352
+ const mark = (0, instance_input_lock_1.getCarriedPasteMark)(sessionName);
353
+ if (mark === null)
354
+ return false;
355
+ logger.warn('carried-paste-mark-wait', {
356
+ sessionName,
357
+ cliToolId,
358
+ originGeneration: mark.originGeneration,
359
+ generation: ticket.generation,
360
+ remainingMs: mark.expiresAt - Date.now(),
361
+ });
362
+ while (Date.now() < mark.expiresAt) {
363
+ await new Promise((resolve) => setTimeout(resolve, Math.min(CARRIED_MARK_POLL_MS, mark.expiresAt - Date.now())));
364
+ if (!composer.clearBeforeSend)
365
+ continue;
366
+ assertInputOwner(ticket, cliToolId, 'the carried paste wait', false);
367
+ let frame;
368
+ try {
369
+ frame = await (0, tmux_1.capturePane)(sessionName, RECHECK_CAPTURE_LINES);
370
+ }
371
+ catch {
372
+ // The re-check after the wait decides about a pane that cannot be read.
373
+ continue;
374
+ }
375
+ if ((0, composer_clear_1.readClearComposer)(frame, cliToolId).state !== 'content')
376
+ continue;
377
+ const result = await (0, composer_clear_1.clearComposer)(sessionName, cliToolId, {
378
+ initialCapture: frame,
379
+ beforePass: () => ticket.isCurrent(),
380
+ });
381
+ (0, tmux_capture_cache_1.invalidateCache)(sessionName);
382
+ logger.warn('carried-paste-withdrawn', {
383
+ sessionName,
384
+ cliToolId,
385
+ originGeneration: mark.originGeneration,
386
+ cleared: result.cleared,
387
+ discardedText: result.discardedText,
388
+ });
709
389
  }
390
+ (0, instance_input_lock_1.clearExpiredCarriedPasteMark)(ticket);
391
+ return true;
392
+ }
393
+ /** Whether the composer in `output` holds any text at all, read as the sender reads it. */
394
+ function composerHoldsText(output, cliToolId, composerSpec, message) {
395
+ const lines = (0, submit_composer_read_1.withoutTrailingBlankRows)((0, cli_patterns_1.stripAnsi)(output).split('\n'));
396
+ return ((0, submit_composer_read_1.readSubmitComposer)(output, cliToolId, composerSpec.reader, lines, lines.slice(-submit_composer_read_1.VERIFY_WINDOW_LINES), message)
397
+ .kind === 'text');
710
398
  }
711
399
  /**
712
400
  * Wait until the composer shows the whole pasted body; decide whether Enter
@@ -728,42 +416,99 @@ async function withdrawUnsentBody(sessionName, cliToolId, composerSpec) {
728
416
  * drawn in ways this module has not measured, and refusing on them would turn
729
417
  * "cannot see it" into "did not send it" for every long message they get.
730
418
  *
419
+ * Issue #3945 (stage 4): an `unseen` on a measured tool is not given up at the
420
+ * end of the 2 s. The composer is watched for {@link LATE_PASTE_OBSERVE_MS}
421
+ * more, still under the input lock — so whatever appears in it is this send's
422
+ * (or a person's typing), never another send's — and a placeholder or body that
423
+ * appears is withdrawn before the throw. A read that throws is a failure like
424
+ * the others: withdrawn, `body-not-landed`. When the body may still arrive —
425
+ * nothing of it was ever seen, it was only partly there, a read failed, or the
426
+ * withdrawal could not be confirmed — a carried mark holds the next send off
427
+ * the composer ({@link leaveCarriedPasteMark}).
428
+ *
731
429
  * @throws Error when the body cannot be confirmed in the composer
732
430
  */
733
431
  async function confirmPasteLanded(params) {
734
- const { sessionName, message, cliToolId, composer, attempts } = params;
432
+ const { sessionName, message, cliToolId, composer, attempts, ticket } = params;
735
433
  let state = 'unseen';
736
434
  let output = '';
737
- for (let attempt = 0; attempt < Math.max(1, attempts); attempt++) {
738
- await new Promise((resolve) => setTimeout(resolve, PASTE_LANDED_POLL_MS));
739
- output = await (0, tmux_1.capturePane)(sessionName, { startLine: -composer.verifyCaptureLines });
740
- state = classifyPasteLanded(output, cliToolId, message, composer);
741
- if (state === 'landed' || state === 'mismatch')
742
- break;
435
+ let readError = null;
436
+ /** ms after the 2 s check that something of the body appeared, during the late watch. */
437
+ let lateAfterMs = null;
438
+ try {
439
+ for (let attempt = 0; attempt < Math.max(1, attempts); attempt++) {
440
+ await new Promise((resolve) => setTimeout(resolve, PASTE_LANDED_POLL_MS));
441
+ output = await (0, tmux_1.capturePane)(sessionName, { startLine: -composer.verifyCaptureLines });
442
+ state = (0, submit_composer_read_1.classifyPasteLanded)(output, cliToolId, message, composer);
443
+ if (state === 'landed' || state === 'mismatch')
444
+ break;
445
+ }
446
+ if (state === 'unseen' && composer.clearBeforeSend) {
447
+ const observeAttempts = Math.ceil(instance_input_lock_1.LATE_PASTE_OBSERVE_MS / PASTE_LANDED_POLL_MS);
448
+ for (let attempt = 1; attempt <= observeAttempts; attempt++) {
449
+ await new Promise((resolve) => setTimeout(resolve, PASTE_LANDED_POLL_MS));
450
+ output = await (0, tmux_1.capturePane)(sessionName, { startLine: -composer.verifyCaptureLines });
451
+ state = (0, submit_composer_read_1.classifyPasteLanded)(output, cliToolId, message, composer);
452
+ if (state !== 'unseen') {
453
+ lateAfterMs = attempt * PASTE_LANDED_POLL_MS;
454
+ break;
455
+ }
456
+ }
457
+ }
743
458
  }
744
- if (state === 'landed')
459
+ catch (error) {
460
+ readError = error instanceof Error ? error.message : String(error);
461
+ }
462
+ if (readError === null && lateAfterMs === null && state === 'landed')
745
463
  return;
746
- if (state === 'unseen' && !composer.clearBeforeSend) {
464
+ if (readError === null && state === 'unseen' && !composer.clearBeforeSend) {
747
465
  logger.warn('paste-landed-unverified', { sessionName, cliToolId, bytes: Buffer.byteLength(message, 'utf8') });
748
466
  return;
749
467
  }
750
468
  const bytes = Buffer.byteLength(message, 'utf8');
751
469
  const lineCount = message.split('\n').length;
752
- const shown = describeComposer(output, cliToolId, composer);
753
- await withdrawUnsentBody(sessionName, cliToolId, composer);
470
+ const shown = readError === null ? describeComposer(output, cliToolId, composer, message) : 'an unreadable pane';
471
+ const withdrawn = await withdrawUnsentBody(sessionName, cliToolId, composer, ticket);
754
472
  (0, tmux_capture_cache_1.invalidateCache)(sessionName);
755
- logger.error('paste-not-landed', { sessionName, cliToolId, state, bytes, lines: lineCount, shown });
756
- const what = state === 'mismatch'
757
- ? `the composer does not hold the message as sent (it shows ${shown})`
758
- : state === 'pasting'
759
- ? `the paste had not finished arriving after ${attempts * PASTE_LANDED_POLL_MS}ms (the composer shows ${shown})`
760
- : `the message never appeared in the composer (${shown})`;
473
+ const mayStillArrive = readError !== null || state === 'unseen' || state === 'pasting' || !withdrawn;
474
+ if (mayStillArrive)
475
+ (0, instance_input_lock_1.leaveCarriedPasteMark)(ticket);
476
+ logger.error('paste-not-landed', {
477
+ sessionName,
478
+ cliToolId,
479
+ state,
480
+ bytes,
481
+ lines: lineCount,
482
+ shown,
483
+ lateAfterMs,
484
+ readError,
485
+ withdrawn,
486
+ carried: mayStillArrive,
487
+ });
488
+ const what = readError !== null
489
+ ? `the composer could not be read while the paste was checked (${readError})`
490
+ : lateAfterMs !== null
491
+ ? `the paste appeared ${lateAfterMs}ms after the ${attempts * PASTE_LANDED_POLL_MS}ms check and was taken back out (the composer showed ${shown})`
492
+ : state === 'mismatch'
493
+ ? `the composer does not hold the message as sent (it shows ${shown})`
494
+ : state === 'pasting'
495
+ ? `the paste had not finished arriving after ${attempts * PASTE_LANDED_POLL_MS}ms (the composer shows ${shown})`
496
+ : `the message never appeared in the composer (${shown})`;
761
497
  throw new Error(`Message body did not arrive intact for session ${sessionName}: ${what}; the message is ${bytes} bytes / ${lineCount} lines. ` +
762
498
  'Enter was not pressed, so nothing was submitted (Issue #2464).');
763
499
  }
764
- /** The text with every whitespace character removed — wrapping and indent proof. */
765
- function compactText(text) {
766
- return text.replace(/\s+/g, '');
500
+ /**
501
+ * Whether the composer shows a paste placeholder whose count is not this body's
502
+ * (Issue #3945): one counting fewer or more, or more than one placeholder.
503
+ */
504
+ function composerShowsForeignPasteToken(output, cliToolId, message, composerSpec) {
505
+ const lines = (0, submit_composer_read_1.withoutTrailingBlankRows)((0, cli_patterns_1.stripAnsi)(output).split('\n'));
506
+ const composer = (0, submit_composer_read_1.readSubmitComposer)(output, cliToolId, composerSpec.reader, lines, lines.slice(-submit_composer_read_1.VERIFY_WINDOW_LINES), message);
507
+ if (composer.kind !== 'text')
508
+ return false;
509
+ if (!composer.rows.some((row) => (0, submit_composer_read_1.findPasteTokens)(row).tokens.length > 0))
510
+ return false;
511
+ return (0, submit_composer_read_1.classifyPasteLanded)(output, cliToolId, message, composerSpec) !== 'landed';
767
512
  }
768
513
  /**
769
514
  * The part of a typed body the composer reader can see (Issue #3366).
@@ -781,6 +526,12 @@ function visibleTypedBody(message) {
781
526
  const blank = lines.findIndex((line, index) => index > first && line.trim() === '');
782
527
  return lines.slice(0, blank < 0 ? lines.length : blank).join('\n');
783
528
  }
529
+ /** Whether the whole codex composer, read past the bounded readers (Issue #3906), is exactly `message`. */
530
+ function codexComposerShowsWholeBody(output, message, composerSpec) {
531
+ const lines = (0, submit_composer_read_1.withoutTrailingBlankRows)((0, cli_patterns_1.stripAnsi)(output).split('\n'));
532
+ const composer = (0, submit_composer_read_1.readSubmitComposer)(output, 'codex', composerSpec.reader, lines, lines.slice(-submit_composer_read_1.VERIFY_WINDOW_LINES), message);
533
+ return composer.kind === 'text' && composer.region !== undefined && (0, submit_composer_read_1.compactText)(composer.region) === (0, submit_composer_read_1.compactText)(message);
534
+ }
784
535
  /**
785
536
  * Wait until the composer shows the typed body; only then may Enter be pressed
786
537
  * (Issue #3366).
@@ -794,29 +545,56 @@ function visibleTypedBody(message) {
794
545
  * a prefix is not enough, because codex can draw the first keystrokes before it
795
546
  * decides the rest are a burst.
796
547
  *
548
+ * On codex the verdict is the whole composer against the whole body
549
+ * ({@link codexComposerShowsWholeBody}, Issue #3906): the extractor's text is
550
+ * the body's first paragraph at most, so on its own it would let Enter go on a
551
+ * body whose later paragraphs had not been drawn.
552
+ *
797
553
  * A body that never appears is taken back out and the send THROWS without
798
554
  * Enter — nothing was submitted, so the caller must not print `Message sent.`.
799
555
  *
800
556
  * @throws Error when the composer does not show the body within the attempts
801
557
  */
802
558
  async function confirmTypedBodyLanded(params) {
803
- const { sessionName, message, cliToolId, composer, attempts } = params;
804
- const expected = compactText(visibleTypedBody(message));
559
+ const { sessionName, message, cliToolId, composer, attempts, ticket } = params;
560
+ const expected = (0, submit_composer_read_1.compactText)(visibleTypedBody(message));
805
561
  if (expected === '')
806
562
  return;
807
563
  let output = '';
808
- for (let attempt = 0; attempt < Math.max(1, attempts); attempt++) {
809
- await new Promise((resolve) => setTimeout(resolve, TYPED_BODY_POLL_MS));
810
- output = await (0, tmux_1.capturePane)(sessionName, { startLine: -composer.verifyCaptureLines });
811
- const read = (0, composer_text_1.extractComposerText)(output, cliToolId);
812
- if (read.state === 'content' && compactText(read.text) === expected)
813
- return;
564
+ let readError = null;
565
+ try {
566
+ for (let attempt = 0; attempt < Math.max(1, attempts); attempt++) {
567
+ await new Promise((resolve) => setTimeout(resolve, TYPED_BODY_POLL_MS));
568
+ output = await (0, tmux_1.capturePane)(sessionName, { startLine: -composer.verifyCaptureLines });
569
+ // Issue #3906: on codex the whole composer must show the whole body. The
570
+ // extractor's excerpt stops at the first blank row, so its match is only
571
+ // the first paragraph — a five-paragraph body with one paragraph drawn
572
+ // would pass on it — and it cannot reach a body of more than four blocks.
573
+ if (cliToolId === 'codex') {
574
+ if (codexComposerShowsWholeBody(output, message, composer))
575
+ return;
576
+ continue;
577
+ }
578
+ const read = (0, composer_text_1.extractComposerText)(output, cliToolId);
579
+ if (read.state === 'content' && (0, submit_composer_read_1.compactText)(read.text) === expected)
580
+ return;
581
+ }
582
+ }
583
+ catch (error) {
584
+ readError = error instanceof Error ? error.message : String(error);
814
585
  }
815
586
  const bytes = Buffer.byteLength(message, 'utf8');
816
- const shown = describeComposer(output, cliToolId, composer);
817
- await withdrawUnsentBody(sessionName, cliToolId, composer);
587
+ const shown = readError === null ? describeComposer(output, cliToolId, composer, message) : 'an unreadable pane';
588
+ // Issue #3945: a body never seen (codex can draw a burst late), a read that
589
+ // threw, or a withdrawal that was not confirmed may still put text in the
590
+ // composer after this throw — the next send waits that out.
591
+ const seen = readError === null && composerHoldsText(output, cliToolId, composer, message);
592
+ const withdrawn = await withdrawUnsentBody(sessionName, cliToolId, composer, ticket);
818
593
  (0, tmux_capture_cache_1.invalidateCache)(sessionName);
819
- logger.error('typed-body-not-landed', { sessionName, cliToolId, bytes, attempts, shown });
594
+ const mayStillArrive = !seen || !withdrawn;
595
+ if (mayStillArrive)
596
+ (0, instance_input_lock_1.leaveCarriedPasteMark)(ticket);
597
+ logger.error('typed-body-not-landed', { sessionName, cliToolId, bytes, attempts, shown, readError, carried: mayStillArrive });
820
598
  throw new Error(`Message body did not appear in the composer for session ${sessionName} within ` +
821
599
  `${attempts * TYPED_BODY_POLL_MS}ms (it shows ${shown}); the message is ${bytes} bytes. ` +
822
600
  'Enter was not pressed, so nothing was submitted (Issue #3366).');
@@ -868,10 +646,18 @@ async function confirmTypedBodyLanded(params) {
868
646
  *
869
647
  * @throws Error when the composer still holds text after the pass cap.
870
648
  */
871
- async function clearComposerBeforeSend(sessionName, cliToolId, composerSpec = (0, composer_spec_1.resolveComposerSpec)(cliToolId)) {
649
+ async function clearComposerBeforeSend(sessionName, cliToolId, composerSpec = (0, composer_spec_1.resolveComposerSpec)(cliToolId), options = {}) {
872
650
  if (!composerSpec.clearBeforeSend)
873
651
  return;
874
- const result = await (0, composer_clear_1.clearComposer)(sessionName, cliToolId);
652
+ // Issue #3945: the first read is the re-check's frame, and every pass asks
653
+ // first whether this send still owns the composer.
654
+ const { ticket } = options;
655
+ const result = await (0, composer_clear_1.clearComposer)(sessionName, cliToolId, {
656
+ ...(options.initialCapture !== undefined ? { initialCapture: options.initialCapture } : {}),
657
+ ...(ticket !== undefined ? { beforePass: () => ticket.isCurrent() } : {}),
658
+ });
659
+ if (ticket !== undefined)
660
+ assertInputOwner(ticket, cliToolId, 'the pre-send clear', false);
875
661
  if (result.state === 'content') {
876
662
  logger.error('pre-send-composer-clear-failed', {
877
663
  sessionName,
@@ -912,23 +698,57 @@ async function clearComposerBeforeSend(sessionName, cliToolId, composerSpec = (0
912
698
  * and Enter waits until the composer shows all of it (Issue #2464); a body that
913
699
  * does not arrive intact THROWS before Enter, with nothing submitted.
914
700
  *
701
+ * Issue #3945: the whole of it — clear, body, Enter, read-back, withdrawal —
702
+ * runs as the session's only writer ({@link withInstanceInputLock}); before
703
+ * anything is typed the pane is re-read under the lock, on every send
704
+ * ({@link recheckComposerBeforeInput}), and a carried paste mark is waited out
705
+ * ({@link waitOutCarriedPaste}, then the re-check again).
706
+ *
915
707
  * @throws Error when the body does not arrive intact, or submit cannot be
916
- * confirmed within the bounded attempts.
708
+ * confirmed within the bounded attempts; `InstanceInputLockTimeoutError`
709
+ * when the composer was not free in time (nothing typed).
917
710
  */
918
711
  async function sendMessageWithSubmitVerification(params) {
712
+ await (0, instance_input_lock_1.withInstanceInputLock)(params.sessionName, (ticket) => sendUnderInputLock(params, ticket));
713
+ }
714
+ async function sendUnderInputLock(params, ticket) {
919
715
  const { sessionName, message, cliToolId, composer = (0, composer_spec_1.resolveComposerSpec)(cliToolId), textInputWaitMs = cli_tool_timing_config_1.TUI_TEXT_INPUT_WAIT_MS, interEnterWaitMs = cli_tool_timing_config_1.TUI_TEXT_INPUT_WAIT_MS, verifyAttempts = DEFAULT_VERIFY_ATTEMPTS, verifyDelayMs = cli_tool_timing_config_1.TUI_MESSAGE_PROCESSED_WAIT_MS, pasteLandedAttempts = DEFAULT_PASTE_LANDED_ATTEMPTS, awaitTypedBody = false, typedBodyAttempts = DEFAULT_TYPED_BODY_ATTEMPTS, } = params;
920
716
  const submitEnterCount = params.submitEnterCount ?? composer.submitEnterCount;
717
+ // -1. Issue #3945 (review-1 #4): every send re-reads the pane once it owns
718
+ // the composer, whether or not it queued — the prompt guard and the
719
+ // tool's readiness wait ran before the lock, and a dialog can open in the
720
+ // waits between them and the first key (claude's settle wait, a queue
721
+ // behind another writer). A dialog refuses the send at once, before any
722
+ // carried paste is waited out (a refusal leaves the mark as it is); a
723
+ // send that did wait one out reads again after the wait. The last read
724
+ // is the pre-send clear's first: a claude/codex send with no mark reads
725
+ // no more often than before; any other tool gains this one capture.
726
+ let frame = await (0, composer_clear_1.recheckComposerBeforeInput)(sessionName, cliToolId);
727
+ if (await waitOutCarriedPaste(sessionName, cliToolId, composer, ticket)) {
728
+ frame = await (0, composer_clear_1.recheckComposerBeforeInput)(sessionName, cliToolId);
729
+ }
921
730
  // 0. Empty the composer first (Issue #1880). The body below is typed at the
922
731
  // TUI's current cursor position, so anything already in the box would be
923
732
  // spliced into it. Throws for a claude composer that could not be emptied.
924
- await clearComposerBeforeSend(sessionName, cliToolId, composer);
733
+ await clearComposerBeforeSend(sessionName, cliToolId, composer, { initialCapture: frame, ticket });
925
734
  if (Buffer.byteLength(message, 'utf8') > exports.LITERAL_SEND_MAX_BYTES) {
926
735
  // 1'. A body that would reach the TUI as more than one pty read is pasted
927
736
  // as ONE bracketed paste, and Enter waits until the composer shows all
928
737
  // of it (Issue #2464). Typed, Claude Code would keep only its last read.
929
738
  const pastedAt = Date.now();
930
- await pasteBody(sessionName, message);
931
- await confirmPasteLanded({ sessionName, message, cliToolId, composer, attempts: pasteLandedAttempts });
739
+ assertInputOwner(ticket, cliToolId, 'the paste', false);
740
+ try {
741
+ await pasteBody(sessionName, message, ticket, cliToolId);
742
+ }
743
+ catch (error) {
744
+ // Whether tmux put any of it into the pane is unknown — except after a
745
+ // refused input boundary (Issue #3992), which stops before `paste-buffer`:
746
+ // a mark then would only hold the next send off for nothing.
747
+ if (!(0, instance_input_lock_1.isInputBoundaryRefusal)(error))
748
+ (0, instance_input_lock_1.leaveCarriedPasteMark)(ticket);
749
+ throw error;
750
+ }
751
+ await confirmPasteLanded({ sessionName, message, cliToolId, composer, attempts: pasteLandedAttempts, ticket });
932
752
  // 2'. Keep the tool's own registration delay as a floor.
933
753
  const remaining = textInputWaitMs - (Date.now() - pastedAt);
934
754
  if (remaining > 0) {
@@ -946,13 +766,29 @@ async function sendMessageWithSubmitVerification(params) {
946
766
  // nowhere at all, with `rc 0`. All four measured on tmux 3.5a; the argv is
947
767
  // built in `lib/tmux/key-sequence.ts`, which carries the table.
948
768
  const typedAt = Date.now();
949
- await (0, tmux_1.sendKeys)(sessionName, message, false, { literal: true });
769
+ assertInputOwner(ticket, cliToolId, 'the body', false);
770
+ // Issue #3953: the send's stamp is taken here — after the lock, the carried
771
+ // mark, the re-check and the clear, right before the body's first key — so a
772
+ // previous turn that ended during any of them is older than this send.
773
+ (0, instance_input_lock_1.noteInputStart)();
774
+ try {
775
+ await (0, tmux_1.sendKeys)(sessionName, message, false, { literal: true });
776
+ }
777
+ catch (error) {
778
+ // Issue #3945 (review-1 #6): a keystroke send that failed may still have
779
+ // put part of the body into the pane (a timed-out `send-keys`, #3880's
780
+ // `indeterminate`), to be drawn after this send has let the composer go.
781
+ // Only a call tmux never started (`TmuxSendError.delivery`) typed nothing.
782
+ if (error?.delivery !== 'not-started')
783
+ (0, instance_input_lock_1.leaveCarriedPasteMark)(ticket);
784
+ throw error;
785
+ }
950
786
  // 2. Let the TUI register the input before pressing Enter. On codex that
951
787
  // means waiting until the body is drawn (Issue #3366): an Enter pressed
952
788
  // while codex still holds the keystrokes as a paste burst becomes a
953
789
  // newline, and the body stays unsent. The fixed wait stays as a floor.
954
790
  if (awaitTypedBody && composer_text_1.SUPPORTED_COMPOSER_TOOLS.has(cliToolId)) {
955
- await confirmTypedBodyLanded({ sessionName, message, cliToolId, composer, attempts: typedBodyAttempts });
791
+ await confirmTypedBodyLanded({ sessionName, message, cliToolId, composer, attempts: typedBodyAttempts, ticket });
956
792
  }
957
793
  const remaining = textInputWaitMs - (Date.now() - typedAt);
958
794
  if (remaining > 0) {
@@ -961,6 +797,7 @@ async function sendMessageWithSubmitVerification(params) {
961
797
  }
962
798
  // 3. Submit as a separate command (double Enter for vibe-local's IME mode).
963
799
  for (let i = 0; i < Math.max(1, submitEnterCount); i++) {
800
+ assertInputOwner(ticket, cliToolId, 'Enter', true);
964
801
  await (0, tmux_1.sendSpecialKeys)(sessionName, ['Enter']);
965
802
  if (i < submitEnterCount - 1) {
966
803
  await new Promise((resolve) => setTimeout(resolve, interEnterWaitMs));
@@ -978,7 +815,7 @@ async function sendMessageWithSubmitVerification(params) {
978
815
  for (let attempt = 0; attempt <= attempts; attempt++) {
979
816
  await new Promise((resolve) => setTimeout(resolve, verifyDelayMs));
980
817
  const output = await (0, tmux_1.capturePane)(sessionName, { startLine: -composer.verifyCaptureLines });
981
- const state = classifySubmit(output, cliToolId, message, composer);
818
+ const state = (0, submit_composer_read_1.classifySubmit)(output, cliToolId, message, composer);
982
819
  if (state === 'submitted') {
983
820
  (0, tmux_capture_cache_1.invalidateCache)(sessionName);
984
821
  return;
@@ -990,7 +827,12 @@ async function sendMessageWithSubmitVerification(params) {
990
827
  // (flavor B). Clear the input line (best-effort) and surface the failure
991
828
  // to the caller instead of ever resending Enter.
992
829
  try {
993
- await (0, tmux_1.clearInputLine)(sessionName);
830
+ if (ticket.isCurrent()) {
831
+ await (0, tmux_1.clearInputLine)(sessionName);
832
+ }
833
+ else {
834
+ logger.error('submit-clear-input-skipped-not-owner', { sessionName, cliToolId, generation: ticket.generation });
835
+ }
994
836
  }
995
837
  catch (clearError) {
996
838
  logger.error('submit-clear-input-failed', {
@@ -1003,15 +845,31 @@ async function sendMessageWithSubmitVerification(params) {
1003
845
  logger.error('submit-replaced-by-tui-completion', { sessionName, cliToolId, attempt });
1004
846
  throw new Error(`Message was replaced by a TUI autocompletion for session ${sessionName}; the input no longer matches the sent text. Cleared the input line without submitting to avoid executing a different command.`);
1005
847
  }
1006
- // state === 'pending' after the final resend's read-back: give up below.
848
+ // state === 'pending' / 'indeterminate' after the final read-back: give up below.
1007
849
  if (attempt === attempts)
1008
850
  break;
851
+ // state === 'indeterminate' (Issue #3906) — no Enter: the composer does not
852
+ // show the body, so another Enter could submit whatever it does show.
853
+ if (state === 'indeterminate') {
854
+ logger.warn('submit-not-confirmed:composer-unreadable', { sessionName, cliToolId, attempt });
855
+ continue;
856
+ }
857
+ // Issue #3945 (review #1): a paste placeholder that does not count this
858
+ // body is not this body. It can only be a paste that arrived after the
859
+ // initial Enter (a carried send's, past its mark), and another Enter would
860
+ // submit it. One that counts exactly this body cannot be told apart: that
861
+ // Enter is the accepted gap (LATE_TOKEN_AFTER_ENTER_SAME_COUNT in the tests).
862
+ if (composerShowsForeignPasteToken(output, cliToolId, message, composer)) {
863
+ logger.warn('submit-not-confirmed:foreign-paste-token', { sessionName, cliToolId, attempt });
864
+ continue;
865
+ }
1009
866
  // state === 'pending' — still typed-but-unsent, resend a single Enter and re-check.
1010
867
  logger.warn('submit-not-confirmed:resending-enter', {
1011
868
  sessionName,
1012
869
  cliToolId,
1013
870
  attempt,
1014
871
  });
872
+ assertInputOwner(ticket, cliToolId, 'a resent Enter', true);
1015
873
  await (0, tmux_1.sendSpecialKeys)(sessionName, ['Enter']);
1016
874
  }
1017
875
  (0, tmux_capture_cache_1.invalidateCache)(sessionName);