sliccy 6.87.3 → 6.88.0

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 (326) hide show
  1. package/README.md +1 -1
  2. package/dist/node-server/hostfs.d.ts +58 -0
  3. package/dist/node-server/hostfs.js +257 -0
  4. package/dist/node-server/index.js +10 -0
  5. package/dist/node-server/runtime-flags.d.ts +22 -0
  6. package/dist/node-server/runtime-flags.js +78 -2
  7. package/dist/ui/.vite/manifest.json +503 -422
  8. package/dist/ui/assets/CLAUDE-4LHXSyPA.js +1 -0
  9. package/dist/ui/assets/CLAUDE-Bio4HPGK.js +1 -0
  10. package/dist/ui/assets/MEMORY-6FXnIBfJ.js +135 -0
  11. package/dist/ui/assets/SKILL-BKUxKc7f.js +296 -0
  12. package/dist/ui/assets/SKILL-BKyxMoME.js +1 -0
  13. package/dist/ui/assets/SKILL-BcELX5TL.js +1 -0
  14. package/dist/ui/assets/SKILL-Bd5ykLEh.js +1 -0
  15. package/dist/ui/assets/SKILL-Bt-RhG0L.js +1 -0
  16. package/dist/ui/assets/SKILL-CED8RXQP.js +69 -0
  17. package/dist/ui/assets/SKILL-CNdAIhbb.js +1 -0
  18. package/dist/ui/assets/SKILL-CcMg6eqt.js +1 -0
  19. package/dist/ui/assets/SKILL-Ch-cOl61.js +1 -0
  20. package/dist/ui/assets/SKILL-CkfptFag.js +132 -0
  21. package/dist/ui/assets/SKILL-Ckg2XbSL.js +114 -0
  22. package/dist/ui/assets/SKILL-D40-t9w0.js +57 -0
  23. package/dist/ui/assets/SKILL-DFKKFkzD.js +96 -0
  24. package/dist/ui/assets/SKILL-DJ815vTN.js +62 -0
  25. package/dist/ui/assets/SKILL-DLXzwsY4.js +1 -0
  26. package/dist/ui/assets/SKILL-DXIigmDy.js +35 -0
  27. package/dist/ui/assets/SKILL-DfSluXpV.js +385 -0
  28. package/dist/ui/assets/SKILL-DhKtVqb-.js +1 -0
  29. package/dist/ui/assets/SKILL-FnBxPcDX.js +1 -0
  30. package/dist/ui/assets/SKILL-HEHb9hIB.js +1 -0
  31. package/dist/ui/assets/SKILL-i1NMDKwT.js +1 -0
  32. package/dist/ui/assets/SKILL-oOIS8LAm.js +1 -0
  33. package/dist/ui/assets/{account-store-Cy3TJKnu.js → account-store-BLu0_ipL.js} +2 -2
  34. package/dist/ui/assets/{account-store-DysucxMw.js → account-store-l8BmmoRx.js} +4 -4
  35. package/dist/ui/assets/adobe-Caluo3Vg.js +2 -0
  36. package/dist/ui/assets/adobe-Cj2iYsHq.js +1 -0
  37. package/dist/ui/assets/{angular-html-Cm4-xod0.js → angular-html-aPuBvESs.js} +1 -1
  38. package/dist/ui/assets/{angular-ts-Dopuir71.js → angular-ts-ocjSXnvf.js} +1 -1
  39. package/dist/ui/assets/anthropic-messages-CpSojOI8.js +39 -0
  40. package/dist/ui/assets/anthropic-messages-DbPJ2ji9.js +39 -0
  41. package/dist/ui/assets/api-endpoint-C00IT5T9.js +1 -0
  42. package/dist/ui/assets/api-endpoint-GRCyib6X.js +1 -0
  43. package/dist/ui/assets/{apply-layout-TIXzvNTN.js → apply-layout-lJ2Uyc3p.js} +1 -1
  44. package/dist/ui/assets/{apps-e--FORGt.js → apps-BRi5S2KV.js} +1 -1
  45. package/dist/ui/assets/{astro-E_b8esPp.js → astro-go1PgQEf.js} +1 -1
  46. package/dist/ui/assets/auto-mount-table-CdyPAwVL.js +1 -0
  47. package/dist/ui/assets/{azure-openai-C5josrBb.js → azure-openai-DtPDwGAY.js} +2 -2
  48. package/dist/ui/assets/azure-openai-responses-BcoOaRCx.js +1 -0
  49. package/dist/ui/assets/azure-openai-responses-DUMDrZ29.js +1 -0
  50. package/dist/ui/assets/{azure-openai-mDyNL8OK.js → azure-openai-xFuHu_hU.js} +2 -2
  51. package/dist/ui/assets/backend-hostfs-Com-zF5W.js +1 -0
  52. package/dist/ui/assets/backend-hostfs-bQQx-S0W.js +1 -0
  53. package/dist/ui/assets/bedrock-camp-BcJEC3Pg.js +1 -0
  54. package/dist/ui/assets/bedrock-camp-LeceEQbU.js +1 -0
  55. package/dist/ui/assets/bedrock-camp-compat-CYnC9BQI.js +1 -0
  56. package/dist/ui/assets/bedrock-camp-compat-CgBMwna8.js +1 -0
  57. package/dist/ui/assets/{blade-mj2TcBTp.js → blade-DPPr6MF0.js} +1 -1
  58. package/dist/ui/assets/catppuccin-frappe-C9Q5zVZY.js +1 -0
  59. package/dist/ui/assets/catppuccin-latte-CtsyrtPq.js +1 -0
  60. package/dist/ui/assets/catppuccin-macchiato-R8nAf1vR.js +1 -0
  61. package/dist/ui/assets/catppuccin-mocha-DjuaAJKi.js +1 -0
  62. package/dist/ui/assets/cerebras-BKhMaWSl.js +1 -0
  63. package/dist/ui/assets/cerebras-CCLa0xVH.js +1 -0
  64. package/dist/ui/assets/chime-CPc6qSh5.js +1 -0
  65. package/dist/ui/assets/claude-model-version-Csn7RPVg.js +1 -0
  66. package/dist/ui/assets/claude-model-version-DoVrYsKi.js +2 -0
  67. package/dist/ui/assets/{client-BTUV7dbh.js → client-DVC0x03n.js} +1 -1
  68. package/dist/ui/assets/{composer-speech-SNeD5SER.js → composer-speech-Cy4g3lh3.js} +1 -1
  69. package/dist/ui/assets/connect-llm-FevTa-aV.js +561 -0
  70. package/dist/ui/assets/{connect-surface-DqU2NC2c.js → connect-surface-T7iCJFeB.js} +1 -1
  71. package/dist/ui/assets/cpp-Ct9pQPqT.js +1 -0
  72. package/dist/ui/assets/{css-vJJohHMc.js → css-DlBQoFxe.js} +1 -1
  73. package/dist/ui/assets/discovery-preference-__0HPYJC.js +1 -0
  74. package/dist/ui/assets/dist-B4LJzMVB.js +1547 -0
  75. package/dist/ui/assets/{ensure-speech-assets-DvFwJX-M.js → ensure-speech-assets-CKwQ54O1.js} +1 -1
  76. package/dist/ui/assets/float-topology-DiK91BlA.js +1 -0
  77. package/dist/ui/assets/{follower-navigate-watcher-CNC7ybEv.js → follower-navigate-watcher-Dz-52eZY.js} +1 -1
  78. package/dist/ui/assets/fs-1btyYJVn.js +1 -0
  79. package/dist/ui/assets/fs-BYtJQhvh.js +2 -0
  80. package/dist/ui/assets/github-BHL_hKU_.js +2 -0
  81. package/dist/ui/assets/github-copilot-CZorsYUj.js +1 -0
  82. package/dist/ui/assets/github-copilot-DVmzgGYz.js +2 -0
  83. package/dist/ui/assets/github-fX2kuECo.js +1 -0
  84. package/dist/ui/assets/{github-install-CFJLPySf.js → github-install-DVzD1asQ.js} +1 -1
  85. package/dist/ui/assets/{github-zip-C7dhlRG8.js → github-zip-5ekKl7Z0.js} +1 -1
  86. package/dist/ui/assets/{go-BJwz_mda.js → go-rLFTqkRN.js} +1 -1
  87. package/dist/ui/assets/google-generative-ai-Dxo91M3n.js +1 -0
  88. package/dist/ui/assets/google-generative-ai-Rjh7hNBV.js +1 -0
  89. package/dist/ui/assets/{google-shared-BMJ_JErv.js → google-shared-CzJgTu-P.js} +3 -3
  90. package/dist/ui/assets/{google-shared-YqcyR4cm.js → google-shared-DQJPCU3d.js} +3 -3
  91. package/dist/ui/assets/google-vertex-61Jj0dk6.js +1 -0
  92. package/dist/ui/assets/google-vertex-DEwkNZJm.js +1 -0
  93. package/dist/ui/assets/{haml-DboNpPfQ.js → haml-Bqgi1Cau.js} +1 -1
  94. package/dist/ui/assets/{handlebars-Bv_jLwHk.js → handlebars-JgcNzdBj.js} +1 -1
  95. package/dist/ui/assets/{hear-D33CHppO.js → hear-BqNAK8-P.js} +1 -1
  96. package/dist/ui/assets/{horizon-bright-Br1oVSNq.js → horizon-bright-DSNQnXHK.js} +1 -1
  97. package/dist/ui/assets/{host-command-G_JIdBPR.js → host-command-C3cIKdbE.js} +1 -1
  98. package/dist/ui/assets/{html-BLkwJ0Yd.js → html-BsvMqTlf.js} +1 -1
  99. package/dist/ui/assets/{html-derivative-B3p5VrMH.js → html-derivative-D9FvRNj4.js} +1 -1
  100. package/dist/ui/assets/icon-example-LUkiEXyS.js +111 -0
  101. package/dist/ui/assets/{jinja-BeFOxtqS.js → jinja-CixBDh_U.js} +1 -1
  102. package/dist/ui/assets/{js-realm-worker-BcijiBMH.js → js-realm-worker-iDrigwwJ.js} +1 -1
  103. package/dist/ui/assets/jsh-runtime-extensions-DpVq60Gw.js +1 -0
  104. package/dist/ui/assets/julia-B5NbrcUp.js +1 -0
  105. package/dist/ui/assets/kanagawa-dragon-Bozd7klA.js +1 -0
  106. package/dist/ui/assets/kanagawa-lotus-BmuOG9ZW.js +1 -0
  107. package/dist/ui/assets/kanagawa-wave-BML5mF2J.js +1 -0
  108. package/dist/ui/assets/{kernel-worker-BiaHa-Mz.js → kernel-worker-BdKtpNzV.js} +613 -4394
  109. package/dist/ui/assets/legacy-api-aliases-BnRqMAef.js +1 -0
  110. package/dist/ui/assets/legacy-api-aliases-oJPAvhVV.js +1 -0
  111. package/dist/ui/assets/{lick-urls-AW0BSaf4.js → lick-urls-DcXOqXGm.js} +1 -1
  112. package/dist/ui/assets/{lick-ws-bridge-DiPcVRfN.js → lick-ws-bridge-CnkYvHKI.js} +1 -1
  113. package/dist/ui/assets/{lick-ws-bridge-CWRES2H2.js → lick-ws-bridge-DOJW_mZp.js} +1 -1
  114. package/dist/ui/assets/{local-llm-CQE3URQQ.js → local-llm-BoLsVU6D.js} +1 -1
  115. package/dist/ui/assets/{local-llm-DVCKFUl_.js → local-llm-aZ3BO7wK.js} +1 -1
  116. package/dist/ui/assets/{main-DQS8QHXU.js → main-CSh1z5qo.js} +3 -3
  117. package/dist/ui/assets/{marko-C3klgjEa.js → marko-DYWPPmCl.js} +1 -1
  118. package/dist/ui/assets/mdc-Cno1UUUH.js +1 -0
  119. package/dist/ui/assets/mistral-conversations-BtaPxrK1.js +4 -0
  120. package/dist/ui/assets/mistral-conversations-CDLVw-9i.js +4 -0
  121. package/dist/ui/assets/{transform-messages-DEFauvrq.js → models-4WTk3EBD.js} +1 -1
  122. package/dist/ui/assets/{transform-messages-N_eMsP2M.js → models-BSkXF4T6.js} +1 -1
  123. package/dist/ui/assets/monokai-B_bV9PQ9.js +1 -0
  124. package/dist/ui/assets/mount-BCaA8NF3.js +1 -0
  125. package/dist/ui/assets/mount-ICXjya6b.js +2 -0
  126. package/dist/ui/assets/{mount-bridge-client-4blXuJO1.js → mount-bridge-client-DZE6sHdr.js} +1 -1
  127. package/dist/ui/assets/mount-recovery-CtadSXiq.js +2 -0
  128. package/dist/ui/assets/new-session-CCcPVim0.js +2 -0
  129. package/dist/ui/assets/oauth-bootstrap-CJ7pyk8I.js +2 -0
  130. package/dist/ui/assets/oauth-service-CTntqv0R.js +1 -0
  131. package/dist/ui/assets/oauth-service-Uk8UIb05.js +1 -0
  132. package/dist/ui/assets/openai-codex-C7WXAsyq.js +1 -0
  133. package/dist/ui/assets/openai-codex-DJHh6O0O.js +1 -0
  134. package/dist/ui/assets/openai-codex-responses-CPOJeFUY.js +7 -0
  135. package/dist/ui/assets/openai-codex-responses-jQR19NyX.js +7 -0
  136. package/dist/ui/assets/openai-completions-DGOcowq8.js +5 -0
  137. package/dist/ui/assets/openai-completions-DGZFJo5D.js +5 -0
  138. package/dist/ui/assets/openai-responses-CDTdSIhv.js +1 -0
  139. package/dist/ui/assets/openai-responses-bnETPgx9.js +1 -0
  140. package/dist/ui/assets/{openai-responses-shared-DxcsuzHF.js → openai-responses-shared-ChgvRZ74.js} +5 -5
  141. package/dist/ui/assets/{openai-responses-shared-DhnqxYC9.js → openai-responses-shared-DqJbHrek.js} +5 -5
  142. package/dist/ui/assets/openrouter-CIXJV3ar.js +1 -0
  143. package/dist/ui/assets/openrouter-CbIgawBs.js +1 -0
  144. package/dist/ui/assets/{openrouter-oauth-DvOb1QMV.js → openrouter-oauth-CfwEmxEv.js} +1 -1
  145. package/dist/ui/assets/{openrouter-oauth-Dy4Qqt06.js → openrouter-oauth-ZehYXklO.js} +1 -1
  146. package/dist/ui/assets/{page-approval-service-Bbc3_KdK.js → page-approval-service-BsXoPdFJ.js} +1 -1
  147. package/dist/ui/assets/panel-rpc-handlers-Bg0_q2j9.js +2 -0
  148. package/dist/ui/assets/{panelize-shell-BRldzPxv.js → panelize-shell-DG3fFAS4.js} +1 -1
  149. package/dist/ui/assets/patterns-ChiGbijt.js +171 -0
  150. package/dist/ui/assets/php-m5Ug_San.js +1 -0
  151. package/dist/ui/assets/port-bridge-client-BhmNRlRv.js +2 -0
  152. package/dist/ui/assets/port-bridge-client-Bz2N1tvn.js +1 -0
  153. package/dist/ui/assets/{provider-D2RXncrR.js → provider-1dH_J0Ky.js} +2 -2
  154. package/dist/ui/assets/{provider-Bk24TjUg.js → provider-CCer_iKN.js} +1 -1
  155. package/dist/ui/assets/{provider-settings-B5B0NtAl.js → provider-settings-DKXi1uSi.js} +1 -1
  156. package/dist/ui/assets/provider-settings-DZxqnVAO.js +2 -0
  157. package/dist/ui/assets/{provider-store-access-Cl5aZRx7.js → provider-store-access-BthQZUzO.js} +2 -2
  158. package/dist/ui/assets/provider-store-access-NzVfMvPw.js +1 -0
  159. package/dist/ui/assets/providers-D8GPTe3s.js +2 -0
  160. package/dist/ui/assets/providers-DdfpdKUf.js +1 -0
  161. package/dist/ui/assets/proxied-fetch-BGeNrvQ4.js +2 -0
  162. package/dist/ui/assets/proxied-fetch-Co-pb0x0.js +1 -0
  163. package/dist/ui/assets/{pug-BPcX_o8k.js → pug-B4bk2kWf.js} +1 -1
  164. package/dist/ui/assets/quick-llm-DscHMm6M.js +1 -0
  165. package/dist/ui/assets/r-C5FwQflr.js +1 -0
  166. package/dist/ui/assets/{recovery-screen-MHXsY2RD.js → recovery-screen-CmxX9RlA.js} +1 -1
  167. package/dist/ui/assets/red-DX1BQOs8.js +1 -0
  168. package/dist/ui/assets/{redirect-uri-B1SxiY-b.js → redirect-uri-CSXbRzUU.js} +1 -1
  169. package/dist/ui/assets/rose-pine-aMsaMD1D.js +1 -0
  170. package/dist/ui/assets/rose-pine-dawn-8PwUyIlP.js +1 -0
  171. package/dist/ui/assets/rose-pine-moon-DO-qXg-I.js +1 -0
  172. package/dist/ui/assets/{scss-0nEf0IT-.js → scss-BaZL6t2Y.js} +1 -1
  173. package/dist/ui/assets/secret-env-CjwX7z7b.js +1 -0
  174. package/dist/ui/assets/secret-topology-0AWfFTh5.js +1 -0
  175. package/dist/ui/assets/{secrets-bridge-client-cWDAnFqs.js → secrets-bridge-client-DCQ44RyR.js} +1 -1
  176. package/dist/ui/assets/{session-freezer-CnFBCb6j.js → session-freezer-cQJKe1j_.js} +3 -3
  177. package/dist/ui/assets/{setup-feature-flags-remote-Dlcwmn-_.js → setup-feature-flags-remote-BxfewGbb.js} +1 -1
  178. package/dist/ui/assets/setup-standalone-prelude-Bv9X4-V2.js +2 -0
  179. package/dist/ui/assets/setup-sudo-B3tWN6O2.js +2 -0
  180. package/dist/ui/assets/{skills-C90t15zW.js → skills-C8Ojzeu6.js} +1 -1
  181. package/dist/ui/assets/{slicc-diff-DsGtkf0J.js → slicc-diff-DhGIKKqP.js} +1 -1
  182. package/dist/ui/assets/slicc-version-CaunkoU5.js +1 -0
  183. package/dist/ui/assets/smithy-Dgaz7aur.js +1 -0
  184. package/dist/ui/assets/solarized-dark-UdsmMDCL.js +1 -0
  185. package/dist/ui/assets/solarized-light-C1IUL_tW.js +1 -0
  186. package/dist/ui/assets/{speak-BDT9rGzg.js → speak-BSK3Souh.js} +1 -1
  187. package/dist/ui/assets/{sql-69VAgb2g.js → sql-DvarVTMJ.js} +1 -1
  188. package/dist/ui/assets/{src-DsDPrXOS.js → src-DXdqCrdV.js} +2 -2
  189. package/dist/ui/assets/{store-Cvg04_Rz.js → store-BPyCiwPs.js} +1 -1
  190. package/dist/ui/assets/{store-BmhLnay6.js → store-CGgqI527.js} +1 -1
  191. package/dist/ui/assets/style-guide-Bgzsk7bf.js +821 -0
  192. package/dist/ui/assets/{sudo-DYhM4jWf.js → sudo-1gsx4XWx.js} +2 -2
  193. package/dist/ui/assets/{svelte-B4PVQJ-7.js → svelte-D4FIy7cP.js} +1 -1
  194. package/dist/ui/assets/swift-CyEgAFGc.js +1 -0
  195. package/dist/ui/assets/temperature-support-B4x2xaWY.js +1 -0
  196. package/dist/ui/assets/temperature-support-Cpml9LfI.js +1 -0
  197. package/dist/ui/assets/transform-messages-DZg9zDcV.js +1 -0
  198. package/dist/ui/assets/transform-messages-XkZ1QnTb.js +1 -0
  199. package/dist/ui/assets/transformers-env-DPjdc2EQ.js +1 -0
  200. package/dist/ui/assets/tray-leader-CP11I609.js +1 -0
  201. package/dist/ui/assets/{tray-leave-runtime-BGfdX5KF.js → tray-leave-runtime-CN7V9V7O.js} +1 -1
  202. package/dist/ui/assets/{tray-runtime-config-B1LF8Kd4.js → tray-runtime-config-CVoPQrT2.js} +1 -1
  203. package/dist/ui/assets/tray-runtime-config-D7cmCcHJ.js +1 -0
  204. package/dist/ui/assets/ts-tags-C4Ifwy6r.js +1 -0
  205. package/dist/ui/assets/{upgrade-detection-Co2MZvYS.js → upgrade-detection-DHKcwE9c.js} +1 -1
  206. package/dist/ui/assets/vesper-DdrHHSXu.js +1 -0
  207. package/dist/ui/assets/{voice-reply-CnP5wEO_.js → voice-reply-BNX-jA0G.js} +1 -1
  208. package/dist/ui/assets/{vue-Dg0Kv3qp.js → vue-Djeyp8pE.js} +1 -1
  209. package/dist/ui/assets/{vue-vine-DdvC-EE2.js → vue-vine-By_xyXdL.js} +1 -1
  210. package/dist/ui/assets/{wc-attach-DsMfUpx8.js → wc-attach-CPoS-Z-g.js} +2 -2
  211. package/dist/ui/assets/{wc-extension-CL-LAE0W.js → wc-extension-vZctlNTg.js} +2 -2
  212. package/dist/ui/assets/wc-float-label-D7p-4xyd.js +1 -0
  213. package/dist/ui/assets/wc-follower-BgCWId1J.js +17 -0
  214. package/dist/ui/assets/wc-live-leqS7MUz.js +8 -0
  215. package/dist/ui/assets/wc-nav-CO_N4L3V.js +2 -0
  216. package/dist/ui/assets/wc-onboarding-B4o-Pdiq.js +2 -0
  217. package/dist/ui/assets/wc-placeholder-BTbGc9bq.js +4 -0
  218. package/dist/ui/assets/wc-settings-B4hsC2Um.js +51 -0
  219. package/dist/ui/assets/{wc-shell-DC5bovWA.js → wc-shell-B9UbR2P2.js} +3 -3
  220. package/dist/ui/assets/{wc-sprinkles-CDP31nXS.js → wc-sprinkles-Ds-rd0k7.js} +2 -2
  221. package/dist/ui/assets/wc-tray-BQls_HTm.js +2 -0
  222. package/dist/ui/assets/{wc-tray-scoops-B2RP8cgD.js → wc-tray-scoops-D8qwcovR.js} +1 -1
  223. package/dist/ui/assets/welcome-CyCMJDqG.js +621 -0
  224. package/dist/ui/assets/whisper-session-DpDs0sDL.js +2 -0
  225. package/dist/ui/assets/x_search-C-5p00-C.js +131 -0
  226. package/dist/ui/assets/xai-grok-DzMkuuG4.js +1 -0
  227. package/dist/ui/assets/xai-grok-kLSQtmUi.js +1 -0
  228. package/dist/ui/index.html +16 -14
  229. package/dist/ui/packages/webapp/index.html +16 -14
  230. package/dist/ui/slicc-diff.js +1 -1
  231. package/package.json +1 -1
  232. package/dist/ui/assets/adobe-C19oqBaU.js +0 -1
  233. package/dist/ui/assets/adobe-Dv-gMc09.js +0 -2
  234. package/dist/ui/assets/anthropic-messages-BX4DpK10.js +0 -39
  235. package/dist/ui/assets/anthropic-messages-C-orWG7m.js +0 -39
  236. package/dist/ui/assets/azure-openai-responses-C2LleG-4.js +0 -1
  237. package/dist/ui/assets/azure-openai-responses-Df9YPxyp.js +0 -1
  238. package/dist/ui/assets/bedrock-camp-B0KF_4RS.js +0 -1
  239. package/dist/ui/assets/bedrock-camp-qpZqnqLa.js +0 -2
  240. package/dist/ui/assets/catppuccin-frappe-3VR1Za6u.js +0 -1
  241. package/dist/ui/assets/catppuccin-latte-DwIHMF0Q.js +0 -1
  242. package/dist/ui/assets/catppuccin-macchiato-DYnBP6_5.js +0 -1
  243. package/dist/ui/assets/catppuccin-mocha-DYhrFGRu.js +0 -1
  244. package/dist/ui/assets/cerebras-CDHmZz_Y.js +0 -1
  245. package/dist/ui/assets/cerebras-DPV0CO1I.js +0 -1
  246. package/dist/ui/assets/cpp-CdhRINFH.js +0 -1
  247. package/dist/ui/assets/discovery-preference-fqUhjzeE.js +0 -1
  248. package/dist/ui/assets/dist-Dwa3Gdd4.js +0 -1547
  249. package/dist/ui/assets/float-topology-BgioAcOd.js +0 -1
  250. package/dist/ui/assets/fs-CIIVB1OK.js +0 -2
  251. package/dist/ui/assets/fs-QyBiZMuq.js +0 -1
  252. package/dist/ui/assets/github-Ctvr_Nd6.js +0 -1
  253. package/dist/ui/assets/github-Dq-ryVOk.js +0 -2
  254. package/dist/ui/assets/github-copilot-DIk_soEH.js +0 -1
  255. package/dist/ui/assets/github-copilot-Dm5mGSYk.js +0 -2
  256. package/dist/ui/assets/google-generative-ai-C9uw7Zks.js +0 -1
  257. package/dist/ui/assets/google-generative-ai-DHBc1oKV.js +0 -1
  258. package/dist/ui/assets/google-vertex-BaT3InWy.js +0 -1
  259. package/dist/ui/assets/google-vertex-DX8CfGr6.js +0 -1
  260. package/dist/ui/assets/julia-DibC-h6i.js +0 -1
  261. package/dist/ui/assets/kanagawa-dragon-CXtmUGW6.js +0 -1
  262. package/dist/ui/assets/kanagawa-lotus-BN08jTvb.js +0 -1
  263. package/dist/ui/assets/kanagawa-wave-CTweb8Dz.js +0 -1
  264. package/dist/ui/assets/legacy-api-aliases-CsTVszvY.js +0 -1
  265. package/dist/ui/assets/legacy-api-aliases-nSD9C16V.js +0 -1
  266. package/dist/ui/assets/mdc-Otire2H_.js +0 -1
  267. package/dist/ui/assets/mistral-conversations-BXo-tb0V.js +0 -4
  268. package/dist/ui/assets/mistral-conversations-Ck257tvp.js +0 -4
  269. package/dist/ui/assets/monokai-CdkpiU2Y.js +0 -1
  270. package/dist/ui/assets/mount-C20u28qg.js +0 -2
  271. package/dist/ui/assets/mount-DSlWOyRg.js +0 -1
  272. package/dist/ui/assets/mount-recovery-Dp2uzDT3.js +0 -2
  273. package/dist/ui/assets/new-session-BmqHuPnd.js +0 -2
  274. package/dist/ui/assets/oauth-bootstrap-CF5Iq7xU.js +0 -2
  275. package/dist/ui/assets/oauth-service-Bbrrl8Mr.js +0 -1
  276. package/dist/ui/assets/oauth-service-Cy5ngmcU.js +0 -1
  277. package/dist/ui/assets/openai-codex-C2ilX51B.js +0 -1
  278. package/dist/ui/assets/openai-codex-bhWf9evO.js +0 -1
  279. package/dist/ui/assets/openai-codex-responses-BQzefg3i.js +0 -7
  280. package/dist/ui/assets/openai-codex-responses-JtcU5b3J.js +0 -7
  281. package/dist/ui/assets/openai-completions-D-HjYi8x.js +0 -5
  282. package/dist/ui/assets/openai-completions-QMfwfjiE.js +0 -5
  283. package/dist/ui/assets/openai-responses-BVHnEPuG.js +0 -1
  284. package/dist/ui/assets/openai-responses-Ca0oWhbv.js +0 -1
  285. package/dist/ui/assets/openrouter-Bo62to17.js +0 -1
  286. package/dist/ui/assets/openrouter-C9_8OqEu.js +0 -1
  287. package/dist/ui/assets/panel-rpc-handlers-Dbhx7m_G.js +0 -2
  288. package/dist/ui/assets/php-BidqsJNR.js +0 -1
  289. package/dist/ui/assets/port-bridge-client-BbVs1yhx.js +0 -2
  290. package/dist/ui/assets/port-bridge-client-DxYLF2-N.js +0 -1
  291. package/dist/ui/assets/provider-settings-BTpBo_o4.js +0 -2
  292. package/dist/ui/assets/provider-store-access-CrgSlufJ.js +0 -1
  293. package/dist/ui/assets/providers-Crdj27DN.js +0 -2
  294. package/dist/ui/assets/providers-DX7EJ4Fn.js +0 -1
  295. package/dist/ui/assets/proxied-fetch-B4g-4VbQ.js +0 -2
  296. package/dist/ui/assets/proxied-fetch-n2pCvcgW.js +0 -1
  297. package/dist/ui/assets/quick-llm-hL6bZGLe.js +0 -1
  298. package/dist/ui/assets/r-Dzep-lPg.js +0 -1
  299. package/dist/ui/assets/red-CJ3rzSJv.js +0 -1
  300. package/dist/ui/assets/rose-pine-BthvhNj6.js +0 -1
  301. package/dist/ui/assets/rose-pine-dawn-Dg85fqjY.js +0 -1
  302. package/dist/ui/assets/rose-pine-moon-hon4tzzS.js +0 -1
  303. package/dist/ui/assets/secret-env-q4hxkt7Z.js +0 -1
  304. package/dist/ui/assets/secret-topology-xLmXoozo.js +0 -1
  305. package/dist/ui/assets/setup-standalone-prelude-Btsjqjoe.js +0 -2
  306. package/dist/ui/assets/setup-sudo-DrmeHwU_.js +0 -2
  307. package/dist/ui/assets/slicc-version-tsUsi909.js +0 -1
  308. package/dist/ui/assets/solarized-dark-DV17i1UV.js +0 -1
  309. package/dist/ui/assets/solarized-light-DSh2HLQt.js +0 -1
  310. package/dist/ui/assets/swift-DonLKvLd.js +0 -1
  311. package/dist/ui/assets/transformers-env-SL0zTs7S.js +0 -1
  312. package/dist/ui/assets/tray-leader-DcRtwWl-.js +0 -1
  313. package/dist/ui/assets/tray-runtime-config-CRGwg9SK.js +0 -1
  314. package/dist/ui/assets/ts-tags-BUIgHz80.js +0 -1
  315. package/dist/ui/assets/vesper-D5bVUKB1.js +0 -1
  316. package/dist/ui/assets/wc-float-label-qqb_uM9y.js +0 -1
  317. package/dist/ui/assets/wc-follower-troAtcMA.js +0 -17
  318. package/dist/ui/assets/wc-live-D1Mon0cw.js +0 -8
  319. package/dist/ui/assets/wc-nav-BV6Jm98e.js +0 -2
  320. package/dist/ui/assets/wc-onboarding-Dg4E9VDR.js +0 -2
  321. package/dist/ui/assets/wc-placeholder-_6RUOpYH.js +0 -4
  322. package/dist/ui/assets/wc-settings-Dy5cPd8c.js +0 -51
  323. package/dist/ui/assets/wc-tray-MFZAPwt4.js +0 -2
  324. package/dist/ui/assets/whisper-session-Cf2gGkoR.js +0 -2
  325. package/dist/ui/assets/xai-grok-C2GEvF8U.js +0 -1
  326. package/dist/ui/assets/xai-grok-CoSPbEFx.js +0 -1
