commandmate 0.1.5 → 0.1.7
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.
- package/.next/BUILD_ID +1 -0
- package/.next/app-build-manifest.json +72 -0
- package/.next/app-path-routes-manifest.json +1 -0
- package/.next/build-manifest.json +32 -0
- package/.next/cache/.tsbuildinfo +1 -0
- package/.next/cache/config.json +7 -0
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/1.pack +0 -0
- package/.next/cache/webpack/client-production/2.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack.old +0 -0
- package/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/export-marker.json +1 -0
- package/.next/images-manifest.json +1 -0
- package/.next/next-minimal-server.js.nft.json +1 -0
- package/.next/next-server.js.nft.json +1 -0
- package/.next/package.json +1 -0
- package/.next/prerender-manifest.json +1 -0
- package/.next/react-loadable-manifest.json +249 -0
- package/.next/required-server-files.json +1 -0
- package/.next/routes-manifest.json +1 -0
- package/.next/server/app/_not-found/page.js +1 -0
- package/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/.next/server/app/_not-found.html +1 -0
- package/.next/server/app/_not-found.meta +6 -0
- package/.next/server/app/_not-found.rsc +10 -0
- package/.next/server/app/api/external-apps/[id]/health/route.js +45 -0
- package/.next/server/app/api/external-apps/[id]/health/route.js.nft.json +1 -0
- package/.next/server/app/api/external-apps/[id]/route.js +45 -0
- package/.next/server/app/api/external-apps/[id]/route.js.nft.json +1 -0
- package/.next/server/app/api/external-apps/route.js +45 -0
- package/.next/server/app/api/external-apps/route.js.nft.json +1 -0
- package/.next/server/app/api/hooks/claude-done/route.js +19 -0
- package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -0
- package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -0
- package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -0
- package/.next/server/app/api/repositories/clone/route.js +1 -0
- package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -0
- package/.next/server/app/api/repositories/route.js +1 -0
- package/.next/server/app/api/repositories/route.js.nft.json +1 -0
- package/.next/server/app/api/repositories/scan/route.js +1 -0
- package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -0
- package/.next/server/app/api/repositories/sync/route.js +1 -0
- package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -0
- package/.next/server/app/api/slash-commands/route.js +1 -0
- package/.next/server/app/api/slash-commands/route.js.nft.json +1 -0
- package/.next/server/app/api/slash-commands.body +1 -0
- package/.next/server/app/api/slash-commands.meta +1 -0
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/capture/route.js +2 -0
- package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/cli-tool/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/cli-tool/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/logs/route.js +19 -0
- package/.next/server/app/api/worktrees/[id]/logs/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/memos/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/memos/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/messages/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/messages/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/search/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/search/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/send/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/slash-commands/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/start-polling/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/start-polling/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/terminal/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/tree/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/tree/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/upload/[...path]/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/upload/[...path]/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/viewed/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/viewed/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/route.js +1 -0
- package/.next/server/app/api/worktrees/route.js.nft.json +1 -0
- package/.next/server/app/apple-icon.png/route.js +1 -0
- package/.next/server/app/apple-icon.png/route.js.nft.json +1 -0
- package/.next/server/app/apple-icon.png.body +0 -0
- package/.next/server/app/apple-icon.png.meta +1 -0
- package/.next/server/app/icon.png/route.js +1 -0
- package/.next/server/app/icon.png/route.js.nft.json +1 -0
- package/.next/server/app/icon.png.body +0 -0
- package/.next/server/app/icon.png.meta +1 -0
- package/.next/server/app/index.html +9 -0
- package/.next/server/app/index.meta +5 -0
- package/.next/server/app/index.rsc +8 -0
- package/.next/server/app/page.js +16 -0
- package/.next/server/app/page.js.nft.json +1 -0
- package/.next/server/app/page_client-reference-manifest.js +1 -0
- package/.next/server/app/proxy/[...path]/route.js +45 -0
- package/.next/server/app/proxy/[...path]/route.js.nft.json +1 -0
- package/.next/server/app/worktrees/[id]/files/[...path]/page.js +1 -0
- package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +1 -0
- package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -0
- package/.next/server/app/worktrees/[id]/page.js +21 -0
- package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -0
- package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -0
- package/.next/server/app/worktrees/[id]/simple-terminal/page.js +4 -0
- package/.next/server/app/worktrees/[id]/simple-terminal/page.js.nft.json +1 -0
- package/.next/server/app/worktrees/[id]/simple-terminal/page_client-reference-manifest.js +1 -0
- package/.next/server/app/worktrees/[id]/terminal/page.js +6 -0
- package/.next/server/app/worktrees/[id]/terminal/page.js.nft.json +1 -0
- package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -0
- package/.next/server/app-paths-manifest.json +46 -0
- package/.next/server/chunks/1318.js +29 -0
- package/.next/server/chunks/1528.js +1 -0
- package/.next/server/chunks/1682.js +6 -0
- package/.next/server/chunks/2518.js +12 -0
- package/.next/server/chunks/3053.js +1 -0
- package/.next/server/chunks/3673.js +1 -0
- package/.next/server/chunks/3853.js +1 -0
- package/.next/server/chunks/434.js +1 -0
- package/.next/server/chunks/4471.js +2 -0
- package/.next/server/chunks/4893.js +2 -0
- package/.next/server/chunks/5972.js +12 -0
- package/.next/server/chunks/6550.js +1 -0
- package/.next/server/chunks/6621.js +1 -0
- package/.next/server/chunks/7213.js +1 -0
- package/.next/server/chunks/7425.js +500 -0
- package/.next/server/chunks/8585.js +1 -0
- package/.next/server/chunks/8887.js +1 -0
- package/.next/server/chunks/8948.js +2 -0
- package/.next/server/chunks/9703.js +31 -0
- package/.next/server/chunks/9723.js +19 -0
- package/.next/server/chunks/font-manifest.json +1 -0
- package/.next/server/edge-runtime-webpack.js +2 -0
- package/.next/server/edge-runtime-webpack.js.map +1 -0
- package/.next/server/font-manifest.json +1 -0
- package/.next/server/functions-config-manifest.json +1 -0
- package/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/.next/server/middleware-build-manifest.js +1 -0
- package/.next/server/middleware-manifest.json +32 -0
- package/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/.next/server/next-font-manifest.js +1 -0
- package/.next/server/next-font-manifest.json +1 -0
- package/.next/server/pages/404.html +1 -0
- package/.next/server/pages/500.html +1 -0
- package/.next/server/pages/_app.js +1 -0
- package/.next/server/pages/_app.js.nft.json +1 -0
- package/.next/server/pages/_document.js +1 -0
- package/.next/server/pages/_document.js.nft.json +1 -0
- package/.next/server/pages/_error.js +1 -0
- package/.next/server/pages/_error.js.nft.json +1 -0
- package/.next/server/pages-manifest.json +1 -0
- package/.next/server/server-reference-manifest.js +1 -0
- package/.next/server/server-reference-manifest.json +1 -0
- package/.next/server/src/middleware.js +14 -0
- package/.next/server/src/middleware.js.map +1 -0
- package/.next/server/webpack-runtime.js +1 -0
- package/.next/static/3jNZMmFnQhc5G7met-OU4/_buildManifest.js +1 -0
- package/.next/static/3jNZMmFnQhc5G7met-OU4/_ssgManifest.js +1 -0
- package/.next/static/chunks/0dbeb660.3e800dfbd28be3bd.js +53 -0
- package/.next/static/chunks/1015.0eaa4da7f61149bc.js +59 -0
- package/.next/static/chunks/1098.49268c9fe1b028fa.js +1 -0
- package/.next/static/chunks/13.feeafc7cc620f8c4.js +1 -0
- package/.next/static/chunks/1423.7b1e8bf760d28078.js +1 -0
- package/.next/static/chunks/1582.9f8590f71ff798ca.js +55 -0
- package/.next/static/chunks/1817.a66d96cedb761daa.js +262 -0
- package/.next/static/chunks/2117-d845c2cd62e344a6.js +2 -0
- package/.next/static/chunks/2398.0b21e4eb7006a230.js +93 -0
- package/.next/static/chunks/2526.8ac62b527c9ab703.js +43 -0
- package/.next/static/chunks/2626.2125083a1ff3b80a.js +29 -0
- package/.next/static/chunks/2689.720a4874b02d4211.js +174 -0
- package/.next/static/chunks/2853-d11a80b03c9a1640.js +1 -0
- package/.next/static/chunks/2957-327e43ef4c12808f.js +1 -0
- package/.next/static/chunks/2cdb6380.35626fc6e41bbba4.js +136 -0
- package/.next/static/chunks/30d07d85-393352a92199f695.js +3 -0
- package/.next/static/chunks/3559.f073f72c4466ce0e.js +1 -0
- package/.next/static/chunks/3574.7a94c27e6a496a56.js +63 -0
- package/.next/static/chunks/383.20683891c9a5f2c4.js +4 -0
- package/.next/static/chunks/3843.3fdda732987f7bb8.js +1 -0
- package/.next/static/chunks/3852.822389f445c9b427.js +1 -0
- package/.next/static/chunks/3991.4bc063cb5be3a86c.js +1 -0
- package/.next/static/chunks/4212.52c1bb34fc97d0d0.js +131 -0
- package/.next/static/chunks/4327.3b84aa049900fdeb.js +60 -0
- package/.next/static/chunks/4362.7bd6f0282e49d79b.js +1 -0
- package/.next/static/chunks/4721.40615a5f4f32b5fb.js +1 -0
- package/.next/static/chunks/4851-45df4d388db5623f.js +1 -0
- package/.next/static/chunks/5112.17318d1c6b28044b.js +1 -0
- package/.next/static/chunks/5126.93fa4e797d609286.js +56 -0
- package/.next/static/chunks/5387.47590ac4ef66c864.js +5 -0
- package/.next/static/chunks/5813.4483664ba482beb1.js +1 -0
- package/.next/static/chunks/6143.1450875bd03a2366.js +36 -0
- package/.next/static/chunks/6406.9653f0d41ab85059.js +1 -0
- package/.next/static/chunks/656.d72f25ce819bd77e.js +149 -0
- package/.next/static/chunks/6678.492e73ca42b2a273.js +62 -0
- package/.next/static/chunks/6725-f7607851b7d57eb1.js +1 -0
- package/.next/static/chunks/6792.3c01ac4dda4b5c6d.js +1 -0
- package/.next/static/chunks/7004.808cbf327ef5955e.js +1 -0
- package/.next/static/chunks/7290.09ef84cf94f90c4d.js +1 -0
- package/.next/static/chunks/7415.6b481c2baf363262.js +148 -0
- package/.next/static/chunks/7648-325564a6e12a3257.js +1 -0
- package/.next/static/chunks/7665.47fccad04449a8f9.js +215 -0
- package/.next/static/chunks/7753.6bdce86b7fde3d10.js +166 -0
- package/.next/static/chunks/8125.245a9df052d274fb.js +1 -0
- package/.next/static/chunks/816-7e340dad784be28c.js +1 -0
- package/.next/static/chunks/8288.4883743fa40672e2.js +24 -0
- package/.next/static/chunks/8522.1607e96011c66877.js +1 -0
- package/.next/static/chunks/8772.863c564498d88487.js +1 -0
- package/.next/static/chunks/8841.dadeb1ece8e46004.js +1 -0
- package/.next/static/chunks/8885.f8d9912b40d74811.js +1 -0
- package/.next/static/chunks/90542734.c1553d0fe7fc14fc.js +1 -0
- package/.next/static/chunks/9365-733d8c05712d2888.js +1 -0
- package/.next/static/chunks/9552.b7dfb7903ead934b.js +1 -0
- package/.next/static/chunks/9834.295b45635ce04f5e.js +24 -0
- package/.next/static/chunks/app/_not-found/page-a9d04e58c81115ec.js +1 -0
- package/.next/static/chunks/app/layout-37e55f11dcc8b1bf.js +1 -0
- package/.next/static/chunks/app/page-9cd00de9cc0abc43.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/files/[...path]/page-9e5adf57cbbbdf05.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-8c6676303b63fdaf.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/simple-terminal/page-16feb3e86e42f4d1.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/terminal/page-be802baffc84dbd2.js +1 -0
- package/.next/static/chunks/d3ac728e.6c9c508274d4d2d5.js +1 -0
- package/.next/static/chunks/fd9d1056-bbe86e4ae099d5cd.js +1 -0
- package/.next/static/chunks/framework-8e0e0f4a6b83a956.js +1 -0
- package/.next/static/chunks/main-a960f4a5e1a2f598.js +1 -0
- package/.next/static/chunks/main-app-420d93e43682fee5.js +1 -0
- package/.next/static/chunks/pages/_app-3c9ca398d360b709.js +1 -0
- package/.next/static/chunks/pages/_error-cf5ca766ac8f493f.js +1 -0
- package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/.next/static/chunks/webpack-3fc79fab9bb738d7.js +1 -0
- package/.next/static/css/5eacd01f773eed7f.css +11 -0
- package/.next/static/css/85fa6dafca566008.css +1 -0
- package/.next/static/css/e174aa24f94ce607.css +3 -0
- package/.next/trace +5 -0
- package/.next/types/app/api/external-apps/[id]/health/route.ts +343 -0
- package/.next/types/app/api/external-apps/[id]/route.ts +343 -0
- package/.next/types/app/api/external-apps/route.ts +343 -0
- package/.next/types/app/api/hooks/claude-done/route.ts +343 -0
- package/.next/types/app/api/repositories/clone/[jobId]/route.ts +343 -0
- package/.next/types/app/api/repositories/clone/route.ts +343 -0
- package/.next/types/app/api/repositories/route.ts +343 -0
- package/.next/types/app/api/repositories/scan/route.ts +343 -0
- package/.next/types/app/api/repositories/sync/route.ts +343 -0
- package/.next/types/app/api/slash-commands/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/auto-yes/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/capture/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/cli-tool/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/current-output/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/files/[...path]/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/interrupt/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/kill-session/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/logs/[filename]/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/logs/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/memos/[memoId]/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/memos/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/messages/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/prompt-response/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/respond/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/search/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/send/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/slash-commands/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/start-polling/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/terminal/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/tree/[...path]/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/tree/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/upload/[...path]/route.ts +343 -0
- package/.next/types/app/api/worktrees/[id]/viewed/route.ts +343 -0
- package/.next/types/app/api/worktrees/route.ts +343 -0
- package/.next/types/app/page.ts +79 -0
- package/.next/types/app/proxy/[...path]/route.ts +343 -0
- package/.next/types/app/worktrees/[id]/files/[...path]/page.ts +79 -0
- package/.next/types/app/worktrees/[id]/page.ts +79 -0
- package/.next/types/app/worktrees/[id]/simple-terminal/page.ts +79 -0
- package/.next/types/app/worktrees/[id]/terminal/page.ts +79 -0
- package/.next/types/package.json +1 -0
- package/README.md +39 -8
- package/dist/cli/commands/init.d.ts +1 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +143 -27
- package/dist/cli/types/index.d.ts +18 -0
- package/dist/cli/types/index.d.ts.map +1 -1
- package/dist/cli/utils/env-setup.d.ts +25 -0
- package/dist/cli/utils/env-setup.d.ts.map +1 -1
- package/dist/cli/utils/env-setup.js +56 -1
- package/dist/cli/utils/prompt.d.ts +68 -0
- package/dist/cli/utils/prompt.d.ts.map +1 -0
- package/dist/cli/utils/prompt.js +208 -0
- package/dist/server/server.js +123 -0
- package/dist/server/src/lib/claude-output.js +33 -0
- package/dist/server/src/lib/claude-session.js +312 -0
- package/dist/server/src/lib/cli-patterns.js +137 -0
- package/dist/server/src/lib/cli-session.js +73 -0
- package/dist/server/src/lib/cli-tools/base.js +51 -0
- package/dist/server/src/lib/cli-tools/claude.js +65 -0
- package/dist/server/src/lib/cli-tools/codex.js +132 -0
- package/dist/server/src/lib/cli-tools/gemini.js +122 -0
- package/dist/server/src/lib/cli-tools/index.js +22 -0
- package/dist/server/src/lib/cli-tools/manager.js +143 -0
- package/dist/server/src/lib/cli-tools/types.js +5 -0
- package/dist/server/src/lib/conversation-logger.js +25 -0
- package/dist/server/src/lib/db-instance.js +51 -0
- package/dist/server/src/lib/db-migrations.js +777 -0
- package/dist/server/src/lib/db.js +835 -0
- package/dist/server/src/lib/env.js +179 -0
- package/dist/server/src/lib/log-manager.js +234 -0
- package/dist/server/src/lib/logger.js +232 -0
- package/dist/server/src/lib/prompt-detector.js +285 -0
- package/dist/server/src/lib/response-poller.js +638 -0
- package/dist/server/src/lib/tmux.js +299 -0
- package/dist/server/src/lib/worktrees.js +231 -0
- package/dist/server/src/lib/ws-server.js +323 -0
- package/dist/server/src/types/clone.js +39 -0
- package/dist/server/src/types/conversation.js +9 -0
- package/dist/server/src/types/external-apps.js +6 -0
- package/dist/server/src/types/infinite-messages.js +65 -0
- package/dist/server/src/types/markdown-editor.js +94 -0
- package/dist/server/src/types/models.js +5 -0
- package/dist/server/src/types/sidebar.js +89 -0
- package/dist/server/src/types/slash-commands.js +47 -0
- package/dist/server/src/types/ui-actions.js +8 -0
- package/dist/server/src/types/ui-state.js +62 -0
- package/package.json +8 -4
|
@@ -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
|
+
}
|