miko-code 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 (379) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +179 -0
  3. package/bin/miko +10 -0
  4. package/dist/client/antigravity.webp +0 -0
  5. package/dist/client/assets/abap-BdImnpbu.js +1 -0
  6. package/dist/client/assets/actionscript-3-CoDkCxhg.js +1 -0
  7. package/dist/client/assets/ada-bCR0ucgS.js +1 -0
  8. package/dist/client/assets/andromeeda-C4gqWexZ.js +1 -0
  9. package/dist/client/assets/angular-html-CU67Zn6k.js +1 -0
  10. package/dist/client/assets/angular-ts-BwZT4LLn.js +1 -0
  11. package/dist/client/assets/apache-Pmp26Uib.js +1 -0
  12. package/dist/client/assets/apex-D8_7TLub.js +1 -0
  13. package/dist/client/assets/apl-dKokRX4l.js +1 -0
  14. package/dist/client/assets/applescript-Co6uUVPk.js +1 -0
  15. package/dist/client/assets/ara-BRHolxvo.js +1 -0
  16. package/dist/client/assets/asciidoc-Ve4PFQV2.js +1 -0
  17. package/dist/client/assets/asm-D_Q5rh1f.js +1 -0
  18. package/dist/client/assets/astro-CbQHKStN.js +1 -0
  19. package/dist/client/assets/aurora-x-D-2ljcwZ.js +1 -0
  20. package/dist/client/assets/awk-DMzUqQB5.js +1 -0
  21. package/dist/client/assets/ayu-dark-DYE7WIF3.js +1 -0
  22. package/dist/client/assets/ayu-light-BA47KaF1.js +1 -0
  23. package/dist/client/assets/ayu-mirage-32ctXXKs.js +1 -0
  24. package/dist/client/assets/ballerina-BFfxhgS-.js +1 -0
  25. package/dist/client/assets/bat-BkioyH1T.js +1 -0
  26. package/dist/client/assets/beancount-k_qm7-4y.js +1 -0
  27. package/dist/client/assets/berry-uYugtg8r.js +1 -0
  28. package/dist/client/assets/bibtex-CHM0blh-.js +1 -0
  29. package/dist/client/assets/bicep-Bmn6On1c.js +1 -0
  30. package/dist/client/assets/bird2-DPOp833l.js +1 -0
  31. package/dist/client/assets/blade-D4QpJJKB.js +1 -0
  32. package/dist/client/assets/bsl-BO_Y6i37.js +1 -0
  33. package/dist/client/assets/c-BIGW1oBm.js +1 -0
  34. package/dist/client/assets/c3-eo99z4R2.js +1 -0
  35. package/dist/client/assets/cadence-Bv_4Rxtq.js +1 -0
  36. package/dist/client/assets/cairo-KRGpt6FW.js +1 -0
  37. package/dist/client/assets/catppuccin-frappe-DFWUc33u.js +1 -0
  38. package/dist/client/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
  39. package/dist/client/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
  40. package/dist/client/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
  41. package/dist/client/assets/clarity-D53aC0YG.js +1 -0
  42. package/dist/client/assets/clojure-P80f7IUj.js +1 -0
  43. package/dist/client/assets/cmake-D1j8_8rp.js +1 -0
  44. package/dist/client/assets/cobol-nwyudZeR.js +1 -0
  45. package/dist/client/assets/codeowners-Bp6g37R7.js +1 -0
  46. package/dist/client/assets/codeql-DsOJ9woJ.js +1 -0
  47. package/dist/client/assets/coffee-Ch7k5sss.js +1 -0
  48. package/dist/client/assets/common-lisp-Cg-RD9OK.js +1 -0
  49. package/dist/client/assets/coq-DkFqJrB1.js +1 -0
  50. package/dist/client/assets/cpp-CofmeUqb.js +1 -0
  51. package/dist/client/assets/crystal-tKQVLTB8.js +1 -0
  52. package/dist/client/assets/csharp-COcwbKMJ.js +1 -0
  53. package/dist/client/assets/css-DPfMkruS.js +1 -0
  54. package/dist/client/assets/csv-fuZLfV_i.js +1 -0
  55. package/dist/client/assets/cue-D82EKSYY.js +1 -0
  56. package/dist/client/assets/cypher-COkxafJQ.js +1 -0
  57. package/dist/client/assets/d-85-TOEBH.js +1 -0
  58. package/dist/client/assets/dark-plus-C3mMm8J8.js +1 -0
  59. package/dist/client/assets/dart-CF10PKvl.js +1 -0
  60. package/dist/client/assets/dax-CEL-wOlO.js +1 -0
  61. package/dist/client/assets/desktop-BmXAJ9_W.js +1 -0
  62. package/dist/client/assets/diff-D97Zzqfu.js +1 -0
  63. package/dist/client/assets/docker-BcOcwvcX.js +1 -0
  64. package/dist/client/assets/dotenv-Da5cRb03.js +1 -0
  65. package/dist/client/assets/dracula-BzJJZx-M.js +1 -0
  66. package/dist/client/assets/dracula-soft-BXkSAIEj.js +1 -0
  67. package/dist/client/assets/dream-maker-BtqSS_iP.js +1 -0
  68. package/dist/client/assets/edge-BkV0erSs.js +1 -0
  69. package/dist/client/assets/elixir-CDX3lj18.js +1 -0
  70. package/dist/client/assets/elm-DbKCFpqz.js +1 -0
  71. package/dist/client/assets/emacs-lisp-C9XAeP06.js +1 -0
  72. package/dist/client/assets/erb-B12qg9BL.js +1 -0
  73. package/dist/client/assets/erlang-DsQrWhSR.js +1 -0
  74. package/dist/client/assets/everforest-dark-BgDCqdQA.js +1 -0
  75. package/dist/client/assets/everforest-light-C8M2exoo.js +1 -0
  76. package/dist/client/assets/fennel-BYunw83y.js +1 -0
  77. package/dist/client/assets/fish-BvzEVeQv.js +1 -0
  78. package/dist/client/assets/fluent-C4IJs8-o.js +1 -0
  79. package/dist/client/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
  80. package/dist/client/assets/fortran-free-form-BxgE0vQu.js +1 -0
  81. package/dist/client/assets/fsharp-CXgrBDvD.js +1 -0
  82. package/dist/client/assets/gdresource-BOOCDP_w.js +1 -0
  83. package/dist/client/assets/gdscript-C5YyOfLZ.js +1 -0
  84. package/dist/client/assets/gdshader-DkwncUOv.js +1 -0
  85. package/dist/client/assets/genie-D0YGMca9.js +1 -0
  86. package/dist/client/assets/gherkin-DyxjwDmM.js +1 -0
  87. package/dist/client/assets/git-commit-F4YmCXRG.js +1 -0
  88. package/dist/client/assets/git-rebase-r7XF79zn.js +1 -0
  89. package/dist/client/assets/github-dark-DHJKELXO.js +1 -0
  90. package/dist/client/assets/github-dark-default-Cuk6v7N8.js +1 -0
  91. package/dist/client/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  92. package/dist/client/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  93. package/dist/client/assets/github-light-DAi9KRSo.js +1 -0
  94. package/dist/client/assets/github-light-default-D7oLnXFd.js +1 -0
  95. package/dist/client/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  96. package/dist/client/assets/gleam-BspZqrRM.js +1 -0
  97. package/dist/client/assets/glimmer-js-Rg0-pVw9.js +1 -0
  98. package/dist/client/assets/glimmer-ts-U6CK756n.js +1 -0
  99. package/dist/client/assets/glsl-DplSGwfg.js +1 -0
  100. package/dist/client/assets/gn-n2N0HUVH.js +1 -0
  101. package/dist/client/assets/gnuplot-DdkO51Og.js +1 -0
  102. package/dist/client/assets/go-CxLEBnE3.js +1 -0
  103. package/dist/client/assets/graphql-ChdNCCLP.js +1 -0
  104. package/dist/client/assets/groovy-gcz8RCvz.js +1 -0
  105. package/dist/client/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  106. package/dist/client/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  107. package/dist/client/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  108. package/dist/client/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  109. package/dist/client/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  110. package/dist/client/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  111. package/dist/client/assets/hack-CaT9iCJl.js +1 -0
  112. package/dist/client/assets/haml-B8DHNrY2.js +1 -0
  113. package/dist/client/assets/handlebars-BL8al0AC.js +1 -0
  114. package/dist/client/assets/haskell-Df6bDoY_.js +1 -0
  115. package/dist/client/assets/haxe-CzTSHFRz.js +1 -0
  116. package/dist/client/assets/hcl-BWvSN4gD.js +1 -0
  117. package/dist/client/assets/hjson-D5-asLiD.js +1 -0
  118. package/dist/client/assets/hlsl-D3lLCCz7.js +1 -0
  119. package/dist/client/assets/horizon-BUw7H-hv.js +1 -0
  120. package/dist/client/assets/horizon-bright-Cn-bp-IR.js +1 -0
  121. package/dist/client/assets/houston-DnULxvSX.js +1 -0
  122. package/dist/client/assets/html-GMplVEZG.js +1 -0
  123. package/dist/client/assets/html-derivative-BFtXZ54Q.js +1 -0
  124. package/dist/client/assets/http-jrhK8wxY.js +1 -0
  125. package/dist/client/assets/hurl-irOxFIW8.js +1 -0
  126. package/dist/client/assets/hxml-Bvhsp5Yf.js +1 -0
  127. package/dist/client/assets/hy-DFXneXwc.js +1 -0
  128. package/dist/client/assets/imba-DGztddWO.js +1 -0
  129. package/dist/client/assets/index-C07zYq_-.css +32 -0
  130. package/dist/client/assets/index-Ce3hNHfL.js +2351 -0
  131. package/dist/client/assets/ini-BEwlwnbL.js +1 -0
  132. package/dist/client/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  133. package/dist/client/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  134. package/dist/client/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  135. package/dist/client/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  136. package/dist/client/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  137. package/dist/client/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  138. package/dist/client/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  139. package/dist/client/assets/java-CylS5w8V.js +1 -0
  140. package/dist/client/assets/javascript-wDzz0qaB.js +1 -0
  141. package/dist/client/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  142. package/dist/client/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  143. package/dist/client/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  144. package/dist/client/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  145. package/dist/client/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  146. package/dist/client/assets/jinja-4LBKfQ-Z.js +1 -0
  147. package/dist/client/assets/jison-wvAkD_A8.js +1 -0
  148. package/dist/client/assets/json-Cp-IABpG.js +1 -0
  149. package/dist/client/assets/json5-C9tS-k6U.js +1 -0
  150. package/dist/client/assets/jsonc-Des-eS-w.js +1 -0
  151. package/dist/client/assets/jsonl-DcaNXYhu.js +1 -0
  152. package/dist/client/assets/jsonnet-DFQXde-d.js +1 -0
  153. package/dist/client/assets/jssm-C2t-YnRu.js +1 -0
  154. package/dist/client/assets/jsx-g9-lgVsj.js +1 -0
  155. package/dist/client/assets/julia-CxzCAyBv.js +1 -0
  156. package/dist/client/assets/just-Cw27pwNe.js +1 -0
  157. package/dist/client/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  158. package/dist/client/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  159. package/dist/client/assets/kanagawa-wave-DWedfzmr.js +1 -0
  160. package/dist/client/assets/kdl-DV7GczEv.js +1 -0
  161. package/dist/client/assets/kotlin-BdnUsdx6.js +1 -0
  162. package/dist/client/assets/kusto-DZf3V79B.js +1 -0
  163. package/dist/client/assets/laserwave-DUszq2jm.js +1 -0
  164. package/dist/client/assets/latex-CWtU0Tv5.js +1 -0
  165. package/dist/client/assets/lean-BZvkOJ9d.js +1 -0
  166. package/dist/client/assets/less-B1dDrJ26.js +1 -0
  167. package/dist/client/assets/light-plus-B7mTdjB0.js +1 -0
  168. package/dist/client/assets/liquid-DYVedYrR.js +1 -0
  169. package/dist/client/assets/llvm-DjAJT7YJ.js +1 -0
  170. package/dist/client/assets/log-2UxHyX5q.js +1 -0
  171. package/dist/client/assets/logo-BtOb2qkB.js +1 -0
  172. package/dist/client/assets/lua-BaeVxFsk.js +1 -0
  173. package/dist/client/assets/luau-C-HG3fhB.js +1 -0
  174. package/dist/client/assets/make-CHLpvVh8.js +1 -0
  175. package/dist/client/assets/markdown-Cvjx9yec.js +1 -0
  176. package/dist/client/assets/marko-CnJfTvn9.js +1 -0
  177. package/dist/client/assets/material-theme-D5KoaKCx.js +1 -0
  178. package/dist/client/assets/material-theme-darker-BfHTSMKl.js +1 -0
  179. package/dist/client/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  180. package/dist/client/assets/material-theme-ocean-CyktbL80.js +1 -0
  181. package/dist/client/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  182. package/dist/client/assets/matlab-D7o27uSR.js +1 -0
  183. package/dist/client/assets/mdc-BMNejdWA.js +1 -0
  184. package/dist/client/assets/mdx-Cmh6b_Ma.js +1 -0
  185. package/dist/client/assets/mermaid-mWjccvbQ.js +1 -0
  186. package/dist/client/assets/min-dark-CafNBF8u.js +1 -0
  187. package/dist/client/assets/min-light-CTRr51gU.js +1 -0
  188. package/dist/client/assets/mipsasm-CKIfxQSi.js +1 -0
  189. package/dist/client/assets/mojo-rZm6bMo-.js +1 -0
  190. package/dist/client/assets/monokai-D4h5O-jR.js +1 -0
  191. package/dist/client/assets/moonbit-_H4v1dQx.js +1 -0
  192. package/dist/client/assets/move-IF9eRakj.js +1 -0
  193. package/dist/client/assets/narrat-DRg8JJMk.js +1 -0
  194. package/dist/client/assets/nextflow-Zz6hmt5N.js +1 -0
  195. package/dist/client/assets/nextflow-groovy-BeH2EWoN.js +1 -0
  196. package/dist/client/assets/nginx-BpAMiNFr.js +1 -0
  197. package/dist/client/assets/night-owl-C39BiMTA.js +1 -0
  198. package/dist/client/assets/night-owl-light-CMTm3GFP.js +1 -0
  199. package/dist/client/assets/nim-CVrawwO9.js +1 -0
  200. package/dist/client/assets/nix-CwoSXNpI.js +1 -0
  201. package/dist/client/assets/nord-Ddv68eIx.js +1 -0
  202. package/dist/client/assets/nushell-Cz2AlsmD.js +1 -0
  203. package/dist/client/assets/objective-c-DXmwc3jG.js +1 -0
  204. package/dist/client/assets/objective-cpp-CLxacb5B.js +1 -0
  205. package/dist/client/assets/ocaml-C0hk2d4L.js +1 -0
  206. package/dist/client/assets/odin-BBf5iR-q.js +1 -0
  207. package/dist/client/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  208. package/dist/client/assets/one-light-C3Wv6jpd.js +1 -0
  209. package/dist/client/assets/openscad-C4EeE6gA.js +1 -0
  210. package/dist/client/assets/pascal-D93ZcfNL.js +1 -0
  211. package/dist/client/assets/perl-C0TMdlhV.js +1 -0
  212. package/dist/client/assets/php-Dhbhpdrm.js +1 -0
  213. package/dist/client/assets/pierre-dark-DF2SEV7i.js +1 -0
  214. package/dist/client/assets/pierre-light-DOlZxES8.js +1 -0
  215. package/dist/client/assets/pkl-u5AG7uiY.js +1 -0
  216. package/dist/client/assets/plastic-3e1v2bzS.js +1 -0
  217. package/dist/client/assets/plsql-ChMvpjG-.js +1 -0
  218. package/dist/client/assets/po-BTJTHyun.js +1 -0
  219. package/dist/client/assets/poimandres-CS3Unz2-.js +1 -0
  220. package/dist/client/assets/polar-C0HS_06l.js +1 -0
  221. package/dist/client/assets/postcss-CXtECtnM.js +1 -0
  222. package/dist/client/assets/powerquery-CEu0bR-o.js +1 -0
  223. package/dist/client/assets/powershell-Dpen1YoG.js +1 -0
  224. package/dist/client/assets/prisma-Dd19v3D-.js +1 -0
  225. package/dist/client/assets/prolog-CbFg5uaA.js +1 -0
  226. package/dist/client/assets/proto-C7zT0LnQ.js +1 -0
  227. package/dist/client/assets/pug-CGlum2m_.js +1 -0
  228. package/dist/client/assets/puppet-BMWR74SV.js +1 -0
  229. package/dist/client/assets/purescript-CklMAg4u.js +1 -0
  230. package/dist/client/assets/python-B6aJPvgy.js +1 -0
  231. package/dist/client/assets/qml-3beO22l8.js +1 -0
  232. package/dist/client/assets/qmldir-C8lEn-DE.js +1 -0
  233. package/dist/client/assets/qss-IeuSbFQv.js +1 -0
  234. package/dist/client/assets/r-Dspwwk_N.js +1 -0
  235. package/dist/client/assets/racket-BqYA7rlc.js +1 -0
  236. package/dist/client/assets/raku-DXvB9xmW.js +1 -0
  237. package/dist/client/assets/razor-Uh8Bk_45.js +1 -0
  238. package/dist/client/assets/red-bN70gL4F.js +1 -0
  239. package/dist/client/assets/reg-C-SQnVFl.js +1 -0
  240. package/dist/client/assets/regexp-CDVJQ6XC.js +1 -0
  241. package/dist/client/assets/rel-C3B-1QV4.js +1 -0
  242. package/dist/client/assets/riscv-BM1_JUlF.js +1 -0
  243. package/dist/client/assets/ron-D8l8udqQ.js +1 -0
  244. package/dist/client/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
  245. package/dist/client/assets/rose-pine-moon-D4_iv3hh.js +1 -0
  246. package/dist/client/assets/rose-pine-qdsjHGoJ.js +1 -0
  247. package/dist/client/assets/rosmsg-BJDFO7_C.js +1 -0
  248. package/dist/client/assets/rst-BrH8l1NY.js +1 -0
  249. package/dist/client/assets/ruby-Dw2BHqvy.js +1 -0
  250. package/dist/client/assets/rust-B1yitclQ.js +1 -0
  251. package/dist/client/assets/sas-cz2c8ADy.js +1 -0
  252. package/dist/client/assets/sass-Cj5Yp3dK.js +1 -0
  253. package/dist/client/assets/scala-C151Ov-r.js +1 -0
  254. package/dist/client/assets/scheme-C98Dy4si.js +1 -0
  255. package/dist/client/assets/scratchpad-page-DcMny6uZ.js +1 -0
  256. package/dist/client/assets/scss-OYdSNvt2.js +1 -0
  257. package/dist/client/assets/sdbl-DVxCFoDh.js +1 -0
  258. package/dist/client/assets/shaderlab-Dg9Lc6iA.js +1 -0
  259. package/dist/client/assets/shellscript-Yzrsuije.js +1 -0
  260. package/dist/client/assets/shellsession-BADoaaVG.js +1 -0
  261. package/dist/client/assets/slack-dark-BthQWCQV.js +1 -0
  262. package/dist/client/assets/slack-ochin-DqwNpetd.js +1 -0
  263. package/dist/client/assets/smalltalk-BERRCDM3.js +1 -0
  264. package/dist/client/assets/snazzy-light-Bw305WKR.js +1 -0
  265. package/dist/client/assets/solarized-dark-DXbdFlpD.js +1 -0
  266. package/dist/client/assets/solarized-light-L9t79GZl.js +1 -0
  267. package/dist/client/assets/solidity-rGO070M0.js +1 -0
  268. package/dist/client/assets/soy-Brmx7dQM.js +1 -0
  269. package/dist/client/assets/sparql-rVzFXLq3.js +1 -0
  270. package/dist/client/assets/splunk-BtCnVYZw.js +1 -0
  271. package/dist/client/assets/sql-BLtJtn59.js +1 -0
  272. package/dist/client/assets/ssh-config-_ykCGR6B.js +1 -0
  273. package/dist/client/assets/stata-BH5u7GGu.js +1 -0
  274. package/dist/client/assets/stylus-BEDo0Tqx.js +1 -0
  275. package/dist/client/assets/surrealql-Bq5Q-fJD.js +1 -0
  276. package/dist/client/assets/svelte-C_ipcX3V.js +1 -0
  277. package/dist/client/assets/swift-D82vCrfD.js +1 -0
  278. package/dist/client/assets/synthwave-84-CbfX1IO0.js +1 -0
  279. package/dist/client/assets/system-verilog-CnnmHF94.js +1 -0
  280. package/dist/client/assets/systemd-4A_iFExJ.js +1 -0
  281. package/dist/client/assets/talonscript-CkByrt1z.js +1 -0
  282. package/dist/client/assets/tasl-QIJgUcNo.js +1 -0
  283. package/dist/client/assets/tcl-dwOrl1Do.js +1 -0
  284. package/dist/client/assets/templ-P3uqSqPl.js +1 -0
  285. package/dist/client/assets/terraform-BETggiCN.js +1 -0
  286. package/dist/client/assets/tex-idrVyKtj.js +1 -0
  287. package/dist/client/assets/tokyo-night-hegEt444.js +1 -0
  288. package/dist/client/assets/toml-vGWfd6FD.js +1 -0
  289. package/dist/client/assets/ts-tags-zn1MmPIZ.js +1 -0
  290. package/dist/client/assets/tsv-B_m7g4N7.js +1 -0
  291. package/dist/client/assets/tsx-COt5Ahok.js +1 -0
  292. package/dist/client/assets/turtle-BsS91CYL.js +1 -0
  293. package/dist/client/assets/twig-DNn4PbVi.js +1 -0
  294. package/dist/client/assets/typescript-BPQ3VLAy.js +1 -0
  295. package/dist/client/assets/typespec-BGHnOYBU.js +1 -0
  296. package/dist/client/assets/typst-DHCkPAjA.js +1 -0
  297. package/dist/client/assets/v-BcVCzyr7.js +1 -0
  298. package/dist/client/assets/vala-CsfeWuGM.js +1 -0
  299. package/dist/client/assets/vb-D17OF-Vu.js +1 -0
  300. package/dist/client/assets/verilog-BQ8w6xss.js +1 -0
  301. package/dist/client/assets/vesper-DU1UobuO.js +1 -0
  302. package/dist/client/assets/vhdl-CeAyd5Ju.js +1 -0
  303. package/dist/client/assets/viml-CJc9bBzg.js +1 -0
  304. package/dist/client/assets/vitesse-black-Bkuqu6BP.js +1 -0
  305. package/dist/client/assets/vitesse-dark-D0r3Knsf.js +1 -0
  306. package/dist/client/assets/vitesse-light-CVO1_9PV.js +1 -0
  307. package/dist/client/assets/vue-DN_0RTcg.js +1 -0
  308. package/dist/client/assets/vue-html-AaS7Mt5G.js +1 -0
  309. package/dist/client/assets/vue-vine-CQOfvN7w.js +1 -0
  310. package/dist/client/assets/vyper-CDx5xZoG.js +1 -0
  311. package/dist/client/assets/wasm-CG6Dc4jp.js +1 -0
  312. package/dist/client/assets/wasm-MzD3tlZU.js +1 -0
  313. package/dist/client/assets/wenyan-BV7otONQ.js +1 -0
  314. package/dist/client/assets/wgsl-Dx-B1_4e.js +1 -0
  315. package/dist/client/assets/wikitext-BhOHFoWU.js +1 -0
  316. package/dist/client/assets/wit-5i3qLPDT.js +1 -0
  317. package/dist/client/assets/wolfram-lXgVvXCa.js +1 -0
  318. package/dist/client/assets/xml-sdJ4AIDG.js +1 -0
  319. package/dist/client/assets/xsl-CtQFsRM5.js +1 -0
  320. package/dist/client/assets/yaml-Buea-lGh.js +1 -0
  321. package/dist/client/assets/zenscript-DVFEvuxE.js +1 -0
  322. package/dist/client/assets/zig-VOosw3JB.js +1 -0
  323. package/dist/client/cursor.png +0 -0
  324. package/dist/client/favicon.svg +17 -0
  325. package/dist/client/finder.png +0 -0
  326. package/dist/client/icons/claude.svg +1 -0
  327. package/dist/client/icons/openai.svg +1 -0
  328. package/dist/client/images/github.png +0 -0
  329. package/dist/client/index.html +15 -0
  330. package/dist/client/logo.svg +17 -0
  331. package/dist/client/terminal.png +0 -0
  332. package/dist/client/vscode.png +0 -0
  333. package/dist/client/warp.png +0 -0
  334. package/package.json +107 -0
  335. package/src/server/agent-instruction-attachments.ts +458 -0
  336. package/src/server/agent.ts +1879 -0
  337. package/src/server/cli-runtime.ts +418 -0
  338. package/src/server/cli-supervisor.ts +90 -0
  339. package/src/server/cli.ts +102 -0
  340. package/src/server/codex-app-server-protocol.ts +478 -0
  341. package/src/server/codex-app-server.ts +1645 -0
  342. package/src/server/data-dir-lock.ts +128 -0
  343. package/src/server/diff-store.ts +1587 -0
  344. package/src/server/durable-file.ts +74 -0
  345. package/src/server/event-store.ts +1448 -0
  346. package/src/server/event.ts +249 -0
  347. package/src/server/external-file-access.ts +48 -0
  348. package/src/server/external-open.ts +259 -0
  349. package/src/server/generate-title.ts +75 -0
  350. package/src/server/git-refresh-poller.ts +92 -0
  351. package/src/server/github-rest-client.ts +176 -0
  352. package/src/server/harness-types.ts +24 -0
  353. package/src/server/keybindings.ts +203 -0
  354. package/src/server/machine-name.ts +22 -0
  355. package/src/server/paths.ts +51 -0
  356. package/src/server/pr-manager.ts +1204 -0
  357. package/src/server/pr-refresh-poller.ts +126 -0
  358. package/src/server/process-utils.ts +18 -0
  359. package/src/server/provider-catalog.ts +90 -0
  360. package/src/server/quick-response.ts +274 -0
  361. package/src/server/read-models.ts +311 -0
  362. package/src/server/restart.ts +33 -0
  363. package/src/server/scratchpad-manager.ts +87 -0
  364. package/src/server/server.ts +759 -0
  365. package/src/server/share.ts +126 -0
  366. package/src/server/terminal-manager.ts +371 -0
  367. package/src/server/update-manager.ts +250 -0
  368. package/src/server/uploads.ts +191 -0
  369. package/src/server/workspace-file-search.ts +191 -0
  370. package/src/server/workspace-manager.ts +627 -0
  371. package/src/server/workspace-polling.ts +10 -0
  372. package/src/server/ws-router.ts +1039 -0
  373. package/src/shared/branding.ts +69 -0
  374. package/src/shared/dev-ports.ts +100 -0
  375. package/src/shared/ports.ts +2 -0
  376. package/src/shared/protocol.ts +217 -0
  377. package/src/shared/tools.ts +324 -0
  378. package/src/shared/types.ts +1220 -0
  379. package/tsconfig.json +35 -0
