commandmate 0.33.1 → 0.33.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 (291) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +290 -290
  3. package/.next/app-path-routes-manifest.json +29 -29
  4. package/.next/build-manifest.json +5 -5
  5. package/.next/diagnostics/framework.json +1 -1
  6. package/.next/next-server.js.nft.json +1 -1
  7. package/.next/prerender-manifest.json +3 -3
  8. package/.next/required-server-files.json +1 -2
  9. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  10. package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
  12. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/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.nft.json +1 -1
  17. package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
  18. package/.next/server/app/api/assistant/messages/route.js +1 -1
  19. package/.next/server/app/api/assistant/messages/route.js.nft.json +1 -1
  20. package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/assistant/session/route.js +1 -1
  22. package/.next/server/app/api/assistant/session/route.js.nft.json +1 -1
  23. package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
  24. package/.next/server/app/api/assistant/start/route.js +32 -1
  25. package/.next/server/app/api/assistant/start/route.js.nft.json +1 -1
  26. package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
  27. package/.next/server/app/api/assistant/terminal/route.js +33 -2
  28. package/.next/server/app/api/assistant/terminal/route.js.nft.json +1 -1
  29. package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
  30. package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
  31. package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  37. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  38. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  40. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  41. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  42. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  43. package/.next/server/app/api/hooks/agent-event/route.js +1 -1
  44. package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
  45. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  46. package/.next/server/app/api/hooks/claude-done/route.js +2 -2
  47. package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
  48. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  49. package/.next/server/app/api/hooks/permission-request/route.js +1 -1
  50. package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
  51. package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
  52. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  53. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  54. package/.next/server/app/api/push/escalation/route.js +1 -1
  55. package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  57. package/.next/server/app/api/push/vapid/route.js +1 -1
  58. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/relays/[relayId]/cancel/route.js +1 -1
  60. package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
  61. package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/relays/route.js +1 -1
  63. package/.next/server/app/api/relays/route.js.nft.json +1 -1
  64. package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
  65. package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
  66. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  67. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  68. package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  70. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
  71. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  72. package/.next/server/app/api/repositories/clone/route.js +1 -1
  73. package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
  74. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  75. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  76. package/.next/server/app/api/repositories/restore/route.js +1 -1
  77. package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
  78. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  79. package/.next/server/app/api/repositories/route.js +1 -1
  80. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  81. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  82. package/.next/server/app/api/repositories/scan/route.js +1 -1
  83. package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
  84. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  85. package/.next/server/app/api/repositories/sync/route.js +1 -1
  86. package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
  87. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  88. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
  90. package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
  91. package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  93. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  94. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  96. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  97. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  98. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  99. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  100. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  101. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  103. package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
  104. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  105. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  106. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  107. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  108. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  109. package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
  110. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  111. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
  112. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
  113. package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
  114. package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
  115. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  116. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  117. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  118. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  119. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  120. package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
  121. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  122. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  124. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  127. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  129. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.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_client-reference-manifest.js +1 -1
  132. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  133. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  135. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  136. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  137. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  138. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  139. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  141. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  142. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  146. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
  148. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
  149. package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
  151. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  152. package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
  153. package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
  154. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  155. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  157. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  158. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  159. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  161. package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
  162. package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
  163. package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
  164. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  165. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
  166. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  167. package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
  168. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
  170. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  171. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  173. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  174. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  175. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  176. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  177. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  178. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
  179. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  180. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  181. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
  182. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  183. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  184. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  185. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  186. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  187. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  188. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  189. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  190. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  191. package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
  192. package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
  193. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  194. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  195. package/.next/server/app/api/worktrees/[id]/terminal/route.js +103 -1
  196. package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
  197. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  198. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  199. package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
  200. package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
  201. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  202. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  203. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  204. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  205. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  206. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  207. package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
  208. package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -1
  209. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  210. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js +1 -1
  211. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
  212. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  213. package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
  214. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  215. package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
  216. package/.next/server/app/api/worktrees/route.js +1 -1
  217. package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
  218. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  219. package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  220. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  221. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  222. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  223. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  224. package/.next/server/app/page_client-reference-manifest.js +1 -1
  225. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  226. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  227. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  228. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  229. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  230. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  231. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  232. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  233. package/.next/server/app/worktrees/[id]/page.js +8 -8
  234. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  235. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  236. package/.next/server/app-paths-manifest.json +29 -29
  237. package/.next/server/chunks/1068.js +1 -0
  238. package/.next/server/chunks/1210.js +1 -1
  239. package/.next/server/chunks/1331.js +2 -2
  240. package/.next/server/chunks/1366.js +5 -3
  241. package/.next/server/chunks/1886.js +2 -2
  242. package/.next/server/chunks/2839.js +1 -0
  243. package/.next/server/chunks/3241.js +1 -1
  244. package/.next/server/chunks/3323.js +1 -0
  245. package/.next/server/chunks/3707.js +1 -1
  246. package/.next/server/chunks/3708.js +1 -1
  247. package/.next/server/chunks/4443.js +1 -1
  248. package/.next/server/chunks/5220.js +1 -1
  249. package/.next/server/chunks/595.js +2 -2
  250. package/.next/server/chunks/650.js +1 -0
  251. package/.next/server/chunks/6781.js +1 -0
  252. package/.next/server/chunks/6808.js +1 -0
  253. package/.next/server/chunks/6838.js +1 -1
  254. package/.next/server/chunks/7875.js +3 -3
  255. package/.next/server/chunks/8918.js +107 -5
  256. package/.next/server/middleware-build-manifest.js +1 -1
  257. package/.next/server/middleware-manifest.json +5 -5
  258. package/.next/server/pages/500.html +1 -1
  259. package/.next/server/server-reference-manifest.json +1 -1
  260. package/.next/server/src/middleware.js.map +1 -1
  261. package/.next/static/chunks/1255-7e5873f06b25e129.js +1 -0
  262. package/.next/static/chunks/{4718-2bc5cdf06573bf54.js → 4718-441a2af91f0374e9.js} +1 -1
  263. package/.next/static/chunks/app/worktrees/[id]/page-38edcd53e51f53b0.js +1 -0
  264. package/.next/static/chunks/{main-6092074a0dc78280.js → main-ac91ed6e71380841.js} +1 -1
  265. package/.next/trace +13 -14
  266. package/dist/server/src/lib/assistant-response-saver.js +168 -12
  267. package/dist/server/src/lib/hooks/sources/antigravity/history.js +204 -9
  268. package/dist/server/src/lib/hooks/sources/claude/history.js +29 -3
  269. package/dist/server/src/lib/hooks/sources/codex/history.js +29 -3
  270. package/dist/server/src/lib/hooks/sources/command-code/history.js +29 -3
  271. package/dist/server/src/lib/hooks/stop-history-capture.js +30 -4
  272. package/dist/server/src/lib/polling/response-checker.js +258 -9
  273. package/dist/server/src/lib/polling/response-poller-core.js +20 -0
  274. package/dist/server/src/lib/polling/structured-history-gate.js +26 -6
  275. package/dist/server/src/lib/response-cleaner.js +84 -0
  276. package/package.json +2 -2
  277. package/.next/server/chunks/21.js +0 -1
  278. package/.next/server/chunks/3086.js +0 -1
  279. package/.next/server/chunks/3270.js +0 -1
  280. package/.next/server/chunks/3925.js +0 -1
  281. package/.next/server/chunks/5043.js +0 -1
  282. package/.next/server/chunks/6306.js +0 -1
  283. package/.next/server/chunks/6363.js +0 -1
  284. package/.next/server/chunks/6491.js +0 -103
  285. package/.next/server/chunks/7890.js +0 -1
  286. package/.next/server/chunks/8063.js +0 -32
  287. package/.next/server/chunks/8687.js +0 -1
  288. package/.next/static/chunks/1255-8cb587d9170b45ed.js +0 -1
  289. package/.next/static/chunks/app/worktrees/[id]/page-13ca0ba551fe5cfb.js +0 -1
  290. /package/.next/static/{9lgw9hA727UMyFhXryGWG → 0a4qrU8WdUwQrlO4mfLMu}/_buildManifest.js +0 -0
  291. /package/.next/static/{9lgw9hA727UMyFhXryGWG → 0a4qrU8WdUwQrlO4mfLMu}/_ssgManifest.js +0 -0
