commandmate 0.30.0 → 0.30.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 (254) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +158 -158
  3. package/.next/app-path-routes-manifest.json +34 -34
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/prerender-manifest.json +3 -3
  6. package/.next/required-server-files.json +1 -1
  7. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  8. package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
  9. package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
  10. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/app/update-check/route.js +1 -1
  12. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/assistant/conversation/route.js.nft.json +1 -1
  14. package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/assistant/current-output/route.js.nft.json +1 -1
  16. package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/assistant/messages/route.js +1 -1
  18. package/.next/server/app/api/assistant/messages/route.js.nft.json +1 -1
  19. package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/assistant/session/route.js +1 -1
  21. package/.next/server/app/api/assistant/session/route.js.nft.json +1 -1
  22. package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/assistant/start/route.js +2 -2
  24. package/.next/server/app/api/assistant/start/route.js.nft.json +1 -1
  25. package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/assistant/terminal/route.js +2 -2
  27. package/.next/server/app/api/assistant/terminal/route.js.nft.json +1 -1
  28. package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
  30. package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
  31. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/capabilities/route.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_client-reference-manifest.js +1 -1
  55. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  57. package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
  58. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  60. package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
  61. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  62. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
  63. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  64. package/.next/server/app/api/repositories/clone/route.js +1 -1
  65. package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
  66. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  67. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  68. package/.next/server/app/api/repositories/restore/route.js +1 -1
  69. package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
  70. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  71. package/.next/server/app/api/repositories/route.js +1 -1
  72. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  73. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  74. package/.next/server/app/api/repositories/scan/route.js +1 -1
  75. package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
  76. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/repositories/sync/route.js +1 -1
  78. package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
  79. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  80. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  81. package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
  82. package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
  83. package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
  84. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  85. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  86. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  87. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  88. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  90. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  91. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  93. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  94. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
  96. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  97. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  98. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  99. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  100. package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
  101. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
  103. package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
  104. package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
  105. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  106. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  107. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  108. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  109. package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
  110. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  111. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  112. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  113. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  114. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  115. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  116. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  117. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  118. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  120. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  121. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  122. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  124. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  127. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  129. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  130. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  132. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  133. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  135. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  136. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
  137. package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
  138. package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
  139. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
  141. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  142. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  146. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  148. package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
  149. package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
  151. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  152. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
  153. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  154. package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
  155. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
  157. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  158. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  159. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  161. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  162. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  163. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  164. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
  165. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  166. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  167. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
  168. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  170. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  171. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  173. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  174. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  175. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  176. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  177. package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
  178. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  179. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  180. package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
  181. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  182. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  183. package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
  184. package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
  185. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  186. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  187. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  188. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  189. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  190. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  191. package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
  192. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  193. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
  194. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  195. package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
  196. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  197. package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
  198. package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
  199. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  200. package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  201. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  202. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  203. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  204. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  205. package/.next/server/app/page_client-reference-manifest.js +1 -1
  206. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  207. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  208. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  209. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  210. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  211. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  212. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  213. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  214. package/.next/server/app/worktrees/[id]/page.js +12 -12
  215. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  216. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  217. package/.next/server/app-paths-manifest.json +34 -34
  218. package/.next/server/chunks/1058.js +1 -1
  219. package/.next/server/chunks/1886.js +2 -2
  220. package/.next/server/chunks/2119.js +1 -1
  221. package/.next/server/chunks/2445.js +1 -1
  222. package/.next/server/chunks/3099.js +5 -0
  223. package/.next/server/chunks/5017.js +1 -1
  224. package/.next/server/chunks/5043.js +1 -0
  225. package/.next/server/chunks/552.js +25 -0
  226. package/.next/server/chunks/6130.js +1 -1
  227. package/.next/server/chunks/6894.js +1 -1
  228. package/.next/server/chunks/9696.js +2 -2
  229. package/.next/server/middleware-manifest.json +5 -5
  230. package/.next/server/pages/500.html +1 -1
  231. package/.next/server/pages-manifest.json +1 -1
  232. package/.next/server/server-reference-manifest.json +1 -1
  233. package/.next/static/chunks/{6381-28d0e95620aa018e.js → 6381-147dde2a967e9458.js} +1 -1
  234. package/.next/static/chunks/app/worktrees/[id]/page-2f73d69187936627.js +1 -0
  235. package/.next/static/css/23f9c40ecc458c77.css +1 -0
  236. package/.next/trace +13 -13
  237. package/dist/server/src/lib/history/user-turn-recorder.js +9 -4
  238. package/dist/server/src/lib/hooks/agent-event-service.js +40 -6
  239. package/dist/server/src/lib/hooks/sources/antigravity/history.js +125 -18
  240. package/dist/server/src/lib/hooks/sources/antigravity/transcript.js +39 -0
  241. package/dist/server/src/lib/hooks/sources/claude/history.js +312 -21
  242. package/dist/server/src/lib/hooks/sources/claude/transcript.js +175 -13
  243. package/dist/server/src/lib/hooks/sources/codex/history.js +100 -13
  244. package/dist/server/src/lib/hooks/stop-history-capture.js +194 -0
  245. package/dist/server/src/lib/polling/response-checker.js +43 -3
  246. package/dist/server/src/lib/polling/structured-history-gate.js +131 -6
  247. package/dist/server/src/lib/session/current-output-builder.js +118 -16
  248. package/package.json +1 -1
  249. package/.next/server/chunks/2827.js +0 -29
  250. package/.next/server/chunks/6781.js +0 -1
  251. package/.next/static/chunks/app/worktrees/[id]/page-d48b95ed554bcd13.js +0 -1
  252. package/.next/static/css/61e10d4b1b11b193.css +0 -1
  253. /package/.next/static/{7K0XXFu_ty4wRSkl4X21E → QXxQbXWoo7ldUyOcv7PCZ}/_buildManifest.js +0 -0
  254. /package/.next/static/{7K0XXFu_ty4wRSkl4X21E → QXxQbXWoo7ldUyOcv7PCZ}/_ssgManifest.js +0 -0
