@ai-projector/ide 0.0.0-stage → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +35 -2
- package/bin/install-desktop +17 -0
- package/bin/install-desktop.cmd +11 -0
- package/bin/projector +22 -0
- package/bin/projector.cmd +11 -0
- package/dist/assets/CodeViewer--WUSmn5i.css +1 -0
- package/dist/assets/CodeViewer-C-C3aibO.js +1 -0
- package/dist/assets/DiscussionView-Cd3exhWx.css +1 -0
- package/dist/assets/DiscussionView-K3YyWE-E.js +2 -0
- package/dist/assets/EditorSettings-DlzJc8cp.js +13 -0
- package/dist/assets/EditorSettings-jSngmpPq.css +1 -0
- package/dist/assets/HtmlViewer-DULKK0_6.js +2 -0
- package/dist/assets/HtmlViewer-XHn9rACG.css +1 -0
- package/dist/assets/ImageViewport-BT_ftU4z.js +1 -0
- package/dist/assets/ImageViewport-JcG9P4B6.css +1 -0
- package/dist/assets/IssueView-ChJFmrTW.js +1 -0
- package/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/assets/MarkdownViewer-C646XbYf.css +1 -0
- package/dist/assets/MarkdownViewer-Dm2MVp3X.js +2 -0
- package/dist/assets/PullRequestView-Cipn5P0H.js +3 -0
- package/dist/assets/PullRequestView-CzZn9mOg.css +1 -0
- package/dist/assets/ReleaseView-Cz6dH4ej.js +2 -0
- package/dist/assets/ReleaseView-VLO9NVfI.css +1 -0
- package/dist/assets/SplitPanes-0-UT7ksm.css +1 -0
- package/dist/assets/SplitPanes-DNDTWIta.js +1 -0
- package/dist/assets/SvgViewer-DP6-1_fw.css +1 -0
- package/dist/assets/SvgViewer-DkoULP8F.js +2 -0
- package/dist/assets/TerminalView-C30_q784.css +1 -0
- package/dist/assets/TerminalView-fWmIbnZn.js +16 -0
- package/dist/assets/TrackerDetail-CBaLycQg.css +1 -0
- package/dist/assets/TrackerDetail-DuzfEwSZ.js +1 -0
- package/dist/assets/UiButton-AkN01P3P.css +1 -0
- package/dist/assets/UiButton-DvucBdmd.js +2 -0
- package/dist/assets/UiPanel-BUDYIo-h.css +1 -0
- package/dist/assets/UiPanel-DtI4DFYT.js +1 -0
- package/dist/assets/UiViewerPage-CMFEzZ2i.css +1 -0
- package/dist/assets/UiViewerPage-aHNgiSjO.js +2 -0
- package/dist/assets/VisualMarkdownEditor-1DNSAYyq.css +1 -0
- package/dist/assets/VisualMarkdownEditor-BHx2olWh.js +1070 -0
- package/dist/assets/_plugin-vue_export-helper-D62Ebo7D.js +3 -0
- package/dist/assets/apl-gfMMiTNf.js +1 -0
- package/dist/assets/asciiarmor-C_eisQCp.js +1 -0
- package/dist/assets/asn1-DCl_8MCW.js +1 -0
- package/dist/assets/asterisk-BEn0Cwpx.js +1 -0
- package/dist/assets/brainfuck-D5EjA2JK.js +1 -0
- package/dist/assets/clike-xvONpD0Z.js +1 -0
- package/dist/assets/clojure-BflJGmDX.js +1 -0
- package/dist/assets/cmake-84nbDH0I.js +1 -0
- package/dist/assets/cobol-DHLQUbN7.js +1 -0
- package/dist/assets/coffeescript-De_zI4J0.js +1 -0
- package/dist/assets/commonlisp-DgAKBe0r.js +1 -0
- package/dist/assets/compiler-dom.esm-bundler-C5a_rSi1.js +9 -0
- package/dist/assets/crystal-Bl6YKCG_.js +1 -0
- package/dist/assets/css-CnaYoQib.js +1 -0
- package/dist/assets/cypher-p9eYesGn.js +1 -0
- package/dist/assets/d-DWkQyNnU.js +1 -0
- package/dist/assets/diff-ChtP43wD.js +1 -0
- package/dist/assets/dist-23D313r2.js +13 -0
- package/dist/assets/dist-9YLT-RM-.js +11 -0
- package/dist/assets/dist-9guQ6tUS.js +1 -0
- package/dist/assets/dist-BA_HKdx1.js +2 -0
- package/dist/assets/dist-BMX-4S0G.js +1 -0
- package/dist/assets/dist-BQmIGtmd.js +6 -0
- package/dist/assets/dist-BVEl6uFx.js +1 -0
- package/dist/assets/dist-BuiJgwGF.js +9 -0
- package/dist/assets/dist-Bzl1vuDO.js +1 -0
- package/dist/assets/dist-C1mn-4rn.js +1 -0
- package/dist/assets/dist-CG79NjMk.js +1 -0
- package/dist/assets/dist-CRLdLpSX.js +2 -0
- package/dist/assets/dist-Coak6JQD.js +1 -0
- package/dist/assets/dist-CpgyHBvu.js +1 -0
- package/dist/assets/dist-CrRIwgTS.js +1 -0
- package/dist/assets/dist-Cu_4z-jQ.js +1 -0
- package/dist/assets/dist-CxoUUhWx.js +1 -0
- package/dist/assets/dist-CzOhSFRQ.js +1 -0
- package/dist/assets/dist-DN5Y0OA5.js +1 -0
- package/dist/assets/dist-Dqsd8MyB.js +1 -0
- package/dist/assets/dist-Dvv0YQ-H.js +23 -0
- package/dist/assets/dist-DzoDV6Eh.js +2 -0
- package/dist/assets/dist-NMUsQt1c.js +1 -0
- package/dist/assets/dist-ZRLBgDFY.js +1 -0
- package/dist/assets/dist-cLGxPfRN.js +1 -0
- package/dist/assets/dist-p1Xy77w3.js +1 -0
- package/dist/assets/dockerfile-DJkHQgkl.js +1 -0
- package/dist/assets/dtd-DTF72YNO.js +1 -0
- package/dist/assets/dylan-S7ucR4pR.js +1 -0
- package/dist/assets/ebnf-D4c0_ac3.js +1 -0
- package/dist/assets/ecl-BVIeWmwY.js +1 -0
- package/dist/assets/editor-theme-ClBxXjSu.js +1 -0
- package/dist/assets/eiffel-BEjRio4Q.js +1 -0
- package/dist/assets/elm-Cshzl8qu.js +1 -0
- package/dist/assets/erlang-BV0c4Hdn.js +1 -0
- package/dist/assets/events.worker-C2Opu9Sc.js +1 -0
- package/dist/assets/external-link-lkcxItwM.js +1 -0
- package/dist/assets/factor-LKH5gN8L.js +1 -0
- package/dist/assets/fcl-ClOhbFR7.js +1 -0
- package/dist/assets/forth-D6RzAl64.js +1 -0
- package/dist/assets/fortran-Bt6PBEDR.js +1 -0
- package/dist/assets/gas-BHEdbvp9.js +1 -0
- package/dist/assets/gherkin-oBAE_ms0.js +1 -0
- package/dist/assets/github-emoji-CXJ5RSZS.js +169 -0
- package/dist/assets/github-emoji-D8dkjuM_.css +1 -0
- package/dist/assets/groovy-CUrWKPia.js +1 -0
- package/dist/assets/haskell-BRsoo5mP.js +1 -0
- package/dist/assets/haxe-DjVOVvNP.js +1 -0
- package/dist/assets/http-CLVgA2GD.js +1 -0
- package/dist/assets/hub-DfPcTPCC.js +1 -0
- package/dist/assets/idl-BUZw3wgd.js +1 -0
- package/dist/assets/javascript-lS2r2ifg.js +1 -0
- package/dist/assets/julia-CQfgDRfP.js +1 -0
- package/dist/assets/livescript-BXxG0Yva.js +1 -0
- package/dist/assets/lua-DPCEkfD_.js +1 -0
- package/dist/assets/main-JoBAi6ol.css +1 -0
- package/dist/assets/main-iz4ud0jC.js +178 -0
- package/dist/assets/mathematica-u8YMmbU0.js +1 -0
- package/dist/assets/mbox-BEMVcqjs.js +1 -0
- package/dist/assets/mirc-C9zpzAZU.js +1 -0
- package/dist/assets/mllike-B45xgp2S.js +1 -0
- package/dist/assets/modelica-CqHI_q-D.js +1 -0
- package/dist/assets/mscgen-qgSLujhx.js +1 -0
- package/dist/assets/mumps-BSzj6Xyz.js +1 -0
- package/dist/assets/nginx-C-ORUuei.js +1 -0
- package/dist/assets/nsis-viPvXFiq.js +1 -0
- package/dist/assets/ntriples-CzMBulkp.js +1 -0
- package/dist/assets/octave-D2Q8cUp1.js +1 -0
- package/dist/assets/oz-BwTct_5T.js +1 -0
- package/dist/assets/pascal-Dp_KdFgX.js +1 -0
- package/dist/assets/perl-BkSkiI9m.js +1 -0
- package/dist/assets/pig-AF4Hwhju.js +1 -0
- package/dist/assets/powershell-D8WpQPaX.js +1 -0
- package/dist/assets/preload-helper-BLdHbfdN.js +1 -0
- package/dist/assets/properties-C357ku5U.js +1 -0
- package/dist/assets/protobuf-D1ij_kNL.js +1 -0
- package/dist/assets/pug-BqCHZ5xT.js +1 -0
- package/dist/assets/puppet-BZyAS7I4.js +1 -0
- package/dist/assets/python-B_1Jd8HM.js +1 -0
- package/dist/assets/q-B9NhS7L_.js +1 -0
- package/dist/assets/r-CxDmU1I4.js +1 -0
- package/dist/assets/rolldown-runtime-XKyaHtl9.js +1 -0
- package/dist/assets/rpm-gpDK5sbt.js +1 -0
- package/dist/assets/ruby-ChfNwlCY.js +1 -0
- package/dist/assets/sas-C2OyD2Y6.js +1 -0
- package/dist/assets/scheme-D9qYN0V5.js +1 -0
- package/dist/assets/shared.esm-bundler-DoSbGLUP.js +2 -0
- package/dist/assets/shared.worker-DpKROrNH.js +1 -0
- package/dist/assets/shell-DwuoZtxw.js +1 -0
- package/dist/assets/sieve-tLWDfEkZ.js +1 -0
- package/dist/assets/simple-mode-DXiLM1-G.js +1 -0
- package/dist/assets/smalltalk-BLp5-jwC.js +1 -0
- package/dist/assets/solr-B78wSQJQ.js +1 -0
- package/dist/assets/sparql-Dz-mlCAC.js +1 -0
- package/dist/assets/spreadsheet-CTIncYxj.js +1 -0
- package/dist/assets/sql-DuQMFDvy.js +1 -0
- package/dist/assets/stex-DNzd62Q_.js +1 -0
- package/dist/assets/styles-CCXo2OoQ.css +1 -0
- package/dist/assets/styles-DZDDPlL3.js +1 -0
- package/dist/assets/stylus-BOVgKnng.js +1 -0
- package/dist/assets/swift-DKB6_1j6.js +1 -0
- package/dist/assets/tcl-BGfruO1u.js +1 -0
- package/dist/assets/textile-C4jVoHG1.js +1 -0
- package/dist/assets/tiddlywiki-VlUiK86J.js +1 -0
- package/dist/assets/tiki-CvUEFusT.js +1 -0
- package/dist/assets/toml-BPTmHmyx.js +1 -0
- package/dist/assets/troff-C2dAgh7P.js +1 -0
- package/dist/assets/ttcn-PPSTk1ow.js +1 -0
- package/dist/assets/ttcn-cfg-2b4Gb5sE.js +1 -0
- package/dist/assets/turtle-Cx3rYX2g.js +1 -0
- package/dist/assets/vb-BthdM_4N.js +1 -0
- package/dist/assets/vbscript-D9f6rSsU.js +1 -0
- package/dist/assets/velocity-CqftRsjg.js +1 -0
- package/dist/assets/verilog-CjI9Y6RI.js +1 -0
- package/dist/assets/vhdl-kS471soi.js +1 -0
- package/dist/assets/webidl-D5jiJvOU.js +1 -0
- package/dist/assets/xquery-BKJx4mf9.js +1 -0
- package/dist/assets/yacas-CXXgtw0p.js +1 -0
- package/dist/assets/z80-Co3PbHdE.js +1 -0
- package/dist/favicon.svg +5 -0
- package/dist/file-icons/LICENSE-lucide.txt +43 -0
- package/dist/file-icons/NOTICE.md +8 -0
- package/dist/file-icons/icons/archive.svg +1 -0
- package/dist/file-icons/icons/assets.svg +1 -0
- package/dist/file-icons/icons/audio.svg +1 -0
- package/dist/file-icons/icons/c.svg +1 -0
- package/dist/file-icons/icons/components.svg +1 -0
- package/dist/file-icons/icons/config.svg +1 -0
- package/dist/file-icons/icons/cpp.svg +1 -0
- package/dist/file-icons/icons/css.svg +1 -0
- package/dist/file-icons/icons/database.svg +1 -0
- package/dist/file-icons/icons/docker.svg +1 -0
- package/dist/file-icons/icons/env.svg +1 -0
- package/dist/file-icons/icons/executable.svg +1 -0
- package/dist/file-icons/icons/file.svg +1 -0
- package/dist/file-icons/icons/folder-open.svg +1 -0
- package/dist/file-icons/icons/folder.svg +1 -0
- package/dist/file-icons/icons/font.svg +1 -0
- package/dist/file-icons/icons/git.svg +1 -0
- package/dist/file-icons/icons/go.svg +1 -0
- package/dist/file-icons/icons/graphql.svg +1 -0
- package/dist/file-icons/icons/html.svg +1 -0
- package/dist/file-icons/icons/ignore.svg +1 -0
- package/dist/file-icons/icons/image.svg +1 -0
- package/dist/file-icons/icons/java.svg +1 -0
- package/dist/file-icons/icons/javascript.svg +1 -0
- package/dist/file-icons/icons/json.svg +1 -0
- package/dist/file-icons/icons/kotlin.svg +1 -0
- package/dist/file-icons/icons/license.svg +1 -0
- package/dist/file-icons/icons/lock.svg +1 -0
- package/dist/file-icons/icons/markdown.svg +1 -0
- package/dist/file-icons/icons/package.svg +1 -0
- package/dist/file-icons/icons/php.svg +1 -0
- package/dist/file-icons/icons/python.svg +1 -0
- package/dist/file-icons/icons/react.svg +1 -0
- package/dist/file-icons/icons/ruby.svg +1 -0
- package/dist/file-icons/icons/rust.svg +1 -0
- package/dist/file-icons/icons/sass.svg +1 -0
- package/dist/file-icons/icons/shell.svg +1 -0
- package/dist/file-icons/icons/source.svg +1 -0
- package/dist/file-icons/icons/svelte.svg +1 -0
- package/dist/file-icons/icons/swift.svg +1 -0
- package/dist/file-icons/icons/tests.svg +1 -0
- package/dist/file-icons/icons/toml.svg +1 -0
- package/dist/file-icons/icons/typescript.svg +1 -0
- package/dist/file-icons/icons/video.svg +1 -0
- package/dist/file-icons/icons/vite.svg +1 -0
- package/dist/file-icons/icons/vue.svg +1 -0
- package/dist/file-icons/icons/yaml.svg +1 -0
- package/dist/file-icons/theme.json +572 -0
- package/dist/file-icons/theme.schema.json +137 -0
- package/dist/github.svg +1 -0
- package/dist/gitlab.svg +1 -0
- package/dist/hub.html +21 -0
- package/dist/icons/apple-touch-icon.png +0 -0
- package/dist/icons/icon-192.png +0 -0
- package/dist/icons/icon-512.png +0 -0
- package/dist/icons/maskable-512.png +0 -0
- package/dist/index.html +42 -0
- package/dist/manifest.webmanifest +37 -0
- package/dist/sw.js +81 -0
- package/package.json +62 -4
- package/packages/cli/app/agent-host.js +163 -0
- package/packages/cli/app/desktop.js +77 -0
- package/packages/cli/app/fix-node-pty.js +52 -0
- package/packages/cli/app/import-companion-key.js +57 -0
- package/packages/cli/app/install-desktop.js +4 -0
- package/packages/cli/app/launch.js +134 -0
- package/packages/cli/app/restart.js +32 -0
- package/packages/cli/commands/logs.js +10 -0
- package/packages/cli/commands/open.js +49 -0
- package/packages/cli/commands/projects.js +18 -0
- package/packages/cli/commands/run.js +39 -0
- package/packages/cli/commands/search.js +19 -0
- package/packages/cli/commands/server.js +32 -0
- package/packages/cli/commands/status.js +42 -0
- package/packages/cli/common/output.js +13 -0
- package/packages/cli/modules/api/index.js +60 -0
- package/packages/cli/modules/arguments/index.js +188 -0
- package/packages/cli/modules/command-runtime/index.js +24 -0
- package/packages/cli/modules/projects/index.js +118 -0
- package/packages/cli/modules/server/index.js +226 -0
- package/packages/cli/modules/server-process/index.js +204 -0
- package/packages/core/modules/agent-features/index.js +8 -0
- package/packages/core/modules/agent-judge/index.js +73 -0
- package/packages/core/modules/agent-read/index.js +25 -0
- package/packages/core/modules/agent-role/index.js +187 -0
- package/packages/core/modules/agent-task/contract.js +34 -0
- package/packages/core/modules/agent-task/index.js +1 -0
- package/packages/core/modules/agent-widgets/bars/index.js +11 -0
- package/packages/core/modules/agent-widgets/button/index.js +19 -0
- package/packages/core/modules/agent-widgets/card/index.js +13 -0
- package/packages/core/modules/agent-widgets/checks/index.js +19 -0
- package/packages/core/modules/agent-widgets/chips/index.js +15 -0
- package/packages/core/modules/agent-widgets/columns/index.js +12 -0
- package/packages/core/modules/agent-widgets/donut/index.js +11 -0
- package/packages/core/modules/agent-widgets/field/index.js +39 -0
- package/packages/core/modules/agent-widgets/form/index.js +18 -0
- package/packages/core/modules/agent-widgets/git-info/index.js +29 -0
- package/packages/core/modules/agent-widgets/image/index.js +22 -0
- package/packages/core/modules/agent-widgets/inline-icon/index.js +45 -0
- package/packages/core/modules/agent-widgets/input/index.js +16 -0
- package/packages/core/modules/agent-widgets/intelligent-form/index.js +32 -0
- package/packages/core/modules/agent-widgets/line/index.js +12 -0
- package/packages/core/modules/agent-widgets/row/index.js +11 -0
- package/packages/core/modules/agent-widgets/safe-secret-show/index.js +21 -0
- package/packages/core/modules/agent-widgets/slider/index.js +18 -0
- package/packages/core/modules/agent-widgets/stat/index.js +16 -0
- package/packages/core/modules/agent-widgets/steps/index.js +14 -0
- package/packages/core/modules/agent-widgets/tab/index.js +12 -0
- package/packages/core/modules/agent-widgets/tabs/index.js +24 -0
- package/packages/core/modules/agents-integration/claude/index.js +1 -0
- package/packages/core/modules/agents-integration/codex/index.js +1 -0
- package/packages/core/modules/agents-integration/cursor/index.js +1 -0
- package/packages/core/modules/agents-integration/kimi/index.js +1 -0
- package/packages/core/modules/agents-integration/opencode/index.js +1 -0
- package/packages/core/modules/app-paths/index.js +14 -0
- package/packages/core/modules/app-paths/logs.js +194 -0
- package/packages/core/modules/app-paths/network-mode.js +24 -0
- package/packages/core/modules/app-paths/paths.js +40 -0
- package/packages/core/modules/app-paths/server-mode.js +18 -0
- package/packages/core/modules/appearance/index.js +35 -0
- package/packages/core/modules/browser/index.js +86 -0
- package/packages/core/modules/devcontainer/classify.js +101 -0
- package/packages/core/modules/devcontainer/contract.js +1 -0
- package/packages/core/modules/devcontainer/index.js +1 -0
- package/packages/core/modules/directories/contract.js +1 -0
- package/packages/core/modules/directories/index.js +1 -0
- package/packages/core/modules/docker/contract.js +1 -0
- package/packages/core/modules/docker/index.js +1 -0
- package/packages/core/modules/editor-themes/index.js +17 -0
- package/packages/core/modules/environment/index.js +1 -0
- package/packages/core/modules/file-icons/contract.js +177 -0
- package/packages/core/modules/file-icons/index.js +1 -0
- package/packages/core/modules/github/index.js +23 -0
- package/packages/core/modules/gitlab/index.js +164 -0
- package/packages/core/modules/hub/index.js +1 -0
- package/packages/core/modules/hub/protocol.js +19 -0
- package/packages/core/modules/ide/agent-command.js +48 -0
- package/packages/core/modules/ide/command-help.js +73 -0
- package/packages/core/modules/ide/commands.js +191 -0
- package/packages/core/modules/ide/index.js +6 -0
- package/packages/core/modules/ide/keybinding-editor.js +34 -0
- package/packages/core/modules/ide/keybindings.js +45 -0
- package/packages/core/modules/ide/palette.js +33 -0
- package/packages/core/modules/ide/safety.js +10 -0
- package/packages/core/modules/launcher/actions.js +5 -0
- package/packages/core/modules/launcher/index.js +5 -0
- package/packages/core/modules/launcher/launcher-model.js +236 -0
- package/packages/core/modules/launcher/launcher.js +76 -0
- package/packages/core/modules/launcher/query.js +42 -0
- package/packages/core/modules/network-mode/index.js +3 -0
- package/packages/core/modules/network-mode/network-mode.js +8 -0
- package/packages/core/modules/os/bash.js +11 -0
- package/packages/core/modules/os/contract.js +1 -0
- package/packages/core/modules/os/index.js +3 -0
- package/packages/core/modules/os/modules/darwin/catalog.js +108 -0
- package/packages/core/modules/os/modules/darwin/directories.js +40 -0
- package/packages/core/modules/os/modules/darwin/docker.js +15 -0
- package/packages/core/modules/os/modules/darwin/gtk.js +6 -0
- package/packages/core/modules/os/modules/darwin/helper.swift +172 -0
- package/packages/core/modules/os/modules/darwin/index.js +12 -0
- package/packages/core/modules/os/modules/darwin/install-desktop.js +135 -0
- package/packages/core/modules/os/modules/darwin/processes.js +97 -0
- package/packages/core/modules/os/modules/darwin/resident.js +235 -0
- package/packages/core/modules/os/modules/darwin/secrets.js +53 -0
- package/packages/core/modules/os/modules/darwin/shell.js +105 -0
- package/packages/core/modules/os/modules/darwin/shortcut.js +61 -0
- package/packages/core/modules/os/modules/darwin/tools.js +52 -0
- package/packages/core/modules/os/modules/darwin/windows.js +135 -0
- package/packages/core/modules/os/modules/linux/bus.js +48 -0
- package/packages/core/modules/os/modules/linux/catalog.js +47 -0
- package/packages/core/modules/os/modules/linux/directories.js +49 -0
- package/packages/core/modules/os/modules/linux/docker.js +48 -0
- package/packages/core/modules/os/modules/linux/index.js +53 -0
- package/packages/core/modules/os/modules/linux/install-desktop.js +66 -0
- package/packages/core/modules/os/modules/linux/processes.js +85 -0
- package/packages/core/modules/os/modules/linux/resident.js +139 -0
- package/packages/core/modules/os/modules/linux/secrets.js +118 -0
- package/packages/core/modules/os/modules/linux/shortcut.js +124 -0
- package/packages/core/modules/os/modules/linux/tools.js +14 -0
- package/packages/core/modules/os/modules/linux/tray.js +190 -0
- package/packages/core/modules/os/modules/linux/windows.js +187 -0
- package/packages/core/modules/os/modules/windows/agent-process.js +60 -0
- package/packages/core/modules/os/modules/windows/alert.js +20 -0
- package/packages/core/modules/os/modules/windows/catalog.js +91 -0
- package/packages/core/modules/os/modules/windows/color-scheme.js +26 -0
- package/packages/core/modules/os/modules/windows/directories.js +101 -0
- package/packages/core/modules/os/modules/windows/docker.js +17 -0
- package/packages/core/modules/os/modules/windows/git.js +42 -0
- package/packages/core/modules/os/modules/windows/hwnd.js +275 -0
- package/packages/core/modules/os/modules/windows/index.js +28 -0
- package/packages/core/modules/os/modules/windows/install-desktop.js +140 -0
- package/packages/core/modules/os/modules/windows/kill-tree.js +26 -0
- package/packages/core/modules/os/modules/windows/processes.js +300 -0
- package/packages/core/modules/os/modules/windows/ps.js +73 -0
- package/packages/core/modules/os/modules/windows/resident-pipe.js +206 -0
- package/packages/core/modules/os/modules/windows/resident.js +286 -0
- package/packages/core/modules/os/modules/windows/secrets.js +110 -0
- package/packages/core/modules/os/modules/windows/shell.js +288 -0
- package/packages/core/modules/os/modules/windows/shortcut.js +82 -0
- package/packages/core/modules/os/modules/windows/tools.js +273 -0
- package/packages/core/modules/os/modules/windows/windows.js +133 -0
- package/packages/core/modules/os/os.js +175 -0
- package/packages/core/modules/os/session-env.js +11 -0
- package/packages/core/modules/os-posix/agent-process.js +105 -0
- package/packages/core/modules/os-posix/contract.js +1 -0
- package/packages/core/modules/os-posix/git.js +26 -0
- package/packages/core/modules/os-posix/index.js +4 -0
- package/packages/core/modules/os-posix/tools.js +258 -0
- package/packages/core/modules/os-posix/xdg.js +8 -0
- package/packages/core/modules/project/contract.js +1 -0
- package/packages/core/modules/project/index.js +1 -0
- package/packages/core/modules/project/ref.js +126 -0
- package/packages/core/modules/server-mode/index.js +3 -0
- package/packages/core/modules/server-mode/server-mode.js +13 -0
- package/packages/core/modules/terminal/contract.js +1 -0
- package/packages/core/modules/terminal/index.js +1 -0
- package/packages/core/modules/usage-analytics/index.js +80 -0
- package/packages/core/modules/widget-catalog/guide.js +76 -0
- package/packages/core/modules/widget-catalog/index.js +219 -0
- package/packages/core/modules/workspace/changes.js +114 -0
- package/packages/core/modules/workspace/contract.js +1 -0
- package/packages/core/modules/workspace/file-size.js +12 -0
- package/packages/core/modules/workspace/files-exclude.js +119 -0
- package/packages/core/modules/workspace/git-decorations.js +4 -0
- package/packages/core/modules/workspace/git-graph.js +35 -0
- package/packages/core/modules/workspace/index.js +11 -0
- package/packages/core/modules/workspace/paths.js +16 -0
- package/packages/core/modules/workspace/pipeline-status.js +86 -0
- package/packages/core/modules/workspace/pull-requests.js +1 -0
- package/packages/core/modules/workspace/pull-status.js +56 -0
- package/packages/core/modules/workspace/scope.js +34 -0
- package/packages/core/modules/workspace/search.js +28 -0
- package/packages/core/modules/workspace/tree-page.js +25 -0
- package/packages/server/app/agents.js +30 -0
- package/packages/server/app/api.js +159 -0
- package/packages/server/app/claude-runner.js +17 -0
- package/packages/server/app/dev-plugin.js +76 -0
- package/packages/server/app/dev-runtime.js +119 -0
- package/packages/server/app/features.js +35 -0
- package/packages/server/app/plugin.js +140 -0
- package/packages/server/app/projector-runner.js +15 -0
- package/packages/server/app/runtime-contract.js +1 -0
- package/packages/server/app/standalone.js +42 -0
- package/packages/server/app/static.js +57 -0
- package/packages/server/app/widgets-mcp.js +36 -0
- package/packages/server/app/widgets.js +54 -0
- package/packages/server/middlewares/local-origin.js +4 -0
- package/packages/server/modules/access/access.js +118 -0
- package/packages/server/modules/access/connections.js +36 -0
- package/packages/server/modules/access/http.js +93 -0
- package/packages/server/modules/access/hub.js +19 -0
- package/packages/server/modules/access/index.js +6 -0
- package/packages/server/modules/access/lan-url.js +21 -0
- package/packages/server/modules/access/password.js +68 -0
- package/packages/server/modules/access/session.js +38 -0
- package/packages/server/modules/agent/agent-host.js +46 -0
- package/packages/server/modules/agent/agent-runs.js +162 -0
- package/packages/server/modules/agent/attachments.js +88 -0
- package/packages/server/modules/agent/backend.js +1 -0
- package/packages/server/modules/agent/chat-archive.js +67 -0
- package/packages/server/modules/agent/command-bridge.js +94 -0
- package/packages/server/modules/agent/controls.js +10 -0
- package/packages/server/modules/agent/event-streams.js +40 -0
- package/packages/server/modules/agent/history-store.js +320 -0
- package/packages/server/modules/agent/history.js +160 -0
- package/packages/server/modules/agent/hosted-process.js +279 -0
- package/packages/server/modules/agent/hosted-run.js +85 -0
- package/packages/server/modules/agent/hosted-runner.js +126 -0
- package/packages/server/modules/agent/index.js +35 -0
- package/packages/server/modules/agent/injection.js +14 -0
- package/packages/server/modules/agent/jobs-diff.js +114 -0
- package/packages/server/modules/agent/jobs-files.js +65 -0
- package/packages/server/modules/agent/jobs-followup.js +66 -0
- package/packages/server/modules/agent/jobs-live.js +180 -0
- package/packages/server/modules/agent/jobs-store.js +59 -0
- package/packages/server/modules/agent/jobs-worktree.js +161 -0
- package/packages/server/modules/agent/jobs.js +316 -0
- package/packages/server/modules/agent/judge-store.js +21 -0
- package/packages/server/modules/agent/lens-request.js +34 -0
- package/packages/server/modules/agent/queue-store.js +21 -0
- package/packages/server/modules/agent/recent-chats.js +63 -0
- package/packages/server/modules/agent/registry.js +108 -0
- package/packages/server/modules/agent/replay.js +84 -0
- package/packages/server/modules/agent/request.js +132 -0
- package/packages/server/modules/agent/role-store.js +21 -0
- package/packages/server/modules/agent/run-hub.js +105 -0
- package/packages/server/modules/agent/run-request.js +208 -0
- package/packages/server/modules/agent/secret-show.js +108 -0
- package/packages/server/modules/agent/side-request.js +142 -0
- package/packages/server/modules/agent/usage-history.js +62 -0
- package/packages/server/modules/agent/worktrees.js +136 -0
- package/packages/server/modules/agent-features/catalog.js +18 -0
- package/packages/server/modules/agent-features/index.js +2 -0
- package/packages/server/modules/agent-features/store.js +172 -0
- package/packages/server/modules/agent-mcp/index.js +106 -0
- package/packages/server/modules/agent-roles/index.js +3 -0
- package/packages/server/modules/agent-roles/project.js +231 -0
- package/packages/server/modules/agent-roles/runtime.js +68 -0
- package/packages/server/modules/agent-roles/store.js +190 -0
- package/packages/server/modules/agents/acp/acp-backend.js +320 -0
- package/packages/server/modules/agents/acp/acp-client.js +153 -0
- package/packages/server/modules/agents/acp/acp-controls.js +179 -0
- package/packages/server/modules/agents/acp/acp-dialect.js +82 -0
- package/packages/server/modules/agents/acp/acp-elicitation.js +135 -0
- package/packages/server/modules/agents/acp/acp-events.js +340 -0
- package/packages/server/modules/agents/acp/acp-process.js +78 -0
- package/packages/server/modules/agents/acp/acp-programs.js +11 -0
- package/packages/server/modules/agents/acp/acp-tools.js +208 -0
- package/packages/server/modules/agents/acp/index.js +4 -0
- package/packages/server/modules/agents/acp/mcp-config.js +100 -0
- package/packages/server/modules/agents/claude-code/claude-code-backend.js +342 -0
- package/packages/server/modules/agents/claude-code/claude-code-checkpoints.js +97 -0
- package/packages/server/modules/agents/claude-code/claude-code-env.js +46 -0
- package/packages/server/modules/agents/claude-code/claude-code-events.js +299 -0
- package/packages/server/modules/agents/claude-code/claude-code-input.js +97 -0
- package/packages/server/modules/agents/claude-code/claude-code-replay.js +71 -0
- package/packages/server/modules/agents/claude-code/claude-code-sessions.js +207 -0
- package/packages/server/modules/agents/claude-code/claude-code-times.js +42 -0
- package/packages/server/modules/agents/claude-code/index.js +2 -0
- package/packages/server/modules/agents/claude-code/questions.js +51 -0
- package/packages/server/modules/agents/codex/dialect.js +130 -0
- package/packages/server/modules/agents/codex/forms.js +24 -0
- package/packages/server/modules/agents/codex/index.js +17 -0
- package/packages/server/modules/agents/cursor/dialect.js +66 -0
- package/packages/server/modules/agents/cursor/images.js +12 -0
- package/packages/server/modules/agents/cursor/index.js +30 -0
- package/packages/server/modules/agents/cursor/plan.js +44 -0
- package/packages/server/modules/agents/cursor/questions.js +37 -0
- package/packages/server/modules/agents/cursor/selection.js +29 -0
- package/packages/server/modules/agents/cursor/task.js +32 -0
- package/packages/server/modules/agents/cursor/todos.js +69 -0
- package/packages/server/modules/agents/ide-mcp/config.js +40 -0
- package/packages/server/modules/agents/ide-mcp/index.js +1 -0
- package/packages/server/modules/agents/ide-mcp/server.js +154 -0
- package/packages/server/modules/agents/kimi/dialect.js +18 -0
- package/packages/server/modules/agents/kimi/index.js +11 -0
- package/packages/server/modules/agents/opencode/dialect.js +232 -0
- package/packages/server/modules/agents/opencode/index.js +21 -0
- package/packages/server/modules/agents/opencode/read.js +46 -0
- package/packages/server/modules/agents/opencode/sessions.js +69 -0
- package/packages/server/modules/agents/projector/agent-lens.js +110 -0
- package/packages/server/modules/agents/projector/agent-tools.js +290 -0
- package/packages/server/modules/agents/projector/answer-doctor.js +32 -0
- package/packages/server/modules/agents/projector/form-doctor.js +33 -0
- package/packages/server/modules/agents/projector/index.js +12 -0
- package/packages/server/modules/agents/projector/project-instructions.js +34 -0
- package/packages/server/modules/agents/projector/projector-backend.js +350 -0
- package/packages/server/modules/agents/projector/projector-budget.js +70 -0
- package/packages/server/modules/agents/projector/projector-compaction.js +128 -0
- package/packages/server/modules/agents/projector/projector-controls.js +70 -0
- package/packages/server/modules/agents/projector/projector-guard.js +196 -0
- package/packages/server/modules/agents/projector/projector-history.js +87 -0
- package/packages/server/modules/agents/projector/projector-hooks.js +201 -0
- package/packages/server/modules/agents/projector/projector-input.js +40 -0
- package/packages/server/modules/agents/projector/projector-mcp-config.js +1 -0
- package/packages/server/modules/agents/projector/projector-mcp.js +119 -0
- package/packages/server/modules/agents/projector/projector-memory.js +92 -0
- package/packages/server/modules/agents/projector/projector-retry.js +52 -0
- package/packages/server/modules/agents/projector/projector-review.js +40 -0
- package/packages/server/modules/agents/projector/projector-side.js +56 -0
- package/packages/server/modules/agents/projector/projector-skills.js +143 -0
- package/packages/server/modules/agents/projector/projector-task.js +235 -0
- package/packages/server/modules/agents/projector/projector-usage.js +19 -0
- package/packages/server/modules/agents/projector/projector-web-search.js +76 -0
- package/packages/server/modules/agents/projector/projector-web.js +172 -0
- package/packages/server/modules/agents/projector/prompts.js +46 -0
- package/packages/server/modules/agents/projector/secrets/secret-destination.js +226 -0
- package/packages/server/modules/agents/projector/secrets/secret-show.js +23 -0
- package/packages/server/modules/agents/projector/secrets/secret-tools.js +124 -0
- package/packages/server/modules/agents/projector/tool-spec.js +4 -0
- package/packages/server/modules/agents/projector/tool-specs.js +167 -0
- package/packages/server/modules/agents/projector/widgets.js +4 -0
- package/packages/server/modules/agents/widgets-mcp/config.js +34 -0
- package/packages/server/modules/agents/widgets-mcp/index.js +1 -0
- package/packages/server/modules/agents-integration/_/usage-cache.js +19 -0
- package/packages/server/modules/agents-integration/claude/client.js +33 -0
- package/packages/server/modules/agents-integration/claude/index.js +1 -0
- package/packages/server/modules/agents-integration/claude/usage.js +49 -0
- package/packages/server/modules/agents-integration/codex/cli.js +86 -0
- package/packages/server/modules/agents-integration/codex/index.js +1 -0
- package/packages/server/modules/agents-integration/codex/usage.js +45 -0
- package/packages/server/modules/agents-integration/cursor/client.js +40 -0
- package/packages/server/modules/agents-integration/cursor/credentials.js +34 -0
- package/packages/server/modules/agents-integration/cursor/index.js +1 -0
- package/packages/server/modules/agents-integration/cursor/usage.js +59 -0
- package/packages/server/modules/agents-integration/kimi/client.js +48 -0
- package/packages/server/modules/agents-integration/kimi/credential-config.js +167 -0
- package/packages/server/modules/agents-integration/kimi/credentials.js +261 -0
- package/packages/server/modules/agents-integration/kimi/index.js +1 -0
- package/packages/server/modules/agents-integration/kimi/usage.js +149 -0
- package/packages/server/modules/agents-integration/opencode/client.js +30 -0
- package/packages/server/modules/agents-integration/opencode/credentials.js +36 -0
- package/packages/server/modules/agents-integration/opencode/index.js +1 -0
- package/packages/server/modules/agents-integration/opencode/usage.js +47 -0
- package/packages/server/modules/appearance/index.js +38 -0
- package/packages/server/modules/browser/cookies.js +112 -0
- package/packages/server/modules/browser/guard.js +55 -0
- package/packages/server/modules/browser/index.js +2 -0
- package/packages/server/modules/browser/key.js +34 -0
- package/packages/server/modules/browser/proxy.js +255 -0
- package/packages/server/modules/browser/rewrite.js +82 -0
- package/packages/server/modules/devcontainer/discovery.js +85 -0
- package/packages/server/modules/devcontainer/exec.js +81 -0
- package/packages/server/modules/devcontainer/index.js +4 -0
- package/packages/server/modules/devcontainer/launch.js +51 -0
- package/packages/server/modules/devcontainer/state.js +68 -0
- package/packages/server/modules/devcontainer/trust.js +41 -0
- package/packages/server/modules/directories/directories.js +34 -0
- package/packages/server/modules/directories/index.js +1 -0
- package/packages/server/modules/docker/actions.js +121 -0
- package/packages/server/modules/docker/daemon.js +72 -0
- package/packages/server/modules/docker/index.js +4 -0
- package/packages/server/modules/docker/settings.js +127 -0
- package/packages/server/modules/docker/snapshot.js +105 -0
- package/packages/server/modules/environments/execution.js +125 -0
- package/packages/server/modules/environments/index.js +3 -0
- package/packages/server/modules/environments/reconcile.js +62 -0
- package/packages/server/modules/environments/settings.js +58 -0
- package/packages/server/modules/events/implementation.js +85 -0
- package/packages/server/modules/events/index.js +1 -0
- package/packages/server/modules/folder-picker/index.js +1 -0
- package/packages/server/modules/folder-picker/pick-folder.js +2 -0
- package/packages/server/modules/git-import/clone.js +47 -0
- package/packages/server/modules/git-import/container.js +57 -0
- package/packages/server/modules/git-import/import.js +82 -0
- package/packages/server/modules/git-import/index.js +4 -0
- package/packages/server/modules/git-import/jobs.js +68 -0
- package/packages/server/modules/github/api.js +260 -0
- package/packages/server/modules/github/browser.js +185 -0
- package/packages/server/modules/github/clone.js +55 -0
- package/packages/server/modules/github/container.js +15 -0
- package/packages/server/modules/github/discussions.js +141 -0
- package/packages/server/modules/github/emojis.js +14 -0
- package/packages/server/modules/github/history.js +205 -0
- package/packages/server/modules/github/index.js +11 -0
- package/packages/server/modules/github/issues.js +81 -0
- package/packages/server/modules/github/navigation.js +35 -0
- package/packages/server/modules/github/pipelines.js +266 -0
- package/packages/server/modules/github/pulls.js +111 -0
- package/packages/server/modules/github/releases.js +241 -0
- package/packages/server/modules/gitlab/api.js +257 -0
- package/packages/server/modules/gitlab/base.js +24 -0
- package/packages/server/modules/gitlab/blob-search.js +110 -0
- package/packages/server/modules/gitlab/browser.js +296 -0
- package/packages/server/modules/gitlab/clone.js +78 -0
- package/packages/server/modules/gitlab/compare.js +68 -0
- package/packages/server/modules/gitlab/connection.js +55 -0
- package/packages/server/modules/gitlab/container.js +15 -0
- package/packages/server/modules/gitlab/history.js +127 -0
- package/packages/server/modules/gitlab/icon.js +67 -0
- package/packages/server/modules/gitlab/index.js +14 -0
- package/packages/server/modules/gitlab/issues.js +61 -0
- package/packages/server/modules/gitlab/merge-requests.js +287 -0
- package/packages/server/modules/gitlab/navigation.js +187 -0
- package/packages/server/modules/gitlab/oauth.js +250 -0
- package/packages/server/modules/gitlab/pipelines.js +240 -0
- package/packages/server/modules/gitlab/releases.js +226 -0
- package/packages/server/modules/gitlab/search.js +75 -0
- package/packages/server/modules/gitlab/trackers.js +96 -0
- package/packages/server/modules/http/download.js +50 -0
- package/packages/server/modules/http/http.js +8 -0
- package/packages/server/modules/http/index.js +2 -0
- package/packages/server/modules/hub/connector.js +114 -0
- package/packages/server/modules/hub/hub.js +142 -0
- package/packages/server/modules/hub/index.js +1 -0
- package/packages/server/modules/ide/editor-settings.js +37 -0
- package/packages/server/modules/ide/index.js +3 -0
- package/packages/server/modules/ide/keybindings.js +37 -0
- package/packages/server/modules/ide/mcp-bridge.js +150 -0
- package/packages/server/modules/instance/index.js +2 -0
- package/packages/server/modules/instance/instance.js +50 -0
- package/packages/server/modules/integration-store/index.js +2 -0
- package/packages/server/modules/integration-store/list.js +12 -0
- package/packages/server/modules/integration-store/store.js +141 -0
- package/packages/server/modules/judge/approval.js +35 -0
- package/packages/server/modules/judge/index.js +3 -0
- package/packages/server/modules/judge/settings.js +35 -0
- package/packages/server/modules/judge/verdict.js +141 -0
- package/packages/server/modules/launcher/browse.js +29 -0
- package/packages/server/modules/launcher/folders.js +138 -0
- package/packages/server/modules/launcher/hosted-search.js +43 -0
- package/packages/server/modules/launcher/index.js +12 -0
- package/packages/server/modules/launcher/launcher.js +352 -0
- package/packages/server/modules/launcher/potential.js +70 -0
- package/packages/server/modules/launcher/project-entries.js +165 -0
- package/packages/server/modules/network/eu-context.js +29 -0
- package/packages/server/modules/network/index.js +1 -0
- package/packages/server/modules/openai-gateway/config.js +125 -0
- package/packages/server/modules/openai-gateway/gateway.js +178 -0
- package/packages/server/modules/openai-gateway/index.js +7 -0
- package/packages/server/modules/preferences/index.js +7 -0
- package/packages/server/modules/preferences/preferences.js +142 -0
- package/packages/server/modules/processes/index.js +6 -0
- package/packages/server/modules/processes/processes.js +174 -0
- package/packages/server/modules/project-presentation/implementation.js +130 -0
- package/packages/server/modules/project-presentation/index.js +1 -0
- package/packages/server/modules/project-widgets/index.js +210 -0
- package/packages/server/modules/projects/discovery.js +179 -0
- package/packages/server/modules/projects/favicon.js +180 -0
- package/packages/server/modules/projects/index.js +11 -0
- package/packages/server/modules/projects/inspect.js +148 -0
- package/packages/server/modules/projects/remote-icon.js +39 -0
- package/packages/server/modules/projects/store.js +41 -0
- package/packages/server/modules/projects/types.js +1 -0
- package/packages/server/modules/providers/atomic-file.js +29 -0
- package/packages/server/modules/providers/balance.js +125 -0
- package/packages/server/modules/providers/index.js +15 -0
- package/packages/server/modules/providers/kinds.js +24 -0
- package/packages/server/modules/providers/model-list.js +16 -0
- package/packages/server/modules/providers/models.js +124 -0
- package/packages/server/modules/providers/openai-client.js +40 -0
- package/packages/server/modules/providers/provider-seeds.js +39 -0
- package/packages/server/modules/providers/provider-store.js +317 -0
- package/packages/server/modules/providers/quiet-model.js +36 -0
- package/packages/server/modules/providers/secret-obfuscation.js +48 -0
- package/packages/server/modules/providers/thinking.js +105 -0
- package/packages/server/modules/providers/types.js +1 -0
- package/packages/server/modules/restart/index.js +1 -0
- package/packages/server/modules/restart/restart.js +56 -0
- package/packages/server/modules/secrets/index.js +1 -0
- package/packages/server/modules/secrets/vault.js +51 -0
- package/packages/server/modules/spend/index.js +2 -0
- package/packages/server/modules/spend/ledger.js +82 -0
- package/packages/server/modules/spend/store.js +92 -0
- package/packages/server/modules/terminal/drop-files.js +42 -0
- package/packages/server/modules/terminal/index.js +15 -0
- package/packages/server/modules/terminal/link-files.js +44 -0
- package/packages/server/modules/terminal/scenario-folder.js +20 -0
- package/packages/server/modules/terminal/session-state.js +85 -0
- package/packages/server/modules/terminal/socket.js +159 -0
- package/packages/server/modules/terminal/terminal-activity.js +56 -0
- package/packages/server/modules/terminal/terminal-file.js +32 -0
- package/packages/server/modules/terminal/terminal-mouse.js +29 -0
- package/packages/server/modules/terminal/terminal.js +308 -0
- package/packages/server/modules/terminal/terminate.js +68 -0
- package/packages/server/modules/terminal-control/control.js +75 -0
- package/packages/server/modules/terminal-control/handlers.js +10 -0
- package/packages/server/modules/terminal-control/index.js +3 -0
- package/packages/server/modules/terminal-control/shared-socket.js +319 -0
- package/packages/server/modules/terminal-control/socket.js +153 -0
- package/packages/server/modules/transport/implementation.js +24 -0
- package/packages/server/modules/transport/index.js +2 -0
- package/packages/server/modules/transport/router.js +16 -0
- package/packages/server/modules/transport/types.js +1 -0
- package/packages/server/modules/usage-analytics/index.js +4 -0
- package/packages/server/modules/usage-analytics/limits.js +144 -0
- package/packages/server/modules/usage-analytics/overview.js +117 -0
- package/packages/server/modules/usage-analytics/providers.js +120 -0
- package/packages/server/modules/usage-analytics/store.js +152 -0
- package/packages/server/modules/window/desktop.js +24 -0
- package/packages/server/modules/window/index.js +8 -0
- package/packages/server/modules/window/window.js +86 -0
- package/packages/server/modules/workspace/archive.py +109 -0
- package/packages/server/modules/workspace/external-files.js +22 -0
- package/packages/server/modules/workspace/files-exclude.js +73 -0
- package/packages/server/modules/workspace/files.js +332 -0
- package/packages/server/modules/workspace/find-paths.js +92 -0
- package/packages/server/modules/workspace/git-branches.js +159 -0
- package/packages/server/modules/workspace/git-compare.js +121 -0
- package/packages/server/modules/workspace/git-history.js +182 -0
- package/packages/server/modules/workspace/git-sync.js +245 -0
- package/packages/server/modules/workspace/git-tree.js +126 -0
- package/packages/server/modules/workspace/git.js +276 -0
- package/packages/server/modules/workspace/ignored.js +23 -0
- package/packages/server/modules/workspace/import.js +190 -0
- package/packages/server/modules/workspace/index.js +15 -0
- package/packages/server/modules/workspace/paths.js +38 -0
- package/packages/server/modules/workspace/reveal.js +14 -0
- package/packages/server/modules/workspace/search.js +136 -0
- package/packages/server/modules/workspace/site.js +62 -0
- package/packages/server/modules/workspace/watcher.js +176 -0
- package/packages/server/routes/api/agent-answer-repair.js +35 -0
- package/packages/server/routes/api/agent-chats.js +77 -0
- package/packages/server/routes/api/agent-features.js +36 -0
- package/packages/server/routes/api/agent-form-repair.js +35 -0
- package/packages/server/routes/api/agent-hooks.js +35 -0
- package/packages/server/routes/api/agent-jobs.js +322 -0
- package/packages/server/routes/api/agent-judge.js +33 -0
- package/packages/server/routes/api/agent-lens.js +27 -0
- package/packages/server/routes/api/agent-mcp.js +41 -0
- package/packages/server/routes/api/agent-memory.js +33 -0
- package/packages/server/routes/api/agent-project-roles.js +112 -0
- package/packages/server/routes/api/agent-project-widgets.js +67 -0
- package/packages/server/routes/api/agent-roles.js +106 -0
- package/packages/server/routes/api/agent-secret-show.js +87 -0
- package/packages/server/routes/api/agent-side.js +70 -0
- package/packages/server/routes/api/agent-skills.js +31 -0
- package/packages/server/routes/api/agent-web.js +27 -0
- package/packages/server/routes/api/agent-worktrees.js +49 -0
- package/packages/server/routes/api/agent.js +269 -0
- package/packages/server/routes/api/analytics.js +21 -0
- package/packages/server/routes/api/app/hide.js +12 -0
- package/packages/server/routes/api/app/mode.js +49 -0
- package/packages/server/routes/api/app/network.js +54 -0
- package/packages/server/routes/api/app/open.js +33 -0
- package/packages/server/routes/api/app/quit.js +14 -0
- package/packages/server/routes/api/app/restart.js +18 -0
- package/packages/server/routes/api/appearance.js +70 -0
- package/packages/server/routes/api/browser.js +27 -0
- package/packages/server/routes/api/claude.js +15 -0
- package/packages/server/routes/api/codex.js +15 -0
- package/packages/server/routes/api/cursor.js +15 -0
- package/packages/server/routes/api/directories.js +16 -0
- package/packages/server/routes/api/docker.js +74 -0
- package/packages/server/routes/api/events.js +25 -0
- package/packages/server/routes/api/health.js +20 -0
- package/packages/server/routes/api/hub.js +26 -0
- package/packages/server/routes/api/ide/commands.js +72 -0
- package/packages/server/routes/api/ide/editor.js +37 -0
- package/packages/server/routes/api/ide/files-exclude.js +37 -0
- package/packages/server/routes/api/ide/keybindings.js +37 -0
- package/packages/server/routes/api/inspect.js +21 -0
- package/packages/server/routes/api/integrations/[...action].js +201 -0
- package/packages/server/routes/api/integrations/github-browse.js +190 -0
- package/packages/server/routes/api/kimi.js +15 -0
- package/packages/server/routes/api/launcher/icon.js +16 -0
- package/packages/server/routes/api/launcher/launch.js +27 -0
- package/packages/server/routes/api/launcher/search.js +20 -0
- package/packages/server/routes/api/launcher/settings.js +68 -0
- package/packages/server/routes/api/openai.js +94 -0
- package/packages/server/routes/api/opencode.js +15 -0
- package/packages/server/routes/api/pick-folder.js +12 -0
- package/packages/server/routes/api/preview-icon.js +21 -0
- package/packages/server/routes/api/projects/[id]/index.js +240 -0
- package/packages/server/routes/api/projects/[id]/site.js +59 -0
- package/packages/server/routes/api/projects/[id]/terminals.js +38 -0
- package/packages/server/routes/api/projects/[id]/workspace-read.js +126 -0
- package/packages/server/routes/api/projects/[id]/workspace.js +147 -0
- package/packages/server/routes/api/projects/index.js +62 -0
- package/packages/server/routes/api/providers/active.js +12 -0
- package/packages/server/routes/api/providers/balance.js +15 -0
- package/packages/server/routes/api/providers/models.js +19 -0
- package/packages/server/routes/api/providers.js +23 -0
- package/packages/server/routes/api/status.js +11 -0
- package/resources/icons/128.png +0 -0
- package/resources/icons/16.png +0 -0
- package/resources/icons/256.png +0 -0
- package/resources/icons/32.png +0 -0
- package/resources/icons/48.png +0 -0
- package/resources/icons/512.png +0 -0
- package/resources/icons/64.png +0 -0
- package/resources/icons/projector.svg +5 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Only the authenticated connector can mark a socket. HTTP headers never establish trust.
|
|
2
|
+
const state = globalThis;
|
|
3
|
+
const sockets = (state.projectorHubSockets ??= new WeakMap());
|
|
4
|
+
export function markHubSocket(socket, origin) {
|
|
5
|
+
sockets.set(socket, origin);
|
|
6
|
+
}
|
|
7
|
+
export function isHubRequest(req) {
|
|
8
|
+
return sockets.has(req.socket);
|
|
9
|
+
}
|
|
10
|
+
export function hubAccessAllowed(req, requireOrigin) {
|
|
11
|
+
const origin = sockets.get(req.socket);
|
|
12
|
+
if (!origin || req.headers.host !== new URL(origin).host)
|
|
13
|
+
return false;
|
|
14
|
+
if (requireOrigin && !req.headers.origin)
|
|
15
|
+
return false;
|
|
16
|
+
if (req.headers.origin && req.headers.origin !== origin)
|
|
17
|
+
return false;
|
|
18
|
+
return (req.url ?? "").startsWith("/api/");
|
|
19
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { accessAllowed, isLocalRequest, lanPassword, registerGatewayGuard, registerGatewayOrigins, } from "./access.js";
|
|
2
|
+
export { authorizeHttp } from "./http.js";
|
|
3
|
+
export { protectLanSockets } from "./connections.js";
|
|
4
|
+
export { hasLanPassword, verifyLanPassword, setLanPassword, clearLanPassword } from "./password.js";
|
|
5
|
+
export { lanUrl, lanUrls } from "./lan-url.js";
|
|
6
|
+
export { markHubSocket } from "./hub.js";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { networkInterfaces } from "node:os";
|
|
2
|
+
import { APP_PORT } from "../../../core/modules/app-paths/index.js";
|
|
3
|
+
function privateAddresses() {
|
|
4
|
+
const result = [];
|
|
5
|
+
for (const entries of Object.values(networkInterfaces())) {
|
|
6
|
+
for (const entry of entries ?? []) {
|
|
7
|
+
if (entry.family !== "IPv4" || entry.internal)
|
|
8
|
+
continue;
|
|
9
|
+
result.push(entry.address);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
/** Все адреса Projector в локальной сети для открытия с других устройств. */
|
|
15
|
+
export function lanUrls() {
|
|
16
|
+
return privateAddresses().map((address) => `http://${address}:${APP_PORT}`);
|
|
17
|
+
}
|
|
18
|
+
/** Первый адрес Projector в локальной сети. */
|
|
19
|
+
export function lanUrl() {
|
|
20
|
+
return lanUrls()[0] ?? null;
|
|
21
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { os } from "../../../core/modules/os/index.js";
|
|
2
|
+
import { mkdirSync, readFileSync, writeFileSync, renameSync, rmSync } from "node:fs";
|
|
3
|
+
import { randomBytes, scryptSync, timingSafeEqual } from "node:crypto";
|
|
4
|
+
import { dirname } from "node:path";
|
|
5
|
+
import { lanPasswordPath } from "../../../core/modules/app-paths/index.js";
|
|
6
|
+
const state = globalThis;
|
|
7
|
+
const listeners = (state.projectorLanPasswordListeners ??= new Set());
|
|
8
|
+
export function onLanPasswordChanged(listener) {
|
|
9
|
+
listeners.add(listener);
|
|
10
|
+
return () => {
|
|
11
|
+
listeners.delete(listener);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function passwordChanged() {
|
|
15
|
+
for (const listener of listeners)
|
|
16
|
+
listener();
|
|
17
|
+
}
|
|
18
|
+
function readStored() {
|
|
19
|
+
try {
|
|
20
|
+
const raw = readFileSync(lanPasswordPath(), "utf8").trim();
|
|
21
|
+
if (!/^[a-f0-9]{32}:[a-f0-9]{128}$/.test(raw))
|
|
22
|
+
throw new Error("Повреждён файл пароля LAN");
|
|
23
|
+
const [salt, hash] = raw.split(":");
|
|
24
|
+
return { salt: Buffer.from(salt, "hex"), hash: Buffer.from(hash, "hex") };
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
if (error.code === "ENOENT")
|
|
28
|
+
return null;
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Changes on every password replacement, including replacement with the same password. */
|
|
33
|
+
export function lanPasswordVersion() {
|
|
34
|
+
return readStored()?.hash.toString("hex") ?? null;
|
|
35
|
+
}
|
|
36
|
+
export function hasLanPassword() {
|
|
37
|
+
return readStored() !== null;
|
|
38
|
+
}
|
|
39
|
+
export function verifyLanPassword(password) {
|
|
40
|
+
const stored = readStored();
|
|
41
|
+
if (!stored)
|
|
42
|
+
return false;
|
|
43
|
+
const candidate = scryptSync(password, stored.salt, stored.hash.length);
|
|
44
|
+
return timingSafeEqual(candidate, stored.hash);
|
|
45
|
+
}
|
|
46
|
+
export function setLanPassword(password) {
|
|
47
|
+
mkdirSync(dirname(lanPasswordPath()), { recursive: true });
|
|
48
|
+
const salt = randomBytes(16);
|
|
49
|
+
const hash = scryptSync(password, salt, 64);
|
|
50
|
+
const file = lanPasswordPath();
|
|
51
|
+
const temporary = `${file}.${randomBytes(8).toString("hex")}.tmp`;
|
|
52
|
+
try {
|
|
53
|
+
writeFileSync(temporary, `${salt.toString("hex")}:${hash.toString("hex")}\n`, {
|
|
54
|
+
mode: 0o600,
|
|
55
|
+
flag: "wx",
|
|
56
|
+
});
|
|
57
|
+
renameSync(temporary, file);
|
|
58
|
+
os.tools.restrictToOwnerSync(file);
|
|
59
|
+
passwordChanged();
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
rmSync(temporary, { force: true });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export function clearLanPassword() {
|
|
66
|
+
rmSync(lanPasswordPath(), { force: true });
|
|
67
|
+
passwordChanged();
|
|
68
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { lanPasswordVersion } from "./password.js";
|
|
3
|
+
const COOKIE = "projector_lan";
|
|
4
|
+
const LIFETIME = 8 * 60 * 60 * 1000;
|
|
5
|
+
const host = globalThis;
|
|
6
|
+
const sessions = (host.projectorLanSessions ??= new Map());
|
|
7
|
+
export function validLanSession(req) {
|
|
8
|
+
const id = req.headers.cookie?.match(/(?:^|;\s*)projector_lan=([a-f0-9]{64})(?:;|$)/)?.[1];
|
|
9
|
+
const session = id ? sessions.get(id) : undefined;
|
|
10
|
+
if (!session)
|
|
11
|
+
return false;
|
|
12
|
+
if (session.expires <= Date.now() || session.version !== lanPasswordVersion()) {
|
|
13
|
+
sessions.delete(id);
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
/** Call only after the request's Bearer password has been verified. */
|
|
19
|
+
export function rememberLanSession(req, res) {
|
|
20
|
+
if (res.hasHeader("Set-Cookie") ||
|
|
21
|
+
!req.headers.authorization?.startsWith("Bearer ") ||
|
|
22
|
+
validLanSession(req))
|
|
23
|
+
return;
|
|
24
|
+
const version = lanPasswordVersion();
|
|
25
|
+
if (!version)
|
|
26
|
+
return;
|
|
27
|
+
for (const [id, session] of sessions) {
|
|
28
|
+
if (session.expires <= Date.now() || session.version !== version)
|
|
29
|
+
sessions.delete(id);
|
|
30
|
+
}
|
|
31
|
+
// Bound memory even when a client authenticates without keeping its cookies.
|
|
32
|
+
if (sessions.size >= 256)
|
|
33
|
+
sessions.delete(sessions.keys().next().value);
|
|
34
|
+
const id = randomBytes(32).toString("hex");
|
|
35
|
+
sessions.set(id, { version, expires: Date.now() + LIFETIME });
|
|
36
|
+
const secure = "encrypted" in req.socket && req.socket.encrypted ? "; Secure" : "";
|
|
37
|
+
res.setHeader("Set-Cookie", `${COOKIE}=${id}; HttpOnly; SameSite=Strict; Path=/; Max-Age=${LIFETIME / 1000}${secure}`);
|
|
38
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { devcontainerForPath } from "../devcontainer/index.js";
|
|
2
|
+
import { environmentForPath } from "../environments/index.js";
|
|
3
|
+
import { readAttachment } from "./attachments.js";
|
|
4
|
+
/** Env names that must not leak from Projector's server into a coding agent's shell. */
|
|
5
|
+
const PRIVATE_ENV = [
|
|
6
|
+
"PROVIDERS_SECRET",
|
|
7
|
+
"OPENAI_API_KEY",
|
|
8
|
+
"DASHSCOPE_API_KEY",
|
|
9
|
+
"QWENCLOUD_API_KEY",
|
|
10
|
+
];
|
|
11
|
+
/** The host environment for an external coding agent, without Projector's own secrets. */
|
|
12
|
+
export function agentEnv() {
|
|
13
|
+
const env = { ...process.env };
|
|
14
|
+
for (const name of PRIVATE_ENV)
|
|
15
|
+
delete env[name];
|
|
16
|
+
return env;
|
|
17
|
+
}
|
|
18
|
+
/** Without a native session the earlier chat is replayed as text. */
|
|
19
|
+
/** The bytes and type of an attached image, for the agents that take images in a prompt. */
|
|
20
|
+
export async function attachedImages(parts) {
|
|
21
|
+
const images = [];
|
|
22
|
+
for (const part of parts ?? []) {
|
|
23
|
+
if (part.type !== "image")
|
|
24
|
+
continue;
|
|
25
|
+
const stored = await readAttachment(part.id);
|
|
26
|
+
if (stored)
|
|
27
|
+
images.push({ name: part.name, mime: stored.mime, data: stored.content.toString("base64") });
|
|
28
|
+
}
|
|
29
|
+
return images;
|
|
30
|
+
}
|
|
31
|
+
export function promptWithHistory(message, history, context = "") {
|
|
32
|
+
const transcript = history
|
|
33
|
+
.slice(-10)
|
|
34
|
+
.map((turn) => `${turn.role === "user" ? "Пользователь" : "Ассистент"}: ${turn.content}`)
|
|
35
|
+
.join("\n\n");
|
|
36
|
+
return [
|
|
37
|
+
...(history.length ? [`Предыдущая переписка в этом чате:\n\n${transcript}`] : []),
|
|
38
|
+
...(context.trim() ? [context.trim()] : []),
|
|
39
|
+
...(history.length ? [`Новое сообщение пользователя:\n${message}`] : [message]),
|
|
40
|
+
].join("\n\n");
|
|
41
|
+
}
|
|
42
|
+
/** An external agent's tools run on the host, so isolating environments are refused. */
|
|
43
|
+
export async function assertHostProject(cwd, label) {
|
|
44
|
+
if ((await devcontainerForPath(cwd)) || (await environmentForPath(cwd)))
|
|
45
|
+
throw new Error(`${label} выполняет инструменты на машине пользователя и недоступен в проектах с Docker-окружением или Dev Container. Откройте терминальную сессию.`);
|
|
46
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
5
|
+
import { dataDir } from "../../../core/modules/app-paths/index.js";
|
|
6
|
+
import { os } from "../../../core/modules/os/index.js";
|
|
7
|
+
/** Runs with a live host, whichever page started them. */
|
|
8
|
+
export async function listLiveRuns() {
|
|
9
|
+
const ids = await readdir(runsRoot()).catch(() => []);
|
|
10
|
+
const runs = await Promise.all(ids
|
|
11
|
+
.filter((id) => RUN_ID.test(id))
|
|
12
|
+
.map(async (id) => {
|
|
13
|
+
if ((await liveHost(id)) === undefined)
|
|
14
|
+
return;
|
|
15
|
+
const record = await readRun(id);
|
|
16
|
+
// A background job shows up as a job, not as a second run.
|
|
17
|
+
if (!record || record.chat?.startsWith(JOB_CHAT))
|
|
18
|
+
return;
|
|
19
|
+
// A run started before its record carried the time: the file's own time is close enough.
|
|
20
|
+
const startedAt = record.startedAt ??
|
|
21
|
+
(await stat(join(runDirectory(id), "run.json")).catch(() => null))?.mtimeMs;
|
|
22
|
+
return {
|
|
23
|
+
id,
|
|
24
|
+
backend: record.backend,
|
|
25
|
+
projectId: record.projectId ?? "",
|
|
26
|
+
chat: record.chat ?? "",
|
|
27
|
+
topic: record.message.trim().slice(0, 120),
|
|
28
|
+
...(record.session ? { session: record.session } : {}),
|
|
29
|
+
...(startedAt !== undefined ? { startedAt } : {}),
|
|
30
|
+
};
|
|
31
|
+
}));
|
|
32
|
+
return runs.filter((run) => !!run);
|
|
33
|
+
}
|
|
34
|
+
/** The `chat` of a run that belongs to a background job (`job:<id>`). */
|
|
35
|
+
export const JOB_CHAT = "job:";
|
|
36
|
+
const RUN_ID = /^[0-9a-f]{12}$/;
|
|
37
|
+
/** A host still alive after this long is stopped and its run removed. */
|
|
38
|
+
const RUN_TTL_MS = 24 * 60 * 60 * 1000;
|
|
39
|
+
/** A finished run nobody rejoined is kept this long, then removed. */
|
|
40
|
+
const RETAIN_MS = 60 * 60 * 1000;
|
|
41
|
+
/** The run of a background job waits longer: a restarted server rejoins it to collect the answer. */
|
|
42
|
+
const JOB_RETAIN_MS = 24 * 60 * 60 * 1000;
|
|
43
|
+
const runsRoot = () => join(dataDir(), "agent", "runs");
|
|
44
|
+
/** The directory of a run; the identifier comes from a client, so its shape is checked. */
|
|
45
|
+
export function runDirectory(id) {
|
|
46
|
+
if (!RUN_ID.test(id))
|
|
47
|
+
throw new Error("Некорректный идентификатор хода");
|
|
48
|
+
return join(runsRoot(), id);
|
|
49
|
+
}
|
|
50
|
+
export async function createRun(record) {
|
|
51
|
+
const id = randomBytes(6).toString("hex");
|
|
52
|
+
const dir = runDirectory(id);
|
|
53
|
+
await mkdir(dir, { recursive: true, mode: 0o700 });
|
|
54
|
+
await writeFile(join(dir, "run.json"), JSON.stringify({ ...record, startedAt: Date.now() }), {
|
|
55
|
+
mode: 0o600,
|
|
56
|
+
});
|
|
57
|
+
return id;
|
|
58
|
+
}
|
|
59
|
+
export async function readRun(id) {
|
|
60
|
+
try {
|
|
61
|
+
return JSON.parse(await readFile(join(runDirectory(id), "run.json"), "utf8"));
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** Notes the agent's session in the stored run. */
|
|
68
|
+
export async function rememberSession(id, session) {
|
|
69
|
+
const record = await readRun(id);
|
|
70
|
+
if (!record || record.session === session)
|
|
71
|
+
return;
|
|
72
|
+
await writeFile(join(runDirectory(id), "run.json"), JSON.stringify({ ...record, session }), {
|
|
73
|
+
mode: 0o600,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/** A disconnected/replaced reader must never erase a run that still has a live owner. */
|
|
77
|
+
export async function removeRun(id) {
|
|
78
|
+
if ((await liveHost(id)) !== undefined)
|
|
79
|
+
return false;
|
|
80
|
+
const dir = runDirectory(id);
|
|
81
|
+
// A deep data directory puts the socket in /tmp instead (see `agentHostAddress`).
|
|
82
|
+
await os.tools.removeAgentHostAddress(dir, os.tools.agentHostAddress(dir));
|
|
83
|
+
// A host that was just signalled may still write; retry instead of failing on ENOTEMPTY.
|
|
84
|
+
await rm(dir, { recursive: true, force: true, maxRetries: 10, retryDelay: 50 });
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
/** The host's process identity, so a pid reused by another program later is never signalled. */
|
|
88
|
+
export async function rememberHost(id, pid) {
|
|
89
|
+
const identity = await os.processes.identity(pid);
|
|
90
|
+
await writeFile(join(runDirectory(id), "process.json"), JSON.stringify({ pid, identity }));
|
|
91
|
+
}
|
|
92
|
+
async function liveHost(id) {
|
|
93
|
+
try {
|
|
94
|
+
const { pid, identity } = JSON.parse(await readFile(join(runDirectory(id), "process.json"), "utf8"));
|
|
95
|
+
return Number.isInteger(pid) && identity && (await os.processes.identity(pid)) === identity
|
|
96
|
+
? pid
|
|
97
|
+
: undefined;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** Stops a run's agent and everything it started, whichever server started it. */
|
|
104
|
+
export async function stopRun(id) {
|
|
105
|
+
const pid = await liveHost(id);
|
|
106
|
+
if (!pid)
|
|
107
|
+
return;
|
|
108
|
+
os.tools.killAgentTree(pid);
|
|
109
|
+
// Signalling is asynchronous: keep the record until the host actually releases the run.
|
|
110
|
+
const deadline = Date.now() + 5000;
|
|
111
|
+
while ((await liveHost(id)) !== undefined && Date.now() < deadline)
|
|
112
|
+
await sleep(25);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Drops what nobody will come back for. A finished run (its host is gone) is kept for
|
|
116
|
+
* `RETAIN_MS` so a reopened page can still replay the answer; a host that outlived `RUN_TTL_MS`
|
|
117
|
+
* is stopped first. Runs are collected at server start, whenever a new run starts, and one
|
|
118
|
+
* `RETAIN_MS` after a run ended unseen, so a crash or a closed page leaves nothing behind.
|
|
119
|
+
*/
|
|
120
|
+
export async function pruneRuns(now = Date.now()) {
|
|
121
|
+
const ids = await readdir(runsRoot()).catch(() => []);
|
|
122
|
+
for (const id of ids) {
|
|
123
|
+
if (!RUN_ID.test(id))
|
|
124
|
+
continue;
|
|
125
|
+
const dir = runDirectory(id);
|
|
126
|
+
const last = await Promise.all(["trace.log", "run.json"].map((name) => stat(join(dir, name)).catch(() => null))).then((found) => found.find(Boolean)?.mtimeMs ?? 0);
|
|
127
|
+
const age = now - last;
|
|
128
|
+
if ((await liveHost(id)) !== undefined) {
|
|
129
|
+
if (age < RUN_TTL_MS)
|
|
130
|
+
continue;
|
|
131
|
+
await stopRun(id);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
const job = (await readRun(id))?.chat?.startsWith(JOB_CHAT);
|
|
135
|
+
if (age < (job ? JOB_RETAIN_MS : RETAIN_MS))
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
await removeRun(id).catch(() => { });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/** Collect finished runs once their retention has passed. */
|
|
142
|
+
export function schedulePrune() {
|
|
143
|
+
setTimeout(() => void pruneRuns().catch(() => { }), RETAIN_MS + 1000).unref();
|
|
144
|
+
}
|
|
145
|
+
const host = globalThis;
|
|
146
|
+
const active = (host.projectorAgentRuns ??= new Map());
|
|
147
|
+
/** Registers how to cancel a run this server is driving; the returned function forgets it. */
|
|
148
|
+
export function trackRun(id, cancel) {
|
|
149
|
+
active.set(id, cancel);
|
|
150
|
+
return () => {
|
|
151
|
+
if (active.get(id) === cancel)
|
|
152
|
+
active.delete(id);
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/** The user pressed stop: cancel the run here, or stop the agent a former server started. */
|
|
156
|
+
export async function cancelRun(id) {
|
|
157
|
+
const cancel = active.get(id);
|
|
158
|
+
if (cancel)
|
|
159
|
+
return cancel();
|
|
160
|
+
await stopRun(id);
|
|
161
|
+
await removeRun(id);
|
|
162
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { dataDir } from "../../../core/modules/app-paths/index.js";
|
|
5
|
+
import { HttpError } from "../http/index.js";
|
|
6
|
+
/** Pictures pasted or dropped into the chat, served inline; anything else is just stored. */
|
|
7
|
+
const TYPES = {
|
|
8
|
+
"image/png": { ext: "png", magic: (head) => head.subarray(1, 4).toString() === "PNG" },
|
|
9
|
+
"image/jpeg": { ext: "jpg", magic: (head) => head[0] === 0xff && head[1] === 0xd8 },
|
|
10
|
+
"image/gif": { ext: "gif", magic: (head) => head.subarray(0, 3).toString() === "GIF" },
|
|
11
|
+
"image/webp": {
|
|
12
|
+
ext: "webp",
|
|
13
|
+
magic: (head) => head.subarray(0, 4).toString() === "RIFF" && head.subarray(8, 12).toString() === "WEBP",
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
/** Files of any type may be attached; pictures also have to be what their header says. */
|
|
17
|
+
const MAX_BYTES = 10 * 1024 * 1024;
|
|
18
|
+
const ID = /^[0-9a-f]{16}$/;
|
|
19
|
+
/** Unused attachments of old chats are removed after this long. */
|
|
20
|
+
const KEEP_MS = 30 * 24 * 60 * 60 * 1000;
|
|
21
|
+
const directory = () => join(dataDir(), "agent", "attachments");
|
|
22
|
+
/** A name that stays readable in a chip and is safe on every platform. */
|
|
23
|
+
function safeName(name) {
|
|
24
|
+
const base = name.split(/[\\/]/).pop() ?? "";
|
|
25
|
+
const clean = base
|
|
26
|
+
.replace(/[\p{Cc}<>:"/\\|?*]+/gu, "_")
|
|
27
|
+
.replace(/^[.\s]+|[.\s]+$/g, "")
|
|
28
|
+
.slice(0, 100);
|
|
29
|
+
return clean || "file";
|
|
30
|
+
}
|
|
31
|
+
async function store(path, content) {
|
|
32
|
+
await writeFile(`${path}.tmp`, content, { mode: 0o600 });
|
|
33
|
+
await rename(`${path}.tmp`, path);
|
|
34
|
+
}
|
|
35
|
+
export async function saveAttachment(req, mime, name) {
|
|
36
|
+
const type = TYPES[mime.trim().toLowerCase()];
|
|
37
|
+
const keptName = safeName(name);
|
|
38
|
+
const chunks = [];
|
|
39
|
+
let size = 0;
|
|
40
|
+
for await (const chunk of req) {
|
|
41
|
+
size += chunk.length;
|
|
42
|
+
if (size > MAX_BYTES)
|
|
43
|
+
throw new HttpError(413, "Файл больше 10 МБ");
|
|
44
|
+
chunks.push(chunk);
|
|
45
|
+
}
|
|
46
|
+
const content = Buffer.concat(chunks);
|
|
47
|
+
if (!content.length)
|
|
48
|
+
throw new HttpError(400, "Пустой файл");
|
|
49
|
+
const id = randomBytes(8).toString("hex");
|
|
50
|
+
await mkdir(directory(), { recursive: true, mode: 0o700 });
|
|
51
|
+
if (type) {
|
|
52
|
+
if (!type.magic(content))
|
|
53
|
+
throw new HttpError(400, "Это не изображение");
|
|
54
|
+
const path = join(directory(), `${id}.${type.ext}`);
|
|
55
|
+
await store(path, content);
|
|
56
|
+
void pruneAttachments().catch(() => { });
|
|
57
|
+
return { id, mime: mime.trim().toLowerCase(), name: keptName, path };
|
|
58
|
+
}
|
|
59
|
+
// A file of any type is kept in its own folder and opened from disk, so the chat holds a
|
|
60
|
+
// normal path the agent can read instead of a copy inside the project.
|
|
61
|
+
const path = join(directory(), id, keptName);
|
|
62
|
+
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
63
|
+
await store(path, content);
|
|
64
|
+
void pruneAttachments().catch(() => { });
|
|
65
|
+
return { id, mime: "application/octet-stream", name: keptName, path };
|
|
66
|
+
}
|
|
67
|
+
/** The stored image, or `null` when the id is unknown or was removed. */
|
|
68
|
+
export async function readAttachment(id) {
|
|
69
|
+
if (!ID.test(id))
|
|
70
|
+
return null;
|
|
71
|
+
for (const [mime, { ext }] of Object.entries(TYPES)) {
|
|
72
|
+
try {
|
|
73
|
+
return { mime, content: await readFile(join(directory(), `${id}.${ext}`)) };
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Not stored under this type.
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
async function pruneAttachments() {
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
for (const file of await readdir(directory())) {
|
|
84
|
+
const path = join(directory(), file);
|
|
85
|
+
if (now - (await stat(path)).mtimeMs > KEEP_MS)
|
|
86
|
+
await rm(path, { recursive: true, force: true });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { chatMetaOf, chatTitle, deleteHistory, historyDatabase, loadHistory, saveHistory, } from "./history-store.js";
|
|
3
|
+
import { readAgentHistory, writeAgentHistory } from "./history.js";
|
|
4
|
+
/** Most chats kept per scope; the oldest unpinned ones go first. */
|
|
5
|
+
const KEEP = 100;
|
|
6
|
+
const archiveKey = (id) => `archive:${id}`;
|
|
7
|
+
export function listArchivedChats(scope) {
|
|
8
|
+
const rows = historyDatabase()
|
|
9
|
+
.prepare("SELECT id, title, updated, pinned FROM archives WHERE scope = ? ORDER BY pinned DESC, updated DESC")
|
|
10
|
+
.all(scope);
|
|
11
|
+
return rows.map((row) => ({
|
|
12
|
+
id: row.id,
|
|
13
|
+
title: row.title,
|
|
14
|
+
updatedAt: row.updated,
|
|
15
|
+
pinned: row.pinned === 1,
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
/** Puts the live chat of `scope` aside and empties it; nothing happens to an empty chat. */
|
|
19
|
+
export async function archiveLiveChat(scope) {
|
|
20
|
+
const turns = await readAgentHistory(scope);
|
|
21
|
+
if (!turns.length)
|
|
22
|
+
return undefined;
|
|
23
|
+
const id = randomUUID();
|
|
24
|
+
const db = historyDatabase();
|
|
25
|
+
const meta = chatMetaOf(scope);
|
|
26
|
+
saveHistory(archiveKey(id), turns);
|
|
27
|
+
db.prepare("INSERT INTO archives (id, scope, title, updated, pinned, project, backend) VALUES (?, ?, ?, ?, 0, ?, ?)").run(id, scope, meta?.title || chatTitle(turns), new Date().toISOString(), meta?.project ?? "", meta?.backend ?? "");
|
|
28
|
+
const extra = db
|
|
29
|
+
.prepare("SELECT id FROM archives WHERE scope = ? AND pinned = 0 ORDER BY updated DESC LIMIT -1 OFFSET ?")
|
|
30
|
+
.all(scope, KEEP);
|
|
31
|
+
for (const row of extra)
|
|
32
|
+
removeArchivedChat(row.id);
|
|
33
|
+
// The live chat is empty now: it should not linger in the project's list of chats, and its
|
|
34
|
+
// queue belongs to the chat that was put aside.
|
|
35
|
+
await writeAgentHistory(scope, [], meta, undefined, undefined, undefined, null);
|
|
36
|
+
return id;
|
|
37
|
+
}
|
|
38
|
+
/** Makes an archived chat the live one (the one that was live is put aside) and returns it. */
|
|
39
|
+
export async function openArchivedChat(scope, id) {
|
|
40
|
+
const row = historyDatabase()
|
|
41
|
+
.prepare("SELECT id, title, project, backend FROM archives WHERE id = ? AND scope = ?")
|
|
42
|
+
.get(id, scope);
|
|
43
|
+
const turns = row ? loadHistory(archiveKey(id)) : undefined;
|
|
44
|
+
if (!row || !turns)
|
|
45
|
+
throw new Error("Чат не найден");
|
|
46
|
+
await archiveLiveChat(scope);
|
|
47
|
+
removeArchivedChat(id);
|
|
48
|
+
const index = row.project && row.backend
|
|
49
|
+
? { project: row.project, backend: row.backend, title: row.title }
|
|
50
|
+
: undefined;
|
|
51
|
+
return writeAgentHistory(scope, turns, index, undefined, undefined, undefined, null);
|
|
52
|
+
}
|
|
53
|
+
export function renameArchivedChat(id, change) {
|
|
54
|
+
const db = historyDatabase();
|
|
55
|
+
if (change.title !== undefined) {
|
|
56
|
+
const title = change.title.trim().slice(0, 200);
|
|
57
|
+
if (!title)
|
|
58
|
+
throw new Error("Название не может быть пустым");
|
|
59
|
+
db.prepare("UPDATE archives SET title = ? WHERE id = ?").run(title, id);
|
|
60
|
+
}
|
|
61
|
+
if (change.pinned !== undefined)
|
|
62
|
+
db.prepare("UPDATE archives SET pinned = ? WHERE id = ?").run(change.pinned ? 1 : 0, id);
|
|
63
|
+
}
|
|
64
|
+
export function removeArchivedChat(id) {
|
|
65
|
+
historyDatabase().prepare("DELETE FROM archives WHERE id = ?").run(id);
|
|
66
|
+
deleteHistory(archiveKey(id));
|
|
67
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
const host = globalThis;
|
|
3
|
+
const pending = (host.projectorCommandPending ??= new Map());
|
|
4
|
+
/** Each request has a single-use capability, delivered only to its originating SSE client. */
|
|
5
|
+
function bridgeRequest(send, payload, signal, timeoutMs, timeoutMessage) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
if (signal.aborted)
|
|
8
|
+
return reject(new Error("Запрос остановлен"));
|
|
9
|
+
const id = randomUUID();
|
|
10
|
+
const finish = (result) => {
|
|
11
|
+
clearTimeout(timer);
|
|
12
|
+
signal.removeEventListener("abort", cancel);
|
|
13
|
+
pending.delete(id);
|
|
14
|
+
if (result.error)
|
|
15
|
+
reject(new Error(result.error));
|
|
16
|
+
else
|
|
17
|
+
resolve(result.output);
|
|
18
|
+
};
|
|
19
|
+
const cancel = () => finish({ error: "Запрос остановлен" });
|
|
20
|
+
const timer = setTimeout(() => finish({ error: timeoutMessage }), timeoutMs);
|
|
21
|
+
pending.set(id, finish);
|
|
22
|
+
signal.addEventListener("abort", cancel, { once: true });
|
|
23
|
+
send({ id, ...payload });
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
export function createCommandBridge(emit, signal, timeoutMs = 60000) {
|
|
27
|
+
return (request) => bridgeRequest((data) => emit("command-request", data), request, signal, timeoutMs, "Projector не ответил на вызов команды");
|
|
28
|
+
}
|
|
29
|
+
/** Resolves `true` only when the user explicitly allows; a denial, timeout or abort rejects or yields `false`. */
|
|
30
|
+
export function createApprovalBridge(emit, signal, timeoutMs = 10 * 60_000) {
|
|
31
|
+
return async (request) => {
|
|
32
|
+
const output = await bridgeRequest((data) => emit("permission-request", data), request, signal, timeoutMs, "Разрешение не получено вовремя");
|
|
33
|
+
const answer = output;
|
|
34
|
+
if (answer?.allow !== true)
|
|
35
|
+
return false;
|
|
36
|
+
return answer.always === true ? "always" : true;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/** Resolves the user's answers, `null` when they skip; abort and timeout reject. */
|
|
40
|
+
export function createQuestionBridge(emit, signal, timeoutMs = 60 * 60_000) {
|
|
41
|
+
return async (request) => {
|
|
42
|
+
const output = await bridgeRequest((data) => emit("question-request", data), request, signal, timeoutMs, "Ответ на вопрос не получен вовремя");
|
|
43
|
+
const answers = output?.answers;
|
|
44
|
+
if (!answers || typeof answers !== "object")
|
|
45
|
+
return null;
|
|
46
|
+
const result = {};
|
|
47
|
+
for (const [id, value] of Object.entries(answers)) {
|
|
48
|
+
if (!Array.isArray(value))
|
|
49
|
+
continue;
|
|
50
|
+
result[id] = value.filter((item) => typeof item === "string").slice(0, 50);
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolves the typed secret, `null` when the user declines. The value reaches only the caller
|
|
57
|
+
* that stores it; no event, error text or log of the bridge carries it.
|
|
58
|
+
*/
|
|
59
|
+
export function createSecretBridge(emit, signal, timeoutMs = 10 * 60_000) {
|
|
60
|
+
return async (request) => {
|
|
61
|
+
const output = await bridgeRequest((data) => emit("secret-request", data), request, signal, timeoutMs, "Секрет не получен вовремя");
|
|
62
|
+
const value = output?.value;
|
|
63
|
+
return typeof value === "string" && value ? value : null;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Requests asked by a run held outside this server (its own process): the answer goes back to that
|
|
68
|
+
* process, which keeps the request open. Registered by whichever server is attached to the run.
|
|
69
|
+
*/
|
|
70
|
+
const relayed = (host.projectorCommandRelayed ??= new Map());
|
|
71
|
+
export function relayRequest(id, deliver) {
|
|
72
|
+
relayed.set(id, deliver);
|
|
73
|
+
}
|
|
74
|
+
export function unrelayRequests(ids) {
|
|
75
|
+
for (const id of ids)
|
|
76
|
+
relayed.delete(id);
|
|
77
|
+
}
|
|
78
|
+
/** Whether the request still waits for its user: a page that joins later may show it. */
|
|
79
|
+
export function isBridgeRequestPending(id) {
|
|
80
|
+
return pending.has(id) || relayed.has(id);
|
|
81
|
+
}
|
|
82
|
+
export function completeCommandRequest(id, result) {
|
|
83
|
+
const finish = pending.get(id);
|
|
84
|
+
if (!finish) {
|
|
85
|
+
const deliver = relayed.get(id);
|
|
86
|
+
if (!deliver)
|
|
87
|
+
return false;
|
|
88
|
+
relayed.delete(id);
|
|
89
|
+
deliver(result);
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
finish(result);
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Longest list sent to the client: agents may hold thousands of past sessions. */
|
|
2
|
+
export const SESSION_LIST_LIMIT = 30;
|
|
3
|
+
export function selectionFrom(value) {
|
|
4
|
+
const selection = {};
|
|
5
|
+
if (value && typeof value === "object")
|
|
6
|
+
for (const [id, item] of Object.entries(value))
|
|
7
|
+
if (typeof item === "string" && id.length <= 100 && item.length <= 300)
|
|
8
|
+
selection[id] = item;
|
|
9
|
+
return selection;
|
|
10
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { onEventClientClose } from "../events/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Answers delivered through a page's events stream, by the page's stream ID: how to detach and
|
|
4
|
+
* whose answer it is. Kept across hot reloads, which leave answers in progress running.
|
|
5
|
+
*/
|
|
6
|
+
const host = globalThis;
|
|
7
|
+
const state = (host.projectorAgentStreams ??= {
|
|
8
|
+
detach: new Map(),
|
|
9
|
+
owners: new Map(),
|
|
10
|
+
});
|
|
11
|
+
/** Replace the page-close subscription only when this generation is activated. */
|
|
12
|
+
export function bindAgentEventStreams() {
|
|
13
|
+
state.off?.();
|
|
14
|
+
const off = onEventClientClose((client) => {
|
|
15
|
+
for (const [stream, owner] of [...state.owners])
|
|
16
|
+
if (owner === client)
|
|
17
|
+
state.detach.get(stream)?.();
|
|
18
|
+
});
|
|
19
|
+
state.off = off;
|
|
20
|
+
return () => {
|
|
21
|
+
off();
|
|
22
|
+
if (state.off === off)
|
|
23
|
+
state.off = undefined;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** Registers an answer of `client`; the returned function forgets it. */
|
|
27
|
+
export function trackEventStream(stream, client, detach) {
|
|
28
|
+
if (!state.off)
|
|
29
|
+
bindAgentEventStreams();
|
|
30
|
+
state.detach.set(stream, detach);
|
|
31
|
+
state.owners.set(stream, client);
|
|
32
|
+
return () => {
|
|
33
|
+
state.detach.delete(stream);
|
|
34
|
+
state.owners.delete(stream);
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** The page stopped waiting for the answer. */
|
|
38
|
+
export function detachEventStream(stream) {
|
|
39
|
+
state.detach.get(stream)?.();
|
|
40
|
+
}
|