commandmate 0.45.1 → 0.46.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 (296) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +302 -298
  3. package/.next/app-path-routes-manifest.json +15 -15
  4. package/.next/build-manifest.json +5 -5
  5. package/.next/prerender-manifest.json +9 -9
  6. package/.next/react-loadable-manifest.json +4 -4
  7. package/.next/required-server-files.json +1 -1
  8. package/.next/server/app/_not-found/page.js +1 -1
  9. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  10. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
  12. package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/app/release-notes/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  18. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/capabilities/route.js +1 -1
  20. package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  22. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  24. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  25. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  27. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  28. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  30. package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
  31. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
  37. package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
  38. package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  40. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  41. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  42. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  43. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  44. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  45. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  46. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  47. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  48. package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
  49. package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
  50. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  51. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  52. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  53. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  54. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  55. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  57. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  58. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  60. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  61. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  63. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  64. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  65. package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
  66. package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
  67. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  68. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +3 -3
  69. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  70. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  71. package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
  72. package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
  73. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  74. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +3 -3
  75. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  76. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  78. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  79. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  80. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  81. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  82. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  83. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  84. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  85. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  86. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  87. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  88. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  90. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  91. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  93. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  94. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  96. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  97. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  98. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  99. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  100. package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
  101. package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  103. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  104. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  105. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  106. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  107. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  108. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  109. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  110. package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
  111. package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
  112. package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
  113. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  114. package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
  115. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  116. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  117. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +3 -3
  118. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +3 -3
  120. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  121. package/.next/server/app/api/worktrees/[id]/schedules/route.js +3 -3
  122. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  124. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  127. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  129. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  130. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  132. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  133. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  135. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  136. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  137. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  138. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  139. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  141. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  142. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  146. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  148. package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
  149. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  150. package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
  151. package/.next/server/app/api/worktrees/route.js +1 -1
  152. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  153. package/.next/server/app/login/page.js +1 -1
  154. package/.next/server/app/login/page.js.nft.json +1 -1
  155. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  156. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  157. package/.next/server/app/more/page.js +1 -1
  158. package/.next/server/app/more/page.js.nft.json +1 -1
  159. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  160. package/.next/server/app/offline/page.js +1 -1
  161. package/.next/server/app/offline/page.js.nft.json +1 -1
  162. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  163. package/.next/server/app/page.js +1 -1
  164. package/.next/server/app/page.js.nft.json +1 -1
  165. package/.next/server/app/page_client-reference-manifest.js +1 -1
  166. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  167. package/.next/server/app/repositories/page.js +2 -2
  168. package/.next/server/app/repositories/page.js.nft.json +1 -1
  169. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  170. package/.next/server/app/review/page.js +1 -1
  171. package/.next/server/app/review/page.js.nft.json +1 -1
  172. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  173. package/.next/server/app/sessions/page.js +1 -1
  174. package/.next/server/app/sessions/page.js.nft.json +1 -1
  175. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  176. package/.next/server/app/skills/[skillId]/page.js +1 -1
  177. package/.next/server/app/skills/[skillId]/page.js.nft.json +1 -1
  178. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  179. package/.next/server/app/skills/installed/page.js +1 -1
  180. package/.next/server/app/skills/installed/page.js.nft.json +1 -1
  181. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  182. package/.next/server/app/skills/page.js +1 -1
  183. package/.next/server/app/skills/page.js.nft.json +1 -1
  184. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  185. package/.next/server/app/worktrees/[id]/files/[...path]/page.js +1 -1
  186. package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +1 -1
  187. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  188. package/.next/server/app/worktrees/[id]/page.js +12 -9
  189. package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
  190. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  191. package/.next/server/app/worktrees/[id]/terminal/page.js +1 -1
  192. package/.next/server/app/worktrees/[id]/terminal/page.js.nft.json +1 -1
  193. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  194. package/.next/server/app-paths-manifest.json +15 -15
  195. package/.next/server/chunks/1341.js +1 -1
  196. package/.next/server/chunks/1501.js +2 -2
  197. package/.next/server/chunks/2119.js +1 -1
  198. package/.next/server/chunks/2283.js +15 -13
  199. package/.next/server/chunks/2404.js +4 -4
  200. package/.next/server/chunks/2445.js +1 -1
  201. package/.next/server/chunks/2560.js +1 -1
  202. package/.next/server/chunks/3543.js +1 -1
  203. package/.next/server/chunks/3945.js +1 -1
  204. package/.next/server/chunks/4072.js +15 -0
  205. package/.next/server/chunks/4207.js +1 -1
  206. package/.next/server/chunks/4718.js +3 -3
  207. package/.next/server/chunks/4837.js +3 -3
  208. package/.next/server/chunks/5625.js +1 -1
  209. package/.next/server/chunks/6130.js +1 -1
  210. package/.next/server/chunks/6345.js +1 -0
  211. package/.next/server/chunks/6401.js +1 -1
  212. package/.next/server/chunks/6722.js +1 -0
  213. package/.next/server/chunks/8098.js +1 -1
  214. package/.next/server/chunks/8356.js +1 -1
  215. package/.next/server/chunks/8581.js +25 -29
  216. package/.next/server/chunks/8728.js +1 -1
  217. package/.next/server/chunks/8800.js +4 -4
  218. package/.next/server/chunks/9731.js +1 -1
  219. package/.next/server/middleware-build-manifest.js +1 -1
  220. package/.next/server/middleware-manifest.json +5 -5
  221. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  222. package/.next/server/pages/500.html +1 -1
  223. package/.next/server/pages/_error.js +2 -2
  224. package/.next/server/server-reference-manifest.json +1 -1
  225. package/.next/static/chunks/{2407-86890b00eeecf391.js → 2407-acb644c5487e1720.js} +1 -1
  226. package/.next/static/chunks/{2619-a305ad4810f1393a.js → 2619-04bc32f026a0d946.js} +1 -1
  227. package/.next/static/chunks/2717.21abf5b6bbd45520.js +1 -0
  228. package/.next/static/chunks/2770-db80aedf6384d594.js +1 -0
  229. package/.next/static/chunks/2863-6a07ec82fb52f4dd.js +1 -0
  230. package/.next/static/chunks/3201-c01f1feed69020e6.js +1 -0
  231. package/.next/static/chunks/4768-ad6f82f034f21eae.js +1 -0
  232. package/.next/static/chunks/5371-a94ed618148287a0.js +1 -0
  233. package/.next/static/chunks/5794-947fb4934d8be193.js +1 -0
  234. package/.next/static/chunks/5927-54315d21f323e204.js +1 -0
  235. package/.next/static/chunks/602-25e45a2422d2a3ea.js +1 -0
  236. package/.next/static/chunks/6606-02ddc006686a6b7d.js +1 -0
  237. package/.next/static/chunks/6654-f3534f35f16644bc.js +1 -0
  238. package/.next/static/chunks/7730-011e137be64403ae.js +1 -0
  239. package/.next/static/chunks/8165-263172c17ae8e8c3.js +1 -0
  240. package/.next/static/chunks/8606-cf6bdbff44a764cf.js +1 -0
  241. package/.next/static/chunks/934-a37509667baa86ee.js +1 -0
  242. package/.next/static/chunks/9465-e5a351baa941f31b.js +1 -0
  243. package/.next/static/chunks/app/layout-ae30ce63569c22be.js +1 -0
  244. package/.next/static/chunks/app/repositories/page-71f5a5ac29b0370d.js +1 -0
  245. package/.next/static/chunks/app/review/page-e2fd4a590646a2d8.js +1 -0
  246. package/.next/static/chunks/app/sessions/page-9859ed61e93e6890.js +1 -0
  247. package/.next/static/chunks/app/skills/[skillId]/page-52ba58712faf3378.js +1 -0
  248. package/.next/static/chunks/app/worktrees/[id]/page-2eb1d0fd0a077b7e.js +1 -0
  249. package/.next/static/chunks/app/worktrees/[id]/terminal/{page-c601f3b3ece6557e.js → page-373ea37b16d930c7.js} +1 -1
  250. package/.next/static/chunks/{webpack-ee3ccbe378c4aa06.js → webpack-c0b821f340afdebf.js} +1 -1
  251. package/.next/static/css/743f79ff19ab91e9.css +1 -0
  252. package/.next/trace +13 -13
  253. package/dist/server/locales/en/worktree.json +46 -16
  254. package/dist/server/locales/ja/worktree.json +46 -16
  255. package/dist/server/src/config/activity-bar-config.js +56 -9
  256. package/dist/server/src/lib/polling/prompt-dedup-state.js +26 -7
  257. package/dist/server/src/lib/polling/prompt-dedup.js +50 -22
  258. package/dist/server/src/lib/polling/response-checker.js +14 -1
  259. package/dist/server/src/lib/polling/response-dedup.js +104 -20
  260. package/dist/server/src/lib/polling/response-poller-core.js +47 -26
  261. package/dist/server/src/lib/session/next-action-helper.js +2 -15
  262. package/dist/server/src/lib/verification/env-clean-gate.js +14 -1
  263. package/dist/server/src/lib/verification/gate-runner.js +17 -11
  264. package/dist/server/src/lib/verification/scope-gate.js +169 -3
  265. package/dist/server/src/types/sidebar.js +1 -0
  266. package/docs/en/architecture.md +26 -14
  267. package/docs/en/user-guide/webapp-guide.md +31 -18
  268. package/package.json +1 -1
  269. package/release-notes/0.46.0.json +110 -0
  270. package/.next/server/chunks/1674.js +0 -15
  271. package/.next/server/chunks/6927.js +0 -1
  272. package/.next/server/chunks/9355.js +0 -1
  273. package/.next/static/chunks/1642-0f1bf8fb8161e10a.js +0 -1
  274. package/.next/static/chunks/2770-827a64760bab8a3a.js +0 -1
  275. package/.next/static/chunks/3922.0bc2e4e168d2b522.js +0 -1
  276. package/.next/static/chunks/4727-4c69d1aa4118cc09.js +0 -1
  277. package/.next/static/chunks/4768-fc0aa1d0891cac08.js +0 -1
  278. package/.next/static/chunks/5371-af1c2b68e983da61.js +0 -1
  279. package/.next/static/chunks/5521-c358c31f60e5e689.js +0 -1
  280. package/.next/static/chunks/6192-a67df090838b9aad.js +0 -1
  281. package/.next/static/chunks/6322-f1b30ed0ee43518f.js +0 -1
  282. package/.next/static/chunks/6654-ac431270fac1a283.js +0 -1
  283. package/.next/static/chunks/8165-3525fb42f1b4976e.js +0 -1
  284. package/.next/static/chunks/8318-01e7d1e5ad0a15a3.js +0 -1
  285. package/.next/static/chunks/8606-79c36d4c204bbd38.js +0 -1
  286. package/.next/static/chunks/9619-6c17a271f7f98fbb.js +0 -1
  287. package/.next/static/chunks/998-2eb5883186abd0bd.js +0 -1
  288. package/.next/static/chunks/app/layout-eaa6365f8f942e88.js +0 -1
  289. package/.next/static/chunks/app/repositories/page-6f7511f4ac8449e2.js +0 -1
  290. package/.next/static/chunks/app/review/page-95f749caae382f46.js +0 -1
  291. package/.next/static/chunks/app/sessions/page-ebfed2c80e916fb8.js +0 -1
  292. package/.next/static/chunks/app/skills/[skillId]/page-e4b14031f946c007.js +0 -1
  293. package/.next/static/chunks/app/worktrees/[id]/page-3372b78fde232b1f.js +0 -1
  294. package/.next/static/css/6faeb04a0b6819d4.css +0 -1
  295. /package/.next/static/{vYIpFRCU_Mt0wtG8F_3-6 → zI2nQ6WKboSbFbMF4EtrJ}/_buildManifest.js +0 -0
  296. /package/.next/static/{vYIpFRCU_Mt0wtG8F_3-6 → zI2nQ6WKboSbFbMF4EtrJ}/_ssgManifest.js +0 -0
