commandmate 0.12.0 → 0.13.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 (229) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +139 -139
  3. package/.next/app-path-routes-manifest.json +28 -28
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/prerender-manifest.json +15 -15
  6. package/.next/required-server-files.json +1 -1
  7. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  8. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  9. package/.next/server/app/api/app/update-check/route.js +1 -1
  10. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
  12. package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
  18. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/daily-summary/route.js +1 -1
  22. package/.next/server/app/api/daily-summary/route.js.nft.json +1 -1
  23. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  24. package/.next/server/app/api/daily-summary/status/route.js +1 -1
  25. package/.next/server/app/api/daily-summary/status/route.js.nft.json +1 -1
  26. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  27. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  28. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/external-apps/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/ollama/models/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
  37. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
  38. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
  39. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  40. package/.next/server/app/api/repositories/clone/route.js +1 -1
  41. package/.next/server/app/api/repositories/clone/route.js.nft.json +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/sidebar/group-order/route_client-reference-manifest.js +1 -1
  49. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
  50. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  51. package/.next/server/app/api/slash-commands/route.js +1 -1
  52. package/.next/server/app/api/slash-commands/route.js.nft.json +1 -1
  53. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  54. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  55. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  56. package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
  57. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  58. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  60. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  61. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  63. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  64. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  65. package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js +1 -1
  66. package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js.nft.json +1 -1
  67. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  68. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js +1 -1
  69. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js.nft.json +1 -1
  70. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  71. package/.next/server/app/api/worktrees/[id]/git/branches/route.js +1 -1
  72. package/.next/server/app/api/worktrees/[id]/git/branches/route.js.nft.json +1 -1
  73. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  74. package/.next/server/app/api/worktrees/[id]/git/checkout/route.js +1 -1
  75. package/.next/server/app/api/worktrees/[id]/git/checkout/route.js.nft.json +1 -1
  76. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/worktrees/[id]/git/commit/route.js +1 -1
  78. package/.next/server/app/api/worktrees/[id]/git/commit/route.js.nft.json +1 -1
  79. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  80. package/.next/server/app/api/worktrees/[id]/git/diff/route.js +1 -1
  81. package/.next/server/app/api/worktrees/[id]/git/diff/route.js.nft.json +1 -1
  82. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  83. package/.next/server/app/api/worktrees/[id]/git/fetch/route.js +1 -1
  84. package/.next/server/app/api/worktrees/[id]/git/fetch/route.js.nft.json +1 -1
  85. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  86. package/.next/server/app/api/worktrees/[id]/git/log/route.js +1 -1
  87. package/.next/server/app/api/worktrees/[id]/git/log/route.js.nft.json +1 -1
  88. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/api/worktrees/[id]/git/pull/route.js +1 -1
  90. package/.next/server/app/api/worktrees/[id]/git/pull/route.js.nft.json +1 -1
  91. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/api/worktrees/[id]/git/push/route.js +1 -1
  93. package/.next/server/app/api/worktrees/[id]/git/push/route.js.nft.json +1 -1
  94. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/api/worktrees/[id]/git/reset/route.js +1 -1
  96. package/.next/server/app/api/worktrees/[id]/git/reset/route.js.nft.json +1 -1
  97. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  98. package/.next/server/app/api/worktrees/[id]/git/revert/route.js +1 -1
  99. package/.next/server/app/api/worktrees/[id]/git/revert/route.js.nft.json +1 -1
  100. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  101. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js +1 -1
  102. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js.nft.json +1 -1
  103. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  104. package/.next/server/app/api/worktrees/[id]/git/stage/route.js +1 -1
  105. package/.next/server/app/api/worktrees/[id]/git/stage/route.js.nft.json +1 -1
  106. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  107. package/.next/server/app/api/worktrees/[id]/git/staged/route.js +1 -1
  108. package/.next/server/app/api/worktrees/[id]/git/staged/route.js.nft.json +1 -1
  109. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  110. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js +1 -1
  111. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js.nft.json +1 -1
  112. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  113. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js +1 -1
  114. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js.nft.json +1 -1
  115. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  116. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js +1 -1
  117. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js.nft.json +1 -1
  118. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js +1 -1
  120. package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js.nft.json +1 -1
  121. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  122. package/.next/server/app/api/worktrees/[id]/git/stash/route.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/git/stash/route.js.nft.json +1 -1
  124. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/git/status/route.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/git/status/route.js.nft.json +1 -1
  127. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/git/unstage/route.js +1 -1
  129. package/.next/server/app/api/worktrees/[id]/git/unstage/route.js.nft.json +1 -1
  130. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js +1 -1
  132. package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js.nft.json +1 -1
  133. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  135. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  136. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  137. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  138. package/.next/server/app/api/worktrees/[id]/marp-render/route.js +1 -1
  139. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  141. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  142. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  146. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  147. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  148. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  149. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  151. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  152. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
  153. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  154. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  155. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
  157. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
  158. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
  159. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
  161. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js.nft.json +1 -1
  162. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  163. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  164. package/.next/server/app/api/worktrees/[id]/start-polling/route_client-reference-manifest.js +1 -1
  165. package/.next/server/app/api/worktrees/[id]/terminal/route.js +1 -1
  166. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  167. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  168. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  170. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  171. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  173. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  174. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  175. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  176. package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  177. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  178. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  179. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  180. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  181. package/.next/server/app/page_client-reference-manifest.js +1 -1
  182. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  183. package/.next/server/app/repositories/page.js +1 -1
  184. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  185. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  186. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  187. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
  188. package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  189. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  190. package/.next/server/app/worktrees/[id]/page.js +3 -3
  191. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  192. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  193. package/.next/server/app-paths-manifest.json +28 -28
  194. package/.next/server/chunks/186.js +1 -1
  195. package/.next/server/chunks/2119.js +1 -1
  196. package/.next/server/chunks/2404.js +2 -1
  197. package/.next/server/chunks/2445.js +1 -1
  198. package/.next/server/chunks/3270.js +1 -1
  199. package/.next/server/chunks/3543.js +1 -1
  200. package/.next/server/chunks/3945.js +1 -1
  201. package/.next/server/chunks/5381.js +1 -1
  202. package/.next/server/chunks/5959.js +3 -3
  203. package/.next/server/chunks/6130.js +1 -1
  204. package/.next/server/chunks/6283.js +1 -1
  205. package/.next/server/chunks/9123.js +1 -1
  206. package/.next/server/chunks/9192.js +1 -0
  207. package/.next/server/middleware-manifest.json +5 -5
  208. package/.next/server/pages/500.html +1 -1
  209. package/.next/server/server-reference-manifest.json +1 -1
  210. package/.next/static/chunks/1668-e703b8b55775844b.js +1 -0
  211. package/.next/static/chunks/{6488-e257111ca7389d05.js → 6488-87bc158682ce8c24.js} +1 -1
  212. package/.next/static/chunks/app/repositories/{page-75f0d70452c6b6c0.js → page-70d4b997492884b8.js} +1 -1
  213. package/.next/static/chunks/app/worktrees/[id]/page-d9a6cb166c73746e.js +1 -0
  214. package/.next/trace +11 -11
  215. package/dist/server/src/lib/cli-tools/antigravity.js +8 -13
  216. package/dist/server/src/lib/cli-tools/codex.js +8 -14
  217. package/dist/server/src/lib/cli-tools/copilot.js +12 -13
  218. package/dist/server/src/lib/cli-tools/gemini.js +8 -13
  219. package/dist/server/src/lib/cli-tools/opencode.js +8 -13
  220. package/dist/server/src/lib/cli-tools/submit-verified-sender.js +174 -0
  221. package/dist/server/src/lib/cli-tools/vibe-local.js +12 -17
  222. package/dist/server/src/lib/session-key-sender.js +11 -9
  223. package/package.json +1 -1
  224. package/.next/server/chunks/5312.js +0 -1
  225. package/.next/static/chunks/1668-7484081c45a44f89.js +0 -1
  226. package/.next/static/chunks/app/worktrees/[id]/page-bf811e793052c917.js +0 -1
  227. package/dist/server/src/lib/pasted-text-helper.js +0 -58
  228. /package/.next/static/{D-aoE4gWfuCUN0GqEPIX3 → qeQn6_9VTrYHitt3mqIG8}/_buildManifest.js +0 -0
  229. /package/.next/static/{D-aoE4gWfuCUN0GqEPIX3 → qeQn6_9VTrYHitt3mqIG8}/_ssgManifest.js +0 -0
@@ -13,7 +13,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.AntigravityTool = void 0;
14
14
  const base_1 = require("./base");
15
15
  const tmux_1 = require("../tmux/tmux");
16
- const pasted_text_helper_1 = require("../pasted-text-helper");
16
+ const submit_verified_sender_1 = require("./submit-verified-sender");
17
17
  const tmux_capture_cache_1 = require("../tmux/tmux-capture-cache");
18
18
  const cli_patterns_1 = require("../detection/cli-patterns");
19
19
  const logger_1 = require("../../lib/logger");
@@ -217,18 +217,13 @@ class AntigravityTool extends base_1.BaseCLITool {
217
217
  try {
218
218
  // Verify agy is at a ready prompt before sending
219
219
  await this.waitForPrompt(sessionName);
220
- // Send message text (without Enter)
221
- await (0, tmux_1.sendKeys)(sessionName, message, false);
222
- // Wait a moment for the text to be typed
223
- await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_TEXT_INPUT_WAIT_MS));
224
- // Send Enter key separately
225
- await (0, tmux_1.sendSpecialKey)(sessionName, 'C-m');
226
- // Wait a moment for the message to be processed
227
- await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_MESSAGE_PROCESSED_WAIT_MS));
228
- // Detect [Pasted text] and resend Enter for multi-line messages
229
- if (message.includes('\n')) {
230
- await (0, pasted_text_helper_1.detectAndResendIfPastedText)(sessionName);
231
- }
220
+ // Issue #1471: Body/Enter separation + read-back submit verification via the
221
+ // shared helper (replaces the old type -> C-m -> `\n`-gated paste recovery).
222
+ await (0, submit_verified_sender_1.sendMessageWithSubmitVerification)({
223
+ sessionName,
224
+ message,
225
+ cliToolId: 'antigravity',
226
+ });
232
227
  // Invalidate cache after sending message (required so the poller re-reads)
