commandmate 0.1.5 → 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 +39 -8
- 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,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Environment variable configuration and validation
|
|
4
|
+
* Provides type-safe access to environment variables
|
|
5
|
+
*
|
|
6
|
+
* Issue #76: Environment variable fallback support
|
|
7
|
+
* Supports both new (CM_*) and legacy (MCBD_*) environment variable names
|
|
8
|
+
*/
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.ENV_MAPPING = void 0;
|
|
14
|
+
exports.resetWarnedKeys = resetWarnedKeys;
|
|
15
|
+
exports.getEnvWithFallback = getEnvWithFallback;
|
|
16
|
+
exports.getEnvByKey = getEnvByKey;
|
|
17
|
+
exports.getLogConfig = getLogConfig;
|
|
18
|
+
exports.getEnv = getEnv;
|
|
19
|
+
exports.validateEnv = validateEnv;
|
|
20
|
+
exports.isAuthRequired = isAuthRequired;
|
|
21
|
+
const path_1 = __importDefault(require("path"));
|
|
22
|
+
// ============================================================
|
|
23
|
+
// Environment Variable Mapping (for fallback support)
|
|
24
|
+
// Issue #76: CommandMate rename - Phase 1
|
|
25
|
+
// ============================================================
|
|
26
|
+
/**
|
|
27
|
+
* Environment variable mapping definition
|
|
28
|
+
* New name -> Old name mapping for fallback support
|
|
29
|
+
*/
|
|
30
|
+
exports.ENV_MAPPING = {
|
|
31
|
+
CM_ROOT_DIR: 'MCBD_ROOT_DIR',
|
|
32
|
+
CM_PORT: 'MCBD_PORT',
|
|
33
|
+
CM_BIND: 'MCBD_BIND',
|
|
34
|
+
CM_AUTH_TOKEN: 'MCBD_AUTH_TOKEN',
|
|
35
|
+
CM_LOG_LEVEL: 'MCBD_LOG_LEVEL',
|
|
36
|
+
CM_LOG_FORMAT: 'MCBD_LOG_FORMAT',
|
|
37
|
+
CM_LOG_DIR: 'MCBD_LOG_DIR',
|
|
38
|
+
CM_DB_PATH: 'MCBD_DB_PATH',
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Set to track warned keys and prevent duplicate warnings
|
|
42
|
+
* Module-scoped to persist across function calls
|
|
43
|
+
*/
|
|
44
|
+
const warnedKeys = new Set();
|
|
45
|
+
/**
|
|
46
|
+
* Reset warned keys (for testing purposes)
|
|
47
|
+
*/
|
|
48
|
+
function resetWarnedKeys() {
|
|
49
|
+
warnedKeys.clear();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get environment variable with fallback support
|
|
53
|
+
*
|
|
54
|
+
* @param newKey - New environment variable name (CM_*)
|
|
55
|
+
* @param oldKey - Old environment variable name (MCBD_*)
|
|
56
|
+
* @returns Environment variable value (undefined if not set)
|
|
57
|
+
*/
|
|
58
|
+
function getEnvWithFallback(newKey, oldKey) {
|
|
59
|
+
const newValue = process.env[newKey];
|
|
60
|
+
if (newValue !== undefined) {
|
|
61
|
+
return newValue;
|
|
62
|
+
}
|
|
63
|
+
const oldValue = process.env[oldKey];
|
|
64
|
+
if (oldValue !== undefined) {
|
|
65
|
+
if (!warnedKeys.has(oldKey)) {
|
|
66
|
+
console.warn(`[DEPRECATED] ${oldKey} is deprecated, use ${newKey} instead`);
|
|
67
|
+
warnedKeys.add(oldKey);
|
|
68
|
+
}
|
|
69
|
+
return oldValue;
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get environment variable using ENV_MAPPING (type-safe version)
|
|
75
|
+
*
|
|
76
|
+
* @param key - New environment variable key (from ENV_MAPPING)
|
|
77
|
+
* @returns Environment variable value (undefined if not set)
|
|
78
|
+
*/
|
|
79
|
+
function getEnvByKey(key) {
|
|
80
|
+
return getEnvWithFallback(key, exports.ENV_MAPPING[key]);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Validate log level
|
|
84
|
+
*/
|
|
85
|
+
function isValidLogLevel(level) {
|
|
86
|
+
return level !== undefined && ['debug', 'info', 'warn', 'error'].includes(level);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get log configuration (with fallback support)
|
|
90
|
+
*
|
|
91
|
+
* @returns Log configuration with level and format
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* const config = getLogConfig();
|
|
96
|
+
* console.log(config.level); // 'debug' in development, 'info' in production
|
|
97
|
+
* console.log(config.format); // 'text' or 'json'
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
function getLogConfig() {
|
|
101
|
+
const levelEnv = getEnvByKey('CM_LOG_LEVEL')?.toLowerCase();
|
|
102
|
+
const formatEnv = getEnvByKey('CM_LOG_FORMAT')?.toLowerCase();
|
|
103
|
+
// Default: debug in development, info in production
|
|
104
|
+
const defaultLevel = process.env.NODE_ENV === 'production' ? 'info' : 'debug';
|
|
105
|
+
return {
|
|
106
|
+
level: isValidLogLevel(levelEnv) ? levelEnv : defaultLevel,
|
|
107
|
+
format: formatEnv === 'json' ? 'json' : 'text',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get and validate environment variables (with fallback support)
|
|
112
|
+
*
|
|
113
|
+
* @throws {Error} If required variables are missing or invalid
|
|
114
|
+
* @returns Validated environment configuration
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const env = getEnv();
|
|
119
|
+
* console.log(`Root directory: ${env.CM_ROOT_DIR}`);
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
function getEnv() {
|
|
123
|
+
// Get raw values with defaults (using fallback support)
|
|
124
|
+
const rootDir = getEnvByKey('CM_ROOT_DIR') || process.cwd();
|
|
125
|
+
const port = parseInt(getEnvByKey('CM_PORT') || '3000', 10);
|
|
126
|
+
const bind = getEnvByKey('CM_BIND') || '127.0.0.1';
|
|
127
|
+
const authToken = getEnvByKey('CM_AUTH_TOKEN');
|
|
128
|
+
const databasePath = getEnvByKey('CM_DB_PATH')
|
|
129
|
+
|| process.env.DATABASE_PATH
|
|
130
|
+
|| path_1.default.join(process.cwd(), 'data', 'cm.db');
|
|
131
|
+
// Validate values
|
|
132
|
+
if (!rootDir) {
|
|
133
|
+
throw new Error('CM_ROOT_DIR (or MCBD_ROOT_DIR) is required');
|
|
134
|
+
}
|
|
135
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
136
|
+
throw new Error(`Invalid CM_PORT: ${getEnvByKey('CM_PORT')}. Must be between 1 and 65535.`);
|
|
137
|
+
}
|
|
138
|
+
if (bind !== '127.0.0.1' && bind !== '0.0.0.0' && bind !== 'localhost') {
|
|
139
|
+
throw new Error(`Invalid CM_BIND: ${bind}. Must be '127.0.0.1', '0.0.0.0', or 'localhost'.`);
|
|
140
|
+
}
|
|
141
|
+
// Require auth token for public binding
|
|
142
|
+
if (bind === '0.0.0.0' && !authToken) {
|
|
143
|
+
throw new Error('CM_AUTH_TOKEN (or MCBD_AUTH_TOKEN) is required when CM_BIND=0.0.0.0');
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
CM_ROOT_DIR: path_1.default.resolve(rootDir),
|
|
147
|
+
CM_PORT: port,
|
|
148
|
+
CM_BIND: bind,
|
|
149
|
+
CM_AUTH_TOKEN: authToken,
|
|
150
|
+
CM_DB_PATH: path_1.default.resolve(databasePath),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Validate environment variables without throwing
|
|
155
|
+
*
|
|
156
|
+
* @returns Validation result with errors if any
|
|
157
|
+
*/
|
|
158
|
+
function validateEnv() {
|
|
159
|
+
const errors = [];
|
|
160
|
+
try {
|
|
161
|
+
getEnv();
|
|
162
|
+
return { valid: true, errors: [] };
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
if (error instanceof Error) {
|
|
166
|
+
errors.push(error.message);
|
|
167
|
+
}
|
|
168
|
+
return { valid: false, errors };
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Check if authentication is required based on bind address
|
|
173
|
+
*
|
|
174
|
+
* @returns True if authentication is required
|
|
175
|
+
*/
|
|
176
|
+
function isAuthRequired() {
|
|
177
|
+
const env = getEnv();
|
|
178
|
+
return env.CM_BIND === '0.0.0.0';
|
|
179
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Log file management for Claude output
|
|
4
|
+
* Generates and manages Markdown log files from Claude's responses
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.getLogFilePath = getLogFilePath;
|
|
11
|
+
exports.createLog = createLog;
|
|
12
|
+
exports.appendToLog = appendToLog;
|
|
13
|
+
exports.readLog = readLog;
|
|
14
|
+
exports.listLogs = listLogs;
|
|
15
|
+
exports.cleanupOldLogs = cleanupOldLogs;
|
|
16
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
17
|
+
const path_1 = __importDefault(require("path"));
|
|
18
|
+
const date_fns_1 = require("date-fns");
|
|
19
|
+
const env_1 = require("./env");
|
|
20
|
+
/**
|
|
21
|
+
* Log directory configuration (with fallback support - Issue #76)
|
|
22
|
+
*/
|
|
23
|
+
const LOG_DIR = (0, env_1.getEnvByKey)('CM_LOG_DIR') || path_1.default.join(process.cwd(), 'data', 'logs');
|
|
24
|
+
/**
|
|
25
|
+
* Get log directory for a CLI tool
|
|
26
|
+
*
|
|
27
|
+
* @param cliToolId - CLI tool ID (claude, codex, gemini)
|
|
28
|
+
* @returns Log directory path
|
|
29
|
+
*/
|
|
30
|
+
function getCliToolLogDir(cliToolId = 'claude') {
|
|
31
|
+
return path_1.default.join(LOG_DIR, cliToolId);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Ensure log directory exists
|
|
35
|
+
*
|
|
36
|
+
* @param cliToolId - CLI tool ID (optional, defaults to 'claude')
|
|
37
|
+
*/
|
|
38
|
+
async function ensureLogDirectory(cliToolId = 'claude') {
|
|
39
|
+
const logDir = getCliToolLogDir(cliToolId);
|
|
40
|
+
try {
|
|
41
|
+
await promises_1.default.access(logDir);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
await promises_1.default.mkdir(logDir, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get log file path for a worktree
|
|
49
|
+
*
|
|
50
|
+
* @param worktreeId - Worktree ID
|
|
51
|
+
* @param cliToolId - CLI tool ID (claude, codex, gemini)
|
|
52
|
+
* @returns Log file path
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* getLogFilePath('feature-foo', 'claude')
|
|
57
|
+
* // => '/path/to/data/logs/claude/feature-foo-2025-01-20.md'
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
function getLogFilePath(worktreeId, cliToolId = 'claude') {
|
|
61
|
+
const date = (0, date_fns_1.format)(new Date(), 'yyyy-MM-dd');
|
|
62
|
+
const filename = `${worktreeId}-${date}.md`;
|
|
63
|
+
const logDir = getCliToolLogDir(cliToolId);
|
|
64
|
+
return path_1.default.join(logDir, filename);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Create a Markdown log file for a conversation
|
|
68
|
+
*
|
|
69
|
+
* @param worktreeId - Worktree ID
|
|
70
|
+
* @param userMessage - User's message
|
|
71
|
+
* @param claudeResponse - Claude's response
|
|
72
|
+
* @param cliToolId - CLI tool ID (claude, codex, gemini)
|
|
73
|
+
* @returns Path to the created log file
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const logPath = await createLog(
|
|
78
|
+
* 'feature-foo',
|
|
79
|
+
* 'Explain this code',
|
|
80
|
+
* 'This code implements...',
|
|
81
|
+
* 'claude'
|
|
82
|
+
* );
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
async function createLog(worktreeId, userMessage, claudeResponse, cliToolId = 'claude') {
|
|
86
|
+
await ensureLogDirectory(cliToolId);
|
|
87
|
+
const logPath = getLogFilePath(worktreeId, cliToolId);
|
|
88
|
+
const timestamp = (0, date_fns_1.format)(new Date(), 'yyyy-MM-dd HH:mm:ss');
|
|
89
|
+
// Check if log file already exists
|
|
90
|
+
let logContent = '';
|
|
91
|
+
try {
|
|
92
|
+
logContent = await promises_1.default.readFile(logPath, 'utf-8');
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// File doesn't exist, create header
|
|
96
|
+
const toolName = cliToolId === 'claude' ? 'Claude Code' : cliToolId === 'codex' ? 'Codex CLI' : 'Gemini CLI';
|
|
97
|
+
logContent = `# ${toolName} Conversation Log: ${worktreeId}\n\n`;
|
|
98
|
+
logContent += `Created: ${timestamp}\n\n`;
|
|
99
|
+
logContent += `---\n\n`;
|
|
100
|
+
}
|
|
101
|
+
// Append new conversation
|
|
102
|
+
logContent += `## Conversation at ${timestamp}\n\n`;
|
|
103
|
+
logContent += `### User\n\n`;
|
|
104
|
+
logContent += `${userMessage}\n\n`;
|
|
105
|
+
logContent += `### ${cliToolId === 'claude' ? 'Claude' : cliToolId === 'codex' ? 'Codex' : 'Gemini'}\n\n`;
|
|
106
|
+
logContent += `${claudeResponse}\n\n`;
|
|
107
|
+
logContent += `---\n\n`;
|
|
108
|
+
await promises_1.default.writeFile(logPath, logContent, 'utf-8');
|
|
109
|
+
return logPath;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Append to existing log file
|
|
113
|
+
*
|
|
114
|
+
* @param worktreeId - Worktree ID
|
|
115
|
+
* @param content - Content to append
|
|
116
|
+
* @param cliToolId - CLI tool ID (claude, codex, gemini)
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* await appendToLog('feature-foo', 'Additional notes...', 'claude');
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
async function appendToLog(worktreeId, content, cliToolId = 'claude') {
|
|
124
|
+
await ensureLogDirectory(cliToolId);
|
|
125
|
+
const logPath = getLogFilePath(worktreeId, cliToolId);
|
|
126
|
+
const timestamp = (0, date_fns_1.format)(new Date(), 'yyyy-MM-dd HH:mm:ss');
|
|
127
|
+
let logContent = '';
|
|
128
|
+
try {
|
|
129
|
+
logContent = await promises_1.default.readFile(logPath, 'utf-8');
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// File doesn't exist, create header
|
|
133
|
+
const toolName = cliToolId === 'claude' ? 'Claude Code' : cliToolId === 'codex' ? 'Codex CLI' : 'Gemini CLI';
|
|
134
|
+
logContent = `# ${toolName} Conversation Log: ${worktreeId}\n\n`;
|
|
135
|
+
logContent += `Created: ${timestamp}\n\n`;
|
|
136
|
+
logContent += `---\n\n`;
|
|
137
|
+
}
|
|
138
|
+
logContent += `${content}\n\n`;
|
|
139
|
+
await promises_1.default.writeFile(logPath, logContent, 'utf-8');
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Read log file content
|
|
143
|
+
*
|
|
144
|
+
* @param worktreeId - Worktree ID
|
|
145
|
+
* @param cliToolId - CLI tool ID (claude, codex, gemini)
|
|
146
|
+
* @returns Log file content, or null if file doesn't exist
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* const log = await readLog('feature-foo', 'claude');
|
|
151
|
+
* if (log) {
|
|
152
|
+
* console.log(log);
|
|
153
|
+
* }
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
async function readLog(worktreeId, cliToolId = 'claude') {
|
|
157
|
+
const logPath = getLogFilePath(worktreeId, cliToolId);
|
|
158
|
+
try {
|
|
159
|
+
return await promises_1.default.readFile(logPath, 'utf-8');
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* List all log files for a worktree
|
|
167
|
+
*
|
|
168
|
+
* @param worktreeId - Worktree ID
|
|
169
|
+
* @param cliToolId - CLI tool ID (claude, codex, gemini), or 'all' for all tools
|
|
170
|
+
* @returns Array of log file paths
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```typescript
|
|
174
|
+
* const logs = await listLogs('feature-foo', 'claude');
|
|
175
|
+
* // => ['/path/to/logs/claude/feature-foo-2025-01-20.md', '/path/to/logs/claude/feature-foo-2025-01-19.md']
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
async function listLogs(worktreeId, cliToolId = 'all') {
|
|
179
|
+
const toolIds = cliToolId === 'all' ? ['claude', 'codex', 'gemini'] : [cliToolId];
|
|
180
|
+
const allLogFiles = [];
|
|
181
|
+
for (const toolId of toolIds) {
|
|
182
|
+
await ensureLogDirectory(toolId);
|
|
183
|
+
const logDir = getCliToolLogDir(toolId);
|
|
184
|
+
try {
|
|
185
|
+
const files = await promises_1.default.readdir(logDir);
|
|
186
|
+
const logFiles = files
|
|
187
|
+
.filter((file) => file.startsWith(`${worktreeId}-`) && file.endsWith('.md'))
|
|
188
|
+
.map((file) => path_1.default.join(logDir, file));
|
|
189
|
+
allLogFiles.push(...logFiles);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
// Directory doesn't exist or is not accessible, skip
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return allLogFiles.sort().reverse(); // Most recent first
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Delete old log files (older than specified days)
|
|
199
|
+
*
|
|
200
|
+
* @param days - Number of days to keep
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```typescript
|
|
204
|
+
* // Delete logs older than 30 days
|
|
205
|
+
* await cleanupOldLogs(30);
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
async function cleanupOldLogs(days = 30) {
|
|
209
|
+
const toolIds = ['claude', 'codex', 'gemini'];
|
|
210
|
+
let totalDeletedCount = 0;
|
|
211
|
+
const now = new Date();
|
|
212
|
+
const cutoffDate = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);
|
|
213
|
+
for (const toolId of toolIds) {
|
|
214
|
+
await ensureLogDirectory(toolId);
|
|
215
|
+
const logDir = getCliToolLogDir(toolId);
|
|
216
|
+
try {
|
|
217
|
+
const files = await promises_1.default.readdir(logDir);
|
|
218
|
+
for (const file of files) {
|
|
219
|
+
if (!file.endsWith('.md'))
|
|
220
|
+
continue;
|
|
221
|
+
const filePath = path_1.default.join(logDir, file);
|
|
222
|
+
const stats = await promises_1.default.stat(filePath);
|
|
223
|
+
if (stats.mtime < cutoffDate) {
|
|
224
|
+
await promises_1.default.unlink(filePath);
|
|
225
|
+
totalDeletedCount++;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
console.error(`Error cleaning up old logs for ${toolId}:`, error);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return totalDeletedCount;
|
|
234
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Structured logging utility for CommandMate
|
|
4
|
+
*
|
|
5
|
+
* Issue #41: Structured logging + log level control
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - [MF-1] Sensitive data filtering (sanitize)
|
|
9
|
+
* - [MF-2] Server/Client log separation
|
|
10
|
+
* - [SF-2] Request ID generation
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const logger = createLogger('prompt-detector');
|
|
15
|
+
* logger.debug('detectPrompt:start', { outputLength: 1500 });
|
|
16
|
+
*
|
|
17
|
+
* const log = logger.withContext({ worktreeId: 'wt-1', requestId: generateRequestId() });
|
|
18
|
+
* log.info('action:complete', { result: 'success' });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.generateRequestId = generateRequestId;
|
|
23
|
+
exports.createLogger = createLogger;
|
|
24
|
+
const env_1 = require("./env");
|
|
25
|
+
// ============================================================
|
|
26
|
+
// [MF-1] Sensitive Data Filtering
|
|
27
|
+
// ============================================================
|
|
28
|
+
/**
|
|
29
|
+
* Sensitive data patterns
|
|
30
|
+
*/
|
|
31
|
+
const SENSITIVE_PATTERNS = [
|
|
32
|
+
// Bearer token
|
|
33
|
+
{ pattern: /Bearer\s+[A-Za-z0-9\-._~+/]+=*/gi, replacement: 'Bearer [REDACTED]' },
|
|
34
|
+
// Password related
|
|
35
|
+
{ pattern: /(password|passwd|pwd)[=:]\s*\S+/gi, replacement: '$1=[REDACTED]' },
|
|
36
|
+
// Token/secret related
|
|
37
|
+
{ pattern: /(token|secret|api_key|apikey|auth)[=:]\s*\S+/gi, replacement: '$1=[REDACTED]' },
|
|
38
|
+
// CM_AUTH_TOKEN (new name - Issue #76)
|
|
39
|
+
{ pattern: /CM_AUTH_TOKEN=\S+/gi, replacement: 'CM_AUTH_TOKEN=[REDACTED]' },
|
|
40
|
+
// MCBD_AUTH_TOKEN (legacy name)
|
|
41
|
+
{ pattern: /MCBD_AUTH_TOKEN=\S+/gi, replacement: 'MCBD_AUTH_TOKEN=[REDACTED]' },
|
|
42
|
+
// Authorization header
|
|
43
|
+
{ pattern: /Authorization:\s*\S+/gi, replacement: 'Authorization: [REDACTED]' },
|
|
44
|
+
// SSH key
|
|
45
|
+
{ pattern: /-----BEGIN\s+\w+\s+PRIVATE\s+KEY-----[\s\S]*?-----END\s+\w+\s+PRIVATE\s+KEY-----/g, replacement: '[SSH_KEY_REDACTED]' },
|
|
46
|
+
];
|
|
47
|
+
/**
|
|
48
|
+
* Sensitive key name patterns
|
|
49
|
+
*/
|
|
50
|
+
const SENSITIVE_KEY_PATTERN = /password|secret|token|key|auth/i;
|
|
51
|
+
/**
|
|
52
|
+
* Sanitize value (mask sensitive data)
|
|
53
|
+
*/
|
|
54
|
+
function sanitize(value) {
|
|
55
|
+
if (typeof value === 'string') {
|
|
56
|
+
let sanitized = value;
|
|
57
|
+
for (const { pattern, replacement } of SENSITIVE_PATTERNS) {
|
|
58
|
+
sanitized = sanitized.replace(pattern, replacement);
|
|
59
|
+
}
|
|
60
|
+
return sanitized;
|
|
61
|
+
}
|
|
62
|
+
if (typeof value === 'object' && value !== null) {
|
|
63
|
+
if (Array.isArray(value)) {
|
|
64
|
+
return value.map(sanitize);
|
|
65
|
+
}
|
|
66
|
+
const result = {};
|
|
67
|
+
for (const [k, v] of Object.entries(value)) {
|
|
68
|
+
// Mask if key name is sensitive
|
|
69
|
+
if (SENSITIVE_KEY_PATTERN.test(k)) {
|
|
70
|
+
result[k] = '[REDACTED]';
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
result[k] = sanitize(v);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
// ============================================================
|
|
81
|
+
// [MF-2] Server/Client Log Separation
|
|
82
|
+
// ============================================================
|
|
83
|
+
/**
|
|
84
|
+
* Check if running on server side
|
|
85
|
+
*/
|
|
86
|
+
function isServer() {
|
|
87
|
+
return typeof window === 'undefined';
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check if should log on client side
|
|
91
|
+
* Only output in development environment
|
|
92
|
+
*/
|
|
93
|
+
function shouldLogOnClient() {
|
|
94
|
+
return process.env.NODE_ENV === 'development';
|
|
95
|
+
}
|
|
96
|
+
// ============================================================
|
|
97
|
+
// Log Level Control
|
|
98
|
+
// ============================================================
|
|
99
|
+
const LOG_LEVELS = {
|
|
100
|
+
debug: 0,
|
|
101
|
+
info: 1,
|
|
102
|
+
warn: 2,
|
|
103
|
+
error: 3,
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Get current log level
|
|
107
|
+
* [SF-1] Get from env.ts
|
|
108
|
+
*/
|
|
109
|
+
function getCurrentLogLevel() {
|
|
110
|
+
const config = (0, env_1.getLogConfig)();
|
|
111
|
+
return config.level;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get log output format
|
|
115
|
+
* [SF-1] Get from env.ts
|
|
116
|
+
*/
|
|
117
|
+
function getLogFormat() {
|
|
118
|
+
const config = (0, env_1.getLogConfig)();
|
|
119
|
+
return config.format;
|
|
120
|
+
}
|
|
121
|
+
// ============================================================
|
|
122
|
+
// Log Output
|
|
123
|
+
// ============================================================
|
|
124
|
+
/**
|
|
125
|
+
* Format log entry
|
|
126
|
+
*/
|
|
127
|
+
function formatLogEntry(entry) {
|
|
128
|
+
if (getLogFormat() === 'json') {
|
|
129
|
+
return JSON.stringify(entry);
|
|
130
|
+
}
|
|
131
|
+
// Text format
|
|
132
|
+
const { timestamp, level, module, action, data, worktreeId, cliToolId, requestId } = entry;
|
|
133
|
+
const contextParts = [worktreeId, cliToolId].filter(Boolean);
|
|
134
|
+
const contextStr = contextParts.length > 0 ? ` [${contextParts.join(':')}]` : '';
|
|
135
|
+
const requestIdStr = requestId ? ` (${requestId.slice(0, 8)})` : '';
|
|
136
|
+
const dataStr = data ? ` ${JSON.stringify(data)}` : '';
|
|
137
|
+
return `[${timestamp}] [${level.toUpperCase()}] [${module}]${contextStr}${requestIdStr} ${action}${dataStr}`;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Execute log output
|
|
141
|
+
*/
|
|
142
|
+
function log(level, module, action, data, context) {
|
|
143
|
+
const currentLevel = getCurrentLogLevel();
|
|
144
|
+
if (LOG_LEVELS[level] < LOG_LEVELS[currentLevel]) {
|
|
145
|
+
return; // Do not output if below threshold
|
|
146
|
+
}
|
|
147
|
+
// [MF-2] Only output on client side in development environment
|
|
148
|
+
if (!isServer() && !shouldLogOnClient()) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
// [MF-1] Sanitize data
|
|
152
|
+
const sanitizedData = data ? sanitize(data) : undefined;
|
|
153
|
+
const entry = {
|
|
154
|
+
level,
|
|
155
|
+
module,
|
|
156
|
+
action,
|
|
157
|
+
timestamp: new Date().toISOString(),
|
|
158
|
+
...context,
|
|
159
|
+
...(sanitizedData && { data: sanitizedData }),
|
|
160
|
+
};
|
|
161
|
+
const formatted = formatLogEntry(entry);
|
|
162
|
+
// Server side: structured log, Client side: console group
|
|
163
|
+
if (isServer()) {
|
|
164
|
+
switch (level) {
|
|
165
|
+
case 'error':
|
|
166
|
+
console.error(formatted);
|
|
167
|
+
break;
|
|
168
|
+
case 'warn':
|
|
169
|
+
console.warn(formatted);
|
|
170
|
+
break;
|
|
171
|
+
default:
|
|
172
|
+
console.log(formatted);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
// Client side (development only)
|
|
177
|
+
const consoleMethod = level === 'error' ? 'error' : level === 'warn' ? 'warn' : 'log';
|
|
178
|
+
console[consoleMethod](`[${module}] ${action}`, sanitizedData || '');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// ============================================================
|
|
182
|
+
// [SF-2] Request ID Generation
|
|
183
|
+
// ============================================================
|
|
184
|
+
/**
|
|
185
|
+
* Generate request ID
|
|
186
|
+
* UUID v4 format
|
|
187
|
+
*/
|
|
188
|
+
function generateRequestId() {
|
|
189
|
+
// crypto.randomUUID() is available in Node.js 19+ and modern browsers
|
|
190
|
+
// Provide fallback implementation
|
|
191
|
+
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
|
|
192
|
+
return crypto.randomUUID();
|
|
193
|
+
}
|
|
194
|
+
// Fallback: simple random ID
|
|
195
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
196
|
+
const r = (Math.random() * 16) | 0;
|
|
197
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
198
|
+
return v.toString(16);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
// ============================================================
|
|
202
|
+
// Logger Factory
|
|
203
|
+
// ============================================================
|
|
204
|
+
/**
|
|
205
|
+
* Create module-specific logger
|
|
206
|
+
*
|
|
207
|
+
* @param module - Module name (e.g., 'prompt-detector', 'cli-session')
|
|
208
|
+
* @returns Logger instance
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```typescript
|
|
212
|
+
* const logger = createLogger('api-worktrees');
|
|
213
|
+
*
|
|
214
|
+
* // Basic usage
|
|
215
|
+
* logger.info('GET:start');
|
|
216
|
+
* logger.debug('statusCheck', { worktreeId: 'wt-1' });
|
|
217
|
+
*
|
|
218
|
+
* // With context
|
|
219
|
+
* const log = logger.withContext({ worktreeId: 'wt-1', requestId: generateRequestId() });
|
|
220
|
+
* log.info('action:complete');
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
function createLogger(module) {
|
|
224
|
+
const createLoggerWithContext = (context) => ({
|
|
225
|
+
debug: (action, data) => log('debug', module, action, data, context),
|
|
226
|
+
info: (action, data) => log('info', module, action, data, context),
|
|
227
|
+
warn: (action, data) => log('warn', module, action, data, context),
|
|
228
|
+
error: (action, data) => log('error', module, action, data, context),
|
|
229
|
+
withContext: (newContext) => createLoggerWithContext({ ...context, ...newContext }),
|
|
230
|
+
});
|
|
231
|
+
return createLoggerWithContext();
|
|
232
|
+
}
|