@@ -55,11 +55,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
55
55
  exports.DUPLICATE_RESPONSE_SKIP_LOG_TICK_INTERVAL = exports.STRUCTURED_HISTORY_RECHECK_TICK_INTERVAL = void 0;
56
56
  exports.isDuplicateResponse = isDuplicateResponse;
57
57
  exports.claimDuplicateResponseSkipLog = claimDuplicateResponseSkipLog;
58
+ exports.resetDuplicateResponseSkipStreak = resetDuplicateResponseSkipStreak;
58
59
  exports.markStructuredHistoryRecheckPending = markStructuredHistoryRecheckPending;
59
60
  exports.settleStructuredHistoryRecheck = settleStructuredHistoryRecheck;
60
61
  exports.claimStructuredHistoryRecheck = claimStructuredHistoryRecheck;
61
62
  exports.clearResponseHashCache = clearResponseHashCache;
62
63
  exports.renameResponseHashCacheKey = renameResponseHashCacheKey;
64
+ exports.renameResponseHashCacheKeys = renameResponseHashCacheKeys;
63
65
  const crypto_1 = require("crypto");
64
66
  const global_state_1 = require("../global-state");
65
67
  const responseHashCache = (0, global_state_1.getOrInitGlobal)('__responseHashCache', () => new Map());