package/README.md CHANGED
@@ -78,7 +78,7 @@ SLICC is for you if:
78
78
  - **Boot full x86 virtual machines in the browser.** `v86 start` runs real operating systems (Alpine, FreeDOS, KolibriOS, ...) on the wasm-based [v86](https://github.com/copy/v86) emulator, entirely client-side. The agent drives the guest from the shell — type, click, screenshot, stream the screen live, save/restore state — and `-net <model>,relay=fetch` gives the guest HTTP access through SLICC's fetch proxy. Install with `ipk add v86`.
79
79
  - **Delegate parallel work to scoops.** Split tasks into isolated sub-agents with their own sandboxes and context, then let the main agent coordinate the results.
80
80
  - **Turn one-off wins into reusable workflows.** Package behavior as skills, build interactive sprinkles, and react to external events with webhooks and cron-driven licks.
81
- - **Mount your local file system.** By default, SLICC is confined to your browser. But you can ask it to mount folders from your local file system, so it can read and write from there. Mount into an empty path such as `/mnt/myproject` so you do not hide existing skills or scripts.
81
+ - **Mount your local file system.** By default, SLICC is confined to your browser. But you can ask it to mount folders from your local file system, so it can read and write from there. Mount into an empty path such as `/mnt/myproject` so you do not hide existing skills or scripts. Picker mounts ask again after a page reload; for folders you always want available, map them in the launcher's mount table (`npx slicc --mount=~/Projects/foo:/mnt/foo`, or Settings → Mounts in Sliccstart.app) and they are mounted automatically on every launch, with no picker or permission prompt — see [Auto-mounted host folders](docs/mounts.md#auto-mounted-host-folders-the-mount-table).
82
82
  - **Mount remote storage as if it were local.** Beyond local folders, `mount --source` bridges S3 buckets, S3-compatible services like Cloudflare R2 and MinIO, and Adobe authoring content — both da.live repositories and Helix 6 sites on the AEM Source Bus — into the same VFS surface. Reads use TTL+ETag caching with conditional revalidation; writes use ETag-conditional PUTs that surface concurrent-edit conflicts as `EBUSY`. Credentials live server-side (`~/.slicc/secrets.env` in CLI, `chrome.storage.local` in the extension via the **Extension options** page) and never reach the agent. After setup: `mount --source s3://my-bucket --profile r2 /mnt/r2`, `mount --source da://my-org/my-repo /mnt/da`, or `mount --source aem://my-org/my-site /mnt/aem`. A `da://` source checks the site config first and re-routes to the Source Bus when the site has been upgraded to Helix 6, rather than quietly mounting a store that no longer holds its content. See [docs/mounts.md](docs/mounts.md) for the full guide.
83
83
 
84
84
  ## Getting started
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Host filesystem bridge — serves the folders named in the mount table
3
+ * (`--mount=<os-path>:<slicc-path>`) to the webapp over the local /api
4
+ * surface, so configured mounts appear in the VFS fully automatically,
5
+ * with no File System Access picker and no Chrome permission prompt.
6
+ *
7
+ * Only paths under a configured mount root are reachable. Every request
8
+ * names a mount by its SLICC target (`?mount=/mnt/project`) plus a
9
+ * mount-relative path (`?path=sub/file.txt`); the mapping to the OS root
10
+ * happens here and `resolveWithinRoot` rejects traversal (`..`) and
11
+ * symlink escapes, so the browser never addresses the host filesystem
12
+ * directly.
13
+ *
14
+ * Protected like every other /api route: same-origin / loopback callers
15
+ * pass, cross-origin callers need the bridge token (see
16
+ * `createThinBridgeCorsMiddleware` in index.ts).
17
+ */
18
+ import type { Express } from 'express';
19
+ import type { HostMountMapping } from './runtime-flags.js';
20
+ /** Matches the webapp's hostfs body cap (backend-hostfs.ts). */
21
+ export declare const HOSTFS_MAX_BODY_BYTES: number;
22
+ /**
23
+ * Resolve `relPath` against `root`, rejecting anything that leaves the root
24
+ * either lexically (`..`) or via symlinks. Symlinks *inside* the root that
25
+ * also point inside the root are followed; a link pointing outside is
26
+ * rejected. The check walks to the nearest existing ancestor so that writes
27
+ * to not-yet-existing paths are still validated.
28
+ */
29
+ export declare function resolveWithinRoot(root: string, relPath: string): Promise<string>;
30
+ interface HostMountRoot {
31
+ /** SLICC target path, e.g. /mnt/project. */
32
+ path: string;
33
+ /** realpath()'d OS root. */
34
+ root: string;
35
+ }
36
+ /**
37
+ * Resolve the configured mappings to realpath'd roots. Mappings whose OS
38
+ * path does not exist (or is not a directory) are dropped with a warning —
39
+ * a missing folder must not take the whole /api surface down, and the
40
+ * webapp will surface the absent mount as "not mounted".
41
+ */
42
+ export declare function resolveHostMountRoots(mounts: readonly HostMountMapping[], warn?: (msg: string) => void): Promise<HostMountRoot[]>;
43
+ /**
44
+ * Register the /api/hostfs routes for the resolved mount roots. The route
45
+ * surface mirrors `MountBackend` 1:1 (webapp `backend-hostfs.ts`):
46
+ *
47
+ * GET /api/hostfs/list?mount=&path= → { entries: [...] }
48
+ * GET /api/hostfs/stat?mount=&path= → { kind, size, mtime }
49
+ * GET /api/hostfs/read?mount=&path= → octet-stream body
50
+ * PUT /api/hostfs/write?mount=&path= ← octet-stream body
51
+ * POST /api/hostfs/mkdir?mount=&path=
52
+ * DELETE /api/hostfs/remove?mount=&path=[&recursive=1]
53
+ *
54
+ * Errors are `{ code, message }` JSON with an errno-derived status so the
55
+ * webapp backend can rethrow faithful `FsError`s.
56
+ */
57
+ export declare function registerHostFsRoutes(app: Express, roots: readonly HostMountRoot[]): void;
58
+ export {};
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Host filesystem bridge — serves the folders named in the mount table
3
+ * (`--mount=<os-path>:<slicc-path>`) to the webapp over the local /api
4
+ * surface, so configured mounts appear in the VFS fully automatically,
5
+ * with no File System Access picker and no Chrome permission prompt.
6
+ *
7
+ * Only paths under a configured mount root are reachable. Every request
8
+ * names a mount by its SLICC target (`?mount=/mnt/project`) plus a
9
+ * mount-relative path (`?path=sub/file.txt`); the mapping to the OS root
10
+ * happens here and `resolveWithinRoot` rejects traversal (`..`) and
11
+ * symlink escapes, so the browser never addresses the host filesystem
12
+ * directly.
13
+ *
14
+ * Protected like every other /api route: same-origin / loopback callers
15
+ * pass, cross-origin callers need the bridge token (see
16
+ * `createThinBridgeCorsMiddleware` in index.ts).
17
+ */
18
+ import express from 'express';
19
+ import { lstat, mkdir, readdir, readFile, realpath, rename, rm, stat, writeFile, } from 'fs/promises';
20
+ import { dirname, resolve, sep } from 'path';
21
+ /** Matches the webapp's hostfs body cap (backend-hostfs.ts). */
22
+ export const HOSTFS_MAX_BODY_BYTES = 100 * 1024 * 1024;
23
+ function errnoCode(err) {
24
+ const code = err?.code;
25
+ return typeof code === 'string' ? code : null;
26
+ }
27
+ /** Map an fs errno (or traversal rejection) to an HTTP status + FsError code. */
28
+ function toFsCodeError(err) {
29
+ const code = errnoCode(err) ?? 'EIO';
30
+ const message = err instanceof Error ? err.message : String(err);
31
+ switch (code) {
32
+ case 'ENOENT':
33
+ return { status: 404, code, message };
34
+ case 'EACCES':
35
+ case 'EPERM':
36
+ return { status: 403, code: 'EACCES', message };
37
+ case 'EISDIR':
38
+ case 'ENOTDIR':
39
+ case 'ENOTEMPTY':
40
+ case 'EEXIST':
41
+ return { status: 409, code, message };
42
+ default:
43
+ return { status: 500, code, message };
44
+ }
45
+ }
46
+ function sendFsError(res, err) {
47
+ const mapped = toFsCodeError(err);
48
+ res.status(mapped.status).json({ code: mapped.code, message: mapped.message });
49
+ }
50
+ /** Traversal/symlink escape → EACCES, so it renders as a permission error. */
51
+ function escapeError(target) {
52
+ const err = new Error(`path escapes the mount root: ${target}`);
53
+ err.code = 'EACCES';
54
+ return err;
55
+ }
56
+ function isWithin(root, target) {
57
+ return target === root || target.startsWith(root + sep);
58
+ }
59
+ /**
60
+ * Resolve `relPath` against `root`, rejecting anything that leaves the root
61
+ * either lexically (`..`) or via symlinks. Symlinks *inside* the root that
62
+ * also point inside the root are followed; a link pointing outside is
63
+ * rejected. The check walks to the nearest existing ancestor so that writes
64
+ * to not-yet-existing paths are still validated.
65
+ */
66
+ export async function resolveWithinRoot(root, relPath) {
67
+ const cleaned = relPath.replace(/^\/+/, '');
68
+ const target = resolve(root, cleaned);
69
+ if (!isWithin(root, target))
70
+ throw escapeError(target);
71
+ // Walk up to the nearest existing ancestor and realpath it; a symlinked
72
+ // ancestor must still land inside the (already realpath'd) root.
73
+ let probe = target;
74
+ for (;;) {
75
+ try {
76
+ const real = await realpath(probe);
77
+ if (!isWithin(root, real) && probe !== root)
78
+ throw escapeError(target);
79
+ break;
80
+ }
81
+ catch (err) {
82
+ if (errnoCode(err) !== 'ENOENT')
83
+ throw err;
84
+ const parent = dirname(probe);
85
+ if (parent === probe)
86
+ break;
87
+ probe = parent;
88
+ }
89
+ }
90
+ return target;
91
+ }
92
+ function statPayload(s) {
93
+ return {
94
+ kind: s.isDirectory() ? 'directory' : 'file',
95
+ size: s.isDirectory() ? 0 : s.size,
96
+ mtime: Math.round(s.mtimeMs),
97
+ };
98
+ }
99
+ /**
100
+ * Resolve the configured mappings to realpath'd roots. Mappings whose OS
101
+ * path does not exist (or is not a directory) are dropped with a warning —
102
+ * a missing folder must not take the whole /api surface down, and the
103
+ * webapp will surface the absent mount as "not mounted".
104
+ */
105
+ export async function resolveHostMountRoots(mounts, warn = (msg) => console.warn(msg)) {
106
+ const roots = [];
107
+ for (const mapping of mounts) {
108
+ try {
109
+ const root = await realpath(mapping.hostPath);
110
+ const s = await stat(root);
111
+ if (!s.isDirectory()) {
112
+ warn(`--mount ${mapping.hostPath}: not a directory, skipping`);
113
+ continue;
114
+ }
115
+ roots.push({ path: mapping.path, root });
116
+ }
117
+ catch {
118
+ warn(`--mount ${mapping.hostPath}: does not exist, skipping`);
119
+ }
120
+ }
121
+ return roots;
122
+ }
123
+ function queryString(req, name) {
124
+ const value = req.query[name];
125
+ return typeof value === 'string' && value.length > 0 ? value : null;
126
+ }
127
+ /**
128
+ * Register the /api/hostfs routes for the resolved mount roots. The route
129
+ * surface mirrors `MountBackend` 1:1 (webapp `backend-hostfs.ts`):
130
+ *
131
+ * GET /api/hostfs/list?mount=&path= → { entries: [...] }
132
+ * GET /api/hostfs/stat?mount=&path= → { kind, size, mtime }
133
+ * GET /api/hostfs/read?mount=&path= → octet-stream body
134
+ * PUT /api/hostfs/write?mount=&path= ← octet-stream body
135
+ * POST /api/hostfs/mkdir?mount=&path=
136
+ * DELETE /api/hostfs/remove?mount=&path=[&recursive=1]
137
+ *
138
+ * Errors are `{ code, message }` JSON with an errno-derived status so the
139
+ * webapp backend can rethrow faithful `FsError`s.
140
+ */
141
+ export function registerHostFsRoutes(app, roots) {
142
+ const byPath = new Map(roots.map((r) => [r.path, r]));
143
+ const withTarget = (handler) => {
144
+ return (req, res) => {
145
+ void (async () => {
146
+ const mount = queryString(req, 'mount');
147
+ const rel = queryString(req, 'path') ?? '';
148
+ const entry = mount ? byPath.get(mount) : undefined;
149
+ if (!entry) {
150
+ res.status(404).json({ code: 'ENOENT', message: `no such mount: ${mount ?? ''}` });
151
+ return;
152
+ }
153
+ try {
154
+ const target = await resolveWithinRoot(entry.root, rel);
155
+ await handler(target, req, res);
156
+ }
157
+ catch (err) {
158
+ sendFsError(res, err);
159
+ }
160
+ })();
161
+ };
162
+ };
163
+ app.get('/api/hostfs/list', withTarget(async (target, _req, res) => {
164
+ const dirents = await readdir(target, { withFileTypes: true });
165
+ const entries = await Promise.all(dirents.map(async (d) => {
166
+ if (d.isDirectory())
167
+ return { name: d.name, kind: 'directory' };
168
+ try {
169
+ // stat() follows symlinks, so a link to a directory classifies as
170
+ // a directory — matching what every subsequent access sees (and
171
+ // the swift server, whose fileExists follows links). Escaping
172
+ // links are still refused at access time by resolveWithinRoot.
173
+ const s = await stat(resolve(target, d.name));
174
+ if (s.isDirectory())
175
+ return { name: d.name, kind: 'directory' };
176
+ return {
177
+ name: d.name,
178
+ kind: 'file',
179
+ size: s.size,
180
+ lastModified: Math.round(s.mtimeMs),
181
+ };
182
+ }
183
+ catch {
184
+ // Raced deletion / dangling link / unreadable: name only.
185
+ return { name: d.name, kind: 'file' };
186
+ }
187
+ }));
188
+ res.json({ entries });
189
+ }));
190
+ app.get('/api/hostfs/stat', withTarget(async (target, _req, res) => {
191
+ res.json(statPayload(await stat(target)));
192
+ }));
193
+ app.get('/api/hostfs/read', withTarget(async (target, _req, res) => {
194
+ // lstat first so a dangling symlink is ENOENT, a directory is EISDIR.
195
+ const s = await stat(target);
196
+ if (s.isDirectory()) {
197
+ sendFsError(res, Object.assign(new Error(`is a directory: ${target}`), { code: 'EISDIR' }));
198
+ return;
199
+ }
200
+ if (s.size > HOSTFS_MAX_BODY_BYTES) {
201
+ res.status(413).json({
202
+ code: 'EFBIG',
203
+ message: `file exceeds the ${HOSTFS_MAX_BODY_BYTES} byte hostfs cap`,
204
+ });
205
+ return;
206
+ }
207
+ const body = await readFile(target);
208
+ res.setHeader('Content-Type', 'application/octet-stream');
209
+ res.send(body);
210
+ }));
211
+ app.put('/api/hostfs/write', express.raw({ type: () => true, limit: HOSTFS_MAX_BODY_BYTES }), withTarget(async (target, req, res) => {
212
+ // Refuse to clobber a directory with a file (fs would throw EISDIR on
213
+ // open, but check explicitly so the error is deterministic).
214
+ try {
215
+ const existing = await lstat(target);
216
+ if (existing.isDirectory()) {
217
+ sendFsError(res, Object.assign(new Error(`is a directory: ${target}`), { code: 'EISDIR' }));
218
+ return;
219
+ }
220
+ }
221
+ catch {
222
+ /* ENOENT — fresh file */
223
+ }
224
+ await mkdir(dirname(target), { recursive: true });
225
+ const body = Buffer.isBuffer(req.body) ? req.body : Buffer.alloc(0);
226
+ // Write-then-rename would break hardlinks and xattrs on user files;
227
+ // plain writeFile matches what local tools do.
228
+ await writeFile(target, body);
229
+ res.json({ ok: true });
230
+ }));
231
+ app.post('/api/hostfs/mkdir', withTarget(async (target, _req, res) => {
232
+ await mkdir(target, { recursive: true });
233
+ res.json({ ok: true });
234
+ }));
235
+ app.post('/api/hostfs/rename', withTarget(async (target, req, res) => {
236
+ const mount = queryString(req, 'mount');
237
+ const toRel = queryString(req, 'to');
238
+ const entry = mount ? byPath.get(mount) : undefined;
239
+ if (!entry || !toRel) {
240
+ res.status(400).json({ code: 'EINVAL', message: 'rename requires mount and to' });
241
+ return;
242
+ }
243
+ const to = await resolveWithinRoot(entry.root, toRel);
244
+ await rename(target, to);
245
+ res.json({ ok: true });
246
+ }));
247
+ app.delete('/api/hostfs/remove', withTarget(async (target, req, res) => {
248
+ const isRoot = roots.some((r) => r.root === target);
249
+ if (isRoot) {
250
+ res.status(403).json({ code: 'EACCES', message: 'refusing to remove a mount root' });
251
+ return;
252
+ }
253
+ const recursive = queryString(req, 'recursive') === '1';
254
+ await rm(target, { recursive, force: false });
255
+ res.json({ ok: true });
256
+ }));
257
+ }
@@ -30,6 +30,7 @@ import { getElectronAppPorts } from './electron-runtime.js';
30
30
  import { ElectronTrayFollower } from './electron-tray-follower.js';
31
31
  import { FileLogger } from './file-logger.js';
32
32
  import { registerHostedBootstrapEndpoint } from './hosted-bootstrap.js';
33
+ import { registerHostFsRoutes, resolveHostMountRoots } from './hostfs.js';
33
34
  import { runInstallCli } from './install-cli.js';
34
35
  import { resolveCliBrowserLaunchUrl } from './launch-url.js';
35
36
  import { createHttpCdp, registerLeaderRestartEndpoint } from './leader-restart.js';
@@ -197,6 +198,7 @@ function createServerState() {
197
198
  electronFollower: null,
198
199
  shuttingDown: false,
199
200
  discoveredTrayJoinUrl: RUNTIME_FLAGS.joinUrl ?? null,
201
+ hostMountRoots: [],
200
202
  bridgeToken: resolveServerBridgeToken(process.env, { thinBridgeMode: THIN_BRIDGE_MODE }),
201
203
  cdpUrl: null,
202
204
  chromeWs: null,
@@ -1106,6 +1108,10 @@ async function main() {
1106
1108
  // after `server.listen()`, so this endpoint must NOT close over a
1107
1109
  // pre-launch snapshot or it would always return null.
1108
1110
  trayJoinUrl: state.discoveredTrayJoinUrl ?? null,
1111
+ // Mount table (--mount=<os-path>:<slicc-path>): served over
1112
+ // /api/hostfs and auto-mounted by the webapp at boot. Only mappings
1113
+ // whose OS folder existed at startup are advertised.
1114
+ autoMounts: state.hostMountRoots.map(({ path, root }) => ({ path, hostPath: root })),
1109
1115
  });
1110
1116
  });
