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,835 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Database operations for myCodeBranchDesk
|
|
4
|
+
* SQLite database client and CRUD operations
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.initDatabase = initDatabase;
|
|
8
|
+
exports.getWorktrees = getWorktrees;
|
|
9
|
+
exports.getRepositories = getRepositories;
|
|
10
|
+
exports.getWorktreeById = getWorktreeById;
|
|
11
|
+
exports.upsertWorktree = upsertWorktree;
|
|
12
|
+
exports.updateWorktreeDescription = updateWorktreeDescription;
|
|
13
|
+
exports.updateWorktreeLink = updateWorktreeLink;
|
|
14
|
+
exports.updateLastViewedAt = updateLastViewedAt;
|
|
15
|
+
exports.getLastAssistantMessageAt = getLastAssistantMessageAt;
|
|
16
|
+
exports.createMessage = createMessage;
|
|
17
|
+
exports.updateMessageContent = updateMessageContent;
|
|
18
|
+
exports.getMessages = getMessages;
|
|
19
|
+
exports.getLastUserMessage = getLastUserMessage;
|
|
20
|
+
exports.getLastMessage = getLastMessage;
|
|
21
|
+
exports.deleteAllMessages = deleteAllMessages;
|
|
22
|
+
exports.getSessionState = getSessionState;
|
|
23
|
+
exports.updateSessionState = updateSessionState;
|
|
24
|
+
exports.setInProgressMessageId = setInProgressMessageId;
|
|
25
|
+
exports.clearInProgressMessageId = clearInProgressMessageId;
|
|
26
|
+
exports.deleteSessionState = deleteSessionState;
|
|
27
|
+
exports.updateLastUserMessage = updateLastUserMessage;
|
|
28
|
+
exports.getMessageById = getMessageById;
|
|
29
|
+
exports.updatePromptData = updatePromptData;
|
|
30
|
+
exports.markPendingPromptsAsAnswered = markPendingPromptsAsAnswered;
|
|
31
|
+
exports.updateFavorite = updateFavorite;
|
|
32
|
+
exports.updateStatus = updateStatus;
|
|
33
|
+
exports.updateCliToolId = updateCliToolId;
|
|
34
|
+
exports.getMemosByWorktreeId = getMemosByWorktreeId;
|
|
35
|
+
exports.getMemoById = getMemoById;
|
|
36
|
+
exports.createMemo = createMemo;
|
|
37
|
+
exports.updateMemo = updateMemo;
|
|
38
|
+
exports.deleteMemo = deleteMemo;
|
|
39
|
+
exports.reorderMemos = reorderMemos;
|
|
40
|
+
exports.getWorktreeIdsByRepository = getWorktreeIdsByRepository;
|
|
41
|
+
exports.deleteRepositoryWorktrees = deleteRepositoryWorktrees;
|
|
42
|
+
const crypto_1 = require("crypto");
|
|
43
|
+
function mapChatMessage(row) {
|
|
44
|
+
return {
|
|
45
|
+
id: row.id,
|
|
46
|
+
worktreeId: row.worktree_id,
|
|
47
|
+
role: row.role,
|
|
48
|
+
content: row.content,
|
|
49
|
+
summary: row.summary || undefined,
|
|
50
|
+
timestamp: new Date(row.timestamp),
|
|
51
|
+
logFileName: row.log_file_name || undefined,
|
|
52
|
+
requestId: row.request_id || undefined,
|
|
53
|
+
messageType: row.message_type || 'normal',
|
|
54
|
+
promptData: row.prompt_data ? JSON.parse(row.prompt_data) : undefined,
|
|
55
|
+
cliToolId: row.cli_tool_id ?? 'claude',
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Initialize database schema
|
|
60
|
+
*/
|
|
61
|
+
function initDatabase(db) {
|
|
62
|
+
// Create worktrees table
|
|
63
|
+
db.exec(`
|
|
64
|
+
CREATE TABLE IF NOT EXISTS worktrees (
|
|
65
|
+
id TEXT PRIMARY KEY,
|
|
66
|
+
name TEXT NOT NULL,
|
|
67
|
+
path TEXT NOT NULL UNIQUE,
|
|
68
|
+
last_message_summary TEXT,
|
|
69
|
+
updated_at INTEGER
|
|
70
|
+
);
|
|
71
|
+
`);
|
|
72
|
+
// Create index for sorting by updated_at
|
|
73
|
+
db.exec(`
|
|
74
|
+
CREATE INDEX IF NOT EXISTS idx_worktrees_updated_at
|
|
75
|
+
ON worktrees(updated_at DESC);
|
|
76
|
+
`);
|
|
77
|
+
// Create chat_messages table
|
|
78
|
+
db.exec(`
|
|
79
|
+
CREATE TABLE IF NOT EXISTS chat_messages (
|
|
80
|
+
id TEXT PRIMARY KEY,
|
|
81
|
+
worktree_id TEXT NOT NULL,
|
|
82
|
+
role TEXT NOT NULL CHECK(role IN ('user', 'assistant')),
|
|
83
|
+
content TEXT NOT NULL,
|
|
84
|
+
summary TEXT,
|
|
85
|
+
timestamp INTEGER NOT NULL,
|
|
86
|
+
log_file_name TEXT,
|
|
87
|
+
request_id TEXT,
|
|
88
|
+
message_type TEXT DEFAULT 'normal',
|
|
89
|
+
prompt_data TEXT,
|
|
90
|
+
cli_tool_id TEXT DEFAULT 'claude',
|
|
91
|
+
|
|
92
|
+
FOREIGN KEY (worktree_id) REFERENCES worktrees(id) ON DELETE CASCADE
|
|
93
|
+
);
|
|
94
|
+
`);
|
|
95
|
+
// Create indexes for chat_messages
|
|
96
|
+
db.exec(`
|
|
97
|
+
CREATE INDEX IF NOT EXISTS idx_messages_worktree_time
|
|
98
|
+
ON chat_messages(worktree_id, timestamp DESC);
|
|
99
|
+
`);
|
|
100
|
+
db.exec(`
|
|
101
|
+
CREATE INDEX IF NOT EXISTS idx_messages_request_id
|
|
102
|
+
ON chat_messages(request_id);
|
|
103
|
+
`);
|
|
104
|
+
db.exec(`
|
|
105
|
+
CREATE INDEX IF NOT EXISTS idx_messages_type
|
|
106
|
+
ON chat_messages(message_type, worktree_id);
|
|
107
|
+
`);
|
|
108
|
+
db.exec(`
|
|
109
|
+
CREATE INDEX IF NOT EXISTS idx_messages_cli_tool
|
|
110
|
+
ON chat_messages(worktree_id, cli_tool_id, timestamp DESC);
|
|
111
|
+
`);
|
|
112
|
+
// Create session_states table
|
|
113
|
+
db.exec(`
|
|
114
|
+
CREATE TABLE IF NOT EXISTS session_states (
|
|
115
|
+
worktree_id TEXT NOT NULL,
|
|
116
|
+
cli_tool_id TEXT NOT NULL DEFAULT 'claude',
|
|
117
|
+
last_captured_line INTEGER DEFAULT 0,
|
|
118
|
+
|
|
119
|
+
PRIMARY KEY (worktree_id, cli_tool_id),
|
|
120
|
+
FOREIGN KEY (worktree_id) REFERENCES worktrees(id) ON DELETE CASCADE
|
|
121
|
+
);
|
|
122
|
+
`);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get latest user message per CLI tool for multiple worktrees (batch query)
|
|
126
|
+
* Optimized to avoid N+1 query problem
|
|
127
|
+
*/
|
|
128
|
+
function getLastMessagesByCliBatch(db, worktreeIds) {
|
|
129
|
+
if (worktreeIds.length === 0) {
|
|
130
|
+
return new Map();
|
|
131
|
+
}
|
|
132
|
+
// Single query to get latest user message for each worktree/cli_tool combination
|
|
133
|
+
// Uses window function to rank messages and filter to only the latest per group
|
|
134
|
+
const placeholders = worktreeIds.map(() => '?').join(',');
|
|
135
|
+
const stmt = db.prepare(`
|
|
136
|
+
WITH ranked_messages AS (
|
|
137
|
+
SELECT
|
|
138
|
+
worktree_id,
|
|
139
|
+
cli_tool_id,
|
|
140
|
+
content,
|
|
141
|
+
ROW_NUMBER() OVER (
|
|
142
|
+
PARTITION BY worktree_id, cli_tool_id
|
|
143
|
+
ORDER BY timestamp DESC
|
|
144
|
+
) as rn
|
|
145
|
+
FROM chat_messages
|
|
146
|
+
WHERE worktree_id IN (${placeholders})
|
|
147
|
+
AND role = 'user'
|
|
148
|
+
AND cli_tool_id IN ('claude', 'codex', 'gemini')
|
|
149
|
+
)
|
|
150
|
+
SELECT worktree_id, cli_tool_id, content
|
|
151
|
+
FROM ranked_messages
|
|
152
|
+
WHERE rn = 1
|
|
153
|
+
`);
|
|
154
|
+
const rows = stmt.all(...worktreeIds);
|
|
155
|
+
// Build result map
|
|
156
|
+
const result = new Map();
|
|
157
|
+
// Initialize all worktree IDs with empty objects
|
|
158
|
+
for (const id of worktreeIds) {
|
|
159
|
+
result.set(id, {});
|
|
160
|
+
}
|
|
161
|
+
// Populate with query results
|
|
162
|
+
for (const row of rows) {
|
|
163
|
+
const existing = result.get(row.worktree_id) || {};
|
|
164
|
+
existing[row.cli_tool_id] = row.content.substring(0, 50);
|
|
165
|
+
result.set(row.worktree_id, existing);
|
|
166
|
+
}
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Get all worktrees sorted by updated_at (desc)
|
|
171
|
+
* Optionally filter by repository path
|
|
172
|
+
* Includes lastViewedAt and lastAssistantMessageAt for unread tracking
|
|
173
|
+
*/
|
|
174
|
+
function getWorktrees(db, repositoryPath) {
|
|
175
|
+
let query = `
|
|
176
|
+
SELECT
|
|
177
|
+
w.id, w.name, w.path, w.repository_path, w.repository_name, w.description,
|
|
178
|
+
w.last_user_message, w.last_user_message_at, w.last_message_summary,
|
|
179
|
+
w.updated_at, w.favorite, w.status, w.link, w.cli_tool_id, w.last_viewed_at,
|
|
180
|
+
(SELECT MAX(timestamp) FROM chat_messages
|
|
181
|
+
WHERE worktree_id = w.id AND role = 'assistant') as last_assistant_message_at
|
|
182
|
+
FROM worktrees w
|
|
183
|
+
`;
|
|
184
|
+
const params = [];
|
|
185
|
+
if (repositoryPath) {
|
|
186
|
+
query += ` WHERE w.repository_path = ?`;
|
|
187
|
+
params.push(repositoryPath);
|
|
188
|
+
}
|
|
189
|
+
query += ` ORDER BY w.updated_at DESC NULLS LAST`;
|
|
190
|
+
const stmt = db.prepare(query);
|
|
191
|
+
const rows = stmt.all(...params);
|
|
192
|
+
// Batch fetch last messages for all worktrees (N+1 optimization)
|
|
193
|
+
const worktreeIds = rows.map(row => row.id);
|
|
194
|
+
const lastMessagesByCliMap = getLastMessagesByCliBatch(db, worktreeIds);
|
|
195
|
+
return rows.map((row) => {
|
|
196
|
+
const lastMessagesByCli = lastMessagesByCliMap.get(row.id) || {};
|
|
197
|
+
return {
|
|
198
|
+
id: row.id,
|
|
199
|
+
name: row.name,
|
|
200
|
+
path: row.path,
|
|
201
|
+
repositoryPath: row.repository_path || '',
|
|
202
|
+
repositoryName: row.repository_name || '',
|
|
203
|
+
description: row.description || undefined,
|
|
204
|
+
lastUserMessage: row.last_user_message || undefined,
|
|
205
|
+
lastUserMessageAt: row.last_user_message_at ? new Date(row.last_user_message_at) : undefined,
|
|
206
|
+
lastMessageSummary: row.last_message_summary || undefined,
|
|
207
|
+
lastMessagesByCli,
|
|
208
|
+
updatedAt: row.updated_at ? new Date(row.updated_at) : undefined,
|
|
209
|
+
lastViewedAt: row.last_viewed_at ? new Date(row.last_viewed_at) : undefined,
|
|
210
|
+
lastAssistantMessageAt: row.last_assistant_message_at ? new Date(row.last_assistant_message_at) : undefined,
|
|
211
|
+
favorite: row.favorite === 1,
|
|
212
|
+
status: row.status || null,
|
|
213
|
+
link: row.link || undefined,
|
|
214
|
+
cliToolId: row.cli_tool_id ?? 'claude',
|
|
215
|
+
};
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Get list of unique repositories from worktrees
|
|
220
|
+
*/
|
|
221
|
+
function getRepositories(db) {
|
|
222
|
+
const stmt = db.prepare(`
|
|
223
|
+
SELECT
|
|
224
|
+
repository_path as path,
|
|
225
|
+
repository_name as name,
|
|
226
|
+
COUNT(*) as worktree_count
|
|
227
|
+
FROM worktrees
|
|
228
|
+
WHERE repository_path IS NOT NULL
|
|
229
|
+
GROUP BY repository_path, repository_name
|
|
230
|
+
ORDER BY repository_name ASC
|
|
231
|
+
`);
|
|
232
|
+
const rows = stmt.all();
|
|
233
|
+
return rows.map((row) => ({
|
|
234
|
+
path: row.path,
|
|
235
|
+
name: row.name,
|
|
236
|
+
worktreeCount: row.worktree_count,
|
|
237
|
+
}));
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Get worktree by ID
|
|
241
|
+
* Includes lastViewedAt and lastAssistantMessageAt for unread tracking
|
|
242
|
+
*/
|
|
243
|
+
function getWorktreeById(db, id) {
|
|
244
|
+
const stmt = db.prepare(`
|
|
245
|
+
SELECT
|
|
246
|
+
w.id, w.name, w.path, w.repository_path, w.repository_name, w.description,
|
|
247
|
+
w.last_user_message, w.last_user_message_at, w.last_message_summary,
|
|
248
|
+
w.updated_at, w.favorite, w.status, w.link, w.cli_tool_id, w.last_viewed_at,
|
|
249
|
+
(SELECT MAX(timestamp) FROM chat_messages
|
|
250
|
+
WHERE worktree_id = w.id AND role = 'assistant') as last_assistant_message_at
|
|
251
|
+
FROM worktrees w
|
|
252
|
+
WHERE w.id = ?
|
|
253
|
+
`);
|
|
254
|
+
const row = stmt.get(id);
|
|
255
|
+
if (!row) {
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
return {
|
|
259
|
+
id: row.id,
|
|
260
|
+
name: row.name,
|
|
261
|
+
path: row.path,
|
|
262
|
+
repositoryPath: row.repository_path || '',
|
|
263
|
+
repositoryName: row.repository_name || '',
|
|
264
|
+
description: row.description || undefined,
|
|
265
|
+
lastUserMessage: row.last_user_message || undefined,
|
|
266
|
+
lastUserMessageAt: row.last_user_message_at ? new Date(row.last_user_message_at) : undefined,
|
|
267
|
+
lastMessageSummary: row.last_message_summary || undefined,
|
|
268
|
+
updatedAt: row.updated_at ? new Date(row.updated_at) : undefined,
|
|
269
|
+
lastViewedAt: row.last_viewed_at ? new Date(row.last_viewed_at) : undefined,
|
|
270
|
+
lastAssistantMessageAt: row.last_assistant_message_at ? new Date(row.last_assistant_message_at) : undefined,
|
|
271
|
+
favorite: row.favorite === 1,
|
|
272
|
+
status: row.status || null,
|
|
273
|
+
link: row.link || undefined,
|
|
274
|
+
cliToolId: row.cli_tool_id ?? 'claude',
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Insert or update worktree
|
|
279
|
+
*/
|
|
280
|
+
function upsertWorktree(db, worktree) {
|
|
281
|
+
// First, remove any existing worktree with the same path but different ID
|
|
282
|
+
// This handles cases where the ID generation scheme has changed
|
|
283
|
+
db.prepare('DELETE FROM worktrees WHERE path = ? AND id != ?').run(worktree.path, worktree.id);
|
|
284
|
+
const stmt = db.prepare(`
|
|
285
|
+
INSERT INTO worktrees (
|
|
286
|
+
id, name, path, repository_path, repository_name, description,
|
|
287
|
+
last_user_message, last_user_message_at, last_message_summary, updated_at, cli_tool_id
|
|
288
|
+
)
|
|
289
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
290
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
291
|
+
name = excluded.name,
|
|
292
|
+
path = excluded.path,
|
|
293
|
+
repository_path = excluded.repository_path,
|
|
294
|
+
repository_name = excluded.repository_name,
|
|
295
|
+
description = COALESCE(excluded.description, worktrees.description),
|
|
296
|
+
last_user_message = COALESCE(excluded.last_user_message, worktrees.last_user_message),
|
|
297
|
+
last_user_message_at = COALESCE(excluded.last_user_message_at, worktrees.last_user_message_at),
|
|
298
|
+
last_message_summary = COALESCE(excluded.last_message_summary, worktrees.last_message_summary),
|
|
299
|
+
updated_at = COALESCE(excluded.updated_at, worktrees.updated_at),
|
|
300
|
+
cli_tool_id = COALESCE(excluded.cli_tool_id, worktrees.cli_tool_id)
|
|
301
|
+
`);
|
|
302
|
+
stmt.run(worktree.id, worktree.name, worktree.path, worktree.repositoryPath || null, worktree.repositoryName || null, worktree.description || null, worktree.lastUserMessage || null, worktree.lastUserMessageAt?.getTime() || null, worktree.lastMessageSummary || null, worktree.updatedAt?.getTime() || null, worktree.cliToolId || 'claude');
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Update worktree description
|
|
306
|
+
*/
|
|
307
|
+
function updateWorktreeDescription(db, worktreeId, description) {
|
|
308
|
+
const stmt = db.prepare(`
|
|
309
|
+
UPDATE worktrees
|
|
310
|
+
SET description = ?
|
|
311
|
+
WHERE id = ?
|
|
312
|
+
`);
|
|
313
|
+
stmt.run(description || null, worktreeId);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Update worktree link
|
|
317
|
+
*/
|
|
318
|
+
function updateWorktreeLink(db, worktreeId, link) {
|
|
319
|
+
const stmt = db.prepare(`
|
|
320
|
+
UPDATE worktrees
|
|
321
|
+
SET link = ?
|
|
322
|
+
WHERE id = ?
|
|
323
|
+
`);
|
|
324
|
+
stmt.run(link || null, worktreeId);
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Update worktree's last_viewed_at timestamp
|
|
328
|
+
* Used for unread tracking (Issue #31)
|
|
329
|
+
*/
|
|
330
|
+
function updateLastViewedAt(db, worktreeId, viewedAt) {
|
|
331
|
+
const stmt = db.prepare(`
|
|
332
|
+
UPDATE worktrees
|
|
333
|
+
SET last_viewed_at = ?
|
|
334
|
+
WHERE id = ?
|
|
335
|
+
`);
|
|
336
|
+
stmt.run(viewedAt.toISOString(), worktreeId);
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Get the timestamp of the most recent assistant message for a worktree
|
|
340
|
+
* Used for unread tracking (Issue #31)
|
|
341
|
+
*/
|
|
342
|
+
function getLastAssistantMessageAt(db, worktreeId) {
|
|
343
|
+
const stmt = db.prepare(`
|
|
344
|
+
SELECT MAX(timestamp) as last_assistant_message_at
|
|
345
|
+
FROM chat_messages
|
|
346
|
+
WHERE worktree_id = ? AND role = 'assistant'
|
|
347
|
+
`);
|
|
348
|
+
const row = stmt.get(worktreeId);
|
|
349
|
+
if (!row || row.last_assistant_message_at === null) {
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
return new Date(row.last_assistant_message_at);
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Create a new chat message
|
|
356
|
+
*/
|
|
357
|
+
function createMessage(db, message) {
|
|
358
|
+
const id = (0, crypto_1.randomUUID)();
|
|
359
|
+
const stmt = db.prepare(`
|
|
360
|
+
INSERT INTO chat_messages
|
|
361
|
+
(id, worktree_id, role, content, summary, timestamp, log_file_name, request_id, message_type, prompt_data, cli_tool_id)
|
|
362
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
363
|
+
`);
|
|
364
|
+
stmt.run(id, message.worktreeId, message.role, message.content, message.summary || null, message.timestamp.getTime(), message.logFileName || null, message.requestId || null, message.messageType || 'normal', message.promptData ? JSON.stringify(message.promptData) : null, message.cliToolId || 'claude');
|
|
365
|
+
// Update worktree's updated_at timestamp
|
|
366
|
+
updateWorktreeTimestamp(db, message.worktreeId, message.timestamp);
|
|
367
|
+
// If this is a user message, update last_user_message
|
|
368
|
+
if (message.role === 'user') {
|
|
369
|
+
updateLastUserMessage(db, message.worktreeId, message.content, message.timestamp);
|
|
370
|
+
}
|
|
371
|
+
return { id, ...message };
|
|
372
|
+
}
|
|
373
|
+
function updateMessageContent(db, messageId, content, options) {
|
|
374
|
+
const assignments = ['content = ?'];
|
|
375
|
+
const params = [content];
|
|
376
|
+
if (options?.summary !== undefined) {
|
|
377
|
+
assignments.push('summary = ?');
|
|
378
|
+
params.push(options.summary ?? null);
|
|
379
|
+
}
|
|
380
|
+
if (options?.logFileName !== undefined) {
|
|
381
|
+
assignments.push('log_file_name = ?');
|
|
382
|
+
params.push(options.logFileName ?? null);
|
|
383
|
+
}
|
|
384
|
+
if (options?.requestId !== undefined) {
|
|
385
|
+
assignments.push('request_id = ?');
|
|
386
|
+
params.push(options.requestId ?? null);
|
|
387
|
+
}
|
|
388
|
+
const stmt = db.prepare(`
|
|
389
|
+
UPDATE chat_messages
|
|
390
|
+
SET ${assignments.join(', ')}
|
|
391
|
+
WHERE id = ?
|
|
392
|
+
`);
|
|
393
|
+
stmt.run(...params, messageId);
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Get messages for a worktree, optionally filtered by CLI tool
|
|
397
|
+
*/
|
|
398
|
+
function getMessages(db, worktreeId, before, limit = 50, cliToolId) {
|
|
399
|
+
let query = `
|
|
400
|
+
SELECT id, worktree_id, role, content, summary, timestamp, log_file_name, request_id, message_type, prompt_data, cli_tool_id
|
|
401
|
+
FROM chat_messages
|
|
402
|
+
WHERE worktree_id = ? AND (? IS NULL OR timestamp < ?)
|
|
403
|
+
`;
|
|
404
|
+
const params = [worktreeId, before?.getTime() || null, before?.getTime() || null];
|
|
405
|
+
// Add CLI tool filter if specified
|
|
406
|
+
if (cliToolId) {
|
|
407
|
+
query += ` AND cli_tool_id = ?`;
|
|
408
|
+
params.push(cliToolId);
|
|
409
|
+
}
|
|
410
|
+
query += ` ORDER BY timestamp DESC LIMIT ?`;
|
|
411
|
+
params.push(limit);
|
|
412
|
+
const stmt = db.prepare(query);
|
|
413
|
+
const rows = stmt.all(...params);
|
|
414
|
+
return rows.map(mapChatMessage);
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Fetch the most recent user-authored message for a worktree.
|
|
418
|
+
*/
|
|
419
|
+
function getLastUserMessage(db, worktreeId) {
|
|
420
|
+
const stmt = db.prepare(`
|
|
421
|
+
SELECT id, worktree_id, role, content, summary, timestamp, log_file_name, request_id, message_type, prompt_data, cli_tool_id
|
|
422
|
+
FROM chat_messages
|
|
423
|
+
WHERE worktree_id = ? AND role = 'user'
|
|
424
|
+
ORDER BY timestamp DESC
|
|
425
|
+
LIMIT 1
|
|
426
|
+
`);
|
|
427
|
+
const row = stmt.get(worktreeId);
|
|
428
|
+
return row ? mapChatMessage(row) : null;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Fetch the most recent message for a worktree (any role).
|
|
432
|
+
* Used to determine if waiting for Claude's response.
|
|
433
|
+
*/
|
|
434
|
+
function getLastMessage(db, worktreeId) {
|
|
435
|
+
const stmt = db.prepare(`
|
|
436
|
+
SELECT id, worktree_id, role, content, summary, timestamp, log_file_name, request_id, message_type, prompt_data, cli_tool_id
|
|
437
|
+
FROM chat_messages
|
|
438
|
+
WHERE worktree_id = ?
|
|
439
|
+
ORDER BY timestamp DESC
|
|
440
|
+
LIMIT 1
|
|
441
|
+
`);
|
|
442
|
+
const row = stmt.get(worktreeId);
|
|
443
|
+
return row ? mapChatMessage(row) : null;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Delete all messages for a worktree
|
|
447
|
+
* Used when killing a session to clear message history
|
|
448
|
+
* Note: Log files are preserved for historical reference
|
|
449
|
+
*/
|
|
450
|
+
function deleteAllMessages(db, worktreeId) {
|
|
451
|
+
const stmt = db.prepare(`
|
|
452
|
+
DELETE FROM chat_messages
|
|
453
|
+
WHERE worktree_id = ?
|
|
454
|
+
`);
|
|
455
|
+
stmt.run(worktreeId);
|
|
456
|
+
console.log(`[deleteAllMessages] Deleted all messages for worktree: ${worktreeId}`);
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Get session state for a worktree
|
|
460
|
+
*/
|
|
461
|
+
function getSessionState(db, worktreeId, cliToolId = 'claude') {
|
|
462
|
+
const stmt = db.prepare(`
|
|
463
|
+
SELECT worktree_id, cli_tool_id, last_captured_line, in_progress_message_id
|
|
464
|
+
FROM session_states
|
|
465
|
+
WHERE worktree_id = ? AND cli_tool_id = ?
|
|
466
|
+
`);
|
|
467
|
+
const row = stmt.get(worktreeId, cliToolId);
|
|
468
|
+
if (!row) {
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
return {
|
|
472
|
+
worktreeId: row.worktree_id,
|
|
473
|
+
cliToolId: row.cli_tool_id,
|
|
474
|
+
lastCapturedLine: row.last_captured_line,
|
|
475
|
+
inProgressMessageId: row.in_progress_message_id || null,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Update session state for a worktree
|
|
480
|
+
*/
|
|
481
|
+
function updateSessionState(db, worktreeId, cliToolId, lastCapturedLine) {
|
|
482
|
+
const stmt = db.prepare(`
|
|
483
|
+
INSERT INTO session_states (worktree_id, cli_tool_id, last_captured_line)
|
|
484
|
+
VALUES (?, ?, ?)
|
|
485
|
+
ON CONFLICT(worktree_id, cli_tool_id) DO UPDATE SET
|
|
486
|
+
last_captured_line = excluded.last_captured_line
|
|
487
|
+
`);
|
|
488
|
+
stmt.run(worktreeId, cliToolId, lastCapturedLine);
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Set the in-progress message ID for a session
|
|
492
|
+
*/
|
|
493
|
+
function setInProgressMessageId(db, worktreeId, cliToolId, messageId) {
|
|
494
|
+
const stmt = db.prepare(`
|
|
495
|
+
INSERT INTO session_states (worktree_id, cli_tool_id, last_captured_line, in_progress_message_id)
|
|
496
|
+
VALUES (?, ?, 0, ?)
|
|
497
|
+
ON CONFLICT(worktree_id, cli_tool_id) DO UPDATE SET
|
|
498
|
+
in_progress_message_id = excluded.in_progress_message_id
|
|
499
|
+
`);
|
|
500
|
+
stmt.run(worktreeId, cliToolId, messageId);
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Clear the in-progress message ID for a session
|
|
504
|
+
*/
|
|
505
|
+
function clearInProgressMessageId(db, worktreeId, cliToolId) {
|
|
506
|
+
setInProgressMessageId(db, worktreeId, cliToolId, null);
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Delete session state for a worktree
|
|
510
|
+
* Called when a session is killed or reset
|
|
511
|
+
*/
|
|
512
|
+
function deleteSessionState(db, worktreeId, cliToolId) {
|
|
513
|
+
if (cliToolId) {
|
|
514
|
+
const stmt = db.prepare(`
|
|
515
|
+
DELETE FROM session_states
|
|
516
|
+
WHERE worktree_id = ? AND cli_tool_id = ?
|
|
517
|
+
`);
|
|
518
|
+
stmt.run(worktreeId, cliToolId);
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
const stmt = db.prepare(`
|
|
522
|
+
DELETE FROM session_states
|
|
523
|
+
WHERE worktree_id = ?
|
|
524
|
+
`);
|
|
525
|
+
stmt.run(worktreeId);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Update worktree's updated_at timestamp
|
|
530
|
+
* @private
|
|
531
|
+
*/
|
|
532
|
+
function updateWorktreeTimestamp(db, worktreeId, timestamp) {
|
|
533
|
+
const stmt = db.prepare(`
|
|
534
|
+
UPDATE worktrees
|
|
535
|
+
SET updated_at = ?
|
|
536
|
+
WHERE id = ?
|
|
537
|
+
`);
|
|
538
|
+
stmt.run(timestamp.getTime(), worktreeId);
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Update worktree's last user message
|
|
542
|
+
*/
|
|
543
|
+
function updateLastUserMessage(db, worktreeId, message, timestamp) {
|
|
544
|
+
const stmt = db.prepare(`
|
|
545
|
+
UPDATE worktrees
|
|
546
|
+
SET last_user_message = ?,
|
|
547
|
+
last_user_message_at = ?
|
|
548
|
+
WHERE id = ?
|
|
549
|
+
`);
|
|
550
|
+
// Truncate message to 200 characters
|
|
551
|
+
const truncatedMessage = message.substring(0, 200);
|
|
552
|
+
stmt.run(truncatedMessage, timestamp.getTime(), worktreeId);
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Get message by ID
|
|
556
|
+
*/
|
|
557
|
+
function getMessageById(db, messageId) {
|
|
558
|
+
const stmt = db.prepare(`
|
|
559
|
+
SELECT id, worktree_id, role, content, summary, timestamp, log_file_name, request_id, message_type, prompt_data, cli_tool_id
|
|
560
|
+
FROM chat_messages
|
|
561
|
+
WHERE id = ?
|
|
562
|
+
`);
|
|
563
|
+
const row = stmt.get(messageId);
|
|
564
|
+
if (!row) {
|
|
565
|
+
return null;
|
|
566
|
+
}
|
|
567
|
+
return mapChatMessage(row);
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Update prompt data for a message
|
|
571
|
+
*/
|
|
572
|
+
function updatePromptData(db, messageId, promptData) {
|
|
573
|
+
const stmt = db.prepare(`
|
|
574
|
+
UPDATE chat_messages
|
|
575
|
+
SET prompt_data = ?
|
|
576
|
+
WHERE id = ?
|
|
577
|
+
`);
|
|
578
|
+
stmt.run(JSON.stringify(promptData), messageId);
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Mark all pending prompts as answered for a worktree/CLI tool
|
|
582
|
+
* This is called when we detect Claude has started processing (new response detected)
|
|
583
|
+
* which means any pending prompts must have been answered via terminal
|
|
584
|
+
*/
|
|
585
|
+
function markPendingPromptsAsAnswered(db, worktreeId, cliToolId) {
|
|
586
|
+
// Find all pending prompt messages for this worktree/CLI tool
|
|
587
|
+
const selectStmt = db.prepare(`
|
|
588
|
+
SELECT id, prompt_data
|
|
589
|
+
FROM chat_messages
|
|
590
|
+
WHERE worktree_id = ?
|
|
591
|
+
AND cli_tool_id = ?
|
|
592
|
+
AND message_type = 'prompt'
|
|
593
|
+
AND json_extract(prompt_data, '$.status') = 'pending'
|
|
594
|
+
ORDER BY timestamp DESC
|
|
595
|
+
`);
|
|
596
|
+
const rows = selectStmt.all(worktreeId, cliToolId);
|
|
597
|
+
if (rows.length === 0) {
|
|
598
|
+
return 0;
|
|
599
|
+
}
|
|
600
|
+
// Update each pending prompt to answered
|
|
601
|
+
const updateStmt = db.prepare(`
|
|
602
|
+
UPDATE chat_messages
|
|
603
|
+
SET prompt_data = ?
|
|
604
|
+
WHERE id = ?
|
|
605
|
+
`);
|
|
606
|
+
let updatedCount = 0;
|
|
607
|
+
for (const row of rows) {
|
|
608
|
+
try {
|
|
609
|
+
const promptData = JSON.parse(row.prompt_data);
|
|
610
|
+
promptData.status = 'answered';
|
|
611
|
+
promptData.answer = '(answered via terminal)';
|
|
612
|
+
promptData.answeredAt = new Date().toISOString();
|
|
613
|
+
updateStmt.run(JSON.stringify(promptData), row.id);
|
|
614
|
+
updatedCount++;
|
|
615
|
+
}
|
|
616
|
+
catch {
|
|
617
|
+
// Skip if prompt_data is invalid JSON
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return updatedCount;
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Update favorite status for a worktree
|
|
624
|
+
*/
|
|
625
|
+
function updateFavorite(db, id, favorite) {
|
|
626
|
+
const stmt = db.prepare(`
|
|
627
|
+
UPDATE worktrees
|
|
628
|
+
SET favorite = ?
|
|
629
|
+
WHERE id = ?
|
|
630
|
+
`);
|
|
631
|
+
stmt.run(favorite ? 1 : 0, id);
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Update status for a worktree
|
|
635
|
+
*/
|
|
636
|
+
function updateStatus(db, id, status) {
|
|
637
|
+
const stmt = db.prepare(`
|
|
638
|
+
UPDATE worktrees
|
|
639
|
+
SET status = ?
|
|
640
|
+
WHERE id = ?
|
|
641
|
+
`);
|
|
642
|
+
stmt.run(status, id);
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Update CLI tool ID for a worktree
|
|
646
|
+
*/
|
|
647
|
+
function updateCliToolId(db, id, cliToolId) {
|
|
648
|
+
const stmt = db.prepare(`
|
|
649
|
+
UPDATE worktrees
|
|
650
|
+
SET cli_tool_id = ?
|
|
651
|
+
WHERE id = ?
|
|
652
|
+
`);
|
|
653
|
+
stmt.run(cliToolId, id);
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Map database row to WorktreeMemo model
|
|
657
|
+
*/
|
|
658
|
+
function mapMemoRow(row) {
|
|
659
|
+
return {
|
|
660
|
+
id: row.id,
|
|
661
|
+
worktreeId: row.worktree_id,
|
|
662
|
+
title: row.title,
|
|
663
|
+
content: row.content,
|
|
664
|
+
position: row.position,
|
|
665
|
+
createdAt: new Date(row.created_at),
|
|
666
|
+
updatedAt: new Date(row.updated_at),
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* Get all memos for a worktree, sorted by position
|
|
671
|
+
*/
|
|
672
|
+
function getMemosByWorktreeId(db, worktreeId) {
|
|
673
|
+
const stmt = db.prepare(`
|
|
674
|
+
SELECT id, worktree_id, title, content, position, created_at, updated_at
|
|
675
|
+
FROM worktree_memos
|
|
676
|
+
WHERE worktree_id = ?
|
|
677
|
+
ORDER BY position ASC
|
|
678
|
+
`);
|
|
679
|
+
const rows = stmt.all(worktreeId);
|
|
680
|
+
return rows.map(mapMemoRow);
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* Get a memo by ID
|
|
684
|
+
*
|
|
685
|
+
* @param db - Database instance
|
|
686
|
+
* @param memoId - ID of the memo
|
|
687
|
+
* @returns Memo or null if not found
|
|
688
|
+
*/
|
|
689
|
+
function getMemoById(db, memoId) {
|
|
690
|
+
const stmt = db.prepare(`
|
|
691
|
+
SELECT id, worktree_id, title, content, position, created_at, updated_at
|
|
692
|
+
FROM worktree_memos
|
|
693
|
+
WHERE id = ?
|
|
694
|
+
`);
|
|
695
|
+
const row = stmt.get(memoId);
|
|
696
|
+
return row ? mapMemoRow(row) : null;
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Create a new memo for a worktree
|
|
700
|
+
*
|
|
701
|
+
* @param db - Database instance
|
|
702
|
+
* @param worktreeId - ID of the worktree
|
|
703
|
+
* @param options - Memo options (title, content, position)
|
|
704
|
+
* @returns Created memo
|
|
705
|
+
*/
|
|
706
|
+
function createMemo(db, worktreeId, options) {
|
|
707
|
+
const id = (0, crypto_1.randomUUID)();
|
|
708
|
+
const now = Date.now();
|
|
709
|
+
const title = options.title ?? 'Memo';
|
|
710
|
+
const content = options.content ?? '';
|
|
711
|
+
const stmt = db.prepare(`
|
|
712
|
+
INSERT INTO worktree_memos (id, worktree_id, title, content, position, created_at, updated_at)
|
|
713
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
714
|
+
`);
|
|
715
|
+
stmt.run(id, worktreeId, title, content, options.position, now, now);
|
|
716
|
+
return {
|
|
717
|
+
id,
|
|
718
|
+
worktreeId,
|
|
719
|
+
title,
|
|
720
|
+
content,
|
|
721
|
+
position: options.position,
|
|
722
|
+
createdAt: new Date(now),
|
|
723
|
+
updatedAt: new Date(now),
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Update an existing memo
|
|
728
|
+
*
|
|
729
|
+
* @param db - Database instance
|
|
730
|
+
* @param memoId - ID of the memo to update
|
|
731
|
+
* @param updates - Fields to update (title and/or content)
|
|
732
|
+
*/
|
|
733
|
+
function updateMemo(db, memoId, updates) {
|
|
734
|
+
const now = Date.now();
|
|
735
|
+
const assignments = ['updated_at = ?'];
|
|
736
|
+
const params = [now];
|
|
737
|
+
if (updates.title !== undefined) {
|
|
738
|
+
assignments.push('title = ?');
|
|
739
|
+
params.push(updates.title);
|
|
740
|
+
}
|
|
741
|
+
if (updates.content !== undefined) {
|
|
742
|
+
assignments.push('content = ?');
|
|
743
|
+
params.push(updates.content);
|
|
744
|
+
}
|
|
745
|
+
params.push(memoId);
|
|
746
|
+
const stmt = db.prepare(`
|
|
747
|
+
UPDATE worktree_memos
|
|
748
|
+
SET ${assignments.join(', ')}
|
|
749
|
+
WHERE id = ?
|
|
750
|
+
`);
|
|
751
|
+
stmt.run(...params);
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Delete a memo by ID
|
|
755
|
+
*
|
|
756
|
+
* @param db - Database instance
|
|
757
|
+
* @param memoId - ID of the memo to delete
|
|
758
|
+
*/
|
|
759
|
+
function deleteMemo(db, memoId) {
|
|
760
|
+
const stmt = db.prepare(`
|
|
761
|
+
DELETE FROM worktree_memos
|
|
762
|
+
WHERE id = ?
|
|
763
|
+
`);
|
|
764
|
+
stmt.run(memoId);
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Reorder memos for a worktree
|
|
768
|
+
*
|
|
769
|
+
* Uses a two-step approach to handle UNIQUE constraint on (worktree_id, position):
|
|
770
|
+
* 1. Set all positions to negative values (temporary)
|
|
771
|
+
* 2. Set new positions from the provided order
|
|
772
|
+
*
|
|
773
|
+
* @param db - Database instance
|
|
774
|
+
* @param worktreeId - ID of the worktree
|
|
775
|
+
* @param memoIds - Array of memo IDs in the desired order
|
|
776
|
+
*/
|
|
777
|
+
function reorderMemos(db, worktreeId, memoIds) {
|
|
778
|
+
if (memoIds.length === 0) {
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
const now = Date.now();
|
|
782
|
+
db.transaction(() => {
|
|
783
|
+
// Step 1: Set all positions to negative values (to avoid UNIQUE constraint violations)
|
|
784
|
+
const resetStmt = db.prepare(`
|
|
785
|
+
UPDATE worktree_memos
|
|
786
|
+
SET position = -1 - position
|
|
787
|
+
WHERE id = ?
|
|
788
|
+
`);
|
|
789
|
+
for (const memoId of memoIds) {
|
|
790
|
+
resetStmt.run(memoId);
|
|
791
|
+
}
|
|
792
|
+
// Step 2: Set new positions based on array order
|
|
793
|
+
const updateStmt = db.prepare(`
|
|
794
|
+
UPDATE worktree_memos
|
|
795
|
+
SET position = ?, updated_at = ?
|
|
796
|
+
WHERE id = ?
|
|
797
|
+
`);
|
|
798
|
+
memoIds.forEach((memoId, index) => {
|
|
799
|
+
updateStmt.run(index, now, memoId);
|
|
800
|
+
});
|
|
801
|
+
})();
|
|
802
|
+
}
|
|
803
|
+
// ============================================================
|
|
804
|
+
// Repository Delete Operations (Issue #69)
|
|
805
|
+
// ============================================================
|
|
806
|
+
/**
|
|
807
|
+
* Get all worktree IDs for a given repository path
|
|
808
|
+
*
|
|
809
|
+
* @param db - Database instance
|
|
810
|
+
* @param repositoryPath - Path of the repository
|
|
811
|
+
* @returns Array of worktree IDs
|
|
812
|
+
*/
|
|
813
|
+
function getWorktreeIdsByRepository(db, repositoryPath) {
|
|
814
|
+
const stmt = db.prepare(`
|
|
815
|
+
SELECT id FROM worktrees WHERE repository_path = ?
|
|
816
|
+
`);
|
|
817
|
+
const rows = stmt.all(repositoryPath);
|
|
818
|
+
return rows.map(r => r.id);
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Delete all worktrees for a given repository path
|
|
822
|
+
* Related data (chat_messages, session_states, worktree_memos) will be
|
|
823
|
+
* automatically deleted via CASCADE foreign key constraints.
|
|
824
|
+
*
|
|
825
|
+
* @param db - Database instance
|
|
826
|
+
* @param repositoryPath - Path of the repository to delete
|
|
827
|
+
* @returns Object containing the count of deleted worktrees
|
|
828
|
+
*/
|
|
829
|
+
function deleteRepositoryWorktrees(db, repositoryPath) {
|
|
830
|
+
const stmt = db.prepare(`
|
|
831
|
+
DELETE FROM worktrees WHERE repository_path = ?
|
|
832
|
+
`);
|
|
833
|
+
const result = stmt.run(repositoryPath);
|
|
834
|
+
return { deletedCount: result.changes };
|
|
835
|
+
}
|