commandmate 0.33.1 → 0.33.3

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 (337) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +307 -307
  3. package/.next/app-path-routes-manifest.json +28 -28
  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 +15 -15
  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.js +1 -1
  14. package/.next/server/app/api/app/update-check/route.js.nft.json +1 -1
  15. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/assistant/conversation/route.js +1 -1
  17. package/.next/server/app/api/assistant/conversation/route.js.nft.json +1 -1
  18. package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/assistant/current-output/route.js +1 -1
  20. package/.next/server/app/api/assistant/current-output/route.js.nft.json +1 -1
  21. package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
  22. package/.next/server/app/api/assistant/messages/route.js +1 -1
  23. package/.next/server/app/api/assistant/messages/route.js.nft.json +1 -1
  24. package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
  25. package/.next/server/app/api/assistant/session/route.js +1 -1
  26. package/.next/server/app/api/assistant/session/route.js.nft.json +1 -1
  27. package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
  28. package/.next/server/app/api/assistant/start/route.js +32 -1
  29. package/.next/server/app/api/assistant/start/route.js.nft.json +1 -1
  30. package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
  31. package/.next/server/app/api/assistant/terminal/route.js +33 -2
  32. package/.next/server/app/api/assistant/terminal/route.js.nft.json +1 -1
  33. package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/assistant/tools/route.js +1 -1
  35. package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
  36. package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
  37. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  38. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  40. package/.next/server/app/api/capabilities/route.js +1 -1
  41. package/.next/server/app/api/capabilities/route.js.nft.json +1 -1
  42. package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
  43. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  44. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  45. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  46. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  47. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  48. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  49. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  50. package/.next/server/app/api/hooks/agent-event/route.js +1 -1
  51. package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
  52. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  53. package/.next/server/app/api/hooks/claude-done/route.js +2 -2
  54. package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
  55. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/hooks/permission-request/route.js +1 -1
  57. package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
  58. package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  60. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  61. package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  63. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  64. package/.next/server/app/api/relays/[relayId]/cancel/route.js +1 -1
  65. package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
  66. package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
  67. package/.next/server/app/api/relays/route.js +1 -1
  68. package/.next/server/app/api/relays/route.js.nft.json +1 -1
  69. package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
  70. package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
  71. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  72. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  73. package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
  74. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  75. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
  76. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/repositories/clone/route.js +1 -1
  78. package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
  79. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  80. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  81. package/.next/server/app/api/repositories/restore/route.js +1 -1
  82. package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
  83. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  84. package/.next/server/app/api/repositories/route.js +1 -1
  85. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  86. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  87. package/.next/server/app/api/repositories/scan/route.js +1 -1
  88. package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
  89. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  90. package/.next/server/app/api/repositories/sync/route.js +1 -1
  91. package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
  92. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  93. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  94. package/.next/server/app/api/settings/default-agents/route.js +1 -1
  95. package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
  96. package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
  97. package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
  98. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  99. package/.next/server/app/api/skills/[id]/route.js +1 -1
  100. package/.next/server/app/api/skills/[id]/route.js.nft.json +1 -1
  101. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/skills/installations/route.js +1 -1
  103. package/.next/server/app/api/skills/installations/route.js.nft.json +1 -1
  104. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  105. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  106. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  107. package/.next/server/app/api/skills/route.js +1 -1
  108. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  109. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  110. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  111. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  112. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  113. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  114. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  115. package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
  116. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  117. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  118. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  120. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  121. package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
  122. package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
  123. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  124. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
  126. package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
  127. package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  129. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  130. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  132. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  133. package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  135. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  136. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  137. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  138. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  139. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  141. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  142. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  146. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  148. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  149. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  151. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  152. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  153. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  154. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  155. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  157. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  158. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  159. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
  161. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
  162. package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
  163. package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
  164. package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
  165. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  166. package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
  167. package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
  168. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  170. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  171. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  173. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  174. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  175. package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
  176. package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
  177. package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
  178. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  179. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
  180. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  181. package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
  182. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
  183. package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
  184. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  185. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  186. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  187. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  188. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  189. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  190. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  191. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  192. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
  193. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  194. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  195. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +1 -1
  196. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
  197. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  198. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  199. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js +1 -1
  200. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js.nft.json +1 -1
  201. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  202. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  203. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  204. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  205. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route.js +1 -1
  206. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route.js.nft.json +1 -1
  207. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  208. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  209. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  210. package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
  211. package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
  212. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  213. package/.next/server/app/api/worktrees/[id]/tasks/route.js +2 -2
  214. package/.next/server/app/api/worktrees/[id]/tasks/route.js.nft.json +1 -1
  215. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  216. package/.next/server/app/api/worktrees/[id]/terminal/route.js +103 -1
  217. package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
  218. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  219. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  220. package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
  221. package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
  222. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  223. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  224. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  225. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  226. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  227. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  228. package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
  229. package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -1
  230. package/.next/server/app/api/worktrees/[id]/verify/route.js.nft.json +1 -1
  231. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  232. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js +1 -1
  233. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js.nft.json +1 -1
  234. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
  235. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  236. package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
  237. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  238. package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
  239. package/.next/server/app/api/worktrees/route.js +1 -1
  240. package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
  241. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  242. package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  243. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  244. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  245. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  246. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  247. package/.next/server/app/page_client-reference-manifest.js +1 -1
  248. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  249. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  250. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  251. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  252. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  253. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  254. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  255. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  256. package/.next/server/app/worktrees/[id]/page.js +10 -10
  257. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  258. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  259. package/.next/server/app-paths-manifest.json +28 -28
  260. package/.next/server/chunks/1068.js +1 -0
  261. package/.next/server/chunks/1210.js +1 -1
  262. package/.next/server/chunks/1331.js +2 -2
  263. package/.next/server/chunks/1366.js +5 -3
  264. package/.next/server/chunks/1501.js +6 -2
  265. package/.next/server/chunks/1886.js +2 -2
  266. package/.next/server/chunks/2119.js +1 -1
  267. package/.next/server/chunks/2445.js +1 -1
  268. package/.next/server/chunks/2839.js +1 -0
  269. package/.next/server/chunks/3123.js +1 -1
  270. package/.next/server/chunks/3241.js +1 -1
  271. package/.next/server/chunks/3323.js +1 -0
  272. package/.next/server/chunks/3707.js +1 -1
  273. package/.next/server/chunks/3708.js +1 -1
  274. package/.next/server/chunks/4443.js +1 -1
  275. package/.next/server/chunks/5220.js +1 -1
  276. package/.next/server/chunks/595.js +2 -2
  277. package/.next/server/chunks/6130.js +1 -0
  278. package/.next/server/chunks/650.js +1 -0
  279. package/.next/server/chunks/6661.js +1 -1
  280. package/.next/server/chunks/6781.js +1 -0
  281. package/.next/server/chunks/6808.js +1 -0
  282. package/.next/server/chunks/7875.js +3 -3
  283. package/.next/server/chunks/7905.js +1 -1
  284. package/.next/server/chunks/8918.js +107 -5
  285. package/.next/server/chunks/9553.js +1 -0
  286. package/.next/server/chunks/9627.js +1 -1
  287. package/.next/server/middleware-build-manifest.js +1 -1
  288. package/.next/server/middleware-manifest.json +5 -5
  289. package/.next/server/pages/500.html +1 -1
  290. package/.next/server/server-reference-manifest.json +1 -1
  291. package/.next/server/src/middleware.js.map +1 -1
  292. package/.next/static/chunks/1255-7e5873f06b25e129.js +1 -0
  293. package/.next/static/chunks/{4718-2bc5cdf06573bf54.js → 4718-814f4ecfd7fcc513.js} +1 -1
  294. package/.next/static/chunks/6022-7a7d1760fc9814c7.js +1 -0
  295. package/.next/static/chunks/app/worktrees/[id]/page-3af707e74a75172b.js +1 -0
  296. package/.next/static/chunks/{main-6092074a0dc78280.js → main-ac91ed6e71380841.js} +1 -1
  297. package/.next/trace +13 -14
  298. package/dist/server/locales/en/worktree.json +9 -2
  299. package/dist/server/locales/ja/worktree.json +9 -2
  300. package/dist/server/src/lib/assistant-response-saver.js +168 -12
  301. package/dist/server/src/lib/cli-tools/vibe-local.js +10 -0
  302. package/dist/server/src/lib/hooks/hook-settings-generator.js +61 -1
  303. package/dist/server/src/lib/hooks/sources/antigravity/history.js +497 -27
  304. package/dist/server/src/lib/hooks/sources/antigravity/transcript.js +103 -0
  305. package/dist/server/src/lib/hooks/sources/claude/history.js +29 -3
  306. package/dist/server/src/lib/hooks/sources/codex/history.js +29 -3
  307. package/dist/server/src/lib/hooks/sources/command-code/history.js +29 -3
  308. package/dist/server/src/lib/hooks/stop-history-capture.js +30 -4
  309. package/dist/server/src/lib/polling/response-checker.js +258 -9
  310. package/dist/server/src/lib/polling/response-poller-core.js +20 -0
  311. package/dist/server/src/lib/polling/structured-history-gate.js +94 -10
  312. package/dist/server/src/lib/response-cleaner.js +84 -0
  313. package/dist/server/src/lib/session/agent-session-lifecycle.js +31 -1
  314. package/dist/server/src/lib/session/session-generation-archive.js +194 -0
  315. package/dist/server/src/lib/tasks/contract-message.js +83 -9
  316. package/dist/server/src/lib/tasks/contract-parser.js +2 -0
  317. package/package.json +2 -2
  318. package/.next/server/chunks/153.js +0 -1
  319. package/.next/server/chunks/21.js +0 -1
  320. package/.next/server/chunks/3086.js +0 -1
  321. package/.next/server/chunks/3270.js +0 -1
  322. package/.next/server/chunks/3925.js +0 -1
  323. package/.next/server/chunks/4299.js +0 -1
  324. package/.next/server/chunks/5043.js +0 -1
  325. package/.next/server/chunks/6306.js +0 -1
  326. package/.next/server/chunks/6363.js +0 -1
  327. package/.next/server/chunks/6491.js +0 -103
  328. package/.next/server/chunks/6838.js +0 -1
  329. package/.next/server/chunks/7366.js +0 -5
  330. package/.next/server/chunks/7890.js +0 -1
  331. package/.next/server/chunks/8063.js +0 -32
  332. package/.next/server/chunks/8687.js +0 -1
  333. package/.next/static/chunks/1255-8cb587d9170b45ed.js +0 -1
  334. package/.next/static/chunks/6022-2fa0b5a82d4ce7b6.js +0 -1
  335. package/.next/static/chunks/app/worktrees/[id]/page-13ca0ba551fe5cfb.js +0 -1
  336. /package/.next/static/{9lgw9hA727UMyFhXryGWG → 9x6U1h52hH_r6pOsGwI_p}/_buildManifest.js +0 -0
  337. /package/.next/static/{9lgw9hA727UMyFhXryGWG → 9x6U1h52hH_r6pOsGwI_p}/_ssgManifest.js +0 -0
