commandmate 0.37.0 → 0.38.1

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 (331) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +176 -176
  3. package/.next/app-path-routes-manifest.json +33 -33
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/prerender-manifest.json +12 -12
  6. package/.next/required-server-files.json +1 -1
  7. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  8. package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
  9. package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
  10. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/app/update-check/route.js +1 -1
  12. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/assistant/conversation/route.js.nft.json +1 -1
  14. package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/assistant/current-output/route.js.nft.json +1 -1
  16. package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/assistant/messages/route.js +1 -1
  18. package/.next/server/app/api/assistant/messages/route.js.nft.json +1 -1
  19. package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/assistant/session/route.js +1 -1
  21. package/.next/server/app/api/assistant/session/route.js.nft.json +1 -1
  22. package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/assistant/start/route.js +1 -1
  24. package/.next/server/app/api/assistant/start/route.js.nft.json +1 -1
  25. package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/assistant/terminal/route.js +1 -1
  27. package/.next/server/app/api/assistant/terminal/route.js.nft.json +1 -1
  28. package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
  30. package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
  31. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/capabilities/route.js +1 -1
  35. package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/daily-summary/route.js +1 -1
  37. package/.next/server/app/api/daily-summary/route.js.nft.json +1 -1
  38. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/daily-summary/status/route.js +1 -1
  40. package/.next/server/app/api/daily-summary/status/route.js.nft.json +1 -1
  41. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  42. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  43. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  44. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  45. package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
  46. package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
  47. package/.next/server/app/api/hooks/agent-event/route.js +1 -1
  48. package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
  49. package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
  50. package/.next/server/app/api/hooks/claude-done/route.js +1 -1
  51. package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
  52. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  53. package/.next/server/app/api/hooks/permission-request/route.js +1 -1
  54. package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
  55. package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
  57. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  58. package/.next/server/app/api/push/escalation/route.js +1 -1
  59. package/.next/server/app/api/push/escalation/route.js.nft.json +1 -1
  60. package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
  61. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/push/vapid/route.js +1 -1
  63. package/.next/server/app/api/push/vapid/route.js.nft.json +1 -1
  64. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  65. package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
  66. package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
  67. package/.next/server/app/api/relays/route.js.nft.json +1 -1
  68. package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
  70. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  71. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  72. package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
  73. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  74. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
  75. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  76. package/.next/server/app/api/repositories/clone/route.js +1 -1
  77. package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
  78. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  79. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  80. package/.next/server/app/api/repositories/restore/route.js +1 -1
  81. package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
  82. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  83. package/.next/server/app/api/repositories/route.js +1 -1
  84. package/.next/server/app/api/repositories/route.js.nft.json +1 -1
  85. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  86. package/.next/server/app/api/repositories/scan/route.js +1 -1
  87. package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
  88. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/api/repositories/sync/route.js +1 -1
  90. package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
  91. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
  93. package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
  94. package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
  96. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  97. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  98. package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
  99. package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
  100. package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
  101. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  102. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  103. package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  104. package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
  105. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  106. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  107. package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
  108. package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
  109. package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
  110. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
  111. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
  112. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  113. package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
  114. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  115. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
  116. package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
  117. package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
  118. package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  120. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +1 -1
  121. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js.nft.json +1 -1
  122. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
  124. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
  125. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
  127. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +4 -3
  129. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js.nft.json +1 -1
  130. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  132. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  133. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  135. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  136. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  137. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  138. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  139. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  141. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  142. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  146. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  148. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  149. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  151. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  152. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  153. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  154. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  155. package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
  157. package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
  158. package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
  159. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
  161. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  162. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  163. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  164. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  165. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  166. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  167. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  168. package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
  170. package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
  171. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
  173. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  174. package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
  175. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
  176. package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
  177. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  178. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  179. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  180. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  181. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +1 -6
  182. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js.nft.json +1 -1
  183. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  184. package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +1 -1
  185. package/.next/server/app/api/worktrees/[id]/schedules/active/route.js.nft.json +1 -1
  186. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  187. package/.next/server/app/api/worktrees/[id]/schedules/route.js +2 -7
  188. package/.next/server/app/api/worktrees/[id]/schedules/route.js.nft.json +1 -1
  189. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  190. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  191. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
  192. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  193. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  194. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
  195. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
  196. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  197. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  198. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  199. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  200. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
  201. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
  202. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  203. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  204. package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
  205. package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
  206. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  207. package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
  208. package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
  209. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  210. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  211. package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
  212. package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
  213. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  214. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  215. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  216. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  217. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  218. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  219. package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
  220. package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -1
  221. package/.next/server/app/api/worktrees/[id]/verify/route.js.nft.json +1 -1
  222. package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
  223. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js +1 -1
  224. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js.nft.json +1 -1
  225. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
  226. package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
  227. package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
  228. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  229. package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
  230. package/.next/server/app/api/worktrees/route.js +1 -1
  231. package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
  232. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  233. package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  234. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  235. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  236. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  237. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  238. package/.next/server/app/page_client-reference-manifest.js +1 -1
  239. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  240. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  241. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  242. package/.next/server/app/sessions/page.js +1 -1
  243. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  244. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  245. package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
  246. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  247. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  248. package/.next/server/app/worktrees/[id]/page.js +11 -9
  249. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  250. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  251. package/.next/server/app-paths-manifest.json +33 -33
  252. package/.next/server/chunks/1467.js +1 -1
  253. package/.next/server/chunks/1707.js +1 -1
  254. package/.next/server/chunks/1886.js +2 -2
  255. package/.next/server/chunks/2119.js +1 -1
  256. package/.next/server/chunks/2445.js +1 -1
  257. package/.next/server/chunks/3480.js +1 -18
  258. package/.next/server/chunks/3730.js +1 -1
  259. package/.next/server/chunks/4207.js +5 -0
  260. package/.next/server/chunks/4443.js +1 -1
  261. package/.next/server/chunks/5164.js +1 -1
  262. package/.next/server/chunks/6130.js +1 -1
  263. package/.next/server/chunks/650.js +1 -1
  264. package/.next/server/chunks/6661.js +1 -1
  265. package/.next/server/chunks/6677.js +2 -2
  266. package/.next/server/chunks/6793.js +13 -0
  267. package/.next/server/chunks/7075.js +1 -1
  268. package/.next/server/chunks/8052.js +74 -0
  269. package/.next/server/chunks/8728.js +2 -2
  270. package/.next/server/chunks/9080.js +1 -1
  271. package/.next/server/middleware-manifest.json +5 -5
  272. package/.next/server/pages/500.html +1 -1
  273. package/.next/server/server-reference-manifest.json +1 -1
  274. package/.next/static/chunks/{2407-c4b1d2aae7e3f59b.js → 2407-be448eda70bc19b6.js} +1 -1
  275. package/.next/static/chunks/4388-a778968d9c4e9327.js +1 -0
  276. package/.next/static/chunks/4949-fa93029d6e05db0d.js +1 -0
  277. package/.next/static/chunks/998-292ebcd30f329eb1.js +1 -0
  278. package/.next/static/chunks/app/sessions/page-fe42c8f6fd59b9e7.js +1 -0
  279. package/.next/static/chunks/app/worktrees/[id]/page-1eb4297af22afac8.js +1 -0
  280. package/.next/static/css/ed092b853e52b5eb.css +1 -0
  281. package/.next/trace +14 -14
  282. package/dist/cli/commands/ls.d.ts +64 -0
  283. package/dist/cli/commands/ls.d.ts.map +1 -1
  284. package/dist/cli/commands/ls.js +238 -30
  285. package/dist/cli/commands/respond.d.ts.map +1 -1
  286. package/dist/cli/commands/respond.js +14 -0
  287. package/dist/cli/commands/status.d.ts.map +1 -1
  288. package/dist/cli/commands/status.js +154 -15
  289. package/dist/cli/docs/agent-operations.d.ts +1 -1
  290. package/dist/cli/docs/agent-operations.d.ts.map +1 -1
  291. package/dist/cli/docs/agent-operations.js +37 -1
  292. package/dist/cli/types/api-responses.d.ts.map +1 -1
  293. package/dist/cli/utils/server-url.d.ts +27 -0
  294. package/dist/cli/utils/server-url.d.ts.map +1 -1
  295. package/dist/cli/utils/server-url.js +48 -6
  296. package/dist/lib/cli-tools/types.d.ts +22 -1
  297. package/dist/lib/cli-tools/types.d.ts.map +1 -1
  298. package/dist/lib/detection/tools/verified-against.d.ts +8 -0
  299. package/dist/lib/detection/tools/verified-against.d.ts.map +1 -1
  300. package/dist/lib/detection/tools/verified-against.js +8 -0
  301. package/dist/server/locales/en/worktree.json +23 -1
  302. package/dist/server/locales/ja/worktree.json +23 -1
  303. package/dist/server/src/lib/cli-tools/agent-mode-spec.js +327 -0
  304. package/dist/server/src/lib/cli-tools/base.js +22 -0
  305. package/dist/server/src/lib/cmate-parser.js +26 -6
  306. package/dist/server/src/lib/cmate-validator.js +354 -0
  307. package/dist/server/src/lib/detection/cli-patterns.js +40 -2
  308. package/dist/server/src/lib/detection/model-info-extractor.js +40 -3
  309. package/dist/server/src/lib/detection/prompt-detect-multiple-choice.js +44 -0
  310. package/dist/server/src/lib/detection/tools/antigravity/detect.js +9 -0
  311. package/dist/server/src/lib/detection/tools/command-code/detect.js +14 -3
  312. package/dist/server/src/lib/detection/tools/command-code/permission.js +104 -0
  313. package/dist/server/src/lib/detection/tools/verified-against.js +8 -0
  314. package/dist/server/src/lib/polling/auto-yes-dialog-gate.js +20 -2
  315. package/dist/server/src/lib/prompt-answer-sender.js +339 -16
  316. package/dist/server/src/lib/session/claude-executor.js +190 -17
  317. package/dist/server/src/types/cli-tool-contracts.js +75 -1
  318. package/dist/types/cli-tool-contracts.d.ts +162 -0
  319. package/dist/types/cli-tool-contracts.d.ts.map +1 -1
  320. package/dist/types/cli-tool-contracts.js +75 -1
  321. package/package.json +1 -1
  322. package/.next/server/chunks/6337.js +0 -1
  323. package/.next/server/chunks/663.js +0 -79
  324. package/.next/static/chunks/4388-410b1d8ed0d8d98b.js +0 -1
  325. package/.next/static/chunks/4949-5b97d1eb769482d2.js +0 -1
  326. package/.next/static/chunks/998-ac0ded6d5eeb4dc0.js +0 -1
  327. package/.next/static/chunks/app/sessions/page-b8651c3f17c36800.js +0 -1
  328. package/.next/static/chunks/app/worktrees/[id]/page-f993ca88fe758599.js +0 -1
  329. package/.next/static/css/c511ecdf1e7f18a0.css +0 -1
  330. /package/.next/static/{0WNCXbrakAsDUEgDarN8N → DryXJ1-iHfWxfrHkkWVy8}/_buildManifest.js +0 -0
  331. /package/.next/static/{0WNCXbrakAsDUEgDarN8N → DryXJ1-iHfWxfrHkkWVy8}/_ssgManifest.js +0 -0
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ /**
3
+ * Command Code's permission dialog, read for the `detectDialog` seam
4
+ * (Issue #2574).
5
+ *
6
+ * ## What this is for, and what it is not
7
+ *
8
+ * Epic #2249 決定 3 left Command Code without a `detectDialog`, and its reason
9
+ * still holds: `PreToolUse` fires AFTER the dialog is answered, so a hook-driven
10
+ * permission decision cannot dismiss it, and Auto-Yes stays on the numbered
11
+ * response path. That decision is about who ANSWERS the dialog. It says nothing
12
+ * about how an answer has to be TYPED, which is the other thing `detectDialog`
13
+ * declares — `answerMode` for #2033's key guard, and `submitMode` for whether
14
+ * the sender follows the digit with an Enter. This module fills only that half;
15
+ * the Auto-Yes rollout for this tool stays `legacy` (see
16
+ * `AUTO_YES_DIALOG_GATE_DEFAULT_MODE`).
17
+ *
18
+ * ## Why the Enter is the defect
19
+ *
20
+ * Measured live on 1.53.1 at 200x1000: a bare `1` (or `2`) closes the dialog and
21
+ * runs the command — the digit is a hotkey. With no `submitMode` on the prompt,
22
+ * `sendPromptAnswer` resolved `answer_then_enter` and sent `C-m` a moment later,
23
+ * by which time the composer was back. A draft typed while the agent was
24
+ * thinking sat in that composer, and the Enter submitted it as a new user
25
+ * message. Declaring `answer_only` here moves that decision onto the frame the
26
+ * answer is actually sent at, so the Auto-Yes poller, `respond` and the chat
27
+ * surface all get it without each consumer having to re-read the screen.
28
+ *
29
+ * ## The shape, on every build captured
30
+ *
31
+ * The same rows on 1.40.1 (`dialog-create-file.txt`, `dialog-shell-command.txt`),
32
+ * 1.49.0 (`dialog-shell-1490.txt`, `dialog-kill-task-1490.txt`) and a live
33
+ * 1.53.1 pane:
34
+ *
35
+ * ──────────────────────────… (200 columns)
36
+ * Execute Shell Command
37
+ * Command Code needs to execute sleep 25 && echo done.
38
+ * Press [ctrl+e] to explain this command
39
+ * ❯ 1. Yes
40
+ * 2. Yes, don't ask again for `sleep` commands in this project
41
+ * 3. No, tell Command Code what to do differently
42
+ * ↑/↓ navigate · enter select · ctrl+e explain · Run cmd --yolo to bypass all permissions (Docs ↗)
43
+ *
44
+ * The rule is positional as well as textual: the hint bar must be the LAST
45
+ * content row and the numbered run must sit directly on top of it. Command Code
46
+ * draws its composer at the bottom of the pane for the whole of a turn and after
47
+ * it, so the only frames whose last row is not the composer are the ones where
48
+ * an overlay took its place. An agent reply that quotes the hint bar still has
49
+ * the composer under it, and an answered dialog is repainted as the tool call
50
+ * with the composer back below.
51
+ *
52
+ * ## Input contract
53
+ *
54
+ * Either spelling of the capture: as captured, or through
55
+ * `stripBoxDrawing(stripAnsi(...))` as Auto-Yes holds it. Nothing below reads
56
+ * the rule row `stripBoxDrawing` blanks, so both reach the same verdict.
57
+ *
58
+ * ## Deliberately not recognised
59
+ *
60
+ * `AskUserQuestion` (`./dialog.ts`, no footer), the `/model` picker (`enter to
61
+ * select · esc to cancel`) and the `/usage` panel (`Press Esc to close`). Their
62
+ * prompts already carry what they need, or have no prompt to answer, and while
63
+ * the rollout is `legacy` a `null` here gates nothing.
64
+ */
65
+ Object.defineProperty(exports, "__esModule", { value: true });
66
+ exports.COMMAND_CODE_PERMISSION_FOOTER_PATTERN = void 0;
67
+ exports.detectCommandCodePermissionDialog = detectCommandCodePermissionDialog;
68
+ const dialog_block_1 = require("../dialog-block");
69
+ /**
70
+ * The hint bar under a permission dialog.
71
+ *
72
+ * `enter select` — not `enter to select`, which is the `/model` picker's — and
73
+ * the `to bypass all permissions` tail, which is what makes it a PERMISSION
74
+ * dialog rather than any other numbered overlay. `ctrl+e explain ·` sits
75
+ * between the two on shell commands and is absent on file edits, so the middle
76
+ * is not spelled out.
77
+ */
78
+ exports.COMMAND_CODE_PERMISSION_FOOTER_PATTERN = /^\s*↑\/↓\s+navigate\s+·\s+enter\s+select\s+·.*\bto\s+bypass\s+all\s+permissions\b/;
79
+ /** The cursor glyph Command Code draws on the highlighted option. */
80
+ const COMMAND_CODE_CURSOR_GLYPH = '❯';
81
+ /**
82
+ * Does this frame carry Command Code's permission dialog?
83
+ *
84
+ * @param frame - The normalised capture, either spelling (see the module docblock)
85
+ * @returns `permission` / `numbered` / `answer_only` with the drawn options, or null
86
+ */
87
+ function detectCommandCodePermissionDialog(frame) {
88
+ const rows = frame.contentLines;
89
+ const footer = rows[rows.length - 1];
90
+ if (footer === undefined || !exports.COMMAND_CODE_PERMISSION_FOOTER_PATTERN.test(footer))
91
+ return null;
92
+ // One footer row and nothing else between it and the bottom option.
93
+ const block = (0, dialog_block_1.findNumberedOptionBlock)(rows, rows.length, 1);
94
+ if (block === null || block.footer !== footer.trim())
95
+ return null;
96
+ if (block.selectedGlyph !== COMMAND_CODE_CURSOR_GLYPH)
97
+ return null;
98
+ return {
99
+ kind: 'permission',
100
+ options: block.options,
101
+ answerMode: 'numbered',
102
+ submitMode: 'answer_only',
103
+ };
104
+ }
@@ -132,6 +132,14 @@ exports.ANTIGRAVITY_VERIFIED_AGAINST = {
132
132
  * nobody took. When a live 1.53.x session is probed — the question screen, the
133
133
  * keys it accepts and what one of them advances — bump this to that exact
134
134
  * version with its own `capturedAt`.
135
+ *
136
+ * ## Not advanced by Issue #2574 either
137
+ *
138
+ * #2574 did send keys at a live 1.53.1 pane, but at the PERMISSION dialog, not
139
+ * the question screen: a bare digit commits it, which is the `submitMode` its
140
+ * `detectDialog` declares. The rule itself was read off the 1.40.1 and 1.49.0
141
+ * dialog frames above, and no 1.53.1 frame was added to the fixture directory,
142
+ * so the condition in the previous paragraph is still unmet.
135
143
  */
136
144
  exports.COMMAND_CODE_VERIFIED_AGAINST = {
137
145
  version: '1.40.1',
@@ -87,6 +87,8 @@ exports.AUTO_YES_DIALOG_GATE_MODES = ['enforce', 'legacy'];
87
87
  * to write a dialog rule against. Gating it on a rule inferred from another
88
88
  * tool's frames is the mistake #1979 had to correct; leaving it `legacy` keeps
89
89
  * agy's Auto-Yes working exactly as it does today.
90
+ * - `command-code` is the one `legacy` tool that DOES declare rules (Issue
91
+ * #2574), and they are not enough to gate on. See its row.
90
92
  */
91
93
  exports.AUTO_YES_DIALOG_GATE_DEFAULT_MODE = {
92
94
  claude: 'enforce',
@@ -99,8 +101,24 @@ exports.AUTO_YES_DIALOG_GATE_DEFAULT_MODE = {
99
101
  // Issue #2250 / Epic #2249 決定 3: Command Code's Auto-Yes stays on the legacy
100
102
  // numbered-response path. Its `PreToolUse` hook fires AFTER the permission
101
103
  // dialog is answered (measured: dialog 00:11:37, answer 00:11:46, hook
102
- // 00:11:46), so a `permissionDecision` cannot dismiss the dialog and there is
103
- // no measured dialog rule to gate on.
104
+ // 00:11:46), so a `permissionDecision` cannot dismiss the dialog.
105
+ //
106
+ // Issue #2574 gave the tool a `detectDialog` (`hasDialogRules: true`) and kept
107
+ // this row `legacy` on purpose. The rule recognises the PERMISSION dialog only;
108
+ // it exists to tell `sendPromptAnswer` that a digit commits without an Enter.
109
+ // Enforcing on it would break the other dialog this tool draws:
110
+ //
111
+ // - `AskUserQuestion` (#2521 / #2522) is not a permission dialog, so
112
+ // `judgeDialogPresence` would answer `present: false` for it and
113
+ // `/prompt-response` would refuse a readable question with
114
+ // `unsupported_dialog_layout`;
115
+ // - teaching the rule that screen would not fix Auto-Yes either: the question
116
+ // reader is anchored on the rule row `stripBoxDrawing` blanks
117
+ // (`tools/command-code/dialog.ts`, 確定仕様 C), and this gate is handed the
118
+ // box-stripped `cleanOutput`, so every question would be suppressed.
119
+ //
120
+ // Promote only once both dialogs are recognised on both spellings, with a
121
+ // `/prompt-response` test pinning that the question is still answered.
104
122
  'command-code': 'legacy',
105
123
  };
106
124
  /**
@@ -7,11 +7,12 @@
7
7
  * the promptType/defaultOptionNumber fallback introduced in Bug1).
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.PromptAnswerRejectedError = exports.ANSWER_MODE_KEYS_REASON = void 0;
10
+ exports.FreeTextAtChoiceOnlyPromptError = exports.FreeTextAnswerRejectedError = exports.FREE_TEXT_AT_MENU_ROW_REASON = exports.PromptAnswerRejectedError = exports.ANSWER_MODE_KEYS_REASON = void 0;
11
11
  exports.sendPromptAnswer = sendPromptAnswer;
12
12
  const tmux_1 = require("./tmux/tmux");
13
13
  const frame_1 = require("../lib/detection/tools/frame");
14
14
  const registry_1 = require("../lib/detection/tools/registry");
15
+ const prompt_detect_multiple_choice_1 = require("../lib/detection/prompt-detect-multiple-choice");
15
16
  const models_1 = require("../types/models");
16
17
  const tmux_capture_cache_1 = require("./tmux/tmux-capture-cache");
17
18
  const cli_tool_timing_config_1 = require("../config/cli-tool-timing-config");
@@ -67,6 +68,130 @@ class PromptAnswerRejectedError extends Error {
67
68
  }
68
69
  }
69
70
  exports.PromptAnswerRejectedError = PromptAnswerRejectedError;
71
+ /**
72
+ * The reason code a caller gets back when free text meets a prompt whose
73
+ * text-bearing options are all menu rows (Issue #2573).
74
+ *
75
+ * The code `/prompt-response` already answers "this answer cannot be mapped onto
76
+ * a choice, and nothing was sent" with (#1681, #2522), so `respond` reports it
77
+ * without a new branch.
78
+ */
79
+ exports.FREE_TEXT_AT_MENU_ROW_REASON = 'unresolvable_answer';
80
+ /**
81
+ * The sentence for each refusal, built from a tool id and option numbers only.
82
+ *
83
+ * Fixed text, a tool id and option numbers, never the answer (SEC-003, as in
84
+ * `prompt-answer-semantic`): the answer is whatever the operator typed, and
85
+ * `/prompt-response` returns this message to the client verbatim.
86
+ *
87
+ * The two sentences sit side by side on purpose. They differ in the one thing
88
+ * the operator has to act on — what to do next — and that is only comparable
89
+ * when both are readable at once.
90
+ */
91
+ function freeTextRefusalMessage(cliToolId, optionNumbers, detail) {
92
+ const numbers = optionNumbers.join(', ');
93
+ if (detail === undefined) {
94
+ return `Refused to type free text at ${cliToolId}'s prompt: option ${numbers} `
95
+ + 'reads as taking your own words, but on this screen it is a menu row, not a text field. '
96
+ + 'The text would be ignored and the Enter after it would confirm whatever is highlighted. '
97
+ + 'Nothing was sent. Answer with the option number, then send the instructions as a message.';
98
+ }
99
+ return `Refused to type free text at ${cliToolId}'s prompt: option ${numbers} is the text field `
100
+ + `on this screen, but the cursor is on option ${detail.cursorOptionNumber}. The text would be `
101
+ + `ignored and the Enter after it would confirm option ${detail.cursorOptionNumber}. Nothing `
102
+ + 'was sent. Move the cursor onto the text field in the terminal and send the text again — '
103
+ + 'sending its option number does not move the cursor, it selects nothing.';
104
+ }
105
+ /**
106
+ * Free text refused BEFORE any key reached the pane (Issue #2573, #2584).
107
+ *
108
+ * A sibling of {@link PromptAnswerRejectedError}, not a use of it, because the
109
+ * two cite different evidence. That one cites the dialog the tool's own rules
110
+ * vouched for (`dialogKind` / `answerMode`), and no such verdict can decide this
111
+ * case: Command Code has had rules since Issue #2574, and the permission dialog
112
+ * this guard is first about is vouched `numbered` — the verdict that lets a
113
+ * DIGIT through — while the `AskUserQuestion` screen whose free text must keep
114
+ * working is deliberately not recognised by those rules at all
115
+ * (`tools/command-code/permission.ts`). `answerMode` says how a CHOICE is
116
+ * pressed; it says nothing about which row is a text field, nor about which row
117
+ * the cursor is on. So what this one cites is the rows.
118
+ *
119
+ * One class rather than two because `/prompt-response` is out of reach of both
120
+ * Issues' scope and matches this type by `instanceof` to report the refusal at
121
+ * all; {@link FreeTextRefusalKind} is what tells the two cases apart.
122
+ */
123
+ class FreeTextAnswerRejectedError extends Error {
124
+ /** Machine-readable code, always {@link FREE_TEXT_AT_MENU_ROW_REASON}. */
125
+ reason;
126
+ /**
127
+ * The text-bearing options this refusal is about: the menu rows for
128
+ * `menu_row`, the measured text field(s) for `cursor_elsewhere`.
129
+ */
130
+ optionNumbers;
131
+ /** Which measurement refused (Issue #2584). */
132
+ kind;
133
+ /** The option the Enter would have confirmed, or null for `menu_row`. */
134
+ cursorOptionNumber;
135
+ constructor(cliToolId, optionNumbers, detail) {
136
+ super(freeTextRefusalMessage(cliToolId, optionNumbers, detail));
137
+ this.name = 'FreeTextAnswerRejectedError';
138
+ this.reason = exports.FREE_TEXT_AT_MENU_ROW_REASON;
139
+ this.optionNumbers = optionNumbers;
140
+ this.kind = detail?.kind ?? 'menu_row';
141
+ this.cursorOptionNumber = detail?.cursorOptionNumber ?? null;
142
+ }
143
+ }
144
+ exports.FreeTextAnswerRejectedError = FreeTextAnswerRejectedError;
145
+ /**
146
+ * Free text refused because NO row on the screen takes typed text (Issue #2583).
147
+ *
148
+ * ## The hole #2573 left
149
+ *
150
+ * {@link FreeTextAnswerRejectedError} looks for rows that READ as taking the
151
+ * operator's own words (`requiresTextInput`, i.e. `TEXT_INPUT_PATTERNS`) and
152
+ * only judges the answer when it finds at least one. A permission dialog with
153
+ * no such row was therefore never judged at all, and the text arm typed the
154
+ * answer and pressed Enter. Measured on 2026-09-16 against develop `9f4b4e29`:
155
+ *
156
+ * | tool | dialog | rows | result |
157
+ * |------|--------|------|--------|
158
+ * | Claude Code 2.1.273 | Bash command | `1. Yes` / `2. Yes, and always allow access to …` / `3. Yes, and switch to auto mode` / `4. No` | `success: true`, the `mkdir` RAN |
159
+ * | Antigravity 1.2.3 | Run this command? | `1. Yes, run command` / `2. Yes, and always allow …` / `3. Yes, … (Persist to settings.json)` / `4. No, cancel` | `success: true`, the `mkdir` RAN |
160
+ *
161
+ * Same screens, but with a path containing the word `custom`, `/custom/i`
162
+ * flagged the quoting row and #2573's guard refused. So what was left decided
163
+ * whether a refusal meaning "do not do this" approved instead: the SPELLING of
164
+ * the command being approved.
165
+ *
166
+ * ## What the caller is told, and why the count rather than the rows
167
+ *
168
+ * There is no row to name here — that is the whole condition — so the message
169
+ * cites how many options the screen has and points at the option number. It
170
+ * never quotes the answer (SEC-003, as in `prompt-answer-semantic`): the answer
171
+ * is whatever the operator typed and `/prompt-response` hands this message back
172
+ * to the client verbatim.
173
+ *
174
+ * Shares {@link FREE_TEXT_AT_MENU_ROW_REASON} with its sibling deliberately:
175
+ * the reason code is what `respond` and `/prompt-response` branch on, and both
176
+ * cases are the same promise to the caller — the answer could not be mapped onto
177
+ * a choice and NOTHING was sent.
178
+ */
179
+ class FreeTextAtChoiceOnlyPromptError extends Error {
180
+ /** Machine-readable code, always {@link FREE_TEXT_AT_MENU_ROW_REASON}. */
181
+ reason;
182
+ /** How many options the screen offers, none of which is a text field. */
183
+ optionCount;
184
+ constructor(cliToolId, optionCount) {
185
+ super(`Refused to type free text at ${cliToolId}'s prompt: none of its ${optionCount} options is a `
186
+ + 'text field on this screen, so the text would be ignored and the Enter after it would '
187
+ + 'confirm whatever is highlighted. Nothing was sent. Answer with the option number instead, '
188
+ + 'then send your instructions as a separate message.');
189
+ this.name = 'FreeTextAtChoiceOnlyPromptError';
190
+ this.reason = exports.FREE_TEXT_AT_MENU_ROW_REASON;
191
+ this.optionCount = optionCount;
192
+ }
193
+ }
194
+ exports.FreeTextAtChoiceOnlyPromptError = FreeTextAtChoiceOnlyPromptError;
70
195
  /**
71
196
  * The pane to judge the tool's own dialog rules against.
72
197
  *
@@ -127,52 +252,68 @@ async function readGuardFrame(params) {
127
252
  * - It never fires for a tool with no measured dialog rules
128
253
  * (`hasDialogRules === false`: gemini, antigravity, vibe-local). Gating on
129
254
  * rules that do not exist would silence those tools, which is the rollout
130
- * mistake `auto-yes-dialog-gate` documents.
255
+ * mistake `auto-yes-dialog-gate` documents. command-code has had rules since
256
+ * Issue #2574 (before it, it belonged in this list and was missing from it);
257
+ * they only ever answer `numbered`, so on that tool this guard never refuses
258
+ * and its reading is used for the Enter instead (see {@link resolveSubmitMode}).
131
259
  * - It does not MAP the answer onto the dialog's buttons. Turning "3" into the
132
260
  * two ←/→ presses that reach `Reject` is Issue P1-7's structured-decision
133
261
  * work; this Issue only stops the wrong keystroke.
134
262
  *
263
+ * @returns The `numbered` dialog the tool vouched for on this frame, or null when
264
+ * the guard did not read one (non-numeric answer, no rules, unreadable pane,
265
+ * or no dialog on screen). Returned so the Enter decision is made off the
266
+ * same reading rather than a second capture (Issue #2574).
135
267
  * @throws {PromptAnswerRejectedError} when the tool vouched for a dialog on this
136
268
  * frame whose `answerMode` is not {@link TEXT_ANSWERABLE_ANSWER_MODE}.
137
269
  */
138
270
  async function assertAnswerModeAcceptsNumber(params) {
139
271
  if (!/^\d+$/.test(params.answer))
140
- return;
272
+ return null;
141
273
  const detector = (0, registry_1.getToolStatusDetector)(params.cliToolId);
142
274
  if (!detector.hasDialogRules)
143
- return;
275
+ return null;
144
276
  const frame = await readGuardFrame(params);
145
277
  if (frame === null)
146
- return;
278
+ return null;
147
279
  const dialog = detector.detectDialog((0, frame_1.normalizeFrame)(frame));
148
280
  if (dialog === null)
149
- return;
281
+ return null;
150
282
  if (dialog.answerMode === TEXT_ANSWERABLE_ANSWER_MODE)
151
- return;
283
+ return dialog;
152
284
  throw new PromptAnswerRejectedError(params.cliToolId, params.answer, dialog);
153
285
  }
154
286
  /**
155
- * Resolve the effective SubmitMode from promptData, fallback, and default.
156
- * Resolution order: promptData.submitMode -> fallbackSubmitMode -> 'answer_then_enter'.
287
+ * Resolve the effective SubmitMode from the dialog on screen, promptData, fallback, and default.
288
+ * Resolution order: dialog.submitMode -> promptData.submitMode -> fallbackSubmitMode -> 'answer_then_enter'.
157
289
  * Invalid values are normalized to 'answer_then_enter' via allowlist validation.
158
290
  *
291
+ * Issue #2574: the dialog comes first because it is the tool's own measurement,
292
+ * read off the frame the answer is about to land on. `promptData` may have been
293
+ * built by the generic parser, which cannot see that a digit is a hotkey —
294
+ * Command Code's permission dialog was published with no `submitMode`, and the
295
+ * Enter sent after its `1` submitted whatever draft was waiting in the composer.
296
+ *
159
297
  * @returns The resolved SubmitMode, guaranteed to be a valid value.
160
298
  */
161
- function resolveSubmitMode(params) {
299
+ function resolveSubmitMode(params, dialog) {
162
300
  const fromPromptData = params.promptData?.type === 'multiple_choice'
163
301
  ? params.promptData.submitMode
164
302
  : undefined;
165
- const raw = fromPromptData ?? params.fallbackSubmitMode ?? 'answer_then_enter';
303
+ const raw = dialog?.submitMode ?? fromPromptData ?? params.fallbackSubmitMode ?? 'answer_then_enter';
166
304
  return (0, models_1.isValidSubmitMode)(raw) ? raw : 'answer_then_enter';
167
305
  }
168
306
  /**
169
307
  * Determine whether the Enter key should be suppressed after sending the answer text.
170
308
  * answer_only mode applies only when the prompt is multiple_choice and the answer is numeric.
309
+ * A numbered dialog the tool vouched for is a multiple-choice prompt in its own right,
310
+ * which covers a caller that could not supply promptData (Issue #2574).
171
311
  */
172
- function shouldSuppressEnter(params, submitMode) {
312
+ function shouldSuppressEnter(params, submitMode, dialog) {
173
313
  if (submitMode !== 'answer_only')
174
314
  return false;
175
- const isMultipleChoice = params.promptData?.type === 'multiple_choice'
315
+ const isMultipleChoice = dialog !== null
316
+ || params.promptData?.type === 'multiple_choice'
176
317
  || params.fallbackPromptType === 'multiple_choice';
177
318
  return isMultipleChoice && /^\d+$/.test(params.answer);
178
319
  }
@@ -186,6 +327,177 @@ function buildNavigationKeys(offset) {
186
327
  const direction = offset > 0 ? 'Down' : 'Up';
187
328
  return Array.from({ length: Math.abs(offset) }, () => direction);
188
329
  }
330
+ /**
331
+ * Refuse free text aimed at a menu row (Issue #2573).
332
+ *
333
+ * ## The hole
334
+ *
335
+ * `PromptPanel` / `MobilePromptSheet` sent the operator's TEXT instead of the
336
+ * option number whenever the selected option had `requiresTextInput`, and
337
+ * `respond <id> "<text>"` sends text by construction. Nothing below maps text
338
+ * onto a choice — the cursor arm takes digits only — so the text arm typed it at
339
+ * the dialog and pressed Enter. On Command Code 1.53.1's permission dialog
340
+ * (`3. No, tell Command Code what to do differently`) the characters are ignored
341
+ * and the Enter confirms the highlighted `1. Yes`: measured, a reason meaning
342
+ * "do not do this" ran the `mkdir` it was sent to stop, and `/prompt-response`
343
+ * answered `success: true`.
344
+ *
345
+ * ## Why it is keyed on the rows and not on "is the answer a number"
346
+ *
347
+ * Free text is the RIGHT answer on the screen next door. Command Code's
348
+ * `AskUserQuestion` ends in `Type something...`, a real `TextInput` (#2522), and
349
+ * both rows carry `requiresTextInput`. So the question is whether the prompt's
350
+ * text-bearing options include one measured to be a field
351
+ * ({@link isTypedTextFieldOption}); only when every one of them is a menu row is
352
+ * the text refused.
353
+ *
354
+ * ## Issue #2583: a screen with no text-bearing row is judged too
355
+ *
356
+ * The bullet that used to sit here said this guard does not judge a prompt with
357
+ * NO `requiresTextInput` option, citing #1726's pin — "sessions the rows cannot
358
+ * speak for keep behaving as they did". It named the hole it was leaving open in
359
+ * as many words (`the same Enter still sits under free text sent at, e.g.,
360
+ * claude's 1. Yes / 2. … / 3. No`), and #2583 then measured it: on claude 2.1.273
361
+ * and agy 1.2.3 a refusal typed at a Bash-approval dialog answered
362
+ * `success: true` and RAN the command. Whether it was refused came down to
363
+ * whether the quoted path happened to contain the word `custom`, which is
364
+ * `/custom/i` in `TEXT_INPUT_PATTERNS` — the spelling of someone else's argument.
365
+ *
366
+ * So the rule is now the one the guard's name always claimed: free text needs a
367
+ * text field, and a `multiple_choice` prompt whose rows are all choices has none.
368
+ *
369
+ * **What this costs, and why it is still the right trade.** #1726's pin is about
370
+ * AUTHORITY: that Issue reads the agent's own `AskUserQuestion` payload and must
371
+ * not let its absence narrow what a hook-less session accepts, because there the
372
+ * screen is the only authority. The rows judged here ARE the screen — the fresh
373
+ * capture `/prompt-response` re-verified, parsed by the same reader that draws
374
+ * the answer panels — so nothing is being second-guessed from a payload that is
375
+ * missing. What #1726 keeps is its actual subject: an out-of-RANGE number is
376
+ * still sent when no payload vouches for the list (this guard reads only
377
+ * non-numeric answers), and a call with no `promptData` at all still goes
378
+ * through untouched. The one case that regresses is an operator who has walked
379
+ * the cursor onto a row that opens a field the rows do not advertise — claude's
380
+ * `4. Type something.`, which no pattern flags — and sends text for it; they now
381
+ * get a refusal with the dialog still up instead of a silent approval. That
382
+ * direction is the safe one, and cursor position is #2584's subject, not this
383
+ * one's.
384
+ *
385
+ * ## What it deliberately does NOT do
386
+ *
387
+ * - It does not judge a call with no `promptData`, nor a `multiple_choice` with
388
+ * an empty option list. Both mean the rows are unknown, which is exactly where
389
+ * #1726's pin still holds — and where `/prompt-response` has already refused
390
+ * for its own reasons if the pane could be read at all.
391
+ * - It does not deliver the reason. Sending the number and then the text as a
392
+ * message is the follow-up (#2573 対応内容 2). Issue #2574 has since removed the
393
+ * Enter that would have landed the reason in the wrong place on command-code,
394
+ * so what is still missing is a measurement, per tool, of where the input goes
395
+ * once the digit has confirmed.
396
+ *
397
+ * @throws {FreeTextAtChoiceOnlyPromptError} when the answer is not a number and
398
+ * no option of the multiple-choice prompt even reads as taking text (#2583).
399
+ * @throws {FreeTextAnswerRejectedError} when the answer is not a number and every
400
+ * text-bearing option of the multiple-choice prompt is a menu row (#2573).
401
+ */
402
+ function assertFreeTextHasATextField(params) {
403
+ if (/^\d+$/.test(params.answer))
404
+ return;
405
+ const { promptData } = params;
406
+ if (promptData?.type !== 'multiple_choice')
407
+ return;
408
+ // No rows to read is not the same as rows that take no text: a prompt this
409
+ // degraded says nothing about where characters land, so it keeps the
410
+ // pre-#2583 path (see the pin discussion above).
411
+ if (promptData.options.length === 0)
412
+ return;
413
+ const textBearing = promptData.options.filter((option) => option.requiresTextInput === true);
414
+ // Issue #2583. Deliberately BEFORE the `isTypedTextFieldOption` reading below
415
+ // and never inside it: that reading decides between a field and a menu row on
416
+ // a screen that has at least one candidate, and this branch is the screen that
417
+ // has none.
418
+ if (textBearing.length === 0) {
419
+ throw new FreeTextAtChoiceOnlyPromptError(params.cliToolId, promptData.options.length);
420
+ }
421
+ if (textBearing.some(prompt_detect_multiple_choice_1.isTypedTextFieldOption))
422
+ return;
423
+ throw new FreeTextAnswerRejectedError(params.cliToolId, textBearing.map((option) => option.number));
424
+ }
425
+ /**
426
+ * Refuse free text while the cursor is on another row (Issue #2584).
427
+ *
428
+ * ## The hole #2573 left open
429
+ *
430
+ * {@link assertFreeTextHasATextField} asks what KIND the text-bearing rows are,
431
+ * and lets the text through the moment one of them is a measured field. On
432
+ * Command Code's `AskUserQuestion` that is one question short, because the field
433
+ * is a row of a list and typed characters only reach it while the cursor is
434
+ * resting there. Measured on 1.53.1 (#2584), with `Type something...` on row 3
435
+ * and the `❯` on row 1:
436
+ *
437
+ * ```
438
+ * ❯ 1. apple
439
+ * 2. banana
440
+ * 3. Type something...
441
+ * ```
442
+ *
443
+ * `answer: "UAT-FREETEXT-KIWI"` was ignored, the Enter after it confirmed
444
+ * `apple`, and `/prompt-response` answered `success: true` — the same failure
445
+ * shape as #2573, reached through the screen #2573 deliberately exempts. The
446
+ * SAME request on the SAME screen with the `❯` on row 3 records the text, so
447
+ * nothing but the cursor decides which of the two it means.
448
+ *
449
+ * ## Why it refuses instead of moving the cursor there first
450
+ *
451
+ * The obvious alternative is to reuse the cursor arm: compute `field - cursor`
452
+ * and send that many Down presses before typing. The arithmetic is available —
453
+ * both numbers are read off the frame — but the KEYS are not measured for this
454
+ * screen. The cursor arm is claude's and agy's by construction
455
+ * (`isCursorNavMultiChoice`, and `tools/command-code/dialog.ts` says so where it
456
+ * publishes this prompt), and what IS measured for Command Code is the opposite
457
+ * input method: the digit is a hotkey that selects on its own, which is why the
458
+ * screen is published `answer_only` (#2574). #2522 measured the remaining half —
459
+ * the digit aimed at the field row selects nothing — so this repository has no
460
+ * measured keystroke that moves this cursor at all.
461
+ *
462
+ * Sending Down at it anyway would, if the list does not take arrow keys,
463
+ * reproduce exactly today's bug with extra keystrokes in front of it and still
464
+ * answer `success: true`. That is the mistake `assertAnswerModeAcceptsNumber`
465
+ * was written against: gate on the measurement, and stop the wrong keystroke
466
+ * rather than invent a mapping. Mapping the answer onto the field — teaching the
467
+ * sender to arm this cursor once the movement key has been measured live — is
468
+ * the follow-up, and it can be added under this guard without changing what any
469
+ * caller sees today.
470
+ *
471
+ * ## What it deliberately does NOT do
472
+ *
473
+ * - It does not fire on a prompt with no measured field: that is #2573's case
474
+ * above (every text-bearing row is a menu row) or the pre-#2573 pass-through
475
+ * (#1726), and neither changes here.
476
+ * - It does not fire when NO option carries the cursor. agy's picker publishes
477
+ * its highlight without `isDefault` at all (`#999`), and a screen whose cursor
478
+ * cannot be read is one this guard has nothing to say about — the same
479
+ * fail-open {@link readGuardFrame} takes for an unreadable pane.
480
+ *
481
+ * @throws {FreeTextAnswerRejectedError} with `kind: 'cursor_elsewhere'` when the
482
+ * answer is not a number, the prompt has a measured text field, and the cursor
483
+ * is resting on some other option.
484
+ */
485
+ function assertFreeTextCursorIsOnTheField(params) {
486
+ if (/^\d+$/.test(params.answer))
487
+ return;
488
+ const { promptData } = params;
489
+ if (promptData?.type !== 'multiple_choice')
490
+ return;
491
+ const fields = promptData.options.filter(prompt_detect_multiple_choice_1.isTypedTextFieldOption);
492
+ if (fields.length === 0)
493
+ return;
494
+ const cursor = promptData.options.find((option) => option.isDefault === true);
495
+ if (cursor === undefined)
496
+ return;
497
+ if ((0, prompt_detect_multiple_choice_1.isTypedTextFieldOption)(cursor))
498
+ return;
499
+ throw new FreeTextAnswerRejectedError(params.cliToolId, fields.map((option) => option.number), { kind: 'cursor_elsewhere', cursorOptionNumber: cursor.number });
500
+ }
189
501
  /**
190
502
  * Send an answer to a tmux session, using cursor-key navigation for
191
503
  * Claude Code / Antigravity multiple-choice prompts and text input for
@@ -202,7 +514,18 @@ async function sendPromptAnswer(params) {
202
514
  // inside the text arm because the number->offset arithmetic the cursor arm
203
515
  // does is just as meaningless on an unnumbered button strip as typing the
204
516
  // digit is.
205
- await assertAnswerModeAcceptsNumber(params);
517
+ const dialog = await assertAnswerModeAcceptsNumber(params);
518
+ // Issue #2573 / #2583: the same promise for text. The text arm below types
519
+ // whatever it is given and presses Enter, so text aimed at a screen that has
520
+ // no text field on it — a menu row that reads as one, or a permission dialog
521
+ // whose rows are all choices — has to stop here, before the branch, or the
522
+ // Enter confirms the highlighted default.
523
+ assertFreeTextHasATextField(params);
524
+ // Issue #2584: and the half #2573 left open. A prompt that HAS a real text
525
+ // field still swallows the characters while the cursor is on another row, and
526
+ // the Enter after them confirms that row — so the cursor has to be checked
527
+ // here too, before the branch.
528
+ assertFreeTextCursorIsOnTheField(params);
206
529
  // Determine if this is an arrow-key-navigated multiple-choice prompt.
207
530
  // Claude Code and Antigravity (agy) both render selection menus that only
208
531
  // respond to cursor navigation + Enter, not to typed option numbers
@@ -276,8 +599,8 @@ async function sendPromptAnswer(params) {
276
599
  // Standard CLI prompt: send text + Enter (y/n, Approve?, etc.)
277
600
  await (0, tmux_1.sendKeys)(sessionName, answer, false);
278
601
  // Issue #616: Resolve submitMode and determine whether to suppress Enter
279
- const resolvedSubmitMode = resolveSubmitMode(params);
280
- if (!shouldSuppressEnter(params, resolvedSubmitMode)) {
602
+ const resolvedSubmitMode = resolveSubmitMode(params, dialog);
603
+ if (!shouldSuppressEnter(params, resolvedSubmitMode, dialog)) {
281
604
  // Wait a moment for the input to be processed
282
605
  await new Promise(resolve => setTimeout(resolve, cli_tool_timing_config_1.TUI_TEXT_INPUT_WAIT_MS));
283
606
  // Send Enter