@rynx-ai/server 0.1.11-beta.3 → 0.1.11-beta.30

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.
Files changed (448) hide show
  1. package/dist/control-api.d.ts +16 -4
  2. package/dist/control-api.js +676 -83
  3. package/dist/control-web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  4. package/dist/control-web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  5. package/dist/control-web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  6. package/dist/control-web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  7. package/dist/control-web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  8. package/dist/control-web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  9. package/dist/control-web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  10. package/dist/control-web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  11. package/dist/control-web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  12. package/dist/control-web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  13. package/dist/control-web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  14. package/dist/control-web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  15. package/dist/control-web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  16. package/dist/control-web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  17. package/dist/control-web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  18. package/dist/control-web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  19. package/dist/control-web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  20. package/dist/control-web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  21. package/dist/control-web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  22. package/dist/control-web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  23. package/dist/control-web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  24. package/dist/control-web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  25. package/dist/control-web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  26. package/dist/control-web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  27. package/dist/control-web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  28. package/dist/control-web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  29. package/dist/control-web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  30. package/dist/control-web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  31. package/dist/control-web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  32. package/dist/control-web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  33. package/dist/control-web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  34. package/dist/control-web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  35. package/dist/control-web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  36. package/dist/control-web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  37. package/dist/control-web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  38. package/dist/control-web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  39. package/dist/control-web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  40. package/dist/control-web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  41. package/dist/control-web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  42. package/dist/control-web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  43. package/dist/control-web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  44. package/dist/control-web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  45. package/dist/control-web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  46. package/dist/control-web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  47. package/dist/control-web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  48. package/dist/control-web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  49. package/dist/control-web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  50. package/dist/control-web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  51. package/dist/control-web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  52. package/dist/control-web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  53. package/dist/control-web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  54. package/dist/control-web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  55. package/dist/control-web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  56. package/dist/control-web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  57. package/dist/control-web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  58. package/dist/control-web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  59. package/dist/control-web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  60. package/dist/control-web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  61. package/dist/control-web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  62. package/dist/control-web/assets/abap-BdImnpbu.js +1 -0
  63. package/dist/control-web/assets/abnfDiagram-VRR7QNED-COu02MlJ.js +1 -0
  64. package/dist/control-web/assets/actionscript-3-CoDkCxhg.js +1 -0
  65. package/dist/control-web/assets/ada-bCR0ucgS.js +1 -0
  66. package/dist/control-web/assets/andromeeda-C4gqWexZ.js +1 -0
  67. package/dist/control-web/assets/angular-html-CU67Zn6k.js +1 -0
  68. package/dist/control-web/assets/angular-ts-BwZT4LLn.js +1 -0
  69. package/dist/control-web/assets/apache-Pmp26Uib.js +1 -0
  70. package/dist/control-web/assets/apex-D8_7TLub.js +1 -0
  71. package/dist/control-web/assets/apl-dKokRX4l.js +1 -0
  72. package/dist/control-web/assets/applescript-Co6uUVPk.js +1 -0
  73. package/dist/control-web/assets/ara-BRHolxvo.js +1 -0
  74. package/dist/control-web/assets/arc-DqiFeYAM.js +1 -0
  75. package/dist/control-web/assets/architectureDiagram-ZJ3FMSHR-BWFGgUV4.js +36 -0
  76. package/dist/control-web/assets/asciidoc-Ve4PFQV2.js +1 -0
  77. package/dist/control-web/assets/asm-D_Q5rh1f.js +1 -0
  78. package/dist/control-web/assets/astro-CbQHKStN.js +1 -0
  79. package/dist/control-web/assets/aurora-x-D-2ljcwZ.js +1 -0
  80. package/dist/control-web/assets/awk-DMzUqQB5.js +1 -0
  81. package/dist/control-web/assets/ayu-dark-DYE7WIF3.js +1 -0
  82. package/dist/control-web/assets/ayu-light-BA47KaF1.js +1 -0
  83. package/dist/control-web/assets/ayu-mirage-32ctXXKs.js +1 -0
  84. package/dist/control-web/assets/ballerina-BFfxhgS-.js +1 -0
  85. package/dist/control-web/assets/bat-BkioyH1T.js +1 -0
  86. package/dist/control-web/assets/beancount-k_qm7-4y.js +1 -0
  87. package/dist/control-web/assets/berry-uYugtg8r.js +1 -0
  88. package/dist/control-web/assets/bibtex-CHM0blh-.js +1 -0
  89. package/dist/control-web/assets/bicep-Bmn6On1c.js +1 -0
  90. package/dist/control-web/assets/bird2-DPOp833l.js +1 -0
  91. package/dist/control-web/assets/blade-D4QpJJKB.js +1 -0
  92. package/dist/control-web/assets/blockDiagram-677ZJIJ3-ZC0bXDzB.js +132 -0
  93. package/dist/control-web/assets/bsl-BO_Y6i37.js +1 -0
  94. package/dist/control-web/assets/c-BIGW1oBm.js +1 -0
  95. package/dist/control-web/assets/c3-eo99z4R2.js +1 -0
  96. package/dist/control-web/assets/c4Diagram-LMCZKHZV-Uupq5I-s.js +10 -0
  97. package/dist/control-web/assets/cadence-Bv_4Rxtq.js +1 -0
  98. package/dist/control-web/assets/cairo-KRGpt6FW.js +1 -0
  99. package/dist/control-web/assets/catppuccin-frappe-DFWUc33u.js +1 -0
  100. package/dist/control-web/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
  101. package/dist/control-web/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
  102. package/dist/control-web/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
  103. package/dist/control-web/assets/channel-3HG15wfa.js +1 -0
  104. package/dist/control-web/assets/chunk-2Q5K7J3B-C77vwuDM.js +1 -0
  105. package/dist/control-web/assets/chunk-32BRIVSS-BkfLE_TX.js +1 -0
  106. package/dist/control-web/assets/chunk-5VM5RSS4-By6zfDWW.js +15 -0
  107. package/dist/control-web/assets/chunk-EX3LRPZG-CO439p_3.js +231 -0
  108. package/dist/control-web/assets/chunk-JWPE2WC7-B9BPEwug.js +1 -0
  109. package/dist/control-web/assets/chunk-MOJQB5TN-CYKygWZz.js +88 -0
  110. package/dist/control-web/assets/chunk-RYQCIY6F-ug-An4HG.js +1 -0
  111. package/dist/control-web/assets/chunk-V7JOEXUC-3UFQGnKX.js +206 -0
  112. package/dist/control-web/assets/chunk-VR4S4FIN-DjspjYUb.js +1 -0
  113. package/dist/control-web/assets/chunk-XXDRQBXY-3znnutie.js +1 -0
  114. package/dist/control-web/assets/clarity-D53aC0YG.js +1 -0
  115. package/dist/control-web/assets/classDiagram-OUVF2IWQ-WmU4L9YT.js +1 -0
  116. package/dist/control-web/assets/classDiagram-v2-EOCWNBFH-WmU4L9YT.js +1 -0
  117. package/dist/control-web/assets/clojure-P80f7IUj.js +1 -0
  118. package/dist/control-web/assets/cmake-D1j8_8rp.js +1 -0
  119. package/dist/control-web/assets/cobol-nwyudZeR.js +1 -0
  120. package/dist/control-web/assets/codeowners-Bp6g37R7.js +1 -0
  121. package/dist/control-web/assets/codeql-DsOJ9woJ.js +1 -0
  122. package/dist/control-web/assets/coffee-Ch7k5sss.js +1 -0
  123. package/dist/control-web/assets/common-lisp-Cg-RD9OK.js +1 -0
  124. package/dist/control-web/assets/coq-DkFqJrB1.js +1 -0
  125. package/dist/control-web/assets/cose-bilkent-JH36ORCC-Dr28goCd.js +1 -0
  126. package/dist/control-web/assets/cpp-CofmeUqb.js +1 -0
  127. package/dist/control-web/assets/crystal-tKQVLTB8.js +1 -0
  128. package/dist/control-web/assets/csharp-COcwbKMJ.js +1 -0
  129. package/dist/control-web/assets/css-DPfMkruS.js +1 -0
  130. package/dist/control-web/assets/csv-fuZLfV_i.js +1 -0
  131. package/dist/control-web/assets/cue-D82EKSYY.js +1 -0
  132. package/dist/control-web/assets/cynefin-VYW2F7L2-Be5uJhnw.js +178 -0
  133. package/dist/control-web/assets/cynefinDiagram-TSTJHNR4-BLxtSvL6.js +62 -0
  134. package/dist/control-web/assets/cypher-COkxafJQ.js +1 -0
  135. package/dist/control-web/assets/cytoscape.esm-DTSO7Bv0.js +331 -0
  136. package/dist/control-web/assets/d-85-TOEBH.js +1 -0
  137. package/dist/control-web/assets/dagre-VKFMJZFB-DPRuDV5p.js +4 -0
  138. package/dist/control-web/assets/dark-plus-C3mMm8J8.js +1 -0
  139. package/dist/control-web/assets/dart-CF10PKvl.js +1 -0
  140. package/dist/control-web/assets/dax-CEL-wOlO.js +1 -0
  141. package/dist/control-web/assets/defaultLocale-DX6XiGOO.js +1 -0
  142. package/dist/control-web/assets/desktop-BmXAJ9_W.js +1 -0
  143. package/dist/control-web/assets/diagram-FQU43EPY-Cybg22U0.js +3 -0
  144. package/dist/control-web/assets/diagram-G47NLZAW-CGeIKUfW.js +24 -0
  145. package/dist/control-web/assets/diagram-NH7WQ7WH-BJq5MBRm.js +24 -0
  146. package/dist/control-web/assets/diagram-OA4YK3LP-DquOQGwg.js +30 -0
  147. package/dist/control-web/assets/diagram-WEI45ONY-Cblb4xP2.js +41 -0
  148. package/dist/control-web/assets/diff-D97Zzqfu.js +1 -0
  149. package/dist/control-web/assets/docker-BcOcwvcX.js +1 -0
  150. package/dist/control-web/assets/dotenv-Da5cRb03.js +1 -0
  151. package/dist/control-web/assets/dracula-BzJJZx-M.js +1 -0
  152. package/dist/control-web/assets/dracula-soft-BXkSAIEj.js +1 -0
  153. package/dist/control-web/assets/dream-maker-BtqSS_iP.js +1 -0
  154. package/dist/control-web/assets/ebnfDiagram-CCIWWBDH-CQjHiOqj.js +1 -0
  155. package/dist/control-web/assets/edge-BkV0erSs.js +1 -0
  156. package/dist/control-web/assets/elixir-CDX3lj18.js +1 -0
  157. package/dist/control-web/assets/elm-DbKCFpqz.js +1 -0
  158. package/dist/control-web/assets/emacs-lisp-C9XAeP06.js +1 -0
  159. package/dist/control-web/assets/erDiagram-Q63AITRT-Bspr3uKJ.js +85 -0
  160. package/dist/control-web/assets/erb-B12qg9BL.js +1 -0
  161. package/dist/control-web/assets/erlang-DsQrWhSR.js +1 -0
  162. package/dist/control-web/assets/everforest-dark-BgDCqdQA.js +1 -0
  163. package/dist/control-web/assets/everforest-light-C8M2exoo.js +1 -0
  164. package/dist/control-web/assets/fennel-BYunw83y.js +1 -0
  165. package/dist/control-web/assets/fish-BvzEVeQv.js +1 -0
  166. package/dist/control-web/assets/flowDiagram-23GEKE2U-CxcZyBA-.js +156 -0
  167. package/dist/control-web/assets/fluent-C4IJs8-o.js +1 -0
  168. package/dist/control-web/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
  169. package/dist/control-web/assets/fortran-free-form-BxgE0vQu.js +1 -0
  170. package/dist/control-web/assets/fsharp-CXgrBDvD.js +1 -0
  171. package/dist/control-web/assets/ganttDiagram-NO4QXBWP-qBdh7A-P.js +292 -0
  172. package/dist/control-web/assets/gdresource-BOOCDP_w.js +1 -0
  173. package/dist/control-web/assets/gdscript-C5YyOfLZ.js +1 -0
  174. package/dist/control-web/assets/gdshader-DkwncUOv.js +1 -0
  175. package/dist/control-web/assets/genie-D0YGMca9.js +1 -0
  176. package/dist/control-web/assets/gherkin-DyxjwDmM.js +1 -0
  177. package/dist/control-web/assets/git-commit-F4YmCXRG.js +1 -0
  178. package/dist/control-web/assets/git-rebase-r7XF79zn.js +1 -0
  179. package/dist/control-web/assets/gitGraphDiagram-IHSO6WYX-BTYub2KT.js +106 -0
  180. package/dist/control-web/assets/github-dark-DHJKELXO.js +1 -0
  181. package/dist/control-web/assets/github-dark-default-Cuk6v7N8.js +1 -0
  182. package/dist/control-web/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  183. package/dist/control-web/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  184. package/dist/control-web/assets/github-light-DAi9KRSo.js +1 -0
  185. package/dist/control-web/assets/github-light-default-D7oLnXFd.js +1 -0
  186. package/dist/control-web/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  187. package/dist/control-web/assets/gleam-BspZqrRM.js +1 -0
  188. package/dist/control-web/assets/glimmer-js-Rg0-pVw9.js +1 -0
  189. package/dist/control-web/assets/glimmer-ts-U6CK756n.js +1 -0
  190. package/dist/control-web/assets/glsl-DplSGwfg.js +1 -0
  191. package/dist/control-web/assets/gn-n2N0HUVH.js +1 -0
  192. package/dist/control-web/assets/gnuplot-DdkO51Og.js +1 -0
  193. package/dist/control-web/assets/go-CxLEBnE3.js +1 -0
  194. package/dist/control-web/assets/graph-C9eacEi8.js +1 -0
  195. package/dist/control-web/assets/graphql-ChdNCCLP.js +1 -0
  196. package/dist/control-web/assets/groovy-gcz8RCvz.js +1 -0
  197. package/dist/control-web/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  198. package/dist/control-web/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  199. package/dist/control-web/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  200. package/dist/control-web/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  201. package/dist/control-web/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  202. package/dist/control-web/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  203. package/dist/control-web/assets/hack-CaT9iCJl.js +1 -0
  204. package/dist/control-web/assets/haml-B8DHNrY2.js +1 -0
  205. package/dist/control-web/assets/handlebars-BL8al0AC.js +1 -0
  206. package/dist/control-web/assets/haskell-Df6bDoY_.js +1 -0
  207. package/dist/control-web/assets/haxe-CzTSHFRz.js +1 -0
  208. package/dist/control-web/assets/hcl-BWvSN4gD.js +1 -0
  209. package/dist/control-web/assets/{highlighted-body-OFNGDK62-DWWsUtHF.js → highlighted-body-OFNGDK62-DyksUrwu.js} +1 -1
  210. package/dist/control-web/assets/hjson-D5-asLiD.js +1 -0
  211. package/dist/control-web/assets/hlsl-D3lLCCz7.js +1 -0
  212. package/dist/control-web/assets/horizon-BUw7H-hv.js +1 -0
  213. package/dist/control-web/assets/horizon-bright-Cn-bp-IR.js +1 -0
  214. package/dist/control-web/assets/houston-DnULxvSX.js +1 -0
  215. package/dist/control-web/assets/html-GMplVEZG.js +1 -0
  216. package/dist/control-web/assets/html-derivative-BFtXZ54Q.js +1 -0
  217. package/dist/control-web/assets/http-jrhK8wxY.js +1 -0
  218. package/dist/control-web/assets/hurl-irOxFIW8.js +1 -0
  219. package/dist/control-web/assets/hxml-Bvhsp5Yf.js +1 -0
  220. package/dist/control-web/assets/hy-DFXneXwc.js +1 -0
  221. package/dist/control-web/assets/imba-DGztddWO.js +1 -0
  222. package/dist/control-web/assets/index-B9SAq_63.js +718 -0
  223. package/dist/control-web/assets/index-BDaSctIT.js +153 -0
  224. package/dist/control-web/assets/index-CtaYRNgJ.css +32 -0
  225. package/dist/control-web/assets/infoDiagram-FWYZ7A6U-ChbQR3Zo.js +2 -0
  226. package/dist/control-web/assets/ini-BEwlwnbL.js +1 -0
  227. package/dist/control-web/assets/init-Gi6I4Gst.js +1 -0
  228. package/dist/control-web/assets/ishikawaDiagram-FXEZZL3T-C-4_qGzn.js +70 -0
  229. package/dist/control-web/assets/java-CylS5w8V.js +1 -0
  230. package/dist/control-web/assets/javascript-wDzz0qaB.js +1 -0
  231. package/dist/control-web/assets/jinja-4LBKfQ-Z.js +1 -0
  232. package/dist/control-web/assets/jison-wvAkD_A8.js +1 -0
  233. package/dist/control-web/assets/journeyDiagram-5HDEW3XC-B090zN18.js +139 -0
  234. package/dist/control-web/assets/json-Cp-IABpG.js +1 -0
  235. package/dist/control-web/assets/json5-C9tS-k6U.js +1 -0
  236. package/dist/control-web/assets/jsonc-Des-eS-w.js +1 -0
  237. package/dist/control-web/assets/jsonl-DcaNXYhu.js +1 -0
  238. package/dist/control-web/assets/jsonnet-DFQXde-d.js +1 -0
  239. package/dist/control-web/assets/jssm-C2t-YnRu.js +1 -0
  240. package/dist/control-web/assets/jsx-g9-lgVsj.js +1 -0
  241. package/dist/control-web/assets/julia-CxzCAyBv.js +1 -0
  242. package/dist/control-web/assets/just-Cw27pwNe.js +1 -0
  243. package/dist/control-web/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  244. package/dist/control-web/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  245. package/dist/control-web/assets/kanagawa-wave-DWedfzmr.js +1 -0
  246. package/dist/control-web/assets/kanban-definition-HUTT4EX6-RlTcRbPs.js +89 -0
  247. package/dist/control-web/assets/kdl-DV7GczEv.js +1 -0
  248. package/dist/control-web/assets/kotlin-BdnUsdx6.js +1 -0
  249. package/dist/control-web/assets/kusto-DZf3V79B.js +1 -0
  250. package/dist/control-web/assets/laserwave-DUszq2jm.js +1 -0
  251. package/dist/control-web/assets/latex-CWtU0Tv5.js +1 -0
  252. package/dist/control-web/assets/layout-DEXfKzaS.js +1 -0
  253. package/dist/control-web/assets/lean-BZvkOJ9d.js +1 -0
  254. package/dist/control-web/assets/less-B1dDrJ26.js +1 -0
  255. package/dist/control-web/assets/light-plus-B7mTdjB0.js +1 -0
  256. package/dist/control-web/assets/linear-DTuNxDqu.js +1 -0
  257. package/dist/control-web/assets/liquid-DYVedYrR.js +1 -0
  258. package/dist/control-web/assets/llvm-DjAJT7YJ.js +1 -0
  259. package/dist/control-web/assets/log-2UxHyX5q.js +1 -0
  260. package/dist/control-web/assets/logo-BtOb2qkB.js +1 -0
  261. package/dist/control-web/assets/lua-BaeVxFsk.js +1 -0
  262. package/dist/control-web/assets/luau-C-HG3fhB.js +1 -0
  263. package/dist/control-web/assets/make-CHLpvVh8.js +1 -0
  264. package/dist/control-web/assets/map-Czzmt4hB.js +1 -0
  265. package/dist/control-web/assets/markdown-Cvjx9yec.js +1 -0
  266. package/dist/control-web/assets/marko-CnJfTvn9.js +1 -0
  267. package/dist/control-web/assets/material-theme-D5KoaKCx.js +1 -0
  268. package/dist/control-web/assets/material-theme-darker-BfHTSMKl.js +1 -0
  269. package/dist/control-web/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  270. package/dist/control-web/assets/material-theme-ocean-CyktbL80.js +1 -0
  271. package/dist/control-web/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  272. package/dist/control-web/assets/matlab-D7o27uSR.js +1 -0
  273. package/dist/control-web/assets/mdc-BMNejdWA.js +1 -0
  274. package/dist/control-web/assets/mdx-Cmh6b_Ma.js +1 -0
  275. package/dist/control-web/assets/mermaid-GHXKKRXX-BYZTj3zW.css +1 -0
  276. package/dist/control-web/assets/mermaid-GHXKKRXX-BkcV3dgg.js +710 -0
  277. package/dist/control-web/assets/mermaid-mWjccvbQ.js +1 -0
  278. package/dist/control-web/assets/min-dark-CafNBF8u.js +1 -0
  279. package/dist/control-web/assets/min-light-CTRr51gU.js +1 -0
  280. package/dist/control-web/assets/mindmap-definition-LN4V7U3C-DYby41E9.js +96 -0
  281. package/dist/control-web/assets/mipsasm-CKIfxQSi.js +1 -0
  282. package/dist/control-web/assets/mojo-rZm6bMo-.js +1 -0
  283. package/dist/control-web/assets/monokai-D4h5O-jR.js +1 -0
  284. package/dist/control-web/assets/moonbit-_H4v1dQx.js +1 -0
  285. package/dist/control-web/assets/move-IF9eRakj.js +1 -0
  286. package/dist/control-web/assets/narrat-DRg8JJMk.js +1 -0
  287. package/dist/control-web/assets/nextflow-Zz6hmt5N.js +1 -0
  288. package/dist/control-web/assets/nextflow-groovy-BeH2EWoN.js +1 -0
  289. package/dist/control-web/assets/nginx-BpAMiNFr.js +1 -0
  290. package/dist/control-web/assets/night-owl-C39BiMTA.js +1 -0
  291. package/dist/control-web/assets/night-owl-light-CMTm3GFP.js +1 -0
  292. package/dist/control-web/assets/nim-CVrawwO9.js +1 -0
  293. package/dist/control-web/assets/nix-CwoSXNpI.js +1 -0
  294. package/dist/control-web/assets/nord-Ddv68eIx.js +1 -0
  295. package/dist/control-web/assets/nushell-Cz2AlsmD.js +1 -0
  296. package/dist/control-web/assets/objective-c-DXmwc3jG.js +1 -0
  297. package/dist/control-web/assets/objective-cpp-CLxacb5B.js +1 -0
  298. package/dist/control-web/assets/ocaml-C0hk2d4L.js +1 -0
  299. package/dist/control-web/assets/odin-BBf5iR-q.js +1 -0
  300. package/dist/control-web/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  301. package/dist/control-web/assets/one-light-C3Wv6jpd.js +1 -0
  302. package/dist/control-web/assets/openscad-C4EeE6gA.js +1 -0
  303. package/dist/control-web/assets/ordinal-Cboi1Yqb.js +1 -0
  304. package/dist/control-web/assets/pascal-D93ZcfNL.js +1 -0
  305. package/dist/control-web/assets/pegDiagram-2B236MQR-CPK6GaEv.js +1 -0
  306. package/dist/control-web/assets/perl-C0TMdlhV.js +1 -0
  307. package/dist/control-web/assets/php-Dhbhpdrm.js +1 -0
  308. package/dist/control-web/assets/pieDiagram-ENE6RG2P-DLCmXuji.js +39 -0
  309. package/dist/control-web/assets/pkl-u5AG7uiY.js +1 -0
  310. package/dist/control-web/assets/plastic-3e1v2bzS.js +1 -0
  311. package/dist/control-web/assets/plsql-ChMvpjG-.js +1 -0
  312. package/dist/control-web/assets/po-BTJTHyun.js +1 -0
  313. package/dist/control-web/assets/poimandres-CS3Unz2-.js +1 -0
  314. package/dist/control-web/assets/polar-C0HS_06l.js +1 -0
  315. package/dist/control-web/assets/postcss-CXtECtnM.js +1 -0
  316. package/dist/control-web/assets/powerquery-CEu0bR-o.js +1 -0
  317. package/dist/control-web/assets/powershell-Dpen1YoG.js +1 -0
  318. package/dist/control-web/assets/prisma-Dd19v3D-.js +1 -0
  319. package/dist/control-web/assets/prolog-CbFg5uaA.js +1 -0
  320. package/dist/control-web/assets/proto-C7zT0LnQ.js +1 -0
  321. package/dist/control-web/assets/pug-CGlum2m_.js +1 -0
  322. package/dist/control-web/assets/puppet-BMWR74SV.js +1 -0
  323. package/dist/control-web/assets/purescript-CklMAg4u.js +1 -0
  324. package/dist/control-web/assets/python-B6aJPvgy.js +1 -0
  325. package/dist/control-web/assets/qml-3beO22l8.js +1 -0
  326. package/dist/control-web/assets/qmldir-C8lEn-DE.js +1 -0
  327. package/dist/control-web/assets/qss-IeuSbFQv.js +1 -0
  328. package/dist/control-web/assets/quadrantDiagram-ABIIQ3AL-RIS8r7CA.js +7 -0
  329. package/dist/control-web/assets/r-Dspwwk_N.js +1 -0
  330. package/dist/control-web/assets/racket-BqYA7rlc.js +1 -0
  331. package/dist/control-web/assets/railroadDiagram-RFXS5EU6-B1HB7xsg.js +1 -0
  332. package/dist/control-web/assets/raku-DXvB9xmW.js +1 -0
  333. package/dist/control-web/assets/razor-Uh8Bk_45.js +1 -0
  334. package/dist/control-web/assets/red-bN70gL4F.js +1 -0
  335. package/dist/control-web/assets/reg-C-SQnVFl.js +1 -0
  336. package/dist/control-web/assets/regexp-CDVJQ6XC.js +1 -0
  337. package/dist/control-web/assets/rel-C3B-1QV4.js +1 -0
  338. package/dist/control-web/assets/requirementDiagram-TGXJPOKE-Inh_4hU0.js +84 -0
  339. package/dist/control-web/assets/riscv-BM1_JUlF.js +1 -0
  340. package/dist/control-web/assets/ron-D8l8udqQ.js +1 -0
  341. package/dist/control-web/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
  342. package/dist/control-web/assets/rose-pine-moon-D4_iv3hh.js +1 -0
  343. package/dist/control-web/assets/rose-pine-qdsjHGoJ.js +1 -0
  344. package/dist/control-web/assets/rosmsg-BJDFO7_C.js +1 -0
  345. package/dist/control-web/assets/rst-BrH8l1NY.js +1 -0
  346. package/dist/control-web/assets/ruby-Dw2BHqvy.js +1 -0
  347. package/dist/control-web/assets/rust-B1yitclQ.js +1 -0
  348. package/dist/control-web/assets/sankeyDiagram-HTMAVEWB-DPF33kPB.js +40 -0
  349. package/dist/control-web/assets/sas-cz2c8ADy.js +1 -0
  350. package/dist/control-web/assets/sass-Cj5Yp3dK.js +1 -0
  351. package/dist/control-web/assets/scala-C151Ov-r.js +1 -0
  352. package/dist/control-web/assets/scheme-C98Dy4si.js +1 -0
  353. package/dist/control-web/assets/scss-OYdSNvt2.js +1 -0
  354. package/dist/control-web/assets/sdbl-DVxCFoDh.js +1 -0
  355. package/dist/control-web/assets/sequenceDiagram-DBY2YBRQ-iywKWoYc.js +162 -0
  356. package/dist/control-web/assets/shaderlab-Dg9Lc6iA.js +1 -0
  357. package/dist/control-web/assets/shellscript-Yzrsuije.js +1 -0
  358. package/dist/control-web/assets/shellsession-BADoaaVG.js +1 -0
  359. package/dist/control-web/assets/sizeCapture-X5ZJPWSS-DlnHubz9.js +1 -0
  360. package/dist/control-web/assets/slack-dark-BthQWCQV.js +1 -0
  361. package/dist/control-web/assets/slack-ochin-DqwNpetd.js +1 -0
  362. package/dist/control-web/assets/smalltalk-BERRCDM3.js +1 -0
  363. package/dist/control-web/assets/snazzy-light-Bw305WKR.js +1 -0
  364. package/dist/control-web/assets/solarized-dark-DXbdFlpD.js +1 -0
  365. package/dist/control-web/assets/solarized-light-L9t79GZl.js +1 -0
  366. package/dist/control-web/assets/solidity-rGO070M0.js +1 -0
  367. package/dist/control-web/assets/soy-Brmx7dQM.js +1 -0
  368. package/dist/control-web/assets/sparql-rVzFXLq3.js +1 -0
  369. package/dist/control-web/assets/splunk-BtCnVYZw.js +1 -0
  370. package/dist/control-web/assets/sql-BLtJtn59.js +1 -0
  371. package/dist/control-web/assets/ssh-config-_ykCGR6B.js +1 -0
  372. package/dist/control-web/assets/stata-BH5u7GGu.js +1 -0
  373. package/dist/control-web/assets/stateDiagram-2N3HPSRC-CShzll2N.js +1 -0
  374. package/dist/control-web/assets/stateDiagram-v2-6OUMAXLB-Cdx0fWna.js +1 -0
  375. package/dist/control-web/assets/stylus-BEDo0Tqx.js +1 -0
  376. package/dist/control-web/assets/surrealql-Bq5Q-fJD.js +1 -0
  377. package/dist/control-web/assets/svelte-C_ipcX3V.js +1 -0
  378. package/dist/control-web/assets/swift-D82vCrfD.js +1 -0
  379. package/dist/control-web/assets/swimlanes-5IMT3BWC-CxlQpFBv.js +2 -0
  380. package/dist/control-web/assets/swimlanesDiagram-G3AALYLV-CoX0jnUu.js +8 -0
  381. package/dist/control-web/assets/synthwave-84-CbfX1IO0.js +1 -0
  382. package/dist/control-web/assets/system-verilog-CnnmHF94.js +1 -0
  383. package/dist/control-web/assets/systemd-4A_iFExJ.js +1 -0
  384. package/dist/control-web/assets/talonscript-CkByrt1z.js +1 -0
  385. package/dist/control-web/assets/tasl-QIJgUcNo.js +1 -0
  386. package/dist/control-web/assets/tcl-dwOrl1Do.js +1 -0
  387. package/dist/control-web/assets/templ-P3uqSqPl.js +1 -0
  388. package/dist/control-web/assets/terraform-BETggiCN.js +1 -0
  389. package/dist/control-web/assets/tex-idrVyKtj.js +1 -0
  390. package/dist/control-web/assets/timeline-definition-FHXFAJF6-Dlx59Xc3.js +120 -0
  391. package/dist/control-web/assets/tokyo-night-hegEt444.js +1 -0
  392. package/dist/control-web/assets/toml-vGWfd6FD.js +1 -0
  393. package/dist/control-web/assets/ts-tags-zn1MmPIZ.js +1 -0
  394. package/dist/control-web/assets/tsv-B_m7g4N7.js +1 -0
  395. package/dist/control-web/assets/tsx-COt5Ahok.js +1 -0
  396. package/dist/control-web/assets/turtle-BsS91CYL.js +1 -0
  397. package/dist/control-web/assets/twig-DNn4PbVi.js +1 -0
  398. package/dist/control-web/assets/typescript-BPQ3VLAy.js +1 -0
  399. package/dist/control-web/assets/typespec-BGHnOYBU.js +1 -0
  400. package/dist/control-web/assets/typst-DHCkPAjA.js +1 -0
  401. package/dist/control-web/assets/v-BcVCzyr7.js +1 -0
  402. package/dist/control-web/assets/vala-CsfeWuGM.js +1 -0
  403. package/dist/control-web/assets/vb-D17OF-Vu.js +1 -0
  404. package/dist/control-web/assets/vennDiagram-L72KCM5P-DLsv4i_t.js +34 -0
  405. package/dist/control-web/assets/verilog-BQ8w6xss.js +1 -0
  406. package/dist/control-web/assets/vesper-DU1UobuO.js +1 -0
  407. package/dist/control-web/assets/vhdl-CeAyd5Ju.js +1 -0
  408. package/dist/control-web/assets/viml-CJc9bBzg.js +1 -0
  409. package/dist/control-web/assets/vitesse-black-Bkuqu6BP.js +1 -0
  410. package/dist/control-web/assets/vitesse-dark-D0r3Knsf.js +1 -0
  411. package/dist/control-web/assets/vitesse-light-CVO1_9PV.js +1 -0
  412. package/dist/control-web/assets/vue-DN_0RTcg.js +1 -0
  413. package/dist/control-web/assets/vue-html-AaS7Mt5G.js +1 -0
  414. package/dist/control-web/assets/vue-vine-CQOfvN7w.js +1 -0
  415. package/dist/control-web/assets/vyper-CDx5xZoG.js +1 -0
  416. package/dist/control-web/assets/wardleyDiagram-EHGQE667-BazV8fpH.js +78 -0
  417. package/dist/control-web/assets/wasm-CG6Dc4jp.js +1 -0
  418. package/dist/control-web/assets/wasm-MzD3tlZU.js +1 -0
  419. package/dist/control-web/assets/wenyan-BV7otONQ.js +1 -0
  420. package/dist/control-web/assets/wgsl-Dx-B1_4e.js +1 -0
  421. package/dist/control-web/assets/wikitext-BhOHFoWU.js +1 -0
  422. package/dist/control-web/assets/wit-5i3qLPDT.js +1 -0
  423. package/dist/control-web/assets/wolfram-lXgVvXCa.js +1 -0
  424. package/dist/control-web/assets/xml-sdJ4AIDG.js +1 -0
  425. package/dist/control-web/assets/xsl-CtQFsRM5.js +1 -0
  426. package/dist/control-web/assets/xychartDiagram-FW5EYKEG-Bx9uDlYu.js +7 -0
  427. package/dist/control-web/assets/yaml-Buea-lGh.js +1 -0
  428. package/dist/control-web/assets/zenscript-DVFEvuxE.js +1 -0
  429. package/dist/control-web/assets/zig-VOosw3JB.js +1 -0
  430. package/dist/control-web/index.html +2 -2
  431. package/dist/control-web-dist.d.ts +1 -1
  432. package/dist/control-web-dist.js +4 -2
  433. package/dist/machine-session-service.d.ts +82 -15
  434. package/dist/machine-session-service.js +670 -80
  435. package/dist/remote-runtime-dispatcher.d.ts +1 -1
  436. package/dist/remote-runtime-dispatcher.js +16 -1
  437. package/dist/remote-runtime-session-projection.js +5 -0
  438. package/dist/server.d.ts +24 -7
  439. package/dist/server.js +207 -46
  440. package/dist/session-portal.d.ts +42 -0
  441. package/dist/session-portal.js +746 -0
  442. package/dist/session-runtime-index.d.ts +2 -6
  443. package/dist/session-runtime-index.js +70 -38
  444. package/dist/terminal-ws.js +8 -6
  445. package/package.json +7 -7
  446. package/dist/control-web/assets/index-BnX7NWJX.js +0 -689
  447. package/dist/control-web/assets/index-CUoWRX2i.css +0 -32
  448. package/dist/control-web/assets/mermaid-GHXKKRXX-C1fxAgiw.js +0 -131
