@neuralnomads/codenomad-dev 0.10.3-dev-20260213-ba418a85

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 (462) hide show
  1. package/README.md +126 -0
  2. package/dist/api-types.js +1 -0
  3. package/dist/auth/auth-store.js +134 -0
  4. package/dist/auth/http-auth.js +37 -0
  5. package/dist/auth/manager.js +128 -0
  6. package/dist/auth/password-hash.js +32 -0
  7. package/dist/auth/session-manager.js +17 -0
  8. package/dist/auth/token-manager.js +27 -0
  9. package/dist/background-processes/manager.js +437 -0
  10. package/dist/bin.js +24 -0
  11. package/dist/config/binaries.js +148 -0
  12. package/dist/config/location.js +57 -0
  13. package/dist/config/schema.js +70 -0
  14. package/dist/config/store.js +200 -0
  15. package/dist/events/bus.js +41 -0
  16. package/dist/filesystem/__tests__/search-cache.test.js +40 -0
  17. package/dist/filesystem/browser.js +285 -0
  18. package/dist/filesystem/search-cache.js +43 -0
  19. package/dist/filesystem/search.js +135 -0
  20. package/dist/index.js +410 -0
  21. package/dist/integrations/github/bot-signature.js +11 -0
  22. package/dist/integrations/github/git-ops.js +133 -0
  23. package/dist/integrations/github/github-types.js +1 -0
  24. package/dist/integrations/github/job-runner.js +608 -0
  25. package/dist/integrations/github/octokit.js +58 -0
  26. package/dist/integrations/github/sanitize-webhook.js +42 -0
  27. package/dist/integrations/github/webhook-verify.js +21 -0
  28. package/dist/integrations/github/workspace-context.js +10 -0
  29. package/dist/integrations/github/worktree-context.js +15 -0
  30. package/dist/launcher.js +149 -0
  31. package/dist/loader.js +21 -0
  32. package/dist/logger.js +109 -0
  33. package/dist/opencode/request-context.js +39 -0
  34. package/dist/opencode/worktree-directory.js +42 -0
  35. package/dist/opencode-config/README.md +32 -0
  36. package/dist/opencode-config/opencode.jsonc +3 -0
  37. package/dist/opencode-config/package.json +9 -0
  38. package/dist/opencode-config/plugin/codenomad.ts +32 -0
  39. package/dist/opencode-config/plugin/lib/background-process.ts +253 -0
  40. package/dist/opencode-config/plugin/lib/client.ts +133 -0
  41. package/dist/opencode-config/plugin/lib/request.ts +214 -0
  42. package/dist/opencode-config-template/README.md +32 -0
  43. package/dist/opencode-config-template/opencode.jsonc +3 -0
  44. package/dist/opencode-config-template/plugin/codenomad.ts +40 -0
  45. package/dist/opencode-config-template/plugin/lib/background-process.ts +160 -0
  46. package/dist/opencode-config-template/plugin/lib/client.ts +165 -0
  47. package/dist/opencode-config.js +26 -0
  48. package/dist/plugins/channel.js +40 -0
  49. package/dist/plugins/handlers.js +17 -0
  50. package/dist/releases/dev-release-monitor.js +75 -0
  51. package/dist/releases/release-monitor.js +107 -0
  52. package/dist/server/http-server.js +547 -0
  53. package/dist/server/network-addresses.js +72 -0
  54. package/dist/server/routes/auth-pages/login.html +134 -0
  55. package/dist/server/routes/auth-pages/token.html +93 -0
  56. package/dist/server/routes/auth.js +134 -0
  57. package/dist/server/routes/background-processes.js +60 -0
  58. package/dist/server/routes/config.js +59 -0
  59. package/dist/server/routes/events.js +43 -0
  60. package/dist/server/routes/filesystem.js +43 -0
  61. package/dist/server/routes/github-plugin.js +215 -0
  62. package/dist/server/routes/github-webhook.js +32 -0
  63. package/dist/server/routes/meta.js +47 -0
  64. package/dist/server/routes/plugin.js +52 -0
  65. package/dist/server/routes/storage.js +52 -0
  66. package/dist/server/routes/workspaces.js +89 -0
  67. package/dist/server/routes/worktrees.js +156 -0
  68. package/dist/server/tls.js +224 -0
  69. package/dist/storage/instance-store.js +56 -0
  70. package/dist/ui/__tests__/remote-ui.test.js +46 -0
  71. package/dist/ui/remote-ui.js +462 -0
  72. package/dist/workspaces/git-worktrees.js +199 -0
  73. package/dist/workspaces/instance-events.js +180 -0
  74. package/dist/workspaces/manager.js +375 -0
  75. package/dist/workspaces/opencode-auth.js +16 -0
  76. package/dist/workspaces/runtime.js +346 -0
  77. package/dist/workspaces/worktree-map.js +116 -0
  78. package/package.json +49 -0
  79. package/public/apple-touch-icon-180x180.png +0 -0
  80. package/public/assets/CodeNomad-Icon-bmTWNPXy.png +0 -0
  81. package/public/assets/abap-BdImnpbu.js +1 -0
  82. package/public/assets/actionscript-3-CfeIJUat.js +1 -0
  83. package/public/assets/ada-bCR0ucgS.js +1 -0
  84. package/public/assets/andromeeda-C-Jbm3Hp.js +1 -0
  85. package/public/assets/angular-html-CU67Zn6k.js +1 -0
  86. package/public/assets/angular-ts-BwZT4LLn.js +1 -0
  87. package/public/assets/apache-Pmp26Uib.js +1 -0
  88. package/public/assets/apex-DhZLUxFE.js +1 -0
  89. package/public/assets/apl-dKokRX4l.js +1 -0
  90. package/public/assets/applescript-Co6uUVPk.js +1 -0
  91. package/public/assets/ara-BRHolxvo.js +1 -0
  92. package/public/assets/asciidoc-Dv7Oe6Be.js +1 -0
  93. package/public/assets/asm-D_Q5rh1f.js +1 -0
  94. package/public/assets/astro-CbQHKStN.js +1 -0
  95. package/public/assets/aurora-x-D-2ljcwZ.js +1 -0
  96. package/public/assets/awk-DMzUqQB5.js +1 -0
  97. package/public/assets/ayu-dark-Cv9koXgw.js +1 -0
  98. package/public/assets/ballerina-BFfxhgS-.js +1 -0
  99. package/public/assets/bat-BkioyH1T.js +1 -0
  100. package/public/assets/beancount-k_qm7-4y.js +1 -0
  101. package/public/assets/berry-D08WgyRC.js +1 -0
  102. package/public/assets/bibtex-CHM0blh-.js +1 -0
  103. package/public/assets/bicep-Bmn6On1c.js +1 -0
  104. package/public/assets/blade-DVc8C-J4.js +1 -0
  105. package/public/assets/bsl-BO_Y6i37.js +1 -0
  106. package/public/assets/c-BIGW1oBm.js +1 -0
  107. package/public/assets/cadence-Bv_4Rxtq.js +1 -0
  108. package/public/assets/cairo-KRGpt6FW.js +1 -0
  109. package/public/assets/catppuccin-frappe-DFWUc33u.js +1 -0
  110. package/public/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
  111. package/public/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
  112. package/public/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
  113. package/public/assets/clarity-D53aC0YG.js +1 -0
  114. package/public/assets/clojure-P80f7IUj.js +1 -0
  115. package/public/assets/cmake-D1j8_8rp.js +1 -0
  116. package/public/assets/cobol-nwyudZeR.js +1 -0
  117. package/public/assets/codeowners-Bp6g37R7.js +1 -0
  118. package/public/assets/codeql-DsOJ9woJ.js +1 -0
  119. package/public/assets/coffee-Ch7k5sss.js +1 -0
  120. package/public/assets/common-lisp-Cg-RD9OK.js +1 -0
  121. package/public/assets/coq-DkFqJrB1.js +1 -0
  122. package/public/assets/core-BSTVzpXI.js +1 -0
  123. package/public/assets/cpp-CofmeUqb.js +1 -0
  124. package/public/assets/crystal-tKQVLTB8.js +1 -0
  125. package/public/assets/csharp-CX12Zw3r.js +1 -0
  126. package/public/assets/css-DPfMkruS.js +1 -0
  127. package/public/assets/csv-fuZLfV_i.js +1 -0
  128. package/public/assets/cue-D82EKSYY.js +1 -0
  129. package/public/assets/cypher-COkxafJQ.js +1 -0
  130. package/public/assets/d-85-TOEBH.js +1 -0
  131. package/public/assets/dark-plus-eOWES_5F.js +1 -0
  132. package/public/assets/dart-CF10PKvl.js +1 -0
  133. package/public/assets/dax-CEL-wOlO.js +1 -0
  134. package/public/assets/desktop-BmXAJ9_W.js +1 -0
  135. package/public/assets/diff-D97Zzqfu.js +1 -0
  136. package/public/assets/docker-BcOcwvcX.js +1 -0
  137. package/public/assets/dotenv-Da5cRb03.js +1 -0
  138. package/public/assets/dracula-BzJJZx-M.js +1 -0
  139. package/public/assets/dracula-soft-BXkSAIEj.js +1 -0
  140. package/public/assets/dream-maker-BtqSS_iP.js +1 -0
  141. package/public/assets/edge-BkV0erSs.js +1 -0
  142. package/public/assets/elixir-CDX3lj18.js +1 -0
  143. package/public/assets/elm-DbKCFpqz.js +1 -0
  144. package/public/assets/emacs-lisp-C9XAeP06.js +1 -0
  145. package/public/assets/erb-BOJIQeun.js +1 -0
  146. package/public/assets/erlang-DsQrWhSR.js +1 -0
  147. package/public/assets/everforest-dark-BgDCqdQA.js +1 -0
  148. package/public/assets/everforest-light-C8M2exoo.js +1 -0
  149. package/public/assets/fennel-BYunw83y.js +1 -0
  150. package/public/assets/fish-BvzEVeQv.js +1 -0
  151. package/public/assets/fluent-C4IJs8-o.js +1 -0
  152. package/public/assets/fortran-fixed-form-BZjJHVRy.js +1 -0
  153. package/public/assets/fortran-free-form-D22FLkUw.js +1 -0
  154. package/public/assets/fsharp-CXgrBDvD.js +1 -0
  155. package/public/assets/gdresource-B7Tvp0Sc.js +1 -0
  156. package/public/assets/gdscript-DTMYz4Jt.js +1 -0
  157. package/public/assets/gdshader-DkwncUOv.js +1 -0
  158. package/public/assets/genie-D0YGMca9.js +1 -0
  159. package/public/assets/gherkin-DyxjwDmM.js +1 -0
  160. package/public/assets/git-commit-F4YmCXRG.js +1 -0
  161. package/public/assets/git-rebase-r7XF79zn.js +1 -0
  162. package/public/assets/github-dark-DHJKELXO.js +1 -0
  163. package/public/assets/github-dark-default-Cuk6v7N8.js +1 -0
  164. package/public/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  165. package/public/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  166. package/public/assets/github-light-DAi9KRSo.js +1 -0
  167. package/public/assets/github-light-default-D7oLnXFd.js +1 -0
  168. package/public/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  169. package/public/assets/gleam-BspZqrRM.js +1 -0
  170. package/public/assets/glimmer-js-Rg0-pVw9.js +1 -0
  171. package/public/assets/glimmer-ts-U6CK756n.js +1 -0
  172. package/public/assets/glsl-DplSGwfg.js +1 -0
  173. package/public/assets/gnuplot-DdkO51Og.js +1 -0
  174. package/public/assets/go-Dn2_MT6a.js +1 -0
  175. package/public/assets/graphql-ChdNCCLP.js +1 -0
  176. package/public/assets/groovy-gcz8RCvz.js +1 -0
  177. package/public/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  178. package/public/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  179. package/public/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  180. package/public/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  181. package/public/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  182. package/public/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  183. package/public/assets/hack-CaT9iCJl.js +1 -0
  184. package/public/assets/haml-B8DHNrY2.js +1 -0
  185. package/public/assets/handlebars-BL8al0AC.js +1 -0
  186. package/public/assets/haskell-Df6bDoY_.js +1 -0
  187. package/public/assets/haxe-CzTSHFRz.js +1 -0
  188. package/public/assets/hcl-BWvSN4gD.js +1 -0
  189. package/public/assets/hjson-D5-asLiD.js +1 -0
  190. package/public/assets/hlsl-D3lLCCz7.js +1 -0
  191. package/public/assets/houston-DnULxvSX.js +1 -0
  192. package/public/assets/html-GMplVEZG.js +1 -0
  193. package/public/assets/html-derivative-BFtXZ54Q.js +1 -0
  194. package/public/assets/http-jrhK8wxY.js +1 -0
  195. package/public/assets/hurl-irOxFIW8.js +1 -0
  196. package/public/assets/hxml-Bvhsp5Yf.js +1 -0
  197. package/public/assets/hy-DFXneXwc.js +1 -0
  198. package/public/assets/imba-DGztddWO.js +1 -0
  199. package/public/assets/index-D4PT0yE4.js +1 -0
  200. package/public/assets/index-DN20ggb1.js +1 -0
  201. package/public/assets/index-DdQ7zIzB.js +1 -0
  202. package/public/assets/index-Dl-rJJuP.js +1 -0
  203. package/public/assets/index-Dlo2gDiy.css +1 -0
  204. package/public/assets/ini-BEwlwnbL.js +1 -0
  205. package/public/assets/java-CylS5w8V.js +1 -0
  206. package/public/assets/javascript-wDzz0qaB.js +1 -0
  207. package/public/assets/jinja-4LBKfQ-Z.js +1 -0
  208. package/public/assets/jison-wvAkD_A8.js +1 -0
  209. package/public/assets/json-Cp-IABpG.js +1 -0
  210. package/public/assets/json5-C9tS-k6U.js +1 -0
  211. package/public/assets/jsonc-Des-eS-w.js +1 -0
  212. package/public/assets/jsonl-DcaNXYhu.js +1 -0
  213. package/public/assets/jsonnet-DFQXde-d.js +1 -0
  214. package/public/assets/jssm-C2t-YnRu.js +1 -0
  215. package/public/assets/jsx-g9-lgVsj.js +1 -0
  216. package/public/assets/julia-C8NyazO9.js +1 -0
  217. package/public/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  218. package/public/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  219. package/public/assets/kanagawa-wave-DWedfzmr.js +1 -0
  220. package/public/assets/kdl-DV7GczEv.js +1 -0
  221. package/public/assets/kotlin-BdnUsdx6.js +1 -0
  222. package/public/assets/kusto-BvAqAH-y.js +1 -0
  223. package/public/assets/laserwave-DUszq2jm.js +1 -0
  224. package/public/assets/latex-BUKiar2Z.js +1 -0
  225. package/public/assets/lean-DP1Csr6i.js +1 -0
  226. package/public/assets/less-B1dDrJ26.js +1 -0
  227. package/public/assets/light-plus-B7mTdjB0.js +1 -0
  228. package/public/assets/liquid-DYVedYrR.js +1 -0
  229. package/public/assets/llvm-BtvRca6l.js +1 -0
  230. package/public/assets/loading-CmEVQgyj.css +1 -0
  231. package/public/assets/loading-DgqIiz-T.js +1 -0
  232. package/public/assets/log-2UxHyX5q.js +1 -0
  233. package/public/assets/logo-BtOb2qkB.js +1 -0
  234. package/public/assets/lua-BbnMAYS6.js +1 -0
  235. package/public/assets/luau-CXu1NL6O.js +1 -0
  236. package/public/assets/main-CSlDZj4f.js +188 -0
  237. package/public/assets/main-HAZkIolJ.css +19 -0
  238. package/public/assets/make-CHLpvVh8.js +1 -0
  239. package/public/assets/markdown-Cvjx9yec.js +1 -0
  240. package/public/assets/marko-CPi9NSCl.js +1 -0
  241. package/public/assets/material-theme-D5KoaKCx.js +1 -0
  242. package/public/assets/material-theme-darker-BfHTSMKl.js +1 -0
  243. package/public/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  244. package/public/assets/material-theme-ocean-CyktbL80.js +1 -0
  245. package/public/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  246. package/public/assets/matlab-D7o27uSR.js +1 -0
  247. package/public/assets/mdc-DUICxH0z.js +1 -0
  248. package/public/assets/mdx-Cmh6b_Ma.js +1 -0
  249. package/public/assets/mermaid-DKYwYmdq.js +1 -0
  250. package/public/assets/min-dark-CafNBF8u.js +1 -0
  251. package/public/assets/min-light-CTRr51gU.js +1 -0
  252. package/public/assets/mipsasm-CKIfxQSi.js +1 -0
  253. package/public/assets/mojo-1DNp92w6.js +1 -0
  254. package/public/assets/monokai-D4h5O-jR.js +1 -0
  255. package/public/assets/move-Bu9oaDYs.js +1 -0
  256. package/public/assets/narrat-DRg8JJMk.js +1 -0
  257. package/public/assets/nextflow-CUEJCptM.js +1 -0
  258. package/public/assets/nginx-DknmC5AR.js +1 -0
  259. package/public/assets/night-owl-C39BiMTA.js +1 -0
  260. package/public/assets/nim-CVrawwO9.js +1 -0
  261. package/public/assets/nix-BbRYJGeE.js +1 -0
  262. package/public/assets/nord-Ddv68eIx.js +1 -0
  263. package/public/assets/nushell-C-sUppwS.js +1 -0
  264. package/public/assets/objective-c-DXmwc3jG.js +1 -0
  265. package/public/assets/objective-cpp-CLxacb5B.js +1 -0
  266. package/public/assets/ocaml-C0hk2d4L.js +1 -0
  267. package/public/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  268. package/public/assets/one-light-PoHY5YXO.js +1 -0
  269. package/public/assets/pascal-D93ZcfNL.js +1 -0
  270. package/public/assets/perl-C0TMdlhV.js +1 -0
  271. package/public/assets/php-CDn_0X-4.js +1 -0
  272. package/public/assets/pkl-u5AG7uiY.js +1 -0
  273. package/public/assets/plastic-3e1v2bzS.js +1 -0
  274. package/public/assets/plsql-ChMvpjG-.js +1 -0
  275. package/public/assets/po-BTJTHyun.js +1 -0
  276. package/public/assets/poimandres-CS3Unz2-.js +1 -0
  277. package/public/assets/polar-C0HS_06l.js +1 -0
  278. package/public/assets/postcss-CXtECtnM.js +1 -0
  279. package/public/assets/powerquery-CEu0bR-o.js +1 -0
  280. package/public/assets/powershell-Dpen1YoG.js +1 -0
  281. package/public/assets/prisma-Dd19v3D-.js +1 -0
  282. package/public/assets/prolog-CbFg5uaA.js +1 -0
  283. package/public/assets/proto-DyJlTyXw.js +1 -0
  284. package/public/assets/pug-CGlum2m_.js +1 -0
  285. package/public/assets/puppet-BMWR74SV.js +1 -0
  286. package/public/assets/purescript-CklMAg4u.js +1 -0
  287. package/public/assets/python-B6aJPvgy.js +1 -0
  288. package/public/assets/qml-3beO22l8.js +1 -0
  289. package/public/assets/qmldir-C8lEn-DE.js +1 -0
  290. package/public/assets/qss-IeuSbFQv.js +1 -0
  291. package/public/assets/r-DiinP2Uv.js +1 -0
  292. package/public/assets/racket-BqYA7rlc.js +1 -0
  293. package/public/assets/raku-DXvB9xmW.js +1 -0
  294. package/public/assets/razor-WgofotgN.js +1 -0
  295. package/public/assets/red-bN70gL4F.js +1 -0
  296. package/public/assets/reg-C-SQnVFl.js +1 -0
  297. package/public/assets/regexp-CDVJQ6XC.js +1 -0
  298. package/public/assets/rel-C3B-1QV4.js +1 -0
  299. package/public/assets/riscv-BM1_JUlF.js +1 -0
  300. package/public/assets/rose-pine-BHrmToEH.js +1 -0
  301. package/public/assets/rose-pine-dawn-CnK8MTSM.js +1 -0
  302. package/public/assets/rose-pine-moon-NleAzG8P.js +1 -0
  303. package/public/assets/rosmsg-BJDFO7_C.js +1 -0
  304. package/public/assets/rst-B0xPkSld.js +1 -0
  305. package/public/assets/ruby-BvKwtOVI.js +1 -0
  306. package/public/assets/rust-B1yitclQ.js +1 -0
  307. package/public/assets/sas-cz2c8ADy.js +1 -0
  308. package/public/assets/sass-Cj5Yp3dK.js +1 -0
  309. package/public/assets/scala-C151Ov-r.js +1 -0
  310. package/public/assets/scheme-C98Dy4si.js +1 -0
  311. package/public/assets/scss-OYdSNvt2.js +1 -0
  312. package/public/assets/sdbl-DVxCFoDh.js +1 -0
  313. package/public/assets/shaderlab-Dg9Lc6iA.js +1 -0
  314. package/public/assets/shellscript-Yzrsuije.js +1 -0
  315. package/public/assets/shellsession-BADoaaVG.js +1 -0
  316. package/public/assets/slack-dark-BthQWCQV.js +1 -0
  317. package/public/assets/slack-ochin-DqwNpetd.js +1 -0
  318. package/public/assets/smalltalk-BERRCDM3.js +1 -0
  319. package/public/assets/snazzy-light-Bw305WKR.js +1 -0
  320. package/public/assets/solarized-dark-DXbdFlpD.js +1 -0
  321. package/public/assets/solarized-light-L9t79GZl.js +1 -0
  322. package/public/assets/solidity-BbcW6ACK.js +1 -0
  323. package/public/assets/soy-Brmx7dQM.js +1 -0
  324. package/public/assets/sparql-rVzFXLq3.js +1 -0
  325. package/public/assets/splunk-BtCnVYZw.js +1 -0
  326. package/public/assets/sql-BLtJtn59.js +1 -0
  327. package/public/assets/ssh-config-_ykCGR6B.js +1 -0
  328. package/public/assets/stata-BH5u7GGu.js +1 -0
  329. package/public/assets/stylus-BEDo0Tqx.js +1 -0
  330. package/public/assets/svelte-3Dk4HxPD.js +1 -0
  331. package/public/assets/swift-Dg5xB15N.js +1 -0
  332. package/public/assets/synthwave-84-CbfX1IO0.js +1 -0
  333. package/public/assets/system-verilog-CnnmHF94.js +1 -0
  334. package/public/assets/systemd-4A_iFExJ.js +1 -0
  335. package/public/assets/talonscript-CkByrt1z.js +1 -0
  336. package/public/assets/tasl-QIJgUcNo.js +1 -0
  337. package/public/assets/tcl-dwOrl1Do.js +1 -0
  338. package/public/assets/templ-W15q3VgB.js +1 -0
  339. package/public/assets/terraform-BETggiCN.js +1 -0
  340. package/public/assets/tex-Cppo0RY3.js +1 -0
  341. package/public/assets/tokyo-night-hegEt444.js +1 -0
  342. package/public/assets/toml-vGWfd6FD.js +1 -0
  343. package/public/assets/ts-tags-zn1MmPIZ.js +1 -0
  344. package/public/assets/tsv-B_m7g4N7.js +1 -0
  345. package/public/assets/tsx-COt5Ahok.js +1 -0
  346. package/public/assets/turtle-BsS91CYL.js +1 -0
  347. package/public/assets/twig-CO9l9SDP.js +1 -0
  348. package/public/assets/typescript-BPQ3VLAy.js +1 -0
  349. package/public/assets/typespec-Df68jz8_.js +1 -0
  350. package/public/assets/typst-DHCkPAjA.js +1 -0
  351. package/public/assets/v-BcVCzyr7.js +1 -0
  352. package/public/assets/vala-CsfeWuGM.js +1 -0
  353. package/public/assets/vb-D17OF-Vu.js +1 -0
  354. package/public/assets/verilog-BQ8w6xss.js +1 -0
  355. package/public/assets/vesper-DU1UobuO.js +1 -0
  356. package/public/assets/vhdl-CeAyd5Ju.js +1 -0
  357. package/public/assets/viml-CJc9bBzg.js +1 -0
  358. package/public/assets/vitesse-black-Bkuqu6BP.js +1 -0
  359. package/public/assets/vitesse-dark-D0r3Knsf.js +1 -0
  360. package/public/assets/vitesse-light-CVO1_9PV.js +1 -0
  361. package/public/assets/vue-CCoi5OLL.js +1 -0
  362. package/public/assets/vue-html-DAAvJJDi.js +1 -0
  363. package/public/assets/vue-vine-_Ih-lPRR.js +1 -0
  364. package/public/assets/vyper-CDx5xZoG.js +1 -0
  365. package/public/assets/wasm-CG6Dc4jp.js +1 -0
  366. package/public/assets/wasm-MzD3tlZU.js +1 -0
  367. package/public/assets/wenyan-BV7otONQ.js +1 -0
  368. package/public/assets/wgsl-Dx-B1_4e.js +1 -0
  369. package/public/assets/wikitext-BhOHFoWU.js +1 -0
  370. package/public/assets/wit-5i3qLPDT.js +1 -0
  371. package/public/assets/wolfram-lXgVvXCa.js +1 -0
  372. package/public/assets/xml-sdJ4AIDG.js +1 -0
  373. package/public/assets/xsl-CtQFsRM5.js +1 -0
  374. package/public/assets/yaml-Buea-lGh.js +1 -0
  375. package/public/assets/zenscript-DVFEvuxE.js +1 -0
  376. package/public/assets/zig-VOosw3JB.js +1 -0
  377. package/public/favicon.ico +0 -0
  378. package/public/index.html +38 -0
  379. package/public/loading.html +28 -0
  380. package/public/logo.png +0 -0
  381. package/public/manifest.webmanifest +1 -0
  382. package/public/maskable-icon-512x512.png +0 -0
  383. package/public/monaco/vs/base/browser/ui/codicons/codicon/codicon.ttf +0 -0
  384. package/public/monaco/vs/base/worker/workerMain.js +31 -0
  385. package/public/monaco/vs/basic-languages/cpp/cpp.js +10 -0
  386. package/public/monaco/vs/basic-languages/kotlin/kotlin.js +10 -0
  387. package/public/monaco/vs/basic-languages/markdown/markdown.js +10 -0
  388. package/public/monaco/vs/basic-languages/python/python.js +10 -0
  389. package/public/monaco/vs/editor/editor.main.css +8 -0
  390. package/public/monaco/vs/editor/editor.main.js +798 -0
  391. package/public/monaco/vs/language/css/cssMode.js +13 -0
  392. package/public/monaco/vs/language/css/cssWorker.js +77 -0
  393. package/public/monaco/vs/language/html/htmlMode.js +13 -0
  394. package/public/monaco/vs/language/html/htmlWorker.js +454 -0
  395. package/public/monaco/vs/language/json/jsonMode.js +19 -0
  396. package/public/monaco/vs/language/json/jsonWorker.js +42 -0
  397. package/public/monaco/vs/language/typescript/tsMode.js +20 -0
  398. package/public/monaco/vs/language/typescript/tsWorker.js +51328 -0
  399. package/public/monaco/vs/loader.js +11 -0
  400. package/public/monaco.worker.js +7 -0
  401. package/public/pwa-192x192.png +0 -0
  402. package/public/pwa-512x512.png +0 -0
  403. package/public/pwa-64x64.png +0 -0
  404. package/public/registerSW.js +1 -0
  405. package/public/sw.js +1 -0
  406. package/public/ui-version.json +3 -0
  407. package/public/workbox-60d14903.js +1 -0
  408. package/scripts/copy-auth-pages.mjs +22 -0
  409. package/scripts/copy-opencode-config.mjs +61 -0
  410. package/scripts/copy-ui-dist.mjs +21 -0
  411. package/src/api-types.ts +326 -0
  412. package/src/auth/auth-store.ts +175 -0
  413. package/src/auth/http-auth.ts +38 -0
  414. package/src/auth/manager.ts +163 -0
  415. package/src/auth/password-hash.ts +49 -0
  416. package/src/auth/session-manager.ts +23 -0
  417. package/src/auth/token-manager.ts +32 -0
  418. package/src/background-processes/manager.ts +519 -0
  419. package/src/bin.ts +29 -0
  420. package/src/config/binaries.ts +192 -0
  421. package/src/config/location.ts +78 -0
  422. package/src/config/schema.ts +104 -0
  423. package/src/config/store.ts +244 -0
  424. package/src/events/bus.ts +45 -0
  425. package/src/filesystem/__tests__/search-cache.test.ts +61 -0
  426. package/src/filesystem/browser.ts +353 -0
  427. package/src/filesystem/search-cache.ts +66 -0
  428. package/src/filesystem/search.ts +184 -0
  429. package/src/index.ts +540 -0
  430. package/src/launcher.ts +177 -0
  431. package/src/loader.ts +21 -0
  432. package/src/logger.ts +133 -0
  433. package/src/opencode-config.ts +31 -0
  434. package/src/plugins/channel.ts +55 -0
  435. package/src/plugins/handlers.ts +36 -0
  436. package/src/releases/dev-release-monitor.ts +118 -0
  437. package/src/releases/release-monitor.ts +149 -0
  438. package/src/server/http-server.ts +693 -0
  439. package/src/server/network-addresses.ts +75 -0
  440. package/src/server/routes/auth-pages/login.html +134 -0
  441. package/src/server/routes/auth-pages/token.html +93 -0
  442. package/src/server/routes/auth.ts +164 -0
  443. package/src/server/routes/background-processes.ts +85 -0
  444. package/src/server/routes/config.ts +76 -0
  445. package/src/server/routes/events.ts +61 -0
  446. package/src/server/routes/filesystem.ts +54 -0
  447. package/src/server/routes/meta.ts +58 -0
  448. package/src/server/routes/plugin.ts +75 -0
  449. package/src/server/routes/storage.ts +66 -0
  450. package/src/server/routes/workspaces.ts +113 -0
  451. package/src/server/routes/worktrees.ts +195 -0
  452. package/src/server/tls.ts +283 -0
  453. package/src/storage/instance-store.ts +64 -0
  454. package/src/ui/__tests__/remote-ui.test.ts +58 -0
  455. package/src/ui/remote-ui.ts +571 -0
  456. package/src/workspaces/git-worktrees.ts +241 -0
  457. package/src/workspaces/instance-events.ts +226 -0
  458. package/src/workspaces/manager.ts +493 -0
  459. package/src/workspaces/opencode-auth.ts +22 -0
  460. package/src/workspaces/runtime.ts +428 -0
  461. package/src/workspaces/worktree-map.ts +129 -0
  462. package/tsconfig.json +17 -0
