@zoer7788/mcp-nexus-node 0.1.6 → 0.1.7
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/package.json +4 -5
- package/vendor/devspace/dist/cli.js +374 -0
- package/vendor/devspace/dist/config.js +253 -0
- package/vendor/devspace/dist/dashboard.js +545 -0
- package/vendor/devspace/dist/db/client.js +29 -0
- package/vendor/devspace/dist/db/migrations.js +123 -0
- package/vendor/devspace/dist/db/schema.js +52 -0
- package/vendor/devspace/dist/git-worktrees.js +134 -0
- package/vendor/devspace/dist/git.js +41 -0
- package/vendor/devspace/dist/logger.js +69 -0
- package/vendor/devspace/dist/oauth-provider.js +237 -0
- package/vendor/devspace/dist/oauth-store.js +138 -0
- package/vendor/devspace/dist/pi-tools.js +81 -0
- package/vendor/devspace/dist/review-checkpoints.js +142 -0
- package/vendor/devspace/dist/roots.js +34 -0
- package/vendor/devspace/dist/server.js +1204 -0
- package/vendor/devspace/dist/skills.js +45 -0
- package/vendor/devspace/dist/ui/.vite/manifest.json +2520 -0
- package/vendor/devspace/dist/ui/assets/abap-CLvhMVsD.js +1 -0
- package/vendor/devspace/dist/ui/assets/actionscript-3--17pq3dv.js +1 -0
- package/vendor/devspace/dist/ui/assets/ada-C5qYipkI.js +1 -0
- package/vendor/devspace/dist/ui/assets/andromeeda-vGVdxbeo.js +1 -0
- package/vendor/devspace/dist/ui/assets/angular-html-Dj4LysSE.js +1 -0
- package/vendor/devspace/dist/ui/assets/angular-ts-CxuC_FFh.js +1 -0
- package/vendor/devspace/dist/ui/assets/apache-U0d_L8uA.js +1 -0
- package/vendor/devspace/dist/ui/assets/apex-CGTLDQj6.js +1 -0
- package/vendor/devspace/dist/ui/assets/apl-RwuvNFFo.js +1 -0
- package/vendor/devspace/dist/ui/assets/applescript-CCn79oCD.js +1 -0
- package/vendor/devspace/dist/ui/assets/ara-4CJ0cIlV.js +1 -0
- package/vendor/devspace/dist/ui/assets/asciidoc-DE70LPWp.js +1 -0
- package/vendor/devspace/dist/ui/assets/asm-Cmm7eHzH.js +1 -0
- package/vendor/devspace/dist/ui/assets/astro-ncoaUbsO.js +1 -0
- package/vendor/devspace/dist/ui/assets/aurora-x-CDeNXAV0.js +1 -0
- package/vendor/devspace/dist/ui/assets/awk-BWXHIvNe.js +1 -0
- package/vendor/devspace/dist/ui/assets/ayu-dark-DluEY0Gj.js +1 -0
- package/vendor/devspace/dist/ui/assets/ayu-light-C3h-C4tm.js +1 -0
- package/vendor/devspace/dist/ui/assets/ayu-mirage-Bqwy1Gya.js +1 -0
- package/vendor/devspace/dist/ui/assets/ballerina-B7ZEbQpA.js +1 -0
- package/vendor/devspace/dist/ui/assets/bat-Bo4NYOV-.js +1 -0
- package/vendor/devspace/dist/ui/assets/beancount-D-usSTwE.js +1 -0
- package/vendor/devspace/dist/ui/assets/berry-DKpUyyne.js +1 -0
- package/vendor/devspace/dist/ui/assets/bibtex-Ci_nEsc7.js +1 -0
- package/vendor/devspace/dist/ui/assets/bicep-CUHmPFLl.js +1 -0
- package/vendor/devspace/dist/ui/assets/bird2-C2hNVINV.js +1 -0
- package/vendor/devspace/dist/ui/assets/blade-Dw8-Lzux.js +1 -0
- package/vendor/devspace/dist/ui/assets/bsl-BkkzgIyY.js +1 -0
- package/vendor/devspace/dist/ui/assets/c-Dpbbo_f2.js +1 -0
- package/vendor/devspace/dist/ui/assets/c3-CnJL0r0V.js +1 -0
- package/vendor/devspace/dist/ui/assets/cadence-CQ2zXKGN.js +1 -0
- package/vendor/devspace/dist/ui/assets/cairo-DLTphjLi.js +1 -0
- package/vendor/devspace/dist/ui/assets/catppuccin-frappe-3VR1Za6u.js +1 -0
- package/vendor/devspace/dist/ui/assets/catppuccin-latte-DwIHMF0Q.js +1 -0
- package/vendor/devspace/dist/ui/assets/catppuccin-macchiato-DYnBP6_5.js +1 -0
- package/vendor/devspace/dist/ui/assets/catppuccin-mocha-DYhrFGRu.js +1 -0
- package/vendor/devspace/dist/ui/assets/clarity-SemFz856.js +1 -0
- package/vendor/devspace/dist/ui/assets/clojure-DqKBuwfJ.js +1 -0
- package/vendor/devspace/dist/ui/assets/cmake-Bj61d0ZC.js +1 -0
- package/vendor/devspace/dist/ui/assets/cobol-4ddX3THy.js +1 -0
- package/vendor/devspace/dist/ui/assets/codeowners-C8r90Shi.js +1 -0
- package/vendor/devspace/dist/ui/assets/codeql-oeQT6MSM.js +1 -0
- package/vendor/devspace/dist/ui/assets/coffee-Bn-a5KqK.js +1 -0
- package/vendor/devspace/dist/ui/assets/common-lisp-Cv5bFMCO.js +1 -0
- package/vendor/devspace/dist/ui/assets/coq-BrsZFFmf.js +1 -0
- package/vendor/devspace/dist/ui/assets/cpp-DoRrlM_T.js +1 -0
- package/vendor/devspace/dist/ui/assets/crystal-DiZfCxn-.js +1 -0
- package/vendor/devspace/dist/ui/assets/csharp-Ct8U2NOr.js +1 -0
- package/vendor/devspace/dist/ui/assets/css-DiQoSjDH.js +1 -0
- package/vendor/devspace/dist/ui/assets/csv-Dx-8-gkx.js +1 -0
- package/vendor/devspace/dist/ui/assets/cue-CE9AQfxI.js +1 -0
- package/vendor/devspace/dist/ui/assets/cypher-ClKdZ_lG.js +1 -0
- package/vendor/devspace/dist/ui/assets/d-qD-0Kul2.js +1 -0
- package/vendor/devspace/dist/ui/assets/dark-plus-Cs2F2srj.js +1 -0
- package/vendor/devspace/dist/ui/assets/dart-DkHntEIa.js +1 -0
- package/vendor/devspace/dist/ui/assets/dax-BkyTk9wS.js +1 -0
- package/vendor/devspace/dist/ui/assets/desktop-Dlh5hvp9.js +1 -0
- package/vendor/devspace/dist/ui/assets/diff-woXpYk--.js +1 -0
- package/vendor/devspace/dist/ui/assets/docker-IyjqRm3v.js +1 -0
- package/vendor/devspace/dist/ui/assets/dotenv-_5a1GRtc.js +1 -0
- package/vendor/devspace/dist/ui/assets/dracula-BHWKrbxM.js +1 -0
- package/vendor/devspace/dist/ui/assets/dracula-soft-5eyTD99u.js +1 -0
- package/vendor/devspace/dist/ui/assets/dream-maker-DW3nJb8Q.js +1 -0
- package/vendor/devspace/dist/ui/assets/edge-wEhCUoEt.js +1 -0
- package/vendor/devspace/dist/ui/assets/elixir-C3obhm0H.js +1 -0
- package/vendor/devspace/dist/ui/assets/elm-DyTBfh1L.js +1 -0
- package/vendor/devspace/dist/ui/assets/emacs-lisp-C9PiwqqW.js +1 -0
- package/vendor/devspace/dist/ui/assets/erb-f4TnXRuY.js +1 -0
- package/vendor/devspace/dist/ui/assets/erlang-Cphh6RMH.js +1 -0
- package/vendor/devspace/dist/ui/assets/everforest-dark-sB-x3p7T.js +1 -0
- package/vendor/devspace/dist/ui/assets/everforest-light-Df2xbC6M.js +1 -0
- package/vendor/devspace/dist/ui/assets/fennel-DQxkIbk2.js +1 -0
- package/vendor/devspace/dist/ui/assets/fish-BJitypiv.js +1 -0
- package/vendor/devspace/dist/ui/assets/fluent-C03EYrpw.js +1 -0
- package/vendor/devspace/dist/ui/assets/fortran-fixed-form-DEKoE2YW.js +1 -0
- package/vendor/devspace/dist/ui/assets/fortran-free-form-CYNrtFtB.js +1 -0
- package/vendor/devspace/dist/ui/assets/fsharp-D13ZGOAj.js +1 -0
- package/vendor/devspace/dist/ui/assets/gdresource-C0sCabJj.js +1 -0
- package/vendor/devspace/dist/ui/assets/gdscript-Cp2uCuqX.js +1 -0
- package/vendor/devspace/dist/ui/assets/gdshader-CBce3t8t.js +1 -0
- package/vendor/devspace/dist/ui/assets/genie-CV2tkWYe.js +1 -0
- package/vendor/devspace/dist/ui/assets/gherkin-DExj1W_8.js +1 -0
- package/vendor/devspace/dist/ui/assets/git-commit-BSykSTBG.js +1 -0
- package/vendor/devspace/dist/ui/assets/git-rebase-vhZbWNfp.js +1 -0
- package/vendor/devspace/dist/ui/assets/github-dark-C-LZuMrd.js +1 -0
- package/vendor/devspace/dist/ui/assets/github-dark-default-DXG-b-1a.js +1 -0
- package/vendor/devspace/dist/ui/assets/github-dark-dimmed-Bx1FflLF.js +1 -0
- package/vendor/devspace/dist/ui/assets/github-dark-high-contrast-B_tTalzw.js +1 -0
- package/vendor/devspace/dist/ui/assets/github-light-EUqPIrTm.js +1 -0
- package/vendor/devspace/dist/ui/assets/github-light-default-BXViO-2h.js +1 -0
- package/vendor/devspace/dist/ui/assets/github-light-high-contrast-B68TUdTA.js +1 -0
- package/vendor/devspace/dist/ui/assets/gleam-CSRkHgEL.js +1 -0
- package/vendor/devspace/dist/ui/assets/glimmer-js-BG7puL6Y.js +1 -0
- package/vendor/devspace/dist/ui/assets/glimmer-ts-CNCfLLL1.js +1 -0
- package/vendor/devspace/dist/ui/assets/glsl-DhT76AL5.js +1 -0
- package/vendor/devspace/dist/ui/assets/gn-ilITqXS6.js +1 -0
- package/vendor/devspace/dist/ui/assets/gnuplot-7GGW24-e.js +1 -0
- package/vendor/devspace/dist/ui/assets/go-BJwz_mda.js +1 -0
- package/vendor/devspace/dist/ui/assets/graphql-CJX08w8y.js +1 -0
- package/vendor/devspace/dist/ui/assets/groovy-CacY0gHj.js +1 -0
- package/vendor/devspace/dist/ui/assets/gruvbox-dark-hard-C820rvS2.js +1 -0
- package/vendor/devspace/dist/ui/assets/gruvbox-dark-medium-BPjhmG05.js +1 -0
- package/vendor/devspace/dist/ui/assets/gruvbox-dark-soft-MrdJrrXF.js +1 -0
- package/vendor/devspace/dist/ui/assets/gruvbox-light-hard-BC_s9l72.js +1 -0
- package/vendor/devspace/dist/ui/assets/gruvbox-light-medium-BAWPOn9u.js +1 -0
- package/vendor/devspace/dist/ui/assets/gruvbox-light-soft-BSMLrYjP.js +1 -0
- package/vendor/devspace/dist/ui/assets/hack-DY4NGCCL.js +1 -0
- package/vendor/devspace/dist/ui/assets/haml-DwSkmVcG.js +1 -0
- package/vendor/devspace/dist/ui/assets/handlebars-CQ_1dEmi.js +1 -0
- package/vendor/devspace/dist/ui/assets/haskell-D8IpX4py.js +1 -0
- package/vendor/devspace/dist/ui/assets/haxe-OTjmBuCE.js +1 -0
- package/vendor/devspace/dist/ui/assets/hcl-Dh228itO.js +1 -0
- package/vendor/devspace/dist/ui/assets/heavy-payload-2rGBiitA.js +4 -0
- package/vendor/devspace/dist/ui/assets/hjson-CxZEssPk.js +1 -0
- package/vendor/devspace/dist/ui/assets/hlsl-Cvrh5tZx.js +1 -0
- package/vendor/devspace/dist/ui/assets/horizon-CE9ld1lL.js +1 -0
- package/vendor/devspace/dist/ui/assets/horizon-bright-Br1oVSNq.js +1 -0
- package/vendor/devspace/dist/ui/assets/houston-CsvMBhTu.js +1 -0
- package/vendor/devspace/dist/ui/assets/html-B_e3Njif.js +1 -0
- package/vendor/devspace/dist/ui/assets/html-derivative-_nHZ_Bk-.js +1 -0
- package/vendor/devspace/dist/ui/assets/http-CfcvPIru.js +1 -0
- package/vendor/devspace/dist/ui/assets/hurl-9vWDQIMO.js +1 -0
- package/vendor/devspace/dist/ui/assets/hxml-B0Qn7Nwc.js +1 -0
- package/vendor/devspace/dist/ui/assets/hy-CZbG8q4J.js +1 -0
- package/vendor/devspace/dist/ui/assets/imba-DsUTQ-LC.js +1 -0
- package/vendor/devspace/dist/ui/assets/ini-B5eOa1yu.js +1 -0
- package/vendor/devspace/dist/ui/assets/java-C4S5r6L5.js +1 -0
- package/vendor/devspace/dist/ui/assets/javascript-BRwqbMMC.js +1 -0
- package/vendor/devspace/dist/ui/assets/jinja-DHxzMMc5.js +1 -0
- package/vendor/devspace/dist/ui/assets/jison-B1DqeWXb.js +1 -0
- package/vendor/devspace/dist/ui/assets/json-DcFTkEdd.js +1 -0
- package/vendor/devspace/dist/ui/assets/json5-BR5RXkoi.js +1 -0
- package/vendor/devspace/dist/ui/assets/jsonc-CYpm1nAK.js +1 -0
- package/vendor/devspace/dist/ui/assets/jsonl-CmCQp5Yx.js +1 -0
- package/vendor/devspace/dist/ui/assets/jsonnet-CJTPZ8u_.js +1 -0
- package/vendor/devspace/dist/ui/assets/jssm-DXw9l8Rf.js +1 -0
- package/vendor/devspace/dist/ui/assets/jsx-DgfmYa9f.js +1 -0
- package/vendor/devspace/dist/ui/assets/julia-3M8SJ8iF.js +1 -0
- package/vendor/devspace/dist/ui/assets/just-UyH7_DNz.js +1 -0
- package/vendor/devspace/dist/ui/assets/kanagawa-dragon-CXtmUGW6.js +1 -0
- package/vendor/devspace/dist/ui/assets/kanagawa-lotus-BN08jTvb.js +1 -0
- package/vendor/devspace/dist/ui/assets/kanagawa-wave-CTweb8Dz.js +1 -0
- package/vendor/devspace/dist/ui/assets/kdl-CsD5j6eV.js +1 -0
- package/vendor/devspace/dist/ui/assets/kotlin-DhhofPvG.js +1 -0
- package/vendor/devspace/dist/ui/assets/kusto-BUv0MjJC.js +1 -0
- package/vendor/devspace/dist/ui/assets/laserwave-C_8bwKvT.js +1 -0
- package/vendor/devspace/dist/ui/assets/latex-wUbha6EX.js +1 -0
- package/vendor/devspace/dist/ui/assets/lean-CewbzKMR.js +1 -0
- package/vendor/devspace/dist/ui/assets/less-DVTAwKKz.js +1 -0
- package/vendor/devspace/dist/ui/assets/light-plus-DVQuIRkW.js +1 -0
- package/vendor/devspace/dist/ui/assets/liquid-DqNTB9kN.js +1 -0
- package/vendor/devspace/dist/ui/assets/llvm-Cm23YOpf.js +1 -0
- package/vendor/devspace/dist/ui/assets/log-BNLmms1o.js +1 -0
- package/vendor/devspace/dist/ui/assets/logo-Cluzi2Zq.js +1 -0
- package/vendor/devspace/dist/ui/assets/lua-DrEQ1QTW.js +1 -0
- package/vendor/devspace/dist/ui/assets/luau-CNKltnaQ.js +1 -0
- package/vendor/devspace/dist/ui/assets/make-Dixweg8N.js +1 -0
- package/vendor/devspace/dist/ui/assets/markdown-BYOwaDjH.js +1 -0
- package/vendor/devspace/dist/ui/assets/marko-B3GJw9Md.js +1 -0
- package/vendor/devspace/dist/ui/assets/material-theme-Bm3Qr25_.js +1 -0
- package/vendor/devspace/dist/ui/assets/material-theme-darker-2IIEA8gg.js +1 -0
- package/vendor/devspace/dist/ui/assets/material-theme-lighter-uhdI0v04.js +1 -0
- package/vendor/devspace/dist/ui/assets/material-theme-ocean-CHQ94UKr.js +1 -0
- package/vendor/devspace/dist/ui/assets/material-theme-palenight-B5W6OYN7.js +1 -0
- package/vendor/devspace/dist/ui/assets/matlab-D7qyCx1q.js +1 -0
- package/vendor/devspace/dist/ui/assets/mdc-BnThk82m.js +1 -0
- package/vendor/devspace/dist/ui/assets/mdx-DQZ5AkYe.js +1 -0
- package/vendor/devspace/dist/ui/assets/mermaid-Bk4SNUv9.js +1 -0
- package/vendor/devspace/dist/ui/assets/min-dark-BSWPekZh.js +1 -0
- package/vendor/devspace/dist/ui/assets/min-light-DDpmG2fV.js +1 -0
- package/vendor/devspace/dist/ui/assets/mipsasm-BMqwQI7S.js +1 -0
- package/vendor/devspace/dist/ui/assets/mojo-BgCJLMeH.js +1 -0
- package/vendor/devspace/dist/ui/assets/monokai-CdkpiU2Y.js +1 -0
- package/vendor/devspace/dist/ui/assets/moonbit-CaWjb8XO.js +1 -0
- package/vendor/devspace/dist/ui/assets/move-B1IS1UjX.js +1 -0
- package/vendor/devspace/dist/ui/assets/narrat-_X_XdTYD.js +1 -0
- package/vendor/devspace/dist/ui/assets/nextflow-Bbiyy34d.js +1 -0
- package/vendor/devspace/dist/ui/assets/nextflow-groovy-Dc_ddanL.js +1 -0
- package/vendor/devspace/dist/ui/assets/nginx-B5IeSsOX.js +1 -0
- package/vendor/devspace/dist/ui/assets/night-owl-DhmEMT88.js +1 -0
- package/vendor/devspace/dist/ui/assets/night-owl-light-eJ-hLW7d.js +1 -0
- package/vendor/devspace/dist/ui/assets/nim-BJraatnS.js +1 -0
- package/vendor/devspace/dist/ui/assets/nix-IvuFDN5E.js +1 -0
- package/vendor/devspace/dist/ui/assets/nord-Cb4Vim4T.js +1 -0
- package/vendor/devspace/dist/ui/assets/nushell-DcLAeLz5.js +1 -0
- package/vendor/devspace/dist/ui/assets/objective-c-D1A_Heim.js +1 -0
- package/vendor/devspace/dist/ui/assets/objective-cpp-BsSzOQcm.js +1 -0
- package/vendor/devspace/dist/ui/assets/ocaml-O90oeIOV.js +1 -0
- package/vendor/devspace/dist/ui/assets/odin-B1RWQWA5.js +1 -0
- package/vendor/devspace/dist/ui/assets/one-dark-pro-CLwyXe_n.js +1 -0
- package/vendor/devspace/dist/ui/assets/one-light-D7Lr4KcI.js +1 -0
- package/vendor/devspace/dist/ui/assets/openscad-BUDT5pXO.js +1 -0
- package/vendor/devspace/dist/ui/assets/pascal-4ZHwLPI5.js +1 -0
- package/vendor/devspace/dist/ui/assets/perl-BAhrR4gt.js +1 -0
- package/vendor/devspace/dist/ui/assets/php-BKRCk_wX.js +1 -0
- package/vendor/devspace/dist/ui/assets/pierre-dark-sU4Zdns8.js +1 -0
- package/vendor/devspace/dist/ui/assets/pierre-dark-soft-HXgun5vs.js +1 -0
- package/vendor/devspace/dist/ui/assets/pierre-light-DWBk51d8.js +1 -0
- package/vendor/devspace/dist/ui/assets/pierre-light-soft-CodEzPxf.js +1 -0
- package/vendor/devspace/dist/ui/assets/pkl-ot-7Btpt.js +1 -0
- package/vendor/devspace/dist/ui/assets/plastic-DQwYfKfQ.js +1 -0
- package/vendor/devspace/dist/ui/assets/plsql-DGHpHOYJ.js +1 -0
- package/vendor/devspace/dist/ui/assets/po-BiJDBrnU.js +1 -0
- package/vendor/devspace/dist/ui/assets/poimandres-DRFjx7u4.js +1 -0
- package/vendor/devspace/dist/ui/assets/polar-C7UOKdEL.js +1 -0
- package/vendor/devspace/dist/ui/assets/postcss-BXeXVLqQ.js +1 -0
- package/vendor/devspace/dist/ui/assets/powerquery-DNMTfnFr.js +1 -0
- package/vendor/devspace/dist/ui/assets/powershell-DshXNtvi.js +1 -0
- package/vendor/devspace/dist/ui/assets/prisma-BsRQq5mF.js +1 -0
- package/vendor/devspace/dist/ui/assets/prolog-iXnhIJG7.js +1 -0
- package/vendor/devspace/dist/ui/assets/proto-DB4EqR-F.js +1 -0
- package/vendor/devspace/dist/ui/assets/pug-B8gmSV7z.js +1 -0
- package/vendor/devspace/dist/ui/assets/puppet-CDv2pdJW.js +1 -0
- package/vendor/devspace/dist/ui/assets/purescript-9MfHhQsQ.js +1 -0
- package/vendor/devspace/dist/ui/assets/python-gzcpVVnB.js +1 -0
- package/vendor/devspace/dist/ui/assets/qml-DKrxIjHR.js +1 -0
- package/vendor/devspace/dist/ui/assets/qmldir-DCQb3MpD.js +1 -0
- package/vendor/devspace/dist/ui/assets/qss-Fe1Jh2GI.js +1 -0
- package/vendor/devspace/dist/ui/assets/r-YASBZvTH.js +1 -0
- package/vendor/devspace/dist/ui/assets/racket-DcIDlBhZ.js +1 -0
- package/vendor/devspace/dist/ui/assets/raku-B3gFvitq.js +1 -0
- package/vendor/devspace/dist/ui/assets/razor-P-XFZqh6.js +1 -0
- package/vendor/devspace/dist/ui/assets/red-CJ3rzSJv.js +1 -0
- package/vendor/devspace/dist/ui/assets/reg-CRGYupPL.js +1 -0
- package/vendor/devspace/dist/ui/assets/regexp-CCpiH6nO.js +1 -0
- package/vendor/devspace/dist/ui/assets/rel-BtDbiS_P.js +1 -0
- package/vendor/devspace/dist/ui/assets/review-payload-BLYwg6t8.js +1 -0
- package/vendor/devspace/dist/ui/assets/riscv-Ckw8ddFX.js +1 -0
- package/vendor/devspace/dist/ui/assets/ron-VUp2lXgN.js +1 -0
- package/vendor/devspace/dist/ui/assets/rose-pine-BthvhNj6.js +1 -0
- package/vendor/devspace/dist/ui/assets/rose-pine-dawn-Dg85fqjY.js +1 -0
- package/vendor/devspace/dist/ui/assets/rose-pine-moon-hon4tzzS.js +1 -0
- package/vendor/devspace/dist/ui/assets/rosmsg-CAekHB0j.js +1 -0
- package/vendor/devspace/dist/ui/assets/rst-CFAzckbn.js +1 -0
- package/vendor/devspace/dist/ui/assets/ruby-Dyp_Rx-S.js +1 -0
- package/vendor/devspace/dist/ui/assets/rust-Cfkwpbl8.js +1 -0
- package/vendor/devspace/dist/ui/assets/sas-YkWZIXxT.js +1 -0
- package/vendor/devspace/dist/ui/assets/sass-DXrisJhu.js +1 -0
- package/vendor/devspace/dist/ui/assets/scala-DKOlJaKm.js +1 -0
- package/vendor/devspace/dist/ui/assets/scheme-DQCgrYNe.js +1 -0
- package/vendor/devspace/dist/ui/assets/scss-Cf89idGl.js +1 -0
- package/vendor/devspace/dist/ui/assets/sdbl-bTVj8UrX.js +1 -0
- package/vendor/devspace/dist/ui/assets/shaderlab-TOUzSsQk.js +1 -0
- package/vendor/devspace/dist/ui/assets/shellscript-BFMb52q8.js +1 -0
- package/vendor/devspace/dist/ui/assets/shellsession-DuthW-5v.js +1 -0
- package/vendor/devspace/dist/ui/assets/slack-dark-DnToyrRv.js +1 -0
- package/vendor/devspace/dist/ui/assets/slack-ochin-B2OO5cIa.js +1 -0
- package/vendor/devspace/dist/ui/assets/smalltalk-B16xEiuN.js +1 -0
- package/vendor/devspace/dist/ui/assets/snazzy-light-4G7pJPwS.js +1 -0
- package/vendor/devspace/dist/ui/assets/solarized-dark-DV17i1UV.js +1 -0
- package/vendor/devspace/dist/ui/assets/solarized-light-DSh2HLQt.js +1 -0
- package/vendor/devspace/dist/ui/assets/solidity-CKzVLygQ.js +1 -0
- package/vendor/devspace/dist/ui/assets/soy-BohVVlJU.js +1 -0
- package/vendor/devspace/dist/ui/assets/sparql-D_iOobhT.js +1 -0
- package/vendor/devspace/dist/ui/assets/splunk-BC2Px7Mm.js +1 -0
- package/vendor/devspace/dist/ui/assets/sql-CnK9R2Gt.js +1 -0
- package/vendor/devspace/dist/ui/assets/ssh-config-BgfXC-Er.js +1 -0
- package/vendor/devspace/dist/ui/assets/stata-D-sV4Vbr.js +1 -0
- package/vendor/devspace/dist/ui/assets/stylus-B6D30XZt.js +1 -0
- package/vendor/devspace/dist/ui/assets/surrealql-ChAy0gHv.js +1 -0
- package/vendor/devspace/dist/ui/assets/svelte-3HBVqG-H.js +1 -0
- package/vendor/devspace/dist/ui/assets/swift-DonLKvLd.js +1 -0
- package/vendor/devspace/dist/ui/assets/synthwave-84-nFMaYfgc.js +1 -0
- package/vendor/devspace/dist/ui/assets/system-verilog-DJ5XKQeo.js +1 -0
- package/vendor/devspace/dist/ui/assets/systemd-BxMlprV5.js +1 -0
- package/vendor/devspace/dist/ui/assets/talonscript-CohzipZa.js +1 -0
- package/vendor/devspace/dist/ui/assets/tasl-DMoTqEGO.js +1 -0
- package/vendor/devspace/dist/ui/assets/tcl-CZd0xW_V.js +1 -0
- package/vendor/devspace/dist/ui/assets/templ-BixlV4Cp.js +1 -0
- package/vendor/devspace/dist/ui/assets/terraform-DswuEJGm.js +1 -0
- package/vendor/devspace/dist/ui/assets/tex-DWoJKHvD.js +1 -0
- package/vendor/devspace/dist/ui/assets/tokyo-night-oM2G3aXe.js +1 -0
- package/vendor/devspace/dist/ui/assets/toml-CcmNWLt0.js +1 -0
- package/vendor/devspace/dist/ui/assets/ts-tags-DLA8eH13.js +1 -0
- package/vendor/devspace/dist/ui/assets/tsv-sltzmVWM.js +1 -0
- package/vendor/devspace/dist/ui/assets/tsx-BYWa5JUz.js +1 -0
- package/vendor/devspace/dist/ui/assets/turtle-ByJddavk.js +1 -0
- package/vendor/devspace/dist/ui/assets/twig-CnY65vAo.js +1 -0
- package/vendor/devspace/dist/ui/assets/typescript-ByInUsro.js +1 -0
- package/vendor/devspace/dist/ui/assets/typespec-B88KGewJ.js +1 -0
- package/vendor/devspace/dist/ui/assets/typst-DI99ib-x.js +1 -0
- package/vendor/devspace/dist/ui/assets/useFileDiffInstance-Dg0pWcJV.js +244 -0
- package/vendor/devspace/dist/ui/assets/v-DETTlOr0.js +1 -0
- package/vendor/devspace/dist/ui/assets/vala-zf12oZj6.js +1 -0
- package/vendor/devspace/dist/ui/assets/vb-Djn5o6TS.js +1 -0
- package/vendor/devspace/dist/ui/assets/verilog-CiiDBU1e.js +1 -0
- package/vendor/devspace/dist/ui/assets/vesper-D5bVUKB1.js +1 -0
- package/vendor/devspace/dist/ui/assets/vhdl-BroJfC0k.js +1 -0
- package/vendor/devspace/dist/ui/assets/viml-DvXPmvsu.js +1 -0
- package/vendor/devspace/dist/ui/assets/vitesse-black-fwtXNY1n.js +1 -0
- package/vendor/devspace/dist/ui/assets/vitesse-dark-BZCL-v6S.js +1 -0
- package/vendor/devspace/dist/ui/assets/vitesse-light-VbXTXTou.js +1 -0
- package/vendor/devspace/dist/ui/assets/vue-Qngt2rkz.js +1 -0
- package/vendor/devspace/dist/ui/assets/vue-html-DDue9upr.js +1 -0
- package/vendor/devspace/dist/ui/assets/vue-vine-DBcAKsA6.js +1 -0
- package/vendor/devspace/dist/ui/assets/vyper-CgoNMtux.js +1 -0
- package/vendor/devspace/dist/ui/assets/wasm-BnjxR4X6.js +1 -0
- package/vendor/devspace/dist/ui/assets/wasm-ByWQv1Qj.js +1 -0
- package/vendor/devspace/dist/ui/assets/wenyan-C8pVoKbM.js +1 -0
- package/vendor/devspace/dist/ui/assets/wgsl-BsKzXJz4.js +1 -0
- package/vendor/devspace/dist/ui/assets/wikitext-ClFFjSW2.js +1 -0
- package/vendor/devspace/dist/ui/assets/wit-DdvCle-K.js +1 -0
- package/vendor/devspace/dist/ui/assets/wolfram-DLL8P-h_.js +1 -0
- package/vendor/devspace/dist/ui/assets/workspace-app-DGD9R89D.css +1 -0
- package/vendor/devspace/dist/ui/assets/workspace-app-DuzpU4Hf.js +118 -0
- package/vendor/devspace/dist/ui/assets/xml-CRLR5jiL.js +1 -0
- package/vendor/devspace/dist/ui/assets/xsl-CmcwyXbm.js +1 -0
- package/vendor/devspace/dist/ui/assets/yaml-Dpe6Eg-k.js +1 -0
- package/vendor/devspace/dist/ui/assets/zenscript-BnlCZFoB.js +1 -0
- package/vendor/devspace/dist/ui/assets/zig-CMLA9XwU.js +1 -0
- package/vendor/devspace/dist/ui/workspace-app.html +15 -0
- package/vendor/devspace/dist/user-config.js +57 -0
- package/vendor/devspace/dist/workspace-store.js +75 -0
- package/vendor/devspace/dist/workspaces.js +226 -0
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
import { timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { loadDevspaceFiles, writeDevspaceConfig, } from "./user-config.js";
|
|
3
|
+
const toolNamingOptions = ["short", "legacy"];
|
|
4
|
+
const widgetOptions = ["full", "changes", "off"];
|
|
5
|
+
const logLevelOptions = ["silent", "error", "warn", "info", "debug"];
|
|
6
|
+
const logFormatOptions = ["json", "pretty"];
|
|
7
|
+
const routeTunnelOptions = ["manual", "cloudflare-named", "ngrok"];
|
|
8
|
+
export function localHttpOrigin(config) {
|
|
9
|
+
const host = config.host === "0.0.0.0" || config.host === "::"
|
|
10
|
+
? "127.0.0.1"
|
|
11
|
+
: config.host;
|
|
12
|
+
const formattedHost = host.includes(":") && !host.startsWith("[")
|
|
13
|
+
? `[${host}]`
|
|
14
|
+
: host;
|
|
15
|
+
return `http://${formattedHost}:${config.port}`;
|
|
16
|
+
}
|
|
17
|
+
export function localDashboardUrl(config) {
|
|
18
|
+
return `${localHttpOrigin(config)}/dashboard`;
|
|
19
|
+
}
|
|
20
|
+
export function dashboardModel(config) {
|
|
21
|
+
const localOrigin = localHttpOrigin(config);
|
|
22
|
+
return {
|
|
23
|
+
name: "DevSpace",
|
|
24
|
+
status: "online",
|
|
25
|
+
localDashboardUrl: `${localOrigin}/dashboard`,
|
|
26
|
+
localMcpUrl: `${localOrigin}/mcp`,
|
|
27
|
+
publicMcpUrl: new URL("/mcp", config.publicBaseUrl).toString(),
|
|
28
|
+
publicBaseUrl: config.publicBaseUrl,
|
|
29
|
+
host: config.host,
|
|
30
|
+
port: config.port,
|
|
31
|
+
allowedRoots: config.allowedRoots,
|
|
32
|
+
allowedHosts: config.allowedHosts,
|
|
33
|
+
widgets: config.widgets,
|
|
34
|
+
minimalTools: config.minimalTools,
|
|
35
|
+
toolNaming: config.toolNaming,
|
|
36
|
+
skillsEnabled: config.skillsEnabled,
|
|
37
|
+
skillPaths: config.skillPaths,
|
|
38
|
+
agentDir: config.agentDir,
|
|
39
|
+
stateDir: config.stateDir,
|
|
40
|
+
worktreeRoot: config.worktreeRoot,
|
|
41
|
+
logging: config.logging,
|
|
42
|
+
routes: config.routes,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function dashboardConfigPayload(config) {
|
|
46
|
+
const files = loadDevspaceFiles();
|
|
47
|
+
return {
|
|
48
|
+
runtime: dashboardModel(config),
|
|
49
|
+
persisted: files.config,
|
|
50
|
+
configPath: files.configPath,
|
|
51
|
+
authPath: files.authPath,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function isDashboardAuthorized(req, config) {
|
|
55
|
+
const token = dashboardTokenFromRequest(req);
|
|
56
|
+
if (!token)
|
|
57
|
+
return false;
|
|
58
|
+
return safeTokenEqual(token, config.oauth.ownerToken);
|
|
59
|
+
}
|
|
60
|
+
export function dashboardTokenFromRequest(req) {
|
|
61
|
+
const directToken = req.header("x-devspace-owner-token")?.trim();
|
|
62
|
+
if (directToken)
|
|
63
|
+
return directToken;
|
|
64
|
+
const authorization = req.header("authorization")?.trim();
|
|
65
|
+
if (!authorization)
|
|
66
|
+
return undefined;
|
|
67
|
+
const [scheme, ...rest] = authorization.split(/\s+/);
|
|
68
|
+
if (scheme?.toLowerCase() !== "bearer")
|
|
69
|
+
return undefined;
|
|
70
|
+
return rest.join(" ").trim() || undefined;
|
|
71
|
+
}
|
|
72
|
+
export function saveDashboardConfigFromBody(body) {
|
|
73
|
+
const files = loadDevspaceFiles();
|
|
74
|
+
const nextConfig = parseDashboardConfigUpdate(body, files.config);
|
|
75
|
+
const configPath = writeDevspaceConfig(nextConfig);
|
|
76
|
+
return { configPath, config: nextConfig };
|
|
77
|
+
}
|
|
78
|
+
export function parseDashboardConfigUpdate(body, currentConfig) {
|
|
79
|
+
const input = asObject(body, "request body");
|
|
80
|
+
const next = { ...currentConfig };
|
|
81
|
+
next.host = requiredString(input.host, "host");
|
|
82
|
+
next.port = requiredPort(input.port);
|
|
83
|
+
next.publicBaseUrl = optionalPublicBaseUrl(input.publicBaseUrl);
|
|
84
|
+
next.allowedRoots = stringArray(input.allowedRoots, "allowedRoots");
|
|
85
|
+
next.allowedHosts = stringArray(input.allowedHosts, "allowedHosts");
|
|
86
|
+
next.minimalTools = requiredBoolean(input.minimalTools, "minimalTools");
|
|
87
|
+
next.toolNaming = oneOf(input.toolNaming, toolNamingOptions, "toolNaming");
|
|
88
|
+
next.widgets = oneOf(input.widgets, widgetOptions, "widgets");
|
|
89
|
+
next.skillsEnabled = requiredBoolean(input.skillsEnabled, "skillsEnabled");
|
|
90
|
+
next.skillPaths = stringArray(input.skillPaths, "skillPaths");
|
|
91
|
+
next.agentDir = optionalNonEmptyString(input.agentDir, "agentDir");
|
|
92
|
+
next.stateDir = optionalNonEmptyString(input.stateDir, "stateDir");
|
|
93
|
+
next.worktreeRoot = optionalNonEmptyString(input.worktreeRoot, "worktreeRoot");
|
|
94
|
+
next.logging = parseLoggingConfig(input.logging);
|
|
95
|
+
next.routes = parseRoutesConfig(input.routes);
|
|
96
|
+
return next;
|
|
97
|
+
}
|
|
98
|
+
export function renderDashboardHtml() {
|
|
99
|
+
return `<!doctype html>
|
|
100
|
+
<html lang="zh-CN">
|
|
101
|
+
<head>
|
|
102
|
+
<meta charset="utf-8">
|
|
103
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
104
|
+
<title>DevSpace 控制台</title>
|
|
105
|
+
<style>
|
|
106
|
+
:root {
|
|
107
|
+
color-scheme: light dark;
|
|
108
|
+
--bg: #0b1020;
|
|
109
|
+
--panel: rgba(255, 255, 255, 0.08);
|
|
110
|
+
--panel-strong: rgba(255, 255, 255, 0.13);
|
|
111
|
+
--border: rgba(255, 255, 255, 0.14);
|
|
112
|
+
--text: #f6f7fb;
|
|
113
|
+
--muted: #aab3c8;
|
|
114
|
+
--accent: #8fd3ff;
|
|
115
|
+
--danger: #ff9a9a;
|
|
116
|
+
--success: #9ff0c0;
|
|
117
|
+
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
118
|
+
}
|
|
119
|
+
* { box-sizing: border-box; }
|
|
120
|
+
body {
|
|
121
|
+
margin: 0;
|
|
122
|
+
min-height: 100vh;
|
|
123
|
+
background:
|
|
124
|
+
radial-gradient(circle at top left, rgba(76, 140, 255, 0.34), transparent 34rem),
|
|
125
|
+
radial-gradient(circle at top right, rgba(69, 214, 178, 0.20), transparent 30rem),
|
|
126
|
+
var(--bg);
|
|
127
|
+
color: var(--text);
|
|
128
|
+
}
|
|
129
|
+
main { max-width: 1120px; margin: 0 auto; padding: 42px 22px 72px; }
|
|
130
|
+
header { display: flex; justify-content: space-between; gap: 24px; align-items: flex-start; margin-bottom: 28px; }
|
|
131
|
+
h1 { margin: 0; font-size: clamp(32px, 6vw, 56px); letter-spacing: -0.05em; }
|
|
132
|
+
h2 { margin: 0 0 14px; font-size: 18px; }
|
|
133
|
+
p { color: var(--muted); line-height: 1.65; }
|
|
134
|
+
.status-pill { display: inline-flex; gap: 8px; align-items: center; padding: 8px 12px; border: 1px solid var(--border); border-radius: 999px; background: var(--panel); color: var(--success); font-weight: 700; white-space: nowrap; }
|
|
135
|
+
.dot { width: 8px; height: 8px; border-radius: 999px; background: currentColor; box-shadow: 0 0 18px currentColor; }
|
|
136
|
+
.grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: 18px; }
|
|
137
|
+
.card { grid-column: span 12; padding: 20px; border: 1px solid var(--border); border-radius: 22px; background: var(--panel); backdrop-filter: blur(16px); box-shadow: 0 20px 60px rgba(0, 0, 0, 0.22); }
|
|
138
|
+
.half { grid-column: span 6; }
|
|
139
|
+
.third { grid-column: span 4; }
|
|
140
|
+
.field { display: grid; gap: 8px; margin-bottom: 14px; }
|
|
141
|
+
label { font-weight: 700; font-size: 13px; color: #e8ecf8; }
|
|
142
|
+
input, textarea, select {
|
|
143
|
+
width: 100%;
|
|
144
|
+
border: 1px solid var(--border);
|
|
145
|
+
border-radius: 13px;
|
|
146
|
+
background: rgba(0, 0, 0, 0.28);
|
|
147
|
+
color: var(--text);
|
|
148
|
+
padding: 11px 12px;
|
|
149
|
+
font: inherit;
|
|
150
|
+
}
|
|
151
|
+
textarea { min-height: 108px; resize: vertical; }
|
|
152
|
+
input[type="checkbox"] { width: auto; transform: translateY(1px); }
|
|
153
|
+
.checkbox { display: flex; align-items: center; gap: 10px; margin: 12px 0; color: var(--muted); }
|
|
154
|
+
.hint { color: var(--muted); font-size: 12px; line-height: 1.45; }
|
|
155
|
+
.actions { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin-top: 16px; }
|
|
156
|
+
button, .button {
|
|
157
|
+
border: 0;
|
|
158
|
+
border-radius: 999px;
|
|
159
|
+
background: #f6f7fb;
|
|
160
|
+
color: #0b1020;
|
|
161
|
+
font-weight: 800;
|
|
162
|
+
padding: 11px 16px;
|
|
163
|
+
cursor: pointer;
|
|
164
|
+
text-decoration: none;
|
|
165
|
+
display: inline-flex;
|
|
166
|
+
align-items: center;
|
|
167
|
+
gap: 8px;
|
|
168
|
+
}
|
|
169
|
+
button.secondary, .button.secondary { background: var(--panel-strong); color: var(--text); border: 1px solid var(--border); }
|
|
170
|
+
button:disabled { opacity: 0.55; cursor: wait; }
|
|
171
|
+
code, .mono { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; }
|
|
172
|
+
.kv { display: grid; gap: 10px; }
|
|
173
|
+
.kv div { display: grid; gap: 4px; padding: 11px; border-radius: 14px; background: rgba(0, 0, 0, 0.18); }
|
|
174
|
+
.kv span { color: var(--muted); font-size: 12px; }
|
|
175
|
+
.kv code { overflow-wrap: anywhere; }
|
|
176
|
+
.hidden { display: none !important; }
|
|
177
|
+
.notice { padding: 12px 14px; border-radius: 14px; border: 1px solid var(--border); color: var(--muted); background: rgba(0, 0, 0, 0.22); }
|
|
178
|
+
.notice.success { color: var(--success); }
|
|
179
|
+
.notice.error { color: var(--danger); }
|
|
180
|
+
.notice.warn { color: #ffd28f; }
|
|
181
|
+
@media (max-width: 820px) { .half, .third { grid-column: span 12; } header { flex-direction: column; } }
|
|
182
|
+
</style>
|
|
183
|
+
</head>
|
|
184
|
+
<body>
|
|
185
|
+
<main>
|
|
186
|
+
<header>
|
|
187
|
+
<section>
|
|
188
|
+
<h1>DevSpace 控制台</h1>
|
|
189
|
+
<p>把原来需要在终端里完成的连接、权限、工具和日志配置,集中到一个本地可视化页面里。</p>
|
|
190
|
+
</section>
|
|
191
|
+
<div class="status-pill"><span class="dot"></span><span id="statusText">加载中</span></div>
|
|
192
|
+
</header>
|
|
193
|
+
|
|
194
|
+
<section id="dashboard">
|
|
195
|
+
<div class="grid">
|
|
196
|
+
<section class="card third">
|
|
197
|
+
<h2>连接地址</h2>
|
|
198
|
+
<div class="kv">
|
|
199
|
+
<div><span>本地 Dashboard</span><code id="localDashboardUrl">-</code></div>
|
|
200
|
+
<div><span>本地 MCP</span><code id="localMcpUrl">-</code></div>
|
|
201
|
+
<div><span>公开 MCP</span><code id="publicMcpUrl">-</code></div>
|
|
202
|
+
</div>
|
|
203
|
+
</section>
|
|
204
|
+
|
|
205
|
+
<section class="card third">
|
|
206
|
+
<h2>运行状态</h2>
|
|
207
|
+
<div class="kv">
|
|
208
|
+
<div><span>Host / Port</span><code id="hostPort">-</code></div>
|
|
209
|
+
<div><span>工具模式</span><code id="toolModeText">-</code></div>
|
|
210
|
+
<div><span>配置文件</span><code id="configPath">-</code></div>
|
|
211
|
+
</div>
|
|
212
|
+
</section>
|
|
213
|
+
|
|
214
|
+
<section class="card third">
|
|
215
|
+
<h2>保存提示</h2>
|
|
216
|
+
<p class="notice warn">修改保存后会写入 <code>~/.devspace/config.json</code>。端口、权限、工具等运行时配置通常需要重启 DevSpace 后生效。</p>
|
|
217
|
+
</section>
|
|
218
|
+
|
|
219
|
+
<form id="configForm" class="card grid">
|
|
220
|
+
<section class="half">
|
|
221
|
+
<h2>连接配置</h2>
|
|
222
|
+
<div class="field"><label for="host">监听 Host</label><input id="host" name="host" placeholder="127.0.0.1"></div>
|
|
223
|
+
<div class="field"><label for="port">端口</label><input id="port" name="port" type="number" min="1" max="65535" placeholder="7676"></div>
|
|
224
|
+
<div class="field"><label for="publicBaseUrl">Public Base URL</label><input id="publicBaseUrl" name="publicBaseUrl" placeholder="https://your-tunnel.example.com"><span class="hint">填公开 HTTPS origin,不要带 /mcp。留空则使用本地地址。</span></div>
|
|
225
|
+
<div class="field"><label for="allowedHosts">Allowed Hosts,一行一个</label><textarea id="allowedHosts" name="allowedHosts" spellcheck="false"></textarea></div>
|
|
226
|
+
</section>
|
|
227
|
+
|
|
228
|
+
<section class="half">
|
|
229
|
+
<h2>权限配置</h2>
|
|
230
|
+
<div class="field"><label for="allowedRoots">允许访问的本地目录,一行一个</label><textarea id="allowedRoots" name="allowedRoots" spellcheck="false"></textarea><span class="hint">DevSpace 只能打开这里列出的目录或其子目录。</span></div>
|
|
231
|
+
<div class="field"><label for="worktreeRoot">Worktree 目录</label><input id="worktreeRoot" name="worktreeRoot" spellcheck="false"></div>
|
|
232
|
+
<div class="field"><label for="stateDir">状态目录</label><input id="stateDir" name="stateDir" spellcheck="false"></div>
|
|
233
|
+
</section>
|
|
234
|
+
|
|
235
|
+
<section class="half">
|
|
236
|
+
<h2>工具与界面</h2>
|
|
237
|
+
<div class="field"><label for="toolMode">工具模式</label><select id="toolMode" name="toolMode"><option value="minimal">Minimal:精简工具</option><option value="full">Full:完整工具</option></select></div>
|
|
238
|
+
<div class="field"><label for="toolNaming">工具命名</label><select id="toolNaming" name="toolNaming"><option value="short">Short:read / edit / bash</option><option value="legacy">Legacy:read_file / edit_file / run_shell</option></select></div>
|
|
239
|
+
<div class="field"><label for="widgets">ChatGPT 工具卡片</label><select id="widgets" name="widgets"><option value="full">Full:所有工具卡片</option><option value="changes">Changes:只显示变更汇总</option><option value="off">Off:关闭卡片</option></select></div>
|
|
240
|
+
<label class="checkbox"><input id="skillsEnabled" name="skillsEnabled" type="checkbox">启用本地 skills</label>
|
|
241
|
+
<div class="field"><label for="skillPaths">额外 Skill 路径,一行一个</label><textarea id="skillPaths" name="skillPaths" spellcheck="false"></textarea></div>
|
|
242
|
+
<div class="field"><label for="agentDir">Agent 目录</label><input id="agentDir" name="agentDir" spellcheck="false"></div>
|
|
243
|
+
</section>
|
|
244
|
+
|
|
245
|
+
<section class="half">
|
|
246
|
+
<h2>日志</h2>
|
|
247
|
+
<div class="field"><label for="logLevel">日志等级</label><select id="logLevel" name="logLevel"><option>silent</option><option>error</option><option>warn</option><option selected>info</option><option>debug</option></select></div>
|
|
248
|
+
<div class="field"><label for="logFormat">日志格式</label><select id="logFormat" name="logFormat"><option>json</option><option>pretty</option></select></div>
|
|
249
|
+
<label class="checkbox"><input id="logRequests" type="checkbox">记录 HTTP 请求</label>
|
|
250
|
+
<label class="checkbox"><input id="logToolCalls" type="checkbox">记录工具调用</label>
|
|
251
|
+
<label class="checkbox"><input id="logAssets" type="checkbox">记录静态资源请求</label>
|
|
252
|
+
<label class="checkbox"><input id="logShellCommands" type="checkbox">记录 shell 命令预览</label>
|
|
253
|
+
<label class="checkbox"><input id="trustProxy" type="checkbox">信任反向代理</label>
|
|
254
|
+
</section>
|
|
255
|
+
|
|
256
|
+
<section class="card" style="grid-column: span 12;">
|
|
257
|
+
<h2>域名 / 路由注册表</h2>
|
|
258
|
+
<p>这里登记多个 ChatGPT 应用入口:一个路由对应一个本地 DevSpace 端口、一个允许目录和一个公开域名。当前版本先保存注册表;后续可在这里接入 Cloudflare named tunnel / ngrok 的一键创建与启动。</p>
|
|
259
|
+
<div class="field">
|
|
260
|
+
<label for="routesJson">Routes JSON</label>
|
|
261
|
+
<textarea id="routesJson" name="routesJson" class="mono" spellcheck="false" style="min-height: 220px;"></textarea>
|
|
262
|
+
<span class="hint">示例:[{"name":"eto","root":"/Users/Zhuanz/Documents/eto","port":8787,"hostname":"eto.omji.top","tunnel":"cloudflare-named","enabled":true}]</span>
|
|
263
|
+
</div>
|
|
264
|
+
</section>
|
|
265
|
+
|
|
266
|
+
<section class="card" style="grid-column: span 12; padding: 0; border: 0; background: transparent; box-shadow: none;">
|
|
267
|
+
<div class="actions">
|
|
268
|
+
<button id="saveButton" type="submit">保存配置</button>
|
|
269
|
+
<button id="reloadButton" class="secondary" type="button">重新读取</button>
|
|
270
|
+
<a id="openMcpLink" class="button secondary" href="/mcp" target="_blank" rel="noreferrer">打开 MCP 地址</a>
|
|
271
|
+
</div>
|
|
272
|
+
<p id="saveMessage" class="notice hidden"></p>
|
|
273
|
+
</section>
|
|
274
|
+
</form>
|
|
275
|
+
</div>
|
|
276
|
+
</section>
|
|
277
|
+
</main>
|
|
278
|
+
|
|
279
|
+
<script>
|
|
280
|
+
const $ = (id) => document.getElementById(id);
|
|
281
|
+
const fields = ["host", "port", "publicBaseUrl", "allowedHosts", "allowedRoots", "worktreeRoot", "stateDir", "toolMode", "toolNaming", "widgets", "skillsEnabled", "skillPaths", "agentDir", "logLevel", "logFormat", "logRequests", "logToolCalls", "logAssets", "logShellCommands", "trustProxy", "routesJson"];
|
|
282
|
+
|
|
283
|
+
function lines(value) { return String(value || "").split(/\\n+/).map((line) => line.trim()).filter(Boolean); }
|
|
284
|
+
function setLines(id, value) { $(id).value = Array.isArray(value) ? value.join("\\n") : ""; }
|
|
285
|
+
function setJson(id, value) { $(id).value = JSON.stringify(value || [], null, 2); }
|
|
286
|
+
function readJson(id) {
|
|
287
|
+
const raw = $(id).value.trim();
|
|
288
|
+
if (!raw) return [];
|
|
289
|
+
return JSON.parse(raw);
|
|
290
|
+
}
|
|
291
|
+
function showMessage(id, text, tone) {
|
|
292
|
+
const el = $(id);
|
|
293
|
+
el.textContent = text;
|
|
294
|
+
el.className = "notice " + (tone || "");
|
|
295
|
+
el.classList.remove("hidden");
|
|
296
|
+
}
|
|
297
|
+
function hideMessage(id) { $(id).classList.add("hidden"); }
|
|
298
|
+
function setBusy(isBusy) {
|
|
299
|
+
$("saveButton").disabled = isBusy;
|
|
300
|
+
$("reloadButton").disabled = isBusy;
|
|
301
|
+
}
|
|
302
|
+
async function api(path, options) {
|
|
303
|
+
const headers = Object.assign({}, options && options.headers ? options.headers : {});
|
|
304
|
+
const response = await fetch(path, Object.assign({}, options, { headers }));
|
|
305
|
+
const json = await response.json().catch(() => ({}));
|
|
306
|
+
if (!response.ok) throw new Error(json.error || ("HTTP " + response.status));
|
|
307
|
+
return json;
|
|
308
|
+
}
|
|
309
|
+
function fillForm(payload) {
|
|
310
|
+
const runtime = payload.runtime;
|
|
311
|
+
const persisted = payload.persisted || {};
|
|
312
|
+
$("statusText").textContent = runtime.status;
|
|
313
|
+
$("localDashboardUrl").textContent = runtime.localDashboardUrl;
|
|
314
|
+
$("localMcpUrl").textContent = runtime.localMcpUrl;
|
|
315
|
+
$("publicMcpUrl").textContent = runtime.publicMcpUrl;
|
|
316
|
+
$("hostPort").textContent = runtime.host + ":" + runtime.port;
|
|
317
|
+
$("toolModeText").textContent = runtime.minimalTools ? "minimal" : "full";
|
|
318
|
+
$("configPath").textContent = payload.configPath;
|
|
319
|
+
$("openMcpLink").href = runtime.localMcpUrl;
|
|
320
|
+
|
|
321
|
+
$("host").value = persisted.host || runtime.host || "127.0.0.1";
|
|
322
|
+
$("port").value = persisted.port || runtime.port || 7676;
|
|
323
|
+
$("publicBaseUrl").value = persisted.publicBaseUrl || runtime.publicBaseUrl || "";
|
|
324
|
+
setLines("allowedHosts", persisted.allowedHosts || runtime.allowedHosts || []);
|
|
325
|
+
setLines("allowedRoots", persisted.allowedRoots || runtime.allowedRoots || []);
|
|
326
|
+
$("worktreeRoot").value = persisted.worktreeRoot || runtime.worktreeRoot || "";
|
|
327
|
+
$("stateDir").value = persisted.stateDir || runtime.stateDir || "";
|
|
328
|
+
$("toolMode").value = (persisted.minimalTools ?? runtime.minimalTools) ? "minimal" : "full";
|
|
329
|
+
$("toolNaming").value = persisted.toolNaming || runtime.toolNaming || "short";
|
|
330
|
+
$("widgets").value = persisted.widgets || runtime.widgets || "full";
|
|
331
|
+
$("skillsEnabled").checked = persisted.skillsEnabled ?? runtime.skillsEnabled ?? true;
|
|
332
|
+
setLines("skillPaths", persisted.skillPaths || runtime.skillPaths || []);
|
|
333
|
+
$("agentDir").value = persisted.agentDir || runtime.agentDir || "";
|
|
334
|
+
const logging = Object.assign({}, runtime.logging || {}, persisted.logging || {});
|
|
335
|
+
$("logLevel").value = logging.level || "info";
|
|
336
|
+
$("logFormat").value = logging.format || "json";
|
|
337
|
+
$("logRequests").checked = logging.requests ?? true;
|
|
338
|
+
$("logToolCalls").checked = logging.toolCalls ?? true;
|
|
339
|
+
$("logAssets").checked = logging.assets ?? false;
|
|
340
|
+
$("logShellCommands").checked = logging.shellCommands ?? false;
|
|
341
|
+
$("trustProxy").checked = logging.trustProxy ?? false;
|
|
342
|
+
setJson("routesJson", persisted.routes || runtime.routes || []);
|
|
343
|
+
}
|
|
344
|
+
function collectForm() {
|
|
345
|
+
const publicBaseUrl = $("publicBaseUrl").value.trim();
|
|
346
|
+
return {
|
|
347
|
+
host: $("host").value.trim(),
|
|
348
|
+
port: Number($("port").value),
|
|
349
|
+
publicBaseUrl: publicBaseUrl || null,
|
|
350
|
+
allowedRoots: lines($("allowedRoots").value),
|
|
351
|
+
allowedHosts: lines($("allowedHosts").value),
|
|
352
|
+
minimalTools: $("toolMode").value === "minimal",
|
|
353
|
+
toolNaming: $("toolNaming").value,
|
|
354
|
+
widgets: $("widgets").value,
|
|
355
|
+
skillsEnabled: $("skillsEnabled").checked,
|
|
356
|
+
skillPaths: lines($("skillPaths").value),
|
|
357
|
+
agentDir: $("agentDir").value.trim() || undefined,
|
|
358
|
+
stateDir: $("stateDir").value.trim() || undefined,
|
|
359
|
+
worktreeRoot: $("worktreeRoot").value.trim() || undefined,
|
|
360
|
+
logging: {
|
|
361
|
+
level: $("logLevel").value,
|
|
362
|
+
format: $("logFormat").value,
|
|
363
|
+
requests: $("logRequests").checked,
|
|
364
|
+
toolCalls: $("logToolCalls").checked,
|
|
365
|
+
assets: $("logAssets").checked,
|
|
366
|
+
shellCommands: $("logShellCommands").checked,
|
|
367
|
+
trustProxy: $("trustProxy").checked
|
|
368
|
+
},
|
|
369
|
+
routes: readJson("routesJson")
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
async function loadConfig() {
|
|
373
|
+
setBusy(true);
|
|
374
|
+
try {
|
|
375
|
+
const payload = await api("/dashboard/api/config");
|
|
376
|
+
fillForm(payload);
|
|
377
|
+
$("dashboard").classList.remove("hidden");
|
|
378
|
+
showMessage("saveMessage", "配置已读取。", "success");
|
|
379
|
+
} catch (error) {
|
|
380
|
+
showMessage("saveMessage", error.message || String(error), "error");
|
|
381
|
+
$("statusText").textContent = "加载失败";
|
|
382
|
+
} finally {
|
|
383
|
+
setBusy(false);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
async function saveConfig(event) {
|
|
387
|
+
event.preventDefault();
|
|
388
|
+
setBusy(true);
|
|
389
|
+
try {
|
|
390
|
+
await api("/dashboard/api/config", {
|
|
391
|
+
method: "PUT",
|
|
392
|
+
headers: { "content-type": "application/json" },
|
|
393
|
+
body: JSON.stringify(collectForm())
|
|
394
|
+
});
|
|
395
|
+
showMessage("saveMessage", "已保存到配置文件。请重启 DevSpace 让所有改动生效。", "success");
|
|
396
|
+
await loadConfig();
|
|
397
|
+
} catch (error) {
|
|
398
|
+
showMessage("saveMessage", error.message || String(error), "error");
|
|
399
|
+
} finally {
|
|
400
|
+
setBusy(false);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
$("reloadButton").addEventListener("click", loadConfig);
|
|
405
|
+
$("configForm").addEventListener("submit", saveConfig);
|
|
406
|
+
loadConfig();
|
|
407
|
+
</script>
|
|
408
|
+
</body>
|
|
409
|
+
</html>`;
|
|
410
|
+
}
|
|
411
|
+
function safeTokenEqual(left, right) {
|
|
412
|
+
const leftBuffer = Buffer.from(left);
|
|
413
|
+
const rightBuffer = Buffer.from(right);
|
|
414
|
+
if (leftBuffer.length !== rightBuffer.length)
|
|
415
|
+
return false;
|
|
416
|
+
return timingSafeEqual(leftBuffer, rightBuffer);
|
|
417
|
+
}
|
|
418
|
+
function asObject(value, field) {
|
|
419
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
420
|
+
throw new Error(`${field} must be an object.`);
|
|
421
|
+
}
|
|
422
|
+
return value;
|
|
423
|
+
}
|
|
424
|
+
function requiredString(value, field) {
|
|
425
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
426
|
+
throw new Error(`${field} must be a non-empty string.`);
|
|
427
|
+
}
|
|
428
|
+
return value.trim();
|
|
429
|
+
}
|
|
430
|
+
function optionalNonEmptyString(value, field) {
|
|
431
|
+
if (value === undefined || value === null || value === "")
|
|
432
|
+
return undefined;
|
|
433
|
+
return requiredString(value, field);
|
|
434
|
+
}
|
|
435
|
+
function requiredPort(value) {
|
|
436
|
+
const port = typeof value === "number" ? value : Number(value);
|
|
437
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
438
|
+
throw new Error("port must be an integer between 1 and 65535.");
|
|
439
|
+
}
|
|
440
|
+
return port;
|
|
441
|
+
}
|
|
442
|
+
function requiredBoolean(value, field) {
|
|
443
|
+
if (typeof value !== "boolean") {
|
|
444
|
+
throw new Error(`${field} must be a boolean.`);
|
|
445
|
+
}
|
|
446
|
+
return value;
|
|
447
|
+
}
|
|
448
|
+
function stringArray(value, field) {
|
|
449
|
+
if (!Array.isArray(value)) {
|
|
450
|
+
throw new Error(`${field} must be an array of strings.`);
|
|
451
|
+
}
|
|
452
|
+
return value.map((item) => {
|
|
453
|
+
if (typeof item !== "string") {
|
|
454
|
+
throw new Error(`${field} must be an array of strings.`);
|
|
455
|
+
}
|
|
456
|
+
return item.trim();
|
|
457
|
+
}).filter(Boolean);
|
|
458
|
+
}
|
|
459
|
+
function optionalPublicBaseUrl(value) {
|
|
460
|
+
if (value === null || value === undefined || value === "")
|
|
461
|
+
return null;
|
|
462
|
+
if (typeof value !== "string")
|
|
463
|
+
throw new Error("publicBaseUrl must be a string or null.");
|
|
464
|
+
return normalizeBaseUrl(value, "publicBaseUrl");
|
|
465
|
+
}
|
|
466
|
+
function normalizeBaseUrl(value, field) {
|
|
467
|
+
const parsed = new URL(value);
|
|
468
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
469
|
+
throw new Error(`${field} must use http or https.`);
|
|
470
|
+
}
|
|
471
|
+
parsed.hash = "";
|
|
472
|
+
parsed.search = "";
|
|
473
|
+
parsed.pathname = parsed.pathname.replace(/\/+$/, "");
|
|
474
|
+
if (parsed.pathname.endsWith("/mcp")) {
|
|
475
|
+
throw new Error(`${field} must be the base URL without /mcp.`);
|
|
476
|
+
}
|
|
477
|
+
return parsed.toString().replace(/\/$/, "");
|
|
478
|
+
}
|
|
479
|
+
function parseRoutesConfig(value) {
|
|
480
|
+
if (value === undefined || value === null)
|
|
481
|
+
return [];
|
|
482
|
+
if (!Array.isArray(value))
|
|
483
|
+
throw new Error("routes must be an array.");
|
|
484
|
+
const seenNames = new Set();
|
|
485
|
+
const seenPorts = new Set();
|
|
486
|
+
const seenHosts = new Set();
|
|
487
|
+
return value.map((entry, index) => {
|
|
488
|
+
const route = asObject(entry, `routes[${index}]`);
|
|
489
|
+
const name = requiredString(route.name, `routes[${index}].name`);
|
|
490
|
+
const root = requiredString(route.root, `routes[${index}].root`);
|
|
491
|
+
const port = requiredPort(route.port);
|
|
492
|
+
const hostname = requiredHostname(route.hostname, `routes[${index}].hostname`);
|
|
493
|
+
const tunnel = oneOf(route.tunnel ?? "manual", routeTunnelOptions, `routes[${index}].tunnel`);
|
|
494
|
+
const publicBaseUrl = route.publicBaseUrl === undefined || route.publicBaseUrl === null || route.publicBaseUrl === ""
|
|
495
|
+
? `https://${hostname}`
|
|
496
|
+
: normalizeBaseUrl(requiredString(route.publicBaseUrl, `routes[${index}].publicBaseUrl`), `routes[${index}].publicBaseUrl`);
|
|
497
|
+
if (seenNames.has(name))
|
|
498
|
+
throw new Error(`Duplicate route name: ${name}`);
|
|
499
|
+
if (seenPorts.has(port))
|
|
500
|
+
throw new Error(`Duplicate route port: ${port}`);
|
|
501
|
+
if (seenHosts.has(hostname))
|
|
502
|
+
throw new Error(`Duplicate route hostname: ${hostname}`);
|
|
503
|
+
seenNames.add(name);
|
|
504
|
+
seenPorts.add(port);
|
|
505
|
+
seenHosts.add(hostname);
|
|
506
|
+
return {
|
|
507
|
+
name,
|
|
508
|
+
root,
|
|
509
|
+
port,
|
|
510
|
+
hostname,
|
|
511
|
+
tunnel,
|
|
512
|
+
publicBaseUrl,
|
|
513
|
+
subdomain: optionalNonEmptyString(route.subdomain, `routes[${index}].subdomain`),
|
|
514
|
+
tunnelName: optionalNonEmptyString(route.tunnelName, `routes[${index}].tunnelName`),
|
|
515
|
+
tunnelId: optionalNonEmptyString(route.tunnelId, `routes[${index}].tunnelId`),
|
|
516
|
+
cloudflareConfig: optionalNonEmptyString(route.cloudflareConfig, `routes[${index}].cloudflareConfig`),
|
|
517
|
+
enabled: route.enabled === undefined ? true : requiredBoolean(route.enabled, `routes[${index}].enabled`),
|
|
518
|
+
};
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
function requiredHostname(value, field) {
|
|
522
|
+
const hostname = requiredString(value, field).toLowerCase();
|
|
523
|
+
if (!/^[a-z0-9]([a-z0-9.-]{0,251}[a-z0-9])?$/.test(hostname) || !hostname.includes(".")) {
|
|
524
|
+
throw new Error(`${field} must be a valid DNS hostname.`);
|
|
525
|
+
}
|
|
526
|
+
return hostname;
|
|
527
|
+
}
|
|
528
|
+
function oneOf(value, options, field) {
|
|
529
|
+
if (typeof value !== "string" || !options.includes(value)) {
|
|
530
|
+
throw new Error(`${field} must be one of: ${options.join(", ")}.`);
|
|
531
|
+
}
|
|
532
|
+
return value;
|
|
533
|
+
}
|
|
534
|
+
function parseLoggingConfig(value) {
|
|
535
|
+
const input = asObject(value, "logging");
|
|
536
|
+
return {
|
|
537
|
+
level: oneOf(input.level, logLevelOptions, "logging.level"),
|
|
538
|
+
format: oneOf(input.format, logFormatOptions, "logging.format"),
|
|
539
|
+
requests: requiredBoolean(input.requests, "logging.requests"),
|
|
540
|
+
assets: requiredBoolean(input.assets, "logging.assets"),
|
|
541
|
+
toolCalls: requiredBoolean(input.toolCalls, "logging.toolCalls"),
|
|
542
|
+
shellCommands: requiredBoolean(input.shellCommands, "logging.shellCommands"),
|
|
543
|
+
trustProxy: requiredBoolean(input.trustProxy, "logging.trustProxy"),
|
|
544
|
+
};
|
|
545
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { chmodSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import Database from "better-sqlite3";
|
|
4
|
+
import { drizzle } from "drizzle-orm/better-sqlite3";
|
|
5
|
+
import * as schema from "./schema.js";
|
|
6
|
+
import { migrateDatabase } from "./migrations.js";
|
|
7
|
+
export function databasePath(stateDir) {
|
|
8
|
+
return join(stateDir, "devspace.sqlite");
|
|
9
|
+
}
|
|
10
|
+
export function openDatabase(stateDir) {
|
|
11
|
+
mkdirSync(stateDir, { recursive: true, mode: 0o700 });
|
|
12
|
+
chmodSync(stateDir, 0o700);
|
|
13
|
+
const path = databasePath(stateDir);
|
|
14
|
+
const sqlite = new Database(path);
|
|
15
|
+
chmodSync(path, 0o600);
|
|
16
|
+
sqlite.pragma("journal_mode = WAL");
|
|
17
|
+
sqlite.pragma("synchronous = NORMAL");
|
|
18
|
+
sqlite.pragma("busy_timeout = 5000");
|
|
19
|
+
sqlite.pragma("foreign_keys = ON");
|
|
20
|
+
migrateDatabase(sqlite);
|
|
21
|
+
return {
|
|
22
|
+
sqlite,
|
|
23
|
+
db: createDrizzleDatabase(sqlite),
|
|
24
|
+
close: () => sqlite.close(),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function createDrizzleDatabase(sqlite) {
|
|
28
|
+
return drizzle(sqlite, { schema });
|
|
29
|
+
}
|