commandmate 0.24.0 → 0.26.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 (295) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +266 -266
  3. package/.next/app-path-routes-manifest.json +15 -15
  4. package/.next/build-manifest.json +5 -5
  5. package/.next/prerender-manifest.json +3 -3
  6. package/.next/react-loadable-manifest.json +3 -3
  7. package/.next/required-server-files.json +1 -1
  8. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  9. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  10. package/.next/server/app/api/app/update-check/route.js +1 -1
  11. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  12. package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
  18. package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  22. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  24. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  25. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  27. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  28. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  30. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  31. package/.next/server/app/api/hooks/permission-request/route.js +1 -1
  32. package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  37. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  38. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  40. package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
  41. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  42. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  43. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  44. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  45. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  46. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  47. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  48. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  49. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  50. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  51. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  52. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  53. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  54. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  55. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  57. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  58. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  60. package/.next/server/app/api/todos/route_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]/cli-tool/route_client-reference-manifest.js +1 -1
  66. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  67. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  68. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  70. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  71. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  72. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  73. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  74. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  75. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  76. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  78. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  79. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  80. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  81. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  82. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  83. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  84. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  85. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  86. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  87. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  88. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  90. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  91. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  93. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  94. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  96. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  97. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  98. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  99. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  100. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  101. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  103. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  104. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  105. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  106. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  107. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  108. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  109. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  110. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  111. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  112. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  113. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  114. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  115. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  116. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  117. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  118. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  120. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  121. package/.next/server/app/api/worktrees/[id]/start-polling/route_client-reference-manifest.js +1 -1
  122. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  124. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  127. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  129. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  130. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  132. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  133. package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  135. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  136. package/.next/server/app/chat/page.js +2 -2
  137. package/.next/server/app/chat/page.js.nft.json +1 -1
  138. package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  139. package/.next/server/app/login/page.js +2 -2
  140. package/.next/server/app/login/page.js.nft.json +1 -1
  141. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  142. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  143. package/.next/server/app/more/page.js +2 -2
  144. package/.next/server/app/more/page.js.nft.json +1 -1
  145. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  146. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  147. package/.next/server/app/page.js +1 -1
  148. package/.next/server/app/page.js.nft.json +1 -1
  149. package/.next/server/app/page_client-reference-manifest.js +1 -1
  150. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  151. package/.next/server/app/repositories/page.js +2 -2
  152. package/.next/server/app/repositories/page.js.nft.json +1 -1
  153. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  154. package/.next/server/app/review/page.js +1 -1
  155. package/.next/server/app/review/page.js.nft.json +1 -1
  156. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  157. package/.next/server/app/sessions/page.js +1 -1
  158. package/.next/server/app/sessions/page.js.nft.json +1 -1
  159. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  160. package/.next/server/app/skills/[skillId]/page.js +2 -2
  161. package/.next/server/app/skills/[skillId]/page.js.nft.json +1 -1
  162. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  163. package/.next/server/app/skills/installed/page.js +2 -2
  164. package/.next/server/app/skills/installed/page.js.nft.json +1 -1
  165. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  166. package/.next/server/app/skills/page.js +2 -2
  167. package/.next/server/app/skills/page.js.nft.json +1 -1
  168. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  169. package/.next/server/app/worktrees/[id]/files/[...path]/page.js +2 -2
  170. package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +1 -1
  171. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  172. package/.next/server/app/worktrees/[id]/page.js +6 -6
  173. package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
  174. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  175. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  176. package/.next/server/app-paths-manifest.json +15 -15
  177. package/.next/server/chunks/2119.js +1 -1
  178. package/.next/server/chunks/2404.js +1 -1
  179. package/.next/server/chunks/2445.js +1 -1
  180. package/.next/server/chunks/3241.js +1 -1
  181. package/.next/server/chunks/3346.js +1 -1
  182. package/.next/server/chunks/4455.js +1 -1
  183. package/.next/server/chunks/5164.js +1 -1
  184. package/.next/server/chunks/5571.js +1 -1
  185. package/.next/server/chunks/5959.js +4 -4
  186. package/.next/server/chunks/6130.js +1 -1
  187. package/.next/server/chunks/6274.js +12 -9
  188. package/.next/server/chunks/6285.js +1 -1
  189. package/.next/server/chunks/7458.js +6 -6
  190. package/.next/server/chunks/848.js +1 -1
  191. package/.next/server/chunks/8730.js +1 -0
  192. package/.next/server/chunks/880.js +1 -1
  193. package/.next/server/chunks/9328.js +1 -1
  194. package/.next/server/chunks/9373.js +4 -3
  195. package/.next/server/middleware-build-manifest.js +1 -1
  196. package/.next/server/middleware-manifest.json +5 -5
  197. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  198. package/.next/server/pages/500.html +1 -1
  199. package/.next/server/server-reference-manifest.json +1 -1
  200. package/.next/static/chunks/2053-dfac2d49227cc942.js +1 -0
  201. package/.next/static/chunks/3898-ef488bfa804507d9.js +1 -0
  202. package/.next/static/chunks/5229-35f9acab97a553c5.js +1 -0
  203. package/.next/static/chunks/{6381-18a6a02a94d00d76.js → 6381-9303430933084b56.js} +1 -1
  204. package/.next/static/chunks/{9599-d29d2f8eeaf7c249.js → 8649-f551b0010dba4986.js} +1 -1
  205. package/.next/static/chunks/9263.f2034ec525abcf72.js +1 -0
  206. package/.next/static/chunks/app/chat/page-439b35c9cb90dbe0.js +1 -0
  207. package/.next/static/chunks/app/login/page-eefd515d8c37e5ee.js +1 -0
  208. package/.next/static/chunks/app/more/page-889b7546a8a553dc.js +1 -0
  209. package/.next/static/chunks/app/page-a8d04ac0e3e4c9fc.js +1 -0
  210. package/.next/static/chunks/app/repositories/page-f3c4d8839b1ca203.js +1 -0
  211. package/.next/static/chunks/app/review/page-6dc88649fe88ac16.js +1 -0
  212. package/.next/static/chunks/app/sessions/page-2c9ed9e969097688.js +1 -0
  213. package/.next/static/chunks/app/skills/[skillId]/page-19beef6121c4c982.js +1 -0
  214. package/.next/static/chunks/app/skills/installed/page-d5b9cef6d21fabda.js +1 -0
  215. package/.next/static/chunks/app/skills/page-06ef637e07dd9377.js +1 -0
  216. package/.next/static/chunks/app/worktrees/[id]/files/[...path]/{page-9ddcb224594f620f.js → page-5fed3984fafcd910.js} +1 -1
  217. package/.next/static/chunks/app/worktrees/[id]/page-fbdf4621a2911ac1.js +1 -0
  218. package/.next/static/chunks/{webpack-3534d858912a6c92.js → webpack-9d892a9ff07c289d.js} +1 -1
  219. package/.next/static/css/e865c4979a41aa03.css +1 -0
  220. package/.next/trace +12 -12
  221. package/README.md +96 -45
  222. package/dist/cli/commands/task.d.ts.map +1 -1
  223. package/dist/cli/commands/task.js +2 -1
  224. package/dist/cli/commands/verify.d.ts +14 -0
  225. package/dist/cli/commands/verify.d.ts.map +1 -1
  226. package/dist/cli/commands/verify.js +109 -3
  227. package/dist/cli/commands/wait.d.ts +2 -0
  228. package/dist/cli/commands/wait.d.ts.map +1 -1
  229. package/dist/cli/commands/wait.js +184 -4
  230. package/dist/cli/types/api-responses.d.ts +172 -0
  231. package/dist/cli/types/api-responses.d.ts.map +1 -1
  232. package/dist/cli/types/index.d.ts +31 -0
  233. package/dist/cli/types/index.d.ts.map +1 -1
  234. package/dist/cli/types/index.js +26 -0
  235. package/dist/cli/utils/verify-runner.d.ts +36 -1
  236. package/dist/cli/utils/verify-runner.d.ts.map +1 -1
  237. package/dist/cli/utils/verify-runner.js +114 -6
  238. package/dist/server/src/config/activity-bar-config.js +5 -1
  239. package/dist/server/src/lib/auto-yes-poller.js +40 -4
  240. package/dist/server/src/lib/auto-yes-state.js +108 -3
  241. package/dist/server/src/lib/cli-tools/antigravity.js +8 -4
  242. package/dist/server/src/lib/cli-tools/codex.js +63 -30
  243. package/dist/server/src/lib/cli-tools/copilot.js +5 -1
  244. package/dist/server/src/lib/cli-tools/gemini.js +15 -15
  245. package/dist/server/src/lib/cli-tools/opencode.js +9 -3
  246. package/dist/server/src/lib/detection/cli-patterns.js +148 -6
  247. package/dist/server/src/lib/detection/status-detector.js +28 -0
  248. package/dist/server/src/lib/detection/upstream-faults.js +120 -0
  249. package/dist/server/src/lib/hooks/permission-decision-service.js +13 -5
  250. package/dist/server/src/lib/hooks/sources/antigravity/hooks-config.js +18 -11
  251. package/dist/server/src/lib/hooks/sources/antigravity/source.js +10 -9
  252. package/dist/server/src/lib/hooks/sources/claude/source.js +5 -2
  253. package/dist/server/src/lib/hooks/sources/codex/hooks-config.js +26 -18
  254. package/dist/server/src/lib/hooks/sources/codex/source.js +6 -9
  255. package/dist/server/src/lib/hooks/sources/copilot/hook-settings.js +22 -12
  256. package/dist/server/src/lib/hooks/sources/copilot/source.js +1 -1
  257. package/dist/server/src/lib/hooks/sources/define-source.js +6 -4
  258. package/dist/server/src/lib/hooks/sources/gemini/settings-generator.js +14 -8
  259. package/dist/server/src/lib/hooks/sources/gemini/source.js +29 -29
  260. package/dist/server/src/lib/hooks/sources/index.js +4 -1
  261. package/dist/server/src/lib/hooks/sources/launch-command.js +61 -0
  262. package/dist/server/src/lib/hooks/sources/legacy-relay.js +2 -1
  263. package/dist/server/src/lib/hooks/sources/opencode/source.js +10 -7
  264. package/dist/server/src/lib/polling/prompt-dedup-state.js +95 -0
  265. package/dist/server/src/lib/polling/response-checker.js +12 -0
  266. package/dist/server/src/lib/polling/response-poller-core.js +11 -1
  267. package/dist/server/src/lib/session/agent-session-lifecycle.js +28 -7
  268. package/dist/server/src/lib/session/claude-session.js +5 -1
  269. package/dist/server/src/lib/session/current-output-builder.js +34 -0
  270. package/dist/server/src/lib/verification/env-snapshot.js +21 -3
  271. package/dist/server/src/lib/verification/gate-runner.js +258 -7
  272. package/dist/server/src/lib/verification/machine-lock.js +204 -0
  273. package/dist/server/src/lib/verification/scope-gate.js +126 -13
  274. package/dist/server/src/lib/verification/verify-config.js +85 -3
  275. package/dist/server/src/lib/verification/worktree-index.js +140 -0
  276. package/package.json +1 -1
  277. package/.next/server/chunks/3451.js +0 -1
  278. package/.next/static/chunks/2053-52d3c82014e1cd54.js +0 -1
  279. package/.next/static/chunks/5229-0610b4e3288e777d.js +0 -1
  280. package/.next/static/chunks/744-3ad06d8c8ca482fc.js +0 -1
  281. package/.next/static/chunks/9263.5259f73f89220d64.js +0 -1
  282. package/.next/static/chunks/app/chat/page-15d13fc024d78f5d.js +0 -1
  283. package/.next/static/chunks/app/login/page-0247a3fb569bb22b.js +0 -1
  284. package/.next/static/chunks/app/more/page-b8ba537baeac8d5b.js +0 -1
  285. package/.next/static/chunks/app/page-afc64708362f31e5.js +0 -1
  286. package/.next/static/chunks/app/repositories/page-3469dacb6be7842f.js +0 -1
  287. package/.next/static/chunks/app/review/page-2d9cb7e068f8f35a.js +0 -1
  288. package/.next/static/chunks/app/sessions/page-7470c2bfd89e0df9.js +0 -1
  289. package/.next/static/chunks/app/skills/[skillId]/page-5e24481162f7ea78.js +0 -1
  290. package/.next/static/chunks/app/skills/installed/page-efd2d710a27f9735.js +0 -1
  291. package/.next/static/chunks/app/skills/page-0498adfc6e48684b.js +0 -1
  292. package/.next/static/chunks/app/worktrees/[id]/page-e611d30e47989e5d.js +0 -1
  293. package/.next/static/css/3ac44cfc082d02ad.css +0 -1
  294. /package/.next/static/{smu4mnL7qMf8w38n9dQJE → hNdNiFes2xLls68SWhAU9}/_buildManifest.js +0 -0
  295. /package/.next/static/{smu4mnL7qMf8w38n9dQJE → hNdNiFes2xLls68SWhAU9}/_ssgManifest.js +0 -0