@@ -18,9 +18,43 @@
18
18
  * buffer, which is false for alternate-screen tools — those are handled by the
19
19
  * response poller instead (Issue #1268 / #1292; see savePendingAssistantResponse).
20
20
  */
21
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
22
+ if (k2 === undefined) k2 = k;
23
+ var desc = Object.getOwnPropertyDescriptor(m, k);
24
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
25
+ desc = { enumerable: true, get: function() { return m[k]; } };
26
+ }
27
+ Object.defineProperty(o, k2, desc);
28
+ }) : (function(o, m, k, k2) {
29
+ if (k2 === undefined) k2 = k;
30
+ o[k2] = m[k];
31
+ }));
32
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
33
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
34
+ }) : function(o, v) {
35
+ o["default"] = v;
36
+ });
37
+ var __importStar = (this && this.__importStar) || (function () {
38
+ var ownKeys = function(o) {
39
+ ownKeys = Object.getOwnPropertyNames || function (o) {
40
+ var ar = [];
41
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
42
+ return ar;
43
+ };
44
+ return ownKeys(o);
45
+ };
46
+ return function (mod) {
47
+ if (mod && mod.__esModule) return mod;
48
+ var result = {};
49
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
50
+ __setModuleDefault(result, mod);
51
+ return result;
52
+ };
53
+ })();
21
54
  Object.defineProperty(exports, "__esModule", { value: true });
22
55
  exports.detectBufferReset = detectBufferReset;
23
56
  exports.cleanCliResponse = cleanCliResponse;
57
+ exports.advanceCapturedLineForTranscriptTurn = advanceCapturedLineForTranscriptTurn;
24
58
  exports.savePendingAssistantResponse = savePendingAssistantResponse;
25
59
  const cli_session_1 = require("./session/cli-session");
26
60
  const db_1 = require("./db");
@@ -82,6 +116,31 @@ function detectBufferReset(currentLineCount, lastCapturedLine) {
82
116
  }
83
117
  return { bufferReset: false, reason: null };
84
118
  }
119
+ /**
120
+ * How many rows of a capture count as "read so far".
121
+ *
122
+ * Trailing blank rows are discarded, for consistency with the response poller's
123
+ * `extractResponse`: tmux pads the pane out to its height, and counting that
124
+ * padding inflates the stored cursor so far past the real content that the
125
+ * poller's dedup check (`result.lineCount <= lastCapturedLine`) can never fire
126
+ * again.
127
+ *
128
+ * The one definition of the count, shared by the two writers of
129
+ * `session_states.last_captured_line` in this module (Issue #2437): the
130
+ * pre-send flush and {@link advanceCapturedLineForTranscriptTurn}. Two spellings
131
+ * of "how far have I read" would be two cursors that disagree.
132
+ *
133
+ * @param output - Raw capture
134
+ * @returns Row count with trailing blank rows removed
135
+ */
136
+ function countCapturedLines(output) {
137
+ const lines = output.split('\n');
138
+ let trimmedLength = lines.length;
139
+ while (trimmedLength > 0 && lines[trimmedLength - 1].trim() === '') {
140
+ trimmedLength--;
141
+ }
142
+ return trimmedLength;
143
+ }
85
144
  /**
86
145
  * Time offset (in milliseconds) for assistant message timestamp
87
146
  * Ensures assistant response appears before user message in chronological order
@@ -91,8 +150,23 @@ const ASSISTANT_TIMESTAMP_OFFSET_MS = 1;
91
150
  /**
92
151
  * Clean CLI tool response based on tool type
93
152
  *
153
+ * Every one of `CLI_TOOL_IDS`' eight tools has a branch (Issue #2437). Until
154
+ * then four of them — codex, command-code, antigravity and vibe-local — fell
155
+ * through to `output.trim()`, and codex's branch said so in as many words:
156
+ * *"Codex doesn't need special cleaning"*. It does. What that branch actually
157
+ * saved was codex's **idle composer**, ANSI and all, as an assistant reply:
158
+ *
159
+ * ```text
160
+ * › Ask Codex to do anything
161
+ *
162
+ * gpt-6-astra xhigh · ~/share/work/… · Main [default]
163
+ * ```
164
+ *
165
+ * See {@link cleanScrollbackResponse} for how the four share one cleaner
166
+ * without sharing a boundary rule.
167
+ *
94
168
  * @param output - Raw output from CLI tool
95
- * @param cliToolId - CLI tool identifier (claude, codex, gemini)
169
+ * @param cliToolId - CLI tool identifier
96
170
  * @returns Cleaned response content
97
171
  */
