commandmate 0.49.1 → 0.49.2

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 (456) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +128 -132
  3. package/.next/app-path-routes-manifest.json +22 -22
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/prerender-manifest.json +12 -12
  6. package/.next/required-server-files.json +1 -1
  7. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  8. package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
  9. package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
  10. package/.next/server/app/api/app/release-notes/route_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  12. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/capabilities/route.js +1 -1
  17. package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
  18. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  22. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  24. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  25. package/.next/server/app/api/hooks/agent-event/route.js +2 -2
  26. package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
  27. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  28. package/.next/server/app/api/hooks/claude-done/route.js +2 -2
  29. package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
  30. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  31. package/.next/server/app/api/hooks/permission-request/route.js +1 -1
  32. package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
  33. package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
  37. package/.next/server/app/api/push/subscriptions/route.js +1 -1
  38. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  40. package/.next/server/app/api/relays/[relayId]/cancel/route.js +1 -1
  41. package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
  42. package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
  43. package/.next/server/app/api/relays/[relayId]/route_client-reference-manifest.js +1 -1
  44. package/.next/server/app/api/relays/route.js +1 -1
  45. package/.next/server/app/api/relays/route.js.nft.json +1 -1
  46. package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
  47. package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
  48. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  49. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  50. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
  51. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  52. package/.next/server/app/api/repositories/clone/route.js +1 -1
  53. package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
  54. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  55. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/repositories/restore/route.js +1 -1
  57. package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
  58. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/repositories/route.js +1 -1
  60. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  61. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/repositories/scan/route.js +1 -1
  63. package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
  64. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  65. package/.next/server/app/api/repositories/sync/route.js +1 -1
  66. package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
  67. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  68. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/settings/default-agents/route.js +1 -1
  70. package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
  71. package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
  72. package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
  73. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  74. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  75. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  76. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  78. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  79. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  80. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  81. package/.next/server/app/api/tasks/[taskId]/route.js +1 -1
  82. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  83. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  84. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  85. package/.next/server/app/api/verification/runs/[runId]/route.js +1 -1
  86. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  87. package/.next/server/app/api/verification/runs/route.js +1 -1
  88. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  90. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  91. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
  93. package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
  94. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
  96. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
  97. package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
  98. package/.next/server/app/api/worktrees/[id]/cli-reference/route.js +1 -1
  99. package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
  100. package/.next/server/app/api/worktrees/[id]/cli-tool/route.js +1 -1
  101. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +1 -1
  103. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  104. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  105. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  106. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  107. package/.next/server/app/api/worktrees/[id]/direct-input/route.js +1 -1
  108. package/.next/server/app/api/worktrees/[id]/direct-input/route.js.nft.json +1 -1
  109. package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
  110. package/.next/server/app/api/worktrees/[id]/env/route.js +1 -1
  111. package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
  112. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
  113. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  114. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +1 -1
  115. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  116. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  117. package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js +1 -1
  118. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js +1 -1
  120. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  121. package/.next/server/app/api/worktrees/[id]/git/branches/route.js +1 -1
  122. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/git/checkout/route.js +1 -1
  124. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/git/commit/route.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  127. package/.next/server/app/api/worktrees/[id]/git/diff/route.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  129. package/.next/server/app/api/worktrees/[id]/git/fetch/route.js +1 -1
  130. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/git/log/route.js +1 -1
  132. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  133. package/.next/server/app/api/worktrees/[id]/git/pull/route.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  135. package/.next/server/app/api/worktrees/[id]/git/push/route.js +1 -1
  136. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  137. package/.next/server/app/api/worktrees/[id]/git/reset/route.js +1 -1
  138. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  139. package/.next/server/app/api/worktrees/[id]/git/revert/route.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  141. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js +1 -1
  142. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/git/stage/route.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/git/staged/route.js +1 -1
  146. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js +1 -1
  148. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  149. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  151. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js +1 -1
  152. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  153. package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js +1 -1
  154. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  155. package/.next/server/app/api/worktrees/[id]/git/stash/route.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  157. package/.next/server/app/api/worktrees/[id]/git/status/route.js +1 -1
  158. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  159. package/.next/server/app/api/worktrees/[id]/git/unstage/route.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  161. package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js +1 -1
  162. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  163. package/.next/server/app/api/worktrees/[id]/instances/notes/route.js +1 -1
  164. package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
  165. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js +1 -1
  166. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
  167. package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
  168. package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
  170. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  171. package/.next/server/app/api/worktrees/[id]/kill-session/route.js +2 -1
  172. package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
  173. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  174. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js +1 -1
  175. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js.nft.json +1 -1
  176. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  177. package/.next/server/app/api/worktrees/[id]/logs/route.js +2 -2
  178. package/.next/server/app/api/worktrees/[id]/logs/route.js.nft.json +1 -1
  179. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  180. package/.next/server/app/api/worktrees/[id]/marp-render/route.js +1 -1
  181. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  182. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js +1 -1
  183. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  184. package/.next/server/app/api/worktrees/[id]/memos/route.js +1 -1
  185. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  186. package/.next/server/app/api/worktrees/[id]/messages/route.js +1 -1
  187. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  188. package/.next/server/app/api/worktrees/[id]/opencode/diff/route.js +1 -1
  189. package/.next/server/app/api/worktrees/[id]/opencode/diff/route.js.nft.json +1 -1
  190. package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
  191. package/.next/server/app/api/worktrees/[id]/opencode/session/route.js +1 -1
  192. package/.next/server/app/api/worktrees/[id]/opencode/session/route.js.nft.json +1 -1
  193. package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
  194. package/.next/server/app/api/worktrees/[id]/opencode/share/route.js +1 -1
  195. package/.next/server/app/api/worktrees/[id]/opencode/share/route.js.nft.json +1 -1
  196. package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
  197. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  198. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
  199. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  200. package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route.js +1 -1
  201. package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route.js.nft.json +1 -1
  202. package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route_client-reference-manifest.js +1 -1
  203. package/.next/server/app/api/worktrees/[id]/resolve-target/route.js +1 -1
  204. package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
  205. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
  206. package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
  207. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  208. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  209. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  210. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  211. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +1 -1
  212. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  213. package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +1 -1
  214. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  215. package/.next/server/app/api/worktrees/[id]/schedules/route.js +1 -1
  216. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  217. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  218. package/.next/server/app/api/worktrees/[id]/send/route.js +2 -2
  219. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  220. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  221. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +3 -3
  222. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
  223. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  224. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  225. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  226. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  227. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  228. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  229. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  230. package/.next/server/app/api/worktrees/[id]/skills/route.js +1 -1
  231. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  232. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
  233. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  234. package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
  235. package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
  236. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  237. package/.next/server/app/api/worktrees/[id]/tasks/route.js +1 -1
  238. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  239. package/.next/server/app/api/worktrees/[id]/terminal/route.js +2 -2
  240. package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
  241. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  242. package/.next/server/app/api/worktrees/[id]/timers/history/route.js +1 -1
  243. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  244. package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
  245. package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
  246. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  247. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js +1 -1
  248. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js.nft.json +1 -1
  249. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  250. package/.next/server/app/api/worktrees/[id]/todos/route.js +1 -1
  251. package/.next/server/app/api/worktrees/[id]/todos/route.js.nft.json +1 -1
  252. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  253. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  254. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  255. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  256. package/.next/server/app/api/worktrees/[id]/verify/config/route.js +1 -1
  257. package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
  258. package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -1
  259. package/.next/server/app/api/worktrees/[id]/verify/route.js.nft.json +1 -1
  260. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  261. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js +1 -1
  262. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js.nft.json +1 -1
  263. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
  264. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route.js +1 -1
  265. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  266. package/.next/server/app/api/worktrees/[id]/verify/runs/route.js +1 -1
  267. package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
  268. package/.next/server/app/api/worktrees/[id]/viewed/route.js +1 -1
  269. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  270. package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
  271. package/.next/server/app/api/worktrees/route.js +1 -1
  272. package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
  273. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  274. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  275. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  276. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  277. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  278. package/.next/server/app/page_client-reference-manifest.js +1 -1
  279. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  280. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  281. package/.next/server/app/review/page.js +1 -1
  282. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  283. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  284. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  285. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  286. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  287. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  288. package/.next/server/app/worktrees/[id]/page.js +2 -2
  289. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  290. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  291. package/.next/server/app-paths-manifest.json +22 -22
  292. package/.next/server/chunks/1062.js +1 -0
  293. package/.next/server/chunks/110.js +1 -0
  294. package/.next/server/chunks/1501.js +5 -4
  295. package/.next/server/chunks/1656.js +2 -2
  296. package/.next/server/chunks/1957.js +2 -0
  297. package/.next/server/chunks/2119.js +1 -1
  298. package/.next/server/chunks/2445.js +1 -1
  299. package/.next/server/chunks/2897.js +1 -0
  300. package/.next/server/chunks/3417.js +1 -0
  301. package/.next/server/chunks/3505.js +1 -1
  302. package/.next/server/chunks/3756.js +1 -0
  303. package/.next/server/chunks/3801.js +3 -3
  304. package/.next/server/chunks/4911.js +1 -0
  305. package/.next/server/chunks/4936.js +1 -0
  306. package/.next/server/chunks/5209.js +2 -1
  307. package/.next/server/chunks/5354.js +1 -1
  308. package/.next/server/chunks/6130.js +1 -1
  309. package/.next/server/chunks/6401.js +1 -1
  310. package/.next/server/chunks/7023.js +2 -2
  311. package/.next/server/chunks/7905.js +1 -1
  312. package/.next/server/chunks/8581.js +15 -15
  313. package/.next/server/chunks/8728.js +2 -2
  314. package/.next/server/chunks/8782.js +1 -1
  315. package/.next/server/chunks/9390.js +1 -1
  316. package/.next/server/chunks/9584.js +1 -1
  317. package/.next/server/chunks/9731.js +2 -2
  318. package/.next/server/middleware-manifest.json +5 -5
  319. package/.next/server/pages/500.html +1 -1
  320. package/.next/server/server-reference-manifest.json +1 -1
  321. package/.next/static/chunks/{2407-675ba6b21844dc3b.js → 2407-07a237575e1ceb9e.js} +1 -1
  322. package/.next/static/chunks/3931-61ad1a4fc0208d0e.js +1 -0
  323. package/.next/static/chunks/5794-7975b8e51e731b19.js +1 -0
  324. package/.next/static/chunks/6966-d8dc6032410ffaba.js +1 -0
  325. package/.next/static/chunks/7197-ed3b3d99ac3bd450.js +1 -0
  326. package/.next/static/chunks/7636-a48cf0f7110250c5.js +1 -0
  327. package/.next/static/chunks/app/layout-4f64316957b0a8e5.js +1 -0
  328. package/.next/static/chunks/app/more/page-ff5af5ca48774c89.js +1 -0
  329. package/.next/static/chunks/app/page-b4863bfe0452e09d.js +1 -0
  330. package/.next/static/chunks/app/review/page-ff3efb96fdf9bb4b.js +1 -0
  331. package/.next/static/chunks/app/sessions/{page-890fd50ec9739973.js → page-c6eb7c02db2f4c80.js} +1 -1
  332. package/.next/static/chunks/app/worktrees/[id]/{page-f6d3ab8185d93aae.js → page-33afc6aa96289fb0.js} +1 -1
  333. package/.next/trace +13 -13
  334. package/dist/cli/commands/ask.d.ts.map +1 -1
  335. package/dist/cli/commands/ask.js +56 -5
  336. package/dist/cli/commands/attach.d.ts +4 -1
  337. package/dist/cli/commands/attach.d.ts.map +1 -1
  338. package/dist/cli/commands/attach.js +19 -7
  339. package/dist/cli/commands/command-target.d.ts +7 -0
  340. package/dist/cli/commands/command-target.d.ts.map +1 -1
  341. package/dist/cli/commands/command-target.js +10 -0
  342. package/dist/cli/commands/instances.d.ts.map +1 -1
  343. package/dist/cli/commands/instances.js +38 -2
  344. package/dist/cli/commands/message-dispatch.d.ts +17 -3
  345. package/dist/cli/commands/message-dispatch.d.ts.map +1 -1
  346. package/dist/cli/commands/message-dispatch.js +14 -8
  347. package/dist/cli/commands/relays.d.ts +2 -1
  348. package/dist/cli/commands/relays.d.ts.map +1 -1
  349. package/dist/cli/commands/relays.js +4 -3
  350. package/dist/cli/commands/respond-strict.d.ts.map +1 -1
  351. package/dist/cli/commands/respond-strict.js +22 -5
  352. package/dist/cli/commands/respond.d.ts +2 -2
  353. package/dist/cli/commands/respond.d.ts.map +1 -1
  354. package/dist/cli/commands/respond.js +40 -37
  355. package/dist/cli/commands/send.d.ts.map +1 -1
  356. package/dist/cli/commands/send.js +8 -4
  357. package/dist/cli/commands/wait-instance.d.ts +9 -1
  358. package/dist/cli/commands/wait-instance.d.ts.map +1 -1
  359. package/dist/cli/commands/wait-instance.js +15 -0
  360. package/dist/cli/commands/wait-poll-state.d.ts +18 -0
  361. package/dist/cli/commands/wait-poll-state.d.ts.map +1 -1
  362. package/dist/cli/commands/wait-verify.d.ts +2 -1
  363. package/dist/cli/commands/wait-verify.d.ts.map +1 -1
  364. package/dist/cli/commands/wait-verify.js +5 -1
  365. package/dist/cli/commands/wait.d.ts.map +1 -1
  366. package/dist/cli/commands/wait.js +37 -13
  367. package/dist/cli/commands/whoami.d.ts.map +1 -1
  368. package/dist/cli/commands/whoami.js +3 -1
  369. package/dist/cli/docs/agent-operations.d.ts +1 -1
  370. package/dist/cli/docs/agent-operations.d.ts.map +1 -1
  371. package/dist/cli/docs/agent-operations.js +1 -0
  372. package/dist/cli/types/api-responses.d.ts +3 -1
  373. package/dist/cli/types/api-responses.d.ts.map +1 -1
  374. package/dist/cli/utils/api-client.d.ts +55 -1
  375. package/dist/cli/utils/api-client.d.ts.map +1 -1
  376. package/dist/cli/utils/api-client.js +220 -18
  377. package/dist/cli/utils/follow-up-command.d.ts +38 -0
  378. package/dist/cli/utils/follow-up-command.d.ts.map +1 -0
  379. package/dist/cli/utils/follow-up-command.js +57 -0
  380. package/dist/cli/utils/reply-ledger.d.ts +1 -1
  381. package/dist/cli/utils/reply-ledger.d.ts.map +1 -1
  382. package/dist/cli/utils/reply-ledger.js +7 -2
  383. package/dist/cli/utils/server-capabilities.d.ts +18 -0
  384. package/dist/cli/utils/server-capabilities.d.ts.map +1 -1
  385. package/dist/cli/utils/server-capabilities.js +36 -3
  386. package/dist/cli/utils/session-target.d.ts +1 -1
  387. package/dist/cli/utils/session-target.d.ts.map +1 -1
  388. package/dist/cli/utils/session-target.js +3 -0
  389. package/dist/cli/utils/verify-runner.d.ts +7 -0
  390. package/dist/cli/utils/verify-runner.d.ts.map +1 -1
  391. package/dist/cli/utils/verify-runner.js +51 -15
  392. package/dist/lib/cli-tools/session-name.d.ts.map +1 -1
  393. package/dist/lib/cli-tools/session-name.js +11 -3
  394. package/dist/lib/session/send-attempt-types.d.ts +25 -0
  395. package/dist/lib/session/send-attempt-types.d.ts.map +1 -1
  396. package/dist/lib/session/send-attempt-types.js +10 -1
  397. package/dist/lib/verification/session-kill-ledger.d.ts +110 -0
  398. package/dist/lib/verification/session-kill-ledger.d.ts.map +1 -0
  399. package/dist/lib/verification/session-kill-ledger.js +174 -0
  400. package/dist/server/locales/en/worktree.json +2 -0
  401. package/dist/server/locales/ja/worktree.json +2 -0
  402. package/dist/server/src/config/cli-tool-timing-config.js +1 -7
  403. package/dist/server/src/lib/auto-yes-poller.js +5 -1
  404. package/dist/server/src/lib/cli-tools/antigravity.js +5 -2
  405. package/dist/server/src/lib/cli-tools/base.js +39 -0
  406. package/dist/server/src/lib/cli-tools/codex.js +7 -4
  407. package/dist/server/src/lib/cli-tools/command-code.js +7 -3
  408. package/dist/server/src/lib/cli-tools/copilot.js +5 -3
  409. package/dist/server/src/lib/cli-tools/gemini.js +10 -2
  410. package/dist/server/src/lib/cli-tools/launch-keys.js +39 -0
  411. package/dist/server/src/lib/cli-tools/opencode-v2.js +6 -2
  412. package/dist/server/src/lib/cli-tools/opencode.js +5 -2
  413. package/dist/server/src/lib/cli-tools/session-name.js +11 -3
  414. package/dist/server/src/lib/cli-tools/submit-composer-read.js +16 -6
  415. package/dist/server/src/lib/cli-tools/submit-verified-sender.js +164 -7
  416. package/dist/server/src/lib/cli-tools/vibe-local.js +4 -2
  417. package/dist/server/src/lib/db/db-migration-path.js +63 -2
  418. package/dist/server/src/lib/detection/prompt-detect-multiple-choice.js +5 -4
  419. package/dist/server/src/lib/hooks/sources/copilot/hook-settings.js +2 -3
  420. package/dist/server/src/lib/prompt-answer-errors.js +76 -2
  421. package/dist/server/src/lib/session/agent-event-state.js +4 -0
  422. package/dist/server/src/lib/session/agent-session-lifecycle.js +6 -1
  423. package/dist/server/src/lib/session/claude-session.js +22 -6
  424. package/dist/server/src/lib/session/current-output-builder.js +5 -3
  425. package/dist/server/src/lib/session/current-output-history-writers.js +1 -1
  426. package/dist/server/src/lib/session/prompt-submit-receipt.js +155 -0
  427. package/dist/server/src/lib/session/prompt-waiting-guard.js +10 -3
  428. package/dist/server/src/lib/session/send-attempt-state.js +48 -0
  429. package/dist/server/src/lib/session/send-attempt-types.js +10 -1
  430. package/dist/server/src/lib/session/send-user-message.js +5 -4
  431. package/dist/server/src/lib/session/session-launch-flight.js +243 -0
  432. package/dist/server/src/lib/session/session-starting-state.js +40 -4
  433. package/dist/server/src/lib/session/structured-prompt.js +12 -9
  434. package/dist/server/src/lib/session/waiting-episode-binding.js +4 -2
  435. package/dist/server/src/lib/session-cleanup.js +32 -0
  436. package/dist/server/src/lib/session-key-sender.js +0 -27
  437. package/dist/server/src/lib/verification/env-clean-gate.js +129 -0
  438. package/dist/server/src/lib/verification/env-snapshot.js +11 -2
  439. package/dist/server/src/lib/verification/session-kill-ledger.js +174 -0
  440. package/package.json +5 -1
  441. package/release-notes/0.49.2.json +49 -0
  442. package/.next/server/chunks/3773.js +0 -1
  443. package/.next/server/chunks/5775.js +0 -1
  444. package/.next/server/chunks/7604.js +0 -2
  445. package/.next/static/chunks/3931-1a1abab16248f14d.js +0 -1
  446. package/.next/static/chunks/4768-ad6f82f034f21eae.js +0 -1
  447. package/.next/static/chunks/5794-80ac3f06f098ea29.js +0 -1
  448. package/.next/static/chunks/6654-f3534f35f16644bc.js +0 -1
  449. package/.next/static/chunks/7665-e9ef6e0a85b9fa49.js +0 -1
  450. package/.next/static/chunks/8606-ce17ffa77f39608e.js +0 -1
  451. package/.next/static/chunks/app/layout-8bfac4724277b47f.js +0 -1
  452. package/.next/static/chunks/app/more/page-87c84987b2765213.js +0 -1
  453. package/.next/static/chunks/app/page-1b820c421db48c2c.js +0 -1
  454. package/.next/static/chunks/app/review/page-e2fd4a590646a2d8.js +0 -1
  455. /package/.next/static/{fqfSDqQMweROeHUzOt_m1 → yGatWDsS532awSs51kXyd}/_buildManifest.js +0 -0
  456. /package/.next/static/{fqfSDqQMweROeHUzOt_m1 → yGatWDsS532awSs51kXyd}/_ssgManifest.js +0 -0