1111
1117
  // Localhost API descriptor — the discoverable surface advertised by the
@@ -1144,6 +1150,10 @@ async function main() {
1144
1150
  registerHostedBootstrapEndpoint(app, { secretStore });
1145
1151
  registerSecretsReloadEndpoint(app, { secretProxy, secretStore, oauthStore });
1146
1152
  }
1153
+ // Host-FS bridge for the mount table (--mount=<os>:<vfs>), every mode.
1154
+ // Roots are resolved once at startup; a folder created later needs a restart.
1155
+ state.hostMountRoots = await resolveHostMountRoots(RUNTIME_FLAGS.mounts);
1156
+ registerHostFsRoutes(app, state.hostMountRoots);
1147
1157
  // Sudo approval endpoint — raises a native OS dialog / TTY prompt from this
1148
1158
  // trusted process so the in-browser agent can request, but never fabricate,
1149
1159
  // an approval. Loopback-only; selects a backend by environment at call time.
@@ -24,7 +24,29 @@ export interface CliRuntimeFlags {
24
24
  installCli: boolean;
25
25
  /** Target directory for --install-cli (default: OS-idiomatic, see install-cli.ts) */
26
26
  installDir: string | null;
27
+ /**
28
+ * Mount table: OS-folder → SLICC-target mappings served over the local
29
+ * host-FS bridge (`/api/hostfs`) and auto-mounted by the webapp at boot,
30
+ * with no picker and no Chrome permission prompt. Filled by repeatable
31
+ * `--mount=<os-path>:<slicc-path>` / `--mount <os-path>:<slicc-path>`
32
+ * flags. Picker-initiated (`mount <path>`) FS-Access mounts are
33
+ * unaffected and keep asking for permission.
34
+ */
35
+ mounts: HostMountMapping[];
36
+ }
37
+ /** One `--mount` entry: an absolute OS folder mapped to a VFS target. */
38
+ export interface HostMountMapping {
39
+ hostPath: string;
40
+ path: string;
27
41
  }
