commandmate 0.22.2 → 0.23.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 (476) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +108 -108
  3. package/.next/app-path-routes-manifest.json +21 -21
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/prerender-manifest.json +12 -12
  6. package/.next/required-server-files.json +1 -1
  7. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  8. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  9. package/.next/server/app/api/app/update-check/route.js +1 -1
  10. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/assistant/conversation/route.js +1 -1
  12. package/.next/server/app/api/assistant/conversation/route.js.nft.json +1 -1
  13. package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/assistant/current-output/route.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 +1 -1
  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 +3 -3
  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 +1 -1
  30. package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
  31. package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/daily-summary/route.js +1 -1
  36. package/.next/server/app/api/daily-summary/route.js.nft.json +1 -1
  37. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  38. package/.next/server/app/api/daily-summary/status/route.js +1 -1
  39. package/.next/server/app/api/daily-summary/status/route.js.nft.json +1 -1
  40. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  41. package/.next/server/app/api/external-apps/[id]/health/route.js +1 -1
  42. package/.next/server/app/api/external-apps/[id]/health/route.js.nft.json +1 -1
  43. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  44. package/.next/server/app/api/external-apps/[id]/route.js +1 -1
  45. package/.next/server/app/api/external-apps/[id]/route.js.nft.json +1 -1
  46. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  47. package/.next/server/app/api/external-apps/route.js +1 -1
  48. package/.next/server/app/api/external-apps/route.js.nft.json +1 -1
  49. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  50. package/.next/server/app/api/fs/browse/route.js +1 -1
  51. package/.next/server/app/api/fs/browse/route.js.nft.json +1 -1
  52. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  53. package/.next/server/app/api/fs/recent-paths/route.js +1 -1
  54. package/.next/server/app/api/fs/recent-paths/route.js.nft.json +1 -1
  55. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/hooks/agent-event/route.js +1 -1
  57. package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
  58. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/hooks/claude-done/route.js +1 -1
  60. package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
  61. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/hooks/permission-request/route.js +1 -1
  63. package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
  64. package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
  65. package/.next/server/app/api/metrics/vibe/route.js +1 -1
  66. package/.next/server/app/api/metrics/vibe/route.js.nft.json +1 -1
  67. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  68. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/push/subscriptions/route.js +1 -1
  70. package/.next/server/app/api/push/subscriptions/route.js.nft.json +1 -1
  71. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  72. package/.next/server/app/api/push/vapid/route.js +1 -1
  73. package/.next/server/app/api/push/vapid/route.js.nft.json +1 -1
  74. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  75. package/.next/server/app/api/repositories/[id]/route.js +1 -1
  76. package/.next/server/app/api/repositories/[id]/route.js.nft.json +1 -1
  77. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  78. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route.js +1 -1
  79. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route.js.nft.json +1 -1
  80. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  81. package/.next/server/app/api/repositories/[id]/todos/route.js +1 -1
  82. package/.next/server/app/api/repositories/[id]/todos/route.js.nft.json +1 -1
  83. package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
  84. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  85. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
  86. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  87. package/.next/server/app/api/repositories/clone/route.js +1 -1
  88. package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
  89. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  90. package/.next/server/app/api/repositories/excluded/route.js +1 -1
  91. package/.next/server/app/api/repositories/excluded/route.js.nft.json +1 -1
  92. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  93. package/.next/server/app/api/repositories/restore/route.js +1 -1
  94. package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
  95. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  96. package/.next/server/app/api/repositories/route.js +1 -1
  97. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  98. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  99. package/.next/server/app/api/repositories/scan/route.js +1 -1
  100. package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
  101. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/repositories/sync/route.js +1 -1
  103. package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
  104. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  105. package/.next/server/app/api/repositories/validate-path/route.js +1 -1
  106. package/.next/server/app/api/repositories/validate-path/route.js.nft.json +1 -1
  107. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  108. package/.next/server/app/api/sidebar/group-order/route.js +1 -1
  109. package/.next/server/app/api/sidebar/group-order/route.js.nft.json +1 -1
  110. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  111. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  112. package/.next/server/app/api/skills/installations/route.js +1 -1
  113. package/.next/server/app/api/skills/installations/route.js.nft.json +1 -1
  114. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  115. package/.next/server/app/api/skills/operations/route.js +1 -1
  116. package/.next/server/app/api/skills/operations/route.js.nft.json +1 -1
  117. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  118. package/.next/server/app/api/skills/reindex/route.js +1 -1
  119. package/.next/server/app/api/skills/reindex/route.js.nft.json +1 -1
  120. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  121. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  122. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  123. package/.next/server/app/api/tasks/[taskId]/cancel/route.js +1 -4
  124. package/.next/server/app/api/tasks/[taskId]/cancel/route.js.nft.json +1 -1
  125. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  126. package/.next/server/app/api/tasks/[taskId]/route.js +1 -4
  127. package/.next/server/app/api/tasks/[taskId]/route.js.nft.json +1 -1
  128. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  129. package/.next/server/app/api/templates/[id]/route.js +1 -1
  130. package/.next/server/app/api/templates/[id]/route.js.nft.json +1 -1
  131. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  132. package/.next/server/app/api/templates/route.js +1 -1
  133. package/.next/server/app/api/templates/route.js.nft.json +1 -1
  134. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  135. package/.next/server/app/api/todos/route.js +1 -1
  136. package/.next/server/app/api/todos/route.js.nft.json +1 -1
  137. package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
  138. package/.next/server/app/api/verification/runs/[runId]/route.js +1 -1
  139. package/.next/server/app/api/verification/runs/[runId]/route.js.nft.json +1 -1
  140. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  141. package/.next/server/app/api/verification/runs/route.js +1 -1
  142. package/.next/server/app/api/verification/runs/route.js.nft.json +1 -1
  143. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  146. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
  148. package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
  149. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/cli-tool/route.js +1 -1
  151. package/.next/server/app/api/worktrees/[id]/cli-tool/route.js.nft.json +1 -1
  152. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  153. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +2 -2
  154. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js.nft.json +1 -1
  155. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  157. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  158. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  159. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js.nft.json +1 -1
  161. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  162. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +2 -2
  163. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js.nft.json +1 -1
  164. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  165. package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js +1 -1
  166. package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js.nft.json +1 -1
  167. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  168. package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js.nft.json +1 -1
  170. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  171. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js.nft.json +1 -1
  173. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  174. package/.next/server/app/api/worktrees/[id]/git/branches/route.js +1 -1
  175. package/.next/server/app/api/worktrees/[id]/git/branches/route.js.nft.json +1 -1
  176. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  177. package/.next/server/app/api/worktrees/[id]/git/checkout/route.js +1 -1
  178. package/.next/server/app/api/worktrees/[id]/git/checkout/route.js.nft.json +1 -1
  179. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  180. package/.next/server/app/api/worktrees/[id]/git/commit/route.js +1 -1
  181. package/.next/server/app/api/worktrees/[id]/git/commit/route.js.nft.json +1 -1
  182. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  183. package/.next/server/app/api/worktrees/[id]/git/diff/route.js +1 -1
  184. package/.next/server/app/api/worktrees/[id]/git/diff/route.js.nft.json +1 -1
  185. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  186. package/.next/server/app/api/worktrees/[id]/git/fetch/route.js +1 -1
  187. package/.next/server/app/api/worktrees/[id]/git/fetch/route.js.nft.json +1 -1
  188. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  189. package/.next/server/app/api/worktrees/[id]/git/log/route.js +1 -1
  190. package/.next/server/app/api/worktrees/[id]/git/log/route.js.nft.json +1 -1
  191. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  192. package/.next/server/app/api/worktrees/[id]/git/pull/route.js +1 -1
  193. package/.next/server/app/api/worktrees/[id]/git/pull/route.js.nft.json +1 -1
  194. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  195. package/.next/server/app/api/worktrees/[id]/git/push/route.js +1 -1
  196. package/.next/server/app/api/worktrees/[id]/git/push/route.js.nft.json +1 -1
  197. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  198. package/.next/server/app/api/worktrees/[id]/git/reset/route.js +1 -1
  199. package/.next/server/app/api/worktrees/[id]/git/reset/route.js.nft.json +1 -1
  200. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  201. package/.next/server/app/api/worktrees/[id]/git/revert/route.js +1 -1
  202. package/.next/server/app/api/worktrees/[id]/git/revert/route.js.nft.json +1 -1
  203. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  204. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js +1 -1
  205. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js.nft.json +1 -1
  206. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  207. package/.next/server/app/api/worktrees/[id]/git/stage/route.js +1 -1
  208. package/.next/server/app/api/worktrees/[id]/git/stage/route.js.nft.json +1 -1
  209. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  210. package/.next/server/app/api/worktrees/[id]/git/staged/route.js +1 -1
  211. package/.next/server/app/api/worktrees/[id]/git/staged/route.js.nft.json +1 -1
  212. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  213. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js +1 -1
  214. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js.nft.json +1 -1
  215. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  216. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js +1 -1
  217. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js.nft.json +1 -1
  218. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  219. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js +1 -1
  220. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js.nft.json +1 -1
  221. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  222. package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js +1 -1
  223. package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js.nft.json +1 -1
  224. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  225. package/.next/server/app/api/worktrees/[id]/git/stash/route.js +1 -1
  226. package/.next/server/app/api/worktrees/[id]/git/stash/route.js.nft.json +1 -1
  227. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  228. package/.next/server/app/api/worktrees/[id]/git/status/route.js +1 -1
  229. package/.next/server/app/api/worktrees/[id]/git/status/route.js.nft.json +1 -1
  230. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  231. package/.next/server/app/api/worktrees/[id]/git/unstage/route.js +1 -1
  232. package/.next/server/app/api/worktrees/[id]/git/unstage/route.js.nft.json +1 -1
  233. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  234. package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js +1 -1
  235. package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js.nft.json +1 -1
  236. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  237. package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
  238. package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
  239. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  240. package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
  241. package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
  242. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  243. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js +1 -1
  244. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js.nft.json +1 -1
  245. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  246. package/.next/server/app/api/worktrees/[id]/logs/route.js +1 -1
  247. package/.next/server/app/api/worktrees/[id]/logs/route.js.nft.json +1 -1
  248. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  249. package/.next/server/app/api/worktrees/[id]/marp-render/route.js +3 -3
  250. package/.next/server/app/api/worktrees/[id]/marp-render/route.js.nft.json +1 -1
  251. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  252. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js +1 -1
  253. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js.nft.json +1 -1
  254. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  255. package/.next/server/app/api/worktrees/[id]/memos/route.js +1 -1
  256. package/.next/server/app/api/worktrees/[id]/memos/route.js.nft.json +1 -1
  257. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  258. package/.next/server/app/api/worktrees/[id]/messages/route.js +1 -1
  259. package/.next/server/app/api/worktrees/[id]/messages/route.js.nft.json +1 -1
  260. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  261. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  262. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
  263. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  264. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
  265. package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
  266. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  267. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  268. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  269. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  270. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +2 -2
  271. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js.nft.json +1 -1
  272. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  273. package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +1 -1
  274. package/.next/server/app/api/worktrees/[id]/schedules/active/route.js.nft.json +1 -1
  275. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  276. package/.next/server/app/api/worktrees/[id]/schedules/route.js +3 -3
  277. package/.next/server/app/api/worktrees/[id]/schedules/route.js.nft.json +1 -1
  278. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  279. package/.next/server/app/api/worktrees/[id]/search/route.js +1 -1
  280. package/.next/server/app/api/worktrees/[id]/search/route.js.nft.json +1 -1
  281. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  282. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
  283. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  284. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  285. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +1 -1
  286. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
  287. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  288. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route.js +1 -1
  289. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route.js.nft.json +1 -1
  290. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  291. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js +1 -1
  292. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js.nft.json +1 -1
  293. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  294. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.js +1 -1
  295. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.js.nft.json +1 -1
  296. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  297. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.js +1 -1
  298. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.js.nft.json +1 -1
  299. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  300. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route.js +1 -1
  301. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route.js.nft.json +1 -1
  302. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  303. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route.js +1 -1
  304. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route.js.nft.json +1 -1
  305. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  306. package/.next/server/app/api/worktrees/[id]/skills/route.js +1 -1
  307. package/.next/server/app/api/worktrees/[id]/skills/route.js.nft.json +1 -1
  308. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  309. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
  310. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js.nft.json +1 -1
  311. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  312. package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
  313. package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
  314. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  315. package/.next/server/app/api/worktrees/[id]/start-polling/route.js +1 -1
  316. package/.next/server/app/api/worktrees/[id]/start-polling/route.js.nft.json +1 -1
  317. package/.next/server/app/api/worktrees/[id]/start-polling/route_client-reference-manifest.js +1 -1
  318. package/.next/server/app/api/worktrees/[id]/tasks/route.js +2 -2
  319. package/.next/server/app/api/worktrees/[id]/tasks/route.js.nft.json +1 -1
  320. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  321. package/.next/server/app/api/worktrees/[id]/terminal/route.js +1 -1
  322. package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
  323. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  324. package/.next/server/app/api/worktrees/[id]/timers/history/route.js +1 -1
  325. package/.next/server/app/api/worktrees/[id]/timers/history/route.js.nft.json +1 -1
  326. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  327. package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
  328. package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
  329. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  330. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js +1 -1
  331. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js.nft.json +1 -1
  332. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  333. package/.next/server/app/api/worktrees/[id]/todos/route.js +1 -1
  334. package/.next/server/app/api/worktrees/[id]/todos/route.js.nft.json +1 -1
  335. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  336. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js +1 -1
  337. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js.nft.json +1 -1
  338. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  339. package/.next/server/app/api/worktrees/[id]/tree/route.js +1 -1
  340. package/.next/server/app/api/worktrees/[id]/tree/route.js.nft.json +1 -1
  341. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  342. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route.js +1 -1
  343. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route.js.nft.json +1 -1
  344. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  345. package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -4
  346. package/.next/server/app/api/worktrees/[id]/verify/route.js.nft.json +1 -1
  347. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  348. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route.js +1 -1
  349. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route.js.nft.json +1 -1
  350. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  351. package/.next/server/app/api/worktrees/[id]/verify/runs/route.js +1 -1
  352. package/.next/server/app/api/worktrees/[id]/verify/runs/route.js.nft.json +1 -1
  353. package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
  354. package/.next/server/app/api/worktrees/[id]/viewed/route.js +1 -1
  355. package/.next/server/app/api/worktrees/[id]/viewed/route.js.nft.json +1 -1
  356. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  357. package/.next/server/app/api/worktrees/route.js +1 -1
  358. package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
  359. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  360. package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  361. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  362. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  363. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  364. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  365. package/.next/server/app/page_client-reference-manifest.js +1 -1
  366. package/.next/server/app/proxy/[...path]/route.js +1 -1
  367. package/.next/server/app/proxy/[...path]/route.js.nft.json +1 -1
  368. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  369. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  370. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  371. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  372. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  373. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  374. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  375. package/.next/server/app/worktrees/[id]/files/[...path]/page.js +1 -1
  376. package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +1 -1
  377. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  378. package/.next/server/app/worktrees/[id]/page.js +2 -2
  379. package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
  380. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  381. package/.next/server/app/worktrees/[id]/terminal/page.js +1 -1
  382. package/.next/server/app/worktrees/[id]/terminal/page.js.nft.json +1 -1
  383. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  384. package/.next/server/app-paths-manifest.json +21 -21
  385. package/.next/server/chunks/1029.js +1 -1
  386. package/.next/server/chunks/1068.js +1 -1
  387. package/.next/server/chunks/2119.js +1 -1
  388. package/.next/server/chunks/2404.js +1 -1
  389. package/.next/server/chunks/2445.js +1 -1
  390. package/.next/server/chunks/2546.js +1 -1
  391. package/.next/server/chunks/3241.js +1 -0
  392. package/.next/server/chunks/3417.js +1 -1
  393. package/.next/server/chunks/406.js +10 -6
  394. package/.next/server/chunks/4444.js +1 -1
  395. package/.next/server/chunks/5959.js +4 -5
  396. package/.next/server/chunks/5998.js +1 -12
  397. package/.next/server/chunks/6130.js +1 -1
  398. package/.next/server/chunks/6274.js +3 -3
  399. package/.next/server/chunks/6401.js +1 -1
  400. package/.next/server/chunks/6781.js +1 -0
  401. package/.next/server/chunks/7458.js +6 -0
  402. package/.next/server/chunks/{3753.js → 7970.js} +57 -32
  403. package/.next/server/chunks/8536.js +1 -1
  404. package/.next/server/chunks/8807.js +180 -127
  405. package/.next/server/chunks/9058.js +1 -1
  406. package/.next/server/chunks/9067.js +1 -1
  407. package/.next/server/chunks/9360.js +1 -1
  408. package/.next/server/chunks/9687.js +2 -2
  409. package/.next/server/middleware-manifest.json +5 -5
  410. package/.next/server/pages/500.html +1 -1
  411. package/.next/server/server-reference-manifest.json +1 -1
  412. package/.next/server/src/middleware.js.map +1 -1
  413. package/.next/static/chunks/{6488-53a3e1d78e4fe8f7.js → 6488-95ba9d24a76f0cc5.js} +1 -1
  414. package/.next/static/chunks/app/worktrees/[id]/{page-6dc0b8c4e808ea3e.js → page-966a451ae7b0903a.js} +1 -1
  415. package/.next/trace +12 -12
  416. package/dist/server/src/config/log-config.js +10 -1
  417. package/dist/server/src/config/safe-directory.js +103 -0
  418. package/dist/server/src/config/system-directories.js +74 -9
  419. package/dist/server/src/lib/cli-tools/antigravity.js +19 -2
  420. package/dist/server/src/lib/cli-tools/codex.js +95 -1
  421. package/dist/server/src/lib/cli-tools/copilot.js +30 -1
  422. package/dist/server/src/lib/cli-tools/gemini.js +28 -2
  423. package/dist/server/src/lib/cli-tools/opencode.js +51 -2
  424. package/dist/server/src/lib/git/git-default-branch.js +59 -0
  425. package/dist/server/src/lib/hooks/agent-event-service.js +205 -0
  426. package/dist/server/src/lib/hooks/agent-event-types.js +7 -86
  427. package/dist/server/src/lib/hooks/hook-settings-generator.js +26 -11
  428. package/dist/server/src/lib/hooks/permission-decision-service.js +269 -0
  429. package/dist/server/src/lib/hooks/sources/abstain.js +78 -0
  430. package/dist/server/src/lib/hooks/sources/antigravity/hooks-config.js +372 -0
  431. package/dist/server/src/lib/hooks/sources/antigravity/source.js +225 -0
  432. package/dist/server/src/lib/hooks/sources/antigravity/tool-id.js +16 -0
  433. package/dist/server/src/lib/hooks/sources/claude/source.js +143 -0
  434. package/dist/server/src/lib/hooks/sources/claude/tool-id.js +18 -0
  435. package/dist/server/src/lib/hooks/sources/codex/hooks-config.js +465 -0
  436. package/dist/server/src/lib/hooks/sources/codex/source.js +138 -0
  437. package/dist/server/src/lib/hooks/sources/codex/tool-id.js +15 -0
  438. package/dist/server/src/lib/hooks/sources/copilot/hook-settings.js +473 -0
  439. package/dist/server/src/lib/hooks/sources/copilot/source.js +210 -0
  440. package/dist/server/src/lib/hooks/sources/copilot/tool-id.js +15 -0
  441. package/dist/server/src/lib/hooks/sources/define-source.js +169 -0
  442. package/dist/server/src/lib/hooks/sources/event-mapper.js +157 -0
  443. package/dist/server/src/lib/hooks/sources/gemini/event-vocabulary.js +102 -0
  444. package/dist/server/src/lib/hooks/sources/gemini/settings-generator.js +315 -0
  445. package/dist/server/src/lib/hooks/sources/gemini/shared-config-tree.js +103 -0
  446. package/dist/server/src/lib/hooks/sources/gemini/source.js +151 -0
  447. package/dist/server/src/lib/hooks/sources/gemini/tool-id.js +17 -0
  448. package/dist/server/src/lib/hooks/sources/hook-event-vocabulary.js +111 -0
  449. package/dist/server/src/lib/hooks/sources/index.js +62 -0
  450. package/dist/server/src/lib/hooks/sources/legacy-relay.js +84 -0
  451. package/dist/server/src/lib/hooks/sources/opencode/client.js +299 -0
  452. package/dist/server/src/lib/hooks/sources/opencode/ingest.js +261 -0
  453. package/dist/server/src/lib/hooks/sources/opencode/mappers.js +154 -0
  454. package/dist/server/src/lib/hooks/sources/opencode/payloads.js +189 -0
  455. package/dist/server/src/lib/hooks/sources/opencode/ports.js +295 -0
  456. package/dist/server/src/lib/hooks/sources/opencode/runtime.js +159 -0
  457. package/dist/server/src/lib/hooks/sources/opencode/source.js +250 -0
  458. package/dist/server/src/lib/hooks/sources/opencode/subscription.js +422 -0
  459. package/dist/server/src/lib/hooks/sources/opencode/tool-id.js +14 -0
  460. package/dist/server/src/lib/hooks/sources/opencode/turn-gate.js +193 -0
  461. package/dist/server/src/lib/hooks/sources/pending-decisions.js +127 -0
  462. package/dist/server/src/lib/hooks/sources/registry.js +111 -0
  463. package/dist/server/src/lib/hooks/sources/types.js +46 -0
  464. package/dist/server/src/lib/session/agent-session-lifecycle.js +82 -0
  465. package/dist/server/src/lib/session/claude-session.js +10 -3
  466. package/dist/server/src/lib/tasks/contract-message.js +175 -0
  467. package/dist/server/src/lib/verification/env-clean-gate.js +320 -0
  468. package/dist/server/src/lib/verification/env-snapshot.js +474 -0
  469. package/dist/server/src/lib/verification/gate-runner.js +802 -0
  470. package/dist/server/src/lib/verification/scope-gate.js +402 -0
  471. package/dist/server/src/lib/verification/verify-config.js +281 -0
  472. package/package.json +1 -1
  473. package/scripts/hooks/cmate-agent-event.sh +73 -3
  474. package/.next/server/chunks/8856.js +0 -4
  475. /package/.next/static/{XpKfn5x6H-mtTaXI9yNmb → wH6K6QNPHSdATFkVoIcy3}/_buildManifest.js +0 -0
  476. /package/.next/static/{XpKfn5x6H-mtTaXI9yNmb → wH6K6QNPHSdATFkVoIcy3}/_ssgManifest.js +0 -0
