commandmate 0.47.2 → 0.49.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 (434) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +180 -180
  3. package/.next/app-path-routes-manifest.json +30 -30
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/prerender-manifest.json +9 -9
  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/release-notes/route_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/app/update/route.js +3 -3
  12. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/capabilities/route.js +1 -1
  18. package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  22. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  24. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  25. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/hooks/agent-event/route.js +2 -2
  27. package/.next/server/app/api/hooks/agent-event/route.js.nft.json +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.js +2 -2
  30. package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
  31. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/hooks/permission-request/route.js +1 -1
  33. package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
  34. package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  37. package/.next/server/app/api/push/escalation/route.js +1 -1
  38. package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  40. package/.next/server/app/api/push/vapid/route.js +1 -1
  41. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  42. package/.next/server/app/api/relays/[relayId]/cancel/route.js +1 -1
  43. package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
  44. package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
  45. package/.next/server/app/api/relays/route.js +1 -1
  46. package/.next/server/app/api/relays/route.js.nft.json +1 -1
  47. package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
  48. package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
  49. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  50. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  51. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
  52. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  53. package/.next/server/app/api/repositories/clone/route.js +1 -1
  54. package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
  55. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  57. package/.next/server/app/api/repositories/restore/route.js +1 -1
  58. package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
  59. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  60. package/.next/server/app/api/repositories/route.js +1 -1
  61. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  62. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  63. package/.next/server/app/api/repositories/scan/route.js +1 -1
  64. package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
  65. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  66. package/.next/server/app/api/repositories/sync/route.js +1 -1
  67. package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
  68. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  70. package/.next/server/app/api/settings/default-agents/route.js +1 -1
  71. package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
  72. package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
  73. package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
  74. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  75. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  76. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  78. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  79. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  80. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  81. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  82. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  83. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  84. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  85. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  86. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  87. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  88. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  89. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  90. package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
  91. package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
  92. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  93. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
  94. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
  95. package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
  96. package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
  97. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  98. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  99. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  100. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  101. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/worktrees/[id]/direct-input/route.js +1 -1
  103. package/.next/server/app/api/worktrees/[id]/direct-input/route.js.nft.json +1 -1
  104. package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
  105. package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
  106. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  107. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  108. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  109. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  110. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  111. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  112. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  113. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  114. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  115. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  116. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  117. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  118. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  120. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  121. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  122. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  124. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  127. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  129. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  130. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  132. package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
  133. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
  135. package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
  136. package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
  137. package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
  138. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  139. package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
  141. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  142. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  146. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  148. package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
  149. package/.next/server/app/api/worktrees/[id]/opencode/session/route.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/opencode/session/route.js.nft.json +1 -1
  151. package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
  152. package/.next/server/app/api/worktrees/[id]/opencode/share/route.js +1 -1
  153. package/.next/server/app/api/worktrees/[id]/opencode/share/route.js.nft.json +1 -1
  154. package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
  155. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
  157. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  158. package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route.js +1 -1
  159. package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route.js.nft.json +1 -1
  160. package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route_client-reference-manifest.js +1 -1
  161. package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
  162. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
  163. package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
  164. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  165. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  166. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  167. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  168. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  170. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  171. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
  173. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  174. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  175. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +3 -3
  176. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
  177. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  178. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  179. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  180. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  181. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  182. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  183. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  184. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  185. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  186. package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
  187. package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
  188. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  189. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  190. package/.next/server/app/api/worktrees/[id]/terminal/route.js +1 -103
  191. package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
  192. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  193. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  194. package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
  195. package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
  196. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  197. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  198. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  199. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  200. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  201. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  202. package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
  203. package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -1
  204. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  205. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js +1 -1
  206. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
  207. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  208. package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
  209. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  210. package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
  211. package/.next/server/app/api/worktrees/route.js +1 -1
  212. package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
  213. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  214. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  215. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  216. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  217. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  218. package/.next/server/app/page_client-reference-manifest.js +1 -1
  219. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  220. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  221. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  222. package/.next/server/app/sessions/page.js +1 -1
  223. package/.next/server/app/sessions/page.js.nft.json +1 -1
  224. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  225. package/.next/server/app/skills/[skillId]/page.js +1 -1
  226. package/.next/server/app/skills/[skillId]/page.js.nft.json +1 -1
  227. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  228. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  229. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  230. package/.next/server/app/worktrees/[id]/files/[...path]/page.js +2 -2
  231. package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +1 -1
  232. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  233. package/.next/server/app/worktrees/[id]/page.js +12 -12
  234. package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
  235. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  236. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  237. package/.next/server/app-paths-manifest.json +30 -30
  238. package/.next/server/chunks/1191.js +11 -4
  239. package/.next/server/chunks/1501.js +1 -1
  240. package/.next/server/chunks/1601.js +2 -2
  241. package/.next/server/chunks/1656.js +2 -2
  242. package/.next/server/chunks/1945.js +3 -3
  243. package/.next/server/chunks/1990.js +103 -0
  244. package/.next/server/chunks/2069.js +1 -0
  245. package/.next/server/chunks/2119.js +1 -1
  246. package/.next/server/chunks/2404.js +1 -1
  247. package/.next/server/chunks/2422.js +1 -1
  248. package/.next/server/chunks/2445.js +1 -1
  249. package/.next/server/chunks/2534.js +1 -1
  250. package/.next/server/chunks/255.js +1 -1
  251. package/.next/server/chunks/3241.js +1 -1
  252. package/.next/server/chunks/3505.js +2 -2
  253. package/.next/server/chunks/4243.js +1 -1
  254. package/.next/server/chunks/4248.js +1 -1
  255. package/.next/server/chunks/4280.js +1 -0
  256. package/.next/server/chunks/5209.js +1 -1
  257. package/.next/server/chunks/6119.js +1 -1
  258. package/.next/server/chunks/6130.js +1 -1
  259. package/.next/server/chunks/6401.js +1 -1
  260. package/.next/server/chunks/6486.js +9 -8
  261. package/.next/server/chunks/6781.js +1 -1
  262. package/.next/server/chunks/720.js +103 -0
  263. package/.next/server/chunks/7604.js +2 -0
  264. package/.next/server/chunks/7905.js +1 -1
  265. package/.next/server/chunks/8581.js +8 -8
  266. package/.next/server/chunks/8728.js +3 -3
  267. package/.next/server/chunks/8791.js +1 -1
  268. package/.next/server/chunks/8807.js +19 -18
  269. package/.next/server/chunks/8918.js +2 -104
  270. package/.next/server/chunks/936.js +1 -1
  271. package/.next/server/chunks/9390.js +1 -1
  272. package/.next/server/chunks/9540.js +1 -1
  273. package/.next/server/chunks/9627.js +5 -5
  274. package/.next/server/chunks/9731.js +2 -2
  275. package/.next/server/middleware-manifest.json +5 -5
  276. package/.next/server/pages/500.html +1 -1
  277. package/.next/server/server-reference-manifest.json +1 -1
  278. package/.next/static/chunks/1128-914c559913546bbc.js +1 -0
  279. package/.next/static/chunks/{2407-a6533805a86d05bd.js → 2407-ab92ae9837c39dce.js} +1 -1
  280. package/.next/static/chunks/{2863-6a07ec82fb52f4dd.js → 2863-7173dc305dffc4f6.js} +1 -1
  281. package/.next/static/chunks/6288-6fadbba6e84393b2.js +1 -0
  282. package/.next/static/chunks/7665-e9ef6e0a85b9fa49.js +1 -0
  283. package/.next/static/chunks/8407-35bbfc84793d7004.js +1 -0
  284. package/.next/static/chunks/9079-987939d231704218.js +1 -0
  285. package/.next/static/chunks/app/{layout-538d8d2746ad1588.js → layout-aa8e66164a4367af.js} +1 -1
  286. package/.next/static/chunks/app/sessions/page-cfd645305e25fd33.js +1 -0
  287. package/.next/static/chunks/app/skills/[skillId]/{page-52ba58712faf3378.js → page-cb6e74fd9a6a571d.js} +1 -1
  288. package/.next/static/chunks/app/worktrees/[id]/files/[...path]/page-704086656fb45699.js +1 -0
  289. package/.next/static/chunks/app/worktrees/[id]/page-a8d7886703ffc7b4.js +1 -0
  290. package/.next/static/css/{743f79ff19ab91e9.css → db8959555c3d9c96.css} +1 -1
  291. package/.next/trace +13 -13
  292. package/dist/cli/commands/auto-yes.d.ts +24 -0
  293. package/dist/cli/commands/auto-yes.d.ts.map +1 -1
  294. package/dist/cli/commands/auto-yes.js +76 -8
  295. package/dist/cli/commands/capture.d.ts.map +1 -1
  296. package/dist/cli/commands/capture.js +5 -0
  297. package/dist/cli/commands/instances.d.ts.map +1 -1
  298. package/dist/cli/commands/instances.js +10 -1
  299. package/dist/cli/commands/prompt.d.ts.map +1 -1
  300. package/dist/cli/commands/prompt.js +5 -3
  301. package/dist/cli/commands/send.d.ts.map +1 -1
  302. package/dist/cli/commands/send.js +19 -6
  303. package/dist/cli/commands/verify.d.ts.map +1 -1
  304. package/dist/cli/commands/verify.js +8 -1
  305. package/dist/cli/commands/wait.d.ts.map +1 -1
  306. package/dist/cli/commands/wait.js +101 -13
  307. package/dist/cli/config/duration-constants.d.ts +16 -13
  308. package/dist/cli/config/duration-constants.d.ts.map +1 -1
  309. package/dist/cli/config/duration-constants.js +21 -21
  310. package/dist/cli/docs/agent-operations.d.ts +2 -2
  311. package/dist/cli/docs/agent-operations.d.ts.map +1 -1
  312. package/dist/cli/docs/agent-operations.js +29 -1
  313. package/dist/cli/types/api-responses.d.ts +145 -3
  314. package/dist/cli/types/api-responses.d.ts.map +1 -1
  315. package/dist/cli/types/index.d.ts +4 -0
  316. package/dist/cli/types/index.d.ts.map +1 -1
  317. package/dist/cli/utils/resource-resolvers.d.ts +0 -18
  318. package/dist/cli/utils/resource-resolvers.d.ts.map +1 -1
  319. package/dist/cli/utils/resource-resolvers.js +1 -51
  320. package/dist/cli/utils/verify-runner.d.ts +24 -1
  321. package/dist/cli/utils/verify-runner.d.ts.map +1 -1
  322. package/dist/cli/utils/verify-runner.js +54 -1
  323. package/dist/config/auto-yes-duration.d.ts +56 -0
  324. package/dist/config/auto-yes-duration.d.ts.map +1 -0
  325. package/dist/config/auto-yes-duration.js +76 -0
  326. package/dist/lib/polling/auto-yes-suppression-reason.d.ts +54 -2
  327. package/dist/lib/polling/auto-yes-suppression-reason.d.ts.map +1 -1
  328. package/dist/lib/polling/auto-yes-suppression-reason.js +33 -2
  329. package/dist/lib/prompt-observation/types.d.ts +13 -0
  330. package/dist/lib/prompt-observation/types.d.ts.map +1 -1
  331. package/dist/server/locales/en/worktree.json +2 -1
  332. package/dist/server/locales/ja/worktree.json +2 -1
  333. package/dist/server/src/config/auto-yes-config.js +14 -19
  334. package/dist/server/src/config/auto-yes-duration.js +76 -0
  335. package/dist/server/src/lib/auto-yes-poller-answer-target.js +38 -0
  336. package/dist/server/src/lib/auto-yes-poller-keys.js +35 -0
  337. package/dist/server/src/lib/auto-yes-poller-session-presence.js +26 -0
  338. package/dist/server/src/lib/auto-yes-poller-tick.js +233 -0
  339. package/dist/server/src/lib/auto-yes-poller.js +337 -376
  340. package/dist/server/src/lib/auto-yes-state.js +59 -4
  341. package/dist/server/src/lib/cli-tools/submit-verified-sender.js +235 -19
  342. package/dist/server/src/lib/db/chat-db.js +5 -1
  343. package/dist/server/src/lib/db/verification-db.js +23 -2
  344. package/dist/server/src/lib/detection/composer-text.js +215 -11
  345. package/dist/server/src/lib/detection/option-recommendation.js +120 -0
  346. package/dist/server/src/lib/detection/prompt-detect-multiple-choice-approval-context.js +290 -0
  347. package/dist/server/src/lib/detection/prompt-detect-multiple-choice-chrome.js +193 -0
  348. package/dist/server/src/lib/detection/prompt-detect-multiple-choice.js +402 -539
  349. package/dist/server/src/lib/detection/prompt-detector.js +92 -21
  350. package/dist/server/src/lib/detection/prompt-screen-key.js +60 -0
  351. package/dist/server/src/lib/detection/tools/antigravity/dialog.js +158 -35
  352. package/dist/server/src/lib/detection/tools/claude/detect.js +111 -10
  353. package/dist/server/src/lib/detection/tools/command-code/dialog.js +67 -0
  354. package/dist/server/src/lib/detection/tools/dialog-block.js +16 -0
  355. package/dist/server/src/lib/detection/upstream-faults.js +19 -2
  356. package/dist/server/src/lib/detection/waiting-screen-reading.js +98 -0
  357. package/dist/server/src/lib/hooks/permission-decision-service.js +7 -0
  358. package/dist/server/src/lib/hooks/structured-decision-response.js +1 -1
  359. package/dist/server/src/lib/polling/auto-yes-confirm-page.js +2 -2
  360. package/dist/server/src/lib/polling/auto-yes-confirmation-ledger-types.js +3 -0
  361. package/dist/server/src/lib/polling/auto-yes-confirmation-ledger.js +34 -3
  362. package/dist/server/src/lib/polling/auto-yes-decision-state.js +195 -0
  363. package/dist/server/src/lib/polling/auto-yes-dialog-gate.js +139 -10
  364. package/dist/server/src/lib/polling/auto-yes-enter-fallback.js +14 -0
  365. package/dist/server/src/lib/polling/auto-yes-manual-answer.js +124 -0
  366. package/dist/server/src/lib/polling/auto-yes-option-effect.js +157 -0
  367. package/dist/server/src/lib/polling/auto-yes-policy.js +11 -5
  368. package/dist/server/src/lib/polling/auto-yes-poller-capture.js +15 -2
  369. package/dist/server/src/lib/polling/auto-yes-poller-generation.js +42 -1
  370. package/dist/server/src/lib/polling/auto-yes-poller-receipt-log.js +42 -5
  371. package/dist/server/src/lib/polling/auto-yes-poller-state.js +147 -49
  372. package/dist/server/src/lib/polling/auto-yes-poller-steps.js +172 -2
  373. package/dist/server/src/lib/polling/auto-yes-prompt-suppression.js +2 -2
  374. package/dist/server/src/lib/polling/auto-yes-question-choice.js +57 -0
  375. package/dist/server/src/lib/polling/auto-yes-resolver.js +96 -21
  376. package/dist/server/src/lib/polling/auto-yes-suppression-reason.js +33 -2
  377. package/dist/server/src/lib/polling/auto-yes-suppression-state.js +25 -1
  378. package/dist/server/src/lib/polling/prompt-screen-reading.js +232 -0
  379. package/dist/server/src/lib/polling/response-checker-dialog-gate.js +39 -0
  380. package/dist/server/src/lib/polling/response-checker.js +145 -58
  381. package/dist/server/src/lib/prompt-answer-sender.js +104 -10
  382. package/dist/server/src/lib/push/notification-dedup.js +15 -2
  383. package/dist/server/src/lib/push/prompt-card-state.js +140 -19
  384. package/dist/server/src/lib/push/prompt-push-gate.js +158 -12
  385. package/dist/server/src/lib/push/push-sender.js +23 -3
  386. package/dist/server/src/lib/push/resolution-push-notifier.js +14 -0
  387. package/dist/server/src/lib/push/waiting-push-notifier.js +139 -17
  388. package/dist/server/src/lib/realtime/terminal-broadcast.js +16 -0
  389. package/dist/server/src/lib/session/agent-event-state.js +25 -5
  390. package/dist/server/src/lib/session/agent-event-turn.js +140 -46
  391. package/dist/server/src/lib/session/cli-session.js +21 -2
  392. package/dist/server/src/lib/session/composer-clear.js +56 -4
  393. package/dist/server/src/lib/session/current-output-builder.js +66 -12
  394. package/dist/server/src/lib/session/send-attempt-state.js +24 -7
  395. package/dist/server/src/lib/session/waiting-episode-binding-observation.js +289 -0
  396. package/dist/server/src/lib/session/waiting-episode-binding-resolve.js +38 -0
  397. package/dist/server/src/lib/session/waiting-episode-binding.js +276 -0
  398. package/dist/server/src/lib/session/waiting-episode-state-ops.js +152 -0
  399. package/dist/server/src/lib/session/waiting-episode-state-store.js +202 -0
  400. package/dist/server/src/lib/session/waiting-episode-state-types.js +6 -0
  401. package/dist/server/src/lib/session/waiting-episode-state.js +68 -91
  402. package/dist/server/src/lib/session/waiting-episode-verdict.js +174 -0
  403. package/dist/server/src/lib/tmux/tmux-capture-cache.js +76 -11
  404. package/dist/server/src/lib/tmux/tmux.js +79 -9
  405. package/dist/server/src/lib/verification/gate-runner.js +172 -16
  406. package/dist/server/src/lib/verification/machine-lock.js +5 -0
  407. package/dist/server/src/lib/ws-server.js +18 -3
  408. package/dist/server/src/types/auto-yes-answer-mode.js +38 -0
  409. package/dist/server/src/types/auto-yes-decision.js +61 -0
  410. package/dist/server/src/types/auto-yes.js +6 -0
  411. package/dist/server/src/types/prompt-reading.js +32 -0
  412. package/dist/types/auto-yes-answer-mode.d.ts +35 -0
  413. package/dist/types/auto-yes-answer-mode.d.ts.map +1 -0
  414. package/dist/types/auto-yes-answer-mode.js +38 -0
  415. package/docs/en/user-guide/webapp-guide.md +47 -13
  416. package/package.json +1 -1
  417. package/public/sw.js +76 -4
  418. package/release-notes/0.48.0.json +57 -0
  419. package/release-notes/0.49.0.json +45 -0
  420. package/.next/server/chunks/1559.js +0 -2
  421. package/.next/server/chunks/2460.js +0 -1
  422. package/.next/server/chunks/5595.js +0 -1
  423. package/.next/server/chunks/610.js +0 -1
  424. package/.next/server/chunks/6722.js +0 -1
  425. package/.next/static/chunks/5371-a549a0d2c2044d41.js +0 -1
  426. package/.next/static/chunks/602-1c1488959215e140.js +0 -1
  427. package/.next/static/chunks/6288-09feba367cc2c65e.js +0 -1
  428. package/.next/static/chunks/8407-155f84e5ba05f1d5.js +0 -1
  429. package/.next/static/chunks/9079-24f9fa549ed298f1.js +0 -1
  430. package/.next/static/chunks/app/sessions/page-e02f1adb1d1c1ccc.js +0 -1
  431. package/.next/static/chunks/app/worktrees/[id]/files/[...path]/page-9cf1ecc59e36a004.js +0 -1
  432. package/.next/static/chunks/app/worktrees/[id]/page-46aced20b2b1c010.js +0 -1
  433. /package/.next/static/{etorRtpxbQqqOzdUeXdw2 → 3_JtAZaKMJEDFIIfkHv4n}/_buildManifest.js +0 -0
  434. /package/.next/static/{etorRtpxbQqqOzdUeXdw2 → 3_JtAZaKMJEDFIIfkHv4n}/_ssgManifest.js +0 -0
