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
@@ -149,7 +149,11 @@ class CopilotTool extends base_1.BaseCLITool {
149
149
  // Fails open in every branch: with `CM_AGENT_HOOKS_INJECT=0`, or with a
150
150
  // settings file that cannot be read or written, this is byte-for-byte the
151
151
  // `gh copilot` this line has always sent.
152
- const launchCommand = (0, agent_session_lifecycle_1.prepareAgentLaunch)({ worktreeId, cliToolId: tool_id_1.COPILOT_CLI_TOOL_ID, instanceId }, hook_settings_1.COPILOT_LAUNCH_COMMAND).command;
152
+ const launchCommand = (0, agent_session_lifecycle_1.buildAgentLaunchCommandLine)({
153
+ target: { worktreeId, cliToolId: tool_id_1.COPILOT_CLI_TOOL_ID, instanceId },
154
+ executablePath: hook_settings_1.COPILOT_LAUNCH_COMMAND,
155
+ worktreePath,
156
+ });
153
157
  // Start Copilot CLI in interactive mode
154
158
  await (0, tmux_1.sendKeys)(sessionName, launchCommand, true);
155
159
  // Wait for Copilot to initialize
@@ -16,7 +16,6 @@ const submit_verified_sender_1 = require("./submit-verified-sender");
16
16
  const tmux_capture_cache_1 = require("../tmux/tmux-capture-cache");
17
17
  const cli_patterns_1 = require("../detection/cli-patterns");
18
18
  const sources_1 = require("../../lib/hooks/sources");
19
- const source_1 = require("../../lib/hooks/sources/gemini/source");
20
19
  const agent_session_lifecycle_1 = require("../../lib/session/agent-session-lifecycle");
21
20
  const logger_1 = require("../../lib/logger");
22
21
  const cli_tool_timing_config_1 = require("../../config/cli-tool-timing-config");
@@ -92,23 +91,24 @@ class GeminiTool extends base_1.BaseCLITool {
92
91
  });
93
92
  // Wait a moment for the session to be created
94
93
  await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_SESSION_CREATE_WAIT_MS));
95
- // Issue #1762: hand this worktree its own hooks config, merged into any
96
- // `.gemini/settings.json` that is already there. Written from here rather
97
- // than from the source's `prepareLaunch` because the worktree path is the
98
- // one input `AgentInstanceRef` does not carry, and gemini is the only tool
99
- // whose config is scoped to a worktree. Fail-open: a config that cannot be
100
- // written costs the events and nothing else.
101
- (0, source_1.injectGeminiHookSettings)(worktreePath, {
102
- worktreeId,
103
- cliToolId: sources_1.GEMINI_CLI_TOOL_ID,
104
- instanceId,
105
- });
106
94
  // Start Gemini CLI in interactive mode (no flags = interactive REPL).
107
- // `prepareAgentLaunch` prefixes `CM_HOOK_URL`, which is what tells the
95
+ //
96
+ // Issue #1762 hands this worktree its own hooks config, merged into any
97
+ // `.gemini/settings.json` that is already there; Issue #1846 moved that
98
+ // write inside `prepareLaunch`, where it belongs — the worktree path is
99
+ // now part of the launch context, so the second entry point this file
100
+ // used to call (`injectGeminiHookSettings`) is gone.
101
+ //
102
+ // The rendered line prefixes `CM_HOOK_URL`, which is what tells the
108
103
  // receiver which instance an event came from — `.gemini/settings.json` is
109
104
  // per worktree and cannot. `CM_AGENT_HOOKS_INJECT=0` returns the bare
110
- // command, unchanged from before this Issue.
111
- const launchCommand = (0, agent_session_lifecycle_1.prepareAgentLaunch)({ worktreeId, cliToolId: sources_1.GEMINI_CLI_TOOL_ID, instanceId }, this.command).command;
105
+ // command, unchanged from before these Issues. Fail-open throughout: a
106
+ // config that cannot be written costs the events and nothing else.
107
+ const launchCommand = (0, agent_session_lifecycle_1.buildAgentLaunchCommandLine)({
108
+ target: { worktreeId, cliToolId: sources_1.GEMINI_CLI_TOOL_ID, instanceId },
109
+ executablePath: this.command,
110
+ worktreePath,
111
+ });
112
112
  await (0, tmux_1.sendKeys)(sessionName, launchCommand, true);
113
113
  // Wait for Gemini to initialize (minimum wait for banner/auth)
114
114
  await new Promise((resolve) => setTimeout(resolve, GEMINI_INIT_WAIT_MS));
