commandmate 0.33.2 → 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 (304) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +122 -122
  3. package/.next/app-path-routes-manifest.json +24 -24
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/prerender-manifest.json +15 -15
  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.js.nft.json +1 -1
  13. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/assistant/conversation/route.js +1 -1
  15. package/.next/server/app/api/assistant/conversation/route.js.nft.json +1 -1
  16. package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/assistant/current-output/route.js +1 -1
  18. package/.next/server/app/api/assistant/current-output/route.js.nft.json +1 -1
  19. package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/assistant/messages/route.js +1 -1
  21. package/.next/server/app/api/assistant/messages/route.js.nft.json +1 -1
  22. package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/assistant/session/route.js +1 -1
  24. package/.next/server/app/api/assistant/session/route.js.nft.json +1 -1
  25. package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/assistant/start/route.js +1 -1
  27. package/.next/server/app/api/assistant/start/route.js.nft.json +1 -1
  28. package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/assistant/terminal/route.js +1 -1
  30. package/.next/server/app/api/assistant/terminal/route.js.nft.json +1 -1
  31. package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/assistant/tools/route.js +1 -1
  33. package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
  34. package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  37. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  38. package/.next/server/app/api/capabilities/route.js +1 -1
  39. package/.next/server/app/api/capabilities/route.js.nft.json +1 -1
  40. package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
  41. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  42. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  43. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  44. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  45. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  46. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  47. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  48. package/.next/server/app/api/hooks/agent-event/route.js +1 -1
  49. package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
  50. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  51. package/.next/server/app/api/hooks/claude-done/route.js +2 -2
  52. package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
  53. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  54. package/.next/server/app/api/hooks/permission-request/route.js +1 -1
  55. package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
  56. package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
  57. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  58. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/push/escalation/route.js +1 -1
  60. package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
  61. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/push/vapid/route.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 +1 -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 +24 -24
  260. package/.next/server/chunks/1501.js +6 -2
  261. package/.next/server/chunks/1886.js +2 -2
  262. package/.next/server/chunks/2119.js +1 -1
  263. package/.next/server/chunks/2445.js +1 -1
  264. package/.next/server/chunks/3123.js +1 -1
  265. package/.next/server/chunks/3241.js +1 -1
  266. package/.next/server/chunks/3323.js +1 -1
  267. package/.next/server/chunks/4443.js +1 -1
  268. package/.next/server/chunks/595.js +2 -2
  269. package/.next/server/chunks/6130.js +1 -0
  270. package/.next/server/chunks/650.js +1 -1
  271. package/.next/server/chunks/6661.js +1 -1
  272. package/.next/server/chunks/6781.js +1 -1
  273. package/.next/server/chunks/7875.js +1 -1
  274. package/.next/server/chunks/7905.js +1 -1
  275. package/.next/server/chunks/8918.js +3 -3
  276. package/.next/server/chunks/9553.js +1 -0
  277. package/.next/server/chunks/9627.js +1 -1
  278. package/.next/server/middleware-manifest.json +5 -5
  279. package/.next/server/pages/500.html +1 -1
  280. package/.next/server/server-reference-manifest.json +1 -1
  281. package/.next/static/chunks/{4718-441a2af91f0374e9.js → 4718-814f4ecfd7fcc513.js} +1 -1
  282. package/.next/static/chunks/6022-7a7d1760fc9814c7.js +1 -0
  283. package/.next/static/chunks/app/worktrees/[id]/page-3af707e74a75172b.js +1 -0
  284. package/.next/trace +13 -13
  285. package/dist/server/locales/en/worktree.json +9 -2
  286. package/dist/server/locales/ja/worktree.json +9 -2
  287. package/dist/server/src/lib/cli-tools/vibe-local.js +10 -0
  288. package/dist/server/src/lib/hooks/hook-settings-generator.js +61 -1
  289. package/dist/server/src/lib/hooks/sources/antigravity/history.js +302 -27
  290. package/dist/server/src/lib/hooks/sources/antigravity/transcript.js +103 -0
  291. package/dist/server/src/lib/polling/structured-history-gate.js +68 -4
  292. package/dist/server/src/lib/session/agent-session-lifecycle.js +31 -1
  293. package/dist/server/src/lib/session/session-generation-archive.js +194 -0
  294. package/dist/server/src/lib/tasks/contract-message.js +83 -9
  295. package/dist/server/src/lib/tasks/contract-parser.js +2 -0
  296. package/package.json +1 -1
  297. package/.next/server/chunks/153.js +0 -1
  298. package/.next/server/chunks/4299.js +0 -1
  299. package/.next/server/chunks/6838.js +0 -1
  300. package/.next/server/chunks/7366.js +0 -5
  301. package/.next/static/chunks/6022-2fa0b5a82d4ce7b6.js +0 -1
  302. package/.next/static/chunks/app/worktrees/[id]/page-38edcd53e51f53b0.js +0 -1
  303. /package/.next/static/{0a4qrU8WdUwQrlO4mfLMu → 9x6U1h52hH_r6pOsGwI_p}/_buildManifest.js +0 -0
  304. /package/.next/static/{0a4qrU8WdUwQrlO4mfLMu → 9x6U1h52hH_r6pOsGwI_p}/_ssgManifest.js +0 -0
@@ -76,6 +76,8 @@ exports.isAntigravityTurnClosingRecord = isAntigravityTurnClosingRecord;
76
76
  exports.isAntigravityTurnWritable = isAntigravityTurnWritable;