28
42
  export declare const DEFAULT_CLI_CDP_PORT = 9222;
29
43
  export declare const DEFAULT_ELECTRON_ATTACH_CDP_PORT = 9223;
44
+ /**
45
+ * Parse a `--mount` value of the form `<os-path>:<slicc-path>`. The split is
46
+ * on the LAST `:` whose remainder is an absolute path, so OS paths containing
47
+ * `:` still parse. A leading `~/` on the OS side expands against `homeDir`.
48
+ * Returns null (never a partial mapping) for anything else, so a stray
49
+ * `--mount=` or a one-sided value never lands in the table.
50
+ */
51
+ export declare function parseMountTableMapping(value: string, homeDir?: string): HostMountMapping | null;
30
52
  export declare function parseCliRuntimeFlags(argv: string[]): CliRuntimeFlags;
@@ -1,5 +1,72 @@
1
1
  export const DEFAULT_CLI_CDP_PORT = 9222;
2
2
  export const DEFAULT_ELECTRON_ATTACH_CDP_PORT = 9223;
3
+ /** `.`/`..` segments or empty (`//`) segments make raw != canonical. */
4
+ function hasDotOrEmptySegments(path) {
5
+ return path
6
+ .split(/[/\\]/)
7
+ .slice(1)
8
+ .some((segment) => segment === '' || segment === '.' || segment === '..');
9
+ }
10
+ /**
11
+ * Normalize an absolute POSIX path. Dot/empty segments are rejected rather
12
+ * than resolved so the accepted value IS its canonical form — the webapp,
13
+ * the /api/hostfs mount key, and VirtualFS.normalizePath all agree on it.
14
+ */
15
+ function normalizeAbsolutePath(value) {
16
+ const trimmed = value.trim();
17
+ if (!trimmed.startsWith('/'))
18
+ return null;
19
+ const stripped = trimmed.length > 1 ? trimmed.replace(/\/+$/, '') : trimmed;
20
+ if (!stripped || (stripped.length > 1 && hasDotOrEmptySegments(stripped)))
21
+ return null;
22
+ return stripped;
23
+ }
24
+ /**
25
+ * Normalize the OS side of a mapping: POSIX absolute, or a Windows drive
26
+ * path (`C:\…` / `C:/…`) — node-server ships on Windows too.
27
+ */
28
+ function normalizeHostPath(value) {
29
+ const trimmed = value.trim();
30
+ if (/^[A-Za-z]:[/\\]/.test(trimmed)) {
31
+ const stripped = trimmed.replace(/[/\\]+$/, '');
32
+ // Keep the root slash on a bare drive (`C:\`).
33
+ if (/^[A-Za-z]:$/.test(stripped))
34
+ return trimmed.slice(0, 3);
35
+ return hasDotOrEmptySegments(stripped.slice(2)) ? null : stripped;
36
+ }
37
+ return normalizeAbsolutePath(trimmed);
38
+ }
39
+ /**
40
+ * Parse a `--mount` value of the form `<os-path>:<slicc-path>`. The split is
41
+ * on the LAST `:` whose remainder is an absolute path, so OS paths containing
42
+ * `:` still parse. A leading `~/` on the OS side expands against `homeDir`.
43
+ * Returns null (never a partial mapping) for anything else, so a stray
44
+ * `--mount=` or a one-sided value never lands in the table.
45
+ */
46
+ export function parseMountTableMapping(value, homeDir = process.env['HOME'] ?? '') {
47
+ const trimmed = value.trim();
48
+ const sep = trimmed.lastIndexOf(':');
49
+ if (sep <= 0)
50
+ return null;
51
+ let hostRaw = trimmed.slice(0, sep).trim();
52
+ const targetRaw = trimmed.slice(sep + 1).trim();
53
+ if (hostRaw === '~' || hostRaw.startsWith('~/')) {
54
+ if (!homeDir)
55
+ return null;
56
+ hostRaw = homeDir + hostRaw.slice(1);
57
+ }
58
+ const hostPath = normalizeHostPath(hostRaw);
59
+ const path = normalizeAbsolutePath(targetRaw);
60
+ if (!hostPath || !path || path === '/')
61
+ return null;
62
+ return { hostPath, path };
63
+ }
64
+ function addMountTablePath(flags, value) {
65
+ const mapping = parseMountTableMapping(value);
66
+ if (mapping && !flags.mounts.some((m) => m.path === mapping.path)) {
67
+ flags.mounts.push(mapping);
68
+ }
69
+ }
3
70
  function looksLikeUrl(value) {
4
71
  return /^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim());