@@ -12,11 +12,23 @@
12
12
  *
13
13
  * So the edge is detected exactly once, here, by {@link observeWaitingEdge}, and
14
14
  * everything else either reads {@link getWaitingEpisode} or subscribes with
15
- * {@link onWaitingTransition}. There is one caller today —
16
- * `worktree-status-helper`, on the list API's per-instance probe — and it passes
17
- * the *composed* verdict (scraper OR structured), so a wait that only the
18
- * agent's own events can see opens an episode exactly like one the screen
19
- * scraper read.
15
+ * {@link onWaitingTransition}. The observers are `worktree-status-helper`, on
16
+ * the list API's per-instance probe — it passes the *composed* verdict (scraper
17
+ * OR structured), so a wait that only the agent's own events can see opens an
18
+ * episode exactly like one the screen scraper read — and `response-checker`
19
+ * (#1790), which opens the episode for a prompt it saved and closes it when it
20
+ * records a reply.
21
+ *
22
+ * Issue #3798 added the agent's own turn transitions as closers: a `stop` that
23
+ * ended the turn an episode belongs to closes it in the same synchronous step
24
+ * that records the stop (`waiting-episode-binding`), so a tool whose reply
25
+ * arrives on a hook closes its wait with no browser open. That needs each
26
+ * episode to carry an identity and the turn it belongs to; see "identity and
27
+ * attribution" below. The screen observers — the status probe, the response
28
+ * poller and now the Auto-Yes poller — go through the same module's
29
+ * observation tables (`observeWaiting`), which refuse a reading made against an
30
+ * episode that has moved since the observer started; {@link observeWaitingEdge}
31
+ * stays for the callers and suites written against #1786.
20
32
  *
21
33
  * ## Where #1788 / #1790 plug in
22
34
  *
@@ -39,46 +51,49 @@
39
51
  * @module lib/session/waiting-episode-state
40
52
  */
41
53
  Object.defineProperty(exports, "__esModule", { value: true });
42
- exports.onWaitingTransition = onWaitingTransition;
54
+ exports.updateEpisodeKind = exports.replaceEpisode = exports.rebindEpisode = exports.openEpisode = exports.closeEpisode = exports.snapshotEpisodeVersions = exports.onWaitingTransition = exports.onWaitingEpisodeTransition = exports.hasOpenWaitingEpisode = exports.getWaitingEpisodeRecord = exports.getWaitingEpisode = exports.getLastClosedEpisode = exports.getEpisodeVersion = exports.clearWaitingTransitionListeners = exports.clearWaitingEpisodes = void 0;
55
+ exports.registerEpisodeBindingResolver = registerEpisodeBindingResolver;
43
56
  exports.observeWaitingEdge = observeWaitingEdge;
44
- exports.getWaitingEpisode = getWaitingEpisode;
45
- exports.hasOpenWaitingEpisode = hasOpenWaitingEpisode;
46
- exports.clearWaitingEpisodes = clearWaitingEpisodes;
47
- exports.clearWaitingTransitionListeners = clearWaitingTransitionListeners;
48
- const auto_yes_state_1 = require("../../lib/auto-yes-state");
49
57
  const logger_1 = require("../../lib/logger");
50
- const global_state_1 = require("../global-state");
58
+ const waiting_episode_state_ops_1 = require("../../lib/session/waiting-episode-state-ops");
59
+ const waiting_episode_state_store_1 = require("../../lib/session/waiting-episode-state-store");
60
+ var waiting_episode_state_store_2 = require("../../lib/session/waiting-episode-state-store");
61
+ Object.defineProperty(exports, "clearWaitingEpisodes", { enumerable: true, get: function () { return waiting_episode_state_store_2.clearWaitingEpisodes; } });
62
+ Object.defineProperty(exports, "clearWaitingTransitionListeners", { enumerable: true, get: function () { return waiting_episode_state_store_2.clearWaitingTransitionListeners; } });
63
+ Object.defineProperty(exports, "getEpisodeVersion", { enumerable: true, get: function () { return waiting_episode_state_store_2.getEpisodeVersion; } });
64
+ Object.defineProperty(exports, "getLastClosedEpisode", { enumerable: true, get: function () { return waiting_episode_state_store_2.getLastClosedEpisode; } });
65
+ Object.defineProperty(exports, "getWaitingEpisode", { enumerable: true, get: function () { return waiting_episode_state_store_2.getWaitingEpisode; } });
66
+ Object.defineProperty(exports, "getWaitingEpisodeRecord", { enumerable: true, get: function () { return waiting_episode_state_store_2.getWaitingEpisodeRecord; } });
67
+ Object.defineProperty(exports, "hasOpenWaitingEpisode", { enumerable: true, get: function () { return waiting_episode_state_store_2.hasOpenWaitingEpisode; } });
68
+ Object.defineProperty(exports, "onWaitingEpisodeTransition", { enumerable: true, get: function () { return waiting_episode_state_store_2.onWaitingEpisodeTransition; } });
69
+ Object.defineProperty(exports, "onWaitingTransition", { enumerable: true, get: function () { return waiting_episode_state_store_2.onWaitingTransition; } });
70
+ Object.defineProperty(exports, "snapshotEpisodeVersions", { enumerable: true, get: function () { return waiting_episode_state_store_2.snapshotEpisodeVersions; } });
71
+ var waiting_episode_state_ops_2 = require("../../lib/session/waiting-episode-state-ops");
72
+ Object.defineProperty(exports, "closeEpisode", { enumerable: true, get: function () { return waiting_episode_state_ops_2.closeEpisode; } });
73
+ Object.defineProperty(exports, "openEpisode", { enumerable: true, get: function () { return waiting_episode_state_ops_2.openEpisode; } });
74
+ Object.defineProperty(exports, "rebindEpisode", { enumerable: true, get: function () { return waiting_episode_state_ops_2.rebindEpisode; } });
75
+ Object.defineProperty(exports, "replaceEpisode", { enumerable: true, get: function () { return waiting_episode_state_ops_2.replaceEpisode; } });
76
+ Object.defineProperty(exports, "updateEpisodeKind", { enumerable: true, get: function () { return waiting_episode_state_ops_2.updateEpisodeKind; } });
51
77
  const logger = (0, logger_1.createLogger)('waiting-episode-state');
52
- /** compositeKey -> the wait currently in progress for that instance. */
53
- const episodes = (0, global_state_1.getOrInitGlobal)('__sessionWaitingEpisodes', () => new Map());
54
- /** Subscribers to the edge. See the module docblock. */
55
- const listeners = (0, global_state_1.getOrInitGlobal)('__sessionWaitingTransitionListeners', () => new Set());
56
- /**
57
- * Subscribe to waiting edges.
58
- *
59
- * @returns An unsubscribe function. Idempotent — calling it twice is harmless.
60
- */
61
- function onWaitingTransition(listener) {
62
- listeners.add(listener);
63
- return () => {
64
- listeners.delete(listener);
65
- };
78
+ /** Install the binding resolver `observeWaitingEdge` uses. The last one wins. */
79
+ function registerEpisodeBindingResolver(resolver) {
80
+ globalThis.__sessionWaitingEpisodeBindingResolver = resolver;
66
81
  }
67
- /** Notify subscribers, containing anything they throw. */
68
- function emit(transition) {
69
- for (const listener of listeners) {
70
- try {
71
- listener(transition);
72
- }
73
- catch (error) {
74
- logger.error('waiting-transition-listener-failed', {
75
- worktreeId: transition.worktreeId,
76
- cliToolId: transition.cliToolId,
77
- instanceId: transition.instanceId ?? transition.cliToolId,
78
- waiting: transition.waiting,
79
- error: error instanceof Error ? error.message : String(error),
80
- });
81
- }
82
+ function resolveBinding(parts, at) {
83
+ const resolver = globalThis.__sessionWaitingEpisodeBindingResolver;
84
+ if (resolver === undefined)
85
+ return waiting_episode_state_store_1.UNKNOWN_BINDING;
86
+ try {
87
+ return resolver(parts, at);
88
+ }
89
+ catch (error) {
90
+ logger.warn('waiting-episode-binding-resolve-failed', {
91
+ worktreeId: parts.worktreeId,
92
+ cliToolId: parts.cliToolId,
93
+ instanceId: parts.instanceId ?? parts.cliToolId,
94
+ error: error instanceof Error ? error.message : String(error),
95
+ });
96
+ return waiting_episode_state_store_1.UNKNOWN_BINDING;
82
97
  }
83
98
  }
84
99
  /**
@@ -89,16 +104,23 @@ function emit(transition) {
89
104
  * `since` and emit nothing, so a listener hears one event per wait rather than
90
105
  * one per poll.
91
106
  *
107
+ * Issue #3798: an episode opened here is bound by the registered resolver
108
+ * (`waiting-episode-binding`), so the turn transitions can end it. The
109
+ * production observers no longer call it: they go through
110
+ * `waiting-episode-binding`'s `observeWaiting`, which also checks that the
111
+ * episode has not moved since they started and that the frame does not
112
+ * predate the close of what it shows.
113
+ *
92
114
  * @returns The episode's `since` while waiting, or null when it is not.
93
115
  */
94
116
  function observeWaitingEdge({ worktreeId, cliToolId, instanceId, waiting, kind = null, structuredSince = null, now = Date.now(), }) {
95
- const key = (0, auto_yes_state_1.buildCompositeKey)(worktreeId, cliToolId, instanceId);
96
- const existing = episodes.get(key);
117
+ const parts = { worktreeId, cliToolId, instanceId };
118
+ const key = (0, waiting_episode_state_store_1.keyOf)(parts);
119
+ const existing = waiting_episode_state_store_1.episodes.get(key);
97
120
  if (!waiting) {
98
121
  if (existing === undefined)
99
122
  return null;
100
- episodes.delete(key);
101
- emit({ worktreeId, cliToolId, instanceId, waiting: false, since: null, kind: null, at: now });
123
+ (0, waiting_episode_state_ops_1.closeEpisode)(parts, (0, waiting_episode_state_store_1.metaOf)(existing).episodeId, 'screen-cleared', now);
102
124
  return null;
103
125
  }
104
126
  if (existing !== undefined) {
@@ -109,51 +131,6 @@ function observeWaitingEdge({ worktreeId, cliToolId, instanceId, waiting, kind =
109
131
  return existing.since;
110
132
  }
111
133
  const since = structuredSince ?? now;
112
- episodes.set(key, { since, kind });
113
- emit({ worktreeId, cliToolId, instanceId, waiting: true, since, kind, at: now });
134
+ (0, waiting_episode_state_ops_1.openEpisode)(parts, { since, kind, binding: resolveBinding(parts, now), openedBy: 'legacy-edge' }, now);
114
135
  return since;
115
136
  }
116
- /**
117
- * @returns The wait in progress for this instance, or null when it is not
118
- * waiting. Read-only: observing the edge is {@link observeWaitingEdge}'s job.
119
- */
120
- function getWaitingEpisode(worktreeId, cliToolId, instanceId) {
121
- return episodes.get((0, auto_yes_state_1.buildCompositeKey)(worktreeId, cliToolId, instanceId)) ?? null;
122
- }
123
- /**
124
- * Whether **any** instance in this worktree is still waiting (Issue #2001).
125
- *
126
- * The cross-device dismissal is keyed on the worktree, because that is what the
127
- * Service Worker `tag` names (`<worktreeId>:prompt`, `push-sender`): two agent
128
- * instances waiting in one worktree share a single notification card on the
129
- * phone. So one instance crossing the closing edge is not on its own a reason
130
- * to clear that card — the card is still telling the truth until the last of
131
- * them has been answered.
132
- *
133
- * The prefix test is exact rather than heuristic: `buildCompositeKey` puts the
134
- * worktree id first and rejects a worktree id containing
135
- * {@link COMPOSITE_KEY_SEPARATOR}, so no other worktree's key can start with
136
- * `<worktreeId>:`.
137
- */
138
- function hasOpenWaitingEpisode(worktreeId) {
139
- const prefix = `${worktreeId}${auto_yes_state_1.COMPOSITE_KEY_SEPARATOR}`;
140
- for (const key of episodes.keys()) {
141
- if (key.startsWith(prefix))
142
- return true;
143
- }
144
- return false;
145
- }
146
- /**
147
- * Drop every episode. Test seam.
148
- *
149
- * CI runs with `fileParallelism: false`, so one process holds this map for the
150
- * whole suite: a test that opens an episode and does not clear it hands the next
151
- * file a session that is already waiting.
152
- */
153
- function clearWaitingEpisodes() {
154
- episodes.clear();
155
- }
156
- /** Drop every subscriber. Test seam, paired with {@link clearWaitingEpisodes}. */
157
- function clearWaitingTransitionListeners() {
158
- listeners.clear();
159
- }
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ /**
3
+ * The T table (Issue #3798, design §2.4): what one turn transition's outcome
4
+ * does to the open waiting episode. Pure — it reads the outcome, the episode's
5
+ * binding and the current generation, and writes nothing. Applying the verdict
6
+ * is `waiting-episode-binding`'s job (Issue #3864 split it out of there).
7
+ *
8
+ * Design: `docs/design/issue-3798-waiting-episode.md`.
9
+ *
10
+ * @module lib/session/waiting-episode-verdict
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.sameGeneration = sameGeneration;
14
+ exports.verdictForOutcome = verdictForOutcome;
15
+ function sameGeneration(a, b) {
16
+ if (a.kind === 'none' || b.kind === 'none')
17
+ return a.kind === b.kind;
18
+ return a.at === b.at;
19
+ }
20
+ const NONE = { action: 'none' };
21
+ const close = (reason) => ({ action: 'close', reason });
22
+ /** The previous record's turn id, for the D and F columns. Null for `none`. */
23
+ function previousTurnId(previous) {
24
+ return previous.kind === 'none' ? null : previous.turnId;
25
+ }
26
+ /** T1–T5: a turn opened. */
27
+ function verdictForOpened(outcome, binding) {
28
+ const { previous, turnId: n, event } = outcome;
29
+ const asTurnN = { kind: 'turn', generation: outcome.generation, turnId: n };
30
+ if (binding.kind === 'screen')
31
+ return NONE;
32
+ if (binding.kind === 'turn' && binding.turnId === n)
33
+ return { action: 'unmatched' }; // ※1
34
+ const p = previousTurnId(previous);
35
+ const tookOverRecord = previous.kind === 'dialog-only' || previous.kind === 'display-only';
36
+ // D: the record this turn took over (R3-4). Only T2 / T3 / T4 have one (※5).
37
+ const isD = binding.kind === 'dialog-only' && binding.recordTurnId === p;
38
+ // T5 (R1-9): a turn replaced while it was open ends every wait but a screen's.
39
+ if (previous.kind === 'open-same-session' || previous.kind === 'open-other-session') {
40
+ return isD ? { action: 'unmatched' } : close('turn-superseded');
41
+ }
42
+ // T4 (R2-4): a prompt ends them too; the turn model drops every decision here.
43
+ if (event === 'user_prompt_submit')
44
+ return close('turn-superseded');
45
+ if (binding.kind === 'turn')
46
+ return close('turn-superseded');
47
+ if (binding.kind === 'dialog-only') {
48
+ if (!isD)
49
+ return close('turn-superseded');
50
+ return tookOverRecord ? { action: 'rebind', binding: asTurnN } : { action: 'unmatched' }; // T1: ※5
51
+ }
52
+ // unattributed — F: nothing opened between the wait and this turn (R2-4).
53
+ return binding.lastClosedTurnId === p ? { action: 'rebind', binding: asTurnN } : close('turn-superseded');
54
+ }
55
+ /** T9–T11: a stop with no turn open. */
56
+ function verdictForStopWithoutTurn(outcome, binding) {
57
+ const { previous } = outcome;
58
+ const p = previousTurnId(previous);
59
+ switch (previous.kind) {
60
+ case 'closed':
61
+ // T9: B (R1-2) and F (R2-1).
62
+ if (binding.kind === 'turn' && binding.turnId === p)
63
+ return close('turn-stop');
64
+ if (binding.kind === 'unattributed' && binding.lastClosedTurnId === p)
65
+ return close('turn-stop');
66
+ if (binding.kind === 'dialog-only' && binding.recordTurnId === p)
67
+ return { action: 'unmatched' }; // ※5
68
+ return NONE;
69
+ case 'dialog-only':
70
+ // T10: D, F and G.
71
+ if (binding.kind === 'dialog-only' && binding.recordTurnId === p)
72
+ return close('turn-stop');
73
+ if (binding.kind === 'unattributed')
74
+ return close('turn-stop');
75
+ return NONE;
76
+ case 'display-only':
77
+ case 'none':
78
+ // T11: D (R3-4) and F.
79
+ if (binding.kind === 'dialog-only' && binding.recordTurnId === p)
80
+ return close('turn-stop');
81
+ if (binding.kind === 'unattributed' && binding.lastClosedTurnId === p)
82
+ return close('turn-stop');
83
+ return NONE;
84
+ default:
85
+ // An open turn is `stopped` / `stop-rejected`, never this outcome.
86
+ return { action: 'unmatched' };
87
+ }
88
+ }
89
+ /** T19 / T20 and the rest of the generation fence. */
90
+ function verdictForGenerationFenced(outcome, binding) {
91
+ // T19 / T20 (R2-8): a session start in the same process keeps a screen.
92
+ if (outcome.source === 'session-start' && binding.kind === 'screen') {
93
+ return sameGeneration(binding.generation, outcome.generation)
94
+ ? NONE
95
+ : { action: 'rebind', binding: { ...binding, generation: outcome.generation } };
96
+ }
97
+ return sameGeneration(binding.generation, outcome.generation) ? NONE : close('generation');
98
+ }
99
+ /** T7. */
100
+ function verdictForRestored(outcome, binding) {
101
+ // T7: a wait opened under the discarded turn belongs to the one put back.
102
+ return binding.kind === 'turn' && binding.turnId === outcome.discardedTurnId
103
+ ? { action: 'rebind', binding: { ...binding, turnId: outcome.restoredTurnId } }
104
+ : NONE;
105
+ }
106
+ /** T8. */
107
+ function verdictForStopped(outcome, binding) {
108
+ // T8.
109
+ return binding.kind === 'turn' && binding.turnId === outcome.turnId ? close('turn-stop') : NONE;
110
+ }
111
+ /** T13. */
112
+ function verdictForSessionEnded(outcome, binding) {
113
+ // T13.
114
+ return binding.kind === 'turn' && binding.turnId === outcome.turnId ? close('turn-session-end') : NONE;
115
+ }
116
+ /** T15 / T16. */
117
+ function verdictForDecisionOpened(outcome, binding, current) {
118
+ // T15 / T16 (R3-6): a dialog the hook reported for a wait the screen showed first.
119
+ return outcome.recordKind === 'dialog-only' && binding.kind === 'unattributed'
120
+ ? {
121
+ action: 'rebind',
122
+ binding: { kind: 'dialog-only', generation: current, recordTurnId: outcome.recordTurnId, sessionId: null },
123
+ }
124
+ : NONE;
125
+ }
126
+ /** T17 / T18. */
127
+ function verdictForDecisionAnswered(outcome, binding) {
128
+ // T17 / T18 (R3-3): an explicit answer that left nothing pending.
129
+ if (outcome.before === 0 || outcome.remaining > 0)
130
+ return NONE;
131
+ const bound = (binding.kind === 'turn' && binding.turnId === outcome.recordTurnId) ||
132
+ (binding.kind === 'dialog-only' && binding.recordTurnId === outcome.recordTurnId);
133
+ return bound ? close('decision-settled') : NONE;
134
+ }
135
+ /** Rows that close a binding of another generation (the I column). */
136
+ const CLOSES_OTHER_GENERATION = new Set([
137
+ 'opened',
138
+ 'stopped',
139
+ 'stop-without-turn',
140
+ 'session-ended',
141
+ ]);
142
+ /** The T table (design §2.4): one outcome on the open episode. */
143
+ function verdictForOutcome(outcome, binding, current) {
144
+ if (outcome.kind === 'generation-fenced')
145
+ return verdictForGenerationFenced(outcome, binding);
146
+ if (!sameGeneration(binding.generation, current)) {
147
+ return CLOSES_OTHER_GENERATION.has(outcome.kind) ? close('generation') : NONE;
148
+ }
149
+ switch (outcome.kind) {
150
+ case 'opened':
151
+ return verdictForOpened(outcome, binding);
152
+ case 'restored':
153
+ return verdictForRestored(outcome, binding);
154
+ case 'stopped':
155
+ return verdictForStopped(outcome, binding);
156
+ case 'stop-without-turn':
157
+ return verdictForStopWithoutTurn(outcome, binding);
158
+ case 'session-ended':
159
+ return verdictForSessionEnded(outcome, binding);
160
+ case 'decision-opened':
161
+ return verdictForDecisionOpened(outcome, binding, current);
162
+ case 'decision-answered':
163
+ return verdictForDecisionAnswered(outcome, binding);
164
+ case 'continued':
165
+ case 'stop-rejected':
166
+ case 'session-end-rejected':
167
+ case 'none':
168
+ // T6, T12, T14, T21.
169
+ return NONE;
170
+ default:
171
+ outcome;
172
+ return NONE;
173
+ }
174
+ }
@@ -24,6 +24,7 @@ exports.isCaptureWindowSaturated = isCaptureWindowSaturated;
24
24
  exports.getCaptureGeneration = getCaptureGeneration;
25
25
  exports.isCaptureGenerationCurrent = isCaptureGenerationCurrent;
26
26
  exports.sliceOutput = sliceOutput;
27
+ exports.sliceCutsHead = sliceCutsHead;
27
28
  exports.getCachedCapture = getCachedCapture;
28
29
  exports.setCachedCapture = setCachedCapture;
29
30
  exports.invalidateCache = invalidateCache;
@@ -87,6 +88,10 @@ function getCache() {
87
88
  function getInflight() {
88
89
  return (0, global_state_1.getOrInitGlobal)('__tmuxCaptureCacheInflight', () => new Map());
89
90
  }
91
+ /** When each in-flight fetch started (Issue #3798), for the callers that join it. */
92
+ function getInflightStartedAt() {
93
+ return (0, global_state_1.getOrInitGlobal)('__tmuxCaptureCacheInflightStartedAt', () => new WeakMap());
94
+ }
90
95
  function getGenerationState() {
91
96
  return (0, global_state_1.getOrInitGlobal)('__tmuxCaptureCacheGeneration', () => ({ global: 0, sessions: new Map() }));
92
97
  }
@@ -122,8 +127,24 @@ function isCaptureGenerationCurrent(sessionName, generation) {
122
127
  // sliceOutput()
123
128
  // =========================================================================
124
129
  /**
125
- * Slice output from the end to return the last requestedLines lines.
126
- * If requestedLines >= total lines, returns the full output.
130
+ * A capture's rows (Issue #3881 third review N4). tmux ends every row with a
131
+ * newline, so the last one terminates a row and is not a row of its own: a
132
+ * 1000-row pane comes back as 1000 rows and a terminator, which `split` makes
133
+ * 1001 elements.
134
+ */
135
+ function rowsOf(output) {
136
+ const terminated = output.endsWith('\n');
137
+ return { rows: (terminated ? output.slice(0, -1) : output).split('\n'), terminated };
138
+ }
139
+ /**
140
+ * Slice output from the end to return the last requestedLines rows.
141
+ * If requestedLines >= total rows, returns the full output.
142
+ *
143
+ * Issue #3881 (third review N4): counted in rows, the terminator kept. Counted
144
+ * in `split` elements, the terminator took one of the requested rows, so a
145
+ * 1000-row pane asked for 1000 rows lost its first row — on an
146
+ * alternate-screen pane, the row that says whether the content begins at the
147
+ * top of the screen.
127
148
  *
128
149
  * @param fullOutput - Full captured output string
129
150
  * @param requestedLines - Number of lines requested from the end
@@ -132,10 +153,21 @@ function isCaptureGenerationCurrent(sessionName, generation) {
132
153
  function sliceOutput(fullOutput, requestedLines) {
133
154
  if (fullOutput === '')
134
155
  return '';
135
- const lines = fullOutput.split('\n');
136
- if (requestedLines >= lines.length)
156
+ const { rows, terminated } = rowsOf(fullOutput);
157
+ if (requestedLines >= rows.length)
137
158
  return fullOutput;
138
- return lines.slice(-requestedLines).join('\n');
159
+ return rows.slice(-requestedLines).join('\n') + (terminated ? '\n' : '');
160
+ }
161
+ /**
162
+ * Whether {@link sliceOutput} drops rows from the top of `fullOutput` (Issue
163
+ * #3881 third review N4): the one fact about a capture's top that its row count
164
+ * cannot tell when the window is exactly the pane's height.
165
+ *
166
+ * @param fullOutput - Full captured output string
167
+ * @param requestedLines - Number of lines requested from the end
168
+ */
169
+ function sliceCutsHead(fullOutput, requestedLines) {
170
+ return fullOutput !== '' && requestedLines < rowsOf(fullOutput).rows.length;
139
171
  }
140
172
  // =========================================================================
141
173
  // getCachedCapture()
@@ -180,8 +212,10 @@ function getCachedCapture(sessionName, requestedLines) {
180
212
  * @param sessionName - tmux session name (cache key)
181
213
  * @param output - Captured output string
182
214
  * @param capturedLines - Number of lines the output was captured with
215
+ * @param fetchStartedAt - When the capture began (Issue #3798); every writer
216
+ * in this app passes it. Defaults to now, the write time
183
217
  */
184
- function setCachedCapture(sessionName, output, capturedLines) {
218
+ function setCachedCapture(sessionName, output, capturedLines, fetchStartedAt) {
185
219
  const cache = getCache();
186
220
  const now = Date.now();
187
221
  // [SEC4-002] Full sweep: remove all TTL-expired entries
@@ -209,8 +243,22 @@ function setCachedCapture(sessionName, output, capturedLines) {
209
243
  output,
210
244
  capturedLines,
211
245
  timestamp: now,
246
+ fetchStartedAt: fetchStartedAt ?? now,
212
247
  });
213
248
  }
249
+ /**
250
+ * When the cached capture of `sessionName` was started, or null when nothing
251
+ * live is cached (Issue #3798). Read-only: an expired entry is left for the
252
+ * next read to evict.
253
+ *
254
+ * @param sessionName - tmux session name (cache key)
255
+ */
256
+ function getCachedCaptureFetchStartedAt(sessionName) {
257
+ const entry = getCache().get(sessionName);
258
+ if (!entry || Date.now() - entry.timestamp > exports.CACHE_TTL_MS)
259
+ return null;
260
+ return entry.fetchStartedAt;
261
+ }
214
262
  // =========================================================================
215
263
  // invalidateCache()
216
264
  // =========================================================================
@@ -262,10 +310,8 @@ function resetCacheForTesting() {
262
310
  globalThis.__tmuxCaptureCache = undefined;
263
311
  globalThis.__tmuxCaptureCacheInflight = undefined;
264
312
  globalThis.__tmuxCaptureCacheGeneration = undefined;
313
+ globalThis.__tmuxCaptureCacheInflightStartedAt = undefined;
265
314
  }
266
- // =========================================================================
267
- // getOrFetchCapture() - singleflight pattern
268
- // =========================================================================
269
315
  /**
270
316
  * Get capture output from cache or fetch it.
271
317
  * Implements singleflight pattern: concurrent requests for the same session
@@ -277,33 +323,52 @@ function resetCacheForTesting() {
277
323
  * @param sessionName - tmux session name
278
324
  * @param requestedLines - Number of lines requested
279
325
  * @param fetchFn - Function to fetch output on cache miss
326
+ * @param onServed - Told where the returned frame came from (Issue #3798),
327
+ * right before it is returned; not called when the capture throws
328
+ * @param onSliced - Told whether the slice to `requestedLines` dropped rows
329
+ * from the top of what tmux returned (Issue #3881 third review N4,
330
+ * {@link sliceCutsHead}), right before it is returned
280
331
  * @returns Captured output (sliced to requestedLines)
281
332
  */
282
- async function getOrFetchCapture(sessionName, requestedLines, fetchFn) {
333
+ async function getOrFetchCapture(sessionName, requestedLines, fetchFn, onServed, onSliced) {
283
334
  // 1. Check cache first
335
+ const cachedStartedAt = getCachedCaptureFetchStartedAt(sessionName);
284
336
  const cached = getCachedCapture(sessionName, requestedLines);
285
337
  if (cached !== null) {
338
+ if (cachedStartedAt !== null)
339
+ onServed?.({ fetchStartedAt: cachedStartedAt, source: 'cache' });
340
+ const entry = getCache().get(sessionName);
341
+ if (entry)
342
+ onSliced?.(sliceCutsHead(entry.output, requestedLines));
286
343
  return cached;
287
344
  }
288
345
  // 2. Check for inflight request (singleflight)
289
346
  const inflight = getInflight();
290
347
  const existingPromise = inflight.get(sessionName);
291
348
  if (existingPromise) {
349
+ const joinedStartedAt = getInflightStartedAt().get(existingPromise);
292
350
  const result = await existingPromise;
351
+ if (joinedStartedAt !== undefined)
352
+ onServed?.({ fetchStartedAt: joinedStartedAt, source: 'joined' });
353
+ onSliced?.(sliceCutsHead(result, requestedLines));
293
354
  return sliceOutput(result, requestedLines);
294
355
  }
295
356
  // 3. Create new fetch promise
296
357
  // Issue #3734: snapshot the generation before fetchFn() starts
297
358
  const generation = getCaptureGeneration(sessionName);
359
+ const fetchStartedAt = Date.now();
298
360
  const fetchPromise = fetchFn();
299
361
  inflight.set(sessionName, fetchPromise);
362
+ getInflightStartedAt().set(fetchPromise, fetchStartedAt);
300
363
  try {
301
364
  const output = await fetchPromise;
302
365
  // Cache non-empty results only [SEC4-007], and only when no invalidation
303
366
  // happened while waiting (Issue #3734)
304
367
  if (output.length > 0 && isCaptureGenerationCurrent(sessionName, generation)) {
305
- setCachedCapture(sessionName, output, exports.CACHE_MAX_CAPTURE_LINES);
368
+ setCachedCapture(sessionName, output, exports.CACHE_MAX_CAPTURE_LINES, fetchStartedAt);
306
369
  }
370
+ onServed?.({ fetchStartedAt, source: 'fetched' });
371
+ onSliced?.(sliceCutsHead(output, requestedLines));
307
372
  return sliceOutput(output, requestedLines);
308
373
  }
309
374
  finally {