@@ -47,6 +47,25 @@
47
47
  * module reads only the former — see {@link ANTIGRAVITY_CLI_HOME_SEGMENTS} — and
48
48
  * the conversation ids are uuids in any case.
49
49
  *
50
+ * ## Saving and finishing are two questions (Issue #2443)
51
+ *
52
+ * agy writes no record that closes a turn, so "may this be saved" has to be
53
+ * answered from the shape of its last words — and an interim report has the
54
+ * same shape as a conclusion. #2438 made the row that follows repairable. #2443
55
+ * separates the *second* consequence of the same evidence: whether the body may
56
+ * be handed onward as the answer. Two states, and the reader reports which one
57
+ * the newest turn is in:
58
+ *
59
+ * - **provisional** — History holds the turn, the scraper stands down, the row
60
+ * keeps being re-read and grown, and `broadcastMessage('message_updated', …)`
61
+ * refreshes what a browser is showing. Nothing leaves the server.
62
+ * - **settled** — agy's own `Stop` arrived at or after the turn's newest
63
+ * record, so the body is the one it finished on. The gate announces the
64
+ * completion edge exactly once for that body.
65
+ *
66
+ * `docs/design/antigravity-turn-completion-2443.md` is the argument, including
67
+ * what happens when the evidence never arrives.
68
+ *
50
69
  * ## Nothing here throws