77
77
  exports.isAntigravityPromptRecord = isAntigravityPromptRecord;
78
78
  exports.renderAntigravityTurn = renderAntigravityTurn;
79
+ exports.antigravityTurnLastRecordAt = antigravityTurnLastRecordAt;
80
+ exports.resolveAntigravityTurnCompletion = resolveAntigravityTurnCompletion;
79
81
  const event_mapper_1 = require("../event-mapper");
80
82
  const turn_body_1 = require("../turn-body");
81
83
  /**
@@ -444,3 +446,104 @@ function renderAntigravityTurn(turn) {
444
446
  unknownRecordTypes: [...unknown],
445
447
  };
446
448
  }
449
+ /**
450
+ * Epoch ms of the newest record agy wrote inside this turn, or 0 (Issue #2443).
451
+ *
452
+ * The maximum rather than `records.at(-1)`: `created_at` is agy's own field and
453
+ * a record that carries none reads as null, so the last record in file order is
454
+ * not always the last one with a clock on it. The prompt record is deliberately
455
+ * outside the walk — `records` holds everything *after* the `USER_INPUT` — which
456
+ * is why {@link resolveAntigravityTurnCompletion} floors the comparison at
457
+ * {@link AntigravityTurnAccumulator.startedAt} as well.
458
+ *
459
+ * @returns Epoch ms, or 0 when the turn has no timestamped record
460
+ */
461
+ function antigravityTurnLastRecordAt(turn) {
462
+ let at = 0;
463
+ for (const record of turn.records) {
464
+ if (record.timestampMs !== null && record.timestampMs > at)
465
+ at = record.timestampMs;
466
+ }
467
+ return at;
468
+ }
469
+ /**
470
+ * Whether agy has vouched for this turn's body (Issue #2443).
471
+ *
472
+ * ## What this is separate from, and why the separation is the Issue
473
+ *
474
+ * {@link isAntigravityTurnWritable} answers "may a row be written from this
475
+ * turn". It has to be generous — agy writes **no record that closes a turn**, so
476
+ * the shape of the last thing it wrote is all there is, and an interim report
477
+ * ("waiting for the worker") is prose with no `tool_calls` exactly like a
478
+ * conclusion is. #2438 made the row that follows from that repairable. What it
479
+ * could not make repairable is everything a save *triggers*: a relay delivering
480
+ * the interim body to the session that asked for the answer cannot be taken
481
+ * back, and `broadcastMessage('message_updated', …)` does not rewind it.
482
+ *
483
+ * So this is the second question — "is this body final" — and it is answered
484
+ * from a different kind of evidence, deliberately:
485
+ *
486
+ * - **not the wording.** "waiting", "Waiting for" and their translations are a
487
+ * model's prose, and a rule keyed on them is wrong the first time the model
488
+ * is asked to answer in another language or writes a conclusion that mentions
489
+ * waiting.
490
+ * - **not a fixed quiet period.** The gaps measured on the reporting machine
491
+ * were 3 / 58 / 156 s from an interim candidate to the next record and 9 /
492
+ * 113 / 118 s from the final one, which overlap: no constant separates them.
493
+ * - **not `status: DONE`** (all 15 measured candidates carry it, early and
494
+ * final alike) **and not `truncated_fields`**, which is agy saying it
495
+ * shortened a field.
496
+ *
497
+ * ## The evidence that is used
498
+ *
499
+ * agy's own `Stop` hook, correlated by instant. `Stop` is agy reporting that its
500
+ * loop ended, and CommandMate already records when one arrived
501
+ * (`session/agent-event-state`'s `getLastStopEventAt`). What makes it usable
502
+ * despite `source.ts`'s warning that a `Stop` can be answered with
503
+ * `{"decision":"continue"}` is that the correlation is an ordering rather than a
504
+ * flag: a stop is evidence about the file **as it was when the stop arrived**.
505
+ *
506
+ * - A resumed loop appends records *after* the stop, which pushes
507
+ * `lastRecordAt` past `stopAt` and takes the confirmation away again. The
508
+ * evidence therefore withdraws itself in exactly the case the warning is
509
+ * about, with no `continue`-detection of its own.
510
+ * - A stop belonging to the *previous* turn is older than this turn's records
511
+ * and confirms nothing.
512
+ * - No stop at all — hooks not wired up, agy killed, CommandMate restarted
513
+ * since — is `no-stop-event`, and the caller keeps the body provisional
514
+ * rather than promoting it.
515
+ *
516
+ * The residual is agy's clock resolution: `created_at` is written to the second,
517
+ * so a record appended in the same second as the stop compares equal to it.
518
+ * That is a sub-second window, it is bounded by one `created_at` tick, and the
519
+ * direction of the error is a body confirmed one record early rather than a turn
520
+ * confirmed that never ended.
521
+ *
522
+ * Pure: the stop instant is a parameter, so this file keeps its no-filesystem,
523
+ * no-database, no-`globalThis` contract and the rule is a property a test states
524
+ * against values rather than against a running server.
525
+ *
526
+ * @param turn - The turn to judge
527
+ * @param stopAt - Epoch ms of this instance's last `Stop`, or null when none has
528
+ * been received
529
+ */
530
+ function resolveAntigravityTurnCompletion(turn, stopAt) {
531
+ const lastRecordAt = antigravityTurnLastRecordAt(turn);
532
+ const base = { confirmed: false, lastRecordAt, stopAt };
533
+ // A turn agy is still working through has no final body to vouch for. Asked
534
+ // before the clock questions so that "it is still running" never reads as
535
+ // "its records are unstamped".
536
+ if (!isAntigravityTurnWritable(turn))
537
+ return { ...base, reason: 'turn-open' };
538
+ if (lastRecordAt <= 0)
539
+ return { ...base, reason: 'no-timestamped-record' };
540
+ if (stopAt === null)
541
+ return { ...base, reason: 'no-stop-event' };
542
+ // `startedAt` as well as the newest record: a turn whose records all predate
543
+ // its own prompt is a shape this reader has not seen, and taking the later of
544
+ // the two cannot make the test easier to pass.
545
+ if (stopAt < Math.max(lastRecordAt, turn.startedAt)) {
546
+ return { ...base, reason: 'stop-before-last-record' };
547
+ }
548
+ return { confirmed: true, reason: 'stop-after-last-record', lastRecordAt, stopAt };
549
+ }
@@ -118,9 +118,41 @@ const logger = (0, logger_1.createLogger)('lib/polling/structured-history-gate')
118
118
  * can see is not a lock.