@@ -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";
@@ -19,6 +20,7 @@ import { parseRuntimeBrowserStateGetParams } from "@rynx-ai/protocol/runtime-bro
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;
@@ -724,6 +726,30 @@ export function createControlRouter(opts) {
724
726
  if (outcome.ok)
725
727
  ctx.body = outcome.result;
726
728
  };
729
+ const runtimeSessionExecutionSettings = async (ctx) => {
730
+ const outcome = await runtimeCall(ctx, "session.execution.get", {
731
+ sessionId: ctx.params.id,
732
+ });
733
+ if (outcome.ok)
734
+ ctx.body = outcome.result;
735
+ };
736
+ const runtimeSessionExecutionSettingsUpdate = async (ctx) => {
737
+ const body = await readRuntimeBody(ctx);
738
+ if (!body)
739
+ return;
740
+ if (!acceptRuntimeBodyKeys(ctx, body, ["model", "reasoningEffort", "collaborationMode"]))
741
+ return;
742
+ const outcome = await runtimeCall(ctx, "session.execution.update", {
743
+ sessionId: ctx.params.id,
744
+ model: body.model,
745
+ reasoningEffort: body.reasoningEffort,
746
+ ...(body.collaborationMode === undefined
747
+ ? {}
748
+ : { collaborationMode: body.collaborationMode }),
749
+ });
750
+ if (outcome.ok)
751
+ ctx.body = outcome.result;
752
+ };
727
753
  const runtimeSessionCreate = async (ctx) => {
728
754
  const body = await readRuntimeBody(ctx);
729
755
  if (!body)
@@ -834,7 +860,13 @@ export function createControlRouter(opts) {
834
860
  };
835
861
  const runtimeSessionResourceUpload = async (ctx) => {
836
862
  const uploadStarted = performance.now();
837
- const mediaType = ctx.get("content-type").split(";", 1)[0]?.trim();
863
+ const mediaType = ctx.get("content-type").split(";", 1)[0]?.trim().toLowerCase();
864
+ const requestedType = ctx.get("x-rynx-resource-type").trim();
865
+ const resourceType = requestedType === "input_image" || requestedType === "input_file"
866
+ ? requestedType
867
+ : SESSION_IMAGE_MEDIA_TYPES.includes(mediaType)
868
+ ? "input_image"
869
+ : "input_file";
838
870
  const clientUploadId = ctx.get("x-rynx-upload-id").trim();
839
871
  const encodedFilename = ctx.get("x-rynx-filename").trim();
840
872
  let filename = "";
@@ -847,7 +879,9 @@ export function createControlRouter(opts) {
847
879
  return;
848
880
  }
849
881
  if (!mediaType ||
850
- !SESSION_IMAGE_MEDIA_TYPES.includes(mediaType) ||
882
+ !isMediaType(mediaType) ||
883
+ (resourceType === "input_image" &&
884
+ !SESSION_IMAGE_MEDIA_TYPES.includes(mediaType)) ||
851
885
  !clientUploadId ||
852
886
  !filename ||
853
887
  filename.length > SESSION_RESOURCE_MAX_FILENAME_CHARS) {
@@ -855,23 +889,21 @@ export function createControlRouter(opts) {
855
889
  ctx.body = { error: "invalid_resource_upload" };
856
890
  return;
857
891
  }
858
- let bytes;
859
- const bodyReadStarted = performance.now();
860
- try {
861
- bytes = await readBoundedBinary(ctx, SESSION_RESOURCE_MAX_IMAGE_BYTES);
862
- }
863
- catch (error) {
864
- ctx.status = error instanceof RequestBodyTooLargeError ? 413 : 400;
865
- ctx.body = {
866
- error: error instanceof RequestBodyTooLargeError
867
- ? "request_too_large"
868
- : "invalid_resource_upload",
869
- };
892
+ const contentLengthHeader = ctx.get("content-length").trim();
893
+ if (!contentLengthHeader) {
894
+ ctx.status = 411;
895
+ ctx.body = { error: "content_length_required" };
870
896
  return;
871
897
  }
872
- if (bytes.byteLength === 0) {
898
+ const byteLength = Number(contentLengthHeader);
899
+ if (!Number.isSafeInteger(byteLength) || byteLength <= 0) {
873
900
  ctx.status = 400;
874
- ctx.body = { error: "empty_resource" };
901
+ ctx.body = { error: "invalid_content_length" };
902
+ return;
903
+ }
904
+ if (resourceType === "input_image" && byteLength > SESSION_RESOURCE_MAX_IMAGE_BYTES) {
905
+ ctx.status = 413;
906
+ ctx.body = { error: "request_too_large" };
875
907
  return;
876
908
  }
877
909
  const sessionId = ctx.params.id;
@@ -879,9 +911,7 @@ export function createControlRouter(opts) {
879
911
  const lease = local ? undefined : await acquireRuntimeLease(ctx);
880
912
  if (!local && !lease)
881
913
  return;
882
- const timings = new Map([
883
- ["body", performance.now() - bodyReadStarted],
884
- ]);
914
+ const timings = new Map();
885
915
  const timed = async (name, operation) => {
886
916
  const started = performance.now();
887
917
  try {
@@ -898,16 +928,18 @@ export function createControlRouter(opts) {
898
928
  ? local.beginResourceUpload({
899
929
  sessionId,
900
930
  clientUploadId,
931
+ type: resourceType,
901
932
  filename,
902
933
  mediaType,
903
- byteLength: bytes.byteLength,
934
+ byteLength,
904
935
  })
905
936
  : lease.call("session.resource.upload.begin", {
906
937
  sessionId,
907
938
  clientUploadId,
939
+ type: resourceType,
908
940
  filename,
909
941
  mediaType,
910
- byteLength: bytes.byteLength,
942
+ byteLength,
911
943
  }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS }));
912
944
  const writeChunk = (uploadId, offset, data) => timed("chunks", () => local
913
945
  ? local.writeResourceUploadChunk({ sessionId, uploadId, offset, data })
@@ -915,44 +947,72 @@ export function createControlRouter(opts) {
915
947
  const commit = (uploadId) => timed("commit", () => local
916
948
  ? local.commitResourceUpload({ sessionId, uploadId })
917
949
  : lease.call("session.resource.upload.commit", { sessionId, uploadId }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS }));
950
+ const discardPartial = (resourceId) => timed("restart", () => local
951
+ ? local.deleteResource({ sessionId, resourceId })
952
+ : lease.call("session.resource.delete", { sessionId, resourceId }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS }));
953
+ let requestResourceId;
954
+ let resourceCommitted = false;
918
955
  try {
919
956
  const resourcePolicy = await policy();
920
957
  if (!resourcePolicy.enabled ||
921
- !resourcePolicy.mediaTypes.includes(mediaType) ||
922
- bytes.byteLength > resourcePolicy.maxImageBytes) {
958
+ (resourceType === "input_image" &&
959
+ (!resourcePolicy.mediaTypes.includes(mediaType) ||
960
+ byteLength > resourcePolicy.maxImageBytes))) {
923
961
  ctx.status = 413;
924
962
  ctx.body = { error: "resource_policy_rejected" };
925
963
  return;
926
964
  }
927
- const begun = await begin();
965
+ let begun = await begin();
928
966
  if (begun.complete && begun.resource) {
967
+ ctx.req.resume();
929
968
  ctx.set("Cache-Control", "no-store");
930
969
  ctx.body = { resource: begun.resource };
931
970
  return;
932
971
  }
933
- if (begun.offset < 0 || begun.offset > bytes.byteLength) {
972
+ if (begun.offset < 0 || begun.offset > byteLength) {
934
973
  throw runtimeProtocolError("Runtime Session resource upload offset is invalid");
935
974
  }
936
- let offset = begun.offset;
937
- while (offset < bytes.byteLength) {
938
- const chunk = bytes.subarray(offset, Math.min(offset + SESSION_RESOURCE_TRANSFER_CHUNK_BYTES, bytes.byteLength));
939
- const written = await writeChunk(begun.uploadId, offset, chunk.toString("base64"));
940
- if (written.offset <= offset || written.offset > bytes.byteLength) {
941
- throw runtimeProtocolError("Runtime Session resource upload did not advance");
975
+ // Browser retries send the complete File body again. A target-side
976
+ // partial cannot be blindly combined with the new body's suffix: the
977
+ // caller may have reused an upload id for changed bytes. Restart the
978
+ // incomplete upload so committed content always matches this request.
979
+ if (begun.offset > 0) {
980
+ const discarded = await discardPartial(begun.resourceId);
981
+ if (!discarded.deleted) {
982
+ throw runtimeProtocolError("Runtime Session partial upload could not be restarted");
983
+ }
984
+ begun = await begin();
985
+ if (begun.complete || begun.offset !== 0) {
986
+ throw runtimeProtocolError("Runtime Session resource upload did not restart");
942
987
  }
943
- offset = written.offset;
944
988
  }
989
+ requestResourceId = begun.resourceId;
990
+ const bodyStarted = performance.now();
991
+ await forwardResourceUploadBody(ctx, begun.uploadId, begun.offset, byteLength, writeChunk);
992
+ timings.set("body", performance.now() - bodyStarted);
945
993
  const committed = await commit(begun.uploadId);
946
994
  if (committed.resource.resourceId !== begun.resourceId ||
995
+ committed.resource.type !== resourceType ||
947
996
  committed.resource.mediaType !== mediaType ||
948
- committed.resource.byteLength !== bytes.byteLength) {
997
+ committed.resource.byteLength !== byteLength) {
949
998
  throw runtimeProtocolError("Runtime Session resource upload identity changed");
950
999
  }
1000
+ resourceCommitted = true;
951
1001
  ctx.status = 201;
952
1002
  ctx.set("Cache-Control", "no-store");
953
1003
  ctx.body = committed;
954
1004
  }
955
1005
  catch (error) {
1006
+ if (requestResourceId && !resourceCommitted) {
1007
+ try {
1008
+ await discardPartial(requestResourceId);
1009
+ }
1010
+ catch {
1011
+ // The original error remains authoritative. Targets also reap stale
1012
+ // uploads, so a disconnected target cannot make cleanup block the
1013
+ // browser response indefinitely.
1014
+ }
1015
+ }
956
1016
  runtimeTargetHostError(ctx, error);
957
1017
  }
958
1018
  finally {
@@ -968,7 +1028,7 @@ export function createControlRouter(opts) {
968
1028
  event: "session.resource.upload.slow",
969
1029
  selector: ctx.params.selector,
970
1030
  sessionId,
971
- byteLength: bytes.byteLength,
1031
+ byteLength,
972
1032
  status: ctx.status,
973
1033
  timings: Object.fromEntries([...timings.entries()].map(([name, duration]) => [
974
1034
  name,
@@ -1012,16 +1072,32 @@ export function createControlRouter(opts) {
1012
1072
  const sessionId = ctx.params.id;
1013
1073
  const resourceId = ctx.params.resourceId;
1014
1074
  const local = ctx.params.selector === "local" ? localSessionResources : undefined;
1015
- const lease = local ? undefined : await acquireRuntimeLease(ctx);
1016
- if (!local && !lease)
1075
+ const invocation = downloadInvocationAbortScope(ctx, shutdownSignal);
1076
+ const lease = local ? undefined : await acquireRuntimeLease(ctx, invocation.signal);
1077
+ if (!local && !lease) {
1078
+ invocation.dispose();
1017
1079
  return;
1080
+ }
1081
+ let streamOwnsLease = false;
1082
+ let cleanedUp = false;
1083
+ const cleanup = () => {
1084
+ if (cleanedUp)
1085
+ return;
1086
+ cleanedUp = true;
1087
+ lease?.release();
1088
+ invocation.dispose();
1089
+ };
1018
1090
  try {
1019
1091
  const { resource } = local
1020
1092
  ? await local.getResource({ sessionId, resourceId })
1021
- : await lease.call("session.resource.get", { sessionId, resourceId }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS });
1093
+ : await lease.call("session.resource.get", { sessionId, resourceId }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
1022
1094
  if (resource.resourceId !== resourceId) {
1023
1095
  throw runtimeProtocolError("Runtime Session resource identity changed");
1024
1096
  }
1097
+ const byteLength = resource.byteLength;
1098
+ if (!Number.isSafeInteger(byteLength) || !byteLength || byteLength < 1) {
1099
+ throw runtimeProtocolError("Runtime Session resource length is invalid");
1100
+ }
1025
1101
  const etag = `"sha256-${resource.sha256}"`;
1026
1102
  ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
1027
1103
  ctx.set("ETag", etag);
@@ -1029,48 +1105,68 @@ export function createControlRouter(opts) {
1029
1105
  ctx.status = 304;
1030
1106
  return;
1031
1107
  }
1032
- const chunks = [];
1033
- let offset = 0;
1034
- while (offset < (resource.byteLength ?? 0)) {
1035
- const result = local
1036
- ? await local.readResource({
1037
- sessionId,
1038
- resourceId,
1039
- offset,
1040
- length: SESSION_RESOURCE_TRANSFER_CHUNK_BYTES,
1041
- })
1042
- : await lease.call("session.resource.read", {
1043
- sessionId,
1044
- resourceId,
1045
- offset,
1046
- length: SESSION_RESOURCE_TRANSFER_CHUNK_BYTES,
1047
- }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS });
1048
- const chunk = Buffer.from(result.data, "base64");
1049
- if (result.offset !== offset + chunk.byteLength || (!result.eof && chunk.byteLength === 0)) {
1050
- throw runtimeProtocolError("Runtime Session resource read did not advance");
1051
- }
1052
- chunks.push(chunk);
1053
- offset = result.offset;
1054
- if (result.eof)
1055
- break;
1056
- }
1057
- const body = Buffer.concat(chunks);
1058
- if (body.byteLength !== resource.byteLength) {
1059
- throw runtimeProtocolError("Runtime Session resource length changed");
1108
+ const requestedRange = ctx.get("range");
1109
+ const ifRange = ctx.get("if-range");
1110
+ const range = ifRange && ifRange !== etag
1111
+ ? undefined
1112
+ : parseSingleByteRange(requestedRange, byteLength);
1113
+ if (range === "unsatisfiable") {
1114
+ ctx.status = 416;
1115
+ ctx.set("Content-Range", `bytes */${byteLength}`);
1116
+ return;
1060
1117
  }
1118
+ const start = range?.start ?? 0;
1119
+ const end = range?.end ?? byteLength - 1;
1120
+ const responseLength = end - start + 1;
1061
1121
  ctx.set("Content-Security-Policy", "default-src 'none'; sandbox");
1062
1122
  ctx.set("Cross-Origin-Resource-Policy", "same-origin");
1063
1123
  ctx.set("X-Content-Type-Options", "nosniff");
1064
- ctx.set("Content-Disposition", "inline");
1124
+ ctx.set("Accept-Ranges", "bytes");
1125
+ ctx.set("Content-Disposition", contentDisposition(resource.filename));
1126
+ if (range) {
1127
+ ctx.status = 206;
1128
+ ctx.set("Content-Range", `bytes ${start}-${end}/${byteLength}`);
1129
+ }
1065
1130
  ctx.type = resource.mediaType;
1066
- ctx.length = body.byteLength;
1131
+ ctx.length = responseLength;
1132
+ if (ctx.method === "HEAD") {
1133
+ ctx.status = range ? 206 : 200;
1134
+ return;
1135
+ }
1136
+ streamOwnsLease = true;
1137
+ const body = Readable.from((async function* () {
1138
+ let offset = start;
1139
+ try {
1140
+ while (offset <= end) {
1141
+ const length = Math.min(SESSION_RESOURCE_TRANSFER_CHUNK_BYTES, end - offset + 1);
1142
+ const result = local
1143
+ ? await local.readResource({ sessionId, resourceId, offset, length })
1144
+ : await lease.call("session.resource.read", { sessionId, resourceId, offset, length }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
1145
+ const chunk = Buffer.from(result.data, "base64");
1146
+ if (result.offset !== offset + chunk.byteLength || chunk.byteLength === 0) {
1147
+ throw runtimeProtocolError("Runtime Session resource read did not advance");
1148
+ }
1149
+ offset = result.offset;
1150
+ yield chunk;
1151
+ }
1152
+ if (offset !== end + 1) {
1153
+ throw runtimeProtocolError("Runtime Session resource length changed");
1154
+ }
1155
+ }
1156
+ finally {
1157
+ cleanup();
1158
+ }
1159
+ })());
1160
+ body.once("close", cleanup);
1067
1161
  ctx.body = body;
1068
1162
  }
1069
1163
  catch (error) {
1070
1164
  runtimeTargetHostError(ctx, error);
1071
1165
  }
1072
1166
  finally {
1073
- lease?.release();
1167
+ if (!streamOwnsLease) {
1168
+ cleanup();
1169
+ }
1074
1170
  }
1075
1171
  };
1076
1172
  const runtimeSessionResourceDelete = async (ctx) => {
@@ -1094,6 +1190,243 @@ export function createControlRouter(opts) {
1094
1190
  if (outcome.ok)
1095
1191
  ctx.body = outcome.result;
1096
1192
  };
1193
+ const runtimeSessionItemFileContent = async (ctx) => {
1194
+ const sessionId = ctx.params.id;
1195
+ const itemId = ctx.params.itemId;
1196
+ const partIndex = Number(ctx.params.partIndex);
1197
+ if (!Number.isSafeInteger(partIndex) || partIndex < 0 || partIndex > 1_024) {
1198
+ ctx.status = 400;
1199
+ ctx.body = { error: "invalid_part_index" };
1200
+ return;
1201
+ }
1202
+ const local = ctx.params.selector === "local" ? localMachineSessions : undefined;
1203
+ const invocation = downloadInvocationAbortScope(ctx, shutdownSignal);
1204
+ const lease = local ? undefined : await acquireRuntimeLease(ctx, invocation.signal);
1205
+ if (!local && !lease) {
1206
+ invocation.dispose();
1207
+ return;
1208
+ }
1209
+ let streamOwnsLease = false;
1210
+ let cleanedUp = false;
1211
+ const cleanup = () => {
1212
+ if (cleanedUp)
1213
+ return;
1214
+ cleanedUp = true;
1215
+ lease?.release();
1216
+ invocation.dispose();
1217
+ };
1218
+ try {
1219
+ const { file } = local
1220
+ ? await local.getFile({ sessionId, itemId, partIndex })
1221
+ : await lease.call("session.file.get", { sessionId, itemId, partIndex }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
1222
+ if (file.itemId !== itemId || file.partIndex !== partIndex) {
1223
+ throw runtimeProtocolError("Runtime Session file identity changed");
1224
+ }
1225
+ const etag = `"file-${file.version}"`;
1226
+ ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
1227
+ ctx.set("ETag", etag);
1228
+ if (ctx.get("if-none-match").split(",").map((value) => value.trim()).includes(etag)) {
1229
+ ctx.status = 304;
1230
+ return;
1231
+ }
1232
+ const requestedRange = ctx.get("range");
1233
+ const ifRange = ctx.get("if-range");
1234
+ const range = ifRange && ifRange !== etag
1235
+ ? undefined
1236
+ : parseSingleByteRange(requestedRange, file.byteLength);
1237
+ if (range === "unsatisfiable") {
1238
+ ctx.status = 416;
1239
+ ctx.set("Content-Range", `bytes */${file.byteLength}`);
1240
+ return;
1241
+ }
1242
+ const start = range?.start ?? 0;
1243
+ const end = range?.end ?? file.byteLength - 1;
1244
+ ctx.set("Content-Security-Policy", "default-src 'none'; sandbox");
1245
+ ctx.set("Cross-Origin-Resource-Policy", "same-origin");
1246
+ ctx.set("X-Content-Type-Options", "nosniff");
1247
+ ctx.set("Accept-Ranges", "bytes");
1248
+ ctx.set("Content-Disposition", contentDisposition(file.filename));
1249
+ if (range) {
1250
+ ctx.status = 206;
1251
+ ctx.set("Content-Range", `bytes ${start}-${end}/${file.byteLength}`);
1252
+ }
1253
+ ctx.type = file.mediaType;
1254
+ ctx.length = end - start + 1;
1255
+ if (ctx.method === "HEAD") {
1256
+ ctx.status = range ? 206 : 200;
1257
+ return;
1258
+ }
1259
+ streamOwnsLease = true;
1260
+ const body = Readable.from((async function* () {
1261
+ let offset = start;
1262
+ try {
1263
+ while (offset <= end) {
1264
+ const length = Math.min(SESSION_RESOURCE_TRANSFER_CHUNK_BYTES, end - offset + 1);
1265
+ const result = local
1266
+ ? await local.readFile({
1267
+ sessionId,
1268
+ itemId,
1269
+ partIndex,
1270
+ version: file.version,
1271
+ offset,
1272
+ length,
1273
+ })
1274
+ : await lease.call("session.file.read", {
1275
+ sessionId,
1276
+ itemId,
1277
+ partIndex,
1278
+ version: file.version,
1279
+ offset,
1280
+ length,
1281
+ }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
1282
+ const chunk = Buffer.from(result.data, "base64");
1283
+ if (result.offset !== offset + chunk.byteLength || chunk.byteLength === 0) {
1284
+ throw runtimeProtocolError("Runtime Session file read did not advance");
1285
+ }
1286
+ offset = result.offset;
1287
+ yield chunk;
1288
+ }
1289
+ }
1290
+ finally {
1291
+ cleanup();
1292
+ }
1293
+ })());
1294
+ body.once("close", cleanup);
1295
+ ctx.body = body;
1296
+ }
1297
+ catch (error) {
1298
+ runtimeTargetHostError(ctx, error);
1299
+ }
1300
+ finally {
1301
+ if (!streamOwnsLease) {
1302
+ cleanup();
1303
+ }
1304
+ }
1305
+ };
1306
+ const runtimeSessionWorkspaceFileContent = async (ctx) => {
1307
+ const sessionId = ctx.params.id;
1308
+ const path = ctx.query.path;
1309
+ if (typeof path !== "string" ||
1310
+ path.length === 0 ||
1311
+ path.length > 4_096 ||
1312
+ path.includes("\0")) {
1313
+ ctx.status = 400;
1314
+ ctx.body = { error: "invalid_workspace_file_path" };
1315
+ return;
1316
+ }
1317
+ const local = ctx.params.selector === "local" ? localMachineSessions : undefined;
1318
+ const invocation = downloadInvocationAbortScope(ctx, shutdownSignal);
1319
+ const lease = local ? undefined : await acquireRuntimeLease(ctx, invocation.signal);
1320
+ if (!local && !lease) {
1321
+ invocation.dispose();
1322
+ return;
1323
+ }
1324
+ let streamOwnsLease = false;
1325
+ let cleanedUp = false;
1326
+ const cleanup = () => {
1327
+ if (cleanedUp)
1328
+ return;
1329
+ cleanedUp = true;
1330
+ lease?.release();
1331
+ invocation.dispose();
1332
+ };
1333
+ try {
1334
+ const { file } = local
1335
+ ? await local.getWorkspaceFile({ sessionId, path })
1336
+ : await lease.call("session.workspace.file.get", { sessionId, path }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
1337
+ if (file.path !== path) {
1338
+ throw runtimeProtocolError("Runtime Session workspace file identity changed");
1339
+ }
1340
+ const etag = `"workspace-file-${file.version}"`;
1341
+ ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
1342
+ ctx.set("ETag", etag);
1343
+ if (ctx.get("if-none-match").split(",").map((value) => value.trim()).includes(etag)) {
1344
+ ctx.status = 304;
1345
+ return;
1346
+ }
1347
+ ctx.set("Content-Security-Policy", "default-src 'none'; sandbox");
1348
+ ctx.set("Cross-Origin-Resource-Policy", "same-origin");
1349
+ ctx.set("X-Content-Type-Options", "nosniff");
1350
+ ctx.set("Accept-Ranges", "bytes");
1351
+ ctx.set("Content-Disposition", contentDisposition(file.filename));
1352
+ ctx.type = file.mediaType;
1353
+ if (file.byteLength === 0) {
1354
+ if (ctx.get("range")) {
1355
+ ctx.status = 416;
1356
+ ctx.set("Content-Range", "bytes */0");
1357
+ return;
1358
+ }
1359
+ ctx.status = 200;
1360
+ ctx.length = 0;
1361
+ if (ctx.method !== "HEAD")
1362
+ ctx.body = Buffer.alloc(0);
1363
+ return;
1364
+ }
1365
+ const requestedRange = ctx.get("range");
1366
+ const ifRange = ctx.get("if-range");
1367
+ const range = ifRange && ifRange !== etag
1368
+ ? undefined
1369
+ : parseSingleByteRange(requestedRange, file.byteLength);
1370
+ if (range === "unsatisfiable") {
1371
+ ctx.status = 416;
1372
+ ctx.set("Content-Range", `bytes */${file.byteLength}`);
1373
+ return;
1374
+ }
1375
+ const start = range?.start ?? 0;
1376
+ const end = range?.end ?? file.byteLength - 1;
1377
+ if (range) {
1378
+ ctx.status = 206;
1379
+ ctx.set("Content-Range", `bytes ${start}-${end}/${file.byteLength}`);
1380
+ }
1381
+ ctx.length = end - start + 1;
1382
+ if (ctx.method === "HEAD") {
1383
+ ctx.status = range ? 206 : 200;
1384
+ return;
1385
+ }
1386
+ streamOwnsLease = true;
1387
+ const body = Readable.from((async function* () {
1388
+ let offset = start;
1389
+ try {
1390
+ while (offset <= end) {
1391
+ const length = Math.min(SESSION_RESOURCE_TRANSFER_CHUNK_BYTES, end - offset + 1);
1392
+ const result = local
1393
+ ? await local.readWorkspaceFile({
1394
+ sessionId,
1395
+ path,
1396
+ version: file.version,
1397
+ offset,
1398
+ length,
1399
+ })
1400
+ : await lease.call("session.workspace.file.read", {
1401
+ sessionId,
1402
+ path,
1403
+ version: file.version,
1404
+ offset,
1405
+ length,
1406
+ }, { timeoutMs: REMOTE_RUNTIME_SESSION_TIMEOUT_MS, signal: invocation.signal });
1407
+ const chunk = Buffer.from(result.data, "base64");
1408
+ if (result.offset !== offset + chunk.byteLength || chunk.byteLength === 0) {
1409
+ throw runtimeProtocolError("Runtime Session workspace file read did not advance");
1410
+ }
1411
+ offset = result.offset;
1412
+ yield chunk;
1413
+ }
1414
+ }
1415
+ finally {
1416
+ cleanup();
1417
+ }
1418
+ })());
1419
+ body.once("close", cleanup);
1420
+ ctx.body = body;
1421
+ }
1422
+ catch (error) {
1423
+ runtimeTargetHostError(ctx, error);
1424
+ }
1425
+ finally {
1426
+ if (!streamOwnsLease)
1427
+ cleanup();
1428
+ }
1429
+ };
1097
1430
  const runtimeSessionMessageEnqueue = async (ctx) => {
1098
1431
  const body = await readRuntimeBody(ctx);
1099
1432
  if (!body)
@@ -1714,6 +2047,8 @@ export function createControlRouter(opts) {
1714
2047
  router.get("/api/runtimes/:selector/sessions/launch-options", publicRuntimeRead(runtimeSessionLaunchOptions));
1715
2048
  router.post("/api/runtimes/:selector/sessions", publicRuntimeMutation(runtimeSessionCreate));
1716
2049
  router.post("/api/runtimes/:selector/sessions/:id/fork", publicRuntimeMutation(runtimeSessionFork));
2050
+ router.get("/api/runtimes/:selector/sessions/:id/execution", publicRuntimeRead(runtimeSessionExecutionSettings));
2051
+ router.put("/api/runtimes/:selector/sessions/:id/execution", publicRuntimeMutation(runtimeSessionExecutionSettingsUpdate));
1717
2052
  router.get("/api/runtimes/:selector/sessions/:id/snapshot", publicRuntimeRead(runtimeSessionSnapshot));
1718
2053
  router.get("/api/runtimes/:selector/sessions/:id/snapshot-page", publicRuntimeRead(runtimeSessionSnapshotPage));
1719
2054
  router.get("/api/runtimes/:selector/sessions/:id/stream", publicRuntimeRead(runtimeSessionStream));
@@ -1723,6 +2058,11 @@ export function createControlRouter(opts) {
1723
2058
  router.post("/api/runtimes/:selector/sessions/:id/resources", publicRuntimeMutation(runtimeSessionResourceUpload));
1724
2059
  router.get("/api/runtimes/:selector/sessions/:id/resources/:resourceId", publicRuntimeRead(runtimeSessionResourceMetadata));
1725
2060
  router.get("/api/runtimes/:selector/sessions/:id/resources/:resourceId/content", publicRuntimeRead(runtimeSessionResourceContent));
2061
+ router.head("/api/runtimes/:selector/sessions/:id/resources/:resourceId/content", publicRuntimeRead(runtimeSessionResourceContent));
2062
+ router.get("/api/runtimes/:selector/sessions/:id/items/:itemId/files/:partIndex/content", publicRuntimeRead(runtimeSessionItemFileContent));
2063
+ router.head("/api/runtimes/:selector/sessions/:id/items/:itemId/files/:partIndex/content", publicRuntimeRead(runtimeSessionItemFileContent));
2064
+ router.get("/api/runtimes/:selector/sessions/:id/workspace/files/content", publicRuntimeRead(runtimeSessionWorkspaceFileContent));
2065
+ router.head("/api/runtimes/:selector/sessions/:id/workspace/files/content", publicRuntimeRead(runtimeSessionWorkspaceFileContent));
1726
2066
  router.delete("/api/runtimes/:selector/sessions/:id/resources/:resourceId", publicRuntimeMutation(runtimeSessionResourceDelete));
1727
2067
  router.post("/api/runtimes/:selector/sessions/:id/messages/queue", publicRuntimeMutation(runtimeSessionMessageEnqueue));
1728
2068
  router.post("/api/runtimes/:selector/sessions/:id/terminal/start", publicRuntimeMutation(runtimeSessionTerminalStart));
@@ -2711,6 +3051,14 @@ export function createControlRouter(opts) {
2711
3051
  router.get("/api/agents", async (ctx) => {
2712
3052
  ctx.body = { agents: await deps.listAgents() };
2713
3053
  });
3054
+ router.get("/api/agents/runtime-options", async (ctx) => {
3055
+ if (!deps.listAgentRuntimeOptions)
3056
+ return notFound(ctx, "local runtime discovery is unavailable");
3057
+ ctx.set("Cache-Control", "no-store");
3058
+ ctx.body = {
3059
+ runtimes: await deps.listAgentRuntimeOptions({ refresh: asString(ctx.query.refresh) === "1" }),
3060
+ };
3061
+ });
2714
3062
  router.get("/api/agents/:id", async (ctx) => {
2715
3063
  const spec = await deps.getAgent(ctx.params.id);
2716
3064
  if (!spec)
@@ -2723,6 +3071,11 @@ export function createControlRouter(opts) {
2723
3071
  if (!id)
2724
3072
  return bad(ctx, "missing agent id");
2725
3073
  try {
3074
+ if (await deps.getAgent(id)) {
3075
+ ctx.status = 409;
3076
+ ctx.body = { error: "agent id already exists" };
3077
+ return;
3078
+ }
2726
3079
  deps.writeAgent(id, body);
2727
3080
  }
2728
3081
  catch (error) {
@@ -2730,6 +3083,19 @@ export function createControlRouter(opts) {
2730
3083
  }
2731
3084
  ctx.body = { ok: true };
2732
3085
  });
3086
+ router.put("/api/agents/:id", async (ctx) => {
3087
+ const id = ctx.params.id;
3088
+ const body = await readJson(ctx);
3089
+ if (!await deps.getAgent(id))
3090
+ return notFound(ctx, "agent not found");
3091
+ try {
3092
+ deps.writeAgent(id, { ...body, id });
3093
+ }
3094
+ catch (error) {
3095
+ return bad(ctx, error instanceof Error ? error.message : String(error));
3096
+ }
3097
+ ctx.body = { ok: true };
3098
+ });
2733
3099
  router.delete("/api/agents/:id", (ctx) => {
2734
3100
  ctx.body = { ok: deps.removeAgent(ctx.params.id) };
2735
3101
  });
@@ -2769,6 +3135,64 @@ export function createControlRouter(opts) {
2769
3135
  return bad(ctx, error instanceof Error ? error.message : String(error));
2770
3136
  }
2771
3137
  });
3138
+ router.post("/api/skills/local-scan", async (ctx) => {
3139
+ if (!deps.scanLocalSkills)
3140
+ return notFound(ctx, "local Skill discovery is unavailable");
3141
+ const body = await readJson(ctx);
3142
+ const runtime = parseProviderCliId(body.runtime);
3143
+ if (!runtime)
3144
+ return bad(ctx, "runtime must be codex, traex, or claude");
3145
+ try {
3146
+ ctx.body = { candidates: await deps.scanLocalSkills(runtime) };
3147
+ }
3148
+ catch (error) {
3149
+ return bad(ctx, error instanceof Error ? error.message : String(error));
3150
+ }
3151
+ });
3152
+ router.post("/api/skills/local-import", async (ctx) => {
3153
+ if (!deps.importLocalSkills)
3154
+ return notFound(ctx, "local Skill import is unavailable");
3155
+ const body = await readJson(ctx);
3156
+ const runtime = parseProviderCliId(body.runtime);
3157
+ const rawKeys = Array.isArray(body.keys) ? body.keys : [];
3158
+ const keys = rawKeys.length > 0
3159
+ ? rawKeys.filter((value) => typeof value === "string" && value.length > 0)
3160
+ : [];
3161
+ if (!runtime)
3162
+ return bad(ctx, "runtime must be codex, traex, or claude");
3163
+ if (keys.length === 0 || keys.length !== rawKeys.length || keys.length > 100) {
3164
+ return bad(ctx, "keys must contain 1-100 non-empty candidate keys");
3165
+ }
3166
+ try {
3167
+ ctx.body = { results: await deps.importLocalSkills(runtime, keys) };
3168
+ }
3169
+ catch (error) {
3170
+ return bad(ctx, error instanceof Error ? error.message : String(error));
3171
+ }
3172
+ });
3173
+ router.post("/api/skills/import-archive", async (ctx) => {
3174
+ if (!deps.importSkillArchive)
3175
+ return notFound(ctx, "Skill archive import is unavailable");
3176
+ let body;
3177
+ try {
3178
+ body = await readJson(ctx, 29 * 1024 * 1024);
3179
+ }
3180
+ catch (error) {
3181
+ return bad(ctx, error instanceof Error ? error.message : String(error));
3182
+ }
3183
+ const filename = asString(body.filename);
3184
+ const contentBase64 = asString(body.contentBase64);
3185
+ if (!filename || !contentBase64)
3186
+ return bad(ctx, "filename and contentBase64 are required");
3187
+ if (contentBase64.length > 28 * 1024 * 1024)
3188
+ return bad(ctx, "archive payload is too large");
3189
+ try {
3190
+ ctx.body = { results: await deps.importSkillArchive(filename, contentBase64) };
3191
+ }
3192
+ catch (error) {
3193
+ return bad(ctx, error instanceof Error ? error.message : String(error));
3194
+ }
3195
+ });
2772
3196
  router.delete("/api/skills/:name", async (ctx) => {
2773
3197
  try {
2774
3198
  ctx.body = { ok: await deps.removeSkill(ctx.params.name) };
@@ -3107,12 +3531,16 @@ export function createControlRouter(opts) {
3107
3531
  const body = await readJson(ctx);
3108
3532
  const agent = asString(body.agent);
3109
3533
  const provider = asString(body.provider);
3534
+ const permissionPreset = parseSessionPermissionPreset(body.permissionPreset);
3110
3535
  if (body.config != null) {
3111
3536
  return bad(ctx, "inline Agent configs are no longer supported; save an Agent first");
3112
3537
  }
3113
3538
  if (Boolean(agent) === Boolean(provider)) {
3114
3539
  return bad(ctx, "provide exactly one Agent or Provider");
3115
3540
  }
3541
+ if (body.permissionPreset !== undefined && !permissionPreset) {
3542
+ return bad(ctx, "permissionPreset must be default, read-only, workspace-write, or full-access");
3543
+ }
3116
3544
  try {
3117
3545
  ctx.body = await localMachineSessions.create({
3118
3546
  ...(agent ? { agent } : { provider: provider }),
@@ -3120,6 +3548,7 @@ export function createControlRouter(opts) {
3120
3548
  ...(asString(body.reasoningEffort)
3121
3549
  ? { reasoningEffort: asString(body.reasoningEffort) }
3122
3550
  : {}),
3551
+ ...(permissionPreset ? { permissionPreset } : {}),
3123
3552
  ...(asString(body.title) ? { title: asString(body.title) } : {}),
3124
3553
  ...(asString(body.projectId) ? { projectId: asString(body.projectId) } : {}),
3125
3554
  });
@@ -3140,7 +3569,20 @@ export function createControlRouter(opts) {
3140
3569
  }
3141
3570
  catch (error) {
3142
3571
  ctx.status = 503;
3143
- ctx.body = { error: error instanceof Error ? error.message : String(error) };
3572
+ const runtimeFailure = error instanceof MachineSessionServiceFailure
3573
+ ? error.runtimeFailure
3574
+ : undefined;
3575
+ const message = runtimeFailure?.message
3576
+ ?? (error instanceof MachineSessionServiceFailure ? error.detail : undefined)
3577
+ ?? (error instanceof Error ? error.message : String(error));
3578
+ ctx.body = {
3579
+ error: message,
3580
+ code: runtimeFailure?.code
3581
+ ?? (error instanceof MachineSessionServiceFailure ? error.code : "runtime_error"),
3582
+ outcome: error instanceof MachineSessionServiceFailure && error.code === "outcome_unknown"
3583
+ ? "unknown"
3584
+ : "not_started",
3585
+ };
3144
3586
  }
3145
3587
  return;
3146
3588
  }
@@ -3159,26 +3601,31 @@ export function createControlRouter(opts) {
3159
3601
  execution: structuredClone(meta.execution),
3160
3602
  });
3161
3603
  if (!live) {
3604
+ const failure = runnerManager.lastLiveSessionFailure?.(id);
3162
3605
  ctx.status = 503;
3163
3606
  ctx.body = {
3164
- error: `live session unavailable (${meta.execution.provider})`,
3165
- ...(runnerManager.lastLiveSessionError?.(id)
3166
- ? { detail: runnerManager.lastLiveSessionError(id) }
3167
- : {}),
3607
+ error: failure?.message
3608
+ ?? runnerManager.lastLiveSessionError?.(id)
3609
+ ?? `live session unavailable (${meta.execution.provider})`,
3610
+ code: failure?.code ?? "live_unavailable",
3611
+ outcome: "not_started",
3168
3612
  };
3169
3613
  return;
3170
3614
  }
3171
- const outcome = await runnerManager.injectMessage(id, message);
3172
- if (outcome === "injected") {
3615
+ const result = await runnerManager.injectMessage(id, message);
3616
+ const outcome = result.outcome;
3617
+ if (outcome === "injected" || outcome === "steered") {
3173
3618
  ctx.body = { ok: true, injected: true };
3174
3619
  return;
3175
3620
  }
3176
3621
  ctx.status = 503;
3622
+ const failure = runnerManager.lastLiveSessionFailure?.(id);
3177
3623
  ctx.body = {
3178
- error: `live injection ${outcome}`,
3179
- ...(runnerManager.lastLiveSessionError?.(id)
3180
- ? { detail: runnerManager.lastLiveSessionError(id) }
3181
- : {}),
3624
+ error: failure?.message
3625
+ ?? runnerManager.lastLiveSessionError?.(id)
3626
+ ?? `live injection ${outcome}`,
3627
+ code: failure?.code ?? "live_inject_failed",
3628
+ outcome: outcome === "failed" ? "unknown" : "not_started",
3182
3629
  };
3183
3630
  });
3184
3631
  // Stop the session's active turn (the web Stop button). For a live native
@@ -3399,11 +3846,28 @@ export function synthesizeSessionTitle(message, limit = 60) {
3399
3846
  return collapsed;
3400
3847
  return `${collapsed.slice(0, limit - 1).trimEnd()}…`;
3401
3848
  }
3402
- async function readJson(ctx) {
3849
+ async function readJson(ctx, maxBytes) {
3403
3850
  const raw = await new Promise((resolve, reject) => {
3404
3851
  let data = "";
3405
- ctx.req.on("data", (chunk) => (data += chunk));
3406
- ctx.req.on("end", () => resolve(data));
3852
+ let bytes = 0;
3853
+ let exceeded = false;
3854
+ ctx.req.on("data", (chunk) => {
3855
+ if (exceeded)
3856
+ return;
3857
+ bytes += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.byteLength;
3858
+ if (maxBytes !== undefined && bytes > maxBytes) {
3859
+ exceeded = true;
3860
+ data = "";
3861
+ return;
3862
+ }
3863
+ data += chunk;
3864
+ });
3865
+ ctx.req.on("end", () => {
3866
+ if (exceeded)
3867
+ reject(new Error("request body is too large"));
3868
+ else
3869
+ resolve(data);
3870
+ });
3407
3871
  ctx.req.on("error", reject);
3408
3872
  });
3409
3873
  if (!raw.trim())
@@ -3424,6 +3888,14 @@ function parseProviderCliId(value) {
3424
3888
  ? value
3425
3889
  : undefined;
3426
3890
  }
3891
+ function parseSessionPermissionPreset(value) {
3892
+ return value === "default" ||
3893
+ value === "read-only" ||
3894
+ value === "workspace-write" ||
3895
+ value === "full-access"
3896
+ ? value
3897
+ : undefined;
3898
+ }
3427
3899
  function parseProviderCliOperation(value) {
3428
3900
  return value === "install" || value === "update" ? value : undefined;
3429
3901
  }
@@ -3439,6 +3911,14 @@ function optionalRuntimeDevice(body) {
3439
3911
  return body.device === undefined ? {} : { device: body.device };
3440
3912
  }
3441
3913
  function remoteRuntimeRpcTimeoutMs(method, params) {
3914
+ // Native startup/delivery owns phase-specific deadlines and returns their
3915
+ // concrete failures. A BFF deadline here would race those phases and replace
3916
+ // the real error with an ambiguous generic RPC timeout. The setup queue also
3917
+ // awaits Terminal startup before acknowledging the request.
3918
+ if (method === "session.message.send" ||
3919
+ method === "session.message.enqueue" ||
3920
+ method === "session.terminal.start")
3921
+ return null;
3442
3922
  if (method === "session.emulator.attach")
3443
3923
  return REMOTE_RUNTIME_EMULATOR_ATTACH_TIMEOUT_MS;
3444
3924
  if (method === "session.emulator.type") {
@@ -3542,6 +4022,36 @@ function pluginInstallInvocationAbortScope(ctx, shutdownSignal) {
3542
4022
  function browserArtifactInvocationAbortScope(ctx, shutdownSignal) {
3543
4023
  return managementInvocationAbortScope(ctx, shutdownSignal, BROWSER_ARTIFACT_OPERATION_TIMEOUT_MS, "Browser artifact operation");
3544
4024
  }
4025
+ function downloadInvocationAbortScope(ctx, shutdownSignal) {
4026
+ const controller = new AbortController();
4027
+ const abort = (reason) => {
4028
+ if (!controller.signal.aborted)
4029
+ controller.abort(reason);
4030
+ };
4031
+ const onRequestAborted = () => abort(namedError("download request aborted", "AbortError"));
4032
+ const onResponseClose = () => {
4033
+ if (!ctx.res.writableEnded) {
4034
+ abort(namedError("download client disconnected", "AbortError"));
4035
+ }
4036
+ };
4037
+ const onShutdown = () => abort(shutdownSignal?.reason ?? namedError("daemon is shutting down", "AbortError"));
4038
+ ctx.req.once("aborted", onRequestAborted);
4039
+ ctx.res.once("close", onResponseClose);
4040
+ if (shutdownSignal?.aborted)
4041
+ onShutdown();
4042
+ else
4043
+ shutdownSignal?.addEventListener("abort", onShutdown, { once: true });
4044
+ if (ctx.req.aborted)
4045
+ onRequestAborted();
4046
+ return {
4047
+ signal: controller.signal,
4048
+ dispose() {
4049
+ ctx.req.removeListener("aborted", onRequestAborted);
4050
+ ctx.res.removeListener("close", onResponseClose);
4051
+ shutdownSignal?.removeEventListener("abort", onShutdown);
4052
+ },
4053
+ };
4054
+ }
3545
4055
  function managementInvocationAbortScope(ctx, shutdownSignal, timeoutMs, label) {
3546
4056
  const controller = new AbortController();
3547
4057
  const abort = (reason) => {
@@ -3762,8 +4272,14 @@ function runtimeTargetHostError(ctx, error, forcedOutcome) {
3762
4272
  const status = runtimeTargetHttpStatus(code);
3763
4273
  ctx.status = status;
3764
4274
  const outcome = forcedOutcome ?? runtimeTargetErrorOutcome(error);
4275
+ const applicationMessage = error instanceof Error && error.name === "DirectRuntimeRpcError"
4276
+ ? error.message.replace(/^Remote Runtime RPC failed: [^:]+: /, "")
4277
+ : undefined;
3765
4278
  ctx.body = {
3766
- error: status === 500 ? "internal_error" : code,
4279
+ error: applicationMessage ?? (status === 500 ? "internal_error" : code),
4280
+ ...(applicationMessage
4281
+ ? { code: status === 500 ? "internal_error" : code }
4282
+ : {}),
3767
4283
  ...(outcome === undefined ? {} : { outcome }),
3768
4284
  };
3769
4285
  }
@@ -3851,6 +4367,83 @@ function publicRuntimeStreamError(error) {
3851
4367
  }
3852
4368
  class RequestBodyTooLargeError extends Error {
3853
4369
  }
4370
+ function isMediaType(value) {
4371
+ return value.length <= 255 && /^[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]+$/.test(value);
4372
+ }
4373
+ async function forwardResourceUploadBody(ctx, uploadId, resumeOffset, expectedBytes, writeChunk) {
4374
+ let received = 0;
4375
+ let remoteOffset = resumeOffset;
4376
+ let carry = Buffer.alloc(0);
4377
+ for await (const raw of ctx.req) {
4378
+ const incoming = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
4379
+ if (received + incoming.byteLength > expectedBytes) {
4380
+ throw runtimeProtocolError("Resource upload exceeds Content-Length");
4381
+ }
4382
+ const skip = Math.min(incoming.byteLength, Math.max(0, resumeOffset - received));
4383
+ received += incoming.byteLength;
4384
+ let cursor = skip;
4385
+ while (cursor < incoming.byteLength) {
4386
+ const needed = SESSION_RESOURCE_TRANSFER_CHUNK_BYTES - carry.byteLength;
4387
+ const take = Math.min(needed, incoming.byteLength - cursor);
4388
+ carry = carry.byteLength === 0
4389
+ ? incoming.subarray(cursor, cursor + take)
4390
+ : Buffer.concat([carry, incoming.subarray(cursor, cursor + take)]);
4391
+ cursor += take;
4392
+ if (carry.byteLength < SESSION_RESOURCE_TRANSFER_CHUNK_BYTES)
4393
+ continue;
4394
+ const written = await writeChunk(uploadId, remoteOffset, carry.toString("base64"));
4395
+ if (written.offset !== remoteOffset + carry.byteLength) {
4396
+ throw runtimeProtocolError("Runtime Session resource upload did not advance");
4397
+ }
4398
+ remoteOffset = written.offset;
4399
+ carry = Buffer.alloc(0);
4400
+ }
4401
+ }
4402
+ if (received !== expectedBytes) {
4403
+ throw runtimeProtocolError("Resource upload ended before Content-Length");
4404
+ }
4405
+ if (carry.byteLength > 0) {
4406
+ const written = await writeChunk(uploadId, remoteOffset, carry.toString("base64"));
4407
+ if (written.offset !== remoteOffset + carry.byteLength) {
4408
+ throw runtimeProtocolError("Runtime Session resource upload did not advance");
4409
+ }
4410
+ remoteOffset = written.offset;
4411
+ }
4412
+ if (remoteOffset !== expectedBytes) {
4413
+ throw runtimeProtocolError("Runtime Session resource upload length changed");
4414
+ }
4415
+ }
4416
+ function parseSingleByteRange(header, byteLength) {
4417
+ if (!header)
4418
+ return undefined;
4419
+ const match = /^bytes=(\d*)-(\d*)$/.exec(header.trim());
4420
+ if (!match || byteLength <= 0)
4421
+ return "unsatisfiable";
4422
+ const [, startText, endText] = match;
4423
+ if (!startText && !endText)
4424
+ return "unsatisfiable";
4425
+ if (!startText) {
4426
+ const suffix = Number(endText);
4427
+ if (!Number.isSafeInteger(suffix) || suffix <= 0)
4428
+ return "unsatisfiable";
4429
+ return { start: Math.max(0, byteLength - suffix), end: byteLength - 1 };
4430
+ }
4431
+ const start = Number(startText);
4432
+ const requestedEnd = endText ? Number(endText) : byteLength - 1;
4433
+ if (!Number.isSafeInteger(start) ||
4434
+ !Number.isSafeInteger(requestedEnd) ||
4435
+ start < 0 ||
4436
+ requestedEnd < start ||
4437
+ start >= byteLength) {
4438
+ return "unsatisfiable";
4439
+ }
4440
+ return { start, end: Math.min(requestedEnd, byteLength - 1) };
4441
+ }
4442
+ function contentDisposition(filename) {
4443
+ if (!filename)
4444
+ return "inline";
4445
+ return `inline; filename*=UTF-8''${encodeURIComponent(filename)}`;
4446
+ }
3854
4447
  async function readBoundedBinary(ctx, maxBytes) {
3855
4448
  const declaredLength = Number(ctx.get("content-length"));
3856
4449
  if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {