@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,267 @@
|
|
|
1
|
+
# WebSocket Module
|
|
2
|
+
|
|
3
|
+
This module owns the server-side WebSocket gateway used by:
|
|
4
|
+
|
|
5
|
+
1. Chat streaming (`/ws`)
|
|
6
|
+
2. Interactive terminal sessions (`/shell`)
|
|
7
|
+
3. Plugin WebSocket passthrough (`/plugin-ws/:pluginName`)
|
|
8
|
+
|
|
9
|
+
It is intentionally structured as **small services** plus a **barrel export** in `index.ts`.
|
|
10
|
+
|
|
11
|
+
## Public API
|
|
12
|
+
|
|
13
|
+
`server/modules/websocket/index.ts` exports:
|
|
14
|
+
|
|
15
|
+
1. `createWebSocketServer(server, dependencies)`
|
|
16
|
+
Creates and wires the shared `ws` server.
|
|
17
|
+
2. `connectedClients` and `WS_OPEN_STATE`
|
|
18
|
+
Shared chat client registry and open-state constant used by other modules.
|
|
19
|
+
|
|
20
|
+
## Why Dependency Injection Is Used
|
|
21
|
+
|
|
22
|
+
The module receives runtime-specific functions from `server/index.js` instead of importing legacy runtime files directly.
|
|
23
|
+
|
|
24
|
+
Benefits:
|
|
25
|
+
|
|
26
|
+
1. Keeps module boundaries clean (`server/modules/*` architecture rule).
|
|
27
|
+
2. Makes each service easier to test in isolation.
|
|
28
|
+
3. Keeps WebSocket transport concerns separate from provider runtime concerns.
|
|
29
|
+
|
|
30
|
+
## Service Map
|
|
31
|
+
|
|
32
|
+
| File | Responsibility |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `services/websocket-server.service.ts` | Creates `WebSocketServer`, binds `verifyClient`, routes connection by pathname |
|
|
35
|
+
| `services/websocket-auth.service.ts` | Authenticates upgrade requests and attaches `request.user` |
|
|
36
|
+
| `services/chat-websocket.service.ts` | Handles `/ws` chat protocol and provider command/session control messages |
|
|
37
|
+
| `services/shell-websocket.service.ts` | Handles `/shell` PTY lifecycle, reconnect buffering, auth URL detection |
|
|
38
|
+
| `services/plugin-websocket-proxy.service.ts` | Bridges client socket to plugin socket |
|
|
39
|
+
| `services/websocket-writer.service.ts` | Adapts raw WebSocket to writer interface (`send`, `setSessionId`, `getSessionId`) |
|
|
40
|
+
| `services/websocket-state.service.ts` | Holds shared chat client set and open-state constant |
|
|
41
|
+
|
|
42
|
+
## High-Level Architecture
|
|
43
|
+
|
|
44
|
+
```mermaid
|
|
45
|
+
flowchart LR
|
|
46
|
+
A[HTTP Server] --> B[createWebSocketServer]
|
|
47
|
+
B --> C[verifyWebSocketClient]
|
|
48
|
+
B --> D{Pathname}
|
|
49
|
+
D -->|/ws| E[handleChatConnection]
|
|
50
|
+
D -->|/shell| F[handleShellConnection]
|
|
51
|
+
D -->|/plugin-ws/:name| G[handlePluginWsProxy]
|
|
52
|
+
D -->|other| H[close()]
|
|
53
|
+
|
|
54
|
+
E --> I[connectedClients Set]
|
|
55
|
+
E --> J[WebSocketWriter]
|
|
56
|
+
F --> K[ptySessionsMap]
|
|
57
|
+
G --> L[Upstream Plugin ws://127.0.0.1:port/ws]
|
|
58
|
+
|
|
59
|
+
I --> M[projects.service broadcastProgress]
|
|
60
|
+
I --> N[sessions-watcher.service projects_updated]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Connection Handshake + Routing
|
|
64
|
+
|
|
65
|
+
```mermaid
|
|
66
|
+
sequenceDiagram
|
|
67
|
+
participant Client
|
|
68
|
+
participant WSS as WebSocketServer
|
|
69
|
+
participant Auth as verifyWebSocketClient
|
|
70
|
+
participant Router as connection router
|
|
71
|
+
participant Chat as /ws handler
|
|
72
|
+
participant Shell as /shell handler
|
|
73
|
+
participant Proxy as /plugin-ws handler
|
|
74
|
+
|
|
75
|
+
Client->>WSS: Upgrade Request
|
|
76
|
+
WSS->>Auth: verifyClient(info)
|
|
77
|
+
alt Platform mode
|
|
78
|
+
Auth->>Auth: authenticateWebSocket(null)
|
|
79
|
+
Auth->>Auth: attach request.user
|
|
80
|
+
else OSS mode
|
|
81
|
+
Auth->>Auth: read token from ?token or Authorization
|
|
82
|
+
Auth->>Auth: authenticateWebSocket(token)
|
|
83
|
+
Auth->>Auth: attach request.user
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
alt Auth failed
|
|
87
|
+
Auth-->>WSS: false (reject handshake)
|
|
88
|
+
else Auth ok
|
|
89
|
+
Auth-->>WSS: true
|
|
90
|
+
WSS->>Router: on("connection", ws, request)
|
|
91
|
+
alt pathname == /ws
|
|
92
|
+
Router->>Chat: handleChatConnection(ws, request, deps.chat)
|
|
93
|
+
else pathname == /shell
|
|
94
|
+
Router->>Shell: handleShellConnection(ws, deps.shell)
|
|
95
|
+
else pathname startsWith /plugin-ws/
|
|
96
|
+
Router->>Proxy: handlePluginWsProxy(ws, pathname, getPluginPort)
|
|
97
|
+
else unknown
|
|
98
|
+
Router->>Router: ws.close()
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## `/ws` Chat Flow
|
|
104
|
+
|
|
105
|
+
When a chat socket connects:
|
|
106
|
+
|
|
107
|
+
1. Add socket to `connectedClients`.
|
|
108
|
+
2. Build `WebSocketWriter` (captures `userId` from authenticated request).
|
|
109
|
+
3. Parse each incoming message with `parseIncomingJsonObject`.
|
|
110
|
+
4. Dispatch by `data.type`.
|
|
111
|
+
5. On close, remove socket from `connectedClients`.
|
|
112
|
+
|
|
113
|
+
### Chat Message Dispatch
|
|
114
|
+
|
|
115
|
+
```mermaid
|
|
116
|
+
flowchart TD
|
|
117
|
+
A[Incoming WS message] --> B[parseIncomingJsonObject]
|
|
118
|
+
B -->|invalid| C[send {type:error}]
|
|
119
|
+
B -->|ok| D{data.type}
|
|
120
|
+
|
|
121
|
+
D -->|claude-command| E[queryClaudeSDK]
|
|
122
|
+
D -->|cursor-command| F[spawnCursor]
|
|
123
|
+
D -->|codex-command| G[queryCodex]
|
|
124
|
+
D -->|gemini-command| H[spawnGemini]
|
|
125
|
+
D -->|cursor-resume| I[spawnCursor resume]
|
|
126
|
+
D -->|abort-session| J[abort by provider]
|
|
127
|
+
D -->|claude-permission-response| K[resolveToolApproval]
|
|
128
|
+
D -->|cursor-abort| L[abortCursorSession]
|
|
129
|
+
D -->|check-session-status| M[is*SessionActive + optional reconnectSessionWriter]
|
|
130
|
+
D -->|get-pending-permissions| N[getPendingApprovalsForSession]
|
|
131
|
+
D -->|get-active-sessions| O[getActive*Sessions]
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Chat Notes
|
|
135
|
+
|
|
136
|
+
1. `abort-session` returns a normalized `complete` message with `aborted: true`.
|
|
137
|
+
2. `check-session-status` returns `{ type: "session-status", isProcessing }`.
|
|
138
|
+
3. Claude status checks can reconnect output stream to the new socket via `reconnectSessionWriter`.
|
|
139
|
+
|
|
140
|
+
## `/shell` Terminal Flow
|
|
141
|
+
|
|
142
|
+
The shell handler manages persistent PTY sessions keyed by:
|
|
143
|
+
|
|
144
|
+
`<projectPath>_<sessionIdOrDefault>[_cmd_<hash>]`
|
|
145
|
+
|
|
146
|
+
This enables reconnect behavior and isolates command-specific plain-shell sessions.
|
|
147
|
+
|
|
148
|
+
### Shell Lifecycle
|
|
149
|
+
|
|
150
|
+
```mermaid
|
|
151
|
+
stateDiagram-v2
|
|
152
|
+
[*] --> WaitingInit
|
|
153
|
+
WaitingInit --> ValidateInit: message.type == init
|
|
154
|
+
ValidateInit --> ReconnectExisting: session key exists and not login reset
|
|
155
|
+
ValidateInit --> SpawnNewPTY: valid path + valid sessionId
|
|
156
|
+
ValidateInit --> EmitError: invalid payload/path/sessionId
|
|
157
|
+
|
|
158
|
+
ReconnectExisting --> Running: attach ws, replay buffer
|
|
159
|
+
SpawnNewPTY --> Running: pty.spawn + wire onData/onExit
|
|
160
|
+
|
|
161
|
+
Running --> Running: input -> pty.write
|
|
162
|
+
Running --> Running: resize -> pty.resize
|
|
163
|
+
Running --> Running: onData -> buffer + output + auth_url detection
|
|
164
|
+
Running --> Exited: onExit
|
|
165
|
+
Running --> Detached: ws close
|
|
166
|
+
|
|
167
|
+
Detached --> Running: reconnect before timeout
|
|
168
|
+
Detached --> Killed: timeout reached -> pty.kill
|
|
169
|
+
Exited --> [*]
|
|
170
|
+
Killed --> [*]
|
|
171
|
+
EmitError --> WaitingInit
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Shell Behaviors in Detail
|
|
175
|
+
|
|
176
|
+
1. `init`:
|
|
177
|
+
Reads `projectPath`, `sessionId`, `provider`, `hasSession`, `initialCommand`, `isPlainShell`.
|
|
178
|
+
2. Login reset:
|
|
179
|
+
For login-like commands, existing keyed PTY session is killed and recreated.
|
|
180
|
+
3. Validation:
|
|
181
|
+
Path must exist and be a directory; `sessionId` must match safe pattern.
|
|
182
|
+
4. Command build:
|
|
183
|
+
Provider-specific command construction with resume semantics.
|
|
184
|
+
5. PTY output buffering:
|
|
185
|
+
Stores up to 5000 chunks for replay on reconnect.
|
|
186
|
+
6. URL detection:
|
|
187
|
+
Strips ANSI, accumulates text buffer, extracts URLs, emits `auth_url` once per normalized URL, supports `autoOpen`.
|
|
188
|
+
7. Close behavior:
|
|
189
|
+
Socket disconnect does not instantly kill PTY; session is kept alive and terminated on timeout.
|
|
190
|
+
|
|
191
|
+
## `/plugin-ws/:pluginName` Proxy Flow
|
|
192
|
+
|
|
193
|
+
```mermaid
|
|
194
|
+
sequenceDiagram
|
|
195
|
+
participant Client
|
|
196
|
+
participant Proxy as handlePluginWsProxy
|
|
197
|
+
participant PM as getPluginPort
|
|
198
|
+
participant Upstream as Plugin WS
|
|
199
|
+
|
|
200
|
+
Client->>Proxy: Connect /plugin-ws/:name
|
|
201
|
+
Proxy->>Proxy: Validate pluginName regex
|
|
202
|
+
alt Invalid name
|
|
203
|
+
Proxy-->>Client: close(4400, "Invalid plugin name")
|
|
204
|
+
else Valid
|
|
205
|
+
Proxy->>PM: getPluginPort(name)
|
|
206
|
+
alt Plugin not running
|
|
207
|
+
Proxy-->>Client: close(4404, "Plugin not running")
|
|
208
|
+
else Port found
|
|
209
|
+
Proxy->>Upstream: new WebSocket(ws://127.0.0.1:port/ws)
|
|
210
|
+
Client-->>Upstream: relay messages bidirectionally
|
|
211
|
+
Upstream-->>Client: relay messages bidirectionally
|
|
212
|
+
Upstream-->>Client: close propagation
|
|
213
|
+
Client-->>Upstream: close propagation
|
|
214
|
+
Upstream-->>Client: close(4502, "Upstream error") on upstream error
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Shared Client Registry and Broadcasts
|
|
220
|
+
|
|
221
|
+
Only chat sockets (`/ws`) are tracked in `connectedClients`.
|
|
222
|
+
|
|
223
|
+
That shared set is consumed by:
|
|
224
|
+
|
|
225
|
+
1. `modules/projects/services/projects-with-sessions-fetch.service.ts`
|
|
226
|
+
Broadcasts `loading_progress` while project snapshots are being built.
|
|
227
|
+
2. `modules/providers/services/sessions-watcher.service.ts`
|
|
228
|
+
Broadcasts `projects_updated` when provider session artifacts change.
|
|
229
|
+
|
|
230
|
+
This design centralizes cross-module realtime fanout without requiring route-local references to WebSocket internals.
|
|
231
|
+
|
|
232
|
+
## Writer Adapter (`WebSocketWriter`)
|
|
233
|
+
|
|
234
|
+
`WebSocketWriter` normalizes chat transport behavior to match existing writer-style interfaces used elsewhere.
|
|
235
|
+
|
|
236
|
+
Methods:
|
|
237
|
+
|
|
238
|
+
1. `send(data)`
|
|
239
|
+
JSON-serializes and sends only if socket is open.
|
|
240
|
+
2. `setSessionId(sessionId)` / `getSessionId()`
|
|
241
|
+
Supports provider session bookkeeping and resume flows.
|
|
242
|
+
3. `updateWebSocket(newRawWs)`
|
|
243
|
+
Allows active session stream redirection on reconnect.
|
|
244
|
+
|
|
245
|
+
## Error Handling and Close Codes
|
|
246
|
+
|
|
247
|
+
Current explicit close codes in this module:
|
|
248
|
+
|
|
249
|
+
1. `4400`: Invalid plugin name
|
|
250
|
+
2. `4404`: Plugin not running
|
|
251
|
+
3. `4502`: Upstream plugin WebSocket error
|
|
252
|
+
|
|
253
|
+
Other errors:
|
|
254
|
+
|
|
255
|
+
1. Chat handler catches and emits `{ type: "error", error }`.
|
|
256
|
+
2. Shell handler catches and writes terminal-visible error output.
|
|
257
|
+
3. Unknown websocket paths are closed immediately.
|
|
258
|
+
|
|
259
|
+
## Extending This Module
|
|
260
|
+
|
|
261
|
+
To add a new websocket route:
|
|
262
|
+
|
|
263
|
+
1. Add a new handler service under `services/`.
|
|
264
|
+
2. Extend `WebSocketServerDependencies` in `websocket-server.service.ts` if needed.
|
|
265
|
+
3. Add a new pathname branch in the router.
|
|
266
|
+
4. Wire dependency injection from `server/index.js`.
|
|
267
|
+
5. Keep `index.ts` as barrel-only export surface.
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import type { WebSocket } from 'ws';
|
|
2
|
+
|
|
3
|
+
import { connectedClients } from '@/modules/websocket/services/websocket-state.service.js';
|
|
4
|
+
import { WebSocketWriter } from '@/modules/websocket/services/websocket-writer.service.js';
|
|
5
|
+
import type {
|
|
6
|
+
AnyRecord,
|
|
7
|
+
AuthenticatedWebSocketRequest,
|
|
8
|
+
LLMProvider,
|
|
9
|
+
} from '@/shared/types.js';
|
|
10
|
+
import { createNormalizedMessage, parseIncomingJsonObject } from '@/shared/utils.js';
|
|
11
|
+
|
|
12
|
+
type ChatIncomingMessage = AnyRecord & {
|
|
13
|
+
type?: string;
|
|
14
|
+
command?: string;
|
|
15
|
+
options?: AnyRecord;
|
|
16
|
+
provider?: string;
|
|
17
|
+
sessionId?: string;
|
|
18
|
+
requestId?: string;
|
|
19
|
+
allow?: unknown;
|
|
20
|
+
updatedInput?: unknown;
|
|
21
|
+
message?: unknown;
|
|
22
|
+
rememberEntry?: unknown;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const DEFAULT_PROVIDER: LLMProvider = 'claude';
|
|
26
|
+
|
|
27
|
+
type ChatWebSocketDependencies = {
|
|
28
|
+
queryClaudeSDK: (command: string, options: unknown, writer: WebSocketWriter) => Promise<unknown>;
|
|
29
|
+
spawnCursor: (command: string, options: unknown, writer: WebSocketWriter) => Promise<unknown>;
|
|
30
|
+
queryCodex: (command: string, options: unknown, writer: WebSocketWriter) => Promise<unknown>;
|
|
31
|
+
spawnGemini: (command: string, options: unknown, writer: WebSocketWriter) => Promise<unknown>;
|
|
32
|
+
abortClaudeSDKSession: (sessionId: string, userId?: string | number | null) => Promise<boolean>;
|
|
33
|
+
abortCursorSession: (sessionId: string) => boolean;
|
|
34
|
+
abortCodexSession: (sessionId: string, userId?: string | number | null) => boolean;
|
|
35
|
+
abortGeminiSession: (sessionId: string) => boolean;
|
|
36
|
+
resolveToolApproval: (
|
|
37
|
+
requestId: string,
|
|
38
|
+
payload: {
|
|
39
|
+
allow: boolean;
|
|
40
|
+
updatedInput?: unknown;
|
|
41
|
+
message?: string;
|
|
42
|
+
rememberEntry?: unknown;
|
|
43
|
+
}
|
|
44
|
+
) => void;
|
|
45
|
+
isClaudeSDKSessionActive: (sessionId: string, userId?: string | number | null) => boolean;
|
|
46
|
+
isCursorSessionActive: (sessionId: string) => boolean;
|
|
47
|
+
isCodexSessionActive: (sessionId: string, userId?: string | number | null) => boolean;
|
|
48
|
+
isGeminiSessionActive: (sessionId: string) => boolean;
|
|
49
|
+
reconnectSessionWriter: (sessionId: string, ws: WebSocket, userId?: string | number | null) => boolean;
|
|
50
|
+
getPendingApprovalsForSession: (sessionId: string, userId?: string | number | null) => unknown[];
|
|
51
|
+
getActiveClaudeSDKSessions: (userId?: string | number | null) => unknown;
|
|
52
|
+
getActiveCursorSessions: () => unknown;
|
|
53
|
+
getActiveCodexSessions: (userId?: string | number | null) => unknown;
|
|
54
|
+
getActiveGeminiSessions: () => unknown;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Normalizes potentially invalid provider names coming from websocket payloads.
|
|
59
|
+
*/
|
|
60
|
+
function readProvider(value: unknown): LLMProvider {
|
|
61
|
+
if (value === 'claude' || value === 'cursor' || value === 'codex' || value === 'gemini') {
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return DEFAULT_PROVIDER;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Extracts the authenticated request user id in the formats currently produced
|
|
70
|
+
* by platform and OSS auth code paths.
|
|
71
|
+
*/
|
|
72
|
+
function readRequestUserId(
|
|
73
|
+
request: AuthenticatedWebSocketRequest | undefined
|
|
74
|
+
): string | number | null {
|
|
75
|
+
const user = request?.user;
|
|
76
|
+
if (!user) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (typeof user.id === 'string' || typeof user.id === 'number') {
|
|
81
|
+
return user.id;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (typeof user.userId === 'string' || typeof user.userId === 'number') {
|
|
85
|
+
return user.userId;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Handles authenticated chat websocket messages used by the main chat panel.
|
|
93
|
+
*/
|
|
94
|
+
export function handleChatConnection(
|
|
95
|
+
ws: WebSocket,
|
|
96
|
+
request: AuthenticatedWebSocketRequest,
|
|
97
|
+
dependencies: ChatWebSocketDependencies
|
|
98
|
+
): void {
|
|
99
|
+
console.log('[INFO] Chat WebSocket connected');
|
|
100
|
+
connectedClients.add(ws);
|
|
101
|
+
|
|
102
|
+
const writer = new WebSocketWriter(ws, readRequestUserId(request));
|
|
103
|
+
|
|
104
|
+
ws.on('message', async (rawMessage) => {
|
|
105
|
+
try {
|
|
106
|
+
const parsed = parseIncomingJsonObject(rawMessage);
|
|
107
|
+
if (!parsed) {
|
|
108
|
+
throw new Error('Invalid websocket payload');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const data = parsed as ChatIncomingMessage;
|
|
112
|
+
const messageType = data.type;
|
|
113
|
+
if (!messageType) {
|
|
114
|
+
throw new Error('Message type is required');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (messageType === 'claude-command') {
|
|
118
|
+
await dependencies.queryClaudeSDK(data.command ?? '', data.options, writer);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (messageType === 'cursor-command') {
|
|
123
|
+
await dependencies.spawnCursor(data.command ?? '', data.options, writer);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (messageType === 'codex-command') {
|
|
128
|
+
await dependencies.queryCodex(data.command ?? '', data.options, writer);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (messageType === 'gemini-command') {
|
|
133
|
+
await dependencies.spawnGemini(data.command ?? '', data.options, writer);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (messageType === 'cursor-resume') {
|
|
138
|
+
await dependencies.spawnCursor(
|
|
139
|
+
'',
|
|
140
|
+
{
|
|
141
|
+
sessionId: data.sessionId,
|
|
142
|
+
resume: true,
|
|
143
|
+
cwd: data.options?.cwd,
|
|
144
|
+
},
|
|
145
|
+
writer
|
|
146
|
+
);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (messageType === 'abort-session') {
|
|
151
|
+
const provider = readProvider(data.provider);
|
|
152
|
+
const sessionId = typeof data.sessionId === 'string' ? data.sessionId : '';
|
|
153
|
+
const userId = writer.userId;
|
|
154
|
+
let success = false;
|
|
155
|
+
|
|
156
|
+
if (provider === 'cursor') {
|
|
157
|
+
success = dependencies.abortCursorSession(sessionId);
|
|
158
|
+
} else if (provider === 'codex') {
|
|
159
|
+
success = dependencies.abortCodexSession(sessionId, userId);
|
|
160
|
+
} else if (provider === 'gemini') {
|
|
161
|
+
success = dependencies.abortGeminiSession(sessionId);
|
|
162
|
+
} else {
|
|
163
|
+
success = await dependencies.abortClaudeSDKSession(sessionId, userId);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
writer.send(
|
|
167
|
+
createNormalizedMessage({
|
|
168
|
+
kind: 'complete',
|
|
169
|
+
exitCode: success ? 0 : 1,
|
|
170
|
+
aborted: true,
|
|
171
|
+
success,
|
|
172
|
+
sessionId,
|
|
173
|
+
provider,
|
|
174
|
+
})
|
|
175
|
+
);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (messageType === 'claude-permission-response') {
|
|
180
|
+
if (typeof data.requestId === 'string' && data.requestId.length > 0) {
|
|
181
|
+
dependencies.resolveToolApproval(data.requestId, {
|
|
182
|
+
allow: Boolean(data.allow),
|
|
183
|
+
updatedInput: data.updatedInput,
|
|
184
|
+
message: typeof data.message === 'string' ? data.message : undefined,
|
|
185
|
+
rememberEntry: data.rememberEntry,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (messageType === 'cursor-abort') {
|
|
192
|
+
const sessionId = typeof data.sessionId === 'string' ? data.sessionId : '';
|
|
193
|
+
const success = dependencies.abortCursorSession(sessionId);
|
|
194
|
+
writer.send(
|
|
195
|
+
createNormalizedMessage({
|
|
196
|
+
kind: 'complete',
|
|
197
|
+
exitCode: success ? 0 : 1,
|
|
198
|
+
aborted: true,
|
|
199
|
+
success,
|
|
200
|
+
sessionId,
|
|
201
|
+
provider: 'cursor',
|
|
202
|
+
})
|
|
203
|
+
);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (messageType === 'check-session-status') {
|
|
208
|
+
const provider = readProvider(data.provider);
|
|
209
|
+
const sessionId = typeof data.sessionId === 'string' ? data.sessionId : '';
|
|
210
|
+
const userId = writer.userId;
|
|
211
|
+
let isActive = false;
|
|
212
|
+
|
|
213
|
+
if (provider === 'cursor') {
|
|
214
|
+
isActive = dependencies.isCursorSessionActive(sessionId);
|
|
215
|
+
} else if (provider === 'codex') {
|
|
216
|
+
isActive = dependencies.isCodexSessionActive(sessionId, userId);
|
|
217
|
+
} else if (provider === 'gemini') {
|
|
218
|
+
isActive = dependencies.isGeminiSessionActive(sessionId);
|
|
219
|
+
} else {
|
|
220
|
+
isActive = dependencies.isClaudeSDKSessionActive(sessionId, userId);
|
|
221
|
+
if (isActive) {
|
|
222
|
+
dependencies.reconnectSessionWriter(sessionId, ws, userId);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
writer.send({
|
|
227
|
+
type: 'session-status',
|
|
228
|
+
sessionId,
|
|
229
|
+
provider,
|
|
230
|
+
isProcessing: isActive,
|
|
231
|
+
});
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (messageType === 'get-pending-permissions') {
|
|
236
|
+
const sessionId = typeof data.sessionId === 'string' ? data.sessionId : '';
|
|
237
|
+
const userId = writer.userId;
|
|
238
|
+
if (sessionId && dependencies.isClaudeSDKSessionActive(sessionId, userId)) {
|
|
239
|
+
const pending = dependencies.getPendingApprovalsForSession(sessionId, userId);
|
|
240
|
+
writer.send({
|
|
241
|
+
type: 'pending-permissions-response',
|
|
242
|
+
sessionId,
|
|
243
|
+
data: pending,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (messageType === 'get-active-sessions') {
|
|
250
|
+
const userId = writer.userId;
|
|
251
|
+
writer.send({
|
|
252
|
+
type: 'active-sessions',
|
|
253
|
+
sessions: {
|
|
254
|
+
claude: dependencies.getActiveClaudeSDKSessions(userId),
|
|
255
|
+
cursor: dependencies.getActiveCursorSessions(),
|
|
256
|
+
codex: dependencies.getActiveCodexSessions(userId),
|
|
257
|
+
gemini: dependencies.getActiveGeminiSessions(),
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
} catch (error) {
|
|
262
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
263
|
+
console.error('[ERROR] Chat WebSocket error:', message);
|
|
264
|
+
writer.send({
|
|
265
|
+
type: 'error',
|
|
266
|
+
error: message,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
ws.on('close', () => {
|
|
272
|
+
console.log('[INFO] Chat client disconnected');
|
|
273
|
+
connectedClients.delete(ws);
|
|
274
|
+
});
|
|
275
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { WebSocket } from 'ws';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Proxies an authenticated client websocket to a plugin websocket endpoint.
|
|
5
|
+
*/
|
|
6
|
+
export function handlePluginWsProxy(
|
|
7
|
+
clientWs: WebSocket,
|
|
8
|
+
pathname: string,
|
|
9
|
+
getPluginPort: (pluginName: string) => number | null
|
|
10
|
+
): void {
|
|
11
|
+
const pluginName = pathname.replace('/plugin-ws/', '');
|
|
12
|
+
if (!pluginName || /[^a-zA-Z0-9_-]/.test(pluginName)) {
|
|
13
|
+
clientWs.close(4400, 'Invalid plugin name');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const port = getPluginPort(pluginName);
|
|
18
|
+
if (!port) {
|
|
19
|
+
clientWs.close(4404, 'Plugin not running');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const upstream = new WebSocket(`ws://127.0.0.1:${port}/ws`);
|
|
24
|
+
|
|
25
|
+
upstream.on('open', () => {
|
|
26
|
+
console.log(`[Plugins] WS proxy connected to "${pluginName}" on port ${port}`);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
upstream.on('message', (data) => {
|
|
30
|
+
if (clientWs.readyState === WebSocket.OPEN) {
|
|
31
|
+
clientWs.send(data);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
clientWs.on('message', (data) => {
|
|
36
|
+
if (upstream.readyState === WebSocket.OPEN) {
|
|
37
|
+
upstream.send(data);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
upstream.on('close', () => {
|
|
42
|
+
if (clientWs.readyState === WebSocket.OPEN) {
|
|
43
|
+
clientWs.close();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
clientWs.on('close', () => {
|
|
48
|
+
if (upstream.readyState === WebSocket.OPEN) {
|
|
49
|
+
upstream.close();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
upstream.on('error', (error) => {
|
|
54
|
+
console.error(`[Plugins] WS proxy error for "${pluginName}":`, error.message);
|
|
55
|
+
if (clientWs.readyState === WebSocket.OPEN) {
|
|
56
|
+
clientWs.close(4502, 'Upstream error');
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
clientWs.on('error', () => {
|
|
61
|
+
if (upstream.readyState === WebSocket.OPEN) {
|
|
62
|
+
upstream.close();
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|