233
228
  (0, tmux_capture_cache_1.invalidateCache)(sessionName);
234
229
  logger.info('sent-message-to-antigravity-session');
@@ -7,7 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.CodexTool = void 0;
8
8
  const base_1 = require("./base");
9
9
  const tmux_1 = require("../tmux/tmux");
10
- const pasted_text_helper_1 = require("../pasted-text-helper");
10
+ const submit_verified_sender_1 = require("./submit-verified-sender");
11
11
  const tmux_capture_cache_1 = require("../tmux/tmux-capture-cache");
12
12
  const cli_patterns_1 = require("../detection/cli-patterns");
13
13
  const logger_1 = require("../../lib/logger");
@@ -209,19 +209,13 @@ class CodexTool extends base_1.BaseCLITool {
209
209
  try {
210
210
  // Verify Codex is at prompt state before sending
211
211
  await this.waitForPrompt(sessionName);
212
- // Send message to Codex (without Enter)
213
- await (0, tmux_1.sendKeys)(sessionName, message, false);
214
- // Wait a moment for the text to be typed
215
- await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_TEXT_INPUT_WAIT_MS));
216
- // Send Enter key separately
217
- await (0, tmux_1.sendSpecialKey)(sessionName, 'C-m');
218
- // Wait a moment for the message to be processed
219
- await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_MESSAGE_PROCESSED_WAIT_MS));
220
- // Issue #212: Detect [Pasted text] and resend Enter for multi-line messages
221
- // MF-001: Single-line messages skip detection (+0ms overhead)
222
- if (message.includes('\n')) {
223
- await (0, pasted_text_helper_1.detectAndResendIfPastedText)(sessionName);
224
- }
212
+ // Issue #1471: Body/Enter separation + read-back submit verification via the
213
+ // shared helper (replaces the old type -> C-m -> `\n`-gated paste recovery).
214
+ await (0, submit_verified_sender_1.sendMessageWithSubmitVerification)({
215
+ sessionName,
216
+ message,
217
+ cliToolId: 'codex',
218
+ });
225
219
  // Issue #405: Invalidate cache after sending message
226
220
  (0, tmux_capture_cache_1.invalidateCache)(sessionName);
227
221
  logger.info('sent-message-to-codex-session:sessionnam');
@@ -12,7 +12,7 @@ exports.CopilotTool = void 0;
12
12
  const child_process_1 = require("child_process");
13
13
  const base_1 = require("./base");
14
14
  const tmux_1 = require("../tmux/tmux");
15
- const pasted_text_helper_1 = require("../pasted-text-helper");
15
+ 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 copilot_constants_1 = require("../../config/copilot-constants");
@@ -246,18 +246,17 @@ class CopilotTool extends base_1.BaseCLITool {
246
246
  logger.info('sent-selection-list-command-to-copilot', { command: slashCmd });
247
247
  return;
248
248
  }
249
- // Send message to Copilot (without Enter)
250
- await (0, tmux_1.sendKeys)(sessionName, message, false);
251
- // Wait a moment for the text to be typed
252
- await new Promise((resolve) => setTimeout(resolve, copilot_constants_1.COPILOT_TEXT_INPUT_DELAY_MS));
253
- // Send Enter key separately
254
- await (0, tmux_1.sendSpecialKey)(sessionName, 'C-m');
255
- // Wait a moment for the message to be processed
256
- await new Promise((resolve) => setTimeout(resolve, copilot_constants_1.COPILOT_SEND_ENTER_DELAY_MS));
257
- // Detect [Pasted text] and resend Enter for multi-line messages
258
- if (message.includes('\n')) {
259
- await (0, pasted_text_helper_1.detectAndResendIfPastedText)(sessionName);
260
- }
249
+ // Issue #1471: Body/Enter separation + read-back submit verification via the
250
+ // shared helper (replaces the old type -> C-m -> `\n`-gated paste recovery).
251
+ // Copilot's own text-input / post-Enter delays are preserved. The selection
252
+ // list slash-command branch above is intentionally NOT routed through here.
253
+ await (0, submit_verified_sender_1.sendMessageWithSubmitVerification)({
254
+ sessionName,
255
+ message,
256
+ cliToolId: 'copilot',
257
+ textInputWaitMs: copilot_constants_1.COPILOT_TEXT_INPUT_DELAY_MS,
258
+ verifyDelayMs: copilot_constants_1.COPILOT_SEND_ENTER_DELAY_MS,
259
+ });
261
260
  // Invalidate cache after sending message
262
261
  (0, tmux_capture_cache_1.invalidateCache)(sessionName);
263
262
  logger.info('sent-message-to-copilot-session');
@@ -12,7 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.GeminiTool = exports.GEMINI_PANE_HEIGHT = void 0;
13
13
  const base_1 = require("./base");
14
14
  const tmux_1 = require("../tmux/tmux");
15
- const pasted_text_helper_1 = require("../pasted-text-helper");
15
+ 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 logger_1 = require("../../lib/logger");
@@ -167,18 +167,13 @@ class GeminiTool extends base_1.BaseCLITool {
167
167
  try {
168
168
  // Verify Gemini is at prompt state before sending
169
169
  await this.waitForPrompt(sessionName);
170
- // Send message to Gemini (without Enter)
171
- await (0, tmux_1.sendKeys)(sessionName, message, false);
172
- // Wait a moment for the text to be typed
173
- await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_TEXT_INPUT_WAIT_MS));
174
- // Send Enter key separately
175
- await (0, tmux_1.sendSpecialKey)(sessionName, 'C-m');
176
- // Wait a moment for the message to be processed
177
- await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_MESSAGE_PROCESSED_WAIT_MS));
178
- // Detect [Pasted text] and resend Enter for multi-line messages
179
- if (message.includes('\n')) {
180
- await (0, pasted_text_helper_1.detectAndResendIfPastedText)(sessionName);
181
- }
170
+ // Issue #1471: Body/Enter separation + read-back submit verification via the
171
+ // shared helper (replaces the old type -> C-m -> `\n`-gated paste recovery).
172
+ await (0, submit_verified_sender_1.sendMessageWithSubmitVerification)({
173
+ sessionName,
174
+ message,
175
+ cliToolId: 'gemini',
176
+ });
182
177
  // Issue #405: Invalidate cache after sending message
183
178
  (0, tmux_capture_cache_1.invalidateCache)(sessionName);
184
179
  logger.info('sent-message-to-gemini-session:sessionna');
@@ -13,7 +13,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.OpenCodeTool = exports.OPENCODE_INIT_WAIT_MS = exports.OPENCODE_PANE_HEIGHT = exports.OPENCODE_EXIT_COMMAND = void 0;
14
14
  const base_1 = require("./base");
15
15
  const tmux_1 = require("../tmux/tmux");
16
- const pasted_text_helper_1 = require("../pasted-text-helper");
16
+ const submit_verified_sender_1 = require("./submit-verified-sender");
17
17
  const tmux_capture_cache_1 = require("../tmux/tmux-capture-cache");
18
18
  const opencode_config_1 = require("./opencode-config");
19
19
  const child_process_1 = require("child_process");
@@ -134,18 +134,13 @@ class OpenCodeTool extends base_1.BaseCLITool {
134
134
  throw new Error(`OpenCode session ${sessionName} does not exist. Start the session first.`);
135
135
  }
136
136
  try {
137
- // Send message to OpenCode (without Enter)
138
- await (0, tmux_1.sendKeys)(sessionName, message, false);
139
- // Wait a moment for the text to be typed
140
- await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_TEXT_INPUT_WAIT_MS));
141
- // Send Enter key separately
142
- await (0, tmux_1.sendSpecialKey)(sessionName, 'C-m');
143
- // Wait a moment for the message to be processed
144
- await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_MESSAGE_PROCESSED_WAIT_MS));
145
- // Detect [Pasted text] and resend Enter for multi-line messages
146
- if (message.includes('\n')) {
147
- await (0, pasted_text_helper_1.detectAndResendIfPastedText)(sessionName);
148
- }
137
+ // Issue #1471: Body/Enter separation + read-back submit verification via the
138
+ // shared helper (replaces the old type -> C-m -> `\n`-gated paste recovery).
139
+ await (0, submit_verified_sender_1.sendMessageWithSubmitVerification)({
140
+ sessionName,
141
+ message,
142
+ cliToolId: 'opencode',
143
+ });
149
144
  // Issue #405: Invalidate cache after sending message
150
145
  (0, tmux_capture_cache_1.invalidateCache)(sessionName);