119
119
  */
120
120
  const captureQueue = (globalThis.__structuredHistoryCaptureQueue ??= new Map());
121
- /** Forget every instance's in-flight capture. Test seam. */
121
+ /**
122
+ * The last completion each instance was announced for (Issue #2443).
123
+ *
124
+ * Keyed by the same triple as {@link captureQueue}, holding whatever
125
+ * `StructuredHistoryCaptureReport.completionKey` the reader minted. Its only job
126
+ * is to make the completion edge an *edge*: the poller re-reads a finished turn
127
+ * every couple of seconds, and #2443 forbids adding a path that re-delivers a
128
+ * body somebody already has.
129
+ *
130
+ * On `globalThis` for the reason {@link captureQueue} is, and in memory for the
131
+ * reason `session/agent-event-state` gives: the value describes a live session,
132
+ * and a restart that forgets it costs at most one extra announcement into a
133
+ * relay whose own stash guard already refuses a second payload.
134
+ */
135
+ const announcedCompletions = (globalThis.__structuredHistoryAnnouncedCompletions ??= new Map());
136
+ /** Forget every instance's in-flight capture and announced completion. Test seam. */
122
137
  function resetStructuredHistoryCaptureQueue() {
123
138
  captureQueue.clear();
139
+ announcedCompletions.clear();
140
+ }
141
+ /**
142
+ * Whether this completion has already been announced for this instance (#2443).
143
+ *
144
+ * A reader that minted no key is always announced — the pre-#2443 behaviour, and
145
+ * the behaviour claude, codex and command-code keep. Records the key as a side
146
+ * effect when the answer is "no", because the two steps must not be separable:
147
+ * an announcement that forgot to record would repeat on the next poll.
148
+ */
149
+ function claimCompletionAnnouncement(key, completionKey) {
150
+ if (completionKey === undefined)
151
+ return true;
152
+ if (announcedCompletions.get(key) === completionKey)
153
+ return false;
154
+ announcedCompletions.set(key, completionKey);
155
+ return true;
124
156
  }
125
157
  /** The queue key; the same triple `buildCompositeKey` spells everywhere else. */
