commandmate 0.31.1 → 0.31.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (299) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +170 -170
  3. package/.next/app-path-routes-manifest.json +29 -29
  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/update/route_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/app/update-check/route.js +1 -1
  12. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/assistant/conversation/route.js.nft.json +1 -1
  14. package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/assistant/current-output/route.js.nft.json +1 -1
  16. package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/assistant/messages/route.js +1 -1
  18. package/.next/server/app/api/assistant/messages/route.js.nft.json +1 -1
  19. package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/assistant/session/route.js +1 -1
  21. package/.next/server/app/api/assistant/session/route.js.nft.json +1 -1
  22. package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/assistant/start/route.js +2 -2
  24. package/.next/server/app/api/assistant/start/route.js.nft.json +1 -1
  25. package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/assistant/terminal/route.js +2 -2
  27. package/.next/server/app/api/assistant/terminal/route.js.nft.json +1 -1
  28. package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
  30. package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
  31. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/capabilities/route.js +1 -1
  35. package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  37. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  38. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  40. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  41. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  42. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  43. package/.next/server/app/api/hooks/agent-event/route.js +1 -1
  44. package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
  45. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  46. package/.next/server/app/api/hooks/claude-done/route.js +2 -2
  47. package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
  48. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  49. package/.next/server/app/api/hooks/permission-request/route.js +1 -1
  50. package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
  51. package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
  52. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  53. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  54. package/.next/server/app/api/push/escalation/route.js +2 -2
  55. package/.next/server/app/api/push/escalation/route.js.nft.json +1 -1
  56. package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
  57. package/.next/server/app/api/push/subscriptions/route.js +1 -1
  58. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/push/vapid/route.js +2 -2
  60. package/.next/server/app/api/push/vapid/route.js.nft.json +1 -1
  61. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
  63. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  64. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  65. package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
  66. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  67. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
  68. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/repositories/clone/route.js +1 -1
  70. package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
  71. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  72. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  73. package/.next/server/app/api/repositories/restore/route.js +1 -1
  74. package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
  75. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  76. package/.next/server/app/api/repositories/route.js +1 -1
  77. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  78. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  79. package/.next/server/app/api/repositories/scan/route.js +1 -1
  80. package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
  81. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  82. package/.next/server/app/api/repositories/sync/route.js +1 -1
  83. package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
  84. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  85. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  86. package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
  87. package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
  88. package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  90. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  91. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  93. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  94. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  96. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  97. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  98. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  99. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  100. package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
  101. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  103. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  104. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  105. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  106. package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
  107. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  108. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
  109. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
  110. package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
  111. package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
  112. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  113. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  114. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  115. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  116. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  117. package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
  118. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  120. package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js +1 -1
  121. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  122. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  124. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  127. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  129. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  130. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  132. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  133. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  135. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  136. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  137. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  138. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  139. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  141. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  142. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
  146. package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
  148. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  149. package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
  151. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  152. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  153. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  154. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  155. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  157. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  158. package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
  159. package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
  161. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  162. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
  163. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  164. package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
  165. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
  166. package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
  167. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  168. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  170. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  171. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  173. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  174. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  175. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
  176. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  177. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  178. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
  179. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  180. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  181. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  182. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  183. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  184. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  185. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  186. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  187. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  188. package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
  189. package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
  190. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  191. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  192. package/.next/server/app/api/worktrees/[id]/terminal/route.js +1 -1
  193. package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
  194. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  195. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  196. package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
  197. package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
  198. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  199. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  200. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  201. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  202. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  203. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  204. package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
  205. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.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/chat/page_client-reference-manifest.js +1 -1
  215. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  216. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  217. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  218. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  219. package/.next/server/app/page_client-reference-manifest.js +1 -1
  220. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  221. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  222. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  223. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  224. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  225. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  226. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  227. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  228. package/.next/server/app/worktrees/[id]/page.js +10 -10
  229. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  230. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  231. package/.next/server/app-paths-manifest.json +29 -29
  232. package/.next/server/chunks/1058.js +1 -1
  233. package/.next/server/chunks/1068.js +1 -1
  234. package/.next/server/chunks/1191.js +2 -2
  235. package/.next/server/chunks/1886.js +1 -1
  236. package/.next/server/chunks/2119.js +1 -1
  237. package/.next/server/chunks/2404.js +1 -1
  238. package/.next/server/chunks/2445.js +1 -1
  239. package/.next/server/chunks/261.js +1 -1
  240. package/.next/server/chunks/2739.js +1 -1
  241. package/.next/server/chunks/3241.js +1 -1
  242. package/.next/server/chunks/3484.js +1 -0
  243. package/.next/server/chunks/358.js +1 -0
  244. package/.next/server/chunks/4325.js +1 -1
  245. package/.next/server/chunks/4393.js +1 -1
  246. package/.next/server/chunks/4443.js +1 -1
  247. package/.next/server/chunks/5017.js +1 -1
  248. package/.next/server/chunks/5120.js +1 -1
  249. package/.next/server/chunks/5164.js +1 -1
  250. package/.next/server/chunks/552.js +3 -3
  251. package/.next/server/chunks/595.js +8 -0
  252. package/.next/server/chunks/6130.js +1 -1
  253. package/.next/server/chunks/8800.js +1 -1
  254. package/.next/server/chunks/8918.js +3 -3
  255. package/.next/server/chunks/9123.js +1 -1
  256. package/.next/server/chunks/9130.js +2 -2
  257. package/.next/server/chunks/9627.js +3 -3
  258. package/.next/server/chunks/9696.js +2 -2
  259. package/.next/server/chunks/9798.js +2 -2
  260. package/.next/server/middleware-manifest.json +5 -5
  261. package/.next/server/pages/500.html +1 -1
  262. package/.next/server/server-reference-manifest.json +1 -1
  263. package/.next/static/chunks/{1783-11c9b4d8a52ebd91.js → 2813-de885de8a4b11910.js} +1 -1
  264. package/.next/static/chunks/4718-07ec4e10186928db.js +1 -0
  265. package/.next/static/chunks/app/worktrees/[id]/page-91b639c90795baa9.js +1 -0
  266. package/.next/static/css/acc4b9c3feb04287.css +1 -0
  267. package/.next/trace +13 -13
  268. package/dist/lib/detection/tools/verified-against.d.ts +24 -24
  269. package/dist/lib/detection/tools/verified-against.js +24 -24
  270. package/dist/server/locales/en/worktree.json +1402 -0
  271. package/dist/server/locales/ja/worktree.json +1402 -0
  272. package/dist/server/src/lib/db/chat-db.js +44 -1
  273. package/dist/server/src/lib/detection/cli-patterns.js +157 -23
  274. package/dist/server/src/lib/detection/model-info-extractor.js +185 -4
  275. package/dist/server/src/lib/detection/tools/antigravity/detect.js +105 -25
  276. package/dist/server/src/lib/detection/tools/antigravity/dialog.js +233 -0
  277. package/dist/server/src/lib/detection/tools/verified-against.js +24 -24
  278. package/dist/server/src/lib/hooks/hook-settings-generator.js +16 -0
  279. package/dist/server/src/lib/hooks/sources/claude/model-switch.js +169 -0
  280. package/dist/server/src/lib/hooks/sources/claude/source.js +14 -1
  281. package/dist/server/src/lib/polling/response-checker.js +17 -1
  282. package/dist/server/src/lib/polling/response-poller-core.js +143 -9
  283. package/dist/server/src/lib/push/index.js +13 -1
  284. package/dist/server/src/lib/push/model-change-push-notifier.js +174 -0
  285. package/dist/server/src/lib/push/notification-dedup.js +2 -1
  286. package/dist/server/src/lib/push/push-sender.js +48 -20
  287. package/dist/server/src/lib/realtime/model-change-broadcast.js +171 -0
  288. package/dist/server/src/lib/realtime/types.js +19 -1
  289. package/dist/server/src/lib/realtime/waiting-broadcast.js +13 -0
  290. package/dist/server/src/lib/session/agent-event-state.js +344 -12
  291. package/package.json +1 -1
  292. package/.next/server/chunks/6894.js +0 -8
  293. package/.next/server/chunks/7187.js +0 -1
  294. package/.next/server/chunks/7472.js +0 -1
  295. package/.next/static/chunks/4718-46e1d2f07c8423ba.js +0 -1
  296. package/.next/static/chunks/app/worktrees/[id]/page-64d4ec3051971760.js +0 -1
  297. package/.next/static/css/5c13ea243dfdcb66.css +0 -1
  298. /package/.next/static/{60mm4_QBuFtFTfo5UMyKU → 0hTIackGXw6v7diXJS6yN}/_buildManifest.js +0 -0
  299. /package/.next/static/{60mm4_QBuFtFTfo5UMyKU → 0hTIackGXw6v7diXJS6yN}/_ssgManifest.js +0 -0
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ /**
3
+ * The wording of "the model changed", and the push that carries it
4
+ * (Issue #2357).
5
+ *
6
+ * ## What this module owns
7
+ *
8
+ * Three things, and the first is the reason the other two live together:
9
+ *
10
+ * 1. **The sentence.** `Model changed from gpt-5.6-sol to gpt-5-mini`, in the
11
+ * reader's language, from `locales/<locale>/worktree.json` —
12
+ * `agentModel.changed`, next to the session row that shows the value on the
13
+ * phone. It is rendered here rather than in `push-sender` because it is also
14
+ * what the history row says: the model edge writes one row into
15
+ * `chat_messages` and sends one push, and a reader comparing the two must
16
+ * find the same words.
17
+ * 2. **Which language the history row is written in.** A row is stored once,
18
+ * and the server has no request to read a cookie from — the edge fires from
19
+ * the hook route or the status poll, neither of which is the reader. The
20
+ * best evidence it has is the language the readers registered their push
21
+ * subscriptions in, so the newest subscription's locale is used, and the
22
+ * default locale when nobody has registered one.
23
+ * 3. **The push itself.** One per transition, through `notifyPushSubscribers`,
24
+ * on the `enabled_prompt` bucket (see `NotificationEvent.modelChange` for
25
+ * why that bucket and why the transport kind reads `failure`).
26
+ *
27
+ * ## Why the dictionaries are static imports
28
+ *
29
+ * The same constraint `push-sender` documents: this module is reached from the
30
+ * custom server's graph (`ws-server` → `waiting-broadcast` →
31
+ * `model-change-broadcast` → here) and is therefore emitted into `dist/server`
32
+ * as CommonJS, where `next-intl` (ESM-only) cannot be required. The JSON is
33
+ * imported directly and `{from}` / `{to}` are substituted by hand.
34
+ *
35
+ * @module lib/push/model-change-push-notifier
36
+ */
37
+ var __importDefault = (this && this.__importDefault) || function (mod) {
38
+ return (mod && mod.__esModule) ? mod : { "default": mod };
39
+ };
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.buildModelChangedSentence = buildModelChangedSentence;
42
+ exports.buildModelChangedBodies = buildModelChangedBodies;
43
+ exports.resolveReadersLocale = resolveReadersLocale;
44
+ exports.notifyModelChangePush = notifyModelChangePush;
45
+ const i18n_config_1 = require("../../config/i18n-config");
46
+ const db_instance_1 = require("../../lib/db/db-instance");
47
+ const push_subscriptions_db_1 = require("../../lib/db/push-subscriptions-db");
48
+ const worktree_db_1 = require("../../lib/db/worktree-db");
49
+ const logger_1 = require("../../lib/logger");
50
+ const worktree_json_1 = __importDefault(require("../../../locales/en/worktree.json"));
51
+ const worktree_json_2 = __importDefault(require("../../../locales/ja/worktree.json"));
52
+ const push_sender_1 = require("./push-sender");
53
+ const vapid_1 = require("./vapid");
54
+ const logger = (0, logger_1.createLogger)('push/model-change-notifier');
55
+ /**
56
+ * The one sentence, per locale. Keyed by `SupportedLocale` so adding a locale
57
+ * without a dictionary is a type error here rather than an English push in a
58
+ * Japanese install.
59
+ */
60
+ const MODEL_CHANGED_TEMPLATES = {
61
+ en: worktree_json_1.default.agentModel.changed,
62
+ ja: worktree_json_2.default.agentModel.changed,
63
+ };
64
+ /**
65
+ * "Model changed from {from} to {to}", in one language.
66
+ *
67
+ * `from` / `to` are the resolved values `sessionStatusByInstance[].model`
68
+ * publishes, verbatim — the same string the phone's session row shows, so the
69
+ * sentence and the row cannot name the same model two ways.
70
+ */
71
+ function buildModelChangedSentence(locale, from, to) {
72
+ return MODEL_CHANGED_TEMPLATES[(0, push_sender_1.resolvePushLocale)(locale)]
73
+ .replace('{from}', from)
74
+ .replace('{to}', to);
75
+ }
76
+ /** The sentence in every supported language, for a per-device fan-out. */
77
+ function buildModelChangedBodies(from, to) {
78
+ const bodies = {};
79
+ for (const locale of i18n_config_1.SUPPORTED_LOCALES) {
80
+ bodies[locale] = buildModelChangedSentence(locale, from, to);
81
+ }
82
+ return bodies;
83
+ }
84
+ /**
85
+ * The language the history row should be written in (Issue #2357).
86
+ *
87
+ * The newest push subscription's locale, because that is the only place the
88
+ * server has ever been told what language a reader reads in — registration
89
+ * resolves it the way the UI does (`resolveLocale`, cookie then
90
+ * `Accept-Language`) and stores it on the row. No subscription at all means the
91
+ * default locale, which is what the UI shows a reader who has chosen nothing.
92
+ *
93
+ * Never throws: a database that cannot answer is a reason to write the row in
94
+ * the default language, not a reason to write no row.
95
+ */
96
+ function resolveReadersLocale(db) {
97
+ try {
98
+ const subscriptions = (0, push_subscriptions_db_1.getAllPushSubscriptions)(db);
99
+ let newest = null;
100
+ for (const sub of subscriptions) {
101
+ const updatedAt = sub.updatedAt.getTime();
102
+ if (newest === null || updatedAt > newest.updatedAt) {
103
+ newest = { updatedAt, locale: sub.locale };
104
+ }
105
+ }
106
+ return (0, push_sender_1.resolvePushLocale)(newest?.locale ?? i18n_config_1.DEFAULT_LOCALE);
107
+ }
108
+ catch {
109
+ return i18n_config_1.DEFAULT_LOCALE;
110
+ }
111
+ }
112
+ /**
113
+ * The worktree's display name, for the notification title. Falls back to the
114
+ * id rather than dropping the notification — the same rule
115
+ * `waiting-push-notifier` applies.
116
+ */
117
+ function resolveWorktreeName(worktreeId) {
118
+ try {
119
+ return (0, worktree_db_1.getWorktreeById)((0, db_instance_1.getDbInstance)(), worktreeId)?.name ?? worktreeId;
120
+ }
121
+ catch {
122
+ return worktreeId;
123
+ }
124
+ }
125
+ /**
126
+ * Notify every opted-in device that this instance changed model (Issue #2357).
127
+ *
128
+ * States the fact and nothing more — no ranking, no "downgraded", because the
129
+ * Issue rules that out and because the server has no table that could say
130
+ * which of two models is the lesser. Never throws; push is advisory and the
131
+ * edge that called this has already been observed.
132
+ *
133
+ * @returns Null when a fan-out was attempted, otherwise why it was not.
134
+ */
135
+ async function notifyModelChangePush(change) {
136
+ if (!(0, vapid_1.isPushConfigured)()) {
137
+ logger.debug('model-change-push-suppressed', {
138
+ worktreeId: change.worktreeId,
139
+ instanceId: change.instanceId,
140
+ reason: 'unconfigured',
141
+ });
142
+ return 'unconfigured';
143
+ }
144
+ try {
145
+ await (0, push_sender_1.notifyPushSubscribers)({
146
+ worktreeId: change.worktreeId,
147
+ worktreeName: resolveWorktreeName(change.worktreeId),
148
+ // The delivery bucket, not the meaning — see `NotificationEvent.modelChange`.
149
+ kind: 'failure',
150
+ agentName: change.instanceId,
151
+ instanceId: change.instanceId,
152
+ modelChange: {
153
+ from: change.from,
154
+ to: change.to,
155
+ body: buildModelChangedBodies(change.from, change.to),
156
+ },
157
+ }, change.at);
158
+ logger.info('model-change-push-raised', {
159
+ worktreeId: change.worktreeId,
160
+ instanceId: change.instanceId,
161
+ from: change.from,
162
+ to: change.to,
163
+ source: change.source,
164
+ });
165
+ }
166
+ catch (error) {
167
+ logger.warn('model-change-push-failed', {
168
+ worktreeId: change.worktreeId,
169
+ instanceId: change.instanceId,
170
+ error: error instanceof Error ? error.message : String(error),
171
+ });
172
+ }
173
+ return null;
174
+ }
@@ -20,7 +20,8 @@ exports.resetWaitingPushDedup = resetWaitingPushDedup;
20
20
  const crypto_1 = require("crypto");