98
172
  function cleanCliResponse(output, cliToolId) {
@@ -106,12 +180,101 @@ function cleanCliResponse(output, cliToolId) {
106
180
  case 'copilot':
107
181
  return (0, response_cleaner_1.cleanCopilotResponse)(output);
108
182
  case 'codex':
109
- // Codex doesn't need special cleaning
110
- return output.trim();
183
+ case 'command-code':
184
+ case 'antigravity':
185
+ case 'vibe-local':
186
+ return (0, response_cleaner_1.cleanScrollbackResponse)(output, cliToolId);
111
187
  default:
112
188
  return output.trim();
113
189
  }
114
190
  }
191
+ /**
192
+ * Move `last_captured_line` past everything a transcript row now covers
193
+ * (Issue #2437).
194
+ *
195
+ * ## The defect this closes
196
+ *
197
+ * The pre-send flush ({@link savePendingAssistantResponse}) reads
198
+ * `lastCapturedLine`, and saves **everything past it** as the pending reply. The
199
+ * only writer of that cursor used to be the flush itself and the response
200
+ * poller — the Stop path that writes the agent's OWN Markdown into History
201
+ * (`hooks/sources/<tool>/history.ts`) never touched it. So on this ordering, which
202
+ * costs nothing to hit at a 2-second poll interval:
203
+ *
204
+ * ```text
205
+ * 1. turn ends → the Stop path writes the turn as a Markdown row (cursor unmoved)
206
+ * 2. `/send` arrives BEFORE the next poll tick
207
+ * 3. the flush saves "everything since the cursor" = the whole finished turn
208
+ * ```
209
+ *
210
+ * The second copy is the pane's scrape of the very same turn, so the chat
211
+ * surface shows one reply twice. A cleaner cannot help: what is duplicated is
212
+ * the real body, not chrome.
213
+ *
214
+ * ## Why a capture rather than an arithmetic bump
215
+ *
216
+ * The cursor is a row index into the pane, and the transcript reader never looks
217
+ * at the pane at all — it reads a JSONL file. The only honest way to say "the
218
+ * pane up to here is already in History" is to ask the pane how tall it is now.
219
+ * The capture is the cached one ({@link captureSessionOutput}, 5s TTL shared
220
+ * with the poller), so a Stop that lands between two ticks usually costs no
221
+ * `tmux capture-pane` at all.
222
+ *
223
+ * ## What it deliberately does not do
224
+ *
225
+ * - **Alternate-screen tools are skipped.** For claude, opencode and copilot the
226
+ * line count is a screen-row constant rather than a cursor (Issue #1268), and
227
+ * {@link savePendingAssistantResponse} refuses to run for them at all — there
228
+ * is no cursor here to advance and writing one would be a lie.
229
+ * - **The cursor only ever moves forward.** A capture shorter than the stored
230
+ * value is a buffer reset, and `detectBufferReset` owns that reading; moving
231
+ * the cursor backwards from here would hand the flush a range it has already
232
+ * saved.
233
+ * - **It never throws, and never changes the caller's answer.** The transcript
234
+ * row is written whether or not this succeeds; a failure here costs one
235
+ * duplicated reply, and a failure that propagated would cost the row.
236
+ *
237
+ * @param target - The instance whose turn was just written to History
238
+ * @returns The cursor's new value, or null when it was left where it was
239
+ */
240
+ async function advanceCapturedLineForTranscriptTurn(target) {
241
+ const { worktreeId, cliToolId } = target;
242
+ const resolvedInstanceId = target.instanceId ?? cliToolId;
243
+ try {
244
+ if ((0, types_1.usesAlternateScreen)(cliToolId)) {
245
+ return null;
246
+ }
247
+ const output = await (0, cli_session_1.captureSessionOutput)(worktreeId, cliToolId, SESSION_OUTPUT_BUFFER_SIZE, target.instanceId);
248
+ if (!output) {
249
+ return null;
250
+ }
251
+ const currentLineCount = countCapturedLines(output);
252
+ const { getDbInstance } = await Promise.resolve().then(() => __importStar(require('./db/db-instance')));
253
+ const db = getDbInstance();
254
+ const lastCapturedLine = (0, db_1.getSessionState)(db, worktreeId, resolvedInstanceId)?.lastCapturedLine || 0;
255
+ if (currentLineCount <= lastCapturedLine) {
256
+ return null;
257
+ }
258
+ (0, db_1.updateSessionState)(db, worktreeId, cliToolId, currentLineCount, target.instanceId);
259
+ logger.info('transcript:cursor-advanced', {
260
+ worktreeId,
261
+ instanceId: resolvedInstanceId,
262
+ from: lastCapturedLine,
263
+ to: currentLineCount,
264
+ });
265
+ return currentLineCount;
266
+ }
267
+ catch (error) {
268
+ // Never the caller's problem: the transcript row is already written, and the
269
+ // worst this costs is the duplicate it was meant to prevent.
270
+ logger.debug('transcript:cursor-advance-failed', {
271
+ worktreeId,
272
+ instanceId: resolvedInstanceId,
273
+ error: error instanceof Error ? error.message : String(error),
274
+ });
275
+ return null;
276
+ }
277
+ }
115
278
  /**
116
279
  * Save pending assistant response before a new user message
117
280
  *
@@ -170,16 +333,9 @@ async function savePendingAssistantResponse(db, worktreeId, cliToolId, userMessa
170
333
  if (!output) {
171
334
  return null;
172
335
  }
173
- // 3. Calculate current line count
174
- // Trim trailing empty lines for consistency with response-poller's extractResponse.
175
- // Without this, tmux buffer padding inflates the line count, causing the poller's
176
- // dedup check (result.lineCount <= lastCapturedLine) to always trigger.
336
+ // 3. Calculate current line count (see countCapturedLines for the trim).
177
337
  const lines = output.split('\n');
178
- let trimmedLength = lines.length;
179
- while (trimmedLength > 0 && lines[trimmedLength - 1].trim() === '') {
180
- trimmedLength--;
181
- }
182
- const currentLineCount = trimmedLength;
338
+ const currentLineCount = countCapturedLines(output);
183
339
  // 4. Detect buffer reset (Issue #59 fix)
184
340
  const { bufferReset, reason } = detectBufferReset(currentLineCount, lastCapturedLine);
185
341
  if (bufferReset) {
@@ -91,7 +91,7 @@ var __importStar = (this && this.__importStar) || (function () {
91
91
  };
92
92
  })();
93
93
  Object.defineProperty(exports, "__esModule", { value: true });
94
- exports.ANTIGRAVITY_CLI_HOME_SEGMENTS = exports.ANTIGRAVITY_TRANSCRIPT_TAIL_BYTES = void 0;
94
+ exports.ANTIGRAVITY_TURN_RECHECK_LIMIT = exports.ANTIGRAVITY_CLI_HOME_SEGMENTS = exports.ANTIGRAVITY_TRANSCRIPT_TAIL_BYTES = void 0;
95
95
  exports.resetAntigravityTranscriptConversations = resetAntigravityTranscriptConversations;
96
96
  exports.resolveAntigravityConversationId = resolveAntigravityConversationId;
97
97
  exports.resolveAntigravityHome = resolveAntigravityHome;
@@ -106,6 +106,7 @@ const path_1 = require("path");
106
106
  const auto_yes_state_1 = require("../../../../lib/auto-yes-state");
107
107
  const transcript_tail_1 = require("../../../../lib/history/transcript-tail");
108
108
  const user_turn_recorder_1 = require("../../../../lib/history/user-turn-recorder");
109
+ const assistant_response_saver_1 = require("../../../../lib/assistant-response-saver");
109
110
  const logger_1 = require("../../../../lib/logger");
110
111
  const agent_transcript_1 = require("../../../../types/agent-transcript");
111
112
  const transcript_1 = require("./transcript");
@@ -288,11 +289,29 @@ function acceptAntigravityTranscriptPath(agyHome, candidate) {
288
289
  *
289
290
  * Never throws.
290
291
  *
292
+ * **A row this reader wrote is not final (Issue #2438).** Before anything is
293
+ * written, the newest already-written turns — at most
294
+ * {@link ANTIGRAVITY_TURN_RECHECK_LIMIT} of them — are re-rendered and compared
295
+ * against the rows they produced, and a row whose turn now renders *strictly
296
+ * longer* is replaced in place. agy has no record that closes a turn, so an
297
+ * interim report reads as a finished answer (`isAntigravityTurnClosingRecord`)
298
+ * and used to freeze a half-written reply into History forever. That is a
299
+ * repair and not a second verdict: growing an older row changes neither the
300
+ * return value nor `report`, both of which are about the **newest** turn.
301
+ *
302
+ * Since Issue #2436 the false can explain itself: pass a
303
+ * `StructuredHistoryCaptureReport` and `outcome` is set to `'not_yet_closed'`
304
+ * when the newest turn is one the agent has not finished writing — the case the
305
+ * `-turn-open` line below reports, and the one where the caller's scraped copy
306
+ * is worth holding rather than saving. Every other false leaves it unset, which
307
+ * the gate reads as `'unavailable'`.
308
+ *
291
309
  * @param target - The instance whose turn just ended
292
310
  * @param capture - See {@link AntigravityTranscriptCapture}
311
+ * @param report - Optional out-parameter; see `StructuredHistoryCaptureReport`
293
312
  * @returns Whether History now holds this turn as the agent's own Markdown
294
313
  */
