commandmate 0.1.0 → 0.1.6

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 (337) hide show
  1. package/.next/BUILD_ID +1 -0
  2. package/.next/app-build-manifest.json +72 -0
  3. package/.next/app-path-routes-manifest.json +1 -0
  4. package/.next/build-manifest.json +32 -0
  5. package/.next/cache/.tsbuildinfo +1 -0
  6. package/.next/cache/config.json +7 -0
  7. package/.next/cache/webpack/client-production/0.pack +0 -0
  8. package/.next/cache/webpack/client-production/1.pack +0 -0
  9. package/.next/cache/webpack/client-production/2.pack +0 -0
  10. package/.next/cache/webpack/client-production/index.pack +0 -0
  11. package/.next/cache/webpack/client-production/index.pack.old +0 -0
  12. package/.next/cache/webpack/edge-server-production/0.pack +0 -0
  13. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  14. package/.next/cache/webpack/server-production/0.pack +0 -0
  15. package/.next/cache/webpack/server-production/index.pack +0 -0
  16. package/.next/export-marker.json +1 -0
  17. package/.next/images-manifest.json +1 -0
  18. package/.next/next-minimal-server.js.nft.json +1 -0
  19. package/.next/next-server.js.nft.json +1 -0
  20. package/.next/package.json +1 -0
  21. package/.next/prerender-manifest.json +1 -0
  22. package/.next/react-loadable-manifest.json +249 -0
  23. package/.next/required-server-files.json +1 -0
  24. package/.next/routes-manifest.json +1 -0
  25. package/.next/server/app/_not-found/page.js +1 -0
  26. package/.next/server/app/_not-found/page.js.nft.json +1 -0
  27. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
  28. package/.next/server/app/_not-found.html +1 -0
  29. package/.next/server/app/_not-found.meta +6 -0
  30. package/.next/server/app/_not-found.rsc +10 -0
  31. package/.next/server/app/api/external-apps/[id]/health/route.js +45 -0
  32. package/.next/server/app/api/external-apps/[id]/health/route.js.nft.json +1 -0
  33. package/.next/server/app/api/external-apps/[id]/route.js +45 -0
  34. package/.next/server/app/api/external-apps/[id]/route.js.nft.json +1 -0
  35. package/.next/server/app/api/external-apps/route.js +45 -0
  36. package/.next/server/app/api/external-apps/route.js.nft.json +1 -0
  37. package/.next/server/app/api/hooks/claude-done/route.js +19 -0
  38. package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -0
  39. package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -0
  40. package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -0
  41. package/.next/server/app/api/repositories/clone/route.js +1 -0
  42. package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -0
  43. package/.next/server/app/api/repositories/route.js +1 -0
  44. package/.next/server/app/api/repositories/route.js.nft.json +1 -0
  45. package/.next/server/app/api/repositories/scan/route.js +1 -0
  46. package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -0
  47. package/.next/server/app/api/repositories/sync/route.js +1 -0
  48. package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -0
  49. package/.next/server/app/api/slash-commands/route.js +1 -0
  50. package/.next/server/app/api/slash-commands/route.js.nft.json +1 -0
  51. package/.next/server/app/api/slash-commands.body +1 -0
  52. package/.next/server/app/api/slash-commands.meta +1 -0
  53. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -0
  54. package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -0
  55. package/.next/server/app/api/worktrees/[id]/capture/route.js +2 -0
  56. package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -0
  57. package/.next/server/app/api/worktrees/[id]/cli-tool/route.js +1 -0
  58. package/.next/server/app/api/worktrees/[id]/cli-tool/route.js.nft.json +1 -0
  59. package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -0
  60. package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -0
  61. package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js +1 -0
  62. package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js.nft.json +1 -0
  63. package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -0
  64. package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -0
  65. package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -0
  66. package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -0
  67. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js +1 -0
  68. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js.nft.json +1 -0
  69. package/.next/server/app/api/worktrees/[id]/logs/route.js +19 -0
  70. package/.next/server/app/api/worktrees/[id]/logs/route.js.nft.json +1 -0
  71. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js +1 -0
  72. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js.nft.json +1 -0
  73. package/.next/server/app/api/worktrees/[id]/memos/route.js +1 -0
  74. package/.next/server/app/api/worktrees/[id]/memos/route.js.nft.json +1 -0
  75. package/.next/server/app/api/worktrees/[id]/messages/route.js +1 -0
  76. package/.next/server/app/api/worktrees/[id]/messages/route.js.nft.json +1 -0
  77. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -0
  78. package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -0
  79. package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -0
  80. package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -0
  81. package/.next/server/app/api/worktrees/[id]/route.js +1 -0
  82. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -0
  83. package/.next/server/app/api/worktrees/[id]/search/route.js +1 -0
  84. package/.next/server/app/api/worktrees/[id]/search/route.js.nft.json +1 -0
  85. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -0
  86. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -0
  87. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -0
  88. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js.nft.json +1 -0
  89. package/.next/server/app/api/worktrees/[id]/start-polling/route.js +1 -0
  90. package/.next/server/app/api/worktrees/[id]/start-polling/route.js.nft.json +1 -0
  91. package/.next/server/app/api/worktrees/[id]/terminal/route.js +1 -0
  92. package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -0
  93. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js +1 -0
  94. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js.nft.json +1 -0
  95. package/.next/server/app/api/worktrees/[id]/tree/route.js +1 -0
  96. package/.next/server/app/api/worktrees/[id]/tree/route.js.nft.json +1 -0
  97. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route.js +1 -0
  98. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route.js.nft.json +1 -0
  99. package/.next/server/app/api/worktrees/[id]/viewed/route.js +1 -0
  100. package/.next/server/app/api/worktrees/[id]/viewed/route.js.nft.json +1 -0
  101. package/.next/server/app/api/worktrees/route.js +1 -0
  102. package/.next/server/app/api/worktrees/route.js.nft.json +1 -0
  103. package/.next/server/app/apple-icon.png/route.js +1 -0
  104. package/.next/server/app/apple-icon.png/route.js.nft.json +1 -0
  105. package/.next/server/app/apple-icon.png.body +0 -0
  106. package/.next/server/app/apple-icon.png.meta +1 -0
  107. package/.next/server/app/icon.png/route.js +1 -0
  108. package/.next/server/app/icon.png/route.js.nft.json +1 -0
  109. package/.next/server/app/icon.png.body +0 -0
  110. package/.next/server/app/icon.png.meta +1 -0
  111. package/.next/server/app/index.html +9 -0
  112. package/.next/server/app/index.meta +5 -0
  113. package/.next/server/app/index.rsc +8 -0
  114. package/.next/server/app/page.js +16 -0
  115. package/.next/server/app/page.js.nft.json +1 -0
  116. package/.next/server/app/page_client-reference-manifest.js +1 -0
  117. package/.next/server/app/proxy/[...path]/route.js +45 -0
  118. package/.next/server/app/proxy/[...path]/route.js.nft.json +1 -0
  119. package/.next/server/app/worktrees/[id]/files/[...path]/page.js +1 -0
  120. package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +1 -0
  121. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -0
  122. package/.next/server/app/worktrees/[id]/page.js +21 -0
  123. package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -0
  124. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -0
  125. package/.next/server/app/worktrees/[id]/simple-terminal/page.js +4 -0
  126. package/.next/server/app/worktrees/[id]/simple-terminal/page.js.nft.json +1 -0
  127. package/.next/server/app/worktrees/[id]/simple-terminal/page_client-reference-manifest.js +1 -0
  128. package/.next/server/app/worktrees/[id]/terminal/page.js +6 -0
  129. package/.next/server/app/worktrees/[id]/terminal/page.js.nft.json +1 -0
  130. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -0
  131. package/.next/server/app-paths-manifest.json +46 -0
  132. package/.next/server/chunks/1318.js +29 -0
  133. package/.next/server/chunks/1528.js +1 -0
  134. package/.next/server/chunks/1682.js +6 -0
  135. package/.next/server/chunks/2518.js +12 -0
  136. package/.next/server/chunks/3053.js +1 -0
  137. package/.next/server/chunks/3673.js +1 -0
  138. package/.next/server/chunks/3853.js +1 -0
  139. package/.next/server/chunks/434.js +1 -0
  140. package/.next/server/chunks/4471.js +2 -0
  141. package/.next/server/chunks/4893.js +2 -0
  142. package/.next/server/chunks/5972.js +12 -0
  143. package/.next/server/chunks/6550.js +1 -0
  144. package/.next/server/chunks/6621.js +1 -0
  145. package/.next/server/chunks/7213.js +1 -0
  146. package/.next/server/chunks/7425.js +500 -0
  147. package/.next/server/chunks/8585.js +1 -0
  148. package/.next/server/chunks/8887.js +1 -0
  149. package/.next/server/chunks/8948.js +2 -0
  150. package/.next/server/chunks/9703.js +31 -0
  151. package/.next/server/chunks/9723.js +19 -0
  152. package/.next/server/chunks/font-manifest.json +1 -0
  153. package/.next/server/edge-runtime-webpack.js +2 -0
  154. package/.next/server/edge-runtime-webpack.js.map +1 -0
  155. package/.next/server/font-manifest.json +1 -0
  156. package/.next/server/functions-config-manifest.json +1 -0
  157. package/.next/server/interception-route-rewrite-manifest.js +1 -0
  158. package/.next/server/middleware-build-manifest.js +1 -0
  159. package/.next/server/middleware-manifest.json +32 -0
  160. package/.next/server/middleware-react-loadable-manifest.js +1 -0
  161. package/.next/server/next-font-manifest.js +1 -0
  162. package/.next/server/next-font-manifest.json +1 -0
  163. package/.next/server/pages/404.html +1 -0
  164. package/.next/server/pages/500.html +1 -0
  165. package/.next/server/pages/_app.js +1 -0
  166. package/.next/server/pages/_app.js.nft.json +1 -0
  167. package/.next/server/pages/_document.js +1 -0
  168. package/.next/server/pages/_document.js.nft.json +1 -0
  169. package/.next/server/pages/_error.js +1 -0
  170. package/.next/server/pages/_error.js.nft.json +1 -0
  171. package/.next/server/pages-manifest.json +1 -0
  172. package/.next/server/server-reference-manifest.js +1 -0
  173. package/.next/server/server-reference-manifest.json +1 -0
  174. package/.next/server/src/middleware.js +14 -0
  175. package/.next/server/src/middleware.js.map +1 -0
  176. package/.next/server/webpack-runtime.js +1 -0
  177. package/.next/static/chunks/0dbeb660.3e800dfbd28be3bd.js +53 -0
  178. package/.next/static/chunks/1015.0eaa4da7f61149bc.js +59 -0
  179. package/.next/static/chunks/1098.49268c9fe1b028fa.js +1 -0
  180. package/.next/static/chunks/13.feeafc7cc620f8c4.js +1 -0
  181. package/.next/static/chunks/1423.7b1e8bf760d28078.js +1 -0
  182. package/.next/static/chunks/1582.9f8590f71ff798ca.js +55 -0
  183. package/.next/static/chunks/1817.a66d96cedb761daa.js +262 -0
  184. package/.next/static/chunks/2117-d845c2cd62e344a6.js +2 -0
  185. package/.next/static/chunks/2398.0b21e4eb7006a230.js +93 -0
  186. package/.next/static/chunks/2526.8ac62b527c9ab703.js +43 -0
  187. package/.next/static/chunks/2626.2125083a1ff3b80a.js +29 -0
  188. package/.next/static/chunks/2689.720a4874b02d4211.js +174 -0
  189. package/.next/static/chunks/2853-d11a80b03c9a1640.js +1 -0
  190. package/.next/static/chunks/2957-327e43ef4c12808f.js +1 -0
  191. package/.next/static/chunks/2cdb6380.35626fc6e41bbba4.js +136 -0
  192. package/.next/static/chunks/30d07d85-393352a92199f695.js +3 -0
  193. package/.next/static/chunks/3559.f073f72c4466ce0e.js +1 -0
  194. package/.next/static/chunks/3574.7a94c27e6a496a56.js +63 -0
  195. package/.next/static/chunks/383.20683891c9a5f2c4.js +4 -0
  196. package/.next/static/chunks/3843.3fdda732987f7bb8.js +1 -0
  197. package/.next/static/chunks/3852.822389f445c9b427.js +1 -0
  198. package/.next/static/chunks/3991.4bc063cb5be3a86c.js +1 -0
  199. package/.next/static/chunks/4212.52c1bb34fc97d0d0.js +131 -0
  200. package/.next/static/chunks/4327.3b84aa049900fdeb.js +60 -0
  201. package/.next/static/chunks/4362.7bd6f0282e49d79b.js +1 -0
  202. package/.next/static/chunks/4721.40615a5f4f32b5fb.js +1 -0
  203. package/.next/static/chunks/4851-45df4d388db5623f.js +1 -0
  204. package/.next/static/chunks/5112.17318d1c6b28044b.js +1 -0
  205. package/.next/static/chunks/5126.93fa4e797d609286.js +56 -0
  206. package/.next/static/chunks/5387.47590ac4ef66c864.js +5 -0
  207. package/.next/static/chunks/5813.4483664ba482beb1.js +1 -0
  208. package/.next/static/chunks/6143.1450875bd03a2366.js +36 -0
  209. package/.next/static/chunks/6406.9653f0d41ab85059.js +1 -0
  210. package/.next/static/chunks/656.d72f25ce819bd77e.js +149 -0
  211. package/.next/static/chunks/6678.492e73ca42b2a273.js +62 -0
  212. package/.next/static/chunks/6725-f7607851b7d57eb1.js +1 -0
  213. package/.next/static/chunks/6792.3c01ac4dda4b5c6d.js +1 -0
  214. package/.next/static/chunks/7004.808cbf327ef5955e.js +1 -0
  215. package/.next/static/chunks/7290.09ef84cf94f90c4d.js +1 -0
  216. package/.next/static/chunks/7415.6b481c2baf363262.js +148 -0
  217. package/.next/static/chunks/7648-325564a6e12a3257.js +1 -0
  218. package/.next/static/chunks/7665.47fccad04449a8f9.js +215 -0
  219. package/.next/static/chunks/7753.6bdce86b7fde3d10.js +166 -0
  220. package/.next/static/chunks/8125.245a9df052d274fb.js +1 -0
  221. package/.next/static/chunks/816-7e340dad784be28c.js +1 -0
  222. package/.next/static/chunks/8288.4883743fa40672e2.js +24 -0
  223. package/.next/static/chunks/8522.1607e96011c66877.js +1 -0
  224. package/.next/static/chunks/8772.863c564498d88487.js +1 -0
  225. package/.next/static/chunks/8841.dadeb1ece8e46004.js +1 -0
  226. package/.next/static/chunks/8885.f8d9912b40d74811.js +1 -0
  227. package/.next/static/chunks/90542734.c1553d0fe7fc14fc.js +1 -0
  228. package/.next/static/chunks/9365-733d8c05712d2888.js +1 -0
  229. package/.next/static/chunks/9552.b7dfb7903ead934b.js +1 -0
  230. package/.next/static/chunks/9834.295b45635ce04f5e.js +24 -0
  231. package/.next/static/chunks/app/_not-found/page-a9d04e58c81115ec.js +1 -0
  232. package/.next/static/chunks/app/layout-37e55f11dcc8b1bf.js +1 -0
  233. package/.next/static/chunks/app/page-9cd00de9cc0abc43.js +1 -0
  234. package/.next/static/chunks/app/worktrees/[id]/files/[...path]/page-9e5adf57cbbbdf05.js +1 -0
  235. package/.next/static/chunks/app/worktrees/[id]/page-8c6676303b63fdaf.js +1 -0
  236. package/.next/static/chunks/app/worktrees/[id]/simple-terminal/page-16feb3e86e42f4d1.js +1 -0
  237. package/.next/static/chunks/app/worktrees/[id]/terminal/page-be802baffc84dbd2.js +1 -0
  238. package/.next/static/chunks/d3ac728e.6c9c508274d4d2d5.js +1 -0
  239. package/.next/static/chunks/fd9d1056-bbe86e4ae099d5cd.js +1 -0
  240. package/.next/static/chunks/framework-8e0e0f4a6b83a956.js +1 -0
  241. package/.next/static/chunks/main-a960f4a5e1a2f598.js +1 -0
  242. package/.next/static/chunks/main-app-420d93e43682fee5.js +1 -0
  243. package/.next/static/chunks/pages/_app-3c9ca398d360b709.js +1 -0
  244. package/.next/static/chunks/pages/_error-cf5ca766ac8f493f.js +1 -0
  245. package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  246. package/.next/static/chunks/webpack-3fc79fab9bb738d7.js +1 -0
  247. package/.next/static/css/5eacd01f773eed7f.css +11 -0
  248. package/.next/static/css/85fa6dafca566008.css +1 -0
  249. package/.next/static/css/e174aa24f94ce607.css +3 -0
  250. package/.next/static/pQTquVjewvoJa7BML07ip/_buildManifest.js +1 -0
  251. package/.next/static/pQTquVjewvoJa7BML07ip/_ssgManifest.js +1 -0
  252. package/.next/trace +5 -0
  253. package/.next/types/app/api/external-apps/[id]/health/route.ts +343 -0
  254. package/.next/types/app/api/external-apps/[id]/route.ts +343 -0
  255. package/.next/types/app/api/external-apps/route.ts +343 -0
  256. package/.next/types/app/api/hooks/claude-done/route.ts +343 -0
  257. package/.next/types/app/api/repositories/clone/[jobId]/route.ts +343 -0
  258. package/.next/types/app/api/repositories/clone/route.ts +343 -0
  259. package/.next/types/app/api/repositories/route.ts +343 -0
  260. package/.next/types/app/api/repositories/scan/route.ts +343 -0
  261. package/.next/types/app/api/repositories/sync/route.ts +343 -0
  262. package/.next/types/app/api/slash-commands/route.ts +343 -0
  263. package/.next/types/app/api/worktrees/[id]/auto-yes/route.ts +343 -0
  264. package/.next/types/app/api/worktrees/[id]/capture/route.ts +343 -0
  265. package/.next/types/app/api/worktrees/[id]/cli-tool/route.ts +343 -0
  266. package/.next/types/app/api/worktrees/[id]/current-output/route.ts +343 -0
  267. package/.next/types/app/api/worktrees/[id]/files/[...path]/route.ts +343 -0
  268. package/.next/types/app/api/worktrees/[id]/interrupt/route.ts +343 -0
  269. package/.next/types/app/api/worktrees/[id]/kill-session/route.ts +343 -0
  270. package/.next/types/app/api/worktrees/[id]/logs/[filename]/route.ts +343 -0
  271. package/.next/types/app/api/worktrees/[id]/logs/route.ts +343 -0
  272. package/.next/types/app/api/worktrees/[id]/memos/[memoId]/route.ts +343 -0
  273. package/.next/types/app/api/worktrees/[id]/memos/route.ts +343 -0
  274. package/.next/types/app/api/worktrees/[id]/messages/route.ts +343 -0
  275. package/.next/types/app/api/worktrees/[id]/prompt-response/route.ts +343 -0
  276. package/.next/types/app/api/worktrees/[id]/respond/route.ts +343 -0
  277. package/.next/types/app/api/worktrees/[id]/route.ts +343 -0
  278. package/.next/types/app/api/worktrees/[id]/search/route.ts +343 -0
  279. package/.next/types/app/api/worktrees/[id]/send/route.ts +343 -0
  280. package/.next/types/app/api/worktrees/[id]/slash-commands/route.ts +343 -0
  281. package/.next/types/app/api/worktrees/[id]/start-polling/route.ts +343 -0
  282. package/.next/types/app/api/worktrees/[id]/terminal/route.ts +343 -0
  283. package/.next/types/app/api/worktrees/[id]/tree/[...path]/route.ts +343 -0
  284. package/.next/types/app/api/worktrees/[id]/tree/route.ts +343 -0
  285. package/.next/types/app/api/worktrees/[id]/upload/[...path]/route.ts +343 -0
  286. package/.next/types/app/api/worktrees/[id]/viewed/route.ts +343 -0
  287. package/.next/types/app/api/worktrees/route.ts +343 -0
  288. package/.next/types/app/page.ts +79 -0
  289. package/.next/types/app/proxy/[...path]/route.ts +343 -0
  290. package/.next/types/app/worktrees/[id]/files/[...path]/page.ts +79 -0
  291. package/.next/types/app/worktrees/[id]/page.ts +79 -0
  292. package/.next/types/app/worktrees/[id]/simple-terminal/page.ts +79 -0
  293. package/.next/types/app/worktrees/[id]/terminal/page.ts +79 -0
  294. package/.next/types/package.json +1 -0
  295. package/README.md +25 -20
  296. package/dist/cli/commands/start.d.ts.map +1 -1
  297. package/dist/cli/commands/start.js +4 -1
  298. package/dist/cli/utils/daemon.d.ts.map +1 -1
  299. package/dist/cli/utils/daemon.js +4 -2
  300. package/dist/cli/utils/paths.d.ts +25 -0
  301. package/dist/cli/utils/paths.d.ts.map +1 -0
  302. package/dist/cli/utils/paths.js +35 -0
  303. package/dist/server/server.js +123 -0
  304. package/dist/server/src/lib/claude-output.js +33 -0
  305. package/dist/server/src/lib/claude-session.js +312 -0
  306. package/dist/server/src/lib/cli-patterns.js +137 -0
  307. package/dist/server/src/lib/cli-session.js +73 -0
  308. package/dist/server/src/lib/cli-tools/base.js +51 -0
  309. package/dist/server/src/lib/cli-tools/claude.js +65 -0
  310. package/dist/server/src/lib/cli-tools/codex.js +132 -0
  311. package/dist/server/src/lib/cli-tools/gemini.js +122 -0
  312. package/dist/server/src/lib/cli-tools/index.js +22 -0
  313. package/dist/server/src/lib/cli-tools/manager.js +143 -0
  314. package/dist/server/src/lib/cli-tools/types.js +5 -0
  315. package/dist/server/src/lib/conversation-logger.js +25 -0
  316. package/dist/server/src/lib/db-instance.js +51 -0
  317. package/dist/server/src/lib/db-migrations.js +777 -0
  318. package/dist/server/src/lib/db.js +835 -0
  319. package/dist/server/src/lib/env.js +179 -0
  320. package/dist/server/src/lib/log-manager.js +234 -0
  321. package/dist/server/src/lib/logger.js +232 -0
  322. package/dist/server/src/lib/prompt-detector.js +285 -0
  323. package/dist/server/src/lib/response-poller.js +638 -0
  324. package/dist/server/src/lib/tmux.js +299 -0
  325. package/dist/server/src/lib/worktrees.js +231 -0
  326. package/dist/server/src/lib/ws-server.js +323 -0
  327. package/dist/server/src/types/clone.js +39 -0
  328. package/dist/server/src/types/conversation.js +9 -0
  329. package/dist/server/src/types/external-apps.js +6 -0
  330. package/dist/server/src/types/infinite-messages.js +65 -0
  331. package/dist/server/src/types/markdown-editor.js +94 -0
  332. package/dist/server/src/types/models.js +5 -0
  333. package/dist/server/src/types/sidebar.js +89 -0
  334. package/dist/server/src/types/slash-commands.js +47 -0
  335. package/dist/server/src/types/ui-actions.js +8 -0
  336. package/dist/server/src/types/ui-state.js +62 -0
  337. package/package.json +14 -6