21
21
  /** Default suppression window: repeats of identical content within this are dropped. */
22
22
  exports.DEFAULT_DEDUP_WINDOW_MS = 30_000;
23
- const lastSent = new Map();
23
+ const lastSent = globalThis.__notificationDedupLastSent ??
24
+ (globalThis.__notificationDedupLastSent = new Map());
24
25
  function contentHash(content) {
25
26
  return (0, crypto_1.createHash)('sha256').update(content).digest('hex');
26
27
  }
@@ -27,6 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  return (mod && mod.__esModule) ? mod : { "default": mod };
28
28
  };
29
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.MODEL_CHANGE_TAG_SUFFIX = void 0;
30
31
  exports.resolvePushLocale = resolvePushLocale;
31
32
  exports.buildExcerpt = buildExcerpt;
32
33
  exports.buildPushPayload = buildPushPayload;
@@ -51,6 +52,11 @@ const PUSH_MESSAGES = {
51
52
  en: notifications_json_1.default.push,
52
53
  ja: notifications_json_2.default.push,
53
54
  };
55
+ /**
56
+ * The `tag` segment a model-change card carries in place of its kind
57
+ * (Issue #2357). Exported so the notifier's tests can name the card they expect.
58
+ */
59
+ exports.MODEL_CHANGE_TAG_SUFFIX = 'model';
54
60
  /**
55
61
  * Narrow a stored subscription locale to one we can actually render.
56
62
  * Subscriptions registered before v42 have `locale = NULL` and land on
@@ -147,25 +153,31 @@ function buildPushPayload(event, locale = i18n_config_1.DEFAULT_LOCALE, now = Da
147
153
  const excerpt = buildExcerpt(event.excerpt);
148
154
  const agentSuffix = event.agentName ? ` (${event.agentName})` : '';
149
155
  const title = `${event.worktreeName}${agentSuffix}`;
150
- const messages = PUSH_MESSAGES[resolvePushLocale(locale)];
151
- const body = event.kind === 'prompt'
152
- ? // Issue #2001: the resolution's body replaces the stale card's, so it
153
- // has to answer the question that card asked. It quotes no excerpt
154
- // the prompt is over, and repeating it would read as a new one.
155
- event.resolved === true
156
- ? messages.promptResolved
157
- : buildWaitingBody(event, messages, excerpt, now)
158
- : event.kind === 'failure'
159
- ? buildFailureBody(event, messages, excerpt)
160
- : // Issue #2045: an update notice is a completion by *bucket*, not by
161
- // content, so it is the one completion whose body is not "Done".
162
- event.updateAvailable
163
- ? messages.updateAvailable
164
- .replace('{agent}', event.updateAvailable.agent)
165
- .replace('{version}', event.updateAvailable.version)
166
- : excerpt
167
- ? messages.completionWithExcerpt.replace('{excerpt}', excerpt)
168
- : messages.completion;
156
+ const resolvedLocale = resolvePushLocale(locale);
157
+ const messages = PUSH_MESSAGES[resolvedLocale];
158
+ const body =
159
+ // Issue #2357: read first, because the event's `kind` is the bucket it is
160
+ // delivered to and says nothing about what it is. See `modelChange`.
161
+ event.modelChange
162
+ ? event.modelChange.body[resolvedLocale]
163
+ : event.kind === 'prompt'
164
+ ? // Issue #2001: the resolution's body replaces the stale card's, so it
165
+ // has to answer the question that card asked. It quotes no excerpt
166
+ // the prompt is over, and repeating it would read as a new one.
167
+ event.resolved === true
168
+ ? messages.promptResolved
169
+ : buildWaitingBody(event, messages, excerpt, now)
170
+ : event.kind === 'failure'
171
+ ? buildFailureBody(event, messages, excerpt)
172
+ : // Issue #2045: an update notice is a completion by *bucket*, not by
173
+ // content, so it is the one completion whose body is not "Done".
174
+ event.updateAvailable
175
+ ? messages.updateAvailable
176
+ .replace('{agent}', event.updateAvailable.agent)
177
+ .replace('{version}', event.updateAvailable.version)
178
+ : excerpt
179
+ ? messages.completionWithExcerpt.replace('{excerpt}', excerpt)
180
+ : messages.completion;
169
181
  return {
170
182
  kind: event.kind,
171
183
  title,
@@ -176,7 +188,12 @@ function buildPushPayload(event, locale = i18n_config_1.DEFAULT_LOCALE, now = Da
176
188
  // Unchanged by #1790, and deliberately: the escalation carries the same tag
177
189
  // as the notification it follows up, so the Service Worker replaces the
178
190
  // stale one instead of stacking a second card for the same wait.
179
- tag: `${event.worktreeId}:${event.kind}`,
191
+ // Issue #2357: a model change gets a tag of its own, so it neither replaces
192
+ // a failure card (its transport bucket) nor is replaced by one; two changes
193
+ // of the same worktree do collapse, which is right — the newer is the fact.
194
+ tag: event.modelChange
195
+ ? `${event.worktreeId}:${exports.MODEL_CHANGE_TAG_SUFFIX}`
196
+ : `${event.worktreeId}:${event.kind}`,
180
197
  timestamp: now,
181
198
  ...(event.waitingKind ? { waitingKind: event.waitingKind } : {}),
182
199
  ...(event.resolved === true ? { resolved: true } : {}),
@@ -252,6 +269,17 @@ function passesDedup(event) {
252
269
  // uses, so the two would suppress each other on a 30 s window neither wants.
253
270
  if (event.resolved === true)
254
271
  return true;
272
+ // Issue #2357: keyed on the transition, not on its wording — the body is
273
+ // localized per device and the same change must not send twice because two
274
+ // readers speak different languages. The producer already emits one edge per
275
+ // transition; this is the second net, on the same 30 s window as the rest.
276
+ if (event.modelChange) {
277
+ return (0, notification_dedup_1.shouldSendNotification)({
278
+ worktreeId: event.worktreeId,
279
+ kind: event.kind,
280
+ content: `${exports.MODEL_CHANGE_TAG_SUFFIX}:${event.instanceId ?? event.agentName ?? ''}:${event.modelChange.from}>${event.modelChange.to}`,
281
+ });
282
+ }
255
283
  if (event.kind === 'prompt' && typeof event.waitingSince === 'number') {
256
284
  return (0, notification_dedup_1.shouldSendWaitingPush)({
257
285
  worktreeId: event.worktreeId,
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ /**
3
+ * What happens when an agent instance changes model (Issue #2357).
4
+ *
5
+ * ## The edge, and its three receivers
6
+ *
7
+ * `agent-event-state` judges the model edge — the merged hook/frame value moving
8
+ * from one model to another, with the first sighting, the value going quiet
9
+ * and a spelling change all ruled out there — and hands it out through
10
+ * `onAgentModelChange`. This module is that subscription, and it is the ONE
11
+ * subscription: the three things the Issue asks for on the receiving side are
12
+ * fanned out from here, in the order that leaves the most durable trace first.
13
+ *
14
+ * 1. **The history row.** One assistant row in `chat_messages`, in the
15
+ * readers' language, so the chat transcript and the History tab both keep
16
+ * "the model changed from A to B" where the conversation is. Written
17
+ * first, because it is the receiver that survives a phone being off.
18
+ * 2. **The room frames.** The row is pushed as a `message` frame — the same
19
+ * frame `sendUserMessage` publishes — so a transcript that is open shows
20
+ * the line without waiting for its poll; then the `model_changed` frame
21
+ * itself, which is what the phone's session row turns amber on.
22
+ * 3. **The push.** `notifyModelChangePush`, fire-and-forget; it has its own
23
+ * dedup and its own logging.
24
+ *
25
+ * Each receiver is wrapped separately: a database that cannot be written must
26
+ * not cost the reader the socket frame, and a socket with no owner must not
27
+ * cost them the push.
28
+ *
29
+ * ## Why `publish` is injected, and who arms this
30
+ *
31
+ * The same shape as `waiting-broadcast`, and armed by it: `ws-server` owns the
32
+ * rooms and calls `startWaitingStatusBroadcast(handleBroadcast)` from
33
+ * `setupWebSocket`, which is the one place in the process that knows which
34
+ * bundle's `rooms` a frame has to reach. That call now arms this subscription
35
+ * too, with the same publisher, and `stopWaitingStatusBroadcast` (from
36
+ * `closeWebSocket`) disarms both — so the listener's lifetime is the server's,
37
+ * and a suite that stands a server up and tears it down leaves nothing pointed
38
+ * at a dead room map.
39
+ *
40
+ * ## Authorization
41
+ *
42
+ * None is bypassed: the publisher is the room broadcaster, and a socket only
43
+ * joins a room through the authenticated `subscribe` path.
44
+ *
45
+ * @module lib/realtime/model-change-broadcast
46
+ */
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.buildModelChangedEvent = buildModelChangedEvent;
49
+ exports.handleAgentModelChange = handleAgentModelChange;
50
+ exports.startModelChangeBroadcast = startModelChangeBroadcast;
51
+ exports.stopModelChangeBroadcast = stopModelChangeBroadcast;
52
+ exports.isModelChangeBroadcastActive = isModelChangeBroadcastActive;
53
+ const db_instance_1 = require("../../lib/db/db-instance");
54
+ const chat_db_1 = require("../../lib/db/chat-db");
55
+ const logger_1 = require("../../lib/logger");
56
+ const model_change_push_notifier_1 = require("../../lib/push/model-change-push-notifier");
57
+ const types_1 = require("../../lib/realtime/types");
58
+ const agent_event_state_1 = require("../../lib/session/agent-event-state");
59
+ const logger = (0, logger_1.createLogger)('model-change-broadcast');
60
+ /**
61
+ * Translate a model edge into the frame clients receive.
62
+ *
63
+ * Field for field the producer's record; `instance` is already resolved there
64
+ * (`instanceId ?? cliToolId`), so a client can match it against its own pane
65
+ * without re-deriving the convention.
66
+ */
67
+ function buildModelChangedEvent(change) {
68
+ return {
69
+ type: types_1.MODEL_CHANGED_EVENT_TYPE,
70
+ worktreeId: change.worktreeId,
71
+ cliTool: change.cliToolId,
72
+ instance: change.instanceId,
73
+ from: change.from,
74
+ to: change.to,
75
+ source: change.source,
76
+ at: change.at,
77
+ };
78
+ }
79
+ /**
80
+ * Write the history row and hand back the `message` frame for it, or null
81
+ * when the database could not take it.
82
+ *
83
+ * Never throws. The sentence is localized once, for the readers' registered
84
+ * language (`resolveReadersLocale`) — a stored row cannot be re-rendered per
85
+ * viewer the way the push body is.
86
+ */
87
+ function recordModelChangeHistory(change) {
88
+ try {
89
+ const db = (0, db_instance_1.getDbInstance)();
90
+ const locale = (0, model_change_push_notifier_1.resolveReadersLocale)(db);
91
+ const message = (0, chat_db_1.createModelChangeMessage)(db, {
92
+ worktreeId: change.worktreeId,
93
+ cliToolId: change.cliToolId,
94
+ instanceId: change.instanceId,
95
+ content: (0, model_change_push_notifier_1.buildModelChangedSentence)(locale, change.from, change.to),
96
+ at: change.at,
97
+ });
98
+ return { type: 'message', worktreeId: change.worktreeId, message };
99
+ }
100
+ catch (error) {
101
+ logger.warn('model-change-history-failed', {
102
+ worktreeId: change.worktreeId,
103
+ instanceId: change.instanceId,
104
+ error: error instanceof Error ? error.message : String(error),
105
+ });
106
+ return null;
107
+ }
108
+ }
109
+ /**
110
+ * Deliver one edge to all three receivers. Exported so a suite can drive the
111
+ * fan-out without a live subscription; never throws.
112
+ */
113
+ function handleAgentModelChange(change, publish) {
114
+ logger.info('model-changed', {
115
+ worktreeId: change.worktreeId,
116
+ cliToolId: change.cliToolId,
117
+ instanceId: change.instanceId,
118
+ from: change.from,
119
+ to: change.to,
120
+ source: change.source,
121
+ });
122
+ const messageFrame = recordModelChangeHistory(change);
123
+ try {
124
+ if (messageFrame)
125
+ publish(change.worktreeId, messageFrame);
126
+ publish(change.worktreeId, buildModelChangedEvent(change));
127
+ }
128
+ catch (error) {
129
+ logger.warn('model-change-broadcast-failed', {
130
+ worktreeId: change.worktreeId,
131
+ instanceId: change.instanceId,
132
+ error: error instanceof Error ? error.message : String(error),
133
+ });
134
+ }
135
+ // Fire-and-forget: `notifyModelChangePush` contains its own failures and
136
+ // logs its own decision, and nothing here has anything to do with the result.
137
+ void (0, model_change_push_notifier_1.notifyModelChangePush)(change);
138
+ }
139
+ /**
140
+ * Subscribe to the model edge and fan it out.
141
+ *
142
+ * Idempotent: calling it again replaces the previous subscription rather than
143
+ * adding a second one, so a re-entered `setupWebSocket` cannot double-send.
144
+ *
145
+ * @param publish - Room broadcaster, normally `ws-server`'s internal one.
146
+ * @returns The unsubscribe function (also reachable as
147
+ * {@link stopModelChangeBroadcast}).
148
+ */
149
+ function startModelChangeBroadcast(publish) {
150
+ stopModelChangeBroadcast();
151
+ const unsubscribe = (0, agent_event_state_1.onAgentModelChange)((change) => {
152
+ handleAgentModelChange(change, publish);
153
+ });
154
+ globalThis.__modelChangeBroadcastUnsubscribe = unsubscribe;
155
+ return unsubscribe;
156
+ }
157
+ /**
158
+ * Drop the subscription, if any. Safe to call when none is active — and called
159
+ * from `stopWaitingStatusBroadcast`, i.e. from `closeWebSocket`.
160
+ */
161
+ function stopModelChangeBroadcast() {
162
+ const existing = globalThis.__modelChangeBroadcastUnsubscribe;
163
+ if (existing) {
164
+ existing();
165
+ globalThis.__modelChangeBroadcastUnsubscribe = undefined;
166
+ }
167
+ }
168
+ /** Whether a subscription is currently active. Test seam. */
169
+ function isModelChangeBroadcastActive() {
170
+ return globalThis.__modelChangeBroadcastUnsubscribe !== undefined;
171
+ }
@@ -9,7 +9,7 @@
9
9
  * the canonical {@link RealtimeEvent}.