51
70
  *
52
71
  * Same contract as the other three readers, for the same reason: this runs
@@ -91,8 +110,9 @@ var __importStar = (this && this.__importStar) || (function () {
91
110
  };
92
111
  })();
93
112
  Object.defineProperty(exports, "__esModule", { value: true });
94
- exports.ANTIGRAVITY_CLI_HOME_SEGMENTS = exports.ANTIGRAVITY_TRANSCRIPT_TAIL_BYTES = void 0;
113
+ exports.ANTIGRAVITY_TURN_RECHECK_LIMIT = exports.ANTIGRAVITY_UNSETTLED_TURN_LIMIT = exports.ANTIGRAVITY_CLI_HOME_SEGMENTS = exports.ANTIGRAVITY_TRANSCRIPT_TAIL_BYTES = void 0;
95
114
  exports.resetAntigravityTranscriptConversations = resetAntigravityTranscriptConversations;
115
+ exports.resetAntigravityUnsettledTurns = resetAntigravityUnsettledTurns;
96
116
  exports.resolveAntigravityConversationId = resolveAntigravityConversationId;
97
117
  exports.resolveAntigravityHome = resolveAntigravityHome;
98
118
  exports.antigravityBrainRoot = antigravityBrainRoot;
@@ -106,6 +126,7 @@ const path_1 = require("path");
106
126
  const auto_yes_state_1 = require("../../../../lib/auto-yes-state");
107
127
  const transcript_tail_1 = require("../../../../lib/history/transcript-tail");
108
128
  const user_turn_recorder_1 = require("../../../../lib/history/user-turn-recorder");
129
+ const assistant_response_saver_1 = require("../../../../lib/assistant-response-saver");
109
130
  const logger_1 = require("../../../../lib/logger");
110
131
  const agent_transcript_1 = require("../../../../types/agent-transcript");
111
132
  const transcript_1 = require("./transcript");
@@ -158,12 +179,153 @@ const ANTIGRAVITY_CONVERSATION_ID_PATTERN = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9
158
179
  * did not would otherwise blank the pointer mid-session.
159
180
  */
160
181
  const conversationPointers = (globalThis.__antigravityTranscriptConversations ??= new Map());
182
+ /**
183
+ * How many written-but-unconfirmed turns one instance may be following (#2443).
184
+ *
185
+ * The bound on the answer to "a saved row must be able to catch up with its
186
+ * conclusion even once three later turns have been written". Sixteen and not
187
+ * "however many are in the window", because the list is walked on **every**
188
+ * poll: each entry costs one indexed `findMessageByRequestId` and, only when
189
+ * that finds a row, one render of a turn that is already parsed. Sixteen turns
190
+ * is more than a working session accumulates without a single `Stop` arriving,
191
+ * and it is a fixed ceiling on a per-instance map rather than a function of a
192
+ * file somebody else appends to.
193
+ *
194
+ * Eviction is oldest-first and is a real loss of coverage, which is why it is
195
+ * logged (`antigravity-transcript-unsettled-evicted`) rather than silent. What
196
+ * is left is #2438's behaviour for that row: the newest
197
+ * {@link ANTIGRAVITY_TURN_RECHECK_LIMIT} turns are re-read regardless of this
198
+ * list, so an evicted entry loses the *extra* reach and not the ordinary one.
199
+ */
200
+ exports.ANTIGRAVITY_UNSETTLED_TURN_LIMIT = 16;
201
+ /**
202
+ * Which written turns are still waiting for agy to vouch for them (#2443).
203
+ *
204
+ * On `globalThis` for the reason {@link conversationPointers} is: under `next
205
+ * dev` the poller's bundle and the hook receiver's bundle each get their own
206
+ * copy of a module-scoped map, and a list only one of the two writers can see is
207
+ * not a list.
208
+ *
209
+ * In memory and not in SQLite, deliberately. The entry describes a turn this
210
+ * *process* wrote provisionally and has not seen confirmed; a restart loses it,
211
+ * and what remains is exactly {@link ANTIGRAVITY_TURN_RECHECK_LIMIT} — the same
212
+ * coverage #2438 shipped. Persisting it would make a row's repair depend on a
213
+ * table that outlives the transcript window it can only be repaired from.
214
+ */
215
+ const unsettledTurns = (globalThis.__antigravityUnsettledTurns ??= new Map());
161
216
  function keyOf(target) {
162
217
  return (0, auto_yes_state_1.buildCompositeKey)(target.worktreeId, target.cliToolId, target.instanceId);
163
218
  }