package/README.md CHANGED
@@ -49,39 +49,43 @@ Claude Code での開発経験があり、本業の傍らで個人開発を続
49
49
 
50
50
  - macOS / Linux(tmux 依存のため Windows は非対応)
51
51
  - Node.js v20+、npm、git、tmux、openssl
52
- - Claude CLI(CLAUDE_HOOKS_STOP 対応)
52
+ - Claude CLI(オプション)
53
53
 
54
- ### CLIコマンドによるセットアップ(推奨)
54
+ ### インストール
55
55
 
56
56
  ```bash
57
- # グローバルインストール
58
57
  npm install -g commandmate
58
+ ```
59
59
 
60
- # 初期化(依存関係チェック、.env作成、DB初期化)
61
- commandmate init
60
+ ### セットアップと起動
62
61
 
63
- # サーバー起動
64
- commandmate start
62
+ ```bash
63
+ commandmate init # 依存チェック、環境設定、DB初期化
64
+ commandmate start --daemon # バックグラウンドで起動
65
65
  ```
66
66
 
67
67
  ブラウザで http://localhost:3000 にアクセスしてください。
68
68
 
69
- #### CLIコマンド一覧
69
+ ### CLI コマンド
70
70
 
71
71
  | コマンド | 説明 |
72
72
  |---------|------|