126
158
  function captureKeyOf(worktreeId, cliToolId, instanceId) {
@@ -296,17 +328,24 @@ async function captureStructuredHistoryTurn(worktreeId, cliToolId, instanceId, c
296
328
  return false;
297
329
  }
298
330
  const resolvedInstanceId = instanceId ?? cliToolId;
299
- return serializePerInstance(captureKeyOf(worktreeId, cliToolId, resolvedInstanceId), async () => {
331
+ const captureKey = captureKeyOf(worktreeId, cliToolId, resolvedInstanceId);
332
+ return serializePerInstance(captureKey, async () => {
300
333
  // The reader's own report, kept local and copied out below: `report` is
301
334
  // the caller's object and must end up holding one verdict, not whatever
302
335
  // the last reader to touch it happened to leave there.
303
336
  const readerReport = {};
304
337
  try {
305
338
  const captured = await reader.capture({ worktreeId, cliToolId, instanceId: resolvedInstanceId }, capture, readerReport);
339
+ // Issue #2443: absent means `settled`, which is what leaves the three
340
+ // readers that have a turn-closing record exactly where they were.
341
+ const completion = readerReport.completion ?? 'settled';
306
342
  if (report) {
307
343
  // A reader that says nothing is read as `unavailable` — the pre-#2436
308
344
  // behaviour, and the safe direction: the scraper keeps the turn.
309
345
  report.outcome = captured ? 'captured' : readerReport.outcome ?? 'unavailable';
346
+ report.completion = completion;
347
+ report.completionKey = readerReport.completionKey;
348
+ report.completionReason = readerReport.completionReason;
310
349
  }
311
350
  // Issue #2377: the moment a relay is waiting for. This is the single
312
351
  // point BOTH triggers of a pull capture pass through — the poller's save
@@ -317,8 +356,33 @@ async function captureStructuredHistoryTurn(worktreeId, cliToolId, instanceId, c
317
356
  // Announced only when the capture actually wrote something: a `false`
318
357
  // means the scraper is still the writer for this turn, and the poller's
319
358
  // own call below will announce it.
320
- if (captured)
321
- (0, relay_triggers_1.onRelayTurnCompleted)(worktreeId, cliToolId, resolvedInstanceId, true);
359
+ //
360
+ // Issue #2443 adds the second condition, and it is the whole Issue.
361
+ // `captured` means History holds the newest turn; it does **not** mean
362
+ // the agent is finished with it, because antigravity has no record that
363
+ // closes a turn and an interim report is saved under the same key the
364
+ // conclusion will land on. Announcing here would hand a relay the
365
+ // interim body as the answer, and `broadcastMessage('message_updated',
366
+ // …)` — the repair #2438 added — does not take a delivered message
367
+ // back. So a provisional capture announces nothing at all; the relay
368
+ // keeps waiting on the deadline it already has, and the settled capture
369
+ // that follows announces the finished body.
370
+ if (captured && completion === 'settled') {
371
+ if (claimCompletionAnnouncement(captureKey, readerReport.completionKey)) {
372
+ (0, relay_triggers_1.onRelayTurnCompleted)(worktreeId, cliToolId, resolvedInstanceId, true);
373
+ }
374
+ }
375
+ else if (captured) {
376
+ logger.info('structured-history-capture-provisional', {
377
+ worktreeId,
378
+ cliToolId,
379
+ instanceId: resolvedInstanceId,
380
+ // The reader's own word for what is missing; see
381
+ // `AntigravityTurnCompletionReason`. This is the line #2443 asks for
382
+ // — the reason left on the relay's waiting path.
383
+ reason: readerReport.completionReason ?? 'unknown',
384
+ });
385
+ }
322
386
  return captured;
323
387
  }
324
388
  catch (error) {
@@ -42,14 +42,26 @@ exports.prepareAgentLaunch = prepareAgentLaunch;
42
42
  exports.buildAgentLaunchCommandLine = buildAgentLaunchCommandLine;
43
43
  const sources_1 = require("../../lib/hooks/sources");
44
44
  const agent_event_state_1 = require("../../lib/session/agent-event-state");
45
+ const session_generation_archive_1 = require("../../lib/session/session-generation-archive");
45
46
  const logger_1 = require("../../lib/logger");
46
47
  const logger = (0, logger_1.createLogger)('lib/session/agent-session-lifecycle');
47
48
  /**
48
- * Open a new event generation for an agent instance that is about to start.
49
+ * Open a new event generation for an agent instance that is about to start,
50
+ * and retire the previous process's chat history (Issue #2444).
49
51
  *
50
52
  * Safe to call for a tool that emits nothing: the fence is a timestamp, and a
51
53
  * tool with no events simply never has any to fence.
52
54
  *
55
+ * The archive rides here rather than in its own seam because this function is
56
+ * already the answer to "a new agent process is being created for this
57
+ * (worktree, instance)" — the one fact that distinguishes a replacement from a
58
+ * reconnect, and the fact `chat_messages.archived` needs. See
59
+ * `lib/session/session-generation-archive` for why observing the *death*
60
+ * instead would archive live conversations. Note that the boundary is this call
61
+ * and not the adoption mark: codex's and opencode's relaunch paths run
62
+ * `reconcileExistingSession`, which sets an adoption mark, so a reader of that
63
+ * mark would miss exactly the endings this exists for.
64
+ *
53
65
  * @param target - The instance being created
54
66
  * @param at - Epoch ms; defaults to now
55
67
  */
@@ -70,6 +82,24 @@ function beginAgentSession(target, at = Date.now()) {
70
82
  // learn by noticing their `respond` no longer has anything to answer.
71
83
  decisionsEvicted: after - before,
72
84
  });
85
+ // Issue #2444: the rows the replaced process wrote are a previous session's
86
+ // history now. Inside a `try` and after the fence on purpose — this module
87
+ // otherwise touches nothing but memory, and a database that is missing,
88
+ // locked or mid-migration must cost a log line, never a session that refuses
89
+ // to start. It is also a no-op by construction wherever there is no database
90
+ // to reach (see `resolveSessionArchiveDatabase`), which is what keeps the
91
+ // suites that call this with tmux mocked and no DB at all unchanged.
92
+ try {
93
+ (0, session_generation_archive_1.archiveSupersededSessionMessages)(target);
94
+ }
95
+ catch (error) {
96
+ logger.warn('session-generation-archive-failed', {
97
+ worktreeId: target.worktreeId,
98
+ cliToolId: target.cliToolId,
99
+ instanceId: target.instanceId ?? target.cliToolId,
100
+ error: error instanceof Error ? error.message : String(error),
101
+ });
102
+ }
73
103
  }
74
104
  /**
75
105
  * The command that starts this agent, with whatever config it needs written
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ /**
3
+ * Retire the previous process's chat history when a new one takes its place
4
+ * (Issue #2444).
5
+ *
6
+ * `chat_messages.archived` means "a previous session's history", and until this
7
+ * module the only thing that ever wrote it was
8
+ * `POST /api/worktrees/:id/kill-session`. That covers the one ending nobody
9
+ * actually gets: a session killed *through CommandMate*. A tmux server that
10
+ * went away, a CLI that was `/exit`ed back to its shell, a machine that
11
+ * rebooted — none of those pass through that route, so the dead session's rows
12
+ * stayed `archived = 0` and the chat surface kept showing them as the current
13
+ * conversation. Worse, the route refuses to help afterwards: with no live
14
+ * session left to kill it returns 404 *before* reaching the archive call, so
15
+ * the rows could not be retired by hand either.
16
+ *
17
+ * ## Why the seam is "a new process starts", not "the old one died"
18
+ *
19
+ * Observing the death is the tempting place — `current-output-builder`'s
20
+ * `!running` branch already knows — and it is the wrong one. `isRunning` is a
21
+ * `has-session` probe with a timeout in front of it and a liquid status
22
+ * verdict behind it; a single slow probe reads as `false` for a session that is
23
+ * very much alive, and archiving there would throw away a live conversation.
24
+ * "A new agent process is being created for this (worktree, instance)" is not a
25
+ * judgement call: {@link beginAgentSession} is called on exactly that fact, on
26
+ * every tool's creation path and on codex's / opencode's relaunch-into-the-same-pane
27
+ * path (#2070), and deliberately NOT on opencode's live-reuse path, where the
28
+ * process is the same process. The rows that belong to the process being
29
+ * replaced are precisely the ones to retire.
30
+ *
31
+ * ## Why it is its own module
32
+ *
33
+ * `agent-session-lifecycle` is an in-memory fence and nothing else — no
34
+ * database, no sockets — and every `src/lib/cli-tools/<tool>.ts` imports it.
35
+ * Keeping the database and the WebSocket here means that graph does not change:
36
+ * the lifecycle module calls one function, inside a `try`, and a failure to
37
+ * archive is a logged warning rather than a session that refuses to start.
38
+ *
39
+ * ## Known limitation
40
+ *
41
+ * A transcript reader that INSERTs a *new* row for the previous session after
42
+ * this has run writes it with `archived = 0`, so it lands in the new session's
43
+ * history. Updates to rows that already exist are unaffected: no writer touches
44
+ * `archived` on update. Measured as rare enough to leave alone — the readers
45
+ * run behind the same `startSession` that triggers this — and it is recorded
46
+ * here rather than guarded, because guarding it means a second notion of "which
47
+ * generation is this row from" and that is the schema #168 rejected.
48
+ *
49
+ * @module lib/session/session-generation-archive
50
+ */
51
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
52
+ if (k2 === undefined) k2 = k;
53
+ var desc = Object.getOwnPropertyDescriptor(m, k);
54
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
55
+ desc = { enumerable: true, get: function() { return m[k]; } };
56
+ }
57
+ Object.defineProperty(o, k2, desc);
58
+ }) : (function(o, m, k, k2) {
59
+ if (k2 === undefined) k2 = k;
60
+ o[k2] = m[k];
61
+ }));
62
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
63
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
64
+ }) : function(o, v) {
65
+ o["default"] = v;
66
+ });
67
+ var __importStar = (this && this.__importStar) || (function () {
68
+ var ownKeys = function(o) {
69
+ ownKeys = Object.getOwnPropertyNames || function (o) {
70
+ var ar = [];
71
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
72
+ return ar;
73
+ };
74
+ return ownKeys(o);
75
+ };
76
+ return function (mod) {
77
+ if (mod && mod.__esModule) return mod;
78
+ var result = {};
79
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
80
+ __setModuleDefault(result, mod);
81
+ return result;
82
+ };
83
+ })();
84
+ Object.defineProperty(exports, "__esModule", { value: true });
85
+ exports.resolveSessionArchiveDatabase = resolveSessionArchiveDatabase;
86
+ exports.archiveSupersededSessionMessages = archiveSupersededSessionMessages;
87
+ const db_instance_1 = require("../../lib/db/db-instance");
88
+ const chat_db_1 = require("../../lib/db/chat-db");
89
+ const types_1 = require("../../lib/realtime/types");
90
+ const logger_1 = require("../../lib/logger");
91
+ const logger = (0, logger_1.createLogger)('lib/session/session-generation-archive');
92
+ /**
93
+ * The database this module archives through, or `null` when there is none to
94
+ * archive through.
95
+ *
96
+ * `getDbInstance()` **creates** a database when the file is not there yet, and
97
+ * that is the one thing this call must never do from here. Every production
98
+ * caller arrives via an API route that has already opened the connection, so
99
+ * the singleton is warm and this is a map lookup. A Vitest worker is the
100
+ * opposite case: `beginAgentSession` is reached by a dozen suites that mock
101
+ * tmux and never touch a database, and opening one for them would either
102
+ * fabricate `<cwd>/data/cm.db` or — when the suite runs in a checkout that has
103
+ * one — hand those fixtures the developer's real chat history to write into.
104
+ *
105
+ * So under Vitest the answer is "no database" unless a test hands one in
106
+ * explicitly (see {@link archiveSupersededSessionMessages}'s `db` parameter) or
107
+ * mocks `@/lib/db/db-instance` **and** clears `VITEST`, which is how the
108
+ * integration test drives the production branch. Only `VITEST` is consulted,
109
+ * never `NODE_ENV`: `vitest.config.ts` `define`s `process.env.NODE_ENV` to the
110
+ * literal `'test'` at transform time, so a `NODE_ENV` check here would fold to
111
+ * a constant and no test could ever reach the other branch.
112
+ */
113
+ function resolveSessionArchiveDatabase() {
114
+ if (process.env.VITEST)
115
+ return null;
116
+ return (0, db_instance_1.getDbInstance)();
117
+ }
118
+ /**
119
+ * Archive the active chat rows of the process being replaced.
120
+ *
121
+ * Scoped to one `(worktreeId, instanceId)` pair, which is what makes a restart
122
+ * of `codex` leave `codex-2`'s conversation alone — the two share a worktree and
123
+ * a tool id and nothing else. Already-archived rows are not touched (the SQL
124
+ * filters on `archived = 0`), so calling this twice is not two generations.
125
+ *
126
+ * Nothing happens when there was nothing to archive: no `recomputeLastUserMessage`
127
+ * (the sidebar's value cannot have changed) and no frame on the wire (a client
128
+ * asked to re-read identical history would just be paying for a round trip).
129
+ * That is also what keeps a healthy-reuse `startSession` — the path that never
130
+ * calls in here at all — indistinguishable from a first-ever launch.
131
+ *
132
+ * Throws whatever the database throws; the caller in `agent-session-lifecycle`
133
+ * catches, because failing to retire old rows must not stop a session from
134
+ * starting.
135
+ *
136
+ * @param target - The instance whose previous process is being replaced
137
+ * @param db - The database to write through; defaults to
138
+ * {@link resolveSessionArchiveDatabase}
139
+ * @returns The row count and the instance it was scoped to
140
+ */
141
+ function archiveSupersededSessionMessages(target, db = resolveSessionArchiveDatabase()) {
142
+ const instanceId = target.instanceId ?? target.cliToolId;
143
+ if (!db)
144
+ return { archived: 0, instanceId };
145
+ const archived = (0, chat_db_1.deleteMessagesByInstance)(db, target.worktreeId, instanceId);
146
+ if (archived === 0)
147
+ return { archived: 0, instanceId };
148
+ // Same pairing `kill-session` uses: the sidebar's `last_user_message` is
149
+ // derived from the *active* rows, so archiving without recomputing leaves it
150
+ // quoting a conversation the surface no longer shows.
151
+ (0, chat_db_1.recomputeLastUserMessage)(db, target.worktreeId);
152
+ logger.info('session-generation-archived', {
153
+ worktreeId: target.worktreeId,
154
+ cliToolId: target.cliToolId,
155
+ instanceId,
156
+ archived,
157
+ });
158
+ broadcastMessagesInvalidated(target.worktreeId, target.cliToolId, instanceId);
159
+ return { archived, instanceId };
160
+ }
161
+ /**
162
+ * Tell every open pane for this instance to re-read its history.
163
+ *
164
+ * A scope rather than a payload, for the reason `MESSAGES_INVALIDATED_EVENT_TYPE`
165
+ * gives: an archive has no row to publish — `message` / `message_updated` can
166
+ * only ever say what a row now *looks like* — so the settled state has to come
167
+ * from the server. PC split panes and the phone both listen through
168
+ * `useSplitMessages`, which matches on (worktreeId, cliToolId, instanceId) and
169
+ * does not branch on `reason`.
170
+ *
171
+ * Detached, and the `ws-server` import is dynamic, for the same bargain
172
+ * `broadcastRecordedRow` in `current-output-builder` strikes: this module sits
173
+ * in the import graph of every `src/lib/cli-tools/<tool>.ts` (through
174
+ * `agent-session-lifecycle`), and none of them should pull the WebSocket server
175
+ * in just by starting a pane. The rows are already committed when this runs, so
176
+ * a socket write that throws cannot turn a completed archive into a failure.
177
+ */
178
+ function broadcastMessagesInvalidated(worktreeId, cliToolId, instanceId) {
179
+ void Promise.resolve().then(() => __importStar(require('../../lib/ws-server'))).then(({ broadcastMessage }) => {
180
+ broadcastMessage(types_1.MESSAGES_INVALIDATED_EVENT_TYPE, {
181
+ worktreeId,
182
+ cliToolId,
183
+ instanceId,
184
+ reason: 'session_generation',
185
+ });
186
+ })
187
+ .catch((error) => {
188
+ logger.warn('session-generation-invalidate-broadcast-failed', {
189
+ worktreeId,
190
+ instanceId,
191
+ error: error instanceof Error ? error.message : String(error),
192
+ });
193
+ });
194
+ }
@@ -15,14 +15,16 @@
15
15
  * @module lib/tasks/contract-message
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.REQUIRE_COMMIT_SOURCE_CONTRACT = exports.REQUIRE_COMMIT_SOURCE_CONFIG = void 0;
18
+ exports.BUILT_IN_GATE_ORDER = exports.REQUIRE_COMMIT_SOURCE_CONTRACT = exports.REQUIRE_COMMIT_SOURCE_CONFIG = void 0;
19
19
  exports.resolveRequireCommit = resolveRequireCommit;