@@ -29,6 +29,26 @@ var ExitCode;
29
29
  exports.WaitExitCode = {
30
30
  SUCCESS: 0,
31
31
  PROMPT_DETECTED: 10,
32
+ /**
33
+ * `--fail-on-upstream-fault`: the agent came back to its composer with an
34
+ * upstream (model API) failure on the frame (Issue #1839).
35
+ *
36
+ * Its own code rather than SUCCESS because the two mean opposite things to a
37
+ * caller: SUCCESS says "the turn ran, judge the result", this says "the turn
38
+ * never ran, send it again". Measured on 2026-08-20 against a stub upstream
39
+ * answering 529, Claude 2.1.236 returns to the composer ~3 s after the send
40
+ * having executed nothing, and `wait --verify` reports 21 (no work evidence) —
41
+ * which reads as "the agent worked and produced nothing" and is why #1834 saw
42
+ * twelve retries burned on a session that only needed to be re-sent later.
43
+ *
44
+ * Its own code rather than riding PROMPT_DETECTED (10) because nothing is
45
+ * waiting to be answered: `respond` has nothing to send here.
46
+ *
47
+ * 11 is deliberately shared with {@link SkillExitCode.BLOCKED}: the two
48
+ * commands' codes are separate namespaces, and 11 is the first value free of
49
+ * PROMPT_DETECTED.
50
+ */
51
+ UPSTREAM_FAULT: 11,
32
52
  TIMEOUT: 124,
33
53
  };