73
- | `commandmate --version` | バージョン表示 |
74
- | `commandmate init` | 初期化(対話形式で設定) |
75
- | `commandmate init --defaults` | デフォルト値で初期化(非対話) |
76
- | `commandmate start` | サーバー起動(フォアグラウンド) |
77
- | `commandmate start --dev` | 開発モードで起動 |
78
- | `commandmate start --daemon` | バックグラウンドで起動 |
73
+ | `commandmate init` | 初期設定(対話形式) |
74
+ | `commandmate init --defaults` | 初期設定(デフォルト値) |
75
+ | `commandmate start --daemon` | バックグラウンド起動 |
76
+ | `commandmate start -p 3001` | ポート指定で起動 |
79
77
  | `commandmate stop` | サーバー停止 |
80
- | `commandmate status` | サーバー状態確認 |
78
+ | `commandmate status` | 状態確認 |
79
+
80
+ 詳しくは [CLI セットアップガイド](./docs/user-guide/cli-setup-guide.md) を参照してください。
81
+
82
+ ### モバイルからのアクセス
83
+
84
+ `commandmate init` で外部アクセスを有効にすると、`CM_BIND=0.0.0.0` と `CM_AUTH_TOKEN` が自動設定されます。同一LAN内から `http://<PCのIP>:3000` にアクセスします。
81
85
 