20
20
  exports.resolveContractGateIds = resolveContractGateIds;
21
+ exports.runsEnvCleanGate = runsEnvCleanGate;
21
22
  exports.contractGateDefinitions = contractGateDefinitions;
22
23
  exports.validateContractAgainstVerifyConfig = validateContractAgainstVerifyConfig;
23
24
  exports.resolveGateCommands = resolveGateCommands;
24
25
  exports.composeContractMessage = composeContractMessage;
25
26
  const verify_config_1 = require("../../lib/verification/verify-config");
27
+ const env_clean_gate_1 = require("../../lib/verification/env-clean-gate");
26
28
  /**
27
29
  * How the built-in gates read in the preamble; they run git plumbing, not shell
28
30
  * commands.
@@ -35,6 +37,14 @@ const verify_config_1 = require("../../lib/verification/verify-config");
35
37
  const WORK_EVIDENCE_ANY_CHANGE_LABEL = `${verify_config_1.WORK_EVIDENCE_GATE_ID}(commit または未 commit の変更が存在すること)`;
36
38
  const WORK_EVIDENCE_COMMIT_LABEL = `${verify_config_1.WORK_EVIDENCE_GATE_ID}(commit が存在すること。未 commit の変更は作業証跡として数えない)`;
37
39
  const SCOPE_LABEL = `${verify_config_1.SCOPE_GATE_ID}(変更ファイルが scope.allow の内側に収まっていること)`;
40
+ /**
41
+ * `env-clean` reads the machine, not the repository, so the preamble has to say
42
+ * so (#2442). Without this row the gate would run — and could fail the run —
43
+ * without ever having been named in the completion criterion the agent was sent,
44
+ * which is the same "declared and never checked" defect pointed the other way.
45
+ */
46
+ const ENV_CLEAN_LABEL = `${verify_config_1.ENV_CLEAN_GATE_ID}(タスク開始時に在ったポート・tmux セッション・$HOME / ~/.commandmate ` +
47
+ '直下のエントリが、増えても減っても不合格)';
38
48
  /** The obligation line, in the two forms the pipeline can actually enforce. */