@@ -148,8 +148,9 @@ function describe(target) {
148
148
  * re-read of the log and a `/clear`.
149
149
  * @param content - The prompt, as the agent recorded it
150
150
  * @param timestampMs - When the agent says it was prompted, epoch ms
151
+ * @param options - See {@link RecordUserTurnOptions}; the defaults are #2196's
151
152
  */
152
- async function recordUserTurn(target, key, content, timestampMs) {
153
+ async function recordUserTurn(target, key, content, timestampMs, options = {}) {
153
154
  const instanceId = target.instanceId ?? target.cliToolId;
154
155
  const normalized = normalizeUserTurnContent(content);
155
156
  if (key.length === 0 || normalized.length === 0) {
@@ -171,7 +172,7 @@ async function recordUserTurn(target, key, content, timestampMs) {
171
172
  };
172
173
  }
173
174
  const at = timestampMs > 0 ? timestampMs : Date.now();
174
- const adopted = adoptExistingRow(chatDb, db, target, instanceId, key, normalized, at);
175
+ const adopted = adoptExistingRow(chatDb, db, target, instanceId, key, normalized, at, options);
175
176
  if (adopted)
176
177
  return adopted;
177
178
  const message = chatDb.createMessage(db, {
@@ -217,13 +218,17 @@ async function recordUserTurn(target, key, content, timestampMs) {
217
218
  *
218
219
  * @returns The claimed row, or null when nothing here belongs to this prompt
219
220
  */
220
- function adoptExistingRow(chatDb, db, target, instanceId, key, normalized, at) {
221
+ function adoptExistingRow(chatDb, db, target, instanceId, key, normalized, at, options) {
222
+ // `Math.min` and not a replacement: {@link RecordUserTurnOptions} may widen
223
+ // the search backwards and may never narrow it, so a caller that supplies a
224
+ // bound *inside* the standard window changes nothing.
225
+ const fromMs = Math.min(at - exports.USER_TURN_ADOPTION_WINDOW_MS, options.adoptionFromMs ?? Number.POSITIVE_INFINITY);
221
226
  const candidates = chatDb
222
227
  .findUnkeyedUserMessages(db, {
223
228
  worktreeId: target.worktreeId,
224
229
  cliToolId: target.cliToolId,
225
230
  instanceId,
226
- fromMs: at - exports.USER_TURN_ADOPTION_WINDOW_MS,
231
+ fromMs,
227
232
  toMs: at + exports.USER_TURN_ADOPTION_WINDOW_MS,
228
233
  })
229
234
  .filter((row) => normalizeUserTurnContent(row.content) === normalized)
@@ -30,6 +30,7 @@ const path_validator_1 = require("../../lib/security/path-validator");
30
30
  const task_transition_service_1 = require("../../lib/tasks/task-transition-service");
31
31
  const gate_runner_1 = require("../../lib/verification/gate-runner");
32
32
  const agent_event_state_1 = require("../../lib/session/agent-event-state");
33
+ const stop_history_capture_1 = require("../../lib/hooks/stop-history-capture");
33
34
  const logger_1 = require("../../lib/logger");
34
35
  const logger = (0, logger_1.createLogger)('lib/hooks/agent-event-service');
35
36
  /**
@@ -144,14 +145,32 @@ function safeRealpath(target) {
144
145
  * Apply a `stop` event to whatever the worktree is currently doing.
145
146
  *
146
147
  * The no-op is the load-bearing case. Sessions with no contract, and therefore
147
- * no task, are the overwhelming majority; for them this records the timestamp
148
- * and returns. Nothing about the existing completion path changes.
148
+ * no task, are the overwhelming majority; for them this records the timestamp,
149
+ * asks the transcript reader for the turn, and returns.
150
+ *
151
+ * ## Why the history read is here (Issue #2246)
152
+ *
153
+ * Because it must happen for *every* stop event and not only for the ones that
154
+ * govern a task — the majority case above is exactly the session whose replies
155
+ * this is trying not to lose — and because both callers of this function are
156
+ * stop receivers (`/api/hooks/agent-event` and the compatibility
157
+ * `/api/hooks/claude-done`). Putting it in one of the routes would have left the
158
+ * other one on the old behaviour.
159
+ *
160
+ * It runs **before** the task lookup so that the two early returns below cannot
161
+ * skip it, and after `recordAgentStopEvent` because the reader resolves its
162
+ * transcript through the session pointer that call refreshes.
163
+ *
164
+ * It is awaited rather than detached. The turn has already ended, so the cost is
165
+ * paid by nobody who is waiting for an answer, and a detached promise here would
166
+ * be one whose failures nothing observes.
149
167
  *
150
168
  * Never throws. A hook is fire-and-forget from a CLI's stop handler, and a
151
169
  * failure here must not become the agent's problem.
152
170
  */
153
171
  async function applyAgentStopEvent(db, worktree, cliToolId, instanceId) {
154
172
  (0, agent_event_state_1.recordAgentStopEvent)(worktree.id, cliToolId, instanceId);
173
+ const structuredHistoryCaptured = await (0, stop_history_capture_1.captureTranscriptTurnOnStop)(worktree, cliToolId, instanceId);
155
174
  let task;
156
175
  try {
157
176
  task = (0, tasks_db_1.getActiveTaskForInstance)(db, worktree.id, cliToolId, instanceId);
@@ -161,10 +180,20 @@ async function applyAgentStopEvent(db, worktree, cliToolId, instanceId) {
161
180
  worktreeId: worktree.id,
162
181
  error: error instanceof Error ? error.message : String(error),
163
182
  });
164
- return { taskId: null, taskEventApplied: false, verificationRunId: null };
183
+ return {
184
+ taskId: null,
185
+ taskEventApplied: false,
186
+ verificationRunId: null,
187
+ structuredHistoryCaptured,
188
+ };
165
189
  }
166
190
  if (!task) {
167
- return { taskId: null, taskEventApplied: false, verificationRunId: null };
191
+ return {
192
+ taskId: null,
193
+ taskEventApplied: false,
194
+ verificationRunId: null,
195
+ structuredHistoryCaptured,
196
+ };
168
197
  }
169
198
  let taskEventApplied = false;
170
199
  try {
@@ -178,7 +207,12 @@ async function applyAgentStopEvent(db, worktree, cliToolId, instanceId) {
178
207
  });
179
208
  }
180
209
  if (!task.contract.success.autoVerifyOnStop) {
181
- return { taskId: task.id, taskEventApplied, verificationRunId: null };
210
+ return {
211
+ taskId: task.id,
212
+ taskEventApplied,
213
+ verificationRunId: null,
214
+ structuredHistoryCaptured,
215
+ };
182
216
  }
183
217
  let verificationRunId = null;
184
218
  try {
@@ -201,5 +235,5 @@ async function applyAgentStopEvent(db, worktree, cliToolId, instanceId) {
201
235
  });
202
236
  }
203
237
  }
204
- return { taskId: task.id, taskEventApplied, verificationRunId };
238
+ return { taskId: task.id, taskEventApplied, verificationRunId, structuredHistoryCaptured };
205
239
  }
@@ -99,6 +99,7 @@ exports.antigravityBrainRoot = antigravityBrainRoot;
99
99
  exports.antigravityTranscriptPath = antigravityTranscriptPath;
100
100
  exports.acceptAntigravityTranscriptPath = acceptAntigravityTranscriptPath;
101
101
  exports.captureAntigravityTranscriptTurn = captureAntigravityTranscriptTurn;
102
+ exports.resolveAntigravityTranscriptPath = resolveAntigravityTranscriptPath;
102
103
  const promises_1 = require("fs/promises");
103
104
  const os_1 = require("os");
104
105
  const path_1 = require("path");
@@ -256,15 +257,21 @@ function acceptAntigravityTranscriptPath(agyHome, candidate) {
256
257
  return resolved;
257
258
  }
258
259
  /**
259
- * Read the newest turn out of this instance's transcript and write it.
260
+ * Read this instance's unwritten turns out of its transcript and write them.
260
261
  *
261
- * **Only the newest turn**, and that is the same deliberate difference from
262
- * opencode's backfill that #2121 documents: every earlier turn already has a
263
- * `chat_messages` row the *scraper* wrote, and writing a Markdown row for it too
264
- * would put the same reply in History twice. One row per turn from the scraper,
265
- * one row per turn from here, so the swap is one-for-one.
262
+ * **Every turn in the window that is not already a row**, oldest first, which is
263
+ * the shape Issue #2246 gave all three pull readers and the reasoning for it is
264
+ * written out once on `../claude/history`'s
265
+ * {@link captureClaudeTranscriptTurn}. The short version: this reader only runs
266
+ * when the poller judges a turn finished, so a missed judgement used to lose a
267
+ * turn permanently — by the next judgement "the newest turn" had moved on.
266
268
  *
267
- * The return value is the poller's instruction. **True** means History holds
269
+ * #2121's one-row-per-turn argument is preserved by the **anchor**: the newest
270
+ * turn in the window this reader has already written is where the backfill
271
+ * starts, and a window with no anchor falls back to the newest turn alone.
272
+ *
273
+ * The return value is the poller's instruction, and it is about the **newest**
274
+ * turn whatever else was written on the way. **True** means History holds
268
275
  * this turn as the agent's own Markdown and the scrape must be dropped. **False**
269
276
  * means it does not, for any reason at all — no conversation pointer, no file, an
270
277
  * unreadable file, a window with no prompt in it — and the scrape must be saved.
@@ -313,8 +320,7 @@ async function captureAntigravityTranscriptTurn(target, capture = {}) {
313
320
  return false;
314
321
  const parsed = (0, transcript_1.parseAntigravityTranscript)(text);
315
322
  const built = (0, transcript_1.buildAntigravityTurns)(parsed.records, conversationId);
316
- const turn = built.turns.at(-1);
317
- if (!turn) {
323
+ if (built.turns.length === 0) {
318
324
  // No `USER_INPUT` in the window. Two ordinary causes, both fail-open: the
319
325
  // 4 MiB window cut mid-conversation, and `transcript_full.jsonl` can hold
320
326
  // less than the whole history — one of the 41 files in the corpus held a
@@ -341,8 +347,33 @@ async function captureAntigravityTranscriptTurn(target, capture = {}) {
341
347
  preludeRecords: built.preludeRecords,
342
348
  });
343
349
  }
344
- const userRow = await recordAntigravityUserTurn(target, turn);
345
- return await writeAntigravityTurn(target, turn, (0, transcript_1.renderAntigravityTurn)(turn), resolveAssistantTimestampMs(turn, userRow), path);
350
+ const pending = await selectUnwrittenAntigravityTurns(target, built.turns);
351
+ if (pending.turns.length === 0) {
352
+ logger.debug('antigravity-transcript-turns-already-saved', {
353
+ worktreeId: target.worktreeId,
354
+ instanceId,
355
+ turnsInWindow: built.turns.length,
356
+ });
357
+ return true;
358
+ }
359
+ if (pending.turns.length > 1) {
360
+ logger.info('antigravity-transcript-backfilling-turns', {
361
+ worktreeId: target.worktreeId,
362
+ instanceId,
363
+ path,
364
+ pendingTurns: pending.turns.length,
365
+ turnsInWindow: built.turns.length,
366
+ anchored: pending.anchored,
367
+ });
368
+ }
369
+ let captured = false;
370
+ for (let index = 0; index < pending.turns.length; index += 1) {
371
+ const turn = pending.turns[index];
372
+ const previousStartedAt = index === 0 ? pending.previousStartedAt : pending.turns[index - 1].startedAt;
373
+ const userRow = await recordAntigravityUserTurn(target, turn, previousStartedAt);
374
+ captured = await writeAntigravityTurn(target, turn, (0, transcript_1.renderAntigravityTurn)(turn), resolveAssistantTimestampMs(turn, userRow), path);
375
+ }
376
+ return captured;
346
377
  }
347
378
  catch (error) {
348
379
  logger.error('antigravity-transcript-capture-failed', {
@@ -353,6 +384,59 @@ async function captureAntigravityTranscriptTurn(target, capture = {}) {
353
384
  return false;
354
385
  }
355
386
  }
387
+ /**
388
+ * The transcript file this instance would be read from, or null (Issue #2246).
389
+ *
390
+ * The same two steps {@link captureAntigravityTranscriptTurn} opens with, asked
391
+ * without reading or writing anything; see `../claude/history`'s
392
+ * {@link resolveClaudeTranscriptPath} for what the Stop receiver does with it.
393
+ *
394
+ * Never throws.
395
+ */
396
+ async function resolveAntigravityTranscriptPath(target, capture = {}) {
397
+ try {
398
+ const conversationId = await resolveAntigravityConversationId(target);
399
+ if (!conversationId)
400
+ return null;
401
+ return await locateAntigravityTranscript(capture.antigravityHome ?? resolveAntigravityHome(), conversationId);
402
+ }
403
+ catch {
404
+ return null;
405
+ }
406
+ }
407
+ /**
408
+ * The turns {@link captureAntigravityTranscriptTurn} still has to write (#2246).
409
+ *
410
+ * The same rule as `../claude/history`'s, on agy's own key: search backwards
411
+ * from the newest turn for one that is already a row, and take everything after
412
+ * it. Record order and never a timestamp — agy stamps `created_at` at
413
+ * second resolution, so a turn and its own reply routinely share an instant.
414
+ *
415
+ * @param turns - Every turn in the window, oldest first
416
+ */
417
+ async function selectUnwrittenAntigravityTurns(target, turns) {
418
+ const [{ getDbInstance }, { findMessageByRequestId }] = await Promise.all([
419
+ Promise.resolve().then(() => __importStar(require('../../../../lib/db/db-instance'))),
420
+ Promise.resolve().then(() => __importStar(require('../../../../lib/db'))),
421
+ ]);
422
+ const db = getDbInstance();
423
+ for (let index = turns.length - 1; index >= 0; index -= 1) {
424
+ const turn = turns[index];
425
+ const requestId = (0, agent_transcript_1.antigravityTurnRequestId)(turn.conversationId, turn.stepIndex);
426
+ if (!findMessageByRequestId(db, target.worktreeId, requestId))
427
+ continue;
428
+ return {
429
+ turns: turns.slice(index + 1),
430
+ previousStartedAt: turn.startedAt,
431
+ anchored: true,
432
+ };
433
+ }
434
+ return {
435
+ turns: turns.slice(-1),
436
+ previousStartedAt: turns.length > 1 ? turns[turns.length - 2].startedAt : 0,
437
+ anchored: false,
438
+ };
439
+ }
356
440
  /**
357
441
  * The transcript file for this conversation, or null.
358
442
  *
@@ -392,12 +476,16 @@ async function isReadableFile(path) {
392
476
  *
393
477
  * Never throws; `recordUserTurn` reports its failures in the return value.
394
478
  */
395
- async function recordAntigravityUserTurn(target, turn) {
479
+ async function recordAntigravityUserTurn(target, turn, previousStartedAt = 0) {
396
480
  const skipped = { outcome: 'skipped', messageId: null, timestampMs: null };
397
481
  const prompt = turn.prompt;
398
482
  if (!prompt)
399
483
  return skipped;
400
- const recorded = await (0, user_turn_recorder_1.recordUserTurn)(target, (0, agent_transcript_1.antigravityPromptRequestId)(turn.conversationId, prompt.stepIndex), prompt.text, prompt.timestampMs);
484
+ // Issue #2246: a turn read late is a turn whose `/send` row may be older than
485
+ // #2196's symmetric window reaches. The previous turn's start is the tightest
486
+ // honest bound, and it only ever widens the search.
487
+ const adoption = previousStartedAt > 0 ? { adoptionFromMs: previousStartedAt } : {};
488
+ const recorded = await (0, user_turn_recorder_1.recordUserTurn)(target, (0, agent_transcript_1.antigravityPromptRequestId)(turn.conversationId, prompt.stepIndex), prompt.text, prompt.timestampMs, adoption);
401
489
  if (recorded.outcome === 'failed') {
402
490
  logger.warn('antigravity-transcript-user-turn-failed', {
403
491
  worktreeId: target.worktreeId,
@@ -444,12 +532,31 @@ function resolveAssistantTimestampMs(turn, userRow) {
444
532
  */
445
533
  async function writeAntigravityTurn(target, turn, rendered, timestampMs, path) {
446
534
  const instanceId = target.instanceId ?? target.cliToolId;
535
+ if (!(0, transcript_1.isAntigravityTurnWritable)(turn)) {
536
+ // agy has not finished this answer and no later prompt has taken over, so
537
+ // what is in the file is a turn in progress. Writing it would put a reply
538
+ // with its last paragraph missing into History permanently — the row is
539
+ // keyed on `(conversationId, step_index)`, so every later read finds it and
540
+ // answers "already saved". That is Issue #2264, reported against claude and
541
+ // structurally identical here: a turn cut off after its `tool_calls` renders
542
+ // a *non-empty* body, so the emptiness guard below cannot see it.
543
+ logger.info('antigravity-transcript-turn-open', {
544
+ worktreeId: target.worktreeId,
545
+ instanceId,
546
+ conversationId: rendered.conversationId,
547
+ stepIndex: rendered.stepIndex,
548
+ records: turn.records.length,
549
+ textBlocks: rendered.textBlocks,
550
+ toolBlocks: rendered.toolBlocks,
551
+ });
552
+ return false;
553
+ }
447
554
  if (rendered.body.length === 0) {
448
- // A turn that said nothing yet. Unlike codex there is no `task_complete` to
449
- // tell an unfinished turn from a silent one, so the body is the only
450
- // evidence there is — and answering false is right for both readings: the
451
- // scraper keeps the reply if there was one, and an empty row that would show
452
- // as a blank answer forever is never written.
555
+ // A turn that said nothing. agy has no `task_complete`, so a closed turn
556
+ // that rendered to nothing and an interrupted one look alike here and
557
+ // answering false is right for both readings: the scraper keeps the reply if
558
+ // there was one, and an empty row that would show as a blank answer forever
559
+ // is never written.
453
560
  logger.info('antigravity-transcript-turn-empty', {
454
561
  worktreeId: target.worktreeId,
455
562
  instanceId,
@@ -72,6 +72,8 @@ exports.readAntigravityTranscriptRecord = readAntigravityTranscriptRecord;
72
72
  exports.parseAntigravityTranscript = parseAntigravityTranscript;
73
73
  exports.extractAntigravityUserRequest = extractAntigravityUserRequest;
74
74
  exports.buildAntigravityTurns = buildAntigravityTurns;
75
+ exports.isAntigravityTurnClosingRecord = isAntigravityTurnClosingRecord;
76
+ exports.isAntigravityTurnWritable = isAntigravityTurnWritable;
75
77
  exports.isAntigravityPromptRecord = isAntigravityPromptRecord;
76
78
  exports.renderAntigravityTurn = renderAntigravityTurn;
77
79
  const event_mapper_1 = require("../event-mapper");
@@ -298,6 +300,8 @@ function buildAntigravityTurns(records, conversationId) {
298
300
  ? { stepIndex: record.stepIndex, text, timestampMs: record.timestampMs ?? startedAt }
299
301
  : null,
300
302
  records: [],
303
+ closed: false,
304
+ superseded: false,
301
305
  overflowed: false,
302
306
  });
303
307
  continue;
@@ -307,14 +311,49 @@ function buildAntigravityTurns(records, conversationId) {
307
311
  preludeRecords += 1;
308
312
  continue;
309
313
  }
314
+ // Assigned rather than or-ed, so what survives is the last `MODEL` record's
315
+ // answer. `SYSTEM` records are ignored here for the same reason they render
316
+ // to nothing: agy injected them, they are not agy speaking.
317
+ if (record.source === exports.ANTIGRAVITY_MODEL_SOURCE) {
318
+ turn.closed = isAntigravityTurnClosingRecord(record);
319
+ }
310
320
  if (turn.records.length >= exports.MAX_ANTIGRAVITY_TURN_RECORDS) {
311
321
  turn.overflowed = true;
312
322
  continue;
313
323
  }
314
324
  turn.records.push(record);
315
325
  }
326
+ // Every turn but the last has a later prompt behind it, and a prompt is proof
327
+ // agy moved on. See {@link AntigravityTurnAccumulator.superseded}.
328
+ for (let index = 0; index < turns.length - 1; index += 1) {
329
+ turns[index].superseded = true;
330
+ }
316
331
  return { turns, preludeRecords };
317
332
  }
333
+ /**
334
+ * Whether this `MODEL` record is agy finishing its answer (Issue #2264).
335
+ *
336
+ * See {@link AntigravityTurnAccumulator.closed} for the argument; the emptiness
337
+ * test is the one {@link renderAntigravityTurn} applies to `content`, so a
338
+ * record that renders to nothing cannot be what makes a turn look finished.
339
+ */
340
+ function isAntigravityTurnClosingRecord(record) {
341
+ if (record.source !== exports.ANTIGRAVITY_MODEL_SOURCE)
342
+ return false;
343
+ if (record.type !== exports.ANTIGRAVITY_PLANNER_TYPE)
344
+ return false;
345
+ if (record.toolCalls.length > 0)
346
+ return false;
347
+ return (record.content ?? '').trim().length > 0;
348
+ }
349
+ /**
350
+ * Whether a writer may record this turn (Issue #2264).
351
+ *
352
+ * Either proof that nothing more is coming — agy answered, or it moved on.
353
+ */
354
+ function isAntigravityTurnWritable(turn) {
355
+ return turn.closed || turn.superseded;
356
+ }
318
357
  /** Whether this record is the one the operator's own text arrived on. */
319
358
  function isAntigravityPromptRecord(record) {
320
359
  return record.source === exports.ANTIGRAVITY_USER_SOURCE && record.type === exports.ANTIGRAVITY_USER_TYPE;