@dyyz1993/codenomad 0.15.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 +173 -0
- package/dist/api-types.js +1 -0
- package/dist/auth/auth-store.js +134 -0
- package/dist/auth/http-auth.js +37 -0
- package/dist/auth/manager.js +140 -0
- package/dist/auth/password-hash.js +32 -0
- package/dist/auth/session-manager.js +17 -0
- package/dist/auth/token-manager.js +27 -0
- package/dist/background-processes/manager.js +576 -0
- package/dist/bin.js +24 -0
- package/dist/cli-upgrade.js +53 -0
- package/dist/cli-upgrade.test.js +31 -0
- package/dist/clients/connection-manager.js +93 -0
- package/dist/config/location.js +57 -0
- package/dist/config/schema.js +71 -0
- package/dist/events/bus.js +45 -0
- package/dist/filesystem/__tests__/browser.test.js +65 -0
- package/dist/filesystem/__tests__/search-cache.test.js +40 -0
- package/dist/filesystem/browser.js +306 -0
- package/dist/filesystem/search-cache.js +43 -0
- package/dist/filesystem/search.js +135 -0
- package/dist/index.js +477 -0
- package/dist/launcher.js +149 -0
- package/dist/loader.js +21 -0
- package/dist/logger.js +109 -0
- package/dist/opencode-config/README.md +32 -0
- package/dist/opencode-config/opencode.jsonc +3 -0
- package/dist/opencode-config/package-lock.json +380 -0
- package/dist/opencode-config/package.json +9 -0
- package/dist/opencode-config/plugin/codenomad.ts +62 -0
- package/dist/opencode-config/plugin/lib/background-process.ts +265 -0
- package/dist/opencode-config/plugin/lib/client.ts +133 -0
- package/dist/opencode-config/plugin/lib/request.ts +214 -0
- package/dist/opencode-config.js +26 -0
- package/dist/plugins/channel.js +40 -0
- package/dist/plugins/handlers.js +17 -0
- package/dist/plugins/voice-mode.js +78 -0
- package/dist/releases/dev-release-monitor.js +75 -0
- package/dist/releases/release-monitor.js +107 -0
- package/dist/server/__tests__/network-addresses.test.js +68 -0
- package/dist/server/__tests__/remote-proxy.test.js +204 -0
- package/dist/server/http-server.js +926 -0
- package/dist/server/network-addresses.js +114 -0
- package/dist/server/remote-proxy.js +466 -0
- package/dist/server/routes/auth-pages/login.html +135 -0
- package/dist/server/routes/auth-pages/token.html +93 -0
- package/dist/server/routes/auth.js +148 -0
- package/dist/server/routes/background-processes.js +78 -0
- package/dist/server/routes/events.js +66 -0
- package/dist/server/routes/filesystem.js +43 -0
- package/dist/server/routes/meta.js +44 -0
- package/dist/server/routes/plugin.js +70 -0
- package/dist/server/routes/remote-proxy.js +42 -0
- package/dist/server/routes/remote-servers.js +142 -0
- package/dist/server/routes/settings.js +69 -0
- package/dist/server/routes/sidecars.js +46 -0
- package/dist/server/routes/speech.js +63 -0
- package/dist/server/routes/storage.js +52 -0
- package/dist/server/routes/workspaces.js +221 -0
- package/dist/server/routes/worktrees.js +156 -0
- package/dist/server/tls.js +224 -0
- package/dist/settings/binaries.js +37 -0
- package/dist/settings/merge-patch.js +33 -0
- package/dist/settings/migrate.js +238 -0
- package/dist/settings/public-config.js +33 -0
- package/dist/settings/service.js +101 -0
- package/dist/settings/yaml-doc-store.js +96 -0
- package/dist/sidecars/manager.js +193 -0
- package/dist/speech/providers/openai-compatible.js +189 -0
- package/dist/speech/service.js +58 -0
- package/dist/storage/instance-store.js +56 -0
- package/dist/ui/__tests__/remote-ui.test.js +67 -0
- package/dist/ui/remote-ui.js +462 -0
- package/dist/workspaces/__tests__/git-worktrees.test.js +43 -0
- package/dist/workspaces/__tests__/spawn.test.js +140 -0
- package/dist/workspaces/git-mutations.js +98 -0
- package/dist/workspaces/git-status.js +323 -0
- package/dist/workspaces/git-worktrees.js +216 -0
- package/dist/workspaces/instance-events.js +180 -0
- package/dist/workspaces/manager.js +368 -0
- package/dist/workspaces/opencode-auth.js +34 -0
- package/dist/workspaces/opencode-auth.test.js +34 -0
- package/dist/workspaces/runtime.js +366 -0
- package/dist/workspaces/spawn.js +219 -0
- package/dist/workspaces/worktree-directory.js +74 -0
- package/dist/workspaces/worktree-map.js +116 -0
- package/package.json +50 -0
- package/public/apple-touch-icon-180x180.png +0 -0
- package/public/assets/ChangesTab-BRNmSjeC.js +2 -0
- package/public/assets/CodeNomad-Icon-bmTWNPXy.png +0 -0
- package/public/assets/DiffToolbar-DPPgfx42.js +1 -0
- package/public/assets/FilesTab-sEeGPOoz.js +2 -0
- package/public/assets/GitChangesTab-tJ-TCq0c.js +2 -0
- package/public/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/public/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/public/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/public/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/public/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/public/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/public/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/public/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/public/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/public/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/public/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/public/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/public/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/public/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/public/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/public/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/public/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/public/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/public/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/public/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/public/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/public/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/public/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/public/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/public/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/public/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/public/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/public/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/public/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/public/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/public/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/public/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/public/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/public/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/public/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/public/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/public/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/public/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/public/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/public/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/public/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/public/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/public/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/public/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/public/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/public/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/public/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/public/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/public/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/public/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/public/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/public/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/public/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/public/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/public/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/public/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/public/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/public/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/public/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/public/assets/SplitFilePanel-CHqNLZvU.js +1 -0
- package/public/assets/StatusTab-DMd0ByCA.js +1 -0
- package/public/assets/abap-BdImnpbu.js +1 -0
- package/public/assets/actionscript-3-CfeIJUat.js +1 -0
- package/public/assets/ada-bCR0ucgS.js +1 -0
- package/public/assets/align-justify-BWapkGTe.js +1 -0
- package/public/assets/andromeeda-C-Jbm3Hp.js +1 -0
- package/public/assets/angular-html-CU67Zn6k.js +1 -0
- package/public/assets/angular-ts-BwZT4LLn.js +1 -0
- package/public/assets/apache-Pmp26Uib.js +1 -0
- package/public/assets/apex-DhZLUxFE.js +1 -0
- package/public/assets/apl-dKokRX4l.js +1 -0
- package/public/assets/applescript-Co6uUVPk.js +1 -0
- package/public/assets/ara-BRHolxvo.js +1 -0
- package/public/assets/asciidoc-Dv7Oe6Be.js +1 -0
- package/public/assets/asm-D_Q5rh1f.js +1 -0
- package/public/assets/astro-CbQHKStN.js +1 -0
- package/public/assets/aurora-x-D-2ljcwZ.js +1 -0
- package/public/assets/awk-DMzUqQB5.js +1 -0
- package/public/assets/ayu-dark-Cv9koXgw.js +1 -0
- package/public/assets/ballerina-BFfxhgS-.js +1 -0
- package/public/assets/bat-BkioyH1T.js +1 -0
- package/public/assets/beancount-k_qm7-4y.js +1 -0
- package/public/assets/berry-D08WgyRC.js +1 -0
- package/public/assets/bibtex-CHM0blh-.js +1 -0
- package/public/assets/bicep-Bmn6On1c.js +1 -0
- package/public/assets/blade-DVc8C-J4.js +1 -0
- package/public/assets/bsl-BO_Y6i37.js +1 -0
- package/public/assets/bundle-full-CXlKQh5B.js +13 -0
- package/public/assets/c-BIGW1oBm.js +1 -0
- package/public/assets/cadence-Bv_4Rxtq.js +1 -0
- package/public/assets/cairo-KRGpt6FW.js +1 -0
- package/public/assets/catppuccin-frappe-DFWUc33u.js +1 -0
- package/public/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
- package/public/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
- package/public/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
- package/public/assets/clarity-D53aC0YG.js +1 -0
- package/public/assets/clojure-P80f7IUj.js +1 -0
- package/public/assets/cmake-D1j8_8rp.js +1 -0
- package/public/assets/cobol-nwyudZeR.js +1 -0
- package/public/assets/codeowners-Bp6g37R7.js +1 -0
- package/public/assets/codeql-DsOJ9woJ.js +1 -0
- package/public/assets/coffee-Ch7k5sss.js +1 -0
- package/public/assets/common-lisp-Cg-RD9OK.js +1 -0
- package/public/assets/coq-DkFqJrB1.js +1 -0
- package/public/assets/cpp-CofmeUqb.js +1 -0
- package/public/assets/crystal-tKQVLTB8.js +1 -0
- package/public/assets/csharp-CX12Zw3r.js +1 -0
- package/public/assets/css-DPfMkruS.js +1 -0
- package/public/assets/csv-fuZLfV_i.js +1 -0
- package/public/assets/cue-D82EKSYY.js +1 -0
- package/public/assets/cypher-COkxafJQ.js +1 -0
- package/public/assets/d-85-TOEBH.js +1 -0
- package/public/assets/dark-plus-eOWES_5F.js +1 -0
- package/public/assets/dart-CF10PKvl.js +1 -0
- package/public/assets/dax-CEL-wOlO.js +1 -0
- package/public/assets/desktop-BmXAJ9_W.js +1 -0
- package/public/assets/diff-D97Zzqfu.js +1 -0
- package/public/assets/diff-viewer-BFtW5J8P.js +1 -0
- package/public/assets/docker-BcOcwvcX.js +1 -0
- package/public/assets/dotenv-Da5cRb03.js +1 -0
- package/public/assets/dracula-BzJJZx-M.js +1 -0
- package/public/assets/dracula-soft-BXkSAIEj.js +1 -0
- package/public/assets/dream-maker-BtqSS_iP.js +1 -0
- package/public/assets/edge-BkV0erSs.js +1 -0
- package/public/assets/elixir-CDX3lj18.js +1 -0
- package/public/assets/elm-DbKCFpqz.js +1 -0
- package/public/assets/emacs-lisp-C9XAeP06.js +1 -0
- package/public/assets/erb-BOJIQeun.js +1 -0
- package/public/assets/erlang-DsQrWhSR.js +1 -0
- package/public/assets/everforest-dark-BgDCqdQA.js +1 -0
- package/public/assets/everforest-light-C8M2exoo.js +1 -0
- package/public/assets/fast-diff-vendor-DgdwVvTQ.js +1 -0
- package/public/assets/fennel-BYunw83y.js +1 -0
- package/public/assets/fish-BvzEVeQv.js +1 -0
- package/public/assets/fluent-C4IJs8-o.js +1 -0
- package/public/assets/fortran-fixed-form-BZjJHVRy.js +1 -0
- package/public/assets/fortran-free-form-D22FLkUw.js +1 -0
- package/public/assets/fsharp-CXgrBDvD.js +1 -0
- package/public/assets/gdresource-B7Tvp0Sc.js +1 -0
- package/public/assets/gdscript-DTMYz4Jt.js +1 -0
- package/public/assets/gdshader-DkwncUOv.js +1 -0
- package/public/assets/genie-D0YGMca9.js +1 -0
- package/public/assets/gherkin-DyxjwDmM.js +1 -0
- package/public/assets/git-commit-F4YmCXRG.js +1 -0
- package/public/assets/git-diff-vendor-CSgooKT_.js +52 -0
- package/public/assets/git-diff-vendor-HAZkIolJ.css +19 -0
- package/public/assets/git-rebase-r7XF79zn.js +1 -0
- package/public/assets/github-dark-DHJKELXO.js +1 -0
- package/public/assets/github-dark-default-Cuk6v7N8.js +1 -0
- package/public/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
- package/public/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
- package/public/assets/github-light-DAi9KRSo.js +1 -0
- package/public/assets/github-light-default-D7oLnXFd.js +1 -0
- package/public/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
- package/public/assets/gleam-BspZqrRM.js +1 -0
- package/public/assets/glimmer-js-Rg0-pVw9.js +1 -0
- package/public/assets/glimmer-ts-U6CK756n.js +1 -0
- package/public/assets/glsl-DplSGwfg.js +1 -0
- package/public/assets/gnuplot-DdkO51Og.js +1 -0
- package/public/assets/go-Dn2_MT6a.js +1 -0
- package/public/assets/graphql-ChdNCCLP.js +1 -0
- package/public/assets/groovy-gcz8RCvz.js +1 -0
- package/public/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
- package/public/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
- package/public/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
- package/public/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
- package/public/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
- package/public/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
- package/public/assets/hack-CaT9iCJl.js +1 -0
- package/public/assets/haml-B8DHNrY2.js +1 -0
- package/public/assets/handlebars-BL8al0AC.js +1 -0
- package/public/assets/haskell-Df6bDoY_.js +1 -0
- package/public/assets/haxe-CzTSHFRz.js +1 -0
- package/public/assets/hcl-BWvSN4gD.js +1 -0
- package/public/assets/highlight-vendor-8FKMu9os.js +10 -0
- package/public/assets/hjson-D5-asLiD.js +1 -0
- package/public/assets/hlsl-D3lLCCz7.js +1 -0
- package/public/assets/houston-DnULxvSX.js +1 -0
- package/public/assets/html-GMplVEZG.js +1 -0
- package/public/assets/html-derivative-BFtXZ54Q.js +1 -0
- package/public/assets/http-jrhK8wxY.js +1 -0
- package/public/assets/hurl-irOxFIW8.js +1 -0
- package/public/assets/hxml-Bvhsp5Yf.js +1 -0
- package/public/assets/hy-DFXneXwc.js +1 -0
- package/public/assets/imba-DGztddWO.js +1 -0
- package/public/assets/index-Bdy3MTIn.js +1 -0
- package/public/assets/index-BvRe9GiS.js +1 -0
- package/public/assets/index-Ctq8RqRf.js +1 -0
- package/public/assets/index-D-NvysdX.js +1 -0
- package/public/assets/index-D6RMBXUk.js +2 -0
- package/public/assets/index-DXI9DoVB.css +1 -0
- package/public/assets/index-DYWkPhKo.js +1 -0
- package/public/assets/index-D_FDiI6a.js +1 -0
- package/public/assets/index-Dty5bSHf.js +1 -0
- package/public/assets/index-H16e4Rqc.js +1 -0
- package/public/assets/ini-BEwlwnbL.js +1 -0
- package/public/assets/java-CylS5w8V.js +1 -0
- package/public/assets/javascript-wDzz0qaB.js +1 -0
- package/public/assets/jinja-4LBKfQ-Z.js +1 -0
- package/public/assets/jison-wvAkD_A8.js +1 -0
- package/public/assets/json-Cp-IABpG.js +1 -0
- package/public/assets/json5-C9tS-k6U.js +1 -0
- package/public/assets/jsonc-Des-eS-w.js +1 -0
- package/public/assets/jsonl-DcaNXYhu.js +1 -0
- package/public/assets/jsonnet-DFQXde-d.js +1 -0
- package/public/assets/jssm-C2t-YnRu.js +1 -0
- package/public/assets/jsx-g9-lgVsj.js +1 -0
- package/public/assets/julia-C8NyazO9.js +1 -0
- package/public/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
- package/public/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
- package/public/assets/kanagawa-wave-DWedfzmr.js +1 -0
- package/public/assets/kdl-DV7GczEv.js +1 -0
- package/public/assets/kotlin-BdnUsdx6.js +1 -0
- package/public/assets/kusto-BvAqAH-y.js +1 -0
- package/public/assets/laserwave-DUszq2jm.js +1 -0
- package/public/assets/latex-BUKiar2Z.js +1 -0
- package/public/assets/lean-DP1Csr6i.js +1 -0
- package/public/assets/less-B1dDrJ26.js +1 -0
- package/public/assets/light-plus-B7mTdjB0.js +1 -0
- package/public/assets/liquid-DYVedYrR.js +1 -0
- package/public/assets/llvm-BtvRca6l.js +1 -0
- package/public/assets/loading-CmEVQgyj.css +1 -0
- package/public/assets/loading-W2Y_wR0P.js +1 -0
- package/public/assets/log-2UxHyX5q.js +1 -0
- package/public/assets/logo-BtOb2qkB.js +1 -0
- package/public/assets/lua-BbnMAYS6.js +1 -0
- package/public/assets/luau-CXu1NL6O.js +1 -0
- package/public/assets/main-Bala0YJ4.js +57 -0
- package/public/assets/make-CHLpvVh8.js +1 -0
- package/public/assets/markdown-Cvjx9yec.js +1 -0
- package/public/assets/markdown-Db8cvZ4Z.js +315 -0
- package/public/assets/marko-CPi9NSCl.js +1 -0
- package/public/assets/material-theme-D5KoaKCx.js +1 -0
- package/public/assets/material-theme-darker-BfHTSMKl.js +1 -0
- package/public/assets/material-theme-lighter-B0m2ddpp.js +1 -0
- package/public/assets/material-theme-ocean-CyktbL80.js +1 -0
- package/public/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
- package/public/assets/matlab-D7o27uSR.js +1 -0
- package/public/assets/mdc-DUICxH0z.js +1 -0
- package/public/assets/mdx-Cmh6b_Ma.js +1 -0
- package/public/assets/mermaid-DKYwYmdq.js +1 -0
- package/public/assets/min-dark-CafNBF8u.js +1 -0
- package/public/assets/min-light-CTRr51gU.js +1 -0
- package/public/assets/mipsasm-CKIfxQSi.js +1 -0
- package/public/assets/mojo-1DNp92w6.js +1 -0
- package/public/assets/monaco-viewer-DWQqXKm3.js +26 -0
- package/public/assets/monokai-D4h5O-jR.js +1 -0
- package/public/assets/move-Bu9oaDYs.js +1 -0
- package/public/assets/narrat-DRg8JJMk.js +1 -0
- package/public/assets/nextflow-CUEJCptM.js +1 -0
- package/public/assets/nginx-DknmC5AR.js +1 -0
- package/public/assets/night-owl-C39BiMTA.js +1 -0
- package/public/assets/nim-CVrawwO9.js +1 -0
- package/public/assets/nix-BbRYJGeE.js +1 -0
- package/public/assets/nord-Ddv68eIx.js +1 -0
- package/public/assets/nushell-C-sUppwS.js +1 -0
- package/public/assets/objective-c-DXmwc3jG.js +1 -0
- package/public/assets/objective-cpp-CLxacb5B.js +1 -0
- package/public/assets/ocaml-C0hk2d4L.js +1 -0
- package/public/assets/one-dark-pro-DVMEJ2y_.js +1 -0
- package/public/assets/one-light-PoHY5YXO.js +1 -0
- package/public/assets/pascal-D93ZcfNL.js +1 -0
- package/public/assets/perl-C0TMdlhV.js +1 -0
- package/public/assets/php-CDn_0X-4.js +1 -0
- package/public/assets/pkl-u5AG7uiY.js +1 -0
- package/public/assets/plastic-3e1v2bzS.js +1 -0
- package/public/assets/plsql-ChMvpjG-.js +1 -0
- package/public/assets/po-BTJTHyun.js +1 -0
- package/public/assets/poimandres-CS3Unz2-.js +1 -0
- package/public/assets/polar-C0HS_06l.js +1 -0
- package/public/assets/postcss-CXtECtnM.js +1 -0
- package/public/assets/powerquery-CEu0bR-o.js +1 -0
- package/public/assets/powershell-Dpen1YoG.js +1 -0
- package/public/assets/prisma-Dd19v3D-.js +1 -0
- package/public/assets/prolog-CbFg5uaA.js +1 -0
- package/public/assets/proto-DyJlTyXw.js +1 -0
- package/public/assets/pug-CGlum2m_.js +1 -0
- package/public/assets/puppet-BMWR74SV.js +1 -0
- package/public/assets/purescript-CklMAg4u.js +1 -0
- package/public/assets/python-B6aJPvgy.js +1 -0
- package/public/assets/qml-3beO22l8.js +1 -0
- package/public/assets/qmldir-C8lEn-DE.js +1 -0
- package/public/assets/qss-IeuSbFQv.js +1 -0
- package/public/assets/r-DiinP2Uv.js +1 -0
- package/public/assets/racket-BqYA7rlc.js +1 -0
- package/public/assets/raku-DXvB9xmW.js +1 -0
- package/public/assets/razor-WgofotgN.js +1 -0
- package/public/assets/red-bN70gL4F.js +1 -0
- package/public/assets/reg-C-SQnVFl.js +1 -0
- package/public/assets/regexp-CDVJQ6XC.js +1 -0
- package/public/assets/rel-C3B-1QV4.js +1 -0
- package/public/assets/riscv-BM1_JUlF.js +1 -0
- package/public/assets/rose-pine-BHrmToEH.js +1 -0
- package/public/assets/rose-pine-dawn-CnK8MTSM.js +1 -0
- package/public/assets/rose-pine-moon-NleAzG8P.js +1 -0
- package/public/assets/rosmsg-BJDFO7_C.js +1 -0
- package/public/assets/rst-B0xPkSld.js +1 -0
- package/public/assets/ruby-BvKwtOVI.js +1 -0
- package/public/assets/rust-B1yitclQ.js +1 -0
- package/public/assets/sas-cz2c8ADy.js +1 -0
- package/public/assets/sass-Cj5Yp3dK.js +1 -0
- package/public/assets/scala-C151Ov-r.js +1 -0
- package/public/assets/scheme-C98Dy4si.js +1 -0
- package/public/assets/scss-OYdSNvt2.js +1 -0
- package/public/assets/sdbl-DVxCFoDh.js +1 -0
- package/public/assets/shaderlab-Dg9Lc6iA.js +1 -0
- package/public/assets/shellscript-Yzrsuije.js +1 -0
- package/public/assets/shellsession-BADoaaVG.js +1 -0
- package/public/assets/slack-dark-BthQWCQV.js +1 -0
- package/public/assets/slack-ochin-DqwNpetd.js +1 -0
- package/public/assets/smalltalk-BERRCDM3.js +1 -0
- package/public/assets/snazzy-light-Bw305WKR.js +1 -0
- package/public/assets/solarized-dark-DXbdFlpD.js +1 -0
- package/public/assets/solarized-light-L9t79GZl.js +1 -0
- package/public/assets/solidity-BbcW6ACK.js +1 -0
- package/public/assets/soy-Brmx7dQM.js +1 -0
- package/public/assets/sparql-rVzFXLq3.js +1 -0
- package/public/assets/splunk-BtCnVYZw.js +1 -0
- package/public/assets/sql-BLtJtn59.js +1 -0
- package/public/assets/ssh-config-_ykCGR6B.js +1 -0
- package/public/assets/stata-BH5u7GGu.js +1 -0
- package/public/assets/stylus-BEDo0Tqx.js +1 -0
- package/public/assets/svelte-3Dk4HxPD.js +1 -0
- package/public/assets/swift-Dg5xB15N.js +1 -0
- package/public/assets/synthwave-84-CbfX1IO0.js +1 -0
- package/public/assets/system-verilog-CnnmHF94.js +1 -0
- package/public/assets/systemd-4A_iFExJ.js +1 -0
- package/public/assets/talonscript-CkByrt1z.js +1 -0
- package/public/assets/tasl-QIJgUcNo.js +1 -0
- package/public/assets/tcl-dwOrl1Do.js +1 -0
- package/public/assets/templ-W15q3VgB.js +1 -0
- package/public/assets/terraform-BETggiCN.js +1 -0
- package/public/assets/tex-Cppo0RY3.js +1 -0
- package/public/assets/tokyo-night-hegEt444.js +1 -0
- package/public/assets/toml-vGWfd6FD.js +1 -0
- package/public/assets/tool-call-D0BYXlFe.js +59 -0
- package/public/assets/ts-tags-zn1MmPIZ.js +1 -0
- package/public/assets/tsv-B_m7g4N7.js +1 -0
- package/public/assets/tsx-COt5Ahok.js +1 -0
- package/public/assets/turtle-BsS91CYL.js +1 -0
- package/public/assets/twig-CO9l9SDP.js +1 -0
- package/public/assets/typescript-BPQ3VLAy.js +1 -0
- package/public/assets/typespec-Df68jz8_.js +1 -0
- package/public/assets/typst-DHCkPAjA.js +1 -0
- package/public/assets/unified-picker-QgONWj_1.js +1 -0
- package/public/assets/v-BcVCzyr7.js +1 -0
- package/public/assets/vala-CsfeWuGM.js +1 -0
- package/public/assets/vb-D17OF-Vu.js +1 -0
- package/public/assets/verilog-BQ8w6xss.js +1 -0
- package/public/assets/vesper-DU1UobuO.js +1 -0
- package/public/assets/vhdl-CeAyd5Ju.js +1 -0
- package/public/assets/viml-CJc9bBzg.js +1 -0
- package/public/assets/vitesse-black-Bkuqu6BP.js +1 -0
- package/public/assets/vitesse-dark-D0r3Knsf.js +1 -0
- package/public/assets/vitesse-light-CVO1_9PV.js +1 -0
- package/public/assets/vue-CCoi5OLL.js +1 -0
- package/public/assets/vue-html-DAAvJJDi.js +1 -0
- package/public/assets/vue-vine-_Ih-lPRR.js +1 -0
- package/public/assets/vyper-CDx5xZoG.js +1 -0
- package/public/assets/wasm-CG6Dc4jp.js +1 -0
- package/public/assets/wasm-MzD3tlZU.js +1 -0
- package/public/assets/wenyan-BV7otONQ.js +1 -0
- package/public/assets/wgsl-Dx-B1_4e.js +1 -0
- package/public/assets/wikitext-BhOHFoWU.js +1 -0
- package/public/assets/wit-5i3qLPDT.js +1 -0
- package/public/assets/wolfram-lXgVvXCa.js +1 -0
- package/public/assets/wrap-text-CEH9wOr_.js +1 -0
- package/public/assets/xml-sdJ4AIDG.js +1 -0
- package/public/assets/xsl-CtQFsRM5.js +1 -0
- package/public/assets/yaml-Buea-lGh.js +1 -0
- package/public/assets/zenscript-DVFEvuxE.js +1 -0
- package/public/assets/zig-VOosw3JB.js +1 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +42 -0
- package/public/loading.html +33 -0
- package/public/logo.png +0 -0
- package/public/manifest.webmanifest +1 -0
- package/public/maskable-icon-512x512.png +0 -0
- package/public/monaco/vs/base/browser/ui/codicons/codicon/codicon.ttf +0 -0
- package/public/monaco/vs/base/worker/workerMain.js +31 -0
- package/public/monaco/vs/basic-languages/cpp/cpp.js +10 -0
- package/public/monaco/vs/basic-languages/kotlin/kotlin.js +10 -0
- package/public/monaco/vs/basic-languages/markdown/markdown.js +10 -0
- package/public/monaco/vs/basic-languages/python/python.js +10 -0
- package/public/monaco/vs/editor/editor.main.css +8 -0
- package/public/monaco/vs/editor/editor.main.js +798 -0
- package/public/monaco/vs/language/css/cssMode.js +13 -0
- package/public/monaco/vs/language/css/cssWorker.js +77 -0
- package/public/monaco/vs/language/html/htmlMode.js +13 -0
- package/public/monaco/vs/language/html/htmlWorker.js +454 -0
- package/public/monaco/vs/language/json/jsonMode.js +19 -0
- package/public/monaco/vs/language/json/jsonWorker.js +42 -0
- package/public/monaco/vs/language/typescript/tsMode.js +20 -0
- package/public/monaco/vs/language/typescript/tsWorker.js +51328 -0
- package/public/monaco/vs/loader.js +11 -0
- package/public/monaco.worker.js +7 -0
- package/public/pwa-192x192.png +0 -0
- package/public/pwa-512x512.png +0 -0
- package/public/pwa-64x64.png +0 -0
- package/public/registerSW.js +1 -0
- package/public/sw.js +1 -0
- package/public/ui-version.json +3 -0
- package/public/workbox-60d14903.js +1 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
export const WORKSPACE_CANDIDATE_CACHE_TTL_MS = 30000;
|
|
3
|
+
const workspaceCandidateCache = new Map();
|
|
4
|
+
export function getWorkspaceCandidates(rootDir, now = Date.now()) {
|
|
5
|
+
const key = normalizeKey(rootDir);
|
|
6
|
+
const cached = workspaceCandidateCache.get(key);
|
|
7
|
+
if (!cached) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
if (cached.expiresAt <= now) {
|
|
11
|
+
workspaceCandidateCache.delete(key);
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
return cloneEntries(cached.candidates);
|
|
15
|
+
}
|
|
16
|
+
export function refreshWorkspaceCandidates(rootDir, builder, now = Date.now()) {
|
|
17
|
+
const key = normalizeKey(rootDir);
|
|
18
|
+
const freshCandidates = builder();
|
|
19
|
+
if (!freshCandidates || freshCandidates.length === 0) {
|
|
20
|
+
workspaceCandidateCache.delete(key);
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
const storedCandidates = cloneEntries(freshCandidates);
|
|
24
|
+
workspaceCandidateCache.set(key, {
|
|
25
|
+
expiresAt: now + WORKSPACE_CANDIDATE_CACHE_TTL_MS,
|
|
26
|
+
candidates: storedCandidates,
|
|
27
|
+
});
|
|
28
|
+
return cloneEntries(storedCandidates);
|
|
29
|
+
}
|
|
30
|
+
export function clearWorkspaceSearchCache(rootDir) {
|
|
31
|
+
if (typeof rootDir === "undefined") {
|
|
32
|
+
workspaceCandidateCache.clear();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const key = normalizeKey(rootDir);
|
|
36
|
+
workspaceCandidateCache.delete(key);
|
|
37
|
+
}
|
|
38
|
+
function cloneEntries(entries) {
|
|
39
|
+
return entries.map((entry) => ({ ...entry }));
|
|
40
|
+
}
|
|
41
|
+
function normalizeKey(rootDir) {
|
|
42
|
+
return path.resolve(rootDir);
|
|
43
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fuzzysort from "fuzzysort";
|
|
4
|
+
import { clearWorkspaceSearchCache, getWorkspaceCandidates, refreshWorkspaceCandidates } from "./search-cache";
|
|
5
|
+
const DEFAULT_LIMIT = 100;
|
|
6
|
+
const MAX_LIMIT = 200;
|
|
7
|
+
const MAX_CANDIDATES = 8000;
|
|
8
|
+
const IGNORED_DIRECTORIES = new Set([".git", ".hg", ".svn", "node_modules", "dist", "build", ".next", ".nuxt", ".turbo", ".cache", "coverage"].map((name) => name.toLowerCase()));
|
|
9
|
+
export function searchWorkspaceFiles(rootDir, query, options = {}) {
|
|
10
|
+
const trimmedQuery = query.trim();
|
|
11
|
+
if (!trimmedQuery) {
|
|
12
|
+
throw new Error("Search query is required");
|
|
13
|
+
}
|
|
14
|
+
const normalizedRoot = path.resolve(rootDir);
|
|
15
|
+
const limit = normalizeLimit(options.limit);
|
|
16
|
+
const typeFilter = options.type ?? "all";
|
|
17
|
+
const refreshRequested = options.refresh === true;
|
|
18
|
+
let entries;
|
|
19
|
+
try {
|
|
20
|
+
if (!refreshRequested) {
|
|
21
|
+
entries = getWorkspaceCandidates(normalizedRoot);
|
|
22
|
+
}
|
|
23
|
+
if (!entries) {
|
|
24
|
+
entries = refreshWorkspaceCandidates(normalizedRoot, () => collectCandidates(normalizedRoot));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
clearWorkspaceSearchCache(normalizedRoot);
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
if (!entries || entries.length === 0) {
|
|
32
|
+
clearWorkspaceSearchCache(normalizedRoot);
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
const candidates = buildCandidateEntries(entries, typeFilter);
|
|
36
|
+
if (candidates.length === 0) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
const matches = fuzzysort.go(trimmedQuery, candidates, {
|
|
40
|
+
key: "key",
|
|
41
|
+
limit,
|
|
42
|
+
});
|
|
43
|
+
if (!matches || matches.length === 0) {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
return matches.map((match) => match.obj.entry);
|
|
47
|
+
}
|
|
48
|
+
function collectCandidates(rootDir) {
|
|
49
|
+
const queue = [""];
|
|
50
|
+
const entries = [];
|
|
51
|
+
while (queue.length > 0 && entries.length < MAX_CANDIDATES) {
|
|
52
|
+
const relativeDir = queue.pop() || "";
|
|
53
|
+
const absoluteDir = relativeDir ? path.join(rootDir, relativeDir) : rootDir;
|
|
54
|
+
let dirents;
|
|
55
|
+
try {
|
|
56
|
+
dirents = fs.readdirSync(absoluteDir, { withFileTypes: true });
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
for (const dirent of dirents) {
|
|
62
|
+
const entryName = dirent.name;
|
|
63
|
+
const lowerName = entryName.toLowerCase();
|
|
64
|
+
const relativePath = relativeDir ? `${relativeDir}/${entryName}` : entryName;
|
|
65
|
+
const absolutePath = path.join(absoluteDir, entryName);
|
|
66
|
+
if (dirent.isDirectory() && IGNORED_DIRECTORIES.has(lowerName)) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
let stats;
|
|
70
|
+
try {
|
|
71
|
+
stats = fs.statSync(absolutePath);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const isDirectory = stats.isDirectory();
|
|
77
|
+
if (isDirectory && !IGNORED_DIRECTORIES.has(lowerName)) {
|
|
78
|
+
if (entries.length < MAX_CANDIDATES) {
|
|
79
|
+
queue.push(relativePath);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const entryType = isDirectory ? "directory" : "file";
|
|
83
|
+
const normalizedPath = normalizeRelativeEntryPath(relativePath);
|
|
84
|
+
const entry = {
|
|
85
|
+
name: entryName,
|
|
86
|
+
path: normalizedPath,
|
|
87
|
+
absolutePath: path.resolve(rootDir, normalizedPath === "." ? "" : normalizedPath),
|
|
88
|
+
type: entryType,
|
|
89
|
+
size: entryType === "file" ? stats.size : undefined,
|
|
90
|
+
modifiedAt: stats.mtime.toISOString(),
|
|
91
|
+
};
|
|
92
|
+
entries.push(entry);
|
|
93
|
+
if (entries.length >= MAX_CANDIDATES) {
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return entries;
|
|
99
|
+
}
|
|
100
|
+
function buildCandidateEntries(entries, filter) {
|
|
101
|
+
const filtered = [];
|
|
102
|
+
for (const entry of entries) {
|
|
103
|
+
if (!shouldInclude(entry.type, filter)) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
filtered.push({ entry, key: buildSearchKey(entry) });
|
|
107
|
+
}
|
|
108
|
+
return filtered;
|
|
109
|
+
}
|
|
110
|
+
function normalizeLimit(limit) {
|
|
111
|
+
if (!limit || Number.isNaN(limit)) {
|
|
112
|
+
return DEFAULT_LIMIT;
|
|
113
|
+
}
|
|
114
|
+
const clamped = Math.min(Math.max(limit, 1), MAX_LIMIT);
|
|
115
|
+
return clamped;
|
|
116
|
+
}
|
|
117
|
+
function shouldInclude(entryType, filter) {
|
|
118
|
+
return filter === "all" || entryType === filter;
|
|
119
|
+
}
|
|
120
|
+
function normalizeRelativeEntryPath(relativePath) {
|
|
121
|
+
if (!relativePath) {
|
|
122
|
+
return ".";
|
|
123
|
+
}
|
|
124
|
+
let normalized = relativePath.replace(/\\+/g, "/");
|
|
125
|
+
if (normalized.startsWith("./")) {
|
|
126
|
+
normalized = normalized.replace(/^\.\/+/, "");
|
|
127
|
+
}
|
|
128
|
+
if (normalized.startsWith("/")) {
|
|
129
|
+
normalized = normalized.replace(/^\/+/g, "");
|
|
130
|
+
}
|
|
131
|
+
return normalized || ".";
|
|
132
|
+
}
|
|
133
|
+
function buildSearchKey(entry) {
|
|
134
|
+
return entry.path.toLowerCase();
|
|
135
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI entry point.
|
|
3
|
+
* For now this only wires the typed modules together; actual command handling comes later.
|
|
4
|
+
*/
|
|
5
|
+
import { Command, InvalidArgumentError, Option } from "commander";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
import { createRequire } from "module";
|
|
9
|
+
import { createHttpServer } from "./server/http-server";
|
|
10
|
+
import { WorkspaceManager } from "./workspaces/manager";
|
|
11
|
+
import { resolveConfigLocation } from "./config/location";
|
|
12
|
+
import { SettingsService } from "./settings/service";
|
|
13
|
+
import { BinaryResolver } from "./settings/binaries";
|
|
14
|
+
import { FileSystemBrowser } from "./filesystem/browser";
|
|
15
|
+
import { EventBus } from "./events/bus";
|
|
16
|
+
import { InstanceStore } from "./storage/instance-store";
|
|
17
|
+
import { InstanceEventBridge } from "./workspaces/instance-events";
|
|
18
|
+
import { createLogger } from "./logger";
|
|
19
|
+
import { launchInBrowser } from "./launcher";
|
|
20
|
+
import { resolveUi } from "./ui/remote-ui";
|
|
21
|
+
import { AuthManager, BOOTSTRAP_TOKEN_STDOUT_PREFIX, DEFAULT_AUTH_COOKIE_NAME, DEFAULT_AUTH_USERNAME } from "./auth/manager";
|
|
22
|
+
import { resolveHttpsOptions } from "./server/tls";
|
|
23
|
+
import { RemoteProxySessionManager } from "./server/remote-proxy";
|
|
24
|
+
import { resolveNetworkAddresses, resolveRemoteAddresses } from "./server/network-addresses";
|
|
25
|
+
import { startDevReleaseMonitor } from "./releases/dev-release-monitor";
|
|
26
|
+
import { SpeechService } from "./speech/service";
|
|
27
|
+
import { SideCarManager } from "./sidecars/manager";
|
|
28
|
+
import { ClientConnectionManager } from "./clients/connection-manager";
|
|
29
|
+
import { PluginChannelManager } from "./plugins/channel";
|
|
30
|
+
import { VoiceModeManager } from "./plugins/voice-mode";
|
|
31
|
+
import { runCliUpgrade } from "./cli-upgrade";
|
|
32
|
+
const require = createRequire(import.meta.url);
|
|
33
|
+
const packageJson = require("../package.json");
|
|
34
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
35
|
+
const __dirname = path.dirname(__filename);
|
|
36
|
+
const DEFAULT_UI_STATIC_DIR = path.resolve(__dirname, "../public");
|
|
37
|
+
const DEFAULT_HOST = "127.0.0.1";
|
|
38
|
+
const DEFAULT_CONFIG_PATH = "~/.config/codenomad/config.json";
|
|
39
|
+
const DEFAULT_HTTPS_PORT = 9898;
|
|
40
|
+
const DEFAULT_HTTP_PORT = 9899;
|
|
41
|
+
function parseCliOptions(argv) {
|
|
42
|
+
const program = new Command()
|
|
43
|
+
.name("codenomad")
|
|
44
|
+
.description("CodeNomad CLI server")
|
|
45
|
+
.version(packageJson.version, "-v, --version", "Show the CLI version")
|
|
46
|
+
.addOption(new Option("--host <host>", "Host interface to bind").env("CLI_HOST").default(DEFAULT_HOST))
|
|
47
|
+
.addOption(new Option("--https <enabled>", "Enable HTTPS listener (true|false)").env("CLI_HTTPS").default("true"))
|
|
48
|
+
.addOption(new Option("--http <enabled>", "Enable HTTP listener (true|false)").env("CLI_HTTP").default("false"))
|
|
49
|
+
.addOption(new Option("--https-port <number>", "HTTPS port (0 for auto)").env("CLI_HTTPS_PORT").default(DEFAULT_HTTPS_PORT).argParser(parsePort))
|
|
50
|
+
.addOption(new Option("--http-port <number>", "HTTP port (0 for auto)").env("CLI_HTTP_PORT").default(DEFAULT_HTTP_PORT).argParser(parsePort))
|
|
51
|
+
.addOption(new Option("--tls-key <path>", "TLS private key (PEM)").env("CLI_TLS_KEY"))
|
|
52
|
+
.addOption(new Option("--tls-cert <path>", "TLS certificate (PEM)").env("CLI_TLS_CERT"))
|
|
53
|
+
.addOption(new Option("--tls-ca <path>", "TLS CA chain (PEM)").env("CLI_TLS_CA"))
|
|
54
|
+
.addOption(new Option("--tlsSANs <list>", "Additional TLS SANs (comma-separated)").env("CLI_TLS_SANS"))
|
|
55
|
+
.addOption(new Option("--workspace-root <path>", "Restricts root path where workspaces can be opened").env("CLI_WORKSPACE_ROOT").default(process.cwd()))
|
|
56
|
+
.addOption(new Option("--root <path>").env("CLI_ROOT").hideHelp(true))
|
|
57
|
+
.addOption(new Option("--unrestricted-root", "Allow browsing the full filesystem").env("CLI_UNRESTRICTED_ROOT").default(false))
|
|
58
|
+
.addOption(new Option("--config <path>", "Path to the config file").env("CLI_CONFIG").default(DEFAULT_CONFIG_PATH))
|
|
59
|
+
.addOption(new Option("--log-level <level>", "Log level (trace|debug|info|warn|error)").env("CLI_LOG_LEVEL"))
|
|
60
|
+
.addOption(new Option("--log-destination <path>", "Log destination file (defaults to stdout)").env("CLI_LOG_DESTINATION"))
|
|
61
|
+
.addOption(new Option("--ui-dir <path>", "Directory containing the built UI bundle").env("CLI_UI_DIR").default(DEFAULT_UI_STATIC_DIR))
|
|
62
|
+
.addOption(new Option("--ui-dev-server <url>", "Proxy UI requests to a running dev server").env("CLI_UI_DEV_SERVER"))
|
|
63
|
+
.addOption(new Option("--ui-no-update", "Disable remote UI updates").env("CLI_UI_NO_UPDATE").default(false))
|
|
64
|
+
.addOption(new Option("--ui-auto-update <enabled>", "Enable remote UI updates (true|false)").env("CLI_UI_AUTO_UPDATE").default("true"))
|
|
65
|
+
.addOption(new Option("--ui-manifest-url <url>", "Remote UI manifest URL").env("CLI_UI_MANIFEST_URL"))
|
|
66
|
+
.addOption(new Option("--launch", "Launch the UI in a browser after start").env("CLI_LAUNCH").default(false))
|
|
67
|
+
.addOption(new Option("--username <username>", "Username for server authentication")
|
|
68
|
+
.env("CODENOMAD_SERVER_USERNAME")
|
|
69
|
+
.default(DEFAULT_AUTH_USERNAME))
|
|
70
|
+
.addOption(new Option("--password <password>", "Password for server authentication").env("CODENOMAD_SERVER_PASSWORD"))
|
|
71
|
+
.addOption(new Option("--auth-cookie-name <name>", "Cookie name for server authentication")
|
|
72
|
+
.env("CODENOMAD_AUTH_COOKIE_NAME")
|
|
73
|
+
.default(DEFAULT_AUTH_COOKIE_NAME))
|
|
74
|
+
.addOption(new Option("--generate-token", "Emit a one-time bootstrap token for desktop")
|
|
75
|
+
.env("CODENOMAD_GENERATE_TOKEN")
|
|
76
|
+
.default(false))
|
|
77
|
+
.addOption(new Option("--dangerously-skip-auth", "Disable CodeNomad's internal auth. Use only behind a trusted perimeter (SSO/VPN/etc).")
|
|
78
|
+
.env("CODENOMAD_SKIP_AUTH")
|
|
79
|
+
.default(false))
|
|
80
|
+
.addOption(new Option("--upgrade [version]", "Upgrade the global CodeNomad CLI server package and exit"));
|
|
81
|
+
program.parse(argv, { from: "user" });
|
|
82
|
+
const parsed = program.opts();
|
|
83
|
+
const upgrade = parsed.upgrade;
|
|
84
|
+
const parseBooleanEnv = (value) => {
|
|
85
|
+
const normalized = (value ?? "").trim().toLowerCase();
|
|
86
|
+
return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "y" || normalized === "on";
|
|
87
|
+
};
|
|
88
|
+
const resolvedRoot = parsed.workspaceRoot ?? parsed.root ?? process.cwd();
|
|
89
|
+
const normalizedHost = resolveHost(parsed.host);
|
|
90
|
+
const autoUpdateString = (parsed.uiAutoUpdate ?? "true").trim().toLowerCase();
|
|
91
|
+
const uiAutoUpdate = autoUpdateString === "1" || autoUpdateString === "true" || autoUpdateString === "yes";
|
|
92
|
+
const httpsEnabled = parseBooleanEnv(parsed.https);
|
|
93
|
+
const httpEnabled = parseBooleanEnv(parsed.http);
|
|
94
|
+
if (upgrade === undefined && !httpsEnabled && !httpEnabled) {
|
|
95
|
+
throw new InvalidArgumentError("At least one listener must be enabled (--https or --http)");
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
host: normalizedHost,
|
|
99
|
+
https: httpsEnabled,
|
|
100
|
+
http: httpEnabled,
|
|
101
|
+
httpsPort: parsed.httpsPort,
|
|
102
|
+
httpPort: parsed.httpPort,
|
|
103
|
+
tlsKeyPath: parsed.tlsKey,
|
|
104
|
+
tlsCertPath: parsed.tlsCert,
|
|
105
|
+
tlsCaPath: parsed.tlsCa,
|
|
106
|
+
tlsSANs: parsed.tlsSANs,
|
|
107
|
+
rootDir: resolvedRoot,
|
|
108
|
+
configPath: parsed.config,
|
|
109
|
+
unrestrictedRoot: Boolean(parsed.unrestrictedRoot),
|
|
110
|
+
logLevel: parsed.logLevel,
|
|
111
|
+
logDestination: parsed.logDestination,
|
|
112
|
+
uiStaticDir: parsed.uiDir,
|
|
113
|
+
uiDevServer: parsed.uiDevServer,
|
|
114
|
+
uiAutoUpdate,
|
|
115
|
+
uiNoUpdate: Boolean(parsed.uiNoUpdate),
|
|
116
|
+
uiManifestUrl: parsed.uiManifestUrl,
|
|
117
|
+
launch: Boolean(parsed.launch),
|
|
118
|
+
authUsername: parsed.username,
|
|
119
|
+
authPassword: parsed.password,
|
|
120
|
+
authCookieName: parsed.authCookieName,
|
|
121
|
+
generateToken: Boolean(parsed.generateToken),
|
|
122
|
+
dangerouslySkipAuth: Boolean(parsed.dangerouslySkipAuth),
|
|
123
|
+
upgrade,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function parsePort(input) {
|
|
127
|
+
const value = Number(input);
|
|
128
|
+
if (!Number.isInteger(value) || value < 0 || value > 65535) {
|
|
129
|
+
throw new InvalidArgumentError("Port must be an integer between 0 and 65535");
|
|
130
|
+
}
|
|
131
|
+
return value;
|
|
132
|
+
}
|
|
133
|
+
function resolveHost(input) {
|
|
134
|
+
const trimmed = input?.trim();
|
|
135
|
+
if (!trimmed)
|
|
136
|
+
return DEFAULT_HOST;
|
|
137
|
+
if (trimmed === "0.0.0.0") {
|
|
138
|
+
return "0.0.0.0";
|
|
139
|
+
}
|
|
140
|
+
if (trimmed === "localhost") {
|
|
141
|
+
return DEFAULT_HOST;
|
|
142
|
+
}
|
|
143
|
+
return trimmed;
|
|
144
|
+
}
|
|
145
|
+
function programHasArg(argv, flag) {
|
|
146
|
+
return argv.includes(flag);
|
|
147
|
+
}
|
|
148
|
+
async function main() {
|
|
149
|
+
const options = parseCliOptions(process.argv.slice(2));
|
|
150
|
+
if (options.upgrade !== undefined) {
|
|
151
|
+
const version = typeof options.upgrade === "string" ? options.upgrade : undefined;
|
|
152
|
+
process.exitCode = await runCliUpgrade(version);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const logger = createLogger({ level: options.logLevel, destination: options.logDestination, component: "app" });
|
|
156
|
+
const workspaceLogger = logger.child({ component: "workspace" });
|
|
157
|
+
const configLogger = logger.child({ component: "config" });
|
|
158
|
+
const eventLogger = logger.child({ component: "events" });
|
|
159
|
+
const logOptions = {
|
|
160
|
+
...options,
|
|
161
|
+
authPassword: options.authPassword ? "[REDACTED]" : undefined,
|
|
162
|
+
};
|
|
163
|
+
logger.info({ options: logOptions }, "Starting CodeNomad CLI server");
|
|
164
|
+
if (options.dangerouslySkipAuth) {
|
|
165
|
+
logger.warn("DANGEROUS: internal authentication is disabled (--dangerously-skip-auth / CODENOMAD_SKIP_AUTH).");
|
|
166
|
+
}
|
|
167
|
+
const eventBus = new EventBus(eventLogger);
|
|
168
|
+
const isLoopbackHost = (host) => host === "127.0.0.1" || host === "::1" || host.startsWith("127.");
|
|
169
|
+
const configLocation = resolveConfigLocation(options.configPath);
|
|
170
|
+
const configDir = configLocation.baseDir;
|
|
171
|
+
if ((options.tlsKeyPath && !options.tlsCertPath) || (!options.tlsKeyPath && options.tlsCertPath)) {
|
|
172
|
+
throw new InvalidArgumentError("--tls-key and --tls-cert must be provided together");
|
|
173
|
+
}
|
|
174
|
+
const serverMeta = {
|
|
175
|
+
localUrl: "http://localhost:0",
|
|
176
|
+
remoteUrl: undefined,
|
|
177
|
+
eventsUrl: `/api/events`,
|
|
178
|
+
host: options.host,
|
|
179
|
+
listeningMode: isLoopbackHost(options.host) ? "local" : "all",
|
|
180
|
+
localPort: 0,
|
|
181
|
+
remotePort: undefined,
|
|
182
|
+
hostLabel: options.host,
|
|
183
|
+
workspaceRoot: options.rootDir,
|
|
184
|
+
addresses: [],
|
|
185
|
+
};
|
|
186
|
+
const authManager = new AuthManager({
|
|
187
|
+
configPath: configLocation.configYamlPath,
|
|
188
|
+
username: options.authUsername,
|
|
189
|
+
password: options.authPassword,
|
|
190
|
+
cookieName: options.authCookieName,
|
|
191
|
+
generateToken: options.generateToken,
|
|
192
|
+
dangerouslySkipAuth: options.dangerouslySkipAuth,
|
|
193
|
+
}, logger.child({ component: "auth" }));
|
|
194
|
+
if (options.generateToken && !options.dangerouslySkipAuth) {
|
|
195
|
+
const token = authManager.issueBootstrapToken();
|
|
196
|
+
if (token) {
|
|
197
|
+
console.log(`${BOOTSTRAP_TOKEN_STDOUT_PREFIX}${token}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const tlsResolution = resolveHttpsOptions({
|
|
201
|
+
enabled: options.https,
|
|
202
|
+
configDir,
|
|
203
|
+
host: options.host,
|
|
204
|
+
tlsKeyPath: options.tlsKeyPath,
|
|
205
|
+
tlsCertPath: options.tlsCertPath,
|
|
206
|
+
tlsCaPath: options.tlsCaPath,
|
|
207
|
+
tlsSANs: options.tlsSANs,
|
|
208
|
+
logger: logger.child({ component: "tls" }),
|
|
209
|
+
});
|
|
210
|
+
const nodeExtraCaCertsPath = !options.http ? tlsResolution?.caCertPath : undefined;
|
|
211
|
+
const settings = new SettingsService(configLocation, eventBus, configLogger);
|
|
212
|
+
const binaryResolver = new BinaryResolver(settings);
|
|
213
|
+
const workspaceManager = new WorkspaceManager({
|
|
214
|
+
rootDir: options.rootDir,
|
|
215
|
+
settings,
|
|
216
|
+
binaryResolver,
|
|
217
|
+
eventBus,
|
|
218
|
+
logger: workspaceLogger,
|
|
219
|
+
getServerBaseUrl: () => serverMeta.localUrl,
|
|
220
|
+
nodeExtraCaCertsPath,
|
|
221
|
+
});
|
|
222
|
+
const fileSystemBrowser = new FileSystemBrowser({
|
|
223
|
+
rootDir: options.rootDir,
|
|
224
|
+
unrestricted: options.unrestrictedRoot,
|
|
225
|
+
});
|
|
226
|
+
const instanceStore = new InstanceStore(configLocation.instancesDir);
|
|
227
|
+
const speechService = new SpeechService(settings, logger.child({ component: "speech" }));
|
|
228
|
+
const sidecarManager = new SideCarManager({
|
|
229
|
+
settings,
|
|
230
|
+
eventBus,
|
|
231
|
+
logger: logger.child({ component: "sidecars" }),
|
|
232
|
+
});
|
|
233
|
+
const instanceEventBridge = new InstanceEventBridge({
|
|
234
|
+
workspaceManager,
|
|
235
|
+
eventBus,
|
|
236
|
+
logger: logger.child({ component: "instance-events" }),
|
|
237
|
+
});
|
|
238
|
+
const uiDirEnvOverride = Boolean(process.env.CLI_UI_DIR);
|
|
239
|
+
const uiDirCliOverride = programHasArg(process.argv.slice(2), "--ui-dir");
|
|
240
|
+
const uiOverrideIsExplicit = uiDirEnvOverride || uiDirCliOverride;
|
|
241
|
+
const uiDirOverride = uiOverrideIsExplicit ? options.uiStaticDir : undefined;
|
|
242
|
+
const autoUpdateEnabled = options.uiAutoUpdate && !options.uiNoUpdate;
|
|
243
|
+
const uiResolution = await resolveUi({
|
|
244
|
+
serverVersion: packageJson.version,
|
|
245
|
+
bundledUiDir: DEFAULT_UI_STATIC_DIR,
|
|
246
|
+
autoUpdate: autoUpdateEnabled,
|
|
247
|
+
overrideUiDir: uiDirOverride,
|
|
248
|
+
uiDevServerUrl: options.uiDevServer,
|
|
249
|
+
manifestUrl: options.uiManifestUrl,
|
|
250
|
+
logger: logger.child({ component: "ui" }),
|
|
251
|
+
});
|
|
252
|
+
serverMeta.serverVersion = packageJson.version;
|
|
253
|
+
serverMeta.ui = {
|
|
254
|
+
version: uiResolution.uiVersion,
|
|
255
|
+
source: uiResolution.source,
|
|
256
|
+
};
|
|
257
|
+
serverMeta.support = {
|
|
258
|
+
supported: uiResolution.supported,
|
|
259
|
+
message: uiResolution.message,
|
|
260
|
+
latestServerVersion: uiResolution.latestServerVersion,
|
|
261
|
+
latestServerUrl: uiResolution.latestServerUrl,
|
|
262
|
+
minServerVersion: uiResolution.minServerVersion,
|
|
263
|
+
};
|
|
264
|
+
const updateChannel = (process.env.CODENOMAD_UPDATE_CHANNEL ?? "").trim().toLowerCase();
|
|
265
|
+
const githubRepo = (process.env.CODENOMAD_GITHUB_REPO ?? "NeuralNomadsAI/CodeNomad").trim();
|
|
266
|
+
const isDevVersion = packageJson.version.includes("-dev.") || packageJson.version.includes("-dev-");
|
|
267
|
+
const enableDevUpdateChecks = updateChannel === "dev" || (updateChannel === "" && isDevVersion);
|
|
268
|
+
const devReleaseMonitor = enableDevUpdateChecks
|
|
269
|
+
? startDevReleaseMonitor({
|
|
270
|
+
currentVersion: packageJson.version,
|
|
271
|
+
repo: githubRepo,
|
|
272
|
+
logger: logger.child({ component: "updates" }),
|
|
273
|
+
onUpdate: (release) => {
|
|
274
|
+
serverMeta.update = release;
|
|
275
|
+
},
|
|
276
|
+
})
|
|
277
|
+
: null;
|
|
278
|
+
const remoteAccessEnabled = options.host === "0.0.0.0" || !isLoopbackHost(options.host);
|
|
279
|
+
const clientConnectionManager = new ClientConnectionManager(logger.child({ component: "client-connections" }));
|
|
280
|
+
const pluginChannel = new PluginChannelManager(logger.child({ component: "plugin-channel" }));
|
|
281
|
+
const remoteProxySessionManager = new RemoteProxySessionManager({
|
|
282
|
+
authManager,
|
|
283
|
+
logger: logger.child({ component: "remote-proxy" }),
|
|
284
|
+
httpsOptions: tlsResolution?.httpsOptions,
|
|
285
|
+
});
|
|
286
|
+
const voiceModeManager = new VoiceModeManager({
|
|
287
|
+
connections: clientConnectionManager,
|
|
288
|
+
channel: pluginChannel,
|
|
289
|
+
logger: logger.child({ component: "voice-mode" }),
|
|
290
|
+
});
|
|
291
|
+
const httpsPortExplicit = programHasArg(process.argv.slice(2), "--https-port") || Boolean(process.env.CLI_HTTPS_PORT);
|
|
292
|
+
const httpPortExplicit = programHasArg(process.argv.slice(2), "--http-port") || Boolean(process.env.CLI_HTTP_PORT);
|
|
293
|
+
const httpsBindPort = httpsPortExplicit ? options.httpsPort : 0;
|
|
294
|
+
const httpBindPort = httpPortExplicit ? options.httpPort : 0;
|
|
295
|
+
// Listener binding rules:
|
|
296
|
+
// - Remote access enabled: HTTP listens on loopback, HTTPS on all IPs (host=0.0.0.0 / LAN IP).
|
|
297
|
+
// - Remote access disabled: both listen on loopback.
|
|
298
|
+
// - HTTP-only mode: respect --host (used for dev/testing).
|
|
299
|
+
const httpsBindHost = remoteAccessEnabled ? options.host : "127.0.0.1";
|
|
300
|
+
const httpBindHost = options.http ? (options.https ? "127.0.0.1" : options.host) : "127.0.0.1";
|
|
301
|
+
const servers = [];
|
|
302
|
+
const httpServer = options.http
|
|
303
|
+
? createHttpServer({
|
|
304
|
+
bindHost: httpBindHost,
|
|
305
|
+
bindPort: httpBindPort,
|
|
306
|
+
defaultPort: options.httpPort,
|
|
307
|
+
protocol: "http",
|
|
308
|
+
workspaceManager,
|
|
309
|
+
settings,
|
|
310
|
+
fileSystemBrowser,
|
|
311
|
+
eventBus,
|
|
312
|
+
serverMeta,
|
|
313
|
+
instanceStore,
|
|
314
|
+
speechService,
|
|
315
|
+
sidecarManager,
|
|
316
|
+
authManager,
|
|
317
|
+
clientConnectionManager,
|
|
318
|
+
pluginChannel,
|
|
319
|
+
voiceModeManager,
|
|
320
|
+
remoteProxySessionManager,
|
|
321
|
+
uiStaticDir: uiResolution.uiStaticDir ?? DEFAULT_UI_STATIC_DIR,
|
|
322
|
+
uiDevServerUrl: uiResolution.uiDevServerUrl,
|
|
323
|
+
logger,
|
|
324
|
+
})
|
|
325
|
+
: null;
|
|
326
|
+
const httpsServer = options.https
|
|
327
|
+
? createHttpServer({
|
|
328
|
+
bindHost: httpsBindHost,
|
|
329
|
+
bindPort: httpsBindPort,
|
|
330
|
+
defaultPort: options.httpsPort,
|
|
331
|
+
protocol: "https",
|
|
332
|
+
httpsOptions: tlsResolution?.httpsOptions,
|
|
333
|
+
workspaceManager,
|
|
334
|
+
settings,
|
|
335
|
+
fileSystemBrowser,
|
|
336
|
+
eventBus,
|
|
337
|
+
serverMeta,
|
|
338
|
+
instanceStore,
|
|
339
|
+
speechService,
|
|
340
|
+
sidecarManager,
|
|
341
|
+
authManager,
|
|
342
|
+
clientConnectionManager,
|
|
343
|
+
pluginChannel,
|
|
344
|
+
voiceModeManager,
|
|
345
|
+
remoteProxySessionManager,
|
|
346
|
+
uiStaticDir: uiResolution.uiStaticDir ?? DEFAULT_UI_STATIC_DIR,
|
|
347
|
+
uiDevServerUrl: undefined,
|
|
348
|
+
logger,
|
|
349
|
+
})
|
|
350
|
+
: null;
|
|
351
|
+
if (httpServer)
|
|
352
|
+
servers.push(httpServer);
|
|
353
|
+
if (httpsServer)
|
|
354
|
+
servers.push(httpsServer);
|
|
355
|
+
const [httpStart, httpsStart] = await Promise.all([
|
|
356
|
+
httpServer ? httpServer.start() : Promise.resolve(null),
|
|
357
|
+
httpsServer ? httpsServer.start() : Promise.resolve(null),
|
|
358
|
+
]);
|
|
359
|
+
const localStart = httpStart ?? httpsStart;
|
|
360
|
+
if (!localStart) {
|
|
361
|
+
throw new Error("No listeners started");
|
|
362
|
+
}
|
|
363
|
+
const remoteStart = httpsStart ?? httpStart;
|
|
364
|
+
const localProtocol = httpStart ? "http" : "https";
|
|
365
|
+
const remoteProtocol = httpsStart ? "https" : "http";
|
|
366
|
+
// Use an explicit IPv4 loopback address for the "local" URL.
|
|
367
|
+
// On macOS, `localhost` often resolves to ::1 first, and it is possible to have
|
|
368
|
+
// another instance bound on IPv6 while this instance binds IPv4 (or vice versa),
|
|
369
|
+
// which can lead clients to talk to the wrong process.
|
|
370
|
+
const localUrl = `${localProtocol}://127.0.0.1:${localStart.port}`;
|
|
371
|
+
let remoteUrl;
|
|
372
|
+
let remoteAddresses = [];
|
|
373
|
+
if (remoteStart) {
|
|
374
|
+
const wantsAll = options.host === "0.0.0.0" || !isLoopbackHost(options.host);
|
|
375
|
+
let remoteHost = options.host;
|
|
376
|
+
if (wantsAll) {
|
|
377
|
+
if (options.host === "0.0.0.0") {
|
|
378
|
+
const resolved = resolveRemoteAddresses({ host: options.host, protocol: remoteProtocol, port: remoteStart.port });
|
|
379
|
+
remoteAddresses = resolved.userVisible;
|
|
380
|
+
remoteUrl = resolved.primaryRemoteUrl ?? `${remoteProtocol}://localhost:${remoteStart.port}`;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
remoteHost = "localhost";
|
|
385
|
+
}
|
|
386
|
+
if (!remoteUrl) {
|
|
387
|
+
remoteUrl = `${remoteProtocol}://${remoteHost}:${remoteStart.port}`;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
serverMeta.localUrl = localUrl;
|
|
391
|
+
serverMeta.localPort = localStart.port;
|
|
392
|
+
serverMeta.remoteUrl = remoteUrl;
|
|
393
|
+
serverMeta.remotePort = remoteStart?.port;
|
|
394
|
+
serverMeta.host = options.host;
|
|
395
|
+
serverMeta.listeningMode = options.host === "0.0.0.0" || !isLoopbackHost(options.host) ? "all" : "local";
|
|
396
|
+
if (serverMeta.remotePort && remoteUrl) {
|
|
397
|
+
serverMeta.addresses = remoteAddresses.length
|
|
398
|
+
? remoteAddresses
|
|
399
|
+
: resolveNetworkAddresses({ host: options.host, protocol: remoteProtocol, port: serverMeta.remotePort });
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
serverMeta.addresses = [];
|
|
403
|
+
}
|
|
404
|
+
console.log(`Local Connection URL : ${serverMeta.localUrl}`);
|
|
405
|
+
if (serverMeta.remoteUrl) {
|
|
406
|
+
console.log(`Remote Connection URL : ${serverMeta.remoteUrl}`);
|
|
407
|
+
const additionalRemoteUrls = serverMeta.addresses
|
|
408
|
+
.map((addr) => addr.remoteUrl)
|
|
409
|
+
.filter((url) => url !== serverMeta.remoteUrl);
|
|
410
|
+
if (additionalRemoteUrls.length > 0) {
|
|
411
|
+
console.log("Other Accessible URLs:");
|
|
412
|
+
for (const url of additionalRemoteUrls) {
|
|
413
|
+
console.log(` - ${url}`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (options.launch) {
|
|
418
|
+
await launchInBrowser(serverMeta.localUrl, logger.child({ component: "launcher" }));
|
|
419
|
+
}
|
|
420
|
+
let shuttingDown = false;
|
|
421
|
+
const shutdown = async () => {
|
|
422
|
+
if (shuttingDown) {
|
|
423
|
+
logger.info("Shutdown already in progress, ignoring signal");
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
shuttingDown = true;
|
|
427
|
+
logger.info("Received shutdown signal, stopping workspaces and server");
|
|
428
|
+
const shutdownWorkspaces = (async () => {
|
|
429
|
+
try {
|
|
430
|
+
instanceEventBridge.shutdown();
|
|
431
|
+
}
|
|
432
|
+
catch (error) {
|
|
433
|
+
logger.warn({ err: error }, "Instance event bridge shutdown failed");
|
|
434
|
+
}
|
|
435
|
+
try {
|
|
436
|
+
await sidecarManager.shutdown();
|
|
437
|
+
}
|
|
438
|
+
catch (error) {
|
|
439
|
+
logger.error({ err: error }, "SideCar manager shutdown failed");
|
|
440
|
+
}
|
|
441
|
+
try {
|
|
442
|
+
clientConnectionManager.shutdown();
|
|
443
|
+
}
|
|
444
|
+
catch (error) {
|
|
445
|
+
logger.warn({ err: error }, "Client connection manager shutdown failed");
|
|
446
|
+
}
|
|
447
|
+
try {
|
|
448
|
+
await workspaceManager.shutdown();
|
|
449
|
+
logger.info("Workspace manager shutdown complete");
|
|
450
|
+
}
|
|
451
|
+
catch (error) {
|
|
452
|
+
logger.error({ err: error }, "Workspace manager shutdown failed");
|
|
453
|
+
}
|
|
454
|
+
})();
|
|
455
|
+
const shutdownHttp = (async () => {
|
|
456
|
+
try {
|
|
457
|
+
await Promise.allSettled(servers.map((srv) => srv.stop()));
|
|
458
|
+
logger.info("HTTP server(s) stopped");
|
|
459
|
+
}
|
|
460
|
+
catch (error) {
|
|
461
|
+
logger.error({ err: error }, "Failed to stop HTTP server");
|
|
462
|
+
}
|
|
463
|
+
})();
|
|
464
|
+
await Promise.allSettled([shutdownWorkspaces, shutdownHttp]);
|
|
465
|
+
// no-op: remote UI manifest replaces GitHub release monitor
|
|
466
|
+
devReleaseMonitor?.stop();
|
|
467
|
+
logger.info("Exiting process");
|
|
468
|
+
process.exit(0);
|
|
469
|
+
};
|
|
470
|
+
process.on("SIGINT", shutdown);
|
|
471
|
+
process.on("SIGTERM", shutdown);
|
|
472
|
+
}
|
|
473
|
+
main().catch((error) => {
|
|
474
|
+
const logger = createLogger({ component: "app" });
|
|
475
|
+
logger.error({ err: error }, "CLI server crashed");
|
|
476
|
+
process.exit(1);
|
|
477
|
+
});
|