commandmate 0.17.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +120 -120
  3. package/.next/app-path-routes-manifest.json +19 -19
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/prerender-manifest.json +12 -12
  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/app/update/route_client-reference-manifest.js +1 -1
  9. package/.next/server/app/api/app/update-check/route.js +1 -1
  10. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
  12. package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
  18. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  22. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  24. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  25. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  27. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  28. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  30. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  31. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/push/subscriptions/route.js +1 -1
  33. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route.js +1 -1
  37. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  38. package/.next/server/app/api/repositories/[id]/todos/route.js +1 -1
  39. package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
  40. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  41. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  42. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  43. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  44. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  45. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  46. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  47. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  48. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  49. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  50. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  51. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  52. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  53. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  54. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  55. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/tasks/[taskId]/route.js +1 -1
  57. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  58. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  60. package/.next/server/app/api/todos/route.js +1 -1
  61. package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/verification/runs/[runId]/route.js +1 -1
  63. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  64. package/.next/server/app/api/verification/runs/route.js +1 -1
  65. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  66. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  67. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  68. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/worktrees/[id]/cli-tool/route.js +1 -1
  70. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  71. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +1 -1
  72. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  73. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  74. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
  75. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  76. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +1 -1
  77. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  78. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  79. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  80. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  81. package/.next/server/app/api/worktrees/[id]/git/branches/route.js +1 -1
  82. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  83. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  84. package/.next/server/app/api/worktrees/[id]/git/commit/route.js +1 -1
  85. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  86. package/.next/server/app/api/worktrees/[id]/git/diff/route.js +1 -1
  87. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  88. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/api/worktrees/[id]/git/log/route.js +1 -1
  90. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  91. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  93. package/.next/server/app/api/worktrees/[id]/git/reset/route.js +1 -1
  94. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/api/worktrees/[id]/git/revert/route.js +1 -1
  96. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  97. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js +1 -1
  98. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  99. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  100. package/.next/server/app/api/worktrees/[id]/git/staged/route.js +1 -1
  101. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  103. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  104. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  105. package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js +1 -1
  106. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  107. package/.next/server/app/api/worktrees/[id]/git/stash/route.js +1 -1
  108. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  109. package/.next/server/app/api/worktrees/[id]/git/status/route.js +1 -1
  110. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  111. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  112. package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js +1 -1
  113. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  114. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  115. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  116. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js +1 -1
  117. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  118. package/.next/server/app/api/worktrees/[id]/logs/route.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  120. package/.next/server/app/api/worktrees/[id]/marp-render/route.js +1 -1
  121. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  122. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  124. package/.next/server/app/api/worktrees/[id]/memos/route.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/messages/route.js +1 -1
  127. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  129. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  130. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +1 -1
  132. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  133. package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  135. package/.next/server/app/api/worktrees/[id]/schedules/route.js +1 -1
  136. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  137. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  138. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
  139. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  141. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  142. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/skills/route.js +1 -1
  146. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
  148. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  149. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/start-polling/route_client-reference-manifest.js +1 -1
  151. package/.next/server/app/api/worktrees/[id]/tasks/route.js +2 -2
  152. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  153. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  154. package/.next/server/app/api/worktrees/[id]/timers/history/route.js +1 -1
  155. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  157. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js +1 -1
  158. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  159. package/.next/server/app/api/worktrees/[id]/todos/route.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  161. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js +1 -1
  162. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  163. package/.next/server/app/api/worktrees/[id]/tree/route.js +1 -1
  164. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  165. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  166. package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -1
  167. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  168. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  170. package/.next/server/app/api/worktrees/[id]/verify/runs/route.js +1 -1
  171. package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/viewed/route.js +1 -1
  173. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  174. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  175. package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  176. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  177. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  178. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  179. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  180. package/.next/server/app/page_client-reference-manifest.js +1 -1
  181. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  182. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  183. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  184. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  185. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  186. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  187. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  188. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  189. package/.next/server/app/worktrees/[id]/page.js +1 -1
  190. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  191. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  192. package/.next/server/app-paths-manifest.json +19 -19
  193. package/.next/server/chunks/1117.js +1 -1
  194. package/.next/server/chunks/3042.js +1 -1
  195. package/.next/server/chunks/3753.js +19 -23
  196. package/.next/server/chunks/5959.js +3 -3
  197. package/.next/server/chunks/6130.js +1 -1
  198. package/.next/server/chunks/6274.js +10 -9
  199. package/.next/server/chunks/6283.js +1 -1
  200. package/.next/server/chunks/8681.js +1 -1
  201. package/.next/server/chunks/8807.js +492 -485
  202. package/.next/server/chunks/8856.js +1 -1
  203. package/.next/server/middleware-manifest.json +5 -5
  204. package/.next/server/pages/500.html +1 -1
  205. package/.next/server/server-reference-manifest.json +1 -1
  206. package/.next/static/chunks/{6488-f4e447464c9e0e22.js → 6488-2c412c29258637b6.js} +1 -1
  207. package/.next/static/chunks/app/worktrees/[id]/{page-5ffc84094830babb.js → page-f6e09d25cd3b56f9.js} +1 -1
  208. package/.next/trace +12 -12
  209. package/dist/cli/commands/auto-yes.d.ts.map +1 -1
  210. package/dist/cli/commands/auto-yes.js +9 -2
  211. package/dist/cli/commands/capture.d.ts +1 -0
  212. package/dist/cli/commands/capture.d.ts.map +1 -1
  213. package/dist/cli/commands/capture.js +112 -2
  214. package/dist/cli/commands/instances.d.ts +24 -0
  215. package/dist/cli/commands/instances.d.ts.map +1 -1
  216. package/dist/cli/commands/instances.js +44 -0
  217. package/dist/cli/commands/respond.d.ts.map +1 -1
  218. package/dist/cli/commands/respond.js +10 -2
  219. package/dist/cli/commands/send.d.ts.map +1 -1
  220. package/dist/cli/commands/send.js +47 -19
  221. package/dist/cli/commands/wait.d.ts +4 -1
  222. package/dist/cli/commands/wait.d.ts.map +1 -1
  223. package/dist/cli/commands/wait.js +134 -10
  224. package/dist/cli/types/api-responses.d.ts +10 -0
  225. package/dist/cli/types/api-responses.d.ts.map +1 -1
  226. package/dist/cli/types/index.d.ts +16 -0
  227. package/dist/cli/types/index.d.ts.map +1 -1
  228. package/dist/cli/utils/pager.d.ts +28 -0
  229. package/dist/cli/utils/pager.d.ts.map +1 -0
  230. package/dist/cli/utils/pager.js +57 -0
  231. package/dist/cli/utils/verify-runner.d.ts +6 -0
  232. package/dist/cli/utils/verify-runner.d.ts.map +1 -1
  233. package/dist/cli/utils/verify-runner.js +1 -0
  234. package/dist/lib/detection/ansi.d.ts +30 -0
  235. package/dist/lib/detection/ansi.d.ts.map +1 -0
  236. package/dist/lib/detection/ansi.js +39 -0
  237. package/dist/lib/tmux/transcript-squeeze.d.ts +76 -0
  238. package/dist/lib/tmux/transcript-squeeze.d.ts.map +1 -0
  239. package/dist/lib/tmux/transcript-squeeze.js +96 -0
  240. package/dist/server/server.js +18 -0
  241. package/dist/server/src/config/tmux-pane-config.js +33 -1
  242. package/dist/server/src/lib/cli-tools/antigravity.js +2 -1
  243. package/dist/server/src/lib/cli-tools/codex.js +3 -2
  244. package/dist/server/src/lib/cli-tools/copilot.js +2 -2
  245. package/dist/server/src/lib/cli-tools/gemini.js +2 -2
  246. package/dist/server/src/lib/cli-tools/opencode.js +2 -2
  247. package/dist/server/src/lib/cli-tools/vibe-local.js +2 -2
  248. package/dist/server/src/lib/db/agent-instances-db.js +53 -0
  249. package/dist/server/src/lib/db/migrations/index.js +2 -0
  250. package/dist/server/src/lib/db/migrations/runner.js +1 -1
  251. package/dist/server/src/lib/db/migrations/v52-orphaned-worktree-children.js +76 -0
  252. package/dist/server/src/lib/db/migrations/worktree-child-tables.js +119 -0
  253. package/dist/server/src/lib/db/tasks-db.js +46 -1
  254. package/dist/server/src/lib/db/verification-db.js +21 -3
  255. package/dist/server/src/lib/db/worktree-db.js +65 -42
  256. package/dist/server/src/lib/detection/cli-patterns.js +24 -1
  257. package/dist/server/src/lib/detection/status-detector.js +52 -2
  258. package/dist/server/src/lib/session/claude-session.js +4 -2
  259. package/dist/server/src/lib/tmux/read-mode-pager.js +161 -0
  260. package/dist/server/src/lib/tmux/read-mode.js +327 -0
  261. package/dist/server/src/lib/tmux/tmux.js +43 -5
  262. package/package.json +1 -1
  263. /package/.next/static/{gR8Sh86RrTynJON8SWkWK → -E7I667pJDTBamyG8M_Z-}/_buildManifest.js +0 -0
  264. /package/.next/static/{gR8Sh86RrTynJON8SWkWK → -E7I667pJDTBamyG8M_Z-}/_ssgManifest.js +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript-squeeze.d.ts","sourceRoot":"","sources":["../../../src/lib/tmux/transcript-squeeze.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,6EAA6E;AAC7E,MAAM,WAAW,aAAa;IAC5B,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,aAAa,CAwC1F"}
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ /**
3
+ * Whitespace squeeze for the on-demand reading mode (Issue #1623).
4
+ *
5
+ * TUI sessions are pinned to a 200x1000 canvas (`src/config/tmux-pane-config.ts`)
6
+ * and the agent draws its transcript near the top and its composer at the very
7
+ * bottom, so a raw `capture-pane` is mostly layout-only blank rows. Measured on a
8
+ * live `mcbd-claude-*` session: 1000 rows, 480 truly empty, 7 more that LOOK empty
9
+ * but carry an SGR sequence (`ESC[49m`) and therefore survive a naive
10
+ * `grep -v '^$'` or `less -s`. Squeezing those runs is what makes `less +G` land
11
+ * on the composer instead of hundreds of rows below the last readable line.
12
+ *
13
+ * ## Relationship to the Web UI normalizer
14
+ *
15
+ * `src/lib/terminal/terminal-display-normalizer.ts` (Issue #1172) solves the same
16
+ * problem for the browser terminal and its rules are the ones reproduced here.
17
+ * This module exists as a separate entry point rather than importing that one
18
+ * because the CLI is compiled by `tsconfig.cli.json`, which sets `"paths": {}` —
19
+ * the normalizer's `@/lib/detection/ansi` import fails there with TS2307 (verified
20
+ * by adding the import and running `tsc --project tsconfig.cli.json`), while the
21
+ * relative import below resolves under every build. The two are held byte-identical
22
+ * by a conformance test over real captures
23
+ * (`tests/unit/lib/tmux/transcript-squeeze.test.ts`), so neither can drift.
24
+ *
25
+ * The transform is DISPLAY-ONLY. Nothing here touches the raw output that status
26
+ * detection, Auto-Yes, the response saver or the DB record consume — those keep
27
+ * full fidelity and full line counts.
28
+ */
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.isVisuallyBlank = isVisuallyBlank;
31
+ exports.squeezeTranscript = squeezeTranscript;
32
+ const ansi_1 = require("../detection/ansi");
33
+ /**
34
+ * A line is visually blank when nothing printable remains after ANSI removal.
35
+ *
36
+ * `.trim()` is deliberate: ECMAScript's WhiteSpace includes U+00A0, which the
37
+ * Claude composer emits (`ESC[38;5;246m❯ ESC[39m`). That line still holds
38
+ * `❯`, so it is content either way, but a row of pure NBSP correctly reads blank.
39
+ */
40
+ function isVisuallyBlank(line) {
41
+ return (0, ansi_1.stripAnsi)(line).trim() === '';
42
+ }
43
+ /**
44
+ * Collapse layout-only blank rows in a `capture-pane` frame.
45
+ *
46
+ * Rules (identical to `normalizeTerminalOutputForDisplay`, Issue #1172):
47
+ * 1. Blankness is judged on `stripAnsi(line).trim()`.
48
+ * 2. Leading and trailing blank runs are removed entirely.
49
+ * 3. An internal blank run of 1-2 rows is kept verbatim (real paragraph spacing).
50
+ * 4. An internal blank run of 3+ rows collapses to ONE row carrying that run's
51
+ * ANSI sequences in order, so a color/reset that spans the gap still applies
52
+ * to the rows below it.
53
+ * 5. Non-blank lines are never altered — content, order and duplicates survive.
54
+ *
55
+ * @param raw - Raw `capture-pane -pe` output
56
+ * @param options - Tail limit
57
+ * @returns The squeezed text plus before/after line counts
58
+ */
59
+ function squeezeTranscript(raw, options = {}) {
60
+ const lines = raw === '' ? [] : raw.split('\n');
61
+ const result = [];
62
+ let seenContent = false;
63
+ let i = 0;
64
+ while (i < lines.length) {
65
+ if (!isVisuallyBlank(lines[i])) {
66
+ result.push(lines[i]);
67
+ seenContent = true;
68
+ i++;
69
+ continue;
70
+ }
71
+ let j = i;
72
+ while (j < lines.length && isVisuallyBlank(lines[j]))
73
+ j++;
74
+ const isLeading = !seenContent;
75
+ const isTrailing = j >= lines.length;
76
+ if (!isLeading && !isTrailing) {
77
+ if (j - i <= 2) {
78
+ for (let k = i; k < j; k++)
79
+ result.push(lines[k]);
80
+ }
81
+ else {
82
+ result.push((0, ansi_1.extractAnsiSequences)(lines.slice(i, j).join('')));
83
+ }
84
+ }
85
+ i = j;
86
+ }
87
+ const tail = options.tail;
88
+ const tailed = tail !== undefined && tail > 0 && result.length > tail;
89
+ const kept = tailed ? result.slice(result.length - tail) : result;
90
+ return {
91
+ text: kept.join('\n'),
92
+ rawLines: lines.length,
93
+ lines: kept.length,
94
+ tailed,
95
+ };
96
+ }
@@ -319,6 +319,24 @@ app.prepare().then(() => {
319
319
  console.log(`> WebSocket server ready`);
320
320
  // Initialize worktrees after server starts
321
321
  await initializeWorktrees();
322
+ // Issue #1623: reconcile the `prefix+g` reading-mode binding on the user's
323
+ // tmux server. Fail-open in its own try/catch — a convenience key must never
324
+ // be able to stop the server from serving.
325
+ //
326
+ // Dynamic import, NOT a top-level static import, for the same reason as the
327
+ // reconcilers above: adding a module graph to server.ts's eval-time graph
328
+ // perturbs Next's AsyncLocalStorage bootstrap under `tsx server.ts`, and the
329
+ // first request that compiles middleware then dies. Do not hoist this.
330
+ try {
331
+ const { initReadMode } = await Promise.resolve().then(() => __importStar(require('./src/lib/tmux/read-mode')));
332
+ const readMode = await initReadMode();
333
+ if (readMode.installed) {
334
+ console.log(`Reading mode ready: press prefix+${readMode.key} in an attached CommandMate session`);
335
+ }
336
+ }
337
+ catch (error) {
338
+ console.error('Error initializing tmux reading mode:', error);
339
+ }
322
340
  // [S3-010] Initialize schedule manager AFTER worktrees are ready
323
341
  (0, schedule_manager_1.initScheduleManager)();
324
342
  // Issue #534: Initialize timer manager AFTER schedule manager
@@ -17,8 +17,40 @@
17
17
  * so `capture-pane` cost / render load stays reasonable.
18
18
  */
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.TUI_PANE_WIDTH = exports.TUI_PANE_HEIGHT = void 0;
20
+ exports.TMUX_HISTORY_LIMIT = exports.TUI_PANE_WIDTH = exports.TUI_PANE_HEIGHT = void 0;
21
21
  /** Fixed pane height (rows) for TUI sessions. Large enough to retain useful history. */
22
22
  exports.TUI_PANE_HEIGHT = 1000;
23
23
  /** Fixed pane width (columns) for TUI sessions. Matches the historical default. */
24
24
  exports.TUI_PANE_WIDTH = 200;
25
+ /**
26
+ * Scrollback lines retained per pane (`history-limit`), Issue #1624.
27
+ *
28
+ * Only NON-alternate-screen tools (codex / gemini / vibe-local / antigravity)
29
+ * consume this: the alternate-screen tools in `ALTERNATE_SCREEN_CLI_TOOLS`
30
+ * (claude / opencode / copilot) keep `history_size` at 0, so scrollback depth is
31
+ * irrelevant to them. See `usesAlternateScreen` in lib/cli-tools/types.ts.
32
+ *
33
+ * WHY 20000 and not the 50000 this used to request — measured on tmux 3.5a with
34
+ * a 200-column pane full of realistic, heavily-SGR-coloured agent output
35
+ * (274 bytes/line as re-emitted by `capture-pane -e`):
36
+ *
37
+ * 1. `capturePane` runs tmux under `execFile` with `maxBuffer: 10 MB`. A full
38
+ * 50000-line capture extrapolates to ~13 MB of escape-laden text, which
39
+ * OVERFLOWS that buffer and makes `capturePane` THROW rather than return a
40
+ * truncated string — i.e. the deepest part of a 50000-line buffer was never
41
+ * readable by this app in the first place. 20000 lines is ~5.2 MB, leaving
42
+ * roughly 2x headroom.
43
+ * 2. Nothing in the app reads deeper than 10000 lines by default (`capturePane`'s
44
+ * options-path default is `-S -10000`; every other call site asks for 1000 or
45
+ * fewer). 20000 keeps a 2x margin over the deepest default read.
46
+ * 3. Memory is charged per line ACTUALLY emitted, not preallocated from the
47
+ * limit: a fresh session cost ~0.3 MB of tmux-server RSS, growing to ~34 MB
48
+ * only after 45000 lines had scrolled (~0.68 KB/line). At 20000 a saturated
49
+ * pane costs ~14 MB, so 20 concurrent sessions cap out near 270 MB instead of
50
+ * the ~680 MB implied by 50000.
51
+ *
52
+ * This is still a 10x increase over tmux's built-in 2000, which is what sessions
53
+ * were actually getting before #1624 (a `mcbd-codex-*` session was observed at
54
+ * 1977/2000 lines used, i.e. actively losing transcript).
55
+ */
56
+ exports.TMUX_HISTORY_LIMIT = 20000;
@@ -119,10 +119,11 @@ class AntigravityTool extends base_1.BaseCLITool {
119
119
  try {
120
120
  // Create tmux session with large history buffer for agy output
121
121
  // (agy is inline-rendered and retains scrollback, like Codex)
122
+ // Scrollback depth comes from the shared TMUX_HISTORY_LIMIT default
123
+ // (Issue #1624) — do not re-hardcode it here.
122
124
  await (0, tmux_1.createSession)({
123
125
  sessionName,
124
126
  workingDirectory: worktreePath,
125
- historyLimit: 50000,
126
127
  });
127
128
  // Wait a moment for the session to be created
128
129
  await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_SESSION_CREATE_WAIT_MS));
@@ -67,11 +67,12 @@ class CodexTool extends base_1.BaseCLITool {
67
67
  return;
68
68
  }
69
69
  try {
70
- // Create tmux session with large history buffer for Codex output
70
+ // Create tmux session. Codex is inline-rendered, so its transcript lives in
71
+ // the pane scrollback — depth comes from the shared TMUX_HISTORY_LIMIT
72
+ // default (Issue #1624), do not re-hardcode it here.
71
73
  await (0, tmux_1.createSession)({
72
74
  sessionName,
73
75
  workingDirectory: worktreePath,
74
- historyLimit: 50000,
75
76
  });
76
77
  // Wait a moment for the session to be created
77
78
  await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_SESSION_CREATE_WAIT_MS));
@@ -113,11 +113,11 @@ class CopilotTool extends base_1.BaseCLITool {
113
113
  return;
114
114
  }
115
115
  try {
116
- // Create tmux session with large history buffer
116
+ // Create tmux session. Scrollback depth comes from the shared
117
+ // TMUX_HISTORY_LIMIT default (Issue #1624) — do not re-hardcode it here.
117
118
  await (0, tmux_1.createSession)({
118
119
  sessionName,
119
120
  workingDirectory: worktreePath,
120
- historyLimit: 50000,
121
121
  });
122
122
  // Wait a moment for the session to be created
123
123
  await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_SESSION_CREATE_WAIT_MS));
