commandmate 0.33.3 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +146 -146
  3. package/.next/app-path-routes-manifest.json +29 -29
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/prerender-manifest.json +9 -9
  6. package/.next/required-server-files.json +1 -1
  7. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  8. package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
  9. package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
  10. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/app/update-check/route.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/assistant/conversation/route.js +1 -1
  14. package/.next/server/app/api/assistant/conversation/route.js.nft.json +1 -1
  15. package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/assistant/current-output/route.js +1 -1
  17. package/.next/server/app/api/assistant/current-output/route.js.nft.json +1 -1
  18. package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/assistant/messages/route.js +1 -1
  20. package/.next/server/app/api/assistant/messages/route.js.nft.json +1 -1
  21. package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
  22. package/.next/server/app/api/assistant/session/route.js +1 -1
  23. package/.next/server/app/api/assistant/session/route.js.nft.json +1 -1
  24. package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
  25. package/.next/server/app/api/assistant/start/route.js +2 -2
  26. package/.next/server/app/api/assistant/start/route.js.nft.json +1 -1
  27. package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
  28. package/.next/server/app/api/assistant/terminal/route.js +3 -3
  29. package/.next/server/app/api/assistant/terminal/route.js.nft.json +1 -1
  30. package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
  31. package/.next/server/app/api/assistant/tools/route.js +1 -1
  32. package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
  33. package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  37. package/.next/server/app/api/capabilities/route.js +1 -1
  38. package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  40. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  41. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  42. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  43. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  44. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  45. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  46. package/.next/server/app/api/hooks/agent-event/route.js +1 -1
  47. package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
  48. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  49. package/.next/server/app/api/hooks/claude-done/route.js +2 -2
  50. package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
  51. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  52. package/.next/server/app/api/hooks/permission-request/route.js +1 -1
  53. package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
  54. package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
  55. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  57. package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
  58. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  60. package/.next/server/app/api/relays/[relayId]/cancel/route.js +1 -1
  61. package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
  62. package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
  63. package/.next/server/app/api/relays/route.js +1 -1
  64. package/.next/server/app/api/relays/route.js.nft.json +1 -1
  65. package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
  66. package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
  67. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  68. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
  70. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  71. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
  72. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  73. package/.next/server/app/api/repositories/clone/route.js +1 -1
  74. package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
  75. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  76. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/repositories/restore/route.js +1 -1
  78. package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
  79. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  80. package/.next/server/app/api/repositories/route.js +1 -1
  81. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  82. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  83. package/.next/server/app/api/repositories/scan/route.js +1 -1
  84. package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
  85. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  86. package/.next/server/app/api/repositories/sync/route.js +1 -1
  87. package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
  88. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  90. package/.next/server/app/api/settings/default-agents/route.js +1 -1
  91. package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
  92. package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
  93. package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
  94. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  96. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  97. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  98. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  99. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  100. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  101. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  103. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  104. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  105. package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
  106. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  107. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  108. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  109. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  110. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  111. package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
  112. package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
  113. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  114. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
  115. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
  116. package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
  117. package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
  118. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  120. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  121. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  122. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
  124. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  127. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  129. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  130. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  132. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.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_client-reference-manifest.js +1 -1
  135. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  136. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  137. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.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_client-reference-manifest.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  141. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  142. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  146. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  148. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  149. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  151. package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
  152. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
  153. package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
  154. package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
  155. package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
  156. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  157. package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
  158. package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
  159. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  161. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  162. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  163. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  164. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  165. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  166. package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
  167. package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
  168. package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  170. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
  171. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/resolve-target/route.js +1 -1
  173. package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
  174. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
  175. package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
  176. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  177. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  178. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  179. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  180. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +1 -1
  181. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  182. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  183. package/.next/server/app/api/worktrees/[id]/schedules/route.js +1 -1
  184. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  185. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  186. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
  187. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  188. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  189. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +2 -2
  190. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
  191. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  192. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  193. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  194. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  195. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  196. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  197. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  198. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  199. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  200. package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
  201. package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
  202. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  203. package/.next/server/app/api/worktrees/[id]/tasks/route.js +2 -2
  204. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  205. package/.next/server/app/api/worktrees/[id]/terminal/route.js +2 -2
  206. package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
  207. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  208. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  209. package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
  210. package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
  211. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  212. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  213. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  214. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  215. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  216. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  217. package/.next/server/app/api/worktrees/[id]/verify/config/route.js +1 -1
  218. package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
  219. package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -1
  220. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  221. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js +1 -1
  222. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
  223. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  224. package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
  225. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  226. package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
  227. package/.next/server/app/api/worktrees/route.js +1 -1
  228. package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
  229. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  230. package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  231. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  232. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  233. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  234. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  235. package/.next/server/app/page.js +1 -1
  236. package/.next/server/app/page_client-reference-manifest.js +1 -1
  237. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  238. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  239. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  240. package/.next/server/app/sessions/page.js +1 -1
  241. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  242. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  243. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  244. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  245. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  246. package/.next/server/app/worktrees/[id]/page.js +8 -8
  247. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  248. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  249. package/.next/server/app-paths-manifest.json +29 -29
  250. package/.next/server/chunks/1049.js +1 -0
  251. package/.next/server/chunks/1501.js +4 -4
  252. package/.next/server/chunks/1886.js +2 -2
  253. package/.next/server/chunks/2119.js +1 -1
  254. package/.next/server/chunks/2404.js +1 -1
  255. package/.next/server/chunks/2445.js +1 -1
  256. package/.next/server/chunks/3241.js +1 -1
  257. package/.next/server/chunks/3323.js +1 -1
  258. package/.next/server/chunks/3480.js +2 -2
  259. package/.next/server/chunks/4443.js +1 -1
  260. package/.next/server/chunks/4802.js +1 -1
  261. package/.next/server/chunks/5164.js +1 -1
  262. package/.next/server/chunks/5571.js +1 -1
  263. package/.next/server/chunks/595.js +1 -1
  264. package/.next/server/chunks/6130.js +1 -1
  265. package/.next/server/chunks/6285.js +1 -1
  266. package/.next/server/chunks/6286.js +7 -7
  267. package/.next/server/chunks/6337.js +1 -1
  268. package/.next/server/chunks/650.js +1 -1
  269. package/.next/server/chunks/663.js +1 -1
  270. package/.next/server/chunks/6677.js +25 -0
  271. package/.next/server/chunks/7075.js +1 -0
  272. package/.next/server/chunks/7905.js +1 -1
  273. package/.next/server/chunks/8583.js +1 -0
  274. package/.next/server/chunks/8918.js +4 -2
  275. package/.next/server/chunks/9080.js +1 -0
  276. package/.next/server/chunks/964.js +1 -0
  277. package/.next/server/middleware-manifest.json +5 -5
  278. package/.next/server/pages/500.html +1 -1
  279. package/.next/server/server-reference-manifest.json +1 -1
  280. package/.next/static/chunks/2053-9ac860ab4e92ac89.js +1 -0
  281. package/.next/static/chunks/2652-18b8fea64413467e.js +1 -0
  282. package/.next/static/chunks/{4718-814f4ecfd7fcc513.js → 4718-2d9f0397a8f931c4.js} +1 -1
  283. package/.next/static/chunks/{8361-9bb887203c456edb.js → 8361-0142beb59be2abf3.js} +1 -1
  284. package/.next/static/chunks/app/{page-022090bf6f932818.js → page-26a42881c8648cd3.js} +1 -1
  285. package/.next/static/chunks/app/sessions/page-a3ab6f122ec60d5a.js +1 -0
  286. package/.next/static/chunks/app/worktrees/[id]/page-a39ec2a0732d11a6.js +1 -0
  287. package/.next/static/css/b09bede85744e1cf.css +1 -0
  288. package/.next/trace +13 -13
  289. package/dist/cli/commands/ask.d.ts.map +1 -1
  290. package/dist/cli/commands/ask.js +11 -2
  291. package/dist/cli/commands/respond.d.ts.map +1 -1
  292. package/dist/cli/commands/respond.js +8 -4
  293. package/dist/cli/commands/send.d.ts.map +1 -1
  294. package/dist/cli/commands/send.js +18 -0
  295. package/dist/cli/commands/wait.d.ts +18 -3
  296. package/dist/cli/commands/wait.d.ts.map +1 -1
  297. package/dist/cli/commands/wait.js +137 -2
  298. package/dist/cli/docs/agent-operations.d.ts +2 -2
  299. package/dist/cli/docs/agent-operations.d.ts.map +1 -1
  300. package/dist/cli/docs/agent-operations.js +41 -1
  301. package/dist/cli/utils/session-target.d.ts +23 -6
  302. package/dist/cli/utils/session-target.d.ts.map +1 -1
  303. package/dist/cli/utils/session-target.js +33 -5
  304. package/dist/server/locales/en/worktree.json +21 -2
  305. package/dist/server/locales/ja/worktree.json +21 -2
  306. package/dist/server/src/config/schedule-config.js +45 -3
  307. package/dist/server/src/lib/cli-tools/antigravity.js +95 -10
  308. package/dist/server/src/lib/cli-tools/submit-verified-sender.js +377 -16
  309. package/dist/server/src/lib/cmate-parser.js +8 -1
  310. package/dist/server/src/lib/detection/prompt-detect-multiple-choice.js +140 -19
  311. package/dist/server/src/lib/detection/tools/claude/detect.js +13 -2
  312. package/dist/server/src/lib/detection/tools/claude/picker-chrome.js +239 -0
  313. package/dist/server/src/lib/detection/tools/claude/prompt.js +74 -6
  314. package/dist/server/src/lib/hooks/sources/claude/history.js +391 -34
  315. package/dist/server/src/lib/hooks/sources/claude/transcript.js +91 -0
  316. package/dist/server/src/lib/polling/auto-yes-dialog-gate.js +114 -11
  317. package/dist/server/src/lib/polling/response-checker.js +82 -3
  318. package/dist/server/src/lib/schedule-manager.js +178 -19
  319. package/dist/server/src/lib/session/ask-user-question-prompt.js +4 -2
  320. package/dist/server/src/lib/session/claude-executor.js +33 -2
  321. package/dist/server/src/lib/session/resolve-session-target.js +37 -9
  322. package/dist/server/src/lib/verification/env-clean-gate.js +81 -4
  323. package/dist/server/src/types/agent-transcript.js +143 -1
  324. package/package.json +1 -1
  325. package/.next/server/chunks/1068.js +0 -1
  326. package/.next/server/chunks/6808.js +0 -1
  327. package/.next/server/chunks/7875.js +0 -25
  328. package/.next/server/chunks/9553.js +0 -1
  329. package/.next/static/chunks/2053-3f299a7a2c7d6767.js +0 -1
  330. package/.next/static/chunks/8772-9be53a530950d804.js +0 -1
  331. package/.next/static/chunks/app/sessions/page-584adf11ae51df10.js +0 -1
  332. package/.next/static/chunks/app/worktrees/[id]/page-3af707e74a75172b.js +0 -1
  333. package/.next/static/css/acd46e25427a2080.css +0 -1
  334. /package/.next/static/{9x6U1h52hH_r6pOsGwI_p → gniPBCKoXtbIOQey8kNcx}/_buildManifest.js +0 -0
  335. /package/.next/static/{9x6U1h52hH_r6pOsGwI_p → gniPBCKoXtbIOQey8kNcx}/_ssgManifest.js +0 -0