151
146
  logger.info('sent-message-to-opencode-session:session');
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ /**
3
+ * Submit-verified message sender (Issues #1469, #1470, #1471).
4
+ *
5
+ * A single shared helper that replaces the seven near-identical
6
+ * "type body -> press Enter -> maybe recover paste" sequences previously
7
+ * duplicated across session-key-sender.ts and every cli-tools/*.ts sendMessage(),
8
+ * plus the terminal API route's raw `sendKeys(command)` batch send.
9
+ *
10
+ * Why this exists (root cause):
11
+ * tmux `send-keys <body> C-m` batches the body and Enter into a SINGLE command.
12
+ * ink/React TUIs (Claude Code, Codex, ...) treat the injected body as a
13
+ * bracketed paste and swallow the trailing C-m as a newline inside the paste
14
+ * buffer, so the message is typed but never submitted. The recovery that used
15
+ * to guard this was gated on `message.includes('\n')` (single-line messages
16
+ * skipped entirely), keyed off Claude's version-specific `[Pasted text #\d+`
17
+ * string, and never verified that submit actually happened (fire-and-forget).
18
+ *
19
+ * This helper fixes all three:
20
+ * 1. Body and Enter are ALWAYS sent as separate tmux commands with a delay
21
+ * between them (never a single body+C-m batch).
22
+ * 2. Recovery + verification apply to EVERY message (no `\n` gate).
23
+ * 3. After submit it reads the pane back and confirms the message actually
24
+ * left the input box (empty input line) or the tool began generating.
25
+ * If it is still pending it resends Enter, bounded; if it can never be
26
+ * confirmed it THROWS (callers must not report success on a stuck send).
27
+ *
28
+ * The verification is intentionally NOT keyed off the version-specific
29
+ * `[Pasted text #\d+` placeholder. That placeholder is used only as one
30
+ * "still pending" positive signal (broadened to be version-resilient); the
31
+ * primary decision is "is the message still sitting on the input line?".
32
+ */
33
+ Object.defineProperty(exports, "__esModule", { value: true });
34
+ exports.isSubmitted = isSubmitted;
35
+ exports.sendMessageWithSubmitVerification = sendMessageWithSubmitVerification;
36
+ const tmux_1 = require("../tmux/tmux");
37
+ const tmux_capture_cache_1 = require("../tmux/tmux-capture-cache");
38
+ const cli_patterns_1 = require("../detection/cli-patterns");
39
+ const cli_tool_timing_config_1 = require("../../config/cli-tool-timing-config");
40
+ const logger_1 = require("../../lib/logger");
41
+ const logger = (0, logger_1.createLogger)('cli-tools/submit-verified-sender');
42
+ /**
43
+ * Version-resilient pasted-text placeholder.
44
+ *
45
+ * Broader than PASTED_TEXT_PATTERN (`/\[Pasted text #\d+/`) so it still matches
46
+ * when a CLI version drops the `#N` and renders `[Pasted text +46 lines]`
47
+ * (Issue #1469 condition 2). Used ONLY as a positive "still in the input box"
48
+ * signal — never as the sole submit gate — so applying it to every tool is safe:
49
+ * a tool that never renders it simply never matches.
50
+ */
51
+ const PASTE_PLACEHOLDER_PATTERN = /\[Pasted text[\s#]/;
52
+ /**
53
+ * Prompt input-line markers across the supported TUIs.
54
+ * claude/gemini/copilot: `>` or `❯`; codex: `›`; antigravity: `>`;
55
+ * vibe-local: `ctx:N% ❯`. Leading whitespace is tolerated (tmux padding).
56
+ */
57
+ const INPUT_LINE_MARKER = /^\s*(?:ctx:\d+%\s*)?[>❯›]/;
58
+ /** Lines of pane tail to inspect when verifying submit. */
59
+ const VERIFY_WINDOW_LINES = 12;
60
+ /** Default bounded read-back attempts before giving up (throwing). */
61
+ const DEFAULT_VERIFY_ATTEMPTS = 4;
62
+ /** Minimum fragment length used to decide the body is still on the input line. */
63
+ const MIN_FRAGMENT_LENGTH = 3;
64
+ const MAX_FRAGMENT_LENGTH = 24;
65
+ /**
66
+ * First non-blank fragment of the message, used to decide whether the body is
67
+ * still sitting on the input line. Only the first line matters because that is
68
+ * what a TUI shows on the prompt line before folding into a paste placeholder.
69
+ */
70
+ function comparableFragment(message) {
71
+ const firstLine = message
72
+ .split('\n')
73
+ .map((l) => l.trim())
74
+ .find((l) => l.length > 0);
75
+ if (!firstLine)
76
+ return '';
77
+ return firstLine.slice(0, MAX_FRAGMENT_LENGTH);
78
+ }
79
+ /**
80
+ * Locate the active input line within the pane tail: the last line that begins
81
+ * with a prompt marker. Scanned bottom-up so a status-bar/footer line rendered
82
+ * BELOW the input box (antigravity's "? for shortcuts", vibe-local's status bar)
83
+ * does not hide the real input line above it.
84
+ */
85
+ function findInputLine(windowLines) {
86
+ for (let i = windowLines.length - 1; i >= 0; i--) {
87
+ if (INPUT_LINE_MARKER.test(windowLines[i])) {
88
+ return windowLines[i];
89
+ }
90
+ }
91
+ return null;
92
+ }
93
+ /**
94
+ * Decide whether a captured pane shows the message as submitted.
95
+ *
96
+ * Version-independent by design — does NOT require the paste placeholder:
97
+ * A. The tool is generating a response -> submitted.
98
+ * B. A paste placeholder is on the input line -> NOT submitted (Enter eaten).
99
+ * C. The body fragment is still on the input line -> NOT submitted.
100
+ * D. Otherwise (empty input line / moved to history) -> submitted.
101
+ *
102
+ * B and C are scoped to the input line only, so the user-message echo that a
103
+ * TUI prints into its history above the prompt never causes a false "pending".
104
+ */
105
+ function isSubmitted(output, cliToolId, message) {
106
+ const clean = (0, cli_patterns_1.stripAnsi)(output);
107
+ const windowLines = clean.split('\n').slice(-VERIFY_WINDOW_LINES);
108
+ const windowStr = windowLines.join('\n');
109
+ // A. Actively generating a response => the message was accepted.
110
+ if ((0, cli_patterns_1.detectThinking)(cliToolId, windowStr)) {
111
+ return true;
112
+ }
113
+ const inputLine = findInputLine(windowLines);
114
+ if (inputLine) {
115
+ // B. A paste placeholder is still folded on the input line => not submitted.
116
+ if (PASTE_PLACEHOLDER_PATTERN.test(inputLine)) {
117
+ return false;
118
+ }
119
+ // C. The typed body is still sitting on the input line => not submitted.
120
+ const fragment = comparableFragment(message);
121
+ if (fragment.length >= MIN_FRAGMENT_LENGTH && inputLine.includes(fragment)) {
122
+ return false;
123
+ }
124
+ }
125
+ // D. Input line is clear (or absent) and nothing is generating => submitted.
126
+ return true;
127
+ }
128
+ /**
129
+ * Type a message body and submit it, then verify the submit actually happened.
130
+ *
131
+ * The body and Enter are always separate tmux commands (never batched), so the
132
+ * TUI cannot swallow the Enter inside a bracketed-paste buffer. After the
133
+ * initial submit the pane is read back up to `verifyAttempts` times; each time
134
+ * it is still pending an extra Enter is sent. If submit can never be confirmed
135
+ * the function THROWS — callers must surface that as a failure, never as
136
+ * success (Issues #1469/#1470/#1471).
137
+ *
138
+ * @throws Error when submit cannot be confirmed within the bounded attempts.
139
+ */
140
+ async function sendMessageWithSubmitVerification(params) {
141
+ const { sessionName, message, cliToolId, textInputWaitMs = cli_tool_timing_config_1.TUI_TEXT_INPUT_WAIT_MS, submitEnterCount = 1, interEnterWaitMs = cli_tool_timing_config_1.TUI_TEXT_INPUT_WAIT_MS, verifyAttempts = DEFAULT_VERIFY_ATTEMPTS, verifyDelayMs = cli_tool_timing_config_1.TUI_MESSAGE_PROCESSED_WAIT_MS, } = params;
142
+ // 1. Type the body only — never send Enter in the same tmux command.
143
+ await (0, tmux_1.sendKeys)(sessionName, message, false);
144
+ // 2. Let the TUI register the input before pressing Enter.
145
+ await new Promise((resolve) => setTimeout(resolve, textInputWaitMs));
146
+ // 3. Submit as a separate command (double Enter for vibe-local's IME mode).
147
+ for (let i = 0; i < Math.max(1, submitEnterCount); i++) {
148
+ await (0, tmux_1.sendSpecialKeys)(sessionName, ['Enter']);
149
+ if (i < submitEnterCount - 1) {
150
+ await new Promise((resolve) => setTimeout(resolve, interEnterWaitMs));
151
+ }
152
+ }
153
+ // 4. Read-back verification: confirm the message left the input box, resend
154
+ // Enter while it is still pending, and throw if it never submits.
155
+ const attempts = Math.max(1, verifyAttempts);
156
+ for (let attempt = 0; attempt < attempts; attempt++) {
157
+ await new Promise((resolve) => setTimeout(resolve, verifyDelayMs));
158
+ const output = await (0, tmux_1.capturePane)(sessionName, { startLine: -VERIFY_WINDOW_LINES });
159
+ if (isSubmitted(output, cliToolId, message)) {
160
+ (0, tmux_capture_cache_1.invalidateCache)(sessionName);
161
+ return;
162
+ }
163
+ // Still typed-but-unsent — resend a single Enter and re-check.
164
+ logger.warn('submit-not-confirmed:resending-enter', {
165
+ sessionName,
166
+ cliToolId,
167
+ attempt,
168
+ });
169
+ await (0, tmux_1.sendSpecialKeys)(sessionName, ['Enter']);
170
+ }
171
+ (0, tmux_capture_cache_1.invalidateCache)(sessionName);
172
+ logger.error('submit-verification-failed', { sessionName, cliToolId, attempts });
173
+ throw new Error(`Message submit could not be confirmed for session ${sessionName} after ${attempts} attempts (typed but unsent)`);
174
+ }
@@ -13,7 +13,7 @@ exports.VibeLocalTool = void 0;
13
13
  const base_1 = require("./base");
14
14
  const types_1 = require("./types");
15
15
  const tmux_1 = require("../tmux/tmux");
16
- const pasted_text_helper_1 = require("../pasted-text-helper");
16
+ const submit_verified_sender_1 = require("./submit-verified-sender");
17
17
  const tmux_capture_cache_1 = require("../tmux/tmux-capture-cache");
18
18
  const db_instance_1 = require("../db/db-instance");
19
19
  const db_1 = require("../db");
@@ -121,22 +121,17 @@ class VibeLocalTool extends base_1.BaseCLITool {
121
121
  throw new Error(`Vibe Local session ${sessionName} does not exist. Start the session first.`);
122
122
  }
123
123
  try {
124
- // Send message to vibe-local (without Enter)
125
- await (0, tmux_1.sendKeys)(sessionName, message, false);
126
- // Wait a moment for the text to be typed
127
- await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_TEXT_INPUT_WAIT_MS));
128
- // vibe-local uses IME mode: first Enter creates a new line,
129
- // second Enter on empty line submits the message.
130
- // Send Enter twice with a short delay between.
131
- await (0, tmux_1.sendSpecialKey)(sessionName, 'C-m');
132
- await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.VIBE_LOCAL_DOUBLE_ENTER_WAIT_MS));
133
- await (0, tmux_1.sendSpecialKey)(sessionName, 'C-m');
134
- // Wait a moment for the message to be processed
135
- await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_MESSAGE_PROCESSED_WAIT_MS));
136
- // Detect [Pasted text] and resend Enter for multi-line messages
137
- if (message.includes('\n')) {
138
- await (0, pasted_text_helper_1.detectAndResendIfPastedText)(sessionName);
139
- }
124
+ // Issue #1471: Body/Enter separation + read-back submit verification via the
125
+ // shared helper. vibe-local's IME mode needs TWO Enter presses (first Enter
126
+ // inserts a newline, the second submits), preserved via submitEnterCount: 2
127
+ // + the same inter-press wait (VIBE_LOCAL_DOUBLE_ENTER_WAIT_MS).
128
+ await (0, submit_verified_sender_1.sendMessageWithSubmitVerification)({
129
+ sessionName,
130
+ message,
131
+ cliToolId: 'vibe-local',
132
+ submitEnterCount: 2,
133
+ interEnterWaitMs: cli_tool_timing_config_1.VIBE_LOCAL_DOUBLE_ENTER_WAIT_MS,
134
+ });
140
135
  // Issue #405: Invalidate cache after sending message