164
- /** Forget every instance's pointer. Test seam. */
219
+ /**
220
+ * Forget every instance's pointer and every unconfirmed row it was following.
221
+ *
222
+ * Test seam. Both maps, because they are two halves of one per-instance state:
223
+ * a suite that reset the pointer and kept the follow list would carry one test's
224
+ * `step_index` values into the next one's conversation.
225
+ */
165
226
  function resetAntigravityTranscriptConversations() {
166
227
  conversationPointers.clear();
228
+ unsettledTurns.clear();
229
+ }
230
+ /** Forget the unconfirmed rows alone. Test seam. */
231
+ function resetAntigravityUnsettledTurns() {
232
+ unsettledTurns.clear();
233
+ }
234
+ /**
235
+ * The steps this instance is following in `conversationId`, oldest first.
236
+ *
237
+ * A conversation that is not the one the list was built for answers empty and
238
+ * drops the list: `/clear` mints a new conversation id, and following the old
239
+ * one's `step_index` values into it would re-check turns that are not the same
240
+ * turns. This is the leak test #2443 asks for, expressed as the read path
241
+ * rather than as a promise.
242
+ */
243
+ function unsettledStepsFor(key, conversationId) {
244
+ const entry = unsettledTurns.get(key);
245
+ if (!entry)
246
+ return [];
247
+ if (entry.conversationId !== conversationId) {
248
+ unsettledTurns.delete(key);
249
+ return [];
250
+ }
251
+ return entry.steps;
252
+ }
253
+ /**
254
+ * Start, or stop, following one written turn (Issue #2443).
255
+ *
256
+ * `confirmed` is {@link AntigravityTurnCompletion.confirmed}: a turn agy has
257
+ * vouched for cannot grow again without a later record, and a later record takes
258
+ * the confirmation away and re-adds it here on the very next pass. So the list
259
+ * holds exactly the rows whose body is still provisional.
260
+ *
261
+ * @returns The step that was evicted to make room, or null
262
+ */
263
+ function noteAntigravityTurnCompletion(key, conversationId, stepIndex, confirmed) {
264
+ const entry = unsettledTurns.get(key);
265
+ if (entry && entry.conversationId !== conversationId)
266
+ unsettledTurns.delete(key);
267
+ if (confirmed) {
268
+ const current = unsettledTurns.get(key);
269
+ if (!current)
270
+ return null;
271
+ current.steps = current.steps.filter((step) => step !== stepIndex);
272
+ if (current.steps.length === 0)
273
+ unsettledTurns.delete(key);
274
+ return null;
275
+ }
276
+ const current = unsettledTurns.get(key) ?? { conversationId, steps: [] };
277
+ unsettledTurns.set(key, current);
278
+ if (current.steps.includes(stepIndex))
279
+ return null;
280
+ current.steps.push(stepIndex);
281
+ if (current.steps.length <= exports.ANTIGRAVITY_UNSETTLED_TURN_LIMIT)
282
+ return null;
283
+ return current.steps.shift() ?? null;
284
+ }
285
+ /** Stop following steps the current read window no longer contains. */
286
+ function forgetAntigravityTurnsOutsideWindow(key, conversationId, present) {
287
+ const entry = unsettledTurns.get(key);
288
+ if (!entry || entry.conversationId !== conversationId)
289
+ return [];
290
+ const dropped = entry.steps.filter((step) => !present.has(step));
291
+ if (dropped.length === 0)
292
+ return [];
293
+ entry.steps = entry.steps.filter((step) => present.has(step));
294
+ if (entry.steps.length === 0)
295
+ unsettledTurns.delete(key);
296
+ return dropped;
297
+ }
298
+ /**
299
+ * When this instance last reported that its loop stopped, or null (#2443).
300
+ *
301
+ * The one piece of evidence {@link resolveAntigravityTurnCompletion} is asked to
302
+ * judge against, read the way {@link resolveAntigravityConversationId} reads its
303
+ * own: dynamically, so `agent-event-state`'s module graph is not a static
304
+ * dependency of the poller, and defensively, so a state module that cannot be
305
+ * reached — or a build in which this reader is newer than its neighbour — is one
306
+ * that knows of no stop rather than one that throws inside the save path.
307
+ *
308
+ * `recordAgentStopEvent` runs **before** the Stop receiver asks for a capture
309
+ * (`lib/hooks/agent-event-service`), so the value is already there on the read
310
+ * that stop itself triggers. That ordering is what lets one seam serve both
311
+ * triggers instead of the receiver having to hand a flag down through the gate.
312
+ */
313
+ async function resolveAntigravityStopAt(target) {
314
+ try {
315
+ const state = await Promise.resolve().then(() => __importStar(require('../../../../lib/session/agent-event-state')));
316
+ const read = state.getLastStopEventAt;
317
+ if (typeof read !== 'function')
318
+ return null;
319
+ return read(target.worktreeId, target.cliToolId, target.instanceId) ?? null;
320
+ }
321
+ catch (error) {
322
+ logger.debug('antigravity-transcript-stop-lookup-failed', {
323
+ worktreeId: target.worktreeId,
324
+ instanceId: target.instanceId ?? target.cliToolId,
325
+ error: error instanceof Error ? error.message : String(error),
326
+ });
327
+ return null;
328
+ }
167
329
  }
168
330
  /**
169
331
  * The conversation id this instance's transcript is under, or null.
@@ -288,11 +450,43 @@ function acceptAntigravityTranscriptPath(agyHome, candidate) {
288
450
  *
289
451
  * Never throws.
290
452
  *
453
+ * **A row this reader wrote is not final (Issue #2438).** Before anything is
454
+ * written, the newest already-written turns — at most
455
+ * {@link ANTIGRAVITY_TURN_RECHECK_LIMIT} of them — are re-rendered and compared
456
+ * against the rows they produced, and a row whose turn now renders *strictly
457
+ * longer* is replaced in place. agy has no record that closes a turn, so an
458
+ * interim report reads as a finished answer (`isAntigravityTurnClosingRecord`)
459
+ * and used to freeze a half-written reply into History forever. That is a
460
+ * repair and not a second verdict: growing an older row changes neither the
461
+ * return value nor `report`, both of which are about the **newest** turn.
462
+ *
463
+ * Since Issue #2436 the false can explain itself: pass a
464
+ * `StructuredHistoryCaptureReport` and `outcome` is set to `'not_yet_closed'`
465
+ * when the newest turn is one the agent has not finished writing — the case the
466
+ * `-turn-open` line below reports, and the one where the caller's scraped copy
467
+ * is worth holding rather than saving. Every other false leaves it unset, which
468
+ * the gate reads as `'unavailable'`.
469
+ *
470
+ * **A saved turn is not a finished turn (Issue #2443).** #2438 made the frozen
471
+ * row repairable and left the other half of the damage in place: the same
472
+ * `true` that tells the poller to drop its scrape also told the relay that the
473
+ * turn was over, so an interim report was **delivered** to whoever had asked
474
+ * agy a question, and no later `message_updated` could take that back. So the
475
+ * `true` now carries a second word. `report.completion` is `'settled'` only
476
+ * when {@link resolveAntigravityTurnCompletion} can show, from agy's own `Stop`
477
+ * event, that the body in hand is the one it finished on; otherwise it is
478
+ * `'provisional'` — History still holds the row, the repair still runs on every
479
+ * later read, and nothing is announced to a relay. Rows written provisionally
480
+ * are followed by `step_index` (see {@link ANTIGRAVITY_UNSETTLED_TURN_LIMIT}),
481
+ * so the conclusion is still picked up once the turn has fallen out of
482
+ * {@link ANTIGRAVITY_TURN_RECHECK_LIMIT}'s window.
483
+ *
291
484
  * @param target - The instance whose turn just ended
292
485
  * @param capture - See {@link AntigravityTranscriptCapture}
486
+ * @param report - Optional out-parameter; see `StructuredHistoryCaptureReport`
293
487
  * @returns Whether History now holds this turn as the agent's own Markdown
294
488
  */