@@ -90,7 +90,7 @@ var __importStar = (this && this.__importStar) || (function () {
90
90
  };
91
91
  })();
92
92
  Object.defineProperty(exports, "__esModule", { value: true });
93
- exports.CLAUDE_TURN_RECHECK_LIMIT = exports.CLAUDE_TRANSCRIPT_TAIL_BYTES = void 0;
93
+ exports.CLAUDE_TURN_RECHECK_LIMIT = exports.CLAUDE_TURN_HEAD_MISSING_MARKER = exports.CLAUDE_TRANSCRIPT_MAX_TAIL_BYTES = exports.CLAUDE_TRANSCRIPT_TAIL_BYTES = void 0;
94
94
  exports.resetClaudeTranscriptSessions = resetClaudeTranscriptSessions;
95
95
  exports.resolveClaudeSessionId = resolveClaudeSessionId;
96
96
  exports.claudeProjectsRoot = claudeProjectsRoot;
@@ -110,21 +110,62 @@ const agent_transcript_1 = require("../../../../types/agent-transcript");
110
110
  const transcript_1 = require("./transcript");
111
111
  const logger = (0, logger_1.createLogger)('lib/hooks/sources/claude/history');
112
112
  /**
113
- * How much of the transcript's tail is read.
113
+ * How much of the transcript's tail is read first.
114
114
  *
115
115
  * The file grows for the life of the session and a long one is tens of
116
116
  * megabytes — the largest on this machine on 2026-08-31 was 23 MB — so reading
117
117
  * it whole on every finished turn would be the most expensive thing the poller
118
- * does. Only turns whose prompt record is inside the window are ever written
119
- * (see {@link captureClaudeTranscriptTurn}), which is also what stops a turn the
118
+ * does. A turn is only ever written from a prompt record inside the window (see
119
+ * {@link captureClaudeTranscriptTurn}), which is also what stops a turn the
120
120
  * window opened halfway through being written from its middle.
121
121
  *
122
- * 4 MiB is roughly two orders of magnitude above the measured size of a single
123
- * turn and still small enough to read and parse in one tick. A turn that
124
- * genuinely does not fit produces orphaned assistant records, which is detected
125
- * and reported rather than written as a headless reply.
122
+ * #2121 sized this as "roughly two orders of magnitude above a single turn".
123
+ * Issue #2470 measured that and it does not hold at the top of the
124
+ * distribution. Over the 27 transcripts in this repository's project directory
125
+ * written in the 14 days to 2026-09-11 1,663 turns — the bytes one turn
126
+ * occupies in the file, from its prompt record to the next, were:
127
+ *
128
+ * | p50 | p90 | p99 | max | over 4 MiB |
129
+ * |---|---|---|---|---|
130
+ * | 0.04 MiB | 0.24 MiB | 4.71 MiB | 23.72 MiB | 19 turns (1.1%) |
131
+ *
132
+ * Every one of the 19 was a long, human-started orchestrate or UAT turn — the
133
+ * replies an operator most wants to read back — and before #2470 every one of
134
+ * them was reported as orphaned records and written by nobody. 4 MiB is kept as
135
+ * the size of the *first* read, which is the whole read for 99% of turns; a turn
136
+ * that does not fit is read further back instead of dropped. See
137
+ * {@link CLAUDE_TRANSCRIPT_MAX_TAIL_BYTES}.
126
138
  */