39
49
  const COMMIT_REQUIRED_LINE = '- 作業完了後は必ず commit すること(未 commit の作業は未完了とみなされる)';
40
50
  const COMMIT_EXPECTED_LINE = '- 作業完了後は commit すること(ただし work-evidence は未 commit の変更も作業証跡として' +
@@ -63,6 +73,18 @@ function resolveRequireCommit(contract, config) {
63
73
  sources.push(exports.REQUIRE_COMMIT_SOURCE_CONTRACT);
64
74
  return { required: sources.length > 0, sources };
65
75
  }
76
+ /**
77
+ * The built-in gates, in the order `gate-runner` runs them.
78
+ *
79
+ * Named once because two things have to agree with it: the resolved gate id list
80
+ * below and the preamble's command list. A contract that typed
81
+ * `gates: [lint, env-clean]` must still be told the order the run will take.
82
+ */
83
+ exports.BUILT_IN_GATE_ORDER = [
84
+ verify_config_1.WORK_EVIDENCE_GATE_ID,
85
+ verify_config_1.SCOPE_GATE_ID,
86
+ verify_config_1.ENV_CLEAN_GATE_ID,
87
+ ];
66
88
  /**
67
89
  * The gate ids a contract asks for, or null for "every gate".
68
90
  *
@@ -70,24 +92,54 @@ function resolveRequireCommit(contract, config) {
70
92
  * gates run. A contract that required work evidence or a clean scope while
71
93
  * listing only `[lint, unit]` would otherwise declare rules that nothing
72
94
  * checked: the flags would read as enforced and the gates would never run.
95
+ *
96
+ * `env-clean` joined that rule in #2442. Only the contract's own half is visible
97
+ * here — `options.requireEnvClean` lives in verify.yaml, which this function does
98
+ * not take — so callers that hold a config OR the two together;
99
+ * `selectGates` in gate-runner already does, and so does
100
+ * {@link resolveGateCommands} for the sentence the agent reads.
73
101
  */