295
- async function captureAntigravityTranscriptTurn(target, capture = {}) {
489
+ async function captureAntigravityTranscriptTurn(target, capture = {}, report) {
296
490
  const instanceId = target.instanceId ?? target.cliToolId;
297
491
  try {
298
492
  const agyHome = capture.antigravityHome ?? resolveAntigravityHome();
@@ -347,13 +541,55 @@ async function captureAntigravityTranscriptTurn(target, capture = {}) {
347
541
  preludeRecords: built.preludeRecords,
348
542
  });
349
543
  }
544
+ // Issue #2443: one read of the evidence, applied to every turn in the
545
+ // window. `stopAt` is agy's own account of when its loop ended; see
546
+ // {@link resolveAntigravityTurnCompletion} for why an ordering against the
547
+ // turn's newest record — rather than a word, a silence or a `status` — is
548
+ // what the promotion to "final" rests on.
549
+ const instanceKey = keyOf(target);
550
+ const stopAt = await resolveAntigravityStopAt(target);
551
+ const completions = new Map();
552
+ for (const turn of built.turns) {
553
+ completions.set(turn.stepIndex, (0, transcript_1.resolveAntigravityTurnCompletion)(turn, stopAt));
554
+ }
555
+ const newestTurn = built.turns[built.turns.length - 1];
556
+ const newestCompletion = completions.get(newestTurn.stepIndex) ??
557
+ (0, transcript_1.resolveAntigravityTurnCompletion)(newestTurn, stopAt);
558
+ // A step this read can no longer see is a step no later read can repair:
559
+ // the 4 MiB tail slid past it, its `USER_INPUT` is outside the window, or
560
+ // the file was replaced. Logged rather than dropped in silence, because it
561
+ // is the boundary of what #2443 promises.
562
+ const forgotten = forgetAntigravityTurnsOutsideWindow(instanceKey, conversationId, new Set(built.turns.map((turn) => turn.stepIndex)));
563
+ if (forgotten.length > 0) {
564
+ logger.info('antigravity-transcript-unsettled-out-of-window', {
565
+ worktreeId: target.worktreeId,
566
+ instanceId,
567
+ conversationId,
568
+ steps: forgotten,
569
+ turnsInWindow: built.turns.length,
570
+ });
571
+ }
350
572
  const pending = await selectUnwrittenAntigravityTurns(target, built.turns);
573
+ const writtenTurns = built.turns.slice(0, built.turns.length - pending.turns.length);
574
+ // Before anything is written: the rows that are already there (#2438). This
575
+ // is deliberately ahead of the early return below, because "the newest turn
576
+ // is already a row" is exactly the state the frozen row the Issue measured
577
+ // was stuck in — agy said "waiting for the worker", the writer saved that,
578
+ // and every later read answered true and did nothing while the conclusion
579
+ // sat in the transcript beside it. Written turns are re-checked whether or
580
+ // not anything is pending, so an old turn can be repaired in the same pass
581
+ // that writes a new one.
582
+ await refreshAntigravityTurnRows(target, selectAntigravityRecheckCandidates(writtenTurns, unsettledStepsFor(instanceKey, conversationId)), path, { instanceKey, conversationId, completions });
351
583
  if (pending.turns.length === 0) {
352
584
  logger.debug('antigravity-transcript-turns-already-saved', {
353
585
  worktreeId: target.worktreeId,
354
586
  instanceId,
355
587
  turnsInWindow: built.turns.length,
356
588
  });
589
+ // Issue #2437: this turn is already History's Markdown, so the pane rows
590
+ // behind it must stop being "unsaved output" the pre-send flush can pick up.
591
+ await (0, assistant_response_saver_1.advanceCapturedLineForTranscriptTurn)(target);
592
+ reportAntigravityCompletion(report, newestTurn, newestCompletion);
357
593
  return true;
358
594
  }
359
595
  if (pending.turns.length > 1) {
@@ -380,7 +616,22 @@ async function captureAntigravityTranscriptTurn(target, capture = {}) {
380
616
  let captured = false;
381
617
  for (let index = 0; index < pending.turns.length; index += 1) {
382
618
  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);
619
+ captured = await writeAntigravityTurn(target, turn, (0, transcript_1.renderAntigravityTurn)(turn), resolveAssistantTimestampMs(turn, userRows[index], (0, transcript_1.antigravityTurnLastRecordAt)(turn), nextTurnOpensAt(pending.turns, userRows, index)), path, report);
620
+ // Issue #2443: a row now exists for this turn, and whether it is the body
621
+ // agy finished on is a separate question from whether it could be saved.
622
+ // An unconfirmed one joins the follow list so that its conclusion is still
623
+ // picked up once three later turns have pushed it out of #2438's window.
624
+ if (captured) {
625
+ noteUnsettledAntigravityTurn(target, instanceKey, turn, completions.get(turn.stepIndex) ?? (0, transcript_1.resolveAntigravityTurnCompletion)(turn, stopAt));
626
+ }
627
+ }
628
+ if (captured) {
629
+ // Issue #2437: History now holds this turn as the agent's own Markdown.
630
+ // Park the pre-send flush's cursor past the pane rows it covers, or a
631
+ // `/send` arriving before the next poll tick saves the whole finished turn
632
+ // a second time.
633
+ await (0, assistant_response_saver_1.advanceCapturedLineForTranscriptTurn)(target);
634
+ reportAntigravityCompletion(report, newestTurn, newestCompletion);
384
635
  }
385
636
  return captured;
386
637
  }
@@ -545,23 +796,6 @@ function resolveAssistantTimestampMs(turn, userRow, lastRecordAt = 0, nextTurnOp
545
796
  const latest = nextTurnOpensAt === null ? Number.POSITIVE_INFINITY : nextTurnOpensAt - 1;
546
797
  return Math.max(earliest, Math.min(lastRecordAt, latest));
547
798
  }
548
- /**
549
- * When the last record agy wrote for this turn was made (Issue #2273).
550
- *
551
- * The maximum rather than `records.at(-1)`: `created_at` is agy's own field and
552
- * a record that carries none reads as null, so the last record in file order is
553
- * not always the last one with a clock on it.
554
- *
555
- * @returns Epoch ms, or 0 when the turn has no timestamped record
556
- */
557
- function lastAntigravityRecordAt(turn) {
558
- let at = 0;
559
- for (const record of turn.records) {
560
- if (record.timestampMs !== null && record.timestampMs > at)
561
- at = record.timestampMs;
562
- }
563
- return at;
564
- }
565
799
  /**
566
800
  * The instant the next pending turn's prompt row carries, or null (Issue #2273).
567
801
  *
@@ -577,6 +811,218 @@ function nextTurnOpensAt(turns, userRows, index) {
577
811
  return null;
578
812
  return userRows[index + 1]?.timestampMs ?? next.startedAt;
579
813
  }
814
+ /**
815
+ * How many already-written turns are re-rendered and compared (Issue #2438).
816
+ *
817
+ * The repair half of #2438 has to look at rows this reader has **already**
818
+ * written, which is the one thing the anchor rule of
819
+ * {@link selectUnwrittenAntigravityTurns} deliberately does not do — so it is
820
+ * bounded here rather than by the read window. Three, the number claude and
821
+ * command-code settled on in #2264 and for the same arithmetic: the poller runs
822
+ * every couple of seconds, re-rendering the whole window on every tick would
823
+ * make a repair the most expensive thing the poll does, and a turn that is going
824
+ * to grow grows within seconds of being written.
825
+ *
826
+ * The cost of the bound is paid by rows a session has already moved three turns
827
+ * past: those keep whatever they were written with. The measured case — one
828
+ * conversation whose only turn was `#0` — is inside it by a wide margin.
829
+ */
830
+ exports.ANTIGRAVITY_TURN_RECHECK_LIMIT = 3;
831
+ /**
832
+ * Replace a saved row whose body has since grown (Issue #2438).
833
+ *
834
+ * The defect this exists for is not that the wrong body was written; it is that
835
+ * the row was written **early**. `isAntigravityTurnClosingRecord` reads prose
836
+ * with no `tool_calls` as agy finishing, and an interim report — "waiting for
837
+ * the worker" — has exactly that shape. The row is keyed
838
+ * `antigravity-turn:<conversationId>#<stepIndex>`, so once it exists every later
839
+ * read finds it, answers "already saved", and the gate suppresses the scrape
840
+ * that could have carried the conclusion instead. Nothing else in the system
841
+ * ever revisits that row.
842
+ *
843
+ * **Strictly longer, never merely different.** Equality is the ordinary case and
844
+ * must cost nothing, and a body that got *shorter* between two reads is not a
845
+ * turn that grew — it is a window that slid, or a truncation marker, and
846
+ * overwriting a full reply with a shorter one is the one outcome worse than the
847
+ * bug. Longer implies different, so one comparison covers both.
848
+ *
849
+ * Only `content` moves. The row's `id`, `request_id`, `timestamp`, worktree,
850
+ * tool and instance are what History sorts and pairs on, and a repair that
851
+ * disturbed any of them would move an old answer to the bottom of the
852
+ * conversation.
853
+ *
854
+ * `message_updated`, never `message`: the row already existed and was already
855
+ * delivered when it was created, so a client that appended instead of replacing
856
+ * would show the reply twice.
857
+ *
858
+ * @param existing - The row `findMessageByRequestId` answered with
859
+ * @returns Whether the row was replaced
860
+ */
861
+ async function growAntigravityTurnRow(target, existing, rendered, path) {
862
+ const instanceId = target.instanceId ?? target.cliToolId;
863
+ // The stored body is the only evidence of what History holds, so a row that
864
+ // carries none is not evidence that anything grew. Same answer as "not
865
+ // longer": leave it alone. This runs inside the poller's save path, where the
866
+ // module contract is that nothing throws.
867
+ const previous = existing.content;
868
+ if (typeof previous !== 'string')
869
+ return false;
870
+ const previousLength = previous.length;
871
+ if (rendered.body.length <= previousLength)
872
+ return false;
873
+ const [{ getDbInstance }, { updateMessageContent }, { broadcastMessage }] = await Promise.all([
874
+ Promise.resolve().then(() => __importStar(require('../../../../lib/db/db-instance'))),
875
+ Promise.resolve().then(() => __importStar(require('../../../../lib/db'))),
876
+ Promise.resolve().then(() => __importStar(require('../../../../lib/ws-server'))),
877
+ ]);
878
+ updateMessageContent(getDbInstance(), existing.id, rendered.body);
879
+ broadcastMessage('message_updated', {
880
+ worktreeId: target.worktreeId,
881
+ message: { ...existing, content: rendered.body },
882
+ });
883
+ logger.info('antigravity-transcript-turn-updated', {
884
+ worktreeId: target.worktreeId,
885
+ instanceId,
886
+ conversationId: rendered.conversationId,
887
+ stepIndex: rendered.stepIndex,
888
+ requestId: existing.requestId,
889
+ path,
890
+ previousLength,
891
+ bodyLength: rendered.body.length,
892
+ textBlocks: rendered.textBlocks,
893
+ toolBlocks: rendered.toolBlocks,
894
+ });
895
+ return true;
896
+ }
897
+ /**
898
+ * Re-read the newest already-written turns and grow the short ones (#2438).
899
+ *
900
+ * Runs before the pending turns are written and independently of whether there
901
+ * are any — the case it exists for is precisely the one
902
+ * {@link captureAntigravityTranscriptTurn} used to return `true` from without
903
+ * doing anything: the newest turn already has a row, and that row stopped at
904
+ * agy's interim report.
905
+ *
906
+ * Turns that are open again are skipped rather than compared. A turn whose last
907
+ * record is a `tool_calls` is one agy is still working through, its body is by
908
+ * definition not the final one, and a repair that raced the agent would rewrite
909
+ * the row on every poll of a long turn. **This is not a second chance to write
910
+ * a turn**: a candidate with no row is left alone, because the anchor rule
911
+ * already decided it is not this pass's to create.
912
+ *
913
+ * The database is asked before the turn is rendered, so a candidate with no row
914
+ * — every candidate, in a session this reader has never written to — costs one
915
+ * indexed lookup and no Markdown.
916
+ *
917
+ * Serialisation is the gate's, per instance: this adds no loop and no timer of
918
+ * its own, it is one more thing the poll's existing pass does.
919
+ *
920
+ * @param candidates - Already-written turns, oldest first, at most
921
+ * {@link ANTIGRAVITY_TURN_RECHECK_LIMIT}
922
+ * @returns How many rows were replaced
923
+ */
924
+ async function refreshAntigravityTurnRows(target, candidates, path, follow) {
925
+ if (candidates.length === 0)
926
+ return 0;
927
+ const [{ getDbInstance }, { findMessageByRequestId }] = await Promise.all([
928
+ Promise.resolve().then(() => __importStar(require('../../../../lib/db/db-instance'))),
929
+ Promise.resolve().then(() => __importStar(require('../../../../lib/db'))),
930
+ ]);
931
+ const db = getDbInstance();
932
+ let updated = 0;
933
+ for (const turn of candidates) {
934
+ // Issue #2443: the row lookup moved ahead of the writable check, because
935
+ // the follow list is a statement about ROWS. A turn that is open again has a
936
+ // row whose body is provisional by definition and must stay followed, and a
937
+ // candidate whose row has gone — History cleared, the key rewritten — is one
938
+ // nothing can repair and is dropped here rather than re-queried forever.
939
+ const existing = findMessageByRequestId(db, target.worktreeId, (0, agent_transcript_1.antigravityTurnRequestId)(turn.conversationId, turn.stepIndex));
940
+ if (!existing) {
941
+ noteAntigravityTurnCompletion(follow.instanceKey, follow.conversationId, turn.stepIndex, true);
942
+ continue;
943
+ }
944
+ noteUnsettledAntigravityTurn(target, follow.instanceKey, turn, follow.completions.get(turn.stepIndex) ?? (0, transcript_1.resolveAntigravityTurnCompletion)(turn, null));
945
+ if (!(0, transcript_1.isAntigravityTurnWritable)(turn))
946
+ continue;
947
+ if (await growAntigravityTurnRow(target, existing, (0, transcript_1.renderAntigravityTurn)(turn), path)) {
948
+ updated += 1;
949
+ }
950
+ }
951
+ return updated;
952
+ }
953
+ /**
954
+ * The written turns to re-read on this pass (Issue #2443).
955
+ *
956
+ * Two sources, concatenated oldest-first and de-duplicated:
957
+ *
958
+ * - **the newest {@link ANTIGRAVITY_TURN_RECHECK_LIMIT}**, which is #2438's
959
+ * window exactly and is what covers the ordinary case — a row saved at an
960
+ * interim report and concluded seconds later, while the session has not moved
961
+ * on. It is kept as a floor rather than replaced, so a cold process (one that
962
+ * restarted, or one whose follow list was evicted) still has #2438's reach.
963
+ * - **the followed steps**, which are the rows this process wrote from a body
964
+ * agy had not vouched for. They are the ones the limit above loses: four
965
+ * prompts queued back to back push the first turn out of the window in
966
+ * seconds, and nothing else in the system ever revisits it.
967
+ *
968
+ * The result is bounded by `ANTIGRAVITY_TURN_RECHECK_LIMIT +
969
+ * {@link ANTIGRAVITY_UNSETTLED_TURN_LIMIT}` — a fixed 19 — whatever the window
970
+ * holds, so a long transcript cannot make a poll's cost grow with it.
971
+ *
972
+ * @param writtenTurns - Turns in the window that already have rows, oldest first
973
+ * @param followed - `step_index` values from the follow list
974
+ */
975
+ function selectAntigravityRecheckCandidates(writtenTurns, followed) {
976
+ const recent = writtenTurns.slice(-exports.ANTIGRAVITY_TURN_RECHECK_LIMIT);
977
+ if (followed.length === 0)
978
+ return recent;
979
+ const inRecent = new Set(recent.map((turn) => turn.stepIndex));
980
+ const followedSteps = new Set(followed);
981
+ const older = writtenTurns.filter((turn) => followedSteps.has(turn.stepIndex) && !inRecent.has(turn.stepIndex));
982
+ return older.length === 0 ? recent : [...older, ...recent];
983
+ }
984
+ /**
985
+ * Follow this row, or stop following it, and say so once (Issue #2443).
986
+ *
987
+ * The log line is the only place an operator can see why a repair did or did not
988
+ * keep happening, so it carries the reason word rather than the boolean:
989
+ * `no-stop-event` and `stop-before-last-record` are very different sessions.
990
+ */
991
+ function noteUnsettledAntigravityTurn(target, instanceKey, turn, completion) {
992
+ const evicted = noteAntigravityTurnCompletion(instanceKey, turn.conversationId, turn.stepIndex, completion.confirmed);
993
+ if (evicted === null)
994
+ return;
995
+ logger.info('antigravity-transcript-unsettled-evicted', {
996
+ worktreeId: target.worktreeId,
997
+ instanceId: target.instanceId ?? target.cliToolId,
998
+ conversationId: turn.conversationId,
999
+ step: evicted,
1000
+ limit: exports.ANTIGRAVITY_UNSETTLED_TURN_LIMIT,
1001
+ });
1002
+ }
1003
+ /**
1004
+ * Tell the caller whether the turn it was handed is final (Issue #2443).
1005
+ *
1006
+ * `completion` is what the gate reads to decide whether a relay may be told the
1007
+ * turn ended; `completionKey` is what stops it being told twice about one body.
1008
+ * The key names the turn **and** the instant of its newest record, so a turn
1009
+ * that grows after being confirmed is a new state and is announced again once
1010
+ * the new state is itself confirmed — which is exactly the `Stop`-then-`continue`
1011
+ * case `./source` warns about, handled without a second rule.
1012
+ *
1013
+ * Left entirely alone when the body is not confirmed, apart from the word
1014
+ * `provisional`: the gate defaults an absent `completion` to `settled`, so this
1015
+ * is the one place antigravity opts out of the pre-#2443 announcement.
1016
+ */
1017
+ function reportAntigravityCompletion(report, turn, completion) {
1018
+ if (!report)
1019
+ return;
1020
+ report.completion = completion.confirmed ? 'settled' : 'provisional';
1021
+ report.completionKey = completion.confirmed
1022
+ ? `${(0, agent_transcript_1.antigravityTurnRequestId)(turn.conversationId, turn.stepIndex)}@${completion.lastRecordAt}`
1023
+ : undefined;
1024
+ report.completionReason = completion.reason;
1025
+ }
580
1026
  /**
581
1027
  * Write one rendered turn, unless it is already there.
582
1028
  *
@@ -587,20 +1033,36 @@ function nextTurnOpensAt(turns, userRows, index) {
587
1033
  * Answering **true** for a turn that was already saved is deliberate. It means
588
1034
  * "History holds this turn as Markdown", which is what the poller needs to know
589
1035
  * — a second poll of the same finished turn must not save the pane's copy on top
590
- * of the row this path wrote.
1036
+ * of the row this path wrote. Since #2438 that row is no longer left as it was
1037
+ * found: it is the same comparison {@link growAntigravityTurnRow} makes for the
1038
+ * turns the recheck window covers, made here where both the row and the turn
1039
+ * are already in hand.
591
1040
  *
592
1041
  * @returns Whether History holds this turn as the agent's own Markdown
593
1042
  */
594
- async function writeAntigravityTurn(target, turn, rendered, timestampMs, path) {
1043
+ async function writeAntigravityTurn(target, turn, rendered, timestampMs, path, report) {
595
1044
  const instanceId = target.instanceId ?? target.cliToolId;
1045
+ // Issue #2436: the caller's report is about the turn THIS call is deciding.
1046
+ // The loop above walks oldest-first, so a verdict left by an earlier turn has
1047
+ // to be cleared before this one's is written.
1048
+ if (report)
1049
+ report.outcome = undefined;
596
1050
  if (!(0, transcript_1.isAntigravityTurnWritable)(turn)) {
597
1051
  // agy has not finished this answer and no later prompt has taken over, so
598
1052
  // 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
1053
+ // with its last paragraph missing into History — the row is keyed on
1054
+ // `(conversationId, step_index)`, so every later read finds it and answers
1055
+ // "already saved". That is Issue #2264, reported against claude and
602
1056
  // structurally identical here: a turn cut off after its `tool_calls` renders
603
1057
  // a *non-empty* body, so the emptiness guard below cannot see it.
1058
+ //
1059
+ // #2438 made such a row repairable rather than making it acceptable: a
1060
+ // short row only grows while its turn is still among the newest
1061
+ // {@link ANTIGRAVITY_TURN_RECHECK_LIMIT}, and nothing at all rewinds what a
1062
+ // relay already delivered from it. Not writing it in the first place is
1063
+ // still the fix; the repair is the second line.
1064
+ if (report)
1065
+ report.outcome = 'not_yet_closed';
604
1066
  logger.info('antigravity-transcript-turn-open', {
605
1067
  worktreeId: target.worktreeId,
606
1068
  instanceId,
@@ -654,12 +1116,20 @@ async function writeAntigravityTurn(target, turn, rendered, timestampMs, path) {
654
1116
  Promise.resolve().then(() => __importStar(require('../../../../lib/ws-server'))),
655
1117
  ]);
656
1118
  const db = getDbInstance();
657
- if (findMessageByRequestId(db, target.worktreeId, requestId)) {
1119
+ const existing = findMessageByRequestId(db, target.worktreeId, requestId);
1120
+ if (existing) {
658
1121
  logger.debug('antigravity-transcript-turn-already-saved', {
659
1122
  worktreeId: target.worktreeId,
660
1123
  instanceId,
661
1124
  requestId,
662
1125
  });
1126
+ // The row may be one of the ones #2438 was reported for — saved at agy's
1127
+ // interim report — and this is the one place that holds both the row and
1128
+ // the turn. The comparison and the notification are not repeated here; see
1129
+ // {@link growAntigravityTurnRow}. The verdict is unchanged: History holds
1130
+ // this turn either way, and `report.outcome` is about this turn's
1131
+ // completeness rather than about an edit.
1132
+ await growAntigravityTurnRow(target, existing, rendered, path);
663
1133
  return true;
664
1134
  }
665
1135
  const message = createMessage(db, {