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
@@ -0,0 +1,777 @@
1
+ "use strict";
2
+ /**
3
+ * Database Migration System
4
+ * Manages schema versioning and migrations for SQLite database
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
+ exports.CURRENT_SCHEMA_VERSION = void 0;
11
+ exports.getCurrentVersion = getCurrentVersion;
12
+ exports.runMigrations = runMigrations;
13
+ exports.rollbackMigrations = rollbackMigrations;
14
+ exports.getMigrationHistory = getMigrationHistory;
15
+ exports.validateSchema = validateSchema;
16
+ const path_1 = __importDefault(require("path"));
17
+ const db_1 = require("./db");
18
+ /**
19
+ * Current schema version
20
+ * Increment this when adding new migrations
21
+ */
22
+ exports.CURRENT_SCHEMA_VERSION = 14;
23
+ /**
24
+ * Migration registry
25
+ * All migrations should be added to this array in order
26
+ */
27
+ const migrations = [
28
+ {
29
+ version: 1,
30
+ name: 'initial-schema',
31
+ up: (db) => {
32
+ // Use existing initDatabase function for initial schema
33
+ (0, db_1.initDatabase)(db);
34
+ },
35
+ down: (db) => {
36
+ // Drop all tables (for testing purposes)
37
+ db.exec(`DROP TABLE IF EXISTS session_states;`);
38
+ db.exec(`DROP TABLE IF EXISTS chat_messages;`);
39
+ db.exec(`DROP TABLE IF EXISTS worktrees;`);
40
+ }
41
+ },
42
+ {
43
+ version: 2,
44
+ name: 'add-multi-repo-and-memo-support',
45
+ up: (db) => {
46
+ // 1. Add new columns to worktrees table
47
+ db.exec(`
48
+ ALTER TABLE worktrees ADD COLUMN repository_path TEXT;
49
+ ALTER TABLE worktrees ADD COLUMN repository_name TEXT;
50
+ ALTER TABLE worktrees ADD COLUMN memo TEXT;
51
+ ALTER TABLE worktrees ADD COLUMN last_user_message TEXT;
52
+ ALTER TABLE worktrees ADD COLUMN last_user_message_at INTEGER;
53
+ `);
54
+ // 2. Create index on repository_path
55
+ db.exec(`
56
+ CREATE INDEX IF NOT EXISTS idx_worktrees_repository
57
+ ON worktrees(repository_path);
58
+ `);
59
+ // 3. Migrate existing data
60
+ // Extract repository information from worktree paths
61
+ const worktrees = db.prepare('SELECT id, path FROM worktrees').all();
62
+ const updateStmt = db.prepare(`
63
+ UPDATE worktrees
64
+ SET repository_path = ?,
65
+ repository_name = ?
66
+ WHERE id = ?
67
+ `);
68
+ for (const wt of worktrees) {
69
+ // Find repository root by looking for .git directory
70
+ const repoPath = findRepositoryRoot(wt.path);
71
+ const repoName = path_1.default.basename(repoPath);
72
+ updateStmt.run(repoPath, repoName, wt.id);
73
+ }
74
+ // 4. Populate last_user_message from chat_messages
75
+ const updateMessageStmt = db.prepare(`
76
+ UPDATE worktrees
77
+ SET last_user_message = ?,
78
+ last_user_message_at = ?
79
+ WHERE id = ?
80
+ `);
81
+ for (const wt of worktrees) {
82
+ const latestUserMsg = db.prepare(`
83
+ SELECT content, timestamp
84
+ FROM chat_messages
85
+ WHERE worktree_id = ? AND role = 'user'
86
+ ORDER BY timestamp DESC
87
+ LIMIT 1
88
+ `).get(wt.id);
89
+ if (latestUserMsg) {
90
+ // Truncate message to 200 characters
91
+ const truncatedMessage = latestUserMsg.content.substring(0, 200);
92
+ updateMessageStmt.run(truncatedMessage, latestUserMsg.timestamp, wt.id);
93
+ }
94
+ }
95
+ },
96
+ down: (db) => {
97
+ // Remove columns (SQLite doesn't support DROP COLUMN directly)
98
+ // Instead, we recreate the table without the new columns
99
+ db.exec(`
100
+ -- Create backup table
101
+ CREATE TABLE worktrees_backup AS
102
+ SELECT id, name, path, last_message_summary, updated_at
103
+ FROM worktrees;
104
+
105
+ -- Drop original table
106
+ DROP TABLE worktrees;
107
+
108
+ -- Recreate original table
109
+ CREATE TABLE worktrees (
110
+ id TEXT PRIMARY KEY,
111
+ name TEXT NOT NULL,
112
+ path TEXT NOT NULL UNIQUE,
113
+ last_message_summary TEXT,
114
+ updated_at INTEGER
115
+ );
116
+
117
+ -- Restore data
118
+ INSERT INTO worktrees (id, name, path, last_message_summary, updated_at)
119
+ SELECT id, name, path, last_message_summary, updated_at
120
+ FROM worktrees_backup;
121
+
122
+ -- Drop backup table
123
+ DROP TABLE worktrees_backup;
124
+
125
+ -- Drop index
126
+ DROP INDEX IF EXISTS idx_worktrees_repository;
127
+ `);
128
+ }
129
+ },
130
+ {
131
+ version: 3,
132
+ name: 'fix-worktree-repository-paths',
133
+ up: (db) => {
134
+ // Fix repository paths for git worktrees
135
+ // The previous migration incorrectly set repository_path to the worktree path itself
136
+ // This migration re-runs the detection with the fixed findRepositoryRoot function
137
+ const worktrees = db.prepare('SELECT id, path FROM worktrees').all();
138
+ const updateStmt = db.prepare(`
139
+ UPDATE worktrees
140
+ SET repository_path = ?,
141
+ repository_name = ?
142
+ WHERE id = ?
143
+ `);
144
+ for (const wt of worktrees) {
145
+ const repoPath = findRepositoryRoot(wt.path);
146
+ const repoName = path_1.default.basename(repoPath);
147
+ updateStmt.run(repoPath, repoName, wt.id);
148
+ }
149
+ },
150
+ down: () => {
151
+ // No down migration needed - this is a data fix
152
+ console.log('No rollback needed for repository path fix');
153
+ }
154
+ },
155
+ {
156
+ version: 4,
157
+ name: 'add-favorite-field',
158
+ up: (db) => {
159
+ // Add favorite column to worktrees table
160
+ db.exec(`
161
+ ALTER TABLE worktrees ADD COLUMN favorite INTEGER DEFAULT 0;
162
+ `);
163
+ // Create index on favorite for faster sorting
164
+ db.exec(`
165
+ CREATE INDEX IF NOT EXISTS idx_worktrees_favorite
166
+ ON worktrees(favorite DESC, updated_at DESC);
167
+ `);
168
+ },
169
+ down: (db) => {
170
+ // Remove favorite column (SQLite doesn't support DROP COLUMN directly)
171
+ // We need to recreate the table without the favorite column
172
+ db.exec(`
173
+ -- Drop the index first
174
+ DROP INDEX IF EXISTS idx_worktrees_favorite;
175
+
176
+ -- Note: In production, you'd need to recreate the table without the favorite column
177
+ -- This is a simplified down migration
178
+ `);
179
+ }
180
+ },
181
+ {
182
+ version: 5,
183
+ name: 'add-status-field',
184
+ up: (db) => {
185
+ // Add status column to worktrees table
186
+ // Values: 'todo', 'doing', 'done', or NULL (not set)
187
+ db.exec(`
188
+ ALTER TABLE worktrees ADD COLUMN status TEXT DEFAULT NULL;
189
+ `);
190
+ // Create index on status for faster filtering
191
+ db.exec(`
192
+ CREATE INDEX IF NOT EXISTS idx_worktrees_status
193
+ ON worktrees(status);
194
+ `);
195
+ },
196
+ down: (rollbackDb) => {
197
+ // Remove status index
198
+ rollbackDb.exec(`
199
+ DROP INDEX IF EXISTS idx_worktrees_status;
200
+ `);
201
+ }
202
+ },
203
+ {
204
+ version: 6,
205
+ name: 'add-link-field',
206
+ up: (db) => {
207
+ // Add link column to worktrees table for storing external URLs
208
+ db.exec(`
209
+ ALTER TABLE worktrees ADD COLUMN link TEXT DEFAULT NULL;
210
+ `);
211
+ },
212
+ down: () => {
213
+ // No down migration needed - SQLite doesn't support DROP COLUMN directly
214
+ console.log('No rollback needed for link field');
215
+ }
216
+ },
217
+ {
218
+ version: 7,
219
+ name: 'add-cli-tool-id',
220
+ up: (db) => {
221
+ // Add cli_tool_id column to worktrees table
222
+ // Default to 'claude' for backward compatibility
223
+ db.exec(`
224
+ ALTER TABLE worktrees ADD COLUMN cli_tool_id TEXT DEFAULT 'claude';
225
+ `);
226
+ // Create index on cli_tool_id for faster filtering by tool type
227
+ db.exec(`
228
+ CREATE INDEX IF NOT EXISTS idx_worktrees_cli_tool
229
+ ON worktrees(cli_tool_id);
230
+ `);
231
+ // Update existing worktrees to explicitly set cli_tool_id to 'claude'
232
+ // This ensures all existing worktrees have a non-null value
233
+ db.exec(`
234
+ UPDATE worktrees SET cli_tool_id = 'claude' WHERE cli_tool_id IS NULL;
235
+ `);
236
+ },
237
+ down: (db) => {
238
+ // Remove the index
239
+ db.exec(`
240
+ DROP INDEX IF EXISTS idx_worktrees_cli_tool;
241
+ `);
242
+ // Note: SQLite doesn't support DROP COLUMN directly
243
+ // In production, you would need to recreate the table without cli_tool_id
244
+ console.log('No full rollback for cli_tool_id column (SQLite limitation)');
245
+ }
246
+ },
247
+ {
248
+ version: 8,
249
+ name: 'change-role-claude-to-assistant',
250
+ up: (db) => {
251
+ // SQLite doesn't support ALTER TABLE MODIFY COLUMN or changing CHECK constraints
252
+ // We need to recreate the table with the new constraint
253
+ // Create new table with updated role constraint
254
+ db.exec(`
255
+ CREATE TABLE chat_messages_new (
256
+ id TEXT PRIMARY KEY,
257
+ worktree_id TEXT NOT NULL,
258
+ role TEXT NOT NULL CHECK (role IN ('user', 'assistant')),
259
+ content TEXT NOT NULL,
260
+ summary TEXT,
261
+ timestamp INTEGER NOT NULL,
262
+ log_file_name TEXT,
263
+ request_id TEXT,
264
+ message_type TEXT DEFAULT 'normal',
265
+ prompt_data TEXT,
266
+ cli_tool_id TEXT DEFAULT 'claude',
267
+ FOREIGN KEY (worktree_id) REFERENCES worktrees(id) ON DELETE CASCADE
268
+ );
269
+ `);
270
+ // Copy data from old table, converting 'claude' role to 'assistant'
271
+ db.exec(`
272
+ INSERT INTO chat_messages_new
273
+ SELECT
274
+ id,
275
+ worktree_id,
276
+ CASE WHEN role = 'claude' THEN 'assistant' ELSE role END as role,
277
+ content,
278
+ summary,
279
+ timestamp,
280
+ log_file_name,
281
+ request_id,
282
+ message_type,
283
+ prompt_data,
284
+ cli_tool_id
285
+ FROM chat_messages;
286
+ `);
287
+ // Drop old table
288
+ db.exec(`DROP TABLE chat_messages;`);
289
+ // Rename new table to original name
290
+ db.exec(`ALTER TABLE chat_messages_new RENAME TO chat_messages;`);
291
+ // Recreate indexes
292
+ db.exec(`
293
+ CREATE INDEX IF NOT EXISTS idx_chat_messages_worktree
294
+ ON chat_messages(worktree_id);
295
+ `);
296
+ db.exec(`
297
+ CREATE INDEX IF NOT EXISTS idx_chat_messages_timestamp
298
+ ON chat_messages(timestamp);
299
+ `);
300
+ console.log('✓ Changed role constraint from "claude" to "assistant"');
301
+ console.log('✓ Updated existing messages with role="claude" to role="assistant"');
302
+ },
303
+ down: (db) => {
304
+ // Rollback: change 'assistant' back to 'claude'
305
+ db.exec(`
306
+ CREATE TABLE chat_messages_new (
307
+ id TEXT PRIMARY KEY,
308
+ worktree_id TEXT NOT NULL,
309
+ role TEXT NOT NULL CHECK (role IN ('user', 'claude')),
310
+ content TEXT NOT NULL,
311
+ summary TEXT,
312
+ timestamp INTEGER NOT NULL,
313
+ log_file_name TEXT,
314
+ request_id TEXT,
315
+ message_type TEXT DEFAULT 'normal',
316
+ prompt_data TEXT,
317
+ cli_tool_id TEXT DEFAULT 'claude',
318
+ FOREIGN KEY (worktree_id) REFERENCES worktrees(id) ON DELETE CASCADE
319
+ );
320
+ `);
321
+ db.exec(`
322
+ INSERT INTO chat_messages_new
323
+ SELECT
324
+ id,
325
+ worktree_id,
326
+ CASE WHEN role = 'assistant' THEN 'claude' ELSE role END as role,
327
+ content,
328
+ summary,
329
+ timestamp,
330
+ log_file_name,
331
+ request_id,
332
+ message_type,
333
+ prompt_data,
334
+ cli_tool_id
335
+ FROM chat_messages;
336
+ `);
337
+ db.exec(`DROP TABLE chat_messages;`);
338
+ db.exec(`ALTER TABLE chat_messages_new RENAME TO chat_messages;`);
339
+ db.exec(`
340
+ CREATE INDEX IF NOT EXISTS idx_chat_messages_worktree
341
+ ON chat_messages(worktree_id);
342
+ `);
343
+ db.exec(`
344
+ CREATE INDEX IF NOT EXISTS idx_chat_messages_timestamp
345
+ ON chat_messages(timestamp);
346
+ `);
347
+ console.log('✓ Rolled back: Changed role constraint from "assistant" to "claude"');
348
+ }
349
+ },
350
+ {
351
+ version: 9,
352
+ name: 'add-in-progress-message-id-to-session-states',
353
+ up: (db) => {
354
+ // Add in_progress_message_id column to session_states table
355
+ // This column tracks the message ID being actively updated during polling
356
+ db.exec(`
357
+ ALTER TABLE session_states ADD COLUMN in_progress_message_id TEXT DEFAULT NULL;
358
+ `);
359
+ console.log('✓ Added in_progress_message_id column to session_states table');
360
+ },
361
+ down: () => {
362
+ // Note: SQLite doesn't support DROP COLUMN directly
363
+ // In production, you would need to recreate the table without in_progress_message_id
364
+ console.log('No full rollback for in_progress_message_id column (SQLite limitation)');
365
+ }
366
+ },
367
+ {
368
+ version: 10,
369
+ name: 'add-worktree-memos-table',
370
+ up: (db) => {
371
+ // 1. Create worktree_memos table
372
+ db.exec(`
373
+ CREATE TABLE worktree_memos (
374
+ id TEXT PRIMARY KEY,
375
+ worktree_id TEXT NOT NULL,
376
+ title TEXT NOT NULL DEFAULT 'Memo',
377
+ content TEXT NOT NULL DEFAULT '',
378
+ position INTEGER NOT NULL DEFAULT 0,
379
+ created_at INTEGER NOT NULL,
380
+ updated_at INTEGER NOT NULL,
381
+
382
+ FOREIGN KEY (worktree_id) REFERENCES worktrees(id) ON DELETE CASCADE,
383
+ UNIQUE(worktree_id, position)
384
+ );
385
+ `);
386
+ // 2. Create index on worktree_id and position
387
+ db.exec(`
388
+ CREATE INDEX idx_worktree_memos_worktree
389
+ ON worktree_memos(worktree_id, position);
390
+ `);
391
+ // 3. Migrate existing memo data from worktrees table
392
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
393
+ const { randomUUID } = require('crypto');
394
+ const worktrees = db.prepare(`
395
+ SELECT id, memo FROM worktrees WHERE memo IS NOT NULL AND memo != ''
396
+ `).all();
397
+ const insertStmt = db.prepare(`
398
+ INSERT INTO worktree_memos (id, worktree_id, title, content, position, created_at, updated_at)
399
+ VALUES (?, ?, 'Memo', ?, 0, ?, ?)
400
+ `);
401
+ const now = Date.now();
402
+ for (const wt of worktrees) {
403
+ insertStmt.run(randomUUID(), wt.id, wt.memo, now, now);
404
+ }
405
+ console.log(`✓ Created worktree_memos table`);
406
+ console.log(`✓ Migrated ${worktrees.length} existing memos to new table`);
407
+ },
408
+ down: (db) => {
409
+ db.exec('DROP TABLE IF EXISTS worktree_memos');
410
+ console.log('✓ Dropped worktree_memos table');
411
+ }
412
+ },
413
+ {
414
+ version: 11,
415
+ name: 'add-viewed-tracking',
416
+ up: (db) => {
417
+ // G3: Add last_viewed_at column to worktrees table
418
+ db.exec(`
419
+ ALTER TABLE worktrees ADD COLUMN last_viewed_at TEXT;
420
+ `);
421
+ // MF2: Add performance index for assistant message queries
422
+ db.exec(`
423
+ CREATE INDEX IF NOT EXISTS idx_chat_messages_assistant_latest
424
+ ON chat_messages(worktree_id, role, timestamp DESC);
425
+ `);
426
+ console.log('✓ Added last_viewed_at column to worktrees table');
427
+ console.log('✓ Created index for assistant message queries');
428
+ },
429
+ down: (db) => {
430
+ db.exec('DROP INDEX IF EXISTS idx_chat_messages_assistant_latest');
431
+ console.log('✓ Dropped idx_chat_messages_assistant_latest index');
432
+ // Note: SQLite doesn't support DROP COLUMN directly
433
+ }
434
+ },
435
+ {
436
+ version: 12,
437
+ name: 'add-external-apps-table',
438
+ up: (db) => {
439
+ // Issue #42: Create external_apps table for proxy routing
440
+ db.exec(`
441
+ CREATE TABLE IF NOT EXISTS external_apps (
442
+ id TEXT PRIMARY KEY,
443
+
444
+ -- Basic info
445
+ name TEXT NOT NULL UNIQUE,
446
+ display_name TEXT NOT NULL,
447
+ description TEXT,
448
+
449
+ -- Routing config
450
+ path_prefix TEXT NOT NULL UNIQUE,
451
+ target_port INTEGER NOT NULL,
452
+ target_host TEXT DEFAULT 'localhost',
453
+
454
+ -- App type
455
+ app_type TEXT NOT NULL CHECK(app_type IN ('sveltekit', 'streamlit', 'nextjs', 'other')),
456
+
457
+ -- WebSocket config
458
+ websocket_enabled INTEGER DEFAULT 0,
459
+ websocket_path_pattern TEXT,
460
+
461
+ -- Status
462
+ enabled INTEGER DEFAULT 1,
463
+
464
+ -- Metadata
465
+ created_at INTEGER NOT NULL,
466
+ updated_at INTEGER NOT NULL
467
+ );
468
+ `);
469
+ // Create indexes for performance
470
+ db.exec(`
471
+ CREATE INDEX idx_external_apps_path_prefix ON external_apps(path_prefix);
472
+ `);
473
+ db.exec(`
474
+ CREATE INDEX idx_external_apps_enabled ON external_apps(enabled);
475
+ `);
476
+ console.log('✓ Created external_apps table');
477
+ console.log('✓ Created indexes for external_apps');
478
+ },
479
+ down: (db) => {
480
+ db.exec('DROP INDEX IF EXISTS idx_external_apps_enabled');
481
+ db.exec('DROP INDEX IF EXISTS idx_external_apps_path_prefix');
482
+ db.exec('DROP TABLE IF EXISTS external_apps');
483
+ console.log('✓ Dropped external_apps table and indexes');
484
+ }
485
+ },
486
+ {
487
+ version: 13,
488
+ name: 'rename-worktree-memo-to-description',
489
+ up: (db) => {
490
+ db.exec(`
491
+ ALTER TABLE worktrees RENAME COLUMN memo TO description;
492
+ `);
493
+ console.log('✓ Renamed worktrees.memo column to description');
494
+ },
495
+ down: (db) => {
496
+ db.exec(`
497
+ ALTER TABLE worktrees RENAME COLUMN description TO memo;
498
+ `);
499
+ console.log('✓ Rolled back: Renamed worktrees.description column back to memo');
500
+ }
501
+ },
502
+ {
503
+ version: 14,
504
+ name: 'add-repositories-and-clone-jobs-tables',
505
+ up: (db) => {
506
+ // Issue #71: Clone URL registration feature
507
+ // Create repositories table for managing cloned repositories
508
+ db.exec(`
509
+ CREATE TABLE IF NOT EXISTS repositories (
510
+ id TEXT PRIMARY KEY,
511
+ name TEXT NOT NULL,
512
+ path TEXT NOT NULL UNIQUE,
513
+ enabled INTEGER NOT NULL DEFAULT 1,
514
+ clone_url TEXT,
515
+ normalized_clone_url TEXT,
516
+ clone_source TEXT CHECK(clone_source IN ('local', 'https', 'ssh')) DEFAULT 'local',
517
+ is_env_managed INTEGER NOT NULL DEFAULT 0,
518
+ created_at INTEGER NOT NULL,
519
+ updated_at INTEGER NOT NULL
520
+ );
521
+ `);
522
+ // Create unique index on normalized_clone_url for duplicate prevention
523
+ // NULL values are allowed (for local repos without clone URL)
524
+ db.exec(`
525
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_repositories_normalized_clone_url
526
+ ON repositories(normalized_clone_url)
527
+ WHERE normalized_clone_url IS NOT NULL;
528
+ `);
529
+ // Create index on path for fast lookups
530
+ db.exec(`
531
+ CREATE INDEX IF NOT EXISTS idx_repositories_path
532
+ ON repositories(path);
533
+ `);
534
+ // Create clone_jobs table for tracking clone operations
535
+ db.exec(`
536
+ CREATE TABLE IF NOT EXISTS clone_jobs (
537
+ id TEXT PRIMARY KEY,
538
+ clone_url TEXT NOT NULL,
539
+ normalized_clone_url TEXT NOT NULL,
540
+ target_path TEXT NOT NULL,
541
+ repository_id TEXT,
542
+ status TEXT NOT NULL CHECK(status IN ('pending', 'running', 'completed', 'failed', 'cancelled')) DEFAULT 'pending',
543
+ pid INTEGER,
544
+ progress INTEGER NOT NULL DEFAULT 0,
545
+ error_category TEXT,
546
+ error_code TEXT,
547
+ error_message TEXT,
548
+ started_at INTEGER,
549
+ completed_at INTEGER,
550
+ created_at INTEGER NOT NULL,
551
+
552
+ FOREIGN KEY (repository_id) REFERENCES repositories(id) ON DELETE SET NULL
553
+ );
554
+ `);
555
+ // Create index on clone_jobs.status for querying active jobs
556
+ db.exec(`
557
+ CREATE INDEX IF NOT EXISTS idx_clone_jobs_status
558
+ ON clone_jobs(status);
559
+ `);
560
+ // Create index on clone_jobs.normalized_clone_url for duplicate prevention
561
+ db.exec(`
562
+ CREATE INDEX IF NOT EXISTS idx_clone_jobs_normalized_clone_url
563
+ ON clone_jobs(normalized_clone_url);
564
+ `);
565
+ console.log('✓ Created repositories table');
566
+ console.log('✓ Created clone_jobs table');
567
+ console.log('✓ Created indexes for repositories and clone_jobs');
568
+ },
569
+ down: (db) => {
570
+ db.exec('DROP INDEX IF EXISTS idx_clone_jobs_normalized_clone_url');
571
+ db.exec('DROP INDEX IF EXISTS idx_clone_jobs_status');
572
+ db.exec('DROP TABLE IF EXISTS clone_jobs');
573
+ db.exec('DROP INDEX IF EXISTS idx_repositories_path');
574
+ db.exec('DROP INDEX IF EXISTS idx_repositories_normalized_clone_url');
575
+ db.exec('DROP TABLE IF EXISTS repositories');
576
+ console.log('✓ Dropped repositories and clone_jobs tables');
577
+ }
578
+ }
579
+ ];
580
+ /**
581
+ * Helper function to find repository root from a worktree path
582
+ * Walks up the directory tree to find .git directory
583
+ * Handles both regular repos (.git directory) and worktrees (.git file)
584
+ */
585
+ function findRepositoryRoot(worktreePath) {
586
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
587
+ const fs = require('fs');
588
+ let currentPath = worktreePath;
589
+ // Walk up the directory tree
590
+ while (currentPath !== path_1.default.dirname(currentPath)) {
591
+ const gitPath = path_1.default.join(currentPath, '.git');
592
+ if (fs.existsSync(gitPath)) {
593
+ const stats = fs.statSync(gitPath);
594
+ if (stats.isDirectory()) {
595
+ // This is a regular repository
596
+ return currentPath;
597
+ }
598
+ else if (stats.isFile()) {
599
+ // This is a git worktree - read the gitdir reference
600
+ const gitFileContent = fs.readFileSync(gitPath, 'utf-8').trim();
601
+ // Format: "gitdir: /path/to/main/repo/.git/worktrees/branch-name"
602
+ const match = gitFileContent.match(/^gitdir:\s*(.+)$/);
603
+ if (match) {
604
+ // Extract main repo path from: /path/to/repo/.git/worktrees/branch-name
605
+ const gitDir = match[1];
606
+ // Remove "/.git/worktrees/branch-name" to get repo root
607
+ const repoRoot = gitDir.split('/.git/')[0];
608
+ return repoRoot;
609
+ }
610
+ }
611
+ }
612
+ currentPath = path_1.default.dirname(currentPath);
613
+ }
614
+ // If no .git found, return the worktree path itself
615
+ return worktreePath;
616
+ }
617
+ /**
618
+ * Get current schema version from database
619
+ */
620
+ function getCurrentVersion(db) {
621
+ try {
622
+ const result = db.prepare('SELECT MAX(version) as version FROM schema_version').get();
623
+ return result?.version ?? 0;
624
+ }
625
+ catch {
626
+ // Table doesn't exist yet
627
+ return 0;
628
+ }
629
+ }
630
+ /**
631
+ * Initialize schema_version table
632
+ */
633
+ function initSchemaVersionTable(db) {
634
+ db.exec(`
635
+ CREATE TABLE IF NOT EXISTS schema_version (
636
+ version INTEGER PRIMARY KEY,
637
+ name TEXT NOT NULL,
638
+ applied_at INTEGER NOT NULL
639
+ );
640
+ `);
641
+ }
642
+ /**
643
+ * Run all pending migrations
644
+ *
645
+ * @param db - Database instance
646
+ * @throws Error if migration fails
647
+ */
648
+ function runMigrations(db) {
649
+ // Initialize schema_version table
650
+ initSchemaVersionTable(db);
651
+ // Get current version
652
+ const currentVersion = getCurrentVersion(db);
653
+ console.log(`Current schema version: ${currentVersion}`);
654
+ // Find pending migrations
655
+ const pendingMigrations = migrations.filter(migration => migration.version > currentVersion);
656
+ if (pendingMigrations.length === 0) {
657
+ console.log('✓ Schema is up to date');
658
+ return;
659
+ }
660
+ console.log(`Found ${pendingMigrations.length} pending migration(s)`);
661
+ // Run each pending migration in a transaction
662
+ for (const migration of pendingMigrations) {
663
+ console.log(`Applying migration ${migration.version}: ${migration.name}...`);
664
+ try {
665
+ // Run migration in transaction
666
+ db.transaction(() => {
667
+ // Execute migration
668
+ migration.up(db);
669
+ // Record migration in schema_version table
670
+ db.prepare(`
671
+ INSERT INTO schema_version (version, name, applied_at)
672
+ VALUES (?, ?, ?)
673
+ `).run(migration.version, migration.name, Date.now());
674
+ })();
675
+ console.log(`✓ Migration ${migration.version} applied successfully`);
676
+ }
677
+ catch (error) {
678
+ const errorMessage = error instanceof Error ? error.message : String(error);
679
+ console.error(`✗ Migration ${migration.version} failed:`, errorMessage);
680
+ throw new Error(`Migration ${migration.version} (${migration.name}) failed: ${errorMessage}`);
681
+ }
682
+ }
683
+ console.log(`✓ All migrations completed. Current version: ${getCurrentVersion(db)}`);
684
+ }
685
+ /**
686
+ * Rollback migrations to a specific version
687
+ *
688
+ * @param db - Database instance
689
+ * @param targetVersion - Version to rollback to
690
+ * @throws Error if rollback is not supported or fails
691
+ */
692
+ function rollbackMigrations(db, targetVersion) {
693
+ const currentVersion = getCurrentVersion(db);
694
+ if (targetVersion >= currentVersion) {
695
+ console.log('No rollback needed');
696
+ return;
697
+ }
698
+ console.log(`Rolling back from version ${currentVersion} to ${targetVersion}...`);
699
+ // Get migrations to rollback (in reverse order)
700
+ const migrationsToRollback = migrations
701
+ .filter(m => m.version > targetVersion && m.version <= currentVersion)
702
+ .sort((a, b) => b.version - a.version);
703
+ for (const migration of migrationsToRollback) {
704
+ if (!migration.down) {
705
+ throw new Error(`Cannot rollback migration ${migration.version} (${migration.name}): ` +
706
+ `no down() function defined`);
707
+ }
708
+ console.log(`Rolling back migration ${migration.version}: ${migration.name}...`);
709
+ try {
710
+ db.transaction(() => {
711
+ // Execute rollback
712
+ migration.down(db);
713
+ // Remove from schema_version table
714
+ db.prepare('DELETE FROM schema_version WHERE version = ?')
715
+ .run(migration.version);
716
+ })();
717
+ console.log(`✓ Migration ${migration.version} rolled back`);
718
+ }
719
+ catch (error) {
720
+ const errorMessage = error instanceof Error ? error.message : String(error);
721
+ console.error(`✗ Rollback ${migration.version} failed:`, errorMessage);
722
+ throw new Error(`Rollback of migration ${migration.version} failed: ${errorMessage}`);
723
+ }
724
+ }
725
+ console.log(`✓ Rollback completed. Current version: ${getCurrentVersion(db)}`);
726
+ }
727
+ /**
728
+ * Get migration history
729
+ *
730
+ * @param db - Database instance
731
+ * @returns Array of applied migrations
732
+ */
733
+ function getMigrationHistory(db) {
734
+ try {
735
+ const rows = db.prepare(`
736
+ SELECT version, name, applied_at
737
+ FROM schema_version
738
+ ORDER BY version ASC
739
+ `).all();
740
+ return rows.map(row => ({
741
+ version: row.version,
742
+ name: row.name,
743
+ appliedAt: new Date(row.applied_at)
744
+ }));
745
+ }
746
+ catch {
747
+ return [];
748
+ }
749
+ }
750
+ /**
751
+ * Validate database schema
752
+ * Checks if all required tables exist
753
+ *
754
+ * @param db - Database instance
755
+ * @returns true if schema is valid
756
+ */
757
+ function validateSchema(db) {
758
+ try {
759
+ const tables = db.prepare(`
760
+ SELECT name FROM sqlite_master
761
+ WHERE type='table' AND name NOT LIKE 'sqlite_%'
762
+ ORDER BY name
763
+ `).all();
764
+ const tableNames = tables.map(t => t.name);
765
+ const requiredTables = ['worktrees', 'chat_messages', 'session_states', 'schema_version', 'worktree_memos', 'external_apps', 'repositories', 'clone_jobs'];
766
+ const missingTables = requiredTables.filter(t => !tableNames.includes(t));
767
+ if (missingTables.length > 0) {
768
+ console.error('Missing required tables:', missingTables.join(', '));
769
+ return false;
770
+ }
771
+ return true;
772
+ }
773
+ catch (schemaError) {
774
+ console.error('Schema validation failed:', schemaError);
775
+ return false;
776
+ }
777
+ }