remote-codex 0.11.1 → 0.11.2
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/apps/supervisor-api/dist/index.js +2271 -773
- package/apps/supervisor-web/dist/assets/core-DIQen2lE.js +12 -0
- package/apps/supervisor-web/dist/assets/{css-DPfMkruS.js → css-CLj8gQPS.js} +1 -1
- package/apps/supervisor-web/dist/assets/engine-javascript-DBd1bXLz.js +141 -0
- package/apps/supervisor-web/dist/assets/graph-vendor-C5ap-Sga.css +1 -0
- package/apps/supervisor-web/dist/assets/graph-vendor-CGzY-MFv.js +23 -0
- package/apps/supervisor-web/dist/assets/{html-GMplVEZG.js → html-pp8916En.js} +1 -1
- package/apps/supervisor-web/dist/assets/index-CbDzXN9T.css +1 -0
- package/apps/supervisor-web/dist/assets/index-DQpHiQXN.js +4 -0
- package/apps/supervisor-web/dist/assets/markdown-vendor-hBDTCSB-.js +291 -0
- package/apps/supervisor-web/dist/assets/react-vendor-o1Xrx7m4.js +60 -0
- package/apps/supervisor-web/dist/assets/{shellscript-Yzrsuije.js → shellscript-CEILq0vU.js} +1 -1
- package/apps/supervisor-web/dist/assets/{sql-BLtJtn59.js → sql-CRqJ_cUM.js} +1 -1
- package/apps/supervisor-web/dist/assets/terminal-vendor-Beg8tuEN.css +32 -0
- package/apps/supervisor-web/dist/assets/{xterm-D92BViLH.js → terminal-vendor-CLGgN91S.js} +17 -6
- package/apps/supervisor-web/dist/assets/thread-ui-BEieA99i.css +1 -0
- package/apps/supervisor-web/dist/assets/thread-ui-CDk3ExRH.js +3516 -0
- package/apps/supervisor-web/dist/assets/ui-vendor-CgOZX1B8.js +425 -0
- package/apps/supervisor-web/dist/index.html +11 -2
- package/apps/supervisor-web/dist/vendor/3Dmol-min.js +2 -0
- package/bin/remote-codex-plugin-mcp.mjs +140 -0
- package/package.json +6 -1
- package/packages/agent-runtime/src/types.ts +1 -0
- package/packages/agent-runtime/src/unavailable-runtime.ts +5 -13
- package/packages/claude/src/runtimeAdapter.ts +7 -5
- package/packages/codex/src/appServerManager.ts +3 -3
- package/packages/codex/src/historyItems.test.ts +2 -4
- package/packages/codex/src/historyItems.ts +13 -18
- package/packages/codex/src/runtime-errors.ts +0 -5
- package/packages/codex/src/runtimeAdapter.ts +3 -0
- package/packages/codex/src/types.ts +1 -0
- package/packages/db/migrations/0018_shell_session_label.sql +1 -0
- package/packages/db/src/repositories.ts +12 -0
- package/packages/db/src/schema.ts +1 -0
- package/packages/opencode/src/historyItems.ts +0 -17
- package/packages/plugin-terminal/package.json +17 -0
- package/packages/plugin-terminal/plugin.json +25 -0
- package/packages/plugin-terminal/src/index.ts +2 -0
- package/packages/plugin-terminal/src/manifest.ts +51 -0
- package/packages/shared/src/index.ts +59 -0
- package/apps/supervisor-api/dist/chunk-6M32PPHZ.js +0 -24507
- package/apps/supervisor-api/dist/chunk-7AA2MFXK.js +0 -24499
- package/apps/supervisor-api/dist/chunk-HKBFCPHH.js +0 -24511
- package/apps/supervisor-api/dist/worker-index.d.ts +0 -2
- package/apps/supervisor-api/dist/worker-index.js +0 -33
- package/apps/supervisor-web/dist/assets/abap-BdImnpbu.js +0 -1
- package/apps/supervisor-web/dist/assets/actionscript-3-CoDkCxhg.js +0 -1
- package/apps/supervisor-web/dist/assets/ada-bCR0ucgS.js +0 -1
- package/apps/supervisor-web/dist/assets/addon-fit-YJmn1quW.js +0 -12
- package/apps/supervisor-web/dist/assets/andromeeda-C4gqWexZ.js +0 -1
- package/apps/supervisor-web/dist/assets/angular-html-CU67Zn6k.js +0 -1
- package/apps/supervisor-web/dist/assets/angular-ts-BwZT4LLn.js +0 -1
- package/apps/supervisor-web/dist/assets/apache-Pmp26Uib.js +0 -1
- package/apps/supervisor-web/dist/assets/apex-D8_7TLub.js +0 -1
- package/apps/supervisor-web/dist/assets/apl-dKokRX4l.js +0 -1
- package/apps/supervisor-web/dist/assets/applescript-Co6uUVPk.js +0 -1
- package/apps/supervisor-web/dist/assets/ara-BRHolxvo.js +0 -1
- package/apps/supervisor-web/dist/assets/asciidoc-Ve4PFQV2.js +0 -1
- package/apps/supervisor-web/dist/assets/asm-D_Q5rh1f.js +0 -1
- package/apps/supervisor-web/dist/assets/astro-CbQHKStN.js +0 -1
- package/apps/supervisor-web/dist/assets/aurora-x-D-2ljcwZ.js +0 -1
- package/apps/supervisor-web/dist/assets/awk-DMzUqQB5.js +0 -1
- package/apps/supervisor-web/dist/assets/ayu-mirage-32ctXXKs.js +0 -1
- package/apps/supervisor-web/dist/assets/ballerina-BFfxhgS-.js +0 -1
- package/apps/supervisor-web/dist/assets/bat-BkioyH1T.js +0 -1
- package/apps/supervisor-web/dist/assets/beancount-k_qm7-4y.js +0 -1
- package/apps/supervisor-web/dist/assets/berry-uYugtg8r.js +0 -1
- package/apps/supervisor-web/dist/assets/bibtex-CHM0blh-.js +0 -1
- package/apps/supervisor-web/dist/assets/bicep-Bmn6On1c.js +0 -1
- package/apps/supervisor-web/dist/assets/bird2-DPOp833l.js +0 -1
- package/apps/supervisor-web/dist/assets/blade-D4QpJJKB.js +0 -1
- package/apps/supervisor-web/dist/assets/bsl-BO_Y6i37.js +0 -1
- package/apps/supervisor-web/dist/assets/c-BIGW1oBm.js +0 -1
- package/apps/supervisor-web/dist/assets/c3-eo99z4R2.js +0 -1
- package/apps/supervisor-web/dist/assets/cadence-Bv_4Rxtq.js +0 -1
- package/apps/supervisor-web/dist/assets/cairo-KRGpt6FW.js +0 -1
- package/apps/supervisor-web/dist/assets/catppuccin-frappe-DFWUc33u.js +0 -1
- package/apps/supervisor-web/dist/assets/catppuccin-latte-C9dUb6Cb.js +0 -1
- package/apps/supervisor-web/dist/assets/catppuccin-macchiato-DQyhUUbL.js +0 -1
- package/apps/supervisor-web/dist/assets/catppuccin-mocha-D87Tk5Gz.js +0 -1
- package/apps/supervisor-web/dist/assets/clarity-D53aC0YG.js +0 -1
- package/apps/supervisor-web/dist/assets/clojure-P80f7IUj.js +0 -1
- package/apps/supervisor-web/dist/assets/cmake-D1j8_8rp.js +0 -1
- package/apps/supervisor-web/dist/assets/cobol-nwyudZeR.js +0 -1
- package/apps/supervisor-web/dist/assets/codeowners-Bp6g37R7.js +0 -1
- package/apps/supervisor-web/dist/assets/codeql-DsOJ9woJ.js +0 -1
- package/apps/supervisor-web/dist/assets/coffee-Ch7k5sss.js +0 -1
- package/apps/supervisor-web/dist/assets/common-lisp-Cg-RD9OK.js +0 -1
- package/apps/supervisor-web/dist/assets/coq-DkFqJrB1.js +0 -1
- package/apps/supervisor-web/dist/assets/cpp-CofmeUqb.js +0 -1
- package/apps/supervisor-web/dist/assets/crystal-tKQVLTB8.js +0 -1
- package/apps/supervisor-web/dist/assets/csharp-COcwbKMJ.js +0 -1
- package/apps/supervisor-web/dist/assets/cue-D82EKSYY.js +0 -1
- package/apps/supervisor-web/dist/assets/cypher-COkxafJQ.js +0 -1
- package/apps/supervisor-web/dist/assets/d-85-TOEBH.js +0 -1
- package/apps/supervisor-web/dist/assets/dark-plus-C3mMm8J8.js +0 -1
- package/apps/supervisor-web/dist/assets/dart-CF10PKvl.js +0 -1
- package/apps/supervisor-web/dist/assets/dax-CEL-wOlO.js +0 -1
- package/apps/supervisor-web/dist/assets/desktop-BmXAJ9_W.js +0 -1
- package/apps/supervisor-web/dist/assets/diff-D97Zzqfu.js +0 -1
- package/apps/supervisor-web/dist/assets/docker-BcOcwvcX.js +0 -1
- package/apps/supervisor-web/dist/assets/dotenv-Da5cRb03.js +0 -1
- package/apps/supervisor-web/dist/assets/dracula-BzJJZx-M.js +0 -1
- package/apps/supervisor-web/dist/assets/dracula-soft-BXkSAIEj.js +0 -1
- package/apps/supervisor-web/dist/assets/dream-maker-BtqSS_iP.js +0 -1
- package/apps/supervisor-web/dist/assets/edge-BkV0erSs.js +0 -1
- package/apps/supervisor-web/dist/assets/elixir-CDX3lj18.js +0 -1
- package/apps/supervisor-web/dist/assets/elm-DbKCFpqz.js +0 -1
- package/apps/supervisor-web/dist/assets/emacs-lisp-C9XAeP06.js +0 -1
- package/apps/supervisor-web/dist/assets/erb-B12qg9BL.js +0 -1
- package/apps/supervisor-web/dist/assets/erlang-DsQrWhSR.js +0 -1
- package/apps/supervisor-web/dist/assets/everforest-dark-BgDCqdQA.js +0 -1
- package/apps/supervisor-web/dist/assets/everforest-light-C8M2exoo.js +0 -1
- package/apps/supervisor-web/dist/assets/fennel-BYunw83y.js +0 -1
- package/apps/supervisor-web/dist/assets/fish-BvzEVeQv.js +0 -1
- package/apps/supervisor-web/dist/assets/fluent-C4IJs8-o.js +0 -1
- package/apps/supervisor-web/dist/assets/fortran-fixed-form-CkoXwp7k.js +0 -1
- package/apps/supervisor-web/dist/assets/fortran-free-form-BxgE0vQu.js +0 -1
- package/apps/supervisor-web/dist/assets/fsharp-CXgrBDvD.js +0 -1
- package/apps/supervisor-web/dist/assets/gdresource-BOOCDP_w.js +0 -1
- package/apps/supervisor-web/dist/assets/gdscript-C5YyOfLZ.js +0 -1
- package/apps/supervisor-web/dist/assets/gdshader-DkwncUOv.js +0 -1
- package/apps/supervisor-web/dist/assets/genie-D0YGMca9.js +0 -1
- package/apps/supervisor-web/dist/assets/gherkin-DyxjwDmM.js +0 -1
- package/apps/supervisor-web/dist/assets/git-commit-F4YmCXRG.js +0 -1
- package/apps/supervisor-web/dist/assets/git-rebase-r7XF79zn.js +0 -1
- package/apps/supervisor-web/dist/assets/github-dark-DHJKELXO.js +0 -1
- package/apps/supervisor-web/dist/assets/github-dark-default-Cuk6v7N8.js +0 -1
- package/apps/supervisor-web/dist/assets/github-dark-dimmed-DH5Ifo-i.js +0 -1
- package/apps/supervisor-web/dist/assets/github-dark-high-contrast-E3gJ1_iC.js +0 -1
- package/apps/supervisor-web/dist/assets/github-light-DAi9KRSo.js +0 -1
- package/apps/supervisor-web/dist/assets/github-light-default-D7oLnXFd.js +0 -1
- package/apps/supervisor-web/dist/assets/github-light-high-contrast-BfjtVDDH.js +0 -1
- package/apps/supervisor-web/dist/assets/gleam-BspZqrRM.js +0 -1
- package/apps/supervisor-web/dist/assets/glimmer-js-Rg0-pVw9.js +0 -1
- package/apps/supervisor-web/dist/assets/glimmer-ts-U6CK756n.js +0 -1
- package/apps/supervisor-web/dist/assets/glsl-DplSGwfg.js +0 -1
- package/apps/supervisor-web/dist/assets/gn-n2N0HUVH.js +0 -1
- package/apps/supervisor-web/dist/assets/gnuplot-DdkO51Og.js +0 -1
- package/apps/supervisor-web/dist/assets/go-CxLEBnE3.js +0 -1
- package/apps/supervisor-web/dist/assets/graphql-ChdNCCLP.js +0 -1
- package/apps/supervisor-web/dist/assets/groovy-gcz8RCvz.js +0 -1
- package/apps/supervisor-web/dist/assets/gruvbox-dark-hard-CFHQjOhq.js +0 -1
- package/apps/supervisor-web/dist/assets/gruvbox-dark-medium-GsRaNv29.js +0 -1
- package/apps/supervisor-web/dist/assets/gruvbox-dark-soft-CVdnzihN.js +0 -1
- package/apps/supervisor-web/dist/assets/gruvbox-light-hard-CH1njM8p.js +0 -1
- package/apps/supervisor-web/dist/assets/gruvbox-light-medium-DRw_LuNl.js +0 -1
- package/apps/supervisor-web/dist/assets/gruvbox-light-soft-hJgmCMqR.js +0 -1
- package/apps/supervisor-web/dist/assets/hack-CaT9iCJl.js +0 -1
- package/apps/supervisor-web/dist/assets/haml-B8DHNrY2.js +0 -1
- package/apps/supervisor-web/dist/assets/handlebars-BL8al0AC.js +0 -1
- package/apps/supervisor-web/dist/assets/haskell-Df6bDoY_.js +0 -1
- package/apps/supervisor-web/dist/assets/haxe-CzTSHFRz.js +0 -1
- package/apps/supervisor-web/dist/assets/hcl-BWvSN4gD.js +0 -1
- package/apps/supervisor-web/dist/assets/highlighted-body-OFNGDK62-p31aS0f0.js +0 -1
- package/apps/supervisor-web/dist/assets/hjson-D5-asLiD.js +0 -1
- package/apps/supervisor-web/dist/assets/hlsl-D3lLCCz7.js +0 -1
- package/apps/supervisor-web/dist/assets/horizon-BUw7H-hv.js +0 -1
- package/apps/supervisor-web/dist/assets/horizon-bright-Cn-bp-IR.js +0 -1
- package/apps/supervisor-web/dist/assets/houston-DnULxvSX.js +0 -1
- package/apps/supervisor-web/dist/assets/html-derivative-BFtXZ54Q.js +0 -1
- package/apps/supervisor-web/dist/assets/http-jrhK8wxY.js +0 -1
- package/apps/supervisor-web/dist/assets/hurl-irOxFIW8.js +0 -1
- package/apps/supervisor-web/dist/assets/hxml-Bvhsp5Yf.js +0 -1
- package/apps/supervisor-web/dist/assets/hy-DFXneXwc.js +0 -1
- package/apps/supervisor-web/dist/assets/imba-DGztddWO.js +0 -1
- package/apps/supervisor-web/dist/assets/index-BiuFei_K.css +0 -32
- package/apps/supervisor-web/dist/assets/index-D1R9CUnx.js +0 -2161
- package/apps/supervisor-web/dist/assets/ini-BEwlwnbL.js +0 -1
- package/apps/supervisor-web/dist/assets/java-CylS5w8V.js +0 -1
- package/apps/supervisor-web/dist/assets/jinja-4LBKfQ-Z.js +0 -1
- package/apps/supervisor-web/dist/assets/jison-wvAkD_A8.js +0 -1
- package/apps/supervisor-web/dist/assets/json5-C9tS-k6U.js +0 -1
- package/apps/supervisor-web/dist/assets/jsonc-Des-eS-w.js +0 -1
- package/apps/supervisor-web/dist/assets/jsonl-DcaNXYhu.js +0 -1
- package/apps/supervisor-web/dist/assets/jsonnet-DFQXde-d.js +0 -1
- package/apps/supervisor-web/dist/assets/jssm-C2t-YnRu.js +0 -1
- package/apps/supervisor-web/dist/assets/julia-CxzCAyBv.js +0 -1
- package/apps/supervisor-web/dist/assets/just-Cw27pwNe.js +0 -1
- package/apps/supervisor-web/dist/assets/kanagawa-dragon-CkXjmgJE.js +0 -1
- package/apps/supervisor-web/dist/assets/kanagawa-lotus-CfQXZHmo.js +0 -1
- package/apps/supervisor-web/dist/assets/kanagawa-wave-DWedfzmr.js +0 -1
- package/apps/supervisor-web/dist/assets/kdl-DV7GczEv.js +0 -1
- package/apps/supervisor-web/dist/assets/kotlin-BdnUsdx6.js +0 -1
- package/apps/supervisor-web/dist/assets/kusto-DZf3V79B.js +0 -1
- package/apps/supervisor-web/dist/assets/laserwave-DUszq2jm.js +0 -1
- package/apps/supervisor-web/dist/assets/latex-CWtU0Tv5.js +0 -1
- package/apps/supervisor-web/dist/assets/lean-BZvkOJ9d.js +0 -1
- package/apps/supervisor-web/dist/assets/less-B1dDrJ26.js +0 -1
- package/apps/supervisor-web/dist/assets/light-plus-B7mTdjB0.js +0 -1
- package/apps/supervisor-web/dist/assets/liquid-DYVedYrR.js +0 -1
- package/apps/supervisor-web/dist/assets/llvm-DjAJT7YJ.js +0 -1
- package/apps/supervisor-web/dist/assets/log-2UxHyX5q.js +0 -1
- package/apps/supervisor-web/dist/assets/logo-BtOb2qkB.js +0 -1
- package/apps/supervisor-web/dist/assets/lua-BaeVxFsk.js +0 -1
- package/apps/supervisor-web/dist/assets/luau-C-HG3fhB.js +0 -1
- package/apps/supervisor-web/dist/assets/make-CHLpvVh8.js +0 -1
- package/apps/supervisor-web/dist/assets/marko-CnJfTvn9.js +0 -1
- package/apps/supervisor-web/dist/assets/material-theme-D5KoaKCx.js +0 -1
- package/apps/supervisor-web/dist/assets/material-theme-darker-BfHTSMKl.js +0 -1
- package/apps/supervisor-web/dist/assets/material-theme-lighter-B0m2ddpp.js +0 -1
- package/apps/supervisor-web/dist/assets/material-theme-ocean-CyktbL80.js +0 -1
- package/apps/supervisor-web/dist/assets/material-theme-palenight-Csfq5Kiy.js +0 -1
- package/apps/supervisor-web/dist/assets/matlab-D7o27uSR.js +0 -1
- package/apps/supervisor-web/dist/assets/mdc-BMNejdWA.js +0 -1
- package/apps/supervisor-web/dist/assets/mdx-Cmh6b_Ma.js +0 -1
- package/apps/supervisor-web/dist/assets/mermaid-mWjccvbQ.js +0 -1
- package/apps/supervisor-web/dist/assets/min-dark-CafNBF8u.js +0 -1
- package/apps/supervisor-web/dist/assets/min-light-CTRr51gU.js +0 -1
- package/apps/supervisor-web/dist/assets/mipsasm-CKIfxQSi.js +0 -1
- package/apps/supervisor-web/dist/assets/mojo-rZm6bMo-.js +0 -1
- package/apps/supervisor-web/dist/assets/monokai-D4h5O-jR.js +0 -1
- package/apps/supervisor-web/dist/assets/moonbit-_H4v1dQx.js +0 -1
- package/apps/supervisor-web/dist/assets/move-IF9eRakj.js +0 -1
- package/apps/supervisor-web/dist/assets/narrat-DRg8JJMk.js +0 -1
- package/apps/supervisor-web/dist/assets/nextflow-Zz6hmt5N.js +0 -1
- package/apps/supervisor-web/dist/assets/nextflow-groovy-BeH2EWoN.js +0 -1
- package/apps/supervisor-web/dist/assets/nginx-BpAMiNFr.js +0 -1
- package/apps/supervisor-web/dist/assets/night-owl-C39BiMTA.js +0 -1
- package/apps/supervisor-web/dist/assets/night-owl-light-CMTm3GFP.js +0 -1
- package/apps/supervisor-web/dist/assets/nim-CVrawwO9.js +0 -1
- package/apps/supervisor-web/dist/assets/nix-CwoSXNpI.js +0 -1
- package/apps/supervisor-web/dist/assets/nord-Ddv68eIx.js +0 -1
- package/apps/supervisor-web/dist/assets/nushell-Cz2AlsmD.js +0 -1
- package/apps/supervisor-web/dist/assets/objective-c-DXmwc3jG.js +0 -1
- package/apps/supervisor-web/dist/assets/objective-cpp-CLxacb5B.js +0 -1
- package/apps/supervisor-web/dist/assets/ocaml-C0hk2d4L.js +0 -1
- package/apps/supervisor-web/dist/assets/odin-BBf5iR-q.js +0 -1
- package/apps/supervisor-web/dist/assets/one-dark-pro-DVMEJ2y_.js +0 -1
- package/apps/supervisor-web/dist/assets/one-light-C3Wv6jpd.js +0 -1
- package/apps/supervisor-web/dist/assets/openscad-C4EeE6gA.js +0 -1
- package/apps/supervisor-web/dist/assets/pascal-D93ZcfNL.js +0 -1
- package/apps/supervisor-web/dist/assets/perl-C0TMdlhV.js +0 -1
- package/apps/supervisor-web/dist/assets/php-Dhbhpdrm.js +0 -1
- package/apps/supervisor-web/dist/assets/pkl-u5AG7uiY.js +0 -1
- package/apps/supervisor-web/dist/assets/plastic-3e1v2bzS.js +0 -1
- package/apps/supervisor-web/dist/assets/plsql-ChMvpjG-.js +0 -1
- package/apps/supervisor-web/dist/assets/po-BTJTHyun.js +0 -1
- package/apps/supervisor-web/dist/assets/poimandres-CS3Unz2-.js +0 -1
- package/apps/supervisor-web/dist/assets/polar-C0HS_06l.js +0 -1
- package/apps/supervisor-web/dist/assets/postcss-CXtECtnM.js +0 -1
- package/apps/supervisor-web/dist/assets/powerquery-CEu0bR-o.js +0 -1
- package/apps/supervisor-web/dist/assets/powershell-Dpen1YoG.js +0 -1
- package/apps/supervisor-web/dist/assets/prisma-Dd19v3D-.js +0 -1
- package/apps/supervisor-web/dist/assets/prolog-CbFg5uaA.js +0 -1
- package/apps/supervisor-web/dist/assets/proto-C7zT0LnQ.js +0 -1
- package/apps/supervisor-web/dist/assets/pug-CGlum2m_.js +0 -1
- package/apps/supervisor-web/dist/assets/puppet-BMWR74SV.js +0 -1
- package/apps/supervisor-web/dist/assets/purescript-CklMAg4u.js +0 -1
- package/apps/supervisor-web/dist/assets/qml-3beO22l8.js +0 -1
- package/apps/supervisor-web/dist/assets/qmldir-C8lEn-DE.js +0 -1
- package/apps/supervisor-web/dist/assets/qss-IeuSbFQv.js +0 -1
- package/apps/supervisor-web/dist/assets/r-Dspwwk_N.js +0 -1
- package/apps/supervisor-web/dist/assets/racket-BqYA7rlc.js +0 -1
- package/apps/supervisor-web/dist/assets/raku-DXvB9xmW.js +0 -1
- package/apps/supervisor-web/dist/assets/razor-Uh8Bk_45.js +0 -1
- package/apps/supervisor-web/dist/assets/red-bN70gL4F.js +0 -1
- package/apps/supervisor-web/dist/assets/reg-C-SQnVFl.js +0 -1
- package/apps/supervisor-web/dist/assets/regexp-CDVJQ6XC.js +0 -1
- package/apps/supervisor-web/dist/assets/rel-C3B-1QV4.js +0 -1
- package/apps/supervisor-web/dist/assets/riscv-BM1_JUlF.js +0 -1
- package/apps/supervisor-web/dist/assets/ron-D8l8udqQ.js +0 -1
- package/apps/supervisor-web/dist/assets/rose-pine-dawn-DHQR4-dF.js +0 -1
- package/apps/supervisor-web/dist/assets/rose-pine-moon-D4_iv3hh.js +0 -1
- package/apps/supervisor-web/dist/assets/rose-pine-qdsjHGoJ.js +0 -1
- package/apps/supervisor-web/dist/assets/rosmsg-BJDFO7_C.js +0 -1
- package/apps/supervisor-web/dist/assets/rst-BrH8l1NY.js +0 -1
- package/apps/supervisor-web/dist/assets/ruby-Dw2BHqvy.js +0 -1
- package/apps/supervisor-web/dist/assets/rust-B1yitclQ.js +0 -1
- package/apps/supervisor-web/dist/assets/sas-cz2c8ADy.js +0 -1
- package/apps/supervisor-web/dist/assets/sass-Cj5Yp3dK.js +0 -1
- package/apps/supervisor-web/dist/assets/scala-C151Ov-r.js +0 -1
- package/apps/supervisor-web/dist/assets/scheme-C98Dy4si.js +0 -1
- package/apps/supervisor-web/dist/assets/scss-OYdSNvt2.js +0 -1
- package/apps/supervisor-web/dist/assets/sdbl-DVxCFoDh.js +0 -1
- package/apps/supervisor-web/dist/assets/shaderlab-Dg9Lc6iA.js +0 -1
- package/apps/supervisor-web/dist/assets/shellsession-BADoaaVG.js +0 -1
- package/apps/supervisor-web/dist/assets/slack-dark-BthQWCQV.js +0 -1
- package/apps/supervisor-web/dist/assets/slack-ochin-DqwNpetd.js +0 -1
- package/apps/supervisor-web/dist/assets/smalltalk-BERRCDM3.js +0 -1
- package/apps/supervisor-web/dist/assets/snazzy-light-Bw305WKR.js +0 -1
- package/apps/supervisor-web/dist/assets/solarized-dark-DXbdFlpD.js +0 -1
- package/apps/supervisor-web/dist/assets/solarized-light-L9t79GZl.js +0 -1
- package/apps/supervisor-web/dist/assets/solidity-rGO070M0.js +0 -1
- package/apps/supervisor-web/dist/assets/soy-Brmx7dQM.js +0 -1
- package/apps/supervisor-web/dist/assets/sparql-rVzFXLq3.js +0 -1
- package/apps/supervisor-web/dist/assets/splunk-BtCnVYZw.js +0 -1
- package/apps/supervisor-web/dist/assets/ssh-config-_ykCGR6B.js +0 -1
- package/apps/supervisor-web/dist/assets/stata-BH5u7GGu.js +0 -1
- package/apps/supervisor-web/dist/assets/stylus-BEDo0Tqx.js +0 -1
- package/apps/supervisor-web/dist/assets/surrealql-Bq5Q-fJD.js +0 -1
- package/apps/supervisor-web/dist/assets/svelte-C_ipcX3V.js +0 -1
- package/apps/supervisor-web/dist/assets/swift-D82vCrfD.js +0 -1
- package/apps/supervisor-web/dist/assets/synthwave-84-CbfX1IO0.js +0 -1
- package/apps/supervisor-web/dist/assets/system-verilog-CnnmHF94.js +0 -1
- package/apps/supervisor-web/dist/assets/systemd-4A_iFExJ.js +0 -1
- package/apps/supervisor-web/dist/assets/talonscript-CkByrt1z.js +0 -1
- package/apps/supervisor-web/dist/assets/tasl-QIJgUcNo.js +0 -1
- package/apps/supervisor-web/dist/assets/tcl-dwOrl1Do.js +0 -1
- package/apps/supervisor-web/dist/assets/templ-P3uqSqPl.js +0 -1
- package/apps/supervisor-web/dist/assets/terraform-BETggiCN.js +0 -1
- package/apps/supervisor-web/dist/assets/tex-idrVyKtj.js +0 -1
- package/apps/supervisor-web/dist/assets/tokyo-night-hegEt444.js +0 -1
- package/apps/supervisor-web/dist/assets/ts-tags-zn1MmPIZ.js +0 -1
- package/apps/supervisor-web/dist/assets/tsv-B_m7g4N7.js +0 -1
- package/apps/supervisor-web/dist/assets/turtle-BsS91CYL.js +0 -1
- package/apps/supervisor-web/dist/assets/twig-DNn4PbVi.js +0 -1
- package/apps/supervisor-web/dist/assets/typespec-BGHnOYBU.js +0 -1
- package/apps/supervisor-web/dist/assets/typst-DHCkPAjA.js +0 -1
- package/apps/supervisor-web/dist/assets/v-BcVCzyr7.js +0 -1
- package/apps/supervisor-web/dist/assets/vala-CsfeWuGM.js +0 -1
- package/apps/supervisor-web/dist/assets/vb-D17OF-Vu.js +0 -1
- package/apps/supervisor-web/dist/assets/verilog-BQ8w6xss.js +0 -1
- package/apps/supervisor-web/dist/assets/vesper-DU1UobuO.js +0 -1
- package/apps/supervisor-web/dist/assets/vhdl-CeAyd5Ju.js +0 -1
- package/apps/supervisor-web/dist/assets/viml-CJc9bBzg.js +0 -1
- package/apps/supervisor-web/dist/assets/vitesse-black-Bkuqu6BP.js +0 -1
- package/apps/supervisor-web/dist/assets/vitesse-dark-D0r3Knsf.js +0 -1
- package/apps/supervisor-web/dist/assets/vitesse-light-CVO1_9PV.js +0 -1
- package/apps/supervisor-web/dist/assets/vue-DN_0RTcg.js +0 -1
- package/apps/supervisor-web/dist/assets/vue-html-AaS7Mt5G.js +0 -1
- package/apps/supervisor-web/dist/assets/vue-vine-CQOfvN7w.js +0 -1
- package/apps/supervisor-web/dist/assets/vyper-CDx5xZoG.js +0 -1
- package/apps/supervisor-web/dist/assets/wasm-CG6Dc4jp.js +0 -1
- package/apps/supervisor-web/dist/assets/wasm-MzD3tlZU.js +0 -1
- package/apps/supervisor-web/dist/assets/wenyan-BV7otONQ.js +0 -1
- package/apps/supervisor-web/dist/assets/wgsl-Dx-B1_4e.js +0 -1
- package/apps/supervisor-web/dist/assets/wikitext-BhOHFoWU.js +0 -1
- package/apps/supervisor-web/dist/assets/wit-5i3qLPDT.js +0 -1
- package/apps/supervisor-web/dist/assets/wolfram-lXgVvXCa.js +0 -1
- package/apps/supervisor-web/dist/assets/xml-sdJ4AIDG.js +0 -1
- package/apps/supervisor-web/dist/assets/xsl-CtQFsRM5.js +0 -1
- package/apps/supervisor-web/dist/assets/zenscript-DVFEvuxE.js +0 -1
- package/apps/supervisor-web/dist/assets/zig-VOosw3JB.js +0 -1
|
@@ -5,15 +5,15 @@ var __export = (target, all) => {
|
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
// src/index.ts
|
|
8
|
-
import
|
|
8
|
+
import fs25 from "fs";
|
|
9
9
|
|
|
10
10
|
// src/app.ts
|
|
11
11
|
import Fastify from "fastify";
|
|
12
12
|
import multipart from "@fastify/multipart";
|
|
13
13
|
import websocket from "@fastify/websocket";
|
|
14
|
-
import { spawn as
|
|
15
|
-
import
|
|
16
|
-
import
|
|
14
|
+
import { spawn as spawn5 } from "child_process";
|
|
15
|
+
import fs24 from "fs";
|
|
16
|
+
import path23 from "path";
|
|
17
17
|
import { ZodError } from "zod";
|
|
18
18
|
|
|
19
19
|
// ../../packages/config/src/index.ts
|
|
@@ -564,6 +564,7 @@ var PluginRegistry = class {
|
|
|
564
564
|
|
|
565
565
|
// ../../packages/plugin-runtime/src/artifacts.ts
|
|
566
566
|
var artifactFenceLanguages = /* @__PURE__ */ new Set(["artifact", "remote-codex-artifact"]);
|
|
567
|
+
var remoteCodexMoleculeMcpToolName = "remote_codex_render_molecule";
|
|
567
568
|
function stableArtifactId(input) {
|
|
568
569
|
return [
|
|
569
570
|
"artifact",
|
|
@@ -634,6 +635,134 @@ function findFencedBlocks(text2, languages) {
|
|
|
634
635
|
}
|
|
635
636
|
return blocks;
|
|
636
637
|
}
|
|
638
|
+
function readBalancedJsonFragment(text2, startIndex) {
|
|
639
|
+
const opener = text2[startIndex];
|
|
640
|
+
const expectedClose = opener === "{" ? "}" : opener === "[" ? "]" : null;
|
|
641
|
+
if (!expectedClose) {
|
|
642
|
+
return null;
|
|
643
|
+
}
|
|
644
|
+
const stack = [expectedClose];
|
|
645
|
+
let inString = false;
|
|
646
|
+
let escaping = false;
|
|
647
|
+
for (let index = startIndex + 1; index < text2.length; index += 1) {
|
|
648
|
+
const char = text2[index];
|
|
649
|
+
if (inString) {
|
|
650
|
+
if (escaping) {
|
|
651
|
+
escaping = false;
|
|
652
|
+
} else if (char === "\\") {
|
|
653
|
+
escaping = true;
|
|
654
|
+
} else if (char === '"') {
|
|
655
|
+
inString = false;
|
|
656
|
+
}
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
if (char === '"') {
|
|
660
|
+
inString = true;
|
|
661
|
+
continue;
|
|
662
|
+
}
|
|
663
|
+
if (char === "{") {
|
|
664
|
+
stack.push("}");
|
|
665
|
+
continue;
|
|
666
|
+
}
|
|
667
|
+
if (char === "[") {
|
|
668
|
+
stack.push("]");
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
if (char === stack.at(-1)) {
|
|
672
|
+
stack.pop();
|
|
673
|
+
if (stack.length === 0) {
|
|
674
|
+
return text2.slice(startIndex, index + 1);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
680
|
+
function containsArtifactFence(text2) {
|
|
681
|
+
return text2.includes("```artifact") || text2.includes("```remote-codex-artifact") || text2.includes("~~~artifact") || text2.includes("~~~remote-codex-artifact");
|
|
682
|
+
}
|
|
683
|
+
function collectArtifactCandidateStrings(value, output, budget, depth = 0) {
|
|
684
|
+
if (output.length >= 20 || depth > 12 || budget.nodes <= 0) {
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
budget.nodes -= 1;
|
|
688
|
+
if (typeof value === "string") {
|
|
689
|
+
if (containsArtifactFence(value)) {
|
|
690
|
+
output.push(value);
|
|
691
|
+
}
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
if (Array.isArray(value)) {
|
|
695
|
+
for (const entry of value) {
|
|
696
|
+
collectArtifactCandidateStrings(entry, output, budget, depth + 1);
|
|
697
|
+
if (output.length >= 20 || budget.nodes <= 0) {
|
|
698
|
+
break;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
if (value && typeof value === "object") {
|
|
704
|
+
for (const entry of Object.values(value)) {
|
|
705
|
+
collectArtifactCandidateStrings(entry, output, budget, depth + 1);
|
|
706
|
+
if (output.length >= 20 || budget.nodes <= 0) {
|
|
707
|
+
break;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
function parseJsonArtifactCandidateStrings(fragment, output) {
|
|
713
|
+
try {
|
|
714
|
+
collectArtifactCandidateStrings(JSON.parse(fragment), output, { nodes: 2e3 });
|
|
715
|
+
} catch {
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
function findJsonFragmentAt(text2, index) {
|
|
719
|
+
let startIndex = index;
|
|
720
|
+
while (startIndex < text2.length && /\s/.test(text2[startIndex] ?? "")) {
|
|
721
|
+
startIndex += 1;
|
|
722
|
+
}
|
|
723
|
+
const char = text2[startIndex];
|
|
724
|
+
if (char !== "{" && char !== "[") {
|
|
725
|
+
return null;
|
|
726
|
+
}
|
|
727
|
+
return readBalancedJsonFragment(text2, startIndex);
|
|
728
|
+
}
|
|
729
|
+
function extractToolJsonArtifactCandidateStrings(text2) {
|
|
730
|
+
const values = [];
|
|
731
|
+
const seenFragments = /* @__PURE__ */ new Set();
|
|
732
|
+
const addFragment = (fragment) => {
|
|
733
|
+
if (!fragment || seenFragments.has(fragment)) {
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
seenFragments.add(fragment);
|
|
737
|
+
parseJsonArtifactCandidateStrings(fragment, values);
|
|
738
|
+
};
|
|
739
|
+
addFragment(findJsonFragmentAt(text2, 0));
|
|
740
|
+
const labelPattern = /(?:^|\n)(?:Arguments|Result)\n/g;
|
|
741
|
+
for (const match of text2.matchAll(labelPattern)) {
|
|
742
|
+
addFragment(findJsonFragmentAt(text2, match.index + match[0].length));
|
|
743
|
+
if (seenFragments.size >= 4 || values.length >= 20) {
|
|
744
|
+
break;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
return values;
|
|
748
|
+
}
|
|
749
|
+
function extractArtifactCandidateTexts(item, text2) {
|
|
750
|
+
const values = [text2];
|
|
751
|
+
if (item.kind !== "toolCall" || ![item.text, item.previewText, text2].some(
|
|
752
|
+
(value) => typeof value === "string" && value.includes(remoteCodexMoleculeMcpToolName)
|
|
753
|
+
)) {
|
|
754
|
+
return values;
|
|
755
|
+
}
|
|
756
|
+
const seen = new Set(values);
|
|
757
|
+
for (const value of extractToolJsonArtifactCandidateStrings(text2)) {
|
|
758
|
+
if (seen.has(value)) {
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
seen.add(value);
|
|
762
|
+
values.push(value);
|
|
763
|
+
}
|
|
764
|
+
return values;
|
|
765
|
+
}
|
|
637
766
|
var ManifestArtifactExtractor = class {
|
|
638
767
|
constructor(manifests) {
|
|
639
768
|
this.manifests = manifests;
|
|
@@ -650,46 +779,57 @@ var ManifestArtifactExtractor = class {
|
|
|
650
779
|
return results;
|
|
651
780
|
}
|
|
652
781
|
extractFromItem(turn, item, context) {
|
|
653
|
-
|
|
782
|
+
const extractableText = [item.text, item.detailText ?? ""].map((entry) => entry.trim()).filter(Boolean).join("\n\n");
|
|
783
|
+
if (item.kind === "artifact" || !extractableText) {
|
|
654
784
|
return [];
|
|
655
785
|
}
|
|
656
786
|
const artifacts = [];
|
|
657
|
-
artifacts.push(...this.extractJsonArtifacts(turn, item, context));
|
|
787
|
+
artifacts.push(...this.extractJsonArtifacts(turn, item, context, extractableText));
|
|
658
788
|
return artifacts;
|
|
659
789
|
}
|
|
660
|
-
extractJsonArtifacts(turn, item, context) {
|
|
790
|
+
extractJsonArtifacts(turn, item, context, text2) {
|
|
661
791
|
const artifacts = [];
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
792
|
+
const extractableTexts = extractArtifactCandidateTexts(item, text2);
|
|
793
|
+
const seenBlocks = /* @__PURE__ */ new Set();
|
|
794
|
+
for (const extractableText of extractableTexts) {
|
|
795
|
+
for (const block of findFencedBlocks(extractableText, artifactFenceLanguages)) {
|
|
796
|
+
const blockKey = `${block.language}
|
|
797
|
+
${block.content}`;
|
|
798
|
+
if (seenBlocks.has(blockKey)) {
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
seenBlocks.add(blockKey);
|
|
802
|
+
if (!block.content) {
|
|
803
|
+
continue;
|
|
804
|
+
}
|
|
805
|
+
let parsed;
|
|
806
|
+
try {
|
|
807
|
+
parsed = JSON.parse(block.content);
|
|
808
|
+
} catch {
|
|
809
|
+
continue;
|
|
810
|
+
}
|
|
811
|
+
const payload = maybeParseArtifactPayload(parsed);
|
|
812
|
+
if (!payload || !this.hasArtifactType(payload.artifactType)) {
|
|
813
|
+
continue;
|
|
814
|
+
}
|
|
815
|
+
artifacts.push({
|
|
816
|
+
id: stableArtifactId({
|
|
817
|
+
turnId: turn.id,
|
|
818
|
+
itemId: item.id,
|
|
819
|
+
pluginId: this.pluginIdForArtifactType(payload.artifactType) ?? "unknown",
|
|
820
|
+
artifactType: payload.artifactType,
|
|
821
|
+
index: artifacts.length
|
|
822
|
+
}),
|
|
680
823
|
pluginId: this.pluginIdForArtifactType(payload.artifactType) ?? "unknown",
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
sourceItemId: item.id,
|
|
691
|
-
createdAt: context.now
|
|
692
|
-
});
|
|
824
|
+
type: payload.artifactType,
|
|
825
|
+
title: payload.title ?? "Plugin artifact",
|
|
826
|
+
summaryText: payload.summaryText ?? null,
|
|
827
|
+
payload: payload.payload,
|
|
828
|
+
sourceTurnId: turn.id,
|
|
829
|
+
sourceItemId: item.id,
|
|
830
|
+
createdAt: context.now
|
|
831
|
+
});
|
|
832
|
+
}
|
|
693
833
|
}
|
|
694
834
|
return artifacts;
|
|
695
835
|
}
|
|
@@ -760,6 +900,19 @@ function optionalStringArray(value, field) {
|
|
|
760
900
|
}
|
|
761
901
|
return value;
|
|
762
902
|
}
|
|
903
|
+
function optionalStringRecord(value, field) {
|
|
904
|
+
if (value === void 0) {
|
|
905
|
+
return void 0;
|
|
906
|
+
}
|
|
907
|
+
if (!isRecord2(value)) {
|
|
908
|
+
throw new Error(`Plugin manifest field "${field}" must be an object.`);
|
|
909
|
+
}
|
|
910
|
+
const entries = Object.entries(value);
|
|
911
|
+
if (entries.some(([, entry]) => typeof entry !== "string")) {
|
|
912
|
+
throw new Error(`Plugin manifest field "${field}" must contain string values.`);
|
|
913
|
+
}
|
|
914
|
+
return Object.fromEntries(entries);
|
|
915
|
+
}
|
|
763
916
|
function parsePluginManifest(value) {
|
|
764
917
|
if (!isRecord2(value)) {
|
|
765
918
|
throw new Error("Plugin manifest must be an object.");
|
|
@@ -788,6 +941,14 @@ function parsePluginManifest(value) {
|
|
|
788
941
|
if (backend !== void 0 && !isRecord2(backend)) {
|
|
789
942
|
throw new Error('Plugin manifest field "capabilities.backend" must be an object.');
|
|
790
943
|
}
|
|
944
|
+
const modelHints = capabilities.modelHints;
|
|
945
|
+
if (modelHints !== void 0 && !Array.isArray(modelHints)) {
|
|
946
|
+
throw new Error('Plugin manifest field "capabilities.modelHints" must be an array.');
|
|
947
|
+
}
|
|
948
|
+
const mcpServers = capabilities.mcpServers;
|
|
949
|
+
if (mcpServers !== void 0 && !Array.isArray(mcpServers)) {
|
|
950
|
+
throw new Error('Plugin manifest field "capabilities.mcpServers" must be an array.');
|
|
951
|
+
}
|
|
791
952
|
return {
|
|
792
953
|
id: assertString(value.id, "id"),
|
|
793
954
|
name: assertString(value.name, "name"),
|
|
@@ -824,12 +985,46 @@ function parsePluginManifest(value) {
|
|
|
824
985
|
return {
|
|
825
986
|
id: assertString(entry.id, `capabilities.threadPanels[${index}].id`),
|
|
826
987
|
label: assertString(entry.label, `capabilities.threadPanels[${index}].label`),
|
|
988
|
+
...typeof entry.kind === "string" ? { kind: entry.kind } : {},
|
|
827
989
|
artifactTypes: optionalStringArray(
|
|
828
990
|
entry.artifactTypes,
|
|
829
991
|
`capabilities.threadPanels[${index}].artifactTypes`
|
|
830
992
|
) ?? []
|
|
831
993
|
};
|
|
832
994
|
}),
|
|
995
|
+
modelHints: (modelHints ?? []).map((entry, index) => {
|
|
996
|
+
if (!isRecord2(entry)) {
|
|
997
|
+
throw new Error(
|
|
998
|
+
`Plugin manifest field "capabilities.modelHints[${index}]" must be an object.`
|
|
999
|
+
);
|
|
1000
|
+
}
|
|
1001
|
+
return {
|
|
1002
|
+
id: assertString(entry.id, `capabilities.modelHints[${index}].id`),
|
|
1003
|
+
text: assertString(entry.text, `capabilities.modelHints[${index}].text`)
|
|
1004
|
+
};
|
|
1005
|
+
}),
|
|
1006
|
+
mcpServers: (mcpServers ?? []).map((entry, index) => {
|
|
1007
|
+
if (!isRecord2(entry)) {
|
|
1008
|
+
throw new Error(
|
|
1009
|
+
`Plugin manifest field "capabilities.mcpServers[${index}]" must be an object.`
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
1012
|
+
const args = optionalStringArray(
|
|
1013
|
+
entry.args,
|
|
1014
|
+
`capabilities.mcpServers[${index}].args`
|
|
1015
|
+
);
|
|
1016
|
+
const env = optionalStringRecord(
|
|
1017
|
+
entry.env,
|
|
1018
|
+
`capabilities.mcpServers[${index}].env`
|
|
1019
|
+
);
|
|
1020
|
+
return {
|
|
1021
|
+
id: assertString(entry.id, `capabilities.mcpServers[${index}].id`),
|
|
1022
|
+
name: assertString(entry.name, `capabilities.mcpServers[${index}].name`),
|
|
1023
|
+
command: assertString(entry.command, `capabilities.mcpServers[${index}].command`),
|
|
1024
|
+
...args ? { args } : {},
|
|
1025
|
+
...env ? { env } : {}
|
|
1026
|
+
};
|
|
1027
|
+
}),
|
|
833
1028
|
...frontend ? {
|
|
834
1029
|
frontend: {
|
|
835
1030
|
...typeof frontend.entry === "string" ? { entry: frontend.entry } : {},
|
|
@@ -2011,7 +2206,7 @@ Subquery.prototype.getSQL = function() {
|
|
|
2011
2206
|
function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
2012
2207
|
const nullifyMap = {};
|
|
2013
2208
|
const result = columns.reduce(
|
|
2014
|
-
(result2, { path:
|
|
2209
|
+
(result2, { path: path24, field }, columnIndex) => {
|
|
2015
2210
|
let decoder;
|
|
2016
2211
|
if (is(field, Column)) {
|
|
2017
2212
|
decoder = field;
|
|
@@ -2021,8 +2216,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
|
2021
2216
|
decoder = field.sql.decoder;
|
|
2022
2217
|
}
|
|
2023
2218
|
let node = result2;
|
|
2024
|
-
for (const [pathChunkIndex, pathChunk] of
|
|
2025
|
-
if (pathChunkIndex <
|
|
2219
|
+
for (const [pathChunkIndex, pathChunk] of path24.entries()) {
|
|
2220
|
+
if (pathChunkIndex < path24.length - 1) {
|
|
2026
2221
|
if (!(pathChunk in node)) {
|
|
2027
2222
|
node[pathChunk] = {};
|
|
2028
2223
|
}
|
|
@@ -2030,8 +2225,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
|
2030
2225
|
} else {
|
|
2031
2226
|
const rawValue = row[columnIndex];
|
|
2032
2227
|
const value = node[pathChunk] = rawValue === null ? null : decoder.mapFromDriverValue(rawValue);
|
|
2033
|
-
if (joinsNotNullableMap && is(field, Column) &&
|
|
2034
|
-
const objectName =
|
|
2228
|
+
if (joinsNotNullableMap && is(field, Column) && path24.length === 2) {
|
|
2229
|
+
const objectName = path24[0];
|
|
2035
2230
|
if (!(objectName in nullifyMap)) {
|
|
2036
2231
|
nullifyMap[objectName] = value === null ? getTableName(field.table) : false;
|
|
2037
2232
|
} else if (typeof nullifyMap[objectName] === "string" && nullifyMap[objectName] !== getTableName(field.table)) {
|
|
@@ -6132,6 +6327,7 @@ var shellSessions = sqliteTable("shell_sessions", {
|
|
|
6132
6327
|
id: text("id").primaryKey(),
|
|
6133
6328
|
workspaceId: text("workspace_id").notNull(),
|
|
6134
6329
|
threadId: text("thread_id"),
|
|
6330
|
+
label: text("label"),
|
|
6135
6331
|
tmuxSessionName: text("tmux_session_name"),
|
|
6136
6332
|
cwd: text("cwd").notNull(),
|
|
6137
6333
|
status: text("status"),
|
|
@@ -6722,12 +6918,16 @@ function getShellSessionRecordById(db, id) {
|
|
|
6722
6918
|
function getShellSessionRecordByThreadId(db, threadId) {
|
|
6723
6919
|
return db.select().from(shellSessions).where(eq(shellSessions.threadId, threadId)).get();
|
|
6724
6920
|
}
|
|
6921
|
+
function listShellSessionRecordsByThreadId(db, threadId) {
|
|
6922
|
+
return db.select().from(shellSessions).where(eq(shellSessions.threadId, threadId)).orderBy(desc(shellSessions.lastActivityAt), desc(shellSessions.createdAt)).all();
|
|
6923
|
+
}
|
|
6725
6924
|
function createShellSessionRecord(db, input) {
|
|
6726
6925
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6727
6926
|
const record = {
|
|
6728
6927
|
id: randomUUID(),
|
|
6729
6928
|
workspaceId: input.workspaceId,
|
|
6730
6929
|
threadId: input.threadId,
|
|
6930
|
+
label: input.label ?? null,
|
|
6731
6931
|
tmuxSessionName: input.tmuxSessionName,
|
|
6732
6932
|
cwd: input.cwd,
|
|
6733
6933
|
status: input.status,
|
|
@@ -7509,12 +7709,12 @@ var CodexAppServerManager = class extends EventEmitter3 {
|
|
|
7509
7709
|
serviceTier: input.serviceTier === void 0 ? void 0 : input.serviceTier,
|
|
7510
7710
|
effort: input.effort ?? null,
|
|
7511
7711
|
sandboxPolicy: input.sandboxPolicy ?? null,
|
|
7512
|
-
collaborationMode: input.collaborationMode ? {
|
|
7513
|
-
mode: input.collaborationMode,
|
|
7712
|
+
collaborationMode: input.collaborationMode || input.developerInstructions ? {
|
|
7713
|
+
mode: input.collaborationMode ?? "default",
|
|
7514
7714
|
settings: {
|
|
7515
7715
|
model: input.model ?? "",
|
|
7516
7716
|
reasoning_effort: input.effort ?? null,
|
|
7517
|
-
developer_instructions: null
|
|
7717
|
+
developer_instructions: input.developerInstructions ?? null
|
|
7518
7718
|
}
|
|
7519
7719
|
} : null
|
|
7520
7720
|
});
|
|
@@ -8311,7 +8511,7 @@ function extractFileChangeEntries(item) {
|
|
|
8311
8511
|
isRecord4(entry.summary) ? entry.summary : null,
|
|
8312
8512
|
isRecord4(entry.diff) ? entry.diff : null
|
|
8313
8513
|
].filter((candidate) => Boolean(candidate));
|
|
8314
|
-
const
|
|
8514
|
+
const path24 = uniqueStrings([
|
|
8315
8515
|
stringOrNull(valueFromRecords(nestedRecords, ["path", "filePath", "targetPath"])),
|
|
8316
8516
|
stringOrNull(
|
|
8317
8517
|
valueFromRecords(nestedRecords, [
|
|
@@ -8358,7 +8558,7 @@ function extractFileChangeEntries(item) {
|
|
|
8358
8558
|
const diffStats = explicitAdditions === 0 && explicitDeletions === 0 && diffText ? countUnifiedDiffStats(diffText) : null;
|
|
8359
8559
|
const additions = explicitAdditions || diffStats?.additions || 0;
|
|
8360
8560
|
const deletions = explicitDeletions || diffStats?.deletions || 0;
|
|
8361
|
-
const normalizedPath =
|
|
8561
|
+
const normalizedPath = path24 ?? (diffText ? projectRelativePathLabel(extractPathFromDiffText(diffText)) : null);
|
|
8362
8562
|
if (!normalizedPath && additions === 0 && deletions === 0) {
|
|
8363
8563
|
return null;
|
|
8364
8564
|
}
|
|
@@ -10167,6 +10367,9 @@ var CodexRuntimeAdapter = class extends EventEmitter4 {
|
|
|
10167
10367
|
if (input.collaborationMode !== void 0) {
|
|
10168
10368
|
turnInput.collaborationMode = input.collaborationMode;
|
|
10169
10369
|
}
|
|
10370
|
+
if (input.developerInstructions !== void 0) {
|
|
10371
|
+
turnInput.developerInstructions = input.developerInstructions;
|
|
10372
|
+
}
|
|
10170
10373
|
const sandboxPolicy = buildSandboxPolicy(input.sandboxMode, input.workspacePath);
|
|
10171
10374
|
if (sandboxPolicy !== void 0) {
|
|
10172
10375
|
turnInput.sandboxPolicy = sandboxPolicy;
|
|
@@ -11899,13 +12102,16 @@ var ClaudeRuntimeAdapter = class extends EventEmitter5 {
|
|
|
11899
12102
|
const servers = await active.query.mcpServerStatus();
|
|
11900
12103
|
return servers.map((server) => this.mapMcpServer(server));
|
|
11901
12104
|
}
|
|
11902
|
-
mapProviderRequest(request,
|
|
12105
|
+
mapProviderRequest(request, options) {
|
|
12106
|
+
void options;
|
|
11903
12107
|
return mapClaudeAskUserQuestionRequest(request);
|
|
11904
12108
|
}
|
|
11905
12109
|
buildProviderRequestResponse(pending, input) {
|
|
11906
12110
|
return buildClaudeProviderRequestResponse(pending, input);
|
|
11907
12111
|
}
|
|
11908
|
-
respondToProviderRequest(
|
|
12112
|
+
respondToProviderRequest(id, result) {
|
|
12113
|
+
void id;
|
|
12114
|
+
void result;
|
|
11909
12115
|
}
|
|
11910
12116
|
async consumeQuery(state) {
|
|
11911
12117
|
const rawMessages = [];
|
|
@@ -12593,14 +12799,14 @@ function displayPath(pathValue, options) {
|
|
|
12593
12799
|
}
|
|
12594
12800
|
return relativePath;
|
|
12595
12801
|
}
|
|
12596
|
-
function toolIsLowInformationPatch(normalized, state, input, patchText,
|
|
12802
|
+
function toolIsLowInformationPatch(normalized, state, input, patchText, path24, metadataStats) {
|
|
12597
12803
|
if (normalized !== "applypatch" && normalized !== "patch") {
|
|
12598
12804
|
return false;
|
|
12599
12805
|
}
|
|
12600
12806
|
if (toolStateStatus(state) !== "running") {
|
|
12601
12807
|
return false;
|
|
12602
12808
|
}
|
|
12603
|
-
if (
|
|
12809
|
+
if (path24 || patchText || metadataStats || stringValue2(state.output)) {
|
|
12604
12810
|
return false;
|
|
12605
12811
|
}
|
|
12606
12812
|
return !isRecord9(input) || Object.keys(input).length === 0;
|
|
@@ -12643,7 +12849,7 @@ function fileChangeStatsFromMetadata(metadata) {
|
|
|
12643
12849
|
if (files.length === 0) {
|
|
12644
12850
|
return null;
|
|
12645
12851
|
}
|
|
12646
|
-
const paths = files.map((file) => stringValue2(file.filePath) ?? stringValue2(file.path) ?? stringValue2(file.relativePath)).filter((
|
|
12852
|
+
const paths = files.map((file) => stringValue2(file.filePath) ?? stringValue2(file.path) ?? stringValue2(file.relativePath)).filter((path24) => Boolean(path24));
|
|
12647
12853
|
const addedLines = files.reduce((total, file) => total + (numberValue(file.additions) ?? numberValue(file.addedLines) ?? numberValue(file.added) ?? 0), 0);
|
|
12648
12854
|
const removedLines = files.reduce((total, file) => total + (numberValue(file.deletions) ?? numberValue(file.removedLines) ?? numberValue(file.removed) ?? 0), 0);
|
|
12649
12855
|
return {
|
|
@@ -12791,28 +12997,28 @@ function mapAssistantTool(messageId2, tool, options) {
|
|
|
12791
12997
|
].includes(normalized)) {
|
|
12792
12998
|
const metadataStats = fileChangeStatsFromMetadata(state.metadata);
|
|
12793
12999
|
const patchText = isRecord9(input) ? stringValue2(input.patchText) ?? stringValue2(input.patch) ?? stringValue2(input.diff) : null;
|
|
12794
|
-
const
|
|
12795
|
-
if (toolIsLowInformationPatch(normalized, state, input, patchText,
|
|
13000
|
+
const path24 = metadataStats?.path ?? filePathFromInput(input) ?? extractPathFromPatchText(patchText);
|
|
13001
|
+
if (toolIsLowInformationPatch(normalized, state, input, patchText, path24, metadataStats)) {
|
|
12796
13002
|
return null;
|
|
12797
13003
|
}
|
|
12798
13004
|
const output = stringValue2(state.output);
|
|
12799
13005
|
const diffStats = countUnifiedDiffStats2(patchText);
|
|
12800
|
-
const displayFilePath = displayPath(
|
|
13006
|
+
const displayFilePath = displayPath(path24, options);
|
|
12801
13007
|
return {
|
|
12802
13008
|
id,
|
|
12803
13009
|
kind: "fileChange",
|
|
12804
13010
|
text: metadataStats ? metadataStats.changedFiles > 1 ? `${metadataStats.changedFiles} changed files` : displayFilePath ?? metadataStats.previewText : displayFilePath ?? output ?? summary ?? name,
|
|
12805
13011
|
previewText: metadataStats ? metadataStats.changedFiles > 1 ? `${metadataStats.changedFiles} changed files` : displayFilePath ?? metadataStats.previewText : displayFilePath ? `${name}: ${displayFilePath}` : output ?? summary ?? name,
|
|
12806
13012
|
detailText,
|
|
12807
|
-
changedFiles: metadataStats?.changedFiles ?? (
|
|
13013
|
+
changedFiles: metadataStats?.changedFiles ?? (path24 ? 1 : null),
|
|
12808
13014
|
addedLines: metadataStats?.addedLines ?? diffStats?.addedLines ?? null,
|
|
12809
13015
|
removedLines: metadataStats?.removedLines ?? diffStats?.removedLines ?? null,
|
|
12810
13016
|
status: toolStateStatus(state)
|
|
12811
13017
|
};
|
|
12812
13018
|
}
|
|
12813
13019
|
if (["read", "grep", "glob", "list", "ls", "bashoutput"].includes(normalized)) {
|
|
12814
|
-
const
|
|
12815
|
-
const text2 = displayPath(
|
|
13020
|
+
const path24 = filePathFromInput(input);
|
|
13021
|
+
const text2 = displayPath(path24, options) ?? summary ?? name;
|
|
12816
13022
|
return {
|
|
12817
13023
|
id,
|
|
12818
13024
|
kind: "fileRead",
|
|
@@ -14843,7 +15049,7 @@ function shouldPersistLiveHistoryItem(item) {
|
|
|
14843
15049
|
function shouldPersistFinalHistoryItem(item) {
|
|
14844
15050
|
return item.kind === "agentMessage" || shouldPersistLiveHistoryItem(item);
|
|
14845
15051
|
}
|
|
14846
|
-
function shouldPersistRuntimeFinalHistoryItem(item
|
|
15052
|
+
function shouldPersistRuntimeFinalHistoryItem(item) {
|
|
14847
15053
|
if (item.kind === "agentMessage" && isTransientAgentHistoryItem(item)) {
|
|
14848
15054
|
return false;
|
|
14849
15055
|
}
|
|
@@ -14895,13 +15101,7 @@ function copyPersistedOrderingHints(item, persistedItem) {
|
|
|
14895
15101
|
return nextItem;
|
|
14896
15102
|
}
|
|
14897
15103
|
function sortHistoryItemsBySequence(items) {
|
|
14898
|
-
|
|
14899
|
-
return items;
|
|
14900
|
-
}
|
|
14901
|
-
return items.map((item, index) => ({ item, index })).sort((left, right) => {
|
|
14902
|
-
const sequenceDelta = historyItemSequence(left.item) - historyItemSequence(right.item);
|
|
14903
|
-
return sequenceDelta === 0 ? left.index - right.index : sequenceDelta;
|
|
14904
|
-
}).map((entry) => entry.item);
|
|
15104
|
+
return sortTurnItemsByRecordedSequence(items);
|
|
14905
15105
|
}
|
|
14906
15106
|
function sortTurnItemsByRecordedSequence(items) {
|
|
14907
15107
|
const leadingItems = [];
|
|
@@ -14914,9 +15114,6 @@ function sortTurnItemsByRecordedSequence(items) {
|
|
|
14914
15114
|
if (!trailingItems.some(hasHistoryItemSequence)) {
|
|
14915
15115
|
return items;
|
|
14916
15116
|
}
|
|
14917
|
-
if (trailingItems.some((item) => historyItemTranscriptOrder(item) !== null)) {
|
|
14918
|
-
return items;
|
|
14919
|
-
}
|
|
14920
15117
|
const sequenceValues = trailingItems.map((item) => historyItemSequence(item)).filter(Number.isFinite);
|
|
14921
15118
|
const maxSequence = sequenceValues.length > 0 ? Math.max(...sequenceValues) : 0;
|
|
14922
15119
|
const orderedItems2 = [];
|
|
@@ -15074,7 +15271,9 @@ function agentTurnToThreadTurnDto(turn, deferredDetails) {
|
|
|
15074
15271
|
startedAt: turn.startedAt ?? parseUuidV7Timestamp(turn.providerTurnId),
|
|
15075
15272
|
status: turn.status,
|
|
15076
15273
|
error: turn.error?.message ?? null,
|
|
15077
|
-
items: visibleRuntimeTurnItems(turn.items)
|
|
15274
|
+
items: visibleRuntimeTurnItems(turn.items).map(
|
|
15275
|
+
(item, transcriptIndex) => item.transcriptOrder === transcriptIndex ? item : { ...item, transcriptOrder: transcriptIndex }
|
|
15276
|
+
)
|
|
15078
15277
|
};
|
|
15079
15278
|
return deferredDetails ? deferLargeHistoryItemDetails(baseTurn, deferredDetails) : baseTurn;
|
|
15080
15279
|
}
|
|
@@ -15113,6 +15312,7 @@ var ThreadLiveStateStore = class {
|
|
|
15113
15312
|
threadTurnItemOrder = /* @__PURE__ */ new Map();
|
|
15114
15313
|
threadNextTurnItemSequence = /* @__PURE__ */ new Map();
|
|
15115
15314
|
threadMaterializedAgentMessageCounts = /* @__PURE__ */ new Map();
|
|
15315
|
+
threadAgentMessageOrderingHints = /* @__PURE__ */ new Map();
|
|
15116
15316
|
displayTurnIdForRuntimeTurn(localThreadId, runtimeTurnId) {
|
|
15117
15317
|
if (!runtimeTurnId) {
|
|
15118
15318
|
return null;
|
|
@@ -15155,6 +15355,7 @@ var ThreadLiveStateStore = class {
|
|
|
15155
15355
|
this.threadLivePlans.delete(localThreadId);
|
|
15156
15356
|
this.threadLiveItems.delete(localThreadId);
|
|
15157
15357
|
this.threadMaterializedAgentMessageCounts.delete(localThreadId);
|
|
15358
|
+
this.threadAgentMessageOrderingHints.delete(localThreadId);
|
|
15158
15359
|
this.clearRecordedTurnItemOrders(localThreadId);
|
|
15159
15360
|
this.runtimeDisplayTurnIds.delete(localThreadId);
|
|
15160
15361
|
this.hiddenRuntimeTurnIds.delete(localThreadId);
|
|
@@ -15179,10 +15380,12 @@ var ThreadLiveStateStore = class {
|
|
|
15179
15380
|
resetRecordedTurnItemOrder(localThreadId, turnId) {
|
|
15180
15381
|
this.threadTurnItemOrder.get(localThreadId)?.delete(turnId);
|
|
15181
15382
|
this.threadNextTurnItemSequence.get(localThreadId)?.delete(turnId);
|
|
15383
|
+
this.threadAgentMessageOrderingHints.get(localThreadId)?.delete(turnId);
|
|
15182
15384
|
}
|
|
15183
15385
|
clearRecordedTurnItemOrders(localThreadId) {
|
|
15184
15386
|
this.threadTurnItemOrder.delete(localThreadId);
|
|
15185
15387
|
this.threadNextTurnItemSequence.delete(localThreadId);
|
|
15388
|
+
this.threadAgentMessageOrderingHints.delete(localThreadId);
|
|
15186
15389
|
}
|
|
15187
15390
|
recordTurnItemOrder(localThreadId, turnId, itemId) {
|
|
15188
15391
|
let threadOrders = this.threadTurnItemOrder.get(localThreadId);
|
|
@@ -15212,6 +15415,71 @@ var ThreadLiveStateStore = class {
|
|
|
15212
15415
|
turnItemOrderSnapshot(localThreadId) {
|
|
15213
15416
|
return this.threadTurnItemOrder.get(localThreadId) ?? /* @__PURE__ */ new Map();
|
|
15214
15417
|
}
|
|
15418
|
+
finalTurnAgentMessageOrderingHints(localThreadId, turnId, items, options = {}) {
|
|
15419
|
+
const hints = /* @__PURE__ */ new Map();
|
|
15420
|
+
const turnOrder = this.threadTurnItemOrder.get(localThreadId)?.get(turnId);
|
|
15421
|
+
const liveAgentMessages = [
|
|
15422
|
+
...this.threadAgentMessageOrderingHints.get(localThreadId)?.get(turnId)?.values() ?? []
|
|
15423
|
+
].map((item) => ({
|
|
15424
|
+
id: item.id,
|
|
15425
|
+
text: normalizeAgentMessageForMatching(item.text),
|
|
15426
|
+
sequence: item.sequence
|
|
15427
|
+
}));
|
|
15428
|
+
const usedLiveAgentIds = /* @__PURE__ */ new Set();
|
|
15429
|
+
const finalAgentItems = items.filter((item) => item.kind === "agentMessage");
|
|
15430
|
+
for (const item of finalAgentItems) {
|
|
15431
|
+
const existingSequence = turnOrder?.get(item.id);
|
|
15432
|
+
if (existingSequence !== void 0) {
|
|
15433
|
+
hints.set(item.id, existingSequence);
|
|
15434
|
+
const matchingLiveAgent = liveAgentMessages.find(
|
|
15435
|
+
(liveAgent) => liveAgent.id === item.id || liveAgent.sequence === existingSequence
|
|
15436
|
+
);
|
|
15437
|
+
if (matchingLiveAgent) {
|
|
15438
|
+
usedLiveAgentIds.add(matchingLiveAgent.id);
|
|
15439
|
+
}
|
|
15440
|
+
continue;
|
|
15441
|
+
}
|
|
15442
|
+
const text2 = normalizeAgentMessageForMatching(item.text);
|
|
15443
|
+
if (!text2) {
|
|
15444
|
+
continue;
|
|
15445
|
+
}
|
|
15446
|
+
let bestMatch = null;
|
|
15447
|
+
for (const liveAgent of liveAgentMessages) {
|
|
15448
|
+
if (usedLiveAgentIds.has(liveAgent.id) || !liveAgent.text) {
|
|
15449
|
+
continue;
|
|
15450
|
+
}
|
|
15451
|
+
const score = agentMessageMatchScore(text2, liveAgent.text);
|
|
15452
|
+
if (score === 0 || bestMatch && bestMatch.score >= score) {
|
|
15453
|
+
continue;
|
|
15454
|
+
}
|
|
15455
|
+
bestMatch = {
|
|
15456
|
+
id: liveAgent.id,
|
|
15457
|
+
sequence: liveAgent.sequence,
|
|
15458
|
+
score
|
|
15459
|
+
};
|
|
15460
|
+
}
|
|
15461
|
+
if (bestMatch) {
|
|
15462
|
+
usedLiveAgentIds.add(bestMatch.id);
|
|
15463
|
+
hints.set(item.id, bestMatch.sequence);
|
|
15464
|
+
}
|
|
15465
|
+
}
|
|
15466
|
+
if (options.allowUnmatchedFallback ?? true) {
|
|
15467
|
+
const remainingLiveAgents = liveAgentMessages.filter((liveAgent) => !usedLiveAgentIds.has(liveAgent.id)).sort((left, right) => left.sequence - right.sequence);
|
|
15468
|
+
let remainingLiveAgentIndex = 0;
|
|
15469
|
+
for (const item of finalAgentItems) {
|
|
15470
|
+
if (hints.has(item.id) || !normalizeAgentMessageForMatching(item.text)) {
|
|
15471
|
+
continue;
|
|
15472
|
+
}
|
|
15473
|
+
const liveAgent = remainingLiveAgents[remainingLiveAgentIndex];
|
|
15474
|
+
if (!liveAgent) {
|
|
15475
|
+
break;
|
|
15476
|
+
}
|
|
15477
|
+
hints.set(item.id, liveAgent.sequence);
|
|
15478
|
+
remainingLiveAgentIndex += 1;
|
|
15479
|
+
}
|
|
15480
|
+
}
|
|
15481
|
+
return hints;
|
|
15482
|
+
}
|
|
15215
15483
|
getLiveItems(localThreadId, allTurns, visibleTurns = allTurns) {
|
|
15216
15484
|
const current = this.threadLiveItems.get(localThreadId);
|
|
15217
15485
|
if (!current) {
|
|
@@ -15227,10 +15495,8 @@ var ThreadLiveStateStore = class {
|
|
|
15227
15495
|
upsertLiveItem(localThreadId, turnId, item) {
|
|
15228
15496
|
const current = this.threadLiveItems.get(localThreadId);
|
|
15229
15497
|
const currentItems = current?.turnId === turnId ? current.items : [];
|
|
15230
|
-
const
|
|
15231
|
-
|
|
15232
|
-
item
|
|
15233
|
-
];
|
|
15498
|
+
const existingIndex = currentItems.findIndex((entry) => entry.id === item.id);
|
|
15499
|
+
const nextItems = existingIndex >= 0 ? currentItems.map((entry, index) => index === existingIndex ? item : entry) : [...currentItems, item];
|
|
15234
15500
|
this.setLiveItems(localThreadId, {
|
|
15235
15501
|
turnId,
|
|
15236
15502
|
items: sortHistoryItemsBySequence(nextItems),
|
|
@@ -15251,16 +15517,43 @@ var ThreadLiveStateStore = class {
|
|
|
15251
15517
|
text: input.delta,
|
|
15252
15518
|
sequence: input.sequence
|
|
15253
15519
|
};
|
|
15520
|
+
this.recordAgentMessageOrderingHint(
|
|
15521
|
+
input.localThreadId,
|
|
15522
|
+
input.turnId,
|
|
15523
|
+
nextItem,
|
|
15524
|
+
input.sequence
|
|
15525
|
+
);
|
|
15254
15526
|
this.setLiveItems(input.localThreadId, {
|
|
15255
15527
|
turnId: input.turnId,
|
|
15256
|
-
items: sortHistoryItemsBySequence(
|
|
15257
|
-
|
|
15258
|
-
|
|
15259
|
-
|
|
15528
|
+
items: sortHistoryItemsBySequence(
|
|
15529
|
+
existing ? currentItems.map(
|
|
15530
|
+
(entry) => entry.id === input.itemId ? nextItem : entry
|
|
15531
|
+
) : [...currentItems, nextItem]
|
|
15532
|
+
),
|
|
15260
15533
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
15261
15534
|
});
|
|
15262
15535
|
return nextItem;
|
|
15263
15536
|
}
|
|
15537
|
+
recordAgentMessageOrderingHint(localThreadId, turnId, item, sequence) {
|
|
15538
|
+
if (item.kind !== "agentMessage" || !Number.isFinite(sequence)) {
|
|
15539
|
+
return;
|
|
15540
|
+
}
|
|
15541
|
+
let threadHints = this.threadAgentMessageOrderingHints.get(localThreadId);
|
|
15542
|
+
if (!threadHints) {
|
|
15543
|
+
threadHints = /* @__PURE__ */ new Map();
|
|
15544
|
+
this.threadAgentMessageOrderingHints.set(localThreadId, threadHints);
|
|
15545
|
+
}
|
|
15546
|
+
let turnHints = threadHints.get(turnId);
|
|
15547
|
+
if (!turnHints) {
|
|
15548
|
+
turnHints = /* @__PURE__ */ new Map();
|
|
15549
|
+
threadHints.set(turnId, turnHints);
|
|
15550
|
+
}
|
|
15551
|
+
turnHints.set(item.id, {
|
|
15552
|
+
id: item.id,
|
|
15553
|
+
text: item.text,
|
|
15554
|
+
sequence
|
|
15555
|
+
});
|
|
15556
|
+
}
|
|
15264
15557
|
reconcileLiveItems(localThreadId, turns) {
|
|
15265
15558
|
const current = this.threadLiveItems.get(localThreadId);
|
|
15266
15559
|
if (!current) {
|
|
@@ -15312,6 +15605,21 @@ var ThreadLiveStateStore = class {
|
|
|
15312
15605
|
return nextLiveItems;
|
|
15313
15606
|
}
|
|
15314
15607
|
};
|
|
15608
|
+
function normalizeAgentMessageForMatching(text2) {
|
|
15609
|
+
return text2.replace(/\s+/g, " ").trim();
|
|
15610
|
+
}
|
|
15611
|
+
function agentMessageMatchScore(finalText, liveText) {
|
|
15612
|
+
if (finalText === liveText) {
|
|
15613
|
+
return 3;
|
|
15614
|
+
}
|
|
15615
|
+
if (liveText.length >= 8 && finalText.includes(liveText)) {
|
|
15616
|
+
return 2;
|
|
15617
|
+
}
|
|
15618
|
+
if (finalText.length >= 8 && liveText.includes(finalText)) {
|
|
15619
|
+
return 1;
|
|
15620
|
+
}
|
|
15621
|
+
return 0;
|
|
15622
|
+
}
|
|
15315
15623
|
|
|
15316
15624
|
// src/thread-usage-accounting.ts
|
|
15317
15625
|
var CONTEXT_BASELINE_TOKENS = 12e3;
|
|
@@ -15899,9 +16207,10 @@ var ThreadRuntimeEventProjector = class {
|
|
|
15899
16207
|
lastError: event.turn.error?.message ?? null,
|
|
15900
16208
|
lastTurnCompletedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
15901
16209
|
});
|
|
16210
|
+
callbacks.persistFinalTurnOrderingHints(record.id, turnId, turnItems);
|
|
16211
|
+
callbacks.persistRuntimeTurnItemsAsDisplayTurn(record.id, rawTurnId, turnId, turnItems);
|
|
15902
16212
|
liveState.setLivePlan(record.id, null);
|
|
15903
16213
|
liveState.setLiveItems(record.id, null);
|
|
15904
|
-
callbacks.persistRuntimeTurnItemsAsDisplayTurn(record.id, rawTurnId, turnId, turnItems);
|
|
15905
16214
|
if (rawTurnId !== turnId) {
|
|
15906
16215
|
callbacks.deletePersistedHistoryItemsForTurn(record.id, rawTurnId);
|
|
15907
16216
|
liveState.resetRecordedTurnItemOrder(record.id, rawTurnId);
|
|
@@ -16310,34 +16619,82 @@ var ThreadDetailAssembler = class {
|
|
|
16310
16619
|
}
|
|
16311
16620
|
input;
|
|
16312
16621
|
threadDetailCache = /* @__PURE__ */ new Map();
|
|
16313
|
-
getCache(localThreadId) {
|
|
16314
|
-
const
|
|
16315
|
-
if (!
|
|
16622
|
+
getCache(localThreadId, options = {}) {
|
|
16623
|
+
const bucket = this.threadDetailCache.get(localThreadId);
|
|
16624
|
+
if (!bucket) {
|
|
16316
16625
|
return null;
|
|
16317
16626
|
}
|
|
16318
|
-
|
|
16319
|
-
|
|
16627
|
+
const key = cacheKeyForDetailOptions(options);
|
|
16628
|
+
if (key === "uncached") {
|
|
16320
16629
|
return null;
|
|
16321
16630
|
}
|
|
16322
|
-
|
|
16631
|
+
const cached = key === "full" ? bucket.full : bucket.latestPages.get(key) ?? null;
|
|
16632
|
+
if (cached && !isExpiredThreadDetailCacheEntry(cached)) {
|
|
16633
|
+
return cached;
|
|
16634
|
+
}
|
|
16635
|
+
if (key === "full") {
|
|
16636
|
+
bucket.full = null;
|
|
16637
|
+
} else {
|
|
16638
|
+
bucket.latestPages.delete(key);
|
|
16639
|
+
}
|
|
16640
|
+
if (!bucket.full && bucket.latestPages.size === 0) {
|
|
16641
|
+
this.threadDetailCache.delete(localThreadId);
|
|
16642
|
+
}
|
|
16643
|
+
return null;
|
|
16323
16644
|
}
|
|
16324
|
-
setCache(localThreadId, entry) {
|
|
16325
|
-
this.threadDetailCache.
|
|
16645
|
+
setCache(localThreadId, options = {}, entry) {
|
|
16646
|
+
const bucket = this.threadDetailCache.get(localThreadId) ?? {
|
|
16647
|
+
full: null,
|
|
16648
|
+
latestPages: /* @__PURE__ */ new Map()
|
|
16649
|
+
};
|
|
16650
|
+
const nextEntry = {
|
|
16326
16651
|
...entry,
|
|
16327
16652
|
cachedAt: Date.now()
|
|
16328
|
-
}
|
|
16653
|
+
};
|
|
16654
|
+
const key = cacheKeyForDetailOptions(options);
|
|
16655
|
+
if (key === "uncached") {
|
|
16656
|
+
return;
|
|
16657
|
+
}
|
|
16658
|
+
if (key === "full") {
|
|
16659
|
+
bucket.full = nextEntry;
|
|
16660
|
+
} else {
|
|
16661
|
+
bucket.latestPages.set(key, nextEntry);
|
|
16662
|
+
}
|
|
16663
|
+
this.threadDetailCache.set(localThreadId, bucket);
|
|
16329
16664
|
}
|
|
16330
16665
|
invalidate(localThreadId) {
|
|
16331
16666
|
this.threadDetailCache.delete(localThreadId);
|
|
16332
16667
|
}
|
|
16333
16668
|
cachedTurns(localThreadId) {
|
|
16334
|
-
|
|
16669
|
+
const bucket = this.threadDetailCache.get(localThreadId);
|
|
16670
|
+
if (!bucket) {
|
|
16671
|
+
return [];
|
|
16672
|
+
}
|
|
16673
|
+
if (bucket.full && !isExpiredThreadDetailCacheEntry(bucket.full)) {
|
|
16674
|
+
return bucket.full.turns;
|
|
16675
|
+
}
|
|
16676
|
+
let newest = null;
|
|
16677
|
+
for (const [key, entry] of bucket.latestPages.entries()) {
|
|
16678
|
+
if (isExpiredThreadDetailCacheEntry(entry)) {
|
|
16679
|
+
bucket.latestPages.delete(key);
|
|
16680
|
+
continue;
|
|
16681
|
+
}
|
|
16682
|
+
if (!newest || entry.cachedAt > newest.cachedAt) {
|
|
16683
|
+
newest = entry;
|
|
16684
|
+
}
|
|
16685
|
+
}
|
|
16686
|
+
if (!bucket.full && bucket.latestPages.size === 0) {
|
|
16687
|
+
this.threadDetailCache.delete(localThreadId);
|
|
16688
|
+
}
|
|
16689
|
+
return newest?.turns ?? [];
|
|
16335
16690
|
}
|
|
16336
16691
|
async buildCacheEntry(input) {
|
|
16337
16692
|
const options = input.options ?? {};
|
|
16338
16693
|
const shouldCacheFullDetail = options.limit === void 0 && options.beforeTurnId === void 0;
|
|
16339
|
-
const
|
|
16340
|
-
|
|
16694
|
+
const cacheKey = cacheKeyForDetailOptions(options);
|
|
16695
|
+
const isPaged = !shouldCacheFullDetail;
|
|
16696
|
+
const cached = this.getCache(input.localThreadId, options);
|
|
16697
|
+
if (cached) {
|
|
16341
16698
|
return cached;
|
|
16342
16699
|
}
|
|
16343
16700
|
let remoteSession = await this.input.callbacks.readRemoteSession(
|
|
@@ -16347,6 +16704,7 @@ var ThreadDetailAssembler = class {
|
|
|
16347
16704
|
if (!remoteSession) {
|
|
16348
16705
|
return this.buildLocalFallbackEntry({
|
|
16349
16706
|
...input,
|
|
16707
|
+
options,
|
|
16350
16708
|
shouldCacheFullDetail
|
|
16351
16709
|
});
|
|
16352
16710
|
}
|
|
@@ -16376,13 +16734,18 @@ var ThreadDetailAssembler = class {
|
|
|
16376
16734
|
remoteSession.turns
|
|
16377
16735
|
);
|
|
16378
16736
|
const visibleTurns = this.input.liveState.visibleRemoteTurns(input.localThreadId, remoteSession.turns).map((turn) => agentTurnToThreadTurnDto(turn, deferredDetails));
|
|
16379
|
-
const
|
|
16737
|
+
const orderedVisibleTurns = applyLiveAgentMessageOrderingHints(
|
|
16380
16738
|
visibleTurns,
|
|
16739
|
+
input.localThreadId,
|
|
16740
|
+
this.input.liveState
|
|
16741
|
+
);
|
|
16742
|
+
const resolvedTurnMetadataById = resolveTurnMetadataByVisibleTurnId(
|
|
16743
|
+
orderedVisibleTurns,
|
|
16381
16744
|
input.turnMetadataById
|
|
16382
16745
|
);
|
|
16383
16746
|
const turns = mergePersistedHistoryItemsIntoTurns(
|
|
16384
16747
|
applyRecordedTurnItemOrders(
|
|
16385
|
-
|
|
16748
|
+
orderedVisibleTurns,
|
|
16386
16749
|
this.input.liveState.turnItemOrderSnapshot(input.localThreadId)
|
|
16387
16750
|
),
|
|
16388
16751
|
persistedItemsByTurnId,
|
|
@@ -16393,12 +16756,13 @@ var ThreadDetailAssembler = class {
|
|
|
16393
16756
|
const entry = {
|
|
16394
16757
|
cachedAt: Date.now(),
|
|
16395
16758
|
turns,
|
|
16396
|
-
totalTurnCount: shouldCacheFullDetail ? turns.length : remoteSession.totalTurnCount ??
|
|
16397
|
-
deferredDetails
|
|
16759
|
+
totalTurnCount: shouldCacheFullDetail ? turns.length : remoteSession.totalTurnCount ?? turns.length,
|
|
16760
|
+
deferredDetails,
|
|
16761
|
+
isPaged
|
|
16398
16762
|
};
|
|
16399
|
-
if (
|
|
16400
|
-
this.setCache(input.localThreadId, entry);
|
|
16401
|
-
return this.
|
|
16763
|
+
if (cacheKey !== "uncached") {
|
|
16764
|
+
this.setCache(input.localThreadId, options, entry);
|
|
16765
|
+
return this.getCache(input.localThreadId, options);
|
|
16402
16766
|
}
|
|
16403
16767
|
return entry;
|
|
16404
16768
|
}
|
|
@@ -16417,7 +16781,7 @@ var ThreadDetailAssembler = class {
|
|
|
16417
16781
|
input.record,
|
|
16418
16782
|
latestThreadTurnMetadata(input.turnMetadataById)
|
|
16419
16783
|
);
|
|
16420
|
-
const localTurns = localSession?.turns ?? [...persistedItemsByTurnId.
|
|
16784
|
+
const localTurns = localSession?.turns ?? [...persistedItemsByTurnId.keys()].map((turnId) => ({
|
|
16421
16785
|
id: turnId,
|
|
16422
16786
|
startedAt: null,
|
|
16423
16787
|
status: "completed",
|
|
@@ -16441,15 +16805,61 @@ var ThreadDetailAssembler = class {
|
|
|
16441
16805
|
cachedAt: Date.now(),
|
|
16442
16806
|
turns,
|
|
16443
16807
|
totalTurnCount: turns.length,
|
|
16444
|
-
deferredDetails
|
|
16808
|
+
deferredDetails,
|
|
16809
|
+
isPaged: !input.shouldCacheFullDetail
|
|
16445
16810
|
};
|
|
16446
|
-
|
|
16447
|
-
|
|
16448
|
-
|
|
16811
|
+
const cacheOptions = input.shouldCacheFullDetail ? {} : input.options;
|
|
16812
|
+
if (cacheKeyForDetailOptions(cacheOptions) !== "uncached") {
|
|
16813
|
+
this.setCache(input.localThreadId, cacheOptions, entry);
|
|
16814
|
+
return this.getCache(input.localThreadId, cacheOptions);
|
|
16449
16815
|
}
|
|
16450
16816
|
return entry;
|
|
16451
16817
|
}
|
|
16452
16818
|
};
|
|
16819
|
+
function isExpiredThreadDetailCacheEntry(entry) {
|
|
16820
|
+
return Date.now() - entry.cachedAt > THREAD_DETAIL_CACHE_TTL_MS;
|
|
16821
|
+
}
|
|
16822
|
+
function cacheKeyForDetailOptions(options) {
|
|
16823
|
+
if (options.beforeTurnId !== void 0) {
|
|
16824
|
+
return "uncached";
|
|
16825
|
+
}
|
|
16826
|
+
if (options.limit === void 0) {
|
|
16827
|
+
return "full";
|
|
16828
|
+
}
|
|
16829
|
+
return `latest:${options.limit}`;
|
|
16830
|
+
}
|
|
16831
|
+
function applyLiveAgentMessageOrderingHints(turns, localThreadId, liveState) {
|
|
16832
|
+
return turns.map((turn) => {
|
|
16833
|
+
const orderingHints = liveState.finalTurnAgentMessageOrderingHints(
|
|
16834
|
+
localThreadId,
|
|
16835
|
+
turn.id,
|
|
16836
|
+
turn.items,
|
|
16837
|
+
{ allowUnmatchedFallback: false }
|
|
16838
|
+
);
|
|
16839
|
+
if (orderingHints.size === 0) {
|
|
16840
|
+
return turn;
|
|
16841
|
+
}
|
|
16842
|
+
let changed = false;
|
|
16843
|
+
const items = turn.items.map((item) => {
|
|
16844
|
+
if (item.kind !== "agentMessage") {
|
|
16845
|
+
return item;
|
|
16846
|
+
}
|
|
16847
|
+
const sequence = orderingHints.get(item.id);
|
|
16848
|
+
if (sequence === void 0 || item.sequence === sequence) {
|
|
16849
|
+
return item;
|
|
16850
|
+
}
|
|
16851
|
+
changed = true;
|
|
16852
|
+
return {
|
|
16853
|
+
...item,
|
|
16854
|
+
sequence
|
|
16855
|
+
};
|
|
16856
|
+
});
|
|
16857
|
+
return changed ? {
|
|
16858
|
+
...turn,
|
|
16859
|
+
items: sortHistoryItemsBySequence(items)
|
|
16860
|
+
} : turn;
|
|
16861
|
+
});
|
|
16862
|
+
}
|
|
16453
16863
|
function buildTurnDto(turn, metadata) {
|
|
16454
16864
|
const tokenUsage = parseThreadTurnTokenUsageJson(metadata?.tokenUsageJson);
|
|
16455
16865
|
return {
|
|
@@ -16932,7 +17342,8 @@ var ThreadPromptTurnCoordinator = class {
|
|
|
16932
17342
|
reasoningEffort: input.normalizedReasoning,
|
|
16933
17343
|
collaborationMode: input.collaborationMode,
|
|
16934
17344
|
sandboxMode: input.sandboxMode,
|
|
16935
|
-
workspacePath: input.workspacePath
|
|
17345
|
+
workspacePath: input.workspacePath,
|
|
17346
|
+
developerInstructions: input.developerInstructions ?? null
|
|
16936
17347
|
};
|
|
16937
17348
|
if (input.hidden !== void 0) {
|
|
16938
17349
|
startTurnInput.hidden = input.hidden;
|
|
@@ -17049,7 +17460,8 @@ var ThreadPromptTurnCoordinator = class {
|
|
|
17049
17460
|
collaborationMode: input.collaborationMode,
|
|
17050
17461
|
sandboxMode: input.sandboxMode,
|
|
17051
17462
|
performanceMode: input.performanceMode,
|
|
17052
|
-
workspacePath: input.workspacePath
|
|
17463
|
+
workspacePath: input.workspacePath,
|
|
17464
|
+
developerInstructions: input.developerInstructions ?? null
|
|
17053
17465
|
});
|
|
17054
17466
|
}
|
|
17055
17467
|
};
|
|
@@ -17480,12 +17892,38 @@ var ThreadHistoryPersistenceCoordinator = class {
|
|
|
17480
17892
|
deletePersistedHistoryItemsForTurn(localThreadId, turnId) {
|
|
17481
17893
|
deleteThreadHistoryItemRecordsByThreadAndTurnId(this.db, localThreadId, turnId);
|
|
17482
17894
|
}
|
|
17895
|
+
persistFinalTurnOrderingHints(localThreadId, turnId, items) {
|
|
17896
|
+
const orderingHints = this.liveState.finalTurnAgentMessageOrderingHints(
|
|
17897
|
+
localThreadId,
|
|
17898
|
+
turnId,
|
|
17899
|
+
items
|
|
17900
|
+
);
|
|
17901
|
+
for (const item of items) {
|
|
17902
|
+
if (item.kind !== "agentMessage" || !shouldPersistRuntimeFinalHistoryItem(item)) {
|
|
17903
|
+
continue;
|
|
17904
|
+
}
|
|
17905
|
+
const sequence = orderingHints.get(item.id);
|
|
17906
|
+
if (sequence === void 0) {
|
|
17907
|
+
continue;
|
|
17908
|
+
}
|
|
17909
|
+
upsertThreadHistoryItemRecord(this.db, {
|
|
17910
|
+
threadId: localThreadId,
|
|
17911
|
+
turnId,
|
|
17912
|
+
itemId: item.id,
|
|
17913
|
+
itemJson: JSON.stringify({
|
|
17914
|
+
...item,
|
|
17915
|
+
sequence,
|
|
17916
|
+
sourceTurnId: turnId
|
|
17917
|
+
})
|
|
17918
|
+
});
|
|
17919
|
+
}
|
|
17920
|
+
}
|
|
17483
17921
|
persistRuntimeTurnItemsAsDisplayTurn(localThreadId, runtimeTurnId, displayTurnId, items) {
|
|
17484
17922
|
if (runtimeTurnId === displayTurnId) {
|
|
17485
17923
|
return;
|
|
17486
17924
|
}
|
|
17487
17925
|
for (const item of items) {
|
|
17488
|
-
if (!shouldPersistRuntimeFinalHistoryItem(item
|
|
17926
|
+
if (!shouldPersistRuntimeFinalHistoryItem(item)) {
|
|
17489
17927
|
continue;
|
|
17490
17928
|
}
|
|
17491
17929
|
const sequence = this.liveState.recordTurnItemOrder(localThreadId, displayTurnId, item.id);
|
|
@@ -19168,6 +19606,16 @@ async function pathExists3(absPath) {
|
|
|
19168
19606
|
return false;
|
|
19169
19607
|
}
|
|
19170
19608
|
}
|
|
19609
|
+
function canUseRuntimePagedTurns(cachedDetail, enrichedTurns, options) {
|
|
19610
|
+
const requestedLimit = options.limit ?? 10;
|
|
19611
|
+
if (enrichedTurns.length > requestedLimit) {
|
|
19612
|
+
return false;
|
|
19613
|
+
}
|
|
19614
|
+
return cachedDetail.totalTurnCount > enrichedTurns.length;
|
|
19615
|
+
}
|
|
19616
|
+
function pluginDeveloperInstructions(pluginService) {
|
|
19617
|
+
return pluginService?.modelContextPrompt() ?? null;
|
|
19618
|
+
}
|
|
19171
19619
|
var ThreadService = class {
|
|
19172
19620
|
constructor(db, agentRuntimes, eventBus, localSessionStore, workspaceRoot, providerManagement, pluginService) {
|
|
19173
19621
|
this.db = db;
|
|
@@ -19343,6 +19791,7 @@ var ThreadService = class {
|
|
|
19343
19791
|
normalizeReasoningEffort: normalizeReasoningEffort2,
|
|
19344
19792
|
normalizeThreadGoalStatusForThread: (goal, record) => this.goalCoordinator.normalizeThreadGoalStatusForThread(goal, record),
|
|
19345
19793
|
persistLiveHistoryItem: (localThreadId, turnId, item) => this.historyPersistence.persistLiveHistoryItem(localThreadId, turnId, item),
|
|
19794
|
+
persistFinalTurnOrderingHints: (localThreadId, turnId, items) => this.historyPersistence.persistFinalTurnOrderingHints(localThreadId, turnId, items),
|
|
19346
19795
|
persistRuntimeTurnItemsAsDisplayTurn: (localThreadId, runtimeTurnId, displayTurnId, items) => this.historyPersistence.persistRuntimeTurnItemsAsDisplayTurn(
|
|
19347
19796
|
localThreadId,
|
|
19348
19797
|
runtimeTurnId,
|
|
@@ -19583,9 +20032,13 @@ var ThreadService = class {
|
|
|
19583
20032
|
const enrichedTurns = this.pluginService?.enrichTurnsWithArtifacts({
|
|
19584
20033
|
threadId: updated.id,
|
|
19585
20034
|
workspacePath: workspace.absPath,
|
|
19586
|
-
turns: cachedDetail.turns
|
|
20035
|
+
turns: cachedDetail.turns,
|
|
20036
|
+
deferredDetails: cachedDetail.deferredDetails
|
|
19587
20037
|
}) ?? cachedDetail.turns;
|
|
19588
|
-
const pagedTurns =
|
|
20038
|
+
const pagedTurns = cachedDetail.isPaged && canUseRuntimePagedTurns(cachedDetail, enrichedTurns, options) ? {
|
|
20039
|
+
turns: enrichedTurns,
|
|
20040
|
+
totalTurnCount: cachedDetail.totalTurnCount
|
|
20041
|
+
} : this.detailAssembler.sliceTurns(enrichedTurns, options);
|
|
19589
20042
|
this.syncPendingPlanDecisionRequestFromTurns(
|
|
19590
20043
|
updated.id,
|
|
19591
20044
|
updated.collaborationMode,
|
|
@@ -19776,6 +20229,7 @@ var ThreadService = class {
|
|
|
19776
20229
|
...record,
|
|
19777
20230
|
providerSessionId
|
|
19778
20231
|
};
|
|
20232
|
+
const developerInstructions = pluginDeveloperInstructions(this.pluginService);
|
|
19779
20233
|
if (record.providerTurnId && record.status === "running") {
|
|
19780
20234
|
if (!turnConfig.supportsRunningTurnInput) {
|
|
19781
20235
|
throw new HttpError(409, {
|
|
@@ -19795,7 +20249,8 @@ var ThreadService = class {
|
|
|
19795
20249
|
collaborationMode: turnConfig.collaborationMode,
|
|
19796
20250
|
sandboxMode: turnConfig.sandboxMode,
|
|
19797
20251
|
performanceMode: turnConfig.performanceMode,
|
|
19798
|
-
workspacePath: workspace.absPath
|
|
20252
|
+
workspacePath: workspace.absPath,
|
|
20253
|
+
developerInstructions
|
|
19799
20254
|
});
|
|
19800
20255
|
}
|
|
19801
20256
|
return this.promptTurnCoordinator.startPromptTurn(localThreadId, connectedRecord, {
|
|
@@ -19806,7 +20261,8 @@ var ThreadService = class {
|
|
|
19806
20261
|
collaborationMode: turnConfig.collaborationMode,
|
|
19807
20262
|
sandboxMode: turnConfig.sandboxMode,
|
|
19808
20263
|
performanceMode: turnConfig.performanceMode,
|
|
19809
|
-
workspacePath: workspace.absPath
|
|
20264
|
+
workspacePath: workspace.absPath,
|
|
20265
|
+
developerInstructions
|
|
19810
20266
|
});
|
|
19811
20267
|
}
|
|
19812
20268
|
async updateThreadSettings(localThreadId, input) {
|
|
@@ -20638,36 +21094,8 @@ function runShellCommand(command, timeoutMs = 0) {
|
|
|
20638
21094
|
});
|
|
20639
21095
|
}
|
|
20640
21096
|
|
|
20641
|
-
// src/routes/shells.ts
|
|
20642
|
-
import { z as z4 } from "zod";
|
|
20643
|
-
async function registerShellRoutes(app2) {
|
|
20644
|
-
const threadIdParams = z4.object({ id: z4.string().uuid() });
|
|
20645
|
-
const shellIdParams = z4.object({ id: z4.string().uuid() });
|
|
20646
|
-
const createShellSchema = z4.object({
|
|
20647
|
-
cols: z4.number().int().positive().optional(),
|
|
20648
|
-
rows: z4.number().int().positive().optional()
|
|
20649
|
-
});
|
|
20650
|
-
app2.get("/api/threads/:id/shell", async (request) => {
|
|
20651
|
-
const params = threadIdParams.parse(request.params);
|
|
20652
|
-
return app2.services.shellService.getThreadShellState(params.id);
|
|
20653
|
-
});
|
|
20654
|
-
app2.post("/api/threads/:id/shell", async (request) => {
|
|
20655
|
-
const params = threadIdParams.parse(request.params);
|
|
20656
|
-
const body = createShellSchema.parse(request.body ?? {});
|
|
20657
|
-
const input = {
|
|
20658
|
-
...body.cols !== void 0 ? { cols: body.cols } : {},
|
|
20659
|
-
...body.rows !== void 0 ? { rows: body.rows } : {}
|
|
20660
|
-
};
|
|
20661
|
-
return app2.services.shellService.createShellForThread(params.id, input);
|
|
20662
|
-
});
|
|
20663
|
-
app2.post("/api/shells/:id/terminate", async (request) => {
|
|
20664
|
-
const params = shellIdParams.parse(request.params);
|
|
20665
|
-
return app2.services.shellService.terminateShell(params.id);
|
|
20666
|
-
});
|
|
20667
|
-
}
|
|
20668
|
-
|
|
20669
21097
|
// src/routes/system.ts
|
|
20670
|
-
import { z as
|
|
21098
|
+
import { z as z4 } from "zod";
|
|
20671
21099
|
|
|
20672
21100
|
// src/workspace-settings.ts
|
|
20673
21101
|
var DEV_HOME_POLICY_KEY = "dev_home";
|
|
@@ -20731,27 +21159,27 @@ async function saveWorkspaceSettings(db, workspaceRoot, input) {
|
|
|
20731
21159
|
}
|
|
20732
21160
|
|
|
20733
21161
|
// src/routes/system.ts
|
|
20734
|
-
var updateProviderHostFileSchema =
|
|
20735
|
-
content:
|
|
21162
|
+
var updateProviderHostFileSchema = z4.object({
|
|
21163
|
+
content: z4.string()
|
|
20736
21164
|
});
|
|
20737
|
-
var archiveIdSchema =
|
|
20738
|
-
var createProviderHostConfigArchiveSchema =
|
|
20739
|
-
label:
|
|
21165
|
+
var archiveIdSchema = z4.string().regex(/^[a-zA-Z0-9_-]+$/);
|
|
21166
|
+
var createProviderHostConfigArchiveSchema = z4.object({
|
|
21167
|
+
label: z4.string().trim().min(1).max(120).optional()
|
|
20740
21168
|
});
|
|
20741
|
-
var renameProviderHostConfigArchiveSchema =
|
|
20742
|
-
label:
|
|
21169
|
+
var renameProviderHostConfigArchiveSchema = z4.object({
|
|
21170
|
+
label: z4.string().trim().min(1).max(120)
|
|
20743
21171
|
});
|
|
20744
|
-
var updateWorkspaceSettingsSchema =
|
|
20745
|
-
devHome:
|
|
21172
|
+
var updateWorkspaceSettingsSchema = z4.object({
|
|
21173
|
+
devHome: z4.string().trim().min(1),
|
|
20746
21174
|
defaultBackend: agentBackendIdSchema.optional()
|
|
20747
21175
|
});
|
|
20748
|
-
var providerParamSchema2 =
|
|
21176
|
+
var providerParamSchema2 = z4.object({
|
|
20749
21177
|
provider: agentBackendIdSchema
|
|
20750
21178
|
});
|
|
20751
21179
|
function parseProviderHostFileParams(params) {
|
|
20752
|
-
return
|
|
21180
|
+
return z4.object({
|
|
20753
21181
|
...providerParamSchema2.shape,
|
|
20754
|
-
name:
|
|
21182
|
+
name: z4.string()
|
|
20755
21183
|
}).parse(params);
|
|
20756
21184
|
}
|
|
20757
21185
|
async function registerSystemRoutes(app2) {
|
|
@@ -20831,7 +21259,7 @@ async function registerSystemRoutes(app2) {
|
|
|
20831
21259
|
return app2.services.providerHostConfigService.createArchive(provider, body);
|
|
20832
21260
|
});
|
|
20833
21261
|
app2.patch("/api/config/providers/:provider/archives/:id", async (request) => {
|
|
20834
|
-
const params =
|
|
21262
|
+
const params = z4.object({
|
|
20835
21263
|
...providerParamSchema2.shape,
|
|
20836
21264
|
id: archiveIdSchema
|
|
20837
21265
|
}).parse(request.params);
|
|
@@ -20845,7 +21273,7 @@ async function registerSystemRoutes(app2) {
|
|
|
20845
21273
|
);
|
|
20846
21274
|
});
|
|
20847
21275
|
app2.post("/api/config/providers/:provider/archives/:id/apply", async (request) => {
|
|
20848
|
-
const params =
|
|
21276
|
+
const params = z4.object({
|
|
20849
21277
|
...providerParamSchema2.shape,
|
|
20850
21278
|
id: archiveIdSchema
|
|
20851
21279
|
}).parse(request.params);
|
|
@@ -20856,67 +21284,67 @@ async function registerSystemRoutes(app2) {
|
|
|
20856
21284
|
// src/routes/threads.ts
|
|
20857
21285
|
import fs16 from "fs/promises";
|
|
20858
21286
|
import path16 from "path";
|
|
20859
|
-
import { z as
|
|
20860
|
-
var createThreadSchema =
|
|
20861
|
-
workspaceId:
|
|
20862
|
-
title:
|
|
21287
|
+
import { z as z5 } from "zod";
|
|
21288
|
+
var createThreadSchema = z5.object({
|
|
21289
|
+
workspaceId: z5.string().uuid(),
|
|
21290
|
+
title: z5.string().optional(),
|
|
20863
21291
|
provider: agentBackendIdSchema.optional(),
|
|
20864
|
-
model:
|
|
20865
|
-
approvalMode:
|
|
21292
|
+
model: z5.string().min(1),
|
|
21293
|
+
approvalMode: z5.enum(["yolo", "guarded"]).default("yolo")
|
|
20866
21294
|
});
|
|
20867
|
-
var promptSchema =
|
|
20868
|
-
prompt:
|
|
20869
|
-
clientRequestId:
|
|
20870
|
-
model:
|
|
20871
|
-
reasoningEffort:
|
|
20872
|
-
collaborationMode:
|
|
20873
|
-
sandboxMode:
|
|
21295
|
+
var promptSchema = z5.object({
|
|
21296
|
+
prompt: z5.string().min(1),
|
|
21297
|
+
clientRequestId: z5.string().min(1).optional(),
|
|
21298
|
+
model: z5.string().min(1).optional(),
|
|
21299
|
+
reasoningEffort: z5.enum(["none", "minimal", "low", "medium", "high", "xhigh"]).nullable().optional(),
|
|
21300
|
+
collaborationMode: z5.enum(["default", "plan"]).optional(),
|
|
21301
|
+
sandboxMode: z5.enum(["read-only", "workspace-write", "danger-full-access"]).nullable().optional()
|
|
20874
21302
|
});
|
|
20875
|
-
var promptAttachmentManifestEntrySchema =
|
|
20876
|
-
clientId:
|
|
20877
|
-
kind:
|
|
20878
|
-
originalName:
|
|
20879
|
-
placeholder:
|
|
21303
|
+
var promptAttachmentManifestEntrySchema = z5.object({
|
|
21304
|
+
clientId: z5.string().min(1),
|
|
21305
|
+
kind: z5.enum(["photo", "file"]),
|
|
21306
|
+
originalName: z5.string().optional(),
|
|
21307
|
+
placeholder: z5.string().min(1)
|
|
20880
21308
|
});
|
|
20881
|
-
var updateThreadSchema =
|
|
20882
|
-
title:
|
|
21309
|
+
var updateThreadSchema = z5.object({
|
|
21310
|
+
title: z5.string().min(1)
|
|
20883
21311
|
});
|
|
20884
|
-
var updateThreadSettingsSchema =
|
|
20885
|
-
model:
|
|
20886
|
-
reasoningEffort:
|
|
20887
|
-
fastMode:
|
|
20888
|
-
collaborationMode:
|
|
20889
|
-
sandboxMode:
|
|
21312
|
+
var updateThreadSettingsSchema = z5.object({
|
|
21313
|
+
model: z5.string().min(1).optional(),
|
|
21314
|
+
reasoningEffort: z5.enum(["none", "minimal", "low", "medium", "high", "xhigh"]).nullable().optional(),
|
|
21315
|
+
fastMode: z5.boolean().optional(),
|
|
21316
|
+
collaborationMode: z5.enum(["default", "plan"]).optional(),
|
|
21317
|
+
sandboxMode: z5.enum(["read-only", "workspace-write", "danger-full-access"]).nullable().optional()
|
|
20890
21318
|
}).refine((body) => Object.keys(body).length > 0, {
|
|
20891
21319
|
message: "At least one thread setting must be provided."
|
|
20892
21320
|
});
|
|
20893
|
-
var updateThreadGoalSchema =
|
|
20894
|
-
objective:
|
|
20895
|
-
status:
|
|
20896
|
-
tokenBudget:
|
|
21321
|
+
var updateThreadGoalSchema = z5.object({
|
|
21322
|
+
objective: z5.string().min(1).nullable().optional(),
|
|
21323
|
+
status: z5.enum(["active", "paused", "budgetLimited", "complete", "terminated"]).nullable().optional(),
|
|
21324
|
+
tokenBudget: z5.number().int().positive().nullable().optional()
|
|
20897
21325
|
}).refine((body) => Object.keys(body).length > 0, {
|
|
20898
21326
|
message: "At least one goal field must be provided."
|
|
20899
21327
|
});
|
|
20900
|
-
var interruptSchema =
|
|
20901
|
-
turnId:
|
|
21328
|
+
var interruptSchema = z5.object({
|
|
21329
|
+
turnId: z5.string().optional()
|
|
20902
21330
|
});
|
|
20903
|
-
var importThreadSchema =
|
|
20904
|
-
sessionId:
|
|
21331
|
+
var importThreadSchema = z5.object({
|
|
21332
|
+
sessionId: z5.string().min(1)
|
|
20905
21333
|
});
|
|
20906
|
-
var resumeThreadSchema =
|
|
20907
|
-
model:
|
|
20908
|
-
sandboxMode:
|
|
21334
|
+
var resumeThreadSchema = z5.object({
|
|
21335
|
+
model: z5.string().min(1).optional(),
|
|
21336
|
+
sandboxMode: z5.enum(["read-only", "workspace-write", "danger-full-access"]).nullable().optional()
|
|
20909
21337
|
});
|
|
20910
|
-
var forkThreadSchema =
|
|
20911
|
-
|
|
20912
|
-
mode:
|
|
21338
|
+
var forkThreadSchema = z5.discriminatedUnion("mode", [
|
|
21339
|
+
z5.object({
|
|
21340
|
+
mode: z5.literal("latest")
|
|
20913
21341
|
}),
|
|
20914
|
-
|
|
20915
|
-
mode:
|
|
20916
|
-
turnId:
|
|
21342
|
+
z5.object({
|
|
21343
|
+
mode: z5.literal("turn"),
|
|
21344
|
+
turnId: z5.string().min(1)
|
|
20917
21345
|
})
|
|
20918
21346
|
]);
|
|
20919
|
-
var hookEventNameSchema =
|
|
21347
|
+
var hookEventNameSchema = z5.enum([
|
|
20920
21348
|
"preToolUse",
|
|
20921
21349
|
"permissionRequest",
|
|
20922
21350
|
"postToolUse",
|
|
@@ -20926,48 +21354,48 @@ var hookEventNameSchema = z6.enum([
|
|
|
20926
21354
|
"userPromptSubmit",
|
|
20927
21355
|
"stop"
|
|
20928
21356
|
]);
|
|
20929
|
-
var createThreadHookSchema =
|
|
20930
|
-
scope:
|
|
21357
|
+
var createThreadHookSchema = z5.object({
|
|
21358
|
+
scope: z5.enum(["global", "project"]),
|
|
20931
21359
|
eventName: hookEventNameSchema,
|
|
20932
|
-
matcher:
|
|
20933
|
-
command:
|
|
20934
|
-
timeoutSec:
|
|
20935
|
-
statusMessage:
|
|
21360
|
+
matcher: z5.string().nullable().optional(),
|
|
21361
|
+
command: z5.string().trim().min(1),
|
|
21362
|
+
timeoutSec: z5.number().int().positive().max(86400).nullable().optional(),
|
|
21363
|
+
statusMessage: z5.string().nullable().optional()
|
|
20936
21364
|
});
|
|
20937
21365
|
var updateThreadHookSchema = createThreadHookSchema.extend({
|
|
20938
21366
|
target: createThreadHookSchema
|
|
20939
21367
|
});
|
|
20940
|
-
var trustThreadHookSchema =
|
|
20941
|
-
key:
|
|
20942
|
-
currentHash:
|
|
21368
|
+
var trustThreadHookSchema = z5.object({
|
|
21369
|
+
key: z5.string().min(1),
|
|
21370
|
+
currentHash: z5.string().min(1)
|
|
20943
21371
|
});
|
|
20944
|
-
var untrustThreadHookSchema =
|
|
20945
|
-
key:
|
|
21372
|
+
var untrustThreadHookSchema = z5.object({
|
|
21373
|
+
key: z5.string().min(1)
|
|
20946
21374
|
});
|
|
20947
|
-
var respondThreadRequestSchema =
|
|
20948
|
-
answers:
|
|
20949
|
-
answers:
|
|
21375
|
+
var respondThreadRequestSchema = z5.object({
|
|
21376
|
+
answers: z5.record(z5.string(), z5.object({
|
|
21377
|
+
answers: z5.array(z5.string())
|
|
20950
21378
|
}))
|
|
20951
21379
|
});
|
|
20952
|
-
var threadDetailQuerySchema =
|
|
20953
|
-
limit:
|
|
20954
|
-
beforeTurnId:
|
|
21380
|
+
var threadDetailQuerySchema = z5.object({
|
|
21381
|
+
limit: z5.coerce.number().int().positive().max(100).optional(),
|
|
21382
|
+
beforeTurnId: z5.string().min(1).optional()
|
|
20955
21383
|
});
|
|
20956
|
-
var exportThreadPdfSchema =
|
|
20957
|
-
format:
|
|
20958
|
-
mode:
|
|
20959
|
-
limit:
|
|
20960
|
-
turnIds:
|
|
20961
|
-
profile:
|
|
20962
|
-
options:
|
|
20963
|
-
includeTokenAndPrice:
|
|
20964
|
-
includeCommandOutput:
|
|
20965
|
-
includeAbsolutePaths:
|
|
21384
|
+
var exportThreadPdfSchema = z5.object({
|
|
21385
|
+
format: z5.enum(["pdf", "html"]).optional(),
|
|
21386
|
+
mode: z5.enum(["latest", "selected"]),
|
|
21387
|
+
limit: z5.number().int().positive().max(100).optional(),
|
|
21388
|
+
turnIds: z5.array(z5.string().min(1)).max(100).optional(),
|
|
21389
|
+
profile: z5.enum(["review", "technical"]).optional(),
|
|
21390
|
+
options: z5.object({
|
|
21391
|
+
includeTokenAndPrice: z5.boolean().optional(),
|
|
21392
|
+
includeCommandOutput: z5.boolean().optional(),
|
|
21393
|
+
includeAbsolutePaths: z5.boolean().optional()
|
|
20966
21394
|
}).optional()
|
|
20967
21395
|
}).refine((body) => body.mode !== "selected" || (body.turnIds?.length ?? 0) > 0, {
|
|
20968
21396
|
message: "turnIds are required for selected exports."
|
|
20969
21397
|
});
|
|
20970
|
-
var queryBooleanSchema =
|
|
21398
|
+
var queryBooleanSchema = z5.preprocess((value) => {
|
|
20971
21399
|
if (value === "true" || value === "1") {
|
|
20972
21400
|
return true;
|
|
20973
21401
|
}
|
|
@@ -20975,21 +21403,21 @@ var queryBooleanSchema = z6.preprocess((value) => {
|
|
|
20975
21403
|
return false;
|
|
20976
21404
|
}
|
|
20977
21405
|
return value;
|
|
20978
|
-
},
|
|
20979
|
-
var exportThreadPdfQuerySchema =
|
|
20980
|
-
format:
|
|
20981
|
-
mode:
|
|
20982
|
-
limit:
|
|
20983
|
-
turnIds:
|
|
20984
|
-
profile:
|
|
21406
|
+
}, z5.boolean());
|
|
21407
|
+
var exportThreadPdfQuerySchema = z5.object({
|
|
21408
|
+
format: z5.enum(["pdf", "html"]).optional(),
|
|
21409
|
+
mode: z5.enum(["latest", "selected"]),
|
|
21410
|
+
limit: z5.coerce.number().int().positive().max(100).optional(),
|
|
21411
|
+
turnIds: z5.string().optional(),
|
|
21412
|
+
profile: z5.enum(["review", "technical"]).optional(),
|
|
20985
21413
|
includeTokenAndPrice: queryBooleanSchema.optional(),
|
|
20986
21414
|
includeCommandOutput: queryBooleanSchema.optional(),
|
|
20987
21415
|
includeAbsolutePaths: queryBooleanSchema.optional()
|
|
20988
21416
|
}).refine((query) => query.mode !== "selected" || Boolean(query.turnIds?.trim()), {
|
|
20989
21417
|
message: "turnIds are required for selected exports."
|
|
20990
21418
|
});
|
|
20991
|
-
var threadImageQuerySchema =
|
|
20992
|
-
path:
|
|
21419
|
+
var threadImageQuerySchema = z5.object({
|
|
21420
|
+
path: z5.string().min(1)
|
|
20993
21421
|
});
|
|
20994
21422
|
async function sendThreadExport(app2, reply, threadId, input) {
|
|
20995
21423
|
const result = await app2.services.threadService.exportThreadTranscript(threadId, input);
|
|
@@ -21089,7 +21517,7 @@ async function parseMultipartPromptRequest(request) {
|
|
|
21089
21517
|
message: "attachmentManifest must be valid JSON."
|
|
21090
21518
|
});
|
|
21091
21519
|
}
|
|
21092
|
-
const manifest =
|
|
21520
|
+
const manifest = z5.array(promptAttachmentManifestEntrySchema).max(MAX_PROMPT_ATTACHMENTS).parse(manifestParsed);
|
|
21093
21521
|
if (manifest.length !== uploadedFiles.length) {
|
|
21094
21522
|
throw new HttpError(400, {
|
|
21095
21523
|
code: "bad_request",
|
|
@@ -21133,7 +21561,7 @@ async function registerThreadRoutes(app2) {
|
|
|
21133
21561
|
return app2.services.threadService.importThread(body.sessionId);
|
|
21134
21562
|
});
|
|
21135
21563
|
app2.get("/api/threads/:id", async (request) => {
|
|
21136
|
-
const params =
|
|
21564
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21137
21565
|
const query = threadDetailQuerySchema.parse(request.query);
|
|
21138
21566
|
return app2.services.threadService.getThreadDetail(params.id, {
|
|
21139
21567
|
...query.limit !== void 0 ? { limit: query.limit } : {},
|
|
@@ -21141,11 +21569,11 @@ async function registerThreadRoutes(app2) {
|
|
|
21141
21569
|
});
|
|
21142
21570
|
});
|
|
21143
21571
|
app2.get("/api/threads/:id/export-turns", async (request) => {
|
|
21144
|
-
const params =
|
|
21572
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21145
21573
|
return app2.services.threadService.listThreadExportTurns(params.id);
|
|
21146
21574
|
});
|
|
21147
21575
|
app2.get("/api/threads/:id/exports/pdf", async (request, reply) => {
|
|
21148
|
-
const params =
|
|
21576
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21149
21577
|
const query = exportThreadPdfQuerySchema.parse(request.query);
|
|
21150
21578
|
const turnIds = query.turnIds?.split(",").map((turnId) => turnId.trim()).filter(Boolean);
|
|
21151
21579
|
const options = {};
|
|
@@ -21169,7 +21597,7 @@ async function registerThreadRoutes(app2) {
|
|
|
21169
21597
|
return sendThreadExport(app2, reply, params.id, input);
|
|
21170
21598
|
});
|
|
21171
21599
|
app2.post("/api/threads/:id/exports/pdf", async (request, reply) => {
|
|
21172
|
-
const params =
|
|
21600
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21173
21601
|
const parsed = exportThreadPdfSchema.parse(request.body);
|
|
21174
21602
|
const input = {
|
|
21175
21603
|
...parsed.format !== void 0 ? { format: parsed.format } : {},
|
|
@@ -21188,9 +21616,9 @@ async function registerThreadRoutes(app2) {
|
|
|
21188
21616
|
return sendThreadExport(app2, reply, params.id, input);
|
|
21189
21617
|
});
|
|
21190
21618
|
app2.get("/api/threads/:id/items/:itemId/detail", async (request) => {
|
|
21191
|
-
const params =
|
|
21192
|
-
id:
|
|
21193
|
-
itemId:
|
|
21619
|
+
const params = z5.object({
|
|
21620
|
+
id: z5.string().uuid(),
|
|
21621
|
+
itemId: z5.string().min(1)
|
|
21194
21622
|
}).parse(request.params);
|
|
21195
21623
|
return app2.services.threadService.getThreadHistoryItemDetail(
|
|
21196
21624
|
params.id,
|
|
@@ -21198,7 +21626,7 @@ async function registerThreadRoutes(app2) {
|
|
|
21198
21626
|
);
|
|
21199
21627
|
});
|
|
21200
21628
|
app2.get("/api/threads/:id/assets/image", async (request, reply) => {
|
|
21201
|
-
const params =
|
|
21629
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21202
21630
|
const query = threadImageQuerySchema.parse(request.query);
|
|
21203
21631
|
const record = getThreadRecordById(app2.services.database.db, params.id);
|
|
21204
21632
|
if (!record) {
|
|
@@ -21244,12 +21672,12 @@ async function registerThreadRoutes(app2) {
|
|
|
21244
21672
|
return reply.send(await fs16.readFile(requestedPath));
|
|
21245
21673
|
});
|
|
21246
21674
|
app2.patch("/api/threads/:id", async (request) => {
|
|
21247
|
-
const params =
|
|
21675
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21248
21676
|
const body = updateThreadSchema.parse(request.body);
|
|
21249
21677
|
return app2.services.threadService.updateThreadTitle(params.id, body.title);
|
|
21250
21678
|
});
|
|
21251
21679
|
app2.delete("/api/threads/:id", async (request) => {
|
|
21252
|
-
const params =
|
|
21680
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21253
21681
|
const shell = getShellSessionRecordByThreadId(app2.services.database.db, params.id);
|
|
21254
21682
|
if (shell) {
|
|
21255
21683
|
if (shell.status !== "exited" && shell.status !== "not_found") {
|
|
@@ -21261,7 +21689,7 @@ async function registerThreadRoutes(app2) {
|
|
|
21261
21689
|
return app2.services.threadService.deleteThread(params.id);
|
|
21262
21690
|
});
|
|
21263
21691
|
app2.patch("/api/threads/:id/settings", async (request) => {
|
|
21264
|
-
const params =
|
|
21692
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21265
21693
|
const body = updateThreadSettingsSchema.parse(request.body);
|
|
21266
21694
|
const input = {
|
|
21267
21695
|
...body.model !== void 0 ? { model: body.model } : {},
|
|
@@ -21273,15 +21701,15 @@ async function registerThreadRoutes(app2) {
|
|
|
21273
21701
|
return app2.services.threadService.updateThreadSettings(params.id, input);
|
|
21274
21702
|
});
|
|
21275
21703
|
app2.post("/api/threads/:id/compact", async (request) => {
|
|
21276
|
-
const params =
|
|
21704
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21277
21705
|
return app2.services.threadService.compactThread(params.id);
|
|
21278
21706
|
});
|
|
21279
21707
|
app2.get("/api/threads/:id/goal", async (request) => {
|
|
21280
|
-
const params =
|
|
21708
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21281
21709
|
return { goal: await app2.services.threadService.getThreadGoal(params.id) };
|
|
21282
21710
|
});
|
|
21283
21711
|
app2.patch("/api/threads/:id/goal", async (request) => {
|
|
21284
|
-
const params =
|
|
21712
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21285
21713
|
const parsedBody = updateThreadGoalSchema.parse(request.body);
|
|
21286
21714
|
const body = {
|
|
21287
21715
|
...parsedBody.objective !== void 0 ? { objective: parsedBody.objective } : {},
|
|
@@ -21291,32 +21719,32 @@ async function registerThreadRoutes(app2) {
|
|
|
21291
21719
|
return { goal: await app2.services.threadService.updateThreadGoal(params.id, body) };
|
|
21292
21720
|
});
|
|
21293
21721
|
app2.delete("/api/threads/:id/goal", async (request) => {
|
|
21294
|
-
const params =
|
|
21722
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21295
21723
|
return app2.services.threadService.clearThreadGoal(params.id);
|
|
21296
21724
|
});
|
|
21297
21725
|
app2.get("/api/threads/:id/fork-turns", async (request) => {
|
|
21298
|
-
const params =
|
|
21726
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21299
21727
|
return app2.services.threadService.listForkTurnOptions(params.id);
|
|
21300
21728
|
});
|
|
21301
21729
|
app2.post("/api/threads/:id/fork", async (request) => {
|
|
21302
|
-
const params =
|
|
21730
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21303
21731
|
const body = forkThreadSchema.parse(request.body);
|
|
21304
21732
|
return app2.services.threadService.forkThread(params.id, body);
|
|
21305
21733
|
});
|
|
21306
21734
|
app2.get("/api/threads/:id/skills", async (request) => {
|
|
21307
|
-
const params =
|
|
21735
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21308
21736
|
return app2.services.threadService.listThreadSkills(params.id);
|
|
21309
21737
|
});
|
|
21310
21738
|
app2.get("/api/threads/:id/mcp-servers", async (request) => {
|
|
21311
|
-
const params =
|
|
21739
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21312
21740
|
return app2.services.threadService.listThreadMcpServers(params.id);
|
|
21313
21741
|
});
|
|
21314
21742
|
app2.get("/api/threads/:id/hooks", async (request) => {
|
|
21315
|
-
const params =
|
|
21743
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21316
21744
|
return app2.services.threadService.listThreadHooks(params.id);
|
|
21317
21745
|
});
|
|
21318
21746
|
app2.post("/api/threads/:id/hooks", async (request) => {
|
|
21319
|
-
const params =
|
|
21747
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21320
21748
|
const parsedBody = createThreadHookSchema.parse(request.body);
|
|
21321
21749
|
const body = {
|
|
21322
21750
|
scope: parsedBody.scope,
|
|
@@ -21329,7 +21757,7 @@ async function registerThreadRoutes(app2) {
|
|
|
21329
21757
|
return app2.services.threadService.createThreadHook(params.id, body);
|
|
21330
21758
|
});
|
|
21331
21759
|
app2.put("/api/threads/:id/hooks", async (request) => {
|
|
21332
|
-
const params =
|
|
21760
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21333
21761
|
const parsedBody = updateThreadHookSchema.parse(request.body);
|
|
21334
21762
|
const body = {
|
|
21335
21763
|
scope: parsedBody.scope,
|
|
@@ -21350,17 +21778,17 @@ async function registerThreadRoutes(app2) {
|
|
|
21350
21778
|
return app2.services.threadService.updateThreadHook(params.id, body);
|
|
21351
21779
|
});
|
|
21352
21780
|
app2.post("/api/threads/:id/hooks/trust", async (request) => {
|
|
21353
|
-
const params =
|
|
21781
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21354
21782
|
const body = trustThreadHookSchema.parse(request.body);
|
|
21355
21783
|
return app2.services.threadService.trustThreadHook(params.id, body);
|
|
21356
21784
|
});
|
|
21357
21785
|
app2.post("/api/threads/:id/hooks/untrust", async (request) => {
|
|
21358
|
-
const params =
|
|
21786
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21359
21787
|
const body = untrustThreadHookSchema.parse(request.body);
|
|
21360
21788
|
return app2.services.threadService.untrustThreadHook(params.id, body);
|
|
21361
21789
|
});
|
|
21362
21790
|
app2.post("/api/threads/:id/resume", async (request) => {
|
|
21363
|
-
const params =
|
|
21791
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21364
21792
|
const body = resumeThreadSchema.parse(request.body ?? {});
|
|
21365
21793
|
const input = {
|
|
21366
21794
|
...body.model !== void 0 ? { model: body.model } : {},
|
|
@@ -21369,13 +21797,13 @@ async function registerThreadRoutes(app2) {
|
|
|
21369
21797
|
return app2.services.threadService.resumeThread(params.id, input);
|
|
21370
21798
|
});
|
|
21371
21799
|
app2.post("/api/threads/:id/disconnect", async (request) => {
|
|
21372
|
-
const params =
|
|
21800
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21373
21801
|
const detail = await app2.services.threadService.disconnectThread(params.id);
|
|
21374
21802
|
await app2.services.shellService.detachThreadViewers(params.id);
|
|
21375
21803
|
return detail;
|
|
21376
21804
|
});
|
|
21377
21805
|
app2.post("/api/threads/:id/prompt", async (request) => {
|
|
21378
|
-
const params =
|
|
21806
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21379
21807
|
const parsed = request.isMultipart() ? await parseMultipartPromptRequest(request) : {
|
|
21380
21808
|
input: (() => {
|
|
21381
21809
|
const parsedBody = promptSchema.parse(request.body);
|
|
@@ -21400,15 +21828,15 @@ async function registerThreadRoutes(app2) {
|
|
|
21400
21828
|
});
|
|
21401
21829
|
});
|
|
21402
21830
|
app2.post("/api/threads/:id/requests/:requestId/respond", async (request) => {
|
|
21403
|
-
const params =
|
|
21404
|
-
id:
|
|
21405
|
-
requestId:
|
|
21831
|
+
const params = z5.object({
|
|
21832
|
+
id: z5.string().uuid(),
|
|
21833
|
+
requestId: z5.string().min(1)
|
|
21406
21834
|
}).parse(request.params);
|
|
21407
21835
|
const body = respondThreadRequestSchema.parse(request.body);
|
|
21408
21836
|
return app2.services.threadService.respondToRequest(params.id, params.requestId, body);
|
|
21409
21837
|
});
|
|
21410
21838
|
app2.post("/api/threads/:id/interrupt", async (request) => {
|
|
21411
|
-
const params =
|
|
21839
|
+
const params = z5.object({ id: z5.string().uuid() }).parse(request.params);
|
|
21412
21840
|
const body = interruptSchema.parse(request.body ?? {});
|
|
21413
21841
|
return app2.services.threadService.interruptThread(params.id, body.turnId);
|
|
21414
21842
|
});
|
|
@@ -21418,27 +21846,46 @@ async function registerThreadRoutes(app2) {
|
|
|
21418
21846
|
import fs17 from "fs/promises";
|
|
21419
21847
|
import path17 from "path";
|
|
21420
21848
|
import { spawn as spawn3 } from "child_process";
|
|
21421
|
-
import {
|
|
21422
|
-
|
|
21423
|
-
|
|
21424
|
-
|
|
21425
|
-
|
|
21849
|
+
import { Readable } from "stream";
|
|
21850
|
+
import { z as z6 } from "zod";
|
|
21851
|
+
var createWorkspaceSchema = z6.union([
|
|
21852
|
+
z6.object({
|
|
21853
|
+
absPath: z6.string().min(1),
|
|
21854
|
+
label: z6.string().min(1).optional()
|
|
21426
21855
|
}),
|
|
21427
|
-
|
|
21428
|
-
gitUrl:
|
|
21429
|
-
label:
|
|
21856
|
+
z6.object({
|
|
21857
|
+
gitUrl: z6.string().min(1),
|
|
21858
|
+
label: z6.string().min(1).optional()
|
|
21430
21859
|
})
|
|
21431
21860
|
]);
|
|
21432
|
-
var updateFavoriteSchema =
|
|
21433
|
-
isFavorite:
|
|
21861
|
+
var updateFavoriteSchema = z6.object({
|
|
21862
|
+
isFavorite: z6.boolean()
|
|
21863
|
+
});
|
|
21864
|
+
var updateWorkspaceSchema = z6.object({
|
|
21865
|
+
label: z6.string().min(1)
|
|
21866
|
+
});
|
|
21867
|
+
var treeQuerySchema = z6.object({
|
|
21868
|
+
path: z6.string().optional(),
|
|
21869
|
+
showHidden: z6.coerce.boolean().optional()
|
|
21434
21870
|
});
|
|
21435
|
-
var
|
|
21436
|
-
|
|
21871
|
+
var workspaceFileQuerySchema = z6.object({
|
|
21872
|
+
path: z6.string().optional().default("")
|
|
21437
21873
|
});
|
|
21438
|
-
var
|
|
21439
|
-
path:
|
|
21440
|
-
|
|
21874
|
+
var workspacePreviewQuerySchema = z6.object({
|
|
21875
|
+
path: z6.string().min(1),
|
|
21876
|
+
offset: z6.coerce.number().int().min(0).optional(),
|
|
21877
|
+
limit: z6.coerce.number().int().positive().max(25e4).optional()
|
|
21441
21878
|
});
|
|
21879
|
+
var PREVIEW_DEFAULT_LIMIT_BYTES = 5e4;
|
|
21880
|
+
var WORKSPACE_UPLOAD_MAX_BYTES = 50 * 1024 * 1024;
|
|
21881
|
+
var WORKSPACE_TREE_IGNORED_NAMES = /* @__PURE__ */ new Set([
|
|
21882
|
+
".git",
|
|
21883
|
+
"node_modules",
|
|
21884
|
+
".next",
|
|
21885
|
+
".turbo",
|
|
21886
|
+
"dist",
|
|
21887
|
+
"build"
|
|
21888
|
+
]);
|
|
21442
21889
|
function toWorkspaceDto2(record) {
|
|
21443
21890
|
return {
|
|
21444
21891
|
id: record.id,
|
|
@@ -21450,6 +21897,159 @@ function toWorkspaceDto2(record) {
|
|
|
21450
21897
|
lastOpenedAt: record.lastOpenedAt
|
|
21451
21898
|
};
|
|
21452
21899
|
}
|
|
21900
|
+
function languageForPath(filePath) {
|
|
21901
|
+
const extension = path17.extname(filePath).slice(1).toLowerCase();
|
|
21902
|
+
switch (extension) {
|
|
21903
|
+
case "js":
|
|
21904
|
+
case "jsx":
|
|
21905
|
+
return "javascript";
|
|
21906
|
+
case "ts":
|
|
21907
|
+
case "tsx":
|
|
21908
|
+
return extension;
|
|
21909
|
+
case "md":
|
|
21910
|
+
case "markdown":
|
|
21911
|
+
return "markdown";
|
|
21912
|
+
case "yml":
|
|
21913
|
+
return "yaml";
|
|
21914
|
+
case "sh":
|
|
21915
|
+
case "bash":
|
|
21916
|
+
return "bash";
|
|
21917
|
+
case "py":
|
|
21918
|
+
return "python";
|
|
21919
|
+
case "rb":
|
|
21920
|
+
return "ruby";
|
|
21921
|
+
case "rs":
|
|
21922
|
+
return "rust";
|
|
21923
|
+
case "go":
|
|
21924
|
+
return "go";
|
|
21925
|
+
case "c":
|
|
21926
|
+
case "h":
|
|
21927
|
+
return "c";
|
|
21928
|
+
case "cc":
|
|
21929
|
+
case "cpp":
|
|
21930
|
+
case "cxx":
|
|
21931
|
+
case "hpp":
|
|
21932
|
+
return "cpp";
|
|
21933
|
+
case "html":
|
|
21934
|
+
case "css":
|
|
21935
|
+
case "json":
|
|
21936
|
+
case "jsonl":
|
|
21937
|
+
case "toml":
|
|
21938
|
+
case "xml":
|
|
21939
|
+
case "sql":
|
|
21940
|
+
case "txt":
|
|
21941
|
+
return extension;
|
|
21942
|
+
default:
|
|
21943
|
+
return extension || "text";
|
|
21944
|
+
}
|
|
21945
|
+
}
|
|
21946
|
+
function relativeWorkspacePath(rootPath, absPath) {
|
|
21947
|
+
const relative = path17.relative(rootPath, absPath);
|
|
21948
|
+
return relative === "" ? "" : relative.split(path17.sep).join("/");
|
|
21949
|
+
}
|
|
21950
|
+
async function resolveWorkspaceItemPath(rootPath, relativePath = "") {
|
|
21951
|
+
const candidate = path17.resolve(rootPath, relativePath || ".");
|
|
21952
|
+
const comparable = await assertPathWithinRoot(rootPath, candidate);
|
|
21953
|
+
return comparable;
|
|
21954
|
+
}
|
|
21955
|
+
async function buildWorkspaceTreeNode(rootPath, absPath, depth = 0) {
|
|
21956
|
+
const stats = await fs17.stat(absPath);
|
|
21957
|
+
const relativePath = relativeWorkspacePath(rootPath, absPath);
|
|
21958
|
+
const name = relativePath ? path17.basename(absPath) : path17.basename(rootPath);
|
|
21959
|
+
if (!stats.isDirectory()) {
|
|
21960
|
+
return {
|
|
21961
|
+
name,
|
|
21962
|
+
path: relativePath,
|
|
21963
|
+
kind: "file",
|
|
21964
|
+
size: stats.size
|
|
21965
|
+
};
|
|
21966
|
+
}
|
|
21967
|
+
const node = {
|
|
21968
|
+
name,
|
|
21969
|
+
path: relativePath,
|
|
21970
|
+
kind: "directory",
|
|
21971
|
+
children: []
|
|
21972
|
+
};
|
|
21973
|
+
if (depth >= 6) {
|
|
21974
|
+
return node;
|
|
21975
|
+
}
|
|
21976
|
+
let entries;
|
|
21977
|
+
try {
|
|
21978
|
+
entries = await fs17.readdir(absPath, { withFileTypes: true });
|
|
21979
|
+
} catch {
|
|
21980
|
+
return node;
|
|
21981
|
+
}
|
|
21982
|
+
const visible = entries.filter((entry) => !entry.name.startsWith(".")).filter((entry) => !WORKSPACE_TREE_IGNORED_NAMES.has(entry.name)).sort((left, right) => {
|
|
21983
|
+
if (left.isDirectory() && !right.isDirectory()) {
|
|
21984
|
+
return -1;
|
|
21985
|
+
}
|
|
21986
|
+
if (!left.isDirectory() && right.isDirectory()) {
|
|
21987
|
+
return 1;
|
|
21988
|
+
}
|
|
21989
|
+
return left.name.localeCompare(right.name);
|
|
21990
|
+
}).slice(0, 400);
|
|
21991
|
+
node.children = (await Promise.all(
|
|
21992
|
+
visible.map(async (entry) => {
|
|
21993
|
+
const childPath = path17.join(absPath, entry.name);
|
|
21994
|
+
try {
|
|
21995
|
+
if (!entry.isDirectory() && !entry.isFile()) {
|
|
21996
|
+
return null;
|
|
21997
|
+
}
|
|
21998
|
+
return await buildWorkspaceTreeNode(rootPath, childPath, depth + 1);
|
|
21999
|
+
} catch {
|
|
22000
|
+
return null;
|
|
22001
|
+
}
|
|
22002
|
+
})
|
|
22003
|
+
)).filter((child) => child !== null);
|
|
22004
|
+
return node;
|
|
22005
|
+
}
|
|
22006
|
+
function requireWorkspaceRecord(app2, workspaceId) {
|
|
22007
|
+
const record = getWorkspaceRecordById(app2.services.database.db, workspaceId);
|
|
22008
|
+
if (!record) {
|
|
22009
|
+
throw new HttpError(404, {
|
|
22010
|
+
code: "not_found",
|
|
22011
|
+
message: "Workspace was not found."
|
|
22012
|
+
});
|
|
22013
|
+
}
|
|
22014
|
+
return record;
|
|
22015
|
+
}
|
|
22016
|
+
function contentTypeForPath(filePath) {
|
|
22017
|
+
switch (path17.extname(filePath).slice(1).toLowerCase()) {
|
|
22018
|
+
case "png":
|
|
22019
|
+
return "image/png";
|
|
22020
|
+
case "jpg":
|
|
22021
|
+
case "jpeg":
|
|
22022
|
+
return "image/jpeg";
|
|
22023
|
+
case "gif":
|
|
22024
|
+
return "image/gif";
|
|
22025
|
+
case "webp":
|
|
22026
|
+
return "image/webp";
|
|
22027
|
+
case "svg":
|
|
22028
|
+
return "image/svg+xml";
|
|
22029
|
+
case "pdf":
|
|
22030
|
+
return "application/pdf";
|
|
22031
|
+
case "json":
|
|
22032
|
+
return "application/json; charset=utf-8";
|
|
22033
|
+
case "html":
|
|
22034
|
+
return "text/html; charset=utf-8";
|
|
22035
|
+
case "css":
|
|
22036
|
+
return "text/css; charset=utf-8";
|
|
22037
|
+
case "js":
|
|
22038
|
+
case "mjs":
|
|
22039
|
+
case "ts":
|
|
22040
|
+
case "tsx":
|
|
22041
|
+
return "text/plain; charset=utf-8";
|
|
22042
|
+
default:
|
|
22043
|
+
return "application/octet-stream";
|
|
22044
|
+
}
|
|
22045
|
+
}
|
|
22046
|
+
function sanitizeUploadFilename(filename) {
|
|
22047
|
+
const baseName = path17.basename(filename?.trim() || "upload");
|
|
22048
|
+
if (!baseName || baseName === "." || baseName === "..") {
|
|
22049
|
+
return "upload";
|
|
22050
|
+
}
|
|
22051
|
+
return baseName;
|
|
22052
|
+
}
|
|
21453
22053
|
function inferGitRepoName(gitUrl) {
|
|
21454
22054
|
const trimmed = gitUrl.trim();
|
|
21455
22055
|
const withoutQuery = trimmed.split(/[?#]/)[0] ?? trimmed;
|
|
@@ -21534,7 +22134,7 @@ async function registerWorkspaceRoutes(app2) {
|
|
|
21534
22134
|
};
|
|
21535
22135
|
});
|
|
21536
22136
|
app2.get("/api/workspaces/:id", async (request) => {
|
|
21537
|
-
const params =
|
|
22137
|
+
const params = z6.object({ id: z6.string().uuid() }).parse(request.params);
|
|
21538
22138
|
const record = getWorkspaceRecordById(app2.services.database.db, params.id);
|
|
21539
22139
|
if (!record) {
|
|
21540
22140
|
throw new HttpError(404, {
|
|
@@ -21544,6 +22144,114 @@ async function registerWorkspaceRoutes(app2) {
|
|
|
21544
22144
|
}
|
|
21545
22145
|
return toWorkspaceDto2(record);
|
|
21546
22146
|
});
|
|
22147
|
+
app2.get("/api/workspaces/:id/files/tree", async (request) => {
|
|
22148
|
+
const params = z6.object({ id: z6.string().uuid() }).parse(request.params);
|
|
22149
|
+
const query = workspaceFileQuerySchema.parse(request.query);
|
|
22150
|
+
const record = requireWorkspaceRecord(app2, params.id);
|
|
22151
|
+
const rootPath = await fs17.realpath(record.absPath);
|
|
22152
|
+
const targetPath = await resolveWorkspaceItemPath(rootPath, query.path);
|
|
22153
|
+
return buildWorkspaceTreeNode(rootPath, targetPath);
|
|
22154
|
+
});
|
|
22155
|
+
app2.get("/api/workspaces/:id/files/preview", async (request) => {
|
|
22156
|
+
const params = z6.object({ id: z6.string().uuid() }).parse(request.params);
|
|
22157
|
+
const query = workspacePreviewQuerySchema.parse(request.query);
|
|
22158
|
+
const record = requireWorkspaceRecord(app2, params.id);
|
|
22159
|
+
const rootPath = await fs17.realpath(record.absPath);
|
|
22160
|
+
const filePath = await resolveWorkspaceItemPath(rootPath, query.path);
|
|
22161
|
+
const stats = await fs17.stat(filePath);
|
|
22162
|
+
if (!stats.isFile()) {
|
|
22163
|
+
throw new HttpError(400, {
|
|
22164
|
+
code: "bad_request",
|
|
22165
|
+
message: "Workspace preview path must point to a file."
|
|
22166
|
+
});
|
|
22167
|
+
}
|
|
22168
|
+
const offset = query.offset ?? 0;
|
|
22169
|
+
const limit = query.limit ?? PREVIEW_DEFAULT_LIMIT_BYTES;
|
|
22170
|
+
const handle = await fs17.open(filePath, "r");
|
|
22171
|
+
try {
|
|
22172
|
+
const length = Math.min(limit, Math.max(0, stats.size - offset));
|
|
22173
|
+
const buffer = Buffer.alloc(length);
|
|
22174
|
+
const read = await handle.read(buffer, 0, length, offset);
|
|
22175
|
+
const nextOffset = offset + read.bytesRead;
|
|
22176
|
+
return {
|
|
22177
|
+
path: relativeWorkspacePath(rootPath, filePath),
|
|
22178
|
+
name: path17.basename(filePath),
|
|
22179
|
+
content: buffer.subarray(0, read.bytesRead).toString("utf8"),
|
|
22180
|
+
language: languageForPath(filePath),
|
|
22181
|
+
size: stats.size,
|
|
22182
|
+
truncated: nextOffset < stats.size,
|
|
22183
|
+
nextOffset
|
|
22184
|
+
};
|
|
22185
|
+
} finally {
|
|
22186
|
+
await handle.close();
|
|
22187
|
+
}
|
|
22188
|
+
});
|
|
22189
|
+
app2.get("/api/workspaces/:id/files/raw", async (request, reply) => {
|
|
22190
|
+
const params = z6.object({ id: z6.string().uuid() }).parse(request.params);
|
|
22191
|
+
const query = workspacePreviewQuerySchema.pick({ path: true }).parse(request.query);
|
|
22192
|
+
const record = requireWorkspaceRecord(app2, params.id);
|
|
22193
|
+
const rootPath = await fs17.realpath(record.absPath);
|
|
22194
|
+
const filePath = await resolveWorkspaceItemPath(rootPath, query.path);
|
|
22195
|
+
const stats = await fs17.stat(filePath);
|
|
22196
|
+
if (!stats.isFile()) {
|
|
22197
|
+
throw new HttpError(400, {
|
|
22198
|
+
code: "bad_request",
|
|
22199
|
+
message: "Raw workspace path must point to a file."
|
|
22200
|
+
});
|
|
22201
|
+
}
|
|
22202
|
+
reply.header("content-type", contentTypeForPath(filePath));
|
|
22203
|
+
return reply.send(Readable.from(await fs17.readFile(filePath)));
|
|
22204
|
+
});
|
|
22205
|
+
app2.get("/api/workspaces/:id/files/download", async (request, reply) => {
|
|
22206
|
+
const params = z6.object({ id: z6.string().uuid() }).parse(request.params);
|
|
22207
|
+
const query = workspaceFileQuerySchema.parse(request.query);
|
|
22208
|
+
const record = requireWorkspaceRecord(app2, params.id);
|
|
22209
|
+
const rootPath = await fs17.realpath(record.absPath);
|
|
22210
|
+
const itemPath = await resolveWorkspaceItemPath(rootPath, query.path);
|
|
22211
|
+
const stats = await fs17.stat(itemPath);
|
|
22212
|
+
if (!stats.isFile()) {
|
|
22213
|
+
throw new HttpError(400, {
|
|
22214
|
+
code: "bad_request",
|
|
22215
|
+
message: "Only file downloads are supported from this endpoint."
|
|
22216
|
+
});
|
|
22217
|
+
}
|
|
22218
|
+
const filename = path17.basename(itemPath);
|
|
22219
|
+
reply.header("content-type", contentTypeForPath(itemPath)).header(
|
|
22220
|
+
"content-disposition",
|
|
22221
|
+
`attachment; filename="${filename}"; filename*=UTF-8''${encodeURIComponent(filename)}`
|
|
22222
|
+
);
|
|
22223
|
+
return reply.send(Readable.from(await fs17.readFile(itemPath)));
|
|
22224
|
+
});
|
|
22225
|
+
app2.post("/api/workspaces/:id/files/upload", async (request) => {
|
|
22226
|
+
const params = z6.object({ id: z6.string().uuid() }).parse(request.params);
|
|
22227
|
+
const record = requireWorkspaceRecord(app2, params.id);
|
|
22228
|
+
const rootPath = await fs17.realpath(record.absPath);
|
|
22229
|
+
const part = await request.file();
|
|
22230
|
+
if (!part) {
|
|
22231
|
+
throw new HttpError(400, {
|
|
22232
|
+
code: "bad_request",
|
|
22233
|
+
message: "A file field is required."
|
|
22234
|
+
});
|
|
22235
|
+
}
|
|
22236
|
+
const buffer = await part.toBuffer();
|
|
22237
|
+
if (buffer.byteLength > WORKSPACE_UPLOAD_MAX_BYTES) {
|
|
22238
|
+
throw new HttpError(400, {
|
|
22239
|
+
code: "bad_request",
|
|
22240
|
+
message: "Workspace uploads must be 50 MB or smaller."
|
|
22241
|
+
});
|
|
22242
|
+
}
|
|
22243
|
+
const filename = sanitizeUploadFilename(part.filename);
|
|
22244
|
+
const destination = await resolveWorkspaceItemPath(rootPath, filename);
|
|
22245
|
+
await fs17.writeFile(destination, buffer);
|
|
22246
|
+
return {
|
|
22247
|
+
kind: "file",
|
|
22248
|
+
file: {
|
|
22249
|
+
path: relativeWorkspacePath(rootPath, destination),
|
|
22250
|
+
name: filename,
|
|
22251
|
+
size: buffer.byteLength
|
|
22252
|
+
}
|
|
22253
|
+
};
|
|
22254
|
+
});
|
|
21547
22255
|
app2.post("/api/workspaces", async (request) => {
|
|
21548
22256
|
const body = createWorkspaceSchema.parse(request.body);
|
|
21549
22257
|
const settings = await getWorkspaceSettings(
|
|
@@ -21588,7 +22296,7 @@ async function registerWorkspaceRoutes(app2) {
|
|
|
21588
22296
|
return toWorkspaceDto2(created);
|
|
21589
22297
|
});
|
|
21590
22298
|
app2.patch("/api/workspaces/:id", async (request) => {
|
|
21591
|
-
const params =
|
|
22299
|
+
const params = z6.object({ id: z6.string().uuid() }).parse(request.params);
|
|
21592
22300
|
const body = updateWorkspaceSchema.parse(request.body);
|
|
21593
22301
|
const record = getWorkspaceRecordById(app2.services.database.db, params.id);
|
|
21594
22302
|
if (!record) {
|
|
@@ -21609,7 +22317,7 @@ async function registerWorkspaceRoutes(app2) {
|
|
|
21609
22317
|
return toWorkspaceDto2(updated);
|
|
21610
22318
|
});
|
|
21611
22319
|
app2.delete("/api/workspaces/:id", async (request) => {
|
|
21612
|
-
const params =
|
|
22320
|
+
const params = z6.object({ id: z6.string().uuid() }).parse(request.params);
|
|
21613
22321
|
const record = getWorkspaceRecordById(app2.services.database.db, params.id);
|
|
21614
22322
|
if (!record) {
|
|
21615
22323
|
throw new HttpError(404, {
|
|
@@ -21633,7 +22341,7 @@ async function registerWorkspaceRoutes(app2) {
|
|
|
21633
22341
|
return { id: params.id };
|
|
21634
22342
|
});
|
|
21635
22343
|
app2.post("/api/workspaces/:id/favorite", async (request) => {
|
|
21636
|
-
const params =
|
|
22344
|
+
const params = z6.object({ id: z6.string().uuid() }).parse(request.params);
|
|
21637
22345
|
const body = updateFavoriteSchema.parse(request.body);
|
|
21638
22346
|
const record = getWorkspaceRecordById(app2.services.database.db, params.id);
|
|
21639
22347
|
if (!record) {
|
|
@@ -21647,7 +22355,7 @@ async function registerWorkspaceRoutes(app2) {
|
|
|
21647
22355
|
return toWorkspaceDto2(updated);
|
|
21648
22356
|
});
|
|
21649
22357
|
app2.post("/api/workspaces/:id/open", async (request) => {
|
|
21650
|
-
const params =
|
|
22358
|
+
const params = z6.object({ id: z6.string().uuid() }).parse(request.params);
|
|
21651
22359
|
const record = getWorkspaceRecordById(app2.services.database.db, params.id);
|
|
21652
22360
|
if (!record) {
|
|
21653
22361
|
throw new HttpError(404, {
|
|
@@ -21662,21 +22370,32 @@ async function registerWorkspaceRoutes(app2) {
|
|
|
21662
22370
|
}
|
|
21663
22371
|
|
|
21664
22372
|
// src/routes/plugins.ts
|
|
21665
|
-
import { z as
|
|
21666
|
-
var pluginParamsSchema =
|
|
21667
|
-
pluginId:
|
|
22373
|
+
import { z as z7 } from "zod";
|
|
22374
|
+
var pluginParamsSchema = z7.object({
|
|
22375
|
+
pluginId: z7.string().min(1)
|
|
21668
22376
|
});
|
|
21669
|
-
var updatePluginSchema =
|
|
21670
|
-
enabled:
|
|
22377
|
+
var updatePluginSchema = z7.object({
|
|
22378
|
+
enabled: z7.boolean()
|
|
21671
22379
|
});
|
|
21672
|
-
var importPluginSchema =
|
|
21673
|
-
enabled:
|
|
21674
|
-
manifestJson:
|
|
21675
|
-
manifest:
|
|
22380
|
+
var importPluginSchema = z7.object({
|
|
22381
|
+
enabled: z7.boolean().optional(),
|
|
22382
|
+
manifestJson: z7.string().optional(),
|
|
22383
|
+
manifest: z7.unknown().optional()
|
|
21676
22384
|
}).refine((value) => value.manifest !== void 0 || value.manifestJson !== void 0, {
|
|
21677
22385
|
message: "Plugin import requires manifest or manifestJson."
|
|
21678
22386
|
});
|
|
21679
22387
|
async function registerPluginRoutes(app2) {
|
|
22388
|
+
async function syncManagedPluginMcpConfig() {
|
|
22389
|
+
await app2.services.pluginService.syncManagedCodexMcpConfig({
|
|
22390
|
+
codexHome: app2.services.config.agentProviders.codex.home ?? null,
|
|
22391
|
+
repoRoot: app2.services.repoRoot
|
|
22392
|
+
});
|
|
22393
|
+
const codexRuntime = app2.services.agentRuntimes.getOptional("codex");
|
|
22394
|
+
if (codexRuntime) {
|
|
22395
|
+
await codexRuntime.stop();
|
|
22396
|
+
await codexRuntime.start();
|
|
22397
|
+
}
|
|
22398
|
+
}
|
|
21680
22399
|
app2.get("/api/plugins", async () => {
|
|
21681
22400
|
return app2.services.pluginService.listPlugins();
|
|
21682
22401
|
});
|
|
@@ -21688,7 +22407,9 @@ async function registerPluginRoutes(app2) {
|
|
|
21688
22407
|
...parsed.manifestJson === void 0 ? {} : { manifestJson: parsed.manifestJson }
|
|
21689
22408
|
};
|
|
21690
22409
|
try {
|
|
21691
|
-
|
|
22410
|
+
const plugin = app2.services.pluginService.importPlugin(body);
|
|
22411
|
+
await syncManagedPluginMcpConfig();
|
|
22412
|
+
return plugin;
|
|
21692
22413
|
} catch (error) {
|
|
21693
22414
|
if (error instanceof SyntaxError) {
|
|
21694
22415
|
throw new HttpError(400, {
|
|
@@ -21717,7 +22438,9 @@ async function registerPluginRoutes(app2) {
|
|
|
21717
22438
|
const { pluginId } = pluginParamsSchema.parse(request.params);
|
|
21718
22439
|
const body = updatePluginSchema.parse(request.body);
|
|
21719
22440
|
try {
|
|
21720
|
-
|
|
22441
|
+
const plugin = app2.services.pluginService.setPluginEnabled(pluginId, body.enabled);
|
|
22442
|
+
await syncManagedPluginMcpConfig();
|
|
22443
|
+
return plugin;
|
|
21721
22444
|
} catch {
|
|
21722
22445
|
throw new HttpError(404, {
|
|
21723
22446
|
code: "not_found",
|
|
@@ -21953,28 +22676,12 @@ var ProviderHostConfigService = class {
|
|
|
21953
22676
|
};
|
|
21954
22677
|
|
|
21955
22678
|
// src/shell/shell-session-service.ts
|
|
22679
|
+
import fs20 from "fs/promises";
|
|
22680
|
+
|
|
22681
|
+
// src/shell/shell-prompt.ts
|
|
21956
22682
|
import fs19 from "fs/promises";
|
|
21957
22683
|
import os3 from "os";
|
|
21958
22684
|
import path19 from "path";
|
|
21959
|
-
async function pathExists5(filePath) {
|
|
21960
|
-
try {
|
|
21961
|
-
await fs19.access(filePath);
|
|
21962
|
-
return true;
|
|
21963
|
-
} catch {
|
|
21964
|
-
return false;
|
|
21965
|
-
}
|
|
21966
|
-
}
|
|
21967
|
-
function nowIso() {
|
|
21968
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
21969
|
-
}
|
|
21970
|
-
function waitForShellTick(milliseconds) {
|
|
21971
|
-
if (process.env.VITEST) {
|
|
21972
|
-
return Promise.resolve();
|
|
21973
|
-
}
|
|
21974
|
-
return new Promise((resolve) => {
|
|
21975
|
-
setTimeout(resolve, milliseconds);
|
|
21976
|
-
});
|
|
21977
|
-
}
|
|
21978
22685
|
function basenameFromPath2(filePath) {
|
|
21979
22686
|
if (!filePath) {
|
|
21980
22687
|
return "";
|
|
@@ -22043,9 +22750,6 @@ function resolveEnvironmentPrefix(environmentText) {
|
|
|
22043
22750
|
}
|
|
22044
22751
|
return null;
|
|
22045
22752
|
}
|
|
22046
|
-
function shellSingleQuote(value) {
|
|
22047
|
-
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
22048
|
-
}
|
|
22049
22753
|
async function resolvePaneEnvironmentPrefix(tmuxManager, sessionName, panePid) {
|
|
22050
22754
|
const sessionPrefix = await tmuxManager.getSessionEnvironmentVariable(
|
|
22051
22755
|
sessionName,
|
|
@@ -22061,6 +22765,9 @@ async function resolvePaneEnvironmentPrefix(tmuxManager, sessionName, panePid) {
|
|
|
22061
22765
|
return null;
|
|
22062
22766
|
}
|
|
22063
22767
|
}
|
|
22768
|
+
function shellSingleQuote(value) {
|
|
22769
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
22770
|
+
}
|
|
22064
22771
|
function buildShellPromptInitScriptContents(command) {
|
|
22065
22772
|
const normalized = command.trim().toLowerCase();
|
|
22066
22773
|
if (normalized === "zsh") {
|
|
@@ -22160,6 +22867,26 @@ clear
|
|
|
22160
22867
|
` : `${sourceCommand}
|
|
22161
22868
|
`;
|
|
22162
22869
|
}
|
|
22870
|
+
|
|
22871
|
+
// src/shell/shell-session-service.ts
|
|
22872
|
+
async function pathExists5(filePath) {
|
|
22873
|
+
try {
|
|
22874
|
+
await fs20.access(filePath);
|
|
22875
|
+
return true;
|
|
22876
|
+
} catch {
|
|
22877
|
+
return false;
|
|
22878
|
+
}
|
|
22879
|
+
}
|
|
22880
|
+
function nowIso() {
|
|
22881
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
22882
|
+
}
|
|
22883
|
+
function uniqueShellSessionName(baseName, index) {
|
|
22884
|
+
if (index <= 1) {
|
|
22885
|
+
return baseName;
|
|
22886
|
+
}
|
|
22887
|
+
const suffix = `-${index}`;
|
|
22888
|
+
return `${baseName.slice(0, Math.max(1, 64 - suffix.length))}${suffix}`;
|
|
22889
|
+
}
|
|
22163
22890
|
function shellThreadId(shell) {
|
|
22164
22891
|
if (!shell.threadId) {
|
|
22165
22892
|
throw new ShellServiceError(
|
|
@@ -22220,25 +22947,25 @@ var ShellServiceError = class extends Error {
|
|
|
22220
22947
|
code;
|
|
22221
22948
|
};
|
|
22222
22949
|
var ShellSessionService = class {
|
|
22223
|
-
constructor(db, eventBus,
|
|
22950
|
+
constructor(db, eventBus, shellBackend) {
|
|
22224
22951
|
this.db = db;
|
|
22225
22952
|
this.eventBus = eventBus;
|
|
22226
|
-
this.
|
|
22953
|
+
this.shellBackend = shellBackend;
|
|
22227
22954
|
}
|
|
22228
22955
|
db;
|
|
22229
22956
|
eventBus;
|
|
22230
|
-
|
|
22957
|
+
shellBackend;
|
|
22231
22958
|
attachments = /* @__PURE__ */ new Map();
|
|
22232
22959
|
async stop() {
|
|
22233
22960
|
for (const [shellId, attachment] of this.attachments) {
|
|
22234
|
-
|
|
22961
|
+
attachment.backendAttachment.dispose();
|
|
22235
22962
|
deleteViewerSessionRecord(this.db, attachment.viewerId);
|
|
22236
22963
|
this.attachments.delete(shellId);
|
|
22237
22964
|
}
|
|
22238
22965
|
}
|
|
22239
22966
|
async syncShellStateOnStartup() {
|
|
22240
22967
|
const records = listShellSessionRecords(this.db);
|
|
22241
|
-
const sessionNames = new Set(await this.
|
|
22968
|
+
const sessionNames = new Set(await this.shellBackend.listSessionNames());
|
|
22242
22969
|
for (const record of records) {
|
|
22243
22970
|
const sessionName = record.tmuxSessionName ?? "";
|
|
22244
22971
|
const nextStatus = sessionNames.has(sessionName) ? "running" : record.status === "exited" ? "exited" : "not_found";
|
|
@@ -22261,23 +22988,33 @@ var ShellSessionService = class {
|
|
|
22261
22988
|
if (!workspace) {
|
|
22262
22989
|
throw new ShellServiceError("thread_not_found", "Workspace not found.");
|
|
22263
22990
|
}
|
|
22264
|
-
const
|
|
22991
|
+
const shells = listShellSessionRecordsByThreadId(this.db, threadId);
|
|
22265
22992
|
const workspacePathStatus = await pathExists5(workspace.absPath) ? "present" : "missing";
|
|
22266
|
-
if (
|
|
22993
|
+
if (shells.length === 0) {
|
|
22267
22994
|
return {
|
|
22268
22995
|
threadId: thread.id,
|
|
22269
22996
|
workspaceId: workspace.id,
|
|
22270
22997
|
workspacePathStatus,
|
|
22271
22998
|
state: workspacePathStatus === "missing" ? "workspace_missing" : "not_created",
|
|
22272
|
-
shell: null
|
|
22999
|
+
shell: null,
|
|
23000
|
+
shells: [],
|
|
23001
|
+
activeShellId: null
|
|
22273
23002
|
};
|
|
22274
23003
|
}
|
|
23004
|
+
const shellDtos = await Promise.all(
|
|
23005
|
+
shells.map((shell) => this.toShellSessionDto(shell.id))
|
|
23006
|
+
);
|
|
23007
|
+
const activeShell = shellDtos.find((shell) => shell.status === "attached") ?? shellDtos.find(
|
|
23008
|
+
(shell) => shell.status !== "exited" && shell.status !== "not_found"
|
|
23009
|
+
) ?? shellDtos[0] ?? null;
|
|
22275
23010
|
return {
|
|
22276
23011
|
threadId: thread.id,
|
|
22277
23012
|
workspaceId: workspace.id,
|
|
22278
23013
|
workspacePathStatus,
|
|
22279
|
-
state:
|
|
22280
|
-
shell:
|
|
23014
|
+
state: activeShell ? activeShell.status : "not_created",
|
|
23015
|
+
shell: activeShell,
|
|
23016
|
+
shells: shellDtos,
|
|
23017
|
+
activeShellId: activeShell?.id ?? null
|
|
22281
23018
|
};
|
|
22282
23019
|
}
|
|
22283
23020
|
async createShellForThread(threadId, options = {}) {
|
|
@@ -22301,26 +23038,21 @@ var ShellSessionService = class {
|
|
|
22301
23038
|
"Workspace path is missing on this machine."
|
|
22302
23039
|
);
|
|
22303
23040
|
}
|
|
22304
|
-
const
|
|
22305
|
-
const
|
|
22306
|
-
|
|
22307
|
-
|
|
22308
|
-
|
|
22309
|
-
|
|
22310
|
-
|
|
22311
|
-
|
|
22312
|
-
|
|
22313
|
-
|
|
22314
|
-
updateShellSessionRecord(this.db, existing.id, {
|
|
22315
|
-
tmuxSessionName,
|
|
22316
|
-
cwd: workspace.absPath,
|
|
22317
|
-
status: "creating",
|
|
22318
|
-
lastActivityAt: nowIso()
|
|
22319
|
-
});
|
|
23041
|
+
const baseSessionName = this.shellBackend.sessionNameForThread(thread.id);
|
|
23042
|
+
const existingShells = listShellSessionRecordsByThreadId(this.db, threadId);
|
|
23043
|
+
const existingSessionNames = new Set(
|
|
23044
|
+
existingShells.map((shell) => shell.tmuxSessionName).filter((name) => Boolean(name))
|
|
23045
|
+
);
|
|
23046
|
+
let sessionIndex = existingShells.length + 1;
|
|
23047
|
+
let tmuxSessionName = uniqueShellSessionName(baseSessionName, sessionIndex);
|
|
23048
|
+
while (existingSessionNames.has(tmuxSessionName) || await this.shellBackend.hasSession(tmuxSessionName)) {
|
|
23049
|
+
sessionIndex += 1;
|
|
23050
|
+
tmuxSessionName = uniqueShellSessionName(baseSessionName, sessionIndex);
|
|
22320
23051
|
}
|
|
22321
|
-
const record =
|
|
23052
|
+
const record = createShellSessionRecord(this.db, {
|
|
22322
23053
|
workspaceId: workspace.id,
|
|
22323
23054
|
threadId: thread.id,
|
|
23055
|
+
label: options.label ?? null,
|
|
22324
23056
|
tmuxSessionName,
|
|
22325
23057
|
cwd: workspace.absPath,
|
|
22326
23058
|
status: "creating"
|
|
@@ -22330,27 +23062,15 @@ var ShellSessionService = class {
|
|
|
22330
23062
|
state: "creating"
|
|
22331
23063
|
});
|
|
22332
23064
|
try {
|
|
22333
|
-
const existingSession = await this.
|
|
23065
|
+
const existingSession = await this.shellBackend.hasSession(tmuxSessionName);
|
|
22334
23066
|
if (!existingSession) {
|
|
22335
|
-
await this.
|
|
22336
|
-
|
|
23067
|
+
await this.shellBackend.createSession({
|
|
23068
|
+
sessionId: tmuxSessionName,
|
|
23069
|
+
threadId: thread.id,
|
|
22337
23070
|
cwd: workspace.absPath,
|
|
22338
23071
|
...options.cols !== void 0 ? { cols: options.cols } : {},
|
|
22339
23072
|
...options.rows !== void 0 ? { rows: options.rows } : {}
|
|
22340
23073
|
});
|
|
22341
|
-
try {
|
|
22342
|
-
const runtime = await this.tmuxManager.getPaneRuntimeInfo(tmuxSessionName);
|
|
22343
|
-
if (isInteractiveShellCommand(runtime.currentCommand)) {
|
|
22344
|
-
await this.tmuxManager.sendInput(
|
|
22345
|
-
tmuxSessionName,
|
|
22346
|
-
await buildShellPromptInitCommand(runtime.currentCommand, {
|
|
22347
|
-
clearScreen: true
|
|
22348
|
-
})
|
|
22349
|
-
);
|
|
22350
|
-
await waitForShellTick(120);
|
|
22351
|
-
}
|
|
22352
|
-
} catch {
|
|
22353
|
-
}
|
|
22354
23074
|
}
|
|
22355
23075
|
updateShellSessionRecord(this.db, record.id, {
|
|
22356
23076
|
status: "running",
|
|
@@ -22361,7 +23081,7 @@ var ShellSessionService = class {
|
|
|
22361
23081
|
status: "not_found"
|
|
22362
23082
|
});
|
|
22363
23083
|
throw new ShellServiceError(
|
|
22364
|
-
"
|
|
23084
|
+
"shell_backend_error",
|
|
22365
23085
|
error instanceof Error ? error.message : "Unable to start shell."
|
|
22366
23086
|
);
|
|
22367
23087
|
}
|
|
@@ -22369,7 +23089,32 @@ var ShellSessionService = class {
|
|
|
22369
23089
|
threadId: thread.id,
|
|
22370
23090
|
state: "detached"
|
|
22371
23091
|
});
|
|
22372
|
-
|
|
23092
|
+
const state = await this.getThreadShellState(threadId);
|
|
23093
|
+
const createdShell = await this.toShellSessionDto(record.id);
|
|
23094
|
+
return {
|
|
23095
|
+
...state,
|
|
23096
|
+
state: createdShell.status,
|
|
23097
|
+
shell: createdShell,
|
|
23098
|
+
activeShellId: createdShell.id
|
|
23099
|
+
};
|
|
23100
|
+
}
|
|
23101
|
+
async updateShell(shellId, input) {
|
|
23102
|
+
const shell = getShellSessionRecordById(this.db, shellId);
|
|
23103
|
+
if (!shell) {
|
|
23104
|
+
throw new ShellServiceError("shell_not_found", "Shell not found.");
|
|
23105
|
+
}
|
|
23106
|
+
const updates = {};
|
|
23107
|
+
if ("label" in input) {
|
|
23108
|
+
const label = input.label?.trim() ?? "";
|
|
23109
|
+
updates.label = label.length > 0 ? label : null;
|
|
23110
|
+
}
|
|
23111
|
+
updateShellSessionRecord(this.db, shell.id, updates);
|
|
23112
|
+
const shellDto = await this.toShellSessionDto(shell.id);
|
|
23113
|
+
this.emitShellEvent(shell.id, "shell.status", {
|
|
23114
|
+
threadId: shellThreadId(shell),
|
|
23115
|
+
state: shellDto.status
|
|
23116
|
+
});
|
|
23117
|
+
return shellDto;
|
|
22373
23118
|
}
|
|
22374
23119
|
async detachThreadViewers(threadId) {
|
|
22375
23120
|
const shell = getShellSessionRecordByThreadId(this.db, threadId);
|
|
@@ -22381,7 +23126,7 @@ var ShellSessionService = class {
|
|
|
22381
23126
|
deleteViewerSessionsByThreadId(this.db, threadId);
|
|
22382
23127
|
return;
|
|
22383
23128
|
}
|
|
22384
|
-
|
|
23129
|
+
attachment.backendAttachment.dispose();
|
|
22385
23130
|
deleteViewerSessionRecord(this.db, attachment.viewerId);
|
|
22386
23131
|
deleteViewerSessionsByThreadId(this.db, threadId);
|
|
22387
23132
|
this.attachments.delete(shell.id);
|
|
@@ -22404,7 +23149,7 @@ var ShellSessionService = class {
|
|
|
22404
23149
|
const existingViewer = getViewerSessionRecordByShellId(this.db, shell.id);
|
|
22405
23150
|
const existingAttachment = this.attachments.get(shell.id);
|
|
22406
23151
|
if (existingAttachment) {
|
|
22407
|
-
|
|
23152
|
+
existingAttachment.backendAttachment.dispose();
|
|
22408
23153
|
deleteViewerSessionRecord(this.db, existingAttachment.viewerId);
|
|
22409
23154
|
this.attachments.delete(shell.id);
|
|
22410
23155
|
this.emitShellEvent(shell.id, "shell.detached", {
|
|
@@ -22416,7 +23161,7 @@ var ShellSessionService = class {
|
|
|
22416
23161
|
} else if (existingViewer) {
|
|
22417
23162
|
deleteViewerSessionRecord(this.db, existingViewer.id);
|
|
22418
23163
|
}
|
|
22419
|
-
const hasSession = await this.
|
|
23164
|
+
const hasSession = await this.shellBackend.hasSession(shellSessionName(shell));
|
|
22420
23165
|
if (!hasSession) {
|
|
22421
23166
|
updateShellSessionRecord(this.db, shell.id, {
|
|
22422
23167
|
status: "not_found"
|
|
@@ -22427,7 +23172,7 @@ var ShellSessionService = class {
|
|
|
22427
23172
|
});
|
|
22428
23173
|
throw new ShellServiceError(
|
|
22429
23174
|
"shell_not_running",
|
|
22430
|
-
"The
|
|
23175
|
+
"The terminal is no longer available."
|
|
22431
23176
|
);
|
|
22432
23177
|
}
|
|
22433
23178
|
const viewer = createViewerSessionRecord(this.db, {
|
|
@@ -22435,31 +23180,52 @@ var ShellSessionService = class {
|
|
|
22435
23180
|
shellId: shell.id,
|
|
22436
23181
|
activeTab: "shell"
|
|
22437
23182
|
});
|
|
22438
|
-
await this.
|
|
22439
|
-
|
|
22440
|
-
options.
|
|
22441
|
-
|
|
22442
|
-
|
|
22443
|
-
|
|
22444
|
-
|
|
22445
|
-
|
|
22446
|
-
|
|
23183
|
+
const attached = await this.shellBackend.attach(shellSessionName(shell), {
|
|
23184
|
+
cols: options.cols,
|
|
23185
|
+
rows: options.rows,
|
|
23186
|
+
onData: (data, session, backendOptions) => {
|
|
23187
|
+
updateShellSessionRecord(this.db, shell.id, {
|
|
23188
|
+
lastActivityAt: nowIso()
|
|
23189
|
+
});
|
|
23190
|
+
updateViewerSessionRecord(this.db, viewer.id, {
|
|
23191
|
+
lastHeartbeatAt: nowIso(),
|
|
23192
|
+
activeTab: "shell"
|
|
23193
|
+
});
|
|
23194
|
+
options.onData(
|
|
23195
|
+
data,
|
|
23196
|
+
shellOutputOptions({
|
|
23197
|
+
replace: backendOptions?.replace === true,
|
|
23198
|
+
cursorX: session.runtime.cursorX,
|
|
23199
|
+
cursorY: session.runtime.cursorY,
|
|
23200
|
+
paneHeight: session.runtime.paneHeight,
|
|
23201
|
+
cwdBaseName: basenameFromPath2(session.runtime.currentPath || shell.cwd),
|
|
23202
|
+
envPrefix: session.runtime.envPrefix ?? void 0,
|
|
23203
|
+
isCommandRunning: session.runtime.isCommandRunning
|
|
23204
|
+
})
|
|
23205
|
+
);
|
|
23206
|
+
},
|
|
23207
|
+
onExit: () => {
|
|
23208
|
+
void this.handleMissingShell(shell, viewer.id);
|
|
23209
|
+
}
|
|
23210
|
+
});
|
|
23211
|
+
const initialSnapshot = attached.session.snapshot;
|
|
23212
|
+
const initialRuntime = attached.session.runtime;
|
|
22447
23213
|
const initialCwdBaseName = basenameFromPath2(initialRuntime.currentPath || shell.cwd);
|
|
22448
|
-
const initialEnvPrefix = await resolvePaneEnvironmentPrefix(
|
|
22449
|
-
this.tmuxManager,
|
|
22450
|
-
shellSessionName(shell),
|
|
22451
|
-
initialRuntime.panePid
|
|
22452
|
-
);
|
|
22453
23214
|
const attachment = {
|
|
22454
23215
|
viewerId: viewer.id,
|
|
22455
23216
|
onData: options.onData,
|
|
22456
|
-
|
|
22457
|
-
void this.pollAttachment(shell.id);
|
|
22458
|
-
}, 250),
|
|
22459
|
-
lastSnapshot: initialSnapshot,
|
|
22460
|
-
polling: false
|
|
23217
|
+
backendAttachment: attached.attachment
|
|
22461
23218
|
};
|
|
22462
23219
|
this.attachments.set(shell.id, attachment);
|
|
23220
|
+
updateShellSessionRecord(this.db, shell.id, {
|
|
23221
|
+
status: "running",
|
|
23222
|
+
lastActivityAt: nowIso()
|
|
23223
|
+
});
|
|
23224
|
+
const shellDto = await this.toShellSessionDto(shell.id);
|
|
23225
|
+
options.onConnected?.({
|
|
23226
|
+
viewerId: viewer.id,
|
|
23227
|
+
shell: shellDto
|
|
23228
|
+
});
|
|
22463
23229
|
if (initialSnapshot) {
|
|
22464
23230
|
options.onData(
|
|
22465
23231
|
initialSnapshot,
|
|
@@ -22469,17 +23235,11 @@ var ShellSessionService = class {
|
|
|
22469
23235
|
cursorY: initialRuntime.cursorY,
|
|
22470
23236
|
paneHeight: initialRuntime.paneHeight,
|
|
22471
23237
|
cwdBaseName: initialCwdBaseName,
|
|
22472
|
-
envPrefix:
|
|
22473
|
-
isCommandRunning:
|
|
22474
|
-
initialRuntime.currentCommand
|
|
22475
|
-
)
|
|
23238
|
+
envPrefix: initialRuntime.envPrefix ?? void 0,
|
|
23239
|
+
isCommandRunning: initialRuntime.isCommandRunning
|
|
22476
23240
|
})
|
|
22477
23241
|
);
|
|
22478
23242
|
}
|
|
22479
|
-
updateShellSessionRecord(this.db, shell.id, {
|
|
22480
|
-
status: "running",
|
|
22481
|
-
lastActivityAt: nowIso()
|
|
22482
|
-
});
|
|
22483
23243
|
this.emitShellEvent(shell.id, "shell.status", {
|
|
22484
23244
|
threadId,
|
|
22485
23245
|
state: "attached",
|
|
@@ -22487,7 +23247,7 @@ var ShellSessionService = class {
|
|
|
22487
23247
|
});
|
|
22488
23248
|
return {
|
|
22489
23249
|
viewerId: viewer.id,
|
|
22490
|
-
shell:
|
|
23250
|
+
shell: shellDto
|
|
22491
23251
|
};
|
|
22492
23252
|
}
|
|
22493
23253
|
async detachShell(shellId, viewerId) {
|
|
@@ -22508,7 +23268,7 @@ var ShellSessionService = class {
|
|
|
22508
23268
|
"This browser session does not own the shell attachment."
|
|
22509
23269
|
);
|
|
22510
23270
|
}
|
|
22511
|
-
|
|
23271
|
+
attachment.backendAttachment.dispose();
|
|
22512
23272
|
deleteViewerSessionRecord(this.db, viewerId);
|
|
22513
23273
|
this.attachments.delete(shell.id);
|
|
22514
23274
|
updateShellSessionRecord(this.db, shell.id, {
|
|
@@ -22523,7 +23283,7 @@ var ShellSessionService = class {
|
|
|
22523
23283
|
}
|
|
22524
23284
|
async sendInput(shellId, viewerId, data) {
|
|
22525
23285
|
const { shell } = this.requireOwnedAttachment(shellId, viewerId);
|
|
22526
|
-
await this.
|
|
23286
|
+
await this.shellBackend.sendInput(shellSessionName(shell), data);
|
|
22527
23287
|
updateShellSessionRecord(this.db, shellId, {
|
|
22528
23288
|
lastActivityAt: nowIso()
|
|
22529
23289
|
});
|
|
@@ -22535,10 +23295,7 @@ var ShellSessionService = class {
|
|
|
22535
23295
|
async clearShell(shellId, viewerId) {
|
|
22536
23296
|
const { shell, attachment } = this.requireOwnedAttachment(shellId, viewerId);
|
|
22537
23297
|
const sessionName = shellSessionName(shell);
|
|
22538
|
-
await this.
|
|
22539
|
-
await waitForShellTick(60);
|
|
22540
|
-
await this.tmuxManager.clearHistory(sessionName);
|
|
22541
|
-
await waitForShellTick(60);
|
|
23298
|
+
const session = await this.shellBackend.clear(sessionName);
|
|
22542
23299
|
updateShellSessionRecord(this.db, shellId, {
|
|
22543
23300
|
lastActivityAt: nowIso()
|
|
22544
23301
|
});
|
|
@@ -22546,7 +23303,18 @@ var ShellSessionService = class {
|
|
|
22546
23303
|
lastHeartbeatAt: nowIso(),
|
|
22547
23304
|
activeTab: "shell"
|
|
22548
23305
|
});
|
|
22549
|
-
|
|
23306
|
+
attachment.onData(
|
|
23307
|
+
session.snapshot,
|
|
23308
|
+
shellOutputOptions({
|
|
23309
|
+
replace: true,
|
|
23310
|
+
cursorX: session.runtime.cursorX,
|
|
23311
|
+
cursorY: session.runtime.cursorY,
|
|
23312
|
+
paneHeight: session.runtime.paneHeight,
|
|
23313
|
+
cwdBaseName: basenameFromPath2(session.runtime.currentPath || shell.cwd),
|
|
23314
|
+
envPrefix: session.runtime.envPrefix ?? void 0,
|
|
23315
|
+
isCommandRunning: session.runtime.isCommandRunning
|
|
23316
|
+
})
|
|
23317
|
+
);
|
|
22550
23318
|
}
|
|
22551
23319
|
async resizeShell(shellId, viewerId, cols, rows) {
|
|
22552
23320
|
const shell = getShellSessionRecordById(this.db, shellId);
|
|
@@ -22566,7 +23334,7 @@ var ShellSessionService = class {
|
|
|
22566
23334
|
"This browser session does not own the shell attachment."
|
|
22567
23335
|
);
|
|
22568
23336
|
}
|
|
22569
|
-
await this.
|
|
23337
|
+
await this.shellBackend.resize(shellSessionName(shell), cols, rows);
|
|
22570
23338
|
updateViewerSessionRecord(this.db, viewerId, {
|
|
22571
23339
|
lastHeartbeatAt: nowIso(),
|
|
22572
23340
|
activeTab: "shell"
|
|
@@ -22579,11 +23347,11 @@ var ShellSessionService = class {
|
|
|
22579
23347
|
}
|
|
22580
23348
|
const attachment = this.attachments.get(shell.id);
|
|
22581
23349
|
if (attachment) {
|
|
22582
|
-
|
|
23350
|
+
attachment.backendAttachment.dispose();
|
|
22583
23351
|
deleteViewerSessionRecord(this.db, attachment.viewerId);
|
|
22584
23352
|
this.attachments.delete(shell.id);
|
|
22585
23353
|
}
|
|
22586
|
-
await this.
|
|
23354
|
+
await this.shellBackend.killSession(shellSessionName(shell));
|
|
22587
23355
|
updateShellSessionRecord(this.db, shell.id, {
|
|
22588
23356
|
status: "exited",
|
|
22589
23357
|
lastActivityAt: nowIso()
|
|
@@ -22605,7 +23373,9 @@ var ShellSessionService = class {
|
|
|
22605
23373
|
id: shell.id,
|
|
22606
23374
|
threadId: shellThreadId(shell),
|
|
22607
23375
|
workspaceId: shell.workspaceId,
|
|
23376
|
+
label: shell.label ?? null,
|
|
22608
23377
|
tmuxSessionName: shellSessionName(shell),
|
|
23378
|
+
backend: this.shellBackend.kind,
|
|
22609
23379
|
cwd: shell.cwd,
|
|
22610
23380
|
status: shellDtoStatus(shell.status, status),
|
|
22611
23381
|
attachedViewerId: this.attachments.get(shell.id)?.viewerId ?? null,
|
|
@@ -22631,30 +23401,6 @@ var ShellSessionService = class {
|
|
|
22631
23401
|
const attachment = this.attachments.get(shell.id);
|
|
22632
23402
|
return attachment ? "attached" : "detached";
|
|
22633
23403
|
}
|
|
22634
|
-
async pollAttachment(shellId) {
|
|
22635
|
-
const attachment = this.attachments.get(shellId);
|
|
22636
|
-
if (!attachment || attachment.polling) {
|
|
22637
|
-
return;
|
|
22638
|
-
}
|
|
22639
|
-
attachment.polling = true;
|
|
22640
|
-
const shell = getShellSessionRecordById(this.db, shellId);
|
|
22641
|
-
if (!shell) {
|
|
22642
|
-
clearInterval(attachment.pollHandle);
|
|
22643
|
-
this.attachments.delete(shellId);
|
|
22644
|
-
deleteViewerSessionRecord(this.db, attachment.viewerId);
|
|
22645
|
-
return;
|
|
22646
|
-
}
|
|
22647
|
-
try {
|
|
22648
|
-
const hasSession = await this.tmuxManager.hasSession(shellSessionName(shell));
|
|
22649
|
-
if (!hasSession) {
|
|
22650
|
-
await this.handleMissingShell(shell, attachment.viewerId);
|
|
22651
|
-
return;
|
|
22652
|
-
}
|
|
22653
|
-
await this.pushSnapshot(shell, attachment);
|
|
22654
|
-
} finally {
|
|
22655
|
-
attachment.polling = false;
|
|
22656
|
-
}
|
|
22657
|
-
}
|
|
22658
23404
|
requireOwnedAttachment(shellId, viewerId) {
|
|
22659
23405
|
const shell = getShellSessionRecordById(this.db, shellId);
|
|
22660
23406
|
if (!shell) {
|
|
@@ -22675,52 +23421,20 @@ var ShellSessionService = class {
|
|
|
22675
23421
|
}
|
|
22676
23422
|
return { shell, attachment };
|
|
22677
23423
|
}
|
|
22678
|
-
async
|
|
22679
|
-
const
|
|
22680
|
-
|
|
22681
|
-
|
|
22682
|
-
|
|
22683
|
-
return;
|
|
23424
|
+
async handleMissingShell(shell, viewerId) {
|
|
23425
|
+
const attachment = this.attachments.get(shell.id);
|
|
23426
|
+
if (attachment) {
|
|
23427
|
+
attachment.backendAttachment.dispose();
|
|
23428
|
+
this.attachments.delete(shell.id);
|
|
22684
23429
|
}
|
|
22685
|
-
|
|
23430
|
+
deleteViewerSessionRecord(this.db, viewerId);
|
|
22686
23431
|
updateShellSessionRecord(this.db, shell.id, {
|
|
23432
|
+
status: "not_found",
|
|
22687
23433
|
lastActivityAt: nowIso()
|
|
22688
23434
|
});
|
|
22689
|
-
|
|
22690
|
-
|
|
22691
|
-
|
|
22692
|
-
});
|
|
22693
|
-
attachment.onData(
|
|
22694
|
-
snapshot,
|
|
22695
|
-
shellOutputOptions({
|
|
22696
|
-
replace: true,
|
|
22697
|
-
cursorX: runtime.cursorX,
|
|
22698
|
-
cursorY: runtime.cursorY,
|
|
22699
|
-
paneHeight: runtime.paneHeight,
|
|
22700
|
-
cwdBaseName: basenameFromPath2(runtime.currentPath || shell.cwd),
|
|
22701
|
-
envPrefix: await resolvePaneEnvironmentPrefix(
|
|
22702
|
-
this.tmuxManager,
|
|
22703
|
-
sessionName,
|
|
22704
|
-
runtime.panePid
|
|
22705
|
-
) ?? void 0,
|
|
22706
|
-
isCommandRunning: !isInteractiveShellCommand(runtime.currentCommand)
|
|
22707
|
-
})
|
|
22708
|
-
);
|
|
22709
|
-
}
|
|
22710
|
-
async handleMissingShell(shell, viewerId) {
|
|
22711
|
-
const attachment = this.attachments.get(shell.id);
|
|
22712
|
-
if (attachment) {
|
|
22713
|
-
clearInterval(attachment.pollHandle);
|
|
22714
|
-
this.attachments.delete(shell.id);
|
|
22715
|
-
}
|
|
22716
|
-
deleteViewerSessionRecord(this.db, viewerId);
|
|
22717
|
-
updateShellSessionRecord(this.db, shell.id, {
|
|
22718
|
-
status: "not_found",
|
|
22719
|
-
lastActivityAt: nowIso()
|
|
22720
|
-
});
|
|
22721
|
-
this.emitShellEvent(shell.id, "shell.exited", {
|
|
22722
|
-
threadId: shellThreadId(shell),
|
|
22723
|
-
state: "not_found"
|
|
23435
|
+
this.emitShellEvent(shell.id, "shell.exited", {
|
|
23436
|
+
threadId: shellThreadId(shell),
|
|
23437
|
+
state: "not_found"
|
|
22724
23438
|
});
|
|
22725
23439
|
}
|
|
22726
23440
|
emitShellEvent(shellId, type, payload) {
|
|
@@ -22733,9 +23447,695 @@ var ShellSessionService = class {
|
|
|
22733
23447
|
}
|
|
22734
23448
|
};
|
|
22735
23449
|
|
|
22736
|
-
// src/
|
|
22737
|
-
|
|
23450
|
+
// ../../packages/plugin-terminal/src/manifest.ts
|
|
23451
|
+
var TERMINAL_PLUGIN_ID = "remote-codex.terminal";
|
|
23452
|
+
var terminalPluginManifest = {
|
|
23453
|
+
id: TERMINAL_PLUGIN_ID,
|
|
23454
|
+
name: "Terminal",
|
|
23455
|
+
version: "0.1.0",
|
|
23456
|
+
description: "Built-in durable terminal panel backed by the supervisor PTY host.",
|
|
23457
|
+
remoteCodex: "^0.11.0",
|
|
23458
|
+
capabilities: {
|
|
23459
|
+
artifactTypes: [],
|
|
23460
|
+
timelineRenderers: [],
|
|
23461
|
+
threadPanels: [
|
|
23462
|
+
{
|
|
23463
|
+
id: "terminal",
|
|
23464
|
+
label: "Terminal",
|
|
23465
|
+
kind: "terminal",
|
|
23466
|
+
artifactTypes: []
|
|
23467
|
+
}
|
|
23468
|
+
],
|
|
23469
|
+
frontend: {
|
|
23470
|
+
entry: "./dist/index.js"
|
|
23471
|
+
},
|
|
23472
|
+
backend: {
|
|
23473
|
+
entry: "./dist/backend.js"
|
|
23474
|
+
}
|
|
23475
|
+
}
|
|
23476
|
+
};
|
|
23477
|
+
|
|
23478
|
+
// ../../packages/plugin-xyz-viewer/src/manifest.ts
|
|
23479
|
+
var XYZ_MOLECULE_ARTIFACT_TYPE = "chemistry.molecule3d";
|
|
23480
|
+
var xyzViewerPluginManifest = {
|
|
23481
|
+
id: "remote-codex.xyz-viewer",
|
|
23482
|
+
name: "XYZ Molecule Viewer",
|
|
23483
|
+
version: "0.1.0",
|
|
23484
|
+
description: "A draft built-in plugin for previewing xyz, extxyz, cif, and pdb molecular structures with 3Dmol.js.",
|
|
23485
|
+
remoteCodex: "^0.11.0",
|
|
23486
|
+
capabilities: {
|
|
23487
|
+
artifactTypes: [
|
|
23488
|
+
{
|
|
23489
|
+
type: XYZ_MOLECULE_ARTIFACT_TYPE,
|
|
23490
|
+
title: "3D Molecule",
|
|
23491
|
+
fileExtensions: ["xyz", "extxyz", "cif", "pdb"]
|
|
23492
|
+
}
|
|
23493
|
+
],
|
|
23494
|
+
timelineRenderers: [XYZ_MOLECULE_ARTIFACT_TYPE],
|
|
23495
|
+
threadPanels: [
|
|
23496
|
+
{
|
|
23497
|
+
id: "xyz-viewer",
|
|
23498
|
+
label: "Molecules",
|
|
23499
|
+
artifactTypes: [XYZ_MOLECULE_ARTIFACT_TYPE]
|
|
23500
|
+
}
|
|
23501
|
+
],
|
|
23502
|
+
modelHints: [
|
|
23503
|
+
{
|
|
23504
|
+
id: "render-molecule",
|
|
23505
|
+
text: "XYZ Molecule Viewer is enabled. When outputting a molecular structure, you must call remote_codex_render_molecule; do not output plain xyz, pdb, cif, or extxyz text. Do not invent coordinates unless asked for an example."
|
|
23506
|
+
}
|
|
23507
|
+
],
|
|
23508
|
+
mcpServers: [
|
|
23509
|
+
{
|
|
23510
|
+
id: "remote-codex-plugin-mcp",
|
|
23511
|
+
name: "remote_codex_plugins",
|
|
23512
|
+
command: "node",
|
|
23513
|
+
args: ["bin/remote-codex-plugin-mcp.mjs"]
|
|
23514
|
+
}
|
|
23515
|
+
],
|
|
23516
|
+
frontend: {
|
|
23517
|
+
entry: "./dist/index.js",
|
|
23518
|
+
style: "./src/styles.css"
|
|
23519
|
+
}
|
|
23520
|
+
}
|
|
23521
|
+
};
|
|
23522
|
+
|
|
23523
|
+
// src/plugins/builtin-plugins.ts
|
|
23524
|
+
var builtinPlugins = [
|
|
23525
|
+
{
|
|
23526
|
+
manifest: terminalPluginManifest,
|
|
23527
|
+
enabledByDefault: true
|
|
23528
|
+
},
|
|
23529
|
+
{
|
|
23530
|
+
manifest: xyzViewerPluginManifest,
|
|
23531
|
+
enabledByDefault: true
|
|
23532
|
+
}
|
|
23533
|
+
];
|
|
23534
|
+
|
|
23535
|
+
// src/plugins/plugin-service.ts
|
|
23536
|
+
import fs21 from "fs/promises";
|
|
22738
23537
|
import path20 from "path";
|
|
23538
|
+
var MANAGED_CODEX_MCP_BEGIN = "# BEGIN remote-codex managed plugin MCP servers";
|
|
23539
|
+
var MANAGED_CODEX_MCP_END = "# END remote-codex managed plugin MCP servers";
|
|
23540
|
+
var REMOTE_CODEX_MOLECULE_MCP_TOOL_NAME = "remote_codex_render_molecule";
|
|
23541
|
+
function jsonString(value) {
|
|
23542
|
+
return JSON.stringify(value);
|
|
23543
|
+
}
|
|
23544
|
+
function normalizeManagedCommand(server, repoRoot) {
|
|
23545
|
+
if (server.name === "remote_codex_plugins") {
|
|
23546
|
+
return {
|
|
23547
|
+
command: process.execPath,
|
|
23548
|
+
args: [path20.join(repoRoot, "bin", "remote-codex-plugin-mcp.mjs")]
|
|
23549
|
+
};
|
|
23550
|
+
}
|
|
23551
|
+
return {
|
|
23552
|
+
command: server.command,
|
|
23553
|
+
args: server.args ?? []
|
|
23554
|
+
};
|
|
23555
|
+
}
|
|
23556
|
+
function stripManagedCodexMcpBlock(content) {
|
|
23557
|
+
const pattern = new RegExp(
|
|
23558
|
+
`\\n?${MANAGED_CODEX_MCP_BEGIN.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${MANAGED_CODEX_MCP_END.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\n?`,
|
|
23559
|
+
"g"
|
|
23560
|
+
);
|
|
23561
|
+
return content.replace(pattern, "\n").replace(/\n{3,}/g, "\n\n").trimEnd();
|
|
23562
|
+
}
|
|
23563
|
+
function stripCodexMcpServerTables(content, serverNames) {
|
|
23564
|
+
const names = new Set(serverNames);
|
|
23565
|
+
if (names.size === 0) {
|
|
23566
|
+
return content.trimEnd();
|
|
23567
|
+
}
|
|
23568
|
+
const output = [];
|
|
23569
|
+
let current = [];
|
|
23570
|
+
let shouldDropCurrentTable = false;
|
|
23571
|
+
function flushCurrent() {
|
|
23572
|
+
if (!shouldDropCurrentTable) {
|
|
23573
|
+
output.push(...current);
|
|
23574
|
+
}
|
|
23575
|
+
current = [];
|
|
23576
|
+
shouldDropCurrentTable = false;
|
|
23577
|
+
}
|
|
23578
|
+
for (const line of content.split("\n")) {
|
|
23579
|
+
const tableMatch = line.match(/^\s*\[([^\]]+)\]\s*$/);
|
|
23580
|
+
if (tableMatch) {
|
|
23581
|
+
flushCurrent();
|
|
23582
|
+
const tablePath = tableMatch[1] ?? "";
|
|
23583
|
+
shouldDropCurrentTable = [...names].some(
|
|
23584
|
+
(name) => tablePath === `mcp_servers.${name}` || tablePath.startsWith(`mcp_servers.${name}.`)
|
|
23585
|
+
);
|
|
23586
|
+
}
|
|
23587
|
+
current.push(line);
|
|
23588
|
+
}
|
|
23589
|
+
flushCurrent();
|
|
23590
|
+
return output.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd();
|
|
23591
|
+
}
|
|
23592
|
+
function buildManagedCodexMcpBlock(servers, repoRoot) {
|
|
23593
|
+
if (servers.length === 0) {
|
|
23594
|
+
return "";
|
|
23595
|
+
}
|
|
23596
|
+
const lines = [
|
|
23597
|
+
MANAGED_CODEX_MCP_BEGIN,
|
|
23598
|
+
"# This block is generated from enabled Remote Codex plugins."
|
|
23599
|
+
];
|
|
23600
|
+
for (const server of servers) {
|
|
23601
|
+
const normalized = normalizeManagedCommand(server, repoRoot);
|
|
23602
|
+
lines.push(
|
|
23603
|
+
"",
|
|
23604
|
+
`[mcp_servers.${server.name}]`,
|
|
23605
|
+
`command = ${jsonString(normalized.command)}`,
|
|
23606
|
+
`args = ${JSON.stringify(normalized.args)}`
|
|
23607
|
+
);
|
|
23608
|
+
const envEntries = Object.entries(server.env ?? {});
|
|
23609
|
+
if (envEntries.length > 0) {
|
|
23610
|
+
lines.push(`[mcp_servers.${server.name}.env]`);
|
|
23611
|
+
for (const [key, value] of envEntries) {
|
|
23612
|
+
lines.push(`${key} = ${jsonString(value)}`);
|
|
23613
|
+
}
|
|
23614
|
+
}
|
|
23615
|
+
}
|
|
23616
|
+
lines.push(MANAGED_CODEX_MCP_END);
|
|
23617
|
+
return lines.join("\n");
|
|
23618
|
+
}
|
|
23619
|
+
function upsertManagedCodexMcpBlock(content, servers, repoRoot, managedServerNames = servers.map((server) => server.name)) {
|
|
23620
|
+
const stripped = stripCodexMcpServerTables(
|
|
23621
|
+
stripManagedCodexMcpBlock(content),
|
|
23622
|
+
managedServerNames
|
|
23623
|
+
);
|
|
23624
|
+
const managedBlock = buildManagedCodexMcpBlock(servers, repoRoot);
|
|
23625
|
+
if (!managedBlock) {
|
|
23626
|
+
return stripped ? `${stripped}
|
|
23627
|
+
` : "";
|
|
23628
|
+
}
|
|
23629
|
+
return `${stripped ? `${stripped}
|
|
23630
|
+
|
|
23631
|
+
` : ""}${managedBlock}
|
|
23632
|
+
`;
|
|
23633
|
+
}
|
|
23634
|
+
var PluginService = class {
|
|
23635
|
+
constructor(registry, settingsStore) {
|
|
23636
|
+
this.registry = registry;
|
|
23637
|
+
this.settingsStore = settingsStore;
|
|
23638
|
+
this.loadPersistedSettings();
|
|
23639
|
+
}
|
|
23640
|
+
registry;
|
|
23641
|
+
settingsStore;
|
|
23642
|
+
settings = {
|
|
23643
|
+
enabled: {},
|
|
23644
|
+
imported: []
|
|
23645
|
+
};
|
|
23646
|
+
listPlugins() {
|
|
23647
|
+
return this.registry.list();
|
|
23648
|
+
}
|
|
23649
|
+
getPlugin(pluginId) {
|
|
23650
|
+
return this.registry.get(pluginId);
|
|
23651
|
+
}
|
|
23652
|
+
setPluginEnabled(pluginId, enabled) {
|
|
23653
|
+
const plugin = this.registry.setEnabled(pluginId, enabled);
|
|
23654
|
+
this.settings.enabled[pluginId] = enabled;
|
|
23655
|
+
this.persistSettings();
|
|
23656
|
+
return plugin;
|
|
23657
|
+
}
|
|
23658
|
+
modelContextPrompt() {
|
|
23659
|
+
const hints = this.registry.enabledManifests().flatMap(
|
|
23660
|
+
(manifest) => manifest.capabilities.modelHints ?? []
|
|
23661
|
+
);
|
|
23662
|
+
const text2 = hints.map((hint) => hint.text.trim()).filter(Boolean).join("\n");
|
|
23663
|
+
return text2 || null;
|
|
23664
|
+
}
|
|
23665
|
+
enabledMcpServers() {
|
|
23666
|
+
const byName = /* @__PURE__ */ new Map();
|
|
23667
|
+
for (const manifest of this.registry.enabledManifests()) {
|
|
23668
|
+
for (const server of manifest.capabilities.mcpServers ?? []) {
|
|
23669
|
+
const existing = byName.get(server.name);
|
|
23670
|
+
if (existing) {
|
|
23671
|
+
byName.set(server.name, {
|
|
23672
|
+
...existing,
|
|
23673
|
+
env: {
|
|
23674
|
+
...existing.env ?? {},
|
|
23675
|
+
...server.env ?? {}
|
|
23676
|
+
},
|
|
23677
|
+
pluginIds: [...existing.pluginIds, manifest.id]
|
|
23678
|
+
});
|
|
23679
|
+
} else {
|
|
23680
|
+
byName.set(server.name, {
|
|
23681
|
+
...server,
|
|
23682
|
+
pluginIds: [manifest.id]
|
|
23683
|
+
});
|
|
23684
|
+
}
|
|
23685
|
+
}
|
|
23686
|
+
}
|
|
23687
|
+
return [...byName.values()].map(({ pluginIds, ...server }) => ({
|
|
23688
|
+
...server,
|
|
23689
|
+
env: {
|
|
23690
|
+
...server.env ?? {},
|
|
23691
|
+
REMOTE_CODEX_ENABLED_PLUGIN_IDS: [...new Set(pluginIds)].sort().join(",")
|
|
23692
|
+
}
|
|
23693
|
+
}));
|
|
23694
|
+
}
|
|
23695
|
+
managedMcpServerNames() {
|
|
23696
|
+
return [
|
|
23697
|
+
...new Set(
|
|
23698
|
+
this.registry.list().flatMap(
|
|
23699
|
+
(plugin) => (plugin.capabilities.mcpServers ?? []).map((server) => server.name)
|
|
23700
|
+
)
|
|
23701
|
+
)
|
|
23702
|
+
].sort();
|
|
23703
|
+
}
|
|
23704
|
+
async syncManagedCodexMcpConfig(input) {
|
|
23705
|
+
if (!input.codexHome) {
|
|
23706
|
+
return;
|
|
23707
|
+
}
|
|
23708
|
+
const configPath = path20.join(input.codexHome, "config.toml");
|
|
23709
|
+
let current = "";
|
|
23710
|
+
try {
|
|
23711
|
+
current = await fs21.readFile(configPath, "utf8");
|
|
23712
|
+
} catch (error) {
|
|
23713
|
+
if (error.code !== "ENOENT") {
|
|
23714
|
+
throw error;
|
|
23715
|
+
}
|
|
23716
|
+
}
|
|
23717
|
+
const next = upsertManagedCodexMcpBlock(
|
|
23718
|
+
current,
|
|
23719
|
+
this.enabledMcpServers(),
|
|
23720
|
+
input.repoRoot,
|
|
23721
|
+
this.managedMcpServerNames()
|
|
23722
|
+
);
|
|
23723
|
+
if (next === current) {
|
|
23724
|
+
return;
|
|
23725
|
+
}
|
|
23726
|
+
await fs21.mkdir(path20.dirname(configPath), { recursive: true });
|
|
23727
|
+
await fs21.writeFile(configPath, next, "utf8");
|
|
23728
|
+
}
|
|
23729
|
+
importPlugin(input) {
|
|
23730
|
+
const manifestInput = input.manifest ?? this.parseManifestJson(input.manifestJson);
|
|
23731
|
+
const manifest = parsePluginManifest(manifestInput);
|
|
23732
|
+
const enabled = input.enabled ?? true;
|
|
23733
|
+
const existing = this.registry.getRegistered(manifest.id);
|
|
23734
|
+
if (existing && existing.source !== "imported") {
|
|
23735
|
+
throw new Error(`Built-in plugin cannot be replaced: ${manifest.id}`);
|
|
23736
|
+
}
|
|
23737
|
+
this.registerImportedManifest(manifest, enabled);
|
|
23738
|
+
const existingIndex = this.settings.imported.findIndex(
|
|
23739
|
+
(entry) => entry.id === manifest.id
|
|
23740
|
+
);
|
|
23741
|
+
if (existingIndex >= 0) {
|
|
23742
|
+
this.settings.imported[existingIndex] = manifest;
|
|
23743
|
+
} else {
|
|
23744
|
+
this.settings.imported.push(manifest);
|
|
23745
|
+
}
|
|
23746
|
+
this.settings.enabled[manifest.id] = enabled;
|
|
23747
|
+
this.persistSettings();
|
|
23748
|
+
const plugin = this.registry.get(manifest.id);
|
|
23749
|
+
if (!plugin) {
|
|
23750
|
+
throw new Error(`Plugin import failed: ${manifest.id}`);
|
|
23751
|
+
}
|
|
23752
|
+
return plugin;
|
|
23753
|
+
}
|
|
23754
|
+
enrichTurnsWithArtifacts(input) {
|
|
23755
|
+
const manifests = this.registry.enabledManifests();
|
|
23756
|
+
if (manifests.length === 0) {
|
|
23757
|
+
return input.turns;
|
|
23758
|
+
}
|
|
23759
|
+
const turnsForExtraction = input.deferredDetails ? materializeDeferredDetailsForArtifactExtraction(
|
|
23760
|
+
input.turns,
|
|
23761
|
+
input.deferredDetails
|
|
23762
|
+
) : input.turns;
|
|
23763
|
+
const enrichedTurns = appendArtifactItemsToTurns(
|
|
23764
|
+
turnsForExtraction,
|
|
23765
|
+
new ManifestArtifactExtractor(manifests),
|
|
23766
|
+
{
|
|
23767
|
+
threadId: input.threadId,
|
|
23768
|
+
workspacePath: input.workspacePath,
|
|
23769
|
+
now: (/* @__PURE__ */ new Date()).toISOString()
|
|
23770
|
+
}
|
|
23771
|
+
);
|
|
23772
|
+
return turnsForExtraction === input.turns ? enrichedTurns : restoreOriginalNonArtifactItems(enrichedTurns, input.turns);
|
|
23773
|
+
}
|
|
23774
|
+
loadPersistedSettings() {
|
|
23775
|
+
if (!this.settingsStore) {
|
|
23776
|
+
return;
|
|
23777
|
+
}
|
|
23778
|
+
this.settings = this.settingsStore.load();
|
|
23779
|
+
for (const manifest of this.settings.imported) {
|
|
23780
|
+
this.registerImportedManifest(
|
|
23781
|
+
manifest,
|
|
23782
|
+
this.settings.enabled[manifest.id] ?? true
|
|
23783
|
+
);
|
|
23784
|
+
}
|
|
23785
|
+
for (const [pluginId, enabled] of Object.entries(this.settings.enabled)) {
|
|
23786
|
+
if (this.registry.get(pluginId)) {
|
|
23787
|
+
this.registry.setEnabled(pluginId, enabled);
|
|
23788
|
+
}
|
|
23789
|
+
}
|
|
23790
|
+
}
|
|
23791
|
+
registerImportedManifest(manifest, enabled) {
|
|
23792
|
+
if (this.registry.get(manifest.id)) {
|
|
23793
|
+
const existing = this.registry.getRegistered(manifest.id);
|
|
23794
|
+
if (existing?.source === "imported") {
|
|
23795
|
+
this.registry.updateImported({
|
|
23796
|
+
manifest,
|
|
23797
|
+
enabledByDefault: enabled,
|
|
23798
|
+
source: "imported"
|
|
23799
|
+
});
|
|
23800
|
+
} else {
|
|
23801
|
+
this.registry.setEnabled(manifest.id, enabled);
|
|
23802
|
+
}
|
|
23803
|
+
return;
|
|
23804
|
+
}
|
|
23805
|
+
this.registry.register({
|
|
23806
|
+
manifest,
|
|
23807
|
+
enabledByDefault: enabled,
|
|
23808
|
+
source: "imported"
|
|
23809
|
+
});
|
|
23810
|
+
}
|
|
23811
|
+
persistSettings() {
|
|
23812
|
+
this.settingsStore?.save(this.settings);
|
|
23813
|
+
}
|
|
23814
|
+
parseManifestJson(manifestJson) {
|
|
23815
|
+
if (!manifestJson?.trim()) {
|
|
23816
|
+
throw new Error("Plugin import requires a manifest object or manifestJson string.");
|
|
23817
|
+
}
|
|
23818
|
+
return JSON.parse(manifestJson);
|
|
23819
|
+
}
|
|
23820
|
+
};
|
|
23821
|
+
function restoreOriginalNonArtifactItems(enrichedTurns, originalTurns) {
|
|
23822
|
+
const originalItemsByTurnId = new Map(
|
|
23823
|
+
originalTurns.map((turn) => [
|
|
23824
|
+
turn.id,
|
|
23825
|
+
new Map(turn.items.map((item) => [item.id, item]))
|
|
23826
|
+
])
|
|
23827
|
+
);
|
|
23828
|
+
return enrichedTurns.map((turn) => {
|
|
23829
|
+
const originalItems = originalItemsByTurnId.get(turn.id);
|
|
23830
|
+
if (!originalItems) {
|
|
23831
|
+
return turn;
|
|
23832
|
+
}
|
|
23833
|
+
return {
|
|
23834
|
+
...turn,
|
|
23835
|
+
items: turn.items.map(
|
|
23836
|
+
(item) => item.kind === "artifact" ? item : originalItems.get(item.id) ?? item
|
|
23837
|
+
)
|
|
23838
|
+
};
|
|
23839
|
+
});
|
|
23840
|
+
}
|
|
23841
|
+
function materializeDeferredDetailsForArtifactExtraction(turns, deferredDetails) {
|
|
23842
|
+
if (deferredDetails.size === 0) {
|
|
23843
|
+
return turns;
|
|
23844
|
+
}
|
|
23845
|
+
return turns.map((turn) => {
|
|
23846
|
+
let changed = false;
|
|
23847
|
+
const items = turn.items.map((item) => {
|
|
23848
|
+
if (!item.hasDeferredDetail || item.detailText || item.kind !== "toolCall" || ![item.text, item.previewText].some(
|
|
23849
|
+
(value) => typeof value === "string" && value.includes(REMOTE_CODEX_MOLECULE_MCP_TOOL_NAME)
|
|
23850
|
+
)) {
|
|
23851
|
+
return item;
|
|
23852
|
+
}
|
|
23853
|
+
const detail = deferredDetails.get(item.id);
|
|
23854
|
+
if (!detail?.text) {
|
|
23855
|
+
return item;
|
|
23856
|
+
}
|
|
23857
|
+
changed = true;
|
|
23858
|
+
return {
|
|
23859
|
+
...item,
|
|
23860
|
+
detailText: detail.text
|
|
23861
|
+
};
|
|
23862
|
+
});
|
|
23863
|
+
return changed ? {
|
|
23864
|
+
...turn,
|
|
23865
|
+
items
|
|
23866
|
+
} : turn;
|
|
23867
|
+
});
|
|
23868
|
+
}
|
|
23869
|
+
|
|
23870
|
+
// src/plugins/plugin-settings-store.ts
|
|
23871
|
+
var PLUGIN_SETTINGS_POLICY_KEY = "plugins";
|
|
23872
|
+
function emptySettings() {
|
|
23873
|
+
return {
|
|
23874
|
+
enabled: {},
|
|
23875
|
+
imported: []
|
|
23876
|
+
};
|
|
23877
|
+
}
|
|
23878
|
+
function parseEnabled(value) {
|
|
23879
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
23880
|
+
return {};
|
|
23881
|
+
}
|
|
23882
|
+
const output = {};
|
|
23883
|
+
for (const [key, enabled] of Object.entries(value)) {
|
|
23884
|
+
if (typeof enabled === "boolean") {
|
|
23885
|
+
output[key] = enabled;
|
|
23886
|
+
} else if (enabled && typeof enabled === "object" && !Array.isArray(enabled) && typeof enabled.enabled === "boolean") {
|
|
23887
|
+
output[key] = enabled.enabled;
|
|
23888
|
+
}
|
|
23889
|
+
}
|
|
23890
|
+
return output;
|
|
23891
|
+
}
|
|
23892
|
+
var PluginSettingsStore = class {
|
|
23893
|
+
constructor(db) {
|
|
23894
|
+
this.db = db;
|
|
23895
|
+
}
|
|
23896
|
+
db;
|
|
23897
|
+
load() {
|
|
23898
|
+
const record = getPolicyRecordByKey(this.db, PLUGIN_SETTINGS_POLICY_KEY);
|
|
23899
|
+
if (!record?.valueJson) {
|
|
23900
|
+
return emptySettings();
|
|
23901
|
+
}
|
|
23902
|
+
try {
|
|
23903
|
+
const parsed = JSON.parse(record.valueJson);
|
|
23904
|
+
return {
|
|
23905
|
+
enabled: parseEnabled(parsed.enabled),
|
|
23906
|
+
imported: Array.isArray(parsed.imported) ? parsed.imported.map((entry) => parsePluginManifest(entry)) : []
|
|
23907
|
+
};
|
|
23908
|
+
} catch {
|
|
23909
|
+
return emptySettings();
|
|
23910
|
+
}
|
|
23911
|
+
}
|
|
23912
|
+
save(settings) {
|
|
23913
|
+
upsertPolicyRecord(
|
|
23914
|
+
this.db,
|
|
23915
|
+
PLUGIN_SETTINGS_POLICY_KEY,
|
|
23916
|
+
JSON.stringify({
|
|
23917
|
+
enabled: settings.enabled,
|
|
23918
|
+
imported: settings.imported
|
|
23919
|
+
})
|
|
23920
|
+
);
|
|
23921
|
+
}
|
|
23922
|
+
};
|
|
23923
|
+
|
|
23924
|
+
// src/plugins/backend-plugin-host.ts
|
|
23925
|
+
var BackendPluginHost = class {
|
|
23926
|
+
constructor(app2) {
|
|
23927
|
+
this.app = app2;
|
|
23928
|
+
}
|
|
23929
|
+
app;
|
|
23930
|
+
socketHandlers = [];
|
|
23931
|
+
registerSocketHandler(handler) {
|
|
23932
|
+
this.socketHandlers.push(handler);
|
|
23933
|
+
}
|
|
23934
|
+
register(contribution) {
|
|
23935
|
+
contribution.registerHttp?.(this.app);
|
|
23936
|
+
contribution.registerSocket?.(this);
|
|
23937
|
+
}
|
|
23938
|
+
async handleSocketMessage(context) {
|
|
23939
|
+
for (const handler of this.socketHandlers) {
|
|
23940
|
+
if (await handler(context)) {
|
|
23941
|
+
return true;
|
|
23942
|
+
}
|
|
23943
|
+
}
|
|
23944
|
+
return false;
|
|
23945
|
+
}
|
|
23946
|
+
};
|
|
23947
|
+
|
|
23948
|
+
// src/shell/pty-shell-backend.ts
|
|
23949
|
+
import path21 from "path";
|
|
23950
|
+
import { spawn as spawn4 } from "@homebridge/node-pty-prebuilt-multiarch";
|
|
23951
|
+
|
|
23952
|
+
// src/shell/default-shell.ts
|
|
23953
|
+
import fs22 from "fs";
|
|
23954
|
+
var POSIX_SHELL_CANDIDATES = ["/bin/bash", "/usr/bin/bash", "/bin/sh"];
|
|
23955
|
+
function resolveDefaultShell(env = process.env) {
|
|
23956
|
+
if (process.platform === "win32") {
|
|
23957
|
+
return env.COMSPEC ?? "cmd.exe";
|
|
23958
|
+
}
|
|
23959
|
+
if (env.SHELL && fs22.existsSync(env.SHELL)) {
|
|
23960
|
+
return env.SHELL;
|
|
23961
|
+
}
|
|
23962
|
+
return POSIX_SHELL_CANDIDATES.find((candidate) => fs22.existsSync(candidate)) ?? "/bin/sh";
|
|
23963
|
+
}
|
|
23964
|
+
|
|
23965
|
+
// src/shell/pty-shell-backend.ts
|
|
23966
|
+
var MAX_SCROLLBACK_BYTES = 512 * 1024;
|
|
23967
|
+
var ANSI_ESCAPE_PATTERN = new RegExp(String.raw`\u001B\[[0-?]*[ -/]*[@-~]`, "g");
|
|
23968
|
+
function shellArgs(shell) {
|
|
23969
|
+
const shellName = path21.basename(shell).toLowerCase();
|
|
23970
|
+
if (process.platform === "win32") {
|
|
23971
|
+
return [];
|
|
23972
|
+
}
|
|
23973
|
+
if (shellName === "bash" || shellName === "zsh" || shellName === "sh") {
|
|
23974
|
+
return ["-l"];
|
|
23975
|
+
}
|
|
23976
|
+
return [];
|
|
23977
|
+
}
|
|
23978
|
+
function trimScrollback(value) {
|
|
23979
|
+
if (value.length <= MAX_SCROLLBACK_BYTES) {
|
|
23980
|
+
return value;
|
|
23981
|
+
}
|
|
23982
|
+
return value.slice(value.length - MAX_SCROLLBACK_BYTES);
|
|
23983
|
+
}
|
|
23984
|
+
function lastVisibleLine(snapshot) {
|
|
23985
|
+
const normalized = snapshot.replace(ANSI_ESCAPE_PATTERN, "");
|
|
23986
|
+
const lines = normalized.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
23987
|
+
return lines.findLast((line) => line.trim().length > 0) ?? "";
|
|
23988
|
+
}
|
|
23989
|
+
function inferRuntime(session) {
|
|
23990
|
+
const promptLine = lastVisibleLine(session.scrollback);
|
|
23991
|
+
const shell = path21.basename(session.shell);
|
|
23992
|
+
const isCommandRunning = session.exitCode !== null ? false : !/[$#>]\s*$/.test(promptLine.trimEnd());
|
|
23993
|
+
return {
|
|
23994
|
+
panePid: session.pty.pid,
|
|
23995
|
+
paneWidth: session.pty.cols,
|
|
23996
|
+
paneHeight: session.pty.rows,
|
|
23997
|
+
currentCommand: isCommandRunning ? session.pty.process : shell,
|
|
23998
|
+
currentPath: session.cwd,
|
|
23999
|
+
isCommandRunning
|
|
24000
|
+
};
|
|
24001
|
+
}
|
|
24002
|
+
var PtyShellBackend = class {
|
|
24003
|
+
kind = "pty";
|
|
24004
|
+
sessions = /* @__PURE__ */ new Map();
|
|
24005
|
+
shell = resolveDefaultShell();
|
|
24006
|
+
sessionNameForThread(threadId) {
|
|
24007
|
+
return `rcx-${threadId.replace(/[^a-zA-Z0-9_-]/g, "").slice(0, 28)}`;
|
|
24008
|
+
}
|
|
24009
|
+
async listSessionNames() {
|
|
24010
|
+
return [...this.sessions.keys()];
|
|
24011
|
+
}
|
|
24012
|
+
async hasSession(sessionId) {
|
|
24013
|
+
return this.sessions.has(sessionId);
|
|
24014
|
+
}
|
|
24015
|
+
async createSession(input) {
|
|
24016
|
+
if (this.sessions.has(input.sessionId)) {
|
|
24017
|
+
return;
|
|
24018
|
+
}
|
|
24019
|
+
const pty = spawn4(this.shell, shellArgs(this.shell), {
|
|
24020
|
+
name: "xterm-256color",
|
|
24021
|
+
cwd: input.cwd,
|
|
24022
|
+
cols: input.cols ?? 120,
|
|
24023
|
+
rows: input.rows ?? 36,
|
|
24024
|
+
env: {
|
|
24025
|
+
...process.env,
|
|
24026
|
+
TERM: "xterm-256color",
|
|
24027
|
+
COLORTERM: process.env.COLORTERM ?? "truecolor"
|
|
24028
|
+
},
|
|
24029
|
+
handleFlowControl: true
|
|
24030
|
+
});
|
|
24031
|
+
const session = {
|
|
24032
|
+
id: input.sessionId,
|
|
24033
|
+
cwd: input.cwd,
|
|
24034
|
+
shell: this.shell,
|
|
24035
|
+
pty,
|
|
24036
|
+
scrollback: "",
|
|
24037
|
+
exitCode: null,
|
|
24038
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
24039
|
+
exitListeners: /* @__PURE__ */ new Set(),
|
|
24040
|
+
dataSubscription: { dispose() {
|
|
24041
|
+
} },
|
|
24042
|
+
exitSubscription: { dispose() {
|
|
24043
|
+
} }
|
|
24044
|
+
};
|
|
24045
|
+
session.dataSubscription = pty.onData((data) => {
|
|
24046
|
+
session.scrollback = trimScrollback(session.scrollback + data);
|
|
24047
|
+
for (const listener of session.listeners) {
|
|
24048
|
+
listener(data);
|
|
24049
|
+
}
|
|
24050
|
+
});
|
|
24051
|
+
session.exitSubscription = pty.onExit(() => {
|
|
24052
|
+
session.exitCode = 0;
|
|
24053
|
+
this.sessions.delete(session.id);
|
|
24054
|
+
for (const listener of session.exitListeners) {
|
|
24055
|
+
listener();
|
|
24056
|
+
}
|
|
24057
|
+
session.dataSubscription.dispose();
|
|
24058
|
+
session.exitSubscription.dispose();
|
|
24059
|
+
});
|
|
24060
|
+
this.sessions.set(input.sessionId, session);
|
|
24061
|
+
}
|
|
24062
|
+
async attach(sessionId, options) {
|
|
24063
|
+
const session = this.requireSession(sessionId);
|
|
24064
|
+
this.resizeIfChanged(session, options.cols, options.rows);
|
|
24065
|
+
const onData = (data) => options.onData(data, this.toBackendSession(session));
|
|
24066
|
+
const onExit = () => options.onExit();
|
|
24067
|
+
session.listeners.add(onData);
|
|
24068
|
+
session.exitListeners.add(onExit);
|
|
24069
|
+
return {
|
|
24070
|
+
session: this.toBackendSession(session),
|
|
24071
|
+
attachment: {
|
|
24072
|
+
dispose: () => {
|
|
24073
|
+
session.listeners.delete(onData);
|
|
24074
|
+
session.exitListeners.delete(onExit);
|
|
24075
|
+
}
|
|
24076
|
+
}
|
|
24077
|
+
};
|
|
24078
|
+
}
|
|
24079
|
+
async sendInput(sessionId, data) {
|
|
24080
|
+
this.requireSession(sessionId).pty.write(data);
|
|
24081
|
+
}
|
|
24082
|
+
async clear(sessionId) {
|
|
24083
|
+
const session = this.requireSession(sessionId);
|
|
24084
|
+
session.scrollback = "";
|
|
24085
|
+
session.pty.clear();
|
|
24086
|
+
session.pty.write("\f");
|
|
24087
|
+
return this.toBackendSession(session);
|
|
24088
|
+
}
|
|
24089
|
+
async resize(sessionId, cols, rows) {
|
|
24090
|
+
this.resizeIfChanged(this.requireSession(sessionId), cols, rows);
|
|
24091
|
+
}
|
|
24092
|
+
async snapshot(sessionId) {
|
|
24093
|
+
return this.toBackendSession(this.requireSession(sessionId));
|
|
24094
|
+
}
|
|
24095
|
+
async killSession(sessionId) {
|
|
24096
|
+
const session = this.sessions.get(sessionId);
|
|
24097
|
+
if (!session) {
|
|
24098
|
+
return;
|
|
24099
|
+
}
|
|
24100
|
+
session.dataSubscription.dispose();
|
|
24101
|
+
session.exitSubscription.dispose();
|
|
24102
|
+
this.sessions.delete(sessionId);
|
|
24103
|
+
try {
|
|
24104
|
+
session.pty.kill();
|
|
24105
|
+
} catch {
|
|
24106
|
+
}
|
|
24107
|
+
}
|
|
24108
|
+
requireSession(sessionId) {
|
|
24109
|
+
const session = this.sessions.get(sessionId);
|
|
24110
|
+
if (!session) {
|
|
24111
|
+
throw new Error("Shell session is no longer available.");
|
|
24112
|
+
}
|
|
24113
|
+
return session;
|
|
24114
|
+
}
|
|
24115
|
+
resizeIfChanged(session, cols, rows) {
|
|
24116
|
+
if (cols <= 0 || rows <= 0) {
|
|
24117
|
+
return;
|
|
24118
|
+
}
|
|
24119
|
+
if (session.pty.cols === cols && session.pty.rows === rows) {
|
|
24120
|
+
return;
|
|
24121
|
+
}
|
|
24122
|
+
session.pty.resize(cols, rows);
|
|
24123
|
+
}
|
|
24124
|
+
toBackendSession(session) {
|
|
24125
|
+
return {
|
|
24126
|
+
id: session.id,
|
|
24127
|
+
cwd: session.cwd,
|
|
24128
|
+
cols: session.pty.cols,
|
|
24129
|
+
rows: session.pty.rows,
|
|
24130
|
+
snapshot: session.scrollback,
|
|
24131
|
+
runtime: inferRuntime(session)
|
|
24132
|
+
};
|
|
24133
|
+
}
|
|
24134
|
+
};
|
|
24135
|
+
|
|
24136
|
+
// src/shell/tmux-manager.ts
|
|
24137
|
+
import fs23 from "fs";
|
|
24138
|
+
import path22 from "path";
|
|
22739
24139
|
import { spawn as spawnChild } from "child_process";
|
|
22740
24140
|
async function defaultExecCommand(command, args) {
|
|
22741
24141
|
return await new Promise((resolve, reject) => {
|
|
@@ -22762,17 +24162,17 @@ async function defaultExecCommand(command, args) {
|
|
|
22762
24162
|
});
|
|
22763
24163
|
}
|
|
22764
24164
|
function resolveExecutablePath(command) {
|
|
22765
|
-
if (command.includes(
|
|
24165
|
+
if (command.includes(path22.sep)) {
|
|
22766
24166
|
return command;
|
|
22767
24167
|
}
|
|
22768
24168
|
const searchPath = process.env.PATH ?? "";
|
|
22769
|
-
for (const entry of searchPath.split(
|
|
24169
|
+
for (const entry of searchPath.split(path22.delimiter)) {
|
|
22770
24170
|
const trimmed = entry.trim();
|
|
22771
24171
|
if (!trimmed) {
|
|
22772
24172
|
continue;
|
|
22773
24173
|
}
|
|
22774
|
-
const candidate =
|
|
22775
|
-
if (
|
|
24174
|
+
const candidate = path22.join(trimmed, command);
|
|
24175
|
+
if (fs23.existsSync(candidate)) {
|
|
22776
24176
|
return candidate;
|
|
22777
24177
|
}
|
|
22778
24178
|
}
|
|
@@ -22784,7 +24184,7 @@ var TmuxManager = class {
|
|
|
22784
24184
|
execCommand;
|
|
22785
24185
|
constructor(options = {}) {
|
|
22786
24186
|
this.command = resolveExecutablePath(options.command ?? "tmux");
|
|
22787
|
-
this.defaultShell = options.defaultShell ??
|
|
24187
|
+
this.defaultShell = options.defaultShell ?? resolveDefaultShell();
|
|
22788
24188
|
this.execCommand = options.execCommand ?? defaultExecCommand;
|
|
22789
24189
|
}
|
|
22790
24190
|
sessionNameForThread(threadId) {
|
|
@@ -23087,211 +24487,383 @@ function tokenizeTmuxInput(data) {
|
|
|
23087
24487
|
return tokens;
|
|
23088
24488
|
}
|
|
23089
24489
|
|
|
23090
|
-
//
|
|
23091
|
-
var
|
|
23092
|
-
|
|
23093
|
-
|
|
23094
|
-
name: "XYZ Molecule Viewer",
|
|
23095
|
-
version: "0.1.0",
|
|
23096
|
-
description: "A draft built-in plugin for previewing xyz, extxyz, cif, and pdb molecular structures with 3Dmol.js.",
|
|
23097
|
-
remoteCodex: "^0.11.0",
|
|
23098
|
-
capabilities: {
|
|
23099
|
-
artifactTypes: [
|
|
23100
|
-
{
|
|
23101
|
-
type: XYZ_MOLECULE_ARTIFACT_TYPE,
|
|
23102
|
-
title: "3D Molecule",
|
|
23103
|
-
fileExtensions: ["xyz", "extxyz", "cif", "pdb"]
|
|
23104
|
-
}
|
|
23105
|
-
],
|
|
23106
|
-
timelineRenderers: [XYZ_MOLECULE_ARTIFACT_TYPE],
|
|
23107
|
-
threadPanels: [
|
|
23108
|
-
{
|
|
23109
|
-
id: "xyz-viewer",
|
|
23110
|
-
label: "Molecules",
|
|
23111
|
-
artifactTypes: [XYZ_MOLECULE_ARTIFACT_TYPE]
|
|
23112
|
-
}
|
|
23113
|
-
],
|
|
23114
|
-
frontend: {
|
|
23115
|
-
entry: "./dist/index.js",
|
|
23116
|
-
style: "./src/styles.css"
|
|
23117
|
-
}
|
|
23118
|
-
}
|
|
23119
|
-
};
|
|
23120
|
-
|
|
23121
|
-
// src/plugins/builtin-plugins.ts
|
|
23122
|
-
var builtinPlugins = [
|
|
23123
|
-
{
|
|
23124
|
-
manifest: xyzViewerPluginManifest,
|
|
23125
|
-
enabledByDefault: true
|
|
23126
|
-
}
|
|
23127
|
-
];
|
|
23128
|
-
|
|
23129
|
-
// src/plugins/plugin-service.ts
|
|
23130
|
-
var PluginService = class {
|
|
23131
|
-
constructor(registry, settingsStore) {
|
|
23132
|
-
this.registry = registry;
|
|
23133
|
-
this.settingsStore = settingsStore;
|
|
23134
|
-
this.loadPersistedSettings();
|
|
24490
|
+
// src/shell/tmux-shell-backend.ts
|
|
24491
|
+
var TmuxShellBackend = class {
|
|
24492
|
+
constructor(tmuxManager = new TmuxManager()) {
|
|
24493
|
+
this.tmuxManager = tmuxManager;
|
|
23135
24494
|
}
|
|
23136
|
-
|
|
23137
|
-
|
|
23138
|
-
|
|
23139
|
-
|
|
23140
|
-
|
|
23141
|
-
};
|
|
23142
|
-
listPlugins() {
|
|
23143
|
-
return this.registry.list();
|
|
24495
|
+
tmuxManager;
|
|
24496
|
+
kind = "tmux";
|
|
24497
|
+
attachments = /* @__PURE__ */ new Map();
|
|
24498
|
+
sessionNameForThread(threadId) {
|
|
24499
|
+
return this.tmuxManager.sessionNameForThread(threadId);
|
|
23144
24500
|
}
|
|
23145
|
-
|
|
23146
|
-
return this.
|
|
24501
|
+
listSessionNames() {
|
|
24502
|
+
return this.tmuxManager.listSessionNames();
|
|
23147
24503
|
}
|
|
23148
|
-
|
|
23149
|
-
|
|
23150
|
-
this.settings.enabled[pluginId] = enabled;
|
|
23151
|
-
this.persistSettings();
|
|
23152
|
-
return plugin;
|
|
24504
|
+
hasSession(sessionId) {
|
|
24505
|
+
return this.tmuxManager.hasSession(sessionId);
|
|
23153
24506
|
}
|
|
23154
|
-
|
|
23155
|
-
|
|
23156
|
-
|
|
23157
|
-
|
|
23158
|
-
|
|
23159
|
-
|
|
23160
|
-
|
|
23161
|
-
|
|
23162
|
-
|
|
23163
|
-
|
|
23164
|
-
|
|
23165
|
-
|
|
23166
|
-
|
|
23167
|
-
|
|
23168
|
-
|
|
23169
|
-
|
|
23170
|
-
|
|
23171
|
-
|
|
23172
|
-
this.persistSettings();
|
|
23173
|
-
const plugin = this.registry.get(manifest.id);
|
|
23174
|
-
if (!plugin) {
|
|
23175
|
-
throw new Error(`Plugin import failed: ${manifest.id}`);
|
|
24507
|
+
async createSession(input) {
|
|
24508
|
+
await this.tmuxManager.createSession({
|
|
24509
|
+
sessionName: input.sessionId,
|
|
24510
|
+
cwd: input.cwd,
|
|
24511
|
+
...input.cols !== void 0 ? { cols: input.cols } : {},
|
|
24512
|
+
...input.rows !== void 0 ? { rows: input.rows } : {}
|
|
24513
|
+
});
|
|
24514
|
+
try {
|
|
24515
|
+
const runtime = await this.tmuxManager.getPaneRuntimeInfo(input.sessionId);
|
|
24516
|
+
if (isInteractiveShellCommand(runtime.currentCommand)) {
|
|
24517
|
+
await this.tmuxManager.sendInput(
|
|
24518
|
+
input.sessionId,
|
|
24519
|
+
await buildShellPromptInitCommand(runtime.currentCommand, {
|
|
24520
|
+
clearScreen: true
|
|
24521
|
+
})
|
|
24522
|
+
);
|
|
24523
|
+
}
|
|
24524
|
+
} catch {
|
|
23176
24525
|
}
|
|
23177
|
-
return plugin;
|
|
23178
24526
|
}
|
|
23179
|
-
|
|
23180
|
-
const
|
|
23181
|
-
if (
|
|
23182
|
-
|
|
24527
|
+
async attach(sessionId, options) {
|
|
24528
|
+
const previous = this.attachments.get(sessionId);
|
|
24529
|
+
if (previous) {
|
|
24530
|
+
previous.disposed = true;
|
|
24531
|
+
clearInterval(previous.pollHandle);
|
|
24532
|
+
this.attachments.delete(sessionId);
|
|
23183
24533
|
}
|
|
23184
|
-
|
|
23185
|
-
|
|
23186
|
-
|
|
23187
|
-
|
|
23188
|
-
|
|
23189
|
-
|
|
23190
|
-
|
|
24534
|
+
await this.tmuxManager.resizeWindow(sessionId, options.cols, options.rows);
|
|
24535
|
+
const session = await this.snapshot(sessionId);
|
|
24536
|
+
const attachment = {
|
|
24537
|
+
disposed: false,
|
|
24538
|
+
lastSnapshot: session.snapshot,
|
|
24539
|
+
polling: false,
|
|
24540
|
+
pollHandle: setInterval(() => {
|
|
24541
|
+
void this.poll(sessionId, attachment, options);
|
|
24542
|
+
}, 250)
|
|
24543
|
+
};
|
|
24544
|
+
this.attachments.set(sessionId, attachment);
|
|
24545
|
+
return {
|
|
24546
|
+
session,
|
|
24547
|
+
attachment: {
|
|
24548
|
+
dispose: () => {
|
|
24549
|
+
attachment.disposed = true;
|
|
24550
|
+
clearInterval(attachment.pollHandle);
|
|
24551
|
+
if (this.attachments.get(sessionId) === attachment) {
|
|
24552
|
+
this.attachments.delete(sessionId);
|
|
24553
|
+
}
|
|
24554
|
+
}
|
|
23191
24555
|
}
|
|
23192
|
-
|
|
24556
|
+
};
|
|
23193
24557
|
}
|
|
23194
|
-
|
|
23195
|
-
|
|
23196
|
-
|
|
23197
|
-
|
|
23198
|
-
|
|
23199
|
-
|
|
23200
|
-
|
|
23201
|
-
|
|
23202
|
-
|
|
23203
|
-
|
|
24558
|
+
sendInput(sessionId, data) {
|
|
24559
|
+
return this.tmuxManager.sendInput(sessionId, data);
|
|
24560
|
+
}
|
|
24561
|
+
async clear(sessionId) {
|
|
24562
|
+
await this.tmuxManager.sendInput(sessionId, "\f");
|
|
24563
|
+
await this.tmuxManager.clearHistory(sessionId);
|
|
24564
|
+
const session = await this.snapshot(sessionId);
|
|
24565
|
+
const attachment = this.attachments.get(sessionId);
|
|
24566
|
+
if (attachment) {
|
|
24567
|
+
attachment.lastSnapshot = session.snapshot;
|
|
23204
24568
|
}
|
|
23205
|
-
|
|
23206
|
-
|
|
23207
|
-
|
|
24569
|
+
return session;
|
|
24570
|
+
}
|
|
24571
|
+
resize(sessionId, cols, rows) {
|
|
24572
|
+
return this.tmuxManager.resizeWindow(sessionId, cols, rows);
|
|
24573
|
+
}
|
|
24574
|
+
async snapshot(sessionId) {
|
|
24575
|
+
const snapshot = await this.tmuxManager.capturePane(sessionId);
|
|
24576
|
+
const runtime = await this.tmuxManager.getPaneRuntimeInfo(sessionId);
|
|
24577
|
+
const envPrefix = await resolvePaneEnvironmentPrefix(
|
|
24578
|
+
this.tmuxManager,
|
|
24579
|
+
sessionId,
|
|
24580
|
+
runtime.panePid
|
|
24581
|
+
);
|
|
24582
|
+
return {
|
|
24583
|
+
id: sessionId,
|
|
24584
|
+
cwd: runtime.currentPath,
|
|
24585
|
+
cols: runtime.paneWidth,
|
|
24586
|
+
rows: runtime.paneHeight,
|
|
24587
|
+
snapshot,
|
|
24588
|
+
runtime: {
|
|
24589
|
+
cursorX: runtime.cursorX,
|
|
24590
|
+
cursorY: runtime.cursorY,
|
|
24591
|
+
paneWidth: runtime.paneWidth,
|
|
24592
|
+
paneHeight: runtime.paneHeight,
|
|
24593
|
+
panePid: runtime.panePid,
|
|
24594
|
+
currentCommand: runtime.currentCommand,
|
|
24595
|
+
currentPath: runtime.currentPath,
|
|
24596
|
+
envPrefix,
|
|
24597
|
+
isCommandRunning: !isInteractiveShellCommand(runtime.currentCommand)
|
|
23208
24598
|
}
|
|
24599
|
+
};
|
|
24600
|
+
}
|
|
24601
|
+
killSession(sessionId) {
|
|
24602
|
+
const attachment = this.attachments.get(sessionId);
|
|
24603
|
+
if (attachment) {
|
|
24604
|
+
attachment.disposed = true;
|
|
24605
|
+
clearInterval(attachment.pollHandle);
|
|
24606
|
+
this.attachments.delete(sessionId);
|
|
23209
24607
|
}
|
|
24608
|
+
return this.tmuxManager.killSession(sessionId);
|
|
23210
24609
|
}
|
|
23211
|
-
|
|
23212
|
-
if (
|
|
23213
|
-
const existing = this.registry.getRegistered(manifest.id);
|
|
23214
|
-
if (existing?.source === "imported") {
|
|
23215
|
-
this.registry.updateImported({
|
|
23216
|
-
manifest,
|
|
23217
|
-
enabledByDefault: enabled,
|
|
23218
|
-
source: "imported"
|
|
23219
|
-
});
|
|
23220
|
-
} else {
|
|
23221
|
-
this.registry.setEnabled(manifest.id, enabled);
|
|
23222
|
-
}
|
|
24610
|
+
async poll(sessionId, attachment, options) {
|
|
24611
|
+
if (attachment.disposed || attachment.polling) {
|
|
23223
24612
|
return;
|
|
23224
24613
|
}
|
|
23225
|
-
|
|
23226
|
-
|
|
23227
|
-
|
|
23228
|
-
|
|
23229
|
-
|
|
23230
|
-
|
|
23231
|
-
|
|
23232
|
-
|
|
23233
|
-
|
|
23234
|
-
|
|
23235
|
-
|
|
23236
|
-
|
|
24614
|
+
attachment.polling = true;
|
|
24615
|
+
try {
|
|
24616
|
+
const exists2 = await this.hasSession(sessionId);
|
|
24617
|
+
if (!exists2) {
|
|
24618
|
+
attachment.disposed = true;
|
|
24619
|
+
clearInterval(attachment.pollHandle);
|
|
24620
|
+
this.attachments.delete(sessionId);
|
|
24621
|
+
options.onExit();
|
|
24622
|
+
return;
|
|
24623
|
+
}
|
|
24624
|
+
const session = await this.snapshot(sessionId);
|
|
24625
|
+
if (session.snapshot !== attachment.lastSnapshot) {
|
|
24626
|
+
attachment.lastSnapshot = session.snapshot;
|
|
24627
|
+
options.onData(session.snapshot, session, { replace: true });
|
|
24628
|
+
}
|
|
24629
|
+
} catch {
|
|
24630
|
+
attachment.disposed = true;
|
|
24631
|
+
clearInterval(attachment.pollHandle);
|
|
24632
|
+
this.attachments.delete(sessionId);
|
|
24633
|
+
options.onExit();
|
|
24634
|
+
} finally {
|
|
24635
|
+
attachment.polling = false;
|
|
23237
24636
|
}
|
|
23238
|
-
return JSON.parse(manifestJson);
|
|
23239
24637
|
}
|
|
23240
24638
|
};
|
|
23241
24639
|
|
|
23242
|
-
// src/
|
|
23243
|
-
|
|
23244
|
-
function
|
|
23245
|
-
|
|
23246
|
-
|
|
23247
|
-
|
|
23248
|
-
|
|
24640
|
+
// src/routes/shells.ts
|
|
24641
|
+
import { z as z8 } from "zod";
|
|
24642
|
+
async function registerShellRoutes(app2, options = {}) {
|
|
24643
|
+
const threadIdParams = z8.object({ id: z8.string().uuid() });
|
|
24644
|
+
const shellIdParams = z8.object({ id: z8.string().uuid() });
|
|
24645
|
+
const createShellSchema = z8.object({
|
|
24646
|
+
cols: z8.number().int().positive().optional(),
|
|
24647
|
+
rows: z8.number().int().positive().optional(),
|
|
24648
|
+
label: z8.string().trim().min(1).max(80).optional()
|
|
24649
|
+
});
|
|
24650
|
+
const updateShellSchema = z8.object({
|
|
24651
|
+
label: z8.string().trim().min(1).max(80).nullable().optional()
|
|
24652
|
+
});
|
|
24653
|
+
const routeOptions = options.preHandler ? { preHandler: options.preHandler } : {};
|
|
24654
|
+
app2.get("/api/threads/:id/shell", routeOptions, async (request) => {
|
|
24655
|
+
const params = threadIdParams.parse(request.params);
|
|
24656
|
+
return app2.services.shellService.getThreadShellState(params.id);
|
|
24657
|
+
});
|
|
24658
|
+
app2.post("/api/threads/:id/shell", routeOptions, async (request) => {
|
|
24659
|
+
const params = threadIdParams.parse(request.params);
|
|
24660
|
+
const body = createShellSchema.parse(request.body ?? {});
|
|
24661
|
+
const input = {
|
|
24662
|
+
...body.cols !== void 0 ? { cols: body.cols } : {},
|
|
24663
|
+
...body.rows !== void 0 ? { rows: body.rows } : {},
|
|
24664
|
+
...body.label !== void 0 ? { label: body.label } : {}
|
|
24665
|
+
};
|
|
24666
|
+
return app2.services.shellService.createShellForThread(params.id, input);
|
|
24667
|
+
});
|
|
24668
|
+
app2.post("/api/shells/:id/terminate", routeOptions, async (request) => {
|
|
24669
|
+
const params = shellIdParams.parse(request.params);
|
|
24670
|
+
return app2.services.shellService.terminateShell(params.id);
|
|
24671
|
+
});
|
|
24672
|
+
app2.patch("/api/shells/:id", routeOptions, async (request) => {
|
|
24673
|
+
const params = shellIdParams.parse(request.params);
|
|
24674
|
+
const body = updateShellSchema.parse(request.body ?? {});
|
|
24675
|
+
const input = {
|
|
24676
|
+
..."label" in body ? { label: body.label ?? null } : {}
|
|
24677
|
+
};
|
|
24678
|
+
return app2.services.shellService.updateShell(params.id, input);
|
|
24679
|
+
});
|
|
23249
24680
|
}
|
|
23250
|
-
|
|
23251
|
-
|
|
23252
|
-
|
|
24681
|
+
|
|
24682
|
+
// src/plugins/terminal-plugin-backend.ts
|
|
24683
|
+
function createTerminalShellBackend(env = process.env) {
|
|
24684
|
+
return env.REMOTE_CODEX_SHELL_BACKEND === "tmux" ? new TmuxShellBackend() : new PtyShellBackend();
|
|
24685
|
+
}
|
|
24686
|
+
function isTerminalPluginEnabled(app2) {
|
|
24687
|
+
return app2.services.pluginService.getPlugin(TERMINAL_PLUGIN_ID)?.enabled === true;
|
|
24688
|
+
}
|
|
24689
|
+
function requireTerminalPluginEnabled(app2) {
|
|
24690
|
+
if (!isTerminalPluginEnabled(app2)) {
|
|
24691
|
+
throw new ShellServiceError(
|
|
24692
|
+
"plugin_disabled",
|
|
24693
|
+
"The Terminal plugin is disabled."
|
|
24694
|
+
);
|
|
23253
24695
|
}
|
|
23254
|
-
|
|
23255
|
-
|
|
23256
|
-
|
|
23257
|
-
|
|
23258
|
-
|
|
23259
|
-
output[key] = enabled.enabled;
|
|
24696
|
+
}
|
|
24697
|
+
function registerTerminalPluginBackend(app2) {
|
|
24698
|
+
app2.register(registerShellRoutes, {
|
|
24699
|
+
preHandler: async () => {
|
|
24700
|
+
requireTerminalPluginEnabled(app2);
|
|
23260
24701
|
}
|
|
23261
|
-
}
|
|
23262
|
-
return output;
|
|
24702
|
+
});
|
|
23263
24703
|
}
|
|
23264
|
-
|
|
23265
|
-
|
|
23266
|
-
|
|
23267
|
-
|
|
23268
|
-
|
|
23269
|
-
|
|
23270
|
-
const record = getPolicyRecordByKey(this.db, PLUGIN_SETTINGS_POLICY_KEY);
|
|
23271
|
-
if (!record?.valueJson) {
|
|
23272
|
-
return emptySettings();
|
|
24704
|
+
function createTerminalPluginBackendContribution() {
|
|
24705
|
+
return {
|
|
24706
|
+
pluginId: TERMINAL_PLUGIN_ID,
|
|
24707
|
+
registerHttp: registerTerminalPluginBackend,
|
|
24708
|
+
registerSocket(host2) {
|
|
24709
|
+
host2.registerSocketHandler(createTerminalSocketHandler());
|
|
23273
24710
|
}
|
|
24711
|
+
};
|
|
24712
|
+
}
|
|
24713
|
+
function createTerminalSocketHandler() {
|
|
24714
|
+
return async (context) => {
|
|
24715
|
+
const { app: app2, message, send } = context;
|
|
24716
|
+
const shellService = app2.services.shellService;
|
|
24717
|
+
const stateKey = `${TERMINAL_PLUGIN_ID}:attached-shell`;
|
|
24718
|
+
const cleanupRegisteredKey = `${TERMINAL_PLUGIN_ID}:cleanup-registered`;
|
|
24719
|
+
const getAttachedShell = () => context.state.get(stateKey);
|
|
24720
|
+
const setAttachedShell = (value) => {
|
|
24721
|
+
if (value) {
|
|
24722
|
+
context.state.set(stateKey, value);
|
|
24723
|
+
} else {
|
|
24724
|
+
context.state.delete(stateKey);
|
|
24725
|
+
}
|
|
24726
|
+
};
|
|
23274
24727
|
try {
|
|
23275
|
-
|
|
23276
|
-
|
|
23277
|
-
|
|
23278
|
-
|
|
23279
|
-
|
|
23280
|
-
|
|
23281
|
-
|
|
24728
|
+
if (message.type === "shell.attach") {
|
|
24729
|
+
requireTerminalPluginEnabled(app2);
|
|
24730
|
+
const attachedShell = getAttachedShell();
|
|
24731
|
+
if (attachedShell && attachedShell.shellId !== message.shellId) {
|
|
24732
|
+
await shellService.detachShell(
|
|
24733
|
+
attachedShell.shellId,
|
|
24734
|
+
attachedShell.viewerId
|
|
24735
|
+
);
|
|
24736
|
+
setAttachedShell(null);
|
|
24737
|
+
}
|
|
24738
|
+
const attachment = await shellService.attachShell(message.shellId, {
|
|
24739
|
+
cols: message.cols,
|
|
24740
|
+
rows: message.rows,
|
|
24741
|
+
onConnected: (connected) => {
|
|
24742
|
+
setAttachedShell({
|
|
24743
|
+
shellId: message.shellId,
|
|
24744
|
+
viewerId: connected.viewerId
|
|
24745
|
+
});
|
|
24746
|
+
send({
|
|
24747
|
+
type: "shell.connected",
|
|
24748
|
+
shellId: message.shellId,
|
|
24749
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24750
|
+
payload: {
|
|
24751
|
+
viewerId: connected.viewerId
|
|
24752
|
+
}
|
|
24753
|
+
});
|
|
24754
|
+
send({
|
|
24755
|
+
type: "shell.status",
|
|
24756
|
+
shellId: message.shellId,
|
|
24757
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24758
|
+
payload: {
|
|
24759
|
+
threadId: connected.shell.threadId,
|
|
24760
|
+
state: "attached",
|
|
24761
|
+
viewerId: connected.viewerId
|
|
24762
|
+
}
|
|
24763
|
+
});
|
|
24764
|
+
},
|
|
24765
|
+
onData: (data, options) => {
|
|
24766
|
+
send({
|
|
24767
|
+
type: "shell.output",
|
|
24768
|
+
shellId: message.shellId,
|
|
24769
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24770
|
+
payload: {
|
|
24771
|
+
data,
|
|
24772
|
+
...options?.replace ? { replace: true } : {},
|
|
24773
|
+
...options?.cursorX !== void 0 ? { cursorX: options.cursorX } : {},
|
|
24774
|
+
...options?.cursorY !== void 0 ? { cursorY: options.cursorY } : {},
|
|
24775
|
+
...options?.paneHeight !== void 0 ? { paneHeight: options.paneHeight } : {},
|
|
24776
|
+
...options?.cwdBaseName !== void 0 ? { cwdBaseName: options.cwdBaseName } : {},
|
|
24777
|
+
...options?.envPrefix !== void 0 ? { envPrefix: options.envPrefix } : {},
|
|
24778
|
+
...options?.isCommandRunning !== void 0 ? { isCommandRunning: options.isCommandRunning } : {}
|
|
24779
|
+
}
|
|
24780
|
+
});
|
|
24781
|
+
}
|
|
24782
|
+
});
|
|
24783
|
+
if (!getAttachedShell()) {
|
|
24784
|
+
setAttachedShell({
|
|
24785
|
+
shellId: message.shellId,
|
|
24786
|
+
viewerId: attachment.viewerId
|
|
24787
|
+
});
|
|
24788
|
+
}
|
|
24789
|
+
if (context.state.get(cleanupRegisteredKey) !== true) {
|
|
24790
|
+
context.state.set(cleanupRegisteredKey, true);
|
|
24791
|
+
context.onClose(() => {
|
|
24792
|
+
const attached = getAttachedShell();
|
|
24793
|
+
if (attached) {
|
|
24794
|
+
void shellService.detachShell(attached.shellId, attached.viewerId).catch(() => {
|
|
24795
|
+
});
|
|
24796
|
+
setAttachedShell(null);
|
|
24797
|
+
}
|
|
24798
|
+
});
|
|
24799
|
+
}
|
|
24800
|
+
return true;
|
|
24801
|
+
}
|
|
24802
|
+
if (message.type === "shell.detach") {
|
|
24803
|
+
requireTerminalPluginEnabled(app2);
|
|
24804
|
+
await shellService.detachShell(message.shellId, message.viewerId);
|
|
24805
|
+
const attachedShell = getAttachedShell();
|
|
24806
|
+
if (attachedShell?.shellId === message.shellId && attachedShell.viewerId === message.viewerId) {
|
|
24807
|
+
setAttachedShell(null);
|
|
24808
|
+
}
|
|
24809
|
+
return true;
|
|
24810
|
+
}
|
|
24811
|
+
if (message.type === "shell.input") {
|
|
24812
|
+
requireTerminalPluginEnabled(app2);
|
|
24813
|
+
await shellService.sendInput(
|
|
24814
|
+
message.shellId,
|
|
24815
|
+
message.viewerId,
|
|
24816
|
+
message.data
|
|
24817
|
+
);
|
|
24818
|
+
return true;
|
|
24819
|
+
}
|
|
24820
|
+
if (message.type === "shell.resize") {
|
|
24821
|
+
requireTerminalPluginEnabled(app2);
|
|
24822
|
+
await shellService.resizeShell(
|
|
24823
|
+
message.shellId,
|
|
24824
|
+
message.viewerId,
|
|
24825
|
+
message.cols,
|
|
24826
|
+
message.rows
|
|
24827
|
+
);
|
|
24828
|
+
return true;
|
|
24829
|
+
}
|
|
24830
|
+
if (message.type === "shell.clear") {
|
|
24831
|
+
requireTerminalPluginEnabled(app2);
|
|
24832
|
+
await shellService.clearShell(message.shellId, message.viewerId);
|
|
24833
|
+
return true;
|
|
24834
|
+
}
|
|
24835
|
+
return false;
|
|
24836
|
+
} catch (error) {
|
|
24837
|
+
if ("shellId" in message) {
|
|
24838
|
+
send(makeShellErrorEnvelope(message.shellId, error));
|
|
24839
|
+
return true;
|
|
24840
|
+
}
|
|
24841
|
+
throw error;
|
|
23282
24842
|
}
|
|
24843
|
+
};
|
|
24844
|
+
}
|
|
24845
|
+
function makeShellErrorEnvelope(shellId, error) {
|
|
24846
|
+
if (error instanceof ShellServiceError) {
|
|
24847
|
+
return {
|
|
24848
|
+
type: "shell.error",
|
|
24849
|
+
shellId,
|
|
24850
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24851
|
+
payload: {
|
|
24852
|
+
code: error.code,
|
|
24853
|
+
message: error.message
|
|
24854
|
+
}
|
|
24855
|
+
};
|
|
23283
24856
|
}
|
|
23284
|
-
|
|
23285
|
-
|
|
23286
|
-
|
|
23287
|
-
|
|
23288
|
-
|
|
23289
|
-
|
|
23290
|
-
|
|
23291
|
-
|
|
23292
|
-
|
|
23293
|
-
|
|
23294
|
-
};
|
|
24857
|
+
return {
|
|
24858
|
+
type: "shell.error",
|
|
24859
|
+
shellId,
|
|
24860
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24861
|
+
payload: {
|
|
24862
|
+
code: "unknown",
|
|
24863
|
+
message: error instanceof Error ? error.message : "Unexpected shell error."
|
|
24864
|
+
}
|
|
24865
|
+
};
|
|
24866
|
+
}
|
|
23295
24867
|
|
|
23296
24868
|
// src/app.ts
|
|
23297
24869
|
var MAX_PROMPT_ATTACHMENTS2 = 10;
|
|
@@ -23307,16 +24879,16 @@ var HttpError = class extends Error {
|
|
|
23307
24879
|
};
|
|
23308
24880
|
function findRepoRoot(start = process.cwd()) {
|
|
23309
24881
|
if (process.env.REMOTE_CODEX_REPO_ROOT) {
|
|
23310
|
-
return
|
|
24882
|
+
return path23.resolve(process.env.REMOTE_CODEX_REPO_ROOT);
|
|
23311
24883
|
}
|
|
23312
|
-
let current =
|
|
23313
|
-
while (current !==
|
|
23314
|
-
if (
|
|
24884
|
+
let current = path23.resolve(start);
|
|
24885
|
+
while (current !== path23.dirname(current)) {
|
|
24886
|
+
if (fs24.existsSync(path23.join(current, "pnpm-workspace.yaml")) && fs24.existsSync(path23.join(current, "scripts", "service-restart.mjs"))) {
|
|
23315
24887
|
return current;
|
|
23316
24888
|
}
|
|
23317
|
-
current =
|
|
24889
|
+
current = path23.dirname(current);
|
|
23318
24890
|
}
|
|
23319
|
-
return
|
|
24891
|
+
return path23.resolve(process.cwd());
|
|
23320
24892
|
}
|
|
23321
24893
|
function createServiceLifecycle() {
|
|
23322
24894
|
return {
|
|
@@ -23328,14 +24900,14 @@ function createServiceLifecycle() {
|
|
|
23328
24900
|
});
|
|
23329
24901
|
}
|
|
23330
24902
|
const repoRoot = findRepoRoot();
|
|
23331
|
-
const restartScript =
|
|
23332
|
-
if (!
|
|
24903
|
+
const restartScript = path23.join(repoRoot, "scripts", "service-restart.mjs");
|
|
24904
|
+
if (!fs24.existsSync(restartScript) || !fs24.existsSync(path23.join(repoRoot, "pnpm-workspace.yaml"))) {
|
|
23333
24905
|
throw new HttpError(503, {
|
|
23334
24906
|
code: "service_unavailable",
|
|
23335
24907
|
message: "Build and restart requires a Remote Codex source checkout. Set REMOTE_CODEX_REPO_ROOT to the checkout path, or update the npm package with npm install -g remote-codex@latest."
|
|
23336
24908
|
});
|
|
23337
24909
|
}
|
|
23338
|
-
const child =
|
|
24910
|
+
const child = spawn5(process.execPath, [restartScript, "launch"], {
|
|
23339
24911
|
cwd: repoRoot,
|
|
23340
24912
|
detached: true,
|
|
23341
24913
|
env: process.env,
|
|
@@ -23356,6 +24928,7 @@ function buildApp(options = {}) {
|
|
|
23356
24928
|
const pluginSettingsStore = new PluginSettingsStore(database.db);
|
|
23357
24929
|
const pluginService = new PluginService(pluginRegistry, pluginSettingsStore);
|
|
23358
24930
|
const runtimeBootstrap = options.runtimeBootstrap ?? createAgentRuntimeBootstrap(config);
|
|
24931
|
+
const repoRoot = findRepoRoot();
|
|
23359
24932
|
const agentRuntimes = options.agentRuntimes ?? runtimeBootstrap.agentRuntimes;
|
|
23360
24933
|
const threadService = new ThreadService(
|
|
23361
24934
|
database.db,
|
|
@@ -23366,7 +24939,11 @@ function buildApp(options = {}) {
|
|
|
23366
24939
|
runtimeBootstrap.codexManagement,
|
|
23367
24940
|
pluginService
|
|
23368
24941
|
);
|
|
23369
|
-
const shellService = options.shellService ?? new ShellSessionService(
|
|
24942
|
+
const shellService = options.shellService ?? new ShellSessionService(
|
|
24943
|
+
database.db,
|
|
24944
|
+
eventBus,
|
|
24945
|
+
createTerminalShellBackend(options.env)
|
|
24946
|
+
);
|
|
23370
24947
|
const providerHostConfigService = new ProviderHostConfigService(
|
|
23371
24948
|
agentRuntimes,
|
|
23372
24949
|
runtimeBootstrap.providerHostHomes
|
|
@@ -23393,8 +24970,11 @@ function buildApp(options = {}) {
|
|
|
23393
24970
|
shellService,
|
|
23394
24971
|
providerHostConfigService,
|
|
23395
24972
|
pluginRegistry,
|
|
23396
|
-
pluginService
|
|
24973
|
+
pluginService,
|
|
24974
|
+
repoRoot
|
|
23397
24975
|
});
|
|
24976
|
+
const backendPluginHost = new BackendPluginHost(app2);
|
|
24977
|
+
backendPluginHost.register(createTerminalPluginBackendContribution());
|
|
23398
24978
|
app2.register(async (realtimeApp) => {
|
|
23399
24979
|
await realtimeApp.register(websocket);
|
|
23400
24980
|
realtimeApp.route({
|
|
@@ -23407,7 +24987,11 @@ function buildApp(options = {}) {
|
|
|
23407
24987
|
});
|
|
23408
24988
|
},
|
|
23409
24989
|
wsHandler: (socket) => {
|
|
23410
|
-
|
|
24990
|
+
const closeHandlers = [];
|
|
24991
|
+
const socketState = /* @__PURE__ */ new Map();
|
|
24992
|
+
const onClose = (handler) => {
|
|
24993
|
+
closeHandlers.push(handler);
|
|
24994
|
+
};
|
|
23411
24995
|
function send(message) {
|
|
23412
24996
|
if (socket.readyState === 1) {
|
|
23413
24997
|
socket.send(JSON.stringify(message));
|
|
@@ -23431,49 +25015,6 @@ function buildApp(options = {}) {
|
|
|
23431
25015
|
return;
|
|
23432
25016
|
}
|
|
23433
25017
|
try {
|
|
23434
|
-
if (parsed.type === "shell.attach") {
|
|
23435
|
-
if (attachedShell && attachedShell.shellId !== parsed.shellId) {
|
|
23436
|
-
await shellService.detachShell(
|
|
23437
|
-
attachedShell.shellId,
|
|
23438
|
-
attachedShell.viewerId
|
|
23439
|
-
);
|
|
23440
|
-
attachedShell = null;
|
|
23441
|
-
}
|
|
23442
|
-
const attachment = await shellService.attachShell(parsed.shellId, {
|
|
23443
|
-
cols: parsed.cols,
|
|
23444
|
-
rows: parsed.rows,
|
|
23445
|
-
onData: (data, options2) => {
|
|
23446
|
-
send({
|
|
23447
|
-
type: "shell.output",
|
|
23448
|
-
shellId: parsed.shellId,
|
|
23449
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
23450
|
-
payload: {
|
|
23451
|
-
data,
|
|
23452
|
-
...options2?.replace ? { replace: true } : {},
|
|
23453
|
-
...options2?.cursorX !== void 0 ? { cursorX: options2.cursorX } : {},
|
|
23454
|
-
...options2?.cursorY !== void 0 ? { cursorY: options2.cursorY } : {},
|
|
23455
|
-
...options2?.paneHeight !== void 0 ? { paneHeight: options2.paneHeight } : {},
|
|
23456
|
-
...options2?.cwdBaseName !== void 0 ? { cwdBaseName: options2.cwdBaseName } : {},
|
|
23457
|
-
...options2?.envPrefix !== void 0 ? { envPrefix: options2.envPrefix } : {},
|
|
23458
|
-
...options2?.isCommandRunning !== void 0 ? { isCommandRunning: options2.isCommandRunning } : {}
|
|
23459
|
-
}
|
|
23460
|
-
});
|
|
23461
|
-
}
|
|
23462
|
-
});
|
|
23463
|
-
attachedShell = {
|
|
23464
|
-
shellId: parsed.shellId,
|
|
23465
|
-
viewerId: attachment.viewerId
|
|
23466
|
-
};
|
|
23467
|
-
send({
|
|
23468
|
-
type: "shell.connected",
|
|
23469
|
-
shellId: parsed.shellId,
|
|
23470
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
23471
|
-
payload: {
|
|
23472
|
-
viewerId: attachment.viewerId
|
|
23473
|
-
}
|
|
23474
|
-
});
|
|
23475
|
-
return;
|
|
23476
|
-
}
|
|
23477
25018
|
if (parsed.type === "supervisor.ping") {
|
|
23478
25019
|
send({
|
|
23479
25020
|
type: "supervisor.pong",
|
|
@@ -23484,47 +25025,23 @@ function buildApp(options = {}) {
|
|
|
23484
25025
|
});
|
|
23485
25026
|
return;
|
|
23486
25027
|
}
|
|
23487
|
-
|
|
23488
|
-
|
|
23489
|
-
|
|
23490
|
-
|
|
23491
|
-
|
|
23492
|
-
|
|
23493
|
-
}
|
|
23494
|
-
if (
|
|
23495
|
-
await shellService.sendInput(
|
|
23496
|
-
parsed.shellId,
|
|
23497
|
-
parsed.viewerId,
|
|
23498
|
-
parsed.data
|
|
23499
|
-
);
|
|
23500
|
-
return;
|
|
23501
|
-
}
|
|
23502
|
-
if (parsed.type === "shell.resize") {
|
|
23503
|
-
await shellService.resizeShell(
|
|
23504
|
-
parsed.shellId,
|
|
23505
|
-
parsed.viewerId,
|
|
23506
|
-
parsed.cols,
|
|
23507
|
-
parsed.rows
|
|
23508
|
-
);
|
|
25028
|
+
const handled = await backendPluginHost.handleSocketMessage({
|
|
25029
|
+
app: app2,
|
|
25030
|
+
send,
|
|
25031
|
+
onClose,
|
|
25032
|
+
state: socketState,
|
|
25033
|
+
message: parsed
|
|
25034
|
+
});
|
|
25035
|
+
if (!handled) {
|
|
23509
25036
|
return;
|
|
23510
25037
|
}
|
|
23511
|
-
|
|
23512
|
-
|
|
23513
|
-
}
|
|
23514
|
-
} catch (error) {
|
|
23515
|
-
if ("shellId" in parsed) {
|
|
23516
|
-
send(makeShellErrorEnvelope(parsed.shellId, error));
|
|
23517
|
-
}
|
|
25038
|
+
} catch {
|
|
25039
|
+
return;
|
|
23518
25040
|
}
|
|
23519
25041
|
});
|
|
23520
25042
|
socket.on("close", () => {
|
|
23521
|
-
|
|
23522
|
-
|
|
23523
|
-
attachedShell.shellId,
|
|
23524
|
-
attachedShell.viewerId
|
|
23525
|
-
).catch(() => {
|
|
23526
|
-
});
|
|
23527
|
-
attachedShell = null;
|
|
25043
|
+
for (const handler of closeHandlers.splice(0)) {
|
|
25044
|
+
handler();
|
|
23528
25045
|
}
|
|
23529
25046
|
unsubscribe();
|
|
23530
25047
|
unsubscribeShell();
|
|
@@ -23534,7 +25051,6 @@ function buildApp(options = {}) {
|
|
|
23534
25051
|
});
|
|
23535
25052
|
app2.register(registerSystemRoutes);
|
|
23536
25053
|
app2.register(registerAgentRuntimeRoutes);
|
|
23537
|
-
app2.register(registerShellRoutes);
|
|
23538
25054
|
app2.register(registerPluginRoutes);
|
|
23539
25055
|
app2.register(registerThreadRoutes);
|
|
23540
25056
|
app2.register(registerWorkspaceRoutes);
|
|
@@ -23576,7 +25092,7 @@ function buildApp(options = {}) {
|
|
|
23576
25092
|
return;
|
|
23577
25093
|
}
|
|
23578
25094
|
if (error instanceof ShellServiceError) {
|
|
23579
|
-
const statusCode = error.code === "thread_not_found" || error.code === "shell_not_found" ? 404 : error.code === "viewer_conflict" || error.code === "thread_not_connected" || error.code === "shell_exists" || error.code === "workspace_missing" || error.code === "shell_not_running" || error.code === "viewer_not_attached" || error.code === "invalid_viewer" ? 409 : 503;
|
|
25095
|
+
const statusCode = error.code === "thread_not_found" || error.code === "shell_not_found" ? 404 : error.code === "viewer_conflict" || error.code === "thread_not_connected" || error.code === "shell_exists" || error.code === "workspace_missing" || error.code === "shell_not_running" || error.code === "viewer_not_attached" || error.code === "invalid_viewer" || error.code === "plugin_disabled" ? 409 : 503;
|
|
23580
25096
|
reply.status(statusCode).send({
|
|
23581
25097
|
code: statusCode === 404 ? "not_found" : statusCode === 409 ? "conflict" : "service_unavailable",
|
|
23582
25098
|
message: error.message,
|
|
@@ -23646,6 +25162,10 @@ function buildApp(options = {}) {
|
|
|
23646
25162
|
});
|
|
23647
25163
|
app2.addHook("onReady", async () => {
|
|
23648
25164
|
try {
|
|
25165
|
+
await pluginService.syncManagedCodexMcpConfig({
|
|
25166
|
+
codexHome: runtimeBootstrap.providerHostHomes.codex ?? null,
|
|
25167
|
+
repoRoot
|
|
25168
|
+
});
|
|
23649
25169
|
await Promise.all(agentRuntimes.all().map((runtime) => runtime.start()));
|
|
23650
25170
|
await shellService.syncShellStateOnStartup();
|
|
23651
25171
|
} catch (error) {
|
|
@@ -23661,31 +25181,9 @@ function requestLog(app2, error) {
|
|
|
23661
25181
|
}
|
|
23662
25182
|
app2.log.error({ error }, "Non-error value reached Fastify error handler.");
|
|
23663
25183
|
}
|
|
23664
|
-
function makeShellErrorEnvelope(shellId, error) {
|
|
23665
|
-
if (error instanceof ShellServiceError) {
|
|
23666
|
-
return {
|
|
23667
|
-
type: "shell.error",
|
|
23668
|
-
shellId,
|
|
23669
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
23670
|
-
payload: {
|
|
23671
|
-
code: error.code,
|
|
23672
|
-
message: error.message
|
|
23673
|
-
}
|
|
23674
|
-
};
|
|
23675
|
-
}
|
|
23676
|
-
return {
|
|
23677
|
-
type: "shell.error",
|
|
23678
|
-
shellId,
|
|
23679
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
23680
|
-
payload: {
|
|
23681
|
-
code: "unknown",
|
|
23682
|
-
message: error instanceof Error ? error.message : "Unexpected shell error."
|
|
23683
|
-
}
|
|
23684
|
-
};
|
|
23685
|
-
}
|
|
23686
25184
|
|
|
23687
25185
|
// src/index.ts
|
|
23688
|
-
if (
|
|
25186
|
+
if (fs25.existsSync(".env")) {
|
|
23689
25187
|
process.loadEnvFile?.(".env");
|
|
23690
25188
|
}
|
|
23691
25189
|
var app = buildApp();
|