127
139
  exports.CLAUDE_TRANSCRIPT_TAIL_BYTES = 4 * 1024 * 1024;
140
+ /**
141
+ * How far back a finished turn's prompt record is looked for (Issue #2470).
142
+ *
143
+ * When the first window holds assistant records and no prompt record at all,
144
+ * {@link captureClaudeTranscriptTurn} doubles it — 8, 16, 32, 64 MiB — until a
145
+ * prompt record is inside, and stops there. 64 MiB is almost three times the
146
+ * largest turn measured (23.72 MiB), and it bounds the one cost this adds:
147
+ * reading up to 60 MiB more of the file, once per ask, for a turn that ran that
148
+ * long. Measured on 2026-09-11 with a synthetic transcript of 20 KiB tool
149
+ * results, reading and parsing a 64 MiB tail took 41 ms (4 MiB: 3 ms).
150
+ *
151
+ * A turn longer than this is still not dropped: what can be read of it is saved
152
+ * behind {@link CLAUDE_TURN_HEAD_MISSING_MARKER}. See
153
+ * {@link captureClaudeTranscriptTurn}.
154
+ */
155
+ exports.CLAUDE_TRANSCRIPT_MAX_TAIL_BYTES = 64 * 1024 * 1024;
156
+ /**
157
+ * The first line of a reply saved without its beginning (Issue #2470).
158
+ *
159
+ * Plain English Markdown, the way {@link CLAUDE_TURN_TRUNCATION_MARKER} marks
160
+ * the other end of a cut reply, rather than a translated string. `content` is
161
+ * fixed when the row is written and read back by every viewer in whatever
162
+ * language they use, and this layer has nobody to ask: the Stop hook that
163
+ * writes the row arrives with no request and no locale behind it. The
164
+ * `--- Output truncated (exceeded 100KB limit) ---` line
165
+ * `lib/session/claude-executor` appends to a scheduled run's output is the same
166
+ * choice for the same reason.
167
+ */
168
+ exports.CLAUDE_TURN_HEAD_MISSING_MARKER = `_(The beginning of this reply is not shown: the turn runs further back than the ${exports.CLAUDE_TRANSCRIPT_MAX_TAIL_BYTES / (1024 * 1024)} MiB of transcript that is read.)_`;
128
169
  /** `.jsonl`; the only extension this reader will open. */
129
170
  const CLAUDE_TRANSCRIPT_EXTENSION = '.jsonl';