@@ -0,0 +1,571 @@
1
+ import { createHash } from "crypto"
2
+ import fs from "fs"
3
+ import { promises as fsp } from "fs"
4
+ import os from "os"
5
+ import path from "path"
6
+ import { Readable } from "stream"
7
+ import { fetch } from "undici"
8
+ import yauzl from "yauzl"
9
+ import type { Logger } from "../logger"
10
+
11
+ export interface RemoteUiManifest {
12
+ minServerVersion: string
13
+ latestUIVersion: string
14
+ uiPackageURL: string
15
+ sha256: string
16
+ latestServerVersion?: string
17
+ latestServerUrl?: string
18
+ }
19
+
20
+ export type UiSource = "bundled" | "downloaded" | "previous" | "override" | "dev-proxy" | "missing"
21
+
22
+ export interface UiResolution {
23
+ uiStaticDir?: string
24
+ uiDevServerUrl?: string
25
+ source: UiSource
26
+ uiVersion?: string
27
+ supported: boolean
28
+ message?: string
29
+ latestServerVersion?: string
30
+ latestServerUrl?: string
31
+ minServerVersion?: string
32
+ }
33
+
34
+ export interface RemoteUiOptions {
35
+ serverVersion: string
36
+ bundledUiDir: string
37
+ autoUpdate: boolean
38
+ overrideUiDir?: string
39
+ uiDevServerUrl?: string
40
+ manifestUrl?: string
41
+ configDir?: string
42
+ logger: Logger
43
+ }
44
+
45
+ const DEFAULT_MANIFEST_URL = "https://ui.codenomad.neuralnomads.ai/version.json"
46
+
47
+ const MANIFEST_TIMEOUT_MS = 5_000
48
+ const ZIP_TIMEOUT_MS = 30_000
49
+
50
+ export async function resolveUi(options: RemoteUiOptions): Promise<UiResolution> {
51
+ const manifestUrl = options.manifestUrl ?? DEFAULT_MANIFEST_URL
52
+
53
+ if (options.uiDevServerUrl) {
54
+ return {
55
+ uiDevServerUrl: options.uiDevServerUrl,
56
+ source: "dev-proxy",
57
+ supported: true,
58
+ }
59
+ }
60
+
61
+ if (options.overrideUiDir) {
62
+ const resolved = await resolveStaticUiDir(options.overrideUiDir)
63
+ return {
64
+ uiStaticDir: resolved ?? options.overrideUiDir,
65
+ source: "override",
66
+ uiVersion: await readUiVersion(resolved ?? options.overrideUiDir),
67
+ supported: true,
68
+ }
69
+ }
70
+
71
+ const uiRoot = resolveUiCacheRoot(options.configDir)
72
+ const currentDir = path.join(uiRoot, "current")
73
+ const previousDir = path.join(uiRoot, "previous")
74
+
75
+ if (!options.autoUpdate) {
76
+ return await resolveFromCacheOrBundled({
77
+ logger: options.logger,
78
+ bundledUiDir: options.bundledUiDir,
79
+ currentDir,
80
+ previousDir,
81
+ supported: true,
82
+ })
83
+ }
84
+
85
+ let manifest: RemoteUiManifest | null = null
86
+ try {
87
+ manifest = await fetchManifest(manifestUrl, options.logger)
88
+ } catch (error) {
89
+ options.logger.debug({ err: error }, "Remote UI manifest unavailable; using cached/bundled UI")
90
+ }
91
+
92
+ if (!manifest) {
93
+ return await resolveFromCacheOrBundled({
94
+ logger: options.logger,
95
+ bundledUiDir: options.bundledUiDir,
96
+ currentDir,
97
+ previousDir,
98
+ supported: true,
99
+ })
100
+ }
101
+
102
+ const supported = compareSemverCore(options.serverVersion, manifest.minServerVersion) >= 0
103
+ if (!supported) {
104
+ const message = "Upgrade App to use latest features"
105
+ return await resolveFromCacheOrBundled({
106
+ logger: options.logger,
107
+ bundledUiDir: options.bundledUiDir,
108
+ currentDir,
109
+ previousDir,
110
+ supported: false,
111
+ message,
112
+ latestServerVersion: manifest.latestServerVersion,
113
+ latestServerUrl: manifest.latestServerUrl,
114
+ minServerVersion: manifest.minServerVersion,
115
+ })
116
+ }
117
+
118
+ const bestLocal = await pickBestLocalUi({
119
+ logger: options.logger,
120
+ bundledUiDir: options.bundledUiDir,
121
+ currentDir,
122
+ previousDir,
123
+ })
124
+
125
+ const remoteIsNewer =
126
+ !bestLocal ||
127
+ compareSemverMaybe(manifest.latestUIVersion, bestLocal.uiVersion) > 0
128
+
129
+ if (!remoteIsNewer) {
130
+ return await resolveFromCacheOrBundled({
131
+ logger: options.logger,
132
+ bundledUiDir: options.bundledUiDir,
133
+ currentDir,
134
+ previousDir,
135
+ supported: true,
136
+ latestServerVersion: manifest.latestServerVersion,
137
+ latestServerUrl: manifest.latestServerUrl,
138
+ minServerVersion: manifest.minServerVersion,
139
+ })
140
+ }
141
+
142
+ try {
143
+ await installRemoteUi({
144
+ manifest,
145
+ uiRoot,
146
+ currentDir,
147
+ previousDir,
148
+ logger: options.logger,
149
+ })
150
+ } catch (error) {
151
+ options.logger.warn({ err: error }, "Failed to install remote UI; falling back")
152
+ return await resolveFromCacheOrBundled({
153
+ logger: options.logger,
154
+ bundledUiDir: options.bundledUiDir,
155
+ currentDir,
156
+ previousDir,
157
+ supported: true,
158
+ latestServerVersion: manifest.latestServerVersion,
159
+ latestServerUrl: manifest.latestServerUrl,
160
+ minServerVersion: manifest.minServerVersion,
161
+ })
162
+ }
163
+
164
+ const installed = await resolveStaticUiDir(currentDir)
165
+ if (installed) {
166
+ return {
167
+ uiStaticDir: installed,
168
+ source: "downloaded",
169
+ uiVersion: await readUiVersion(installed),
170
+ supported: true,
171
+ latestServerVersion: manifest.latestServerVersion,
172
+ latestServerUrl: manifest.latestServerUrl,
173
+ minServerVersion: manifest.minServerVersion,
174
+ }
175
+ }
176
+
177
+ return await resolveFromCacheOrBundled({
178
+ logger: options.logger,
179
+ bundledUiDir: options.bundledUiDir,
180
+ currentDir,
181
+ previousDir,
182
+ supported: true,
183
+ latestServerVersion: manifest.latestServerVersion,
184
+ latestServerUrl: manifest.latestServerUrl,
185
+ minServerVersion: manifest.minServerVersion,
186
+ })
187
+ }
188
+
189
+ function resolveUiCacheRoot(configDir?: string): string {
190
+ if (configDir) {
191
+ return path.join(configDir, "ui")
192
+ }
193
+ return path.join(os.homedir(), ".config", "codenomad", "ui")
194
+ }
195
+
196
+ async function resolveFromCacheOrBundled(args: {
197
+ logger: Logger
198
+ bundledUiDir: string
199
+ currentDir: string
200
+ previousDir: string
201
+ supported: boolean
202
+ message?: string
203
+ latestServerVersion?: string
204
+ latestServerUrl?: string
205
+ minServerVersion?: string
206
+ }): Promise<UiResolution> {
207
+ const bestLocal = await pickBestLocalUi({
208
+ logger: args.logger,
209
+ bundledUiDir: args.bundledUiDir,
210
+ currentDir: args.currentDir,
211
+ previousDir: args.previousDir,
212
+ })
213
+
214
+ if (bestLocal) {
215
+ return {
216
+ uiStaticDir: bestLocal.uiStaticDir,
217
+ source: bestLocal.source,
218
+ uiVersion: bestLocal.uiVersion,
219
+ supported: args.supported,
220
+ message: args.message,
221
+ latestServerVersion: args.latestServerVersion,
222
+ latestServerUrl: args.latestServerUrl,
223
+ minServerVersion: args.minServerVersion,
224
+ }
225
+ }
226
+
227
+ args.logger.warn({ bundledUiDir: args.bundledUiDir }, "No UI assets found")
228
+ return {
229
+ uiStaticDir: args.bundledUiDir,
230
+ source: "missing",
231
+ supported: args.supported,
232
+ message: args.message,
233
+ latestServerVersion: args.latestServerVersion,
234
+ latestServerUrl: args.latestServerUrl,
235
+ minServerVersion: args.minServerVersion,
236
+ }
237
+ }
238
+
239
+ async function pickBestLocalUi(args: {
240
+ logger: Logger
241
+ bundledUiDir: string
242
+ currentDir: string
243
+ previousDir: string
244
+ }): Promise<{ uiStaticDir: string; source: UiSource; uiVersion?: string } | null> {
245
+ const candidates: Array<{ uiStaticDir: string; source: UiSource; uiVersion?: string; priority: number }> = []
246
+
247
+ const currentResolved = await resolveStaticUiDir(args.currentDir)
248
+ if (currentResolved) {
249
+ candidates.push({
250
+ uiStaticDir: currentResolved,
251
+ source: "downloaded",
252
+ uiVersion: await readUiVersion(currentResolved),
253
+ priority: 2,
254
+ })
255
+ }
256
+
257
+ const bundledResolved = await resolveStaticUiDir(args.bundledUiDir)
258
+ if (bundledResolved) {
259
+ candidates.push({
260
+ uiStaticDir: bundledResolved,
261
+ source: "bundled",
262
+ uiVersion: await readUiVersion(bundledResolved),
263
+ priority: 1,
264
+ })
265
+ }
266
+
267
+ const previousResolved = await resolveStaticUiDir(args.previousDir)
268
+ if (previousResolved) {
269
+ candidates.push({
270
+ uiStaticDir: previousResolved,
271
+ source: "previous",
272
+ uiVersion: await readUiVersion(previousResolved),
273
+ priority: 0,
274
+ })
275
+ }
276
+
277
+ if (candidates.length === 0) {
278
+ return null
279
+ }
280
+
281
+ candidates.sort((a, b) => {
282
+ const versionCmp = compareSemverMaybe(a.uiVersion, b.uiVersion)
283
+ if (versionCmp !== 0) return -versionCmp
284
+ return b.priority - a.priority
285
+ })
286
+
287
+ const best = candidates[0]
288
+ if (!best) return null
289
+ return { uiStaticDir: best.uiStaticDir, source: best.source, uiVersion: best.uiVersion }
290
+ }
291
+
292
+ function compareSemverMaybe(a: string | undefined, b: string | undefined): number {
293
+ if (!a && !b) return 0
294
+ if (!a) return -1
295
+ if (!b) return 1
296
+ return compareSemverCore(a, b)
297
+ }
298
+
299
+ async function resolveStaticUiDir(uiDir: string): Promise<string | null> {
300
+ try {
301
+ const indexPath = path.join(uiDir, "index.html")
302
+ await fsp.access(indexPath, fs.constants.R_OK)
303
+ return uiDir
304
+ } catch {
305
+ return null
306
+ }
307
+ }
308
+
309
+ interface UiVersionFile {
310
+ uiVersion?: string
311
+ version?: string
312
+ }
313
+
314
+ async function readUiVersion(uiDir: string): Promise<string | undefined> {
315
+ try {
316
+ const content = await fsp.readFile(path.join(uiDir, "ui-version.json"), "utf-8")
317
+ const parsed = JSON.parse(content) as UiVersionFile
318
+ return parsed.uiVersion ?? parsed.version
319
+ } catch {
320
+ return undefined
321
+ }
322
+ }
323
+
324
+ async function fetchManifest(url: string, logger: Logger): Promise<RemoteUiManifest> {
325
+ const controller = new AbortController()
326
+ const timeout = setTimeout(() => controller.abort(), MANIFEST_TIMEOUT_MS)
327
+ try {
328
+ const response = await fetch(url, {
329
+ signal: controller.signal,
330
+ headers: {
331
+ Accept: "application/json",
332
+ "User-Agent": "CodeNomad-CLI",
333
+ },
334
+ })
335
+ if (!response.ok) {
336
+ throw new Error(`Manifest responded with ${response.status}`)
337
+ }
338
+ const json = (await response.json()) as RemoteUiManifest
339
+ validateManifest(json)
340
+ return json
341
+ } catch (error) {
342
+ logger.debug({ err: error, url }, "Failed to fetch remote UI manifest")
343
+ throw error
344
+ } finally {
345
+ clearTimeout(timeout)
346
+ }
347
+ }
348
+
349
+ function validateManifest(manifest: RemoteUiManifest) {
350
+ const required: Array<keyof RemoteUiManifest> = ["minServerVersion", "latestUIVersion", "uiPackageURL", "sha256"]
351
+ for (const key of required) {
352
+ const value = manifest[key]
353
+ if (typeof value !== "string" || value.trim().length === 0) {
354
+ throw new Error(`Manifest missing ${key}`)
355
+ }
356
+ }
357
+ if (!/^https:\/\//i.test(manifest.uiPackageURL)) {
358
+ throw new Error("uiPackageURL must be https")
359
+ }
360
+ if (!/^[a-f0-9]{64}$/i.test(manifest.sha256.trim())) {
361
+ throw new Error("sha256 must be 64 hex chars")
362
+ }
363
+ }
364
+
365
+ async function installRemoteUi(args: {
366
+ manifest: RemoteUiManifest
367
+ uiRoot: string
368
+ currentDir: string
369
+ previousDir: string
370
+ logger: Logger
371
+ }) {
372
+ await fsp.mkdir(args.uiRoot, { recursive: true })
373
+
374
+ const tmpDir = path.join(args.uiRoot, `tmp-${Date.now()}`)
375
+ const zipPath = path.join(args.uiRoot, `ui-${args.manifest.latestUIVersion}.zip`)
376
+
377
+ try {
378
+ await downloadFile(args.manifest.uiPackageURL, zipPath, args.logger)
379
+ const digest = await sha256File(zipPath)
380
+ if (digest.toLowerCase() !== args.manifest.sha256.toLowerCase()) {
381
+ throw new Error(`sha256 mismatch for UI zip (expected ${args.manifest.sha256}, got ${digest})`)
382
+ }
383
+
384
+ await extractZip(zipPath, tmpDir)
385
+
386
+ const indexPath = path.join(tmpDir, "index.html")
387
+ if (!fs.existsSync(indexPath)) {
388
+ throw new Error("Extracted UI missing index.html")
389
+ }
390
+
391
+ await rotateDirs({ currentDir: args.currentDir, previousDir: args.previousDir, logger: args.logger })
392
+
393
+ fs.rmSync(args.currentDir, { recursive: true, force: true })
394
+ fs.renameSync(tmpDir, args.currentDir)
395
+ } finally {
396
+ fs.rmSync(tmpDir, { recursive: true, force: true })
397
+ fs.rmSync(zipPath, { force: true })
398
+ }
399
+ }
400
+
401
+ async function rotateDirs(args: { currentDir: string; previousDir: string; logger: Logger }) {
402
+ try {
403
+ if (fs.existsSync(args.previousDir)) {
404
+ fs.rmSync(args.previousDir, { recursive: true, force: true })
405
+ }
406
+ if (fs.existsSync(args.currentDir)) {
407
+ fs.renameSync(args.currentDir, args.previousDir)
408
+ }
409
+ } catch (error) {
410
+ args.logger.warn({ err: error }, "Failed to rotate UI cache directories")
411
+ }
412
+ }
413
+
414
+ async function downloadFile(url: string, targetPath: string, logger: Logger) {
415
+ const controller = new AbortController()
416
+ const timeout = setTimeout(() => controller.abort(), ZIP_TIMEOUT_MS)
417
+ try {
418
+ const response = await fetch(url, {
419
+ signal: controller.signal,
420
+ headers: {
421
+ Accept: "application/octet-stream",
422
+ "User-Agent": "CodeNomad-CLI",
423
+ },
424
+ })
425
+ if (!response.ok || !response.body) {
426
+ throw new Error(`UI zip download failed with ${response.status}`)
427
+ }
428
+
429
+ await fsp.mkdir(path.dirname(targetPath), { recursive: true })
430
+ const fileStream = fs.createWriteStream(targetPath)
431
+
432
+ const body = response.body
433
+ if (!body) {
434
+ throw new Error("UI zip response missing body")
435
+ }
436
+
437
+ const nodeStream = Readable.fromWeb(body as any)
438
+
439
+ await new Promise<void>((resolve, reject) => {
440
+ nodeStream.pipe(fileStream)
441
+ nodeStream.on("error", reject)
442
+ fileStream.on("error", reject)
443
+ fileStream.on("finish", () => resolve())
444
+ })
445
+
446
+ logger.debug({ url, targetPath }, "Downloaded remote UI bundle")
447
+ } finally {
448
+ clearTimeout(timeout)
449
+ }
450
+ }
451
+
452
+ async function sha256File(filePath: string): Promise<string> {
453
+ const hash = createHash("sha256")
454
+ const stream = fs.createReadStream(filePath)
455
+ await new Promise<void>((resolve, reject) => {
456
+ stream.on("data", (chunk) => hash.update(chunk))
457
+ stream.on("error", reject)
458
+ stream.on("end", () => resolve())
459
+ })
460
+ return hash.digest("hex")
461
+ }
462
+
463
+ async function extractZip(zipPath: string, targetDir: string): Promise<void> {
464
+ await fsp.mkdir(targetDir, { recursive: true })
465
+
466
+ await new Promise<void>((resolve, reject) => {
467
+ yauzl.open(zipPath, { lazyEntries: true }, (openErr, zipfile) => {
468
+ if (openErr || !zipfile) {
469
+ reject(openErr ?? new Error("Unable to open zip"))
470
+ return
471
+ }
472
+
473
+ const root = path.resolve(targetDir)
474
+
475
+ const closeWithError = (error: unknown) => {
476
+ try {
477
+ zipfile.close()
478
+ } catch {
479
+ // ignore
480
+ }
481
+ reject(error)
482
+ }
483
+
484
+ zipfile.readEntry()
485
+
486
+ zipfile.on("entry", (entry) => {
487
+ // Normalize and guard against zip-slip.
488
+ const entryPath = entry.fileName.replace(/\\/g, "/")
489
+
490
+ const segments = entryPath.split("/").filter(Boolean)
491
+ if (segments.some((segment: string) => segment === "..") || path.isAbsolute(entryPath)) {
492
+ closeWithError(new Error(`Invalid zip entry path: ${entry.fileName}`))
493
+ return
494
+ }
495
+
496
+ const destination = path.resolve(targetDir, entryPath)
497
+ if (!destination.startsWith(root + path.sep) && destination !== root) {
498
+ closeWithError(new Error(`Zip entry escapes target dir: ${entry.fileName}`))
499
+ return
500
+ }
501
+
502
+ const isDirectory = entry.fileName.endsWith("/")
503
+
504
+ if (isDirectory) {
505
+ fsp
506
+ .mkdir(destination, { recursive: true })
507
+ .then(() => zipfile.readEntry())
508
+ .catch((error) => closeWithError(error))
509
+ return
510
+ }
511
+
512
+ fsp
513
+ .mkdir(path.dirname(destination), { recursive: true })
514
+ .then(() => {
515
+ zipfile.openReadStream(entry, (streamErr, readStream) => {
516
+ if (streamErr || !readStream) {
517
+ closeWithError(streamErr ?? new Error("Unable to read zip entry"))
518
+ return
519
+ }
520
+
521
+ const writeStream = fs.createWriteStream(destination)
522
+ const cleanup = (error?: unknown) => {
523
+ readStream.destroy()
524
+ writeStream.destroy()
525
+ if (error) {
526
+ closeWithError(error)
527
+ }
528
+ }
529
+
530
+ readStream.on("error", cleanup)
531
+ writeStream.on("error", cleanup)
532
+ writeStream.on("finish", () => zipfile.readEntry())
533
+
534
+ readStream.pipe(writeStream)
535
+ })
536
+ })
537
+ .catch((error) => closeWithError(error))
538
+ })
539
+
540
+ zipfile.on("end", () => {
541
+ zipfile.close()
542
+ resolve()
543
+ })
544
+
545
+ zipfile.on("error", (error) => closeWithError(error))
546
+ })
547
+ })
548
+ }
549
+
550
+ function compareSemverCore(a: string, b: string): number {
551
+ const pa = parseSemverCore(a)
552
+ const pb = parseSemverCore(b)
553
+ if (pa.major !== pb.major) return pa.major > pb.major ? 1 : -1
554
+ if (pa.minor !== pb.minor) return pa.minor > pb.minor ? 1 : -1
555
+ if (pa.patch !== pb.patch) return pa.patch > pb.patch ? 1 : -1
556
+ return 0
557
+ }
558
+
559
+ function parseSemverCore(value: string): { major: number; minor: number; patch: number } {
560
+ const core = value.trim().replace(/^v/i, "").split("-", 1)[0] ?? "0.0.0"
561
+ const parts = core.split(".")
562
+ const parsePart = (input: string | undefined) => {
563
+ const n = Number.parseInt((input ?? "0").replace(/[^0-9]/g, ""), 10)
564
+ return Number.isFinite(n) ? n : 0
565
+ }
566
+ return {
567
+ major: parsePart(parts[0]),
568
+ minor: parsePart(parts[1]),
569
+ patch: parsePart(parts[2]),
570
+ }
571
+ }