@@ -97,7 +99,9 @@ exports.STRUCTURED_HISTORY_RECHECK_TICK_INTERVAL = 3;
97
99
  *
98
100
  * On `globalThis` for the same reason `responseHashCache` is, and cleared and
99
101
  * moved at exactly the same moments — see the module comment. A new
100
- * (non-duplicate) response restarts it in {@link isDuplicateResponse}.
102
+ * (non-duplicate) response restarts it in {@link isDuplicateResponse}, and a
103
+ * tick that reads the frame and finds no reply on it ends the run without
104
+ * touching the hash — see {@link resetDuplicateResponseSkipStreak} (#3552).
101
105
  */
102
106
  const duplicateResponseSkipStreak = (0, global_state_1.getOrInitGlobal)('__duplicateResponseSkipStreak', () => new Map());
103
107
  /**
@@ -148,6 +152,28 @@ function claimDuplicateResponseSkipLog(pollerKey) {
148
152
  const suppressed = consecutive === 1 ? 0 : exports.DUPLICATE_RESPONSE_SKIP_LOG_TICK_INTERVAL - 1;
149
153
  return { log, consecutive, suppressed };
150
154
  }
155
+ /**
156
+ * End the current run of duplicate response ticks for this pollerKey without
157
+ * touching the cached hash (Issue #3552).
158
+ *
159
+ * Called by `response-checker` on the ticks that read the frame and decide it
160
+ * is not a duplicate of the saved reply: an unfinished frame
161
+ * (`extractCompletedTurn`), a finished frame with a live prompt on it, and a
162
+ * finished frame whose response is empty. The reply is no longer on screen, so
163
+ * if the same reply comes back the next duplicate is the first of a new run and
164
+ * logs. The hash stays: whether the returning reply is saved again is the
165
+ * guard's question (#1268), and this only thins the log line (#3519).
166
+ *
167
+ * Not called at the entrance of a finished frame — that would make every
168
+ * duplicate tick the first of its run — nor on a tick that skipped extraction
169
+ * on the line count (null) or returned on the cursor: neither says the reply
170
+ * has left the screen (the same judgement as #3538).
171
+ *
172
+ * @param pollerKey - Poller key ("worktreeId:instanceId")
173
+ */
174
+ function resetDuplicateResponseSkipStreak(pollerKey) {
175
+ duplicateResponseSkipStreak.delete(pollerKey);
176
+ }
151
177
  /**
152
178
  * Note that the transcript reader has unfinished business for this pollerKey
153
179
  * (Issue #2399).
@@ -233,6 +259,55 @@ function clearResponseHashCache(pollerKey) {
233
259
  // Issue #3519: the skip count is about the same hash.
234
260
  duplicateResponseSkipStreak.delete(pollerKey);
235
261
  }
262
+ /** Remove everything held under `key` and return it. */
263
+ function takeResponseDedupState(key) {
264
+ const state = {
265
+ hash: responseHashCache.get(key),
266
+ recheck: structuredHistoryRecheckCache.get(key),
267
+ streak: duplicateResponseSkipStreak.get(key),
268
+ };
269
+ responseHashCache.delete(key);
270
+ structuredHistoryRecheckCache.delete(key);
271
+ duplicateResponseSkipStreak.delete(key);
272
+ return state;
273
+ }
274
+ /**
275
+ * Write state lifted by {@link takeResponseDedupState} under `key`.
276
+ *
277
+ * `replaceRecheckWithHash` is the one difference between the batch and the
278
+ * single rename (Issue #3553): when a hash lands, the batch also replaces the
279
+ * recheck under `key` — deleting it when the source had none — so a recheck
280
+ * owed for a different turn is not attached to the hash that just arrived. The
281
+ * single rename keeps its earlier behaviour and leaves such a recheck alone.
282
+ */
283
+ function putResponseDedupState(key, state, replaceRecheckWithHash) {
284
+ if (state.hash !== undefined)
285
+ responseHashCache.set(key, state.hash);
286
+ // Issue #2399: the recheck caveat moves with the hash it is about. Leaving it
287
+ // behind would strand a turn whose transcript is still open — the new key
288
+ // starts owing nothing, so every later tick returns at the dedup guard and the
289
+ // Markdown row is never written. It moves without a hash too: the
290
+ // `lineCountIsCursor` path marks it with no hash cached.
291
+ if (state.recheck !== undefined) {
292
+ structuredHistoryRecheckCache.set(key, state.recheck);
293
+ }
294
+ else if (replaceRecheckWithHash && state.hash !== undefined) {
295
+ structuredHistoryRecheckCache.delete(key);
296
+ }
297
+ // Issue #3519: the skip count moves with the hash too, so a rename mid-run
298
+ // does not restart the thinning and log as if a new run had begun.
299
+ // Issue #3552: whenever the hash under `newKey` is replaced, so is its count
300
+ // — a count left over from the hash that was there before is about a
301
+ // different reply (the same rule as `renamePromptHashCacheKey`, #3538).
302
+ if (state.hash === undefined)
303
+ return;
304
+ if (state.streak !== undefined) {
305
+ duplicateResponseSkipStreak.set(key, state.streak);
306
+ }
307
+ else {
308
+ duplicateResponseSkipStreak.delete(key);
309
+ }
310
+ }
236
311
  /**
237
312
  * Move the cached hash from one pollerKey to another.
238
313
  *
@@ -241,7 +316,8 @@ function clearResponseHashCache(pollerKey) {
241
316
  * during THIS turn?", and the turn does not end just because the ID moved —
242
317
  * dropping it would re-save the screen currently on display.
243
318
  *
244
- * No-op when nothing is cached under `oldKey`.
319
+ * No-op when nothing is cached under `oldKey`. A batch of renames whose keys
320
+ * overlap must go through {@link renameResponseHashCacheKeys} instead.
245
321
  *
246
322
  * @param oldKey - Poller key the cache entry lives under
247
323
  * @param newKey - Poller key it should live under
@@ -249,22 +325,30 @@ function clearResponseHashCache(pollerKey) {
249
325
  function renameResponseHashCacheKey(oldKey, newKey) {
250
326
  if (oldKey === newKey)
251
327
  return;
252
- const hash = responseHashCache.get(oldKey);
253
- responseHashCache.delete(oldKey);
254
- if (hash !== undefined)
255
- responseHashCache.set(newKey, hash);
256
- // Issue #2399: the recheck caveat moves with the hash it is about. Leaving it
257
- // behind would strand a turn whose transcript is still open — the new key
258
- // starts owing nothing, so every later tick returns at the dedup guard and the
259
- // Markdown row is never written.
260
- const ticksToWait = structuredHistoryRecheckCache.get(oldKey);
261
- structuredHistoryRecheckCache.delete(oldKey);
262
- if (ticksToWait !== undefined)
263
- structuredHistoryRecheckCache.set(newKey, ticksToWait);
264
- // Issue #3519: the skip count moves with the hash too, so a rename mid-run
265
- // does not restart the thinning and log as if a new run had begun.
266
- const streak = duplicateResponseSkipStreak.get(oldKey);
267
- duplicateResponseSkipStreak.delete(oldKey);
268
- if (streak !== undefined)
269
- duplicateResponseSkipStreak.set(newKey, streak);
328
+ putResponseDedupState(newKey, takeResponseDedupState(oldKey), false);
329
+ }
330
+ /**
331
+ * Move the response dedup state of a whole batch of pollerKeys (Issue #3553).
332
+ *
333
+ * Every source key is lifted before any destination is written, so a swap
334
+ * (A→B, B→A) or a chain (A→B→C) cannot overwrite a source that has not moved
335
+ * yet — calling {@link renameResponseHashCacheKey} once per pair would leave
336
+ * A with its own state and B empty after a swap. Each destination ends up with
337
+ * exactly what its source held: hash, skip count and recheck, the recheck
338
+ * moving even without a hash. A recheck already at the destination is
339
+ * replaced along with the hash, never kept beside the moved one.
340
+ *
341
+ * Pairs with `oldKey === newKey` are ignored.
342
+ *
343
+ * @param renames - Poller key moves applied together
344
+ */
345
+ function renameResponseHashCacheKeys(renames) {
346
+ const lifted = [];
347
+ for (const { oldKey, newKey } of renames) {
348
+ if (oldKey === newKey)
349
+ continue;
350
+ lifted.push({ newKey, state: takeResponseDedupState(oldKey) });
351
+ }
352
+ for (const { newKey, state } of lifted)
353
+ putResponseDedupState(newKey, state, true);
270
354
  }
@@ -532,8 +532,11 @@ function splitPollerKey(pollerKey) {
532
532
  * one in-flight TUI response may be truncated at the rename boundary; the next
533
533
  * turn accumulates normally.
534
534
  *
535
- * Takes the whole batch because IDs can swap (A→B, B→A): every source key is
536
- * removed before any destination key is written.
535
+ * Takes the whole batch because IDs can swap (A→B, B→A) or chain (A→B→C):
536
+ * every source key is removed before any destination key is written. That
537
+ * includes the dedup state (Issue #3553) — of running pollers and paused chains
538
+ * alike — which is lifted off every source key in one pass and only then
539
+ * written, so a pair handled early cannot overwrite a source handled later.
537
540
  *
538
541
  * @param renames - Worktree ID pairs being applied
539
542
  * @param resolveCliToolId - Maps a poller's (worktree, instance) back to its CLI
@@ -596,33 +599,21 @@ function migrateResponsePollerWorktreeIds(renames, resolveCliToolId) {
596
599
  coordinator.pendingRestart.delete(move.oldKey);
597
600
  carried.set(move.newKey, { startedAt: exports.pollingStartTimes.get(move.oldKey) });
598
601
  exports.pollingStartTimes.delete(move.oldKey);
599
- (0, prompt_dedup_1.renamePromptHashCacheKey)(move.oldKey, move.newKey);
600
- (0, response_dedup_1.renameResponseHashCacheKey)(move.oldKey, move.newKey);
601
- // Issue #1695: the prompt hash moved on the line above, so the guard keeps
602
- // suppressing the prompt on screen under the new ID. Its tally has to move
603
- // with it, or `capture --json` reports zero skips for a session that is
604
- // still skipping. Old worktree ID comes back out of the key we just left.
605
- const movedFrom = splitPollerKey(move.oldKey);
606
- if (movedFrom) {
607
- (0, prompt_dedup_state_1.renamePromptDedupSkips)(movedFrom.worktreeId, move.newWorktreeId, move.cliToolId, move.instanceId);
608
- }
609
602
  (0, tui_accumulator_1.clearTuiAccumulator)(move.oldKey);
610
603
  }
604
+ // Stop the abandoned pollers before any dedup state is written: the stop
605
+ // clears every cache under its key, and that key can be the destination of
606
+ // another move in this batch (A:x paused → B:x while B:x is abandoned).
607
+ // Stopped afterwards, it erased the state that had just arrived (#3553).
608
+ // An abandoned key is never a move source, so nothing still to be moved is
609
+ // lost here; and the paused chains are collected after it, as before, so a
610
+ // pause the stop ends is not carried.
611
611
  for (const pollerKey of abandoned) {
612
612
  stopPollingByKey(pollerKey);
613
613
  logger.warn('poller:migrate-abandoned', { pollerKey });
614
614
  }
615
- // Phase 2: restart each poller under its new identity.
616
- for (const move of moves) {
617
- const startedAt = carried.get(move.newKey)?.startedAt;
618
- exports.pollingStartTimes.set(move.newKey, startedAt ?? Date.now());
619
- if (isFullScreenTui(move.cliToolId)) {
620
- (0, tui_accumulator_1.initTuiAccumulator)(move.newKey);
621
- }
622
- scheduleNextResponsePoll(move.newWorktreeId, move.cliToolId, move.instanceId);
623
- }
624
- // Issue #2230: a chain paused on a prompt has no timer, so the loop above
625
- // never sees it — but it is holding the response hash for the turn it paused
615
+ // Issue #2230: a chain paused on a prompt has no timer, so the loops here
616
+ // never see it — but it is holding the response hash for the turn it paused
626
617
  // on, and `/respond` will resume it under the NEW ID. Move the hash and the
627
618
  // pause mark with it; the chain itself stays paused until that resume.
628
619
  const pausedMoves = [];
@@ -635,11 +626,41 @@ function migrateResponsePollerWorktreeIds(renames, resolveCliToolId) {
635
626
  continue;
636
627
  pausedMoves.push({ oldKey: pollerKey, newKey: `${newWorktreeId}:${parts.instanceId}` });
637
628
  }
629
+ // Issue #3553: the dedup state of the whole batch moves in one call per map
630
+ // family, each lifting every source before writing any destination. Re-keyed
631
+ // pair by pair, a swap left A with its own state and B empty.
632
+ (0, prompt_dedup_1.renamePromptHashCacheKeys)(moves);
633
+ (0, response_dedup_1.renameResponseHashCacheKeys)([...moves, ...pausedMoves]);
634
+ // Issue #1695: the prompt hash moved above, so the guard keeps suppressing
635
+ // the prompt on screen under the new ID. Its tally has to move with it, or
636
+ // `capture --json` reports zero skips for a session that is still skipping.
637
+ // Old worktree ID comes back out of the key being left.
638
+ (0, prompt_dedup_state_1.renamePromptDedupSkipsBatch)(moves.flatMap((move) => {
639
+ const movedFrom = splitPollerKey(move.oldKey);
640
+ return movedFrom
641
+ ? [{
642
+ oldWorktreeId: movedFrom.worktreeId,
643
+ newWorktreeId: move.newWorktreeId,
644
+ cliToolId: move.cliToolId,
645
+ instanceId: move.instanceId,
646
+ }]
647
+ : [];
648
+ }));
649
+ // Phase 2: restart each poller under its new identity.
650
+ for (const move of moves) {
651
+ const startedAt = carried.get(move.newKey)?.startedAt;
652
+ exports.pollingStartTimes.set(move.newKey, startedAt ?? Date.now());
653
+ if (isFullScreenTui(move.cliToolId)) {
654
+ (0, tui_accumulator_1.initTuiAccumulator)(move.newKey);
655
+ }
656
+ scheduleNextResponsePoll(move.newWorktreeId, move.cliToolId, move.instanceId);
657
+ }
658
+ // Issue #2230: the pause marks of the chains collected above follow their
659
+ // hashes (moved with the batch). All removed before any is added, for the
660
+ // same swap reason.
638
661
  for (const move of pausedMoves)
639
662
  coordinator.pausedOnPrompt.delete(move.oldKey);
640
- for (const move of pausedMoves) {
641
- (0, response_dedup_1.renameResponseHashCacheKey)(move.oldKey, move.newKey);
663
+ for (const move of pausedMoves)
642
664
  coordinator.pausedOnPrompt.add(move.newKey);
643
- }
644
665
  return moves;
645
666
  }
@@ -3,14 +3,14 @@
3
3
  * Next Action Helper - Derived state for worktree next actions and review status.
4
4
  *
5
5
  * Issue #600: UX refresh - provides getNextAction() and getReviewStatus()
6
- * for Review screen and WorktreeCard display.
6
+ * for the Review screen (via `/api/worktrees`) and the sidebar row
7
+ * (`toBranchItem` in `src/types/sidebar.ts`).
7
8
  *
8
9
  * Uses exhaustive check (satisfies never) pattern to catch future
9
10
  * SessionStatus extensions at compile time [DR2-005].
10
11
  */
11
12
  Object.defineProperty(exports, "__esModule", { value: true });
12
13
  exports.NEXT_ACTION_KEYS = void 0;
13
- exports.isNextActionKey = isNextActionKey;
14
14
  exports.getNextAction = getNextAction;
15
15
  exports.getReviewStatus = getReviewStatus;
16
16
  /**
@@ -31,19 +31,6 @@ exports.NEXT_ACTION_KEYS = {
31
31
  checkStalled: 'nextAction.checkStalled',
32
32
  running: 'nextAction.running',
33
33
  };
34
- const NEXT_ACTION_KEY_SET = new Set(Object.values(exports.NEXT_ACTION_KEYS));
35
- /**
36
- * Whether a value is a key this module produces (Issue #1787).
37
- *
38
- * `Worktree.nextAction` is a plain `string` on the wire, and a server that
39
- * predates this Issue still sends the old English literal. Callers must gate
40
- * `t()` on this: next-intl reports a missing key by rendering the key path, so
41
- * feeding it `"Approve / Reject"` would put `worktree.Approve / Reject` on
42
- * screen. Anything that fails this test is rendered verbatim instead.
43
- */
44
- function isNextActionKey(value) {
45
- return NEXT_ACTION_KEY_SET.has(value);
46
- }
47
34
  /**
48
35
  * Determine the next action for a given session state.
49
36
  *
@@ -39,6 +39,7 @@ exports.ENV_CLEAN_GUIDANCE = exports.MAX_REPORTED_ENV_CHANGES = exports.isLivePi
39
39
  exports.resolveRequireEnvClean = resolveRequireEnvClean;
40
40
  exports.attributeSessionName = attributeSessionName;
41
41
  exports.attributeAnchor = attributeAnchor;
42
+ exports.isZcompdumpEntry = isZcompdumpEntry;
42
43
  exports.demoVitestPid = demoVitestPid;
43
44
  exports.attributeHomeEntry = attributeHomeEntry;
44
45
  exports.resolveTaskSessionName = resolveTaskSessionName;
@@ -200,6 +201,17 @@ exports.readLivePidCwd = readLivePidCwd;
200
201
  * established.
201
202
  */
202
203
  const DEMO_VITEST_HOME_ENTRY = /^\.commandmate-demo-vitest-([1-9]\d*)$/;
204
+ /**
205
+ * zsh's `compinit` cache: `~/.zcompdump` itself, and the `~/.zcompdump.<host>.<pid>`
206
+ * scratch file it writes before renaming (#3664). A worker's shell start makes
207
+ * it; the pid in it is already gone by the time the gate looks. Only these two
208
+ * shapes — any other `.zcompdump*` name stays a violation.
209
+ */
210
+ const ZCOMPDUMP_HOME_ENTRY = /^\.zcompdump(?:\.[A-Za-z0-9._-]+\.[1-9]\d*)?$/;
211
+ /** Whether a `$HOME` entry name is a zsh compinit cache file (#3664). */
212
+ function isZcompdumpEntry(name) {
213
+ return ZCOMPDUMP_HOME_ENTRY.test(name);
214
+ }
203
215
  const isLivePid = (pid) => {
204
216
  try {
205
217
  process.kill(pid, 0);
@@ -581,7 +593,8 @@ function diffEnvSnapshots(baseline, final, context, options = {}) {
581
593
  const afterKeys = new Set(after.entries.map((entry) => entry.key));
582
594
  // Only `home-entries`, and only by the whole name: the same string under
583
595
  // `~/.commandmate` is a different directory and stays counted.
584
- const isIgnoredByConfig = (entry) => probeId === 'home-entries' && ignoredHomeEntries.has(entry.key);
596
+ const isIgnoredByConfig = (entry) => probeId === 'home-entries' &&
597
+ (ignoredHomeEntries.has(entry.key) || isZcompdumpEntry(entry.key));
585
598
  const added = [];
586
599
  const ignoredAdded = [];
587
600
  const taskSessionAdded = [];
@@ -751,7 +751,10 @@ function namesOpencodeInstance(db, worktreeId, instanceId) {
751
751
  * gates — the precise failure `verify-completion.sh` was written to catch.
752
752
  *
753
753
  * Contract files are evidence of the *orchestrator*, not of the agent, so
754
- * neither side counts them (see {@link CONTRACT_DIR_PREFIX}).
754
+ * neither side counts them (see {@link CONTRACT_DIR_PREFIX}). Nor is the
755
+ * orchestrator's module-reference fold commit (orchestrate 6-4, judged by
756
+ * scope-gate's `collectBranchCommitChanges`): a branch that holds only a fold
757
+ * has no work of the worker's in it (#3633).
755
758
  *
756
759
  * ## The opencode second witness (Issue #2043)
757
760
  *
@@ -796,18 +799,20 @@ async function evaluateWorkEvidence(worktreePath, baseRef, requireCommit, agentE
796
799
  // pathspec is not exclusions alone, and it anchors both patterns at the root
797
800
  // rather than at cwd. A setup commit that only carries the contract must not
798
801
  // read as a commit's worth of work.
799
- const revList = await runGit([
800
- 'rev-list',
801
- '--count',
802
- `${base}..HEAD`,
803
- '--',
804
- ':(top)',
805
- `:(exclude,top)${scope_gate_1.CONTRACT_DIR_PREFIX}`,
806
- ], worktreePath);
802
+ const revList = await runGit(['rev-list', `${base}..HEAD`, '--', ':(top)', `:(exclude,top)${scope_gate_1.CONTRACT_DIR_PREFIX}`], worktreePath);
807
803
  if (revList.code !== 0) {
808
- return done('error', `work-evidence: 'git rev-list --count ${base}..HEAD' failed.`, null);
804
+ return done('error', `work-evidence: 'git rev-list ${base}..HEAD' failed.`, null);
809
805
  }
810
- const commitCount = Number.parseInt(revList.stdout.trim(), 10);
806
+ // The orchestrator's fold commit is not the worker's (#3633), by the same
807
+ // rule the scope gate drops what only folds touched (#3588).
808
+ const branchChanges = await (0, scope_gate_1.collectBranchCommitChanges)(worktreePath, base);
809
+ if ('error' in branchChanges) {
810
+ return done('error', `work-evidence: ${branchChanges.error}`, null);
811
+ }
812
+ const foldShas = new Set(branchChanges.changes.filter((c) => c.fold).map((c) => c.sha));
813
+ const branchShas = revList.stdout.split('\n').filter((sha) => sha.trim() !== '');
814
+ const foldCount = branchShas.filter((sha) => foldShas.has(sha)).length;
815
+ const commitCount = branchShas.length - foldCount;
811
816
  // -z -uall for the same reasons scope-gate uses them: the human format
812
817
  // C-quotes paths with spaces and joins renames with ` -> `, and the default
813
818
  // untracked mode collapses a fresh `.commandmate/tasks/` to one directory
@@ -841,6 +846,7 @@ async function evaluateWorkEvidence(worktreePath, baseRef, requireCommit, agentE
841
846
  const summary = `work-evidence: baseRef=${baseRef} commits=${commitCount} uncommitted=${uncommittedCount}` +
842
847
  (requireCommit.required ? ' requireCommit=true' : '') +
843
848
  ' (contract files excluded)' +
849
+ (foldCount > 0 ? ` (${foldCount} orchestrator fold commit(s) excluded)` : '') +
844
850
  (skillInstalledCount > 0
845
851
  ? ` (${skillInstalledCount} CommandMate-installed Skill file(s) excluded)`
846
852
  : '') +
@@ -30,11 +30,16 @@
30
30
  * @module lib/verification/scope-gate
31
31
  */
32
32
  Object.defineProperty(exports, "__esModule", { value: true });
33
- exports.SCOPE_SKIP_NOT_REQUIRED = exports.SCOPE_SKIP_NO_CONTRACT = exports.ScopeMatcher = exports.CONTRACT_DIR_PREFIX = exports.SCOPE_EXEMPT_CONTRACT_PATH = exports.SCOPE_EXEMPT_ALWAYS_ALLOWED = exports.SCOPE_PATTERN_ARROW = exports.ALWAYS_ALLOWED_PREFIX = exports.SCOPE_ALLOW_GUIDANCE = exports.MAX_REPORTED_VIOLATIONS = void 0;
33
+ exports.SCOPE_SKIP_NOT_REQUIRED = exports.SCOPE_SKIP_NO_CONTRACT = exports.ScopeMatcher = exports.ORCHESTRATOR_FOLD_TRAILER_VALUE = exports.ORCHESTRATOR_FOLD_TRAILER_KEY = exports.ORCHESTRATOR_FILES = exports.CONTRACT_DIR_PREFIX = exports.SCOPE_EXEMPT_CONTRACT_PATH = exports.SCOPE_EXEMPT_ALWAYS_ALLOWED = exports.SCOPE_PATTERN_ARROW = exports.ALWAYS_ALLOWED_PREFIX = exports.SCOPE_ALLOW_GUIDANCE = exports.MAX_REPORTED_VIOLATIONS = void 0;
34
+ exports.isOrchestratorOnlyCommit = isOrchestratorOnlyCommit;
35
+ exports.parseBranchCommits = parseBranchCommits;
36
+ exports.isFoldCommit = isFoldCommit;
37
+ exports.orchestratorOnlyPaths = orchestratorOnlyPaths;
34
38
  exports.isContractPath = isContractPath;
35
39
  exports.parsePorcelainEntries = parsePorcelainEntries;
36
40
  exports.parsePorcelainStatusEntries = parsePorcelainStatusEntries;
37
41
  exports.isSkillInstalledUntrackedEntry = isSkillInstalledUntrackedEntry;
42
+ exports.collectBranchCommitChanges = collectBranchCommitChanges;
38
43
  exports.collectChangedPaths = collectChangedPaths;
39
44
  exports.scopeSkipDetachedContract = scopeSkipDetachedContract;
40
45
  exports.evaluateScope = evaluateScope;
@@ -117,6 +122,88 @@ exports.SCOPE_EXEMPT_CONTRACT_PATH = '(exempt: contract path)';
117
122
  * explicit `deny` can still catch an agent weakening its own gates.
118
123
  */
119
124
  exports.CONTRACT_DIR_PREFIX = '.commandmate/tasks/';
125
+ /**
126
+ * Files the orchestrator commits on a PR branch after the worker's checks
127
+ * (orchestrate 6-4: the module-reference fold) (#3588).
128
+ *
129
+ * Copy of `ORCHESTRATOR_FILES` in `scripts/orchestrate/pr-common.mjs`, where
130
+ * `merge-pr.mjs` uses the same file rule to look past a fold commit to the
131
+ * worker's HEAD. A test imports the .mjs and compares the two arrays, so the
132
+ * merge side and this gate cannot drift apart.
133
+ */
134
+ exports.ORCHESTRATOR_FILES = ['docs/module-reference.md'];
135
+ /**
136
+ * The trailer that marks a fold commit, read the way `git interpret-trailers`
137
+ * reads it — from the message's trailer block only, so the same words in the
138
+ * middle of a body do not count (#3588).
139
+ *
140
+ * The file set alone cannot tell the orchestrator's fold from a worker that
141
+ * committed module-reference on its own, so this gate also requires the
142
+ * trailer. `workHeads` in pr-common.mjs deliberately does not: the merge side
143
+ * only decides which HEAD's records to read, and stays permissive.
144
+ */
145
+ exports.ORCHESTRATOR_FOLD_TRAILER_KEY = 'Orchestrator-Fold';
146
+ exports.ORCHESTRATOR_FOLD_TRAILER_VALUE = 'module-reference';
147
+ /**
148
+ * Whether a commit's file list is the orchestrator's: at least one file, and
149
+ * every file in {@link ORCHESTRATOR_FILES} — the file rule of `workHeads` in
150
+ * `scripts/orchestrate/pr-common.mjs` (#3588).
151
+ */
152
+ function isOrchestratorOnlyCommit(files) {
153
+ return files.length > 0 && files.every((file) => exports.ORCHESTRATOR_FILES.includes(file));
154
+ }
155
+ const FIELD_SEPARATOR = '\x1f';
156
+ const TRAILER_SEPARATOR = '\x1e';
157
+ /**
158
+ * Per commit: sha, parents, fold trailer values. With `-z` each record ends in
159
+ * NUL, which no commit message can contain; the sha and parent fields are hex,
160
+ * so only the trailer field is free text, and it is last.
161
+ */
162
+ const BRANCH_COMMITS_FORMAT = `--format=%H%x1f%P%x1f%(trailers:key=${exports.ORCHESTRATOR_FOLD_TRAILER_KEY},` +
163
+ 'valueonly,unfold,separator=%x1e)';
164
+ /** Parse `git log -z` output in {@link BRANCH_COMMITS_FORMAT} (#3588). */
165
+ function parseBranchCommits(output) {
166
+ const commits = [];
167
+ for (const record of output.split('\0')) {
168
+ const first = record.indexOf(FIELD_SEPARATOR);
169
+ const second = record.indexOf(FIELD_SEPARATOR, first + 1);
170
+ if (first <= 0 || second < 0)
171
+ continue;
172
+ const trailers = record.slice(second + 1);
173
+ commits.push({
174
+ sha: record.slice(0, first),
175
+ parents: record.slice(first + 1, second).split(' ').filter(Boolean),
176
+ foldTrailers: trailers === '' ? [] : trailers.split(TRAILER_SEPARATOR),
177
+ });
178
+ }
179
+ return commits;
180
+ }
181
+ /** Whether a non-merge commit is a fold (#3588): the trailer and the file rule both hold. */
182
+ function isFoldCommit(commit, files) {
183
+ return (commit.parents.length === 1 &&
184
+ commit.foldTrailers.includes(exports.ORCHESTRATOR_FOLD_TRAILER_VALUE) &&
185
+ isOrchestratorOnlyCommit(files));
186
+ }
187
+ /**
188
+ * Paths that only fold commits touched on the branch (#3588).
189
+ *
190
+ * A path any other non-merge commit also touched is not returned: a worker
191
+ * that committed `docs/module-reference.md` itself — alone or with other
192
+ * files — is still judged on it. Merges are not passed in
193
+ * ({@link collectBranchCommitChanges} skips them): a merge's own edit inside
194
+ * {@link ORCHESTRATOR_FILES} is the approved integration of a refresh and
195
+ * leaves a fold-only path excluded, while its edits elsewhere stay in the
196
+ * branch diff and are judged as the worker's.
197
+ */
198
+ function orchestratorOnlyPaths(commits) {
199
+ const byOrchestrator = new Set();
200
+ const byWorker = new Set();
201
+ for (const commit of commits) {
202
+ const target = commit.fold ? byOrchestrator : byWorker;
203
+ commit.files.forEach((file) => target.add(file));
204
+ }
205
+ return new Set([...byOrchestrator].filter((path) => !byWorker.has(path)));
206
+ }
120
207
  /** Whether git reported a path that {@link CONTRACT_DIR_PREFIX} excludes. */
121
208
  function isContractPath(path) {
122
209
  return path.startsWith(exports.CONTRACT_DIR_PREFIX);
@@ -352,6 +439,61 @@ function parsePorcelainStatusEntries(output) {
352
439
  function isSkillInstalledUntrackedEntry(entry, owned) {
353
440
  return entry.status === '??' && entry.paths.every((path) => owned.has(path));
354
441
  }
442
+ /**
443
+ * The non-merge commits of `<base>..HEAD` of a worktree, each judged by
444
+ * {@link isFoldCommit} (#3588). The scope gate drops what only folds touched
445
+ * ({@link orchestratorOnlyPaths}); the work-evidence gate does not count a
446
+ * fold as the worker's commit (#3633). Empty when no commit carries the fold
447
+ * trailer: none can be a fold, so the per-commit calls are skipped.
448
+ *
449
+ * File lists come from one `git diff-tree -z` per commit rather than from one
450
+ * `git log --name-only -z` stream: in that stream a commit header and a path
451
+ * are both NUL-terminated fields, and a path may start with a newline or a
452
+ * control character, so no parse of it can tell them apart. diff-tree prints
453
+ * paths and nothing else.
454
+ *
455
+ * A merge's own edits are split by path. Inside {@link ORCHESTRATOR_FILES}
456
+ * they are the approved integration — orchestrate lets the orchestrator
457
+ * resolve a refresh conflict in shared files such as module-reference by
458
+ * machine — so a fold-only path stays excluded. Every other path a merge edits
459
+ * is never a candidate (a fold changes only ORCHESTRATOR_FILES), so it stays in
460
+ * the branch diff and scope judges it as the worker's. Merges are therefore
461
+ * skipped here without asking `git diff-tree --cc`.
462
+ */
463
+ async function collectBranchCommitChanges(worktreePath, base) {
464
+ const log = await runGit(['log', '-z', BRANCH_COMMITS_FORMAT, `${base}..HEAD`], worktreePath);
465
+ if (log.code !== 0) {
466
+ return {
467
+ error: `'git log ${base}..HEAD' failed.` + (log.stderr.trim() ? `\n${log.stderr.trim()}` : ''),
468
+ };
469
+ }
470
+ const commits = parseBranchCommits(log.stdout);
471
+ // Nothing to exclude without a trailer; skip the per-commit calls.
472
+ if (!commits.some((commit) => commit.foldTrailers.length > 0))
473
+ return { changes: [] };
474
+ const changes = [];
475
+ for (const commit of commits) {
476
+ if (commit.parents.length !== 1)
477
+ continue;
478
+ const tree = await runGit(['diff-tree', '--no-commit-id', '--name-only', '-z', '--no-renames', '-r', commit.sha], worktreePath);
479
+ if (tree.code !== 0) {
480
+ return {
481
+ error: `'git diff-tree ${commit.sha}' failed.` +
482
+ (tree.stderr.trim() ? `\n${tree.stderr.trim()}` : ''),
483
+ };
484
+ }
485
+ const files = splitNul(tree.stdout);
486
+ changes.push({ sha: commit.sha, files, fold: isFoldCommit(commit, files) });
487
+ }
488
+ return { changes };
489
+ }
490
+ /** {@link orchestratorOnlyPaths} for `<base>..HEAD` of a worktree (#3588). */
491
+ async function collectOrchestratorOnlyPaths(worktreePath, base) {
492
+ const result = await collectBranchCommitChanges(worktreePath, base);
493
+ if ('error' in result)
494
+ return result;
495
+ return { paths: orchestratorOnlyPaths(result.changes) };
496
+ }
355
497
  /**
356
498
  * Every path this worktree changed relative to `baseRef`.
357
499
  *
@@ -379,6 +521,18 @@ async function collectChangedPaths(worktreePath, baseRef) {
379
521
  (diff.stderr.trim() ? `\n${diff.stderr.trim()}` : ''),
380
522
  };
381
523
  }
524
+ // The orchestrator's fold commit (6-4) can sit under a re-instructed worker's
525
+ // commits; what only it touched is not the worker's change (#3588).
526
+ const orchestratorOnly = await collectOrchestratorOnlyPaths(worktreePath, base);
527
+ if ('error' in orchestratorOnly)
528
+ return orchestratorOnly;
529
+ const orchestratorExcluded = new Set();
530
+ const committed = splitNul(diff.stdout).filter((path) => {
531
+ if (!orchestratorOnly.paths.has(path))
532
+ return true;
533
+ orchestratorExcluded.add(path);
534
+ return false;
535
+ });
382
536
  // -uall: without it a new directory collapses to a single `?? dir/` entry, and
383
537
  // the gate would judge a directory name instead of the files inside it.
384
538
  const status = await runGit(['status', '--porcelain', '-z', '--untracked-files=all'], worktreePath);
@@ -405,12 +559,14 @@ async function collectChangedPaths(worktreePath, baseRef) {
405
559
  return true;
406
560
  });
407
561
  // Both sides are filtered, not just the working tree: an orchestrator may
408
- // also have committed the contract as a setup commit (#1580).
409
- const paths = new Set([...splitNul(diff.stdout), ...workingTree.flatMap((entry) => entry.paths)].filter((path) => !isContractPath(path)));
562
+ // also have committed the contract as a setup commit (#1580). The working
563
+ // tree keeps an uncommitted module-reference edit: no fold commit made it.
564
+ const paths = new Set([...committed, ...workingTree.flatMap((entry) => entry.paths)].filter((path) => !isContractPath(path)));
410
565
  return {
411
566
  paths: [...paths].sort(),
412
567
  mergeBase: base,
413
568
  agentStateExcluded: [...agentStateExcluded].sort(),
569
+ orchestratorExcluded: [...orchestratorExcluded].filter((path) => !paths.has(path)).sort(),
414
570
  };
415
571
  }
416
572
  // =============================================================================
@@ -470,6 +626,15 @@ function formatAgentStateExcluded(excluded) {
470
626
  ...(remainder > 0 ? [` ... (+${remainder} more)`] : []),
471
627
  ];
472
628
  }
629
+ /** The `excluded:` section naming orchestrator-only committed paths (#3588). */
630
+ function formatOrchestratorExcluded(excluded) {
631
+ if (excluded.length === 0)
632
+ return [];
633
+ return [
634
+ 'excluded (changed only by orchestrator commits, not counted as change):',
635
+ ...excluded.map((path) => ` ~ ${path}`),
636
+ ];
637
+ }
473
638
  /**
474
639
  * Reasons the gate has nothing to judge, phrased for `log_tail`.
475
640
  *
@@ -546,6 +711,7 @@ async function evaluateScope(worktreePath, scope, requireScopeClean, baseRef, co
546
711
  `deny: ${formatPatterns(scope.deny)}`,
547
712
  ...formatAdmitted(admitted),
548
713
  ...formatAgentStateExcluded(changed.agentStateExcluded),
714
+ ...formatOrchestratorExcluded(changed.orchestratorExcluded),
549
715
  ].join('\n');
550
716
  if (violations.length === 0) {
551
717
  // An empty change set passes: work-evidence is the gate that judges "nothing
@@ -337,6 +337,7 @@ function toBranchItem(worktree) {
337
337
  exitedInstanceIds,
338
338
  unclassifiedInstanceIds,
339
339
  worktreePath: worktree.path,
340
+ worktreeStatus: worktree.status ?? null,
340
341
  waitingKind,
341
342
  awaitingInstruction,
342
343
  // `promptType` mirrors what `/api/worktrees` does with the same data