@thevinci/web 1.0.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/README.md +197 -0
- package/bin/cli-entry.js +55 -0
- package/bin/cli-output.js +145 -0
- package/bin/cli.js +4887 -0
- package/bin/cli.test.js +64 -0
- package/dist/apple-touch-icon-120x120.png +0 -0
- package/dist/apple-touch-icon-152x152.png +0 -0
- package/dist/apple-touch-icon-167x167.png +0 -0
- package/dist/apple-touch-icon-180x180.png +0 -0
- package/dist/apple-touch-icon.png +0 -0
- package/dist/apple-touch-icon.svg +528 -0
- package/dist/assets/JsonTreeView-CSm9OzXG.js +1 -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/MarkdownRendererImpl-DensKOLc.js +6 -0
- package/dist/assets/MultiRunWindow-Bo7THayo.js +1 -0
- package/dist/assets/OnboardingScreen-BDqmzTVR.js +2 -0
- package/dist/assets/SettingsWindow-coz__Ykw.js +1 -0
- package/dist/assets/TerminalView-DrZ-i3Dr.js +1 -0
- package/dist/assets/ToolOutputDialog-Eglzslt3.js +16 -0
- package/dist/assets/es-4o9ciP61.js +15 -0
- package/dist/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- package/dist/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/dist/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- package/dist/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- package/dist/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2 +0 -0
- package/dist/assets/ibm-plex-mono-latin-600-normal-DWFSQ4vo.woff +0 -0
- package/dist/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
- package/dist/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
- package/dist/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
- package/dist/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
- package/dist/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
- package/dist/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
- package/dist/assets/index-DLTDToSP.css +1 -0
- package/dist/assets/index-DgiFEKGN.js +1 -0
- package/dist/assets/ko-B20imCHE.js +15 -0
- package/dist/assets/main-BV3KOtdA.css +1 -0
- package/dist/assets/main-CDKJj0sH.js +226 -0
- package/dist/assets/main-LC-PSNVM.js +2 -0
- package/dist/assets/miniChat-CQUiG_cr.js +2 -0
- package/dist/assets/modelPrefsAutoSave-Dm799vzR.js +6986 -0
- package/dist/assets/pl-DQJ7LSzj.js +15 -0
- package/dist/assets/pt-BR-OmjHUz9y.js +15 -0
- package/dist/assets/renderElectronMiniChatApp-CARbeW0G.js +2 -0
- package/dist/assets/uk-BNFxOlO4.js +15 -0
- package/dist/assets/vendor--DBfsbEis.css +1 -0
- package/dist/assets/vendor-.bun-B9l0ZNi2.js +4094 -0
- package/dist/assets/wasm-CG6Dc4jp.js +1 -0
- package/dist/assets/wasmSttWorker-Dtlxac_K.js +1 -0
- package/dist/assets/wasmSttWorker-oo7Dm_jy.js +1806 -0
- package/dist/assets/worker-CbT6TVo7.js +155 -0
- package/dist/assets/zh-CN-C6T-Ac7F.js +15 -0
- package/dist/favicon-16.png +0 -0
- package/dist/favicon-32.png +0 -0
- package/dist/favicon.png +0 -0
- package/dist/favicon.svg +528 -0
- package/dist/index.html +607 -0
- package/dist/logo-dark-192x192.png +0 -0
- package/dist/logo-dark-512x512.png +0 -0
- package/dist/logo-dark-512x512.svg +528 -0
- package/dist/logo-light-192x192.png +0 -0
- package/dist/logo-light-512x512.png +0 -0
- package/dist/logo-light-512x512.svg +528 -0
- package/dist/mini-chat.html +16 -0
- package/dist/pwa-192.png +0 -0
- package/dist/pwa-512.png +0 -0
- package/dist/pwa-maskable-192.png +0 -0
- package/dist/pwa-maskable-512.png +0 -0
- package/dist/site.webmanifest +21 -0
- package/dist/sw.js +1 -0
- package/package.json +118 -0
- package/public/apple-touch-icon-120x120.png +0 -0
- package/public/apple-touch-icon-152x152.png +0 -0
- package/public/apple-touch-icon-167x167.png +0 -0
- package/public/apple-touch-icon-180x180.png +0 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/apple-touch-icon.svg +528 -0
- package/public/favicon-16.png +0 -0
- package/public/favicon-32.png +0 -0
- package/public/favicon.png +0 -0
- package/public/favicon.svg +528 -0
- package/public/logo-dark-192x192.png +0 -0
- package/public/logo-dark-512x512.png +0 -0
- package/public/logo-dark-512x512.svg +528 -0
- package/public/logo-light-192x192.png +0 -0
- package/public/logo-light-512x512.png +0 -0
- package/public/logo-light-512x512.svg +528 -0
- package/public/pwa-192.png +0 -0
- package/public/pwa-512.png +0 -0
- package/public/pwa-maskable-192.png +0 -0
- package/public/pwa-maskable-512.png +0 -0
- package/public/site.webmanifest +21 -0
- package/server/TERMINAL_WS_PROTOCOL.md +48 -0
- package/server/index.d.ts +39 -0
- package/server/index.js +1311 -0
- package/server/lib/cloudflare-tunnel.js +650 -0
- package/server/lib/event-stream/DOCUMENTATION.md +61 -0
- package/server/lib/event-stream/directory-ws-bridge.js +185 -0
- package/server/lib/event-stream/global-hub.js +158 -0
- package/server/lib/event-stream/global-hub.test.js +140 -0
- package/server/lib/event-stream/global-ws-bridge.js +206 -0
- package/server/lib/event-stream/index.js +25 -0
- package/server/lib/event-stream/protocol.js +131 -0
- package/server/lib/event-stream/protocol.test.js +182 -0
- package/server/lib/event-stream/runtime.js +180 -0
- package/server/lib/event-stream/runtime.test.js +512 -0
- package/server/lib/event-stream/upstream-reader.js +226 -0
- package/server/lib/event-stream/upstream-reader.test.js +276 -0
- package/server/lib/fs/DOCUMENTATION.md +36 -0
- package/server/lib/fs/routes.js +1040 -0
- package/server/lib/fs/search.js +238 -0
- package/server/lib/git/DOCUMENTATION.md +152 -0
- package/server/lib/git/credentials.js +74 -0
- package/server/lib/git/identity-storage.js +112 -0
- package/server/lib/git/index.js +6 -0
- package/server/lib/git/routes.js +972 -0
- package/server/lib/git/service.js +3432 -0
- package/server/lib/git/service.test.js +39 -0
- package/server/lib/github/DOCUMENTATION.md +171 -0
- package/server/lib/github/auth.js +307 -0
- package/server/lib/github/device-flow.js +50 -0
- package/server/lib/github/index.js +24 -0
- package/server/lib/github/octokit.js +10 -0
- package/server/lib/github/pr-status.js +519 -0
- package/server/lib/github/repo/fork-detection.js +102 -0
- package/server/lib/github/repo/index.js +55 -0
- package/server/lib/github/routes.js +1560 -0
- package/server/lib/magic-prompts/routes.js +63 -0
- package/server/lib/magic-prompts/runtime.js +119 -0
- package/server/lib/notifications/DOCUMENTATION.md +122 -0
- package/server/lib/notifications/emitter-runtime.js +102 -0
- package/server/lib/notifications/index.js +4 -0
- package/server/lib/notifications/message.js +52 -0
- package/server/lib/notifications/message.test.js +34 -0
- package/server/lib/notifications/push-runtime.js +304 -0
- package/server/lib/notifications/routes.js +315 -0
- package/server/lib/notifications/runtime.js +566 -0
- package/server/lib/notifications/template-runtime.js +349 -0
- package/server/lib/notifications/template-runtime.test.js +26 -0
- package/server/lib/opencode/DOCUMENTATION.md +362 -0
- package/server/lib/opencode/agents.js +634 -0
- package/server/lib/opencode/auth-state-runtime.js +88 -0
- package/server/lib/opencode/auth.js +83 -0
- package/server/lib/opencode/bootstrap-runtime.js +131 -0
- package/server/lib/opencode/cli-entry-runtime.js +43 -0
- package/server/lib/opencode/cli-options.js +128 -0
- package/server/lib/opencode/commands.js +339 -0
- package/server/lib/opencode/config-entity-routes.js +370 -0
- package/server/lib/opencode/core-routes.js +500 -0
- package/server/lib/opencode/core-routes.test.js +26 -0
- package/server/lib/opencode/env-config.js +74 -0
- package/server/lib/opencode/env-keys.js +68 -0
- package/server/lib/opencode/env-runtime.js +1162 -0
- package/server/lib/opencode/env-runtime.test.js +116 -0
- package/server/lib/opencode/feature-routes-runtime.js +244 -0
- package/server/lib/opencode/hmr-state-runtime.js +85 -0
- package/server/lib/opencode/index.js +66 -0
- package/server/lib/opencode/lifecycle.js +1019 -0
- package/server/lib/opencode/lifecycle.test.js +240 -0
- package/server/lib/opencode/mcp.js +278 -0
- package/server/lib/opencode/network-runtime.js +104 -0
- package/server/lib/opencode/network-runtime.test.js +37 -0
- package/server/lib/opencode/opencode-resolution-runtime.js +71 -0
- package/server/lib/opencode/path-utils.js +100 -0
- package/server/lib/opencode/path-utils.test.js +71 -0
- package/server/lib/opencode/project-directory-runtime.js +124 -0
- package/server/lib/opencode/project-icon-routes.js +399 -0
- package/server/lib/opencode/project-icon-routes.test.js +107 -0
- package/server/lib/opencode/providers.js +96 -0
- package/server/lib/opencode/proxy.js +445 -0
- package/server/lib/opencode/pwa-manifest-routes.js +257 -0
- package/server/lib/opencode/pwa-manifest-routes.test.js +133 -0
- package/server/lib/opencode/routes.js +541 -0
- package/server/lib/opencode/server-startup-runtime.js +156 -0
- package/server/lib/opencode/server-utils-runtime.js +168 -0
- package/server/lib/opencode/server-utils-runtime.test.js +135 -0
- package/server/lib/opencode/session-runtime.js +356 -0
- package/server/lib/opencode/session-runtime.test.js +151 -0
- package/server/lib/opencode/settings-helpers.js +770 -0
- package/server/lib/opencode/settings-helpers.test.js +109 -0
- package/server/lib/opencode/settings-normalization-runtime.js +428 -0
- package/server/lib/opencode/settings-runtime.js +826 -0
- package/server/lib/opencode/settings-runtime.test.js +85 -0
- package/server/lib/opencode/shared.js +615 -0
- package/server/lib/opencode/shutdown-runtime.js +139 -0
- package/server/lib/opencode/shutdown-runtime.test.js +58 -0
- package/server/lib/opencode/skill-routes.js +701 -0
- package/server/lib/opencode/skills.js +548 -0
- package/server/lib/opencode/startup-pipeline-runtime.js +130 -0
- package/server/lib/opencode/static-routes-runtime.js +65 -0
- package/server/lib/opencode/theme-runtime.js +167 -0
- package/server/lib/opencode/tunnel-auth.js +591 -0
- package/server/lib/opencode/tunnel-wiring-runtime.js +94 -0
- package/server/lib/opencode/vinci-routes.js +76 -0
- package/server/lib/opencode/watcher.js +115 -0
- package/server/lib/opencode/watcher.test.js +239 -0
- package/server/lib/preview/proxy-runtime.js +1333 -0
- package/server/lib/preview/proxy-runtime.test.js +144 -0
- package/server/lib/projects/project-config.js +567 -0
- package/server/lib/projects/project-config.test.js +175 -0
- package/server/lib/projects/project-id.js +13 -0
- package/server/lib/quota/DOCUMENTATION.md +58 -0
- package/server/lib/quota/index.js +25 -0
- package/server/lib/quota/providers/claude.js +107 -0
- package/server/lib/quota/providers/codex.js +113 -0
- package/server/lib/quota/providers/copilot.js +165 -0
- package/server/lib/quota/providers/google/api.js +92 -0
- package/server/lib/quota/providers/google/auth.js +108 -0
- package/server/lib/quota/providers/google/index.js +124 -0
- package/server/lib/quota/providers/google/transforms.js +109 -0
- package/server/lib/quota/providers/index.js +168 -0
- package/server/lib/quota/providers/interface.js +55 -0
- package/server/lib/quota/providers/kimi.js +108 -0
- package/server/lib/quota/providers/minimax-cn-coding-plan.js +140 -0
- package/server/lib/quota/providers/minimax-coding-plan.js +139 -0
- package/server/lib/quota/providers/nanogpt.js +124 -0
- package/server/lib/quota/providers/ollama-cloud.js +112 -0
- package/server/lib/quota/providers/openai.js +91 -0
- package/server/lib/quota/providers/openrouter.js +92 -0
- package/server/lib/quota/providers/zai.js +91 -0
- package/server/lib/quota/providers/zhipuai-coding-plan.js +133 -0
- package/server/lib/quota/providers/zhipuai.js +114 -0
- package/server/lib/quota/routes.js +27 -0
- package/server/lib/quota/utils/auth.js +50 -0
- package/server/lib/quota/utils/formatters.js +85 -0
- package/server/lib/quota/utils/formatters.test.js +54 -0
- package/server/lib/quota/utils/index.js +10 -0
- package/server/lib/quota/utils/transformers.js +55 -0
- package/server/lib/scheduled-tasks/DOCUMENTATION.md +44 -0
- package/server/lib/scheduled-tasks/routes.js +235 -0
- package/server/lib/scheduled-tasks/runtime.js +773 -0
- package/server/lib/scheduled-tasks/runtime.test.js +100 -0
- package/server/lib/security/request-security.js +115 -0
- package/server/lib/session-folders/routes.js +63 -0
- package/server/lib/session-folders/routes.test.js +102 -0
- package/server/lib/skills-catalog/DOCUMENTATION.md +178 -0
- package/server/lib/skills-catalog/cache.js +29 -0
- package/server/lib/skills-catalog/clawdhub/api.js +158 -0
- package/server/lib/skills-catalog/clawdhub/index.js +30 -0
- package/server/lib/skills-catalog/clawdhub/install.js +238 -0
- package/server/lib/skills-catalog/clawdhub/scan.js +113 -0
- package/server/lib/skills-catalog/curated-sources.js +21 -0
- package/server/lib/skills-catalog/git.js +77 -0
- package/server/lib/skills-catalog/index.js +42 -0
- package/server/lib/skills-catalog/install.js +294 -0
- package/server/lib/skills-catalog/scan.js +221 -0
- package/server/lib/skills-catalog/source.js +87 -0
- package/server/lib/terminal/DOCUMENTATION.md +76 -0
- package/server/lib/terminal/index.js +31 -0
- package/server/lib/terminal/output-replay-buffer.js +78 -0
- package/server/lib/terminal/output-replay-buffer.test.js +75 -0
- package/server/lib/terminal/runtime.js +850 -0
- package/server/lib/terminal/runtime.test.js +96 -0
- package/server/lib/terminal/terminal-ws-protocol.js +68 -0
- package/server/lib/terminal/terminal-ws-protocol.test.js +145 -0
- package/server/lib/text/DOCUMENTATION.md +35 -0
- package/server/lib/text/summarization.js +138 -0
- package/server/lib/text/summarization.test.js +34 -0
- package/server/lib/tts/DOCUMENTATION.md +146 -0
- package/server/lib/tts/base-url.js +62 -0
- package/server/lib/tts/capability-runtime.js +31 -0
- package/server/lib/tts/index.js +19 -0
- package/server/lib/tts/routes.js +261 -0
- package/server/lib/tts/routes.test.js +53 -0
- package/server/lib/tts/service.js +178 -0
- package/server/lib/tts/stt.js +75 -0
- package/server/lib/tunnels/DOCUMENTATION.md +18 -0
- package/server/lib/tunnels/index.js +166 -0
- package/server/lib/tunnels/managed-config.js +201 -0
- package/server/lib/tunnels/providers/cloudflare.js +260 -0
- package/server/lib/tunnels/registry.js +51 -0
- package/server/lib/tunnels/routes.js +605 -0
- package/server/lib/tunnels/types.js +219 -0
- package/server/lib/ui-auth/DOCUMENTATION.md +38 -0
- package/server/lib/ui-auth/ui-auth.js +673 -0
- package/server/lib/ui-auth/ui-passkeys.js +545 -0
- package/server/opencode-proxy.test.js +151 -0
- package/server/proxy-headers.js +61 -0
- package/server/proxy-headers.test.js +58 -0
- package/server/sse-routes.test.js +152 -0
package/server/index.js
ADDED
|
@@ -0,0 +1,1311 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import compression from 'compression';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { spawn, spawnSync } from 'child_process';
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import http from 'http';
|
|
8
|
+
import net from 'net';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import os from 'os';
|
|
11
|
+
import crypto from 'crypto';
|
|
12
|
+
import { createUiAuth } from './lib/ui-auth/ui-auth.js';
|
|
13
|
+
import { createTunnelAuth } from './lib/opencode/tunnel-auth.js';
|
|
14
|
+
import { createManagedTunnelConfigRuntime } from './lib/tunnels/managed-config.js';
|
|
15
|
+
import { createTunnelProviderRegistry } from './lib/tunnels/registry.js';
|
|
16
|
+
import { createCloudflareTunnelProvider } from './lib/tunnels/providers/cloudflare.js';
|
|
17
|
+
import { createRequestSecurityRuntime } from './lib/security/request-security.js';
|
|
18
|
+
import {
|
|
19
|
+
TUNNEL_MODE_MANAGED_LOCAL,
|
|
20
|
+
TUNNEL_MODE_MANAGED_REMOTE,
|
|
21
|
+
TUNNEL_MODE_QUICK,
|
|
22
|
+
TUNNEL_PROVIDER_CLOUDFLARE,
|
|
23
|
+
TunnelServiceError,
|
|
24
|
+
isSupportedTunnelMode,
|
|
25
|
+
normalizeOptionalPath,
|
|
26
|
+
normalizeTunnelStartRequest,
|
|
27
|
+
normalizeTunnelMode,
|
|
28
|
+
normalizeTunnelProvider,
|
|
29
|
+
} from './lib/tunnels/types.js';
|
|
30
|
+
import { prepareNotificationLastMessage } from './lib/notifications/index.js';
|
|
31
|
+
import { registerTtsRoutes } from './lib/tts/routes.js';
|
|
32
|
+
import { detectSayTtsCapability } from './lib/tts/capability-runtime.js';
|
|
33
|
+
import { createTerminalRuntime } from './lib/terminal/runtime.js';
|
|
34
|
+
import {
|
|
35
|
+
createGlobalUiEventBroadcaster,
|
|
36
|
+
createGlobalMessageStreamHub,
|
|
37
|
+
createMessageStreamWsRuntime,
|
|
38
|
+
DEFAULT_UPSTREAM_STALL_TIMEOUT_MS,
|
|
39
|
+
UPSTREAM_STALL_TIMEOUT_CONCURRENT_MS,
|
|
40
|
+
} from './lib/event-stream/index.js';
|
|
41
|
+
import { createFsSearchRuntime as createFsSearchRuntimeFactory } from './lib/fs/search.js';
|
|
42
|
+
import { createOpenCodeLifecycleRuntime } from './lib/opencode/lifecycle.js';
|
|
43
|
+
import { createOpenCodeEnvRuntime } from './lib/opencode/env-runtime.js';
|
|
44
|
+
import { resolveOpenCodeEnvConfig } from './lib/opencode/env-config.js';
|
|
45
|
+
import { createHmrStateRuntime } from './lib/opencode/hmr-state-runtime.js';
|
|
46
|
+
import { createOpenCodeNetworkRuntime } from './lib/opencode/network-runtime.js';
|
|
47
|
+
import { createOpenCodeAuthStateRuntime } from './lib/opencode/auth-state-runtime.js';
|
|
48
|
+
import { createProjectDirectoryRuntime } from './lib/opencode/project-directory-runtime.js';
|
|
49
|
+
import { createSettingsNormalizationRuntime } from './lib/opencode/settings-normalization-runtime.js';
|
|
50
|
+
import { createSettingsHelpers } from './lib/opencode/settings-helpers.js';
|
|
51
|
+
import { createThemeRuntime } from './lib/opencode/theme-runtime.js';
|
|
52
|
+
import { createFeatureRoutesRuntime } from './lib/opencode/feature-routes-runtime.js';
|
|
53
|
+
import { parseServeCliOptions } from './lib/opencode/cli-options.js';
|
|
54
|
+
import {
|
|
55
|
+
registerAuthAndAccessRoutes,
|
|
56
|
+
registerCommonRequestMiddleware,
|
|
57
|
+
registerServerStatusRoutes,
|
|
58
|
+
} from './lib/opencode/core-routes.js';
|
|
59
|
+
import { registerVinciRoutes } from './lib/opencode/vinci-routes.js';
|
|
60
|
+
import { createServerUtilsRuntime } from './lib/opencode/server-utils-runtime.js';
|
|
61
|
+
import { createStaticRoutesRuntime } from './lib/opencode/static-routes-runtime.js';
|
|
62
|
+
import { createSettingsRuntime } from './lib/opencode/settings-runtime.js';
|
|
63
|
+
import { createOpenCodeResolutionRuntime } from './lib/opencode/opencode-resolution-runtime.js';
|
|
64
|
+
import { createBootstrapRuntime } from './lib/opencode/bootstrap-runtime.js';
|
|
65
|
+
import { createSessionRuntime } from './lib/opencode/session-runtime.js';
|
|
66
|
+
import { createOpenCodeWatcherRuntime } from './lib/opencode/watcher.js';
|
|
67
|
+
import { createScheduledTasksRuntime } from './lib/scheduled-tasks/runtime.js';
|
|
68
|
+
import { createServerStartupRuntime } from './lib/opencode/server-startup-runtime.js';
|
|
69
|
+
import { createTunnelWiringRuntime } from './lib/opencode/tunnel-wiring-runtime.js';
|
|
70
|
+
import { createStartupPipelineRuntime } from './lib/opencode/startup-pipeline-runtime.js';
|
|
71
|
+
import { runCliEntryIfMain } from './lib/opencode/cli-entry-runtime.js';
|
|
72
|
+
import { registerNotificationRoutes } from './lib/notifications/routes.js';
|
|
73
|
+
import { createNotificationEmitterRuntime } from './lib/notifications/emitter-runtime.js';
|
|
74
|
+
import { createNotificationTriggerRuntime } from './lib/notifications/runtime.js';
|
|
75
|
+
import { createPushRuntime } from './lib/notifications/push-runtime.js';
|
|
76
|
+
import { createNotificationTemplateRuntime } from './lib/notifications/template-runtime.js';
|
|
77
|
+
import { createGracefulShutdownRuntime } from './lib/opencode/shutdown-runtime.js';
|
|
78
|
+
import { createProjectConfigRuntime } from './lib/projects/project-config.js';
|
|
79
|
+
import { createPreviewProxyRuntime } from './lib/preview/proxy-runtime.js';
|
|
80
|
+
import { createProxyMiddleware, responseInterceptor } from 'http-proxy-middleware';
|
|
81
|
+
import webPush from 'web-push';
|
|
82
|
+
|
|
83
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
84
|
+
const __dirname = path.dirname(__filename);
|
|
85
|
+
|
|
86
|
+
const DEFAULT_PORT = 3900;
|
|
87
|
+
const DESKTOP_NOTIFY_PREFIX = '[VinciDesktopNotify] ';
|
|
88
|
+
const uiNotificationClients = new Set();
|
|
89
|
+
const uiNotificationWsClients = new Set();
|
|
90
|
+
const uiVinciEventClients = new Set();
|
|
91
|
+
const HEALTH_CHECK_INTERVAL = 15000;
|
|
92
|
+
const SHUTDOWN_TIMEOUT = 10000;
|
|
93
|
+
const MODELS_DEV_API_URL = 'https://models.dev/api.json';
|
|
94
|
+
const MODELS_METADATA_CACHE_TTL = 5 * 60 * 1000;
|
|
95
|
+
const CLIENT_RELOAD_DELAY_MS = 800;
|
|
96
|
+
const OPEN_CODE_READY_GRACE_MS = 12000;
|
|
97
|
+
const LONG_REQUEST_TIMEOUT_MS = 4 * 60 * 1000;
|
|
98
|
+
const TUNNEL_BOOTSTRAP_TTL_DEFAULT_MS = 30 * 60 * 1000;
|
|
99
|
+
const TUNNEL_BOOTSTRAP_TTL_MIN_MS = 60 * 1000;
|
|
100
|
+
const TUNNEL_BOOTSTRAP_TTL_MAX_MS = 24 * 60 * 60 * 1000;
|
|
101
|
+
const TUNNEL_SESSION_TTL_DEFAULT_MS = 8 * 60 * 60 * 1000;
|
|
102
|
+
const TUNNEL_SESSION_TTL_MIN_MS = 5 * 60 * 1000;
|
|
103
|
+
const TUNNEL_SESSION_TTL_MAX_MS = 30 * 24 * 60 * 60 * 1000;
|
|
104
|
+
|
|
105
|
+
function headerIncludesEventStream(value) {
|
|
106
|
+
if (typeof value === 'string') {
|
|
107
|
+
return value.toLowerCase().includes('text/event-stream');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (Array.isArray(value)) {
|
|
111
|
+
return value.some((entry) => typeof entry === 'string' && entry.toLowerCase().includes('text/event-stream'));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* SSE endpoint paths that must never be compressed by the compression middleware.
|
|
119
|
+
*
|
|
120
|
+
* The compression middleware filter runs before route handlers, so
|
|
121
|
+
* `res.getHeader('Content-Type')` is still undefined at that point.
|
|
122
|
+
* This means the Accept-header check alone is not sufficient for
|
|
123
|
+
* non-standard clients (e.g. curl, fetch) that omit Accept.
|
|
124
|
+
* Path-based exclusion acts as a deterministic fallback.
|
|
125
|
+
*/
|
|
126
|
+
const SSE_PATH_PREFIXES = [
|
|
127
|
+
'/api/event',
|
|
128
|
+
'/api/global/event',
|
|
129
|
+
'/api/notifications/stream',
|
|
130
|
+
'/api/vinci/events',
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
function shouldSkipCompression(req, res) {
|
|
134
|
+
if (headerIncludesEventStream(req.headers.accept)) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const pathname = req.path || req.url || '';
|
|
139
|
+
if ((pathname === '/api' || pathname.startsWith('/api/')) && shouldSkipApiCompression()) {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (pathname.startsWith('/api/terminal/') && pathname.endsWith('/stream')) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
for (const prefix of SSE_PATH_PREFIXES) {
|
|
147
|
+
if (pathname === prefix) {
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return headerIncludesEventStream(res.getHeader('Content-Type'));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const VINCI_VERSION = (() => {
|
|
156
|
+
try {
|
|
157
|
+
const packagePath = path.resolve(__dirname, '..', 'package.json');
|
|
158
|
+
const raw = fs.readFileSync(packagePath, 'utf8');
|
|
159
|
+
const pkg = JSON.parse(raw);
|
|
160
|
+
if (pkg && typeof pkg.version === 'string' && pkg.version.trim().length > 0) {
|
|
161
|
+
return pkg.version.trim();
|
|
162
|
+
}
|
|
163
|
+
} catch {
|
|
164
|
+
}
|
|
165
|
+
return 'unknown';
|
|
166
|
+
})();
|
|
167
|
+
|
|
168
|
+
const isEnvFlagEnabled = (value) => {
|
|
169
|
+
if (value === true || value === 1) return true;
|
|
170
|
+
if (typeof value !== 'string') return false;
|
|
171
|
+
const normalized = value.trim().toLowerCase();
|
|
172
|
+
return normalized === '1' || normalized === 'true';
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const isEnvFlagDisabled = (value) => {
|
|
176
|
+
if (value === false || value === 0) return true;
|
|
177
|
+
if (typeof value !== 'string') return false;
|
|
178
|
+
const normalized = value.trim().toLowerCase();
|
|
179
|
+
return normalized === '0' || normalized === 'false';
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const shouldSkipApiCompression = () => {
|
|
183
|
+
if (isEnvFlagEnabled(process.env.VINCI_SKIP_API_COMPRESSION)) return true;
|
|
184
|
+
if (isEnvFlagEnabled(process.env.VINCI_COMPRESS_API)) return false;
|
|
185
|
+
if (isEnvFlagDisabled(process.env.VINCI_COMPRESS_API)) return true;
|
|
186
|
+
return process.env.VINCI_RUNTIME === 'desktop';
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const VINCI_VERBOSE_REQUEST_LOGS = isEnvFlagEnabled(process.env.VINCI_VERBOSE_REQUEST_LOGS);
|
|
190
|
+
|
|
191
|
+
const PLAN_MODE_EXPERIMENT_ENABLED =
|
|
192
|
+
isEnvFlagEnabled(process.env.OPENCODE_EXPERIMENTAL_PLAN_MODE)
|
|
193
|
+
|| isEnvFlagEnabled(process.env.OPENCODE_EXPERIMENTAL);
|
|
194
|
+
|
|
195
|
+
const fsPromises = fs.promises;
|
|
196
|
+
|
|
197
|
+
const settingsNormalizationRuntime = createSettingsNormalizationRuntime({
|
|
198
|
+
os,
|
|
199
|
+
path,
|
|
200
|
+
processLike: process,
|
|
201
|
+
tunnelBootstrapTtlDefaultMs: TUNNEL_BOOTSTRAP_TTL_DEFAULT_MS,
|
|
202
|
+
tunnelBootstrapTtlMinMs: TUNNEL_BOOTSTRAP_TTL_MIN_MS,
|
|
203
|
+
tunnelBootstrapTtlMaxMs: TUNNEL_BOOTSTRAP_TTL_MAX_MS,
|
|
204
|
+
tunnelSessionTtlDefaultMs: TUNNEL_SESSION_TTL_DEFAULT_MS,
|
|
205
|
+
tunnelSessionTtlMinMs: TUNNEL_SESSION_TTL_MIN_MS,
|
|
206
|
+
tunnelSessionTtlMaxMs: TUNNEL_SESSION_TTL_MAX_MS,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const normalizeDirectoryPath = (...args) => settingsNormalizationRuntime.normalizeDirectoryPath(...args);
|
|
210
|
+
const normalizePathForPersistence = (...args) => settingsNormalizationRuntime.normalizePathForPersistence(...args);
|
|
211
|
+
const normalizeSettingsPaths = (...args) => settingsNormalizationRuntime.normalizeSettingsPaths(...args);
|
|
212
|
+
const normalizeTunnelBootstrapTtlMs = (...args) => settingsNormalizationRuntime.normalizeTunnelBootstrapTtlMs(...args);
|
|
213
|
+
const normalizeTunnelSessionTtlMs = (...args) => settingsNormalizationRuntime.normalizeTunnelSessionTtlMs(...args);
|
|
214
|
+
const normalizeManagedRemoteTunnelHostname = (...args) =>
|
|
215
|
+
settingsNormalizationRuntime.normalizeManagedRemoteTunnelHostname(...args);
|
|
216
|
+
const normalizeManagedRemoteTunnelPresets = (...args) =>
|
|
217
|
+
settingsNormalizationRuntime.normalizeManagedRemoteTunnelPresets(...args);
|
|
218
|
+
const normalizeManagedRemoteTunnelPresetTokens = (...args) =>
|
|
219
|
+
settingsNormalizationRuntime.normalizeManagedRemoteTunnelPresetTokens(...args);
|
|
220
|
+
const isUnsafeSkillRelativePath = (...args) => settingsNormalizationRuntime.isUnsafeSkillRelativePath(...args);
|
|
221
|
+
const sanitizeTypographySizesPartial = (...args) =>
|
|
222
|
+
settingsNormalizationRuntime.sanitizeTypographySizesPartial(...args);
|
|
223
|
+
const normalizeStringArray = (...args) => settingsNormalizationRuntime.normalizeStringArray(...args);
|
|
224
|
+
const sanitizeModelRefs = (...args) => settingsNormalizationRuntime.sanitizeModelRefs(...args);
|
|
225
|
+
const sanitizeSkillCatalogs = (...args) => settingsNormalizationRuntime.sanitizeSkillCatalogs(...args);
|
|
226
|
+
const sanitizeProjects = (...args) => settingsNormalizationRuntime.sanitizeProjects(...args);
|
|
227
|
+
|
|
228
|
+
const VINCI_USER_CONFIG_ROOT = process.env.VINCI_DATA_DIR
|
|
229
|
+
? path.resolve(process.env.VINCI_DATA_DIR)
|
|
230
|
+
: path.join(os.homedir(), '.vinci');
|
|
231
|
+
const VINCI_USER_THEMES_DIR = path.join(VINCI_USER_CONFIG_ROOT, 'themes');
|
|
232
|
+
const VINCI_PROJECTS_CONFIG_DIR = path.join(VINCI_USER_CONFIG_ROOT, 'projects');
|
|
233
|
+
|
|
234
|
+
const MAX_THEME_JSON_BYTES = 512 * 1024;
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
const themeRuntime = createThemeRuntime({
|
|
238
|
+
fsPromises,
|
|
239
|
+
path,
|
|
240
|
+
themesDir: VINCI_USER_THEMES_DIR,
|
|
241
|
+
maxThemeJsonBytes: MAX_THEME_JSON_BYTES,
|
|
242
|
+
logger: console,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
const readCustomThemesFromDisk = (...args) => themeRuntime.readCustomThemesFromDisk(...args);
|
|
246
|
+
|
|
247
|
+
let notificationTemplateRuntime = null;
|
|
248
|
+
|
|
249
|
+
const createTimeoutSignal = (...args) => notificationTemplateRuntime.createTimeoutSignal(...args);
|
|
250
|
+
const formatProjectLabel = (...args) => notificationTemplateRuntime.formatProjectLabel(...args);
|
|
251
|
+
const resolveNotificationTemplate = (...args) => notificationTemplateRuntime.resolveNotificationTemplate(...args);
|
|
252
|
+
const shouldApplyResolvedTemplateMessage = (...args) => notificationTemplateRuntime.shouldApplyResolvedTemplateMessage(...args);
|
|
253
|
+
const fetchFreeZenModels = (...args) => notificationTemplateRuntime.fetchFreeZenModels(...args);
|
|
254
|
+
const extractTextFromParts = (...args) => notificationTemplateRuntime.extractTextFromParts(...args);
|
|
255
|
+
const extractLastMessageText = (...args) => notificationTemplateRuntime.extractLastMessageText(...args);
|
|
256
|
+
const fetchLastAssistantMessageText = (...args) => notificationTemplateRuntime.fetchLastAssistantMessageText(...args);
|
|
257
|
+
const maybeCacheSessionInfoFromEvent = (...args) => notificationTemplateRuntime.maybeCacheSessionInfoFromEvent(...args);
|
|
258
|
+
const buildTemplateVariables = (...args) => notificationTemplateRuntime.buildTemplateVariables(...args);
|
|
259
|
+
const getCachedZenModels = (...args) => notificationTemplateRuntime.getCachedZenModels(...args);
|
|
260
|
+
|
|
261
|
+
const VINCI_DATA_DIR = process.env.VINCI_DATA_DIR
|
|
262
|
+
? path.resolve(process.env.VINCI_DATA_DIR)
|
|
263
|
+
: path.join(os.homedir(), '.vinci');
|
|
264
|
+
const SETTINGS_FILE_PATH = path.join(VINCI_DATA_DIR, 'settings.json');
|
|
265
|
+
const PUSH_SUBSCRIPTIONS_FILE_PATH = path.join(VINCI_DATA_DIR, 'push-subscriptions.json');
|
|
266
|
+
const CLOUDFLARE_MANAGED_REMOTE_TUNNELS_FILE_PATH = path.join(VINCI_DATA_DIR, 'cloudflare-managed-remote-tunnels.json');
|
|
267
|
+
const CLOUDFLARE_LEGACY_NAMED_TUNNELS_FILE_PATH = path.join(VINCI_DATA_DIR, 'cloudflare-named-tunnels.json');
|
|
268
|
+
const CLOUDFLARE_MANAGED_REMOTE_TUNNELS_VERSION = 1;
|
|
269
|
+
|
|
270
|
+
const managedTunnelConfigRuntime = createManagedTunnelConfigRuntime({
|
|
271
|
+
fsPromises,
|
|
272
|
+
path,
|
|
273
|
+
normalizeManagedRemoteTunnelHostname,
|
|
274
|
+
normalizeManagedRemoteTunnelPresets,
|
|
275
|
+
constants: {
|
|
276
|
+
CLOUDFLARE_MANAGED_REMOTE_TUNNELS_FILE_PATH,
|
|
277
|
+
CLOUDFLARE_LEGACY_NAMED_TUNNELS_FILE_PATH,
|
|
278
|
+
CLOUDFLARE_MANAGED_REMOTE_TUNNELS_VERSION,
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
const readManagedRemoteTunnelConfigFromDisk = (...args) => managedTunnelConfigRuntime.readManagedRemoteTunnelConfigFromDisk(...args);
|
|
283
|
+
const syncManagedRemoteTunnelConfigWithPresets = (...args) => managedTunnelConfigRuntime.syncManagedRemoteTunnelConfigWithPresets(...args);
|
|
284
|
+
const upsertManagedRemoteTunnelToken = (...args) => managedTunnelConfigRuntime.upsertManagedRemoteTunnelToken(...args);
|
|
285
|
+
const resolveManagedRemoteTunnelToken = (...args) => managedTunnelConfigRuntime.resolveManagedRemoteTunnelToken(...args);
|
|
286
|
+
|
|
287
|
+
const settingsHelpers = createSettingsHelpers({
|
|
288
|
+
normalizePathForPersistence,
|
|
289
|
+
normalizeDirectoryPath,
|
|
290
|
+
normalizeTunnelBootstrapTtlMs,
|
|
291
|
+
normalizeTunnelSessionTtlMs,
|
|
292
|
+
normalizeTunnelProvider,
|
|
293
|
+
normalizeTunnelMode,
|
|
294
|
+
normalizeOptionalPath,
|
|
295
|
+
normalizeManagedRemoteTunnelHostname,
|
|
296
|
+
normalizeManagedRemoteTunnelPresets,
|
|
297
|
+
normalizeManagedRemoteTunnelPresetTokens,
|
|
298
|
+
sanitizeTypographySizesPartial,
|
|
299
|
+
normalizeStringArray,
|
|
300
|
+
sanitizeModelRefs,
|
|
301
|
+
sanitizeSkillCatalogs,
|
|
302
|
+
sanitizeProjects,
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
const normalizePwaAppName = (...args) => settingsHelpers.normalizePwaAppName(...args);
|
|
306
|
+
const normalizePwaOrientation = (...args) => settingsHelpers.normalizePwaOrientation(...args);
|
|
307
|
+
const sanitizeSettingsUpdate = (...args) => settingsHelpers.sanitizeSettingsUpdate(...args);
|
|
308
|
+
const mergePersistedSettings = (...args) => settingsHelpers.mergePersistedSettings(...args);
|
|
309
|
+
const formatSettingsResponse = (...args) => settingsHelpers.formatSettingsResponse(...args);
|
|
310
|
+
|
|
311
|
+
const projectDirectoryRuntime = createProjectDirectoryRuntime({
|
|
312
|
+
fsPromises,
|
|
313
|
+
path,
|
|
314
|
+
normalizeDirectoryPath,
|
|
315
|
+
getReadSettingsFromDiskMigrated: () => readSettingsFromDiskMigrated,
|
|
316
|
+
sanitizeProjects,
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
const resolveDirectoryCandidate = (...args) => projectDirectoryRuntime.resolveDirectoryCandidate(...args);
|
|
320
|
+
const validateDirectoryPath = (...args) => projectDirectoryRuntime.validateDirectoryPath(...args);
|
|
321
|
+
const resolveProjectDirectory = (...args) => projectDirectoryRuntime.resolveProjectDirectory(...args);
|
|
322
|
+
const resolveOptionalProjectDirectory = (...args) => projectDirectoryRuntime.resolveOptionalProjectDirectory(...args);
|
|
323
|
+
|
|
324
|
+
const settingsRuntime = createSettingsRuntime({
|
|
325
|
+
fsPromises,
|
|
326
|
+
path,
|
|
327
|
+
crypto,
|
|
328
|
+
SETTINGS_FILE_PATH,
|
|
329
|
+
sanitizeProjects,
|
|
330
|
+
sanitizeSettingsUpdate,
|
|
331
|
+
mergePersistedSettings,
|
|
332
|
+
normalizeSettingsPaths,
|
|
333
|
+
normalizeStringArray,
|
|
334
|
+
formatSettingsResponse,
|
|
335
|
+
resolveDirectoryCandidate,
|
|
336
|
+
normalizeManagedRemoteTunnelHostname,
|
|
337
|
+
normalizeManagedRemoteTunnelPresets,
|
|
338
|
+
normalizeManagedRemoteTunnelPresetTokens,
|
|
339
|
+
syncManagedRemoteTunnelConfigWithPresets,
|
|
340
|
+
upsertManagedRemoteTunnelToken,
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
const readSettingsFromDiskMigrated = (...args) => settingsRuntime.readSettingsFromDiskMigrated(...args);
|
|
344
|
+
const readSettingsFromDisk = (...args) => settingsRuntime.readSettingsFromDisk(...args);
|
|
345
|
+
const writeSettingsToDisk = (...args) => settingsRuntime.writeSettingsToDisk(...args);
|
|
346
|
+
const persistSettings = (...args) => settingsRuntime.persistSettings(...args);
|
|
347
|
+
|
|
348
|
+
const requestSecurityRuntime = createRequestSecurityRuntime({
|
|
349
|
+
readSettingsFromDiskMigrated,
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
const getUiSessionTokenFromRequest = (...args) => requestSecurityRuntime.getUiSessionTokenFromRequest(...args);
|
|
353
|
+
|
|
354
|
+
const pushRuntime = createPushRuntime({
|
|
355
|
+
fsPromises,
|
|
356
|
+
path,
|
|
357
|
+
webPush,
|
|
358
|
+
PUSH_SUBSCRIPTIONS_FILE_PATH,
|
|
359
|
+
readSettingsFromDiskMigrated,
|
|
360
|
+
writeSettingsToDisk,
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
const getOrCreateVapidKeys = (...args) => pushRuntime.getOrCreateVapidKeys(...args);
|
|
364
|
+
const addOrUpdatePushSubscription = (...args) => pushRuntime.addOrUpdatePushSubscription(...args);
|
|
365
|
+
const removePushSubscription = (...args) => pushRuntime.removePushSubscription(...args);
|
|
366
|
+
const sendPushToAllUiSessions = (...args) => pushRuntime.sendPushToAllUiSessions(...args);
|
|
367
|
+
const updateUiVisibility = (...args) => pushRuntime.updateUiVisibility(...args);
|
|
368
|
+
const isAnyUiVisible = (...args) => pushRuntime.isAnyUiVisible(...args);
|
|
369
|
+
const isUiVisible = (...args) => pushRuntime.isUiVisible(...args);
|
|
370
|
+
const ensurePushInitialized = (...args) => pushRuntime.ensurePushInitialized(...args);
|
|
371
|
+
const setPushInitialized = (...args) => pushRuntime.setPushInitialized(...args);
|
|
372
|
+
|
|
373
|
+
const TERMINAL_INPUT_WS_MAX_REBINDS_PER_WINDOW = 128;
|
|
374
|
+
const TERMINAL_INPUT_WS_REBIND_WINDOW_MS = 60 * 1000;
|
|
375
|
+
const TERMINAL_INPUT_WS_HEARTBEAT_INTERVAL_MS = 15 * 1000;
|
|
376
|
+
|
|
377
|
+
const rejectWebSocketUpgrade = (...args) => requestSecurityRuntime.rejectWebSocketUpgrade(...args);
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
const isRequestOriginAllowed = (...args) => requestSecurityRuntime.isRequestOriginAllowed(...args);
|
|
381
|
+
|
|
382
|
+
const notificationEmitterRuntime = createNotificationEmitterRuntime({
|
|
383
|
+
process,
|
|
384
|
+
getDesktopNotifyEnabled: () => ENV_DESKTOP_NOTIFY,
|
|
385
|
+
desktopNotifyPrefix: DESKTOP_NOTIFY_PREFIX,
|
|
386
|
+
getUiNotificationClients: () => uiNotificationClients,
|
|
387
|
+
getBroadcastGlobalUiEvent: () => broadcastGlobalUiEvent,
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
const writeSseEvent = (...args) => notificationEmitterRuntime.writeSseEvent(...args);
|
|
391
|
+
const emitDesktopNotification = (...args) => notificationEmitterRuntime.emitDesktopNotification(...args);
|
|
392
|
+
const broadcastGlobalUiEvent = createGlobalUiEventBroadcaster({
|
|
393
|
+
sseClients: uiNotificationClients,
|
|
394
|
+
wsClients: uiNotificationWsClients,
|
|
395
|
+
writeSseEvent,
|
|
396
|
+
});
|
|
397
|
+
const broadcastUiNotification = (...args) => notificationEmitterRuntime.broadcastUiNotification(...args);
|
|
398
|
+
|
|
399
|
+
const sessionRuntime = createSessionRuntime({
|
|
400
|
+
writeSseEvent,
|
|
401
|
+
getNotificationClients: () => uiNotificationClients,
|
|
402
|
+
broadcastEvent: broadcastGlobalUiEvent,
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
const getActiveSessionCount = () => {
|
|
406
|
+
const snapshot = sessionRuntime.getSessionActivitySnapshot();
|
|
407
|
+
return Object.values(snapshot).filter((entry) => entry.type === 'busy').length;
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
const getUpstreamStallTimeoutMs = () => (
|
|
411
|
+
getActiveSessionCount() > 1
|
|
412
|
+
? UPSTREAM_STALL_TIMEOUT_CONCURRENT_MS
|
|
413
|
+
: DEFAULT_UPSTREAM_STALL_TIMEOUT_MS
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
const projectConfigRuntime = createProjectConfigRuntime({
|
|
417
|
+
fsPromises,
|
|
418
|
+
path,
|
|
419
|
+
projectsDirPath: VINCI_PROJECTS_CONFIG_DIR,
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// HMR-persistent state via globalThis
|
|
423
|
+
// These values survive Vite HMR reloads to prevent zombie OpenCode processes
|
|
424
|
+
const hmrStateRuntime = createHmrStateRuntime({
|
|
425
|
+
globalThisLike: globalThis,
|
|
426
|
+
os,
|
|
427
|
+
processLike: process,
|
|
428
|
+
stateKey: '__vinciHmrState',
|
|
429
|
+
});
|
|
430
|
+
const hmrState = hmrStateRuntime.getOrCreateHmrState();
|
|
431
|
+
hmrStateRuntime.ensureUserProvidedOpenCodePassword(hmrState);
|
|
432
|
+
|
|
433
|
+
// Non-HMR state (safe to reset on reload)
|
|
434
|
+
let healthCheckInterval = null;
|
|
435
|
+
let server = null;
|
|
436
|
+
let expressApp = null;
|
|
437
|
+
let currentRestartPromise = null;
|
|
438
|
+
let isRestartingOpenCode = false;
|
|
439
|
+
let openCodeApiPrefix = '';
|
|
440
|
+
let openCodeApiPrefixDetected = true;
|
|
441
|
+
let openCodeApiDetectionTimer = null;
|
|
442
|
+
let lastOpenCodeError = null;
|
|
443
|
+
let lastOpenCodeLaunchDiagnostics = null;
|
|
444
|
+
let isOpenCodeReady = false;
|
|
445
|
+
let openCodeNotReadySince = 0;
|
|
446
|
+
let isExternalOpenCode = false;
|
|
447
|
+
let exitOnShutdown = true;
|
|
448
|
+
let uiAuthController = null;
|
|
449
|
+
let activeTunnelController = null;
|
|
450
|
+
let globalWatcherStartPromise = null;
|
|
451
|
+
const tunnelProviderRegistry = createTunnelProviderRegistry([
|
|
452
|
+
createCloudflareTunnelProvider(),
|
|
453
|
+
]);
|
|
454
|
+
tunnelProviderRegistry.seal();
|
|
455
|
+
const tunnelAuthController = createTunnelAuth();
|
|
456
|
+
let runtimeManagedRemoteTunnelToken = '';
|
|
457
|
+
let runtimeManagedRemoteTunnelHostname = '';
|
|
458
|
+
let terminalRuntime = null;
|
|
459
|
+
let messageStreamRuntime = null;
|
|
460
|
+
const userProvidedOpenCodePassword = hmrStateRuntime.getUserProvidedOpenCodePassword(hmrState);
|
|
461
|
+
const initialOpenCodeAuthState = hmrStateRuntime.resolveOpenCodeAuthFromState({
|
|
462
|
+
hmrState,
|
|
463
|
+
userProvidedOpenCodePassword,
|
|
464
|
+
});
|
|
465
|
+
let openCodeAuthPassword = initialOpenCodeAuthState.openCodeAuthPassword;
|
|
466
|
+
let openCodeAuthSource = initialOpenCodeAuthState.openCodeAuthSource;
|
|
467
|
+
|
|
468
|
+
// Sync helper - call after modifying any HMR state variable
|
|
469
|
+
const syncToHmrState = () => {
|
|
470
|
+
hmrStateRuntime.syncStateFromRuntime(hmrState, {
|
|
471
|
+
openCodeProcess,
|
|
472
|
+
openCodePort,
|
|
473
|
+
openCodeBaseUrl,
|
|
474
|
+
isShuttingDown,
|
|
475
|
+
signalsAttached,
|
|
476
|
+
openCodeWorkingDirectory,
|
|
477
|
+
openCodeAuthPassword,
|
|
478
|
+
openCodeAuthSource,
|
|
479
|
+
});
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
// Sync helper - call to restore state from HMR (e.g., on module reload)
|
|
483
|
+
const syncFromHmrState = () => {
|
|
484
|
+
const restored = hmrStateRuntime.restoreRuntimeFromState({
|
|
485
|
+
hmrState,
|
|
486
|
+
userProvidedOpenCodePassword,
|
|
487
|
+
});
|
|
488
|
+
openCodeProcess = restored.openCodeProcess;
|
|
489
|
+
openCodePort = restored.openCodePort;
|
|
490
|
+
openCodeBaseUrl = restored.openCodeBaseUrl;
|
|
491
|
+
isShuttingDown = restored.isShuttingDown;
|
|
492
|
+
signalsAttached = restored.signalsAttached;
|
|
493
|
+
openCodeWorkingDirectory = restored.openCodeWorkingDirectory;
|
|
494
|
+
openCodeAuthPassword = restored.openCodeAuthPassword;
|
|
495
|
+
openCodeAuthSource = restored.openCodeAuthSource;
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
// Module-level variables that shadow HMR state
|
|
499
|
+
// These are synced to/from hmrState to survive HMR reloads
|
|
500
|
+
let openCodeProcess = hmrState.openCodeProcess;
|
|
501
|
+
let openCodePort = hmrState.openCodePort;
|
|
502
|
+
let openCodeBaseUrl = hmrState.openCodeBaseUrl ?? null;
|
|
503
|
+
let isShuttingDown = hmrState.isShuttingDown;
|
|
504
|
+
let signalsAttached = hmrState.signalsAttached;
|
|
505
|
+
let openCodeWorkingDirectory = hmrState.openCodeWorkingDirectory;
|
|
506
|
+
|
|
507
|
+
const {
|
|
508
|
+
configuredOpenCodePort: ENV_CONFIGURED_OPENCODE_PORT,
|
|
509
|
+
configuredOpenCodeHost: ENV_CONFIGURED_OPENCODE_HOST,
|
|
510
|
+
effectivePort: ENV_EFFECTIVE_PORT,
|
|
511
|
+
configuredOpenCodeHostname: ENV_CONFIGURED_OPENCODE_HOSTNAME,
|
|
512
|
+
} = resolveOpenCodeEnvConfig({
|
|
513
|
+
env: process.env,
|
|
514
|
+
logger: console,
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
const ENV_SKIP_OPENCODE_START = process.env.OPENCODE_SKIP_START === 'true' ||
|
|
518
|
+
process.env.VINCI_SKIP_OPENCODE_START === 'true';
|
|
519
|
+
const ENV_DESKTOP_NOTIFY = (() => {
|
|
520
|
+
if (process.env.VINCI_DESKTOP_NOTIFY === 'true') {
|
|
521
|
+
return true;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (process.env.VINCI_RUNTIME === 'desktop') {
|
|
525
|
+
return true;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const argv0 = typeof process.argv?.[0] === 'string' ? process.argv[0] : '';
|
|
529
|
+
const argv1 = typeof process.argv?.[1] === 'string' ? process.argv[1] : '';
|
|
530
|
+
return /vinci-server/i.test(argv0) || /vinci-server/i.test(argv1);
|
|
531
|
+
})();
|
|
532
|
+
const ENV_CONFIGURED_OPENCODE_WSL_DISTRO =
|
|
533
|
+
typeof process.env.OPENCODE_WSL_DISTRO === 'string' && process.env.OPENCODE_WSL_DISTRO.trim().length > 0
|
|
534
|
+
? process.env.OPENCODE_WSL_DISTRO.trim()
|
|
535
|
+
: (
|
|
536
|
+
typeof process.env.VINCI_OPENCODE_WSL_DISTRO === 'string' &&
|
|
537
|
+
process.env.VINCI_OPENCODE_WSL_DISTRO.trim().length > 0
|
|
538
|
+
? process.env.VINCI_OPENCODE_WSL_DISTRO.trim()
|
|
539
|
+
: null
|
|
540
|
+
);
|
|
541
|
+
|
|
542
|
+
const openCodeAuthStateRuntime = createOpenCodeAuthStateRuntime({
|
|
543
|
+
crypto,
|
|
544
|
+
process,
|
|
545
|
+
getAuthPassword: () => openCodeAuthPassword,
|
|
546
|
+
setAuthPassword: (value) => {
|
|
547
|
+
openCodeAuthPassword = value;
|
|
548
|
+
},
|
|
549
|
+
getAuthSource: () => openCodeAuthSource,
|
|
550
|
+
setAuthSource: (value) => {
|
|
551
|
+
openCodeAuthSource = value;
|
|
552
|
+
},
|
|
553
|
+
getUserProvidedPassword: () => userProvidedOpenCodePassword,
|
|
554
|
+
syncToHmrState,
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
const getOpenCodeAuthHeaders = (...args) => openCodeAuthStateRuntime.getOpenCodeAuthHeaders(...args);
|
|
558
|
+
const isOpenCodeConnectionSecure = (...args) => openCodeAuthStateRuntime.isOpenCodeConnectionSecure(...args);
|
|
559
|
+
const ensureLocalOpenCodeServerPassword = (...args) => openCodeAuthStateRuntime.ensureLocalOpenCodeServerPassword(...args);
|
|
560
|
+
|
|
561
|
+
const openCodeNetworkState = {};
|
|
562
|
+
Object.defineProperties(openCodeNetworkState, {
|
|
563
|
+
openCodePort: { get: () => openCodePort, set: (value) => { openCodePort = value; } },
|
|
564
|
+
openCodeBaseUrl: { get: () => openCodeBaseUrl, set: (value) => { openCodeBaseUrl = value; } },
|
|
565
|
+
openCodeApiPrefix: { get: () => openCodeApiPrefix, set: (value) => { openCodeApiPrefix = value; } },
|
|
566
|
+
openCodeApiPrefixDetected: { get: () => openCodeApiPrefixDetected, set: (value) => { openCodeApiPrefixDetected = value; } },
|
|
567
|
+
openCodeApiDetectionTimer: { get: () => openCodeApiDetectionTimer, set: (value) => { openCodeApiDetectionTimer = value; } },
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
const openCodeNetworkRuntime = createOpenCodeNetworkRuntime({
|
|
571
|
+
state: openCodeNetworkState,
|
|
572
|
+
getOpenCodeAuthHeaders,
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
const waitForReady = (...args) => openCodeNetworkRuntime.waitForReady(...args);
|
|
576
|
+
const normalizeApiPrefix = (...args) => openCodeNetworkRuntime.normalizeApiPrefix(...args);
|
|
577
|
+
const setDetectedOpenCodeApiPrefix = (...args) => openCodeNetworkRuntime.setDetectedOpenCodeApiPrefix(...args);
|
|
578
|
+
const buildOpenCodeUrl = (...args) => openCodeNetworkRuntime.buildOpenCodeUrl(...args);
|
|
579
|
+
const ensureOpenCodeApiPrefix = (...args) => openCodeNetworkRuntime.ensureOpenCodeApiPrefix(...args);
|
|
580
|
+
const scheduleOpenCodeApiDetection = (...args) => openCodeNetworkRuntime.scheduleOpenCodeApiDetection(...args);
|
|
581
|
+
|
|
582
|
+
const ENV_CONFIGURED_API_PREFIX = normalizeApiPrefix(
|
|
583
|
+
process.env.OPENCODE_API_PREFIX || process.env.VINCI_API_PREFIX || ''
|
|
584
|
+
);
|
|
585
|
+
|
|
586
|
+
if (ENV_CONFIGURED_API_PREFIX && ENV_CONFIGURED_API_PREFIX !== '') {
|
|
587
|
+
console.warn('Ignoring configured OpenCode API prefix; API runs at root.');
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
let cachedLoginShellEnvSnapshot;
|
|
591
|
+
let resolvedOpencodeBinary = null;
|
|
592
|
+
let resolvedOpencodeBinarySource = null;
|
|
593
|
+
let resolvedNodeBinary = null;
|
|
594
|
+
let resolvedBunBinary = null;
|
|
595
|
+
let resolvedGitBinary = null;
|
|
596
|
+
let useWslForOpencode = false;
|
|
597
|
+
let resolvedWslBinary = null;
|
|
598
|
+
let resolvedWslOpencodePath = null;
|
|
599
|
+
let resolvedWslDistro = null;
|
|
600
|
+
|
|
601
|
+
const openCodeEnvState = {};
|
|
602
|
+
Object.defineProperties(openCodeEnvState, {
|
|
603
|
+
cachedLoginShellEnvSnapshot: { get: () => cachedLoginShellEnvSnapshot, set: (value) => { cachedLoginShellEnvSnapshot = value; } },
|
|
604
|
+
resolvedOpencodeBinary: { get: () => resolvedOpencodeBinary, set: (value) => { resolvedOpencodeBinary = value; } },
|
|
605
|
+
resolvedOpencodeBinarySource: { get: () => resolvedOpencodeBinarySource, set: (value) => { resolvedOpencodeBinarySource = value; } },
|
|
606
|
+
resolvedNodeBinary: { get: () => resolvedNodeBinary, set: (value) => { resolvedNodeBinary = value; } },
|
|
607
|
+
resolvedBunBinary: { get: () => resolvedBunBinary, set: (value) => { resolvedBunBinary = value; } },
|
|
608
|
+
resolvedGitBinary: { get: () => resolvedGitBinary, set: (value) => { resolvedGitBinary = value; } },
|
|
609
|
+
useWslForOpencode: { get: () => useWslForOpencode, set: (value) => { useWslForOpencode = value; } },
|
|
610
|
+
resolvedWslBinary: { get: () => resolvedWslBinary, set: (value) => { resolvedWslBinary = value; } },
|
|
611
|
+
resolvedWslOpencodePath: { get: () => resolvedWslOpencodePath, set: (value) => { resolvedWslOpencodePath = value; } },
|
|
612
|
+
resolvedWslDistro: { get: () => resolvedWslDistro, set: (value) => { resolvedWslDistro = value; } },
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
const openCodeEnvRuntime = createOpenCodeEnvRuntime({
|
|
616
|
+
state: openCodeEnvState,
|
|
617
|
+
normalizeDirectoryPath,
|
|
618
|
+
readSettingsFromDiskMigrated,
|
|
619
|
+
ENV_CONFIGURED_OPENCODE_WSL_DISTRO,
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
const applyLoginShellEnvSnapshot = (...args) => openCodeEnvRuntime.applyLoginShellEnvSnapshot(...args);
|
|
623
|
+
const getLoginShellEnvSnapshot = (...args) => openCodeEnvRuntime.getLoginShellEnvSnapshot(...args);
|
|
624
|
+
const ensureOpencodeCliEnv = (...args) => openCodeEnvRuntime.ensureOpencodeCliEnv(...args);
|
|
625
|
+
const applyOpencodeBinaryFromSettings = (...args) => openCodeEnvRuntime.applyOpencodeBinaryFromSettings(...args);
|
|
626
|
+
const resolveOpencodeCliPath = (...args) => openCodeEnvRuntime.resolveOpencodeCliPath(...args);
|
|
627
|
+
const isExecutable = (...args) => openCodeEnvRuntime.isExecutable(...args);
|
|
628
|
+
const searchPathFor = (...args) => openCodeEnvRuntime.searchPathFor(...args);
|
|
629
|
+
const resolveGitBinaryForSpawn = (...args) => openCodeEnvRuntime.resolveGitBinaryForSpawn(...args);
|
|
630
|
+
const resolveWslExecutablePath = (...args) => openCodeEnvRuntime.resolveWslExecutablePath(...args);
|
|
631
|
+
const buildWslExecArgs = (...args) => openCodeEnvRuntime.buildWslExecArgs(...args);
|
|
632
|
+
const resolveManagedOpenCodeLaunchSpec = (...args) => openCodeEnvRuntime.resolveManagedOpenCodeLaunchSpec(...args);
|
|
633
|
+
const clearResolvedOpenCodeBinary = (...args) => openCodeEnvRuntime.clearResolvedOpenCodeBinary(...args);
|
|
634
|
+
const openCodeResolutionRuntime = createOpenCodeResolutionRuntime({
|
|
635
|
+
path,
|
|
636
|
+
resolveOpencodeCliPath,
|
|
637
|
+
applyOpencodeBinaryFromSettings,
|
|
638
|
+
ensureOpencodeCliEnv,
|
|
639
|
+
resolveManagedOpenCodeLaunchSpec,
|
|
640
|
+
getResolvedState: () => ({
|
|
641
|
+
resolvedOpencodeBinary,
|
|
642
|
+
resolvedOpencodeBinarySource,
|
|
643
|
+
useWslForOpencode,
|
|
644
|
+
resolvedWslBinary,
|
|
645
|
+
resolvedWslOpencodePath,
|
|
646
|
+
resolvedWslDistro,
|
|
647
|
+
resolvedNodeBinary,
|
|
648
|
+
resolvedBunBinary,
|
|
649
|
+
}),
|
|
650
|
+
setResolvedOpencodeBinarySource: (value) => {
|
|
651
|
+
resolvedOpencodeBinarySource = value;
|
|
652
|
+
},
|
|
653
|
+
});
|
|
654
|
+
const getOpenCodeResolutionSnapshot = (...args) =>
|
|
655
|
+
openCodeResolutionRuntime.getOpenCodeResolutionSnapshot(...args);
|
|
656
|
+
|
|
657
|
+
applyLoginShellEnvSnapshot();
|
|
658
|
+
|
|
659
|
+
notificationTemplateRuntime = createNotificationTemplateRuntime({
|
|
660
|
+
readSettingsFromDisk,
|
|
661
|
+
persistSettings,
|
|
662
|
+
buildOpenCodeUrl,
|
|
663
|
+
getOpenCodeAuthHeaders,
|
|
664
|
+
resolveGitBinaryForSpawn,
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
const notificationTriggerRuntime = createNotificationTriggerRuntime({
|
|
668
|
+
readSettingsFromDisk,
|
|
669
|
+
prepareNotificationLastMessage,
|
|
670
|
+
buildTemplateVariables,
|
|
671
|
+
extractLastMessageText,
|
|
672
|
+
fetchLastAssistantMessageText,
|
|
673
|
+
resolveNotificationTemplate,
|
|
674
|
+
shouldApplyResolvedTemplateMessage,
|
|
675
|
+
emitDesktopNotification,
|
|
676
|
+
broadcastUiNotification,
|
|
677
|
+
sendPushToAllUiSessions,
|
|
678
|
+
buildOpenCodeUrl,
|
|
679
|
+
getOpenCodeAuthHeaders,
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
const maybeSendPushForTrigger = (...args) => notificationTriggerRuntime.maybeSendPushForTrigger(...args);
|
|
683
|
+
const setAutoAcceptSession = (...args) => notificationTriggerRuntime.setAutoAcceptSession(...args);
|
|
684
|
+
|
|
685
|
+
const globalMessageStreamHub = createGlobalMessageStreamHub({
|
|
686
|
+
buildOpenCodeUrl,
|
|
687
|
+
getOpenCodeAuthHeaders,
|
|
688
|
+
upstreamStallTimeoutMs: getUpstreamStallTimeoutMs,
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
const openCodeWatcherRuntime = createOpenCodeWatcherRuntime({
|
|
692
|
+
waitForOpenCodePort: (...args) => waitForOpenCodePort(...args),
|
|
693
|
+
buildOpenCodeUrl,
|
|
694
|
+
getOpenCodeAuthHeaders,
|
|
695
|
+
parseSseDataPayload: (...args) => parseSseDataPayload(...args),
|
|
696
|
+
globalEventHub: globalMessageStreamHub,
|
|
697
|
+
onPayload: (payload) => {
|
|
698
|
+
maybeCacheSessionInfoFromEvent(payload);
|
|
699
|
+
void maybeSendPushForTrigger(payload);
|
|
700
|
+
sessionRuntime.processOpenCodeSsePayload(payload);
|
|
701
|
+
},
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
const processForwardedEventPayload = (payload, emitSyntheticEvent) => {
|
|
705
|
+
if (!payload || typeof payload !== 'object' || typeof emitSyntheticEvent !== 'function') {
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
maybeCacheSessionInfoFromEvent(payload);
|
|
710
|
+
|
|
711
|
+
if (payload.type !== 'session.status') {
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
const properties = payload.properties && typeof payload.properties === 'object' ? payload.properties : {};
|
|
716
|
+
const statusInfo = properties.status && typeof properties.status === 'object' ? properties.status : {};
|
|
717
|
+
const info = properties.info && typeof properties.info === 'object' ? properties.info : {};
|
|
718
|
+
const sessionId = typeof properties.sessionID === 'string' ? properties.sessionID.trim() : '';
|
|
719
|
+
const status = typeof statusInfo.type === 'string'
|
|
720
|
+
? statusInfo.type.trim()
|
|
721
|
+
: (typeof info.type === 'string' ? info.type.trim() : '');
|
|
722
|
+
|
|
723
|
+
if (!sessionId || !status) {
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
emitSyntheticEvent({
|
|
728
|
+
type: 'vinci:session-status',
|
|
729
|
+
properties: {
|
|
730
|
+
sessionId,
|
|
731
|
+
status,
|
|
732
|
+
timestamp: Date.now(),
|
|
733
|
+
metadata: {
|
|
734
|
+
attempt: typeof statusInfo.attempt === 'number'
|
|
735
|
+
? statusInfo.attempt
|
|
736
|
+
: (typeof info.attempt === 'number' ? info.attempt : undefined),
|
|
737
|
+
message: typeof statusInfo.message === 'string'
|
|
738
|
+
? statusInfo.message
|
|
739
|
+
: (typeof info.message === 'string' ? info.message : undefined),
|
|
740
|
+
next: typeof statusInfo.next === 'number'
|
|
741
|
+
? statusInfo.next
|
|
742
|
+
: (typeof info.next === 'number' ? info.next : undefined),
|
|
743
|
+
},
|
|
744
|
+
needsAttention: false,
|
|
745
|
+
},
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
emitSyntheticEvent({
|
|
749
|
+
type: 'vinci:session-activity',
|
|
750
|
+
properties: {
|
|
751
|
+
sessionId,
|
|
752
|
+
phase: status === 'busy' || status === 'retry' ? 'busy' : 'idle',
|
|
753
|
+
},
|
|
754
|
+
});
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
const serverUtilsRuntime = createServerUtilsRuntime({
|
|
759
|
+
fs,
|
|
760
|
+
os,
|
|
761
|
+
path,
|
|
762
|
+
process,
|
|
763
|
+
openCodeReadyGraceMs: OPEN_CODE_READY_GRACE_MS,
|
|
764
|
+
longRequestTimeoutMs: LONG_REQUEST_TIMEOUT_MS,
|
|
765
|
+
getRuntime: () => ({
|
|
766
|
+
openCodePort,
|
|
767
|
+
openCodeBaseUrl,
|
|
768
|
+
openCodeNotReadySince,
|
|
769
|
+
isOpenCodeReady,
|
|
770
|
+
isRestartingOpenCode,
|
|
771
|
+
}),
|
|
772
|
+
getOpenCodeAuthHeaders,
|
|
773
|
+
buildOpenCodeUrl,
|
|
774
|
+
ensureOpenCodeApiPrefix,
|
|
775
|
+
getUiNotificationClients: () => uiNotificationClients,
|
|
776
|
+
getOpenCodePort: () => openCodePort,
|
|
777
|
+
setOpenCodePortState: (value) => {
|
|
778
|
+
openCodePort = value;
|
|
779
|
+
},
|
|
780
|
+
syncToHmrState,
|
|
781
|
+
markOpenCodeNotReady: () => {
|
|
782
|
+
isOpenCodeReady = false;
|
|
783
|
+
},
|
|
784
|
+
setOpenCodeNotReadySince: (value) => {
|
|
785
|
+
openCodeNotReadySince = value;
|
|
786
|
+
},
|
|
787
|
+
clearLastOpenCodeError: () => {
|
|
788
|
+
lastOpenCodeError = null;
|
|
789
|
+
},
|
|
790
|
+
getLoginShellPath: () => {
|
|
791
|
+
const snapshot = getLoginShellEnvSnapshot();
|
|
792
|
+
if (!snapshot || typeof snapshot.PATH !== 'string' || snapshot.PATH.length === 0) {
|
|
793
|
+
return null;
|
|
794
|
+
}
|
|
795
|
+
return snapshot.PATH;
|
|
796
|
+
},
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
const setOpenCodePort = (...args) => serverUtilsRuntime.setOpenCodePort(...args);
|
|
800
|
+
const waitForOpenCodePort = (...args) => serverUtilsRuntime.waitForOpenCodePort(...args);
|
|
801
|
+
const buildAugmentedPath = (...args) => serverUtilsRuntime.buildAugmentedPath(...args);
|
|
802
|
+
const buildManagedOpenCodePath = (...args) => serverUtilsRuntime.buildManagedOpenCodePath(...args);
|
|
803
|
+
const parseSseDataPayload = (...args) => serverUtilsRuntime.parseSseDataPayload(...args);
|
|
804
|
+
const staticRoutesRuntime = createStaticRoutesRuntime({
|
|
805
|
+
fs,
|
|
806
|
+
path,
|
|
807
|
+
process,
|
|
808
|
+
__dirname,
|
|
809
|
+
express,
|
|
810
|
+
resolveProjectDirectory,
|
|
811
|
+
buildOpenCodeUrl,
|
|
812
|
+
getOpenCodeAuthHeaders,
|
|
813
|
+
readSettingsFromDiskMigrated,
|
|
814
|
+
normalizePwaAppName,
|
|
815
|
+
normalizePwaOrientation,
|
|
816
|
+
});
|
|
817
|
+
const featureRoutesRuntime = createFeatureRoutesRuntime({
|
|
818
|
+
clientReloadDelayMs: CLIENT_RELOAD_DELAY_MS,
|
|
819
|
+
});
|
|
820
|
+
const bootstrapRuntime = createBootstrapRuntime({
|
|
821
|
+
createUiAuth,
|
|
822
|
+
registerServerStatusRoutes,
|
|
823
|
+
registerCommonRequestMiddleware,
|
|
824
|
+
registerAuthAndAccessRoutes,
|
|
825
|
+
registerTtsRoutes,
|
|
826
|
+
registerNotificationRoutes,
|
|
827
|
+
registerVinciRoutes,
|
|
828
|
+
express,
|
|
829
|
+
});
|
|
830
|
+
const tunnelWiringRuntime = createTunnelWiringRuntime({
|
|
831
|
+
crypto,
|
|
832
|
+
URL,
|
|
833
|
+
tunnelProviderRegistry,
|
|
834
|
+
tunnelAuthController,
|
|
835
|
+
readSettingsFromDiskMigrated,
|
|
836
|
+
readManagedRemoteTunnelConfigFromDisk,
|
|
837
|
+
normalizeTunnelProvider,
|
|
838
|
+
normalizeTunnelMode,
|
|
839
|
+
normalizeOptionalPath,
|
|
840
|
+
normalizeManagedRemoteTunnelHostname,
|
|
841
|
+
normalizeTunnelBootstrapTtlMs,
|
|
842
|
+
normalizeTunnelSessionTtlMs,
|
|
843
|
+
isSupportedTunnelMode,
|
|
844
|
+
upsertManagedRemoteTunnelToken,
|
|
845
|
+
resolveManagedRemoteTunnelToken,
|
|
846
|
+
TUNNEL_MODE_QUICK,
|
|
847
|
+
TUNNEL_MODE_MANAGED_LOCAL,
|
|
848
|
+
TUNNEL_MODE_MANAGED_REMOTE,
|
|
849
|
+
TUNNEL_PROVIDER_CLOUDFLARE,
|
|
850
|
+
TunnelServiceError,
|
|
851
|
+
getActiveTunnelController: () => activeTunnelController,
|
|
852
|
+
setActiveTunnelController: (value) => {
|
|
853
|
+
activeTunnelController = value;
|
|
854
|
+
},
|
|
855
|
+
getRuntimeManagedRemoteTunnelHostname: () => runtimeManagedRemoteTunnelHostname,
|
|
856
|
+
setRuntimeManagedRemoteTunnelHostname: (value) => {
|
|
857
|
+
runtimeManagedRemoteTunnelHostname = value;
|
|
858
|
+
},
|
|
859
|
+
getRuntimeManagedRemoteTunnelToken: () => runtimeManagedRemoteTunnelToken,
|
|
860
|
+
setRuntimeManagedRemoteTunnelToken: (value) => {
|
|
861
|
+
runtimeManagedRemoteTunnelToken = value;
|
|
862
|
+
},
|
|
863
|
+
});
|
|
864
|
+
const startupPipelineRuntime = createStartupPipelineRuntime({
|
|
865
|
+
createTerminalRuntime,
|
|
866
|
+
createMessageStreamWsRuntime,
|
|
867
|
+
createServerStartupRuntime,
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
const openCodeLifecycleState = {};
|
|
871
|
+
Object.defineProperties(openCodeLifecycleState, {
|
|
872
|
+
openCodeProcess: { get: () => openCodeProcess, set: (value) => { openCodeProcess = value; } },
|
|
873
|
+
openCodePort: { get: () => openCodePort, set: (value) => { openCodePort = value; } },
|
|
874
|
+
openCodeBaseUrl: { get: () => openCodeBaseUrl, set: (value) => { openCodeBaseUrl = value; } },
|
|
875
|
+
openCodeWorkingDirectory: { get: () => openCodeWorkingDirectory, set: (value) => { openCodeWorkingDirectory = value; } },
|
|
876
|
+
currentRestartPromise: { get: () => currentRestartPromise, set: (value) => { currentRestartPromise = value; } },
|
|
877
|
+
isRestartingOpenCode: { get: () => isRestartingOpenCode, set: (value) => { isRestartingOpenCode = value; } },
|
|
878
|
+
openCodeApiPrefix: { get: () => openCodeApiPrefix, set: (value) => { openCodeApiPrefix = value; } },
|
|
879
|
+
openCodeApiPrefixDetected: { get: () => openCodeApiPrefixDetected, set: (value) => { openCodeApiPrefixDetected = value; } },
|
|
880
|
+
openCodeApiDetectionTimer: { get: () => openCodeApiDetectionTimer, set: (value) => { openCodeApiDetectionTimer = value; } },
|
|
881
|
+
lastOpenCodeError: { get: () => lastOpenCodeError, set: (value) => { lastOpenCodeError = value; } },
|
|
882
|
+
lastOpenCodeLaunchDiagnostics: { get: () => lastOpenCodeLaunchDiagnostics, set: (value) => { lastOpenCodeLaunchDiagnostics = value; } },
|
|
883
|
+
isOpenCodeReady: { get: () => isOpenCodeReady, set: (value) => { isOpenCodeReady = value; } },
|
|
884
|
+
openCodeNotReadySince: { get: () => openCodeNotReadySince, set: (value) => { openCodeNotReadySince = value; } },
|
|
885
|
+
isExternalOpenCode: { get: () => isExternalOpenCode, set: (value) => { isExternalOpenCode = value; } },
|
|
886
|
+
isShuttingDown: { get: () => isShuttingDown, set: (value) => { isShuttingDown = value; } },
|
|
887
|
+
healthCheckInterval: { get: () => healthCheckInterval, set: (value) => { healthCheckInterval = value; } },
|
|
888
|
+
expressApp: { get: () => expressApp, set: (value) => { expressApp = value; } },
|
|
889
|
+
useWslForOpencode: { get: () => useWslForOpencode, set: (value) => { useWslForOpencode = value; } },
|
|
890
|
+
resolvedWslBinary: { get: () => resolvedWslBinary, set: (value) => { resolvedWslBinary = value; } },
|
|
891
|
+
resolvedWslOpencodePath: { get: () => resolvedWslOpencodePath, set: (value) => { resolvedWslOpencodePath = value; } },
|
|
892
|
+
resolvedWslDistro: { get: () => resolvedWslDistro, set: (value) => { resolvedWslDistro = value; } },
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
const openCodeLifecycleRuntime = createOpenCodeLifecycleRuntime({
|
|
896
|
+
state: openCodeLifecycleState,
|
|
897
|
+
env: {
|
|
898
|
+
ENV_CONFIGURED_OPENCODE_PORT,
|
|
899
|
+
ENV_CONFIGURED_OPENCODE_HOST,
|
|
900
|
+
ENV_EFFECTIVE_PORT,
|
|
901
|
+
ENV_CONFIGURED_OPENCODE_HOSTNAME,
|
|
902
|
+
ENV_SKIP_OPENCODE_START,
|
|
903
|
+
},
|
|
904
|
+
syncToHmrState,
|
|
905
|
+
syncFromHmrState,
|
|
906
|
+
getOpenCodeAuthHeaders,
|
|
907
|
+
buildOpenCodeUrl,
|
|
908
|
+
waitForReady,
|
|
909
|
+
normalizeApiPrefix,
|
|
910
|
+
applyOpencodeBinaryFromSettings,
|
|
911
|
+
ensureOpencodeCliEnv,
|
|
912
|
+
ensureLocalOpenCodeServerPassword,
|
|
913
|
+
buildWslExecArgs,
|
|
914
|
+
resolveWslExecutablePath,
|
|
915
|
+
resolveManagedOpenCodeLaunchSpec,
|
|
916
|
+
setOpenCodePort,
|
|
917
|
+
setDetectedOpenCodeApiPrefix,
|
|
918
|
+
setupProxy: (...args) => setupProxy(...args),
|
|
919
|
+
ensureOpenCodeApiPrefix,
|
|
920
|
+
clearResolvedOpenCodeBinary,
|
|
921
|
+
buildAugmentedPath,
|
|
922
|
+
buildManagedOpenCodePath,
|
|
923
|
+
getManagedOpenCodeShellEnvSnapshot: getLoginShellEnvSnapshot,
|
|
924
|
+
getActiveSessionCount,
|
|
925
|
+
readSettingsFromDiskMigrated,
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
const restartOpenCode = (...args) => openCodeLifecycleRuntime.restartOpenCode(...args);
|
|
929
|
+
const waitForOpenCodeReady = (...args) => openCodeLifecycleRuntime.waitForOpenCodeReady(...args);
|
|
930
|
+
const waitForAgentPresence = (...args) => openCodeLifecycleRuntime.waitForAgentPresence(...args);
|
|
931
|
+
const refreshOpenCodeAfterConfigChange = (...args) => openCodeLifecycleRuntime.refreshOpenCodeAfterConfigChange(...args);
|
|
932
|
+
const startHealthMonitoring = () => openCodeLifecycleRuntime.startHealthMonitoring(HEALTH_CHECK_INTERVAL);
|
|
933
|
+
const triggerHealthCheck = () => openCodeLifecycleRuntime.triggerHealthCheck();
|
|
934
|
+
const scheduledTasksRuntime = createScheduledTasksRuntime({
|
|
935
|
+
projectConfigRuntime,
|
|
936
|
+
listProjects: async () => {
|
|
937
|
+
const settings = await readSettingsFromDiskMigrated();
|
|
938
|
+
return sanitizeProjects(settings?.projects || []);
|
|
939
|
+
},
|
|
940
|
+
buildOpenCodeUrl,
|
|
941
|
+
getOpenCodeAuthHeaders,
|
|
942
|
+
waitForOpenCodeReady,
|
|
943
|
+
emitTaskRunEvent: (event) => {
|
|
944
|
+
for (const client of uiVinciEventClients) {
|
|
945
|
+
try {
|
|
946
|
+
writeSseEvent(client, {
|
|
947
|
+
type: 'vinci:scheduled-task-ran',
|
|
948
|
+
properties: {
|
|
949
|
+
projectId: event.projectID,
|
|
950
|
+
taskId: event.taskID,
|
|
951
|
+
ranAt: event.ranAt,
|
|
952
|
+
status: event.status,
|
|
953
|
+
...(event.sessionID ? { sessionId: event.sessionID } : {}),
|
|
954
|
+
},
|
|
955
|
+
});
|
|
956
|
+
} catch {
|
|
957
|
+
uiVinciEventClients.delete(client);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
},
|
|
961
|
+
logger: console,
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
const ensureGlobalWatcherStarted = async () => {
|
|
965
|
+
if (globalWatcherStartPromise) {
|
|
966
|
+
return globalWatcherStartPromise;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
globalWatcherStartPromise = openCodeWatcherRuntime.start().catch((error) => {
|
|
970
|
+
globalWatcherStartPromise = null;
|
|
971
|
+
throw error;
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
return globalWatcherStartPromise;
|
|
975
|
+
};
|
|
976
|
+
const bootstrapOpenCodeAtStartup = async (...args) => {
|
|
977
|
+
await openCodeLifecycleRuntime.bootstrapOpenCodeAtStartup(...args);
|
|
978
|
+
scheduleOpenCodeApiDetection();
|
|
979
|
+
if (openCodeLifecycleState.openCodeProcess && !openCodeLifecycleState.isExternalOpenCode) {
|
|
980
|
+
startHealthMonitoring();
|
|
981
|
+
}
|
|
982
|
+
if (ENV_DESKTOP_NOTIFY) {
|
|
983
|
+
void ensureGlobalWatcherStarted().catch((error) => {
|
|
984
|
+
console.warn(`Global event watcher startup failed: ${error?.message || error}`);
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
};
|
|
988
|
+
const killProcessOnPort = (...args) => openCodeLifecycleRuntime.killProcessOnPort(...args);
|
|
989
|
+
const waitForPortRelease = (...args) => openCodeLifecycleRuntime.waitForPortRelease(...args);
|
|
990
|
+
|
|
991
|
+
const fetchAgentsSnapshot = (...args) => serverUtilsRuntime.fetchAgentsSnapshot(...args);
|
|
992
|
+
const fetchProvidersSnapshot = (...args) => serverUtilsRuntime.fetchProvidersSnapshot(...args);
|
|
993
|
+
const fetchModelsSnapshot = (...args) => serverUtilsRuntime.fetchModelsSnapshot(...args);
|
|
994
|
+
const setupProxy = (...args) => serverUtilsRuntime.setupProxy(...args);
|
|
995
|
+
const gracefulShutdownRuntime = createGracefulShutdownRuntime({
|
|
996
|
+
process,
|
|
997
|
+
shutdownTimeoutMs: SHUTDOWN_TIMEOUT,
|
|
998
|
+
getExitOnShutdown: () => exitOnShutdown,
|
|
999
|
+
getIsShuttingDown: () => isShuttingDown,
|
|
1000
|
+
setIsShuttingDown: (value) => {
|
|
1001
|
+
isShuttingDown = value;
|
|
1002
|
+
},
|
|
1003
|
+
syncToHmrState,
|
|
1004
|
+
openCodeWatcherRuntime,
|
|
1005
|
+
sessionRuntime,
|
|
1006
|
+
getHealthCheckInterval: () => healthCheckInterval,
|
|
1007
|
+
clearHealthCheckInterval: (value) => clearInterval(value),
|
|
1008
|
+
getTerminalRuntime: () => terminalRuntime,
|
|
1009
|
+
setTerminalRuntime: (value) => {
|
|
1010
|
+
terminalRuntime = value;
|
|
1011
|
+
},
|
|
1012
|
+
getMessageStreamRuntime: () => messageStreamRuntime,
|
|
1013
|
+
setMessageStreamRuntime: (value) => {
|
|
1014
|
+
messageStreamRuntime = value;
|
|
1015
|
+
},
|
|
1016
|
+
shouldSkipOpenCodeStop: () => ENV_SKIP_OPENCODE_START || isExternalOpenCode,
|
|
1017
|
+
getOpenCodePort: () => openCodePort,
|
|
1018
|
+
getOpenCodeProcess: () => openCodeProcess,
|
|
1019
|
+
setOpenCodeProcess: (value) => {
|
|
1020
|
+
openCodeProcess = value;
|
|
1021
|
+
},
|
|
1022
|
+
killProcessOnPort,
|
|
1023
|
+
waitForPortRelease,
|
|
1024
|
+
getServer: () => server,
|
|
1025
|
+
getUiAuthController: () => uiAuthController,
|
|
1026
|
+
setUiAuthController: (value) => {
|
|
1027
|
+
uiAuthController = value;
|
|
1028
|
+
},
|
|
1029
|
+
getActiveTunnelController: () => activeTunnelController,
|
|
1030
|
+
setActiveTunnelController: (value) => {
|
|
1031
|
+
activeTunnelController = value;
|
|
1032
|
+
},
|
|
1033
|
+
tunnelAuthController,
|
|
1034
|
+
scheduledTasksRuntime,
|
|
1035
|
+
});
|
|
1036
|
+
|
|
1037
|
+
const gracefulShutdown = (...args) => gracefulShutdownRuntime.gracefulShutdown(...args);
|
|
1038
|
+
|
|
1039
|
+
async function main(options = {}) {
|
|
1040
|
+
const port = Number.isFinite(options.port) && options.port >= 0 ? Math.trunc(options.port) : DEFAULT_PORT;
|
|
1041
|
+
const host = typeof options.host === 'string' && options.host.length > 0 ? options.host : undefined;
|
|
1042
|
+
const tryCfTunnel = options.tryCfTunnel === true;
|
|
1043
|
+
const shouldUseCanonicalTunnelConfig = typeof options.tunnelMode === 'string'
|
|
1044
|
+
|| typeof options.tunnelProvider === 'string'
|
|
1045
|
+
|| options.tunnelConfigPath === null
|
|
1046
|
+
|| typeof options.tunnelConfigPath === 'string'
|
|
1047
|
+
|| typeof options.tunnelToken === 'string'
|
|
1048
|
+
|| typeof options.tunnelHostname === 'string';
|
|
1049
|
+
const startupTunnelRequest = shouldUseCanonicalTunnelConfig
|
|
1050
|
+
? normalizeTunnelStartRequest({
|
|
1051
|
+
provider: normalizeTunnelProvider(options.tunnelProvider),
|
|
1052
|
+
mode: options.tunnelMode,
|
|
1053
|
+
configPath: normalizeOptionalPath(options.tunnelConfigPath),
|
|
1054
|
+
token: typeof options.tunnelToken === 'string' ? options.tunnelToken.trim() : '',
|
|
1055
|
+
hostname: normalizeManagedRemoteTunnelHostname(options.tunnelHostname),
|
|
1056
|
+
})
|
|
1057
|
+
: (tryCfTunnel
|
|
1058
|
+
? {
|
|
1059
|
+
provider: TUNNEL_PROVIDER_CLOUDFLARE,
|
|
1060
|
+
mode: TUNNEL_MODE_QUICK,
|
|
1061
|
+
configPath: undefined,
|
|
1062
|
+
token: '',
|
|
1063
|
+
hostname: undefined,
|
|
1064
|
+
}
|
|
1065
|
+
: null);
|
|
1066
|
+
const attachSignals = options.attachSignals !== false;
|
|
1067
|
+
const onTunnelReady = typeof options.onTunnelReady === 'function' ? options.onTunnelReady : null;
|
|
1068
|
+
if (typeof options.exitOnShutdown === 'boolean') {
|
|
1069
|
+
exitOnShutdown = options.exitOnShutdown;
|
|
1070
|
+
}
|
|
1071
|
+
if (typeof options.onDesktopNotification === 'function') {
|
|
1072
|
+
notificationEmitterRuntime.setOnDesktopNotification(options.onDesktopNotification);
|
|
1073
|
+
}
|
|
1074
|
+
if (typeof options.getIsWindowFocused === 'function') {
|
|
1075
|
+
notificationTriggerRuntime.setGetIsWindowFocused(options.getIsWindowFocused);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
console.log(`Starting Vinci on port ${port === 0 ? 'auto' : port}`);
|
|
1079
|
+
|
|
1080
|
+
const sayTTSCapability = await detectSayTtsCapability(process);
|
|
1081
|
+
|
|
1082
|
+
const app = express();
|
|
1083
|
+
const serverStartedAt = new Date().toISOString();
|
|
1084
|
+
app.set('trust proxy', true);
|
|
1085
|
+
app.use(compression({
|
|
1086
|
+
filter: (req, res) => {
|
|
1087
|
+
if (shouldSkipCompression(req, res)) return false;
|
|
1088
|
+
return compression.filter(req, res);
|
|
1089
|
+
},
|
|
1090
|
+
threshold: 1024,
|
|
1091
|
+
}));
|
|
1092
|
+
expressApp = app;
|
|
1093
|
+
server = http.createServer(app);
|
|
1094
|
+
|
|
1095
|
+
const uiPassword = typeof options.uiPassword === 'string' ? options.uiPassword : null;
|
|
1096
|
+
const bootstrapResult = bootstrapRuntime.setupBaseRoutes(app, {
|
|
1097
|
+
process,
|
|
1098
|
+
vinciVersion: VINCI_VERSION,
|
|
1099
|
+
runtimeName: process.env.VINCI_RUNTIME || 'web',
|
|
1100
|
+
serverStartedAt,
|
|
1101
|
+
gracefulShutdown,
|
|
1102
|
+
getHealthSnapshot: () => {
|
|
1103
|
+
const launchSpec = resolvedOpencodeBinary && !useWslForOpencode
|
|
1104
|
+
? resolveManagedOpenCodeLaunchSpec(resolvedOpencodeBinary)
|
|
1105
|
+
: null;
|
|
1106
|
+
return {
|
|
1107
|
+
openCodePort,
|
|
1108
|
+
openCodeRunning: Boolean(openCodePort && isOpenCodeReady && !isRestartingOpenCode),
|
|
1109
|
+
openCodeSecureConnection: isOpenCodeConnectionSecure(),
|
|
1110
|
+
openCodeAuthSource: openCodeAuthSource || null,
|
|
1111
|
+
openCodeApiPrefix: '',
|
|
1112
|
+
openCodeApiPrefixDetected: true,
|
|
1113
|
+
isOpenCodeReady,
|
|
1114
|
+
lastOpenCodeError,
|
|
1115
|
+
lastOpenCodeLaunchDiagnostics,
|
|
1116
|
+
opencodeBinaryResolved: resolvedOpencodeBinary || null,
|
|
1117
|
+
opencodeBinarySource: resolvedOpencodeBinarySource || null,
|
|
1118
|
+
opencodeLaunchBinary: launchSpec?.binary || null,
|
|
1119
|
+
opencodeLaunchArgs: launchSpec?.args || [],
|
|
1120
|
+
opencodeLaunchWrapperType: launchSpec?.wrapperType || null,
|
|
1121
|
+
opencodeViaWsl: useWslForOpencode,
|
|
1122
|
+
opencodeWslBinary: resolvedWslBinary || null,
|
|
1123
|
+
opencodeWslPath: resolvedWslOpencodePath || null,
|
|
1124
|
+
opencodeWslDistro: resolvedWslDistro || null,
|
|
1125
|
+
nodeBinaryResolved: resolvedNodeBinary || null,
|
|
1126
|
+
bunBinaryResolved: resolvedBunBinary || null,
|
|
1127
|
+
desktopNotifyEnabled: ENV_DESKTOP_NOTIFY,
|
|
1128
|
+
planModeExperimentalEnabled: PLAN_MODE_EXPERIMENT_ENABLED,
|
|
1129
|
+
};
|
|
1130
|
+
},
|
|
1131
|
+
verboseRequestLogs: VINCI_VERBOSE_REQUEST_LOGS,
|
|
1132
|
+
uiPassword,
|
|
1133
|
+
tunnelAuthController,
|
|
1134
|
+
readSettingsFromDiskMigrated,
|
|
1135
|
+
normalizeTunnelSessionTtlMs,
|
|
1136
|
+
sayTTSCapability,
|
|
1137
|
+
ensurePushInitialized,
|
|
1138
|
+
ensureGlobalWatcherStarted,
|
|
1139
|
+
getOrCreateVapidKeys,
|
|
1140
|
+
getUiSessionTokenFromRequest,
|
|
1141
|
+
writeSettingsToDisk,
|
|
1142
|
+
addOrUpdatePushSubscription,
|
|
1143
|
+
removePushSubscription,
|
|
1144
|
+
updateUiVisibility,
|
|
1145
|
+
isUiVisible,
|
|
1146
|
+
getUiNotificationClients: () => uiNotificationClients,
|
|
1147
|
+
writeSseEvent,
|
|
1148
|
+
sessionRuntime,
|
|
1149
|
+
setPushInitialized,
|
|
1150
|
+
fs,
|
|
1151
|
+
os,
|
|
1152
|
+
path,
|
|
1153
|
+
server,
|
|
1154
|
+
__dirname,
|
|
1155
|
+
vinciDataDir: VINCI_DATA_DIR,
|
|
1156
|
+
modelsDevApiUrl: MODELS_DEV_API_URL,
|
|
1157
|
+
modelsMetadataCacheTtl: MODELS_METADATA_CACHE_TTL,
|
|
1158
|
+
fetchFreeZenModels,
|
|
1159
|
+
getCachedZenModels,
|
|
1160
|
+
setAutoAcceptSession,
|
|
1161
|
+
});
|
|
1162
|
+
uiAuthController = bootstrapResult.uiAuthController;
|
|
1163
|
+
|
|
1164
|
+
const tunnelRuntimeContext = tunnelWiringRuntime.initialize(app, port);
|
|
1165
|
+
const { tunnelService, startTunnelWithNormalizedRequest } = tunnelRuntimeContext;
|
|
1166
|
+
|
|
1167
|
+
await featureRoutesRuntime.registerRoutes(app, {
|
|
1168
|
+
crypto,
|
|
1169
|
+
fs,
|
|
1170
|
+
os,
|
|
1171
|
+
path,
|
|
1172
|
+
fsPromises,
|
|
1173
|
+
spawn,
|
|
1174
|
+
resolveGitBinaryForSpawn,
|
|
1175
|
+
createFsSearchRuntime: createFsSearchRuntimeFactory,
|
|
1176
|
+
vinciDataDir: VINCI_DATA_DIR,
|
|
1177
|
+
vinciUserConfigRoot: VINCI_USER_CONFIG_ROOT,
|
|
1178
|
+
normalizeDirectoryPath,
|
|
1179
|
+
resolveProjectDirectory,
|
|
1180
|
+
resolveOptionalProjectDirectory,
|
|
1181
|
+
validateDirectoryPath,
|
|
1182
|
+
readCustomThemesFromDisk,
|
|
1183
|
+
refreshOpenCodeAfterConfigChange,
|
|
1184
|
+
getOpenCodeResolutionSnapshot,
|
|
1185
|
+
formatSettingsResponse,
|
|
1186
|
+
readSettingsFromDisk,
|
|
1187
|
+
readSettingsFromDiskMigrated,
|
|
1188
|
+
persistSettings,
|
|
1189
|
+
sanitizeProjects,
|
|
1190
|
+
sanitizeSkillCatalogs,
|
|
1191
|
+
isUnsafeSkillRelativePath,
|
|
1192
|
+
buildOpenCodeUrl,
|
|
1193
|
+
getOpenCodeAuthHeaders,
|
|
1194
|
+
getOpenCodePort: () => openCodePort,
|
|
1195
|
+
buildAugmentedPath,
|
|
1196
|
+
projectConfigRuntime,
|
|
1197
|
+
scheduledTasksRuntime,
|
|
1198
|
+
getVinciEventClients: () => uiVinciEventClients,
|
|
1199
|
+
writeSseEvent,
|
|
1200
|
+
});
|
|
1201
|
+
|
|
1202
|
+
const previewProxyRuntime = createPreviewProxyRuntime({
|
|
1203
|
+
crypto,
|
|
1204
|
+
URL,
|
|
1205
|
+
createProxyMiddleware,
|
|
1206
|
+
responseInterceptor,
|
|
1207
|
+
});
|
|
1208
|
+
previewProxyRuntime.attach(app, {
|
|
1209
|
+
server,
|
|
1210
|
+
express,
|
|
1211
|
+
uiAuthController,
|
|
1212
|
+
isRequestOriginAllowed,
|
|
1213
|
+
rejectWebSocketUpgrade,
|
|
1214
|
+
});
|
|
1215
|
+
|
|
1216
|
+
const startupPipelineResult = await startupPipelineRuntime.run({
|
|
1217
|
+
app,
|
|
1218
|
+
server,
|
|
1219
|
+
express,
|
|
1220
|
+
fs,
|
|
1221
|
+
path,
|
|
1222
|
+
uiAuthController,
|
|
1223
|
+
buildAugmentedPath,
|
|
1224
|
+
searchPathFor,
|
|
1225
|
+
isExecutable,
|
|
1226
|
+
isRequestOriginAllowed,
|
|
1227
|
+
rejectWebSocketUpgrade,
|
|
1228
|
+
buildOpenCodeUrl,
|
|
1229
|
+
getOpenCodeAuthHeaders,
|
|
1230
|
+
globalEventHub: globalMessageStreamHub,
|
|
1231
|
+
processForwardedEventPayload,
|
|
1232
|
+
messageStreamWsClients: uiNotificationWsClients,
|
|
1233
|
+
upstreamStallTimeoutMs: getUpstreamStallTimeoutMs,
|
|
1234
|
+
terminalHeartbeatIntervalMs: TERMINAL_INPUT_WS_HEARTBEAT_INTERVAL_MS,
|
|
1235
|
+
terminalRebindWindowMs: TERMINAL_INPUT_WS_REBIND_WINDOW_MS,
|
|
1236
|
+
terminalMaxRebindsPerWindow: TERMINAL_INPUT_WS_MAX_REBINDS_PER_WINDOW,
|
|
1237
|
+
setupProxy,
|
|
1238
|
+
scheduleOpenCodeApiDetection,
|
|
1239
|
+
bootstrapOpenCodeAtStartup,
|
|
1240
|
+
triggerHealthCheck,
|
|
1241
|
+
staticRoutesRuntime,
|
|
1242
|
+
process,
|
|
1243
|
+
crypto,
|
|
1244
|
+
normalizeTunnelBootstrapTtlMs,
|
|
1245
|
+
readSettingsFromDiskMigrated,
|
|
1246
|
+
tunnelAuthController,
|
|
1247
|
+
startTunnelWithNormalizedRequest,
|
|
1248
|
+
gracefulShutdown,
|
|
1249
|
+
getSignalsAttached: () => signalsAttached,
|
|
1250
|
+
setSignalsAttached: (value) => {
|
|
1251
|
+
signalsAttached = value;
|
|
1252
|
+
},
|
|
1253
|
+
syncToHmrState,
|
|
1254
|
+
TUNNEL_MODE_QUICK,
|
|
1255
|
+
TUNNEL_MODE_MANAGED_LOCAL,
|
|
1256
|
+
TUNNEL_MODE_MANAGED_REMOTE,
|
|
1257
|
+
host,
|
|
1258
|
+
port,
|
|
1259
|
+
startupTunnelRequest,
|
|
1260
|
+
onTunnelReady,
|
|
1261
|
+
tunnelRuntimeContext,
|
|
1262
|
+
attachSignals,
|
|
1263
|
+
});
|
|
1264
|
+
terminalRuntime = startupPipelineResult.terminalRuntime;
|
|
1265
|
+
messageStreamRuntime = startupPipelineResult.messageStreamRuntime;
|
|
1266
|
+
|
|
1267
|
+
try {
|
|
1268
|
+
await scheduledTasksRuntime.start();
|
|
1269
|
+
} catch (error) {
|
|
1270
|
+
console.warn('[ScheduledTasks] Failed to start runtime:', error?.message || error);
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
return {
|
|
1274
|
+
expressApp: app,
|
|
1275
|
+
httpServer: server,
|
|
1276
|
+
getPort: () => tunnelRuntimeContext.getActivePort(),
|
|
1277
|
+
getOpenCodePort: () => openCodePort,
|
|
1278
|
+
getTunnelUrl: () => tunnelService.getPublicUrl(),
|
|
1279
|
+
getQuitRiskStatus: () => ({
|
|
1280
|
+
tunnel: {
|
|
1281
|
+
active: Boolean(tunnelService.getPublicUrl()),
|
|
1282
|
+
},
|
|
1283
|
+
scheduledTasks: scheduledTasksRuntime.getStatus(),
|
|
1284
|
+
}),
|
|
1285
|
+
isReady: () => isOpenCodeReady,
|
|
1286
|
+
restartOpenCode: () => restartOpenCode(),
|
|
1287
|
+
stop: (shutdownOptions = {}) =>
|
|
1288
|
+
gracefulShutdown({ exitProcess: shutdownOptions.exitProcess ?? false })
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
runCliEntryIfMain({
|
|
1293
|
+
process,
|
|
1294
|
+
currentFilename: __filename,
|
|
1295
|
+
parseServeCliOptions,
|
|
1296
|
+
defaultPort: DEFAULT_PORT,
|
|
1297
|
+
cloudflareProvider: TUNNEL_PROVIDER_CLOUDFLARE,
|
|
1298
|
+
managedLocalMode: TUNNEL_MODE_MANAGED_LOCAL,
|
|
1299
|
+
setExitOnShutdown: (value) => {
|
|
1300
|
+
exitOnShutdown = value;
|
|
1301
|
+
},
|
|
1302
|
+
startServer: main,
|
|
1303
|
+
});
|
|
1304
|
+
|
|
1305
|
+
export {
|
|
1306
|
+
gracefulShutdown,
|
|
1307
|
+
setupProxy,
|
|
1308
|
+
restartOpenCode,
|
|
1309
|
+
main as startWebUiServer,
|
|
1310
|
+
parseServeCliOptions as parseArgs,
|
|
1311
|
+
};
|