141
136
  (0, tmux_capture_cache_1.invalidateCache)(sessionName);
142
137
  logger.info('sent-message-to-vibe-local-session:sessi');
@@ -15,7 +15,7 @@ exports.sendMessageToSession = sendMessageToSession;
15
15
  exports.stopSession = stopSession;
16
16
  const tmux_1 = require("./tmux/tmux");
17
17
  const cli_patterns_1 = require("./detection/cli-patterns");
18
- const pasted_text_helper_1 = require("./pasted-text-helper");
18
+ const submit_verified_sender_1 = require("./cli-tools/submit-verified-sender");
19
19
  const tmux_capture_cache_1 = require("./tmux/tmux-capture-cache");
20
20
  const errors_1 = require("./errors");
21
21
  const cli_tool_timing_config_1 = require("../config/cli-tool-timing-config");
@@ -112,14 +112,16 @@ async function sendMessageToSession(sessionName, message, postPromptDelay, promp
112
112
  }
113
113
  // Stability delay after prompt detection
114
114
  await new Promise((resolve) => setTimeout(resolve, postPromptDelay));
115
- // Send message using sendKeys consistently (CONS-001)
116
- await (0, tmux_1.sendKeys)(sessionName, message, false);
117
- await (0, tmux_1.sendKeys)(sessionName, '', true);
118
- // Issue #212: Detect [Pasted text] and resend Enter for multi-line messages
119
- // MF-001: Single-line messages skip detection (+0ms overhead)
120
- if (message.includes('\n')) {
121
- await (0, pasted_text_helper_1.detectAndResendIfPastedText)(sessionName);
122
- }
115
+ // Issue #1469: Body and Enter are sent as SEPARATE tmux commands (never a
116
+ // single body+C-m batch) and the submit is read-back verified. This replaces
117
+ // the old fire-and-forget `sendKeys(message,false)` + `sendKeys('',true)` that
118
+ // let Claude's ink TUI swallow the trailing C-m as a bracketed-paste newline,
119
+ // leaving the message typed but unsent. Throws if submit cannot be confirmed.
120
+ await (0, submit_verified_sender_1.sendMessageWithSubmitVerification)({
121
+ sessionName,
122
+ message,
123
+ cliToolId: 'claude',
124
+ });
123
125
  // Issue #405: Invalidate cache after sending message
124
126
  (0, tmux_capture_cache_1.invalidateCache)(sessionName);
125
127
  logger.info('sent-message-to-session', { sessionName });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commandmate",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "A local control plane for agent CLIs — orchestration and visibility for Claude Code, Codex, Gemini CLI, and more across Git worktrees",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -1 +0,0 @@
