@glwhappen/web-code 1.32.0
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/LICENSE +718 -0
- package/README.de.md +250 -0
- package/README.ja.md +242 -0
- package/README.ko.md +242 -0
- package/README.md +252 -0
- package/README.ru.md +250 -0
- package/README.tr.md +252 -0
- package/README.zh-CN.md +242 -0
- package/dist/api-docs.html +879 -0
- package/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/assets/index-Ct6oPUQk.css +32 -0
- package/dist/assets/index-u6XmIqLb.js +1346 -0
- package/dist/assets/vendor-codemirror-OwyKSvPE.js +41 -0
- package/dist/assets/vendor-react-BGZc9oRE.js +59 -0
- package/dist/assets/vendor-xterm-CJZjLICi.js +66 -0
- package/dist/clear-cache.html +85 -0
- package/dist/convert-icons.md +53 -0
- package/dist/favicon.png +0 -0
- package/dist/favicon.svg +9 -0
- package/dist/generate-icons.js +49 -0
- package/dist/icons/claude-ai-icon.svg +1 -0
- package/dist/icons/codex-white.svg +3 -0
- package/dist/icons/codex.svg +3 -0
- package/dist/icons/cursor-white.svg +12 -0
- package/dist/icons/cursor.svg +1 -0
- package/dist/icons/gemini-ai-icon.svg +1 -0
- package/dist/icons/icon-128x128.png +0 -0
- package/dist/icons/icon-128x128.svg +12 -0
- package/dist/icons/icon-144x144.png +0 -0
- package/dist/icons/icon-144x144.svg +12 -0
- package/dist/icons/icon-152x152.png +0 -0
- package/dist/icons/icon-152x152.svg +12 -0
- package/dist/icons/icon-192x192.png +0 -0
- package/dist/icons/icon-192x192.svg +12 -0
- package/dist/icons/icon-384x384.png +0 -0
- package/dist/icons/icon-384x384.svg +12 -0
- package/dist/icons/icon-512x512.png +0 -0
- package/dist/icons/icon-512x512.svg +12 -0
- package/dist/icons/icon-72x72.png +0 -0
- package/dist/icons/icon-72x72.svg +12 -0
- package/dist/icons/icon-96x96.png +0 -0
- package/dist/icons/icon-96x96.svg +12 -0
- package/dist/icons/icon-template.svg +12 -0
- package/dist/index.html +52 -0
- package/dist/logo-128.png +0 -0
- package/dist/logo-256.png +0 -0
- package/dist/logo-32.png +0 -0
- package/dist/logo-512.png +0 -0
- package/dist/logo-64.png +0 -0
- package/dist/logo.svg +17 -0
- package/dist/manifest.json +61 -0
- package/dist/screenshots/cli-selection.png +0 -0
- package/dist/screenshots/desktop-main.png +0 -0
- package/dist/screenshots/mobile-chat.png +0 -0
- package/dist/screenshots/tools-modal.png +0 -0
- package/dist/sw.js +124 -0
- package/dist-server/server/claude-sdk.js +738 -0
- package/dist-server/server/claude-sdk.js.map +1 -0
- package/dist-server/server/cli.js +641 -0
- package/dist-server/server/cli.js.map +1 -0
- package/dist-server/server/constants/config.js +6 -0
- package/dist-server/server/constants/config.js.map +1 -0
- package/dist-server/server/cursor-cli.js +271 -0
- package/dist-server/server/cursor-cli.js.map +1 -0
- package/dist-server/server/gemini-cli.js +539 -0
- package/dist-server/server/gemini-cli.js.map +1 -0
- package/dist-server/server/gemini-response-handler.js +72 -0
- package/dist-server/server/gemini-response-handler.js.map +1 -0
- package/dist-server/server/index.js +1340 -0
- package/dist-server/server/index.js.map +1 -0
- package/dist-server/server/load-env.js +32 -0
- package/dist-server/server/load-env.js.map +1 -0
- package/dist-server/server/middleware/auth.js +117 -0
- package/dist-server/server/middleware/auth.js.map +1 -0
- package/dist-server/server/modules/database/connection.js +125 -0
- package/dist-server/server/modules/database/connection.js.map +1 -0
- package/dist-server/server/modules/database/index.js +13 -0
- package/dist-server/server/modules/database/index.js.map +1 -0
- package/dist-server/server/modules/database/init-db.js +18 -0
- package/dist-server/server/modules/database/init-db.js.map +1 -0
- package/dist-server/server/modules/database/migrations.js +419 -0
- package/dist-server/server/modules/database/migrations.js.map +1 -0
- package/dist-server/server/modules/database/repositories/api-keys.js +72 -0
- package/dist-server/server/modules/database/repositories/api-keys.js.map +1 -0
- package/dist-server/server/modules/database/repositories/app-config.js +47 -0
- package/dist-server/server/modules/database/repositories/app-config.js.map +1 -0
- package/dist-server/server/modules/database/repositories/credentials.js +68 -0
- package/dist-server/server/modules/database/repositories/credentials.js.map +1 -0
- package/dist-server/server/modules/database/repositories/github-tokens.js +54 -0
- package/dist-server/server/modules/database/repositories/github-tokens.js.map +1 -0
- package/dist-server/server/modules/database/repositories/notification-preferences.js +72 -0
- package/dist-server/server/modules/database/repositories/notification-preferences.js.map +1 -0
- package/dist-server/server/modules/database/repositories/projects.db.integration.test.js +67 -0
- package/dist-server/server/modules/database/repositories/projects.db.integration.test.js.map +1 -0
- package/dist-server/server/modules/database/repositories/projects.db.js +185 -0
- package/dist-server/server/modules/database/repositories/projects.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/push-subscriptions.js +49 -0
- package/dist-server/server/modules/database/repositories/push-subscriptions.js.map +1 -0
- package/dist-server/server/modules/database/repositories/scan-state.db.js +31 -0
- package/dist-server/server/modules/database/repositories/scan-state.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/sessions.db.integration.test.js +64 -0
- package/dist-server/server/modules/database/repositories/sessions.db.integration.test.js.map +1 -0
- package/dist-server/server/modules/database/repositories/sessions.db.js +150 -0
- package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/users.js +116 -0
- package/dist-server/server/modules/database/repositories/users.js.map +1 -0
- package/dist-server/server/modules/database/repositories/vapid-keys.js +38 -0
- package/dist-server/server/modules/database/repositories/vapid-keys.js.map +1 -0
- package/dist-server/server/modules/database/schema.js +150 -0
- package/dist-server/server/modules/database/schema.js.map +1 -0
- package/dist-server/server/modules/projects/index.js +4 -0
- package/dist-server/server/modules/projects/index.js.map +1 -0
- package/dist-server/server/modules/projects/projects.routes.js +225 -0
- package/dist-server/server/modules/projects/projects.routes.js.map +1 -0
- package/dist-server/server/modules/projects/services/project-clone.service.js +220 -0
- package/dist-server/server/modules/projects/services/project-clone.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/project-delete.service.js +83 -0
- package/dist-server/server/modules/projects/services/project-delete.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/project-management.service.js +99 -0
- package/dist-server/server/modules/projects/services/project-management.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/project-star.service.js +60 -0
- package/dist-server/server/modules/projects/services/project-star.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/projects-has-taskmaster.service.js +171 -0
- package/dist-server/server/modules/projects/services/projects-has-taskmaster.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +213 -0
- package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -0
- package/dist-server/server/modules/projects/tests/project-clone.service.test.js +129 -0
- package/dist-server/server/modules/projects/tests/project-clone.service.test.js.map +1 -0
- package/dist-server/server/modules/projects/tests/project-management.service.test.js +89 -0
- package/dist-server/server/modules/projects/tests/project-management.service.test.js.map +1 -0
- package/dist-server/server/modules/projects/tests/project-star.service.test.js +99 -0
- package/dist-server/server/modules/projects/tests/project-star.service.test.js.map +1 -0
- package/dist-server/server/modules/projects/tests/projects-has-taskmaster.service.test.js +88 -0
- package/dist-server/server/modules/projects/tests/projects-has-taskmaster.service.test.js.map +1 -0
- package/dist-server/server/modules/providers/index.js +5 -0
- package/dist-server/server/modules/providers/index.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +104 -0
- package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js +103 -0
- package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +116 -0
- package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +546 -0
- package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js +198 -0
- package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude.provider.js +17 -0
- package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js +84 -0
- package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js +107 -0
- package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +123 -0
- package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +513 -0
- package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js +82 -0
- package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex.provider.js +17 -0
- package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js +118 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js +80 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js +105 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +545 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js +28 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +17 -0
- package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js +254 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js +82 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js +312 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js +484 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js +33 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/gemini/gemini.provider.js +17 -0
- package/dist-server/server/modules/providers/list/gemini/gemini.provider.js.map +1 -0
- package/dist-server/server/modules/providers/provider.registry.js +31 -0
- package/dist-server/server/modules/providers/provider.registry.js.map +1 -0
- package/dist-server/server/modules/providers/provider.routes.js +377 -0
- package/dist-server/server/modules/providers/provider.routes.js.map +1 -0
- package/dist-server/server/modules/providers/services/mcp.service.js +69 -0
- package/dist-server/server/modules/providers/services/mcp.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/provider-auth.service.js +25 -0
- package/dist-server/server/modules/providers/services/provider-auth.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/session-conversations-search.service.js +984 -0
- package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/session-synchronizer.service.js +56 -0
- package/dist-server/server/modules/providers/services/session-synchronizer.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/sessions-watcher.service.js +269 -0
- package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/sessions.service.js +179 -0
- package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/skills.service.js +11 -0
- package/dist-server/server/modules/providers/services/skills.service.js.map +1 -0
- package/dist-server/server/modules/providers/shared/base/abstract.provider.js +14 -0
- package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -0
- package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js +102 -0
- package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/shared/skills/skills.provider.js +45 -0
- package/dist-server/server/modules/providers/shared/skills/skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/tests/mcp.test.js +250 -0
- package/dist-server/server/modules/providers/tests/mcp.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/skills.test.js +226 -0
- package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -0
- package/dist-server/server/modules/websocket/index.js +3 -0
- package/dist-server/server/modules/websocket/index.js.map +1 -0
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js +192 -0
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js +52 -0
- package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js +360 -0
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/websocket-auth.service.js +32 -0
- package/dist-server/server/modules/websocket/services/websocket-auth.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/websocket-server.service.js +36 -0
- package/dist-server/server/modules/websocket/services/websocket-server.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/websocket-state.service.js +14 -0
- package/dist-server/server/modules/websocket/services/websocket-state.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/websocket-writer.service.js +32 -0
- package/dist-server/server/modules/websocket/services/websocket-writer.service.js.map +1 -0
- package/dist-server/server/openai-codex.js +418 -0
- package/dist-server/server/openai-codex.js.map +1 -0
- package/dist-server/server/routes/admin.js +109 -0
- package/dist-server/server/routes/admin.js.map +1 -0
- package/dist-server/server/routes/agent.js +1145 -0
- package/dist-server/server/routes/agent.js.map +1 -0
- package/dist-server/server/routes/auth.js +123 -0
- package/dist-server/server/routes/auth.js.map +1 -0
- package/dist-server/server/routes/commands.js +487 -0
- package/dist-server/server/routes/commands.js.map +1 -0
- package/dist-server/server/routes/cursor.js +49 -0
- package/dist-server/server/routes/cursor.js.map +1 -0
- package/dist-server/server/routes/gemini.js +25 -0
- package/dist-server/server/routes/gemini.js.map +1 -0
- package/dist-server/server/routes/git.js +1263 -0
- package/dist-server/server/routes/git.js.map +1 -0
- package/dist-server/server/routes/mcp-utils.js +29 -0
- package/dist-server/server/routes/mcp-utils.js.map +1 -0
- package/dist-server/server/routes/plugins.js +266 -0
- package/dist-server/server/routes/plugins.js.map +1 -0
- package/dist-server/server/routes/settings.js +259 -0
- package/dist-server/server/routes/settings.js.map +1 -0
- package/dist-server/server/routes/taskmaster.js +1360 -0
- package/dist-server/server/routes/taskmaster.js.map +1 -0
- package/dist-server/server/routes/user.js +115 -0
- package/dist-server/server/routes/user.js.map +1 -0
- package/dist-server/server/services/notification-orchestrator.js +177 -0
- package/dist-server/server/services/notification-orchestrator.js.map +1 -0
- package/dist-server/server/services/vapid-keys.js +27 -0
- package/dist-server/server/services/vapid-keys.js.map +1 -0
- package/dist-server/server/sessionManager.js +215 -0
- package/dist-server/server/sessionManager.js.map +1 -0
- package/dist-server/server/shared/claude-cli-path.js +103 -0
- package/dist-server/server/shared/claude-cli-path.js.map +1 -0
- package/dist-server/server/shared/claude-cli-path.test.js +45 -0
- package/dist-server/server/shared/claude-cli-path.test.js.map +1 -0
- package/dist-server/server/shared/default-user.js +29 -0
- package/dist-server/server/shared/default-user.js.map +1 -0
- package/dist-server/server/shared/frontmatter.js +16 -0
- package/dist-server/server/shared/frontmatter.js.map +1 -0
- package/dist-server/server/shared/interfaces.js +2 -0
- package/dist-server/server/shared/interfaces.js.map +1 -0
- package/dist-server/server/shared/types.js +2 -0
- package/dist-server/server/shared/types.js.map +1 -0
- package/dist-server/server/shared/utils.js +633 -0
- package/dist-server/server/shared/utils.js.map +1 -0
- package/dist-server/server/utils/colors.js +20 -0
- package/dist-server/server/utils/colors.js.map +1 -0
- package/dist-server/server/utils/commandParser.js +255 -0
- package/dist-server/server/utils/commandParser.js.map +1 -0
- package/dist-server/server/utils/gitConfig.js +36 -0
- package/dist-server/server/utils/gitConfig.js.map +1 -0
- package/dist-server/server/utils/mcp-detector.js +134 -0
- package/dist-server/server/utils/mcp-detector.js.map +1 -0
- package/dist-server/server/utils/plugin-loader.js +413 -0
- package/dist-server/server/utils/plugin-loader.js.map +1 -0
- package/dist-server/server/utils/plugin-process-manager.js +163 -0
- package/dist-server/server/utils/plugin-process-manager.js.map +1 -0
- package/dist-server/server/utils/runtime-paths.js +30 -0
- package/dist-server/server/utils/runtime-paths.js.map +1 -0
- package/dist-server/server/utils/taskmaster-websocket.js +124 -0
- package/dist-server/server/utils/taskmaster-websocket.js.map +1 -0
- package/dist-server/server/utils/url-detection.js +58 -0
- package/dist-server/server/utils/url-detection.js.map +1 -0
- package/dist-server/shared/modelConstants.js +99 -0
- package/dist-server/shared/modelConstants.js.map +1 -0
- package/dist-server/shared/networkHosts.js +20 -0
- package/dist-server/shared/networkHosts.js.map +1 -0
- package/package.json +169 -0
- package/scripts/fix-node-pty.js +67 -0
- package/server/claude-sdk.js +864 -0
- package/server/cli.js +688 -0
- package/server/constants/config.js +5 -0
- package/server/cursor-cli.js +334 -0
- package/server/gemini-cli.js +622 -0
- package/server/gemini-response-handler.js +79 -0
- package/server/index.js +1505 -0
- package/server/load-env.js +34 -0
- package/server/middleware/auth.js +142 -0
- package/server/modules/database/connection.ts +143 -0
- package/server/modules/database/index.ts +12 -0
- package/server/modules/database/init-db.ts +17 -0
- package/server/modules/database/migrations.ts +496 -0
- package/server/modules/database/repositories/api-keys.ts +119 -0
- package/server/modules/database/repositories/app-config.ts +53 -0
- package/server/modules/database/repositories/credentials.ts +106 -0
- package/server/modules/database/repositories/github-tokens.ts +100 -0
- package/server/modules/database/repositories/notification-preferences.ts +103 -0
- package/server/modules/database/repositories/projects.db.integration.test.ts +78 -0
- package/server/modules/database/repositories/projects.db.ts +210 -0
- package/server/modules/database/repositories/push-subscriptions.ts +80 -0
- package/server/modules/database/repositories/scan-state.db.ts +42 -0
- package/server/modules/database/repositories/sessions.db.integration.test.ts +78 -0
- package/server/modules/database/repositories/sessions.db.ts +230 -0
- package/server/modules/database/repositories/users.ts +186 -0
- package/server/modules/database/repositories/vapid-keys.ts +57 -0
- package/server/modules/database/schema.ts +159 -0
- package/server/modules/projects/index.ts +6 -0
- package/server/modules/projects/projects.routes.ts +292 -0
- package/server/modules/projects/services/project-clone.service.ts +327 -0
- package/server/modules/projects/services/project-delete.service.ts +95 -0
- package/server/modules/projects/services/project-management.service.ts +158 -0
- package/server/modules/projects/services/project-star.service.ts +78 -0
- package/server/modules/projects/services/projects-has-taskmaster.service.ts +257 -0
- package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +355 -0
- package/server/modules/projects/tests/project-clone.service.test.ts +186 -0
- package/server/modules/projects/tests/project-management.service.test.ts +122 -0
- package/server/modules/projects/tests/project-star.service.test.ts +128 -0
- package/server/modules/projects/tests/projects-has-taskmaster.service.test.ts +107 -0
- package/server/modules/providers/README.md +346 -0
- package/server/modules/providers/index.ts +5 -0
- package/server/modules/providers/list/claude/claude-auth.provider.ts +124 -0
- package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -0
- package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +179 -0
- package/server/modules/providers/list/claude/claude-sessions.provider.ts +642 -0
- package/server/modules/providers/list/claude/claude-skills.provider.ts +257 -0
- package/server/modules/providers/list/claude/claude.provider.ts +24 -0
- package/server/modules/providers/list/codex/codex-auth.provider.ts +100 -0
- package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -0
- package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +182 -0
- package/server/modules/providers/list/codex/codex-sessions.provider.ts +589 -0
- package/server/modules/providers/list/codex/codex-skills.provider.ts +100 -0
- package/server/modules/providers/list/codex/codex.provider.ts +24 -0
- package/server/modules/providers/list/cursor/cursor-auth.provider.ts +143 -0
- package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -0
- package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +155 -0
- package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +624 -0
- package/server/modules/providers/list/cursor/cursor-skills.provider.ts +31 -0
- package/server/modules/providers/list/cursor/cursor.provider.ts +24 -0
- package/server/modules/providers/list/gemini/gemini-auth.provider.ts +307 -0
- package/server/modules/providers/list/gemini/gemini-mcp.provider.ts +110 -0
- package/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.ts +407 -0
- package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +552 -0
- package/server/modules/providers/list/gemini/gemini-skills.provider.ts +36 -0
- package/server/modules/providers/list/gemini/gemini.provider.ts +24 -0
- package/server/modules/providers/provider.registry.ts +36 -0
- package/server/modules/providers/provider.routes.ts +488 -0
- package/server/modules/providers/services/mcp.service.ts +94 -0
- package/server/modules/providers/services/provider-auth.service.ts +26 -0
- package/server/modules/providers/services/session-conversations-search.service.ts +1319 -0
- package/server/modules/providers/services/session-synchronizer.service.ts +75 -0
- package/server/modules/providers/services/sessions-watcher.service.ts +318 -0
- package/server/modules/providers/services/sessions.service.ts +240 -0
- package/server/modules/providers/services/skills.service.ts +15 -0
- package/server/modules/providers/shared/base/abstract.provider.ts +29 -0
- package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -0
- package/server/modules/providers/shared/skills/skills.provider.ts +64 -0
- package/server/modules/providers/tests/mcp.test.ts +293 -0
- package/server/modules/providers/tests/skills.test.ts +446 -0
- package/server/modules/websocket/README.md +267 -0
- package/server/modules/websocket/index.ts +2 -0
- package/server/modules/websocket/services/chat-websocket.service.ts +275 -0
- package/server/modules/websocket/services/plugin-websocket-proxy.service.ts +65 -0
- package/server/modules/websocket/services/shell-websocket.service.ts +489 -0
- package/server/modules/websocket/services/websocket-auth.service.ts +54 -0
- package/server/modules/websocket/services/websocket-server.service.ts +58 -0
- package/server/modules/websocket/services/websocket-state.service.ts +16 -0
- package/server/modules/websocket/services/websocket-writer.service.ts +38 -0
- package/server/openai-codex.js +474 -0
- package/server/routes/admin.js +128 -0
- package/server/routes/agent.js +1246 -0
- package/server/routes/auth.js +144 -0
- package/server/routes/commands.js +556 -0
- package/server/routes/cursor.js +52 -0
- package/server/routes/gemini.js +30 -0
- package/server/routes/git.js +1493 -0
- package/server/routes/mcp-utils.js +31 -0
- package/server/routes/plugins.js +307 -0
- package/server/routes/settings.js +286 -0
- package/server/routes/taskmaster.js +1468 -0
- package/server/routes/user.js +123 -0
- package/server/services/notification-orchestrator.js +228 -0
- package/server/services/vapid-keys.js +36 -0
- package/server/sessionManager.js +248 -0
- package/server/shared/claude-cli-path.test.ts +61 -0
- package/server/shared/claude-cli-path.ts +139 -0
- package/server/shared/default-user.ts +30 -0
- package/server/shared/frontmatter.ts +18 -0
- package/server/shared/interfaces.ts +111 -0
- package/server/shared/types.ts +406 -0
- package/server/shared/utils.ts +763 -0
- package/server/tsconfig.json +36 -0
- package/server/utils/colors.js +21 -0
- package/server/utils/commandParser.js +305 -0
- package/server/utils/gitConfig.js +34 -0
- package/server/utils/mcp-detector.js +147 -0
- package/server/utils/plugin-loader.js +457 -0
- package/server/utils/plugin-process-manager.js +184 -0
- package/server/utils/runtime-paths.js +37 -0
- package/server/utils/taskmaster-websocket.js +135 -0
- package/server/utils/url-detection.js +71 -0
- package/shared/modelConstants.js +107 -0
- package/shared/networkHosts.js +22 -0
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
import { Database } from 'better-sqlite3';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
APP_CONFIG_TABLE_SCHEMA_SQL,
|
|
5
|
+
LAST_SCANNED_AT_SQL,
|
|
6
|
+
PROJECTS_TABLE_SCHEMA_SQL,
|
|
7
|
+
PUSH_SUBSCRIPTIONS_TABLE_SCHEMA_SQL,
|
|
8
|
+
SESSIONS_TABLE_SCHEMA_SQL,
|
|
9
|
+
USER_NOTIFICATION_PREFERENCES_TABLE_SCHEMA_SQL,
|
|
10
|
+
VAPID_KEYS_TABLE_SCHEMA_SQL,
|
|
11
|
+
} from '@/modules/database/schema.js';
|
|
12
|
+
|
|
13
|
+
const SQLITE_UUID_SQL = `
|
|
14
|
+
lower(hex(randomblob(4))) || '-' ||
|
|
15
|
+
lower(hex(randomblob(2))) || '-' ||
|
|
16
|
+
lower(hex(randomblob(2))) || '-' ||
|
|
17
|
+
lower(hex(randomblob(2))) || '-' ||
|
|
18
|
+
lower(hex(randomblob(6)))
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
type TableInfoRow = {
|
|
22
|
+
name: string;
|
|
23
|
+
pk: number;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const addColumnToTableIfNotExists = (
|
|
27
|
+
db: Database,
|
|
28
|
+
tableName: string,
|
|
29
|
+
columnNames: string[],
|
|
30
|
+
columnName: string,
|
|
31
|
+
columnType: string
|
|
32
|
+
) => {
|
|
33
|
+
if (!columnNames.includes(columnName)) {
|
|
34
|
+
console.log(`Running migration: Adding ${columnName} column to ${tableName} table`);
|
|
35
|
+
db.exec(`ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${columnType}`);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const tableExists = (db: Database, tableName: string): boolean =>
|
|
40
|
+
Boolean(
|
|
41
|
+
db
|
|
42
|
+
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?")
|
|
43
|
+
.get(tableName)
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const getTableInfo = (db: Database, tableName: string): TableInfoRow[] =>
|
|
47
|
+
db.prepare(`PRAGMA table_info(${tableName})`).all() as TableInfoRow[];
|
|
48
|
+
|
|
49
|
+
const migrateLegacySessionNames = (db: Database): void => {
|
|
50
|
+
const hasLegacySessionNamesTable = tableExists(db, 'session_names');
|
|
51
|
+
const hasSessionsTable = tableExists(db, 'sessions');
|
|
52
|
+
|
|
53
|
+
if (!hasLegacySessionNamesTable) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (hasSessionsTable) {
|
|
58
|
+
console.log('Running migration: Merging session_names into sessions');
|
|
59
|
+
db.exec(`
|
|
60
|
+
INSERT INTO sessions (session_id, user_id, provider, custom_name, created_at, updated_at)
|
|
61
|
+
SELECT
|
|
62
|
+
session_id,
|
|
63
|
+
COALESCE(
|
|
64
|
+
(SELECT id FROM users WHERE is_active = 1 ORDER BY id LIMIT 1),
|
|
65
|
+
1
|
|
66
|
+
),
|
|
67
|
+
COALESCE(provider, 'claude'),
|
|
68
|
+
custom_name,
|
|
69
|
+
COALESCE(created_at, CURRENT_TIMESTAMP),
|
|
70
|
+
COALESCE(updated_at, CURRENT_TIMESTAMP)
|
|
71
|
+
FROM session_names
|
|
72
|
+
WHERE true
|
|
73
|
+
ON CONFLICT(user_id, session_id) DO UPDATE SET
|
|
74
|
+
provider = excluded.provider,
|
|
75
|
+
custom_name = COALESCE(excluded.custom_name, sessions.custom_name),
|
|
76
|
+
created_at = COALESCE(sessions.created_at, excluded.created_at),
|
|
77
|
+
updated_at = COALESCE(excluded.updated_at, sessions.updated_at)
|
|
78
|
+
`);
|
|
79
|
+
db.exec('DROP TABLE session_names');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
console.log('Running migration: Renaming session_names table to sessions');
|
|
84
|
+
db.exec('ALTER TABLE session_names RENAME TO sessions');
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const migrateLegacyWorkspaceTableIntoProjects = (db: Database): void => {
|
|
88
|
+
db.exec(PROJECTS_TABLE_SCHEMA_SQL);
|
|
89
|
+
|
|
90
|
+
if (!tableExists(db, 'workspace_original_paths')) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log('Running migration: Migrating workspace_original_paths data into projects');
|
|
95
|
+
db.exec(`
|
|
96
|
+
INSERT INTO projects (project_id, user_id, project_path, custom_project_name, isStarred, isArchived)
|
|
97
|
+
SELECT
|
|
98
|
+
CASE
|
|
99
|
+
WHEN workspace_id IS NULL OR trim(workspace_id) = ''
|
|
100
|
+
THEN ${SQLITE_UUID_SQL}
|
|
101
|
+
ELSE workspace_id
|
|
102
|
+
END,
|
|
103
|
+
COALESCE(
|
|
104
|
+
(SELECT id FROM users WHERE is_active = 1 ORDER BY id LIMIT 1),
|
|
105
|
+
1
|
|
106
|
+
),
|
|
107
|
+
workspace_path,
|
|
108
|
+
custom_workspace_name,
|
|
109
|
+
COALESCE(isStarred, 0),
|
|
110
|
+
0
|
|
111
|
+
FROM workspace_original_paths
|
|
112
|
+
WHERE workspace_path IS NOT NULL AND trim(workspace_path) <> ''
|
|
113
|
+
ON CONFLICT(user_id, project_path) DO UPDATE SET
|
|
114
|
+
custom_project_name = COALESCE(projects.custom_project_name, excluded.custom_project_name),
|
|
115
|
+
isStarred = COALESCE(projects.isStarred, excluded.isStarred)
|
|
116
|
+
`);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const rebuildProjectsTableWithPrimaryKeySchema = (db: Database): void => {
|
|
120
|
+
const hasProjectsTable = tableExists(db, 'projects');
|
|
121
|
+
if (!hasProjectsTable) {
|
|
122
|
+
db.exec(PROJECTS_TABLE_SCHEMA_SQL);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const projectsTableInfo = getTableInfo(db, 'projects');
|
|
127
|
+
const columnNames = projectsTableInfo.map((column) => column.name);
|
|
128
|
+
const hasProjectIdPrimaryKey = projectsTableInfo.some(
|
|
129
|
+
(column) => column.name === 'project_id' && column.pk === 1,
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const shouldRebuild = !hasProjectIdPrimaryKey || !columnNames.includes('user_id');
|
|
133
|
+
|
|
134
|
+
if (!shouldRebuild) {
|
|
135
|
+
addColumnToTableIfNotExists(db, 'projects', columnNames, 'custom_project_name', 'TEXT DEFAULT NULL');
|
|
136
|
+
addColumnToTableIfNotExists(db, 'projects', columnNames, 'isStarred', 'BOOLEAN DEFAULT 0');
|
|
137
|
+
addColumnToTableIfNotExists(db, 'projects', columnNames, 'isArchived', 'BOOLEAN DEFAULT 0');
|
|
138
|
+
db.exec(`
|
|
139
|
+
UPDATE projects
|
|
140
|
+
SET project_id = ${SQLITE_UUID_SQL}
|
|
141
|
+
WHERE project_id IS NULL OR trim(project_id) = ''
|
|
142
|
+
`);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
console.log('Running migration: Rebuilding projects table to enforce user_id + project_id primary key schema');
|
|
147
|
+
|
|
148
|
+
const projectPathExpression = columnNames.includes('project_path')
|
|
149
|
+
? 'project_path'
|
|
150
|
+
: columnNames.includes('workspace_path')
|
|
151
|
+
? 'workspace_path'
|
|
152
|
+
: 'NULL';
|
|
153
|
+
|
|
154
|
+
const userIdExpression = columnNames.includes('user_id')
|
|
155
|
+
? 'user_id'
|
|
156
|
+
: 'COALESCE((SELECT id FROM users WHERE is_active = 1 ORDER BY id LIMIT 1), 1)';
|
|
157
|
+
|
|
158
|
+
const customProjectNameExpression = columnNames.includes('custom_project_name')
|
|
159
|
+
? 'custom_project_name'
|
|
160
|
+
: columnNames.includes('custom_workspace_name')
|
|
161
|
+
? 'custom_workspace_name'
|
|
162
|
+
: 'NULL';
|
|
163
|
+
|
|
164
|
+
const isStarredExpression = columnNames.includes('isStarred') ? 'COALESCE(isStarred, 0)' : '0';
|
|
165
|
+
|
|
166
|
+
const isArchivedExpression = columnNames.includes('isArchived') ? 'COALESCE(isArchived, 0)' : '0';
|
|
167
|
+
|
|
168
|
+
const projectIdExpression = columnNames.includes('project_id')
|
|
169
|
+
? `CASE
|
|
170
|
+
WHEN project_id IS NULL OR trim(project_id) = ''
|
|
171
|
+
THEN ${SQLITE_UUID_SQL}
|
|
172
|
+
ELSE project_id
|
|
173
|
+
END`
|
|
174
|
+
: SQLITE_UUID_SQL;
|
|
175
|
+
|
|
176
|
+
db.exec('PRAGMA foreign_keys = OFF');
|
|
177
|
+
try {
|
|
178
|
+
db.exec('BEGIN TRANSACTION');
|
|
179
|
+
db.exec('DROP TABLE IF EXISTS projects__new');
|
|
180
|
+
db.exec(`
|
|
181
|
+
CREATE TABLE projects__new (
|
|
182
|
+
project_id TEXT PRIMARY KEY NOT NULL,
|
|
183
|
+
user_id INTEGER NOT NULL,
|
|
184
|
+
project_path TEXT NOT NULL,
|
|
185
|
+
custom_project_name TEXT DEFAULT NULL,
|
|
186
|
+
isStarred BOOLEAN DEFAULT 0,
|
|
187
|
+
isArchived BOOLEAN DEFAULT 0,
|
|
188
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
189
|
+
UNIQUE(user_id, project_path)
|
|
190
|
+
)
|
|
191
|
+
`);
|
|
192
|
+
db.exec(`
|
|
193
|
+
WITH source_rows AS (
|
|
194
|
+
SELECT
|
|
195
|
+
${userIdExpression} AS user_id,
|
|
196
|
+
${projectPathExpression} AS project_path,
|
|
197
|
+
${customProjectNameExpression} AS custom_project_name,
|
|
198
|
+
${isStarredExpression} AS isStarred,
|
|
199
|
+
${isArchivedExpression} AS isArchived,
|
|
200
|
+
${projectIdExpression} AS candidate_project_id,
|
|
201
|
+
rowid AS source_rowid
|
|
202
|
+
FROM projects
|
|
203
|
+
WHERE ${projectPathExpression} IS NOT NULL AND trim(${projectPathExpression}) <> ''
|
|
204
|
+
),
|
|
205
|
+
deduped_paths AS (
|
|
206
|
+
SELECT
|
|
207
|
+
user_id,
|
|
208
|
+
project_path,
|
|
209
|
+
custom_project_name,
|
|
210
|
+
isStarred,
|
|
211
|
+
isArchived,
|
|
212
|
+
candidate_project_id,
|
|
213
|
+
source_rowid,
|
|
214
|
+
ROW_NUMBER() OVER (PARTITION BY user_id, project_path ORDER BY source_rowid) AS project_path_rank
|
|
215
|
+
FROM source_rows
|
|
216
|
+
),
|
|
217
|
+
prepared_rows AS (
|
|
218
|
+
SELECT
|
|
219
|
+
CASE
|
|
220
|
+
WHEN ROW_NUMBER() OVER (PARTITION BY candidate_project_id ORDER BY source_rowid) = 1
|
|
221
|
+
THEN candidate_project_id
|
|
222
|
+
ELSE ${SQLITE_UUID_SQL}
|
|
223
|
+
END AS project_id,
|
|
224
|
+
user_id,
|
|
225
|
+
project_path,
|
|
226
|
+
custom_project_name,
|
|
227
|
+
isStarred,
|
|
228
|
+
isArchived
|
|
229
|
+
FROM deduped_paths
|
|
230
|
+
WHERE project_path_rank = 1
|
|
231
|
+
)
|
|
232
|
+
INSERT INTO projects__new (
|
|
233
|
+
project_id,
|
|
234
|
+
user_id,
|
|
235
|
+
project_path,
|
|
236
|
+
custom_project_name,
|
|
237
|
+
isStarred,
|
|
238
|
+
isArchived
|
|
239
|
+
)
|
|
240
|
+
SELECT
|
|
241
|
+
project_id,
|
|
242
|
+
user_id,
|
|
243
|
+
project_path,
|
|
244
|
+
custom_project_name,
|
|
245
|
+
isStarred,
|
|
246
|
+
isArchived
|
|
247
|
+
FROM prepared_rows
|
|
248
|
+
`);
|
|
249
|
+
db.exec('DROP TABLE projects');
|
|
250
|
+
db.exec('ALTER TABLE projects__new RENAME TO projects');
|
|
251
|
+
db.exec('COMMIT');
|
|
252
|
+
} catch (migrationError) {
|
|
253
|
+
db.exec('ROLLBACK');
|
|
254
|
+
throw migrationError;
|
|
255
|
+
} finally {
|
|
256
|
+
db.exec('PRAGMA foreign_keys = ON');
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const rebuildSessionsTableWithProjectSchema = (db: Database): void => {
|
|
261
|
+
const hasSessions = tableExists(db, 'sessions');
|
|
262
|
+
if (!hasSessions) {
|
|
263
|
+
db.exec(SESSIONS_TABLE_SCHEMA_SQL);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const sessionsTableInfo = getTableInfo(db, 'sessions');
|
|
268
|
+
const columnNames = sessionsTableInfo.map((column) => column.name);
|
|
269
|
+
const primaryKeyColumns = sessionsTableInfo
|
|
270
|
+
.filter((column) => column.pk > 0)
|
|
271
|
+
.sort((a, b) => a.pk - b.pk)
|
|
272
|
+
.map((column) => column.name);
|
|
273
|
+
|
|
274
|
+
const shouldRebuild =
|
|
275
|
+
!columnNames.includes('project_path') ||
|
|
276
|
+
!columnNames.includes('user_id') ||
|
|
277
|
+
primaryKeyColumns.length !== 2 ||
|
|
278
|
+
primaryKeyColumns[0] !== 'user_id' ||
|
|
279
|
+
primaryKeyColumns[1] !== 'session_id' ||
|
|
280
|
+
!columnNames.includes('provider');
|
|
281
|
+
|
|
282
|
+
if (!shouldRebuild) {
|
|
283
|
+
addColumnToTableIfNotExists(db, 'sessions', columnNames, 'jsonl_path', 'TEXT');
|
|
284
|
+
addColumnToTableIfNotExists(db, 'sessions', columnNames, 'isArchived', 'BOOLEAN DEFAULT 0');
|
|
285
|
+
addColumnToTableIfNotExists(db, 'sessions', columnNames, 'created_at', 'DATETIME');
|
|
286
|
+
addColumnToTableIfNotExists(db, 'sessions', columnNames, 'updated_at', 'DATETIME');
|
|
287
|
+
db.exec('UPDATE sessions SET isArchived = COALESCE(isArchived, 0)');
|
|
288
|
+
db.exec('UPDATE sessions SET created_at = COALESCE(created_at, CURRENT_TIMESTAMP)');
|
|
289
|
+
db.exec('UPDATE sessions SET updated_at = COALESCE(updated_at, CURRENT_TIMESTAMP)');
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
console.log('Running migration: Rebuilding sessions table to project-based schema');
|
|
294
|
+
|
|
295
|
+
const projectPathExpression = columnNames.includes('project_path')
|
|
296
|
+
? 'project_path'
|
|
297
|
+
: columnNames.includes('workspace_path')
|
|
298
|
+
? 'workspace_path'
|
|
299
|
+
: 'NULL';
|
|
300
|
+
|
|
301
|
+
const providerExpression = columnNames.includes('provider')
|
|
302
|
+
? "COALESCE(provider, 'claude')"
|
|
303
|
+
: "'claude'";
|
|
304
|
+
|
|
305
|
+
const userIdExpression = columnNames.includes('user_id')
|
|
306
|
+
? 'user_id'
|
|
307
|
+
: 'COALESCE((SELECT id FROM users WHERE is_active = 1 ORDER BY id LIMIT 1), 1)';
|
|
308
|
+
|
|
309
|
+
const customNameExpression = columnNames.includes('custom_name')
|
|
310
|
+
? 'custom_name'
|
|
311
|
+
: 'NULL';
|
|
312
|
+
|
|
313
|
+
const jsonlPathExpression = columnNames.includes('jsonl_path')
|
|
314
|
+
? 'jsonl_path'
|
|
315
|
+
: 'NULL';
|
|
316
|
+
|
|
317
|
+
const isArchivedExpression = columnNames.includes('isArchived')
|
|
318
|
+
? 'COALESCE(isArchived, 0)'
|
|
319
|
+
: '0';
|
|
320
|
+
|
|
321
|
+
const createdAtExpression = columnNames.includes('created_at')
|
|
322
|
+
? 'COALESCE(created_at, CURRENT_TIMESTAMP)'
|
|
323
|
+
: 'CURRENT_TIMESTAMP';
|
|
324
|
+
|
|
325
|
+
const updatedAtExpression = columnNames.includes('updated_at')
|
|
326
|
+
? 'COALESCE(updated_at, CURRENT_TIMESTAMP)'
|
|
327
|
+
: 'CURRENT_TIMESTAMP';
|
|
328
|
+
|
|
329
|
+
db.exec('PRAGMA foreign_keys = OFF');
|
|
330
|
+
try {
|
|
331
|
+
db.exec('BEGIN TRANSACTION');
|
|
332
|
+
db.exec('DROP TABLE IF EXISTS sessions__new');
|
|
333
|
+
db.exec(`
|
|
334
|
+
CREATE TABLE sessions__new (
|
|
335
|
+
session_id TEXT NOT NULL,
|
|
336
|
+
user_id INTEGER NOT NULL,
|
|
337
|
+
provider TEXT NOT NULL DEFAULT 'claude',
|
|
338
|
+
custom_name TEXT,
|
|
339
|
+
project_path TEXT,
|
|
340
|
+
jsonl_path TEXT,
|
|
341
|
+
isArchived BOOLEAN DEFAULT 0,
|
|
342
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
343
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
344
|
+
PRIMARY KEY (user_id, session_id),
|
|
345
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
346
|
+
FOREIGN KEY (user_id, project_path) REFERENCES projects(user_id, project_path)
|
|
347
|
+
ON DELETE CASCADE
|
|
348
|
+
ON UPDATE CASCADE
|
|
349
|
+
)
|
|
350
|
+
`);
|
|
351
|
+
db.exec(`
|
|
352
|
+
WITH source_rows AS (
|
|
353
|
+
SELECT
|
|
354
|
+
session_id,
|
|
355
|
+
${userIdExpression} AS user_id,
|
|
356
|
+
${providerExpression} AS provider,
|
|
357
|
+
${customNameExpression} AS custom_name,
|
|
358
|
+
${projectPathExpression} AS project_path,
|
|
359
|
+
${jsonlPathExpression} AS jsonl_path,
|
|
360
|
+
${isArchivedExpression} AS isArchived,
|
|
361
|
+
${createdAtExpression} AS created_at,
|
|
362
|
+
${updatedAtExpression} AS updated_at,
|
|
363
|
+
rowid AS source_rowid
|
|
364
|
+
FROM sessions
|
|
365
|
+
WHERE session_id IS NOT NULL AND trim(session_id) <> ''
|
|
366
|
+
),
|
|
367
|
+
ranked_rows AS (
|
|
368
|
+
SELECT
|
|
369
|
+
session_id,
|
|
370
|
+
user_id,
|
|
371
|
+
provider,
|
|
372
|
+
custom_name,
|
|
373
|
+
project_path,
|
|
374
|
+
jsonl_path,
|
|
375
|
+
isArchived,
|
|
376
|
+
created_at,
|
|
377
|
+
updated_at,
|
|
378
|
+
ROW_NUMBER() OVER (
|
|
379
|
+
PARTITION BY user_id, session_id
|
|
380
|
+
ORDER BY datetime(COALESCE(updated_at, created_at)) DESC, source_rowid DESC
|
|
381
|
+
) AS session_rank
|
|
382
|
+
FROM source_rows
|
|
383
|
+
)
|
|
384
|
+
INSERT INTO sessions__new (
|
|
385
|
+
session_id,
|
|
386
|
+
user_id,
|
|
387
|
+
provider,
|
|
388
|
+
custom_name,
|
|
389
|
+
project_path,
|
|
390
|
+
jsonl_path,
|
|
391
|
+
isArchived,
|
|
392
|
+
created_at,
|
|
393
|
+
updated_at
|
|
394
|
+
)
|
|
395
|
+
SELECT
|
|
396
|
+
session_id,
|
|
397
|
+
user_id,
|
|
398
|
+
provider,
|
|
399
|
+
custom_name,
|
|
400
|
+
project_path,
|
|
401
|
+
jsonl_path,
|
|
402
|
+
isArchived,
|
|
403
|
+
created_at,
|
|
404
|
+
updated_at
|
|
405
|
+
FROM ranked_rows
|
|
406
|
+
WHERE session_rank = 1
|
|
407
|
+
`);
|
|
408
|
+
db.exec('DROP TABLE sessions');
|
|
409
|
+
db.exec('ALTER TABLE sessions__new RENAME TO sessions');
|
|
410
|
+
db.exec('COMMIT');
|
|
411
|
+
} catch (migrationError) {
|
|
412
|
+
db.exec('ROLLBACK');
|
|
413
|
+
throw migrationError;
|
|
414
|
+
} finally {
|
|
415
|
+
db.exec('PRAGMA foreign_keys = ON');
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
const ensureProjectsForSessionPaths = (db: Database): void => {
|
|
420
|
+
if (!tableExists(db, 'sessions')) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
db.exec(`
|
|
425
|
+
INSERT INTO projects (project_id, user_id, project_path, custom_project_name, isStarred, isArchived)
|
|
426
|
+
SELECT
|
|
427
|
+
${SQLITE_UUID_SQL},
|
|
428
|
+
user_id,
|
|
429
|
+
project_path,
|
|
430
|
+
NULL,
|
|
431
|
+
0,
|
|
432
|
+
0
|
|
433
|
+
FROM sessions
|
|
434
|
+
WHERE project_path IS NOT NULL AND trim(project_path) <> ''
|
|
435
|
+
ON CONFLICT(user_id, project_path) DO NOTHING
|
|
436
|
+
`);
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
export const runMigrations = (db: Database) => {
|
|
440
|
+
try {
|
|
441
|
+
const usersTableInfo = db.prepare('PRAGMA table_info(users)').all() as { name: string }[];
|
|
442
|
+
const userColumnNames = usersTableInfo.map((column) => column.name);
|
|
443
|
+
|
|
444
|
+
addColumnToTableIfNotExists(db, 'users', userColumnNames, 'git_name', 'TEXT');
|
|
445
|
+
addColumnToTableIfNotExists(db, 'users', userColumnNames, 'git_email', 'TEXT');
|
|
446
|
+
addColumnToTableIfNotExists(
|
|
447
|
+
db,
|
|
448
|
+
'users',
|
|
449
|
+
userColumnNames,
|
|
450
|
+
'has_completed_onboarding',
|
|
451
|
+
'BOOLEAN DEFAULT 0'
|
|
452
|
+
);
|
|
453
|
+
addColumnToTableIfNotExists(db, 'users', userColumnNames, 'is_admin', 'BOOLEAN DEFAULT 0');
|
|
454
|
+
|
|
455
|
+
db.exec("UPDATE users SET is_admin = 1 WHERE id = 1 AND is_active = 1");
|
|
456
|
+
|
|
457
|
+
db.exec(APP_CONFIG_TABLE_SCHEMA_SQL);
|
|
458
|
+
db.exec(USER_NOTIFICATION_PREFERENCES_TABLE_SCHEMA_SQL);
|
|
459
|
+
db.exec(VAPID_KEYS_TABLE_SCHEMA_SQL);
|
|
460
|
+
db.exec(PUSH_SUBSCRIPTIONS_TABLE_SCHEMA_SQL);
|
|
461
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_push_subscriptions_user_id ON push_subscriptions(user_id)');
|
|
462
|
+
|
|
463
|
+
db.exec(PROJECTS_TABLE_SCHEMA_SQL);
|
|
464
|
+
rebuildProjectsTableWithPrimaryKeySchema(db);
|
|
465
|
+
|
|
466
|
+
migrateLegacyWorkspaceTableIntoProjects(db);
|
|
467
|
+
rebuildSessionsTableWithProjectSchema(db);
|
|
468
|
+
migrateLegacySessionNames(db);
|
|
469
|
+
ensureProjectsForSessionPaths(db);
|
|
470
|
+
|
|
471
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_session_ids_lookup ON sessions(user_id, session_id)');
|
|
472
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id)');
|
|
473
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_sessions_project_path ON sessions(user_id, project_path)');
|
|
474
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_sessions_is_archived ON sessions(isArchived)');
|
|
475
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_projects_user_id ON projects(user_id)');
|
|
476
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_projects_user_path ON projects(user_id, project_path)');
|
|
477
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_projects_is_starred ON projects(isStarred)');
|
|
478
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_projects_is_archived ON projects(isArchived)');
|
|
479
|
+
|
|
480
|
+
db.exec('DROP INDEX IF EXISTS idx_session_names_lookup');
|
|
481
|
+
db.exec('DROP INDEX IF EXISTS idx_sessions_workspace_path');
|
|
482
|
+
db.exec('DROP INDEX IF EXISTS idx_workspace_original_paths_is_starred');
|
|
483
|
+
db.exec('DROP INDEX IF EXISTS idx_workspace_original_paths_workspace_id');
|
|
484
|
+
|
|
485
|
+
if (tableExists(db, 'workspace_original_paths')) {
|
|
486
|
+
console.log('Running migration: Dropping legacy workspace_original_paths table');
|
|
487
|
+
db.exec('DROP TABLE workspace_original_paths');
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
db.exec(LAST_SCANNED_AT_SQL);
|
|
491
|
+
console.log('Database migrations completed successfully');
|
|
492
|
+
} catch (error: any) {
|
|
493
|
+
console.error('Error running migrations:', error.message);
|
|
494
|
+
throw error;
|
|
495
|
+
}
|
|
496
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API keys repository.
|
|
3
|
+
*
|
|
4
|
+
* Manages API keys used for external/programmatic access to the backend.
|
|
5
|
+
* Keys are prefixed with `ck_` and tied to a user via foreign key.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import crypto from 'crypto';
|
|
9
|
+
|
|
10
|
+
import { getConnection } from '@/modules/database/connection.js';
|
|
11
|
+
|
|
12
|
+
type ApiKeyRow = {
|
|
13
|
+
id: number;
|
|
14
|
+
key_name: string;
|
|
15
|
+
api_key: string;
|
|
16
|
+
created_at: string;
|
|
17
|
+
last_used: string | null;
|
|
18
|
+
is_active: number;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type CreateApiKeyResult = {
|
|
22
|
+
id: number | bigint;
|
|
23
|
+
keyName: string;
|
|
24
|
+
apiKey: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type ValidatedApiKeyUser = {
|
|
28
|
+
id: number;
|
|
29
|
+
username: string;
|
|
30
|
+
api_key_id: number;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Helpers
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
/** Generates a cryptographically random API key with the `ck_` prefix. */
|
|
38
|
+
function generateApiKey(): string {
|
|
39
|
+
return 'ck_' + crypto.randomBytes(32).toString('hex');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
// Queries
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
export const apiKeysDb = {
|
|
47
|
+
generateApiKey,
|
|
48
|
+
|
|
49
|
+
/** Creates a new API key for the given user and returns it for one-time display. */
|
|
50
|
+
createApiKey(userId: number, keyName: string): CreateApiKeyResult {
|
|
51
|
+
const db = getConnection();
|
|
52
|
+
const apiKey = generateApiKey();
|
|
53
|
+
const result = db
|
|
54
|
+
.prepare(
|
|
55
|
+
'INSERT INTO api_keys (user_id, key_name, api_key) VALUES (?, ?, ?)'
|
|
56
|
+
)
|
|
57
|
+
.run(userId, keyName, apiKey);
|
|
58
|
+
return { id: result.lastInsertRowid, keyName, apiKey };
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
/** Lists all API keys for a user, most recent first. */
|
|
62
|
+
getApiKeys(userId: number): ApiKeyRow[] {
|
|
63
|
+
const db = getConnection();
|
|
64
|
+
return db
|
|
65
|
+
.prepare(
|
|
66
|
+
'SELECT id, key_name, api_key, created_at, last_used, is_active FROM api_keys WHERE user_id = ? ORDER BY created_at DESC'
|
|
67
|
+
)
|
|
68
|
+
.all(userId) as ApiKeyRow[];
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Validates an API key and resolves the owning user.
|
|
73
|
+
* If the key is valid, its `last_used` timestamp is updated as a side effect.
|
|
74
|
+
* Returns undefined when the key is invalid or the user is inactive.
|
|
75
|
+
*/
|
|
76
|
+
validateApiKey(apiKey: string): ValidatedApiKeyUser | undefined {
|
|
77
|
+
const db = getConnection();
|
|
78
|
+
const row = db
|
|
79
|
+
.prepare(
|
|
80
|
+
`SELECT u.id, u.username, ak.id as api_key_id
|
|
81
|
+
FROM api_keys ak
|
|
82
|
+
JOIN users u ON ak.user_id = u.id
|
|
83
|
+
WHERE ak.api_key = ? AND ak.is_active = 1 AND u.is_active = 1`
|
|
84
|
+
)
|
|
85
|
+
.get(apiKey) as ValidatedApiKeyUser | undefined;
|
|
86
|
+
|
|
87
|
+
if (row) {
|
|
88
|
+
db.prepare(
|
|
89
|
+
'UPDATE api_keys SET last_used = CURRENT_TIMESTAMP WHERE id = ?'
|
|
90
|
+
).run(row.api_key_id);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return row;
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
/** Permanently removes an API key. Returns true if a row was deleted. */
|
|
97
|
+
deleteApiKey(userId: number, apiKeyId: number): boolean {
|
|
98
|
+
const db = getConnection();
|
|
99
|
+
const result = db
|
|
100
|
+
.prepare('DELETE FROM api_keys WHERE id = ? AND user_id = ?')
|
|
101
|
+
.run(apiKeyId, userId);
|
|
102
|
+
return result.changes > 0;
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
/** Enables or disables an API key without deleting it. */
|
|
106
|
+
toggleApiKey(
|
|
107
|
+
userId: number,
|
|
108
|
+
apiKeyId: number,
|
|
109
|
+
isActive: boolean
|
|
110
|
+
): boolean {
|
|
111
|
+
const db = getConnection();
|
|
112
|
+
const result = db
|
|
113
|
+
.prepare(
|
|
114
|
+
'UPDATE api_keys SET is_active = ? WHERE id = ? AND user_id = ?'
|
|
115
|
+
)
|
|
116
|
+
.run(isActive ? 1 : 0, apiKeyId, userId);
|
|
117
|
+
return result.changes > 0;
|
|
118
|
+
},
|
|
119
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App config repository.
|
|
3
|
+
*
|
|
4
|
+
* Key-value store for application-level configuration that persists
|
|
5
|
+
* across restarts (JWT secret, feature flags, etc.). Values are always
|
|
6
|
+
* stored as strings; callers handle parsing.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import crypto from 'crypto';
|
|
10
|
+
|
|
11
|
+
import { getConnection } from '@/modules/database/connection.js';
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Queries
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
export const appConfigDb = {
|
|
18
|
+
/** Returns the stored value for a config key, or null if missing. */
|
|
19
|
+
get(key: string): string | null {
|
|
20
|
+
try {
|
|
21
|
+
const db = getConnection();
|
|
22
|
+
const row = db
|
|
23
|
+
.prepare('SELECT value FROM app_config WHERE key = ?')
|
|
24
|
+
.get(key) as { value: string } | undefined;
|
|
25
|
+
return row?.value ?? null;
|
|
26
|
+
} catch {
|
|
27
|
+
// Swallow errors so early-startup reads (e.g. JWT secret) do not crash.
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
/** Inserts or updates a config key (upsert). */
|
|
33
|
+
set(key: string, value: string): void {
|
|
34
|
+
const db = getConnection();
|
|
35
|
+
db.prepare(
|
|
36
|
+
'INSERT INTO app_config (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value'
|
|
37
|
+
).run(key, value);
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Returns the JWT signing secret, generating and persisting one
|
|
42
|
+
* if it does not already exist. This ensures the secret survives
|
|
43
|
+
* server restarts while being created automatically on first boot.
|
|
44
|
+
*/
|
|
45
|
+
getOrCreateJwtSecret(): string {
|
|
46
|
+
let secret = appConfigDb.get('jwt_secret');
|
|
47
|
+
if (!secret) {
|
|
48
|
+
secret = crypto.randomBytes(64).toString('hex');
|
|
49
|
+
appConfigDb.set('jwt_secret', secret);
|
|
50
|
+
}
|
|
51
|
+
return secret;
|
|
52
|
+
},
|
|
53
|
+
};
|