74
102
  function resolveContractGateIds(contract) {
75
103
  const gates = contract.verify.gates;
76
104
  if (!gates)
77
105
  return null;
78
- const builtIns = [
106
+ const required = new Map([
79
107
  [verify_config_1.WORK_EVIDENCE_GATE_ID, contract.success.requireWorkEvidence],
80
108
  [verify_config_1.SCOPE_GATE_ID, contract.success.requireScopeClean],
81
- ];
109
+ [verify_config_1.ENV_CLEAN_GATE_ID, contract.success.requireEnvClean],
110
+ ]);
82
111
  // Built-ins are listed first and in their execution order even when the
83
112
  // contract already named one, so the resolved list reads as the order the run
84
113
  // will actually take rather than the order the contract happened to type.
85
- const selected = builtIns
86
- .filter(([id, required]) => required || gates.includes(id))
87
- .map(([id]) => id);
88
- const rest = gates.filter((id) => !builtIns.some(([builtIn]) => builtIn === id));
114
+ const selected = exports.BUILT_IN_GATE_ORDER.filter((id) => required.get(id) === true || gates.includes(id));
115
+ const rest = gates.filter((id) => !exports.BUILT_IN_GATE_ORDER.includes(id));
89
116
  return [...selected, ...rest];
90
117
  }