1
- "use strict";exports.id=5312,exports.ids=[5312],exports.modules={45312:(a,b,c)=>{c.d(b,{nX:()=>J,z0:()=>w,lY:()=>K,SN:()=>L,Pt:()=>y,ID:()=>k,Wz:()=>A,NM:()=>t,ac:()=>u,$G:()=>j,t$:()=>o,mk:()=>O,Lz:()=>B,om:()=>E,FW:()=>Y,C4:()=>Z,Z3:()=>$,S7:()=>V,lw:()=>W,x7:()=>d.x7,jr:()=>G,Iz:()=>C,Ey:()=>R,X_:()=>S,VM:()=>Q,oC:()=>P,X0:()=>D});var d=c(63271),e=c(46065);let f=Symbol("default-branch-unresolved");async function g(a){let b=await (0,e.Bc)(["symbolic-ref","refs/remotes/origin/HEAD","--short"],a);if(null===b)return f;let c=b.trim();return c.startsWith("origin/")?c.slice(7):null}async function h(a){let b=await g(a);return"string"==typeof b?b:null}var i=c(65417);async function j(a,b){let c,[d,f,g]=await Promise.all([(0,e.Bc)(["rev-parse","--abbrev-ref","HEAD"],a),(0,e.Bc)(["rev-parse","--short","HEAD"],a),(0,e.Bc)(["status","--porcelain"],a)]);return c=null===d?"(unknown)":"HEAD"===d?"(detached HEAD)":d,{currentBranch:c,initialBranch:b,isBranchMismatch:null!==b&&"(unknown)"!==c&&"(detached HEAD)"!==c&&c!==b,commitHash:f??"(unknown)",isDirty:null!==g&&g.length>0}}async function k(a){let b=await (0,e.Bc)(["rev-list","--left-right","--count","@{upstream}...HEAD"],a);if(null===b)return null;let c=b.split(" ");if(2!==c.length)return null;let d=parseInt(c[0],10),f=parseInt(c[1],10);return Number.isInteger(d)&&Number.isInteger(f)?{ahead:f,behind:d}:null}function l(a){switch(a){case"A":return"added";case"D":return"deleted";case"R":case"C":return"renamed";default:return"modified"}}let m=new Set(["DD","AU","UD","UA","DU","AA","UU"]);function n(a){let b=a.indexOf(" -> ");return -1!==b?a.slice(b+4):a}async function o(a){return function(a){let b=[],c=[],d=[];if(!a)return{staged:b,unstaged:c,untracked:d};for(let e of a.split("\n")){if(e.length<4)continue;let a=e[0],f=e[1],g=e.slice(3);if(!g)continue;if("?"===a&&"?"===f){d.push({path:n(g),status:"untracked"});continue}let h=n(g);if("U"===a||"U"===f||m.has(`${a}${f}`)){c.push({path:h,status:"unmerged"});continue}" "!==a&&"?"!==a&&b.push({path:h,status:l(a)})," "!==f&&"?"!==f&&c.push({path:h,status:l(f)})}return{staged:b,unstaged:c,untracked:d}}(await (0,e.rS)(["status","--porcelain"],a,i.Ev))}var p=c(29021),q=c.n(p),r=c(72626);let s=(0,r.h)("git-log");async function t(a,b=50,c=0){let d=(await (0,e.rS)(["log",`--max-count=${b}`,`--skip=${c}`,"--format=%H%n%h%n%s%n%an%n%aI","--"],a,e.t1)).trim();if(!d)return[];let f=d.split("\n"),g=[];for(let a=0;a+4<f.length;a+=5)g.push({hash:f[a],shortHash:f[a+1],message:f[a+2],author:f[a+3],date:f[a+4]});return g}async function u(a,b){try{let c=(await (0,e.rS)(["log","-1","--format=%H%n%h%n%s%n%an%n%aI",b,"--"],a,e.t1)).trim().split("\n");if(c.length<5)return null;let d={hash:c[0],shortHash:c[1],message:c[2],author:c[3],date:c[4]},f=await (0,e.rS)(["diff-tree","--no-commit-id","-r","--name-status",b,"--"],a,e.t1),g=function(a){let b=[];for(let c of a.trim().split("\n")){if(!c.trim())continue;let a=c.split(" ");if(a.length<2)continue;let d=a[0].trim(),e=a[a.length-1].trim();d.startsWith("R")?b.push({path:e,status:"renamed"}):"A"===d?b.push({path:e,status:"added"}):"D"===d?b.push({path:e,status:"deleted"}):b.push({path:e,status:"modified"})}return b}(f);return{commit:d,files:g}}catch(b){if(b instanceof d.y0||b instanceof d.wo)throw b;let a=b instanceof Error?b.message:"";if(a.includes("unknown revision")||a.includes("bad object"))return null;throw b}}async function v(a,b,c){if(!q().existsSync(a))return[];try{let{stdout:d}=await (0,e.mf)("git",["log","--all",`--since=${b}`,`--until=${c}`,`--format=%h\x1f%s\x1f%an`,"--"],{cwd:a,timeout:5e3}),f=d.trim();if(!f)return[];let g=[];for(let a of f.split("\n")){let b=a.split("\x1f");3===b.length&&g.push({shortHash:b[0],message:b[1],author:b[2]})}return g}catch(b){return s.error("git:commit-log-failed",{repoPath:a,error:b instanceof Error?b.message:"Unknown error"}),[]}}async function w(a,b,c){let d=await Promise.allSettled(a.map(async a=>({id:a.id,name:a.name,commits:await v(a.path,b,c)}))),e=new Map;for(let a of d)"fulfilled"===a.status&&a.value.commits.length>0&&e.set(a.value.id,{name:a.value.name,commits:a.value.commits});return e}let x=/(?:(?:closes|fixes|resolves)\s+)?#(\d+)/gi;function y(a){let b=new Set;for(let c of a){let a;for(x.lastIndex=0;null!==(a=x.exec(c));)b.add(parseInt(a[1],10))}return Array.from(b).sort((a,b)=>a-b)}let z=(0,r.h)("git-diff");async function A(a,b,c){try{return(await (0,e.rS)(["show",b,"--",c],a,e.t1)).trim()||null}catch(a){if(a instanceof d.y0||a instanceof d.wo)throw a;return null}}async function B(a,b,c){let f=function(a,b){switch(b){case"staged":return["diff","--cached","--",a];case"untracked":return["diff","--no-index","--","/dev/null",a];default:return["diff","--",a]}}(b,c);try{let{stdout:b}=await (0,e.mf)("git",f,{cwd:a,timeout:e.t1});return b.trim()||null}catch(a){if(a.killed||"ERR_CHILD_PROCESS_EXEC_TIMEOUT"===a.code||"ETIMEDOUT"===a.code)throw new d.y0(`Git command timed out after ${e.t1}ms`);if((a.stderr||a.message||"").includes("not a git repository"))throw new d.wo("Not a git repository");if("string"==typeof a.stdout)return a.stdout.trim()||null;throw z.error("git:working-diff-failed",{args:f.join(" "),error:a.message}),Error("Failed to execute git command")}}async function C(a,b){await (0,e.dX)(a,async()=>{await (0,e.rS)(["add","--",...b],a,i.Ev)})}async function D(a,b){await (0,e.dX)(a,async()=>{await (0,e.rS)(["restore","--staged","--",...b],a,i.Ev)})}async function E(a,b,c){await (0,e.dX)(a,async()=>{let f=["commit","-m",b];c&&f.push("--amend"),f.push("--");try{await (0,e.rS)(f,a,i.Ev)}catch(b){let a=b instanceof Error?b.message:"";if(/nothing to commit|no changes added to commit|nothing added to commit/i.test(a))throw new d.mZ("Nothing to commit");throw b}})}function F(a){let b=new Map;if(!a)return b;let c=null;for(let d of a.split("\n")){let a=d.trimEnd();if(a.startsWith("worktree "))c=a.slice(9).trim();else if(a.startsWith("branch ")&&c){let d=a.slice(7).trim(),e=d.startsWith("refs/heads/")?d.slice(11):d;e&&b.set(e,c)}else""===a&&(c=null)}return b}async function G(a,b="local"){let c="local"===b||"all"===b,d="remote"===b||"all"===b,[f,g,h,i,j]=await Promise.all([c?(0,e.Bc)(["branch","--list"],a):Promise.resolve(""),d?(0,e.Bc)(["branch","-r"],a):Promise.resolve(""),(0,e.Bc)(["symbolic-ref","refs/remotes/origin/HEAD","--short"],a),(0,e.Bc)(["worktree","list","--porcelain"],a),(0,e.Bc)(["for-each-ref","--format=%(refname:short)%09%(upstream:short)%09%(upstream:track)","refs/heads"],a)]),k=h?h.trim():null,l=F(i??""),m=function(a){let b=new Map;if(!a)return b;for(let c of a.split("\n")){if(!c.trim())continue;let[a,d="",e=""]=c.split(" ");if(!a)continue;let f=d.trim()||null,g=null;if(f){let a=e.match(/ahead (\d+)/),b=e.match(/behind (\d+)/);a||b?g={ahead:a?parseInt(a[1],10):0,behind:b?parseInt(b[1],10):0}:/gone/.test(e)||(g={ahead:0,behind:0})}b.set(a,{upstream:f,aheadBehind:g})}return b}(j??""),n=[];if(c)for(let{name:a,isCurrent:b}of function(a){let b=[];if(!a)return b;for(let c of a.split("\n")){let a=c.trimEnd();if(!a.trim())continue;let d=a.startsWith("* "),e=a.replace(/^[*+]?\s+/,"").trim();!e||e.startsWith("(")||b.push({name:e,isCurrent:d})}return b}(f??"")){let c=m.get(a);n.push({name:a,isCurrent:b,isRemote:!1,isDefault:null!==k&&k===`origin/${a}`,upstream:c?.upstream??null,aheadBehind:c?.aheadBehind??null,checkedOutWorktreePath:l.get(a)??null})}if(d)for(let a of function(a){let b=[];if(!a)return b;for(let c of a.split("\n")){let a=c.trim();a&&(a.includes("->")||b.push(a))}return b}(g??""))n.push({name:a,isCurrent:!1,isRemote:!0,isDefault:null!==k&&k===a,upstream:null,aheadBehind:null,checkedOutWorktreePath:null});return n}async function H(a,b){let c=await (0,e.Bc)(["worktree","list","--porcelain"],a);if(null===c)return null;let d=F(c).get(b);return d&&d!==a?d:null}function I(a){if(a instanceof d.y0||a instanceof d.wo||a instanceof d.rI)throw a;let b=a instanceof Error?a.message:String(a),c=a?.stderr??"",e=`${c} ${b}`;if(/did not match|not a valid ref|not found|unknown revision|invalid reference|couldn't find remote ref/i.test(e))throw new d.ur("Branch not found");throw a}async function J(a,b){let{branch:c,createIfMissing:f=!1,from:g,force:h=!1}=b,j=await H(a,c);if(j)throw new d.oK("Branch is checked out in another worktree",j);if(!h){let b=await (0,e.Bc)(["status","--porcelain"],a);if(null!==b&&b.length>0)throw new d.d_("Working tree has uncommitted changes")}await (0,e.dX)(a,async()=>{let b;f?(b=["switch","-c",c],g&&b.push(g),b.push("--")):b=c.startsWith("origin/")?["switch","-c",c.slice(7),"--track",c,"--"]:h?["checkout","-f",c,"--"]:["switch",c,"--"];try{await (0,e.rS)(b,a,i.Ev)}catch(a){I(a)}})}async function K(a,b){let{name:c,from:d}=b;await (0,e.dX)(a,async()=>{let b=["branch",c];d&&b.push(d),b.push("--");try{await (0,e.rS)(b,a,i.Ev)}catch(a){I(a)}})}async function L(a,b){let{name:c,force:f=!1}=b,g=await (0,e.Bc)(["rev-parse","--abbrev-ref","HEAD"],a);if(null!==g&&g.trim()===c)throw new d.MC("Cannot delete the current branch");let j=await h(a);if(null!==j&&j===c)throw new d.qb("Cannot delete the default branch");await (0,e.dX)(a,async()=>{try{await (0,e.rS)(["branch",f?"-D":"-d",c,"--"],a,i.Ev)}catch(e){let a=e instanceof Error?e.message:String(e),b=e?.stderr??"",c=`${b} ${a}`;if(/not fully merged/i.test(c))throw new d.A6("Branch is not fully merged");I(e)}})}let M=(0,r.h)("git-stash"),N=/^stash@\{(\d+)\}$/;async function O(a){let b=await (0,e.Bc)(["stash","list","--format=%gd%x09%s%x09%cI%x09%H"],a);if(null===b)return[];let c=[];if(!b||!b.trim())return c;for(let a of b.split("\n")){if(!a.trim())continue;let[b="",d="",e="",f=""]=a.split(" "),g=b.match(N);g&&c.push({index:parseInt(g[1],10),message:d,branch:function(a){let b=a.match(/^WIP on ([^:]+):/);if(b)return b[1].trim()||null;let c=a.match(/^On ([^:]+):/);return c&&c[1].trim()||null}(d),date:e,sha:f})}return c}async function P(a,b){let{message:c,includeUntracked:f}=b;await (0,e.dX)(a,async()=>{let b=["stash","push"];f&&b.push("--include-untracked"),c&&b.push("-m",c),b.push("--");try{await (0,e.rS)(b,a,i.Ev)}catch(c){let a=c instanceof Error?c.message:"",b=c?.stderr??"";if(/No local changes to save|No stash entries|No local changes/i.test(`${b} ${a}`))throw new d.s$("No local changes to stash");throw c}})}async function Q(a,b){return(0,e.dX)(a,async()=>{let c=await (0,e.mY)(["stash","pop","--",`stash@{${b}}`],a);return c.conflict?{...c,stashRetained:!0}:c})}async function R(a,b){return(0,e.dX)(a,async()=>(0,e.mY)(["stash","apply","--",`stash@{${b}}`],a))}async function S(a,b){M.warn("git:danger:stash-drop",{operation:"stash-drop",worktreePath:a,index:b,timestamp:new Date().toISOString()}),await (0,e.dX)(a,async()=>{await (0,e.rS)(["stash","drop","--",`stash@{${b}}`],a,i.Ev)})}let T=(0,r.h)("git-reset");async function U(a){let b=await (0,e.Bc)(["rev-parse","--abbrev-ref","HEAD"],a);if(null===b)return!1;let c=b.trim(),d=await g(a);return"string"==typeof d?d===c:null!==d&&("main"===c||"master"===c)}async function V(a,b){let{target:c,mode:f}=b;if("hard"===f){if(await U(a))throw T.warn("git:danger:hard-reset-blocked",{operation:"reset",worktreePath:a,target:c,mode:f,timestamp:new Date().toISOString()}),new d.BN("Cannot hard-reset the default branch");T.warn("git:danger:hard-reset",{operation:"reset",worktreePath:a,target:c,mode:f,timestamp:new Date().toISOString()})}await (0,e.dX)(a,async()=>{await (0,e.rS)(["reset",`--${f}`,c,"--"],a,i.Ev)})}async function W(a,b){let{commitHash:c,noCommit:d}=b;return T.warn("git:danger:revert",{operation:"revert",worktreePath:a,commitHash:c,noCommit:!0===d,timestamp:new Date().toISOString()}),(0,e.dX)(a,async()=>{let b=["revert"];return d&&b.push("--no-commit"),b.push(c,"--"),(0,e.mY)(b,a)})}let X=(0,r.h)("git-remote");async function Y(a,b){let{remote:c="origin",prune:d}=b,f=["fetch"];d&&f.push("--prune"),f.push(c,"--"),await (0,e.sl)(f,a,i.dw)}async function Z(a,b){let{remote:c="origin",branch:d,rebase:f,ffOnly:g}=b;return(0,e.dX)(a,async()=>{let b=["pull"];return f&&b.push("--rebase"),g&&b.push("--ff-only"),b.push(c),d&&b.push(d),b.push("--"),(0,e.mY)(b,a,i.A$,!0)})}async function $(a,b){let{remote:c="origin",branch:f,force:g,forceWithLease:j,setUpstream:k}=b;if(g||j){let b=await h(a);if(null!==b&&b===f)throw new d.rm;X.warn("git:danger:force-push",{operation:"push",worktreePath:a,branch:f,forceWithLease:!0===j,timestamp:new Date().toISOString()})}await (0,e.dX)(a,async()=>{let b=["push"];j?b.push("--force-with-lease"):g&&b.push("--force"),k&&b.push("-u"),b.push(c,`${f}:refs/heads/${f}`,"--"),await (0,e.sl)(b,a,i.fL)})}}};
@@ -1 +0,0 @@
1
- "use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1668],{34380:(e,s,l)=>{l.d(s,{B:()=>A});var t=l(95155),n=l(12115),a=l(18955),r=l(744),i=l(54014),d=l(37381);function o(e){var s,l,t,n,a;let r=e.agentInstances&&e.agentInstances.length>0?e.agentInstances.map(e=>e.alias||e.cliTool):null!=(l=e.selectedAgents)?l:e.cliToolId?[e.cliToolId]:[];return{id:e.id,name:e.name,repositoryName:null!=(t=e.repositoryDisplayName)?t:e.repositoryName,syncedBranch:null!=(n=e.branch)?n:null,liveBranch:null!=(a=null==(s=e.gitStatus)?void 0:s.currentBranch)?a:null,dirty:e.gitStatus?e.gitStatus.isDirty:null,agents:[...new Set(r)],sessionRunning:!0===e.isSessionRunning}}let c={status:"loading",options:[]};async function u(e){let s=await fetch("/api/worktrees",{signal:e,headers:{Accept:"application/json"}});if(!s.ok)throw Error("HTTP ".concat(s.status));let l=await s.json(),t=null==l?void 0:l.worktrees;if(!Array.isArray(t))throw Error("Malformed worktree list");return t.map(o)}function x(e){let{selectedWorktreeId:s,onSelect:l,disabled:i=!1}=e,o=(0,a.c)("skills"),[x,p]=(0,n.useState)(c),[g,h]=(0,n.useState)(0);(0,n.useEffect)(()=>{let e=new AbortController;return p(c),u(e.signal).then(s=>{e.signal.aborted||p({status:"loaded",options:s})}).catch(()=>{e.signal.aborted||p({status:"error",options:[]})}),()=>e.abort()},[g]);let k=(0,n.useCallback)(()=>h(e=>e+1),[]);return"loading"===x.status?(0,t.jsxs)("div",{className:"space-y-2","data-testid":"skill-target-loading",children:[(0,t.jsx)("p",{className:"text-sm text-muted-foreground",children:o("target.loading")}),(0,t.jsx)(r.EA,{className:"h-24 w-full rounded-lg"})]}):"error"===x.status?(0,t.jsxs)(r.Zp,{className:"space-y-3","data-testid":"skill-target-error",children:[(0,t.jsx)(d.u,{tone:"danger",children:o("target.errorNotice")}),(0,t.jsx)(r.$n,{variant:"secondary",size:"sm",onClick:k,"data-testid":"skill-target-retry",children:o("target.retry")})]}):0===x.options.length?(0,t.jsx)(r.Zp,{"data-testid":"skill-target-empty",children:(0,t.jsx)("p",{className:"text-sm text-muted-foreground",children:o("target.empty")})}):(0,t.jsxs)("div",{className:"space-y-3","data-testid":"skill-target-selector",children:[(0,t.jsx)("div",{role:"radiogroup","aria-label":o("target.heading"),className:"space-y-2",children:x.options.map(e=>(0,t.jsx)(m,{option:e,selected:e.id===s,disabled:i,onSelect:l},e.id))}),(0,t.jsx)(d.u,{tone:"neutral","data-testid":"skill-target-branch-notice",children:o("target.branchFreshnessNotice")})]})}function m(e){var s;let{option:l,selected:n,disabled:i,onSelect:d}=e,o=(0,a.c)("skills"),c=null!=(s=l.liveBranch)?s:l.syncedBranch;return(0,t.jsxs)("button",{type:"button",role:"radio","aria-checked":n,disabled:i,onClick:()=>d(l.id),"data-testid":"skill-target-option-".concat(l.id),className:"w-full rounded-lg border px-3 py-2.5 text-left transition-colors disabled:cursor-not-allowed disabled:opacity-60 ".concat(n?"border-accent-500 bg-accent-50 dark:bg-accent-950/40":"border-border bg-card hover:bg-muted"),children:[(0,t.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,t.jsx)("span",{className:"text-sm font-semibold text-foreground break-all",children:l.name}),n&&(0,t.jsx)(r.Ex,{variant:"info",children:o("target.selected")})]}),(0,t.jsxs)("dl",{className:"mt-1.5 grid grid-cols-1 gap-x-4 gap-y-1 sm:grid-cols-2",children:[(0,t.jsx)(p,{label:o("target.repository"),children:l.repositoryName}),(0,t.jsx)(p,{label:o("target.branch"),children:null!=c?c:o("target.branchUnknown")}),(0,t.jsx)(p,{label:o("target.agents"),children:l.agents.length>0?l.agents.join(", "):o("target.agentsNone")}),(0,t.jsx)(p,{label:o("target.workingTree"),children:o(null===l.dirty?"target.workingTreeUnknown":l.dirty?"target.workingTreeDirty":"target.workingTreeClean")})]}),l.sessionRunning&&(0,t.jsx)("p",{className:"mt-1.5 text-xs text-muted-foreground","data-testid":"skill-target-session-".concat(l.id),children:o("target.sessionRunning")})]})}function p(e){let{label:s,children:l}=e;return(0,t.jsxs)("div",{className:"min-w-0",children:[(0,t.jsx)("dt",{className:"text-xs font-medium text-muted-foreground",children:s}),(0,t.jsx)("dd",{className:"text-xs text-foreground break-words",children:l})]})}var g=l(95584);function h(e){let{label:s,children:l}=e;return(0,t.jsxs)("div",{className:"min-w-0",children:[(0,t.jsx)("dt",{className:"text-xs font-medium text-muted-foreground",children:s}),(0,t.jsx)("dd",{className:"mt-0.5 break-words text-sm text-foreground",children:l})]})}function k(e){let{level:s,kind:l,label:n}=e,i=(0,a.c)("skills");return(0,t.jsxs)(r.Ex,{variant:g.eK[s],"data-testid":"skill-plan-risk-".concat(l,"-").concat(s),children:[n,": ",i(g.pP[s])]})}function f(e){let{entry:s}=e,l=(0,a.c)("skills"),n=g.KL[s.reason];return(0,t.jsxs)("li",{className:"space-y-1.5 rounded-md border border-border px-3 py-2","data-testid":"skill-plan-file-".concat(s.path),children:[(0,t.jsxs)("div",{className:"flex flex-wrap items-center gap-2",children:[(0,t.jsx)(r.Ex,{variant:g.tC[s.change],children:l(g.AS[s.change])}),(0,t.jsx)("span",{className:"break-all font-mono text-xs text-foreground",children:s.path}),s.generated&&(0,t.jsx)(r.Ex,{variant:"gray",children:l("plan.fileGenerated")})]}),n&&(0,t.jsx)("p",{className:"text-xs text-muted-foreground",children:l(n)}),s.gitIgnored&&(0,t.jsx)("p",{className:"text-xs text-warning-foreground",children:l("plan.gitIgnored")}),s.binary?(0,t.jsx)("p",{className:"text-xs text-muted-foreground",children:l("plan.diffBinary")}):s.diff?(0,t.jsxs)("details",{children:[(0,t.jsx)("summary",{className:"cursor-pointer text-xs text-accent-600 dark:text-accent-400",children:l("plan.diffToggle",{additions:s.additions,deletions:s.deletions})}),(0,t.jsx)("pre",{className:"mt-1 overflow-x-auto rounded bg-muted p-2 font-mono text-[11px] leading-snug text-foreground",children:s.diff}),s.diffTruncated&&(0,t.jsx)("p",{className:"mt-1 text-xs text-muted-foreground",children:l("plan.diffTruncated")})]}):null]})}function j(e){var s,l,n;let{plan:i}=e,o=(0,a.c)("skills"),{target:c,skill:u}=i,x=u.compatibility.commandmate;return(0,t.jsxs)(r.Zp,{className:"space-y-4","data-testid":"skill-install-plan",children:[(0,t.jsxs)("div",{className:"space-y-1",children:[(0,t.jsx)("h3",{className:"text-sm font-semibold text-foreground",children:o("plan.heading")}),(0,t.jsx)("p",{className:"text-xs text-muted-foreground",children:o("plan.expiresAt",{timestamp:i.expiresAt})})]}),(0,t.jsxs)("section",{className:"space-y-2",children:[(0,t.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:o("plan.targetHeading")}),(0,t.jsxs)("dl",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[(0,t.jsx)(h,{label:o("target.repository"),children:c.repositoryName}),(0,t.jsx)(h,{label:o("target.heading"),children:c.worktreeName}),(0,t.jsx)(h,{label:o("target.branch"),children:null!=(s=c.branch)?s:o("target.branchUnknown")}),(0,t.jsx)(h,{label:o("plan.headStateLabel"),children:o(null!=(l=g.kF[c.headState])?l:"plan.headState.unknown")}),(0,t.jsx)(h,{label:o("target.workingTree"),children:c.workingTreeDirty?o("target.workingTreeDirty"):o("target.workingTreeClean")}),(0,t.jsx)(h,{label:o("plan.installRoot"),children:(0,t.jsx)("span",{className:"break-all font-mono text-xs",children:(c.installRoots&&c.installRoots.length>0?c.installRoots:[c.installRoot]).map(e=>(0,t.jsx)("span",{className:"block",children:e},e))})}),(0,t.jsx)(h,{label:o("plan.existingInstall"),children:c.existingInstall?o("plan.existingInstallVersion",{version:c.existingInstall.version}):o("plan.existingInstallNone")}),(0,t.jsx)(h,{label:o("detail.recommendedVersion"),children:(0,t.jsx)("span",{className:"font-mono text-xs",children:u.version})})]})]}),(0,t.jsxs)("section",{className:"space-y-2","data-testid":"skill-plan-risk-section",children:[(0,t.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:o("plan.riskHeading")}),(0,t.jsxs)("div",{className:"flex flex-wrap gap-1.5",children:[(0,t.jsx)(k,{level:u.declaredRisk,kind:"declared",label:o("plan.riskDeclared")}),(0,t.jsx)(k,{level:u.computedRisk,kind:"computed",label:o("plan.riskComputed")}),(0,t.jsx)(k,{level:u.effectiveRisk,kind:"effective",label:o("plan.riskEffective")})]}),(0,t.jsx)("p",{className:"break-words text-sm text-foreground",children:u.riskRationale}),(0,t.jsx)(d.u,{tone:"neutral",children:o("plan.riskNotice")})]}),(0,t.jsxs)("section",{className:"space-y-2","data-testid":"skill-plan-permissions",children:[(0,t.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:o("permissions.heading")}),u.declaredPermissions.length>0?(0,t.jsx)("div",{className:"flex flex-wrap gap-1.5",children:u.declaredPermissions.map(e=>(0,t.jsx)(r.Ex,{variant:"warning",children:g.z2[e]?o(g.z2[e]):e},e))}):(0,t.jsx)("p",{className:"text-sm text-muted-foreground",children:o("plan.permissionsNone")}),(0,t.jsx)(d.u,{tone:"warning",children:o("permissions.declarationOnlyNotice")})]}),(0,t.jsxs)("section",{className:"space-y-2","data-testid":"skill-plan-requirements",children:[(0,t.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:o("requirements.heading")}),0===u.requirements.commands.length&&0===u.requirements.networkHosts.length?(0,t.jsx)("p",{className:"text-sm text-muted-foreground",children:o("plan.requirementsNone")}):(0,t.jsxs)("dl",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[u.requirements.commands.length>0&&(0,t.jsx)(h,{label:o("plan.requirementsCommands"),children:u.requirements.commands.map(e=>{var s;return"".concat(e.name," ").concat(null!=(s=e.versionRange)?s:o("plan.commandAnyVersion"))}).join(", ")}),u.requirements.networkHosts.length>0&&(0,t.jsx)(h,{label:o("plan.requirementsHosts"),children:u.requirements.networkHosts.join(", ")})]})]}),(0,t.jsxs)("section",{className:"space-y-2","data-testid":"skill-plan-scripts",children:[(0,t.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:o("plan.scriptsHeading")}),0===u.executablePaths.length&&0===u.scriptPaths.length?(0,t.jsx)("p",{className:"text-sm text-muted-foreground",children:o("plan.scriptsNone")}):(0,t.jsx)("ul",{className:"space-y-1",children:[...new Set([...u.scriptPaths,...u.executablePaths])].map(e=>(0,t.jsx)("li",{className:"break-all font-mono text-xs text-foreground",children:e},e))})]}),"compatible"!==x.status&&(0,t.jsx)(d.u,{tone:"warning","data-testid":"skill-plan-compatibility-notice",children:o((0,g.e5)(x.messageKey),{range:x.requiredRange,currentVersion:null!=(n=x.currentVersion)?n:""})}),i.warnings.length>0&&(0,t.jsxs)("section",{className:"space-y-2","data-testid":"skill-plan-warnings",children:[(0,t.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:o("plan.warningsHeading")}),(0,t.jsx)("ul",{className:"space-y-1",children:i.warnings.map(e=>(0,t.jsx)("li",{className:"text-xs text-warning-foreground",children:g.RO[e]?o(g.RO[e]):e},e))})]}),(0,t.jsxs)("section",{className:"space-y-2","data-testid":"skill-plan-files",children:[(0,t.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:o("plan.filesHeading")}),(0,t.jsx)("p",{className:"text-xs text-muted-foreground","data-testid":"skill-plan-stats",children:o("plan.stats",{added:i.stats.added,modified:i.stats.modified,unchanged:i.stats.unchanged,conflicted:i.stats.conflicted,unmanaged:i.stats.unmanaged})}),0===i.files.length?(0,t.jsx)("p",{className:"text-sm text-muted-foreground",children:o("plan.filesEmpty")}):(0,t.jsx)("ul",{className:"space-y-2",children:i.files.map(e=>(0,t.jsx)(f,{entry:e},e.path))})]}),i.blockers.length>0&&(0,t.jsxs)("section",{className:"space-y-2","data-testid":"skill-install-blockers",children:[(0,t.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wide text-danger-foreground",children:o("plan.blockersHeading")}),(0,t.jsx)("ul",{className:"space-y-1",children:i.blockers.map(e=>{var s,l;return(0,t.jsxs)("li",{className:"text-xs text-danger-foreground",children:[e.path&&(0,t.jsx)("span",{className:"mr-1 break-all font-mono",children:e.path}),e.code.startsWith("skills.")?o((0,g.e5)(e.code),{range:x.requiredRange,currentVersion:null!=(s=x.currentVersion)?s:""}):g.KL[e.code]?o(g.KL[e.code]):e.code]},"".concat(e.code,":").concat(null!=(l=e.path)?l:""))})}),(0,t.jsx)(d.u,{tone:"danger",children:o("plan.blockedNotice")})]})]})}function b(e){let{entry:s}=e,l=(0,a.c)("skills"),n=g.Mj[s.disposition],i=g.hJ[s.reason];return(0,t.jsxs)("li",{className:"flex flex-wrap items-center gap-2","data-testid":"skill-uninstall-file-".concat(s.path),children:[(0,t.jsx)(r.Ex,{variant:"remove"===s.disposition?"info":"warning",children:n?l(n):s.disposition}),(0,t.jsx)("span",{className:"break-all font-mono text-xs text-foreground",children:s.path}),i&&(0,t.jsx)("span",{className:"text-xs text-muted-foreground",children:l(i)})]})}function y(e){var s;let{plan:l}=e,n=(0,a.c)("skills"),{target:o,skill:c}=l;return(0,t.jsxs)(r.Zp,{className:"space-y-4","data-testid":"skill-uninstall-plan",children:[(0,t.jsxs)("div",{className:"space-y-1",children:[(0,t.jsx)("h3",{className:"text-sm font-semibold text-foreground",children:n("uninstall.heading")}),(0,t.jsx)("p",{className:"text-xs text-muted-foreground",children:n("uninstall.expiresAt",{timestamp:l.expiresAt})})]}),(0,t.jsxs)("dl",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[(0,t.jsx)(h,{label:n("target.repository"),children:o.repositoryName}),(0,t.jsx)(h,{label:n("target.heading"),children:o.worktreeName}),(0,t.jsx)(h,{label:n("target.branch"),children:null!=(s=o.branch)?s:n("target.branchUnknown")}),(0,t.jsx)(h,{label:n("uninstall.installedVersion"),children:(0,t.jsx)("span",{className:"font-mono text-xs",children:c.version||n("uninstall.versionUnknown")})}),(0,t.jsx)(h,{label:n("plan.installRoot"),children:(0,t.jsx)("span",{className:"break-all font-mono text-xs",children:o.installRoot})}),(0,t.jsx)(h,{label:n("target.workingTree"),children:o.workingTreeDirty?n("target.workingTreeDirty"):n("target.workingTreeClean")})]}),(0,t.jsx)("p",{className:"text-xs text-muted-foreground","data-testid":"skill-uninstall-stats",children:n("uninstall.stats",{removable:l.stats.removable,modified:l.stats.modified,missing:l.stats.missing,unknown:l.stats.unknown,irregular:l.stats.irregular})}),(0,t.jsxs)("section",{className:"space-y-2",children:[(0,t.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:n("uninstall.removalsHeading")}),0===l.removals.length?(0,t.jsx)("p",{className:"text-sm text-muted-foreground",children:n("uninstall.removalsEmpty")}):(0,t.jsx)("ul",{className:"space-y-1.5",children:l.removals.map(e=>(0,t.jsx)(b,{entry:e},e.path))})]}),(0,t.jsxs)("section",{className:"space-y-2",children:[(0,t.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:n("uninstall.retainedHeading")}),0===l.retained.length?(0,t.jsx)("p",{className:"text-sm text-muted-foreground",children:n("uninstall.retainedEmpty")}):(0,t.jsx)("ul",{className:"space-y-1.5",children:l.retained.map(e=>(0,t.jsx)(b,{entry:e},e.path))})]}),(0,t.jsxs)("div",{className:"space-y-2",children:[l.skill.agents.length>0&&(0,t.jsx)("div",{className:"flex flex-wrap gap-1.5","data-testid":"skill-uninstall-agents",children:l.skill.agents.map(e=>(0,t.jsx)(r.Ex,{variant:"gray",children:(0,i.f_)(e.agent)},e.agent))}),(0,t.jsx)(d.u,{tone:"neutral",children:n((0,g.e5)(l.nextActionKey))})]}),l.blockers.length>0&&(0,t.jsxs)("section",{className:"space-y-2","data-testid":"skill-uninstall-blockers",children:[(0,t.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wide text-danger-foreground",children:n("uninstall.blockersHeading")}),(0,t.jsx)("ul",{className:"space-y-1",children:l.blockers.map(e=>{var s;return(0,t.jsxs)("li",{className:"text-xs text-danger-foreground",children:[e.path&&(0,t.jsx)("span",{className:"mr-1 break-all font-mono",children:e.path}),n((0,g.e5)(e.messageKey))]},"".concat(e.code,":").concat(null!=(s=e.path)?s:""))})})]})]})}var N=l(80130);let w={worktreeId:null,busy:null,installPlan:null,uninstallPlan:null,installResult:null,uninstallResult:null,riskAcknowledged:!1,failure:null};function v(e){return{...e,installPlan:null,uninstallPlan:null,installResult:null,uninstallResult:null,riskAcknowledged:!1,failure:null}}function R(e,s){return"".concat(e,"-").concat(s)}function C(e){let{failure:s}=e,l=(0,a.c)("skills");return(0,t.jsxs)("div",{className:"space-y-2","data-testid":"skill-operation-error",children:[(0,t.jsxs)(d.u,{tone:"danger",children:[(0,t.jsx)("p",{className:"font-medium",children:l("operation.errorHeading")}),(0,t.jsx)("p",{className:"mt-1",children:l((0,g.FW)(s.code))}),(0,t.jsx)("p",{className:"mt-1 break-words",children:l("state.errorCode",{code:s.code})})]}),s.nextActionKey&&(0,t.jsx)(d.u,{tone:"warning",children:l((0,g.e5)(s.nextActionKey))}),s.blockers&&s.blockers.length>0&&(0,t.jsx)("ul",{className:"space-y-1","data-testid":"skill-operation-error-blockers",children:s.blockers.map(e=>{var s;return(0,t.jsxs)("li",{className:"text-xs text-danger-foreground",children:[e.path&&(0,t.jsx)("span",{className:"mr-1 break-all font-mono",children:e.path}),l((0,g.e5)(e.messageKey))]},"".concat(e.code,":").concat(null!=(s=e.path)?s:""))})})]})}function I(e){let{agents:s,skillId:l,version:n}=e,r=(0,a.c)("skills");return 0===s.length?null:(0,t.jsxs)("div",{className:"space-y-1","data-testid":"skill-operation-reload",children:[(0,t.jsx)("h4",{className:"text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:r("operation.reloadHeading")}),(0,t.jsx)("ul",{className:"space-y-1",children:s.map(e=>(0,t.jsx)("li",{className:"text-xs text-muted-foreground",children:r((0,g.e5)(e.messageKey),{agent:(0,i.f_)(e.agent),skillId:l,version:n})},e.agent))})]})}function A(e){var s;let{skillId:l,version:i,blockedReason:o,worktreeId:c}=e,u=(0,a.c)("skills"),[m,p]=(0,n.useState)(()=>c?{...w,worktreeId:c}:w),h=(0,n.useCallback)(e=>{p(s=>s.worktreeId===e?s:v({...s,worktreeId:e,busy:null}))},[]);(0,n.useEffect)(()=>{c&&h(c)},[c,h]);let k=(0,n.useCallback)(async()=>{let e=m.worktreeId;if(!e)return;p(e=>({...v(e),busy:"install-plan"}));let s=await (0,N.Q6)(e,l,{version:null!=i?i:void 0});p(e=>({...e,busy:null,installPlan:s.ok?s.data.plan:null,failure:s.ok?null:s.failure}))},[l,m.worktreeId,i]),f=(0,n.useCallback)(async()=>{let e=m.worktreeId,s=m.installPlan;if(!e||!s||s.requiresRiskAcknowledgement&&!m.riskAcknowledged)return;p(e=>({...e,busy:"install-apply",failure:null}));let t=await (0,N.Xi)(e,l,{planToken:s.token,version:s.skill.version,acknowledgeRisk:!!s.requiresRiskAcknowledgement||void 0,idempotencyKey:R("skill-install",s.token)});p(e=>({...e,busy:null,installPlan:t.ok?null:e.installPlan,installResult:t.ok?t.data:null,failure:t.ok?null:t.failure}))},[l,m.installPlan,m.riskAcknowledged,m.worktreeId]),b=(0,n.useCallback)(async()=>{let e=m.worktreeId;if(!e)return;p(e=>({...v(e),busy:"uninstall-plan"}));let s=await (0,N.hN)(e,l);p(e=>({...e,busy:null,uninstallPlan:s.ok?s.data.plan:null,failure:s.ok?null:s.failure}))},[l,m.worktreeId]),A=(0,n.useCallback)(async()=>{let e=m.worktreeId,s=m.uninstallPlan;if(!e||!s)return;p(e=>({...e,busy:"uninstall-apply",failure:null}));let t=await (0,N.E)(e,l,{planToken:s.token,idempotencyKey:R("skill-uninstall",s.token)});p(e=>({...e,busy:null,uninstallPlan:t.ok?null:e.uninstallPlan,uninstallResult:t.ok?t.data:null,failure:t.ok?null:t.failure}))},[l,m.uninstallPlan,m.worktreeId]),T=(0,n.useCallback)(()=>{p(e=>v(e))},[]),P=null!==m.busy,E=m.installPlan,H=m.uninstallPlan,q=null!=o?o:u(m.worktreeId?"plan.ready":"plan.chooseTarget"),S=null!==E&&E.requiresRiskAcknowledgement&&!m.riskAcknowledged;return(0,t.jsxs)("div",{className:"space-y-3","data-testid":"skill-install-panel",children:[!c&&(0,t.jsx)(x,{selectedWorktreeId:m.worktreeId,onSelect:h,disabled:P}),(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,t.jsx)(r.$n,{variant:"primary",disabled:P||null!==o||!m.worktreeId,onClick:k,"data-testid":"skill-install-action","aria-describedby":"skill-install-reason",children:u("install-plan"===m.busy?"plan.building":"plan.build")}),(0,t.jsx)(r.$n,{variant:"secondary",disabled:P||!m.worktreeId,onClick:b,"data-testid":"skill-uninstall-action",children:u("uninstall-plan"===m.busy?"uninstall.building":"uninstall.build")})]}),(0,t.jsx)("p",{id:"skill-install-reason",className:"text-sm text-muted-foreground","data-testid":"skill-install-reason",children:q}),m.failure&&(0,t.jsx)(C,{failure:m.failure}),E&&(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsx)(j,{plan:E}),E.requiresRiskAcknowledgement&&(0,t.jsxs)(r.Zp,{className:"space-y-3","data-testid":"skill-install-risk-acknowledgement",children:[(0,t.jsx)(d.u,{tone:"danger",children:u((0,g.e5)(null!=(s=E.riskAcknowledgementMessageKey)?s:"skills.plan.highRiskAcknowledgement"))}),(0,t.jsxs)("label",{className:"flex items-start gap-2 text-sm text-foreground",children:[(0,t.jsx)(r.Sc,{checked:m.riskAcknowledged,onCheckedChange:e=>p(s=>({...s,riskAcknowledged:!0===e})),disabled:P,"data-testid":"skill-install-risk-checkbox",className:"mt-0.5"}),(0,t.jsx)("span",{children:u("plan.acknowledgeLabel")})]})]}),(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,t.jsx)(r.$n,{variant:E.requiresRiskAcknowledgement?"danger":"primary",disabled:P||!E.installable||S,onClick:f,"data-testid":"skill-install-confirm",children:u("install-apply"===m.busy?"plan.confirming":"plan.confirm")}),(0,t.jsx)(r.$n,{variant:"ghost",disabled:P,onClick:T,"data-testid":"skill-install-discard",children:u("plan.discard")})]})]}),H&&(0,t.jsxs)("div",{className:"space-y-3",children:[(0,t.jsx)(y,{plan:H}),(0,t.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,t.jsx)(r.$n,{variant:"danger",disabled:P||!H.removable,onClick:A,"data-testid":"skill-uninstall-confirm",children:u("uninstall-apply"===m.busy?"uninstall.confirming":"uninstall.confirm")}),(0,t.jsx)(r.$n,{variant:"ghost",disabled:P,onClick:T,"data-testid":"skill-uninstall-discard",children:u("plan.discard")})]})]}),m.installResult&&(0,t.jsxs)(r.Zp,{className:"space-y-3","data-testid":"skill-install-result",children:[(0,t.jsx)("h3",{className:"text-sm font-semibold text-foreground",children:u("operation.installedHeading")}),(0,t.jsx)(d.u,{tone:"info",children:u((0,g.e5)(m.installResult.operation.nextActionKey))}),m.installResult.operation.replayed&&(0,t.jsx)(d.u,{tone:"neutral","data-testid":"skill-operation-replayed",children:u("operation.replayNotice")}),m.installResult.install&&"files"in m.installResult.install&&(0,t.jsx)("p",{className:"text-xs text-muted-foreground",children:u("operation.filesWritten",{count:m.installResult.install.files.length})}),"reload"in m.installResult&&(0,t.jsx)(I,{agents:m.installResult.reload.agents,skillId:m.installResult.reload.skillId,version:m.installResult.reload.version}),(0,t.jsx)(r.$n,{variant:"secondary",size:"sm",onClick:T,"data-testid":"skill-operation-reset",children:u("operation.startOver")})]}),m.uninstallResult&&(0,t.jsxs)(r.Zp,{className:"space-y-3","data-testid":"skill-uninstall-result",children:[(0,t.jsx)("h3",{className:"text-sm font-semibold text-foreground",children:u("operation.uninstalledHeading")}),(0,t.jsx)(d.u,{tone:"info",children:u((0,g.e5)(m.uninstallResult.operation.nextActionKey))}),m.uninstallResult.operation.replayed&&(0,t.jsx)(d.u,{tone:"neutral","data-testid":"skill-operation-replayed",children:u("operation.replayNotice")}),m.uninstallResult.uninstall&&"removedFiles"in m.uninstallResult.uninstall&&(0,t.jsx)("p",{className:"text-xs text-muted-foreground",children:u("operation.filesRemoved",{count:m.uninstallResult.uninstall.removedFiles.length})}),"reload"in m.uninstallResult&&(0,t.jsx)(I,{agents:m.uninstallResult.reload.agents,skillId:m.uninstallResult.reload.skillId,version:m.uninstallResult.reload.version}),(0,t.jsx)(r.$n,{variant:"secondary",size:"sm",onClick:T,"data-testid":"skill-operation-reset",children:u("operation.startOver")})]})]})}},53482:(e,s,l)=>{l.d(s,{i:()=>o});var t=l(95155),n=l(12115),a=l(60322),r=l(9900);function i(){return(0,t.jsx)("svg",{className:"h-3.5 w-3.5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"})})}function d(){return(0,t.jsx)("svg",{className:"h-3.5 w-3.5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,t.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M5 13l4 4L19 7"})})}function o(e){let{text:s,className:l="",label:o="Copy"}=e,[c,u]=(0,n.useState)(!1),x=(0,n.useRef)(null);(0,n.useEffect)(()=>()=>{x.current&&clearTimeout(x.current)},[]);let m=(0,n.useCallback)(async()=>{try{await (0,a.l)(s),u(!0),x.current&&clearTimeout(x.current),x.current=setTimeout(()=>u(!1),r.s7)}catch(e){}},[s]);return(0,t.jsxs)("button",{type:"button",onClick:m,className:"inline-flex items-center gap-1 rounded border border-border bg-surface px-2 py-0.5 text-[11px] font-medium text-foreground transition-colors hover:bg-muted ".concat(l),"aria-label":c?"Copied":o,title:c?"Copied!":o,children:[c?(0,t.jsx)(d,{}):(0,t.jsx)(i,{}),(0,t.jsx)("span",{children:c?"Copied":o})]})}},60322:(e,s,l)=>{l.d(s,{l:()=>n});let t=/\x1b\[[0-9;]*[a-zA-Z]|\x1b\][^\x07]*\x07|\[[0-9;]*m/g;async function n(e){var s;if(!e||0===e.trim().length)return;let l=e.replace(t,"");if(null==(s=navigator.clipboard)?void 0:s.writeText)try{await navigator.clipboard.writeText(l);return}catch(e){}let n=document.createElement("textarea");n.value=l,n.style.position="fixed",n.style.left="-9999px",n.style.top="-9999px",n.style.opacity="0",document.body.appendChild(n),n.focus(),n.select();try{document.execCommand("copy")}finally{document.body.removeChild(n)}}},76246:(e,s,l)=>{l.d(s,{o:()=>t});function t(e){return e?e.split("/").map(encodeURIComponent).join("/"):""}}}]);