@rynx-ai/server 0.1.11-beta.5 → 0.1.11-beta.51
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/dist/control-api.d.ts +11 -5
- package/dist/control-api.js +699 -95
- package/dist/control-web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/control-web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/control-web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/control-web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/control-web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/control-web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/control-web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/control-web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/control-web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/control-web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/control-web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/control-web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/control-web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/control-web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/control-web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/control-web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/control-web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/control-web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/control-web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/control-web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/control-web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/control-web/assets/abap-CLvhMVsD.js +1 -0
- package/dist/control-web/assets/abnfDiagram-VRR7QNED-D_NL89dn.js +1 -0
- package/dist/control-web/assets/actionscript-3--17pq3dv.js +1 -0
- package/dist/control-web/assets/ada-C5qYipkI.js +1 -0
- package/dist/control-web/assets/andromeeda-vGVdxbeo.js +1 -0
- package/dist/control-web/assets/angular-html-DlZBZkSp.js +1 -0
- package/dist/control-web/assets/angular-ts-BVPGOT0K.js +1 -0
- package/dist/control-web/assets/apache-U0d_L8uA.js +1 -0
- package/dist/control-web/assets/apex-CGTLDQj6.js +1 -0
- package/dist/control-web/assets/apl-cDmXqmZ-.js +1 -0
- package/dist/control-web/assets/applescript-CCn79oCD.js +1 -0
- package/dist/control-web/assets/ara-4CJ0cIlV.js +1 -0
- package/dist/control-web/assets/arc-Pry-7G1_.js +1 -0
- package/dist/control-web/assets/architecture-TIHT7OUA-C9wU1KtW.js +1 -0
- package/dist/control-web/assets/architectureDiagram-ZJ3FMSHR-CV0rxVH6.js +36 -0
- package/dist/control-web/assets/array-BifhSqXX.js +1 -0
- package/dist/control-web/assets/asciidoc-DE70LPWp.js +1 -0
- package/dist/control-web/assets/asm-Cmm7eHzH.js +1 -0
- package/dist/control-web/assets/astro-B1Q6BwBx.js +1 -0
- package/dist/control-web/assets/aurora-x-CDeNXAV0.js +1 -0
- package/dist/control-web/assets/awk-BWXHIvNe.js +1 -0
- package/dist/control-web/assets/ayu-dark-DluEY0Gj.js +1 -0
- package/dist/control-web/assets/ayu-light-C3h-C4tm.js +1 -0
- package/dist/control-web/assets/ayu-mirage-Bqwy1Gya.js +1 -0
- package/dist/control-web/assets/ballerina-B7ZEbQpA.js +1 -0
- package/dist/control-web/assets/bat-Bo4NYOV-.js +1 -0
- package/dist/control-web/assets/beancount-D-usSTwE.js +1 -0
- package/dist/control-web/assets/berry-DKpUyyne.js +1 -0
- package/dist/control-web/assets/bibtex-Ci_nEsc7.js +1 -0
- package/dist/control-web/assets/bicep-CUHmPFLl.js +1 -0
- package/dist/control-web/assets/bird2-C2hNVINV.js +1 -0
- package/dist/control-web/assets/blade-Xpu-LGTm.js +1 -0
- package/dist/control-web/assets/blockDiagram-677ZJIJ3-Cc7nrkZh.js +132 -0
- package/dist/control-web/assets/bsl-BkkzgIyY.js +1 -0
- package/dist/control-web/assets/c-iCihek07.js +1 -0
- package/dist/control-web/assets/c3-CnJL0r0V.js +1 -0
- package/dist/control-web/assets/c4Diagram-LMCZKHZV-BPRU9m-F.js +10 -0
- package/dist/control-web/assets/cadence-CQ2zXKGN.js +1 -0
- package/dist/control-web/assets/cairo-DLTphjLi.js +1 -0
- package/dist/control-web/assets/catppuccin-frappe-3VR1Za6u.js +1 -0
- package/dist/control-web/assets/catppuccin-latte-DwIHMF0Q.js +1 -0
- package/dist/control-web/assets/catppuccin-macchiato-DYnBP6_5.js +1 -0
- package/dist/control-web/assets/catppuccin-mocha-DYhrFGRu.js +1 -0
- package/dist/control-web/assets/channel-BFm2_j8K.js +1 -0
- package/dist/control-web/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- package/dist/control-web/assets/chunk-32BRIVSS-Bbq3O54m.js +1 -0
- package/dist/control-web/assets/chunk-52WLFC77-sD4al-Ob.js +10 -0
- package/dist/control-web/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- package/dist/control-web/assets/chunk-7BUUIJ7U-Bb538aSH.js +1 -0
- package/dist/control-web/assets/chunk-C7G6YPKG-DqHaDS1O.js +1 -0
- package/dist/control-web/assets/chunk-EX3LRPZG-36GNQ5wp.js +231 -0
- package/dist/control-web/assets/chunk-HOUHSVGY-DeZ63q1j.js +1 -0
- package/dist/control-web/assets/chunk-ICXQ74PX-D2yF6lD_.js +2 -0
- package/dist/control-web/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- package/dist/control-web/assets/chunk-KEIR6QF5-BICK3FdT.js +161 -0
- package/dist/control-web/assets/chunk-MOJQB5TN-CdaKyBz5.js +88 -0
- package/dist/control-web/assets/chunk-OGEWGWER-eOXC7kiH.js +1 -0
- package/dist/control-web/assets/chunk-PUDLZKDR-6w0LILL_.js +156 -0
- package/dist/control-web/assets/chunk-Q4XR5HBZ-CXgD5TGL.js +70 -0
- package/dist/control-web/assets/chunk-RYQCIY6F-BsoV8yK2.js +1 -0
- package/dist/control-web/assets/chunk-V7JOEXUC-BfoZ78b6.js +206 -0
- package/dist/control-web/assets/chunk-VR4S4FIN-BW2gCEMQ.js +1 -0
- package/dist/control-web/assets/chunk-WYO6CB5R-CHn7hulw.js +128 -0
- package/dist/control-web/assets/chunk-XXDRQBXY-DqAYeljN.js +1 -0
- package/dist/control-web/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- package/dist/control-web/assets/chunk-ZGVPDNZ5-CmFP0-fr.js +62 -0
- package/dist/control-web/assets/clarity-SemFz856.js +1 -0
- package/dist/control-web/assets/classDiagram-OUVF2IWQ-CUe_bETB.js +1 -0
- package/dist/control-web/assets/classDiagram-v2-EOCWNBFH-CUe_bETB.js +1 -0
- package/dist/control-web/assets/clojure-DqKBuwfJ.js +1 -0
- package/dist/control-web/assets/cmake-Bj61d0ZC.js +1 -0
- package/dist/control-web/assets/cobol-BsV-839J.js +1 -0
- package/dist/control-web/assets/codeowners-C8r90Shi.js +1 -0
- package/dist/control-web/assets/codeql-oeQT6MSM.js +1 -0
- package/dist/control-web/assets/coffee-CiiSLhB6.js +1 -0
- package/dist/control-web/assets/common-lisp-Cv5bFMCO.js +1 -0
- package/dist/control-web/assets/coq-BrsZFFmf.js +1 -0
- package/dist/control-web/assets/cose-bilkent-JH36ORCC-lJEhNiw_.js +1 -0
- package/dist/control-web/assets/cpp-DjoE5qBx.js +1 -0
- package/dist/control-web/assets/crystal-DDxHDkHz.js +1 -0
- package/dist/control-web/assets/csharp-Ct8U2NOr.js +1 -0
- package/dist/control-web/assets/css-LjpOdHib.js +1 -0
- package/dist/control-web/assets/csv-Dx-8-gkx.js +1 -0
- package/dist/control-web/assets/cue-CE9AQfxI.js +1 -0
- package/dist/control-web/assets/cynefin-VYW2F7L2-NaLr7Qlq.js +1 -0
- package/dist/control-web/assets/cynefinDiagram-TSTJHNR4-C90wpjAI.js +62 -0
- package/dist/control-web/assets/cypher-ClKdZ_lG.js +1 -0
- package/dist/control-web/assets/cytoscape.esm-B-NFISlW.js +321 -0
- package/dist/control-web/assets/d-qD-0Kul2.js +1 -0
- package/dist/control-web/assets/dagre-Buvkdvvj.js +1 -0
- package/dist/control-web/assets/dagre-VKFMJZFB-BxrPFWTb.js +4 -0
- package/dist/control-web/assets/dark-plus-Cs2F2srj.js +1 -0
- package/dist/control-web/assets/dart-DkHntEIa.js +1 -0
- package/dist/control-web/assets/dax-BkyTk9wS.js +1 -0
- package/dist/control-web/assets/defaultLocale-BFoDCU3G.js +1 -0
- package/dist/control-web/assets/desktop-Dlh5hvp9.js +1 -0
- package/dist/control-web/assets/diagram-FQU43EPY-VIQINsvz.js +3 -0
- package/dist/control-web/assets/diagram-G47NLZAW-DFeAfYXn.js +24 -0
- package/dist/control-web/assets/diagram-NH7WQ7WH-ATzdppDd.js +24 -0
- package/dist/control-web/assets/diagram-OA4YK3LP-DJZpWmbl.js +30 -0
- package/dist/control-web/assets/diagram-WEI45ONY-CqDHcW3g.js +41 -0
- package/dist/control-web/assets/diff-woXpYk--.js +1 -0
- package/dist/control-web/assets/dist-Dx9YWgcW.js +153 -0
- package/dist/control-web/assets/dist-v5Q1xZ2K.js +1 -0
- package/dist/control-web/assets/docker-IyjqRm3v.js +1 -0
- package/dist/control-web/assets/dotenv-_5a1GRtc.js +1 -0
- package/dist/control-web/assets/dracula-BHWKrbxM.js +1 -0
- package/dist/control-web/assets/dracula-soft-5eyTD99u.js +1 -0
- package/dist/control-web/assets/dream-maker-DW3nJb8Q.js +1 -0
- package/dist/control-web/assets/ebnfDiagram-CCIWWBDH-DnP6dHND.js +1 -0
- package/dist/control-web/assets/edge-8z7Jp9dO.js +1 -0
- package/dist/control-web/assets/elixir-CUV54ev5.js +1 -0
- package/dist/control-web/assets/elm-o4NJxfws.js +1 -0
- package/dist/control-web/assets/emacs-lisp-C9PiwqqW.js +1 -0
- package/dist/control-web/assets/erDiagram-Q63AITRT-Bo8bFqrZ.js +85 -0
- package/dist/control-web/assets/erb-CIsHcwm1.js +1 -0
- package/dist/control-web/assets/erlang-Cphh6RMH.js +1 -0
- package/dist/control-web/assets/eventmodeling-45OFAUF4-DTN8wqsu.js +1 -0
- package/dist/control-web/assets/everforest-dark-sB-x3p7T.js +1 -0
- package/dist/control-web/assets/everforest-light-Df2xbC6M.js +1 -0
- package/dist/control-web/assets/fennel-DQxkIbk2.js +1 -0
- package/dist/control-web/assets/fish-BJitypiv.js +1 -0
- package/dist/control-web/assets/flowDiagram-23GEKE2U-BwjqRyvd.js +1 -0
- package/dist/control-web/assets/fluent-C03EYrpw.js +1 -0
- package/dist/control-web/assets/fortran-fixed-form-DEKoE2YW.js +1 -0
- package/dist/control-web/assets/fortran-free-form-CYNrtFtB.js +1 -0
- package/dist/control-web/assets/fsharp-D13ZGOAj.js +1 -0
- package/dist/control-web/assets/ganttDiagram-NO4QXBWP-kxQaBTzd.js +292 -0
- package/dist/control-web/assets/gdresource-C0sCabJj.js +1 -0
- package/dist/control-web/assets/gdscript-Cp2uCuqX.js +1 -0
- package/dist/control-web/assets/gdshader-CBce3t8t.js +1 -0
- package/dist/control-web/assets/genie-CV2tkWYe.js +1 -0
- package/dist/control-web/assets/gherkin-DExj1W_8.js +1 -0
- package/dist/control-web/assets/git-commit-BSykSTBG.js +1 -0
- package/dist/control-web/assets/git-rebase-BDPpS8w6.js +1 -0
- package/dist/control-web/assets/gitGraph-TEB2WS4Q-a646NnuJ.js +1 -0
- package/dist/control-web/assets/gitGraphDiagram-IHSO6WYX-BBe0q0At.js +106 -0
- package/dist/control-web/assets/github-dark-C-LZuMrd.js +1 -0
- package/dist/control-web/assets/github-dark-default-DXG-b-1a.js +1 -0
- package/dist/control-web/assets/github-dark-dimmed-Bx1FflLF.js +1 -0
- package/dist/control-web/assets/github-dark-high-contrast-B_tTalzw.js +1 -0
- package/dist/control-web/assets/github-light-EUqPIrTm.js +1 -0
- package/dist/control-web/assets/github-light-default-BXViO-2h.js +1 -0
- package/dist/control-web/assets/github-light-high-contrast-B68TUdTA.js +1 -0
- package/dist/control-web/assets/gleam-CSRkHgEL.js +1 -0
- package/dist/control-web/assets/glimmer-js-OEO36pDk.js +1 -0
- package/dist/control-web/assets/glimmer-ts-BnAPyISE.js +1 -0
- package/dist/control-web/assets/glsl-D5MA2a_X.js +1 -0
- package/dist/control-web/assets/gn-ilITqXS6.js +1 -0
- package/dist/control-web/assets/gnuplot-7GGW24-e.js +1 -0
- package/dist/control-web/assets/go-BJwz_mda.js +1 -0
- package/dist/control-web/assets/graphlib-DS17s2tU.js +1 -0
- package/dist/control-web/assets/graphql-Ctjuxyvl.js +1 -0
- package/dist/control-web/assets/groovy-CacY0gHj.js +1 -0
- package/dist/control-web/assets/gruvbox-dark-hard-C820rvS2.js +1 -0
- package/dist/control-web/assets/gruvbox-dark-medium-BPjhmG05.js +1 -0
- package/dist/control-web/assets/gruvbox-dark-soft-MrdJrrXF.js +1 -0
- package/dist/control-web/assets/gruvbox-light-hard-BC_s9l72.js +1 -0
- package/dist/control-web/assets/gruvbox-light-medium-BAWPOn9u.js +1 -0
- package/dist/control-web/assets/gruvbox-light-soft-BSMLrYjP.js +1 -0
- package/dist/control-web/assets/hack-D_mkkoLd.js +1 -0
- package/dist/control-web/assets/haml-mpgecWZ6.js +1 -0
- package/dist/control-web/assets/handlebars-CAx_777f.js +1 -0
- package/dist/control-web/assets/haskell-D8IpX4py.js +1 -0
- package/dist/control-web/assets/haxe-OTjmBuCE.js +1 -0
- package/dist/control-web/assets/hcl-Dh228itO.js +1 -0
- package/dist/control-web/assets/highlighted-body-OFNGDK62-DVCHy9oI.js +1 -0
- package/dist/control-web/assets/hjson-CxZEssPk.js +1 -0
- package/dist/control-web/assets/hlsl-Cvrh5tZx.js +1 -0
- package/dist/control-web/assets/horizon-CE9ld1lL.js +1 -0
- package/dist/control-web/assets/horizon-bright-Br1oVSNq.js +1 -0
- package/dist/control-web/assets/houston-CsvMBhTu.js +1 -0
- package/dist/control-web/assets/html-B2lrdnWr.js +1 -0
- package/dist/control-web/assets/html-derivative-CDfZYcul.js +1 -0
- package/dist/control-web/assets/http-kmH8AyfE.js +1 -0
- package/dist/control-web/assets/hurl-DCZHXKU4.js +1 -0
- package/dist/control-web/assets/hxml-B0Qn7Nwc.js +1 -0
- package/dist/control-web/assets/hy-CZbG8q4J.js +1 -0
- package/dist/control-web/assets/imba-DsUTQ-LC.js +1 -0
- package/dist/control-web/assets/index-D7URT6K_.js +140 -0
- package/dist/control-web/assets/index-uEpvRMX9.css +1 -0
- package/dist/control-web/assets/info-DKCQHKI2-Cp_JrY-b.js +1 -0
- package/dist/control-web/assets/infoDiagram-FWYZ7A6U-CAm-h4F_.js +2 -0
- package/dist/control-web/assets/ini-B5eOa1yu.js +1 -0
- package/dist/control-web/assets/init-C-OQMol4.js +1 -0
- package/dist/control-web/assets/ishikawaDiagram-FXEZZL3T-O17pqcWr.js +70 -0
- package/dist/control-web/assets/java-DdHNQ9hk.js +1 -0
- package/dist/control-web/assets/javascript-obGGvMPs.js +1 -0
- package/dist/control-web/assets/jinja-BMiPVedm.js +1 -0
- package/dist/control-web/assets/jison-CBjhYtSs.js +1 -0
- package/dist/control-web/assets/journeyDiagram-5HDEW3XC-DQ-JuSoR.js +139 -0
- package/dist/control-web/assets/json-DAgxKhMr.js +1 -0
- package/dist/control-web/assets/json5-BR5RXkoi.js +1 -0
- package/dist/control-web/assets/jsonc-CYpm1nAK.js +1 -0
- package/dist/control-web/assets/jsonl-CmCQp5Yx.js +1 -0
- package/dist/control-web/assets/jsonnet-CJTPZ8u_.js +1 -0
- package/dist/control-web/assets/jssm-DXw9l8Rf.js +1 -0
- package/dist/control-web/assets/jsx-gTgmArGx.js +1 -0
- package/dist/control-web/assets/julia-CjHxn3vf.js +1 -0
- package/dist/control-web/assets/just-DMArCiVH.js +1 -0
- package/dist/control-web/assets/kanagawa-dragon-CXtmUGW6.js +1 -0
- package/dist/control-web/assets/kanagawa-lotus-BN08jTvb.js +1 -0
- package/dist/control-web/assets/kanagawa-wave-CTweb8Dz.js +1 -0
- package/dist/control-web/assets/kanban-definition-HUTT4EX6-Cgv3kPbm.js +89 -0
- package/dist/control-web/assets/katex-CyHG4N6b.js +1 -0
- package/dist/control-web/assets/kdl-CsD5j6eV.js +1 -0
- package/dist/control-web/assets/kotlin-DhhofPvG.js +1 -0
- package/dist/control-web/assets/kusto-BUv0MjJC.js +1 -0
- package/dist/control-web/assets/laserwave-C_8bwKvT.js +1 -0
- package/dist/control-web/assets/latex-D9bvcAJr.js +1 -0
- package/dist/control-web/assets/lean-CewbzKMR.js +1 -0
- package/dist/control-web/assets/less-DVTAwKKz.js +1 -0
- package/dist/control-web/assets/lib-BZ_F5vVH.js +1 -0
- package/dist/control-web/assets/light-plus-DVQuIRkW.js +1 -0
- package/dist/control-web/assets/line-DUsXzGJZ.js +1 -0
- package/dist/control-web/assets/linear-DmucvK78.js +1 -0
- package/dist/control-web/assets/liquid-CCX5qouA.js +1 -0
- package/dist/control-web/assets/llvm-Cm23YOpf.js +1 -0
- package/dist/control-web/assets/log-BNLmms1o.js +1 -0
- package/dist/control-web/assets/logo-Cluzi2Zq.js +1 -0
- package/dist/control-web/assets/lua-FONpmTUP.js +1 -0
- package/dist/control-web/assets/luau-CNKltnaQ.js +1 -0
- package/dist/control-web/assets/make-Dixweg8N.js +1 -0
- package/dist/control-web/assets/map-BaFkSB1l.js +1 -0
- package/dist/control-web/assets/markdown-BYOwaDjH.js +1 -0
- package/dist/control-web/assets/markdown-streamdown-4N4AcNp5.js +433 -0
- package/dist/control-web/assets/markdown-streamdown-DEcVZfaU.css +1 -0
- package/dist/control-web/assets/marko-oPGh3KfH.js +1 -0
- package/dist/control-web/assets/material-theme-Bm3Qr25_.js +1 -0
- package/dist/control-web/assets/material-theme-darker-2IIEA8gg.js +1 -0
- package/dist/control-web/assets/material-theme-lighter-uhdI0v04.js +1 -0
- package/dist/control-web/assets/material-theme-ocean-CHQ94UKr.js +1 -0
- package/dist/control-web/assets/material-theme-palenight-B5W6OYN7.js +1 -0
- package/dist/control-web/assets/matlab-D7qyCx1q.js +1 -0
- package/dist/control-web/assets/mdc-B_uQHOlt.js +1 -0
- package/dist/control-web/assets/mdx-DQZ5AkYe.js +1 -0
- package/dist/control-web/assets/mermaid-Bk4SNUv9.js +1 -0
- package/dist/control-web/assets/mermaid-GHXKKRXX-BElZGKGd.js +1 -0
- package/dist/control-web/assets/mermaid-parser.core-VMln12Kd.js +7 -0
- package/dist/control-web/assets/min-dark-BSWPekZh.js +1 -0
- package/dist/control-web/assets/min-light-DDpmG2fV.js +1 -0
- package/dist/control-web/assets/mindmap-definition-LN4V7U3C-Bn0lH-UM.js +96 -0
- package/dist/control-web/assets/mipsasm-BMqwQI7S.js +1 -0
- package/dist/control-web/assets/mojo-BgCJLMeH.js +1 -0
- package/dist/control-web/assets/monokai-CdkpiU2Y.js +1 -0
- package/dist/control-web/assets/moonbit-CaWjb8XO.js +1 -0
- package/dist/control-web/assets/move-B1IS1UjX.js +1 -0
- package/dist/control-web/assets/narrat-_X_XdTYD.js +1 -0
- package/dist/control-web/assets/nextflow-Bbiyy34d.js +1 -0
- package/dist/control-web/assets/nextflow-groovy-Dc_ddanL.js +1 -0
- package/dist/control-web/assets/nginx-BTMw9COX.js +1 -0
- package/dist/control-web/assets/night-owl-DhmEMT88.js +1 -0
- package/dist/control-web/assets/night-owl-light-eJ-hLW7d.js +1 -0
- package/dist/control-web/assets/nim-8PQFL6ZB.js +1 -0
- package/dist/control-web/assets/nix-IvuFDN5E.js +1 -0
- package/dist/control-web/assets/nord-Cb4Vim4T.js +1 -0
- package/dist/control-web/assets/nushell-DcLAeLz5.js +1 -0
- package/dist/control-web/assets/objective-c-D1A_Heim.js +1 -0
- package/dist/control-web/assets/objective-cpp-BsSzOQcm.js +1 -0
- package/dist/control-web/assets/ocaml-O90oeIOV.js +1 -0
- package/dist/control-web/assets/odin-B1RWQWA5.js +1 -0
- package/dist/control-web/assets/one-dark-pro-CLwyXe_n.js +1 -0
- package/dist/control-web/assets/one-light-D7Lr4KcI.js +1 -0
- package/dist/control-web/assets/openscad-BUDT5pXO.js +1 -0
- package/dist/control-web/assets/ordinal-BDEzSJ7C.js +1 -0
- package/dist/control-web/assets/packet-7NZHBO7P-Zw8iJ8lo.js +1 -0
- package/dist/control-web/assets/pascal-4ZHwLPI5.js +1 -0
- package/dist/control-web/assets/path-fybaL0A-.js +1 -0
- package/dist/control-web/assets/pegDiagram-2B236MQR-CtF7vVs_.js +1 -0
- package/dist/control-web/assets/perl-Vf0i0hAx.js +1 -0
- package/dist/control-web/assets/php-am1OsKhm.js +1 -0
- package/dist/control-web/assets/pie-RZYD4A2V-su_3QGU2.js +1 -0
- package/dist/control-web/assets/pieDiagram-ENE6RG2P-BkMUBLE1.js +39 -0
- package/dist/control-web/assets/pkl-ot-7Btpt.js +1 -0
- package/dist/control-web/assets/plastic-DQwYfKfQ.js +1 -0
- package/dist/control-web/assets/plsql-DGHpHOYJ.js +1 -0
- package/dist/control-web/assets/po-BiJDBrnU.js +1 -0
- package/dist/control-web/assets/poimandres-DRFjx7u4.js +1 -0
- package/dist/control-web/assets/polar-C7UOKdEL.js +1 -0
- package/dist/control-web/assets/postcss-BXeXVLqQ.js +1 -0
- package/dist/control-web/assets/powerquery-DNMTfnFr.js +1 -0
- package/dist/control-web/assets/powershell-DshXNtvi.js +1 -0
- package/dist/control-web/assets/prisma-BsRQq5mF.js +1 -0
- package/dist/control-web/assets/prolog-iXnhIJG7.js +1 -0
- package/dist/control-web/assets/proto-DB4EqR-F.js +1 -0
- package/dist/control-web/assets/pug-DO6yvBr3.js +1 -0
- package/dist/control-web/assets/puppet-CDv2pdJW.js +1 -0
- package/dist/control-web/assets/purescript-9MfHhQsQ.js +1 -0
- package/dist/control-web/assets/python-gzcpVVnB.js +1 -0
- package/dist/control-web/assets/qml-_a-QhfPD.js +1 -0
- package/dist/control-web/assets/qmldir-DCQb3MpD.js +1 -0
- package/dist/control-web/assets/qss-Fe1Jh2GI.js +1 -0
- package/dist/control-web/assets/quadrantDiagram-ABIIQ3AL-ba-VaqMe.js +7 -0
- package/dist/control-web/assets/r-D6UWEOL2.js +1 -0
- package/dist/control-web/assets/racket-DcIDlBhZ.js +1 -0
- package/dist/control-web/assets/radar-I7S5WNFK-Dat0rqem.js +1 -0
- package/dist/control-web/assets/railroad-3IZDKUUU-Dh2-s8r8.js +1 -0
- package/dist/control-web/assets/railroad-abnf-AHOZXSZD-CNUwq0JR.js +1 -0
- package/dist/control-web/assets/railroad-ebnf-EBAXGLYW-RHr0duea.js +1 -0
- package/dist/control-web/assets/railroad-peg-LSFZ7HO6-CVBWS2eU.js +1 -0
- package/dist/control-web/assets/railroadDiagram-RFXS5EU6-BiJX3SY-.js +1 -0
- package/dist/control-web/assets/raku-B3gFvitq.js +1 -0
- package/dist/control-web/assets/razor-CMVBVp3T.js +1 -0
- package/dist/control-web/assets/red-CJ3rzSJv.js +1 -0
- package/dist/control-web/assets/reg-CRGYupPL.js +1 -0
- package/dist/control-web/assets/regexp-DR20uMnK.js +1 -0
- package/dist/control-web/assets/rel-BtDbiS_P.js +1 -0
- package/dist/control-web/assets/requirementDiagram-TGXJPOKE-CFfakCzs.js +84 -0
- package/dist/control-web/assets/riscv-Ckw8ddFX.js +1 -0
- package/dist/control-web/assets/rolldown-runtime-hePW80VL.js +1 -0
- package/dist/control-web/assets/ron-VUp2lXgN.js +1 -0
- package/dist/control-web/assets/rose-pine-BthvhNj6.js +1 -0
- package/dist/control-web/assets/rose-pine-dawn-Dg85fqjY.js +1 -0
- package/dist/control-web/assets/rose-pine-moon-hon4tzzS.js +1 -0
- package/dist/control-web/assets/rosmsg-CAekHB0j.js +1 -0
- package/dist/control-web/assets/rough.esm-Dy-Kn_BL.js +1 -0
- package/dist/control-web/assets/rst-CgIrbW_q.js +1 -0
- package/dist/control-web/assets/ruby-Dp6Zud9H.js +1 -0
- package/dist/control-web/assets/rust-Cfkwpbl8.js +1 -0
- package/dist/control-web/assets/sankeyDiagram-HTMAVEWB-jgDi0God.js +40 -0
- package/dist/control-web/assets/sas-B6p8-ynO.js +1 -0
- package/dist/control-web/assets/sass-DXrisJhu.js +1 -0
- package/dist/control-web/assets/scala-DKOlJaKm.js +1 -0
- package/dist/control-web/assets/scheme-DQCgrYNe.js +1 -0
- package/dist/control-web/assets/scss-DcoSS-ti.js +1 -0
- package/dist/control-web/assets/sdbl-bTVj8UrX.js +1 -0
- package/dist/control-web/assets/sequenceDiagram-DBY2YBRQ-DBfyyb0N.js +162 -0
- package/dist/control-web/assets/shaderlab-TOUzSsQk.js +1 -0
- package/dist/control-web/assets/shellscript-Da78Ox-3.js +1 -0
- package/dist/control-web/assets/shellsession-CVsQGYfZ.js +1 -0
- package/dist/control-web/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +1 -0
- package/dist/control-web/assets/slack-dark-DnToyrRv.js +1 -0
- package/dist/control-web/assets/slack-ochin-B2OO5cIa.js +1 -0
- package/dist/control-web/assets/smalltalk-B16xEiuN.js +1 -0
- package/dist/control-web/assets/snazzy-light-4G7pJPwS.js +1 -0
- package/dist/control-web/assets/solarized-dark-DV17i1UV.js +1 -0
- package/dist/control-web/assets/solarized-light-DSh2HLQt.js +1 -0
- package/dist/control-web/assets/solidity-CKzVLygQ.js +1 -0
- package/dist/control-web/assets/soy-B5n_eHSp.js +1 -0
- package/dist/control-web/assets/sparql-D_iOobhT.js +1 -0
- package/dist/control-web/assets/splunk-BC2Px7Mm.js +1 -0
- package/dist/control-web/assets/sql-ClgswhA6.js +1 -0
- package/dist/control-web/assets/src-B6xuSHsQ.js +1 -0
- package/dist/control-web/assets/ssh-config-BgfXC-Er.js +1 -0
- package/dist/control-web/assets/stata-RoaAgbqU.js +1 -0
- package/dist/control-web/assets/stateDiagram-2N3HPSRC-Dwb_ncVi.js +1 -0
- package/dist/control-web/assets/stateDiagram-v2-6OUMAXLB-DI0opaA1.js +1 -0
- package/dist/control-web/assets/stylus-B6D30XZt.js +1 -0
- package/dist/control-web/assets/surrealql-DIn4NJsS.js +1 -0
- package/dist/control-web/assets/svelte-CIt8Fl9I.js +1 -0
- package/dist/control-web/assets/swift-DonLKvLd.js +1 -0
- package/dist/control-web/assets/swimlanes-5IMT3BWC-DW0LuiIV.js +2 -0
- package/dist/control-web/assets/swimlanesDiagram-G3AALYLV-DDTVjcOR.js +8 -0
- package/dist/control-web/assets/synthwave-84-nFMaYfgc.js +1 -0
- package/dist/control-web/assets/system-verilog-DJ5XKQeo.js +1 -0
- package/dist/control-web/assets/systemd-BxMlprV5.js +1 -0
- package/dist/control-web/assets/talonscript-CohzipZa.js +1 -0
- package/dist/control-web/assets/tasl-DMoTqEGO.js +1 -0
- package/dist/control-web/assets/tcl-CZd0xW_V.js +1 -0
- package/dist/control-web/assets/templ-BREsJpNc.js +1 -0
- package/dist/control-web/assets/terraform-DswuEJGm.js +1 -0
- package/dist/control-web/assets/tex-0w6-Dtgt.js +1 -0
- package/dist/control-web/assets/timeline-definition-FHXFAJF6-DeX4B_B8.js +120 -0
- package/dist/control-web/assets/tokyo-night-oM2G3aXe.js +1 -0
- package/dist/control-web/assets/toml-CcmNWLt0.js +1 -0
- package/dist/control-web/assets/treeView-QDETBFTQ-D1UXtICj.js +1 -0
- package/dist/control-web/assets/treemap-6X3UGDF4-CrppzjZH.js +1 -0
- package/dist/control-web/assets/ts-tags-q3pptdMi.js +1 -0
- package/dist/control-web/assets/tsv-sltzmVWM.js +1 -0
- package/dist/control-web/assets/tsx-CUOciP0b.js +1 -0
- package/dist/control-web/assets/turtle-ByJddavk.js +1 -0
- package/dist/control-web/assets/twig-LIeLXgf5.js +1 -0
- package/dist/control-web/assets/typescript-BydbNFcO.js +1 -0
- package/dist/control-web/assets/typespec-B88KGewJ.js +1 -0
- package/dist/control-web/assets/typst-DI99ib-x.js +1 -0
- package/dist/control-web/assets/v-DETTlOr0.js +1 -0
- package/dist/control-web/assets/vala-zf12oZj6.js +1 -0
- package/dist/control-web/assets/vb-Djn5o6TS.js +1 -0
- package/dist/control-web/assets/vennDiagram-L72KCM5P-BYpf-7VR.js +34 -0
- package/dist/control-web/assets/verilog-CiiDBU1e.js +1 -0
- package/dist/control-web/assets/vesper-D5bVUKB1.js +1 -0
- package/dist/control-web/assets/vhdl-BroJfC0k.js +1 -0
- package/dist/control-web/assets/viml-DvXPmvsu.js +1 -0
- package/dist/control-web/assets/vitesse-black-fwtXNY1n.js +1 -0
- package/dist/control-web/assets/vitesse-dark-BZCL-v6S.js +1 -0
- package/dist/control-web/assets/vitesse-light-VbXTXTou.js +1 -0
- package/dist/control-web/assets/vue-DVSfBueU.js +1 -0
- package/dist/control-web/assets/vue-html-DkKkQnZL.js +1 -0
- package/dist/control-web/assets/vue-vine-pWqEcBkW.js +1 -0
- package/dist/control-web/assets/vyper-CgoNMtux.js +1 -0
- package/dist/control-web/assets/wardley-OPB4EBWU-B9rA0UsV.js +1 -0
- package/dist/control-web/assets/wardleyDiagram-EHGQE667-BdvAUa5F.js +78 -0
- package/dist/control-web/assets/wasm-BnjxR4X6.js +1 -0
- package/dist/control-web/assets/wasm-ByWQv1Qj.js +1 -0
- package/dist/control-web/assets/wenyan-C8pVoKbM.js +1 -0
- package/dist/control-web/assets/wgsl-BsKzXJz4.js +1 -0
- package/dist/control-web/assets/wikitext-ClFFjSW2.js +1 -0
- package/dist/control-web/assets/wit-DdvCle-K.js +1 -0
- package/dist/control-web/assets/wolfram-DLL8P-h_.js +1 -0
- package/dist/control-web/assets/xml-BlnrEAEy.js +1 -0
- package/dist/control-web/assets/xsl-BOPS8gLt.js +1 -0
- package/dist/control-web/assets/xychartDiagram-FW5EYKEG-BaEV3pGm.js +7 -0
- package/dist/control-web/assets/yaml-Du_6cdrH.js +1 -0
- package/dist/control-web/assets/zenscript-BnlCZFoB.js +1 -0
- package/dist/control-web/assets/zig-CMLA9XwU.js +1 -0
- package/dist/control-web/index.html +3 -2
- package/dist/control-web-dist.d.ts +1 -1
- package/dist/control-web-dist.js +4 -2
- package/dist/desktop-browser-host.d.ts +12 -1
- package/dist/desktop-browser-host.js +110 -13
- package/dist/direct-runtime-server.js +187 -153
- package/dist/machine-session-service.d.ts +96 -15
- package/dist/machine-session-service.js +745 -115
- package/dist/remote-runtime-dispatcher.d.ts +2 -2
- package/dist/remote-runtime-dispatcher.js +39 -2
- package/dist/remote-runtime-session-projection.d.ts +1 -0
- package/dist/remote-runtime-session-projection.js +12 -0
- package/dist/server.d.ts +67 -16
- package/dist/server.js +422 -55
- package/dist/session-browser-service.d.ts +50 -4
- package/dist/session-browser-service.js +232 -11
- package/dist/session-browser-surface-coordinator.d.ts +2 -0
- package/dist/session-browser-surface-coordinator.js +15 -0
- package/dist/session-pending-inputs.d.ts +42 -0
- package/dist/session-pending-inputs.js +87 -0
- package/dist/session-portal.d.ts +54 -0
- package/dist/session-portal.js +997 -0
- package/dist/session-runtime-index.d.ts +3 -6
- package/dist/session-runtime-index.js +96 -38
- package/dist/session-terminal-host.d.ts +22 -2
- package/dist/session-terminal-host.js +66 -83
- package/dist/terminal-ws.d.ts +4 -1
- package/dist/terminal-ws.js +93 -27
- package/package.json +7 -7
- package/dist/control-web/assets/highlighted-body-OFNGDK62-B4mcMjmm.js +0 -1
- package/dist/control-web/assets/index-5n6D-i-c.css +0 -32
- package/dist/control-web/assets/index-D56JQ9oi.js +0 -709
- package/dist/control-web/assets/mermaid-GHXKKRXX-DnL0iDTi.js +0 -131
package/dist/control-api.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* owns that state and exposes its own management application.
|
|
8
8
|
*/
|
|
9
9
|
import { timingSafeEqual } from "node:crypto";
|
|
10
|
+
import { Readable } from "node:stream";
|
|
10
11
|
import Router from "@koa/router";
|
|
11
12
|
import { skillInstallRecipeSchema, } from "@rynx-ai/core";
|
|
12
13
|
import { DAEMON_BROWSER_ARTIFACT_CLEAN_PATH, DAEMON_BROWSER_ARTIFACT_INSTALL_PATH, DAEMON_BROWSER_ARTIFACT_UPDATE_PATH, DAEMON_BROWSER_ARTIFACT_VERSION_PATH, DAEMON_CHROME_INSPECTION_PATH, DAEMON_CLEANUP_SESSIONS_PATH, DAEMON_MAINTENANCE_LEASE_HEADER, DAEMON_MAINTENANCE_LEASE_RELEASE_PATH, DAEMON_SHUTDOWN_IF_IDLE_PATH, parseDaemonBrowserArtifactInstallInput, parseDaemonBrowserArtifactUpdateInput, parseDaemonChromeInspectionConfigureInput, parseDaemonCleanupSessionsInput, } from "@rynx-ai/protocol/control";
|
|
@@ -14,11 +15,12 @@ import { DIRECT_RUNTIME_CONTROL_PATH, encodePairingCode, } from "@rynx-ai/protoc
|
|
|
14
15
|
import { PLUGIN_CONSOLE_INSTALL_PREPARATIONS_PATH, PLUGIN_CONSOLE_MARKETPLACES_PATH, PLUGIN_INSTALL_PREPARATIONS_PATH, PLUGIN_MARKETPLACES_PATH, parsePluginInstallCommitInput, parsePluginInstallPrepareInput, parsePluginMarketplaceAddInput, } from "@rynx-ai/protocol/plugin-management";
|
|
15
16
|
import { parseDaemonStatus } from "@rynx-ai/protocol/remote-runtime";
|
|
16
17
|
import { materializeRemoteRuntimeSessionEvent, materializeRemoteRuntimeSessionRuntimeSnapshot, parseRemoteRuntimeRpcRequest, REMOTE_RUNTIME_RPC_MAX_FRAME_BYTES, SESSION_IMAGE_MEDIA_TYPES, SESSION_RESOURCE_MAX_IMAGE_BYTES, SESSION_RESOURCE_MAX_FILENAME_CHARS, SESSION_RESOURCE_TRANSFER_CHUNK_BYTES, REMOTE_RUNTIME_SESSION_MAX_PAGE_SIZE, } from "@rynx-ai/protocol/remote-runtime-rpc";
|
|
17
|
-
import { RUNTIME_BROWSER_BOOTSTRAP_PATH, RUNTIME_BROWSER_CAPABILITY_HEADER, RUNTIME_BROWSER_MANAGEMENT_PATH_PREFIX, RUNTIME_BROWSER_RPC_PATH, RUNTIME_BROWSER_SESSION_ID_HEADER, parseRuntimeBrowserBootstrapCredential, } from "@rynx-ai/protocol/runtime-browser-bootstrap";
|
|
18
|
+
import { RUNTIME_BROWSER_BOOTSTRAP_PATH, RUNTIME_BROWSER_CAPABILITY_HEADER, RUNTIME_BROWSER_MANAGEMENT_PATH_PREFIX, RUNTIME_BROWSER_RPC_PATH, RUNTIME_BROWSER_EXECUTE_PATH, RUNTIME_BROWSER_SESSION_ID_HEADER, parseRuntimeBrowserBootstrapCredential, parseRuntimeBrowserAutomationCommand, } from "@rynx-ai/protocol/runtime-browser-bootstrap";
|
|
18
19
|
import { parseRuntimeBrowserStateGetParams } from "@rynx-ai/protocol/runtime-browser";
|
|
19
20
|
import { encodeDaemonStatus } from "./remote-runtime.js";
|
|
20
21
|
import { SessionRuntimeIndex } from "./session-runtime-index.js";
|
|
21
22
|
import { authorizeRuntimeWebRequest, RUNTIME_WEB_CAPABILITY, RUNTIME_WEB_CAPABILITY_HEADER, } from "./runtime-web-auth.js";
|
|
23
|
+
import { MachineSessionServiceFailure, } from "./machine-session-service.js";
|
|
22
24
|
const PLUGIN_CLI_BODY_MAX_BYTES = 512 * 1024;
|
|
23
25
|
const PLUGIN_CLI_STDIN_MAX_BYTES = 256 * 1024;
|
|
24
26
|
const PLUGIN_CLI_ARG_MAX_BYTES = 4 * 1024;
|
|
@@ -54,6 +56,8 @@ const RUNTIME_TARGET_SELECTOR_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._~-]{0,255}$/;
|
|
|
54
56
|
const SESSION_INTERACTION_RESOLUTION_MAX_BYTES = 128 * 1024;
|
|
55
57
|
const RUNTIME_BROWSER_RPC_METHODS = new Set([
|
|
56
58
|
"browser.state.get",
|
|
59
|
+
"browser.request-headers.get",
|
|
60
|
+
"browser.request-headers.set",
|
|
57
61
|
"browser.open",
|
|
58
62
|
"browser.close",
|
|
59
63
|
"browser.page.create",
|
|
@@ -630,6 +634,7 @@ export function createControlRouter(opts) {
|
|
|
630
634
|
let afterId;
|
|
631
635
|
let bytes = 0;
|
|
632
636
|
let runtime;
|
|
637
|
+
let pendingInputs = [];
|
|
633
638
|
try {
|
|
634
639
|
for (let pageIndex = 0; pageIndex < REMOTE_RUNTIME_SESSION_BFF_MAX_PAGES; pageIndex += 1) {
|
|
635
640
|
const page = await lease.call("session.snapshot.get", {
|
|
@@ -641,6 +646,7 @@ export function createControlRouter(opts) {
|
|
|
641
646
|
throw runtimeProtocolError("Runtime Session snapshot identity changed");
|
|
642
647
|
}
|
|
643
648
|
runtime = page.runtime;
|
|
649
|
+
pendingInputs = page.pendingInputs ?? [];
|
|
644
650
|
for (const item of page.items) {
|
|
645
651
|
if (ids.has(item.id)) {
|
|
646
652
|
throw runtimeProtocolError("Runtime Session snapshot repeated an item");
|
|
@@ -660,6 +666,7 @@ export function createControlRouter(opts) {
|
|
|
660
666
|
ctx.body = {
|
|
661
667
|
sessionId,
|
|
662
668
|
items,
|
|
669
|
+
pendingInputs,
|
|
663
670
|
runtime: materializeRemoteRuntimeSessionRuntimeSnapshot(runtime, items),
|
|
664
671
|
};
|
|
665
672
|
return;
|
|
@@ -735,12 +742,15 @@ export function createControlRouter(opts) {
|
|
|
735
742
|
const body = await readRuntimeBody(ctx);
|
|
736
743
|
if (!body)
|
|
737
744
|
return;
|
|
738
|
-
if (!acceptRuntimeBodyKeys(ctx, body, ["model", "reasoningEffort"]))
|
|
745
|
+
if (!acceptRuntimeBodyKeys(ctx, body, ["model", "reasoningEffort", "collaborationMode"]))
|
|
739
746
|
return;
|
|
740
747
|
const outcome = await runtimeCall(ctx, "session.execution.update", {
|
|
741
748
|
sessionId: ctx.params.id,
|
|
742
749
|
model: body.model,
|
|
743
750
|
reasoningEffort: body.reasoningEffort,
|
|
751
|
+
...(body.collaborationMode === undefined
|
|
752
|
+
? {}
|
|
753
|
+
: { collaborationMode: body.collaborationMode }),
|
|
744
754
|
});
|
|
745
755
|
if (outcome.ok)
|
|
746
756
|
ctx.body = outcome.result;
|
|
@@ -855,7 +865,13 @@ export function createControlRouter(opts) {
|
|
|
855
865
|
};
|
|
856
866
|
const runtimeSessionResourceUpload = async (ctx) => {
|
|
857
867
|
const uploadStarted = performance.now();
|
|
858
|
-
const mediaType = ctx.get("content-type").split(";", 1)[0]?.trim();
|
|
868
|
+
const mediaType = ctx.get("content-type").split(";", 1)[0]?.trim().toLowerCase();
|
|
869
|
+
const requestedType = ctx.get("x-rynx-resource-type").trim();
|
|
870
|
+
const resourceType = requestedType === "input_image" || requestedType === "input_file"
|
|
871
|
+
? requestedType
|
|
872
|
+
: SESSION_IMAGE_MEDIA_TYPES.includes(mediaType)
|
|
873
|
+
? "input_image"
|
|
874
|
+
: "input_file";
|
|
859
875
|
const clientUploadId = ctx.get("x-rynx-upload-id").trim();
|
|
860
876
|
const encodedFilename = ctx.get("x-rynx-filename").trim();
|
|
861
877
|
let filename = "";
|
|
@@ -868,7 +884,9 @@ export function createControlRouter(opts) {
|
|
|
868
884
|
return;
|
|
869
885
|
}
|
|
870
886
|
if (!mediaType ||
|
|
871
|
-
!
|
|
887
|
+
!isMediaType(mediaType) ||
|
|
888
|
+
(resourceType === "input_image" &&
|
|
889
|
+
!SESSION_IMAGE_MEDIA_TYPES.includes(mediaType)) ||
|
|
872
890
|
!clientUploadId ||
|
|
873
891
|
!filename ||
|
|
874
892
|
filename.length > SESSION_RESOURCE_MAX_FILENAME_CHARS) {
|
|
@@ -876,23 +894,21 @@ export function createControlRouter(opts) {
|
|
|
876
894
|
ctx.body = { error: "invalid_resource_upload" };
|
|
877
895
|
return;
|
|
878
896
|
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
}
|
|
884
|
-
catch (error) {
|
|
885
|
-
ctx.status = error instanceof RequestBodyTooLargeError ? 413 : 400;
|
|
886
|
-
ctx.body = {
|
|
887
|
-
error: error instanceof RequestBodyTooLargeError
|
|
888
|
-
? "request_too_large"
|
|
889
|
-
: "invalid_resource_upload",
|
|
890
|
-
};
|
|
897
|
+
const contentLengthHeader = ctx.get("content-length").trim();
|
|
898
|
+
if (!contentLengthHeader) {
|
|
899
|
+
ctx.status = 411;
|
|
900
|
+
ctx.body = { error: "content_length_required" };
|
|
891
901
|
return;
|
|
892
902
|
}
|
|
893
|
-
|
|
903
|
+
const byteLength = Number(contentLengthHeader);
|
|
904
|
+
if (!Number.isSafeInteger(byteLength) || byteLength <= 0) {
|
|
894
905
|
ctx.status = 400;
|
|
895
|
-
ctx.body = { error: "
|
|
906
|
+
ctx.body = { error: "invalid_content_length" };
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
if (resourceType === "input_image" && byteLength > SESSION_RESOURCE_MAX_IMAGE_BYTES) {
|
|
910
|
+
ctx.status = 413;
|
|
911
|
+
ctx.body = { error: "request_too_large" };
|
|
896
912
|
return;
|
|
897
913
|
}
|
|
898
914
|
const sessionId = ctx.params.id;
|
|
@@ -900,9 +916,7 @@ export function createControlRouter(opts) {
|
|
|
900
916
|
const lease = local ? undefined : await acquireRuntimeLease(ctx);
|
|
901
917
|
if (!local && !lease)
|
|
902
918
|
return;
|
|
903
|
-
const timings = new Map(
|
|
904
|
-
["body", performance.now() - bodyReadStarted],
|
|
905
|
-
]);
|
|
919
|
+
const timings = new Map();
|
|
906
920
|
const timed = async (name, operation) => {
|
|
907
921
|
const started = performance.now();
|
|
908
922
|
try {
|
|
@@ -919,16 +933,18 @@ export function createControlRouter(opts) {
|
|
|
919
933
|
? local.beginResourceUpload({
|
|
920
934
|
sessionId,
|
|
921
935
|
clientUploadId,
|
|
936
|
+
type: resourceType,
|
|
922
937
|
filename,
|
|
923
938
|
mediaType,
|
|
924
|
-
byteLength
|
|
939
|
+
byteLength,
|
|
925
940
|
})
|
|
926
941
|
: lease.call("session.resource.upload.begin", {
|
|
927
942
|
sessionId,
|
|
928
943
|
clientUploadId,
|
|
944
|
+
type: resourceType,
|
|
929
945
|
filename,
|
|
930
946
|
mediaType,
|
|
931
|
-
byteLength
|
|
947
|
+
byteLength,
|
|
932
948
|
}, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS }));
|
|
933
949
|
const writeChunk = (uploadId, offset, data) => timed("chunks", () => local
|
|
934
950
|
? local.writeResourceUploadChunk({ sessionId, uploadId, offset, data })
|
|
@@ -936,44 +952,72 @@ export function createControlRouter(opts) {
|
|
|
936
952
|
const commit = (uploadId) => timed("commit", () => local
|
|
937
953
|
? local.commitResourceUpload({ sessionId, uploadId })
|
|
938
954
|
: lease.call("session.resource.upload.commit", { sessionId, uploadId }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS }));
|
|
955
|
+
const discardPartial = (resourceId) => timed("restart", () => local
|
|
956
|
+
? local.deleteResource({ sessionId, resourceId })
|
|
957
|
+
: lease.call("session.resource.delete", { sessionId, resourceId }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS }));
|
|
958
|
+
let requestResourceId;
|
|
959
|
+
let resourceCommitted = false;
|
|
939
960
|
try {
|
|
940
961
|
const resourcePolicy = await policy();
|
|
941
962
|
if (!resourcePolicy.enabled ||
|
|
942
|
-
|
|
943
|
-
|
|
963
|
+
(resourceType === "input_image" &&
|
|
964
|
+
(!resourcePolicy.mediaTypes.includes(mediaType) ||
|
|
965
|
+
byteLength > resourcePolicy.maxImageBytes))) {
|
|
944
966
|
ctx.status = 413;
|
|
945
967
|
ctx.body = { error: "resource_policy_rejected" };
|
|
946
968
|
return;
|
|
947
969
|
}
|
|
948
|
-
|
|
970
|
+
let begun = await begin();
|
|
949
971
|
if (begun.complete && begun.resource) {
|
|
972
|
+
ctx.req.resume();
|
|
950
973
|
ctx.set("Cache-Control", "no-store");
|
|
951
974
|
ctx.body = { resource: begun.resource };
|
|
952
975
|
return;
|
|
953
976
|
}
|
|
954
|
-
if (begun.offset < 0 || begun.offset >
|
|
977
|
+
if (begun.offset < 0 || begun.offset > byteLength) {
|
|
955
978
|
throw runtimeProtocolError("Runtime Session resource upload offset is invalid");
|
|
956
979
|
}
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
980
|
+
// Browser retries send the complete File body again. A target-side
|
|
981
|
+
// partial cannot be blindly combined with the new body's suffix: the
|
|
982
|
+
// caller may have reused an upload id for changed bytes. Restart the
|
|
983
|
+
// incomplete upload so committed content always matches this request.
|
|
984
|
+
if (begun.offset > 0) {
|
|
985
|
+
const discarded = await discardPartial(begun.resourceId);
|
|
986
|
+
if (!discarded.deleted) {
|
|
987
|
+
throw runtimeProtocolError("Runtime Session partial upload could not be restarted");
|
|
988
|
+
}
|
|
989
|
+
begun = await begin();
|
|
990
|
+
if (begun.complete || begun.offset !== 0) {
|
|
991
|
+
throw runtimeProtocolError("Runtime Session resource upload did not restart");
|
|
963
992
|
}
|
|
964
|
-
offset = written.offset;
|
|
965
993
|
}
|
|
994
|
+
requestResourceId = begun.resourceId;
|
|
995
|
+
const bodyStarted = performance.now();
|
|
996
|
+
await forwardResourceUploadBody(ctx, begun.uploadId, begun.offset, byteLength, writeChunk);
|
|
997
|
+
timings.set("body", performance.now() - bodyStarted);
|
|
966
998
|
const committed = await commit(begun.uploadId);
|
|
967
999
|
if (committed.resource.resourceId !== begun.resourceId ||
|
|
1000
|
+
committed.resource.type !== resourceType ||
|
|
968
1001
|
committed.resource.mediaType !== mediaType ||
|
|
969
|
-
committed.resource.byteLength !==
|
|
1002
|
+
committed.resource.byteLength !== byteLength) {
|
|
970
1003
|
throw runtimeProtocolError("Runtime Session resource upload identity changed");
|
|
971
1004
|
}
|
|
1005
|
+
resourceCommitted = true;
|
|
972
1006
|
ctx.status = 201;
|
|
973
1007
|
ctx.set("Cache-Control", "no-store");
|
|
974
1008
|
ctx.body = committed;
|
|
975
1009
|
}
|
|
976
1010
|
catch (error) {
|
|
1011
|
+
if (requestResourceId && !resourceCommitted) {
|
|
1012
|
+
try {
|
|
1013
|
+
await discardPartial(requestResourceId);
|
|
1014
|
+
}
|
|
1015
|
+
catch {
|
|
1016
|
+
// The original error remains authoritative. Targets also reap stale
|
|
1017
|
+
// uploads, so a disconnected target cannot make cleanup block the
|
|
1018
|
+
// browser response indefinitely.
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
977
1021
|
runtimeTargetHostError(ctx, error);
|
|
978
1022
|
}
|
|
979
1023
|
finally {
|
|
@@ -989,7 +1033,7 @@ export function createControlRouter(opts) {
|
|
|
989
1033
|
event: "session.resource.upload.slow",
|
|
990
1034
|
selector: ctx.params.selector,
|
|
991
1035
|
sessionId,
|
|
992
|
-
byteLength
|
|
1036
|
+
byteLength,
|
|
993
1037
|
status: ctx.status,
|
|
994
1038
|
timings: Object.fromEntries([...timings.entries()].map(([name, duration]) => [
|
|
995
1039
|
name,
|
|
@@ -1033,16 +1077,32 @@ export function createControlRouter(opts) {
|
|
|
1033
1077
|
const sessionId = ctx.params.id;
|
|
1034
1078
|
const resourceId = ctx.params.resourceId;
|
|
1035
1079
|
const local = ctx.params.selector === "local" ? localSessionResources : undefined;
|
|
1036
|
-
const
|
|
1037
|
-
|
|
1080
|
+
const invocation = downloadInvocationAbortScope(ctx, shutdownSignal);
|
|
1081
|
+
const lease = local ? undefined : await acquireRuntimeLease(ctx, invocation.signal);
|
|
1082
|
+
if (!local && !lease) {
|
|
1083
|
+
invocation.dispose();
|
|
1038
1084
|
return;
|
|
1085
|
+
}
|
|
1086
|
+
let streamOwnsLease = false;
|
|
1087
|
+
let cleanedUp = false;
|
|
1088
|
+
const cleanup = () => {
|
|
1089
|
+
if (cleanedUp)
|
|
1090
|
+
return;
|
|
1091
|
+
cleanedUp = true;
|
|
1092
|
+
lease?.release();
|
|
1093
|
+
invocation.dispose();
|
|
1094
|
+
};
|
|
1039
1095
|
try {
|
|
1040
1096
|
const { resource } = local
|
|
1041
1097
|
? await local.getResource({ sessionId, resourceId })
|
|
1042
|
-
: await lease.call("session.resource.get", { sessionId, resourceId }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS });
|
|
1098
|
+
: await lease.call("session.resource.get", { sessionId, resourceId }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
|
|
1043
1099
|
if (resource.resourceId !== resourceId) {
|
|
1044
1100
|
throw runtimeProtocolError("Runtime Session resource identity changed");
|
|
1045
1101
|
}
|
|
1102
|
+
const byteLength = resource.byteLength;
|
|
1103
|
+
if (!Number.isSafeInteger(byteLength) || !byteLength || byteLength < 1) {
|
|
1104
|
+
throw runtimeProtocolError("Runtime Session resource length is invalid");
|
|
1105
|
+
}
|
|
1046
1106
|
const etag = `"sha256-${resource.sha256}"`;
|
|
1047
1107
|
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
|
1048
1108
|
ctx.set("ETag", etag);
|
|
@@ -1050,48 +1110,68 @@ export function createControlRouter(opts) {
|
|
|
1050
1110
|
ctx.status = 304;
|
|
1051
1111
|
return;
|
|
1052
1112
|
}
|
|
1053
|
-
const
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
})
|
|
1063
|
-
: await lease.call("session.resource.read", {
|
|
1064
|
-
sessionId,
|
|
1065
|
-
resourceId,
|
|
1066
|
-
offset,
|
|
1067
|
-
length: SESSION_RESOURCE_TRANSFER_CHUNK_BYTES,
|
|
1068
|
-
}, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS });
|
|
1069
|
-
const chunk = Buffer.from(result.data, "base64");
|
|
1070
|
-
if (result.offset !== offset + chunk.byteLength || (!result.eof && chunk.byteLength === 0)) {
|
|
1071
|
-
throw runtimeProtocolError("Runtime Session resource read did not advance");
|
|
1072
|
-
}
|
|
1073
|
-
chunks.push(chunk);
|
|
1074
|
-
offset = result.offset;
|
|
1075
|
-
if (result.eof)
|
|
1076
|
-
break;
|
|
1077
|
-
}
|
|
1078
|
-
const body = Buffer.concat(chunks);
|
|
1079
|
-
if (body.byteLength !== resource.byteLength) {
|
|
1080
|
-
throw runtimeProtocolError("Runtime Session resource length changed");
|
|
1113
|
+
const requestedRange = ctx.get("range");
|
|
1114
|
+
const ifRange = ctx.get("if-range");
|
|
1115
|
+
const range = ifRange && ifRange !== etag
|
|
1116
|
+
? undefined
|
|
1117
|
+
: parseSingleByteRange(requestedRange, byteLength);
|
|
1118
|
+
if (range === "unsatisfiable") {
|
|
1119
|
+
ctx.status = 416;
|
|
1120
|
+
ctx.set("Content-Range", `bytes */${byteLength}`);
|
|
1121
|
+
return;
|
|
1081
1122
|
}
|
|
1123
|
+
const start = range?.start ?? 0;
|
|
1124
|
+
const end = range?.end ?? byteLength - 1;
|
|
1125
|
+
const responseLength = end - start + 1;
|
|
1082
1126
|
ctx.set("Content-Security-Policy", "default-src 'none'; sandbox");
|
|
1083
1127
|
ctx.set("Cross-Origin-Resource-Policy", "same-origin");
|
|
1084
1128
|
ctx.set("X-Content-Type-Options", "nosniff");
|
|
1085
|
-
ctx.set("
|
|
1129
|
+
ctx.set("Accept-Ranges", "bytes");
|
|
1130
|
+
ctx.set("Content-Disposition", contentDisposition(resource.filename));
|
|
1131
|
+
if (range) {
|
|
1132
|
+
ctx.status = 206;
|
|
1133
|
+
ctx.set("Content-Range", `bytes ${start}-${end}/${byteLength}`);
|
|
1134
|
+
}
|
|
1086
1135
|
ctx.type = resource.mediaType;
|
|
1087
|
-
ctx.length =
|
|
1136
|
+
ctx.length = responseLength;
|
|
1137
|
+
if (ctx.method === "HEAD") {
|
|
1138
|
+
ctx.status = range ? 206 : 200;
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
streamOwnsLease = true;
|
|
1142
|
+
const body = Readable.from((async function* () {
|
|
1143
|
+
let offset = start;
|
|
1144
|
+
try {
|
|
1145
|
+
while (offset <= end) {
|
|
1146
|
+
const length = Math.min(SESSION_RESOURCE_TRANSFER_CHUNK_BYTES, end - offset + 1);
|
|
1147
|
+
const result = local
|
|
1148
|
+
? await local.readResource({ sessionId, resourceId, offset, length })
|
|
1149
|
+
: await lease.call("session.resource.read", { sessionId, resourceId, offset, length }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
|
|
1150
|
+
const chunk = Buffer.from(result.data, "base64");
|
|
1151
|
+
if (result.offset !== offset + chunk.byteLength || chunk.byteLength === 0) {
|
|
1152
|
+
throw runtimeProtocolError("Runtime Session resource read did not advance");
|
|
1153
|
+
}
|
|
1154
|
+
offset = result.offset;
|
|
1155
|
+
yield chunk;
|
|
1156
|
+
}
|
|
1157
|
+
if (offset !== end + 1) {
|
|
1158
|
+
throw runtimeProtocolError("Runtime Session resource length changed");
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
finally {
|
|
1162
|
+
cleanup();
|
|
1163
|
+
}
|
|
1164
|
+
})());
|
|
1165
|
+
body.once("close", cleanup);
|
|
1088
1166
|
ctx.body = body;
|
|
1089
1167
|
}
|
|
1090
1168
|
catch (error) {
|
|
1091
1169
|
runtimeTargetHostError(ctx, error);
|
|
1092
1170
|
}
|
|
1093
1171
|
finally {
|
|
1094
|
-
|
|
1172
|
+
if (!streamOwnsLease) {
|
|
1173
|
+
cleanup();
|
|
1174
|
+
}
|
|
1095
1175
|
}
|
|
1096
1176
|
};
|
|
1097
1177
|
const runtimeSessionResourceDelete = async (ctx) => {
|
|
@@ -1115,6 +1195,243 @@ export function createControlRouter(opts) {
|
|
|
1115
1195
|
if (outcome.ok)
|
|
1116
1196
|
ctx.body = outcome.result;
|
|
1117
1197
|
};
|
|
1198
|
+
const runtimeSessionItemFileContent = async (ctx) => {
|
|
1199
|
+
const sessionId = ctx.params.id;
|
|
1200
|
+
const itemId = ctx.params.itemId;
|
|
1201
|
+
const partIndex = Number(ctx.params.partIndex);
|
|
1202
|
+
if (!Number.isSafeInteger(partIndex) || partIndex < 0 || partIndex > 1_024) {
|
|
1203
|
+
ctx.status = 400;
|
|
1204
|
+
ctx.body = { error: "invalid_part_index" };
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
const local = ctx.params.selector === "local" ? localMachineSessions : undefined;
|
|
1208
|
+
const invocation = downloadInvocationAbortScope(ctx, shutdownSignal);
|
|
1209
|
+
const lease = local ? undefined : await acquireRuntimeLease(ctx, invocation.signal);
|
|
1210
|
+
if (!local && !lease) {
|
|
1211
|
+
invocation.dispose();
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
let streamOwnsLease = false;
|
|
1215
|
+
let cleanedUp = false;
|
|
1216
|
+
const cleanup = () => {
|
|
1217
|
+
if (cleanedUp)
|
|
1218
|
+
return;
|
|
1219
|
+
cleanedUp = true;
|
|
1220
|
+
lease?.release();
|
|
1221
|
+
invocation.dispose();
|
|
1222
|
+
};
|
|
1223
|
+
try {
|
|
1224
|
+
const { file } = local
|
|
1225
|
+
? await local.getFile({ sessionId, itemId, partIndex })
|
|
1226
|
+
: await lease.call("session.file.get", { sessionId, itemId, partIndex }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
|
|
1227
|
+
if (file.itemId !== itemId || file.partIndex !== partIndex) {
|
|
1228
|
+
throw runtimeProtocolError("Runtime Session file identity changed");
|
|
1229
|
+
}
|
|
1230
|
+
const etag = `"file-${file.version}"`;
|
|
1231
|
+
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
|
1232
|
+
ctx.set("ETag", etag);
|
|
1233
|
+
if (ctx.get("if-none-match").split(",").map((value) => value.trim()).includes(etag)) {
|
|
1234
|
+
ctx.status = 304;
|
|
1235
|
+
return;
|
|
1236
|
+
}
|
|
1237
|
+
const requestedRange = ctx.get("range");
|
|
1238
|
+
const ifRange = ctx.get("if-range");
|
|
1239
|
+
const range = ifRange && ifRange !== etag
|
|
1240
|
+
? undefined
|
|
1241
|
+
: parseSingleByteRange(requestedRange, file.byteLength);
|
|
1242
|
+
if (range === "unsatisfiable") {
|
|
1243
|
+
ctx.status = 416;
|
|
1244
|
+
ctx.set("Content-Range", `bytes */${file.byteLength}`);
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
const start = range?.start ?? 0;
|
|
1248
|
+
const end = range?.end ?? file.byteLength - 1;
|
|
1249
|
+
ctx.set("Content-Security-Policy", "default-src 'none'; sandbox");
|
|
1250
|
+
ctx.set("Cross-Origin-Resource-Policy", "same-origin");
|
|
1251
|
+
ctx.set("X-Content-Type-Options", "nosniff");
|
|
1252
|
+
ctx.set("Accept-Ranges", "bytes");
|
|
1253
|
+
ctx.set("Content-Disposition", contentDisposition(file.filename));
|
|
1254
|
+
if (range) {
|
|
1255
|
+
ctx.status = 206;
|
|
1256
|
+
ctx.set("Content-Range", `bytes ${start}-${end}/${file.byteLength}`);
|
|
1257
|
+
}
|
|
1258
|
+
ctx.type = file.mediaType;
|
|
1259
|
+
ctx.length = end - start + 1;
|
|
1260
|
+
if (ctx.method === "HEAD") {
|
|
1261
|
+
ctx.status = range ? 206 : 200;
|
|
1262
|
+
return;
|
|
1263
|
+
}
|
|
1264
|
+
streamOwnsLease = true;
|
|
1265
|
+
const body = Readable.from((async function* () {
|
|
1266
|
+
let offset = start;
|
|
1267
|
+
try {
|
|
1268
|
+
while (offset <= end) {
|
|
1269
|
+
const length = Math.min(SESSION_RESOURCE_TRANSFER_CHUNK_BYTES, end - offset + 1);
|
|
1270
|
+
const result = local
|
|
1271
|
+
? await local.readFile({
|
|
1272
|
+
sessionId,
|
|
1273
|
+
itemId,
|
|
1274
|
+
partIndex,
|
|
1275
|
+
version: file.version,
|
|
1276
|
+
offset,
|
|
1277
|
+
length,
|
|
1278
|
+
})
|
|
1279
|
+
: await lease.call("session.file.read", {
|
|
1280
|
+
sessionId,
|
|
1281
|
+
itemId,
|
|
1282
|
+
partIndex,
|
|
1283
|
+
version: file.version,
|
|
1284
|
+
offset,
|
|
1285
|
+
length,
|
|
1286
|
+
}, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
|
|
1287
|
+
const chunk = Buffer.from(result.data, "base64");
|
|
1288
|
+
if (result.offset !== offset + chunk.byteLength || chunk.byteLength === 0) {
|
|
1289
|
+
throw runtimeProtocolError("Runtime Session file read did not advance");
|
|
1290
|
+
}
|
|
1291
|
+
offset = result.offset;
|
|
1292
|
+
yield chunk;
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
finally {
|
|
1296
|
+
cleanup();
|
|
1297
|
+
}
|
|
1298
|
+
})());
|
|
1299
|
+
body.once("close", cleanup);
|
|
1300
|
+
ctx.body = body;
|
|
1301
|
+
}
|
|
1302
|
+
catch (error) {
|
|
1303
|
+
runtimeTargetHostError(ctx, error);
|
|
1304
|
+
}
|
|
1305
|
+
finally {
|
|
1306
|
+
if (!streamOwnsLease) {
|
|
1307
|
+
cleanup();
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
};
|
|
1311
|
+
const runtimeSessionWorkspaceFileContent = async (ctx) => {
|
|
1312
|
+
const sessionId = ctx.params.id;
|
|
1313
|
+
const path = ctx.query.path;
|
|
1314
|
+
if (typeof path !== "string" ||
|
|
1315
|
+
path.length === 0 ||
|
|
1316
|
+
path.length > 4_096 ||
|
|
1317
|
+
path.includes("\0")) {
|
|
1318
|
+
ctx.status = 400;
|
|
1319
|
+
ctx.body = { error: "invalid_workspace_file_path" };
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
const local = ctx.params.selector === "local" ? localMachineSessions : undefined;
|
|
1323
|
+
const invocation = downloadInvocationAbortScope(ctx, shutdownSignal);
|
|
1324
|
+
const lease = local ? undefined : await acquireRuntimeLease(ctx, invocation.signal);
|
|
1325
|
+
if (!local && !lease) {
|
|
1326
|
+
invocation.dispose();
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
let streamOwnsLease = false;
|
|
1330
|
+
let cleanedUp = false;
|
|
1331
|
+
const cleanup = () => {
|
|
1332
|
+
if (cleanedUp)
|
|
1333
|
+
return;
|
|
1334
|
+
cleanedUp = true;
|
|
1335
|
+
lease?.release();
|
|
1336
|
+
invocation.dispose();
|
|
1337
|
+
};
|
|
1338
|
+
try {
|
|
1339
|
+
const { file } = local
|
|
1340
|
+
? await local.getWorkspaceFile({ sessionId, path })
|
|
1341
|
+
: await lease.call("session.workspace.file.get", { sessionId, path }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
|
|
1342
|
+
if (file.path !== path) {
|
|
1343
|
+
throw runtimeProtocolError("Runtime Session workspace file identity changed");
|
|
1344
|
+
}
|
|
1345
|
+
const etag = `"workspace-file-${file.version}"`;
|
|
1346
|
+
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
|
1347
|
+
ctx.set("ETag", etag);
|
|
1348
|
+
if (ctx.get("if-none-match").split(",").map((value) => value.trim()).includes(etag)) {
|
|
1349
|
+
ctx.status = 304;
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
ctx.set("Content-Security-Policy", "default-src 'none'; sandbox");
|
|
1353
|
+
ctx.set("Cross-Origin-Resource-Policy", "same-origin");
|
|
1354
|
+
ctx.set("X-Content-Type-Options", "nosniff");
|
|
1355
|
+
ctx.set("Accept-Ranges", "bytes");
|
|
1356
|
+
ctx.set("Content-Disposition", contentDisposition(file.filename));
|
|
1357
|
+
ctx.type = file.mediaType;
|
|
1358
|
+
if (file.byteLength === 0) {
|
|
1359
|
+
if (ctx.get("range")) {
|
|
1360
|
+
ctx.status = 416;
|
|
1361
|
+
ctx.set("Content-Range", "bytes */0");
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
ctx.status = 200;
|
|
1365
|
+
ctx.length = 0;
|
|
1366
|
+
if (ctx.method !== "HEAD")
|
|
1367
|
+
ctx.body = Buffer.alloc(0);
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
const requestedRange = ctx.get("range");
|
|
1371
|
+
const ifRange = ctx.get("if-range");
|
|
1372
|
+
const range = ifRange && ifRange !== etag
|
|
1373
|
+
? undefined
|
|
1374
|
+
: parseSingleByteRange(requestedRange, file.byteLength);
|
|
1375
|
+
if (range === "unsatisfiable") {
|
|
1376
|
+
ctx.status = 416;
|
|
1377
|
+
ctx.set("Content-Range", `bytes */${file.byteLength}`);
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
const start = range?.start ?? 0;
|
|
1381
|
+
const end = range?.end ?? file.byteLength - 1;
|
|
1382
|
+
if (range) {
|
|
1383
|
+
ctx.status = 206;
|
|
1384
|
+
ctx.set("Content-Range", `bytes ${start}-${end}/${file.byteLength}`);
|
|
1385
|
+
}
|
|
1386
|
+
ctx.length = end - start + 1;
|
|
1387
|
+
if (ctx.method === "HEAD") {
|
|
1388
|
+
ctx.status = range ? 206 : 200;
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
streamOwnsLease = true;
|
|
1392
|
+
const body = Readable.from((async function* () {
|
|
1393
|
+
let offset = start;
|
|
1394
|
+
try {
|
|
1395
|
+
while (offset <= end) {
|
|
1396
|
+
const length = Math.min(SESSION_RESOURCE_TRANSFER_CHUNK_BYTES, end - offset + 1);
|
|
1397
|
+
const result = local
|
|
1398
|
+
? await local.readWorkspaceFile({
|
|
1399
|
+
sessionId,
|
|
1400
|
+
path,
|
|
1401
|
+
version: file.version,
|
|
1402
|
+
offset,
|
|
1403
|
+
length,
|
|
1404
|
+
})
|
|
1405
|
+
: await lease.call("session.workspace.file.read", {
|
|
1406
|
+
sessionId,
|
|
1407
|
+
path,
|
|
1408
|
+
version: file.version,
|
|
1409
|
+
offset,
|
|
1410
|
+
length,
|
|
1411
|
+
}, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
|
|
1412
|
+
const chunk = Buffer.from(result.data, "base64");
|
|
1413
|
+
if (result.offset !== offset + chunk.byteLength || chunk.byteLength === 0) {
|
|
1414
|
+
throw runtimeProtocolError("Runtime Session workspace file read did not advance");
|
|
1415
|
+
}
|
|
1416
|
+
offset = result.offset;
|
|
1417
|
+
yield chunk;
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
finally {
|
|
1421
|
+
cleanup();
|
|
1422
|
+
}
|
|
1423
|
+
})());
|
|
1424
|
+
body.once("close", cleanup);
|
|
1425
|
+
ctx.body = body;
|
|
1426
|
+
}
|
|
1427
|
+
catch (error) {
|
|
1428
|
+
runtimeTargetHostError(ctx, error);
|
|
1429
|
+
}
|
|
1430
|
+
finally {
|
|
1431
|
+
if (!streamOwnsLease)
|
|
1432
|
+
cleanup();
|
|
1433
|
+
}
|
|
1434
|
+
};
|
|
1118
1435
|
const runtimeSessionMessageEnqueue = async (ctx) => {
|
|
1119
1436
|
const body = await readRuntimeBody(ctx);
|
|
1120
1437
|
if (!body)
|
|
@@ -1174,6 +1491,32 @@ export function createControlRouter(opts) {
|
|
|
1174
1491
|
if (outcome.ok)
|
|
1175
1492
|
ctx.body = outcome.result;
|
|
1176
1493
|
};
|
|
1494
|
+
const runtimeBrowserRequestHeaders = async (ctx) => {
|
|
1495
|
+
const outcome = await runtimeCall(ctx, "browser.request-headers.get", {
|
|
1496
|
+
sessionId: ctx.params.id,
|
|
1497
|
+
});
|
|
1498
|
+
if (outcome.ok) {
|
|
1499
|
+
ctx.set("Cache-Control", "no-store");
|
|
1500
|
+
ctx.body = outcome.result;
|
|
1501
|
+
}
|
|
1502
|
+
};
|
|
1503
|
+
const runtimeBrowserRequestHeadersUpdate = async (ctx) => {
|
|
1504
|
+
const body = await readRuntimeBody(ctx);
|
|
1505
|
+
if (!body)
|
|
1506
|
+
return;
|
|
1507
|
+
if (!acceptRuntimeBodyKeys(ctx, body, ["expectedRevision", "enabled", "headers"]))
|
|
1508
|
+
return;
|
|
1509
|
+
const outcome = await runtimeCall(ctx, "browser.request-headers.set", {
|
|
1510
|
+
sessionId: ctx.params.id,
|
|
1511
|
+
expectedRevision: body.expectedRevision,
|
|
1512
|
+
enabled: body.enabled,
|
|
1513
|
+
headers: body.headers,
|
|
1514
|
+
});
|
|
1515
|
+
if (outcome.ok) {
|
|
1516
|
+
ctx.set("Cache-Control", "no-store");
|
|
1517
|
+
ctx.body = outcome.result;
|
|
1518
|
+
}
|
|
1519
|
+
};
|
|
1177
1520
|
const runtimeBrowserOpen = async (ctx) => {
|
|
1178
1521
|
const body = await readRuntimeBody(ctx);
|
|
1179
1522
|
if (!body)
|
|
@@ -1746,12 +2089,22 @@ export function createControlRouter(opts) {
|
|
|
1746
2089
|
router.post("/api/runtimes/:selector/sessions/:id/resources", publicRuntimeMutation(runtimeSessionResourceUpload));
|
|
1747
2090
|
router.get("/api/runtimes/:selector/sessions/:id/resources/:resourceId", publicRuntimeRead(runtimeSessionResourceMetadata));
|
|
1748
2091
|
router.get("/api/runtimes/:selector/sessions/:id/resources/:resourceId/content", publicRuntimeRead(runtimeSessionResourceContent));
|
|
2092
|
+
router.head("/api/runtimes/:selector/sessions/:id/resources/:resourceId/content", publicRuntimeRead(runtimeSessionResourceContent));
|
|
2093
|
+
router.get("/api/runtimes/:selector/sessions/:id/items/:itemId/files/:partIndex/content", publicRuntimeRead(runtimeSessionItemFileContent));
|
|
2094
|
+
router.head("/api/runtimes/:selector/sessions/:id/items/:itemId/files/:partIndex/content", publicRuntimeRead(runtimeSessionItemFileContent));
|
|
2095
|
+
router.get("/api/runtimes/:selector/sessions/:id/workspace/files/content", publicRuntimeRead(runtimeSessionWorkspaceFileContent));
|
|
2096
|
+
router.head("/api/runtimes/:selector/sessions/:id/workspace/files/content", publicRuntimeRead(runtimeSessionWorkspaceFileContent));
|
|
1749
2097
|
router.delete("/api/runtimes/:selector/sessions/:id/resources/:resourceId", publicRuntimeMutation(runtimeSessionResourceDelete));
|
|
1750
2098
|
router.post("/api/runtimes/:selector/sessions/:id/messages/queue", publicRuntimeMutation(runtimeSessionMessageEnqueue));
|
|
1751
2099
|
router.post("/api/runtimes/:selector/sessions/:id/terminal/start", publicRuntimeMutation(runtimeSessionTerminalStart));
|
|
1752
2100
|
router.post("/api/runtimes/:selector/sessions/:id/interactions/:interactionId/resolve", publicRuntimeMutation(runtimeSessionResolveInteraction));
|
|
1753
2101
|
router.delete("/api/runtimes/:selector/sessions/:id", publicRuntimeMutation(runtimeSessionDelete));
|
|
1754
2102
|
router.get("/api/runtimes/:selector/sessions/:id/browser", publicRuntimeRead(runtimeBrowserState));
|
|
2103
|
+
router.get("/api/runtimes/:selector/sessions/:id/browser/request-headers",
|
|
2104
|
+
// Header values may be sensitive. Reading them requires the same
|
|
2105
|
+
// process-lifetime capability and Portal grant as a mutation.
|
|
2106
|
+
publicRuntimeMutation(runtimeBrowserRequestHeaders));
|
|
2107
|
+
router.put("/api/runtimes/:selector/sessions/:id/browser/request-headers", publicRuntimeMutation(runtimeBrowserRequestHeadersUpdate));
|
|
1755
2108
|
router.post("/api/runtimes/:selector/sessions/:id/browser/open", publicRuntimeMutation(runtimeBrowserOpen));
|
|
1756
2109
|
router.post("/api/runtimes/:selector/sessions/:id/browser/close", publicRuntimeMutation(runtimeBrowserClose));
|
|
1757
2110
|
router.post("/api/runtimes/:selector/sessions/:id/browser/pages", publicRuntimeMutation(runtimeBrowserPageCreate));
|
|
@@ -1771,6 +2124,71 @@ export function createControlRouter(opts) {
|
|
|
1771
2124
|
router.post("/api/internal/runtimes/:selector/emulator/gesture", internalRuntimeCall(runtimeGestureEmulator));
|
|
1772
2125
|
router.post("/api/internal/runtimes/:selector/emulator/kill", internalRuntimeCall((ctx) => runtimeDeviceCommand(ctx, "emulator.kill")));
|
|
1773
2126
|
router.post("/api/internal/runtimes/:selector/emulator/shutdown", internalRuntimeCall((ctx) => runtimeDeviceCommand(ctx, "emulator.shutdown")));
|
|
2127
|
+
const executeLocalBrowser = async (ctx, management) => {
|
|
2128
|
+
if (!runtimeLocalBrowser?.executeForSession) {
|
|
2129
|
+
notFound(ctx, "Page automation requires a Runtime upgrade");
|
|
2130
|
+
return;
|
|
2131
|
+
}
|
|
2132
|
+
if (!isLoopbackRequest(ctx)) {
|
|
2133
|
+
ctx.status = 403;
|
|
2134
|
+
ctx.body = { error: "loopback_only" };
|
|
2135
|
+
return;
|
|
2136
|
+
}
|
|
2137
|
+
let sessionId;
|
|
2138
|
+
if (management) {
|
|
2139
|
+
if (!isConfiguredDaemonManagement(daemonManagement)) {
|
|
2140
|
+
notFound(ctx, "Daemon management is unavailable");
|
|
2141
|
+
return;
|
|
2142
|
+
}
|
|
2143
|
+
if (!authorizeLoopbackManagementRequest(ctx, daemonManagement.managementToken))
|
|
2144
|
+
return;
|
|
2145
|
+
try {
|
|
2146
|
+
sessionId = parseRuntimeBrowserStateGetParams({ sessionId: ctx.params.sessionId }).sessionId;
|
|
2147
|
+
}
|
|
2148
|
+
catch {
|
|
2149
|
+
bad(ctx, "invalid Session id");
|
|
2150
|
+
return;
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
else {
|
|
2154
|
+
try {
|
|
2155
|
+
const credential = parseRuntimeBrowserBootstrapCredential({
|
|
2156
|
+
sessionId: ctx.get(RUNTIME_BROWSER_SESSION_ID_HEADER), capability: ctx.get(RUNTIME_BROWSER_CAPABILITY_HEADER),
|
|
2157
|
+
});
|
|
2158
|
+
if (!await runtimeLocalBrowser.authorizeCredential(credential))
|
|
2159
|
+
throw new Error("unauthorized");
|
|
2160
|
+
sessionId = credential.sessionId;
|
|
2161
|
+
}
|
|
2162
|
+
catch {
|
|
2163
|
+
ctx.status = 401;
|
|
2164
|
+
ctx.body = { error: "invalid Runtime Browser Session capability" };
|
|
2165
|
+
return;
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
if (!ctx.is("application/json")) {
|
|
2169
|
+
ctx.status = 415;
|
|
2170
|
+
ctx.body = { error: "unsupported_media_type" };
|
|
2171
|
+
return;
|
|
2172
|
+
}
|
|
2173
|
+
let command;
|
|
2174
|
+
try {
|
|
2175
|
+
command = parseRuntimeBrowserAutomationCommand(await readBoundedJson(ctx, 128 * 1024));
|
|
2176
|
+
}
|
|
2177
|
+
catch (error) {
|
|
2178
|
+
ctx.status = error instanceof RequestBodyTooLargeError ? 413 : 400;
|
|
2179
|
+
ctx.body = { error: "invalid_request" };
|
|
2180
|
+
return;
|
|
2181
|
+
}
|
|
2182
|
+
try {
|
|
2183
|
+
ctx.set("Cache-Control", "no-store");
|
|
2184
|
+
ctx.body = await runtimeLocalBrowser.executeForSession(sessionId, command);
|
|
2185
|
+
}
|
|
2186
|
+
catch (error) {
|
|
2187
|
+
runtimeLocalBrowserError(ctx, error);
|
|
2188
|
+
}
|
|
2189
|
+
};
|
|
2190
|
+
router.post(RUNTIME_BROWSER_EXECUTE_PATH, (ctx) => executeLocalBrowser(ctx, false));
|
|
2191
|
+
router.post(`${RUNTIME_BROWSER_MANAGEMENT_PATH_PREFIX}/:sessionId/execute`, (ctx) => executeLocalBrowser(ctx, true));
|
|
1774
2192
|
router.get(RUNTIME_BROWSER_BOOTSTRAP_PATH, async (ctx) => {
|
|
1775
2193
|
if (!runtimeLocalBrowser) {
|
|
1776
2194
|
return notFound(ctx, "Runtime-local Browser automation is not configured");
|
|
@@ -1948,10 +2366,17 @@ export function createControlRouter(opts) {
|
|
|
1948
2366
|
}
|
|
1949
2367
|
if (!authorizeLoopbackManagementRequest(ctx, daemonManagement.managementToken))
|
|
1950
2368
|
return;
|
|
1951
|
-
|
|
2369
|
+
if (ctx.get(DAEMON_MAINTENANCE_LEASE_HEADER).trim()) {
|
|
2370
|
+
ctx.set("Cache-Control", "no-store");
|
|
2371
|
+
ctx.status = 410;
|
|
2372
|
+
ctx.body = {
|
|
2373
|
+
error: "cross-process maintenance leases are retired; upgrade the caller",
|
|
2374
|
+
};
|
|
2375
|
+
return;
|
|
2376
|
+
}
|
|
1952
2377
|
let result;
|
|
1953
2378
|
try {
|
|
1954
|
-
result = await daemonManagement.shutdownIfIdle(
|
|
2379
|
+
result = await daemonManagement.shutdownIfIdle();
|
|
1955
2380
|
}
|
|
1956
2381
|
catch (error) {
|
|
1957
2382
|
ctx.set("Cache-Control", "no-store");
|
|
@@ -1966,15 +2391,16 @@ export function createControlRouter(opts) {
|
|
|
1966
2391
|
ctx.body = result;
|
|
1967
2392
|
});
|
|
1968
2393
|
router.post(DAEMON_MAINTENANCE_LEASE_RELEASE_PATH, (ctx) => {
|
|
1969
|
-
if (!isConfiguredDaemonManagement(daemonManagement)
|
|
1970
|
-
|
|
1971
|
-
return notFound(ctx, "daemon maintenance lease management is not configured");
|
|
2394
|
+
if (!isConfiguredDaemonManagement(daemonManagement)) {
|
|
2395
|
+
return notFound(ctx, "daemon management is not configured");
|
|
1972
2396
|
}
|
|
1973
2397
|
if (!authorizeLoopbackManagementRequest(ctx, daemonManagement.managementToken))
|
|
1974
2398
|
return;
|
|
1975
|
-
|
|
2399
|
+
// Compatibility for updaters released before Plugin-owned drain became
|
|
2400
|
+
// the sole upgrade fence. New daemons never acquire a Host lease.
|
|
2401
|
+
const result = { outcome: "not_active" };
|
|
1976
2402
|
ctx.set("Cache-Control", "no-store");
|
|
1977
|
-
ctx.status =
|
|
2403
|
+
ctx.status = 200;
|
|
1978
2404
|
ctx.body = result;
|
|
1979
2405
|
});
|
|
1980
2406
|
router.post(DAEMON_BROWSER_ARTIFACT_INSTALL_PATH, async (ctx) => {
|
|
@@ -3178,7 +3604,7 @@ export function createControlRouter(opts) {
|
|
|
3178
3604
|
// ── sessions (channel-agnostic agent runs) ───────────────────────────────
|
|
3179
3605
|
// Create a session bound to a preset agent (`agent`) or an inline spec
|
|
3180
3606
|
// (`config`, the config-driven / remote-ready path), then drive it with
|
|
3181
|
-
// messages over SSE.
|
|
3607
|
+
// messages over SSE. Creating the session does not submit a message.
|
|
3182
3608
|
// One unified list: every session is a machine-session record. The registry
|
|
3183
3609
|
// (console + every channel) supplies identity — `source` is a plain field, not
|
|
3184
3610
|
// parsed from the id — and the canonical log supplies recency. A legacy session
|
|
@@ -3252,7 +3678,20 @@ export function createControlRouter(opts) {
|
|
|
3252
3678
|
}
|
|
3253
3679
|
catch (error) {
|
|
3254
3680
|
ctx.status = 503;
|
|
3255
|
-
|
|
3681
|
+
const runtimeFailure = error instanceof MachineSessionServiceFailure
|
|
3682
|
+
? error.runtimeFailure
|
|
3683
|
+
: undefined;
|
|
3684
|
+
const message = runtimeFailure?.message
|
|
3685
|
+
?? (error instanceof MachineSessionServiceFailure ? error.detail : undefined)
|
|
3686
|
+
?? (error instanceof Error ? error.message : String(error));
|
|
3687
|
+
ctx.body = {
|
|
3688
|
+
error: message,
|
|
3689
|
+
code: runtimeFailure?.code
|
|
3690
|
+
?? (error instanceof MachineSessionServiceFailure ? error.code : "runtime_error"),
|
|
3691
|
+
outcome: error instanceof MachineSessionServiceFailure && error.code === "outcome_unknown"
|
|
3692
|
+
? "unknown"
|
|
3693
|
+
: "not_started",
|
|
3694
|
+
};
|
|
3256
3695
|
}
|
|
3257
3696
|
return;
|
|
3258
3697
|
}
|
|
@@ -3271,26 +3710,31 @@ export function createControlRouter(opts) {
|
|
|
3271
3710
|
execution: structuredClone(meta.execution),
|
|
3272
3711
|
});
|
|
3273
3712
|
if (!live) {
|
|
3713
|
+
const failure = runnerManager.lastLiveSessionFailure?.(id);
|
|
3274
3714
|
ctx.status = 503;
|
|
3275
3715
|
ctx.body = {
|
|
3276
|
-
error:
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3716
|
+
error: failure?.message
|
|
3717
|
+
?? runnerManager.lastLiveSessionError?.(id)
|
|
3718
|
+
?? `live session unavailable (${meta.execution.provider})`,
|
|
3719
|
+
code: failure?.code ?? "live_unavailable",
|
|
3720
|
+
outcome: "not_started",
|
|
3280
3721
|
};
|
|
3281
3722
|
return;
|
|
3282
3723
|
}
|
|
3283
|
-
const
|
|
3284
|
-
|
|
3724
|
+
const result = await runnerManager.injectMessage(id, message);
|
|
3725
|
+
const outcome = result.outcome;
|
|
3726
|
+
if (outcome === "injected" || outcome === "steered") {
|
|
3285
3727
|
ctx.body = { ok: true, injected: true };
|
|
3286
3728
|
return;
|
|
3287
3729
|
}
|
|
3288
3730
|
ctx.status = 503;
|
|
3731
|
+
const failure = runnerManager.lastLiveSessionFailure?.(id);
|
|
3289
3732
|
ctx.body = {
|
|
3290
|
-
error:
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3733
|
+
error: failure?.message
|
|
3734
|
+
?? runnerManager.lastLiveSessionError?.(id)
|
|
3735
|
+
?? `live injection ${outcome}`,
|
|
3736
|
+
code: failure?.code ?? "live_inject_failed",
|
|
3737
|
+
outcome: outcome === "failed" ? "unknown" : "not_started",
|
|
3294
3738
|
};
|
|
3295
3739
|
});
|
|
3296
3740
|
// Stop the session's active turn (the web Stop button). For a live native
|
|
@@ -3316,6 +3760,7 @@ export function createControlRouter(opts) {
|
|
|
3316
3760
|
ctx.body = {
|
|
3317
3761
|
sessionId: id,
|
|
3318
3762
|
items: sessionLog ? await sessionLog.snapshot(id) : [],
|
|
3763
|
+
pendingInputs: [],
|
|
3319
3764
|
runtime: sessionRuntimeIndex.snapshot(id),
|
|
3320
3765
|
};
|
|
3321
3766
|
});
|
|
@@ -3406,7 +3851,15 @@ export function createControlRouter(opts) {
|
|
|
3406
3851
|
ctx.body = { error: "session_resource_cleanup_failed" };
|
|
3407
3852
|
return;
|
|
3408
3853
|
}
|
|
3409
|
-
runnerManager?.
|
|
3854
|
+
if (runnerManager?.terminateLiveSession) {
|
|
3855
|
+
await runnerManager.terminateLiveSession(id).catch((error) => {
|
|
3856
|
+
console.warn(`[control-api] session=${id} live teardown failed during deletion; continuing best-effort: ${error instanceof Error ? error.message : String(error)}`);
|
|
3857
|
+
return false;
|
|
3858
|
+
});
|
|
3859
|
+
}
|
|
3860
|
+
else {
|
|
3861
|
+
runnerManager?.stopRunner(id);
|
|
3862
|
+
}
|
|
3410
3863
|
sessionBus?.close(id);
|
|
3411
3864
|
deps.removeSessionMeta(id);
|
|
3412
3865
|
// Hard-delete the transcript too — the session list is meta ∪ log, so
|
|
@@ -3503,8 +3956,8 @@ function abortAsNull(signal) {
|
|
|
3503
3956
|
});
|
|
3504
3957
|
}
|
|
3505
3958
|
/** Derive a one-line session title from the first user message: collapse
|
|
3506
|
-
* whitespace, trim, and
|
|
3507
|
-
*
|
|
3959
|
+
* whitespace, trim, and fit within `limit` characters, including an ellipsis
|
|
3960
|
+
* when truncated. No LLM call is made. */
|
|
3508
3961
|
export function synthesizeSessionTitle(message, limit = 60) {
|
|
3509
3962
|
const collapsed = message.replace(/\s+/g, " ").trim();
|
|
3510
3963
|
if (collapsed.length <= limit)
|
|
@@ -3576,6 +4029,14 @@ function optionalRuntimeDevice(body) {
|
|
|
3576
4029
|
return body.device === undefined ? {} : { device: body.device };
|
|
3577
4030
|
}
|
|
3578
4031
|
function remoteRuntimeRpcTimeoutMs(method, params) {
|
|
4032
|
+
// Native startup/delivery owns phase-specific deadlines and returns their
|
|
4033
|
+
// concrete failures. A BFF deadline here would race those phases and replace
|
|
4034
|
+
// the real error with an ambiguous generic RPC timeout. The setup queue also
|
|
4035
|
+
// awaits Terminal startup before acknowledging the request.
|
|
4036
|
+
if (method === "session.message.send" ||
|
|
4037
|
+
method === "session.message.enqueue" ||
|
|
4038
|
+
method === "session.terminal.start")
|
|
4039
|
+
return null;
|
|
3579
4040
|
if (method === "session.emulator.attach")
|
|
3580
4041
|
return REMOTE_RUNTIME_EMULATOR_ATTACH_TIMEOUT_MS;
|
|
3581
4042
|
if (method === "session.emulator.type") {
|
|
@@ -3679,6 +4140,36 @@ function pluginInstallInvocationAbortScope(ctx, shutdownSignal) {
|
|
|
3679
4140
|
function browserArtifactInvocationAbortScope(ctx, shutdownSignal) {
|
|
3680
4141
|
return managementInvocationAbortScope(ctx, shutdownSignal, BROWSER_ARTIFACT_OPERATION_TIMEOUT_MS, "Browser artifact operation");
|
|
3681
4142
|
}
|
|
4143
|
+
function downloadInvocationAbortScope(ctx, shutdownSignal) {
|
|
4144
|
+
const controller = new AbortController();
|
|
4145
|
+
const abort = (reason) => {
|
|
4146
|
+
if (!controller.signal.aborted)
|
|
4147
|
+
controller.abort(reason);
|
|
4148
|
+
};
|
|
4149
|
+
const onRequestAborted = () => abort(namedError("download request aborted", "AbortError"));
|
|
4150
|
+
const onResponseClose = () => {
|
|
4151
|
+
if (!ctx.res.writableEnded) {
|
|
4152
|
+
abort(namedError("download client disconnected", "AbortError"));
|
|
4153
|
+
}
|
|
4154
|
+
};
|
|
4155
|
+
const onShutdown = () => abort(shutdownSignal?.reason ?? namedError("daemon is shutting down", "AbortError"));
|
|
4156
|
+
ctx.req.once("aborted", onRequestAborted);
|
|
4157
|
+
ctx.res.once("close", onResponseClose);
|
|
4158
|
+
if (shutdownSignal?.aborted)
|
|
4159
|
+
onShutdown();
|
|
4160
|
+
else
|
|
4161
|
+
shutdownSignal?.addEventListener("abort", onShutdown, { once: true });
|
|
4162
|
+
if (ctx.req.aborted)
|
|
4163
|
+
onRequestAborted();
|
|
4164
|
+
return {
|
|
4165
|
+
signal: controller.signal,
|
|
4166
|
+
dispose() {
|
|
4167
|
+
ctx.req.removeListener("aborted", onRequestAborted);
|
|
4168
|
+
ctx.res.removeListener("close", onResponseClose);
|
|
4169
|
+
shutdownSignal?.removeEventListener("abort", onShutdown);
|
|
4170
|
+
},
|
|
4171
|
+
};
|
|
4172
|
+
}
|
|
3682
4173
|
function managementInvocationAbortScope(ctx, shutdownSignal, timeoutMs, label) {
|
|
3683
4174
|
const controller = new AbortController();
|
|
3684
4175
|
const abort = (reason) => {
|
|
@@ -3899,8 +4390,14 @@ function runtimeTargetHostError(ctx, error, forcedOutcome) {
|
|
|
3899
4390
|
const status = runtimeTargetHttpStatus(code);
|
|
3900
4391
|
ctx.status = status;
|
|
3901
4392
|
const outcome = forcedOutcome ?? runtimeTargetErrorOutcome(error);
|
|
4393
|
+
const applicationMessage = error instanceof Error && error.name === "DirectRuntimeRpcError"
|
|
4394
|
+
? error.message.replace(/^Remote Runtime RPC failed: [^:]+: /, "")
|
|
4395
|
+
: undefined;
|
|
3902
4396
|
ctx.body = {
|
|
3903
|
-
error: status === 500 ? "internal_error" : code,
|
|
4397
|
+
error: applicationMessage ?? (status === 500 ? "internal_error" : code),
|
|
4398
|
+
...(applicationMessage
|
|
4399
|
+
? { code: status === 500 ? "internal_error" : code }
|
|
4400
|
+
: {}),
|
|
3904
4401
|
...(outcome === undefined ? {} : { outcome }),
|
|
3905
4402
|
};
|
|
3906
4403
|
}
|
|
@@ -3909,9 +4406,19 @@ function runtimeLocalBrowserError(ctx, error) {
|
|
|
3909
4406
|
? error.code
|
|
3910
4407
|
: undefined;
|
|
3911
4408
|
switch (code) {
|
|
4409
|
+
case "human_control_active":
|
|
4410
|
+
ctx.status = 409;
|
|
4411
|
+
ctx.body = { error: code, hint: "Release Browser Control before Agent actions." };
|
|
4412
|
+
return;
|
|
4413
|
+
case "command_timeout":
|
|
4414
|
+
ctx.status = 504;
|
|
4415
|
+
ctx.body = { error: "command_timeout", outcome: "unknown" };
|
|
4416
|
+
return;
|
|
3912
4417
|
case "invalid_request":
|
|
3913
4418
|
ctx.status = 400;
|
|
3914
|
-
ctx.body = { error: "invalid_request"
|
|
4419
|
+
ctx.body = { error: "invalid_request", ...(error instanceof Error && error.name === "PageAutomationError"
|
|
4420
|
+
? { message: error.message.slice(0, 2048), hint: "Run rynx skills get browser for Browser resources; after opening a Browser, use rynx browser exec -- --help for page commands." }
|
|
4421
|
+
: {}) };
|
|
3915
4422
|
return;
|
|
3916
4423
|
case "not_found":
|
|
3917
4424
|
ctx.status = 404;
|
|
@@ -3923,10 +4430,30 @@ function runtimeLocalBrowserError(ctx, error) {
|
|
|
3923
4430
|
ctx.body = { error: "unavailable" };
|
|
3924
4431
|
return;
|
|
3925
4432
|
case "host_failure":
|
|
3926
|
-
case "outcome_unknown":
|
|
3927
4433
|
ctx.status = 502;
|
|
3928
4434
|
ctx.body = { error: "operation_failed" };
|
|
3929
4435
|
return;
|
|
4436
|
+
case "outcome_unknown":
|
|
4437
|
+
ctx.status = 502;
|
|
4438
|
+
ctx.body = { error: "outcome_unknown", outcome: "unknown", hint: "Do not replay this action. Run rynx browser exec -- snapshot -i to inspect its outcome." };
|
|
4439
|
+
return;
|
|
4440
|
+
case "driver_restarted":
|
|
4441
|
+
case "generation_mismatch":
|
|
4442
|
+
ctx.status = 409;
|
|
4443
|
+
ctx.body = { error: code, hint: "Run rynx browser exec -- snapshot -i for fresh Page references." };
|
|
4444
|
+
return;
|
|
4445
|
+
case "capacity":
|
|
4446
|
+
ctx.status = 429;
|
|
4447
|
+
ctx.body = { error: "capacity" };
|
|
4448
|
+
return;
|
|
4449
|
+
case "unsupported":
|
|
4450
|
+
ctx.status = 501;
|
|
4451
|
+
ctx.body = { error: "unsupported", hint: "Upgrade the Runtime and Desktop Host together." };
|
|
4452
|
+
return;
|
|
4453
|
+
case "command_failed":
|
|
4454
|
+
ctx.status = 422;
|
|
4455
|
+
ctx.body = { error: "command_failed", message: error instanceof Error ? error.message : "agent-browser command failed", hint: "Run rynx browser exec -- --help, or inspect a fresh snapshot before another action." };
|
|
4456
|
+
return;
|
|
3930
4457
|
default:
|
|
3931
4458
|
ctx.status = 500;
|
|
3932
4459
|
ctx.body = { error: "internal_error" };
|
|
@@ -3988,6 +4515,83 @@ function publicRuntimeStreamError(error) {
|
|
|
3988
4515
|
}
|
|
3989
4516
|
class RequestBodyTooLargeError extends Error {
|
|
3990
4517
|
}
|
|
4518
|
+
function isMediaType(value) {
|
|
4519
|
+
return value.length <= 255 && /^[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]+$/.test(value);
|
|
4520
|
+
}
|
|
4521
|
+
async function forwardResourceUploadBody(ctx, uploadId, resumeOffset, expectedBytes, writeChunk) {
|
|
4522
|
+
let received = 0;
|
|
4523
|
+
let remoteOffset = resumeOffset;
|
|
4524
|
+
let carry = Buffer.alloc(0);
|
|
4525
|
+
for await (const raw of ctx.req) {
|
|
4526
|
+
const incoming = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
|
|
4527
|
+
if (received + incoming.byteLength > expectedBytes) {
|
|
4528
|
+
throw runtimeProtocolError("Resource upload exceeds Content-Length");
|
|
4529
|
+
}
|
|
4530
|
+
const skip = Math.min(incoming.byteLength, Math.max(0, resumeOffset - received));
|
|
4531
|
+
received += incoming.byteLength;
|
|
4532
|
+
let cursor = skip;
|
|
4533
|
+
while (cursor < incoming.byteLength) {
|
|
4534
|
+
const needed = SESSION_RESOURCE_TRANSFER_CHUNK_BYTES - carry.byteLength;
|
|
4535
|
+
const take = Math.min(needed, incoming.byteLength - cursor);
|
|
4536
|
+
carry = carry.byteLength === 0
|
|
4537
|
+
? incoming.subarray(cursor, cursor + take)
|
|
4538
|
+
: Buffer.concat([carry, incoming.subarray(cursor, cursor + take)]);
|
|
4539
|
+
cursor += take;
|
|
4540
|
+
if (carry.byteLength < SESSION_RESOURCE_TRANSFER_CHUNK_BYTES)
|
|
4541
|
+
continue;
|
|
4542
|
+
const written = await writeChunk(uploadId, remoteOffset, carry.toString("base64"));
|
|
4543
|
+
if (written.offset !== remoteOffset + carry.byteLength) {
|
|
4544
|
+
throw runtimeProtocolError("Runtime Session resource upload did not advance");
|
|
4545
|
+
}
|
|
4546
|
+
remoteOffset = written.offset;
|
|
4547
|
+
carry = Buffer.alloc(0);
|
|
4548
|
+
}
|
|
4549
|
+
}
|
|
4550
|
+
if (received !== expectedBytes) {
|
|
4551
|
+
throw runtimeProtocolError("Resource upload ended before Content-Length");
|
|
4552
|
+
}
|
|
4553
|
+
if (carry.byteLength > 0) {
|
|
4554
|
+
const written = await writeChunk(uploadId, remoteOffset, carry.toString("base64"));
|
|
4555
|
+
if (written.offset !== remoteOffset + carry.byteLength) {
|
|
4556
|
+
throw runtimeProtocolError("Runtime Session resource upload did not advance");
|
|
4557
|
+
}
|
|
4558
|
+
remoteOffset = written.offset;
|
|
4559
|
+
}
|
|
4560
|
+
if (remoteOffset !== expectedBytes) {
|
|
4561
|
+
throw runtimeProtocolError("Runtime Session resource upload length changed");
|
|
4562
|
+
}
|
|
4563
|
+
}
|
|
4564
|
+
function parseSingleByteRange(header, byteLength) {
|
|
4565
|
+
if (!header)
|
|
4566
|
+
return undefined;
|
|
4567
|
+
const match = /^bytes=(\d*)-(\d*)$/.exec(header.trim());
|
|
4568
|
+
if (!match || byteLength <= 0)
|
|
4569
|
+
return "unsatisfiable";
|
|
4570
|
+
const [, startText, endText] = match;
|
|
4571
|
+
if (!startText && !endText)
|
|
4572
|
+
return "unsatisfiable";
|
|
4573
|
+
if (!startText) {
|
|
4574
|
+
const suffix = Number(endText);
|
|
4575
|
+
if (!Number.isSafeInteger(suffix) || suffix <= 0)
|
|
4576
|
+
return "unsatisfiable";
|
|
4577
|
+
return { start: Math.max(0, byteLength - suffix), end: byteLength - 1 };
|
|
4578
|
+
}
|
|
4579
|
+
const start = Number(startText);
|
|
4580
|
+
const requestedEnd = endText ? Number(endText) : byteLength - 1;
|
|
4581
|
+
if (!Number.isSafeInteger(start) ||
|
|
4582
|
+
!Number.isSafeInteger(requestedEnd) ||
|
|
4583
|
+
start < 0 ||
|
|
4584
|
+
requestedEnd < start ||
|
|
4585
|
+
start >= byteLength) {
|
|
4586
|
+
return "unsatisfiable";
|
|
4587
|
+
}
|
|
4588
|
+
return { start, end: Math.min(requestedEnd, byteLength - 1) };
|
|
4589
|
+
}
|
|
4590
|
+
function contentDisposition(filename) {
|
|
4591
|
+
if (!filename)
|
|
4592
|
+
return "inline";
|
|
4593
|
+
return `inline; filename*=UTF-8''${encodeURIComponent(filename)}`;
|
|
4594
|
+
}
|
|
3991
4595
|
async function readBoundedBinary(ctx, maxBytes) {
|
|
3992
4596
|
const declaredLength = Number(ctx.get("content-length"));
|
|
3993
4597
|
if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {
|