5
72
  }
@@ -25,6 +92,7 @@ function createDefaultFlags() {
25
92
  hosted: false,
26
93
  installCli: false,
27
94
  installDir: null,
95
+ mounts: [],
28
96
  };
29
97
  }
30
98
  /** Next argv entry, but only when it exists and is not itself a `--` flag. */
@@ -103,6 +171,10 @@ function applyEqualsFlag(flags, arg) {
103
171
  flags.joinUrl = arg.slice('--join='.length).trim() || null;
104
172
  return true;
105
173
  }
174
+ if (arg.startsWith('--mount=')) {
175
+ addMountTablePath(flags, arg.slice('--mount='.length));
176
+ return true;
177
+ }
106
178
  if (arg.startsWith('--electron-app=')) {
107
179
  flags.electron = true;
108
180
  flags.electronApp = arg.slice('--electron-app='.length).trim() || null;
@@ -110,7 +182,7 @@ function applyEqualsFlag(flags, arg) {
110
182
  }
111
183
  return false;
112
184
  }
113
- /** `--prompt`/`--env-file`/`--profile`/`--install-dir` followed by a value token. Returns tokens consumed. */
185
+ /** `--prompt`/`--env-file`/`--profile`/`--install-dir`/`--mount` followed by a value token. Returns tokens consumed. */
114
186
  function applyPlainValueFlag(flags, argv, index, arg) {
115
187
  const next = nextValueArg(argv, index);
116
188
  if (next === null) {
@@ -125,6 +197,9 @@ function applyPlainValueFlag(flags, argv, index, arg) {
125
197
  else if (arg === '--install-dir') {
126
198
  flags.installDir = next.trim() || null;
127
199
  }
200
+ else if (arg === '--mount') {
201
+ addMountTablePath(flags, next);
202
+ }
128
203
  else {
129
204
  flags.profile = next.trim() || null;
130
205
  }
@@ -176,7 +251,8 @@ function applyValueFlag(flags, argv, index, arg) {
176
251
  if (arg === '--prompt' ||
177
252
  arg === '--env-file' ||
178
253
  arg === '--profile' ||
179
- arg === '--install-dir') {
254
+ arg === '--install-dir' ||
255
+ arg === '--mount') {
180
256
  return applyPlainValueFlag(flags, argv, index, arg);
181
257
  }
182
258
  if (arg === '--lead' || arg === '--join') {