@@ -0,0 +1,402 @@
1
+ "use strict";
2
+ /**
3
+ * Built-in `scope` gate: reconcile what actually changed in the worktree against
4
+ * the contract's `scope.allow` / `scope.deny` (Issue #1546, Phase 2-2).
5
+ *
6
+ * Canonical spec: docs/design/task-contract.md §2.2
7
+ *
8
+ * A parallel worker that edits a shared config file, or quietly rewrites a
9
+ * module another worker owns, produces a green run and a broken integration.
10
+ * The contract already declares which paths the task may touch; this gate is
11
+ * what makes that declaration something other than a comment.
12
+ *
13
+ * Promoted from `.claude/skills/orchestrate-monitor/scripts/verify-scope.sh`.
14
+ * That script is a *grep* guard over one file rather than a diff-versus-glob
15
+ * check, so what carries over is not its logic but the two ways it false-reported
16
+ * (both recorded in feedback_orchestrate_monitor_started_guard):
17
+ *
18
+ * 1. It matched a forbidden pattern that appeared only in explanatory prose.
19
+ * The analogue here is judging text instead of paths, so nothing in this
20
+ * module ever greps content: the file set comes from git plumbing, and the
21
+ * verdict comes from matching whole paths.
22
+ * 2. Its `grep -c ... || echo 0` idiom emitted a two-line "0\n0" that the
23
+ * caller read as a count. The analogue is git output that parses into
24
+ * phantom entries, so every git call here is `-z`: the human formats quote
25
+ * and arrow-join paths, and splitting those on whitespace invents files
26
+ * that do not exist.
27
+ *
28
+ * Server-only: spawns git and is called from the verification engine.
29
+ *
30
+ * @module lib/verification/scope-gate
31
+ */
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.ALWAYS_ALLOWED_PREFIX = exports.SCOPE_ALLOW_GUIDANCE = exports.MAX_REPORTED_VIOLATIONS = void 0;
34
+ exports.isContractPath = isContractPath;
35
+ exports.parsePorcelainEntries = parsePorcelainEntries;
36
+ exports.collectChangedPaths = collectChangedPaths;
37
+ exports.scopeSkipDetachedContract = scopeSkipDetachedContract;
38
+ exports.evaluateScope = evaluateScope;
39
+ const child_process_1 = require("child_process");
40
+ /**
41
+ * Violations listed in `log_tail` before the rest are summarised as a count.
42
+ *
43
+ * A worker that ran in the wrong directory can put thousands of paths out of
44
+ * scope, and log_tail is stored per gate in SQLite.
45
+ */
46
+ exports.MAX_REPORTED_VIOLATIONS = 100;
47
+ /**
48
+ * Actionable coda appended to every scope failure report (#1683).
49
+ *
50
+ * The violating paths alone say *what* failed but not what to do about it —
51
+ * #1678 B-2 is a worker structurally unable to pass because a lockfile was
52
+ * missing from the issue's target-file list, and nothing in the output said so.
53
+ * The wording answers both directions a violation can resolve: widen the
54
+ * declared scope when the diff is intended, revert when it is not. Re-sending
55
+ * is named because scope is judged from the contract's send-time snapshot, so
56
+ * editing the YAML in place changes nothing.
57
+ */
58
+ exports.SCOPE_ALLOW_GUIDANCE = "To allow this diff, add the paths above to the contract's scope.allow (the " +
59
+ "issue's target-file list) and re-send the task (`send --contract`) — scope " +
60
+ 'is judged from the send-time snapshot, so editing the contract file alone ' +
61
+ 'changes nothing. A path matching deny: is a deliberate prohibition; revert ' +
62
+ 'it instead.';
63
+ /**
64
+ * Paths that are in scope no matter what the contract says.
65
+ *
66
+ * The contract file lives here, so a contract whose own `allow` list forgot to
67
+ * mention `.commandmate/` would fail the moment it was committed — the scope
68
+ * declaration would make its own storage a violation. The exemption covers the
69
+ * `allow` requirement only; an explicit `deny` still applies, because a deny is
70
+ * a deliberate prohibition and silently ignoring one is worse than the accident
71
+ * this exemption prevents.
72
+ */
73
+ exports.ALWAYS_ALLOWED_PREFIX = '.commandmate/';
74
+ /**
75
+ * Execution contracts, dropped from both gates' change sets entirely (#1580).
76
+ *
77
+ * An orchestrator writes `.commandmate/tasks/<task>.yaml` into a worktree and
78
+ * sends immediately, without committing it. Counting that file as change makes
79
+ * an agent that did nothing indistinguishable from one that did something:
80
+ * work-evidence sees a dirty tree and passes, and the run that should have been
81
+ * `not_started` collects a row of green gates instead.
82
+ *
83
+ * Dropping it is tamper-safe because the contract is snapshotted into
84
+ * `tasks.contract_json` at send time (src/lib/db/tasks-db.ts), so editing the
85
+ * file afterwards cannot change what the run is judged against.
86
+ * `.commandmate/verify.yaml` has no such snapshot — the gates are re-read from
87
+ * the file on every run — so it stays in the change set, where a contract's
88
+ * explicit `deny` can still catch an agent weakening its own gates.
89
+ */
90
+ exports.CONTRACT_DIR_PREFIX = '.commandmate/tasks/';
91
+ /** Whether git reported a path that {@link CONTRACT_DIR_PREFIX} excludes. */
92
+ function isContractPath(path) {
93
+ return path.startsWith(exports.CONTRACT_DIR_PREFIX);
94
+ }
95
+ // =============================================================================
96
+ // Glob matching
97
+ // =============================================================================
98
+ /**
99
+ * Translate a scope glob into an anchored regular expression.
100
+ *
101
+ * Deliberately a small, documented subset rather than a glob library. The
102
+ * semantics are fixed in docs/design/task-contract.md §2.2:
103
+ *
104
+ * - `**` as a whole path segment crosses directory boundaries, including zero of
105
+ * them: `a/**` matches `a/b` and `a/b/c`, `**\/*.ts` matches `x.ts`.
106
+ * - `*` and `?` never cross `/`. Leading dots are ordinary characters, so
107
+ * `.github/**` and `*.md` behave the way they read.
108
+ * - `{a,b}` is alternation, nestable. Unbalanced braces are literal, as in a
109
+ * shell — `src/{a` is a path with a brace in it, not a syntax error.
110
+ * - `[` and `]` are **literal**. This repository routes through
111
+ * `src/app/proxy/[...path]/`, and treating those as character classes would
112
+ * make the pattern that names them match nothing at all — a silent no-match is
113
+ * the failure mode this gate exists to avoid.
114
+ * - A pattern that matches a directory also matches everything beneath it, so
115
+ * `src/lib`, `src/lib/` and `src/lib/**` all mean the same thing. Without this
116
+ * rule, `allow: ["src/lib/verification"]` — the way people write a directory —
117
+ * would put every file inside it out of scope.
118
+ */
119
+ function globToRegExp(rawPattern) {
120
+ // A trailing slash carries no information once the rule above applies.
121
+ const pattern = rawPattern.replace(/\/+$/, '');
122
+ const bracesBalanced = hasBalancedBraces(pattern);
123
+ let source = '';
124
+ let depth = 0;
125
+ let i = 0;
126
+ while (i < pattern.length) {
127
+ const char = pattern[i];
128
+ if (char === '*') {
129
+ let end = i;
130
+ while (pattern[end] === '*')
131
+ end += 1;
132
+ const isGlobstar = end - i > 1;
133
+ const atSegmentStart = i === 0 || pattern[i - 1] === '/';
134
+ if (isGlobstar && atSegmentStart && pattern[end] === '/') {
135
+ // Consume the following slash too: `a/**/b` has to match `a/b`.
136
+ source += '(?:[^/]*/)*';
137
+ i = end + 1;
138
+ continue;
139
+ }
140
+ if (isGlobstar && atSegmentStart && end === pattern.length) {
141
+ source += '.*';
142
+ i = end;
143
+ continue;
144
+ }
145
+ // `**` that is not a whole segment (`a**b`) cannot mean "cross
146
+ // directories" without also matching `a/x/b`, which the pattern does not
147
+ // say. Collapse it to a single-segment wildcard.
148
+ source += '[^/]*';
149
+ i = end;
150
+ continue;
151
+ }
152
+ if (char === '?') {
153
+ source += '[^/]';
154
+ i += 1;
155
+ continue;
156
+ }
157
+ if (bracesBalanced && char === '{') {
158
+ depth += 1;
159
+ source += '(?:';
160
+ i += 1;
161
+ continue;
162
+ }
163
+ if (bracesBalanced && char === '}' && depth > 0) {
164
+ depth -= 1;
165
+ source += ')';
166
+ i += 1;
167
+ continue;
168
+ }
169
+ if (bracesBalanced && char === ',' && depth > 0) {
170
+ source += '|';
171
+ i += 1;
172
+ continue;
173
+ }
174
+ source += char.replace(/[.*+?^${}()|[\]\\]/, '\\$&');
175
+ i += 1;
176
+ }
177
+ return new RegExp(`^${source}(?:/.*)?$`);
178
+ }
179
+ function hasBalancedBraces(pattern) {
180
+ let depth = 0;
181
+ for (const char of pattern) {
182
+ if (char === '{')
183
+ depth += 1;
184
+ else if (char === '}') {
185
+ depth -= 1;
186
+ if (depth < 0)
187
+ return false;
188
+ }
189
+ }
190
+ return depth === 0;
191
+ }
192
+ /**
193
+ * A scope declaration compiled once per run.
194
+ *
195
+ * Compiling per pattern per file would rebuild the same regexes for every one of
196
+ * potentially thousands of changed paths.
197
+ */
198
+ class ScopeMatcher {
199
+ contractPath;
200
+ allow;
201
+ deny;
202
+ /**
203
+ * @param contractPath the contract's own path, exempted alongside
204
+ * {@link ALWAYS_ALLOWED_PREFIX} for contracts kept outside `.commandmate/`
205
+ */
206
+ constructor(scope, contractPath = null) {
207
+ this.contractPath = contractPath;
208
+ this.allow = scope.allow.map(globToRegExp);
209
+ this.deny = scope.deny.map(globToRegExp);
210
+ }
211
+ /**
212
+ * Whether `path` is a scope violation.
213
+ *
214
+ * `path` is a repository-root-relative POSIX path as git reports it.
215
+ */
216
+ isViolation(path) {
217
+ if (this.deny.some((pattern) => pattern.test(path)))
218
+ return true;
219
+ if (path.startsWith(exports.ALWAYS_ALLOWED_PREFIX) || path === this.contractPath)
220
+ return false;
221
+ return !this.allow.some((pattern) => pattern.test(path));
222
+ }
223
+ }
224
+ exports.ScopeMatcher = ScopeMatcher;
225
+ // =============================================================================
226
+ // Changed-path collection
227
+ // =============================================================================
228
+ /** Run a git plumbing command. No shell: every argument here is code-supplied. */
229
+ function runGit(args, cwd) {
230
+ return new Promise((resolve) => {
231
+ let stdout = '';
232
+ let stderr = '';
233
+ const child = (0, child_process_1.spawn)('git', args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
234
+ child.stdout?.on('data', (chunk) => {
235
+ stdout += chunk.toString('utf8');
236
+ });
237
+ child.stderr?.on('data', (chunk) => {
238
+ stderr += chunk.toString('utf8');
239
+ });
240
+ child.on('error', (error) => resolve({ code: null, stdout: '', stderr: error.message }));
241
+ child.on('close', (code) => resolve({ code, stdout, stderr }));
242
+ });
243
+ }
244
+ function splitNul(output) {
245
+ return output.split('\0').filter((field) => field !== '');
246
+ }
247
+ /**
248
+ * Paths in `git status --porcelain -z -uall` output.
249
+ *
250
+ * Measured format (git 2.49): every record is `XY<space><path>NUL`, and a
251
+ * rename or copy appends the original path as the *next* NUL field —
252
+ * `R new.txt\0old.txt\0`. Note that this is the reverse of the human
253
+ * `old -> new` rendering, and that `-z` writes paths verbatim while the human
254
+ * format C-quotes anything containing a space. Both paths of a rename are
255
+ * returned: moving a file *out of* a permitted directory is a change to that
256
+ * directory, and judging only the destination would miss it.
257
+ *
258
+ * Grouped per entry rather than flattened because work-evidence counts entries,
259
+ * and a rename that moved a contract file into real work has to stay countable
260
+ * as one change (#1580).
261
+ */
262
+ function parsePorcelainEntries(output) {
263
+ const fields = output.split('\0');
264
+ const entries = [];
265
+ let i = 0;
266
+ while (i < fields.length) {
267
+ const entry = fields[i];
268
+ i += 1;
269
+ // "XY " plus at least one path character.
270
+ if (entry.length < 4)
271
+ continue;
272
+ const paths = [entry.slice(3)];
273
+ const [x, y] = entry;
274
+ if (x === 'R' || x === 'C' || y === 'R' || y === 'C') {
275
+ const original = fields[i];
276
+ i += 1;
277
+ if (original)
278
+ paths.push(original);
279
+ }
280
+ entries.push(paths);
281
+ }
282
+ return entries;
283
+ }
284
+ /**
285
+ * Every path this worktree changed relative to `baseRef`.
286
+ *
287
+ * The union of committed and uncommitted change is deliberate: looking only at
288
+ * commits misses a deviation the agent has not committed yet, and looking only
289
+ * at the working tree misses everything it did commit.
290
+ *
291
+ * @returns the paths, or a message describing which git call could not answer
292
+ */
293
+ async function collectChangedPaths(worktreePath, baseRef) {
294
+ const mergeBase = await runGit(['merge-base', baseRef, 'HEAD'], worktreePath);
295
+ if (mergeBase.code !== 0 || mergeBase.stdout.trim() === '') {
296
+ return {
297
+ error: `'git merge-base ${baseRef} HEAD' failed; base ref is unreachable from this worktree.` +
298
+ (mergeBase.stderr.trim() ? `\n${mergeBase.stderr.trim()}` : ''),
299
+ };
300
+ }
301
+ const base = mergeBase.stdout.trim();
302
+ // --no-renames so a committed rename reports both paths (--name-only alone
303
+ // reports the destination only, once rename detection folds the pair).
304
+ const diff = await runGit(['diff', '--name-only', '-z', '--no-renames', base, 'HEAD'], worktreePath);
305
+ if (diff.code !== 0) {
306
+ return {
307
+ error: `'git diff --name-only ${base} HEAD' failed.` +
308
+ (diff.stderr.trim() ? `\n${diff.stderr.trim()}` : ''),
309
+ };
310
+ }
311
+ // -uall: without it a new directory collapses to a single `?? dir/` entry, and
312
+ // the gate would judge a directory name instead of the files inside it.
313
+ const status = await runGit(['status', '--porcelain', '-z', '--untracked-files=all'], worktreePath);
314
+ if (status.code !== 0) {
315
+ return {
316
+ error: "'git status --porcelain' failed." +
317
+ (status.stderr.trim() ? `\n${status.stderr.trim()}` : ''),
318
+ };
319
+ }
320
+ // Both sides are filtered, not just the working tree: an orchestrator may
321
+ // also have committed the contract as a setup commit (#1580).
322
+ const paths = new Set([...splitNul(diff.stdout), ...parsePorcelainEntries(status.stdout).flat()].filter((path) => !isContractPath(path)));
323
+ return { paths: [...paths].sort(), mergeBase: base };
324
+ }
325
+ // =============================================================================
326
+ // Gate evaluation
327
+ // =============================================================================
328
+ function formatPatterns(patterns) {
329
+ return patterns.length > 0 ? patterns.join(', ') : '(none)';
330
+ }
331
+ /**
332
+ * Reasons the gate has nothing to judge, phrased for `log_tail`.
333
+ *
334
+ * A skip is recorded rather than omitted: a run with no scope row at all is
335
+ * indistinguishable from a run predating the gate, and "we looked and no
336
+ * contract declared a scope" is the answer the reader needs.
337
+ */
338
+ exports.SCOPE_SKIP_NO_CONTRACT = 'scope: no contract is attached to this run, so no scope is declared to check.';
339
+ exports.SCOPE_SKIP_NOT_REQUIRED = 'scope: the contract sets success.requireScopeClean: false.';
340
+ /**
341
+ * The skip that is *not* harmless: a contract exists and this run could not be
342
+ * attached to it (#1620).
343
+ *
344
+ * Worded apart from {@link SCOPE_SKIP_NO_CONTRACT} on purpose. Both are skips,
345
+ * but only one of them means "there was nothing to judge" — reporting the other
346
+ * with the same sentence is what let a run whose scope was never checked read
347
+ * as a repository that simply does not use contracts. The task id is named so
348
+ * the reader can go and look at what was not judged.
349
+ */
350
+ function scopeSkipDetachedContract(taskId, status) {
351
+ return (`scope: task ${taskId} declares a scope for this worktree, but it is ${status} and ` +
352
+ 'this run was not attached to it, so its scope was NOT judged. ' +
353
+ 'Name the task when starting the run (`wait --verify` does this automatically).');
354
+ }
355
+ /**
356
+ * Judge the worktree's changes against a contract's scope.
357
+ *
358
+ * @param scope declared scope, or null when no contract is attached to the run
359
+ * @param requireScopeClean the contract's `success.requireScopeClean`
360
+ * @param baseRef ref the change set is computed against; null when unresolved
361
+ * @param contractPath the contract's own path, always exempt from `allow`
362
+ */
363
+ async function evaluateScope(worktreePath, scope, requireScopeClean, baseRef, contractPath = null) {
364
+ const startedAt = Date.now();
365
+ const done = (status, logTail, exitCode) => ({
366
+ status,
367
+ exitCode,
368
+ startedAt,
369
+ durationMs: Date.now() - startedAt,
370
+ logTail,
371
+ });
372
+ if (!scope)
373
+ return done('skipped', exports.SCOPE_SKIP_NO_CONTRACT, null);
374
+ if (!requireScopeClean)
375
+ return done('skipped', exports.SCOPE_SKIP_NOT_REQUIRED, null);
376
+ if (!baseRef) {
377
+ return done('error', 'scope: no base ref, so there is nothing to diff against. Set options.baseRef in ' +
378
+ '.commandmate/verify.yaml; origin/HEAD did not resolve a default branch.', null);
379
+ }
380
+ const changed = await collectChangedPaths(worktreePath, baseRef);
381
+ if ('error' in changed)
382
+ return done('error', `scope: ${changed.error}`, null);
383
+ const matcher = new ScopeMatcher(scope, contractPath);
384
+ const violations = changed.paths.filter((path) => matcher.isViolation(path));
385
+ const summary = `scope: baseRef=${baseRef} changed=${changed.paths.length} violations=${violations.length}\n` +
386
+ `allow: ${formatPatterns(scope.allow)}\ndeny: ${formatPatterns(scope.deny)}`;
387
+ if (violations.length === 0) {
388
+ // An empty change set passes: work-evidence is the gate that judges "nothing
389
+ // happened", and failing here too would report one problem as two.
390
+ return done('passed', summary, 0);
391
+ }
392
+ const listed = violations.slice(0, exports.MAX_REPORTED_VIOLATIONS);
393
+ const remainder = violations.length - listed.length;
394
+ const report = [
395
+ summary,
396
+ 'out of scope:',
397
+ ...listed.map((path) => ` - ${path}`),
398
+ ...(remainder > 0 ? [` ... and ${remainder} more`] : []),
399
+ exports.SCOPE_ALLOW_GUIDANCE,
400
+ ].join('\n');
401
+ return done('failed', report, 1);
402
+ }
@@ -0,0 +1,281 @@
1
+ "use strict";
2
+ /**
3
+ * Loader and validator for `.commandmate/verify.yaml`.
4
+ *
5
+ * Canonical spec: docs/design/verification-config.md
6
+ * Phase 0 reference implementation: .claude/skills/cmate-verify/scripts/verify-run.sh
7
+ *
8
+ * Server-only: reads from disk, so import this from API routes / CLI only.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.VerifyConfigError = exports.DEFAULT_MAX_LOG_TAIL_BYTES = exports.DEFAULT_TIMEOUT_SEC = exports.VERIFY_CONFIG_RELATIVE_PATH = exports.RESERVED_GATE_IDS = exports.ENV_CLEAN_GATE_ID = exports.SCOPE_GATE_ID = exports.WORK_EVIDENCE_GATE_ID = void 0;
12
+ exports.loadVerifyConfig = loadVerifyConfig;
13
+ const fs_1 = require("fs");
14
+ const path_1 = require("path");
15
+ const yaml_1 = require("yaml");
16
+ /**
17
+ * Built-in gate that answers "is there any work here to verify?".
18
+ *
19
+ * Declared here rather than in the runner so modules that only reason *about*
20
+ * gate selection (task contracts) can name it without importing the engine.
21
+ */
22
+ exports.WORK_EVIDENCE_GATE_ID = 'work-evidence';
23
+ /**
24
+ * Built-in gate that reconciles the changed files against the contract's
25
+ * `scope.allow` / `scope.deny` (#1546). Declared alongside work-evidence for the
26
+ * same reason: `lib/tasks/contract-message.ts` has to name it while resolving a
27
+ * contract's gate list, and must not pull the engine in to do so.
28
+ */
29
+ exports.SCOPE_GATE_ID = 'scope';
30
+ /**
31
+ * Built-in gate that reconciles the *machine* against the snapshot taken when
32
+ * the task was created (#1740): listening CommandMate servers, `mcbd-*` tmux
33
+ * sessions, `$HOME` and `~/.commandmate`. `scope` answers what a delegation
34
+ * changed inside the repository; this answers what it changed outside one.
35
+ */
36
+ exports.ENV_CLEAN_GATE_ID = 'env-clean';
37
+ /** Gate IDs reserved for built-in gates; using one in `gates` is a config error. */
38
+ exports.RESERVED_GATE_IDS = [
39
+ exports.WORK_EVIDENCE_GATE_ID,
40
+ exports.SCOPE_GATE_ID,
41
+ exports.ENV_CLEAN_GATE_ID,
42
+ ];
43
+ exports.VERIFY_CONFIG_RELATIVE_PATH = '.commandmate/verify.yaml';
44
+ exports.DEFAULT_TIMEOUT_SEC = 600;
45
+ exports.DEFAULT_MAX_LOG_TAIL_BYTES = 8192;
46
+ const MIN_TIMEOUT_SEC = 1;
47
+ const MAX_TIMEOUT_SEC = 7200;
48
+ const MAX_LOG_TAIL_BYTES = 1048576;
49
+ const GATE_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,31}$/;
50
+ const TOP_LEVEL_KEYS = ['version', 'gates', 'options'];
51
+ const GATE_KEYS = ['id', 'command', 'timeoutSec'];
52
+ const OPTION_KEYS = [
53
+ 'baseRef',
54
+ 'skipInPrimaryCheckout',
55
+ 'maxLogTailBytes',
56
+ 'requireCommit',
57
+ 'requireEnvClean',
58
+ ];
59
+ class VerifyConfigError extends Error {
60
+ issues;
61
+ constructor(issues) {
62
+ super(`invalid verify config:\n${issues.map((issue) => ` - ${issue}`).join('\n')}`);
63
+ this.name = 'VerifyConfigError';
64
+ this.issues = issues;
65
+ }
66
+ }
67
+ exports.VerifyConfigError = VerifyConfigError;
68
+ function isMapping(value) {
69
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
70
+ }
71
+ /**
72
+ * The bash reference parser strips outer quotes before comparing, so `timeoutSec: "900"`
73
+ * means 900 there. Accept the same spelling, but only an exact decimal literal.
74
+ */
75
+ function asInteger(value) {
76
+ if (typeof value === 'number')
77
+ return Number.isInteger(value) ? value : null;
78
+ if (typeof value === 'string' && /^-?\d+$/.test(value))
79
+ return Number(value);
80
+ return null;
81
+ }
82
+ function asBoolean(value) {
83
+ if (typeof value === 'boolean')
84
+ return value;
85
+ if (value === 'true')
86
+ return true;
87
+ if (value === 'false')
88
+ return false;
89
+ return null;
90
+ }
91
+ function describe(value) {
92
+ if (value === undefined)
93
+ return 'nothing';
94
+ if (value === null)
95
+ return 'null';
96
+ if (typeof value === 'string')
97
+ return JSON.stringify(value);
98
+ if (Array.isArray(value))
99
+ return 'a list';
100
+ if (typeof value === 'object')
101
+ return 'a mapping';
102
+ return String(value);
103
+ }
104
+ function collectUnknownKeys(mapping, allowed, at, issues) {
105
+ for (const key of Object.keys(mapping)) {
106
+ if (!allowed.includes(key)) {
107
+ issues.push(`${at}: unknown key "${key}" (v1 is a closed set)`);
108
+ }
109
+ }
110
+ }
111
+ function validateGates(value, issues) {
112
+ if (value === undefined || value === null) {
113
+ issues.push('gates: required, at least one gate must be defined');
114
+ return [];
115
+ }
116
+ if (!Array.isArray(value)) {
117
+ issues.push(`gates: must be a list (got ${describe(value)})`);
118
+ return [];
119
+ }
120
+ if (value.length === 0) {
121
+ issues.push('gates: at least one gate must be defined');
122
+ return [];
123
+ }
124
+ const gates = [];
125
+ const seenIds = new Set();
126
+ value.forEach((entry, index) => {
127
+ const at = `gates[${index}]`;
128
+ const issuesBefore = issues.length;
129
+ if (!isMapping(entry)) {
130
+ issues.push(`${at}: must be a mapping (got ${describe(entry)})`);
131
+ return;
132
+ }
133
+ collectUnknownKeys(entry, GATE_KEYS, at, issues);
134
+ if (typeof entry.id !== 'string' || entry.id === '') {
135
+ issues.push(`${at}.id: required, must be a non-empty string (got ${describe(entry.id)})`);
136
+ }
137
+ else if (!GATE_ID_PATTERN.test(entry.id)) {
138
+ issues.push(`${at}.id: "${entry.id}" must match ${GATE_ID_PATTERN.source}`);
139
+ }
140
+ else if (exports.RESERVED_GATE_IDS.includes(entry.id)) {
141
+ issues.push(`${at}.id: "${entry.id}" is reserved for a built-in gate`);
142
+ }
143
+ else if (seenIds.has(entry.id)) {
144
+ issues.push(`${at}.id: duplicate gate id "${entry.id}"`);
145
+ }
146
+ else {
147
+ seenIds.add(entry.id);
148
+ }
149
+ if (typeof entry.command !== 'string' || entry.command.trim() === '') {
150
+ issues.push(`${at}.command: required, must be a non-empty string (got ${describe(entry.command)})`);
151
+ }
152
+ let timeoutSec = exports.DEFAULT_TIMEOUT_SEC;
153
+ if (entry.timeoutSec !== undefined) {
154
+ const parsed = asInteger(entry.timeoutSec);
155
+ if (parsed === null) {
156
+ issues.push(`${at}.timeoutSec: must be an integer (got ${describe(entry.timeoutSec)})`);
157
+ }
158
+ else if (parsed < MIN_TIMEOUT_SEC || parsed > MAX_TIMEOUT_SEC) {
159
+ issues.push(`${at}.timeoutSec: must be ${MIN_TIMEOUT_SEC}..${MAX_TIMEOUT_SEC} (got ${parsed})`);
160
+ }
161
+ else {
162
+ timeoutSec = parsed;
163
+ }
164
+ }
165
+ if (issues.length === issuesBefore) {
166
+ gates.push({ id: entry.id, command: entry.command, timeoutSec });
167
+ }
168
+ });
169
+ return gates;
170
+ }
171
+ function validateOptions(value, issues) {
172
+ const options = {
173
+ baseRef: null,
174
+ skipInPrimaryCheckout: true,
175
+ maxLogTailBytes: exports.DEFAULT_MAX_LOG_TAIL_BYTES,
176
+ requireCommit: false,
177
+ requireEnvClean: false,
178
+ };
179
+ // A childless `options:` key parses as null and means "all defaults".
180
+ if (value === undefined || value === null)
181
+ return options;
182
+ if (!isMapping(value)) {
183
+ issues.push(`options: must be a mapping (got ${describe(value)})`);
184
+ return options;
185
+ }
186
+ collectUnknownKeys(value, OPTION_KEYS, 'options', issues);
187
+ if (value.baseRef !== undefined) {
188
+ if (typeof value.baseRef !== 'string' || value.baseRef.trim() === '') {
189
+ issues.push(`options.baseRef: must be a non-empty string (got ${describe(value.baseRef)})`);
190
+ }
191
+ else {
192
+ options.baseRef = value.baseRef;
193
+ }
194
+ }
195
+ if (value.skipInPrimaryCheckout !== undefined) {
196
+ const parsed = asBoolean(value.skipInPrimaryCheckout);
197
+ if (parsed === null) {
198
+ issues.push(`options.skipInPrimaryCheckout: must be true or false (got ${describe(value.skipInPrimaryCheckout)})`);
199
+ }
200
+ else {
201
+ options.skipInPrimaryCheckout = parsed;
202
+ }
203
+ }
204
+ if (value.requireCommit !== undefined) {
205
+ const parsed = asBoolean(value.requireCommit);
206
+ if (parsed === null) {
207
+ issues.push(`options.requireCommit: must be true or false (got ${describe(value.requireCommit)})`);
208
+ }
209
+ else {
210
+ options.requireCommit = parsed;
211
+ }
212
+ }
213
+ if (value.requireEnvClean !== undefined) {
214
+ const parsed = asBoolean(value.requireEnvClean);
215
+ if (parsed === null) {
216
+ issues.push(`options.requireEnvClean: must be true or false (got ${describe(value.requireEnvClean)})`);
217
+ }
218
+ else {
219
+ options.requireEnvClean = parsed;
220
+ }
221
+ }
222
+ if (value.maxLogTailBytes !== undefined) {
223
+ const parsed = asInteger(value.maxLogTailBytes);
224
+ if (parsed === null) {
225
+ issues.push(`options.maxLogTailBytes: must be an integer (got ${describe(value.maxLogTailBytes)})`);
226
+ }
227
+ else if (parsed < 0 || parsed > MAX_LOG_TAIL_BYTES) {
228
+ issues.push(`options.maxLogTailBytes: must be 0..${MAX_LOG_TAIL_BYTES} (got ${parsed})`);
229
+ }
230
+ else {
231
+ options.maxLogTailBytes = parsed;
232
+ }
233
+ }
234
+ return options;
235
+ }
236
+ function parseVerifyConfig(raw, configPath) {
237
+ let document;
238
+ try {
239
+ document = (0, yaml_1.parse)(raw);
240
+ }
241
+ catch (error) {
242
+ throw new VerifyConfigError([`${configPath}: YAML parse error: ${error.message}`]);
243
+ }
244
+ if (!isMapping(document)) {
245
+ throw new VerifyConfigError([
246
+ `${configPath}: expected a YAML mapping at the top level (got ${describe(document)})`,
247
+ ]);
248
+ }
249
+ const issues = [];
250
+ collectUnknownKeys(document, TOP_LEVEL_KEYS, 'top level', issues);
251
+ if (!('version' in document)) {
252
+ issues.push('version: required, v1 configs must declare "version: 1"');
253
+ }
254
+ else if (asInteger(document.version) !== 1) {
255
+ issues.push(`version: must be 1 (got ${describe(document.version)})`);
256
+ }
257
+ const gates = validateGates(document.gates, issues);
258
+ const options = validateOptions(document.options, issues);
259
+ if (issues.length > 0)
260
+ throw new VerifyConfigError(issues);
261
+ return { version: 1, gates, options };
262
+ }
263
+ /**
264
+ * Read and validate `<repoPath>/.commandmate/verify.yaml`.
265
+ *
266
+ * @returns the validated config, or null when the file does not exist
267
+ * @throws VerifyConfigError with every violation collected in `issues`
268
+ */
269
+ function loadVerifyConfig(repoPath) {
270
+ const configPath = (0, path_1.join)(repoPath, exports.VERIFY_CONFIG_RELATIVE_PATH);
271
+ let raw;
272
+ try {
273
+ raw = (0, fs_1.readFileSync)(configPath, 'utf8');
274
+ }
275
+ catch (error) {
276
+ if (error.code === 'ENOENT')
277
+ return null;
278
+ throw new VerifyConfigError([`${configPath}: ${error.message}`]);
279
+ }
280
+ return parseVerifyConfig(raw, configPath);
281
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commandmate",
3
- "version": "0.22.2",
3
+ "version": "0.23.0",
4
4
  "description": "A local control plane for agent CLIs — orchestration and visibility for Claude Code, Codex, Gemini CLI, and more across Git worktrees",
5
5
  "keywords": [
6
6
  "claude-code",