@@ -0,0 +1,1039 @@
1
+ import { realpath } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import type { ServerWebSocket } from 'bun';
4
+ import {
5
+ type ClientEnvelope,
6
+ isClientEnvelope,
7
+ type ServerEnvelope,
8
+ type SubscriptionTopic,
9
+ } from 'src/shared/protocol';
10
+ import type {
11
+ ChatAttachment,
12
+ MikoStatus,
13
+ WorkspaceGitHubSnapshot,
14
+ WorkspaceGitSnapshot,
15
+ WorkspaceHealthState,
16
+ } from 'src/shared/types';
17
+ import type { AgentCoordinator } from './agent';
18
+ import {
19
+ writeCreatePrInstructionsAttachment,
20
+ writeFailingCiLogsAttachment,
21
+ writeMergeConflictInstructionsAttachment,
22
+ writeReviewInstructionsAttachment,
23
+ writeSelectedReviewCommentsAttachment,
24
+ } from './agent-instruction-attachments';
25
+ import type { DiffStore } from './diff-store';
26
+ import type { EventStore } from './event-store';
27
+ import { openExternal } from './external-open';
28
+ import type { KeybindingsManager } from './keybindings';
29
+ import { requireExistingDirectoryPath } from './paths';
30
+ import type { PrManager } from './pr-manager';
31
+ import {
32
+ deriveDirectoryListSnapshot,
33
+ deriveSessionSnapshot,
34
+ deriveSidebarSnapshot,
35
+ deriveWorkspaceSnapshot,
36
+ } from './read-models';
37
+ import type { ScratchpadManager } from './scratchpad-manager';
38
+ import type { TerminalManager } from './terminal-manager';
39
+ import type { UpdateManager } from './update-manager';
40
+ import { listWorkspaceFiles, searchWorkspaceFiles } from './workspace-file-search';
41
+ import type { WorkspaceManager, WorkspaceTurnIntent } from './workspace-manager';
42
+
43
+ const DEFAULT_SESSION_RECENT_LIMIT = 300;
44
+
45
+ export interface ClientState {
46
+ subscriptions: Map<string, SubscriptionTopic>;
47
+ snapshotSignatures: Map<string, string>;
48
+ }
49
+
50
+ interface CreateWsRouterArgs {
51
+ store: EventStore;
52
+ diffStore: Pick<
53
+ DiffStore,
54
+ | 'getWorkspaceGitSnapshot'
55
+ | 'refreshWorkspaceGitSnapshot'
56
+ | 'fetchWorkspaceGit'
57
+ | 'initializeGit'
58
+ | 'getGitHubPublishInfo'
59
+ | 'checkGitHubRepoAvailability'
60
+ | 'publishToGitHub'
61
+ | 'inspectGitHubBackedRepo'
62
+ | 'discardFile'
63
+ | 'ignoreFile'
64
+ | 'readPatch'
65
+ | 'readFileContents'
66
+ | 'readExternalFileContents'
67
+ >;
68
+ workspaceManager: WorkspaceManager;
69
+ prManager: PrManager;
70
+ scratchpadManager: ScratchpadManager;
71
+ agent: AgentCoordinator;
72
+ terminals: TerminalManager;
73
+ keybindings: KeybindingsManager;
74
+ machineDisplayName: string;
75
+ updateManager: UpdateManager | null;
76
+ refreshWorkspacePrStage: (workspaceId: string, options?: { force?: boolean }) => Promise<unknown>;
77
+ }
78
+
79
+ function send(ws: ServerWebSocket<ClientState>, message: ServerEnvelope) {
80
+ ws.send(JSON.stringify(message));
81
+ }
82
+
83
+ function ensureSnapshotSignatures(ws: ServerWebSocket<ClientState>) {
84
+ if (!ws.data.snapshotSignatures) {
85
+ ws.data.snapshotSignatures = new Map();
86
+ }
87
+ return ws.data.snapshotSignatures;
88
+ }
89
+
90
+ async function realpathOrNull(filePath: string) {
91
+ try {
92
+ return await realpath(filePath);
93
+ } catch {
94
+ return null;
95
+ }
96
+ }
97
+
98
+ function toolInputFilePath(input: unknown) {
99
+ if (!input || typeof input !== 'object') return null;
100
+ const filePath = (input as { filePath?: unknown }).filePath;
101
+ return typeof filePath === 'string' ? filePath : null;
102
+ }
103
+
104
+ async function sessionTranscriptAllowsExternalPath(args: {
105
+ store: EventStore;
106
+ workspaceId: string;
107
+ sessionId: string;
108
+ requestedPath: string;
109
+ }) {
110
+ if (!path.isAbsolute(args.requestedPath)) return false;
111
+ const session = args.store.getSession(args.sessionId);
112
+ if (!session || session.workspaceId !== args.workspaceId) return false;
113
+
114
+ const requestedRealPath = await realpathOrNull(args.requestedPath);
115
+ if (!requestedRealPath) return false;
116
+
117
+ for (const entry of args.store.getMessages(args.sessionId)) {
118
+ if (entry.kind !== 'tool_call') continue;
119
+ const filePath = toolInputFilePath(entry.tool.input);
120
+ if (!filePath || !path.isAbsolute(filePath)) continue;
121
+ const candidateRealPath = await realpathOrNull(filePath);
122
+ if (candidateRealPath === requestedRealPath) return true;
123
+ }
124
+
125
+ return false;
126
+ }
127
+
128
+ function createGitSnapshots(store: EventStore, diffStore: CreateWsRouterArgs['diffStore']) {
129
+ const gitSnapshots = new Map<string, WorkspaceGitSnapshot>();
130
+ for (const workspace of store.listWorkspaces()) {
131
+ gitSnapshots.set(workspace.id, diffStore.getWorkspaceGitSnapshot(workspace.id));
132
+ }
133
+ return gitSnapshots;
134
+ }
135
+
136
+ function createGithubSnapshots(store: EventStore, prManager: PrManager) {
137
+ const githubSnapshots = new Map<string, WorkspaceGitHubSnapshot>();
138
+ for (const workspace of store.listWorkspaces()) {
139
+ const snapshot = prManager.getWorkspaceGitHubSnapshot(workspace.id);
140
+ if (snapshot) githubSnapshots.set(workspace.id, snapshot);
141
+ }
142
+ return githubSnapshots;
143
+ }
144
+
145
+ export function createWsRouter({
146
+ store,
147
+ diffStore,
148
+ workspaceManager,
149
+ prManager,
150
+ scratchpadManager,
151
+ agent,
152
+ terminals,
153
+ keybindings,
154
+ machineDisplayName,
155
+ updateManager,
156
+ refreshWorkspacePrStage,
157
+ }: CreateWsRouterArgs) {
158
+ const sockets = new Set<ServerWebSocket<ClientState>>();
159
+ const workspaceHealthStates = new Map<string, WorkspaceHealthState>();
160
+
161
+ function getActiveStatuses() {
162
+ return agent.getActiveStatuses() as Map<string, MikoStatus>;
163
+ }
164
+
165
+ function getDrainingSessionIds() {
166
+ return agent.getDrainingSessionIds();
167
+ }
168
+
169
+ async function refreshWorkspaceOpenState(workspaceId: string) {
170
+ if (!store.getWorkspace(workspaceId)) return;
171
+
172
+ const [healthState] = await Promise.all([
173
+ workspaceManager.getWorkspaceHealthState(workspaceId),
174
+ refreshWorkspaceGit(workspaceId, false),
175
+ ]);
176
+
177
+ workspaceHealthStates.set(workspaceId, healthState);
178
+
179
+ const workspace = store.getWorkspace(workspaceId);
180
+ if (workspace?.reviewState !== 'in_review') return;
181
+
182
+ if (refreshWorkspacePrStage) {
183
+ await refreshWorkspacePrStage(workspace.id);
184
+ } else {
185
+ await prManager.refreshWorkspacePrState(workspace.id);
186
+ }
187
+ }
188
+
189
+ async function createEnvelope(id: string, topic: SubscriptionTopic): Promise<ServerEnvelope> {
190
+ if (topic.type === 'sidebar') {
191
+ return {
192
+ type: 'snapshot',
193
+ id,
194
+ snapshot: {
195
+ type: 'sidebar',
196
+ data: deriveSidebarSnapshot({
197
+ state: store.state,
198
+ activeStatuses: getActiveStatuses(),
199
+ gitSnapshots: createGitSnapshots(store, diffStore),
200
+ githubSnapshots: createGithubSnapshots(store, prManager),
201
+ }),
202
+ },
203
+ };
204
+ }
205
+
206
+ if (topic.type === 'directories') {
207
+ return {
208
+ type: 'snapshot',
209
+ id,
210
+ snapshot: {
211
+ type: 'directories',
212
+ data: deriveDirectoryListSnapshot(store.state, machineDisplayName),
213
+ },
214
+ };
215
+ }
216
+
217
+ if (topic.type === 'workspace') {
218
+ const workspace = store.getWorkspace(topic.workspaceId);
219
+ return {
220
+ type: 'snapshot',
221
+ id,
222
+ snapshot: {
223
+ type: 'workspace',
224
+ data: workspace
225
+ ? deriveWorkspaceSnapshot({
226
+ state: store.state,
227
+ activeStatuses: getActiveStatuses(),
228
+ workspaceId: topic.workspaceId,
229
+ healthState: workspaceHealthStates.get(topic.workspaceId),
230
+ git: diffStore.getWorkspaceGitSnapshot(topic.workspaceId),
231
+ github: prManager.getWorkspaceGitHubSnapshot(topic.workspaceId),
232
+ })
233
+ : null,
234
+ },
235
+ };
236
+ }
237
+
238
+ if (topic.type === 'session') {
239
+ return {
240
+ type: 'snapshot',
241
+ id,
242
+ snapshot: {
243
+ type: 'session',
244
+ data: deriveSessionSnapshot(
245
+ store.state,
246
+ getActiveStatuses(),
247
+ getDrainingSessionIds(),
248
+ topic.sessionId,
249
+ agent.getPendingTool(topic.sessionId),
250
+ agent.getQueuedMessages(topic.sessionId),
251
+ (sessionId) =>
252
+ store.getRecentSessionHistory(
253
+ sessionId,
254
+ topic.recentLimit ?? DEFAULT_SESSION_RECENT_LIMIT,
255
+ ),
256
+ ),
257
+ },
258
+ };
259
+ }
260
+
261
+ if (topic.type === 'scratchpad') {
262
+ return {
263
+ type: 'snapshot',
264
+ id,
265
+ snapshot: {
266
+ type: 'scratchpad',
267
+ data: await scratchpadManager.getSnapshot(topic.workspaceId),
268
+ },
269
+ };
270
+ }
271
+
272
+ if (topic.type === 'keybindings') {
273
+ return {
274
+ type: 'snapshot',
275
+ id,
276
+ snapshot: { type: 'keybindings', data: keybindings.getSnapshot() },
277
+ };
278
+ }
279
+
280
+ if (topic.type === 'update') {
281
+ return {
282
+ type: 'snapshot',
283
+ id,
284
+ snapshot: {
285
+ type: 'update',
286
+ data: updateManager?.getSnapshot() ?? {
287
+ currentVersion: 'unknown',
288
+ latestVersion: null,
289
+ status: 'idle',
290
+ updateAvailable: false,
291
+ lastCheckedAt: null,
292
+ error: null,
293
+ installAction: 'restart',
294
+ },
295
+ },
296
+ };
297
+ }
298
+
299
+ return {
300
+ type: 'snapshot',
301
+ id,
302
+ snapshot: {
303
+ type: 'terminal',
304
+ data: terminals.getSnapshot(topic.terminalId),
305
+ },
306
+ };
307
+ }
308
+
309
+ async function pushSnapshots(ws: ServerWebSocket<ClientState>) {
310
+ const snapshotSignatures = ensureSnapshotSignatures(ws);
311
+ for (const [id, topic] of ws.data.subscriptions.entries()) {
312
+ const envelope = await createEnvelope(id, topic);
313
+ if (envelope.type !== 'snapshot') continue;
314
+
315
+ const signature = JSON.stringify(envelope.snapshot);
316
+ if (snapshotSignatures.get(id) === signature) continue;
317
+
318
+ snapshotSignatures.set(id, signature);
319
+ send(ws, envelope);
320
+ }
321
+ }
322
+
323
+ async function broadcastSnapshots() {
324
+ for (const ws of sockets) {
325
+ await pushSnapshots(ws);
326
+ }
327
+ }
328
+
329
+ function broadcastError(message: string) {
330
+ for (const ws of sockets) {
331
+ send(ws, { type: 'error', message });
332
+ }
333
+ }
334
+
335
+ async function pushSubscribedSnapshot(topicType: SubscriptionTopic['type']) {
336
+ for (const ws of sockets) {
337
+ const snapshotSignatures = ensureSnapshotSignatures(ws);
338
+ for (const [id, topic] of ws.data.subscriptions.entries()) {
339
+ if (topic.type !== topicType) continue;
340
+ const envelope = await createEnvelope(id, topic);
341
+ if (envelope.type !== 'snapshot') continue;
342
+
343
+ const signature = JSON.stringify(envelope.snapshot);
344
+ if (snapshotSignatures.get(id) === signature) continue;
345
+
346
+ snapshotSignatures.set(id, signature);
347
+ send(ws, envelope);
348
+ }
349
+ }
350
+ }
351
+
352
+ async function pushScratchpadSnapshot(workspaceId: string) {
353
+ for (const ws of sockets) {
354
+ const snapshotSignatures = ensureSnapshotSignatures(ws);
355
+ for (const [id, topic] of ws.data.subscriptions.entries()) {
356
+ if (topic.type !== 'scratchpad' || topic.workspaceId !== workspaceId) continue;
357
+ const envelope = await createEnvelope(id, topic);
358
+ if (envelope.type !== 'snapshot') continue;
359
+
360
+ const signature = JSON.stringify(envelope.snapshot);
361
+ if (snapshotSignatures.get(id) === signature) continue;
362
+
363
+ snapshotSignatures.set(id, signature);
364
+ send(ws, envelope);
365
+ }
366
+ }
367
+ }
368
+
369
+ async function pushTerminalSnapshot(terminalId: string) {
370
+ for (const ws of sockets) {
371
+ const snapshotSignatures = ensureSnapshotSignatures(ws);
372
+ for (const [id, topic] of ws.data.subscriptions.entries()) {
373
+ if (topic.type !== 'terminal' || topic.terminalId !== terminalId) continue;
374
+ const envelope = await createEnvelope(id, topic);
375
+ if (envelope.type !== 'snapshot') continue;
376
+
377
+ const signature = JSON.stringify(envelope.snapshot);
378
+ if (snapshotSignatures.get(id) === signature) continue;
379
+
380
+ snapshotSignatures.set(id, signature);
381
+ send(ws, envelope);
382
+ }
383
+ }
384
+ }
385
+
386
+ function pushTerminalEvent(
387
+ terminalId: string,
388
+ event: Extract<ServerEnvelope, { type: 'event' }>['event'],
389
+ ) {
390
+ for (const ws of sockets) {
391
+ for (const [id, topic] of ws.data.subscriptions.entries()) {
392
+ if (topic.type !== 'terminal' || topic.terminalId !== terminalId) continue;
393
+ send(ws, { type: 'event', id, event });
394
+ }
395
+ }
396
+ }
397
+
398
+ const disposeTerminalEvents = terminals.onEvent((event) => {
399
+ pushTerminalEvent(event.terminalId, event);
400
+ });
401
+
402
+ const disposeKeybindingEvents = keybindings.onChange(() => {
403
+ void pushSubscribedSnapshot('keybindings');
404
+ });
405
+
406
+ const disposeUpdateEvents =
407
+ updateManager?.onChange(() => {
408
+ void pushSubscribedSnapshot('update');
409
+ }) ?? (() => {});
410
+
411
+ agent.setBackgroundErrorReporter?.(broadcastError);
412
+
413
+ function requireWorkspace(workspaceId: string) {
414
+ return store.requireWorkspace(workspaceId);
415
+ }
416
+
417
+ function stripTrailingSlash(value: string) {
418
+ return value.replace(/\/+$/u, '');
419
+ }
420
+
421
+ function readPersistedPullRequestPatch(workspaceId: string, filePath: string) {
422
+ const workspace = store.getWorkspace(workspaceId);
423
+ const normalizedPath = stripTrailingSlash(filePath);
424
+ const file = workspace?.pullRequest?.files?.find(
425
+ (candidate) => stripTrailingSlash(candidate.path) === normalizedPath,
426
+ );
427
+ if (!file?.patch) return null;
428
+ return { path: file.path, patch: file.patch, patchDigest: file.patchDigest };
429
+ }
430
+
431
+ async function sendWorkspaceInstruction(
432
+ workspaceId: string,
433
+ sessionId: string,
434
+ content: string,
435
+ attachments: ChatAttachment[] = [],
436
+ intent: WorkspaceTurnIntent,
437
+ ) {
438
+ const session = store.requireSession(sessionId);
439
+ if (session.workspaceId !== workspaceId) {
440
+ throw new Error('Session does not belong to workspace');
441
+ }
442
+
443
+ let markedIntent = false;
444
+ try {
445
+ // Workspace actions carry a post-turn intent (PR/Git refresh) that the running turn consumes
446
+ // on settle. They must reserve the agent session before marking the intent so concurrent
447
+ // actions cannot queue and then overwrite the intent for the already-starting turn.
448
+ return await agent.sendWhenIdle(
449
+ {
450
+ type: 'session.send',
451
+ sessionId,
452
+ workspaceId,
453
+ content,
454
+ attachments,
455
+ modelOptions: {},
456
+ },
457
+ () => {
458
+ workspaceManager.markWorkspaceInstructionTurnStarted({ workspaceId, sessionId, intent });
459
+ markedIntent = true;
460
+ },
461
+ );
462
+ } catch (error) {
463
+ if (markedIntent) workspaceManager.clearWorkspaceInstructionTurn(sessionId);
464
+ throw error;
465
+ }
466
+ }
467
+
468
+ async function refreshWorkspaceGit(workspaceId: string, fetchRemote: boolean) {
469
+ const workspace = requireWorkspace(workspaceId);
470
+ if (fetchRemote) {
471
+ const result = await diffStore.fetchWorkspaceGit({
472
+ workspaceId: workspace.id,
473
+ workspacePath: workspace.localPath,
474
+ });
475
+ return result;
476
+ }
477
+
478
+ const snapshotChanged = await diffStore.refreshWorkspaceGitSnapshot(
479
+ workspace.id,
480
+ workspace.localPath,
481
+ );
482
+ return { ok: true as const, branchName: workspace.branchName, snapshotChanged };
483
+ }
484
+
485
+ async function handleCommand(
486
+ ws: ServerWebSocket<ClientState>,
487
+ message: Extract<ClientEnvelope, { type: 'command' }>,
488
+ ) {
489
+ const { command, id } = message;
490
+ try {
491
+ switch (command.type) {
492
+ case 'system.ping': {
493
+ send(ws, { type: 'ack', id });
494
+ return;
495
+ }
496
+ case 'system.openExternal': {
497
+ await openExternal(command);
498
+ send(ws, { type: 'ack', id });
499
+ return;
500
+ }
501
+ case 'update.check': {
502
+ const snapshot = updateManager
503
+ ? await updateManager.checkForUpdates({ force: command.force })
504
+ : {
505
+ currentVersion: 'unknown',
506
+ latestVersion: null,
507
+ status: 'error' as const,
508
+ updateAvailable: false,
509
+ lastCheckedAt: Date.now(),
510
+ error: 'Update manager unavailable.',
511
+ installAction: 'restart' as const,
512
+ };
513
+ send(ws, { type: 'ack', id, result: snapshot });
514
+ return;
515
+ }
516
+ case 'update.install': {
517
+ if (!updateManager) throw new Error('Update manager unavailable.');
518
+ const result = await updateManager.installUpdate();
519
+ send(ws, { type: 'ack', id, result });
520
+ return;
521
+ }
522
+ case 'settings.readKeybindings': {
523
+ send(ws, { type: 'ack', id, result: keybindings.getSnapshot() });
524
+ return;
525
+ }
526
+ case 'settings.writeKeybindings': {
527
+ const snapshot = await keybindings.write(command.bindings);
528
+ send(ws, { type: 'ack', id, result: snapshot });
529
+ return;
530
+ }
531
+ case 'directory.add': {
532
+ const localPath = await requireExistingDirectoryPath(command.localPath);
533
+ const inspection = await diffStore.inspectGitHubBackedRepo(localPath);
534
+ if (!inspection.ok) {
535
+ throw new Error(
536
+ inspection.message ?? 'Directory must be a GitHub-backed git repository.',
537
+ );
538
+ }
539
+
540
+ if (!inspection.githubOwner || !inspection.githubRepo) {
541
+ throw new Error('Directory must have a GitHub origin remote.');
542
+ }
543
+
544
+ if (inspection.defaultBranchName !== 'main') {
545
+ throw new Error('Directory must have a main branch before it can be added.');
546
+ }
547
+
548
+ const directory = await store.addDirectory({
549
+ ...command,
550
+ localPath: inspection.repoRoot ?? localPath,
551
+ githubOwner: inspection.githubOwner,
552
+ githubRepo: inspection.githubRepo,
553
+ });
554
+ send(ws, { type: 'ack', id, result: { directoryId: directory.id } });
555
+ break;
556
+ }
557
+ case 'directory.remove': {
558
+ await store.removeDirectory(command.directoryId);
559
+ send(ws, { type: 'ack', id });
560
+ break;
561
+ }
562
+ case 'directory.initializeGit': {
563
+ const result = await diffStore.initializeGit({ localPath: command.localPath });
564
+ send(ws, { type: 'ack', id, result });
565
+ break;
566
+ }
567
+ case 'directory.getGithubPublishInfo': {
568
+ const result = await diffStore.getGitHubPublishInfo({ localPath: command.localPath });
569
+ send(ws, { type: 'ack', id, result });
570
+ return;
571
+ }
572
+ case 'directory.checkGithubRepoAvailability': {
573
+ const result = await diffStore.checkGitHubRepoAvailability(command);
574
+ send(ws, { type: 'ack', id, result });
575
+ return;
576
+ }
577
+ case 'directory.publishToGithub': {
578
+ const result = await diffStore.publishToGitHub(command);
579
+ send(ws, { type: 'ack', id, result });
580
+ break;
581
+ }
582
+ case 'workspace.create': {
583
+ const result = await workspaceManager.createWorkspace(command.directoryId);
584
+ send(ws, {
585
+ type: 'ack',
586
+ id,
587
+ result: { workspaceId: result.workspace.id, sessionId: result.session?.id ?? null },
588
+ });
589
+ break;
590
+ }
591
+ case 'workspace.remove': {
592
+ await store.removeWorkspace(command.workspaceId);
593
+ send(ws, { type: 'ack', id });
594
+ break;
595
+ }
596
+ case 'workspace.setVisibility': {
597
+ await store.setWorkspaceVisibilityState(command.workspaceId, command.visibilityState);
598
+ send(ws, { type: 'ack', id });
599
+ break;
600
+ }
601
+ case 'workspace.renameBranch': {
602
+ const workspace = await workspaceManager.renameWorkspaceBranch(
603
+ command.workspaceId,
604
+ command.branchName,
605
+ );
606
+ send(ws, { type: 'ack', id, result: { workspaceId: workspace.id } });
607
+ break;
608
+ }
609
+ case 'workspace.continueOnNewBranch': {
610
+ const activeStatuses = agent.getActiveStatuses();
611
+ const drainingSessionIds = agent.getDrainingSessionIds();
612
+ const hasRunningSession = store
613
+ .listSessionsByWorkspace(command.workspaceId)
614
+ .some(
615
+ (session) => activeStatuses.has(session.id) || drainingSessionIds.has(session.id),
616
+ );
617
+ if (hasRunningSession) {
618
+ throw new Error('Cannot continue a workspace while an agent is running');
619
+ }
620
+
621
+ const workspace = await workspaceManager.continueWorkspaceOnNewBranch(
622
+ command.workspaceId,
623
+ );
624
+ send(ws, { type: 'ack', id, result: { workspaceId: workspace.id } });
625
+ break;
626
+ }
627
+ case 'workspace.markRead': {
628
+ await store.setWorkspaceUnreadAgentResult(command.workspaceId, false);
629
+ send(ws, { type: 'ack', id });
630
+ break;
631
+ }
632
+ case 'workspace.refreshGit': {
633
+ const result = await refreshWorkspaceGit(
634
+ command.workspaceId,
635
+ command.fetchRemote ?? false,
636
+ );
637
+ send(ws, { type: 'ack', id, result });
638
+ break;
639
+ }
640
+ case 'workspace.refreshPrStage': {
641
+ const result = await refreshWorkspacePrStage(command.workspaceId, { force: true });
642
+ send(ws, { type: 'ack', id, result });
643
+ break;
644
+ }
645
+ case 'workspace.readDiffPatch': {
646
+ const workspace = requireWorkspace(command.workspaceId);
647
+ try {
648
+ const result = await diffStore.readPatch({
649
+ workspacePath: workspace.localPath,
650
+ path: command.path,
651
+ });
652
+ send(ws, { type: 'ack', id, result });
653
+ return;
654
+ } catch (error) {
655
+ const canUsePersistedPatch =
656
+ error instanceof Error && error.message.startsWith('File is no longer changed:');
657
+ const fallback = canUsePersistedPatch
658
+ ? readPersistedPullRequestPatch(command.workspaceId, command.path)
659
+ : null;
660
+ if (!fallback) throw error;
661
+ send(ws, { type: 'ack', id, result: fallback });
662
+ return;
663
+ }
664
+ }
665
+ case 'workspace.discardFile': {
666
+ const workspace = requireWorkspace(command.workspaceId);
667
+ const result = await diffStore.discardFile({
668
+ workspaceId: workspace.id,
669
+ workspacePath: workspace.localPath,
670
+ path: command.path,
671
+ });
672
+ send(ws, { type: 'ack', id, result });
673
+ break;
674
+ }
675
+ case 'workspace.readFile': {
676
+ const workspace = requireWorkspace(command.workspaceId);
677
+ const result = await diffStore.readFileContents({
678
+ workspaceId: workspace.id,
679
+ workspacePath: workspace.localPath,
680
+ path: command.path,
681
+ });
682
+ send(ws, { type: 'ack', id, result });
683
+ return;
684
+ }
685
+ case 'file.readExternal': {
686
+ const allowed = await sessionTranscriptAllowsExternalPath({
687
+ store,
688
+ workspaceId: command.workspaceId,
689
+ sessionId: command.sessionId,
690
+ requestedPath: command.path,
691
+ });
692
+ if (!allowed) throw new Error('External file is not available in this session.');
693
+ const result = await diffStore.readExternalFileContents({ path: command.path });
694
+ send(ws, { type: 'ack', id, result });
695
+ return;
696
+ }
697
+
698
+ case 'workspace.listFiles': {
699
+ const workspace = requireWorkspace(command.workspaceId);
700
+ if (workspace.setupState !== 'ready') throw new Error('Workspace is not ready yet');
701
+ const result = await listWorkspaceFiles(workspace.localPath, command.limit);
702
+ send(ws, { type: 'ack', id, result });
703
+ return;
704
+ }
705
+ case 'workspace.searchFiles': {
706
+ const workspace = requireWorkspace(command.workspaceId);
707
+ if (workspace.setupState !== 'ready') throw new Error('Workspace is not ready yet');
708
+ const result = await searchWorkspaceFiles(
709
+ workspace.localPath,
710
+ command.query,
711
+ command.limit,
712
+ );
713
+ send(ws, { type: 'ack', id, result });
714
+ return;
715
+ }
716
+ case 'workspace.commitAndPush': {
717
+ const result = await sendWorkspaceInstruction(
718
+ command.workspaceId,
719
+ command.sessionId,
720
+ 'Commit and Push',
721
+ [],
722
+ 'commit_and_push',
723
+ );
724
+ send(ws, { type: 'ack', id, result });
725
+ break;
726
+ }
727
+ case 'workspace.pullLatestMain': {
728
+ const result = await sendWorkspaceInstruction(
729
+ command.workspaceId,
730
+ command.sessionId,
731
+ 'Pull latest main',
732
+ [],
733
+ 'pull_latest_main',
734
+ );
735
+ send(ws, { type: 'ack', id, result });
736
+ break;
737
+ }
738
+ case 'workspace.createPr': {
739
+ const workspace = requireWorkspace(command.workspaceId);
740
+ const directory = store.requireDirectory(workspace.directoryId);
741
+ await diffStore.refreshWorkspaceGitSnapshot(workspace.id, workspace.localPath);
742
+ const attachment = await writeCreatePrInstructionsAttachment({
743
+ workspace,
744
+ directory,
745
+ git: diffStore.getWorkspaceGitSnapshot(workspace.id),
746
+ });
747
+ const result = await sendWorkspaceInstruction(
748
+ command.workspaceId,
749
+ command.sessionId,
750
+ 'Create a pull request using the attached instructions.',
751
+ [attachment],
752
+ 'create_pr',
753
+ );
754
+ send(ws, { type: 'ack', id, result });
755
+ break;
756
+ }
757
+ case 'workspace.fixCi': {
758
+ const workspace = requireWorkspace(command.workspaceId);
759
+ const logs = await prManager.fetchFailingCheckLogs(workspace.id);
760
+ const attachment = await writeFailingCiLogsAttachment({ workspace, logs });
761
+ const result = await sendWorkspaceInstruction(
762
+ command.workspaceId,
763
+ command.sessionId,
764
+ 'Fix the failing CI using the attached logs.',
765
+ [attachment],
766
+ 'fix_ci',
767
+ );
768
+ send(ws, { type: 'ack', id, result });
769
+ break;
770
+ }
771
+ case 'workspace.resolveMergeConflicts': {
772
+ const workspace = requireWorkspace(command.workspaceId);
773
+ const directory = store.requireDirectory(workspace.directoryId);
774
+ const github = prManager.getWorkspaceGitHubSnapshot(workspace.id);
775
+ if (!github || github.status === 'none' || github.status === 'unknown') {
776
+ throw new Error('Workspace does not have a current pull request snapshot');
777
+ }
778
+ if (github.hasMergeConflicts === undefined) {
779
+ throw new Error('Workspace merge conflict status is unknown');
780
+ }
781
+ if (!github.hasMergeConflicts) {
782
+ throw new Error('Workspace does not have merge conflicts to resolve');
783
+ }
784
+ await diffStore.refreshWorkspaceGitSnapshot(workspace.id, workspace.localPath);
785
+ const attachment = await writeMergeConflictInstructionsAttachment({
786
+ workspace,
787
+ directory,
788
+ git: diffStore.getWorkspaceGitSnapshot(workspace.id),
789
+ github,
790
+ });
791
+ const result = await sendWorkspaceInstruction(
792
+ command.workspaceId,
793
+ command.sessionId,
794
+ 'Resolve merge conflicts using the attached instructions.',
795
+ [attachment],
796
+ 'resolve_merge_conflicts',
797
+ );
798
+ send(ws, { type: 'ack', id, result });
799
+ break;
800
+ }
801
+ case 'workspace.markPrReady': {
802
+ const result = await prManager.markWorkspacePullRequestReady(command.workspaceId);
803
+ send(ws, { type: 'ack', id, result });
804
+ break;
805
+ }
806
+ case 'workspace.addressReviewComments': {
807
+ const workspace = requireWorkspace(command.workspaceId);
808
+ const github = prManager.getWorkspaceGitHubSnapshot(workspace.id);
809
+ if (!github || github.status === 'none' || github.status === 'unknown') {
810
+ throw new Error('Workspace does not have a current pull request snapshot');
811
+ }
812
+ if (command.commentIds.length === 0) {
813
+ throw new Error('Select at least one review comment');
814
+ }
815
+
816
+ const commentsById = new Map(github.comments.map((comment) => [comment.id, comment]));
817
+ const selectedComments = command.commentIds.map((commentId) => {
818
+ const comment = commentsById.get(commentId);
819
+ if (!comment) throw new Error(`Review comment is no longer available: ${commentId}`);
820
+ return comment;
821
+ });
822
+
823
+ const attachment = await writeSelectedReviewCommentsAttachment({
824
+ workspace,
825
+ comments: selectedComments,
826
+ prNumber: github.prNumber,
827
+ prTitle: github.title,
828
+ });
829
+ const result = await sendWorkspaceInstruction(
830
+ command.workspaceId,
831
+ command.sessionId,
832
+ 'Address the selected PR review comments using the attached review context.',
833
+ [attachment],
834
+ 'address_review_comments',
835
+ );
836
+ send(ws, { type: 'ack', id, result });
837
+ break;
838
+ }
839
+ case 'workspace.mergePr': {
840
+ const result = await prManager.mergeWorkspacePullRequest(command.workspaceId);
841
+ send(ws, { type: 'ack', id, result });
842
+ break;
843
+ }
844
+ case 'workspace.reviewChanges': {
845
+ const workspace = requireWorkspace(command.workspaceId);
846
+ const directory = store.requireDirectory(workspace.directoryId);
847
+ await diffStore.refreshWorkspaceGitSnapshot(workspace.id, workspace.localPath);
848
+ const attachment = await writeReviewInstructionsAttachment({
849
+ workspace,
850
+ directory,
851
+ git: diffStore.getWorkspaceGitSnapshot(workspace.id),
852
+ });
853
+ const session = await store.createSession(workspace.id);
854
+ try {
855
+ await sendWorkspaceInstruction(
856
+ command.workspaceId,
857
+ session.id,
858
+ 'Review the changes in this workspace using the attached instructions.',
859
+ [attachment],
860
+ 'review',
861
+ );
862
+ } catch (error) {
863
+ await agent.cancel(session.id);
864
+ await agent.closeSession(session.id);
865
+ await store.removeSession(session.id);
866
+ throw error;
867
+ }
868
+ await broadcastSnapshots();
869
+ send(ws, { type: 'ack', id, result: { sessionId: session.id } });
870
+ return;
871
+ }
872
+ case 'workspace.updateScratchpad': {
873
+ requireWorkspace(command.workspaceId);
874
+ const snapshot = await scratchpadManager.updateScratchpad(
875
+ command.workspaceId,
876
+ command.content,
877
+ );
878
+ send(ws, { type: 'ack', id, result: snapshot });
879
+ await pushScratchpadSnapshot(command.workspaceId);
880
+ return;
881
+ }
882
+ case 'session.create': {
883
+ const session = await store.createSession(command.workspaceId);
884
+ send(ws, { type: 'ack', id, result: { sessionId: session.id } });
885
+ break;
886
+ }
887
+ case 'session.rename': {
888
+ await store.renameSession(command.sessionId, command.title);
889
+ send(ws, { type: 'ack', id });
890
+ break;
891
+ }
892
+ case 'session.remove': {
893
+ await agent.cancel(command.sessionId);
894
+ await agent.closeSession(command.sessionId);
895
+ await store.removeSession(command.sessionId);
896
+ send(ws, { type: 'ack', id });
897
+ break;
898
+ }
899
+ case 'session.send': {
900
+ const result = await agent.send(command);
901
+ send(ws, { type: 'ack', id, result });
902
+ break;
903
+ }
904
+ case 'session.cancel': {
905
+ await agent.cancel(command.sessionId);
906
+ send(ws, { type: 'ack', id });
907
+ break;
908
+ }
909
+ case 'session.stopDraining': {
910
+ await agent.stopDraining(command.sessionId);
911
+ send(ws, { type: 'ack', id });
912
+ break;
913
+ }
914
+ case 'session.loadHistory': {
915
+ const result = store.getMessagesPageBefore(
916
+ command.sessionId,
917
+ command.beforeCursor,
918
+ command.limit,
919
+ );
920
+ send(ws, { type: 'ack', id, result });
921
+ return;
922
+ }
923
+ case 'session.respondTool': {
924
+ await agent.respondTool(command);
925
+ send(ws, { type: 'ack', id });
926
+ break;
927
+ }
928
+ case 'session.listCommands': {
929
+ const result = await agent.listCommands(command.sessionId, command.provider);
930
+ send(ws, { type: 'ack', id, result });
931
+ break;
932
+ }
933
+ case 'session.dequeue': {
934
+ await agent.dequeueMessage(command.sessionId, command.messageId);
935
+ send(ws, { type: 'ack', id });
936
+ break;
937
+ }
938
+ case 'terminal.create': {
939
+ const workspace = requireWorkspace(command.workspaceId);
940
+ if (workspace.setupState !== 'ready') throw new Error('Workspace is not ready yet');
941
+ const snapshot = terminals.createTerminal({
942
+ workspacePath: workspace.localPath,
943
+ terminalId: command.terminalId,
944
+ cols: command.cols,
945
+ rows: command.rows,
946
+ scrollback: command.scrollback,
947
+ });
948
+ send(ws, { type: 'ack', id, result: snapshot });
949
+ return;
950
+ }
951
+ case 'terminal.input': {
952
+ terminals.write(command.terminalId, command.data);
953
+ send(ws, { type: 'ack', id });
954
+ return;
955
+ }
956
+ case 'terminal.resize': {
957
+ terminals.resize(command.terminalId, command.cols, command.rows);
958
+ send(ws, { type: 'ack', id });
959
+ return;
960
+ }
961
+ case 'terminal.close': {
962
+ terminals.close(command.terminalId);
963
+ send(ws, { type: 'ack', id });
964
+ await pushTerminalSnapshot(command.terminalId);
965
+ return;
966
+ }
967
+ }
968
+
969
+ await broadcastSnapshots();
970
+ } catch (error) {
971
+ const messageText = error instanceof Error ? error.message : String(error);
972
+ console.error('[ws-router] command failed', { id, type: command.type, message: messageText });
973
+ send(ws, { type: 'error', id, message: messageText });
974
+ }
975
+ }
976
+
977
+ return {
978
+ handleOpen(ws: ServerWebSocket<ClientState>) {
979
+ sockets.add(ws);
980
+ },
981
+ handleClose(ws: ServerWebSocket<ClientState>) {
982
+ sockets.delete(ws);
983
+ },
984
+ broadcastSnapshots,
985
+ async handleMessage(
986
+ ws: ServerWebSocket<ClientState>,
987
+ raw: string | Buffer | ArrayBuffer | Uint8Array,
988
+ ) {
989
+ let parsed: unknown;
990
+ try {
991
+ parsed = JSON.parse(String(raw));
992
+ } catch {
993
+ send(ws, { type: 'error', message: 'Invalid JSON' });
994
+ return;
995
+ }
996
+
997
+ if (!isClientEnvelope(parsed)) {
998
+ send(ws, { type: 'error', message: 'Invalid envelope' });
999
+ return;
1000
+ }
1001
+
1002
+ if (parsed.type === 'subscribe') {
1003
+ const snapshotSignatures = ensureSnapshotSignatures(ws);
1004
+ ws.data.subscriptions.set(parsed.id, parsed.topic);
1005
+ snapshotSignatures.delete(parsed.id);
1006
+
1007
+ if (parsed.topic.type === 'workspace') {
1008
+ const { workspaceId } = parsed.topic;
1009
+ if (store.getWorkspace(workspaceId)) {
1010
+ void refreshWorkspaceOpenState(workspaceId)
1011
+ .then(() => pushSnapshots(ws))
1012
+ .catch((error) =>
1013
+ broadcastError(error instanceof Error ? error.message : String(error)),
1014
+ );
1015
+ }
1016
+ }
1017
+
1018
+ await pushSnapshots(ws);
1019
+ return;
1020
+ }
1021
+
1022
+ if (parsed.type === 'unsubscribe') {
1023
+ const snapshotSignatures = ensureSnapshotSignatures(ws);
1024
+ ws.data.subscriptions.delete(parsed.id);
1025
+ snapshotSignatures.delete(parsed.id);
1026
+ send(ws, { type: 'ack', id: parsed.id });
1027
+ return;
1028
+ }
1029
+
1030
+ await handleCommand(ws, parsed);
1031
+ },
1032
+ dispose() {
1033
+ agent.setBackgroundErrorReporter?.(null);
1034
+ disposeTerminalEvents();
1035
+ disposeKeybindingEvents();
1036
+ disposeUpdateEvents();
1037
+ },
1038
+ };
1039
+ }