82
- ### シェルスクリプトによるセットアップ(レガシー)
86
+ ## 開発者向けセットアップ
83
87
 
84
- > **Note**: シェルスクリプトは非推奨です。CLIコマンドの使用を推奨します。
88
+ コントリビューターや開発環境を構築する場合は、git clone を使用してください。
85
89
 
86
90
  ```bash
87
91
  git clone https://github.com/Kewton/CommandMate.git
@@ -102,7 +106,7 @@ npm run build
102
106
  npm start
103
107
  ```
104
108
 
105
- スマホから利用する場合は `commandmate init` または `./scripts/setup-env.sh` で外部アクセスを有効にすると、`CM_BIND=0.0.0.0` `CM_AUTH_TOKEN` が自動設定されます。同一LAN内から `http://<PCのIP>:3000` にアクセスします。
109
+ > **Note**: `./scripts/*` スクリプトは開発環境でのみ使用可能です。グローバルインストール(`npm install -g`)では `commandmate` CLI を使用してください。
106
110
 
107
111
  > **Note**: 旧名称の環境変数(`MCBD_*`)も後方互換性のためサポートされていますが、新名称(`CM_*`)の使用を推奨します。
108
112
 
@@ -130,13 +134,14 @@ A: 現時点では個人利用を想定しています。複数人での同時
130
134
 
