commandmate 0.1.0 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/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/static/pQTquVjewvoJa7BML07ip/_buildManifest.js +1 -0
- package/.next/static/pQTquVjewvoJa7BML07ip/_ssgManifest.js +1 -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 +25 -20
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +4 -1
- package/dist/cli/utils/daemon.d.ts.map +1 -1
- package/dist/cli/utils/daemon.js +4 -2
- package/dist/cli/utils/paths.d.ts +25 -0
- package/dist/cli/utils/paths.d.ts.map +1 -0
- package/dist/cli/utils/paths.js +35 -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 +14 -6
package/README.md
CHANGED
|
@@ -49,39 +49,43 @@ Claude Code での開発経験があり、本業の傍らで個人開発を続
|
|
|
49
49
|
|
|
50
50
|
- macOS / Linux(tmux 依存のため Windows は非対応)
|
|
51
51
|
- Node.js v20+、npm、git、tmux、openssl
|
|
52
|
-
- Claude CLI
|
|
52
|
+
- Claude CLI(オプション)
|
|
53
53
|
|
|
54
|
-
###
|
|
54
|
+
### インストール
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
|
-
# グローバルインストール
|
|
58
57
|
npm install -g commandmate
|
|
58
|
+
```
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
commandmate init
|
|
60
|
+
### セットアップと起動
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
commandmate
|
|
62
|
+
```bash
|
|
63
|
+
commandmate init # 依存チェック、環境設定、DB初期化
|
|
64
|
+
commandmate start --daemon # バックグラウンドで起動
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
ブラウザで http://localhost:3000 にアクセスしてください。
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
### CLI コマンド
|
|
70
70
|
|
|
71
71
|
| コマンド | 説明 |
|
|
72
72
|
|---------|------|
|
|
73
|
-
| `commandmate
|
|
74
|
-
| `commandmate init` |
|
|
75
|
-
| `commandmate
|
|
76
|
-
| `commandmate start` |
|
|
77
|
-
| `commandmate start --dev` | 開発モードで起動 |
|
|
78
|
-
| `commandmate start --daemon` | バックグラウンドで起動 |
|
|
73
|
+
| `commandmate init` | 初期設定(対話形式) |
|
|
74
|
+
| `commandmate init --defaults` | 初期設定(デフォルト値) |
|
|
75
|
+
| `commandmate start --daemon` | バックグラウンド起動 |
|
|
76
|
+
| `commandmate start -p 3001` | ポート指定で起動 |
|
|
79
77
|
| `commandmate stop` | サーバー停止 |
|
|
80
|
-
| `commandmate status` |
|
|
78
|
+
| `commandmate status` | 状態確認 |
|
|
79
|
+
|
|
80
|
+
詳しくは [CLI セットアップガイド](./docs/user-guide/cli-setup-guide.md) を参照してください。
|
|
81
|
+
|
|
82
|
+
### モバイルからのアクセス
|
|
83
|
+
|
|
84
|
+
`commandmate init` で外部アクセスを有効にすると、`CM_BIND=0.0.0.0` と `CM_AUTH_TOKEN` が自動設定されます。同一LAN内から `http://<PCのIP>:3000` にアクセスします。
|
|
81
85
|
|
|
82
|
-
|
|
86
|
+
## 開発者向けセットアップ
|
|
83
87
|
|
|
84
|
-
|
|
88
|
+
コントリビューターや開発環境を構築する場合は、git clone を使用してください。
|
|
85
89
|
|
|
86
90
|
```bash
|
|
87
91
|
git clone https://github.com/Kewton/CommandMate.git
|
|
@@ -102,7 +106,7 @@ npm run build
|
|
|
102
106
|
npm start
|
|
103
107
|
```
|
|
104
108
|
|
|
105
|
-
|
|
109
|
+
> **Note**: `./scripts/*` スクリプトは開発環境でのみ使用可能です。グローバルインストール(`npm install -g`)では `commandmate` CLI を使用してください。
|
|
106
110
|
|
|
107
111
|
> **Note**: 旧名称の環境変数(`MCBD_*`)も後方互換性のためサポートされていますが、新名称(`CM_*`)の使用を推奨します。
|
|
108
112
|
|
|
@@ -130,13 +134,14 @@ A: 現時点では個人利用を想定しています。複数人での同時
|
|
|
130
134
|
|
|
131
135
|
| ドキュメント | 説明 |
|
|
132
136
|
|-------------|------|
|
|
137
|
+
| [CLI セットアップガイド](./docs/user-guide/cli-setup-guide.md) | インストールと初期設定 |
|
|
138
|
+
| [Webアプリ操作ガイド](./docs/user-guide/webapp-guide.md) | Webアプリの基本操作 |
|
|
139
|
+
| [クイックスタート](./docs/user-guide/quick-start.md) | Claude Codeコマンドの使い方 |
|
|
133
140
|
| [コンセプト](./docs/concept.md) | ビジョンと解決する課題 |
|
|
134
141
|
| [アーキテクチャ](./docs/architecture.md) | システム設計 |
|
|
135
142
|
| [デプロイガイド](./docs/DEPLOYMENT.md) | 本番環境構築手順 |
|
|
136
143
|
| [移行ガイド](./docs/migration-to-commandmate.md) | MyCodeBranchDesk からの移行手順 |
|
|
137
144
|
| [UI/UXガイド](./docs/UI_UX_GUIDE.md) | UI実装の詳細 |
|
|
138
|
-
| [Webアプリ操作ガイド](./docs/user-guide/webapp-guide.md) | Webアプリの基本操作 |
|
|
139
|
-
| [クイックスタート](./docs/user-guide/quick-start.md) | Claude Codeコマンドの使い方 |
|
|
140
145
|
| [Trust & Safety](./docs/TRUST_AND_SAFETY.md) | セキュリティと権限の考え方 |
|
|
141
146
|
|
|
142
147
|
## Contributing
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/start.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,YAAY,EAAY,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/start.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,YAAY,EAAY,MAAM,UAAU,CAAC;AASlD;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAuHvE"}
|
|
@@ -13,6 +13,7 @@ const types_1 = require("../types");
|
|
|
13
13
|
const logger_1 = require("../utils/logger");
|
|
14
14
|
const daemon_1 = require("../utils/daemon");
|
|
15
15
|
const security_logger_1 = require("../utils/security-logger");
|
|
16
|
+
const paths_1 = require("../utils/paths");
|
|
16
17
|
const logger = new logger_1.CLILogger();
|
|
17
18
|
const PID_FILE = (0, path_1.join)(process.cwd(), '.commandmate.pid');
|
|
18
19
|
/**
|
|
@@ -77,8 +78,10 @@ async function startCommand(options) {
|
|
|
77
78
|
if (options.port) {
|
|
78
79
|
env.CM_PORT = String(options.port);
|
|
79
80
|
}
|
|
81
|
+
// Use package installation directory, not current working directory
|
|
82
|
+
const packageRoot = (0, paths_1.getPackageRoot)();
|
|
80
83
|
const child = (0, child_process_1.spawn)('npm', ['run', npmScript], {
|
|
81
|
-
cwd:
|
|
84
|
+
cwd: packageRoot,
|
|
82
85
|
env,
|
|
83
86
|
stdio: 'inherit',
|
|
84
87
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/daemon.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/daemon.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAItD;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAa;gBAEnB,WAAW,EAAE,MAAM;IAI/B;;;;OAIG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IA8CnD;;;;OAIG;IACG,IAAI,CAAC,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IA8BpD;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IA6B/C;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAInC;;OAEG;YACW,WAAW;CAiB1B"}
|
package/dist/cli/utils/daemon.js
CHANGED
|
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
8
8
|
exports.DaemonManager = void 0;
|
|
9
9
|
const child_process_1 = require("child_process");
|
|
10
10
|
const pid_manager_1 = require("./pid-manager");
|
|
11
|
+
const paths_1 = require("./paths");
|
|
11
12
|
/**
|
|
12
13
|
* Daemon manager for background server process
|
|
13
14
|
*/
|
|
@@ -29,7 +30,8 @@ class DaemonManager {
|
|
|
29
30
|
// Clean up stale PID file
|
|
30
31
|
this.pidManager.removePid();
|
|
31
32
|
const npmScript = options.dev ? 'dev' : 'start';
|
|
32
|
-
|
|
33
|
+
// Use package installation directory, not current working directory
|
|
34
|
+
const packageRoot = (0, paths_1.getPackageRoot)();
|
|
33
35
|
// Build environment
|
|
34
36
|
const env = { ...process.env };
|
|
35
37
|
if (options.port) {
|
|
@@ -37,7 +39,7 @@ class DaemonManager {
|
|
|
37
39
|
}
|
|
38
40
|
// Spawn detached process
|
|
39
41
|
const child = (0, child_process_1.spawn)('npm', ['run', npmScript], {
|
|
40
|
-
cwd,
|
|
42
|
+
cwd: packageRoot,
|
|
41
43
|
env,
|
|
42
44
|
detached: true,
|
|
43
45
|
stdio: 'ignore',
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path Utilities for CLI
|
|
3
|
+
* Issue #96: npm install CLI support
|
|
4
|
+
*
|
|
5
|
+
* Provides utilities to resolve package installation directory
|
|
6
|
+
* regardless of where the CLI is invoked from.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Get the root directory of the CommandMate package installation.
|
|
10
|
+
*
|
|
11
|
+
* When installed globally via npm, the CLI runs from:
|
|
12
|
+
* <global-modules>/commandmate/dist/cli/utils/paths.js
|
|
13
|
+
*
|
|
14
|
+
* This function returns the package root:
|
|
15
|
+
* <global-modules>/commandmate/
|
|
16
|
+
*
|
|
17
|
+
* @returns Absolute path to the package root directory
|
|
18
|
+
*/
|
|
19
|
+
export declare function getPackageRoot(): string;
|
|
20
|
+
/**
|
|
21
|
+
* Get the path to package.json
|
|
22
|
+
* @returns Absolute path to package.json
|
|
23
|
+
*/
|
|
24
|
+
export declare function getPackageJsonPath(): string;
|
|
25
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/paths.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAIvC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Path Utilities for CLI
|
|
4
|
+
* Issue #96: npm install CLI support
|
|
5
|
+
*
|
|
6
|
+
* Provides utilities to resolve package installation directory
|
|
7
|
+
* regardless of where the CLI is invoked from.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.getPackageRoot = getPackageRoot;
|
|
11
|
+
exports.getPackageJsonPath = getPackageJsonPath;
|
|
12
|
+
const path_1 = require("path");
|
|
13
|
+
/**
|
|
14
|
+
* Get the root directory of the CommandMate package installation.
|
|
15
|
+
*
|
|
16
|
+
* When installed globally via npm, the CLI runs from:
|
|
17
|
+
* <global-modules>/commandmate/dist/cli/utils/paths.js
|
|
18
|
+
*
|
|
19
|
+
* This function returns the package root:
|
|
20
|
+
* <global-modules>/commandmate/
|
|
21
|
+
*
|
|
22
|
+
* @returns Absolute path to the package root directory
|
|
23
|
+
*/
|
|
24
|
+
function getPackageRoot() {
|
|
25
|
+
// __dirname points to dist/cli/utils when this file is compiled
|
|
26
|
+
// We need to go up 3 levels: utils → cli → dist → package root
|
|
27
|
+
return (0, path_1.join)(__dirname, '..', '..', '..');
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get the path to package.json
|
|
31
|
+
* @returns Absolute path to package.json
|
|
32
|
+
*/
|
|
33
|
+
function getPackageJsonPath() {
|
|
34
|
+
return (0, path_1.join)(getPackageRoot(), 'package.json');
|
|
35
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Custom Next.js Server with WebSocket Support
|
|
4
|
+
* Integrates WebSocket server for real-time communication
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
// IMPORTANT: Register uncaught exception handler FIRST, before any imports
|
|
11
|
+
// This ensures we catch WebSocket frame errors before other handlers
|
|
12
|
+
process.on('uncaughtException', (error) => {
|
|
13
|
+
// Check for WebSocket-related errors that are non-fatal
|
|
14
|
+
const isWebSocketError = error.code === 'WS_ERR_INVALID_UTF8' ||
|
|
15
|
+
error.code === 'WS_ERR_INVALID_CLOSE_CODE' ||
|
|
16
|
+
error.code === 'WS_ERR_UNEXPECTED_RSV_1' ||
|
|
17
|
+
error.code === 'ECONNRESET' ||
|
|
18
|
+
error.code === 'EPIPE' ||
|
|
19
|
+
(error instanceof RangeError && error.message?.includes('Invalid WebSocket frame')) ||
|
|
20
|
+
error.message?.includes('write after end');
|
|
21
|
+
if (isWebSocketError) {
|
|
22
|
+
// Silently ignore these non-fatal WebSocket frame errors
|
|
23
|
+
// They commonly occur when mobile browsers send malformed close frames
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
// For other uncaught exceptions, log and exit
|
|
27
|
+
console.error('Uncaught exception:', error);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
});
|
|
30
|
+
const http_1 = require("http");
|
|
31
|
+
const url_1 = require("url");
|
|
32
|
+
const next_1 = __importDefault(require("next"));
|
|
33
|
+
const ws_server_1 = require("./src/lib/ws-server");
|
|
34
|
+
const worktrees_1 = require("./src/lib/worktrees");
|
|
35
|
+
const db_instance_1 = require("./src/lib/db-instance");
|
|
36
|
+
const response_poller_1 = require("./src/lib/response-poller");
|
|
37
|
+
const db_migrations_1 = require("./src/lib/db-migrations");
|
|
38
|
+
const env_1 = require("./src/lib/env");
|
|
39
|
+
const dev = process.env.NODE_ENV !== 'production';
|
|
40
|
+
const hostname = (0, env_1.getEnvByKey)('CM_BIND') || '127.0.0.1';
|
|
41
|
+
const port = parseInt((0, env_1.getEnvByKey)('CM_PORT') || '3000', 10);
|
|
42
|
+
// Create Next.js app
|
|
43
|
+
const app = (0, next_1.default)({ dev, hostname, port });
|
|
44
|
+
const handle = app.getRequestHandler();
|
|
45
|
+
app.prepare().then(() => {
|
|
46
|
+
// Create HTTP server
|
|
47
|
+
const server = (0, http_1.createServer)(async (req, res) => {
|
|
48
|
+
try {
|
|
49
|
+
const parsedUrl = (0, url_1.parse)(req.url, true);
|
|
50
|
+
await handle(req, res, parsedUrl);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
console.error('Error handling request', err);
|
|
54
|
+
res.statusCode = 500;
|
|
55
|
+
res.end('Internal Server Error');
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
// Setup WebSocket server
|
|
59
|
+
(0, ws_server_1.setupWebSocket)(server);
|
|
60
|
+
// Scan and sync worktrees on startup
|
|
61
|
+
async function initializeWorktrees() {
|
|
62
|
+
try {
|
|
63
|
+
// Run database migrations first
|
|
64
|
+
console.log('Running database migrations...');
|
|
65
|
+
const db = (0, db_instance_1.getDbInstance)();
|
|
66
|
+
(0, db_migrations_1.runMigrations)(db);
|
|
67
|
+
// Get repository paths from environment variables
|
|
68
|
+
const repositoryPaths = (0, worktrees_1.getRepositoryPaths)();
|
|
69
|
+
if (repositoryPaths.length === 0) {
|
|
70
|
+
console.warn('Warning: No repository paths configured');
|
|
71
|
+
console.warn('Set WORKTREE_REPOS (comma-separated) or MCBD_ROOT_DIR');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
console.log(`Configured repositories: ${repositoryPaths.length}`);
|
|
75
|
+
repositoryPaths.forEach((path, i) => {
|
|
76
|
+
console.log(` ${i + 1}. ${path}`);
|
|
77
|
+
});
|
|
78
|
+
// Scan all repositories
|
|
79
|
+
const worktrees = await (0, worktrees_1.scanMultipleRepositories)(repositoryPaths);
|
|
80
|
+
// Sync to database
|
|
81
|
+
(0, worktrees_1.syncWorktreesToDB)(db, worktrees);
|
|
82
|
+
console.log(`✓ Total: ${worktrees.length} worktree(s) synced to database`);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
console.error('Error initializing worktrees:', error);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
server.listen(port, async (err) => {
|
|
89
|
+
if (err)
|
|
90
|
+
throw err;
|
|
91
|
+
console.log(`> Ready on http://${hostname}:${port}`);
|
|
92
|
+
console.log(`> WebSocket server ready`);
|
|
93
|
+
// Initialize worktrees after server starts
|
|
94
|
+
await initializeWorktrees();
|
|
95
|
+
});
|
|
96
|
+
// Graceful shutdown with timeout
|
|
97
|
+
let isShuttingDown = false;
|
|
98
|
+
function gracefulShutdown(signal) {
|
|
99
|
+
if (isShuttingDown) {
|
|
100
|
+
console.log('Shutdown already in progress, forcing exit...');
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
isShuttingDown = true;
|
|
104
|
+
console.log(`${signal} received: shutting down...`);
|
|
105
|
+
// Stop polling first
|
|
106
|
+
(0, response_poller_1.stopAllPolling)();
|
|
107
|
+
// Close WebSocket connections immediately (don't wait)
|
|
108
|
+
(0, ws_server_1.closeWebSocket)();
|
|
109
|
+
// Force exit after 3 seconds if graceful shutdown fails
|
|
110
|
+
const forceExitTimeout = setTimeout(() => {
|
|
111
|
+
console.log('Graceful shutdown timeout, forcing exit...');
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}, 3000);
|
|
114
|
+
// Try graceful HTTP server close
|
|
115
|
+
server.close(() => {
|
|
116
|
+
clearTimeout(forceExitTimeout);
|
|
117
|
+
console.log('Server closed gracefully');
|
|
118
|
+
process.exit(0);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
|
122
|
+
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
|
123
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Claude output parsing utilities
|
|
4
|
+
* Shared between webhook handlers and polling logic
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.parseClaudeOutput = parseClaudeOutput;
|
|
8
|
+
const LOG_FILE_REGEX = /📄 Session log: (.+?\/([^\/\s]+\.jsonl))/;
|
|
9
|
+
const REQUEST_ID_REGEX = /Request ID: ([^\s\n]+)/;
|
|
10
|
+
const SUMMARY_REGEX = /Summary: (.+?)(?:\n─|$)/s;
|
|
11
|
+
/**
|
|
12
|
+
* Parse Claude CLI output and extract metadata that the UI relies on.
|
|
13
|
+
*
|
|
14
|
+
* @param output Raw tmux capture string
|
|
15
|
+
*/
|
|
16
|
+
function parseClaudeOutput(output) {
|
|
17
|
+
const result = {
|
|
18
|
+
content: output,
|
|
19
|
+
};
|
|
20
|
+
const logFileMatch = LOG_FILE_REGEX.exec(output);
|
|
21
|
+
if (logFileMatch) {
|
|
22
|
+
result.logFileName = logFileMatch[2];
|
|
23
|
+
}
|
|
24
|
+
const requestIdMatch = REQUEST_ID_REGEX.exec(output);
|
|
25
|
+
if (requestIdMatch) {
|
|
26
|
+
result.requestId = requestIdMatch[1];
|
|
27
|
+
}
|
|
28
|
+
const summaryMatch = SUMMARY_REGEX.exec(output);
|
|
29
|
+
if (summaryMatch) {
|
|
30
|
+
result.summary = summaryMatch[1].trim();
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Claude CLI session management
|
|
4
|
+
* Manages Claude CLI sessions within tmux for each worktree
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.getSessionName = getSessionName;
|
|
8
|
+
exports.isClaudeInstalled = isClaudeInstalled;
|
|
9
|
+
exports.isClaudeRunning = isClaudeRunning;
|
|
10
|
+
exports.getClaudeSessionState = getClaudeSessionState;
|
|
11
|
+
exports.startClaudeSession = startClaudeSession;
|
|
12
|
+
exports.sendMessageToClaude = sendMessageToClaude;
|
|
13
|
+
exports.captureClaudeOutput = captureClaudeOutput;
|
|
14
|
+
exports.stopClaudeSession = stopClaudeSession;
|
|
15
|
+
exports.restartClaudeSession = restartClaudeSession;
|
|
16
|
+
const tmux_1 = require("./tmux");
|
|
17
|
+
const child_process_1 = require("child_process");
|
|
18
|
+
const util_1 = require("util");
|
|
19
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
20
|
+
/**
|
|
21
|
+
* Cached Claude CLI path
|
|
22
|
+
*/
|
|
23
|
+
let cachedClaudePath = null;
|
|
24
|
+
/**
|
|
25
|
+
* Get Claude CLI path dynamically
|
|
26
|
+
* Uses CLAUDE_PATH environment variable if set, otherwise finds via 'which'
|
|
27
|
+
*/
|
|
28
|
+
async function getClaudePath() {
|
|
29
|
+
// Return cached path if available
|
|
30
|
+
if (cachedClaudePath) {
|
|
31
|
+
return cachedClaudePath;
|
|
32
|
+
}
|
|
33
|
+
// Check environment variable first
|
|
34
|
+
if (process.env.CLAUDE_PATH) {
|
|
35
|
+
cachedClaudePath = process.env.CLAUDE_PATH;
|
|
36
|
+
return cachedClaudePath;
|
|
37
|
+
}
|
|
38
|
+
// Find claude via 'which' command
|
|
39
|
+
try {
|
|
40
|
+
const { stdout } = await execAsync('which claude', { timeout: 5000 });
|
|
41
|
+
cachedClaudePath = stdout.trim();
|
|
42
|
+
return cachedClaudePath;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Fallback to common paths
|
|
46
|
+
const fallbackPaths = [
|
|
47
|
+
'/opt/homebrew/bin/claude', // macOS Homebrew (Apple Silicon)
|
|
48
|
+
'/usr/local/bin/claude', // macOS Homebrew (Intel) / Linux
|
|
49
|
+
'/usr/bin/claude', // Linux system install
|
|
50
|
+
];
|
|
51
|
+
for (const path of fallbackPaths) {
|
|
52
|
+
try {
|
|
53
|
+
await execAsync(`test -x "${path}"`, { timeout: 1000 });
|
|
54
|
+
cachedClaudePath = path;
|
|
55
|
+
return cachedClaudePath;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Path not found, try next
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
throw new Error('Claude CLI not found. Set CLAUDE_PATH environment variable or install Claude CLI.');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get tmux session name for a worktree
|
|
66
|
+
*
|
|
67
|
+
* @param worktreeId - Worktree ID
|
|
68
|
+
* @returns tmux session name
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* getSessionName('feature-foo') // => 'mcbd-claude-feature-foo'
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
function getSessionName(worktreeId) {
|
|
76
|
+
return `mcbd-claude-${worktreeId}`;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Check if Claude is installed and available
|
|
80
|
+
*
|
|
81
|
+
* @returns True if Claude CLI is available
|
|
82
|
+
*/
|
|
83
|
+
async function isClaudeInstalled() {
|
|
84
|
+
try {
|
|
85
|
+
await execAsync('which claude', { timeout: 5000 });
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Check if Claude session is running
|
|
94
|
+
*
|
|
95
|
+
* @param worktreeId - Worktree ID
|
|
96
|
+
* @returns True if Claude session exists and is running
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* const running = await isClaudeRunning('feature-foo');
|
|
101
|
+
* if (running) {
|
|
102
|
+
* console.log('Claude is ready');
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
async function isClaudeRunning(worktreeId) {
|
|
107
|
+
const sessionName = getSessionName(worktreeId);
|
|
108
|
+
return await (0, tmux_1.hasSession)(sessionName);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get Claude session state
|
|
112
|
+
*
|
|
113
|
+
* @param worktreeId - Worktree ID
|
|
114
|
+
* @returns Session state information
|
|
115
|
+
*/
|
|
116
|
+
async function getClaudeSessionState(worktreeId) {
|
|
117
|
+
const sessionName = getSessionName(worktreeId);
|
|
118
|
+
const isRunning = await (0, tmux_1.hasSession)(sessionName);
|
|
119
|
+
return {
|
|
120
|
+
sessionName,
|
|
121
|
+
isRunning,
|
|
122
|
+
lastActivity: new Date(),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Start a Claude CLI session in tmux
|
|
127
|
+
*
|
|
128
|
+
* @param options - Session options
|
|
129
|
+
* @throws {Error} If Claude CLI is not installed or session creation fails
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* await startClaudeSession({
|
|
134
|
+
* worktreeId: 'feature-foo',
|
|
135
|
+
* worktreePath: '/path/to/worktree',
|
|
136
|
+
* baseUrl: 'http://localhost:3000',
|
|
137
|
+
* });
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
async function startClaudeSession(options) {
|
|
141
|
+
const { worktreeId, worktreePath } = options;
|
|
142
|
+
// Check if Claude is installed
|
|
143
|
+
const claudeAvailable = await isClaudeInstalled();
|
|
144
|
+
if (!claudeAvailable) {
|
|
145
|
+
throw new Error('Claude CLI is not installed or not in PATH');
|
|
146
|
+
}
|
|
147
|
+
const sessionName = getSessionName(worktreeId);
|
|
148
|
+
// Check if session already exists
|
|
149
|
+
const exists = await (0, tmux_1.hasSession)(sessionName);
|
|
150
|
+
if (exists) {
|
|
151
|
+
console.log(`Claude session ${sessionName} already exists`);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
// Create tmux session with large history buffer for Claude output
|
|
156
|
+
await (0, tmux_1.createSession)({
|
|
157
|
+
sessionName,
|
|
158
|
+
workingDirectory: worktreePath,
|
|
159
|
+
historyLimit: 50000,
|
|
160
|
+
});
|
|
161
|
+
// Get Claude CLI path dynamically
|
|
162
|
+
const claudePath = await getClaudePath();
|
|
163
|
+
// Start Claude CLI in interactive mode using dynamically resolved path
|
|
164
|
+
await (0, tmux_1.sendKeys)(sessionName, claudePath, true);
|
|
165
|
+
// Wait for Claude to initialize with dynamic detection
|
|
166
|
+
// Check for Claude prompt instead of fixed delay
|
|
167
|
+
const maxWaitTime = 10000; // 10 seconds max
|
|
168
|
+
const pollInterval = 500; // Check every 500ms
|
|
169
|
+
const startTime = Date.now();
|
|
170
|
+
while (Date.now() - startTime < maxWaitTime) {
|
|
171
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
172
|
+
try {
|
|
173
|
+
const output = await (0, tmux_1.capturePane)(sessionName, { startLine: -50 });
|
|
174
|
+
// Claude is ready when we see the prompt (> ) or separator line
|
|
175
|
+
if (/^>\s*$/m.test(output) || /^─{10,}$/m.test(output)) {
|
|
176
|
+
console.log(`✓ Claude initialized in ${Date.now() - startTime}ms`);
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// Ignore capture errors during initialization
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
console.log(`✓ Started Claude session: ${sessionName}`);
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
188
|
+
throw new Error(`Failed to start Claude session: ${errorMessage}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Send a message to Claude CLI
|
|
193
|
+
*
|
|
194
|
+
* @param worktreeId - Worktree ID
|
|
195
|
+
* @param message - Message content to send
|
|
196
|
+
* @throws {Error} If session doesn't exist
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```typescript
|
|
200
|
+
* await sendMessageToClaude('feature-foo', 'Explain this code');
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
async function sendMessageToClaude(worktreeId, message) {
|
|
204
|
+
const sessionName = getSessionName(worktreeId);
|
|
205
|
+
// Check if session exists
|
|
206
|
+
const exists = await (0, tmux_1.hasSession)(sessionName);
|
|
207
|
+
if (!exists) {
|
|
208
|
+
throw new Error(`Claude session ${sessionName} does not exist. Start the session first.`);
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
// Send message to Claude (without Enter)
|
|
212
|
+
await (0, tmux_1.sendKeys)(sessionName, message, false);
|
|
213
|
+
// Wait a moment for the text to be typed
|
|
214
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
215
|
+
// Send Enter key to submit (single Enter submits in Claude Code CLI)
|
|
216
|
+
await execAsync(`tmux send-keys -t "${sessionName}" C-m`);
|
|
217
|
+
// Wait a moment for the message to be processed
|
|
218
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
219
|
+
console.log(`✓ Sent message to Claude session: ${sessionName}`);
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
223
|
+
throw new Error(`Failed to send message to Claude: ${errorMessage}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Capture Claude session output
|
|
228
|
+
*
|
|
229
|
+
* @param worktreeId - Worktree ID
|
|
230
|
+
* @param lines - Number of lines to capture (default: 1000)
|
|
231
|
+
* @returns Captured output
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```typescript
|
|
235
|
+
* const output = await captureClaudeOutput('feature-foo');
|
|
236
|
+
* console.log(output);
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
async function captureClaudeOutput(worktreeId, lines = 1000) {
|
|
240
|
+
const sessionName = getSessionName(worktreeId);
|
|
241
|
+
// Check if session exists
|
|
242
|
+
const exists = await (0, tmux_1.hasSession)(sessionName);
|
|
243
|
+
if (!exists) {
|
|
244
|
+
throw new Error(`Claude session ${sessionName} does not exist`);
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
return await (0, tmux_1.capturePane)(sessionName, { startLine: -lines });
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
251
|
+
throw new Error(`Failed to capture Claude output: ${errorMessage}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Stop a Claude session
|
|
256
|
+
*
|
|
257
|
+
* @param worktreeId - Worktree ID
|
|
258
|
+
* @returns True if session was stopped, false if it didn't exist
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ```typescript
|
|
262
|
+
* await stopClaudeSession('feature-foo');
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
async function stopClaudeSession(worktreeId) {
|
|
266
|
+
const sessionName = getSessionName(worktreeId);
|
|
267
|
+
try {
|
|
268
|
+
// Send Ctrl+D to exit Claude gracefully
|
|
269
|
+
const exists = await (0, tmux_1.hasSession)(sessionName);
|
|
270
|
+
if (exists) {
|
|
271
|
+
await (0, tmux_1.sendKeys)(sessionName, '', false);
|
|
272
|
+
// Send Ctrl+D (ASCII 4)
|
|
273
|
+
await execAsync(`tmux send-keys -t "${sessionName}" C-d`);
|
|
274
|
+
// Wait a moment for Claude to exit
|
|
275
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
276
|
+
}
|
|
277
|
+
// Kill the tmux session
|
|
278
|
+
const killed = await (0, tmux_1.killSession)(sessionName);
|
|
279
|
+
if (killed) {
|
|
280
|
+
console.log(`✓ Stopped Claude session: ${sessionName}`);
|
|
281
|
+
}
|
|
282
|
+
return killed;
|
|
283
|
+
}
|
|
284
|
+
catch (error) {
|
|
285
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
286
|
+
console.error(`Error stopping Claude session: ${errorMessage}`);
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Restart a Claude session
|
|
292
|
+
*
|
|
293
|
+
* @param options - Session options
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* ```typescript
|
|
297
|
+
* await restartClaudeSession({
|
|
298
|
+
* worktreeId: 'feature-foo',
|
|
299
|
+
* worktreePath: '/path/to/worktree',
|
|
300
|
+
* baseUrl: 'http://localhost:3000',
|
|
301
|
+
* });
|
|
302
|
+
* ```
|
|
303
|
+
*/
|
|
304
|
+
async function restartClaudeSession(options) {
|
|
305
|
+
const { worktreeId } = options;
|
|
306
|
+
// Stop existing session
|
|
307
|
+
await stopClaudeSession(worktreeId);
|
|
308
|
+
// Wait a moment before restarting
|
|
309
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
310
|
+
// Start new session
|
|
311
|
+
await startClaudeSession(options);
|
|
312
|
+
}
|