@bytespell/shella 0.1.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 (446) hide show
  1. package/README.md +79 -0
  2. package/bin/cli.js +191 -0
  3. package/dist/server/index.d.ts +2 -0
  4. package/dist/server/index.js +94 -0
  5. package/dist/server/middleware/cors.d.ts +6 -0
  6. package/dist/server/middleware/cors.js +8 -0
  7. package/dist/server/routes/logs.d.ts +2 -0
  8. package/dist/server/routes/logs.js +29 -0
  9. package/dist/server/routes/model-state.d.ts +2 -0
  10. package/dist/server/routes/model-state.js +81 -0
  11. package/dist/server/routes/proxy.d.ts +2 -0
  12. package/dist/server/routes/proxy.js +122 -0
  13. package/dist/server/routes/windows.d.ts +2 -0
  14. package/dist/server/routes/windows.js +125 -0
  15. package/dist/server/schema.d.ts +204 -0
  16. package/dist/server/schema.js +18 -0
  17. package/dist/server/services/database.d.ts +5 -0
  18. package/dist/server/services/database.js +110 -0
  19. package/dist/server/services/sse-manager.d.ts +16 -0
  20. package/dist/server/services/sse-manager.js +44 -0
  21. package/dist/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  22. package/dist/web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  23. package/dist/web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  24. package/dist/web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  25. package/dist/web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  26. package/dist/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  27. package/dist/web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  28. package/dist/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  29. package/dist/web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  30. package/dist/web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  31. package/dist/web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  32. package/dist/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  33. package/dist/web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  34. package/dist/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  35. package/dist/web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  36. package/dist/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  37. package/dist/web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  38. package/dist/web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  39. package/dist/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  40. package/dist/web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  41. package/dist/web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  42. package/dist/web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  43. package/dist/web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  44. package/dist/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  45. package/dist/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  46. package/dist/web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  47. package/dist/web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  48. package/dist/web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  49. package/dist/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  50. package/dist/web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  51. package/dist/web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  52. package/dist/web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  53. package/dist/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  54. package/dist/web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  55. package/dist/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  56. package/dist/web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  57. package/dist/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  58. package/dist/web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  59. package/dist/web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  60. package/dist/web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  61. package/dist/web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  62. package/dist/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  63. package/dist/web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  64. package/dist/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  65. package/dist/web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  66. package/dist/web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  67. package/dist/web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  68. package/dist/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  69. package/dist/web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  70. package/dist/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  71. package/dist/web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  72. package/dist/web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  73. package/dist/web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  74. package/dist/web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  75. package/dist/web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  76. package/dist/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  77. package/dist/web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  78. package/dist/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  79. package/dist/web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  80. package/dist/web/assets/_baseUniq-Dj1Rdun9.js +1 -0
  81. package/dist/web/assets/abap-BdImnpbu.js +1 -0
  82. package/dist/web/assets/actionscript-3-CfeIJUat.js +1 -0
  83. package/dist/web/assets/ada-bCR0ucgS.js +1 -0
  84. package/dist/web/assets/amazon-bedrock-B_u4Gv8g.svg +3 -0
  85. package/dist/web/assets/andromeeda-C-Jbm3Hp.js +1 -0
  86. package/dist/web/assets/angular-html-CU67Zn6k.js +1 -0
  87. package/dist/web/assets/angular-ts-BwZT4LLn.js +1 -0
  88. package/dist/web/assets/apache-Pmp26Uib.js +1 -0
  89. package/dist/web/assets/apex-DDbsPZ6N.js +1 -0
  90. package/dist/web/assets/apl-dKokRX4l.js +1 -0
  91. package/dist/web/assets/applescript-Co6uUVPk.js +1 -0
  92. package/dist/web/assets/ara-BRHolxvo.js +1 -0
  93. package/dist/web/assets/arc-BcAe_L9C.js +1 -0
  94. package/dist/web/assets/architectureDiagram-VXUJARFQ-CUydP-HB.js +36 -0
  95. package/dist/web/assets/asciidoc-Dv7Oe6Be.js +1 -0
  96. package/dist/web/assets/asm-D_Q5rh1f.js +1 -0
  97. package/dist/web/assets/astro-CbQHKStN.js +1 -0
  98. package/dist/web/assets/aurora-x-D-2ljcwZ.js +1 -0
  99. package/dist/web/assets/awk-DMzUqQB5.js +1 -0
  100. package/dist/web/assets/ayu-dark-Cv9koXgw.js +1 -0
  101. package/dist/web/assets/ballerina-BFfxhgS-.js +1 -0
  102. package/dist/web/assets/bat-BkioyH1T.js +1 -0
  103. package/dist/web/assets/beancount-k_qm7-4y.js +1 -0
  104. package/dist/web/assets/berry-uYugtg8r.js +1 -0
  105. package/dist/web/assets/bibtex-CHM0blh-.js +1 -0
  106. package/dist/web/assets/bicep-Bmn6On1c.js +1 -0
  107. package/dist/web/assets/blade-DVc8C-J4.js +1 -0
  108. package/dist/web/assets/blockDiagram-VD42YOAC-D7ENTm-e.js +122 -0
  109. package/dist/web/assets/bsl-BO_Y6i37.js +1 -0
  110. package/dist/web/assets/c-BIGW1oBm.js +1 -0
  111. package/dist/web/assets/c4Diagram-YG6GDRKO-DE6z4ano.js +10 -0
  112. package/dist/web/assets/cadence-Bv_4Rxtq.js +1 -0
  113. package/dist/web/assets/cairo-KRGpt6FW.js +1 -0
  114. package/dist/web/assets/catppuccin-frappe-DFWUc33u.js +1 -0
  115. package/dist/web/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
  116. package/dist/web/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
  117. package/dist/web/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
  118. package/dist/web/assets/channel-C1Y873om.js +1 -0
  119. package/dist/web/assets/chunk-4BX2VUAB-f1AgJ5-4.js +1 -0
  120. package/dist/web/assets/chunk-55IACEB6-CRc_DE4C.js +1 -0
  121. package/dist/web/assets/chunk-B4BG7PRW-BeFQ_8yC.js +165 -0
  122. package/dist/web/assets/chunk-DI55MBZ5-_SEo9TtQ.js +220 -0
  123. package/dist/web/assets/chunk-FMBD7UC4-6M3K7zkj.js +15 -0
  124. package/dist/web/assets/chunk-QN33PNHL-BGGg7fLk.js +1 -0
  125. package/dist/web/assets/chunk-QZHKN3VN-Q6HkNG6r.js +1 -0
  126. package/dist/web/assets/chunk-TZMSLE5B-D3UMAT7-.js +1 -0
  127. package/dist/web/assets/clarity-D53aC0YG.js +1 -0
  128. package/dist/web/assets/classDiagram-2ON5EDUG-DLBhGros.js +1 -0
  129. package/dist/web/assets/classDiagram-v2-WZHVMYZB-DLBhGros.js +1 -0
  130. package/dist/web/assets/clojure-P80f7IUj.js +1 -0
  131. package/dist/web/assets/clone-DVBZ10mH.js +1 -0
  132. package/dist/web/assets/cmake-D1j8_8rp.js +1 -0
  133. package/dist/web/assets/cobol-nwyudZeR.js +1 -0
  134. package/dist/web/assets/code-block-QI2IAROF-BzpuLcBt.js +2 -0
  135. package/dist/web/assets/codeowners-Bp6g37R7.js +1 -0
  136. package/dist/web/assets/codeql-DsOJ9woJ.js +1 -0
  137. package/dist/web/assets/coffee-Ch7k5sss.js +1 -0
  138. package/dist/web/assets/common-lisp-Cg-RD9OK.js +1 -0
  139. package/dist/web/assets/coq-DkFqJrB1.js +1 -0
  140. package/dist/web/assets/cose-bilkent-S5V4N54A-BIcssrhL.js +1 -0
  141. package/dist/web/assets/cpp-CofmeUqb.js +1 -0
  142. package/dist/web/assets/crystal-tKQVLTB8.js +1 -0
  143. package/dist/web/assets/csharp-K5feNrxe.js +1 -0
  144. package/dist/web/assets/css-DPfMkruS.js +1 -0
  145. package/dist/web/assets/csv-fuZLfV_i.js +1 -0
  146. package/dist/web/assets/cue-D82EKSYY.js +1 -0
  147. package/dist/web/assets/cypher-COkxafJQ.js +1 -0
  148. package/dist/web/assets/cytoscape.esm-5J0xJHOV.js +321 -0
  149. package/dist/web/assets/d-85-TOEBH.js +1 -0
  150. package/dist/web/assets/dagre-6UL2VRFP-YaA_gyjx.js +4 -0
  151. package/dist/web/assets/dark-plus-C3mMm8J8.js +1 -0
  152. package/dist/web/assets/dart-CF10PKvl.js +1 -0
  153. package/dist/web/assets/dax-CEL-wOlO.js +1 -0
  154. package/dist/web/assets/deepinfra-Dq_BB8I0.svg +4 -0
  155. package/dist/web/assets/defaultLocale-C4B-KCzX.js +1 -0
  156. package/dist/web/assets/desktop-BmXAJ9_W.js +1 -0
  157. package/dist/web/assets/diagram-PSM6KHXK-r6WVaeIu.js +24 -0
  158. package/dist/web/assets/diagram-QEK2KX5R-DtTKn621.js +43 -0
  159. package/dist/web/assets/diagram-S2PKOQOG-BINNPg42.js +24 -0
  160. package/dist/web/assets/diff-D97Zzqfu.js +1 -0
  161. package/dist/web/assets/docker-BcOcwvcX.js +1 -0
  162. package/dist/web/assets/dotenv-Da5cRb03.js +1 -0
  163. package/dist/web/assets/dracula-BzJJZx-M.js +1 -0
  164. package/dist/web/assets/dracula-soft-BXkSAIEj.js +1 -0
  165. package/dist/web/assets/dream-maker-BtqSS_iP.js +1 -0
  166. package/dist/web/assets/edge-BkV0erSs.js +1 -0
  167. package/dist/web/assets/elixir-CDX3lj18.js +1 -0
  168. package/dist/web/assets/elm-DbKCFpqz.js +1 -0
  169. package/dist/web/assets/emacs-lisp-C9XAeP06.js +1 -0
  170. package/dist/web/assets/erDiagram-Q2GNP2WA-DXIwYH9k.js +60 -0
  171. package/dist/web/assets/erb-BOJIQeun.js +1 -0
  172. package/dist/web/assets/erlang-DsQrWhSR.js +1 -0
  173. package/dist/web/assets/everforest-dark-BgDCqdQA.js +1 -0
  174. package/dist/web/assets/everforest-light-C8M2exoo.js +1 -0
  175. package/dist/web/assets/fennel-BYunw83y.js +1 -0
  176. package/dist/web/assets/fish-BvzEVeQv.js +1 -0
  177. package/dist/web/assets/flowDiagram-NV44I4VS-D8Bad7wU.js +162 -0
  178. package/dist/web/assets/fluent-C4IJs8-o.js +1 -0
  179. package/dist/web/assets/fortran-fixed-form-BZjJHVRy.js +1 -0
  180. package/dist/web/assets/fortran-free-form-D22FLkUw.js +1 -0
  181. package/dist/web/assets/fsharp-CXgrBDvD.js +1 -0
  182. package/dist/web/assets/ganttDiagram-JELNMOA3-DSiZGBoG.js +267 -0
  183. package/dist/web/assets/gdresource-B7Tvp0Sc.js +1 -0
  184. package/dist/web/assets/gdscript-DTMYz4Jt.js +1 -0
  185. package/dist/web/assets/gdshader-DkwncUOv.js +1 -0
  186. package/dist/web/assets/genie-D0YGMca9.js +1 -0
  187. package/dist/web/assets/gherkin-DyxjwDmM.js +1 -0
  188. package/dist/web/assets/git-commit-F4YmCXRG.js +1 -0
  189. package/dist/web/assets/git-rebase-r7XF79zn.js +1 -0
  190. package/dist/web/assets/gitGraphDiagram-NY62KEGX-CCxrAUDj.js +65 -0
  191. package/dist/web/assets/github-dark-DHJKELXO.js +1 -0
  192. package/dist/web/assets/github-dark-default-Cuk6v7N8.js +1 -0
  193. package/dist/web/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  194. package/dist/web/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  195. package/dist/web/assets/github-light-DAi9KRSo.js +1 -0
  196. package/dist/web/assets/github-light-default-D7oLnXFd.js +1 -0
  197. package/dist/web/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  198. package/dist/web/assets/gleam-BspZqrRM.js +1 -0
  199. package/dist/web/assets/glimmer-js-Rg0-pVw9.js +1 -0
  200. package/dist/web/assets/glimmer-ts-U6CK756n.js +1 -0
  201. package/dist/web/assets/glsl-DplSGwfg.js +1 -0
  202. package/dist/web/assets/gnuplot-DdkO51Og.js +1 -0
  203. package/dist/web/assets/go-Dn2_MT6a.js +1 -0
  204. package/dist/web/assets/google-vertex-BCu5nGvk.svg +10 -0
  205. package/dist/web/assets/graph-CcI3NtJu.js +1 -0
  206. package/dist/web/assets/graphql-ChdNCCLP.js +1 -0
  207. package/dist/web/assets/groovy-gcz8RCvz.js +1 -0
  208. package/dist/web/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  209. package/dist/web/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  210. package/dist/web/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  211. package/dist/web/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  212. package/dist/web/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  213. package/dist/web/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  214. package/dist/web/assets/hack-CaT9iCJl.js +1 -0
  215. package/dist/web/assets/haml-B8DHNrY2.js +1 -0
  216. package/dist/web/assets/handlebars-BL8al0AC.js +1 -0
  217. package/dist/web/assets/haskell-Df6bDoY_.js +1 -0
  218. package/dist/web/assets/haxe-CzTSHFRz.js +1 -0
  219. package/dist/web/assets/hcl-BWvSN4gD.js +1 -0
  220. package/dist/web/assets/hjson-D5-asLiD.js +1 -0
  221. package/dist/web/assets/hlsl-D3lLCCz7.js +1 -0
  222. package/dist/web/assets/houston-DnULxvSX.js +1 -0
  223. package/dist/web/assets/html-GMplVEZG.js +1 -0
  224. package/dist/web/assets/html-derivative-BFtXZ54Q.js +1 -0
  225. package/dist/web/assets/http-jrhK8wxY.js +1 -0
  226. package/dist/web/assets/huggingface-DlwzPJmc.svg +3 -0
  227. package/dist/web/assets/hurl-irOxFIW8.js +1 -0
  228. package/dist/web/assets/hxml-Bvhsp5Yf.js +1 -0
  229. package/dist/web/assets/hy-DFXneXwc.js +1 -0
  230. package/dist/web/assets/imba-DGztddWO.js +1 -0
  231. package/dist/web/assets/index-B0jWvqrS.css +1 -0
  232. package/dist/web/assets/index-BCTWtQQB.js +1716 -0
  233. package/dist/web/assets/infoDiagram-WHAUD3N6-C3OGZjzs.js +2 -0
  234. package/dist/web/assets/ini-BEwlwnbL.js +1 -0
  235. package/dist/web/assets/init-Gi6I4Gst.js +1 -0
  236. package/dist/web/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
  237. package/dist/web/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
  238. package/dist/web/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
  239. package/dist/web/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
  240. package/dist/web/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
  241. package/dist/web/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
  242. package/dist/web/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
  243. package/dist/web/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
  244. package/dist/web/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
  245. package/dist/web/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
  246. package/dist/web/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
  247. package/dist/web/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
  248. package/dist/web/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
  249. package/dist/web/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
  250. package/dist/web/assets/java-CylS5w8V.js +1 -0
  251. package/dist/web/assets/javascript-wDzz0qaB.js +1 -0
  252. package/dist/web/assets/jinja-4LBKfQ-Z.js +1 -0
  253. package/dist/web/assets/jison-wvAkD_A8.js +1 -0
  254. package/dist/web/assets/journeyDiagram-XKPGCS4Q-aT-Wsw7y.js +139 -0
  255. package/dist/web/assets/json-Cp-IABpG.js +1 -0
  256. package/dist/web/assets/json5-C9tS-k6U.js +1 -0
  257. package/dist/web/assets/jsonc-Des-eS-w.js +1 -0
  258. package/dist/web/assets/jsonl-DcaNXYhu.js +1 -0
  259. package/dist/web/assets/jsonnet-DFQXde-d.js +1 -0
  260. package/dist/web/assets/jssm-C2t-YnRu.js +1 -0
  261. package/dist/web/assets/jsx-g9-lgVsj.js +1 -0
  262. package/dist/web/assets/julia-C8NyazO9.js +1 -0
  263. package/dist/web/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  264. package/dist/web/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  265. package/dist/web/assets/kanagawa-wave-DWedfzmr.js +1 -0
  266. package/dist/web/assets/kanban-definition-3W4ZIXB7-DpUj9tx6.js +89 -0
  267. package/dist/web/assets/katex-DvXFAOB1.css +1 -0
  268. package/dist/web/assets/kdl-DV7GczEv.js +1 -0
  269. package/dist/web/assets/kimi-for-coding-eVEHug_h.svg +3 -0
  270. package/dist/web/assets/kotlin-BdnUsdx6.js +1 -0
  271. package/dist/web/assets/kusto-BvAqAH-y.js +1 -0
  272. package/dist/web/assets/laserwave-DUszq2jm.js +1 -0
  273. package/dist/web/assets/latex-BdAV_C_H.js +1 -0
  274. package/dist/web/assets/layout-Ujef10t5.js +1 -0
  275. package/dist/web/assets/lean-Bc6EcWN3.js +1 -0
  276. package/dist/web/assets/less-B1dDrJ26.js +1 -0
  277. package/dist/web/assets/light-plus-B7mTdjB0.js +1 -0
  278. package/dist/web/assets/linear-CLfbwX-c.js +1 -0
  279. package/dist/web/assets/liquid-DYVedYrR.js +1 -0
  280. package/dist/web/assets/llvm-BtvRca6l.js +1 -0
  281. package/dist/web/assets/log-2UxHyX5q.js +1 -0
  282. package/dist/web/assets/logo-BtOb2qkB.js +1 -0
  283. package/dist/web/assets/lua-BbnMAYS6.js +1 -0
  284. package/dist/web/assets/luau-CXu1NL6O.js +1 -0
  285. package/dist/web/assets/lucidquery-DRFbix82.svg +3 -0
  286. package/dist/web/assets/make-CHLpvVh8.js +1 -0
  287. package/dist/web/assets/markdown-Cvjx9yec.js +1 -0
  288. package/dist/web/assets/marko-CPi9NSCl.js +1 -0
  289. package/dist/web/assets/material-theme-D5KoaKCx.js +1 -0
  290. package/dist/web/assets/material-theme-darker-BfHTSMKl.js +1 -0
  291. package/dist/web/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  292. package/dist/web/assets/material-theme-ocean-CyktbL80.js +1 -0
  293. package/dist/web/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  294. package/dist/web/assets/matlab-D7o27uSR.js +1 -0
  295. package/dist/web/assets/mdc-DUICxH0z.js +1 -0
  296. package/dist/web/assets/mdx-Cmh6b_Ma.js +1 -0
  297. package/dist/web/assets/mermaid-DKYwYmdq.js +1 -0
  298. package/dist/web/assets/mermaid.core-BAK_ixpL.js +191 -0
  299. package/dist/web/assets/min-D8VL4G-w.js +1 -0
  300. package/dist/web/assets/min-dark-CafNBF8u.js +1 -0
  301. package/dist/web/assets/min-light-CTRr51gU.js +1 -0
  302. package/dist/web/assets/mindmap-definition-VGOIOE7T-ChCIxiAQ.js +68 -0
  303. package/dist/web/assets/mipsasm-CKIfxQSi.js +1 -0
  304. package/dist/web/assets/mojo-1DNp92w6.js +1 -0
  305. package/dist/web/assets/monokai-D4h5O-jR.js +1 -0
  306. package/dist/web/assets/moonshotai-BeF2wtIV.svg +3 -0
  307. package/dist/web/assets/move-Bu9oaDYs.js +1 -0
  308. package/dist/web/assets/narrat-DRg8JJMk.js +1 -0
  309. package/dist/web/assets/nextflow-BrzmwbiE.js +1 -0
  310. package/dist/web/assets/nginx-DknmC5AR.js +1 -0
  311. package/dist/web/assets/night-owl-C39BiMTA.js +1 -0
  312. package/dist/web/assets/nim-CVrawwO9.js +1 -0
  313. package/dist/web/assets/nix-c8nO5XWb.js +1 -0
  314. package/dist/web/assets/nord-Ddv68eIx.js +1 -0
  315. package/dist/web/assets/nushell-C-sUppwS.js +1 -0
  316. package/dist/web/assets/objective-c-DXmwc3jG.js +1 -0
  317. package/dist/web/assets/objective-cpp-CLxacb5B.js +1 -0
  318. package/dist/web/assets/ocaml-C0hk2d4L.js +1 -0
  319. package/dist/web/assets/ollama-cloud-BIdeu-re.svg +7 -0
  320. package/dist/web/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  321. package/dist/web/assets/one-light-PoHY5YXO.js +1 -0
  322. package/dist/web/assets/openscad-C4EeE6gA.js +1 -0
  323. package/dist/web/assets/ordinal-Cboi1Yqb.js +1 -0
  324. package/dist/web/assets/pascal-D93ZcfNL.js +1 -0
  325. package/dist/web/assets/perl-C0TMdlhV.js +1 -0
  326. package/dist/web/assets/php-CDn_0X-4.js +1 -0
  327. package/dist/web/assets/pieDiagram-ADFJNKIX-jlQ1USe2.js +30 -0
  328. package/dist/web/assets/pierre-dark-BXuwtOqb.js +1 -0
  329. package/dist/web/assets/pierre-light-dckrK0oj.js +1 -0
  330. package/dist/web/assets/pkl-u5AG7uiY.js +1 -0
  331. package/dist/web/assets/plastic-3e1v2bzS.js +1 -0
  332. package/dist/web/assets/plsql-ChMvpjG-.js +1 -0
  333. package/dist/web/assets/po-BTJTHyun.js +1 -0
  334. package/dist/web/assets/poimandres-CS3Unz2-.js +1 -0
  335. package/dist/web/assets/polar-C0HS_06l.js +1 -0
  336. package/dist/web/assets/postcss-CXtECtnM.js +1 -0
  337. package/dist/web/assets/powerquery-CEu0bR-o.js +1 -0
  338. package/dist/web/assets/powershell-Dpen1YoG.js +1 -0
  339. package/dist/web/assets/prisma-Dd19v3D-.js +1 -0
  340. package/dist/web/assets/prolog-CbFg5uaA.js +1 -0
  341. package/dist/web/assets/proto-DyJlTyXw.js +1 -0
  342. package/dist/web/assets/pug-CGlum2m_.js +1 -0
  343. package/dist/web/assets/puppet-BMWR74SV.js +1 -0
  344. package/dist/web/assets/purescript-CklMAg4u.js +1 -0
  345. package/dist/web/assets/python-B6aJPvgy.js +1 -0
  346. package/dist/web/assets/qml-3beO22l8.js +1 -0
  347. package/dist/web/assets/qmldir-C8lEn-DE.js +1 -0
  348. package/dist/web/assets/qss-IeuSbFQv.js +1 -0
  349. package/dist/web/assets/quadrantDiagram-AYHSOK5B-Dj2wmV1N.js +7 -0
  350. package/dist/web/assets/r-DiinP2Uv.js +1 -0
  351. package/dist/web/assets/racket-BqYA7rlc.js +1 -0
  352. package/dist/web/assets/raku-DXvB9xmW.js +1 -0
  353. package/dist/web/assets/razor-CE9lU5zL.js +1 -0
  354. package/dist/web/assets/red-bN70gL4F.js +1 -0
  355. package/dist/web/assets/reg-C-SQnVFl.js +1 -0
  356. package/dist/web/assets/regexp-CDVJQ6XC.js +1 -0
  357. package/dist/web/assets/rel-C3B-1QV4.js +1 -0
  358. package/dist/web/assets/requirementDiagram-UZGBJVZJ-Umq3-C8j.js +64 -0
  359. package/dist/web/assets/riscv-BM1_JUlF.js +1 -0
  360. package/dist/web/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
  361. package/dist/web/assets/rose-pine-moon-D4_iv3hh.js +1 -0
  362. package/dist/web/assets/rose-pine-qdsjHGoJ.js +1 -0
  363. package/dist/web/assets/rosmsg-BJDFO7_C.js +1 -0
  364. package/dist/web/assets/rst-B0xPkSld.js +1 -0
  365. package/dist/web/assets/ruby-BvKwtOVI.js +1 -0
  366. package/dist/web/assets/rust-B1yitclQ.js +1 -0
  367. package/dist/web/assets/sankeyDiagram-TZEHDZUN-Ce6gdeOT.js +10 -0
  368. package/dist/web/assets/sas-cz2c8ADy.js +1 -0
  369. package/dist/web/assets/sass-Cj5Yp3dK.js +1 -0
  370. package/dist/web/assets/scala-C151Ov-r.js +1 -0
  371. package/dist/web/assets/scheme-C98Dy4si.js +1 -0
  372. package/dist/web/assets/scss-OYdSNvt2.js +1 -0
  373. package/dist/web/assets/sdbl-DVxCFoDh.js +1 -0
  374. package/dist/web/assets/sequenceDiagram-WL72ISMW-DJGrGFRW.js +145 -0
  375. package/dist/web/assets/shaderlab-Dg9Lc6iA.js +1 -0
  376. package/dist/web/assets/shellscript-Yzrsuije.js +1 -0
  377. package/dist/web/assets/shellsession-BADoaaVG.js +1 -0
  378. package/dist/web/assets/slack-dark-BthQWCQV.js +1 -0
  379. package/dist/web/assets/slack-ochin-DqwNpetd.js +1 -0
  380. package/dist/web/assets/smalltalk-BERRCDM3.js +1 -0
  381. package/dist/web/assets/snazzy-light-Bw305WKR.js +1 -0
  382. package/dist/web/assets/solarized-dark-DXbdFlpD.js +1 -0
  383. package/dist/web/assets/solarized-light-L9t79GZl.js +1 -0
  384. package/dist/web/assets/solidity-rGO070M0.js +1 -0
  385. package/dist/web/assets/soy-Brmx7dQM.js +1 -0
  386. package/dist/web/assets/sparql-rVzFXLq3.js +1 -0
  387. package/dist/web/assets/splunk-BtCnVYZw.js +1 -0
  388. package/dist/web/assets/sql-BLtJtn59.js +1 -0
  389. package/dist/web/assets/ssh-config-_ykCGR6B.js +1 -0
  390. package/dist/web/assets/stata-BH5u7GGu.js +1 -0
  391. package/dist/web/assets/stateDiagram-FKZM4ZOC-D-zz3TRT.js +1 -0
  392. package/dist/web/assets/stateDiagram-v2-4FDKWEC3-CARvDj2s.js +1 -0
  393. package/dist/web/assets/stylus-BEDo0Tqx.js +1 -0
  394. package/dist/web/assets/svelte-3Dk4HxPD.js +1 -0
  395. package/dist/web/assets/swift-Dg5xB15N.js +1 -0
  396. package/dist/web/assets/synthwave-84-CbfX1IO0.js +1 -0
  397. package/dist/web/assets/system-verilog-CnnmHF94.js +1 -0
  398. package/dist/web/assets/systemd-4A_iFExJ.js +1 -0
  399. package/dist/web/assets/talonscript-CkByrt1z.js +1 -0
  400. package/dist/web/assets/tasl-QIJgUcNo.js +1 -0
  401. package/dist/web/assets/tcl-dwOrl1Do.js +1 -0
  402. package/dist/web/assets/templ-W15q3VgB.js +1 -0
  403. package/dist/web/assets/terraform-BETggiCN.js +1 -0
  404. package/dist/web/assets/tex-CxkMU7Pf.js +1 -0
  405. package/dist/web/assets/timeline-definition-IT6M3QCI-C8M7N84Y.js +61 -0
  406. package/dist/web/assets/tokyo-night-hegEt444.js +1 -0
  407. package/dist/web/assets/toml-vGWfd6FD.js +1 -0
  408. package/dist/web/assets/treemap-KMMF4GRG-B_8-FlJu.js +128 -0
  409. package/dist/web/assets/ts-tags-zn1MmPIZ.js +1 -0
  410. package/dist/web/assets/tsv-B_m7g4N7.js +1 -0
  411. package/dist/web/assets/tsx-COt5Ahok.js +1 -0
  412. package/dist/web/assets/turtle-BsS91CYL.js +1 -0
  413. package/dist/web/assets/twig-CO9l9SDP.js +1 -0
  414. package/dist/web/assets/typescript-BPQ3VLAy.js +1 -0
  415. package/dist/web/assets/typespec-BGHnOYBU.js +1 -0
  416. package/dist/web/assets/typst-DHCkPAjA.js +1 -0
  417. package/dist/web/assets/v-BcVCzyr7.js +1 -0
  418. package/dist/web/assets/vala-CsfeWuGM.js +1 -0
  419. package/dist/web/assets/vb-D17OF-Vu.js +1 -0
  420. package/dist/web/assets/venice-CeIHfrIB.svg +4 -0
  421. package/dist/web/assets/verilog-BQ8w6xss.js +1 -0
  422. package/dist/web/assets/vesper-DU1UobuO.js +1 -0
  423. package/dist/web/assets/vhdl-CeAyd5Ju.js +1 -0
  424. package/dist/web/assets/viml-CJc9bBzg.js +1 -0
  425. package/dist/web/assets/vitesse-black-Bkuqu6BP.js +1 -0
  426. package/dist/web/assets/vitesse-dark-D0r3Knsf.js +1 -0
  427. package/dist/web/assets/vitesse-light-CVO1_9PV.js +1 -0
  428. package/dist/web/assets/vue-DnHKYNfI.js +1 -0
  429. package/dist/web/assets/vue-html-CChd_i61.js +1 -0
  430. package/dist/web/assets/vue-vine-8moa0y9V.js +1 -0
  431. package/dist/web/assets/vyper-CDx5xZoG.js +1 -0
  432. package/dist/web/assets/wasm-CG6Dc4jp.js +1 -0
  433. package/dist/web/assets/wasm-MzD3tlZU.js +1 -0
  434. package/dist/web/assets/wenyan-BV7otONQ.js +1 -0
  435. package/dist/web/assets/wgsl-Dx-B1_4e.js +1 -0
  436. package/dist/web/assets/wikitext-BhOHFoWU.js +1 -0
  437. package/dist/web/assets/wit-5i3qLPDT.js +1 -0
  438. package/dist/web/assets/wolfram-lXgVvXCa.js +1 -0
  439. package/dist/web/assets/xml-sdJ4AIDG.js +1 -0
  440. package/dist/web/assets/xsl-CtQFsRM5.js +1 -0
  441. package/dist/web/assets/xychartDiagram-PRI3JC2R-DDPGTO3C.js +7 -0
  442. package/dist/web/assets/yaml-Buea-lGh.js +1 -0
  443. package/dist/web/assets/zenscript-DVFEvuxE.js +1 -0
  444. package/dist/web/assets/zig-VOosw3JB.js +1 -0
  445. package/dist/web/index.html +20 -0
  446. package/package.json +99 -0