131
135
  | ドキュメント | 説明 |
132
136
  |-------------|------|
137
+ | [CLI セットアップガイド](./docs/user-guide/cli-setup-guide.md) | インストールと初期設定 |
138
+ | [Webアプリ操作ガイド](./docs/user-guide/webapp-guide.md) | Webアプリの基本操作 |
139
+ | [クイックスタート](./docs/user-guide/quick-start.md) | Claude Codeコマンドの使い方 |
133
140
  | [コンセプト](./docs/concept.md) | ビジョンと解決する課題 |
134
141
  | [アーキテクチャ](./docs/architecture.md) | システム設計 |
135
142
  | [デプロイガイド](./docs/DEPLOYMENT.md) | 本番環境構築手順 |
136
143
  | [移行ガイド](./docs/migration-to-commandmate.md) | MyCodeBranchDesk からの移行手順 |
137
144
  | [UI/UXガイド](./docs/UI_UX_GUIDE.md) | UI実装の詳細 |
138
- | [Webアプリ操作ガイド](./docs/user-guide/webapp-guide.md) | Webアプリの基本操作 |
139
- | [クイックスタート](./docs/user-guide/quick-start.md) | Claude Codeコマンドの使い方 |
140
145
  | [Trust & Safety](./docs/TRUST_AND_SAFETY.md) | セキュリティと権限の考え方 |
141
146
 
142
147
  ## Contributing