130
171
  /**
@@ -252,6 +293,36 @@ function acceptClaudeTranscriptHint(homeDir, hint) {
252
293
  * where the earlier turns really are the scraper's, and there is no evidence in
253
294
  * the window that says otherwise.
254
295
  *
296
+ * ## A turn longer than the window (Issue #2470)
297
+ *
298
+ * A turn can be bigger than {@link CLAUDE_TRANSCRIPT_TAIL_BYTES} — 1.1% of the
299
+ * turns measured were, and they were the longest replies of all. Its window
300
+ * holds its assistant records and no prompt record, so `buildClaudeTurns` finds
301
+ * no turn, and before #2470 this answered false with nobody left to write the
302
+ * reply: the Stop receiver has no scrape to fall back on, and the poller that
303
+ * has one may have been restarted, or have given up at its 30-minute limit, long
304
+ * before a fifty-minute turn ends. The measured case wrote no row at all.
305
+ *
306
+ * Two steps now, and both only when the window holds orphaned assistant records
307
+ * and **no** prompt record. A window with a prompt record anywhere in it is read
308
+ * exactly as before, byte for byte.
309
+ *
310
+ * 1. **Read further back** ({@link extendClaudeTranscriptRead}). The window
311
+ * doubles, up to {@link CLAUDE_TRANSCRIPT_MAX_TAIL_BYTES}, until a prompt
312
+ * record is in it, and the turn is then written like any other — user row,
313
+ * backfill anchor, #2264's open-turn gate and all.
314
+ * 2. **Save what can be read** ({@link captureHeadlessClaudeTurn}). A turn whose
315
+ * prompt is further back than even that is written as a reply behind
316
+ * {@link CLAUDE_TURN_HEAD_MISSING_MARKER}, with no user row, keyed on the
317
+ * record that closed it. Only when the read stopped at the limit rather than
318
+ * at the start of the file: a whole file with no prompt record in it is not a
319
+ * turn too long to reach but a shape this reader does not understand, and the
320
+ * scraper keeps it, as it did before.
321
+ *
322
+ * Either way the answer is still about the newest turn and means what it always
323
+ * meant: a headless row answers true because History now holds the turn, and an
324
+ * open one answers false with `not_yet_closed`.
325
+ *
255
326
  * The return value is the poller's instruction, so the two failure directions
256
327
  * are worth stating plainly. **True** means this path has recorded the turn and
257
328
  * the scrape must be dropped. **False** means it has not, for any reason at all
@@ -296,20 +367,29 @@ async function captureClaudeTranscriptTurn(target, capture, report) {
296
367
  });
297
368
  return false;
298
369
  }
299
- const text = await readClaudeTranscriptTail(path);
300
- if (text === null)
370
+ const read = await readClaudeTranscriptTurns(target, path, sessionId ?? '');
371
+ if (read === null)
301
372
  return false;
302
- const parsed = (0, transcript_1.parseClaudeTranscript)(text);
303
- const built = (0, transcript_1.buildClaudeTurns)(parsed.records, sessionId ?? '');
373
+ const { parsed, built } = read;
304
374
  if (built.turns.length === 0) {
305
- logger.info('claude-transcript-no-turn', {
375
+ const orphaned = built.orphanedAssistantRecords;
376
+ // A warning since Issue #2470: when this line was `info`, the measured
377
+ // incident — a fifty-minute turn whose reply reached no writer at all —
378
+ // was three of them in a row and nothing else.
379
+ logger.warn('claude-transcript-no-turn', {
306
380
  worktreeId: target.worktreeId,
307
381
  instanceId,
308
382
  path,
309
383
  records: parsed.records.length,
310
384
  malformedLines: parsed.malformedLines,
311
- orphanedAssistantRecords: built.orphanedAssistantRecords,
385
+ orphanedAssistantRecords: orphaned,
386
+ // Orphans are the one reason the window can be to blame, so they are
387
+ // when how much of the file the read covered is worth reading.
388
+ ...(orphaned > 0 ? { readBytes: read.size - read.startByte, size: read.size } : {}),
312
389
  });
390
+ if (orphaned > 0 && read.reachedLimit) {
391
+ return await captureHeadlessClaudeTurn(target, parsed.records, sessionId ?? '', path, report);
392
+ }
313
393
  return false;
314
394
  }
315
395
  if (parsed.malformedLines > 0 || built.orphanedAssistantRecords > 0) {
@@ -318,11 +398,12 @@ async function captureClaudeTranscriptTurn(target, capture, report) {
318
398
  // both are the kind of thing that must be visible when it stops being
319
399
  // small.
320
400
  //
321
- // `orphanedAssistantRecords` is also the shape the Issue #2196 tail-window
322
- // trap takes: a turn whose prompt record fell outside
323
- // CLAUDE_TRANSCRIPT_TAIL_BYTES has assistant records and no prompt to
324
- // record a user row from. It is reported here rather than dropped in
325
- // silence, exactly as #2121 left it.
401
+ // `orphanedAssistantRecords` used to be the shape the Issue #2196
402
+ // tail-window trap took as well: a turn whose prompt record fell outside
403
+ // CLAUDE_TRANSCRIPT_TAIL_BYTES. Since #2470 that shape never gets here —
404
+ // a window with no prompt record in it is read further back first so
405
+ // what is counted now is the harmless half: the tail of an earlier turn,
406
+ // in front of the prompt that opened the newest one.
326
407
  logger.info('claude-transcript-partial-read', {
327
408
  worktreeId: target.worktreeId,
328
409
  instanceId,
@@ -421,10 +502,14 @@ async function captureClaudeTranscriptTurn(target, capture, report) {
421
502
  * after its user row (`resolveAssistantTimestampMs`), so the rows do not
422
503
  * carry an ordering that could be trusted for this.
423
504
  * - **The window bounds it.** `buildClaudeTurns` only opens a turn on a prompt
424
- * record, so a turn whose prompt fell outside
425
- * {@link CLAUDE_TRANSCRIPT_TAIL_BYTES} is not in `turns` at all and cannot be
426
- * backfilled from its middle. Its records are counted as
427
- * `orphanedAssistantRecords` instead, which is what the caller reports.
505
+ * record, so a turn whose prompt fell outside the window is not in `turns` at
506
+ * all and cannot be backfilled from its middle. Its records are counted as
507
+ * `orphanedAssistantRecords` instead, which is what the caller reports. Since
508
+ * Issue #2470 the window can be wider than {@link CLAUDE_TRANSCRIPT_TAIL_BYTES}
509
+ * — widened only because the newest turn's prompt was not in the first one —
510
+ * and the rule is the same over it: an older turn the wider read happens to
511
+ * bring in is a candidate like any other, and one whose prompt is still
512
+ * outside is not.
428
513
  *
429
514
  * A window with no anchor answers with the newest turn alone. See
430
515
  * {@link captureClaudeTranscriptTurn} for why that is #2121's behaviour rather
@@ -486,9 +571,15 @@ async function resolveClaudeTranscriptPath(target, capture) {
486
571
  * different things to the client. A prompt-derived key is a promise that a row
487
572
  * with the same id is coming; this one is a promise that no such row exists, so
488
573
  * the bubble it draws is cleared by the session going idle rather than by a swap.
574
+ *
575
+ * Since Issue #2470 a row for the same turn usually does follow — under the
576
+ * prompt's key once the writer has read back far enough to find it, or under
577
+ * `claudeHeadlessTurnId` when it cannot — but never under this key, which is one
578
+ * per session and must not be written: the session's second long turn would
579
+ * find the first one's row and read "already saved".
489
580
  */