@@ -74,11 +74,11 @@ class GeminiTool extends base_1.BaseCLITool {
74
74
  return;
75
75
  }
76
76
  try {
77
- // Create tmux session with large history buffer
77
+ // Create tmux session. Scrollback depth comes from the shared
78
+ // TMUX_HISTORY_LIMIT default (Issue #1624) — do not re-hardcode it here.
78
79
  await (0, tmux_1.createSession)({
79
80
  sessionName,
80
81
  workingDirectory: worktreePath,
81
- historyLimit: 50000,
82
82
  });
83
83
  // Wait a moment for the session to be created
84
84
  await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_SESSION_CREATE_WAIT_MS));
@@ -89,11 +89,11 @@ class OpenCodeTool extends base_1.BaseCLITool {
89
89
  try {
90
90
  // Generate opencode.json if not present (non-fatal on failure)
91
91
  await (0, opencode_config_1.ensureOpencodeConfig)(worktreePath);
92
- // Create tmux session with large history buffer
92
+ // Create tmux session. Scrollback depth comes from the shared
93
+ // TMUX_HISTORY_LIMIT default (Issue #1624) — do not re-hardcode it here.
93
94
  await (0, tmux_1.createSession)({
94
95
  sessionName,
95
96
  workingDirectory: worktreePath,
96
- historyLimit: 50000,
97
97
  });
98
98
  // Wait a moment for the session to be created
99
99
  await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_SESSION_CREATE_WAIT_MS));
