@vividcodeai/embeddedcowork 0.0.21 → 0.0.23

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 (437) hide show
  1. package/dist/api-types.js +1 -0
  2. package/dist/auth/auth-store.js +134 -0
  3. package/dist/auth/http-auth.js +37 -0
  4. package/dist/auth/manager.js +140 -0
  5. package/dist/auth/password-hash.js +32 -0
  6. package/dist/auth/session-manager.js +17 -0
  7. package/dist/auth/token-manager.js +27 -0
  8. package/dist/background-processes/manager.js +576 -0
  9. package/dist/bin.js +24 -0
  10. package/dist/clients/connection-manager.js +93 -0
  11. package/dist/config/location.js +57 -0
  12. package/dist/config/schema.js +72 -0
  13. package/dist/events/bus.js +47 -0
  14. package/dist/filesystem/__tests__/search-cache.test.js +40 -0
  15. package/dist/filesystem/browser.js +292 -0
  16. package/dist/filesystem/search-cache.js +43 -0
  17. package/dist/filesystem/search.js +135 -0
  18. package/dist/index.js +496 -0
  19. package/dist/launcher.js +149 -0
  20. package/dist/loader.js +21 -0
  21. package/dist/logger.js +109 -0
  22. package/dist/opencode-config/README.md +32 -0
  23. package/dist/opencode-config/opencode.jsonc +35 -0
  24. package/dist/opencode-config/package.json +9 -0
  25. package/dist/opencode-config/plugin/embeddedcowork.ts +62 -0
  26. package/dist/opencode-config/plugin/lib/background-process.ts +265 -0
  27. package/dist/opencode-config/plugin/lib/client.ts +133 -0
  28. package/dist/opencode-config/plugin/lib/request.ts +214 -0
  29. package/dist/opencode-config.js +15 -0
  30. package/dist/opencode-downloader.js +295 -0
  31. package/dist/opencode-paths.js +167 -0
  32. package/dist/plugins/channel.js +40 -0
  33. package/dist/plugins/handlers.js +17 -0
  34. package/dist/plugins/voice-mode.js +78 -0
  35. package/dist/releases/dev-release-monitor.js +75 -0
  36. package/dist/releases/release-monitor.js +107 -0
  37. package/dist/runtime-paths.js +67 -0
  38. package/dist/server/__tests__/network-addresses.test.js +68 -0
  39. package/dist/server/__tests__/remote-proxy.test.js +204 -0
  40. package/dist/server/http-server.js +998 -0
  41. package/dist/server/network-addresses.js +114 -0
  42. package/dist/server/remote-proxy.js +466 -0
  43. package/dist/server/routes/auth-pages/login.html +135 -0
  44. package/dist/server/routes/auth-pages/token.html +93 -0
  45. package/dist/server/routes/auth.js +149 -0
  46. package/dist/server/routes/background-processes.js +78 -0
  47. package/dist/server/routes/events.js +66 -0
  48. package/dist/server/routes/filesystem.js +43 -0
  49. package/dist/server/routes/meta.js +44 -0
  50. package/dist/server/routes/opencode-status.js +10 -0
  51. package/dist/server/routes/plugin.js +70 -0
  52. package/dist/server/routes/remote-proxy.js +42 -0
  53. package/dist/server/routes/remote-servers.js +142 -0
  54. package/dist/server/routes/settings.js +69 -0
  55. package/dist/server/routes/sidecars.js +46 -0
  56. package/dist/server/routes/speech.js +63 -0
  57. package/dist/server/routes/storage.js +52 -0
  58. package/dist/server/routes/workspaces.js +221 -0
  59. package/dist/server/routes/worktrees.js +156 -0
  60. package/dist/server/tls.js +224 -0
  61. package/dist/settings/binaries.js +37 -0
  62. package/dist/settings/merge-patch.js +33 -0
  63. package/dist/settings/migrate.js +238 -0
  64. package/dist/settings/public-config.js +33 -0
  65. package/dist/settings/service.js +101 -0
  66. package/dist/settings/yaml-doc-store.js +96 -0
  67. package/dist/sidecars/manager.js +193 -0
  68. package/dist/speech/providers/openai-compatible.js +189 -0
  69. package/dist/speech/service.js +58 -0
  70. package/dist/storage/instance-store.js +56 -0
  71. package/dist/ui/__tests__/remote-ui.test.js +67 -0
  72. package/dist/ui/remote-ui.js +462 -0
  73. package/dist/workspaces/__tests__/spawn.test.js +139 -0
  74. package/dist/workspaces/git-mutations.js +98 -0
  75. package/dist/workspaces/git-status.js +323 -0
  76. package/dist/workspaces/git-worktrees.js +216 -0
  77. package/dist/workspaces/instance-events.js +180 -0
  78. package/dist/workspaces/manager.js +432 -0
  79. package/dist/workspaces/opencode-auth.js +16 -0
  80. package/dist/workspaces/runtime.js +366 -0
  81. package/dist/workspaces/spawn.js +219 -0
  82. package/dist/workspaces/worktree-directory.js +74 -0
  83. package/dist/workspaces/worktree-map.js +116 -0
  84. package/package.json +3 -12
  85. package/public/apple-touch-icon-180x180.png +0 -0
  86. package/public/assets/ChangesTab-C4_zdV74.js +2 -0
  87. package/public/assets/DiffToolbar-BsUPigM5.js +1 -0
  88. package/public/assets/EmbeddedCowork-Icon-DSw5nKk7.png +0 -0
  89. package/public/assets/FilesTab-Drvo30nM.js +2 -0
  90. package/public/assets/GitChangesTab-BhV6qTfP.js +2 -0
  91. package/public/assets/SplitFilePanel-BBrs329I.js +1 -0
  92. package/public/assets/StatusTab-DfYWlTSX.js +1 -0
  93. package/public/assets/abap-BdImnpbu.js +1 -0
  94. package/public/assets/actionscript-3-CfeIJUat.js +1 -0
  95. package/public/assets/ada-bCR0ucgS.js +1 -0
  96. package/public/assets/andromeeda-C-Jbm3Hp.js +1 -0
  97. package/public/assets/angular-html-CU67Zn6k.js +1 -0
  98. package/public/assets/angular-ts-BwZT4LLn.js +1 -0
  99. package/public/assets/apache-Pmp26Uib.js +1 -0
  100. package/public/assets/apex-DhZLUxFE.js +1 -0
  101. package/public/assets/apl-dKokRX4l.js +1 -0
  102. package/public/assets/applescript-Co6uUVPk.js +1 -0
  103. package/public/assets/ara-BRHolxvo.js +1 -0
  104. package/public/assets/asciidoc-Dv7Oe6Be.js +1 -0
  105. package/public/assets/asm-D_Q5rh1f.js +1 -0
  106. package/public/assets/astro-CbQHKStN.js +1 -0
  107. package/public/assets/aurora-x-D-2ljcwZ.js +1 -0
  108. package/public/assets/awk-DMzUqQB5.js +1 -0
  109. package/public/assets/ayu-dark-Cv9koXgw.js +1 -0
  110. package/public/assets/ballerina-BFfxhgS-.js +1 -0
  111. package/public/assets/bat-BkioyH1T.js +1 -0
  112. package/public/assets/beancount-k_qm7-4y.js +1 -0
  113. package/public/assets/berry-D08WgyRC.js +1 -0
  114. package/public/assets/bibtex-CHM0blh-.js +1 -0
  115. package/public/assets/bicep-Bmn6On1c.js +1 -0
  116. package/public/assets/blade-DVc8C-J4.js +1 -0
  117. package/public/assets/bsl-BO_Y6i37.js +1 -0
  118. package/public/assets/bundle-full-CAZqmV2E.js +13 -0
  119. package/public/assets/c-BIGW1oBm.js +1 -0
  120. package/public/assets/cadence-Bv_4Rxtq.js +1 -0
  121. package/public/assets/cairo-KRGpt6FW.js +1 -0
  122. package/public/assets/catppuccin-frappe-DFWUc33u.js +1 -0
  123. package/public/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
  124. package/public/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
  125. package/public/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
  126. package/public/assets/clarity-D53aC0YG.js +1 -0
  127. package/public/assets/clojure-P80f7IUj.js +1 -0
  128. package/public/assets/cmake-D1j8_8rp.js +1 -0
  129. package/public/assets/cobol-nwyudZeR.js +1 -0
  130. package/public/assets/codeowners-Bp6g37R7.js +1 -0
  131. package/public/assets/codeql-DsOJ9woJ.js +1 -0
  132. package/public/assets/coffee-Ch7k5sss.js +1 -0
  133. package/public/assets/common-lisp-Cg-RD9OK.js +1 -0
  134. package/public/assets/coq-DkFqJrB1.js +1 -0
  135. package/public/assets/core-DhEqZVGG.js +1 -0
  136. package/public/assets/cpp-CofmeUqb.js +1 -0
  137. package/public/assets/crystal-tKQVLTB8.js +1 -0
  138. package/public/assets/csharp-CX12Zw3r.js +1 -0
  139. package/public/assets/css-DPfMkruS.js +1 -0
  140. package/public/assets/csv-fuZLfV_i.js +1 -0
  141. package/public/assets/cue-D82EKSYY.js +1 -0
  142. package/public/assets/cypher-COkxafJQ.js +1 -0
  143. package/public/assets/d-85-TOEBH.js +1 -0
  144. package/public/assets/dark-plus-eOWES_5F.js +1 -0
  145. package/public/assets/dart-CF10PKvl.js +1 -0
  146. package/public/assets/dax-CEL-wOlO.js +1 -0
  147. package/public/assets/desktop-BmXAJ9_W.js +1 -0
  148. package/public/assets/diff-D97Zzqfu.js +1 -0
  149. package/public/assets/diff-viewer--UIZ5GEn.js +1 -0
  150. package/public/assets/docker-BcOcwvcX.js +1 -0
  151. package/public/assets/dotenv-Da5cRb03.js +1 -0
  152. package/public/assets/dracula-BzJJZx-M.js +1 -0
  153. package/public/assets/dracula-soft-BXkSAIEj.js +1 -0
  154. package/public/assets/dream-maker-BtqSS_iP.js +1 -0
  155. package/public/assets/edge-BkV0erSs.js +1 -0
  156. package/public/assets/elixir-CDX3lj18.js +1 -0
  157. package/public/assets/elm-DbKCFpqz.js +1 -0
  158. package/public/assets/emacs-lisp-C9XAeP06.js +1 -0
  159. package/public/assets/erb-BOJIQeun.js +1 -0
  160. package/public/assets/erlang-DsQrWhSR.js +1 -0
  161. package/public/assets/event-DjZVAIBO.js +1 -0
  162. package/public/assets/everforest-dark-BgDCqdQA.js +1 -0
  163. package/public/assets/everforest-light-C8M2exoo.js +1 -0
  164. package/public/assets/fast-diff-vendor-DgdwVvTQ.js +1 -0
  165. package/public/assets/fennel-BYunw83y.js +1 -0
  166. package/public/assets/fish-BvzEVeQv.js +1 -0
  167. package/public/assets/fluent-C4IJs8-o.js +1 -0
  168. package/public/assets/fortran-fixed-form-BZjJHVRy.js +1 -0
  169. package/public/assets/fortran-free-form-D22FLkUw.js +1 -0
  170. package/public/assets/fsharp-CXgrBDvD.js +1 -0
  171. package/public/assets/gdresource-B7Tvp0Sc.js +1 -0
  172. package/public/assets/gdscript-DTMYz4Jt.js +1 -0
  173. package/public/assets/gdshader-DkwncUOv.js +1 -0
  174. package/public/assets/genie-D0YGMca9.js +1 -0
  175. package/public/assets/gherkin-DyxjwDmM.js +1 -0
  176. package/public/assets/git-commit-F4YmCXRG.js +1 -0
  177. package/public/assets/git-diff-vendor-CSgooKT_.js +52 -0
  178. package/public/assets/git-diff-vendor-HAZkIolJ.css +19 -0
  179. package/public/assets/git-rebase-r7XF79zn.js +1 -0
  180. package/public/assets/github-dark-DHJKELXO.js +1 -0
  181. package/public/assets/github-dark-default-Cuk6v7N8.js +1 -0
  182. package/public/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  183. package/public/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  184. package/public/assets/github-light-DAi9KRSo.js +1 -0
  185. package/public/assets/github-light-default-D7oLnXFd.js +1 -0
  186. package/public/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  187. package/public/assets/gleam-BspZqrRM.js +1 -0
  188. package/public/assets/glimmer-js-Rg0-pVw9.js +1 -0
  189. package/public/assets/glimmer-ts-U6CK756n.js +1 -0
  190. package/public/assets/glsl-DplSGwfg.js +1 -0
  191. package/public/assets/gnuplot-DdkO51Og.js +1 -0
  192. package/public/assets/go-Dn2_MT6a.js +1 -0
  193. package/public/assets/graphql-ChdNCCLP.js +1 -0
  194. package/public/assets/groovy-gcz8RCvz.js +1 -0
  195. package/public/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  196. package/public/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  197. package/public/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  198. package/public/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  199. package/public/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  200. package/public/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  201. package/public/assets/hack-CaT9iCJl.js +1 -0
  202. package/public/assets/haml-B8DHNrY2.js +1 -0
  203. package/public/assets/handlebars-BL8al0AC.js +1 -0
  204. package/public/assets/haskell-Df6bDoY_.js +1 -0
  205. package/public/assets/haxe-CzTSHFRz.js +1 -0
  206. package/public/assets/hcl-BWvSN4gD.js +1 -0
  207. package/public/assets/highlight-vendor-8FKMu9os.js +10 -0
  208. package/public/assets/hjson-D5-asLiD.js +1 -0
  209. package/public/assets/hlsl-D3lLCCz7.js +1 -0
  210. package/public/assets/houston-DnULxvSX.js +1 -0
  211. package/public/assets/html-GMplVEZG.js +1 -0
  212. package/public/assets/html-derivative-BFtXZ54Q.js +1 -0
  213. package/public/assets/http-jrhK8wxY.js +1 -0
  214. package/public/assets/hurl-irOxFIW8.js +1 -0
  215. package/public/assets/hxml-Bvhsp5Yf.js +1 -0
  216. package/public/assets/hy-DFXneXwc.js +1 -0
  217. package/public/assets/imba-DGztddWO.js +1 -0
  218. package/public/assets/index--0EL0_Tu.js +2 -0
  219. package/public/assets/index-BKMyzTSR.js +1 -0
  220. package/public/assets/index-BLouhjer.js +1 -0
  221. package/public/assets/index-CLSJ4cO9.js +1 -0
  222. package/public/assets/index-CgjnEdBS.js +1 -0
  223. package/public/assets/index-ChCPoe9m.js +1 -0
  224. package/public/assets/index-Co-dJ-Xs.js +1 -0
  225. package/public/assets/index-Ctcq8Rhl.css +1 -0
  226. package/public/assets/index-Da0V-sLI.js +1 -0
  227. package/public/assets/index-hOT6sqTO.js +1 -0
  228. package/public/assets/ini-BEwlwnbL.js +1 -0
  229. package/public/assets/java-CylS5w8V.js +1 -0
  230. package/public/assets/javascript-wDzz0qaB.js +1 -0
  231. package/public/assets/jinja-4LBKfQ-Z.js +1 -0
  232. package/public/assets/jison-wvAkD_A8.js +1 -0
  233. package/public/assets/json-Cp-IABpG.js +1 -0
  234. package/public/assets/json5-C9tS-k6U.js +1 -0
  235. package/public/assets/jsonc-Des-eS-w.js +1 -0
  236. package/public/assets/jsonl-DcaNXYhu.js +1 -0
  237. package/public/assets/jsonnet-DFQXde-d.js +1 -0
  238. package/public/assets/jssm-C2t-YnRu.js +1 -0
  239. package/public/assets/jsx-g9-lgVsj.js +1 -0
  240. package/public/assets/julia-C8NyazO9.js +1 -0
  241. package/public/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  242. package/public/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  243. package/public/assets/kanagawa-wave-DWedfzmr.js +1 -0
  244. package/public/assets/kdl-DV7GczEv.js +1 -0
  245. package/public/assets/kotlin-BdnUsdx6.js +1 -0
  246. package/public/assets/kusto-BvAqAH-y.js +1 -0
  247. package/public/assets/laserwave-DUszq2jm.js +1 -0
  248. package/public/assets/latex-BUKiar2Z.js +1 -0
  249. package/public/assets/lean-DP1Csr6i.js +1 -0
  250. package/public/assets/less-B1dDrJ26.js +1 -0
  251. package/public/assets/light-plus-B7mTdjB0.js +1 -0
  252. package/public/assets/liquid-DYVedYrR.js +1 -0
  253. package/public/assets/llvm-BtvRca6l.js +1 -0
  254. package/public/assets/loading-CugGjKDZ.css +1 -0
  255. package/public/assets/loading-CvW03p4Z.js +2 -0
  256. package/public/assets/log-2UxHyX5q.js +1 -0
  257. package/public/assets/logo-BtOb2qkB.js +1 -0
  258. package/public/assets/lua-BbnMAYS6.js +1 -0
  259. package/public/assets/luau-CXu1NL6O.js +1 -0
  260. package/public/assets/main-ByuKWHRz.js +53 -0
  261. package/public/assets/make-CHLpvVh8.js +1 -0
  262. package/public/assets/markdown-BBFC6uy4.js +58 -0
  263. package/public/assets/markdown-Cvjx9yec.js +1 -0
  264. package/public/assets/marko-CPi9NSCl.js +1 -0
  265. package/public/assets/material-theme-D5KoaKCx.js +1 -0
  266. package/public/assets/material-theme-darker-BfHTSMKl.js +1 -0
  267. package/public/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  268. package/public/assets/material-theme-ocean-CyktbL80.js +1 -0
  269. package/public/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  270. package/public/assets/matlab-D7o27uSR.js +1 -0
  271. package/public/assets/mdc-DUICxH0z.js +1 -0
  272. package/public/assets/mdx-Cmh6b_Ma.js +1 -0
  273. package/public/assets/mermaid-DKYwYmdq.js +1 -0
  274. package/public/assets/min-dark-CafNBF8u.js +1 -0
  275. package/public/assets/min-light-CTRr51gU.js +1 -0
  276. package/public/assets/mipsasm-CKIfxQSi.js +1 -0
  277. package/public/assets/mojo-1DNp92w6.js +1 -0
  278. package/public/assets/monaco-viewer-DnczYBfh.js +26 -0
  279. package/public/assets/monokai-D4h5O-jR.js +1 -0
  280. package/public/assets/move-Bu9oaDYs.js +1 -0
  281. package/public/assets/narrat-DRg8JJMk.js +1 -0
  282. package/public/assets/nextflow-CUEJCptM.js +1 -0
  283. package/public/assets/nginx-DknmC5AR.js +1 -0
  284. package/public/assets/night-owl-C39BiMTA.js +1 -0
  285. package/public/assets/nim-CVrawwO9.js +1 -0
  286. package/public/assets/nix-BbRYJGeE.js +1 -0
  287. package/public/assets/nord-Ddv68eIx.js +1 -0
  288. package/public/assets/nushell-C-sUppwS.js +1 -0
  289. package/public/assets/objective-c-DXmwc3jG.js +1 -0
  290. package/public/assets/objective-cpp-CLxacb5B.js +1 -0
  291. package/public/assets/ocaml-C0hk2d4L.js +1 -0
  292. package/public/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  293. package/public/assets/one-light-PoHY5YXO.js +1 -0
  294. package/public/assets/pascal-D93ZcfNL.js +1 -0
  295. package/public/assets/perl-C0TMdlhV.js +1 -0
  296. package/public/assets/php-CDn_0X-4.js +1 -0
  297. package/public/assets/pkl-u5AG7uiY.js +1 -0
  298. package/public/assets/plastic-3e1v2bzS.js +1 -0
  299. package/public/assets/plsql-ChMvpjG-.js +1 -0
  300. package/public/assets/po-BTJTHyun.js +1 -0
  301. package/public/assets/poimandres-CS3Unz2-.js +1 -0
  302. package/public/assets/polar-C0HS_06l.js +1 -0
  303. package/public/assets/postcss-CXtECtnM.js +1 -0
  304. package/public/assets/powerquery-CEu0bR-o.js +1 -0
  305. package/public/assets/powershell-Dpen1YoG.js +1 -0
  306. package/public/assets/prisma-Dd19v3D-.js +1 -0
  307. package/public/assets/prolog-CbFg5uaA.js +1 -0
  308. package/public/assets/proto-DyJlTyXw.js +1 -0
  309. package/public/assets/pug-CGlum2m_.js +1 -0
  310. package/public/assets/puppet-BMWR74SV.js +1 -0
  311. package/public/assets/purescript-CklMAg4u.js +1 -0
  312. package/public/assets/python-B6aJPvgy.js +1 -0
  313. package/public/assets/qml-3beO22l8.js +1 -0
  314. package/public/assets/qmldir-C8lEn-DE.js +1 -0
  315. package/public/assets/qss-IeuSbFQv.js +1 -0
  316. package/public/assets/r-DiinP2Uv.js +1 -0
  317. package/public/assets/racket-BqYA7rlc.js +1 -0
  318. package/public/assets/raku-DXvB9xmW.js +1 -0
  319. package/public/assets/razor-WgofotgN.js +1 -0
  320. package/public/assets/red-bN70gL4F.js +1 -0
  321. package/public/assets/reg-C-SQnVFl.js +1 -0
  322. package/public/assets/regexp-CDVJQ6XC.js +1 -0
  323. package/public/assets/rel-C3B-1QV4.js +1 -0
  324. package/public/assets/riscv-BM1_JUlF.js +1 -0
  325. package/public/assets/rose-pine-BHrmToEH.js +1 -0
  326. package/public/assets/rose-pine-dawn-CnK8MTSM.js +1 -0
  327. package/public/assets/rose-pine-moon-NleAzG8P.js +1 -0
  328. package/public/assets/rosmsg-BJDFO7_C.js +1 -0
  329. package/public/assets/rst-B0xPkSld.js +1 -0
  330. package/public/assets/ruby-BvKwtOVI.js +1 -0
  331. package/public/assets/rust-B1yitclQ.js +1 -0
  332. package/public/assets/sas-cz2c8ADy.js +1 -0
  333. package/public/assets/sass-Cj5Yp3dK.js +1 -0
  334. package/public/assets/scala-C151Ov-r.js +1 -0
  335. package/public/assets/scheme-C98Dy4si.js +1 -0
  336. package/public/assets/scss-OYdSNvt2.js +1 -0
  337. package/public/assets/sdbl-DVxCFoDh.js +1 -0
  338. package/public/assets/shaderlab-Dg9Lc6iA.js +1 -0
  339. package/public/assets/shellscript-Yzrsuije.js +1 -0
  340. package/public/assets/shellsession-BADoaaVG.js +1 -0
  341. package/public/assets/slack-dark-BthQWCQV.js +1 -0
  342. package/public/assets/slack-ochin-DqwNpetd.js +1 -0
  343. package/public/assets/smalltalk-BERRCDM3.js +1 -0
  344. package/public/assets/snazzy-light-Bw305WKR.js +1 -0
  345. package/public/assets/solarized-dark-DXbdFlpD.js +1 -0
  346. package/public/assets/solarized-light-L9t79GZl.js +1 -0
  347. package/public/assets/solidity-BbcW6ACK.js +1 -0
  348. package/public/assets/soy-Brmx7dQM.js +1 -0
  349. package/public/assets/sparql-rVzFXLq3.js +1 -0
  350. package/public/assets/splunk-BtCnVYZw.js +1 -0
  351. package/public/assets/sql-BLtJtn59.js +1 -0
  352. package/public/assets/ssh-config-_ykCGR6B.js +1 -0
  353. package/public/assets/stata-BH5u7GGu.js +1 -0
  354. package/public/assets/stylus-BEDo0Tqx.js +1 -0
  355. package/public/assets/svelte-3Dk4HxPD.js +1 -0
  356. package/public/assets/swift-Dg5xB15N.js +1 -0
  357. package/public/assets/synthwave-84-CbfX1IO0.js +1 -0
  358. package/public/assets/system-verilog-CnnmHF94.js +1 -0
  359. package/public/assets/systemd-4A_iFExJ.js +1 -0
  360. package/public/assets/talonscript-CkByrt1z.js +1 -0
  361. package/public/assets/tasl-QIJgUcNo.js +1 -0
  362. package/public/assets/tcl-dwOrl1Do.js +1 -0
  363. package/public/assets/templ-W15q3VgB.js +1 -0
  364. package/public/assets/terraform-BETggiCN.js +1 -0
  365. package/public/assets/tex-Cppo0RY3.js +1 -0
  366. package/public/assets/todo-BLpUqy61.js +1 -0
  367. package/public/assets/tokyo-night-hegEt444.js +1 -0
  368. package/public/assets/toml-vGWfd6FD.js +1 -0
  369. package/public/assets/tool-call-B4Xz6FbC.js +60 -0
  370. package/public/assets/ts-tags-zn1MmPIZ.js +1 -0
  371. package/public/assets/tsv-B_m7g4N7.js +1 -0
  372. package/public/assets/tsx-COt5Ahok.js +1 -0
  373. package/public/assets/turtle-BsS91CYL.js +1 -0
  374. package/public/assets/twig-CO9l9SDP.js +1 -0
  375. package/public/assets/typescript-BPQ3VLAy.js +1 -0
  376. package/public/assets/typespec-Df68jz8_.js +1 -0
  377. package/public/assets/typst-DHCkPAjA.js +1 -0
  378. package/public/assets/unified-picker-BrzM_sH6.js +1 -0
  379. package/public/assets/v-BcVCzyr7.js +1 -0
  380. package/public/assets/vala-CsfeWuGM.js +1 -0
  381. package/public/assets/vb-D17OF-Vu.js +1 -0
  382. package/public/assets/verilog-BQ8w6xss.js +1 -0
  383. package/public/assets/vesper-DU1UobuO.js +1 -0
  384. package/public/assets/vhdl-CeAyd5Ju.js +1 -0
  385. package/public/assets/viml-CJc9bBzg.js +1 -0
  386. package/public/assets/vitesse-black-Bkuqu6BP.js +1 -0
  387. package/public/assets/vitesse-dark-D0r3Knsf.js +1 -0
  388. package/public/assets/vitesse-light-CVO1_9PV.js +1 -0
  389. package/public/assets/vue-CCoi5OLL.js +1 -0
  390. package/public/assets/vue-html-DAAvJJDi.js +1 -0
  391. package/public/assets/vue-vine-_Ih-lPRR.js +1 -0
  392. package/public/assets/vyper-CDx5xZoG.js +1 -0
  393. package/public/assets/wasm-CG6Dc4jp.js +1 -0
  394. package/public/assets/wasm-MzD3tlZU.js +1 -0
  395. package/public/assets/wenyan-BV7otONQ.js +1 -0
  396. package/public/assets/wgsl-Dx-B1_4e.js +1 -0
  397. package/public/assets/wikitext-BhOHFoWU.js +1 -0
  398. package/public/assets/wit-5i3qLPDT.js +1 -0
  399. package/public/assets/wolfram-lXgVvXCa.js +1 -0
  400. package/public/assets/wrap-text-B1i7zgLk.js +1 -0
  401. package/public/assets/xml-sdJ4AIDG.js +1 -0
  402. package/public/assets/xsl-CtQFsRM5.js +1 -0
  403. package/public/assets/yaml-Buea-lGh.js +1 -0
  404. package/public/assets/zenscript-DVFEvuxE.js +1 -0
  405. package/public/assets/zig-VOosw3JB.js +1 -0
  406. package/public/favicon.ico +0 -0
  407. package/public/index.html +44 -0
  408. package/public/loading.html +33 -0
  409. package/public/logo.png +0 -0
  410. package/public/manifest.webmanifest +1 -0
  411. package/public/maskable-icon-512x512.png +0 -0
  412. package/public/monaco/vs/base/browser/ui/codicons/codicon/codicon.ttf +0 -0
  413. package/public/monaco/vs/base/worker/workerMain.js +31 -0
  414. package/public/monaco/vs/basic-languages/cpp/cpp.js +10 -0
  415. package/public/monaco/vs/basic-languages/kotlin/kotlin.js +10 -0
  416. package/public/monaco/vs/basic-languages/markdown/markdown.js +10 -0
  417. package/public/monaco/vs/basic-languages/python/python.js +10 -0
  418. package/public/monaco/vs/editor/editor.main.css +8 -0
  419. package/public/monaco/vs/editor/editor.main.js +798 -0
  420. package/public/monaco/vs/language/css/cssMode.js +13 -0
  421. package/public/monaco/vs/language/css/cssWorker.js +77 -0
  422. package/public/monaco/vs/language/html/htmlMode.js +13 -0
  423. package/public/monaco/vs/language/html/htmlWorker.js +454 -0
  424. package/public/monaco/vs/language/json/jsonMode.js +19 -0
  425. package/public/monaco/vs/language/json/jsonWorker.js +42 -0
  426. package/public/monaco/vs/language/typescript/tsMode.js +20 -0
  427. package/public/monaco/vs/language/typescript/tsWorker.js +51328 -0
  428. package/public/monaco/vs/loader.js +11 -0
  429. package/public/monaco.worker.js +7 -0
  430. package/public/pwa-192x192.png +0 -0
  431. package/public/pwa-512x512.png +0 -0
  432. package/public/pwa-64x64.png +0 -0
  433. package/public/registerSW.js +1 -0
  434. package/public/sw.js +1 -0
  435. package/public/ui-version.json +3 -0
  436. package/public/workbox-60d14903.js +1 -0
  437. package/bin/cli.js +0 -56