490
581
  function headlessClaudeTurnKey(sessionId) {
491
- return (0, agent_transcript_1.claudeTurnRequestId)(`partial:${sessionId}`);
582
+ return (0, agent_transcript_1.claudeTurnRequestId)(`${agent_transcript_1.CLAUDE_HEADLESS_TURN_ID_PREFIX}${sessionId}`);
492
583
  }
493
584
  /**
494
585
  * Everything the window holds for a turn whose prompt record is outside it.
@@ -502,6 +593,12 @@ function headlessClaudeTurnKey(sessionId) {
502
593
  *
503
594
  * Only the records before the first prompt record are taken, which is exactly
504
595
  * the set `buildClaudeTurns` counted as orphaned.
596
+ *
597
+ * The writer's counterpart is `buildHeadlessClaudeTurn` (Issue #2470), and the
598
+ * two are kept apart on purpose. That one is keyed on the record that closed
599
+ * the turn, reads `closed` off it, and keeps the turn's *end* when the block cap
600
+ * bites; this one keeps the first window's first blocks, as the live bubble
601
+ * always has, and its accumulator still never reaches a writer.
505
602
  */
506
603
  function collectHeadlessClaudeTurn(records, sessionId) {
507
604
  const blocks = [];
@@ -559,6 +656,19 @@ function collectHeadlessClaudeTurn(records, sessionId) {
559
656
  * has just finished is harmless: the settled row carries the same
560
657
  * {@link ClaudeTurnProgress.turnKey}, so the client replaces one with the other.
561
658
  *
659
+ * **Not widened (Issue #2470).** The writer reads further back than
660
+ * {@link CLAUDE_TRANSCRIPT_TAIL_BYTES} when a window holds no prompt record; this
661
+ * reader deliberately does not, and keeps the one window and the `partial`
662
+ * bubble. The Issue left the choice to a measurement, and the measurement is
663
+ * about *when* the cost is paid rather than how big it is: a 64 MiB tail read
664
+ * and parsed in 41 ms on 2026-09-11 against 3 ms for 4 MiB, which is nothing
665
+ * once per finished turn and is a 10–40 ms stall of the server's event loop
666
+ * **every second** here — this runs on each generating tick with a subscriber
667
+ * (`CHAT_TURN_PROGRESS_MIN_INTERVAL_MS`), and the only turns that would widen are
668
+ * the ones that generate longest. What the wider read would buy is the prompt's
669
+ * key on the bubble instead of the partial marker; the reply itself is already
670
+ * on screen, and the row the writer saves when the turn ends replaces it.
671
+ *
562
672
  * Never throws.
563
673
  *
564
674
  * @param target - The instance whose turn is in flight
@@ -576,14 +686,14 @@ async function readClaudeTurnProgress(target, capture) {
576
686
  const path = await locateClaudeTranscript(homeDir, capture, sessionId);
577
687
  if (!path)
578
688
  return null;
579
- const text = await readClaudeTranscriptTail(path);
580
- if (text === null)
689
+ const window = await readClaudeTranscriptTail(path);
690
+ if (window === null)
581
691
  return null;
582
692
  // A fragment at the tail of a file being appended to is the normal case here
583
693
  // — this reader runs *while* Claude is writing — and `parseClaudeTranscript`
584
694
  // already counts it rather than throwing. Nothing extra is needed, and that
585
695
  // is the property `claude-transcript-progress-2199` pins.
586
- const parsed = (0, transcript_1.parseClaudeTranscript)(text);
696
+ const parsed = (0, transcript_1.parseClaudeTranscript)(window.text);
587
697
  const built = (0, transcript_1.buildClaudeTurns)(parsed.records, sessionId ?? '');
588
698
  const turn = built.turns.at(-1);
589
699
  if (turn) {
@@ -785,6 +895,8 @@ async function isReadableFile(path) {
785
895
  return false;
786
896
  }
787
897
  }
898
+ /** `\n`, which in UTF-8 is one byte and never part of another character. */
899
+ const LINE_FEED = 0x0a;
788
900
  /**
789
901
  * The last {@link CLAUDE_TRANSCRIPT_TAIL_BYTES} of the file, as UTF-8.
790
902
  *
@@ -793,7 +905,13 @@ async function isReadableFile(path) {
793
905
  * it would count as malformed anyway, and dropping it deliberately keeps that
794
906
  * counter meaning "the writer was mid-append", which is the thing worth seeing.
795
907
  *
796
- * @returns The text, or null when the file could not be read
908
+ * Since Issue #2470 the cut line is found by its byte rather than its
909
+ * character, because the window now says where its text starts and a read
910
+ * further back continues from there. The text is the same either way: the line
911
+ * feed is one byte that no other character contains, so decoding what follows
912
+ * it gives exactly what decoding the whole window and slicing after it did.
913
+ *
914
+ * @returns The window, or null when the file could not be read
797
915
  */
798
916
  async function readClaudeTranscriptTail(path) {
799
917
  let handle;
@@ -803,14 +921,20 @@ async function readClaudeTranscriptTail(path) {
803
921
  const offset = Math.max(0, size - exports.CLAUDE_TRANSCRIPT_TAIL_BYTES);
804
922
  const length = size - offset;
805
923
  if (length <= 0)
806
- return '';
924
+ return { text: '', size, startByte: 0 };
807
925
  const buffer = Buffer.alloc(length);
808
926
  const { bytesRead } = await handle.read(buffer, 0, length, offset);
809
- const text = buffer.subarray(0, bytesRead).toString('utf8');
927
+ const bytes = buffer.subarray(0, bytesRead);
810
928
  if (offset === 0)
811
- return text;
812
- const firstBreak = text.indexOf('\n');
813
- return firstBreak === -1 ? '' : text.slice(firstBreak + 1);
929
+ return { text: bytes.toString('utf8'), size, startByte: 0 };
930
+ const firstBreak = bytes.indexOf(LINE_FEED);
931
+ if (firstBreak === -1)
932
+ return { text: '', size, startByte: size };
933
+ return {
934
+ text: bytes.subarray(firstBreak + 1).toString('utf8'),
935
+ size,
936
+ startByte: offset + firstBreak + 1,
937
+ };
814
938
  }
815
939
  catch (error) {
816
940
  logger.warn('claude-transcript-read-failed', {
@@ -823,6 +947,237 @@ async function readClaudeTranscriptTail(path) {
823
947
  await handle?.close().catch(() => { });
824
948
  }
825
949
  }
950
+ /**
951
+ * The whole lines of `[from, to)`, for a read continuing in front of one whose
952
+ * text started at `to` (Issue #2470).
953
+ *
954
+ * `to` is always the start of a line — it is where the previous read's text
955
+ * began — so the only line that can be cut is the one at `from`, and it is
956
+ * dropped for the reason {@link readClaudeTranscriptTail} drops it.
957
+ *
958
+ * @returns The span, or null when fewer bytes came back than were asked for —
959
+ * the file is no longer the one the reads before this were taken from
960
+ */
961
+ async function readClaudeTranscriptSpan(handle, from, to) {
962
+ const length = to - from;
963
+ const buffer = Buffer.alloc(length);
964
+ const { bytesRead } = await handle.read(buffer, 0, length, from);
965
+ if (bytesRead !== length)
966
+ return null;
967
+ if (from === 0)
968
+ return { text: buffer.toString('utf8'), startByte: 0 };
969
+ const firstBreak = buffer.indexOf(LINE_FEED);
970
+ if (firstBreak === -1)
971
+ return { text: '', startByte: to };
972
+ return { text: buffer.subarray(firstBreak + 1).toString('utf8'), startByte: from + firstBreak + 1 };
973
+ }
974
+ /**
975
+ * The transcript's last records, read back far enough to hold the newest turn's
976
+ * prompt record where that is possible (Issue #2470).
977
+ *
978
+ * The first read is {@link readClaudeTranscriptTail} and nothing else, and for a
979
+ * window holding a prompt record anywhere that is the whole of it: the records
980
+ * and the turns are exactly what they were before #2470. Only a window of
981
+ * orphaned assistant records and no prompt record is read further back — see
982
+ * {@link extendClaudeTranscriptRead}.
983
+ *
984
+ * @returns The records and turns, or null when the file could not be read
985
+ */
986
+ async function readClaudeTranscriptTurns(target, path, sessionId) {
987
+ const window = await readClaudeTranscriptTail(path);
988
+ if (window === null)
989
+ return null;
990
+ const parsed = (0, transcript_1.parseClaudeTranscript)(window.text);
991
+ const built = (0, transcript_1.buildClaudeTurns)(parsed.records, sessionId);
992
+ const read = {
993
+ parsed,
994
+ built,
995
+ size: window.size,
996
+ startByte: window.startByte,
997
+ reachedLimit: false,
998
+ };
999
+ if (built.turns.length > 0 || built.orphanedAssistantRecords === 0 || window.startByte === 0) {
1000
+ return read;
1001
+ }
1002
+ // A read further back that fails leaves the first window's answer standing,
1003
+ // which is the pre-#2470 answer: no turn, and the scraper keeps it.
1004
+ return (await extendClaudeTranscriptRead(target, path, sessionId, read)) ?? read;
1005
+ }
1006
+ /**
1007
+ * Double the window until the newest turn's prompt record is in it (Issue #2470).
1008
+ *
1009
+ * 8, 16, 32, 64 MiB, stopping at the first size that brings a prompt record in,
1010
+ * at the start of the file, or at {@link CLAUDE_TRANSCRIPT_MAX_TAIL_BYTES}. One
1011
+ * sequence per ask, and one `claude-transcript-window-extended` line for it.
1012
+ *
1013
+ * Each step reads only the bytes in front of the previous one and puts their
1014
+ * records in front of the records already parsed, so the cost of reaching a
1015
+ * prompt 20 MiB back is one read of 20-odd MiB, not four overlapping ones. That
1016
+ * is sound because the file is append-only and every read of one ask is bounded
1017
+ * by the size it was first opened at: the bytes already read do not change. It
1018
+ * also means the newest prompt record, once there is one, is in the span just
1019
+ * read — nothing behind it held one — which is where its offset is looked up.
1020
+ *
1021
+ * @returns The widened read, or null when a read failed part-way
1022
+ */
1023
+ async function extendClaudeTranscriptRead(target, path, sessionId, first) {
1024
+ const { size } = first;
1025
+ let handle;
1026
+ try {
1027
+ handle = await (0, promises_1.open)(path, 'r');
1028
+ let records = first.parsed.records;
1029
+ let malformedLines = first.parsed.malformedLines;
1030
+ let built = first.built;
1031
+ let startByte = first.startByte;
1032
+ let windowBytes = exports.CLAUDE_TRANSCRIPT_TAIL_BYTES;
1033
+ let promptOffsetFromEnd = null;
1034
+ while (built.turns.length === 0 &&
1035
+ startByte > 0 &&
1036
+ windowBytes < exports.CLAUDE_TRANSCRIPT_MAX_TAIL_BYTES) {
1037
+ windowBytes *= 2;
1038
+ const span = await readClaudeTranscriptSpan(handle, Math.max(0, size - windowBytes), startByte);
1039
+ if (span === null)
1040
+ return null;
1041
+ const prefix = (0, transcript_1.parseClaudeTranscript)(span.text);
1042
+ records = [...prefix.records, ...records];
1043
+ malformedLines += prefix.malformedLines;
1044
+ startByte = span.startByte;
1045
+ built = (0, transcript_1.buildClaudeTurns)(records, sessionId);
1046
+ const newest = built.turns.at(-1);
1047
+ if (newest)
1048
+ promptOffsetFromEnd = claudeRecordOffsetFromEnd(span, newest.promptUuid, size);
1049
+ }
1050
+ logger.info('claude-transcript-window-extended', {
1051
+ worktreeId: target.worktreeId,
1052
+ instanceId: target.instanceId ?? target.cliToolId,
1053
+ path,
1054
+ fromBytes: exports.CLAUDE_TRANSCRIPT_TAIL_BYTES,
1055
+ toBytes: windowBytes,
1056
+ size,
1057
+ // Null when no prompt record was found; see `reachedLimit`.
1058
+ promptOffsetFromEnd,
1059
+ records: records.length,
1060
+ });
1061
+ return {
1062
+ parsed: { records, malformedLines },
1063
+ built,
1064
+ size,
1065
+ startByte,
1066
+ reachedLimit: built.turns.length === 0 && startByte > 0,
1067
+ };
1068
+ }
1069
+ catch (error) {
1070
+ logger.warn('claude-transcript-read-failed', {
1071
+ path,
1072
+ error: error instanceof Error ? error.message : String(error),
1073
+ });
1074
+ return null;
1075
+ }
1076
+ finally {
1077
+ await handle?.close().catch(() => { });
1078
+ }
1079
+ }
1080
+ /**
1081
+ * How far from the end of the file the line holding this record starts, or null.
1082
+ *
1083
+ * The number `claude-transcript-window-extended` reports, and nothing branches
1084
+ * on it: it says how much bigger than the first window the turn was. A line is
1085
+ * accepted only once it parses as the record with this `uuid`, because the same
1086
+ * string is also the next record's `parentUuid`.
1087
+ */
1088
+ function claudeRecordOffsetFromEnd(span, uuid, size) {
1089
+ const { text } = span;
1090
+ for (let at = text.indexOf(uuid); at !== -1; at = text.indexOf(uuid, at + uuid.length)) {
1091
+ const lineStart = text.lastIndexOf('\n', at) + 1;
1092
+ const lineEnd = text.indexOf('\n', at);
1093
+ let record = null;
1094
+ try {
1095
+ record = (0, transcript_1.readClaudeTranscriptRecord)(JSON.parse(text.slice(lineStart, lineEnd === -1 ? text.length : lineEnd)));
1096
+ }
1097
+ catch {
1098
+ // Not a whole record; keep looking.
1099
+ }
1100
+ if (record?.uuid === uuid) {
1101
+ return size - span.startByte - Buffer.byteLength(text.slice(0, lineStart), 'utf8');
1102
+ }
1103
+ }
1104
+ return null;
1105
+ }
1106
+ /** A turn with no prompt record writes no user row; see {@link recordClaudeUserTurn}. */
1107
+ const NO_USER_ROW = { outcome: 'skipped', messageId: null, timestampMs: null };
1108
+ /**
1109
+ * Save what can be read of a turn whose prompt record is out of reach (Issue #2470).
1110
+ *
1111
+ * The safety net under {@link CLAUDE_TRANSCRIPT_MAX_TAIL_BYTES}: the window has
1112
+ * been widened as far as it goes and still holds no prompt record, so there is
1113
+ * no prompt `uuid` to key a row on and no user row to write. What the window
1114
+ * does hold is the turn's end — the part the operator most wants, and the part a
1115
+ * long turn's pane has scrolled furthest past — and this writes that rather than
1116
+ * leave the turn with no row at all. The body opens with
1117
+ * {@link CLAUDE_TURN_HEAD_MISSING_MARKER}, so it never reads as the whole reply.
1118
+ *
1119
+ * Everything that makes a prompt-opened row safe to write applies unchanged,
1120
+ * because the row goes through the same {@link writeClaudeTurn}: an open turn is
1121
+ * refused and reported `not_yet_closed` (#2264, #2436), an empty one is handed
1122
+ * back to the scraper, and a second read finds the row by its key and answers
1123
+ * true. The key is the one difference, and {@link buildHeadlessClaudeTurn} says
1124
+ * why it can be written under at all: it names the record that closed the turn,
1125
+ * which every later read sees too.
1126
+ *
1127
+ * Neither the live bubble's body nor its key. {@link collectHeadlessClaudeTurn}
1128
+ * builds the bubble from the first window under the session's one live key, and
1129
+ * that key, written, would make the session's next long turn read "already
1130
+ * saved".
1131
+ *
1132
+ * @returns Whether History now holds the turn, marked as missing its beginning
1133
+ */
1134
+ async function captureHeadlessClaudeTurn(target, records, sessionId, path, report) {
1135
+ const instanceId = target.instanceId ?? target.cliToolId;
1136
+ const headless = (0, transcript_1.buildHeadlessClaudeTurn)(records, sessionId);
1137
+ if (headless === null) {
1138
+ logger.debug('claude-transcript-headless-unkeyed', {
1139
+ worktreeId: target.worktreeId,
1140
+ instanceId,
1141
+ path,
1142
+ });
1143
+ return false;
1144
+ }
1145
+ const { turn } = headless;
1146
+ const rendered = (0, transcript_1.renderClaudeTurn)(turn);
1147
+ logger.info('claude-transcript-headless-turn', {
1148
+ worktreeId: target.worktreeId,
1149
+ instanceId,
1150
+ sessionId: turn.sessionId,
1151
+ requestId: (0, agent_transcript_1.claudeTurnRequestId)(turn.promptUuid),
1152
+ path,
1153
+ assistantRecords: turn.assistantRecords,
1154
+ overflowed: turn.overflowed,
1155
+ });
1156
+ const captured = await writeClaudeTurn(target, turn,
1157
+ // An empty body stays empty, so the writer hands the turn back to the
1158
+ // scraper instead of saving a row that is nothing but the marker.
1159
+ rendered.body.length === 0 ? rendered : markClaudeTurnHeadMissing(rendered), resolveAssistantTimestampMs(turn, NO_USER_ROW, headless.lastRecordAt, null), path, report);
1160
+ if (captured) {
1161
+ // Issue #2437, for the reason the prompt-opened path gives.
1162
+ await (0, assistant_response_saver_1.advanceCapturedLineForTranscriptTurn)(target);
1163
+ }
1164
+ return captured;
1165
+ }
1166
+ /**
1167
+ * A rendered turn with {@link CLAUDE_TURN_HEAD_MISSING_MARKER} as its first line.
1168
+ *
1169
+ * Held to {@link MAX_CLAUDE_TURN_BODY_LENGTH} the way `renderClaudeTurn` holds
1170
+ * every body, so a turn already cut at its end is still cut the same way.
1171
+ */
1172
+ function markClaudeTurnHeadMissing(rendered) {
1173
+ let body = `${exports.CLAUDE_TURN_HEAD_MISSING_MARKER}\n\n${rendered.body}`;
1174
+ if (body.length > transcript_1.MAX_CLAUDE_TURN_BODY_LENGTH) {
1175
+ body =
1176
+ body.slice(0, transcript_1.MAX_CLAUDE_TURN_BODY_LENGTH - transcript_1.CLAUDE_TURN_TRUNCATION_MARKER.length) +
1177
+ transcript_1.CLAUDE_TURN_TRUNCATION_MARKER;
1178
+ }
1179
+ return { ...rendered, body };
1180
+ }
826
1181
  /**
827
1182
  * How many already-written turns are re-rendered and compared (Issue #2264).
828
1183
  *
@@ -935,7 +1290,9 @@ async function refreshClaudeTurnRows(target, candidates, path) {
935
1290
  *
936
1291
  * `findMessageByRequestId` is both the idempotency check and the reason a
937
1292
  * repeat poll does not duplicate the row: the id is derived from the prompt
938
- * record's `uuid`, which does not change between reads of the same file.
1293
+ * record's `uuid` or, for a turn whose prompt record is out of reach (Issue
1294
+ * #2470), from the record that closed it (`claudeHeadlessTurnId`) — and neither
1295
+ * changes between reads of the same file.
939
1296
  *
940
1297
  * Answering **true** for a turn that was already saved is deliberate. It means
941
1298
  * "History holds this turn as Markdown", which is exactly what the poller needs
@@ -68,7 +68,9 @@ exports.isClaudeTurnClosingRecord = isClaudeTurnClosingRecord;
68
68
  exports.isClaudeTurnWritable = isClaudeTurnWritable;
69
69
  exports.createClaudeTurn = createClaudeTurn;
70
70
  exports.buildClaudeTurns = buildClaudeTurns;
71
+ exports.buildHeadlessClaudeTurn = buildHeadlessClaudeTurn;
71
72
  exports.renderClaudeTurn = renderClaudeTurn;
73
+ const agent_transcript_1 = require("../../../../types/agent-transcript");
72
74
  const event_mapper_1 = require("../event-mapper");
73
75
  const turn_body_1 = require("../turn-body");
74
76
  /**
@@ -588,6 +590,95 @@ function buildClaudeTurns(records, sessionId) {
588
590
  }
589
591
  return { turns, orphanedAssistantRecords, sidechainRecords };
590
592
  }
593
+ /**
594
+ * The turn the records in front of the first prompt record belong to (Issue #2470).
595
+ *
596
+ * {@link buildClaudeTurns} counts these as orphans and drops them, and for the
597
+ * case it was written for that is right: a window that opens mid-turn over a
598
+ * long session holds the tail of a turn that was written back when it was the
599
+ * newest. This is for the other case, and `./history` only calls it there — a
600
+ * window widened to its limit that still holds **no** prompt record at all, so
601
+ * these records are the newest turn and no other reader is going to write them.
602
+ *
603
+ * Built by the rules `buildClaudeTurns` applies to a turn, so the two cannot
604
+ * disagree about what one is: sidechains skipped, `closed` read off the **last**
605
+ * assistant record ({@link isClaudeTurnClosingRecord}), `stopReasonObserved` set
606
+ * by any. `./history`'s writer therefore refuses a headless turn that is still
607
+ * open exactly as it refuses any other (#2264).
608
+ *
609
+ * The key is {@link claudeHeadlessTurnId} of the last assistant record's `uuid`;
610
+ * see that function for the census behind choosing it over the first record in
611
+ * the window. Once the turn is closed, the last assistant record is the one
612
+ * record every later read of it is guaranteed to see.
613
+ *
614
+ * **When the block cap bites, the end is kept, not the beginning** — the reverse
615
+ * of `buildClaudeTurns`. A prompt-opened turn keeps its first
616
+ * {@link MAX_CLAUDE_TURN_BLOCKS} because that is where its reply starts; a
617
+ * headless one has already lost its start, and what is worth keeping of the rest
618
+ * is where the reply ends.
619
+ *
620
+ * @param records - In file order
621
+ * @param sessionId - Fallback for records that carry no `sessionId`
622
+ * @returns The turn, or null when no assistant record precedes the first prompt
623
+ * record, or when the last one has no `uuid` to key the turn on
624
+ */
625
+ function buildHeadlessClaudeTurn(records, sessionId) {
626
+ const blocks = [];
627
+ let assistantRecords = 0;
628
+ let closed = false;
629
+ let stopReasonObserved = false;
630
+ let superseded = false;
631
+ let firstRecordAt = 0;
632
+ let lastRecordAt = 0;
633
+ let last = null;
634
+ for (const record of records) {
635
+ if (record.isSidechain)
636
+ continue;
637
+ if (isClaudePromptRecord(record)) {
638
+ // A later prompt is proof nothing more is coming, as it is for
639
+ // `buildClaudeTurns`. `./history` never hands this a window holding one.
640
+ superseded = true;
641
+ break;
642
+ }
643
+ if (record.type !== 'assistant')
644
+ continue;
645
+ assistantRecords += 1;
646
+ // Assigned, not or-ed — the last record's answer stands. See buildClaudeTurns.
647
+ closed = isClaudeTurnClosingRecord(record);
648
+ if (record.stopReason !== null)
649
+ stopReasonObserved = true;
650
+ if (record.timestampMs !== null) {
651
+ if (firstRecordAt === 0)
652
+ firstRecordAt = record.timestampMs;
653
+ lastRecordAt = Math.max(lastRecordAt, record.timestampMs);
654
+ }
655
+ for (const block of record.blocks)
656
+ blocks.push(block);
657
+ last = record;
658
+ }
659
+ if (last === null || !last.uuid)
660
+ return null;
661
+ const turnSessionId = last.sessionId ?? sessionId;
662
+ const overflowed = blocks.length > exports.MAX_CLAUDE_TURN_BLOCKS;
663
+ return {
664
+ turn: {
665
+ sessionId: turnSessionId,
666
+ promptUuid: (0, agent_transcript_1.claudeHeadlessTurnId)(turnSessionId, last.uuid),
667
+ // The earliest instant the window can vouch for. `./history` only uses it
668
+ // as the floor it dates the row against, and it is never above lastRecordAt.
669
+ startedAt: firstRecordAt,
670
+ promptText: '',
671
+ promptIsOperatorInput: false,
672
+ blocks: overflowed ? blocks.slice(-exports.MAX_CLAUDE_TURN_BLOCKS) : blocks,
673
+ assistantRecords,
674
+ closed,
675
+ superseded,
676
+ stopReasonObserved,
677
+ overflowed,
678
+ },
679
+ lastRecordAt,
680
+ };
681
+ }
591
682
  /**
592
683
  * Block types that carry nothing a reader wants.
593
684
  *