@@ -66,11 +66,11 @@ class VibeLocalTool extends base_1.BaseCLITool {
66
66
  return;
67
67
  }
68
68
  try {
69
- // Create tmux session with large history buffer
69
+ // Create tmux session. Scrollback depth comes from the shared
70
+ // TMUX_HISTORY_LIMIT default (Issue #1624) — do not re-hardcode it here.
70
71
  await (0, tmux_1.createSession)({
71
72
  sessionName,
72
73
  workingDirectory: worktreePath,
73
- historyLimit: 50000,
74
74
  });
75
75
  // Wait a moment for the session to be created
76
76
  await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_SESSION_CREATE_WAIT_MS));
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.InvalidAgentInstanceError = exports.AgentInstanceLimitError = void 0;
16
16
  exports.getAgentInstances = getAgentInstances;
17
17
  exports.getAgentInstance = getAgentInstance;
18
+ exports.resolveInstanceCliTool = resolveInstanceCliTool;
18
19
  exports.countAgentInstances = countAgentInstances;
19
20
  exports.setAgentInstances = setAgentInstances;
20
21
  exports.addAgentInstance = addAgentInstance;
@@ -103,6 +104,58 @@ function getAgentInstance(db, worktreeId, instanceId) {
103
104
  `).get(worktreeId, instanceId);
104
105
  return row ? mapAgentInstance(row) : null;
105
106
  }
107
+ /**
108
+ * Resolve which CLI tool backs a targeted agent instance (Issue #1629).
109
+ *
110
+ * The CLI tool id is part of the tmux session name, so getting it wrong starts
111
+ * (or looks for) the wrong agent under a session name that claims otherwise:
112
+ * `--instance codex` used to start Claude in `mcbd-claude-<wt>-codex`.
113
+ *
114
+ * Resolution order:
115
+ * 1. the roster entry for `instanceId` — the roster is what declares that
116
+ * `codex` is a codex instance, so it wins over the worktree default
117
+ * 2. `requestedCliTool`, for an instance the roster does not know about
118
+ * (the ad-hoc `send --instance <new-id>` / `--register` flow)
119
+ * 3. `instanceId` when it is itself a CLI tool id — that is how the primary
120
+ * instance is anchored (Issue #868), and holds without a roster row
121
+ * 4. no signal (`cliToolId: null`) — the caller falls back to its default
122
+ *
123
+ * An explicit `requestedCliTool` that contradicts the roster is reported as a
124
+ * conflict rather than silently overriding it: the roster is user-maintained
125
+ * and a mismatch means one of the two is wrong. Callers surface it as an error.
126
+ *
127
+ * @param db - Database instance
128
+ * @param worktreeId - Worktree ID
129
+ * @param instanceId - Targeted agent instance ID (omitted for the primary instance)
130
+ * @param requestedCliTool - CLI tool explicitly named by the caller, if any
131
+ */
132
+ function resolveInstanceCliTool(db, worktreeId, instanceId, requestedCliTool) {
133
+ if (!instanceId) {
134
+ return { ok: true, cliToolId: requestedCliTool ?? null };
135
+ }
136
+ const registered = getAgentInstance(db, worktreeId, instanceId);
137
+ if (registered && (0, types_1.isCliToolType)(registered.cliTool)) {
138
+ if (requestedCliTool && requestedCliTool !== registered.cliTool) {
139
+ return {
140
+ ok: false,
141
+ instanceId,
142
+ rosterCliTool: registered.cliTool,
143
+ requestedCliTool,
144
+ };
145
+ }
146
+ return { ok: true, cliToolId: registered.cliTool };
147
+ }
148
+ // Not registered: an instance id that names a CLI tool is that tool's primary
149
+ // instance by definition, which outranks the worktree default but not an
150
+ // explicit request.
151
+ if (requestedCliTool) {
152
+ return { ok: true, cliToolId: requestedCliTool };
153
+ }
154
+ if ((0, types_1.isCliToolType)(instanceId)) {
155
+ return { ok: true, cliToolId: instanceId };
156
+ }
157
+ return { ok: true, cliToolId: null };
158
+ }
106
159
  /**
107
160
  * Count agent instances for a worktree.
108
161
  */
@@ -35,6 +35,7 @@ const v48_skill_operations_audit_index_1 = require("./v48-skill-operations-audit
35
35
  const v49_verification_runs_1 = require("./v49-verification-runs");
36
36
  const v50_tasks_1 = require("./v50-tasks");
37
37
  const v51_task_events_1 = require("./v51-task-events");
38
+ const v52_orphaned_worktree_children_1 = require("./v52-orphaned-worktree-children");
38
39
  /**
39
40
  * Complete ordered list of all migrations.
40
41
  * Used internally by the barrel file (db-migrations.ts); NOT exported from the barrel (DR2-004).
@@ -73,4 +74,5 @@ exports.migrations = [
73
74
  ...v49_verification_runs_1.v49_migrations,
74
75
  ...v50_tasks_1.v50_migrations,
75
76
  ...v51_task_events_1.v51_migrations,
77
+ ...v52_orphaned_worktree_children_1.v52_migrations,
76
78
  ];
@@ -17,7 +17,7 @@ const path_1 = __importDefault(require("path"));
17
17
  * Current schema version
18
18
  * Increment this when adding new migrations
19
19
  */
20
- exports.CURRENT_SCHEMA_VERSION = 51;
20
+ exports.CURRENT_SCHEMA_VERSION = 52;
21
21
  /**
22
22
  * Get current schema version from database
23
23
  */
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ /**
3
+ * Migration v52: delete child rows pointing at a worktree that no longer exists
4
+ * (Issue #1621, Phase 0).
5
+ *
6
+ * `getWorktreeChildTables` used to enumerate child tables from foreign-key
7
+ * metadata alone, so `tasks` (#1548), `verification_runs` (#1544) and
8
+ * `skill_operations` (#1428) — each holding a `worktree_id` with no constraint
9
+ * declared — were invisible to both the rename path and the delete path. No
10
+ * CASCADE fires without a foreign key, so every worktree deleted since those
11
+ * tables landed left their rows behind, and every worktree ID rename left them
12
+ * addressing an ID nothing resolves. The code fix stops new orphans; this
13
+ * migration removes the ones already written.
14
+ *
15
+ * The sweep reuses the shared enumeration rather than naming tables, so the
16
+ * FK-less tables above and the FK-declared ones are treated identically — an
17
+ * orphan in a CASCADE table is equally unreachable, it just needed a
18
+ * `foreign_keys = OFF` window to be created.
19
+ *
20
+ * Three deliberate narrowings:
21
+ *
22
+ * - Append-only ledgers are excluded (`getDeletableWorktreeChildTables`).
23
+ * `skill_operations` holds a `worktree_id` and does have rows referencing
24
+ * worktrees that are gone, but it declares `BEFORE DELETE ... RAISE(ABORT)`
25
+ * (#1234) and is read across every worktree by the audit feed. Deleting from
26
+ * it aborts the statement, which here would roll back the migration and take
27
+ * startup with it (measured). Its rows are history, not orphans.
28
+ * - `worktree_id IS NULL` rows are left alone. Every current child table
29
+ * declares the column NOT NULL, so this cannot fire today; if a future table
30
+ * makes it nullable, a NULL means "not attached", not "attached to something
31
+ * gone", and deleting it would be data loss rather than cleanup.
32
+ * - `verification_gate_results` has no `worktree_id` and is not swept directly.
33
+ * It reaches its worktree through `verification_runs(id) ON DELETE CASCADE`,
34
+ * so deleting the orphaned runs takes its rows with them (better-sqlite3
35
+ * enables `foreign_keys` by default, and db-instance.ts sets it explicitly).
36
+ * `task_events` is *not* in the same position: v51 declares no foreign key to
37
+ * `tasks` on purpose, because history that vanishes with its subject cannot
38
+ * be audited afterwards. That is a design choice, not an orphan, so it stays.
39
+ */
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.v52_migrations = void 0;
42
+ const worktree_child_tables_1 = require("./worktree-child-tables");
43
+ exports.v52_migrations = [
44
+ {
45
+ version: 52,
46
+ name: 'delete-orphaned-worktree-children',
47
+ up: (db) => {
48
+ let deleted = 0;
49
+ for (const { table, column } of (0, worktree_child_tables_1.getDeletableWorktreeChildTables)(db)) {
50
+ // Identifiers come from sqlite_master / PRAGMA, never from user input.
51
+ // The alias is `cm_parent` rather than something short like `w` so it
52
+ // cannot collide with a child table that happens to be named the same.
53
+ const result = db
54
+ .prepare(`DELETE FROM "${table}"
55
+ WHERE "${column}" IS NOT NULL
56
+ AND NOT EXISTS (
57
+ SELECT 1 FROM worktrees AS cm_parent
58
+ WHERE cm_parent.id = "${table}"."${column}"
59
+ )`)
60
+ .run();
61
+ if (result.changes > 0) {
62
+ console.log(`Deleted ${result.changes} orphaned row(s) from ${table}.${column}`);
63
+ deleted += result.changes;
64
+ }
65
+ }
66
+ if (deleted === 0) {
67
+ console.log('No orphaned worktree child rows found');
68
+ }
69
+ },
70
+ down: () => {
71
+ // Deleted rows cannot be resurrected. Defined anyway so rollback tooling
72
+ // (and the tests that rebuild a v51 database) keep working.
73
+ console.log('No rollback for orphaned child row cleanup (rows are gone)');
74
+ },
75
+ },
76
+ ];
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ /**
3
+ * Live-schema introspection for "which tables reference a worktree".
4
+ *
5
+ * Lives under `migrations/` rather than next to `worktree-db.ts` because the
6
+ * dependency has to point this way: migration v52 sweeps orphans with the same
7
+ * enumeration the runtime uses, and a migration that imports `worktree-db.ts`
8
+ * inherits every mock of it — `vi.mock('@/lib/db/worktree-db')` in an unrelated
9
+ * suite made `runMigrations` throw `No "getDeletableWorktreeChildTables" export
10
+ * is defined` (measured across 5 tests). Schema introspection is the more
11
+ * foundational of the two, so it is what the other side imports.
12
+ *
13
+ * Issue #1621.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.getWorktreeChildTables = getWorktreeChildTables;
17
+ exports.getWriteGuardedTables = getWriteGuardedTables;
18
+ exports.getDeletableWorktreeChildTables = getDeletableWorktreeChildTables;
19
+ /** Conventional name of the column holding a worktree reference. */
20
+ const WORKTREE_REFERENCE_COLUMN = 'worktree_id';
21
+ /**
22
+ * Discover every table that references a worktree, along with the referencing
23
+ * column. Derived dynamically from the live schema so it never drifts out of
24
+ * sync with future migrations that add child tables.
25
+ *
26
+ * Two sources are unioned:
27
+ *
28
+ * 1. a `worktree_id` column, **whether or not** the table declares a foreign key
29
+ * 2. a declared foreign key to `worktrees(id)`, whatever the column is named
30
+ *
31
+ * Source 1 is what Issue #1621 adds. FK metadata alone (all this did before)
32
+ * silently skipped `tasks` (#1548), `verification_runs` (#1544) and
33
+ * `skill_operations` (#1428): all three carry a `worktree_id` but declare no
34
+ * constraint, so a rename left them pointing at an ID that no longer exists and
35
+ * a delete left them behind as orphans — no CASCADE fires without a FK.
36
+ *
37
+ * Source 2 is kept so a future table whose FK column is *not* named
38
+ * `worktree_id` keeps being followed; dropping it would be a regression for
39
+ * every table #1151 already handled.
40
+ *
41
+ * Issue #1151, #1621.
42
+ */
43
+ function getWorktreeChildTables(db) {
44
+ const tables = db
45
+ .prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'")
46
+ .all();
47
+ const children = [];
48
+ const seen = new Set();
49
+ const add = (table, column) => {
50
+ // JSON encoding keeps the pair unambiguous whatever the identifiers contain.
51
+ const key = JSON.stringify([table, column]);
52
+ if (seen.has(key))
53
+ return;
54
+ seen.add(key);
55
+ children.push({ table, column });
56
+ };
57
+ for (const { name: tableName } of tables) {
58
+ if (tableName === 'worktrees')
59
+ continue;
60
+ // PRAGMA identifiers cannot be bound; `tableName` comes from sqlite_master,
61
+ // not user input, so string interpolation here is safe.
62
+ const columns = db.prepare(`PRAGMA table_info("${tableName}")`).all();
63
+ if (columns.some((column) => column.name === WORKTREE_REFERENCE_COLUMN)) {
64
+ add(tableName, WORKTREE_REFERENCE_COLUMN);
65
+ }
66
+ const fks = db.prepare(`PRAGMA foreign_key_list("${tableName}")`).all();
67
+ for (const fk of fks) {
68
+ if (fk.table === 'worktrees' && (fk.to === 'id' || fk.to === null)) {
69
+ add(tableName, fk.from);
70
+ }
71
+ }
72
+ }
73
+ return children;
74
+ }
75
+ /**
76
+ * Tables the schema itself refuses to let us rewrite, per statement kind.
77
+ *
78
+ * An append-only ledger enforces itself with a `BEFORE UPDATE` / `BEFORE DELETE`
79
+ * trigger that calls `RAISE(ABORT, ...)`; `skill_operations` declares both
80
+ * (#1234, migrations v44/v48). Such a table carries a `worktree_id` yet is
81
+ * deliberately *not* owned by its worktree's lifetime: `querySkillOperationAudit`
82
+ * reads it across every worktree for the dashboard feed, exactly like v51 keeps
83
+ * `task_events` alive after its task is gone. Sweeping it is not cleanup, it is
84
+ * destroying audit history — and it does not even fail safely: the trigger
85
+ * aborts the statement, which rolls back the whole enclosing transaction, so a
86
+ * blind sweep breaks worktree deletion outright (measured: `deleteWorktreesByIds`
87
+ * threw `skill_operations is append-only` and the worktree row survived; the
88
+ * same sweep inside migration v52 fails startup).
89
+ *
90
+ * Detected from trigger SQL rather than by table name so a future ledger is
91
+ * protected the moment it declares its guard (Issue #1621).
92
+ */
93
+ function getWriteGuardedTables(db) {
94
+ const triggers = db
95
+ .prepare("SELECT tbl_name, sql FROM sqlite_master WHERE type = 'trigger'")
96
+ .all();
97
+ const noUpdate = new Set();
98
+ const noDelete = new Set();
99
+ for (const trigger of triggers) {
100
+ if (!trigger.sql)
101
+ continue;
102
+ if (!/\bRAISE\s*\(\s*ABORT/i.test(trigger.sql))
103
+ continue;
104
+ if (/\bBEFORE\s+UPDATE\b/i.test(trigger.sql))
105
+ noUpdate.add(trigger.tbl_name);
106
+ if (/\bBEFORE\s+DELETE\b/i.test(trigger.sql))
107
+ noDelete.add(trigger.tbl_name);
108
+ }
109
+ return { noUpdate, noDelete };
110
+ }
111
+ /**
112
+ * Child tables whose rows a worktree actually owns — everything
113
+ * getWorktreeChildTables reports, minus the append-only ledgers that outlive it.
114
+ * This is the set a delete or an orphan sweep may touch (Issue #1621).
115
+ */
116
+ function getDeletableWorktreeChildTables(db) {
117
+ const { noDelete } = getWriteGuardedTables(db);
118
+ return getWorktreeChildTables(db).filter(({ table }) => !noDelete.has(table));
119
+ }
@@ -13,13 +13,14 @@
13
13
  * failure `verification-db.ts` guards against.
14
14
  */
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.ACTIVE_TASK_STATUSES = exports.TERMINAL_TASK_STATUSES = exports.TASK_STATUSES = void 0;
16
+ exports.VERIFIABLE_TASK_STATUSES = exports.ACTIVE_TASK_STATUSES = exports.TERMINAL_TASK_STATUSES = exports.TASK_STATUSES = void 0;
17
17
  exports.isTerminalTaskStatus = isTerminalTaskStatus;
18
18
  exports.createTask = createTask;
19
19
  exports.getTask = getTask;
20
20
  exports.listTasks = listTasks;
21
21
  exports.updateTaskStatus = updateTaskStatus;
22
22
  exports.getActiveTask = getActiveTask;
23
+ exports.getVerifiableTask = getVerifiableTask;
23
24
  exports.getActiveTaskForInstance = getActiveTaskForInstance;
24
25
  const crypto_1 = require("crypto");
25
26
  /**
@@ -61,6 +62,27 @@ exports.ACTIVE_TASK_STATUSES = [
61
62
  'waiting_input',
62
63
  'verifying',
63
64
  ];
65
+ /**
66
+ * Statuses a verification run that has to *discover* its task may attach to.
67
+ *
68
+ * The active three plus the two the state machine explicitly reopens:
69
+ * `transitionTask` accepts `verify_started` from `failed` and `not_started`
70
+ * because a task can fail on one run and pass on the retry. Resolving only the
71
+ * active three meant that reopening was reachable only by a caller that already
72
+ * knew the task id — so the retry every agent performs after a red gate found
73
+ * no contract, and with it no scope to judge (#1620).
74
+ *
75
+ * `succeeded` and `cancelled` stay out: those are closed for good, and a run
76
+ * that silently adopted one would be judging work against a verdict already
77
+ * given. {@link ACTIVE_TASK_STATUSES} keeps its narrower meaning for the
78
+ * callers that ask "what is this agent working on right now" (Auto-Yes, prompt
79
+ * events), where a finished task must not answer.
80
+ */
81
+ exports.VERIFIABLE_TASK_STATUSES = [
82
+ ...exports.ACTIVE_TASK_STATUSES,
83
+ 'failed',
84
+ 'not_started',
85
+ ];
64
86
  function isTerminalTaskStatus(status) {
65
87
  return exports.TERMINAL_TASK_STATUSES.includes(status);
66
88
  }
@@ -185,6 +207,29 @@ function getActiveTask(db, worktreeId, cliToolId, instanceId) {
185
207
  .get(...params, ...exports.ACTIVE_TASK_STATUSES);
186
208
  return row ? mapTaskRow(row) : null;
187
209
  }
210
+ /**
211
+ * The task a verification run should attach to when the caller cannot name one.
212
+ *
213
+ * Worktree-scoped for the same reason {@link getActiveTask} is: the gates run
214
+ * over the whole working tree, so there is nothing finer to narrow by. Ordered
215
+ * like {@link getActiveTask} — most recently updated first, insertion order
216
+ * breaking a same-millisecond tie — so the answer is the last task to have
217
+ * moved, not whichever row SQLite happened to reach first.
218
+ *
219
+ * @see VERIFIABLE_TASK_STATUSES for why this is wider than "active"
220
+ */
221
+ function getVerifiableTask(db, worktreeId) {
222
+ const placeholders = exports.VERIFIABLE_TASK_STATUSES.map(() => '?').join(', ');
223
+ const row = db
224
+ .prepare(`
225
+ SELECT ${TASK_COLUMNS} FROM tasks
226
+ WHERE worktree_id = ? AND status IN (${placeholders})
227
+ ORDER BY updated_at DESC, created_at DESC, rowid DESC
228
+ LIMIT 1
229
+ `)
230
+ .get(worktreeId, ...exports.VERIFIABLE_TASK_STATUSES);
231
+ return row ? mapTaskRow(row) : null;
232
+ }
188
233
  /**
189
234
  * The active task governing one agent instance, or null.
190
235
  *