@@ -0,0 +1,214 @@
1
+ import http from "http"
2
+ import https from "https"
3
+ import { Readable } from "stream"
4
+
5
+ export type PluginEvent = {
6
+ type: string
7
+ properties?: Record<string, unknown>
8
+ }
9
+
10
+ export type EmbeddedCoworkConfig = {
11
+ instanceId: string
12
+ baseUrl: string
13
+ }
14
+
15
+ export function getEmbeddedCoworkConfig(): EmbeddedCoworkConfig {
16
+ return {
17
+ instanceId: requireEnv("EMBEDDEDCOWORK_INSTANCE_ID"),
18
+ baseUrl: requireEnv("EMBEDDEDCOWORK_BASE_URL"),
19
+ }
20
+ }
21
+
22
+ export function createEmbeddedCoworkRequester(config: EmbeddedCoworkConfig) {
23
+ const rawBaseUrl = (config.baseUrl ?? "").trim()
24
+ const baseUrl = rawBaseUrl.replace(/\/+$/, "")
25
+ const pluginBase = `${baseUrl}/workspaces/${encodeURIComponent(config.instanceId)}/plugin`
26
+ const authorization = buildInstanceAuthorizationHeader()
27
+
28
+ const buildUrl = (path: string) => {
29
+ if (path.startsWith("http://") || path.startsWith("https://")) {
30
+ return path
31
+ }
32
+ const normalized = path.startsWith("/") ? path : `/${path}`
33
+ return `${pluginBase}${normalized}`
34
+ }
35
+
36
+ const buildHeaders = (headers: HeadersInit | undefined, hasBody: boolean): Record<string, string> => {
37
+ const output: Record<string, string> = normalizeHeaders(headers)
38
+ output.Authorization = authorization
39
+ if (hasBody) {
40
+ output["Content-Type"] = output["Content-Type"] ?? "application/json"
41
+ }
42
+ return output
43
+ }
44
+
45
+ const fetchWithAuth = async (path: string, init?: RequestInit): Promise<Response> => {
46
+ const url = buildUrl(path)
47
+ const hasBody = init?.body !== undefined
48
+ const headers = buildHeaders(init?.headers, hasBody)
49
+
50
+ // The EmbeddedCowork plugin only talks to the local EmbeddedCowork server.
51
+ // Use a single request implementation that tolerates custom/self-signed certs
52
+ // without disabling TLS verification for the whole Node process.
53
+ return nodeFetch(url, { ...init, headers }, { rejectUnauthorized: false })
54
+ }
55
+
56
+ const requestJson = async <T>(path: string, init?: RequestInit): Promise<T> => {
57
+ const response = await fetchWithAuth(path, init)
58
+ if (!response.ok) {
59
+ const message = await response.text().catch(() => "")
60
+ throw new Error(message || `Request failed with ${response.status}`)
61
+ }
62
+
63
+ if (response.status === 204) {
64
+ return undefined as T
65
+ }
66
+
67
+ return (await response.json()) as T
68
+ }
69
+
70
+ const requestVoid = async (path: string, init?: RequestInit): Promise<void> => {
71
+ const response = await fetchWithAuth(path, init)
72
+ if (!response.ok) {
73
+ const message = await response.text().catch(() => "")
74
+ throw new Error(message || `Request failed with ${response.status}`)
75
+ }
76
+ }
77
+
78
+ const requestSseBody = async (path: string): Promise<ReadableStream<Uint8Array>> => {
79
+ const response = await fetchWithAuth(path, { headers: { Accept: "text/event-stream" } })
80
+ if (!response.ok || !response.body) {
81
+ throw new Error(`SSE unavailable (${response.status})`)
82
+ }
83
+ return response.body as ReadableStream<Uint8Array>
84
+ }
85
+
86
+ return {
87
+ buildUrl,
88
+ fetch: fetchWithAuth,
89
+ requestJson,
90
+ requestVoid,
91
+ requestSseBody,
92
+ }
93
+ }
94
+
95
+ async function nodeFetch(
96
+ url: string,
97
+ init: RequestInit & { headers?: Record<string, string> },
98
+ tls: { rejectUnauthorized: boolean },
99
+ ): Promise<Response> {
100
+ const parsed = new URL(url)
101
+ const isHttps = parsed.protocol === "https:"
102
+ const requestFn = isHttps ? https.request : http.request
103
+
104
+ const method = (init.method ?? "GET").toUpperCase()
105
+ const headers = init.headers ?? {}
106
+ const body = init.body
107
+
108
+ return await new Promise<Response>((resolve, reject) => {
109
+ const req = requestFn(
110
+ {
111
+ protocol: parsed.protocol,
112
+ hostname: parsed.hostname,
113
+ port: parsed.port ? Number(parsed.port) : undefined,
114
+ path: `${parsed.pathname}${parsed.search}`,
115
+ method,
116
+ headers,
117
+ ...(isHttps ? { rejectUnauthorized: tls.rejectUnauthorized } : {}),
118
+ },
119
+ (res) => {
120
+ const responseHeaders = new Headers()
121
+ for (const [key, value] of Object.entries(res.headers)) {
122
+ if (value === undefined) continue
123
+ if (Array.isArray(value)) {
124
+ responseHeaders.set(key, value.join(", "))
125
+ } else {
126
+ responseHeaders.set(key, String(value))
127
+ }
128
+ }
129
+
130
+ // Convert Node stream -> Web ReadableStream for Response.
131
+ const webBody = Readable.toWeb(res) as unknown as ReadableStream<Uint8Array>
132
+ resolve(new Response(webBody, { status: res.statusCode ?? 0, headers: responseHeaders }))
133
+ },
134
+ )
135
+
136
+ const signal = init.signal
137
+ const abort = () => {
138
+ const err = new Error("Request aborted")
139
+ ;(err as any).name = "AbortError"
140
+ req.destroy(err)
141
+ reject(err)
142
+ }
143
+
144
+ if (signal) {
145
+ if (signal.aborted) {
146
+ abort()
147
+ return
148
+ }
149
+ signal.addEventListener("abort", abort, { once: true })
150
+ req.once("close", () => signal.removeEventListener("abort", abort))
151
+ }
152
+
153
+ req.once("error", reject)
154
+
155
+ if (body === undefined || body === null) {
156
+ req.end()
157
+ return
158
+ }
159
+
160
+ if (typeof body === "string") {
161
+ req.end(body)
162
+ return
163
+ }
164
+
165
+ if (body instanceof Uint8Array) {
166
+ req.end(Buffer.from(body))
167
+ return
168
+ }
169
+
170
+ if (body instanceof ArrayBuffer) {
171
+ req.end(Buffer.from(new Uint8Array(body)))
172
+ return
173
+ }
174
+
175
+ // Fallback for less common BodyInit types.
176
+ req.end(String(body))
177
+ })
178
+ }
179
+
180
+ function requireEnv(key: string): string {
181
+ const value = process.env[key]
182
+ if (!value || !value.trim()) {
183
+ throw new Error(`[EmbeddedCoworkPlugin] Missing required env var ${key}`)
184
+ }
185
+ return value
186
+ }
187
+
188
+ function buildInstanceAuthorizationHeader(): string {
189
+ const username = requireEnv("OPENCODE_SERVER_USERNAME")
190
+ const password = requireEnv("OPENCODE_SERVER_PASSWORD")
191
+ const token = Buffer.from(`${username}:${password}`, "utf8").toString("base64")
192
+ return `Basic ${token}`
193
+ }
194
+
195
+ function normalizeHeaders(headers: HeadersInit | undefined): Record<string, string> {
196
+ const output: Record<string, string> = {}
197
+ if (!headers) return output
198
+
199
+ if (headers instanceof Headers) {
200
+ headers.forEach((value, key) => {
201
+ output[key] = value
202
+ })
203
+ return output
204
+ }
205
+
206
+ if (Array.isArray(headers)) {
207
+ for (const [key, value] of headers) {
208
+ output[key] = value
209
+ }
210
+ return output
211
+ }
212
+
213
+ return { ...headers }
214
+ }
@@ -0,0 +1,15 @@
1
+ import { existsSync } from "fs";
2
+ import { createLogger } from "./logger";
3
+ import { resolveOpencodeTemplateDir } from "./runtime-paths";
4
+ const log = createLogger({ component: "opencode-config" });
5
+ const templateDir = resolveOpencodeTemplateDir(import.meta.url);
6
+ const isDevBuild = Boolean(process.env.EMBEDDEDCOWORK_DEV ?? process.env.CLI_UI_DEV_SERVER);
7
+ export function getOpencodeConfigDir() {
8
+ if (!existsSync(templateDir)) {
9
+ throw new Error(`EmbeddedCowork Opencode config template missing at ${templateDir}`);
10
+ }
11
+ if (isDevBuild) {
12
+ log.debug({ templateDir }, "Using Opencode config template directly (dev mode)");
13
+ }
14
+ return templateDir;
15
+ }
@@ -0,0 +1,295 @@
1
+ import { createWriteStream, existsSync, mkdirSync, chmodSync, readFileSync, createReadStream, renameSync } from "fs";
2
+ import { stat, mkdir } from "fs/promises";
3
+ import path from "path";
4
+ import os from "os";
5
+ import { spawnSync } from "child_process";
6
+ import yauzl from "yauzl";
7
+ import tar from "tar";
8
+ import { BIN_DIR, BINARY_NAME } from "./opencode-paths";
9
+ const GITHUB_API = "https://api.github.com/repos/anomalyco/opencode/releases/latest";
10
+ const GITHUB_DL = "https://github.com/anomalyco/opencode/releases/latest/download";
11
+ export class OpencodeDownloader {
12
+ constructor(logger) {
13
+ this.logger = logger;
14
+ }
15
+ getDownloadTarget() {
16
+ const platform = process.platform;
17
+ const arch = process.arch;
18
+ let osName;
19
+ switch (platform) {
20
+ case "win32":
21
+ osName = "windows";
22
+ break;
23
+ case "darwin":
24
+ osName = "darwin";
25
+ break;
26
+ case "linux":
27
+ osName = "linux";
28
+ break;
29
+ default:
30
+ throw new Error(`Unsupported platform: ${platform}`);
31
+ }
32
+ let archName;
33
+ switch (arch) {
34
+ case "x64":
35
+ archName = "x64";
36
+ break;
37
+ case "arm64":
38
+ archName = "arm64";
39
+ break;
40
+ default:
41
+ throw new Error(`Unsupported architecture: ${arch}`);
42
+ }
43
+ let target = `${osName}-${archName}`;
44
+ if (arch === "x64" && !this.hasAvx2()) {
45
+ target += "-baseline";
46
+ }
47
+ if (platform === "linux" && this.isMusl()) {
48
+ target += "-musl";
49
+ }
50
+ const archiveExt = platform === "linux" ? ".tar.gz" : ".zip";
51
+ return { filename: `opencode-${target}${archiveExt}`, archiveExt };
52
+ }
53
+ hasAvx2() {
54
+ if (process.platform === "win32") {
55
+ try {
56
+ const ps = `(Add-Type -MemberDefinition "[DllImport(\"kernel32.dll\")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)`;
57
+ const result = spawnSync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", ps], { encoding: "utf8", timeout: 5000 });
58
+ const out = result.stdout?.trim()?.toLowerCase();
59
+ return out === "true" || out === "1";
60
+ }
61
+ catch {
62
+ return true;
63
+ }
64
+ }
65
+ if (process.platform === "darwin") {
66
+ try {
67
+ const result = spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], { encoding: "utf8" });
68
+ return result.status === 0 && result.stdout.trim() === "1";
69
+ }
70
+ catch {
71
+ return true;
72
+ }
73
+ }
74
+ if (process.platform === "linux") {
75
+ try {
76
+ const cpuinfo = readFileSync("/proc/cpuinfo", "utf8");
77
+ return /avx2/i.test(cpuinfo);
78
+ }
79
+ catch {
80
+ return true;
81
+ }
82
+ }
83
+ return true;
84
+ }
85
+ isMusl() {
86
+ try {
87
+ const result = spawnSync("ldd", ["--version"], { encoding: "utf8" });
88
+ return result.stderr?.toLowerCase().includes("musl") ?? false;
89
+ }
90
+ catch {
91
+ return existsSync("/etc/alpine-release");
92
+ }
93
+ }
94
+ async getLatestVersion() {
95
+ const now = Date.now();
96
+ if (OpencodeDownloader.versionCache && now < OpencodeDownloader.versionCache.expiry) {
97
+ return OpencodeDownloader.versionCache.version;
98
+ }
99
+ const res = await fetch(GITHUB_API, {
100
+ headers: { Accept: "application/json", "User-Agent": "embeddedcowork" },
101
+ signal: AbortSignal.timeout(10000),
102
+ });
103
+ if (!res.ok)
104
+ throw new Error(`Failed to fetch latest version: HTTP ${res.status}`);
105
+ const data = (await res.json());
106
+ const version = data.tag_name.replace(/^v/, "");
107
+ OpencodeDownloader.versionCache = { version, expiry: now + 30000 };
108
+ return version;
109
+ }
110
+ async downloadWithRetry(url, dest, progressCb, retries = 5) {
111
+ for (let attempt = 1; attempt <= retries; attempt++) {
112
+ let writer = null;
113
+ try {
114
+ const res = await fetch(url);
115
+ if (!res.ok)
116
+ throw new Error(`HTTP ${res.status} ${res.statusText}`);
117
+ const total = Number(res.headers.get("content-length") ?? 0);
118
+ let current = 0;
119
+ const reader = res.body?.getReader();
120
+ if (!reader)
121
+ throw new Error("Response body is not readable");
122
+ writer = createWriteStream(dest);
123
+ while (true) {
124
+ const { done, value } = await reader.read();
125
+ if (done)
126
+ break;
127
+ current += value.length;
128
+ progressCb?.(current, total);
129
+ writer.write(value);
130
+ }
131
+ await new Promise((resolve, reject) => {
132
+ writer.end((err) => (err ? reject(err) : resolve()));
133
+ });
134
+ return;
135
+ }
136
+ catch (err) {
137
+ if (writer) {
138
+ writer.destroy();
139
+ writer = null;
140
+ }
141
+ try {
142
+ import("fs/promises").then((fs) => fs.unlink(dest)).catch(() => { });
143
+ }
144
+ catch { }
145
+ if (attempt === retries)
146
+ throw err;
147
+ const delay = Math.min(1000 * Math.pow(2, attempt - 1), 30000);
148
+ this.logger?.warn({ attempt, retries, err }, `Download attempt ${attempt} failed, retrying in ${delay}ms`);
149
+ await new Promise((r) => setTimeout(r, delay));
150
+ }
151
+ }
152
+ }
153
+ async extractZip(zipPath, outDir) {
154
+ return new Promise((resolve, reject) => {
155
+ yauzl.open(zipPath, { lazyEntries: true }, (err, zipfile) => {
156
+ if (err || !zipfile)
157
+ return reject(err ?? new Error("Failed to open zip"));
158
+ zipfile.readEntry();
159
+ zipfile.on("entry", (entry) => {
160
+ if (entry.fileName === BINARY_NAME || entry.fileName.endsWith(`/${BINARY_NAME}`)) {
161
+ zipfile.openReadStream(entry, (err2, readStream) => {
162
+ if (err2 || !readStream)
163
+ return reject(err2 ?? new Error("Failed to open read stream"));
164
+ const tmpPath = path.join(outDir, BINARY_NAME + ".tmp");
165
+ const destPath = path.join(outDir, BINARY_NAME);
166
+ const writer = createWriteStream(tmpPath);
167
+ readStream.pipe(writer);
168
+ writer.on("finish", () => {
169
+ chmodSync(tmpPath, 0o755);
170
+ renameSync(tmpPath, destPath);
171
+ resolve();
172
+ });
173
+ writer.on("error", (e) => {
174
+ try {
175
+ import("fs/promises").then((fs) => fs.unlink(tmpPath)).catch(() => { });
176
+ }
177
+ catch { }
178
+ reject(e);
179
+ });
180
+ });
181
+ }
182
+ else {
183
+ zipfile.readEntry();
184
+ }
185
+ });
186
+ zipfile.on("error", reject);
187
+ zipfile.on("end", () => reject(new Error("Binary not found in archive")));
188
+ });
189
+ });
190
+ }
191
+ async extractTarGz(tarPath, outDir) {
192
+ const extractPath = path.join(outDir, "extracted");
193
+ await mkdir(extractPath, { recursive: true });
194
+ await tar.extract({
195
+ file: tarPath,
196
+ cwd: extractPath,
197
+ filter: (filePath) => filePath === BINARY_NAME || filePath.endsWith(`/${BINARY_NAME}`),
198
+ });
199
+ const binarySrc = path.join(extractPath, BINARY_NAME);
200
+ const tmpPath = path.join(outDir, BINARY_NAME + ".tmp");
201
+ const binaryDest = path.join(outDir, BINARY_NAME);
202
+ await new Promise((resolve, reject) => {
203
+ const src = createReadStream(binarySrc);
204
+ const dst = createWriteStream(tmpPath);
205
+ src.pipe(dst);
206
+ dst.on("finish", () => {
207
+ chmodSync(tmpPath, 0o755);
208
+ renameSync(tmpPath, binaryDest);
209
+ resolve();
210
+ });
211
+ dst.on("error", (e) => {
212
+ try {
213
+ import("fs/promises").then((fs) => fs.unlink(tmpPath)).catch(() => { });
214
+ }
215
+ catch { }
216
+ reject(e);
217
+ });
218
+ src.on("error", (e) => {
219
+ try {
220
+ import("fs/promises").then((fs) => fs.unlink(tmpPath)).catch(() => { });
221
+ }
222
+ catch { }
223
+ reject(e);
224
+ });
225
+ });
226
+ }
227
+ getInstalledPath() {
228
+ return path.join(BIN_DIR, BINARY_NAME);
229
+ }
230
+ async verifyBinary(binaryPath) {
231
+ if (!existsSync(binaryPath))
232
+ return null;
233
+ try {
234
+ const result = spawnSync(binaryPath, ["--version"], { encoding: "utf8", timeout: 5000 });
235
+ if (result.status === 0) {
236
+ return (result.stdout ?? result.stderr ?? "").trim();
237
+ }
238
+ }
239
+ catch { }
240
+ this.logger?.warn({ path: binaryPath }, "Binary exists but --version failed, proceeding anyway");
241
+ return binaryPath;
242
+ }
243
+ async ensureDownloaded(statusCb) {
244
+ const target = this.getDownloadTarget();
245
+ const binaryPath = this.getInstalledPath();
246
+ const existingVersion = await this.verifyBinary(binaryPath);
247
+ try {
248
+ const latestVersion = await this.getLatestVersion();
249
+ if (existingVersion && existingVersion.includes(latestVersion)) {
250
+ this.logger?.info({ version: latestVersion, path: binaryPath }, "OpenCode binary is up to date");
251
+ return binaryPath;
252
+ }
253
+ }
254
+ catch (err) {
255
+ if (existingVersion) {
256
+ this.logger?.warn({ err }, "Failed to check latest version, using existing binary");
257
+ return binaryPath;
258
+ }
259
+ }
260
+ mkdirSync(BIN_DIR, { recursive: true });
261
+ const tmpDir = path.join(os.tmpdir(), "embeddedcowork-dl");
262
+ mkdirSync(tmpDir, { recursive: true });
263
+ const archivePath = path.join(tmpDir, target.filename);
264
+ const downloadUrl = `${GITHUB_DL}/${target.filename}`;
265
+ try {
266
+ statusCb?.({ type: "downloading", progress: { current: 0, total: 0 } });
267
+ await this.downloadWithRetry(downloadUrl, archivePath, (current, total) => {
268
+ statusCb?.({ type: "downloading", progress: { current, total } });
269
+ });
270
+ statusCb?.({ type: "extracting" });
271
+ if (target.archiveExt === ".zip") {
272
+ await this.extractZip(archivePath, BIN_DIR);
273
+ }
274
+ else {
275
+ await this.extractTarGz(archivePath, BIN_DIR);
276
+ }
277
+ statusCb?.({ type: "verifying" });
278
+ const version = await this.verifyBinary(binaryPath);
279
+ if (!version) {
280
+ throw new Error("Downloaded binary failed verification");
281
+ }
282
+ this.logger?.info({ version, path: binaryPath }, "OpenCode binary downloaded and verified");
283
+ statusCb?.({ type: "completed", binaryPath });
284
+ return binaryPath;
285
+ }
286
+ finally {
287
+ try {
288
+ await stat(archivePath);
289
+ await import("fs/promises").then((fs) => fs.unlink(archivePath));
290
+ }
291
+ catch { }
292
+ }
293
+ }
294
+ }
295
+ OpencodeDownloader.versionCache = null;
@@ -0,0 +1,167 @@
1
+ import { spawnSync } from "child_process";
2
+ import { existsSync } from "fs";
3
+ import path from "path";
4
+ import os from "os";
5
+ import { OpencodeDownloader } from "./opencode-downloader";
6
+ // ── Path constants ──────────────────────────────────────────
7
+ export const BIN_DIR = path.join(os.homedir(), ".embeddedcowork", "bin");
8
+ export const BINARY_NAME = process.platform === "win32" ? "opencode.exe" : "opencode";
9
+ export const INSTALLED_BINARY_PATH = path.join(BIN_DIR, BINARY_NAME);
10
+ // ── Shell helpers ───────────────────────────────────────────
11
+ function defaultShellPath() {
12
+ const configured = process.env.SHELL?.trim();
13
+ if (configured)
14
+ return configured;
15
+ return process.platform === "darwin" ? "/bin/zsh" : "/bin/bash";
16
+ }
17
+ function shellEscape(input) {
18
+ if (!input)
19
+ return "''";
20
+ return `'${input.replace(/'/g, `'\\''`)}'`;
21
+ }
22
+ function wrapCommandForShell(command, shellPath) {
23
+ const shellName = path.basename(shellPath).toLowerCase();
24
+ if (shellName.includes("bash")) {
25
+ return `if [ -f ~/.bashrc ]; then source ~/.bashrc >/dev/null 2>&1; fi; ${command}`;
26
+ }
27
+ if (shellName.includes("zsh")) {
28
+ return `if [ -f ~/.zshrc ]; then source ~/.zshrc >/dev/null 2>&1; fi; ${command}`;
29
+ }
30
+ return command;
31
+ }
32
+ function buildShellArgs(shellPath, command) {
33
+ const shellName = path.basename(shellPath).toLowerCase();
34
+ if (shellName.includes("zsh"))
35
+ return ["-l", "-i", "-c", command];
36
+ return ["-l", "-c", command];
37
+ }
38
+ // ── Binary lookup ───────────────────────────────────────────
39
+ export function resolveBinaryPathFromUserShell(identifier) {
40
+ if (process.platform === "win32")
41
+ return null;
42
+ const shellPath = defaultShellPath();
43
+ const lookupCommand = wrapCommandForShell(`command -v ${shellEscape(identifier)}`, shellPath);
44
+ const result = spawnSync(shellPath, buildShellArgs(shellPath, lookupCommand), {
45
+ encoding: "utf8",
46
+ env: {
47
+ ...process.env,
48
+ npm_config_prefix: undefined,
49
+ NPM_CONFIG_PREFIX: undefined,
50
+ },
51
+ });
52
+ if (result.status !== 0)
53
+ return null;
54
+ const resolved = String(result.stdout ?? "")
55
+ .split(/\r?\n/)
56
+ .map((line) => line.trim())
57
+ .find((line) => line.length > 0);
58
+ return resolved ?? null;
59
+ }
60
+ /**
61
+ * Resolve an opencode binary identifier to an absolute path.
62
+ * Order: absolute/relative → which/where → shell command -v → installed path → raw identifier
63
+ */
64
+ export function resolveBinary(identifier) {
65
+ if (!identifier)
66
+ return identifier;
67
+ if (path.isAbsolute(identifier) || identifier.includes("/") || identifier.includes("\\") || identifier.startsWith(".")) {
68
+ return identifier;
69
+ }
70
+ const locator = process.platform === "win32" ? "where" : "which";
71
+ try {
72
+ const result = spawnSync(locator, [identifier], { encoding: "utf8" });
73
+ if (result.status === 0 && result.stdout) {
74
+ const candidates = result.stdout
75
+ .split(/\r?\n/)
76
+ .map((line) => line.trim())
77
+ .filter((line) => line.length > 0)
78
+ .filter((line) => !/^INFO:/i.test(line));
79
+ if (candidates.length > 0) {
80
+ return candidates[0];
81
+ }
82
+ }
83
+ }
84
+ catch { }
85
+ const shellResolved = resolveBinaryPathFromUserShell(identifier);
86
+ if (shellResolved)
87
+ return shellResolved;
88
+ if (existsSync(INSTALLED_BINARY_PATH))
89
+ return INSTALLED_BINARY_PATH;
90
+ return identifier;
91
+ }
92
+ let downloadPhase = "idle";
93
+ let downloadProgress = { current: 0, total: 0 };
94
+ let downloadError;
95
+ function setDownloadPhase(phase) {
96
+ downloadPhase = phase;
97
+ if (phase === "idle" || phase === "completed" || phase === "error") {
98
+ downloadProgress = { current: 0, total: 0 };
99
+ }
100
+ }
101
+ export function getDownloadProgress() {
102
+ return { ...downloadProgress };
103
+ }
104
+ export function getDownloadPhase() {
105
+ return downloadPhase;
106
+ }
107
+ export function getDownloadError() {
108
+ return downloadError;
109
+ }
110
+ /**
111
+ * Check whether opencode is available on this system.
112
+ * Uses the same lookup order as resolveBinary("opencode").
113
+ * Returns additional download progress info when not available.
114
+ */
115
+ export function getOpencodeStatus() {
116
+ const resolved = resolveBinary("opencode");
117
+ const available = resolved !== "opencode" && existsSync(resolved);
118
+ if (available)
119
+ return { available: true };
120
+ return {
121
+ available: false,
122
+ status: downloadPhase,
123
+ progress: downloadPhase === "downloading" ? { ...downloadProgress } : undefined,
124
+ error: downloadError,
125
+ };
126
+ }
127
+ export function isBinaryAvailable() {
128
+ const resolved = resolveBinary("opencode");
129
+ return resolved !== "opencode" && existsSync(resolved);
130
+ }
131
+ // ── Download trigger (global singleton) ─────────────────────
132
+ let downloadPromise = null;
133
+ export function triggerBinaryDownload(logger) {
134
+ if (downloadPromise)
135
+ return downloadPromise;
136
+ setDownloadPhase("downloading");
137
+ downloadError = undefined;
138
+ const downloader = new OpencodeDownloader(logger);
139
+ downloadPromise = downloader
140
+ .ensureDownloaded((status) => {
141
+ if (status.type === "downloading") {
142
+ downloadPhase = "downloading";
143
+ downloadProgress = status.progress;
144
+ }
145
+ else if (status.type === "extracting") {
146
+ setDownloadPhase("extracting");
147
+ }
148
+ else if (status.type === "verifying") {
149
+ setDownloadPhase("verifying");
150
+ }
151
+ else if (status.type === "completed") {
152
+ setDownloadPhase("completed");
153
+ }
154
+ })
155
+ .then(() => {
156
+ logger.info("OpenCode auto-download completed");
157
+ setDownloadPhase("completed");
158
+ downloadPromise = null;
159
+ })
160
+ .catch((err) => {
161
+ const message = err instanceof Error ? err.message : String(err);
162
+ logger.error({ err }, "OpenCode auto-download failed");
163
+ downloadPhase = "error";
164
+ downloadError = message;
165
+ });
166
+ return downloadPromise;
167
+ }