295
- async function captureAntigravityTranscriptTurn(target, capture = {}) {
314
+ async function captureAntigravityTranscriptTurn(target, capture = {}, report) {
296
315
  const instanceId = target.instanceId ?? target.cliToolId;
297
316
  try {
298
317
  const agyHome = capture.antigravityHome ?? resolveAntigravityHome();
@@ -348,12 +367,26 @@ async function captureAntigravityTranscriptTurn(target, capture = {}) {
348
367
  });
349
368
  }
350
369
  const pending = await selectUnwrittenAntigravityTurns(target, built.turns);
370
+ // Before anything is written: the rows that are already there (#2438). This
371
+ // is deliberately ahead of the early return below, because "the newest turn
372
+ // is already a row" is exactly the state the frozen row the Issue measured
373
+ // was stuck in — agy said "waiting for the worker", the writer saved that,
374
+ // and every later read answered true and did nothing while the conclusion
375
+ // sat in the transcript beside it. Written turns are re-checked whether or
376
+ // not anything is pending, so an old turn can be repaired in the same pass
377
+ // that writes a new one.
378
+ await refreshAntigravityTurnRows(target, built.turns
379
+ .slice(0, built.turns.length - pending.turns.length)
380
+ .slice(-exports.ANTIGRAVITY_TURN_RECHECK_LIMIT), path);
351
381
  if (pending.turns.length === 0) {
352
382
  logger.debug('antigravity-transcript-turns-already-saved', {
353
383
  worktreeId: target.worktreeId,
354
384
  instanceId,
355
385
  turnsInWindow: built.turns.length,
356
386
  });
387
+ // Issue #2437: this turn is already History's Markdown, so the pane rows
388
+ // behind it must stop being "unsaved output" the pre-send flush can pick up.
389
+ await (0, assistant_response_saver_1.advanceCapturedLineForTranscriptTurn)(target);
357
390
  return true;
358
391
  }
359
392
  if (pending.turns.length > 1) {
@@ -380,7 +413,14 @@ async function captureAntigravityTranscriptTurn(target, capture = {}) {
380
413
  let captured = false;
381
414
  for (let index = 0; index < pending.turns.length; index += 1) {
382
415
  const turn = pending.turns[index];
383
- captured = await writeAntigravityTurn(target, turn, (0, transcript_1.renderAntigravityTurn)(turn), resolveAssistantTimestampMs(turn, userRows[index], lastAntigravityRecordAt(turn), nextTurnOpensAt(pending.turns, userRows, index)), path);
416
+ captured = await writeAntigravityTurn(target, turn, (0, transcript_1.renderAntigravityTurn)(turn), resolveAssistantTimestampMs(turn, userRows[index], lastAntigravityRecordAt(turn), nextTurnOpensAt(pending.turns, userRows, index)), path, report);
417
+ }
418
+ if (captured) {
419
+ // Issue #2437: History now holds this turn as the agent's own Markdown.
420
+ // Park the pre-send flush's cursor past the pane rows it covers, or a
421
+ // `/send` arriving before the next poll tick saves the whole finished turn
422
+ // a second time.
423
+ await (0, assistant_response_saver_1.advanceCapturedLineForTranscriptTurn)(target);
384
424
  }
385
425
  return captured;
386
426
  }
@@ -577,6 +617,137 @@ function nextTurnOpensAt(turns, userRows, index) {
577
617
  return null;
578
618
  return userRows[index + 1]?.timestampMs ?? next.startedAt;
579
619
  }
620
+ /**
621
+ * How many already-written turns are re-rendered and compared (Issue #2438).
622
+ *
623
+ * The repair half of #2438 has to look at rows this reader has **already**
624
+ * written, which is the one thing the anchor rule of
625
+ * {@link selectUnwrittenAntigravityTurns} deliberately does not do — so it is
626
+ * bounded here rather than by the read window. Three, the number claude and
627
+ * command-code settled on in #2264 and for the same arithmetic: the poller runs
628
+ * every couple of seconds, re-rendering the whole window on every tick would
629
+ * make a repair the most expensive thing the poll does, and a turn that is going
630
+ * to grow grows within seconds of being written.
631
+ *
632
+ * The cost of the bound is paid by rows a session has already moved three turns
633
+ * past: those keep whatever they were written with. The measured case — one
634
+ * conversation whose only turn was `#0` — is inside it by a wide margin.
635
+ */
636
+ exports.ANTIGRAVITY_TURN_RECHECK_LIMIT = 3;
637
+ /**
638
+ * Replace a saved row whose body has since grown (Issue #2438).
639
+ *
640
+ * The defect this exists for is not that the wrong body was written; it is that
641
+ * the row was written **early**. `isAntigravityTurnClosingRecord` reads prose
642
+ * with no `tool_calls` as agy finishing, and an interim report — "waiting for
643
+ * the worker" — has exactly that shape. The row is keyed
644
+ * `antigravity-turn:<conversationId>#<stepIndex>`, so once it exists every later
645
+ * read finds it, answers "already saved", and the gate suppresses the scrape
646
+ * that could have carried the conclusion instead. Nothing else in the system
647
+ * ever revisits that row.
648
+ *
649
+ * **Strictly longer, never merely different.** Equality is the ordinary case and
650
+ * must cost nothing, and a body that got *shorter* between two reads is not a
651
+ * turn that grew — it is a window that slid, or a truncation marker, and
652
+ * overwriting a full reply with a shorter one is the one outcome worse than the
653
+ * bug. Longer implies different, so one comparison covers both.
654
+ *
655
+ * Only `content` moves. The row's `id`, `request_id`, `timestamp`, worktree,
656
+ * tool and instance are what History sorts and pairs on, and a repair that
657
+ * disturbed any of them would move an old answer to the bottom of the
658
+ * conversation.
659
+ *
660
+ * `message_updated`, never `message`: the row already existed and was already
661
+ * delivered when it was created, so a client that appended instead of replacing
662
+ * would show the reply twice.
663
+ *
664
+ * @param existing - The row `findMessageByRequestId` answered with
665
+ * @returns Whether the row was replaced
666
+ */
667
+ async function growAntigravityTurnRow(target, existing, rendered, path) {
668
+ const instanceId = target.instanceId ?? target.cliToolId;
669
+ // The stored body is the only evidence of what History holds, so a row that
670
+ // carries none is not evidence that anything grew. Same answer as "not
671
+ // longer": leave it alone. This runs inside the poller's save path, where the
672
+ // module contract is that nothing throws.
673
+ const previous = existing.content;
674
+ if (typeof previous !== 'string')
675
+ return false;
676
+ const previousLength = previous.length;
677
+ if (rendered.body.length <= previousLength)
678
+ return false;
679
+ const [{ getDbInstance }, { updateMessageContent }, { broadcastMessage }] = await Promise.all([
680
+ Promise.resolve().then(() => __importStar(require('../../../../lib/db/db-instance'))),
681
+ Promise.resolve().then(() => __importStar(require('../../../../lib/db'))),
682
+ Promise.resolve().then(() => __importStar(require('../../../../lib/ws-server'))),
683
+ ]);
684
+ updateMessageContent(getDbInstance(), existing.id, rendered.body);
685
+ broadcastMessage('message_updated', {
686
+ worktreeId: target.worktreeId,
687
+ message: { ...existing, content: rendered.body },
688
+ });
689
+ logger.info('antigravity-transcript-turn-updated', {
690
+ worktreeId: target.worktreeId,
691
+ instanceId,
692
+ conversationId: rendered.conversationId,
693
+ stepIndex: rendered.stepIndex,
694
+ requestId: existing.requestId,
695
+ path,
696
+ previousLength,
697
+ bodyLength: rendered.body.length,
698
+ textBlocks: rendered.textBlocks,
699
+ toolBlocks: rendered.toolBlocks,
700
+ });
701
+ return true;
702
+ }
703
+ /**
704
+ * Re-read the newest already-written turns and grow the short ones (#2438).
705
+ *
706
+ * Runs before the pending turns are written and independently of whether there
707
+ * are any — the case it exists for is precisely the one
708
+ * {@link captureAntigravityTranscriptTurn} used to return `true` from without
709
+ * doing anything: the newest turn already has a row, and that row stopped at
710
+ * agy's interim report.
711
+ *
712
+ * Turns that are open again are skipped rather than compared. A turn whose last
713
+ * record is a `tool_calls` is one agy is still working through, its body is by
714
+ * definition not the final one, and a repair that raced the agent would rewrite
715
+ * the row on every poll of a long turn. **This is not a second chance to write
716
+ * a turn**: a candidate with no row is left alone, because the anchor rule
717
+ * already decided it is not this pass's to create.
718
+ *
719
+ * The database is asked before the turn is rendered, so a candidate with no row
720
+ * — every candidate, in a session this reader has never written to — costs one
721
+ * indexed lookup and no Markdown.
722
+ *
723
+ * Serialisation is the gate's, per instance: this adds no loop and no timer of
724
+ * its own, it is one more thing the poll's existing pass does.
725
+ *
726
+ * @param candidates - Already-written turns, oldest first, at most
727
+ * {@link ANTIGRAVITY_TURN_RECHECK_LIMIT}
728
+ * @returns How many rows were replaced
729
+ */
730
+ async function refreshAntigravityTurnRows(target, candidates, path) {
731
+ if (candidates.length === 0)
732
+ return 0;
733
+ const [{ getDbInstance }, { findMessageByRequestId }] = await Promise.all([
734
+ Promise.resolve().then(() => __importStar(require('../../../../lib/db/db-instance'))),
735
+ Promise.resolve().then(() => __importStar(require('../../../../lib/db'))),
736
+ ]);
737
+ const db = getDbInstance();
738
+ let updated = 0;
739
+ for (const turn of candidates) {
740
+ if (!(0, transcript_1.isAntigravityTurnWritable)(turn))
741
+ continue;
742
+ const existing = findMessageByRequestId(db, target.worktreeId, (0, agent_transcript_1.antigravityTurnRequestId)(turn.conversationId, turn.stepIndex));
743
+ if (!existing)
744
+ continue;
745
+ if (await growAntigravityTurnRow(target, existing, (0, transcript_1.renderAntigravityTurn)(turn), path)) {
746
+ updated += 1;
747
+ }
748
+ }
749
+ return updated;
750
+ }
580
751
  /**
581
752
  * Write one rendered turn, unless it is already there.
582
753
  *
@@ -587,20 +758,36 @@ function nextTurnOpensAt(turns, userRows, index) {
587
758
  * Answering **true** for a turn that was already saved is deliberate. It means
588
759
  * "History holds this turn as Markdown", which is what the poller needs to know
589
760
  * — a second poll of the same finished turn must not save the pane's copy on top
590
- * of the row this path wrote.
761
+ * of the row this path wrote. Since #2438 that row is no longer left as it was
762
+ * found: it is the same comparison {@link growAntigravityTurnRow} makes for the
763
+ * turns the recheck window covers, made here where both the row and the turn
764
+ * are already in hand.
591
765
  *
592
766
  * @returns Whether History holds this turn as the agent's own Markdown
593
767
  */
594
- async function writeAntigravityTurn(target, turn, rendered, timestampMs, path) {
768
+ async function writeAntigravityTurn(target, turn, rendered, timestampMs, path, report) {
595
769
  const instanceId = target.instanceId ?? target.cliToolId;
770
+ // Issue #2436: the caller's report is about the turn THIS call is deciding.
771
+ // The loop above walks oldest-first, so a verdict left by an earlier turn has
772
+ // to be cleared before this one's is written.
773
+ if (report)
774
+ report.outcome = undefined;
596
775
  if (!(0, transcript_1.isAntigravityTurnWritable)(turn)) {
597
776
  // agy has not finished this answer and no later prompt has taken over, so
598
777
  // what is in the file is a turn in progress. Writing it would put a reply
599
- // with its last paragraph missing into History permanently — the row is
600
- // keyed on `(conversationId, step_index)`, so every later read finds it and
601
- // answers "already saved". That is Issue #2264, reported against claude and
778
+ // with its last paragraph missing into History — the row is keyed on
779
+ // `(conversationId, step_index)`, so every later read finds it and answers
780
+ // "already saved". That is Issue #2264, reported against claude and
602
781
  // structurally identical here: a turn cut off after its `tool_calls` renders
603
782
  // a *non-empty* body, so the emptiness guard below cannot see it.
783
+ //
784
+ // #2438 made such a row repairable rather than making it acceptable: a
785
+ // short row only grows while its turn is still among the newest
786
+ // {@link ANTIGRAVITY_TURN_RECHECK_LIMIT}, and nothing at all rewinds what a
787
+ // relay already delivered from it. Not writing it in the first place is
788
+ // still the fix; the repair is the second line.
789
+ if (report)
790
+ report.outcome = 'not_yet_closed';
604
791
  logger.info('antigravity-transcript-turn-open', {
605
792
  worktreeId: target.worktreeId,
606
793
  instanceId,
@@ -654,12 +841,20 @@ async function writeAntigravityTurn(target, turn, rendered, timestampMs, path) {
654
841
  Promise.resolve().then(() => __importStar(require('../../../../lib/ws-server'))),
655
842
  ]);
656
843
  const db = getDbInstance();
657
- if (findMessageByRequestId(db, target.worktreeId, requestId)) {
844
+ const existing = findMessageByRequestId(db, target.worktreeId, requestId);
845
+ if (existing) {
658
846
  logger.debug('antigravity-transcript-turn-already-saved', {
659
847
  worktreeId: target.worktreeId,
660
848
  instanceId,
661
849
  requestId,
662
850
  });
851
+ // The row may be one of the ones #2438 was reported for — saved at agy's
852
+ // interim report — and this is the one place that holds both the row and
853
+ // the turn. The comparison and the notification are not repeated here; see
854
+ // {@link growAntigravityTurnRow}. The verdict is unchanged: History holds
855
+ // this turn either way, and `report.outcome` is about this turn's
856
+ // completeness rather than about an edit.
857
+ await growAntigravityTurnRow(target, existing, rendered, path);
663
858
  return true;
664
859
  }
665
860
  const message = createMessage(db, {
@@ -104,6 +104,7 @@ const os_1 = require("os");
104
104
  const path_1 = require("path");
105
105
  const auto_yes_state_1 = require("../../../../lib/auto-yes-state");
106
106
  const user_turn_recorder_1 = require("../../../../lib/history/user-turn-recorder");
107
+ const assistant_response_saver_1 = require("../../../../lib/assistant-response-saver");
107
108
  const logger_1 = require("../../../../lib/logger");
108
109
  const agent_transcript_1 = require("../../../../types/agent-transcript");
109
110
  const transcript_1 = require("./transcript");
@@ -266,10 +267,18 @@ function acceptClaudeTranscriptHint(homeDir, hint) {
266
267
  *
267
268
  * Never throws.
268
269
  *
270
+ * Since Issue #2436 the false can explain itself: pass a
271
+ * `StructuredHistoryCaptureReport` and `outcome` is set to `'not_yet_closed'`
272
+ * when the newest turn is one the agent has not finished writing — the case the
273
+ * `-turn-open` line below reports, and the one where the caller's scraped copy
274
+ * is worth holding rather than saving. Every other false leaves it unset, which
275
+ * the gate reads as `'unavailable'`.
276
+ *
269
277
  * @param target - The instance whose turn just ended
278
+ * @param report - Optional out-parameter; see `StructuredHistoryCaptureReport`
270
279
  * @returns Whether History now holds this instance's newest turn as Markdown
271
280
  */
272
- async function captureClaudeTranscriptTurn(target, capture) {
281
+ async function captureClaudeTranscriptTurn(target, capture, report) {
273
282
  const instanceId = target.instanceId ?? target.cliToolId;
274
283
  try {
275
284
  const homeDir = capture.homeDir ?? (0, os_1.homedir)();
@@ -340,6 +349,9 @@ async function captureClaudeTranscriptTurn(target, capture) {
340
349
  instanceId,
341
350
  turnsInWindow: built.turns.length,
342
351
  });
352
+ // Issue #2437: this turn is already History's Markdown, so the pane rows
353
+ // behind it must stop being "unsaved output" the pre-send flush can pick up.
354
+ await (0, assistant_response_saver_1.advanceCapturedLineForTranscriptTurn)(target);
343
355
  return true;
344
356
  }
345
357
  if (pending.turns.length > 1) {
@@ -374,7 +386,14 @@ async function captureClaudeTranscriptTurn(target, capture) {
374
386
  let captured = false;
375
387
  for (let index = 0; index < pending.turns.length; index += 1) {
376
388
  const turn = pending.turns[index];
377
- captured = await writeClaudeTurn(target, turn, (0, transcript_1.renderClaudeTurn)(turn), resolveAssistantTimestampMs(turn, userRows[index], lastRecordAt.get(turn.promptUuid) ?? 0, nextTurnOpensAt(pending.turns, userRows, index)), path);
389
+ captured = await writeClaudeTurn(target, turn, (0, transcript_1.renderClaudeTurn)(turn), resolveAssistantTimestampMs(turn, userRows[index], lastRecordAt.get(turn.promptUuid) ?? 0, nextTurnOpensAt(pending.turns, userRows, index)), path, report);
390
+ }
391
+ if (captured) {
392
+ // Issue #2437: History now holds this turn as the agent's own Markdown.
393
+ // Park the pre-send flush's cursor past the pane rows it covers, or a
394
+ // `/send` arriving before the next poll tick saves the whole finished turn
395
+ // a second time.
396
+ await (0, assistant_response_saver_1.advanceCapturedLineForTranscriptTurn)(target);
378
397
  }
379
398
  return captured;
380
399
  }
@@ -925,8 +944,13 @@ async function refreshClaudeTurnRows(target, candidates, path) {
925
944
  *
926
945
  * @returns Whether History holds this turn as the agent's own Markdown
927
946
  */
928
- async function writeClaudeTurn(target, turn, rendered, timestampMs, path) {
947
+ async function writeClaudeTurn(target, turn, rendered, timestampMs, path, report) {
929
948
  const instanceId = target.instanceId ?? target.cliToolId;
949
+ // Issue #2436: the caller's report is about the turn THIS call is deciding.
950
+ // The loop above walks oldest-first, so a verdict left by an earlier turn has
951
+ // to be cleared before this one's is written.
952
+ if (report)
953
+ report.outcome = undefined;
930
954
  if (!(0, transcript_1.isClaudeTurnWritable)(turn)) {
931
955
  // The agent has not said `end_turn` for this prompt and no later prompt has
932
956
  // taken over, so what is in the file is a turn in progress. Writing it would
@@ -941,6 +965,8 @@ async function writeClaudeTurn(target, turn, rendered, timestampMs, path) {
941
965
  // Handing it back to the scraper costs the Markdown rendering for this turn
942
966
  // and nothing else: the Stop receiver asks again after a short delay, and
943
967
  // the poller asks again when the pane returns to the composer.
968
+ if (report)
969
+ report.outcome = 'not_yet_closed';
944
970
  logger.info('claude-transcript-turn-open', {
945
971
  worktreeId: target.worktreeId,
946
972
  instanceId,
@@ -101,6 +101,7 @@ const path_1 = require("path");
101
101
  const auto_yes_state_1 = require("../../../../lib/auto-yes-state");
102
102
  const transcript_tail_1 = require("../../../../lib/history/transcript-tail");
103
103
  const user_turn_recorder_1 = require("../../../../lib/history/user-turn-recorder");
104
+ const assistant_response_saver_1 = require("../../../../lib/assistant-response-saver");
104
105
  const logger_1 = require("../../../../lib/logger");
105
106
  const agent_transcript_1 = require("../../../../types/agent-transcript");
106
107
  const transcript_1 = require("./transcript");
@@ -332,11 +333,19 @@ async function scanForRollout(dir, sessionId, depth) {
332
333
  *
333
334
  * Never throws.
334
335
  *
336
+ * Since Issue #2436 the false can explain itself: pass a
337
+ * `StructuredHistoryCaptureReport` and `outcome` is set to `'not_yet_closed'`
338
+ * when the newest turn is one the agent has not finished writing — the case the
339
+ * `-turn-open` line below reports, and the one where the caller's scraped copy
340
+ * is worth holding rather than saving. Every other false leaves it unset, which
341
+ * the gate reads as `'unavailable'`.
342
+ *
335
343
  * @param target - The instance whose turn just ended
336
344
  * @param capture - See {@link CodexTranscriptCapture}
345
+ * @param report - Optional out-parameter; see `StructuredHistoryCaptureReport`
337
346
  * @returns Whether History now holds this turn as the agent's own Markdown
338
347
  */
339
- async function captureCodexTranscriptTurn(target, capture = {}) {
348
+ async function captureCodexTranscriptTurn(target, capture = {}, report) {
340
349
  const instanceId = target.instanceId ?? target.cliToolId;
341
350
  try {
342
351
  const codexHome = capture.codexHome ?? resolveCodexHome();
@@ -395,6 +404,9 @@ async function captureCodexTranscriptTurn(target, capture = {}) {
395
404
  instanceId,
396
405
  turnsInWindow: built.turns.length,
397
406
  });
407
+ // Issue #2437: this turn is already History's Markdown, so the pane rows
408
+ // behind it must stop being "unsaved output" the pre-send flush can pick up.
409
+ await (0, assistant_response_saver_1.advanceCapturedLineForTranscriptTurn)(target);
398
410
  return true;
399
411
  }
400
412
  if (pending.turns.length > 1) {
@@ -428,7 +440,14 @@ async function captureCodexTranscriptTurn(target, capture = {}) {
428
440
  let captured = false;
429
441
  for (let index = 0; index < pending.turns.length; index += 1) {
430
442
  const turn = pending.turns[index];
431
- captured = await writeCodexTurn(target, turn, (0, transcript_1.renderCodexTurn)(turn), resolveAssistantTimestampMs(turn, userRows[index], lastRecordAt.get(turn.turnId) ?? 0, nextTurnOpensAt(pending.turns, userRows, index)), windowFacts);
443
+ captured = await writeCodexTurn(target, turn, (0, transcript_1.renderCodexTurn)(turn), resolveAssistantTimestampMs(turn, userRows[index], lastRecordAt.get(turn.turnId) ?? 0, nextTurnOpensAt(pending.turns, userRows, index)), windowFacts, report);
444
+ }
445
+ if (captured) {
446
+ // Issue #2437: History now holds this turn as the agent's own Markdown.
447
+ // Park the pre-send flush's cursor past the pane rows it covers, or a
448
+ // `/send` arriving before the next poll tick saves the whole finished turn
449
+ // a second time.
450
+ await (0, assistant_response_saver_1.advanceCapturedLineForTranscriptTurn)(target);
432
451
  }
433
452
  return captured;
434
453
  }
@@ -670,14 +689,21 @@ function nextTurnOpensAt(turns, userRows, index) {
670
689
  *
671
690
  * @returns Whether History holds this turn as the agent's own Markdown
672
691
  */
673
- async function writeCodexTurn(target, turn, rendered, timestampMs, windowFacts) {
692
+ async function writeCodexTurn(target, turn, rendered, timestampMs, windowFacts, report) {
674
693
  const instanceId = target.instanceId ?? target.cliToolId;
694
+ // Issue #2436: the caller's report is about the turn THIS call is deciding.
695
+ // The loop above walks oldest-first, so a verdict left by an earlier turn has
696
+ // to be cleared before this one's is written.
697
+ if (report)
698
+ report.outcome = undefined;
675
699
  if (!turn.closed) {
676
700
  // codex has not written the `task_complete` for this `turn_id` yet, so what
677
701
  // is in the file is a turn in progress. Writing it would put a truncated
678
702
  // reply in History permanently — and unlike an empty one, a truncated one
679
703
  // looks finished. Handing it back to the scraper costs the Markdown
680
704
  // rendering for this turn and nothing else.
705
+ if (report)
706
+ report.outcome = 'not_yet_closed';
681
707
  logger.info('codex-transcript-turn-open', {
682
708
  worktreeId: target.worktreeId,
683
709
  instanceId,