@@ -1 +1 @@
1
- {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/start.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,YAAY,EAAY,MAAM,UAAU,CAAC;AAQlD;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAoHvE"}
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/start.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,YAAY,EAAY,MAAM,UAAU,CAAC;AASlD;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAuHvE"}
@@ -13,6 +13,7 @@ const types_1 = require("../types");
13
13
  const logger_1 = require("../utils/logger");
14
14
  const daemon_1 = require("../utils/daemon");
15
15
  const security_logger_1 = require("../utils/security-logger");
16
+ const paths_1 = require("../utils/paths");
16
17
  const logger = new logger_1.CLILogger();
17
18
  const PID_FILE = (0, path_1.join)(process.cwd(), '.commandmate.pid');
18
19
  /**
@@ -77,8 +78,10 @@ async function startCommand(options) {
77
78
  if (options.port) {
78
79
  env.CM_PORT = String(options.port);
79
80
  }
81
+ // Use package installation directory, not current working directory
82
+ const packageRoot = (0, paths_1.getPackageRoot)();
80
83
  const child = (0, child_process_1.spawn)('npm', ['run', npmScript], {
81
- cwd: process.cwd(),
84
+ cwd: packageRoot,
82
85
  env,
83
86
  stdio: 'inherit',
84
87
  });
@@ -1 +1 @@
1
- {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/daemon.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGtD;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAa;gBAEnB,WAAW,EAAE,MAAM;IAI/B;;;;OAIG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IA6CnD;;;;OAIG;IACG,IAAI,CAAC,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IA8BpD;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IA6B/C;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAInC;;OAEG;YACW,WAAW;CAiB1B"}
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/daemon.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAItD;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAa;gBAEnB,WAAW,EAAE,MAAM;IAI/B;;;;OAIG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IA8CnD;;;;OAIG;IACG,IAAI,CAAC,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IA8BpD;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IA6B/C;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAInC;;OAEG;YACW,WAAW;CAiB1B"}
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
8
8
  exports.DaemonManager = void 0;
9
9
  const child_process_1 = require("child_process");
10
10
  const pid_manager_1 = require("./pid-manager");
11
+ const paths_1 = require("./paths");
11
12
  /**
12
13
  * Daemon manager for background server process
13
14
  */
@@ -29,7 +30,8 @@ class DaemonManager {
29
30
  // Clean up stale PID file
30
31
  this.pidManager.removePid();
31
32
  const npmScript = options.dev ? 'dev' : 'start';
32
- const cwd = process.cwd();
33
+ // Use package installation directory, not current working directory
34
+ const packageRoot = (0, paths_1.getPackageRoot)();
33
35
  // Build environment
34
36
  const env = { ...process.env };
35
37
  if (options.port) {
@@ -37,7 +39,7 @@ class DaemonManager {
37
39
  }
38
40
  // Spawn detached process
39
41
  const child = (0, child_process_1.spawn)('npm', ['run', npmScript], {
40
- cwd,
42
+ cwd: packageRoot,
41
43
  env,
42
44
  detached: true,
43
45
  stdio: 'ignore',
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Path Utilities for CLI
3
+ * Issue #96: npm install CLI support
4
+ *
5
+ * Provides utilities to resolve package installation directory
6
+ * regardless of where the CLI is invoked from.
7
+ */
8
+ /**
9
+ * Get the root directory of the CommandMate package installation.
10
+ *
11
+ * When installed globally via npm, the CLI runs from:
12
+ * <global-modules>/commandmate/dist/cli/utils/paths.js
13
+ *
14
+ * This function returns the package root:
15
+ * <global-modules>/commandmate/
16
+ *
17
+ * @returns Absolute path to the package root directory
18
+ */
19
+ export declare function getPackageRoot(): string;
20
+ /**
21
+ * Get the path to package.json
22
+ * @returns Absolute path to package.json
23
+ */
24
+ export declare function getPackageJsonPath(): string;
25
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/paths.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAIvC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C"}
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ /**
3
+ * Path Utilities for CLI
4
+ * Issue #96: npm install CLI support
5
+ *
6
+ * Provides utilities to resolve package installation directory
7
+ * regardless of where the CLI is invoked from.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.getPackageRoot = getPackageRoot;
11
+ exports.getPackageJsonPath = getPackageJsonPath;
12
+ const path_1 = require("path");
13
+ /**
14
+ * Get the root directory of the CommandMate package installation.
15
+ *
16
+ * When installed globally via npm, the CLI runs from:
17
+ * <global-modules>/commandmate/dist/cli/utils/paths.js
18
+ *
19
+ * This function returns the package root:
20
+ * <global-modules>/commandmate/
21
+ *
22
+ * @returns Absolute path to the package root directory
23
+ */
24
+ function getPackageRoot() {
25
+ // __dirname points to dist/cli/utils when this file is compiled
26
+ // We need to go up 3 levels: utils → cli → dist → package root
27
+ return (0, path_1.join)(__dirname, '..', '..', '..');
28
+ }
29
+ /**
30
+ * Get the path to package.json
31
+ * @returns Absolute path to package.json
32
+ */
33
+ function getPackageJsonPath() {
34
+ return (0, path_1.join)(getPackageRoot(), 'package.json');
35
+ }
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ /**
3
+ * Custom Next.js Server with WebSocket Support
4
+ * Integrates WebSocket server for real-time communication
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ // IMPORTANT: Register uncaught exception handler FIRST, before any imports
11
+ // This ensures we catch WebSocket frame errors before other handlers
12
+ process.on('uncaughtException', (error) => {
13
+ // Check for WebSocket-related errors that are non-fatal
14
+ const isWebSocketError = error.code === 'WS_ERR_INVALID_UTF8' ||
15
+ error.code === 'WS_ERR_INVALID_CLOSE_CODE' ||
16
+ error.code === 'WS_ERR_UNEXPECTED_RSV_1' ||
17
+ error.code === 'ECONNRESET' ||
18
+ error.code === 'EPIPE' ||
19
+ (error instanceof RangeError && error.message?.includes('Invalid WebSocket frame')) ||
20
+ error.message?.includes('write after end');
21
+ if (isWebSocketError) {
22
+ // Silently ignore these non-fatal WebSocket frame errors
23
+ // They commonly occur when mobile browsers send malformed close frames
24
+ return;
25
+ }
26
+ // For other uncaught exceptions, log and exit
27
+ console.error('Uncaught exception:', error);
28
+ process.exit(1);
29
+ });
30
+ const http_1 = require("http");
31
+ const url_1 = require("url");
32
+ const next_1 = __importDefault(require("next"));
33
+ const ws_server_1 = require("./src/lib/ws-server");
34
+ const worktrees_1 = require("./src/lib/worktrees");
35
+ const db_instance_1 = require("./src/lib/db-instance");
36
+ const response_poller_1 = require("./src/lib/response-poller");
37
+ const db_migrations_1 = require("./src/lib/db-migrations");
38
+ const env_1 = require("./src/lib/env");
39
+ const dev = process.env.NODE_ENV !== 'production';
40
+ const hostname = (0, env_1.getEnvByKey)('CM_BIND') || '127.0.0.1';
41
+ const port = parseInt((0, env_1.getEnvByKey)('CM_PORT') || '3000', 10);
42
+ // Create Next.js app
43
+ const app = (0, next_1.default)({ dev, hostname, port });
44
+ const handle = app.getRequestHandler();
45
+ app.prepare().then(() => {
46
+ // Create HTTP server
47
+ const server = (0, http_1.createServer)(async (req, res) => {
48
+ try {
49
+ const parsedUrl = (0, url_1.parse)(req.url, true);
50
+ await handle(req, res, parsedUrl);
51
+ }
52
+ catch (err) {
53
+ console.error('Error handling request', err);
54
+ res.statusCode = 500;
55
+ res.end('Internal Server Error');
56
+ }
57
+ });
58
+ // Setup WebSocket server
59
+ (0, ws_server_1.setupWebSocket)(server);
60
+ // Scan and sync worktrees on startup
61
+ async function initializeWorktrees() {
62
+ try {
63
+ // Run database migrations first
64
+ console.log('Running database migrations...');
65
+ const db = (0, db_instance_1.getDbInstance)();
66
+ (0, db_migrations_1.runMigrations)(db);
67
+ // Get repository paths from environment variables
68
+ const repositoryPaths = (0, worktrees_1.getRepositoryPaths)();
69
+ if (repositoryPaths.length === 0) {
70
+ console.warn('Warning: No repository paths configured');
71
+ console.warn('Set WORKTREE_REPOS (comma-separated) or MCBD_ROOT_DIR');
72
+ return;
73
+ }
74
+ console.log(`Configured repositories: ${repositoryPaths.length}`);
75
+ repositoryPaths.forEach((path, i) => {
76
+ console.log(` ${i + 1}. ${path}`);
77
+ });
78
+ // Scan all repositories
79
+ const worktrees = await (0, worktrees_1.scanMultipleRepositories)(repositoryPaths);
80
+ // Sync to database
81
+ (0, worktrees_1.syncWorktreesToDB)(db, worktrees);
82
+ console.log(`✓ Total: ${worktrees.length} worktree(s) synced to database`);
83
+ }
84
+ catch (error) {
85
+ console.error('Error initializing worktrees:', error);
86
+ }
87
+ }
88
+ server.listen(port, async (err) => {
89
+ if (err)
90
+ throw err;
91
+ console.log(`> Ready on http://${hostname}:${port}`);
92
+ console.log(`> WebSocket server ready`);
93
+ // Initialize worktrees after server starts
94
+ await initializeWorktrees();
95
+ });
96
+ // Graceful shutdown with timeout
97
+ let isShuttingDown = false;
98
+ function gracefulShutdown(signal) {
99
+ if (isShuttingDown) {
100
+ console.log('Shutdown already in progress, forcing exit...');
101
+ process.exit(1);
102
+ }
103
+ isShuttingDown = true;
104
+ console.log(`${signal} received: shutting down...`);
105
+ // Stop polling first
106
+ (0, response_poller_1.stopAllPolling)();
107
+ // Close WebSocket connections immediately (don't wait)
108
+ (0, ws_server_1.closeWebSocket)();
109
+ // Force exit after 3 seconds if graceful shutdown fails
110
+ const forceExitTimeout = setTimeout(() => {
111
+ console.log('Graceful shutdown timeout, forcing exit...');
112
+ process.exit(1);
113
+ }, 3000);
114
+ // Try graceful HTTP server close
115
+ server.close(() => {
116
+ clearTimeout(forceExitTimeout);
117
+ console.log('Server closed gracefully');
118
+ process.exit(0);
119
+ });
120
+ }
121
+ process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
122
+ process.on('SIGINT', () => gracefulShutdown('SIGINT'));
123
+ });
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ /**
3
+ * Claude output parsing utilities
4
+ * Shared between webhook handlers and polling logic
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.parseClaudeOutput = parseClaudeOutput;
8
+ const LOG_FILE_REGEX = /📄 Session log: (.+?\/([^\/\s]+\.jsonl))/;
9
+ const REQUEST_ID_REGEX = /Request ID: ([^\s\n]+)/;
10
+ const SUMMARY_REGEX = /Summary: (.+?)(?:\n─|$)/s;
11
+ /**
12
+ * Parse Claude CLI output and extract metadata that the UI relies on.
13
+ *
14
+ * @param output Raw tmux capture string
15
+ */
16
+ function parseClaudeOutput(output) {
17
+ const result = {
18
+ content: output,
19
+ };
20
+ const logFileMatch = LOG_FILE_REGEX.exec(output);
21
+ if (logFileMatch) {
22
+ result.logFileName = logFileMatch[2];
23
+ }
24
+ const requestIdMatch = REQUEST_ID_REGEX.exec(output);
25
+ if (requestIdMatch) {
26
+ result.requestId = requestIdMatch[1];
27
+ }
28
+ const summaryMatch = SUMMARY_REGEX.exec(output);
29
+ if (summaryMatch) {
30
+ result.summary = summaryMatch[1].trim();
31
+ }
32
+ return result;
33
+ }
@@ -0,0 +1,312 @@
1
+ "use strict";
2
+ /**
3
+ * Claude CLI session management
4
+ * Manages Claude CLI sessions within tmux for each worktree
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.getSessionName = getSessionName;
8
+ exports.isClaudeInstalled = isClaudeInstalled;
9
+ exports.isClaudeRunning = isClaudeRunning;
10
+ exports.getClaudeSessionState = getClaudeSessionState;
11
+ exports.startClaudeSession = startClaudeSession;
12
+ exports.sendMessageToClaude = sendMessageToClaude;
13
+ exports.captureClaudeOutput = captureClaudeOutput;
14
+ exports.stopClaudeSession = stopClaudeSession;
15
+ exports.restartClaudeSession = restartClaudeSession;
16
+ const tmux_1 = require("./tmux");
17
+ const child_process_1 = require("child_process");
18
+ const util_1 = require("util");
19
+ const execAsync = (0, util_1.promisify)(child_process_1.exec);
20
+ /**
21
+ * Cached Claude CLI path
22
+ */
23
+ let cachedClaudePath = null;
24
+ /**
25
+ * Get Claude CLI path dynamically
26
+ * Uses CLAUDE_PATH environment variable if set, otherwise finds via 'which'
27
+ */
28
+ async function getClaudePath() {
29
+ // Return cached path if available
30
+ if (cachedClaudePath) {
31
+ return cachedClaudePath;
32
+ }
33
+ // Check environment variable first
34
+ if (process.env.CLAUDE_PATH) {
35
+ cachedClaudePath = process.env.CLAUDE_PATH;
36
+ return cachedClaudePath;
37
+ }
38
+ // Find claude via 'which' command
39
+ try {
40
+ const { stdout } = await execAsync('which claude', { timeout: 5000 });
41
+ cachedClaudePath = stdout.trim();
42
+ return cachedClaudePath;
43
+ }
44
+ catch {
45
+ // Fallback to common paths
46
+ const fallbackPaths = [
47
+ '/opt/homebrew/bin/claude', // macOS Homebrew (Apple Silicon)
48
+ '/usr/local/bin/claude', // macOS Homebrew (Intel) / Linux
49
+ '/usr/bin/claude', // Linux system install
50
+ ];
51
+ for (const path of fallbackPaths) {
52
+ try {
53
+ await execAsync(`test -x "${path}"`, { timeout: 1000 });
54
+ cachedClaudePath = path;
55
+ return cachedClaudePath;
56
+ }
57
+ catch {
58
+ // Path not found, try next
59
+ }
60
+ }
61
+ throw new Error('Claude CLI not found. Set CLAUDE_PATH environment variable or install Claude CLI.');
62
+ }
63
+ }
64
+ /**
65
+ * Get tmux session name for a worktree
66
+ *
67
+ * @param worktreeId - Worktree ID
68
+ * @returns tmux session name
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * getSessionName('feature-foo') // => 'mcbd-claude-feature-foo'
73
+ * ```
74
+ */
75
+ function getSessionName(worktreeId) {
76
+ return `mcbd-claude-${worktreeId}`;
77
+ }
78
+ /**
79
+ * Check if Claude is installed and available
80
+ *
81
+ * @returns True if Claude CLI is available
82
+ */
83
+ async function isClaudeInstalled() {
84
+ try {
85
+ await execAsync('which claude', { timeout: 5000 });
86
+ return true;
87
+ }
88
+ catch {
89
+ return false;
90
+ }
91
+ }
92
+ /**
93
+ * Check if Claude session is running
94
+ *
95
+ * @param worktreeId - Worktree ID
96
+ * @returns True if Claude session exists and is running
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * const running = await isClaudeRunning('feature-foo');
101
+ * if (running) {
102
+ * console.log('Claude is ready');
103
+ * }
104
+ * ```
105
+ */
106
+ async function isClaudeRunning(worktreeId) {
107
+ const sessionName = getSessionName(worktreeId);
108
+ return await (0, tmux_1.hasSession)(sessionName);
109
+ }
110
+ /**
111
+ * Get Claude session state
112
+ *
113
+ * @param worktreeId - Worktree ID
114
+ * @returns Session state information
115
+ */
116
+ async function getClaudeSessionState(worktreeId) {
117
+ const sessionName = getSessionName(worktreeId);
118
+ const isRunning = await (0, tmux_1.hasSession)(sessionName);
119
+ return {
120
+ sessionName,
121
+ isRunning,
122
+ lastActivity: new Date(),
123
+ };
124
+ }
125
+ /**
126
+ * Start a Claude CLI session in tmux
127
+ *
128
+ * @param options - Session options
129
+ * @throws {Error} If Claude CLI is not installed or session creation fails
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * await startClaudeSession({
134
+ * worktreeId: 'feature-foo',
135
+ * worktreePath: '/path/to/worktree',
136
+ * baseUrl: 'http://localhost:3000',
137
+ * });
138
+ * ```
139
+ */
140
+ async function startClaudeSession(options) {
141
+ const { worktreeId, worktreePath } = options;
142
+ // Check if Claude is installed
143
+ const claudeAvailable = await isClaudeInstalled();
144
+ if (!claudeAvailable) {
145
+ throw new Error('Claude CLI is not installed or not in PATH');
146
+ }
147
+ const sessionName = getSessionName(worktreeId);
148
+ // Check if session already exists
149
+ const exists = await (0, tmux_1.hasSession)(sessionName);
150
+ if (exists) {
151
+ console.log(`Claude session ${sessionName} already exists`);
152
+ return;
153
+ }
154
+ try {
155
+ // Create tmux session with large history buffer for Claude output
156
+ await (0, tmux_1.createSession)({
157
+ sessionName,
158
+ workingDirectory: worktreePath,
159
+ historyLimit: 50000,
160
+ });
161
+ // Get Claude CLI path dynamically
162
+ const claudePath = await getClaudePath();
163
+ // Start Claude CLI in interactive mode using dynamically resolved path
164
+ await (0, tmux_1.sendKeys)(sessionName, claudePath, true);
165
+ // Wait for Claude to initialize with dynamic detection
166
+ // Check for Claude prompt instead of fixed delay
167
+ const maxWaitTime = 10000; // 10 seconds max
168
+ const pollInterval = 500; // Check every 500ms
169
+ const startTime = Date.now();
170
+ while (Date.now() - startTime < maxWaitTime) {
171
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
172
+ try {
173
+ const output = await (0, tmux_1.capturePane)(sessionName, { startLine: -50 });
174
+ // Claude is ready when we see the prompt (> ) or separator line
175
+ if (/^>\s*$/m.test(output) || /^─{10,}$/m.test(output)) {
176
+ console.log(`✓ Claude initialized in ${Date.now() - startTime}ms`);
177
+ break;
178
+ }
179
+ }
180
+ catch {
181
+ // Ignore capture errors during initialization
182
+ }
183
+ }
184
+ console.log(`✓ Started Claude session: ${sessionName}`);
185
+ }
186
+ catch (error) {
187
+ const errorMessage = error instanceof Error ? error.message : String(error);
188
+ throw new Error(`Failed to start Claude session: ${errorMessage}`);
189
+ }
190
+ }
191
+ /**
192
+ * Send a message to Claude CLI
193
+ *
194
+ * @param worktreeId - Worktree ID
195
+ * @param message - Message content to send
196
+ * @throws {Error} If session doesn't exist
197
+ *
198
+ * @example
199
+ * ```typescript
200
+ * await sendMessageToClaude('feature-foo', 'Explain this code');
201
+ * ```
202
+ */
203
+ async function sendMessageToClaude(worktreeId, message) {
204
+ const sessionName = getSessionName(worktreeId);
205
+ // Check if session exists
206
+ const exists = await (0, tmux_1.hasSession)(sessionName);
207
+ if (!exists) {
208
+ throw new Error(`Claude session ${sessionName} does not exist. Start the session first.`);
209
+ }
210
+ try {
211
+ // Send message to Claude (without Enter)
212
+ await (0, tmux_1.sendKeys)(sessionName, message, false);
213
+ // Wait a moment for the text to be typed
214
+ await new Promise((resolve) => setTimeout(resolve, 100));
215
+ // Send Enter key to submit (single Enter submits in Claude Code CLI)
216
+ await execAsync(`tmux send-keys -t "${sessionName}" C-m`);
217
+ // Wait a moment for the message to be processed
218
+ await new Promise((resolve) => setTimeout(resolve, 200));
219
+ console.log(`✓ Sent message to Claude session: ${sessionName}`);
220
+ }
221
+ catch (error) {
222
+ const errorMessage = error instanceof Error ? error.message : String(error);
223
+ throw new Error(`Failed to send message to Claude: ${errorMessage}`);
224
+ }
225
+ }
226
+ /**
227
+ * Capture Claude session output
228
+ *
229
+ * @param worktreeId - Worktree ID
230
+ * @param lines - Number of lines to capture (default: 1000)
231
+ * @returns Captured output
232
+ *
233
+ * @example
234
+ * ```typescript
235
+ * const output = await captureClaudeOutput('feature-foo');
236
+ * console.log(output);
237
+ * ```
238
+ */
239
+ async function captureClaudeOutput(worktreeId, lines = 1000) {
240
+ const sessionName = getSessionName(worktreeId);
241
+ // Check if session exists
242
+ const exists = await (0, tmux_1.hasSession)(sessionName);
243
+ if (!exists) {
244
+ throw new Error(`Claude session ${sessionName} does not exist`);
245
+ }
246
+ try {
247
+ return await (0, tmux_1.capturePane)(sessionName, { startLine: -lines });
248
+ }
249
+ catch (error) {
250
+ const errorMessage = error instanceof Error ? error.message : String(error);
251
+ throw new Error(`Failed to capture Claude output: ${errorMessage}`);
252
+ }
253
+ }
254
+ /**
255
+ * Stop a Claude session
256
+ *
257
+ * @param worktreeId - Worktree ID
258
+ * @returns True if session was stopped, false if it didn't exist
259
+ *
260
+ * @example
261
+ * ```typescript
262
+ * await stopClaudeSession('feature-foo');
263
+ * ```
264
+ */
265
+ async function stopClaudeSession(worktreeId) {
266
+ const sessionName = getSessionName(worktreeId);
267
+ try {
268
+ // Send Ctrl+D to exit Claude gracefully
269
+ const exists = await (0, tmux_1.hasSession)(sessionName);
270
+ if (exists) {
271
+ await (0, tmux_1.sendKeys)(sessionName, '', false);
272
+ // Send Ctrl+D (ASCII 4)
273
+ await execAsync(`tmux send-keys -t "${sessionName}" C-d`);
274
+ // Wait a moment for Claude to exit
275
+ await new Promise((resolve) => setTimeout(resolve, 500));
276
+ }
277
+ // Kill the tmux session
278
+ const killed = await (0, tmux_1.killSession)(sessionName);
279
+ if (killed) {
280
+ console.log(`✓ Stopped Claude session: ${sessionName}`);
281
+ }
282
+ return killed;
283
+ }
284
+ catch (error) {
285
+ const errorMessage = error instanceof Error ? error.message : String(error);
286
+ console.error(`Error stopping Claude session: ${errorMessage}`);
287
+ return false;
288
+ }
289
+ }
290
+ /**
291
+ * Restart a Claude session
292
+ *
293
+ * @param options - Session options
294
+ *
295
+ * @example
296
+ * ```typescript
297
+ * await restartClaudeSession({
298
+ * worktreeId: 'feature-foo',
299
+ * worktreePath: '/path/to/worktree',
300
+ * baseUrl: 'http://localhost:3000',
301
+ * });
302
+ * ```
303
+ */
304
+ async function restartClaudeSession(options) {
305
+ const { worktreeId } = options;
306
+ // Stop existing session
307
+ await stopClaudeSession(worktreeId);
308
+ // Wait a moment before restarting
309
+ await new Promise((resolve) => setTimeout(resolve, 1000));
310
+ // Start new session
311
+ await startClaudeSession(options);
312
+ }