10
10
  */
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.MESSAGES_INVALIDATED_EVENT_TYPE = exports.MAX_CHAT_TURN_PROGRESS_BODY_LENGTH = exports.CHAT_TURN_PROGRESS_MIN_INTERVAL_MS = exports.CHAT_TURN_PROGRESS_EVENT_TYPE = exports.VERSION_MISMATCH_EVENT_TYPE = exports.CLIENT_VERSION_MESSAGE_TYPE = void 0;
12
+ exports.MODEL_CHANGED_EVENT_TYPE = exports.MESSAGES_INVALIDATED_EVENT_TYPE = exports.MAX_CHAT_TURN_PROGRESS_BODY_LENGTH = exports.CHAT_TURN_PROGRESS_MIN_INTERVAL_MS = exports.CHAT_TURN_PROGRESS_EVENT_TYPE = exports.VERSION_MISMATCH_EVENT_TYPE = exports.CLIENT_VERSION_MESSAGE_TYPE = void 0;
13
13
  exports.isVersionMismatch = isVersionMismatch;
14
14
  exports.truncateChatTurnProgressBody = truncateChatTurnProgressBody;
15
15
  exports.parseRealtimeEvent = parseRealtimeEvent;
@@ -143,6 +143,24 @@ function truncateChatTurnProgressBody(body, maxLength = exports.MAX_CHAT_TURN_PR
143
143
  * an omitted field would simply never match.
144
144
  */
145
145
  exports.MESSAGES_INVALIDATED_EVENT_TYPE = 'messages_invalidated';
146
+ /**
147
+ * "This instance is now on a different model" (Issue #2357).
148
+ *
149
+ * Emitted once per transition from `agent-event-state`'s model edge, on the
150
+ * same room broadcast `session_status_changed` rides — so every client that
151
+ * subscribed to the worktree hears it, and one that never subscribed does not.
152
+ * It is its own type rather than a field on `session_status_changed` because
153
+ * the consumers do not overlap: the phone's session row is the only thing that
154
+ * reacts, and every `session_status_changed` listener would otherwise have to
155
+ * learn to ignore it.
156
+ *
157
+ * `from` and `to` are the resolved values `sessionStatusByInstance[].model`
158
+ * publishes, verbatim — the client shows them, it does not compare them. The
159
+ * suppression rules (`null → value`, `value → null`, a first sighting, a
160
+ * spelling change) are applied by the producer, and there is nothing here for
161
+ * a client to re-judge.
162
+ */
163
+ exports.MODEL_CHANGED_EVENT_TYPE = 'model_changed';
146
164
  /**
147
165
  * Parse a raw WebSocket frame into the inner realtime event.
148
166
  *
@@ -37,6 +37,7 @@ exports.buildWaitingStatusEvent = buildWaitingStatusEvent;
37
37
  exports.startWaitingStatusBroadcast = startWaitingStatusBroadcast;
38
38
  exports.stopWaitingStatusBroadcast = stopWaitingStatusBroadcast;
39
39
  exports.isWaitingStatusBroadcastActive = isWaitingStatusBroadcastActive;
40
+ const model_change_broadcast_1 = require("../../lib/realtime/model-change-broadcast");
40
41
  const waiting_episode_state_1 = require("../../lib/session/waiting-episode-state");
41
42
  /**
42
43
  * Translate a waiting crossing into the frame clients receive.
@@ -63,6 +64,14 @@ function buildWaitingStatusEvent(transition) {
63
64
  * Idempotent: calling it again replaces the previous subscription rather than
64
65
  * adding a second one, so a re-entered `setupWebSocket` cannot double-send.
65
66
  *
67
+ * Issue #2357: this is also where the model edge is armed. `setupWebSocket`
68
+ * calls exactly one function to start the edge → room subscriptions, and it
69
+ * is this one; the model-change fan-out (`model-change-broadcast`) needs the
70
+ * same publisher for the same reason the waiting edge does — the closure has
71
+ * to hold the bundle's own `rooms` — so it is started here with it, and
72
+ * stopped with it below, rather than growing a second arming call in
73
+ * `ws-server` for every edge that comes along.
74
+ *
66
75
  * @param publish - Room broadcaster, normally `ws-server`'s internal one.
67
76
  * @returns The unsubscribe function (also reachable as
68
77
  * {@link stopWaitingStatusBroadcast}).
@@ -73,12 +82,15 @@ function startWaitingStatusBroadcast(publish) {
73
82
  publish(transition.worktreeId, buildWaitingStatusEvent(transition));
74
83
  });
75
84
  globalThis.__waitingStatusBroadcastUnsubscribe = unsubscribe;
85
+ (0, model_change_broadcast_1.startModelChangeBroadcast)(publish);
76
86
  return unsubscribe;
77
87
  }
78
88
  /**
79
89
  * Drop the subscription, if any. Safe to call when none is active — and called
80
90
  * from `closeWebSocket`, so a suite that stands a server up and tears it down
81
91
  * does not leave a listener pointed at a dead room map.
92
+ *
93
+ * Issue #2357: drops the model edge's subscription with it, for the same reason.
82
94
  */
83
95
  function stopWaitingStatusBroadcast() {
84
96
  const existing = globalThis.__waitingStatusBroadcastUnsubscribe;
@@ -86,6 +98,7 @@ function stopWaitingStatusBroadcast() {
86
98
  existing();
87
99
  globalThis.__waitingStatusBroadcastUnsubscribe = undefined;
88
100
  }
101
+ (0, model_change_broadcast_1.stopModelChangeBroadcast)();
89
102
  }
90
103
  /** Whether a subscription is currently active. Test seam. */
91
104
  function isWaitingStatusBroadcastActive() {