package/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # Shella
2
+
3
+ Self-hosted AI coding agents. Access from your phone.
4
+
5
+ Run multiple AI agents in parallel, persist sessions across devices, and manage everything from a touch-friendly mobile interface.
6
+
7
+ ## Install
8
+
9
+ ### npx (Developers)
10
+
11
+ ```bash
12
+ npx @bytespell/shella
13
+ ```
14
+
15
+ Opens at `http://localhost:3067`. Access from your phone using the LAN IP shown.
16
+
17
+ ### Docker (Homelab)
18
+
19
+ ```yaml
20
+ # docker-compose.yml
21
+ services:
22
+ shella:
23
+ image: ghcr.io/bytespell/shella
24
+ ports:
25
+ - '3067:3067'
26
+ volumes:
27
+ - /path/to/projects:/project
28
+ - shella-data:/root/.config/shella
29
+ restart: unless-stopped
30
+
31
+ volumes:
32
+ shella-data:
33
+ ```
34
+
35
+ ```bash
36
+ docker compose up -d
37
+ # Access at http://<server-ip>:3067
38
+ ```
39
+
40
+ ## Features
41
+
42
+ - **Parallel agents** - Run multiple agents on different tasks simultaneously
43
+ - **Session persistence** - Sessions survive restarts, pick up from any device
44
+ - **Cross-device sync** - Same windows, same state, real-time sync
45
+ - **Mobile-first** - Touch-optimized for iOS Safari
46
+
47
+ ## CLI Options
48
+
49
+ ```bash
50
+ shella # Start with defaults
51
+ shella --port 3000 # Custom web port
52
+ shella --opencode-port 5000 # Custom OpenCode port
53
+ shella --no-open # Don't open browser
54
+ shella --help # Show help
55
+ ```
56
+
57
+ ## Development
58
+
59
+ ```bash
60
+ # Install dependencies
61
+ npm install
62
+
63
+ # Start dev servers (Vite + Express + OpenCode)
64
+ npm run start:dev
65
+
66
+ # Build for production
67
+ npm run build
68
+
69
+ # Test production build locally
70
+ node bin/cli.js --no-open
71
+ ```
72
+
73
+ ## Requirements
74
+
75
+ - Node.js 20.19+ or 22.12+
76
+
77
+ ## License
78
+
79
+ MIT
package/bin/cli.js ADDED
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ import { createOpencodeServer } from '@opencode-ai/sdk';
4
+ import { networkInterfaces } from 'os';
5
+ import { spawn } from 'child_process';
6
+ import { createConnection } from 'net';
7
+ import path from 'path';
8
+ import { fileURLToPath } from 'url';
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
+ const VERSION = '0.1.0';
11
+ /**
12
+ * Check if a port is available
13
+ */
14
+ async function isPortAvailable(port) {
15
+ return new Promise((resolve) => {
16
+ const socket = createConnection({ port, host: '127.0.0.1' });
17
+ socket.setTimeout(1000);
18
+ socket.on('connect', () => {
19
+ socket.destroy();
20
+ resolve(false); // Port is in use
21
+ });
22
+ socket.on('timeout', () => {
23
+ socket.destroy();
24
+ resolve(true); // Port is available
25
+ });
26
+ socket.on('error', () => {
27
+ resolve(true); // Port is available (connection refused)
28
+ });
29
+ });
30
+ }
31
+ /**
32
+ * Get the LAN IP address for mobile access
33
+ */
34
+ function getLanIp() {
35
+ const interfaces = networkInterfaces();
36
+ for (const [name, addrs] of Object.entries(interfaces)) {
37
+ // Skip loopback, docker, veth, bridge interfaces
38
+ if (/^(lo|docker|veth|br-|virbr)/.test(name))
39
+ continue;
40
+ for (const addr of addrs || []) {
41
+ if (addr.family === 'IPv4' && !addr.internal) {
42
+ return addr.address;
43
+ }
44
+ }
45
+ }
46
+ return 'localhost';
47
+ }
48
+ /**
49
+ * Print a nice boxed message with the access URL
50
+ */
51
+ function printAccessBox(lanIp, port) {
52
+ const url = `http://${lanIp}:${port}`;
53
+ const urlLine = ` ${url}`;
54
+ const width = Math.max(44, urlLine.length + 4);
55
+ const border = '-'.repeat(width);
56
+ const pad = (s) => s + ' '.repeat(width - s.length);
57
+ console.log(`
58
+ +${border}+
59
+ |${pad('')}|
60
+ |${pad(' Access from any device:')}|
61
+ |${pad('')}|
62
+ |${pad(urlLine)}|
63
+ |${pad('')}|
64
+ +${border}+
65
+ `);
66
+ }
67
+ let opencodeServer = null;
68
+ let expressProcess = null;
69
+ async function startCommand(options) {
70
+ const port = parseInt(options.port);
71
+ const opencodePort = parseInt(options.opencodePort);
72
+ console.log(`Shella v${VERSION}\n`);
73
+ // Check if ports are available
74
+ const webPortAvailable = await isPortAvailable(port);
75
+ const ocPortAvailable = await isPortAvailable(opencodePort);
76
+ if (!webPortAvailable) {
77
+ console.error(`Error: Port ${port} is already in use.`);
78
+ console.error(`\nTry one of these:`);
79
+ console.error(` - Stop the process using port ${port}`);
80
+ console.error(` - Use a different port: shella --port 3070`);
81
+ process.exit(1);
82
+ }
83
+ if (!ocPortAvailable) {
84
+ console.error(`Error: Port ${opencodePort} is already in use (OpenCode port).`);
85
+ console.error(`\nThis usually means OpenCode is already running.`);
86
+ console.error(`\nTry one of these:`);
87
+ console.error(` - Kill the existing OpenCode: pkill -f "opencode serve"`);
88
+ console.error(` - Use a different port: shella --opencode-port 4097`);
89
+ process.exit(1);
90
+ }
91
+ // Start OpenCode server using the bundled binary
92
+ console.log('Starting OpenCode...');
93
+ try {
94
+ opencodeServer = await createOpencodeServer({
95
+ port: opencodePort,
96
+ timeout: 30000,
97
+ });
98
+ console.log(` OpenCode ready (port ${opencodePort})`);
99
+ }
100
+ catch (err) {
101
+ const message = err instanceof Error ? err.message : String(err);
102
+ console.error(`\nFailed to start OpenCode: ${message}`);
103
+ if (message.includes('port')) {
104
+ console.error(`\nThe port ${opencodePort} may be in use. Try:`);
105
+ console.error(` shella --opencode-port 4097`);
106
+ }
107
+ process.exit(1);
108
+ }
109
+ // Start Express server in production mode
110
+ console.log('Starting Shella server...');
111
+ const serverPath = path.join(__dirname, '..', 'dist', 'server', 'index.js');
112
+ expressProcess = spawn('node', [serverPath], {
113
+ env: {
114
+ ...process.env,
115
+ NODE_ENV: 'production',
116
+ PORT: String(port),
117
+ },
118
+ stdio: ['ignore', 'pipe', 'pipe'],
119
+ });
120
+ // Wait for server to be ready
121
+ await new Promise((resolve, reject) => {
122
+ const timeout = setTimeout(() => {
123
+ reject(new Error('Server startup timeout (10s). Check logs for errors.'));
124
+ }, 10000);
125
+ expressProcess.stdout?.on('data', (data) => {
126
+ const output = data.toString();
127
+ if (output.includes('Running on')) {
128
+ clearTimeout(timeout);
129
+ resolve();
130
+ }
131
+ // Forward output but strip the prefix since we add our own
132
+ process.stdout.write(output.replace(/\[shella-server\] /g, ' '));
133
+ });
134
+ expressProcess.stderr?.on('data', (data) => {
135
+ process.stderr.write(data);
136
+ });
137
+ expressProcess.on('error', (err) => {
138
+ clearTimeout(timeout);
139
+ reject(new Error(`Failed to spawn server: ${err.message}`));
140
+ });
141
+ expressProcess.on('exit', (code) => {
142
+ if (code !== 0 && code !== null) {
143
+ clearTimeout(timeout);
144
+ reject(new Error(`Server exited with code ${code}`));
145
+ }
146
+ });
147
+ });
148
+ console.log(` Shella ready (port ${port})`);
149
+ // Print access box
150
+ const lanIp = getLanIp();
151
+ printAccessBox(lanIp, port);
152
+ console.log('Press Ctrl+C to stop\n');
153
+ // Open browser if requested
154
+ if (options.open) {
155
+ const url = `http://localhost:${port}`;
156
+ const openCommand = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
157
+ spawn(openCommand, [url], { stdio: 'ignore', detached: true }).unref();
158
+ }
159
+ }
160
+ /**
161
+ * Graceful shutdown handler
162
+ */
163
+ function shutdown() {
164
+ console.log('\nShutting down...');
165
+ if (expressProcess) {
166
+ expressProcess.kill('SIGTERM');
167
+ expressProcess = null;
168
+ }
169
+ if (opencodeServer) {
170
+ opencodeServer.close();
171
+ opencodeServer = null;
172
+ }
173
+ console.log('Goodbye!');
174
+ process.exit(0);
175
+ }
176
+ // Handle shutdown signals
177
+ process.on('SIGINT', shutdown);
178
+ process.on('SIGTERM', shutdown);
179
+ // CLI definition
180
+ program
181
+ .name('shella')
182
+ .description('Self-hosted AI coding agents. Access from your phone.')
183
+ .version(VERSION);
184
+ program
185
+ .command('start', { isDefault: true })
186
+ .description('Start Shella')
187
+ .option('-p, --port <port>', 'Web server port', '3067')
188
+ .option('--opencode-port <port>', 'OpenCode server port', '4096')
189
+ .option('--no-open', "Don't open browser automatically")
190
+ .action(startCommand);
191
+ program.parse();
@@ -0,0 +1,2 @@
1
+ declare const CONFIG_DIR: string;
2
+ export { CONFIG_DIR };
@@ -0,0 +1,94 @@
1
+ import express from 'express';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import os from 'os';
5
+ import { fileURLToPath } from 'url';
6
+ import { corsMiddleware } from './middleware/cors.js';
7
+ import windowsRoutes from './routes/windows.js';
8
+ import modelStateRoutes from './routes/model-state.js';
9
+ import logsRoutes from './routes/logs.js';
10
+ import proxyRoutes from './routes/proxy.js';
11
+ import { getDatabase } from './services/database.js';
12
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
+ // Runtime mode detection
14
+ const isProd = process.env.NODE_ENV === 'production';
15
+ // Port: 3067 in prod, 3068 in dev (Vite uses 3067 in dev)
16
+ const PORT = process.env.PORT || (isProd ? 3067 : 3068);
17
+ // Config directory: ~/.config/shella/
18
+ const CONFIG_DIR = path.join(os.homedir(), '.config', 'shella');
19
+ // Log file: ~/.config/shella/shella.log in prod, ./dev.log in dev
20
+ const LOG_FILE = isProd
21
+ ? path.join(CONFIG_DIR, 'shella.log')
22
+ : path.resolve(process.cwd(), 'dev.log');
23
+ /**
24
+ * Ensure config directory exists
25
+ */
26
+ function ensureConfigDir() {
27
+ if (!fs.existsSync(CONFIG_DIR)) {
28
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
29
+ console.log(`[shella-server] Created config directory: ${CONFIG_DIR}`);
30
+ }
31
+ }
32
+ const app = express();
33
+ // CORS - allow all origins for mobile debugging
34
+ app.use(corsMiddleware);
35
+ // JSON body parsing
36
+ app.use(express.json());
37
+ // Health check
38
+ app.get('/health', (_req, res) => res.json({ status: 'ok' }));
39
+ // Mount API routes
40
+ app.use('/__shella', windowsRoutes);
41
+ app.use('/__model-state', modelStateRoutes);
42
+ app.use('/__logs', logsRoutes);
43
+ app.use('/api', proxyRoutes);
44
+ // Production: serve static files from dist/web/
45
+ if (isProd) {
46
+ const webDir = path.join(__dirname, '..', 'web');
47
+ if (fs.existsSync(webDir)) {
48
+ console.log(`[shella-server] Serving static files from ${webDir}`);
49
+ app.use(express.static(webDir));
50
+ // SPA fallback: serve index.html for non-API routes
51
+ // Express 5 requires named wildcards, use {*path} syntax
52
+ app.get('{*path}', (req, res, next) => {
53
+ // Skip API routes
54
+ if (req.path.startsWith('/api') ||
55
+ req.path.startsWith('/__shella') ||
56
+ req.path.startsWith('/__model-state') ||
57
+ req.path.startsWith('/__logs') ||
58
+ req.path.startsWith('/health')) {
59
+ return next();
60
+ }
61
+ res.sendFile(path.join(webDir, 'index.html'));
62
+ });
63
+ }
64
+ else {
65
+ console.warn(`[shella-server] Warning: ${webDir} not found. Static serving disabled.`);
66
+ }
67
+ }
68
+ /**
69
+ * Start the server
70
+ */
71
+ async function start() {
72
+ // Ensure config directory exists in prod
73
+ if (isProd) {
74
+ ensureConfigDir();
75
+ }
76
+ // Initialize database before starting server
77
+ await getDatabase();
78
+ // Clear/create log file on server start
79
+ const logDir = path.dirname(LOG_FILE);
80
+ if (!fs.existsSync(logDir)) {
81
+ fs.mkdirSync(logDir, { recursive: true });
82
+ }
83
+ fs.writeFileSync(LOG_FILE, `--- Shella server started ${new Date().toISOString()} ---\n`);
84
+ app.listen(PORT, () => {
85
+ console.log(`[shella-server] Running on http://localhost:${PORT}`);
86
+ console.log(`[shella-server] Mode: ${isProd ? 'production' : 'development'}`);
87
+ console.log(`[shella-server] Logging to ${LOG_FILE}`);
88
+ });
89
+ }
90
+ start().catch((err) => {
91
+ console.error('[shella-server] Failed to start:', err);
92
+ process.exit(1);
93
+ });
94
+ export { CONFIG_DIR };
@@ -0,0 +1,6 @@
1
+ import cors from 'cors';
2
+ export declare const corsMiddleware: (req: cors.CorsRequest, res: {
3
+ statusCode?: number | undefined;
4
+ setHeader(key: string, value: string): any;
5
+ end(): any;
6
+ }, next: (err?: any) => any) => void;
@@ -0,0 +1,8 @@
1
+ import cors from 'cors';
2
+ // Allow all origins for mobile debugging over LAN
3
+ export const corsMiddleware = cors({
4
+ origin: true,
5
+ credentials: true,
6
+ methods: ['GET', 'POST', 'PATCH', 'DELETE', 'OPTIONS'],
7
+ allowedHeaders: ['Content-Type', 'X-Client-Id', 'Accept'],
8
+ });
@@ -0,0 +1,2 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
@@ -0,0 +1,29 @@
1
+ import { Router } from 'express';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ const LOG_FILE = path.resolve(process.cwd(), 'dev.log');
5
+ const router = Router();
6
+ // POST /__logs - receive browser console logs
7
+ router.post('/', (req, res) => {
8
+ try {
9
+ const { level, args } = req.body;
10
+ const prefix = level === 'error' ? '🔴' : level === 'warn' ? '🟡' : '🌐';
11
+ const timestamp = new Date().toISOString().slice(11, 23); // HH:MM:SS.mmm
12
+ const message = args
13
+ .map((a) => (typeof a === 'object' ? JSON.stringify(a) : String(a)))
14
+ .join(' ');
15
+ const line = `${timestamp} ${prefix} ${message}`;
16
+ // Log to terminal
17
+ console.log(line);
18
+ // Append to file
19
+ fs.appendFileSync(LOG_FILE, line + '\n');
20
+ res.sendStatus(200);
21
+ }
22
+ catch {
23
+ const fallback = `${new Date().toISOString().slice(11, 23)} 🌐 [parse error] ${JSON.stringify(req.body)}`;
24
+ console.log(fallback);
25
+ fs.appendFileSync(LOG_FILE, fallback + '\n');
26
+ res.sendStatus(200);
27
+ }
28
+ });
29
+ export default router;
@@ -0,0 +1,2 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
@@ -0,0 +1,81 @@
1
+ import { Router } from 'express';
2
+ import path from 'path';
3
+ import fs from 'fs';
4
+ import { STATE_DIR } from '../services/database.js';
5
+ const MODEL_STATE_FILE = path.join(STATE_DIR, 'model.json');
6
+ function ensureStateDir() {
7
+ if (!fs.existsSync(STATE_DIR)) {
8
+ fs.mkdirSync(STATE_DIR, { recursive: true });
9
+ }
10
+ }
11
+ function readModelState() {
12
+ try {
13
+ if (!fs.existsSync(MODEL_STATE_FILE)) {
14
+ return { recent: [], favorite: [] };
15
+ }
16
+ const data = fs.readFileSync(MODEL_STATE_FILE, 'utf-8');
17
+ const parsed = JSON.parse(data);
18
+ return {
19
+ recent: Array.isArray(parsed.recent) ? parsed.recent : [],
20
+ favorite: Array.isArray(parsed.favorite) ? parsed.favorite : [],
21
+ variant: typeof parsed.variant === 'object' && parsed.variant !== null ? parsed.variant : {},
22
+ };
23
+ }
24
+ catch (err) {
25
+ console.error('[model-state] Failed to read model state:', err);
26
+ return { recent: [], favorite: [] };
27
+ }
28
+ }
29
+ function writeModelState(state) {
30
+ try {
31
+ ensureStateDir();
32
+ fs.writeFileSync(MODEL_STATE_FILE, JSON.stringify(state, null, 2), 'utf-8');
33
+ }
34
+ catch (err) {
35
+ console.error('[model-state] Failed to write model state:', err);
36
+ throw err;
37
+ }
38
+ }
39
+ function toggleFavorite(model) {
40
+ const state = readModelState();
41
+ const exists = state.favorite.some((f) => f.providerID === model.providerID && f.modelID === model.modelID);
42
+ if (exists) {
43
+ // Remove from favorites
44
+ state.favorite = state.favorite.filter((f) => f.providerID !== model.providerID || f.modelID !== model.modelID);
45
+ }
46
+ else {
47
+ // Add to favorites
48
+ state.favorite = [model, ...state.favorite];
49
+ }
50
+ writeModelState(state);
51
+ return state;
52
+ }
53
+ const router = Router();
54
+ // GET /__model-state - read model state
55
+ router.get('/', (_req, res) => {
56
+ try {
57
+ const state = readModelState();
58
+ res.json({ recent: state.recent, favorite: state.favorite });
59
+ }
60
+ catch (err) {
61
+ console.error('[model-state] Failed to get model state:', err);
62
+ res.status(500).json({ error: 'Failed to read model state' });
63
+ }
64
+ });
65
+ // POST /__model-state/favorite - toggle favorite
66
+ router.post('/favorite', (req, res) => {
67
+ try {
68
+ const model = req.body;
69
+ if (!model.providerID || !model.modelID) {
70
+ res.status(400).json({ error: 'providerID and modelID required' });
71
+ return;
72
+ }
73
+ const state = toggleFavorite(model);
74
+ res.json({ recent: state.recent, favorite: state.favorite });
75
+ }
76
+ catch (err) {
77
+ console.error('[model-state] Failed to toggle favorite:', err);
78
+ res.status(500).json({ error: 'Failed to update model state' });
79
+ }
80
+ });
81
+ export default router;
@@ -0,0 +1,2 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
@@ -0,0 +1,122 @@
1
+ import { Router } from 'express';
2
+ const OPENCODE_URL = process.env.OPENCODE_URL || 'http://localhost:4096';
3
+ const router = Router();
4
+ // Routes that should return 202 immediately without waiting for OpenCode response.
5
+ // These are "fire-and-forget" - the browser doesn't need the response body,
6
+ // and waiting would cause the UI to hang while OpenCode processes the request.
7
+ const FIRE_AND_FORGET_PATTERNS = [
8
+ { method: 'POST', pattern: /^\/session\/[^/]+\/shell$/ },
9
+ { method: 'POST', pattern: /^\/session\/[^/]+\/command$/ },
10
+ { method: 'POST', pattern: /^\/session\/[^/]+\/abort$/ },
11
+ { method: 'POST', pattern: /^\/session\/[^/]+\/revert$/ },
12
+ { method: 'POST', pattern: /^\/session\/[^/]+\/unrevert$/ },
13
+ { method: 'POST', pattern: /^\/session\/[^/]+\/summarize$/ },
14
+ // Permission endpoints (old and new SDK versions)
15
+ { method: 'POST', pattern: /^\/session\/[^/]+\/permissions\/[^/]+$/ },
16
+ { method: 'POST', pattern: /^\/permission\/[^/]+\/reply$/ },
17
+ ];
18
+ const isFireAndForget = (method, path) => {
19
+ // Strip query string for matching
20
+ const pathWithoutQuery = path.split('?')[0];
21
+ return FIRE_AND_FORGET_PATTERNS.some((route) => route.method === method && route.pattern.test(pathWithoutQuery));
22
+ };
23
+ const buildTargetUrl = (req) => {
24
+ const url = new URL(req.url, OPENCODE_URL);
25
+ return url;
26
+ };
27
+ const buildHeaders = (req, includeBody) => {
28
+ const headers = {};
29
+ if (typeof req.headers['accept'] === 'string') {
30
+ headers['accept'] = req.headers['accept'];
31
+ }
32
+ if (includeBody) {
33
+ headers['content-type'] = 'application/json';
34
+ }
35
+ return headers;
36
+ };
37
+ const hasBody = (method) => {
38
+ return ['POST', 'PUT', 'PATCH'].includes(method);
39
+ };
40
+ // Fire-and-forget: send request to OpenCode but return 202 immediately
41
+ const fireAndForget = (req, label) => {
42
+ const url = buildTargetUrl(req);
43
+ const headers = buildHeaders(req, hasBody(req.method));
44
+ fetch(url, {
45
+ method: req.method,
46
+ headers,
47
+ body: hasBody(req.method) ? JSON.stringify(req.body ?? {}) : undefined,
48
+ }).catch((error) => {
49
+ console.error(`[proxy] ${label} fire-and-forget error:`, error);
50
+ });
51
+ };
52
+ // Stream proxy: forward request and stream response back
53
+ const streamProxy = async (req, res) => {
54
+ const url = buildTargetUrl(req);
55
+ const headers = buildHeaders(req, hasBody(req.method));
56
+ try {
57
+ const response = await fetch(url, {
58
+ method: req.method,
59
+ headers,
60
+ body: hasBody(req.method) ? JSON.stringify(req.body ?? {}) : undefined,
61
+ });
62
+ // Forward status
63
+ res.status(response.status);
64
+ // Forward headers (except content-length which may be wrong after buffering)
65
+ response.headers.forEach((value, key) => {
66
+ if (key.toLowerCase() !== 'content-length') {
67
+ res.setHeader(key, value);
68
+ }
69
+ });
70
+ // Handle 204 No Content
71
+ if (response.status === 204 || !response.body) {
72
+ res.end();
73
+ return;
74
+ }
75
+ // Check if this is SSE
76
+ const contentType = response.headers.get('content-type') ?? '';
77
+ const isSSE = contentType.includes('text/event-stream');
78
+ if (isSSE) {
79
+ // SSE: stream chunks as they arrive
80
+ res.setHeader('Cache-Control', 'no-cache');
81
+ res.setHeader('Connection', 'keep-alive');
82
+ const reader = response.body.getReader();
83
+ try {
84
+ while (true) {
85
+ const { done, value } = await reader.read();
86
+ if (done)
87
+ break;
88
+ res.write(value);
89
+ }
90
+ }
91
+ finally {
92
+ reader.releaseLock();
93
+ }
94
+ res.end();
95
+ }
96
+ else {
97
+ // Non-SSE: buffer and send
98
+ const buffer = Buffer.from(await response.arrayBuffer());
99
+ res.send(buffer);
100
+ }
101
+ }
102
+ catch (error) {
103
+ console.error(`[proxy] ${req.method} ${req.url} error:`, error);
104
+ res.status(502).json({ error: 'Failed to proxy request to OpenCode' });
105
+ }
106
+ };
107
+ // Log all proxied requests
108
+ router.use((req, _res, next) => {
109
+ console.log(`[proxy] ${req.method} ${req.url}`);
110
+ next();
111
+ });
112
+ // Main proxy handler
113
+ router.use('/', async (req, res) => {
114
+ if (isFireAndForget(req.method, req.url)) {
115
+ const label = req.url.split('?')[0];
116
+ fireAndForget(req, label);
117
+ res.status(202).end();
118
+ return;
119
+ }
120
+ await streamProxy(req, res);
121
+ });
122
+ export default router;
@@ -0,0 +1,2 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;