@@ -31,6 +31,8 @@ const terminal_keys_1 = require("../../types/terminal-keys");
31
31
  const cli_tool_timing_config_1 = require("../../config/cli-tool-timing-config");
32
32
  const tmux_pane_config_1 = require("../../config/tmux-pane-config");
33
33
  const session_starting_state_1 = require("../session/session-starting-state");
34
+ const session_launch_flight_1 = require("../session/session-launch-flight");
35
+ const launch_keys_1 = require("./launch-keys");
34
36
  const execAsync = (0, util_1.promisify)(child_process_1.exec);
35
37
  const logger = (0, logger_1.createLogger)('cli-tools/base');
36
38
  /**
@@ -221,6 +223,27 @@ class BaseCLITool {
221
223
  * @throws Whatever {@link launchSession} threw — unchanged, after reporting
222
224
  */
223
225
  async startSession(worktreeId, worktreePath, instanceId, model) {
226
+ // Issue #3981: one launch per session (`session-launch-flight`). A second
227
+ // request joins the launch in progress instead of starting its own — whose
228
+ // reuse branch would kill the first one's half-launched pane — and a caller
229
+ // that holds the input lock is refused rather than made to wait (R1). A
230
+ // name that does not validate is left to `launchSession` to refuse, and
231
+ // reported as before. A start that asks for a model the launch in
232
+ // progress is not starting with is refused instead of joining it (#2771).
233
+ let sessionName = null;
234
+ try {
235
+ sessionName = this.getSessionName(worktreeId, instanceId);
236
+ }
237
+ catch {
238
+ // fall through: launchSession throws on it, inside the reporting below
239
+ }
240
+ const launch = () => this.startSessionOnce(worktreeId, worktreePath, instanceId, model);
241
+ if (sessionName === null)
242
+ return launch();
243
+ return (0, session_launch_flight_1.runSessionLaunch)(sessionName, this.name, launch, { cliToolId: this.id, model });
244
+ }
245
+ /** {@link startSession}'s body: one launch, its failure reported once. */
246
+ async startSessionOnce(worktreeId, worktreePath, instanceId, model) {
224
247
  // Issue #3195: this launch's "starting" record is written under this token
225
248
  // (see `session-starting-state`), so the `finally` below clears this
226
249
  // launch's record and never a later launch's of the same instance.
@@ -615,6 +638,11 @@ class BaseCLITool {
615
638
  */
616
639
  async requireSession(label, worktreeId, instanceId, options) {
617
640
  const sessionName = this.getSessionName(worktreeId, instanceId);
641
+ // Issue #3981: a pane another request is still launching reads as
642
+ // "exists, tool not live" and would be relaunched or typed into. Wait for
643
+ // that launch first — or, holding the input lock (claude and codex send
644
+ // under it), refuse with nothing typed (R1).
645
+ await (0, session_launch_flight_1.settleSessionLaunch)(sessionName, this.name);
618
646
  const exists = await (0, tmux_1.hasSession)(sessionName);
619
647
  if (!exists) {
620
648
  throw new Error(`${label} session ${sessionName} does not exist. Start the session first.`);
@@ -683,6 +711,17 @@ class BaseCLITool {
683
711
  }
684
712
  return { sessionName, exists, live: false };
685
713
  }
714
+ /**
715
+ * Type a launch's keys — its launch line, and anything that has to go in
716
+ * before it — in one `exclusive` turn of the instance input lock (Issue
717
+ * #3981, `./launch-keys`). The waits after the keys stay outside the lock.
718
+ *
719
+ * @param sessionName - tmux session name
720
+ * @param steps - Lines typed with Enter, or steps that type their own keys
721
+ */
722
+ async typeLaunchLines(sessionName, steps) {
723
+ await (0, launch_keys_1.typeLaunchLines)(sessionName, steps);
724
+ }
686
725
  /**
687
726
  * Create the tmux session a launch types into, then wait
688
727
  * {@link TUI_SESSION_CREATE_WAIT_MS} for it. Creation path only: on the #2070
@@ -244,11 +244,13 @@ class CodexTool extends base_1.BaseCLITool {
244
244
  // as the new one's.
245
245
  const relaunchIntoSamePane = async () => {
246
246
  (0, agent_session_lifecycle_1.beginAgentSession)({ worktreeId, cliToolId: sources_1.CODEX_CLI_TOOL_ID, instanceId });
247
- await (0, tmux_1.sendKeys)(sessionName, (0, launch_screen_1.withLaunchScreenCleared)(launchCommand), true);
247
+ // Issue #3981: one writer's turn, as the first launch line below.
248
+ await this.typeLaunchLines(sessionName, [(0, launch_screen_1.withLaunchScreenCleared)(launchCommand)]);
248
249
  await new Promise((resolve) => setTimeout(resolve, CODEX_INIT_WAIT_MS));
249
250
  };
250
- // Start Codex CLI in interactive mode
251
- await (0, tmux_1.sendKeys)(sessionName, (0, launch_screen_1.withLaunchScreenCleared)(launchCommand), true);
251
+ // Start Codex CLI in interactive mode. Issue #3981: in one writer's turn
252
+ // of the input lock (joined when this launch runs inside a send's).
253
+ await this.typeLaunchLines(sessionName, [(0, launch_screen_1.withLaunchScreenCleared)(launchCommand)]);
252
254
  // Wait for Codex to initialize
253
255
  await new Promise((resolve) => setTimeout(resolve, CODEX_INIT_WAIT_MS));
254
256
  // Poll until Codex interactive prompt is ready
@@ -771,7 +773,8 @@ class CodexTool extends base_1.BaseCLITool {
771
773
  }
772
774
  catch (error) {
773
775
  const errorMessage = (0, errors_1.getErrorMessage)(error);
774
- throw new Error(`Failed to send message to Codex: ${errorMessage}`);
776
+ // Issue #4031: the cause keeps a failed `load-buffer`'s code (`classifySendFailure`).
777
+ throw new Error(`Failed to send message to Codex: ${errorMessage}`, { cause: error });
775
778
  }
776
779
  }
777
780
  /**
@@ -238,11 +238,14 @@ class CommandCodeTool extends base_1.BaseCLITool {
238
238
  // shared TMUX_HISTORY_LIMIT default (Issue #1624).
239
239
  await this.createLaunchPane(sessionName, worktreePath);
240
240
  }
241
- await (0, tmux_1.sendKeys)(sessionName, (0, launch_screen_1.withLaunchScreenCleared)(buildCommandCodeLaunchCommand({
241
+ // Issue #3981: in one writer's turn of the input lock; the readiness
242
+ // wait below stays outside it.
243
+ const launchCommand = buildCommandCodeLaunchCommand({
242
244
  target: { worktreeId, cliToolId: tool_id_1.COMMAND_CODE_CLI_TOOL_ID, instanceId },
243
245
  executablePath: this.command,
244
246
  worktreePath,
245
- })), true);
247
+ });
248
+ await this.typeLaunchLines(sessionName, [(0, launch_screen_1.withLaunchScreenCleared)(launchCommand)]);
246
249
  await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.COMMAND_CODE_INIT_WAIT_MS));
247
250
  await this.waitForReady(sessionName);
248
251
  logger.info('started-command-code-session');
@@ -368,7 +371,8 @@ class CommandCodeTool extends base_1.BaseCLITool {
368
371
  // Issue #3006: passed through unwrapped so its `code` reaches the route.
369
372
  if ((0, session_start_error_1.isSessionStartTimeoutError)(error))
370
373
  throw error;
371
- const wrapped = new Error(`Failed to send message to Command Code: ${(0, errors_1.getErrorMessage)(error)}`);
374
+ // Issue #4031: the cause keeps a failed `load-buffer`'s code (`classifySendFailure`).
375
+ const wrapped = new Error(`Failed to send message to Command Code: ${(0, errors_1.getErrorMessage)(error)}`, { cause: error });
372
376
  // Issue #3772: the plan review refusal comes before the body; keep its code.
373
377
  if (error?.code === send_attempt_types_1.PLAN_REVIEW_SEND_REFUSED_CODE) {
374
378
  throw Object.assign(wrapped, { code: send_attempt_types_1.PLAN_REVIEW_SEND_REFUSED_CODE });
@@ -380,8 +380,9 @@ class CopilotTool extends base_1.BaseCLITool {
380
380
  // leaves it (`cli-tools/launch-window`).
381
381
  (0, launch_window_1.beginLaunchWindow)(sessionName);
382
382
  try {
383
- // Start Copilot CLI in interactive mode
384
- await (0, tmux_1.sendKeys)(sessionName, (0, launch_screen_1.withLaunchScreenCleared)(launchCommand), true);
383
+ // Start Copilot CLI in interactive mode. Issue #3981: in one writer's
384
+ // turn of the input lock; the readiness wait below stays outside it.
385
+ await this.typeLaunchLines(sessionName, [(0, launch_screen_1.withLaunchScreenCleared)(launchCommand)]);
385
386
  // Issue #1907: no blind sleep before this. The 4-second one that used to
386
387
  // sit here was a guess at how long copilot takes to paint (measured on
387
388
  // 1.0.80: banner at ~1.3 s, folder-trust dialog at ~2.5 s), and it was
@@ -742,7 +743,8 @@ class CopilotTool extends base_1.BaseCLITool {
742
743
  }
743
744
  catch (error) {
744
745
  const errorMessage = (0, errors_1.getErrorMessage)(error);
745
- throw new Error(`Failed to send message to Copilot: ${errorMessage}`);
746
+ // Issue #4031: the cause keeps a failed `load-buffer`'s code (`classifySendFailure`).
747
+ throw new Error(`Failed to send message to Copilot: ${errorMessage}`, { cause: error });
746
748
  }
747
749
  }
748
750
  /**
@@ -111,7 +111,8 @@ class GeminiTool extends base_1.BaseCLITool {
111
111
  // already in the pane is not run as part of it. Only the keys: the
112
112
  // waits below stay outside the lock, where a send waiting for the
113
113
  // prompt cannot be held behind them.
114
- await (0, instance_input_lock_1.withInstanceInputLock)(sessionName, () => (0, tmux_1.sendKeys)(sessionName, (0, launch_screen_1.withLaunchScreenCleared)(launchCommand), true));
114
+ // Issue #3981: through the one launch-key writer every tool shares.
115
+ await this.typeLaunchLines(sessionName, [(0, launch_screen_1.withLaunchScreenCleared)(launchCommand)]);
115
116
  // Wait for Gemini to initialize (minimum wait for banner/auth)
116
117
  await new Promise((resolve) => setTimeout(resolve, GEMINI_INIT_WAIT_MS));
117
118
  // Poll until Gemini interactive prompt is ready
@@ -207,6 +208,9 @@ class GeminiTool extends base_1.BaseCLITool {
207
208
  /**
208
209
  * Wait for Gemini prompt before sending a message.
209
210
  * Used by sendMessage to ensure Gemini is ready to accept input.
211
+ *
212
+ * @throws Error (`Gemini prompt not ready`) when the prompt did not appear
213
+ * within {@link GEMINI_PROMPT_WAIT_TIMEOUT_MS}; nothing was typed
210
214
  */
211
215
  async waitForPrompt(sessionName) {
212
216
  const startTime = Date.now();
@@ -225,7 +229,10 @@ class GeminiTool extends base_1.BaseCLITool {
225
229
  }
226
230
  await new Promise((resolve) => setTimeout(resolve, pollInterval));
227
231
  }
232
+ // Issue #3981: give up without typing, as codex does. Sending anyway put the
233
+ // body into whatever held the pane (a dialog, a slow start, a shell).
228
234
  logger.info('gemini-prompt-not-detected');
235
+ throw new Error('Gemini prompt not ready: timed out waiting for the input prompt before sending');
229
236
  }
230
237
  /**
231
238
  * Send a message to Gemini interactive session
@@ -258,7 +265,8 @@ class GeminiTool extends base_1.BaseCLITool {
258
265
  }
259
266
  catch (error) {
260
267
  const errorMessage = (0, errors_1.getErrorMessage)(error);
261
- throw new Error(`Failed to send message to Gemini: ${errorMessage}`);
268
+ // Issue #4031: the cause keeps a failed `load-buffer`'s code (`classifySendFailure`).
269
+ throw new Error(`Failed to send message to Gemini: ${errorMessage}`, { cause: error });
262
270
  }
263
271
  }
264
272
  /**
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ /**
3
+ * The keys a launch types into its pane, in one writer's turn (Issue #3981).
4
+ *
5
+ * #3975 put gemini's and claude's launch lines under the instance input lock;
6
+ * the other seven launch sites, and claude's `unset CLAUDECODE` before its
7
+ * line, still typed with no lock, so a send holding the composer could have
8
+ * them land in the middle of its body, paste or Enter. Every launch now types
9
+ * through {@link typeLaunchLines}: one `exclusive` turn for all of its lines
10
+ * (R2 of `session-launch-flight`), joined when the launcher already holds the
11
+ * lock (codex relaunching inside a send). The init polls and readiness waits
12
+ * that follow stay outside (#3975), so a send waiting for the prompt is never
13
+ * held behind them.
14
+ *
15
+ * @module lib/cli-tools/launch-keys
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.typeLaunchLines = typeLaunchLines;
19
+ const tmux_1 = require("../tmux/tmux");
20
+ const instance_input_lock_1 = require("../session/instance-input-lock");
21
+ /**
22
+ * Type `steps` into `sessionName` as one `exclusive` writer, in order.
23
+ *
24
+ * @param sessionName - tmux session name
25
+ * @param steps - Lines (typed with Enter) and self-typing steps
26
+ * @throws Whatever `withInstanceInputLock` throws when not admitted; nothing was typed then
27
+ */
28
+ async function typeLaunchLines(sessionName, steps) {
29
+ await (0, instance_input_lock_1.withInstanceInputLock)(sessionName, async () => {
30
+ for (const step of steps) {
31
+ if (typeof step === 'string') {
32
+ await (0, tmux_1.sendKeys)(sessionName, step, true);
33
+ }
34
+ else {
35
+ await step();
36
+ }
37
+ }
38
+ });
39
+ }
@@ -235,7 +235,10 @@ class OpenCodeV2Tool extends base_1.BaseCLITool {
235
235
  if (port === null) {
236
236
  logger.warn('opencode-v2-launch-without-server', { worktreeId, instanceId });
237
237
  }
238
- await (0, tmux_1.sendKeys)(sessionName, (0, launch_screen_1.withLaunchScreenCleared)((0, agent_session_lifecycle_1.buildAgentLaunchCommandLine)({ target, executablePath: executable.path, worktreePath })), true);
238
+ // Issue #3981: in one writer's turn of the input lock; the readiness
239
+ // wait below stays outside it.
240
+ const launchCommand = (0, agent_session_lifecycle_1.buildAgentLaunchCommandLine)({ target, executablePath: executable.path, worktreePath });
241
+ await this.typeLaunchLines(sessionName, [(0, launch_screen_1.withLaunchScreenCleared)(launchCommand)]);
239
242
  await this.waitForReady(sessionName);
240
243
  await (0, runtime_1.attachOpencodeV2EventStream)(target);
241
244
  logger.info('started-opencode-v2-session');
@@ -313,7 +316,8 @@ class OpenCodeV2Tool extends base_1.BaseCLITool {
313
316
  logger.info('sent-message-to-opencode-v2-session');
314
317
  }
315
318
  catch (error) {
316
- throw new Error(`Failed to send message to OpenCode V2: ${(0, errors_1.getErrorMessage)(error)}`);
319
+ // Issue #4031: the cause keeps a failed `load-buffer`'s code (`classifySendFailure`).
320
+ throw new Error(`Failed to send message to OpenCode V2: ${(0, errors_1.getErrorMessage)(error)}`, { cause: error });
317
321
  }
318
322
  }
319
323
  /**
@@ -335,7 +335,9 @@ class OpenCodeTool extends base_1.BaseCLITool {
335
335
  });
336
336
  }
337
337
  const launchedAt = Date.now();
338
- await (0, tmux_1.sendKeys)(sessionName, (0, launch_screen_1.withLaunchScreenCleared)(launchCommand), true);
338
+ // Issue #3981: in one writer's turn of the input lock; the readiness
339
+ // wait below stays outside it.
340
+ await this.typeLaunchLines(sessionName, [(0, launch_screen_1.withLaunchScreenCleared)(launchCommand)]);
339
341
  // Issue #1908: poll for opencode's own composer instead of sleeping 15 s.
340
342
  await this.waitForReady(sessionName);
341
343
  // Issue #1763: subscribe once the server is up. Health-checked first, so
@@ -691,7 +693,8 @@ class OpenCodeTool extends base_1.BaseCLITool {
691
693
  }
692
694
  catch (error) {
693
695
  const errorMessage = (0, errors_1.getErrorMessage)(error);
694
- throw new Error(`Failed to send message to OpenCode: ${errorMessage}`);
696
+ // Issue #4031: the cause keeps a failed `load-buffer`'s code (`classifySendFailure`).
697
+ throw new Error(`Failed to send message to OpenCode: ${errorMessage}`, { cause: error });
695
698
  }
696
699
  }
697
700
  /**
@@ -44,8 +44,16 @@ const legacy_session_alias_1 = require("../tmux/legacy-session-alias");
44
44
  const SESSION_NAME_PREFIX = 'mcbd-';
45
45
  /** Shape of a session-name namespace: 8 lowercase hex digits (Issue #2866). */
46
46
  exports.SESSION_NAMESPACE_PATTERN = /^[0-9a-f]{8}$/;
47
- /** CLI tool ids, longest first, so a longer id is never read as a shorter one. */
48
- const CLI_TOOL_IDS_LONGEST_FIRST = [...types_1.CLI_TOOL_IDS].sort((a, b) => b.length - a.length);
47
+ /**
48
+ * CLI tool ids, longest first, so a longer id is never read as a shorter one.
49
+ *
50
+ * Read when called, not when this module loads (Issue #3981): modules loaded
51
+ * early (`session-starting-state`) import this one, and a module-load read of
52
+ * `CLI_TOOL_IDS` reaches a test's getter mock before it can answer.
53
+ */
54
+ function cliToolIdsLongestFirst() {
55
+ return [...types_1.CLI_TOOL_IDS].sort((a, b) => b.length - a.length);
56
+ }
49
57
  /**
50
58
  * The namespace this process names its sessions with, or null (legacy names).
51
59
  *
@@ -150,7 +158,7 @@ function parseSessionName(name) {
150
158
  namespace = body.slice(0, dash);
151
159
  body = body.slice(dash + 1);
152
160
  }
153
- const cliToolId = CLI_TOOL_IDS_LONGEST_FIRST.find((id) => body.startsWith(`${id}-`));
161
+ const cliToolId = cliToolIdsLongestFirst().find((id) => body.startsWith(`${id}-`));
154
162
  if (!cliToolId)
155
163
  return null;
156
164
  const rest = body.slice(cliToolId.length + 1);
@@ -10,6 +10,7 @@ exports.withoutTrailingBlankRows = withoutTrailingBlankRows;
10
10
  exports.findPasteTokens = findPasteTokens;
11
11
  exports.readSubmitComposer = readSubmitComposer;
12
12
  exports.classifySubmit = classifySubmit;
13
+ exports.classifySubmitWithRule = classifySubmitWithRule;
13
14
  exports.isSubmitted = isSubmitted;
14
15
  exports.classifyPasteLanded = classifyPasteLanded;
15
16
  exports.compactText = compactText;
@@ -452,6 +453,15 @@ function readSubmitComposer(output, cliToolId, reader, lines, windowLines, messa
452
453
  * the tool's own, so every existing three-argument caller is unchanged.
453
454
  */
454
455
  function classifySubmit(output, cliToolId, message, composerSpec = (0, composer_spec_1.resolveComposerSpec)(cliToolId)) {
456
+ return classifySubmitWithRule(output, cliToolId, message, composerSpec).state;
457
+ }
458
+ /**
459
+ * {@link classifySubmit} with the rule that decided the frame (Issue #4035).
460
+ * The sender logs the rule with every verdict, and treats a `submitted` from B
461
+ * or F — the screen saying only "the body is not in the composer" — as weaker
462
+ * evidence than A on a tool whose own hook reports the prompt.
463
+ */
464
+ function classifySubmitWithRule(output, cliToolId, message, composerSpec = (0, composer_spec_1.resolveComposerSpec)(cliToolId)) {
455
465
  const clean = (0, cli_patterns_1.stripAnsi)(output);
456
466
  const lines = withoutTrailingBlankRows(clean.split('\n'));
457
467
  const windowLines = lines.slice(-exports.VERIFY_WINDOW_LINES);
@@ -461,34 +471,34 @@ function classifySubmit(output, cliToolId, message, composerSpec = (0, composer_
461
471
  // pinned to the bottom of the pane, and widening it to opencode's whole
462
472
  // frame would match `esc interrupt` printed inside a reply.
463
473
  if ((0, cli_patterns_1.detectThinking)(cliToolId, windowStr)) {
464
- return 'submitted';
474
+ return { state: 'submitted', rule: 'A' };
465
475
  }
466
476
  const composer = readSubmitComposer(output, cliToolId, composerSpec.reader, lines, windowLines, message);
467
477
  // B. No composer visible (scrolled off / dialog / still starting), or the
468
478
  // composer is empty => the message left the box => submitted.
469
479
  if (composer.kind !== 'text') {
470
- return 'submitted';
480
+ return { state: 'submitted', rule: composer.kind === 'absent' ? 'B-absent' : 'B-empty' };
471
481
  }
472
482
  // C. A paste placeholder is still folded into the composer => body is there.
473
483
  if (composer.rows.some((row) => PASTE_PLACEHOLDER_PATTERN.test(row) || findPasteTokens(row).tokens.length > 0)) {
474
- return 'pending';
484
+ return { state: 'pending', rule: 'C' };
475
485
  }
476
486
  // D. The typed body is still sitting in the composer => resend Enter.
477
487
  if (inputMatchesBody(composer.text, message)) {
478
- return 'pending';
488
+ return { state: 'pending', rule: 'D' };
479
489
  }
480
490
  // E. A different slash command is in the composer => a completion popup
481
491
  // replaced what we typed. (Scoped to `/…` so idle-prompt placeholders that
482
492
  // some TUIs paint on an empty composer are never mistaken for this.)
483
493
  if (REPLACEMENT_COMMAND_PATTERN.test(composer.text)) {
484
- return 'replaced';
494
+ return { state: 'replaced', rule: 'E' };
485
495
  }
486
496
  // F. Non-empty, non-command steady-state text (idle placeholder / hint) =>
487
497
  // submitted, preserving the pre-#1501 permissive default. Not for a codex
488
498
  // composer above the window (Issue #3906): before #3906 that frame was
489
499
  // read as no composer at all; text there that is not the body says
490
500
  // neither that the message left nor that Enter would send it.
491
- return composer.outsideWindow ? 'indeterminate' : 'submitted';
501
+ return composer.outsideWindow ? { state: 'indeterminate', rule: 'F-outside' } : { state: 'submitted', rule: 'F' };
492
502
  }
493
503
  /**
494
504
  * Backward-compatible boolean view of {@link classifySubmit}: submitted vs not.
@@ -89,6 +89,13 @@
89
89
  * checks it still owns the composer before every key, watches an `unseen`
90
90
  * paste a little longer before giving up, and leaves a mark for a body that
91
91
  * may still arrive, which the next send waits out ({@link waitOutCarriedPaste}).
92
+ *
93
+ * Issue #4035 is a claude session's first prompt reported sent when it was
94
+ * not. Keys typed right after the prompt appeared were drawn ~1 s later and
95
+ * their Enter was lost, while the read-back still showed the dim placeholder
96
+ * (rule F). On that first prompt a B or F verdict now waits for claude's own
97
+ * `UserPromptSubmit` ({@link awaitPromptReport}), and a later send that clears
98
+ * a body this one called sent says so ({@link reportSubmittedBodyInComposer}).
92
99
  */
93
100
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
94
101
  if (k2 === undefined) k2 = k;
@@ -124,7 +131,7 @@ var __importStar = (this && this.__importStar) || (function () {
124
131
  };
125
132
  })();
126
133
  Object.defineProperty(exports, "__esModule", { value: true });
127
- exports.LITERAL_SEND_MAX_BYTES = exports.isSubmitted = exports.classifySubmit = exports.classifyPasteLanded = exports.recheckComposerBeforeInput = void 0;
134
+ exports.PROMPT_REPORT_WAIT_MS = exports.LITERAL_SEND_MAX_BYTES = exports.isSubmitted = exports.classifySubmitWithRule = exports.classifySubmit = exports.classifyPasteLanded = exports.recheckComposerBeforeInput = void 0;
128
135
  exports.clearComposerBeforeSend = clearComposerBeforeSend;
129
136
  exports.sendMessageWithSubmitVerification = sendMessageWithSubmitVerification;
130
137
  const childProcess = __importStar(require("child_process"));
@@ -137,6 +144,9 @@ const logger_1 = require("../../lib/logger");
137
144
  const global_state_1 = require("../../lib/global-state");
138
145
  const composer_clear_1 = require("../../lib/session/composer-clear");
139
146
  Object.defineProperty(exports, "recheckComposerBeforeInput", { enumerable: true, get: function () { return composer_clear_1.recheckComposerBeforeInput; } });
147
+ const prompt_submit_receipt_1 = require("../../lib/session/prompt-submit-receipt");
148
+ const send_attempt_state_1 = require("../../lib/session/send-attempt-state");
149
+ const send_attempt_types_1 = require("../../lib/session/send-attempt-types");
140
150
  const instance_input_lock_1 = require("../../lib/session/instance-input-lock");
141
151
  const composer_text_1 = require("../../lib/detection/composer-text");
142
152
  const submit_composer_read_1 = require("./submit-composer-read");
@@ -145,6 +155,7 @@ const submit_composer_read_1 = require("./submit-composer-read");
145
155
  var submit_composer_read_2 = require("./submit-composer-read");
146
156
  Object.defineProperty(exports, "classifyPasteLanded", { enumerable: true, get: function () { return submit_composer_read_2.classifyPasteLanded; } });
147
157
  Object.defineProperty(exports, "classifySubmit", { enumerable: true, get: function () { return submit_composer_read_2.classifySubmit; } });
158
+ Object.defineProperty(exports, "classifySubmitWithRule", { enumerable: true, get: function () { return submit_composer_read_2.classifySubmitWithRule; } });
148
159
  Object.defineProperty(exports, "isSubmitted", { enumerable: true, get: function () { return submit_composer_read_2.isSubmitted; } });
149
160
  const logger = (0, logger_1.createLogger)('cli-tools/submit-verified-sender');
150
161
  /**
@@ -203,6 +214,15 @@ const RECHECK_CAPTURE_LINES = 200;
203
214
  const CARRIED_MARK_POLL_MS = 200;
204
215
  /** Default bounded recovery Enters (each read back) before giving up (throwing). */
205
216
  const DEFAULT_VERIFY_ATTEMPTS = 4;
217
+ /**
218
+ * How long a B/F verdict on a session's first prompt waits for the agent's own
219
+ * report of it (Issue #4035). Claude 2.1.314 reported the first prompt 0.66–0.74 s
220
+ * after the send began in all 29 submitted first sends measured; an unsent body
221
+ * was drawn into the composer 0.9–1.7 s after its Enter.
222
+ */
223
+ exports.PROMPT_REPORT_WAIT_MS = 5000;
224
+ /** How often the report and the composer are looked at during that wait. */
225
+ const PROMPT_REPORT_POLL_MS = 100;
206
226
  /** Run one tmux command, optionally feeding it `input` on stdin. */
207
227
  function runTmux(args, input) {
208
228
  return new Promise((resolve, reject) => {
@@ -234,6 +254,12 @@ function runTmux(args, input) {
234
254
  * `load-buffer` ran. A lost ticket drops the buffer and throws before anything
235
255
  * reaches the pane (`input lock lost, nothing was typed`).
236
256
  *
257
+ * Issue #4011: a failed `load-buffer` throws with `delivery: 'not-started'`
258
+ * (the field `TmuxSendError` carries) — it runs before `paste-buffer`, so none
259
+ * of the body reached the pane, however it failed (an exit status or a timeout).
260
+ * Issue #4031: worded `Failed to load message into tmux buffer` and coded
261
+ * `PASTE_NOT_STARTED_CODE`, so `classifySendFailure` records it `not-sent`.
262
+ *
237
263
  * @throws Error when either tmux command fails, or `ticket` lost the composer
238
264
  */
239
265
  async function pasteBody(sessionName, message, ticket, cliToolId) {
@@ -245,7 +271,13 @@ async function pasteBody(sessionName, message, ticket, cliToolId) {
245
271
  catch (error) {
246
272
  await runTmux(['delete-buffer', '-b', bufferName]).catch(() => undefined);
247
273
  const errorMessage = error instanceof Error ? error.message : String(error);
248
- throw new Error(`Failed to paste message into tmux session: ${errorMessage}`);
274
+ // Issue #4031: its own wording and code, apart from `paste-buffer`'s
275
+ // failure below (whose body may be on the pane), so the send is recorded
276
+ // `not-sent` with or without a bound relay.
277
+ throw Object.assign(new Error(`Failed to load message into tmux buffer: ${errorMessage}`), {
278
+ delivery: 'not-started',
279
+ code: send_attempt_types_1.PASTE_NOT_STARTED_CODE,
280
+ });
249
281
  }
250
282
  if (!ticket.isCurrent()) {
251
283
  await runTmux(['delete-buffer', '-b', bufferName]).catch(() => undefined);
@@ -599,6 +631,67 @@ async function confirmTypedBodyLanded(params) {
599
631
  `${attempts * TYPED_BODY_POLL_MS}ms (it shows ${shown}); the message is ${bytes} bytes. ` +
600
632
  'Enter was not pressed, so nothing was submitted (Issue #3366).');
601
633
  }
634
+ /**
635
+ * Whether a verdict is one the agent's own report must back (Issue #4035):
636
+ * `submitted` from B or F — the screen saying only that the body is not in the
637
+ * composer. A (generating) stands on its own. A body starting with `/` or `!`
638
+ * is run by the TUI itself, which is not measured to report it as a prompt.
639
+ */
640
+ function needsPromptReport(state, rule, message) {
641
+ if (state !== 'submitted' || rule === 'A')
642
+ return false;
643
+ return !/^\s*[/!]/.test(message);
644
+ }
645
+ /**
646
+ * Watch a session's first prompt until the agent reports it (Issue #4035).
647
+ *
648
+ * Reads the hook record and the composer every {@link PROMPT_REPORT_POLL_MS}
649
+ * until `deadline`, without pressing anything. The deadline is the send's, not
650
+ * the call's: a send that waits again after a resent Enter gets only what is
651
+ * left of its {@link PROMPT_REPORT_WAIT_MS} (it holds the input lock meanwhile).
652
+ *
653
+ * - the agent reported the prompt — `received`;
654
+ * - the screen changes its verdict — generating (A), or the body drawn into
655
+ * the composer after all (C/D, `pending`: the caller resends Enter, as for
656
+ * any typed-but-unsent body), or a completion (E) — `screen`, with the frame;
657
+ * - neither, to the end — `unreported`: nothing says the message left.
658
+ */
659
+ async function awaitPromptReport(params) {
660
+ const { sessionName, message, cliToolId, composer, enteredAt, deadline } = params;
661
+ let rule = params.rule;
662
+ while (Date.now() < deadline) {
663
+ await new Promise((resolve) => setTimeout(resolve, PROMPT_REPORT_POLL_MS));
664
+ if ((0, prompt_submit_receipt_1.readPromptSubmitReceipt)(sessionName, cliToolId, enteredAt) === 'received')
665
+ return { verdict: 'received' };
666
+ const output = await (0, tmux_1.capturePane)(sessionName, { startLine: -composer.verifyCaptureLines });
667
+ const verdict = (0, submit_composer_read_1.classifySubmitWithRule)(output, cliToolId, message, composer);
668
+ if (verdict.state !== 'submitted' || verdict.rule === 'A')
669
+ return { verdict: 'screen', ...verdict, output };
670
+ rule = verdict.rule;
671
+ }
672
+ if ((0, prompt_submit_receipt_1.readPromptSubmitReceipt)(sessionName, cliToolId, enteredAt) === 'received')
673
+ return { verdict: 'received' };
674
+ return { verdict: 'unreported', rule };
675
+ }
676
+ /**
677
+ * Say so when the pre-send clear finds the body this session last reported
678
+ * submitted (Issue #4035): that body never reached the agent, and the send that
679
+ * said `sent` for it was wrong. The instance's `lastSend` is turned
680
+ * `indeterminate` (the send now running records its own outcome after it).
681
+ */
682
+ function reportSubmittedBodyInComposer(sessionName, cliToolId, composerText, cleared) {
683
+ if (composerText === '' || !(0, prompt_submit_receipt_1.matchesSubmittedBody)(sessionName, composerText))
684
+ return;
685
+ const target = (0, prompt_submit_receipt_1.getPromptSubmitTarget)(sessionName);
686
+ if (target !== null)
687
+ (0, send_attempt_state_1.markLastSendDiscarded)({ ...target, instanceId: target.instanceId ?? target.cliToolId });
688
+ logger.warn('pre-send-found-submitted-body', {
689
+ sessionName,
690
+ cliToolId,
691
+ cleared,
692
+ length: composerText.length,
693
+ });
694
+ }
602
695
  /**
603
696
  * Empty the composer before the body is typed into it (Issue #1880).
604
697
  *
@@ -658,6 +751,7 @@ async function clearComposerBeforeSend(sessionName, cliToolId, composerSpec = (0
658
751
  });
659
752
  if (ticket !== undefined)
660
753
  assertInputOwner(ticket, cliToolId, 'the pre-send clear', false);
754
+ reportSubmittedBodyInComposer(sessionName, cliToolId, result.discardedText, result.state !== 'content');
661
755
  if (result.state === 'content') {
662
756
  logger.error('pre-send-composer-clear-failed', {
663
757
  sessionName,
@@ -742,9 +836,11 @@ async function sendUnderInputLock(params, ticket) {
742
836
  }
743
837
  catch (error) {
744
838
  // 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))
839
+ // refused input boundary (Issue #3992) or a failed `load-buffer` (Issue
840
+ // #4011, `not-started`), both before `paste-buffer`: a mark then would
841
+ // only hold the next send off for nothing.
842
+ const notStarted = error?.delivery === 'not-started';
843
+ if (!(0, instance_input_lock_1.isInputBoundaryRefusal)(error) && !notStarted)
748
844
  (0, instance_input_lock_1.leaveCarriedPasteMark)(ticket);
749
845
  throw error;
750
846
  }
@@ -796,6 +892,8 @@ async function sendUnderInputLock(params, ticket) {
796
892
  }
797
893
  }
798
894
  // 3. Submit as a separate command (double Enter for vibe-local's IME mode).
895
+ // Issue #4035: the agent's own report of the prompt counts from here.
896
+ const enteredAt = Date.now();
799
897
  for (let i = 0; i < Math.max(1, submitEnterCount); i++) {
800
898
  assertInputOwner(ticket, cliToolId, 'Enter', true);
801
899
  await (0, tmux_1.sendSpecialKeys)(sessionName, ['Enter']);
@@ -812,11 +910,62 @@ async function sendUnderInputLock(params, ticket) {
812
910
  // was reported "could not be confirmed" — a sent message as exit 99. The
813
911
  // last read sends nothing: no Enter goes out that is not read back.
814
912
  const attempts = Math.max(1, verifyAttempts);
913
+ // Issue #4035: one wait for the agent's report per send, however many reads.
914
+ let promptReportDeadline = null;
815
915
  for (let attempt = 0; attempt <= attempts; attempt++) {
816
916
  await new Promise((resolve) => setTimeout(resolve, verifyDelayMs));
817
- const output = await (0, tmux_1.capturePane)(sessionName, { startLine: -composer.verifyCaptureLines });
818
- const state = (0, submit_composer_read_1.classifySubmit)(output, cliToolId, message, composer);
917
+ let output = await (0, tmux_1.capturePane)(sessionName, { startLine: -composer.verifyCaptureLines });
918
+ let { state, rule } = (0, submit_composer_read_1.classifySubmitWithRule)(output, cliToolId, message, composer);
919
+ const receipt = needsPromptReport(state, rule, message)
920
+ ? (0, prompt_submit_receipt_1.readPromptSubmitReceipt)(sessionName, cliToolId, enteredAt)
921
+ : 'not-required';
922
+ // Issue #4035: every verdict names the rule that gave it, so a send reported
923
+ // `sent` can be traced to what the screen showed.
924
+ logger.info('submit-classified', { sessionName, cliToolId, attempt, state, rule, receipt });
925
+ if (receipt === 'awaited') {
926
+ // Issue #4035: the screen says only that the body is not in the composer,
927
+ // on a session that has not reported a prompt yet. Watch, without Enter,
928
+ // until the agent reports it or the composer shows the body after all.
929
+ promptReportDeadline ??= Date.now() + exports.PROMPT_REPORT_WAIT_MS;
930
+ const watched = await awaitPromptReport({
931
+ sessionName,
932
+ message,
933
+ cliToolId,
934
+ composer,
935
+ enteredAt,
936
+ rule,
937
+ deadline: promptReportDeadline,
938
+ });
939
+ if (watched.verdict === 'unreported') {
940
+ (0, tmux_capture_cache_1.invalidateCache)(sessionName);
941
+ logger.error('submit-not-confirmed:prompt-unreported', {
942
+ sessionName,
943
+ cliToolId,
944
+ attempt,
945
+ rule: watched.rule,
946
+ waitedMs: exports.PROMPT_REPORT_WAIT_MS,
947
+ });
948
+ throw new Error(`Message submit could not be confirmed for session ${sessionName}: the composer did not show the body ` +
949
+ `(rule ${watched.rule}) but the agent did not report the prompt within ${exports.PROMPT_REPORT_WAIT_MS}ms ` +
950
+ '(Issue #4035).');
951
+ }
952
+ if (watched.verdict === 'received') {
953
+ logger.info('submit-confirmed-by-prompt-hook', { sessionName, cliToolId, attempt, rule });
954
+ state = 'submitted';
955
+ }
956
+ else {
957
+ ({ state, rule, output } = watched);
958
+ logger.info('submit-classified', { sessionName, cliToolId, attempt, state, rule, receipt: 'awaited' });
959
+ }
960
+ }
819
961
  if (state === 'submitted') {
962
+ // Issue #4035: only a body the screen alone called submitted is remembered
963
+ // for the next send's clear. One the agent reported did leave, and the same
964
+ // text back in the composer is claude restoring it (Esc), the history (↑),
965
+ // or a person typing it — not a send that never arrived.
966
+ if ((0, prompt_submit_receipt_1.readPromptSubmitReceipt)(sessionName, cliToolId, enteredAt) !== 'received') {
967
+ (0, prompt_submit_receipt_1.noteSubmittedBody)(sessionName, message);
968
+ }
820
969
  (0, tmux_capture_cache_1.invalidateCache)(sessionName);
821
970
  return;
822
971
  }
@@ -863,6 +1012,14 @@ async function sendUnderInputLock(params, ticket) {
863
1012
  logger.warn('submit-not-confirmed:foreign-paste-token', { sessionName, cliToolId, attempt });
864
1013
  continue;
865
1014
  }
1015
+ // Issue #4035: the Enter thought lost may only have been late — the agent
1016
+ // reporting the prompt now means it went, and another Enter would land on an
1017
+ // empty composer, or on a dialog that the prompt just opened.
1018
+ if ((0, prompt_submit_receipt_1.readPromptSubmitReceipt)(sessionName, cliToolId, enteredAt) === 'received') {
1019
+ logger.info('submit-confirmed-by-prompt-hook', { sessionName, cliToolId, attempt, rule });
1020
+ (0, tmux_capture_cache_1.invalidateCache)(sessionName);
1021
+ return;
1022
+ }
866
1023
  // state === 'pending' — still typed-but-unsent, resend a single Enter and re-check.
867
1024
  logger.warn('submit-not-confirmed:resending-enter', {
868
1025
  sessionName,