34
54
  /**
@@ -56,6 +76,12 @@ exports.VerifyExitCode = {
56
76
  */
57
77
  exports.WAIT_EXIT_CODE_PRIORITY = [
58
78
  exports.WaitExitCode.PROMPT_DETECTED,
79
+ // Issue #1839: below PROMPT_DETECTED because a prompt is actionable right now
80
+ // and an upstream fault is not, and above the verify verdicts because a turn
81
+ // that never ran makes those verdicts meaningless — reporting VERIFY_FAILED
82
+ // for a worktree whose agent never executed is the misattribution #1839 exists
83
+ // to end.
84
+ exports.WaitExitCode.UPSTREAM_FAULT,
59
85
  exports.VerifyExitCode.VERIFY_FAILED,
60
86
  exports.VerifyExitCode.NOT_STARTED,
61
87
  exports.WaitExitCode.TIMEOUT,
@@ -10,12 +10,47 @@
10
10
  *
11
11
  * @module cli/utils/verify-runner
12
12
  */
13
- import type { VerificationRunStatus, VerificationRunView } from '../types/api-responses';
13
+ import type { VerificationFlakyDetail, VerificationRunStatus, VerificationRunView } from '../types/api-responses';
14
14
  import { ApiClient } from './api-client';
15
15
  /** Matches the wait command's cadence; runs are minutes long, not seconds. */
16
16
  export declare const VERIFY_POLL_INTERVAL_MS = 5000;
17
17
  /** Built-in gate id; mirrors WORK_EVIDENCE_GATE_ID in lib/verification/gate-runner.ts. */
18
18
  export declare const WORK_EVIDENCE_GATE_ID = "work-evidence";
19
+ /**
20
+ * Marker a mutexed gate writes into its log tail; mirrors MUTEX_LOG_PREFIX in
21
+ * lib/verification/gate-runner.ts (Issue #1771).
22
+ *
23
+ * Mirrored rather than imported because `tsconfig.cli.json` compiles
24
+ * `src/cli/**` alone with no path aliases, so the CLI bundle never pulls in the
25
+ * server's dependency graph. `tests/unit/verification/gate-mutex.test.ts` pins
26
+ * the two together by importing both.
27
+ */
28
+ export declare const MUTEX_LOG_PREFIX = "[mutex]";
29
+ /**
30
+ * Marker a retried gate writes into its log tail; mirrors FLAKY_LOG_PREFIX in
31
+ * lib/verification/gate-runner.ts (Issue #1772).
32
+ *
33
+ * Mirrored rather than imported for the same reason the mutex prefix is, and
34
+ * pinned to the runner's spelling by `tests/unit/verification/gate-flaky.test.ts`.
35
+ */
36
+ export declare const FLAKY_LOG_PREFIX = "[flaky]";
37
+ /**
38
+ * Label a gate whose two runs disagreed. Not a `VerificationGateStatus`: the
39
+ * schema has no such status and #1772 added no migration, so FLAKY is a reading
40
+ * of the marker laid over the stored `passed`/`failed` verdict.
41
+ */
42
+ export declare const FLAKY_GATE_LABEL = "FLAKY";
43
+ /**
44
+ * Read a retried gate's two runs back out of its log tail (Issue #1772).
45
+ *
46
+ * `verification_gate_results` stores one status, one exit code and one duration,
47
+ * so the second run's numbers only exist in the log — the same carrier
48
+ * work-evidence's counts and the scope gate's evidence already use.
49
+ *
50
+ * @returns null when the gate was never retried, which is every gate that did
51
+ * not declare `retryOnFail: 1` and every one that passed first time.
52
+ */
53
+ export declare function parseFlakyMarker(logTail: string | null | undefined): VerificationFlakyDetail | null;
19
54
  /**
20
55
  * Lines of a failing gate's log echoed to stderr before the rest becomes a
21
56
  * count (#1683).
@@ -1 +1 @@
1
- {"version":3,"file":"verify-runner.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/verify-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAEV,qBAAqB,EACrB,mBAAmB,EAGpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,SAAS,EAAiC,MAAM,cAAc,CAAC;AAExE,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C,0FAA0F;AAC1F,eAAO,MAAM,qBAAqB,kBAAkB,CAAC;AAErD;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,OAAO,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACnC,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,GAAG,CAAC,EAAE,mBAAmB,CAAC;CAC3B;AAUD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAW1E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,CAOnF;AAuGD;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,mBAAmB,CAAC,CAyD9B"}
1
+ {"version":3,"file":"verify-runner.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/verify-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EACV,uBAAuB,EAEvB,qBAAqB,EACrB,mBAAmB,EAGpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,SAAS,EAAiC,MAAM,cAAc,CAAC;AAExE,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C,0FAA0F;AAC1F,eAAO,MAAM,qBAAqB,kBAAkB,CAAC;AAErD;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAU1C;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAE1C;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,UAAU,CAAC;AAoBxC;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACjC,uBAAuB,GAAG,IAAI,CAehC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,OAAO,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACnC,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,GAAG,CAAC,EAAE,mBAAmB,CAAC;CAC3B;AAUD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAW1E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,CAOnF;AAuID;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,mBAAmB,CAAC,CAyD9B"}
@@ -12,7 +12,8 @@
12
12
  * @module cli/utils/verify-runner
13
13
  */
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.MAX_PRINTED_LOG_TAIL_LINES = exports.WORK_EVIDENCE_GATE_ID = exports.VERIFY_POLL_INTERVAL_MS = void 0;
15
+ exports.MAX_PRINTED_LOG_TAIL_LINES = exports.FLAKY_GATE_LABEL = exports.FLAKY_LOG_PREFIX = exports.MUTEX_LOG_PREFIX = exports.WORK_EVIDENCE_GATE_ID = exports.VERIFY_POLL_INTERVAL_MS = void 0;
16
+ exports.parseFlakyMarker = parseFlakyMarker;
16
17
  exports.exitCodeForRunStatus = exitCodeForRunStatus;
17
18
  exports.parseGateIds = parseGateIds;
18
19
  exports.runVerification = runVerification;
@@ -22,6 +23,79 @@ const api_client_1 = require("./api-client");
22
23
  exports.VERIFY_POLL_INTERVAL_MS = 5000;
23
24
  /** Built-in gate id; mirrors WORK_EVIDENCE_GATE_ID in lib/verification/gate-runner.ts. */
24
25
  exports.WORK_EVIDENCE_GATE_ID = 'work-evidence';
26
+ /**
27
+ * Marker a mutexed gate writes into its log tail; mirrors MUTEX_LOG_PREFIX in
28
+ * lib/verification/gate-runner.ts (Issue #1771).
29
+ *
30
+ * Mirrored rather than imported because `tsconfig.cli.json` compiles
31
+ * `src/cli/**` alone with no path aliases, so the CLI bundle never pulls in the
32
+ * server's dependency graph. `tests/unit/verification/gate-mutex.test.ts` pins
33
+ * the two together by importing both.
34
+ */
35
+ exports.MUTEX_LOG_PREFIX = '[mutex]';
36
+ /**
37
+ * Time a gate spent queued for its `mutex`, as written by the runner.
38
+ *
39
+ * Anchored to the start of a line so a gate whose own output happens to contain
40
+ * `waited=` cannot supply the number.
41
+ */
42
+ const MUTEX_WAITED_PATTERN = /^\[mutex\] [^\n]*?\bwaited=([0-9]+(?:\.[0-9]+)?s)/m;
43
+ /**
44
+ * Marker a retried gate writes into its log tail; mirrors FLAKY_LOG_PREFIX in
45
+ * lib/verification/gate-runner.ts (Issue #1772).
46
+ *
47
+ * Mirrored rather than imported for the same reason the mutex prefix is, and
48
+ * pinned to the runner's spelling by `tests/unit/verification/gate-flaky.test.ts`.
49
+ */
50
+ exports.FLAKY_LOG_PREFIX = '[flaky]';
51
+ /**
52
+ * Label a gate whose two runs disagreed. Not a `VerificationGateStatus`: the
53
+ * schema has no such status and #1772 added no migration, so FLAKY is a reading
54
+ * of the marker laid over the stored `passed`/`failed` verdict.
55
+ */
56
+ exports.FLAKY_GATE_LABEL = 'FLAKY';
57
+ /**
58
+ * The runner's marker line, anchored to the start of a line so a gate whose own
59
+ * output happens to print `outcome=` cannot supply the numbers.
60
+ */
61
+ const FLAKY_PATTERN = /^\[flaky\] runs=(\d+) outcome=(flaky|fail) exit=(\S+) duration=(\S+) verdict=(pass|fail)$/m;
62
+ /** `n/a` is what the runner writes for a run killed by a signal. */
63
+ function parseExitField(value) {
64
+ return /^-?\d+$/.test(value) ? Number(value) : null;
65
+ }
66
+ /** `45.0s` back into milliseconds; anything else is a value we cannot read. */
67
+ function parseDurationField(value) {
68
+ const match = /^([0-9]+(?:\.[0-9]+)?)s$/.exec(value);
69
+ return match ? Math.round(Number(match[1]) * 1000) : null;
70
+ }
71
+ /**
72
+ * Read a retried gate's two runs back out of its log tail (Issue #1772).
73
+ *
74
+ * `verification_gate_results` stores one status, one exit code and one duration,
75
+ * so the second run's numbers only exist in the log — the same carrier
76
+ * work-evidence's counts and the scope gate's evidence already use.
77
+ *
78
+ * @returns null when the gate was never retried, which is every gate that did
79
+ * not declare `retryOnFail: 1` and every one that passed first time.
80
+ */
81
+ function parseFlakyMarker(logTail) {
82
+ if (!logTail)
83
+ return null;
84
+ const match = FLAKY_PATTERN.exec(logTail);
85
+ if (!match)
86
+ return null;
87
+ return {
88
+ runs: Number(match[1]),
89
+ outcome: match[2],
90
+ exitCodes: match[3].split(',').map(parseExitField),
91
+ durationsMs: match[4].split(',').map(parseDurationField),
92
+ verdict: match[5],
93
+ // Kept verbatim so the GATE line prints exactly what the runner wrote,
94
+ // rather than a re-rendering that could round differently.
95
+ exit: match[3],
96
+ duration: match[4],
97
+ };
98
+ }
25
99
  /**
26
100
  * Lines of a failing gate's log echoed to stderr before the rest becomes a
27
101
  * count (#1683).
@@ -83,11 +157,27 @@ function formatDetail(gate) {
83
157
  return reason ? reason.slice(0, 160) : 'not run';
84
158
  }
85
159
  const parts = [];
86
- if (gate.exitCode !== null && gate.exitCode !== undefined)
87
- parts.push(`exit=${gate.exitCode}`);
88
- if (gate.durationMs !== null && gate.durationMs !== undefined) {
89
- parts.push(`${(gate.durationMs / 1000).toFixed(1)}s`);
160
+ // A retried gate reports both runs (#1772). The stored columns hold only the
161
+ // run whose verdict was recorded, so printing them would silently drop half
162
+ // of the evidence the retry exists to produce.
163
+ const flaky = parseFlakyMarker(gate.logTail);
164
+ if (flaky) {
165
+ parts.push(`exit=${flaky.exit}`, flaky.duration);
90
166
  }
167
+ else {
168
+ if (gate.exitCode !== null && gate.exitCode !== undefined)
169
+ parts.push(`exit=${gate.exitCode}`);
170
+ if (gate.durationMs !== null && gate.durationMs !== undefined) {
171
+ parts.push(`${(gate.durationMs / 1000).toFixed(1)}s`);
172
+ }
173
+ }
174
+ // After the duration and never merged into it (#1771): the duration is what
175
+ // the gate's command took, the wait is what the machine made it queue for.
176
+ // Adding them would hide contention inside a number that timeout budgets and
177
+ // "did this gate get slower" are read from.
178
+ const waited = MUTEX_WAITED_PATTERN.exec(gate.logTail ?? '');
179
+ if (waited)
180
+ parts.push(`waited=${waited[1]}`);
91
181
  return parts.join(', ');
92
182
  }
93
183
  /**
@@ -105,8 +195,26 @@ function formatDetail(gate) {
105
195
  function formatGateSource(gate) {
106
196
  return gate.source === 'contract' ? ' [contract]' : '';
107
197
  }
198
+ /**
199
+ * The verdict word on a gate's line.
200
+ *
201
+ * FLAKY displaces PASS/FAIL rather than being appended to it (Issue #1772),
202
+ * because the whole point is that neither of those two words was true of this
203
+ * gate: it failed and then it passed. How the run *counted* it is not lost —
204
+ * `flakyIsPass` decided the stored status, which is what the RESULT line and
205
+ * the exit code are built from, so a FLAKY line on a `RESULT failed` run reads
206
+ * exactly as it should.
207
+ *
208
+ * A gate that failed twice keeps FAIL: the retry agreed, and nothing about it
209
+ * was flaky.
210
+ */
211
+ function gateLabel(gate) {
212
+ if (parseFlakyMarker(gate.logTail)?.outcome === 'flaky')
213
+ return exports.FLAKY_GATE_LABEL;
214
+ return GATE_LABELS[gate.status] ?? gate.status.toUpperCase();
215
+ }
108
216
  function formatGateLine(gate) {
109
- const label = GATE_LABELS[gate.status] ?? gate.status.toUpperCase();
217
+ const label = gateLabel(gate);
110
218
  const detail = formatDetail(gate);
111
219
  const head = detail ? `GATE ${gate.gateId} ${label} (${detail})` : `GATE ${gate.gateId} ${label}`;
112
220
  return `${head}${formatGateSource(gate)}`;
@@ -9,7 +9,7 @@
9
9
  * - `src/components/worktree/ActivityPane.tsx`
10
10
  * - `src/components/worktree/WorktreeDetailRefactored.tsx`
11
11
  *
12
- * The Activity Bar is a 48px-wide vertical bar that hosts 7 activities.
12
+ * The Activity Bar is a 48px-wide vertical bar that hosts the activities below.
13
13
  * Re-clicking the active icon toggles the ActivityPane closed (null).
14
14
  */
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -33,6 +33,10 @@ exports.ACTIVITIES = [
33
33
  { id: 'todo', labelKey: 'activityBar.todo', icon: lucide_react_1.ListTodo },
34
34
  // Issue #1441: worktree-scoped Skill install/uninstall management.
35
35
  { id: 'skills', labelKey: 'activityBar.skills', icon: lucide_react_1.Sparkles },
36
+ // Issue #1816: the execution contract and the verification gates. Appended
37
+ // rather than inserted so the existing ArrowUp/ArrowDown order — which users
38
+ // and tests both index by position — is unchanged.
39
+ { id: 'verification', labelKey: 'activityBar.verification', icon: lucide_react_1.ShieldCheck },
36
40
  ];
37
41
  /**
38
42
  * Set of valid ActivityId values for runtime validation.
@@ -296,7 +296,43 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
296
296
  if (isDuplicatePrompt(pollerState, promptKey)) {
297
297
  return 'duplicate';
298
298
  }
299
- // 3. Resolve auto answer under the execution contract's policy (Issue #1547).
299
+ // 3. Issue #1829: codex's own launch dialogs are CodexTool.waitForReady()'s
300
+ // to answer, not the poller's. Every one of them defaults to option 1, and
301
+ // the base rules answer the default:
302
+ //
303
+ // "Hooks need review" -> 1. Review hooks (undoes Issue #1760; the pane
304
+ // then sits two screens deep in a review UI that
305
+ // only `t`/`esc` leave, reported as `running`)
306
+ // "Update available" -> 1. Update now (undoes Issue #890; runs
307
+ // `npm install -g @openai/codex`, killing codex)
308
+ // "Do you trust …" -> 1. Yes, continue
309
+ //
310
+ // waitForReady answers the same screens deliberately and differently ('3',
311
+ // '2', '1' — each without a trailing Enter), but only during startSession,
312
+ // while this poller runs on its own 2s phase for the life of the session.
313
+ // Whichever sees the dialog first decides, so the fix is to leave them all
314
+ // to the tool. Auto-answer layer only: detectPrompt above still reports the
315
+ // prompt, so the human keeps seeing the screen and the response poller
316
+ // still notifies them about it.
317
+ const launchDialog = cliToolId === 'codex' ? (0, cli_patterns_1.getCodexLifecycleDialog)(cleanOutput) : null;
318
+ if (launchDialog) {
319
+ // Recorded through the #1684 channel so `capture --json` and `cmate wait`
320
+ // can name the reason instead of showing a worker that went quiet.
321
+ (0, auto_yes_suppression_state_1.recordPolicySuppression)(worktreeId, cliToolId, instanceId, {
322
+ reason: 'agent-launch-dialog',
323
+ mode: null,
324
+ promptType: promptDetection.promptData.type,
325
+ });
326
+ logger.warn('poller:auto-yes-skipped-launch-dialog', {
327
+ worktreeId,
328
+ cliToolId,
329
+ instanceId,
330
+ dialog: launchDialog,
331
+ promptType: promptDetection.promptData.type,
332
+ });
333
+ return 'no_answer';
334
+ }
335
+ // 4. Resolve auto answer under the execution contract's policy (Issue #1547).
300
336
  // Auto-Yes calls detectPrompt directly instead of going through
301
337
  // status-detector, so this is the only place the policy can gate an
302
338
  // auto-answer: a prompt the policy withholds is left for a human, and the
@@ -328,7 +364,7 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
328
364
  if (answer === null) {
329
365
  return 'no_answer';
330
366
  }
331
- // 4. Send answer to tmux (Issue #896: resolve the instance-specific session)
367
+ // 5. Send answer to tmux (Issue #896: resolve the instance-specific session)
332
368
  const manager = manager_1.CLIToolManager.getInstance();
333
369
  const cliTool = manager.getTool(cliToolId);
334
370
  const sessionName = cliTool.getSessionName(worktreeId, instanceId);
@@ -343,10 +379,10 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
343
379
  finally {
344
380
  (0, tmux_capture_cache_1.invalidateCache)(sessionName);
345
381
  }
346
- // 5. Update timestamp and reset error count
382
+ // 6. Update timestamp and reset error count
347
383
  updateLastServerResponseTimestamp(compositeKey, Date.now());
348
384
  resetErrorCount(compositeKey);
349
- // 6. Record answered prompt key and timestamp
385
+ // 7. Record answered prompt key and timestamp
350
386
  pollerState.lastAnsweredPromptKey = promptKey;
351
387
  pollerState.lastAnsweredAt = Date.now();
352
388
  logger.info('poller:response-sent', { worktreeId, cliToolId, instanceId });
@@ -11,7 +11,7 @@
11
11
  * auto-yes-poller.ts -> auto-yes-state.ts -> path-validator.ts
12
12
  */
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.THINKING_CHECK_LINE_COUNT = exports.MAX_CONCURRENT_POLLERS = exports.MAX_CONSECUTIVE_ERRORS = exports.MAX_BACKOFF_MS = exports.DUPLICATE_RETRY_EXPIRY_MS = exports.COOLDOWN_INTERVAL_MS = exports.POLLING_INTERVAL_MS = exports.executeRegexWithTimeout = exports.COMPOSITE_KEY_SEPARATOR = void 0;
14
+ exports.THINKING_CHECK_LINE_COUNT = exports.MAX_CONCURRENT_POLLERS = exports.MAX_CONSECUTIVE_ERRORS = exports.MAX_BACKOFF_MS = exports.DUPLICATE_RETRY_EXPIRY_MS = exports.COOLDOWN_INTERVAL_MS = exports.POLLING_INTERVAL_MS = exports.STOP_MATCH_EXCERPT_CONTEXT_LINES = exports.STOP_MATCH_EXCERPT_TRUNCATION_MARKER = exports.STOP_MATCH_EXCERPT_MAX_BYTES = exports.executeRegexWithTimeout = exports.COMPOSITE_KEY_SEPARATOR = void 0;
15
15
  exports.buildCompositeKey = buildCompositeKey;
16
16
  exports.extractWorktreeId = extractWorktreeId;
17
17
  exports.extractCliToolId = extractCliToolId;
@@ -21,6 +21,7 @@ exports.getAutoYesState = getAutoYesState;
21
21
  exports.setAutoYesEnabled = setAutoYesEnabled;
22
22
  exports.disableAutoYes = disableAutoYes;
23
23
  exports.clearAllAutoYesStates = clearAllAutoYesStates;
24
+ exports.truncateToUtf8Bytes = truncateToUtf8Bytes;
24
25
  exports.checkStopCondition = checkStopCondition;
25
26
  exports.deleteAutoYesState = deleteAutoYesState;
26
27
  exports.getAutoYesStateCompositeKeys = getAutoYesStateCompositeKeys;
@@ -204,9 +205,12 @@ function setAutoYesEnabled(worktreeId, cliToolId, enabled, duration, stopPattern
204
205
  * @param cliToolId - CLI tool type (default: 'claude')
205
206
  * @param reason - Optional reason for disabling ('expired' | 'stop_pattern_matched')
206
207
  * @param instanceId - Optional instance identifier (Issue #896; defaults to primary)
208
+ * @param stopMatchedText - Optional excerpt of what the stop pattern matched
209
+ * (Issue #1694). Deliberately *not* carried over from the existing state: it
210
+ * belongs to `reason`, so a disable for any other reason stores none.
207
211
  * @returns Updated auto-yes state
208
212
  */
209
- function disableAutoYes(worktreeId, cliToolId = 'claude', reason, instanceId) {
213
+ function disableAutoYes(worktreeId, cliToolId = 'claude', reason, instanceId, stopMatchedText) {
210
214
  const key = buildCompositeKey(worktreeId, cliToolId, instanceId);
211
215
  const existing = autoYesStates.get(key);
212
216
  const state = {
@@ -215,6 +219,7 @@ function disableAutoYes(worktreeId, cliToolId = 'claude', reason, instanceId) {
215
219
  expiresAt: existing?.expiresAt ?? 0,
216
220
  stopPattern: existing?.stopPattern,
217
221
  stopReason: reason,
222
+ stopMatchedText,
218
223
  };
219
224
  autoYesStates.set(key, state);
220
225
  return state;
@@ -235,6 +240,103 @@ function clearAllAutoYesStates() {
235
240
  */
236
241
  var auto_yes_config_2 = require("../config/auto-yes-config");
237
242
  Object.defineProperty(exports, "executeRegexWithTimeout", { enumerable: true, get: function () { return auto_yes_config_2.executeRegexWithTimeout; } });
243
+ /**
244
+ * Maximum size of the stop-pattern excerpt, in UTF-8 bytes, marker included
245
+ * (Issue #1694).
246
+ *
247
+ * The excerpt answers one question — "is this a real stop or did a build log
248
+ * happen to contain the pattern?" (#1678 A-5) — and a couple of lines answer
249
+ * it. The cap is a hard bound rather than a hint because `cleanOutput` is a
250
+ * whole terminal frame and a greedy pattern can match all of it, and because
251
+ * the value rides in every `capture --json` poll for the rest of the session.
252
+ */
253
+ exports.STOP_MATCH_EXCERPT_MAX_BYTES = 400;
254
+ /**
255
+ * Appended when the excerpt was cut to fit {@link STOP_MATCH_EXCERPT_MAX_BYTES}.
256
+ *
257
+ * Cutting silently would make a fragment read as the whole match, which is the
258
+ * wrong conclusion in exactly the triage this field exists for.
259
+ */
260
+ exports.STOP_MATCH_EXCERPT_TRUNCATION_MARKER = '…[truncated]';
261
+ /** Lines of context kept on either side of the match (Issue #1694). */
262
+ exports.STOP_MATCH_EXCERPT_CONTEXT_LINES = 1;
263
+ /** Shared encoder for byte-length math (UTF-8 by spec). */
264
+ const utf8Encoder = new TextEncoder();
265
+ /** UTF-8 byte length of a string. */
266
+ function utf8ByteLength(text) {
267
+ return utf8Encoder.encode(text).length;
268
+ }
269
+ /**
270
+ * Cut `text` down to `maxBytes` UTF-8 bytes, marker included, never splitting a
271
+ * character (Issue #1694).
272
+ *
273
+ * The budget is measured in bytes rather than characters because the excerpt is
274
+ * copied verbatim into a JSON payload, and a Japanese terminal frame costs 3
275
+ * bytes per character — a character cap would let one frame publish three times
276
+ * the intended payload.
277
+ *
278
+ * @internal Exported for testing purposes only.
279
+ * @param text - Text to bound
280
+ * @param maxBytes - Byte ceiling for the returned string (marker included)
281
+ * @returns `text` unchanged when it already fits, otherwise a prefix of it with
282
+ * {@link STOP_MATCH_EXCERPT_TRUNCATION_MARKER} appended
283
+ */
284
+ function truncateToUtf8Bytes(text, maxBytes = exports.STOP_MATCH_EXCERPT_MAX_BYTES) {
285
+ if (utf8ByteLength(text) <= maxBytes)
286
+ return text;
287
+ const budget = maxBytes - utf8ByteLength(exports.STOP_MATCH_EXCERPT_TRUNCATION_MARKER);
288
+ if (budget <= 0)
289
+ return exports.STOP_MATCH_EXCERPT_TRUNCATION_MARKER;
290
+ let used = 0;
291
+ let kept = '';
292
+ // for..of iterates code points, so a surrogate pair is never halved.
293
+ for (const char of text) {
294
+ const size = utf8ByteLength(char);
295
+ if (used + size > budget)
296
+ break;
297
+ kept += char;
298
+ used += size;
299
+ }
300
+ return kept + exports.STOP_MATCH_EXCERPT_TRUNCATION_MARKER;
301
+ }
302
+ /**
303
+ * Build the excerpt shown for a stop-pattern hit (Issue #1694).
304
+ *
305
+ * Whole lines, not the raw match: a pattern like `error` matched against a
306
+ * terminal frame yields the six characters `error`, which tells the operator
307
+ * nothing about whether it came from the agent asking a question or from a
308
+ * dependency's build log scrolling past. The surrounding line is the smallest
309
+ * unit that carries that.
310
+ *
311
+ * @param regex - The already-constructed stop pattern (no `g` flag, so `exec`
312
+ * is position-independent and does not disturb the caller's `test`)
313
+ * @param output - ANSI-stripped terminal output the pattern matched
314
+ * @returns Bounded excerpt, or null when the match cannot be located
315
+ */
316
+ function buildStopMatchExcerpt(regex, output) {
317
+ let match;
318
+ try {
319
+ match = regex.exec(output);
320
+ }
321
+ catch {
322
+ return null;
323
+ }
324
+ if (!match)
325
+ return null;
326
+ const matchStart = match.index;
327
+ const matchEnd = matchStart + match[0].length;
328
+ const lines = output.split('\n');
329
+ const firstLine = output.slice(0, matchStart).split('\n').length - 1;
330
+ const lastLine = output.slice(0, matchEnd).split('\n').length - 1;
331
+ const from = Math.max(0, firstLine - exports.STOP_MATCH_EXCERPT_CONTEXT_LINES);
332
+ const to = Math.min(lines.length - 1, lastLine + exports.STOP_MATCH_EXCERPT_CONTEXT_LINES);
333
+ const raw = lines.slice(from, to + 1).join('\n');
334
+ // Terminal frames are padded with blank lines and trailing spaces; those are
335
+ // pure noise here and eat the byte budget. A whitespace-only match keeps its
336
+ // raw form rather than becoming an empty, unexplained field.
337
+ const trimmed = raw.trim();
338
+ return truncateToUtf8Bytes(trimmed.length > 0 ? trimmed : raw);
339
+ }
238
340
  /**
239
341
  * Check if the terminal output matches the stop condition pattern.
240
342
  * If matched, disables auto-yes for the worktree/agent.
@@ -275,7 +377,10 @@ function checkStopCondition(compositeKey, cleanOutput, onStopMatched) {
275
377
  return false;
276
378
  }
277
379
  if (matched) {
278
- disableAutoYes(worktreeId, cliToolId, 'stop_pattern_matched', instanceId);
380
+ // Issue #1694: what matched, not just that something did. Built here
381
+ // because this is the only frame that still holds the output.
382
+ const stopMatchedText = buildStopMatchExcerpt(regex, cleanOutput) ?? undefined;
383
+ disableAutoYes(worktreeId, cliToolId, 'stop_pattern_matched', instanceId, stopMatchedText);
279
384
  if (onStopMatched) {
280
385
  onStopMatched(compositeKey);
281
386
  }
@@ -136,15 +136,19 @@ class AntigravityTool extends base_1.BaseCLITool {
136
136
  await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_SESSION_CREATE_WAIT_MS));
137
137
  // Start agy in interactive mode, optionally pinned to a model.
138
138
  //
139
- // Issue #1762: `prepareAgentLaunch` merges CommandMate's named hook into
139
+ // Issue #1762: the launch merges CommandMate's named hook into
140
140
  // `~/.gemini/config/hooks.json` — agy's single global config, shared with
141
141
  // gemini's tree and with whatever the user has in it — and prefixes
142
142
  // `CM_HOOK_URL`. That variable is the *only* correlation channel agy has:
143
143
  // its payloads carry no `cwd`, its hooks run in `~/.gemini/config`, and
144
144
  // one file serves every worktree on the machine. `--model` is appended
145
- // after, so the env prefix stays in front of the command.
146
- // `CM_AGENT_HOOKS_INJECT=0` returns bare `agy`, unchanged from before.
147
- const base = (0, agent_session_lifecycle_1.prepareAgentLaunch)({ worktreeId, cliToolId: sources_1.ANTIGRAVITY_CLI_TOOL_ID, instanceId }, this.command).command;
145
+ // after the rendered line, so the env assignments stay in front of the
146
+ // command. `CM_AGENT_HOOKS_INJECT=0` returns bare `agy`, unchanged.
147
+ const base = (0, agent_session_lifecycle_1.buildAgentLaunchCommandLine)({
148
+ target: { worktreeId, cliToolId: sources_1.ANTIGRAVITY_CLI_TOOL_ID, instanceId },
149
+ executablePath: this.command,
150
+ worktreePath,
151
+ });
148
152
  const launchCommand = model ? `${base} --model ${shellSingleQuote(model)}` : base;
149
153
  await (0, tmux_1.sendKeys)(sessionName, launchCommand, true);
150
154
  // Wait for agy to initialize
@@ -31,33 +31,6 @@ const CODEX_POLL_INTERVAL_MS = 1000;
31
31
  const CODEX_INIT_MAX_ATTEMPTS = 30;
32
32
  /** Timeout for waiting for prompt before sending a message */
33
33
  const CODEX_PROMPT_WAIT_TIMEOUT_MS = 15000;
34
- /**
35
- * Anchors of codex's "Hooks need review" dialog (Issue #1760, measured on
36
- * codex-cli 0.147.0):
37
- *
38
- * ```
39
- * Hooks need review
40
- * 5 hooks are new or changed.
41
- * Hooks can run outside the sandbox after you trust them.
42
- *
43
- * > 1. Review hooks
44
- * 2. Trust all and continue
45
- * 3. Continue without trusting (hooks won't run)
46
- * ```
47
- *
48
- * It has to be handled here rather than in `getCodexActiveDialog`, which
49
- * classifies it as `null`: its wording matches none of that function's three
50
- * anchors (`Skip until next version` / `Do you trust` / `Press enter to
51
- * continue`). Measured consequence of leaving it alone, on a pane with the
52
- * generated `hooks.json` present: `isCodexPromptReady` stays false for the full
53
- * 30-attempt window and the session is then handed to `sendMessage` still
54
- * sitting on the dialog. Every launch, because "continue without trusting" is
55
- * not remembered — verified by relaunching and getting the same screen.
56
- *
57
- * Both strings are required so a "hooks" mention elsewhere cannot select an
58
- * option on a live prompt.
59
- */
60
- const CODEX_HOOKS_REVIEW_ANCHORS = ['Hooks need review', 'Continue without trusting'];
61
34
  /**
62
35
  * Option 3, "Continue without trusting (hooks won't run)".
63
36
  *
@@ -72,21 +45,57 @@ const CODEX_HOOKS_REVIEW_ANCHORS = ['Hooks need review', 'Continue without trust
72
45
  * Sent alone, like the other numbered dialogs (Issue #890): codex confirms a
73
46
  * numbered selection instantly, and a trailing Enter would land on the next
74
47
  * screen. Verified live — the prompt was ready on the following poll.
48
+ *
49
+ * Re-verified on codex-cli 0.148.0 for Issue #1829, against the objection that
50
+ * the dialog's own footer says `Press enter to confirm`. With the trust hashes
51
+ * invalidated and Auto-Yes off, a session launched onto this dialog reached
52
+ * `› Ask Codex to do anything` and then ran the message it was sent — on the
53
+ * `'3'` alone. The footer and the number key are not exclusive: the number
54
+ * selects AND confirms, Enter confirms the highlighted option. That is also why
55
+ * a trailing Enter is so costly here — the number having already advanced the
56
+ * screen, the Enter lands on the NEXT one, which is precisely how a pane ends up
57
+ * two screens deep in the hooks review UI.
75
58
  */
76
59
  const CODEX_HOOKS_REVIEW_DECLINE_KEY = '3';
60
+ /**
61
+ * How many times `waitForReady` may press `esc` to climb out of codex's hooks
62
+ * review screens (Issue #1829).
63
+ *
64
+ * Two is the depth of the UI — detail -> list -> closed — and the cap exists
65
+ * because the alternative is one press per poll: 30 keystrokes into whatever is
66
+ * really on screen if the classifier is ever wrong about a frame. Two spare
67
+ * presses cover a redraw landing between capture and send.
68
+ */
69
+ const CODEX_HOOKS_SCREEN_MAX_ESCAPES = 4;
77
70
  /**
78
71
  * Whether the pane is sitting on the hooks review dialog.
79
72
  *
80
73
  * Position-independent on purpose, unlike `getCodexActiveDialog`: the only
81
74
  * caller checks `isCodexPromptReady` first and returns when a genuine prompt
82
75
  * exists, so residual dialog text above a live prompt is never reached, and a
83
- * one-shot guard stops the key being sent twice.
76
+ * one-shot guard stops the key being sent twice. Callers OUTSIDE this launch
77
+ * sequence must use `getCodexLifecycleDialog` instead, which is position-based.
78
+ *
79
+ * The dialog has to be handled here rather than in `getCodexActiveDialog`, which
80
+ * classifies it as `null`: its wording matches none of that function's three
81
+ * anchors (`Skip until next version` / `Do you trust` / `Press enter to
82
+ * continue`). Measured consequence of leaving it alone, on a pane with the
83
+ * generated `hooks.json` present: `isCodexPromptReady` stays false for the full
84
+ * 30-attempt window and the session is then handed to `sendMessage` still
85
+ * sitting on the dialog. Every launch, because "continue without trusting" is
86
+ * not remembered — verified by relaunching and getting the same screen.
87
+ *
88
+ * The anchors themselves live in `detection/cli-patterns` (Issue #1829): the
89
+ * Auto-Yes poller has to recognise the same screen in order to keep its hands
90
+ * off it, and two copies of the anchors would be two chances to disagree about
91
+ * what this dialog is.
84
92
  *
85
93
  * @param output - ANSI-stripped pane capture
86
94
  * @returns True when both anchors of the dialog are present
95
+ * @see CODEX_HOOKS_REVIEW_ANCHORS
87
96
  */
88
97
  function isCodexHooksReviewDialog(output) {
89
- return CODEX_HOOKS_REVIEW_ANCHORS.every((anchor) => output.includes(anchor));
98
+ return cli_patterns_1.CODEX_HOOKS_REVIEW_ANCHORS.every((anchor) => output.includes(anchor));
90
99
  }
91
100
  /**
92
101
  * Codex CLI tool implementation
@@ -157,7 +166,11 @@ class CodexTool extends base_1.BaseCLITool {
157
166
  // Falls back to the bare command on any failure and when
158
167
  // `CM_AGENT_HOOKS_INJECT=0`; a session that starts without hooks is the
159
168
  // pre-#1760 status quo, and a session that fails to start is not.
160
- const launchCommand = (0, agent_session_lifecycle_1.prepareAgentLaunch)({ worktreeId, cliToolId: sources_1.CODEX_CLI_TOOL_ID, instanceId }, this.command).command;
169
+ const launchCommand = (0, agent_session_lifecycle_1.buildAgentLaunchCommandLine)({
170
+ target: { worktreeId, cliToolId: sources_1.CODEX_CLI_TOOL_ID, instanceId },
171
+ executablePath: this.command,
172
+ worktreePath,
173
+ });
161
174
  // Start Codex CLI in interactive mode
162
175
  await (0, tmux_1.sendKeys)(sessionName, launchCommand, true);
163
176
  // Wait for Codex to initialize
@@ -185,6 +198,7 @@ class CodexTool extends base_1.BaseCLITool {
185
198
  let updateDialogHandled = false;
186
199
  let trustDialogHandled = false;
187
200
  let hooksReviewHandled = false;
201
+ let hooksScreenEscapes = 0;
188
202
  for (let i = 0; i < CODEX_INIT_MAX_ATTEMPTS; i++) {
189
203
  try {
190
204
  const rawOutput = await (0, tmux_1.capturePane)(sessionName, 50);
@@ -208,6 +222,25 @@ class CodexTool extends base_1.BaseCLITool {
208
222
  await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.CODEX_DIALOG_SETTLE_MS));
209
223
  continue;
210
224
  }
225
+ // Issue #1829: back out of the two screens the hooks dialog leads to.
226
+ // Confirming its option 1 -- which the Auto-Yes poller did on two live
227
+ // sessions, and which a human can do too -- opens a review UI whose only
228
+ // exits are `t` and `esc`. `t` is out: it writes `[hooks.state…]` into
229
+ // the operator's own ~/.codex/config.toml, the grant Issue #1760
230
+ // declined on their behalf. So `esc`, once per poll until the screens
231
+ // are gone. Before this, nothing sent either key: the whole 30-attempt
232
+ // window elapsed, waitForReady returned as if ready, and the session was
233
+ // left parked there -- reported as `running`, because neither screen
234
+ // carries an option, a confirm footer or a thinking indicator.
235
+ const hooksScreen = (0, cli_patterns_1.getCodexLifecycleDialog)(output);
236
+ if ((hooksScreen === 'hooks-list' || hooksScreen === 'hooks-detail') &&
237
+ hooksScreenEscapes < CODEX_HOOKS_SCREEN_MAX_ESCAPES) {
238
+ await (0, tmux_1.sendSpecialKey)(sessionName, 'Escape');
239
+ hooksScreenEscapes++;
240
+ logger.info('codex-hooks-screen-escaped');
241
+ await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.CODEX_DIALOG_SETTLE_MS));
242
+ continue;
243
+ }
211
244
  // Issue #892: classify the bottom-most ACTIVE dialog by position. A dialog
212
245
  // whose text is only residual scrollback above a genuine prompt returns
213
246
  // null here, so no stray key is sent after it has been dismissed.