118
+ /**
119
+ * Whether a verification run for this contract will include `env-clean` (#2442).
120
+ *
121
+ * Three declarations can put the gate in a run and the baseline has to be
122
+ * recorded for all three, because the snapshot is taken once — at send — and
123
+ * cannot be reconstructed later:
124
+ *
125
+ * 1. `options.requireEnvClean` in the repository's verify.yaml,
126
+ * 2. `success.requireEnvClean` in the contract,
127
+ * 3. the contract naming `env-clean` in `verify.gates`.
128
+ *
129
+ * (3) is the one that was easy to miss. Opening the id to `verify.gates` without
130
+ * also asking here would have made every contract that used it report UNKNOWN
131
+ * forever: `selectGates` would run the gate, and `recordEnvBaseline` — reading
132
+ * only the OR of (1) and (2) — would never have written anything to compare
133
+ * against. An operator's `verify --gates env-clean` on a task created without any
134
+ * of the three still reports UNKNOWN, which is correct: no baseline exists, and
135
+ * inventing one from the state at verification time is the fail-open this gate
136
+ * refuses.
137
+ */
138
+ function runsEnvCleanGate(contract, config) {
139
+ if ((0, env_clean_gate_1.resolveRequireEnvClean)(contract, config).required)
140
+ return true;
141
+ return resolveContractGateIds(contract)?.includes(verify_config_1.ENV_CLEAN_GATE_ID) ?? false;
142
+ }
91
143
  /**
92
144
  * The gates this contract defines itself (#1791).
93
145
  *
@@ -146,7 +198,16 @@ function validateContractAgainstVerifyConfig(contract, config) {
146
198
  "repository's own — rename the contract gate.");
147
199
  }
148
200
  if (gates) {
149
- const known = new Set([verify_config_1.WORK_EVIDENCE_GATE_ID, verify_config_1.SCOPE_GATE_ID, ...configIds]);
201
+ // `env-clean` joins the built-ins a contract may name (#2442). It is a
202
+ // reserved id, so it can never appear in `configIds` — leaving it out of this
203
+ // set made `verify.gates: [env-clean]` an unknown id at send, which is how
204
+ // the gate ended up reachable only through the repository-wide switch.
205
+ const known = new Set([
206
+ verify_config_1.WORK_EVIDENCE_GATE_ID,
207
+ verify_config_1.SCOPE_GATE_ID,
208
+ verify_config_1.ENV_CLEAN_GATE_ID,
209
+ ...configIds,
210
+ ]);
150
211
  const defined = new Set(definitions.map((gate) => gate.id));
151
212
  const unknown = gates.filter((id) => !known.has(id) && !defined.has(id));
152
213
  if (unknown.length > 0) {
@@ -174,11 +235,16 @@ function resolveGateCommands(contract, config) {
174
235
  const builtInLabels = new Map([
175
236
  [verify_config_1.WORK_EVIDENCE_GATE_ID, workEvidenceLabel],
176
237
  [verify_config_1.SCOPE_GATE_ID, SCOPE_LABEL],
238
+ // Without this row a contract naming `env-clean` resolved to `undefined` and
239
+ // the preamble handed the agent the literal string "undefined" as one of the
240
+ // commands it had to pass.
241
+ [verify_config_1.ENV_CLEAN_GATE_ID, ENV_CLEAN_LABEL],
177
242
  ]);
178
243
  // Contract-defined gates run after the repository's own, so the preamble
179
244
  // lists them in that order too — the line claims to be "the commands that
180
245
  // will run", and an order it invents would be the first thing to drift.
181
246
  const declared = [...config.gates, ...contractGateDefinitions(contract)];
247
+ const envCleanRequired = (0, env_clean_gate_1.resolveRequireEnvClean)(contract, config).required;
182
248
  const selected = resolveContractGateIds(contract);
183
249
  if (!selected) {
184
250
  // An omitted gates list runs every gate, and the built-ins are still governed
@@ -186,10 +252,18 @@ function resolveGateCommands(contract, config) {
186
252
  const builtIns = [workEvidenceLabel];
187
253
  if (contract.success.requireScopeClean)
188
254
  builtIns.push(SCOPE_LABEL);
255
+ if (envCleanRequired)
256
+ builtIns.push(ENV_CLEAN_LABEL);
189
257
  return [...builtIns, ...declared.map((gate) => gate.command)];
190
258
  }
259
+ // Re-derive the built-in prefix instead of trusting `selected`'s: the
260
+ // repository-wide `options.requireEnvClean` forces the gate into the run
261
+ // without appearing in the contract at all, and a preamble that omitted it
262
+ // would hand the agent a completion criterion the run does not use.
263
+ const builtIns = exports.BUILT_IN_GATE_ORDER.filter((id) => selected.includes(id) || (id === verify_config_1.ENV_CLEAN_GATE_ID && envCleanRequired));
264
+ const rest = selected.filter((id) => !exports.BUILT_IN_GATE_ORDER.includes(id));
191
265
  const byId = new Map(declared.map((gate) => [gate.id, gate.command]));
192
- return selected.map((id) => builtInLabels.get(id) ?? byId.get(id));
266
+ return [...builtIns, ...rest].map((id) => builtInLabels.get(id) ?? byId.get(id));
193
267
  }
194
268
  /**
195
269
  * Compose the message sent to the agent: contract preamble, then the goal.
@@ -76,6 +76,7 @@ const SUCCESS_KEYS = [
76
76
  'requireWorkEvidence',
77
77
  'requireScopeClean',
78
78
  'requireCommit',
79
+ 'requireEnvClean',
79
80
  'autoVerifyOnStop',
80
81
  ];
81
82
  class TaskContractError extends Error {
@@ -314,6 +315,7 @@ function validateSuccess(value, issues) {
314
315
  requireWorkEvidence: true,
315
316
  requireScopeClean: true,
316
317
  requireCommit: false,
318
+ requireEnvClean: false,
317
319
  autoVerifyOnStop: false,
318
320
  };
319
321
  if (value === undefined || value === null)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commandmate",
3
- "version": "0.33.2",
3
+ "version": "0.33.3",
4
4
  "description": "A local control plane for agent CLIs — orchestration and visibility for Claude Code, Codex, Gemini CLI, and more across Git worktrees",
5
5
  "keywords": [
6
6
  "claude-code",