@@ -148,9 +148,15 @@ class OpenCodeTool extends base_1.BaseCLITool {
148
148
  // that nothing can read back (§5.9). Null means "no structured events",
149
149
  // and the launch below is then the pre-#1763 bare command.
150
150
  await (0, runtime_1.reserveOpencodeServerPort)(target, worktreePath);
151
- // Start OpenCode TUI. `prepareAgentLaunch` asks the tool's own
152
- // `AgentEventSource` for the command line (S3/S4/S5) and never throws.
153
- const launchCommand = (0, agent_session_lifecycle_1.prepareAgentLaunch)(target, this.command).command;
151
+ // Start OpenCode TUI. `buildAgentLaunchCommandLine` asks the tool's own
152
+ // `AgentEventSource` for the plan (S3/S4/S5) and never throws. opencode's
153
+ // environment is empty it is the one source with no correlation
154
+ // variable, because CommandMate holds the connection (#1846).
155
+ const launchCommand = (0, agent_session_lifecycle_1.buildAgentLaunchCommandLine)({
156
+ target,
157
+ executablePath: this.command,
158
+ worktreePath,
159
+ });
154
160
  await (0, tmux_1.sendKeys)(sessionName, launchCommand, true);
155
161
  // Wait for OpenCode to initialize (GPU model loading via Ollama)
156
162
  await new Promise((resolve) => setTimeout(resolve, exports.OPENCODE_INIT_WAIT_MS));
@@ -4,11 +4,12 @@
4
4
  * Shared between response-poller.ts and API routes
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.CLAUDE_SESSION_ERROR_REGEX_PATTERNS = exports.CLAUDE_SESSION_ERROR_PATTERNS = exports.extractAnsiSequences = exports.stripAnsi = exports.ANTIGRAVITY_SKIP_PATTERNS = exports.ANTIGRAVITY_SELECTION_LIST_PATTERN = exports.ANTIGRAVITY_SEPARATOR_PATTERN = exports.ANTIGRAVITY_THINKING_PATTERN = exports.ANTIGRAVITY_PROMPT_PATTERN = exports.VIBE_LOCAL_THINKING_PATTERN = exports.VIBE_LOCAL_PROMPT_PATTERN = exports.COPILOT_SKIP_PATTERNS = exports.COPILOT_SELECTION_LIST_PATTERN = exports.COPILOT_SEPARATOR_PATTERN = exports.COPILOT_THINKING_PATTERN = exports.COPILOT_PROMPT_PATTERN = exports.OPENCODE_SKIP_PATTERNS = exports.OPENCODE_SEPARATOR_PATTERN = exports.CLAUDE_SELECTION_LIST_FOOTER = exports.CLAUDE_MODEL_OVERLAY_FOOTER_PATTERN = exports.OPENCODE_SELECTION_LIST_PATTERN = exports.OPENCODE_PROCESSING_INDICATOR = exports.OPENCODE_RESPONSE_COMPLETE = exports.OPENCODE_LOADING_PATTERN = exports.OPENCODE_THINKING_PATTERN = exports.OPENCODE_PROMPT_AFTER_RESPONSE = exports.OPENCODE_PROMPT_PATTERN = exports.GEMINI_THINKING_PATTERN = exports.GEMINI_PROMPT_PATTERN = exports.MAX_PASTED_TEXT_RETRIES = exports.PASTED_TEXT_DETECT_DELAY = exports.PASTED_TEXT_PATTERN = exports.CODEX_STATUS_BAR_PATTERN = exports.CODEX_PAGER_FOOTER_PATTERN = exports.CODEX_APPROVAL_FOOTER_PATTERN = exports.CODEX_SELECTION_LIST_PATTERN = exports.CODEX_SEPARATOR_PATTERN = exports.CODEX_DIALOG_PATTERN = exports.CODEX_PROMPT_PATTERN = exports.CLAUDE_TRUST_DIALOG_PATTERN = exports.CLAUDE_SEPARATOR_PATTERN = exports.CLAUDE_PROMPT_PATTERN = exports.CODEX_INTERRUPT_HINT_PATTERN = exports.CODEX_THINKING_PATTERN = exports.CLAUDE_INTERRUPT_HINT_PATTERN = exports.CLAUDE_THINKING_PATTERN = exports.CLAUDE_SPINNER_CHARS = void 0;
7
+ exports.CLAUDE_SESSION_ERROR_REGEX_PATTERNS = exports.CLAUDE_SESSION_ERROR_PATTERNS = exports.extractAnsiSequences = exports.stripAnsi = exports.ANTIGRAVITY_SKIP_PATTERNS = exports.ANTIGRAVITY_SELECTION_LIST_PATTERN = exports.ANTIGRAVITY_SEPARATOR_PATTERN = exports.ANTIGRAVITY_THINKING_PATTERN = exports.ANTIGRAVITY_PROMPT_PATTERN = exports.VIBE_LOCAL_THINKING_PATTERN = exports.VIBE_LOCAL_PROMPT_PATTERN = exports.COPILOT_SKIP_PATTERNS = exports.COPILOT_SELECTION_LIST_PATTERN = exports.COPILOT_SEPARATOR_PATTERN = exports.COPILOT_THINKING_PATTERN = exports.COPILOT_PROMPT_PATTERN = exports.OPENCODE_SKIP_PATTERNS = exports.OPENCODE_SEPARATOR_PATTERN = exports.CLAUDE_SELECTION_LIST_FOOTER = exports.CLAUDE_MODEL_OVERLAY_FOOTER_PATTERN = exports.OPENCODE_SELECTION_LIST_PATTERN = exports.OPENCODE_PROCESSING_INDICATOR = exports.OPENCODE_RESPONSE_COMPLETE = exports.OPENCODE_LOADING_PATTERN = exports.OPENCODE_THINKING_PATTERN = exports.OPENCODE_PROMPT_AFTER_RESPONSE = exports.OPENCODE_PROMPT_PATTERN = exports.GEMINI_THINKING_PATTERN = exports.GEMINI_PROMPT_PATTERN = exports.MAX_PASTED_TEXT_RETRIES = exports.PASTED_TEXT_DETECT_DELAY = exports.PASTED_TEXT_PATTERN = exports.CODEX_STATUS_BAR_PATTERN = exports.CODEX_PAGER_FOOTER_PATTERN = exports.CODEX_APPROVAL_FOOTER_PATTERN = exports.CODEX_SELECTION_LIST_PATTERN = exports.CODEX_SEPARATOR_PATTERN = exports.CODEX_HOOKS_REVIEW_ANCHORS = exports.CODEX_DIALOG_PATTERN = exports.CODEX_PROMPT_PATTERN = exports.CLAUDE_TRUST_DIALOG_PATTERN = exports.CLAUDE_SEPARATOR_PATTERN = exports.CLAUDE_PROMPT_PATTERN = exports.CODEX_INTERRUPT_HINT_PATTERN = exports.CODEX_THINKING_PATTERN = exports.CLAUDE_INTERRUPT_HINT_PATTERN = exports.CLAUDE_THINKING_PATTERN = exports.CLAUDE_SPINNER_CHARS = void 0;
8
8
  exports.isCodexTurnActive = isCodexTurnActive;
9
9
  exports.findClaudeChromeStart = findClaudeChromeStart;
10
10
  exports.isCodexPromptReady = isCodexPromptReady;
11
11
  exports.getCodexActiveDialog = getCodexActiveDialog;
12
+ exports.getCodexLifecycleDialog = getCodexLifecycleDialog;
12
13
  exports.detectThinking = detectThinking;
13
14
  exports.getCliToolPatterns = getCliToolPatterns;
14
15
  exports.stripBoxDrawing = stripBoxDrawing;
@@ -330,7 +331,18 @@ function isCodexPromptReady(output) {
330
331
  * update dialog wins over its own "Press enter to continue" footer, because Enter
331
332
  * on the update dialog could confirm the default "1. Update now" (npm install).
332
333
  */
333
- function getCodexActiveDialog(output) {
334
+ /**
335
+ * The lines of Codex's ACTIVE region: everything strictly below the bottom-most
336
+ * genuine input-prompt line, or the whole frame when there is no prompt line
337
+ * (Issue #892).
338
+ *
339
+ * This is the one rule that keeps every Codex dialog classifier honest.
340
+ * capturePane returns scrollback, so a dialog that was answered minutes ago is
341
+ * still in the frame; only what sits BELOW the live prompt is still awaiting a
342
+ * key. Shared by getCodexActiveDialog and getCodexLifecycleDialog so the two
343
+ * cannot drift into disagreeing about what "active" means.
344
+ */
345
+ function codexActiveRegionLines(output) {
334
346
  const lines = output.split('\n');
335
347
  // Index of the bottom-most genuine input-prompt line (-1 if none).
336
348
  let promptIdx = -1;
@@ -340,10 +352,12 @@ function getCodexActiveDialog(output) {
340
352
  break;
341
353
  }
342
354
  }
343
- // Active region = lines strictly below the genuine prompt (the whole frame when
344
- // there is no genuine prompt). Residual dialog text above a live prompt is
345
- // excluded, so a dialog lingering in scrollback is never treated as active.
346
- const active = lines.slice(promptIdx + 1).join('\n');
355
+ return lines.slice(promptIdx + 1);
356
+ }
357
+ function getCodexActiveDialog(output) {
358
+ // Residual dialog text above a live prompt is excluded, so a dialog lingering
359
+ // in scrollback is never treated as active.
360
+ const active = codexActiveRegionLines(output).join('\n');
347
361
  if (active === '') {
348
362
  return null;
349
363
  }
@@ -359,6 +373,134 @@ function getCodexActiveDialog(output) {
359
373
  }
360
374
  return null;
361
375
  }
376
+ /**
377
+ * Anchors of codex's "Hooks need review" launch dialog — screen 1 of the three
378
+ * it can put in front of a session (Issue #1760, re-measured on codex-cli
379
+ * 0.148.0 for Issue #1829):
380
+ *
381
+ * ```
382
+ * Hooks need review
383
+ * 4 hooks are new or changed.
384
+ * Hooks can run outside the sandbox after you trust them.
385
+ *
386
+ * > 1. Review hooks
387
+ * 2. Trust all and continue
388
+ * 3. Continue without trusting (hooks won't run)
389
+ * Press enter to confirm or esc to go back
390
+ * ```
391
+ *
392
+ * The hook COUNT is data — 0.147.0 said 5, 0.148.0 said 4 — so neither anchor
393
+ * reads it. Both strings are required so a "hooks" mention elsewhere cannot
394
+ * select an option on a live prompt.
395
+ */
396
+ exports.CODEX_HOOKS_REVIEW_ANCHORS = ['Hooks need review', 'Continue without trusting'];
397
+ /**
398
+ * Footer of screen 2, the hooks LIST, new in codex-cli 0.148.0 (Issue #1829):
399
+ * `Press t to trust all; enter to review hooks; esc to close`.
400
+ *
401
+ * The semicolon is what separates it from screen 3's footer — "trust all;" and
402
+ * "trust;" are disjoint — and matching the footer rather than the table above it
403
+ * keeps the two screens distinguishable by a single line each.
404
+ */
405
+ const CODEX_HOOKS_LIST_FOOTER_PATTERN = /press\s+t\s+to\s+trust\s+all\s*;/i;
406
+ /**
407
+ * Footer of screen 3, the per-hook review DETAIL (Issue #1829):
408
+ * `Press t to trust; esc to go back`. Where both live sessions in the Issue were
409
+ * found parked.
410
+ */
411
+ const CODEX_HOOKS_DETAIL_FOOTER_PATTERN = /press\s+t\s+to\s+trust\s*;/i;
412
+ /**
413
+ * How much of the active region {@link getCodexLifecycleDialog} judges, in
414
+ * non-blank lines counted from the bottom (Issue #1829).
415
+ *
416
+ * `getCodexActiveDialog` searches the whole active region, which is right for
417
+ * its caller: `waitForReady` only ever runs during `startSession`, when nothing
418
+ * else can be on screen. This classifier runs on every Auto-Yes poll for the
419
+ * life of the session, where "active region" alone is not enough — a codex
420
+ * approval request renders no `› ` composer line, so an approval that comes up
421
+ * while a dismissed hooks screen is still inside the capture window would have
422
+ * the whole frame as its active region and would be mistaken for the dialog.
423
+ * Requiring the dialog to be in the TAIL is what separates the screen the user
424
+ * is looking at from the one they have already left.
425
+ *
426
+ * 12 lines fits the tallest screen this has to recognise (the review dialog's
427
+ * two anchors sit 6 lines apart) and none of the shorter frames below it.
428
+ */
429
+ const CODEX_LIFECYCLE_TAIL_LINES = 12;
430
+ /**
431
+ * The interactive update dialog, by its option-3 label or its option-1 line.
432
+ *
433
+ * Deliberately stricter than `getCodexActiveDialog`'s `Update` AND `Skip`
434
+ * fallback: that pair can occur in ordinary agent output, and here a false
435
+ * positive silently stops Auto-Yes answering a real prompt. Both anchors below
436
+ * are dialog chrome that agent output does not produce.
437
+ */
438
+ const CODEX_UPDATE_DIALOG_ANCHORS = [
439
+ /skip until next version/i,
440
+ /^\s*[›❯]?\s*\d+\.\s*Update now/im,
441
+ ];
442
+ /** The directory-trust dialog's question line. */
443
+ const CODEX_TRUST_DIALOG_ANCHOR = /Do you trust/;
444
+ /**
445
+ * Classify the bottom-most ACTIVE codex lifecycle screen (Issue #1829).
446
+ *
447
+ * Position-based, via {@link codexActiveRegionLines}: a dialog left in
448
+ * scrollback above a live prompt is not active and returns `null`. That is not
449
+ * a detail — the auto-answer guard in the Auto-Yes poller is built on this
450
+ * function, and a whole-frame version of it would switch Auto-Yes off for the
451
+ * rest of a codex session the moment any launch dialog scrolled past.
452
+ *
453
+ * The two hooks screens are matched FIRST and bottom-up, because a stuck pane
454
+ * holds screen 2 above screen 3 and the way out of each differs. The remaining
455
+ * three are region-level substring tests, which is all their anchors allow:
456
+ * the review dialog's are on two different lines.
457
+ *
458
+ * Deliberately NOT used to decide whether a prompt exists. `detectPrompt` still
459
+ * reports these screens, so a human still sees them; what this function gates is
460
+ * only whether a machine may answer on their behalf.
461
+ *
462
+ * @param output - ANSI-stripped pane capture
463
+ * @returns The active lifecycle screen, or null when none is
464
+ */
465
+ function getCodexLifecycleDialog(output) {
466
+ const activeLines = codexActiveRegionLines(output);
467
+ const window = [];
468
+ for (let i = activeLines.length - 1; i >= 0 && window.length < CODEX_LIFECYCLE_TAIL_LINES; i--) {
469
+ if (activeLines[i].trim() === '')
470
+ continue;
471
+ window.unshift(activeLines[i]);
472
+ }
473
+ if (window.length === 0)
474
+ return null;
475
+ const text = window.join('\n');
476
+ // One bottom-up pass, returning on the first line that decides the question --
477
+ // including the lines that decide it NEGATIVELY. A stuck pane holds screen 2
478
+ // above screen 3, and an approval request can come up with a hooks screen
479
+ // still inside the capture window; in both cases the screen the user is
480
+ // looking at is the lower one.
481
+ for (let i = window.length - 1; i >= 0; i--) {
482
+ const line = window[i];
483
+ if (CODEX_HOOKS_LIST_FOOTER_PATTERN.test(line))
484
+ return 'hooks-list';
485
+ if (CODEX_HOOKS_DETAIL_FOOTER_PATTERN.test(line))
486
+ return 'hooks-detail';
487
+ // The agent asking the human for permission mid-turn (Issue #1628's
488
+ // "esc to cancel" footer, which no lifecycle screen wears). This is exactly
489
+ // the prompt Auto-Yes exists to answer, so whatever lifecycle text is still
490
+ // above it has been left behind and must not withhold the answer.
491
+ if (exports.CODEX_APPROVAL_FOOTER_PATTERN.test(line))
492
+ return null;
493
+ if (CODEX_UPDATE_DIALOG_ANCHORS.some((pattern) => pattern.test(line)))
494
+ return 'update';
495
+ if (CODEX_TRUST_DIALOG_ANCHOR.test(line))
496
+ return 'trust';
497
+ // Both anchors required, so a stray "hooks" mention cannot claim the screen.
498
+ if (line.includes(exports.CODEX_HOOKS_REVIEW_ANCHORS[1]) && text.includes(exports.CODEX_HOOKS_REVIEW_ANCHORS[0])) {
499
+ return 'hooks-review';
500
+ }
501
+ }
502
+ return null;
503
+ }
362
504
  /**
363
505
  * Codex separator pattern
364
506
  */
@@ -53,6 +53,8 @@ exports.STATUS_REASON = {
53
53
  CODEX_SELECTION_LIST: 'codex_selection_list',
54
54
  /** Issue #1017: Codex pager / edit-previous (transcript) mode. */
55
55
  CODEX_PAGER: 'codex_pager',
56
+ /** Issue #1829: Codex's hooks review screens, which only `t`/`esc` leave. */
57
+ CODEX_HOOKS_REVIEW: 'codex_hooks_review',
56
58
  ANTIGRAVITY_SELECTION_LIST: 'antigravity_selection_list',
57
59
  OPENCODE_RESPONSE_COMPLETE: 'opencode_response_complete',
58
60
  INPUT_PROMPT: 'input_prompt',
@@ -73,6 +75,9 @@ exports.SELECTION_LIST_REASONS = new Set([
73
75
  exports.STATUS_REASON.CODEX_SELECTION_LIST,
74
76
  // Issue #1017: Codex pager/edit-previous mode also drives NavigationButtons.
75
77
  exports.STATUS_REASON.CODEX_PAGER,
78
+ // Issue #1829: the hooks review screens have no numbered options — `t` and
79
+ // `esc` are the only ways out, and NavigationButtons is how a human sends them.
80
+ exports.STATUS_REASON.CODEX_HOOKS_REVIEW,
76
81
  exports.STATUS_REASON.ANTIGRAVITY_SELECTION_LIST,
77
82
  ]);
78
83
  /**
@@ -288,6 +293,29 @@ function detectSessionStatus(output, cliToolId, lastOutputTimestamp) {
288
293
  promptDetection: codexPagerPromptDetection,
289
294
  };
290
295
  }
296
+ // 0.75. Codex: the hooks review screens (Issue #1829)
297
+ // codex-cli 0.148.0 answers "1. Review hooks" with a two-screen review UI:
298
+ // screen 2 "Press t to trust all; enter to review hooks; esc to close"
299
+ // screen 3 "Press t to trust; esc to go back"
300
+ // Neither carries a numbered option, a "press enter to confirm" footer, or any
301
+ // thinking indicator, so every branch below falls through to the `running`
302
+ // default -- which is how two live sessions sat parked on screen 3 while the UI
303
+ // and `cmate wait` both reported them as busy. They are the bottom-most
304
+ // interactive element and nothing but a keypress moves them: that is `waiting`.
305
+ // Checked ahead of prompt detection because the transcript rows on screen 2 are
306
+ // ordinary text that must not be read as options.
307
+ if (cliToolId === 'codex') {
308
+ const codexLifecycleDialog = (0, cli_patterns_1.getCodexLifecycleDialog)(cleanOutput);
309
+ if (codexLifecycleDialog === 'hooks-list' || codexLifecycleDialog === 'hooks-detail') {
310
+ return {
311
+ status: 'waiting',
312
+ confidence: 'high',
313
+ reason: exports.STATUS_REASON.CODEX_HOOKS_REVIEW,
314
+ hasActivePrompt: false,
315
+ promptDetection: (0, prompt_detector_1.detectPrompt)((0, cli_patterns_1.stripBoxDrawing)(cleanOutput), (0, cli_patterns_1.buildDetectPromptOptions)(cliToolId)),
316
+ };
317
+ }
318
+ }
291
319
  // 0.8. Codex: selection list detection BEFORE prompt detection (Issue #622)
292
320
  // CODEX_SELECTION_LIST_PATTERN matches "press enter to confirm/select" footer.
293
321
  // Without this early check, detectPrompt() at priority 1 would detect the numbered
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ /**
3
+ * Signatures of an upstream (model API) fault, as they appear on an agent's
4
+ * terminal frame (Issue #1839).
5
+ *
6
+ * Moved here from `scripts/canary/expectations.ts`, where Issue #1727 first
7
+ * wrote them, because the canary is no longer the only reader: `capture --json`
8
+ * publishes the match as `upstreamFault` and `wait --fail-on-upstream-fault`
9
+ * branches on it. Two copies of a pattern list whose whole job is *not* to be
10
+ * over-eager would drift, and the drift would be silent on both sides.
11
+ *
12
+ * A leaf module by design — it imports nothing but {@link stripAnsi}, so the
13
+ * canary (which runs outside Next) and the server payload builder can share it
14
+ * without either pulling in the other's dependencies.
15
+ *
16
+ * ## What a match means, and what it does not
17
+ *
18
+ * A match means the signature was on the frame. A **non**-match means nothing at
19
+ * all about upstream health: the pane may have scrolled, the agent may render a
20
+ * failure with wording nobody has seen yet, and Issue #1834 measured a case
21
+ * where the pane went blank instead of carrying a banner. Nothing in this
22
+ * module — and nothing reading it — may report "no fault" as "upstream is
23
+ * healthy".
24
+ *
25
+ * @module lib/detection/upstream-faults
26
+ */
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.UPSTREAM_FAULT_TRUNCATION_MARKER = exports.UPSTREAM_FAULT_EXCERPT_MAX_BYTES = exports.UPSTREAM_FAULTS = void 0;
29
+ exports.matchUpstreamFault = matchUpstreamFault;
30
+ exports.findUpstreamFault = findUpstreamFault;
31
+ const ansi_1 = require("./ansi");
32
+ /**
33
+ * Patterns are anchored on ERROR wording, not on the words "usage limit".
34
+ * Claude's own banner advertises "up to 50% of your weekly usage limit on
35
+ * Fable 5" on a perfectly healthy frame — a looser pattern marked every
36
+ * scenario of a run as `blocked` (measured 2026-08-06), which would have hidden
37
+ * real regressions behind a fake infrastructure excuse.
38
+ *
39
+ * Order is precedence: the first match wins, so the specific overload wording
40
+ * is listed ahead of the generic `API Error` catch-all. The line Claude 2.1.236
41
+ * prints on a 529 storm contains both (`API Error: Repeated 529 Overloaded
42
+ * errors …`, measured for Issue #1839), and `overloaded` is the more useful of
43
+ * the two answers because it carries `selfRetrying: true`.
44
+ */
45
+ exports.UPSTREAM_FAULTS = [
46
+ { id: 'overloaded', pattern: /\b5\d{2}\s+Overloaded\b/i, selfRetrying: true },
47
+ { id: 'retrying', pattern: /Retrying in \d+s\s*[·•]\s*attempt \d+\/\d+/i, selfRetrying: true },
48
+ { id: 'limit-reached', pattern: /\blimit reached\b/i, selfRetrying: false },
49
+ { id: 'api-error', pattern: /\bAPI Error(?::|\s+\d{3})/i, selfRetrying: false },
50
+ ];
51
+ /**
52
+ * Bound on {@link UpstreamFaultMatch.matchedText}, in UTF-8 **bytes**.
53
+ *
54
+ * Bytes rather than characters for the reason Issue #1694 gives for its own
55
+ * excerpt: a Japanese frame runs three bytes to the character, so a
56
+ * character-counted bound publishes three times the payload it promises. The
57
+ * excerpt rides every `current-output` response of a faulted session, and those
58
+ * responses are polled every few seconds.
59
+ */
60
+ exports.UPSTREAM_FAULT_EXCERPT_MAX_BYTES = 200;
61
+ /** Appended when {@link UPSTREAM_FAULT_EXCERPT_MAX_BYTES} cut the excerpt. */
62
+ exports.UPSTREAM_FAULT_TRUNCATION_MARKER = '…[truncated]';
63
+ /**
64
+ * Truncate to a UTF-8 byte budget on a code-point boundary.
65
+ *
66
+ * A local copy rather than `truncateToUtf8Bytes` from `lib/auto-yes-state`: that
67
+ * module reaches the database and the Auto-Yes state machine, and this one is a
68
+ * leaf the canary imports from outside Next. Accumulating code points (never
69
+ * UTF-16 units) is what keeps a surrogate pair whole.
70
+ */
71
+ function truncateExcerpt(text) {
72
+ const encoder = new TextEncoder();
73
+ if (encoder.encode(text).length <= exports.UPSTREAM_FAULT_EXCERPT_MAX_BYTES)
74
+ return text;
75
+ // The marker is inside the budget, not on top of it: the bound is a promise
76
+ // about the published field, and a caller sizing a log line by it must not be
77
+ // handed twelve more characters than it asked for.
78
+ const budget = exports.UPSTREAM_FAULT_EXCERPT_MAX_BYTES - encoder.encode(exports.UPSTREAM_FAULT_TRUNCATION_MARKER).length;
79
+ let bytes = 0;
80
+ let out = '';
81
+ for (const char of text) {
82
+ const size = encoder.encode(char).length;
83
+ if (bytes + size > budget)
84
+ break;
85
+ bytes += size;
86
+ out += char;
87
+ }
88
+ return `${out}${exports.UPSTREAM_FAULT_TRUNCATION_MARKER}`;
89
+ }
90
+ /**
91
+ * The first upstream fault visible in the frame, with its line.
92
+ *
93
+ * ANSI is stripped first: the signature words are routinely split by colour
94
+ * sequences on a live pane.
95
+ */
96
+ function matchUpstreamFault(frame) {
97
+ const clean = (0, ansi_1.stripAnsi)(frame);
98
+ for (const fault of exports.UPSTREAM_FAULTS) {
99
+ const match = fault.pattern.exec(clean);
100
+ // The patterns are unanchored and stateless (no /g), so `exec` cannot carry
101
+ // a lastIndex between calls — but reading `index` requires exec regardless.
102
+ if (!match)
103
+ continue;
104
+ const lineStart = clean.lastIndexOf('\n', match.index) + 1;
105
+ const lineEnd = clean.indexOf('\n', match.index);
106
+ const line = clean.slice(lineStart, lineEnd === -1 ? undefined : lineEnd).trim();
107
+ return { fault, matchedText: truncateExcerpt(line || match[0]) };
108
+ }
109
+ return null;
110
+ }
111
+ /**
112
+ * First upstream fault visible in the frame, if any.
113
+ *
114
+ * Kept alongside {@link matchUpstreamFault} because the canary only ever wanted
115
+ * the classification (`id` / `selfRetrying`), and a caller that does not need
116
+ * the excerpt should not have to reach through a wrapper for it.
117
+ */
118
+ function findUpstreamFault(frame) {
119
+ return matchUpstreamFault(frame)?.fault ?? null;
120
+ }
@@ -63,6 +63,10 @@ const NO_DECISION = (reason) => ({
63
63
  behavior: null,
64
64
  reason,
65
65
  });
66
+ /** Production policy source: the active task's contract, TTL-cached. */
67
+ function readContractPolicy(session) {
68
+ return (0, auto_yes_policy_1.getSessionAutoYesPolicy)(session.worktreeId, session.cliToolId, session.instanceId);
69
+ }
66
70
  /**
67
71
  * The verdict for one permission request. Pure apart from reading Auto-Yes
68
72
  * state and the (TTL-cached) contract policy; the recording side effects live
@@ -80,8 +84,10 @@ const NO_DECISION = (reason) => ({
80
84
  *
81
85
  * @param session - Worktree / tool / instance the request came from
82
86
  * @param payload - Parsed payload, or null when it could not be parsed
87
+ * @param deps - Substitutions for the database-backed lookups; see
88
+ * {@link PermissionDecisionDeps}. Omit in the server.
83
89
  */
84
- function decidePermissionRequest(session, payload) {
90
+ function decidePermissionRequest(session, payload, deps = {}) {
85
91
  if (!payload) {
86
92
  return NO_DECISION('unknown-payload');
87
93
  }
@@ -98,7 +104,7 @@ function decidePermissionRequest(session, payload) {
98
104
  if (!state?.enabled) {
99
105
  return NO_DECISION('auto-yes-disabled');
100
106
  }
101
- const policy = (0, auto_yes_policy_1.getSessionAutoYesPolicy)(worktreeId, cliToolId, instanceId);
107
+ const policy = (deps.readPolicy ?? readContractPolicy)({ worktreeId, cliToolId, instanceId });
102
108
  const denial = (0, auto_yes_resolver_1.evaluatePolicyAgainstTexts)(exports.PERMISSION_REQUEST_PROMPT_TYPE, (0, permission_request_payload_1.collectToolInputMatchTexts)(payload.toolName, payload.toolInput), policy);
103
109
  if (denial) {
104
110
  return {
@@ -214,10 +220,12 @@ function reportPendingDialog(session, payload) {
214
220
  *
215
221
  * @param session - Worktree / tool / instance the request came from
216
222
  * @param payload - Parsed payload, or null when it could not be parsed
223
+ * @param deps - Substitutions for the database-backed lookups; see
224
+ * {@link PermissionDecisionDeps}. Omit in the server.
217
225
  * @returns The verdict the route serialises
218
226
  */
219
- function resolvePermissionRequest(session, payload) {
220
- const decision = decidePermissionRequest(session, payload);
227
+ function resolvePermissionRequest(session, payload, deps = {}) {
228
+ const decision = decidePermissionRequest(session, payload, deps);
221
229
  // Issue #1726: `AskUserQuestion` raises a `PermissionRequest` carrying the
222
230
  // same `tool_input` its `PreToolUse` does (§5.6), so the questions are
223
231
  // recorded from here too. Redundant on a session this server started — both
@@ -263,7 +271,7 @@ function resolvePermissionRequest(session, payload) {
263
271
  });
264
272
  }
265
273
  if (decision.behavior === 'allow' && payload) {
266
- recordAllowedPermission(session, payload);
274
+ (deps.recordAllow ?? recordAllowedPermission)(session, payload);
267
275
  }
268
276
  return decision;
269
277
  }
@@ -87,6 +87,7 @@ const logger_1 = require("../../../../lib/logger");
87
87
  // The `~/.gemini` tree belongs to gemini; agy lives inside it. The merge that
88
88
  // keeps the two from erasing each other is written once, there.
89
89
  const shared_config_tree_1 = require("../gemini/shared-config-tree");
90
+ const launch_command_1 = require("../launch-command");
90
91
  const tool_id_1 = require("./tool-id");
91
92
  const logger = (0, logger_1.createLogger)('lib/hooks/sources/antigravity/hooks-config');
92
93
  /**
@@ -347,26 +348,32 @@ function writeAntigravityHooksConfig(options = {}) {
347
348
  * terminal, so the variable is set here and nowhere else.
348
349
  *
349
350
  * The executable is quoted but not otherwise touched, so a caller may append its
350
- * own flags — `AntigravityTool.startSession` adds `--model` — after the value
351
- * this returns.
351
+ * own flags — `AntigravityTool.startSession` adds `--model` — after the rendered
352
+ * line. Since Issue #1846 the two variables come back as `env` rather than as a
353
+ * prefix on the command, which is also what keeps `--model` appendable: the
354
+ * caller appends to the *rendered* line and the assignments stay in front of it
355
+ * by construction rather than by the caller remembering to.
352
356
  *
353
- * Never throws, and returns the executable unchanged when injection is off.
357
+ * Never throws, and returns the executable with an empty environment when
358
+ * injection is off.
354
359
  *
355
360
  * @param executablePath - `agy`, or a resolved path to it
356
361
  * @param target - The instance being started
357
- * @returns The command line to type into the pane
362
+ * @returns The command to type into the pane and the environment it needs
358
363
  */
359
364
  function buildAntigravityLaunchCommand(executablePath, target, options = {}) {
360
365
  if (!(0, hook_settings_generator_1.isHookInjectionEnabled)())
361
- return executablePath;
366
+ return { command: executablePath, env: {} };
362
367
  if (!(0, types_1.isValidInstanceId)((0, hook_settings_generator_1.resolveTargetInstanceId)(target))) {
363
368
  logger.warn('antigravity-hook-invalid-instance-id', { worktreeId: target.worktreeId });
364
- return executablePath;
369
+ return { command: executablePath, env: {} };
365
370
  }
366
371
  const scoped = { ...target, cliToolId: tool_id_1.ANTIGRAVITY_CLI_TOOL_ID };
367
- const url = (0, hook_settings_generator_1.buildAgentEventUrl)(scoped, options);
368
- const permissionUrl = (0, hook_settings_generator_1.buildPermissionRequestUrl)(scoped, options);
369
- return (`CM_HOOK_URL=${(0, hook_settings_generator_1.shellQuote)(url)} ` +
370
- `${exports.ANTIGRAVITY_PERMISSION_URL_ENV_VAR}=${(0, hook_settings_generator_1.shellQuote)(permissionUrl)} ` +
371
- `${(0, hook_settings_generator_1.shellQuote)(executablePath)}`);
372
+ return {
373
+ command: (0, hook_settings_generator_1.shellQuote)(executablePath),
374
+ env: {
375
+ [launch_command_1.AGENT_EVENT_URL_ENV_VAR]: (0, hook_settings_generator_1.buildAgentEventUrl)(scoped, options),
376
+ [exports.ANTIGRAVITY_PERMISSION_URL_ENV_VAR]: (0, hook_settings_generator_1.buildPermissionRequestUrl)(scoped, options),
377
+ },
378
+ };
372
379
  }
@@ -215,15 +215,16 @@ exports.antigravityAgentEventSource = (0, define_source_1.definePushHookSource)(
215
215
  encodeVerdict: encodeAntigravityVerdict,
216
216
  // Unlike gemini, the whole config is reachable from here: the file is global,
217
217
  // so no worktree path is needed and `prepareLaunch` really does write it.
218
- prepareLaunch: (target, executablePath) => {
218
+ prepareLaunch: ({ target, executablePath }) => {
219
219
  const settingsPath = (0, hooks_config_1.writeAntigravityHooksConfig)();
220
- return {
221
- command: (0, hooks_config_1.buildAntigravityLaunchCommand)(executablePath, {
222
- worktreeId: target.worktreeId,
223
- instanceId: target.instanceId,
224
- cliToolId: tool_id_1.ANTIGRAVITY_CLI_TOOL_ID,
225
- }),
226
- settingsPath,
227
- };
220
+ // #1846: the two correlation URLs are the plan's `env`. `worktreePath` is
221
+ // in the context now and deliberately unused here — agy's config is one
222
+ // file for the machine, so there is nothing per-worktree to write.
223
+ const { command, env } = (0, hooks_config_1.buildAntigravityLaunchCommand)(executablePath, {
224
+ worktreeId: target.worktreeId,
225
+ instanceId: target.instanceId,
226
+ cliToolId: tool_id_1.ANTIGRAVITY_CLI_TOOL_ID,
227
+ });
228
+ return { command, settingsPath, env };
228
229
  },
229
230
  });
@@ -128,7 +128,7 @@ exports.claudeAgentEventSource = (0, define_source_1.definePushHookSource)({
128
128
  // S3 / S4 / S5. Delegated rather than reimplemented: `buildClaudeLaunchCommand`
129
129
  // writes the settings file, falls back to the bare path on any failure, and is
130
130
  // covered byte-for-byte by `tests/unit/hooks/hook-settings-generator.test.ts`.
131
- prepareLaunch: (target, executablePath) => {
131
+ prepareLaunch: ({ target, executablePath }) => {
132
132
  const command = (0, hook_settings_generator_1.buildClaudeLaunchCommand)(executablePath, {
133
133
  worktreeId: target.worktreeId,
134
134
  instanceId: target.instanceId,
@@ -145,6 +145,9 @@ exports.claudeAgentEventSource = (0, define_source_1.definePushHookSource)({
145
145
  cliToolId: target.cliToolId,
146
146
  })
147
147
  : null;
148
- return { command, settingsPath };
148
+ // Empty, and the only source for which that is uninteresting: `--settings`
149
+ // carries the correlation keys inside the file, so Claude never needed the
150
+ // environment prefix the other four sources reached for (#1846).
151
+ return { command, settingsPath, env: {} };
149
152
  },
150
153
  });