@vividcodeai/embeddedcowork-dev 0.0.3-dev-20260507-b76190e8

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 (434) hide show
  1. package/README.md +173 -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 +140 -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 +576 -0
  10. package/dist/bin.js +24 -0
  11. package/dist/clients/connection-manager.js +93 -0
  12. package/dist/config/location.js +57 -0
  13. package/dist/config/schema.js +71 -0
  14. package/dist/events/bus.js +45 -0
  15. package/dist/filesystem/__tests__/search-cache.test.js +40 -0
  16. package/dist/filesystem/browser.js +292 -0
  17. package/dist/filesystem/search-cache.js +43 -0
  18. package/dist/filesystem/search.js +135 -0
  19. package/dist/index.js +466 -0
  20. package/dist/launcher.js +149 -0
  21. package/dist/loader.js +21 -0
  22. package/dist/logger.js +109 -0
  23. package/dist/opencode-config/README.md +32 -0
  24. package/dist/opencode-config/opencode.jsonc +3 -0
  25. package/dist/opencode-config/package.json +9 -0
  26. package/dist/opencode-config/plugin/embeddedcowork.ts +62 -0
  27. package/dist/opencode-config/plugin/lib/background-process.ts +265 -0
  28. package/dist/opencode-config/plugin/lib/client.ts +133 -0
  29. package/dist/opencode-config/plugin/lib/request.ts +214 -0
  30. package/dist/opencode-config.js +15 -0
  31. package/dist/plugins/channel.js +40 -0
  32. package/dist/plugins/handlers.js +17 -0
  33. package/dist/plugins/voice-mode.js +78 -0
  34. package/dist/releases/dev-release-monitor.js +75 -0
  35. package/dist/releases/release-monitor.js +107 -0
  36. package/dist/runtime-paths.js +67 -0
  37. package/dist/server/__tests__/network-addresses.test.js +68 -0
  38. package/dist/server/__tests__/remote-proxy.test.js +204 -0
  39. package/dist/server/http-server.js +996 -0
  40. package/dist/server/network-addresses.js +114 -0
  41. package/dist/server/remote-proxy.js +466 -0
  42. package/dist/server/routes/auth-pages/login.html +135 -0
  43. package/dist/server/routes/auth-pages/token.html +93 -0
  44. package/dist/server/routes/auth.js +149 -0
  45. package/dist/server/routes/background-processes.js +78 -0
  46. package/dist/server/routes/events.js +66 -0
  47. package/dist/server/routes/filesystem.js +43 -0
  48. package/dist/server/routes/meta.js +44 -0
  49. package/dist/server/routes/plugin.js +70 -0
  50. package/dist/server/routes/remote-proxy.js +42 -0
  51. package/dist/server/routes/remote-servers.js +142 -0
  52. package/dist/server/routes/settings.js +69 -0
  53. package/dist/server/routes/sidecars.js +46 -0
  54. package/dist/server/routes/speech.js +63 -0
  55. package/dist/server/routes/storage.js +52 -0
  56. package/dist/server/routes/workspaces.js +221 -0
  57. package/dist/server/routes/worktrees.js +156 -0
  58. package/dist/server/tls.js +224 -0
  59. package/dist/settings/binaries.js +37 -0
  60. package/dist/settings/merge-patch.js +33 -0
  61. package/dist/settings/migrate.js +238 -0
  62. package/dist/settings/public-config.js +33 -0
  63. package/dist/settings/service.js +101 -0
  64. package/dist/settings/yaml-doc-store.js +96 -0
  65. package/dist/sidecars/manager.js +193 -0
  66. package/dist/speech/providers/openai-compatible.js +189 -0
  67. package/dist/speech/service.js +58 -0
  68. package/dist/storage/instance-store.js +56 -0
  69. package/dist/ui/__tests__/remote-ui.test.js +67 -0
  70. package/dist/ui/remote-ui.js +462 -0
  71. package/dist/workspaces/__tests__/spawn.test.js +139 -0
  72. package/dist/workspaces/git-mutations.js +98 -0
  73. package/dist/workspaces/git-status.js +323 -0
  74. package/dist/workspaces/git-worktrees.js +216 -0
  75. package/dist/workspaces/instance-events.js +180 -0
  76. package/dist/workspaces/manager.js +420 -0
  77. package/dist/workspaces/opencode-auth.js +16 -0
  78. package/dist/workspaces/runtime.js +366 -0
  79. package/dist/workspaces/spawn.js +219 -0
  80. package/dist/workspaces/worktree-directory.js +74 -0
  81. package/dist/workspaces/worktree-map.js +116 -0
  82. package/package.json +57 -0
  83. package/public/apple-touch-icon-180x180.png +0 -0
  84. package/public/assets/ChangesTab-C2DJXDf9.js +2 -0
  85. package/public/assets/DiffToolbar-De-3SRCF.js +1 -0
  86. package/public/assets/EmbeddedCowork-Icon-DSw5nKk7.png +0 -0
  87. package/public/assets/FilesTab-BuQ00MEc.js +2 -0
  88. package/public/assets/GitChangesTab-D9bf2jkM.js +2 -0
  89. package/public/assets/SplitFilePanel-B-3h60o2.js +1 -0
  90. package/public/assets/StatusTab-D5s19fRN.js +1 -0
  91. package/public/assets/abap-BdImnpbu.js +1 -0
  92. package/public/assets/actionscript-3-CfeIJUat.js +1 -0
  93. package/public/assets/ada-bCR0ucgS.js +1 -0
  94. package/public/assets/andromeeda-C-Jbm3Hp.js +1 -0
  95. package/public/assets/angular-html-CU67Zn6k.js +1 -0
  96. package/public/assets/angular-ts-BwZT4LLn.js +1 -0
  97. package/public/assets/apache-Pmp26Uib.js +1 -0
  98. package/public/assets/apex-DhZLUxFE.js +1 -0
  99. package/public/assets/apl-dKokRX4l.js +1 -0
  100. package/public/assets/applescript-Co6uUVPk.js +1 -0
  101. package/public/assets/ara-BRHolxvo.js +1 -0
  102. package/public/assets/asciidoc-Dv7Oe6Be.js +1 -0
  103. package/public/assets/asm-D_Q5rh1f.js +1 -0
  104. package/public/assets/astro-CbQHKStN.js +1 -0
  105. package/public/assets/aurora-x-D-2ljcwZ.js +1 -0
  106. package/public/assets/awk-DMzUqQB5.js +1 -0
  107. package/public/assets/ayu-dark-Cv9koXgw.js +1 -0
  108. package/public/assets/ballerina-BFfxhgS-.js +1 -0
  109. package/public/assets/bat-BkioyH1T.js +1 -0
  110. package/public/assets/beancount-k_qm7-4y.js +1 -0
  111. package/public/assets/berry-D08WgyRC.js +1 -0
  112. package/public/assets/bibtex-CHM0blh-.js +1 -0
  113. package/public/assets/bicep-Bmn6On1c.js +1 -0
  114. package/public/assets/blade-DVc8C-J4.js +1 -0
  115. package/public/assets/bsl-BO_Y6i37.js +1 -0
  116. package/public/assets/bundle-full-CdNbUxmo.js +13 -0
  117. package/public/assets/c-BIGW1oBm.js +1 -0
  118. package/public/assets/cadence-Bv_4Rxtq.js +1 -0
  119. package/public/assets/cairo-KRGpt6FW.js +1 -0
  120. package/public/assets/catppuccin-frappe-DFWUc33u.js +1 -0
  121. package/public/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
  122. package/public/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
  123. package/public/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
  124. package/public/assets/clarity-D53aC0YG.js +1 -0
  125. package/public/assets/clojure-P80f7IUj.js +1 -0
  126. package/public/assets/cmake-D1j8_8rp.js +1 -0
  127. package/public/assets/cobol-nwyudZeR.js +1 -0
  128. package/public/assets/codeowners-Bp6g37R7.js +1 -0
  129. package/public/assets/codeql-DsOJ9woJ.js +1 -0
  130. package/public/assets/coffee-Ch7k5sss.js +1 -0
  131. package/public/assets/common-lisp-Cg-RD9OK.js +1 -0
  132. package/public/assets/coq-DkFqJrB1.js +1 -0
  133. package/public/assets/core-DhEqZVGG.js +1 -0
  134. package/public/assets/cpp-CofmeUqb.js +1 -0
  135. package/public/assets/crystal-tKQVLTB8.js +1 -0
  136. package/public/assets/csharp-CX12Zw3r.js +1 -0
  137. package/public/assets/css-DPfMkruS.js +1 -0
  138. package/public/assets/csv-fuZLfV_i.js +1 -0
  139. package/public/assets/cue-D82EKSYY.js +1 -0
  140. package/public/assets/cypher-COkxafJQ.js +1 -0
  141. package/public/assets/d-85-TOEBH.js +1 -0
  142. package/public/assets/dark-plus-eOWES_5F.js +1 -0
  143. package/public/assets/dart-CF10PKvl.js +1 -0
  144. package/public/assets/dax-CEL-wOlO.js +1 -0
  145. package/public/assets/desktop-BmXAJ9_W.js +1 -0
  146. package/public/assets/diff-D97Zzqfu.js +1 -0
  147. package/public/assets/diff-viewer-B1l_VZc1.js +1 -0
  148. package/public/assets/docker-BcOcwvcX.js +1 -0
  149. package/public/assets/dotenv-Da5cRb03.js +1 -0
  150. package/public/assets/dracula-BzJJZx-M.js +1 -0
  151. package/public/assets/dracula-soft-BXkSAIEj.js +1 -0
  152. package/public/assets/dream-maker-BtqSS_iP.js +1 -0
  153. package/public/assets/edge-BkV0erSs.js +1 -0
  154. package/public/assets/elixir-CDX3lj18.js +1 -0
  155. package/public/assets/elm-DbKCFpqz.js +1 -0
  156. package/public/assets/emacs-lisp-C9XAeP06.js +1 -0
  157. package/public/assets/erb-BOJIQeun.js +1 -0
  158. package/public/assets/erlang-DsQrWhSR.js +1 -0
  159. package/public/assets/event-DjZVAIBO.js +1 -0
  160. package/public/assets/everforest-dark-BgDCqdQA.js +1 -0
  161. package/public/assets/everforest-light-C8M2exoo.js +1 -0
  162. package/public/assets/fast-diff-vendor-DgdwVvTQ.js +1 -0
  163. package/public/assets/fennel-BYunw83y.js +1 -0
  164. package/public/assets/fish-BvzEVeQv.js +1 -0
  165. package/public/assets/fluent-C4IJs8-o.js +1 -0
  166. package/public/assets/fortran-fixed-form-BZjJHVRy.js +1 -0
  167. package/public/assets/fortran-free-form-D22FLkUw.js +1 -0
  168. package/public/assets/fsharp-CXgrBDvD.js +1 -0
  169. package/public/assets/gdresource-B7Tvp0Sc.js +1 -0
  170. package/public/assets/gdscript-DTMYz4Jt.js +1 -0
  171. package/public/assets/gdshader-DkwncUOv.js +1 -0
  172. package/public/assets/genie-D0YGMca9.js +1 -0
  173. package/public/assets/gherkin-DyxjwDmM.js +1 -0
  174. package/public/assets/git-commit-F4YmCXRG.js +1 -0
  175. package/public/assets/git-diff-vendor-CSgooKT_.js +52 -0
  176. package/public/assets/git-diff-vendor-HAZkIolJ.css +19 -0
  177. package/public/assets/git-rebase-r7XF79zn.js +1 -0
  178. package/public/assets/github-dark-DHJKELXO.js +1 -0
  179. package/public/assets/github-dark-default-Cuk6v7N8.js +1 -0
  180. package/public/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  181. package/public/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  182. package/public/assets/github-light-DAi9KRSo.js +1 -0
  183. package/public/assets/github-light-default-D7oLnXFd.js +1 -0
  184. package/public/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  185. package/public/assets/gleam-BspZqrRM.js +1 -0
  186. package/public/assets/glimmer-js-Rg0-pVw9.js +1 -0
  187. package/public/assets/glimmer-ts-U6CK756n.js +1 -0
  188. package/public/assets/glsl-DplSGwfg.js +1 -0
  189. package/public/assets/gnuplot-DdkO51Og.js +1 -0
  190. package/public/assets/go-Dn2_MT6a.js +1 -0
  191. package/public/assets/graphql-ChdNCCLP.js +1 -0
  192. package/public/assets/groovy-gcz8RCvz.js +1 -0
  193. package/public/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  194. package/public/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  195. package/public/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  196. package/public/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  197. package/public/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  198. package/public/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  199. package/public/assets/hack-CaT9iCJl.js +1 -0
  200. package/public/assets/haml-B8DHNrY2.js +1 -0
  201. package/public/assets/handlebars-BL8al0AC.js +1 -0
  202. package/public/assets/haskell-Df6bDoY_.js +1 -0
  203. package/public/assets/haxe-CzTSHFRz.js +1 -0
  204. package/public/assets/hcl-BWvSN4gD.js +1 -0
  205. package/public/assets/highlight-vendor-8FKMu9os.js +10 -0
  206. package/public/assets/hjson-D5-asLiD.js +1 -0
  207. package/public/assets/hlsl-D3lLCCz7.js +1 -0
  208. package/public/assets/houston-DnULxvSX.js +1 -0
  209. package/public/assets/html-GMplVEZG.js +1 -0
  210. package/public/assets/html-derivative-BFtXZ54Q.js +1 -0
  211. package/public/assets/http-jrhK8wxY.js +1 -0
  212. package/public/assets/hurl-irOxFIW8.js +1 -0
  213. package/public/assets/hxml-Bvhsp5Yf.js +1 -0
  214. package/public/assets/hy-DFXneXwc.js +1 -0
  215. package/public/assets/imba-DGztddWO.js +1 -0
  216. package/public/assets/index-B2LsA7hD.js +1 -0
  217. package/public/assets/index-BErmCqgL.js +1 -0
  218. package/public/assets/index-BKMyzTSR.js +1 -0
  219. package/public/assets/index-BKvZBimW.js +1 -0
  220. package/public/assets/index-BQeBs108.js +1 -0
  221. package/public/assets/index-BqQARTCd.js +1 -0
  222. package/public/assets/index-C9Tl2tHH.js +2 -0
  223. package/public/assets/index-CLSJ4cO9.js +1 -0
  224. package/public/assets/index-DElsPAzQ.css +1 -0
  225. package/public/assets/index-ixx_g9gD.js +1 -0
  226. package/public/assets/ini-BEwlwnbL.js +1 -0
  227. package/public/assets/java-CylS5w8V.js +1 -0
  228. package/public/assets/javascript-wDzz0qaB.js +1 -0
  229. package/public/assets/jinja-4LBKfQ-Z.js +1 -0
  230. package/public/assets/jison-wvAkD_A8.js +1 -0
  231. package/public/assets/json-Cp-IABpG.js +1 -0
  232. package/public/assets/json5-C9tS-k6U.js +1 -0
  233. package/public/assets/jsonc-Des-eS-w.js +1 -0
  234. package/public/assets/jsonl-DcaNXYhu.js +1 -0
  235. package/public/assets/jsonnet-DFQXde-d.js +1 -0
  236. package/public/assets/jssm-C2t-YnRu.js +1 -0
  237. package/public/assets/jsx-g9-lgVsj.js +1 -0
  238. package/public/assets/julia-C8NyazO9.js +1 -0
  239. package/public/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  240. package/public/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  241. package/public/assets/kanagawa-wave-DWedfzmr.js +1 -0
  242. package/public/assets/kdl-DV7GczEv.js +1 -0
  243. package/public/assets/kotlin-BdnUsdx6.js +1 -0
  244. package/public/assets/kusto-BvAqAH-y.js +1 -0
  245. package/public/assets/laserwave-DUszq2jm.js +1 -0
  246. package/public/assets/latex-BUKiar2Z.js +1 -0
  247. package/public/assets/lean-DP1Csr6i.js +1 -0
  248. package/public/assets/less-B1dDrJ26.js +1 -0
  249. package/public/assets/light-plus-B7mTdjB0.js +1 -0
  250. package/public/assets/liquid-DYVedYrR.js +1 -0
  251. package/public/assets/llvm-BtvRca6l.js +1 -0
  252. package/public/assets/loading-CQjaT4lJ.js +2 -0
  253. package/public/assets/loading-CugGjKDZ.css +1 -0
  254. package/public/assets/log-2UxHyX5q.js +1 -0
  255. package/public/assets/logo-BtOb2qkB.js +1 -0
  256. package/public/assets/lua-BbnMAYS6.js +1 -0
  257. package/public/assets/luau-CXu1NL6O.js +1 -0
  258. package/public/assets/main-C1yBw4P8.js +53 -0
  259. package/public/assets/make-CHLpvVh8.js +1 -0
  260. package/public/assets/markdown-Cvjx9yec.js +1 -0
  261. package/public/assets/markdown-D5eIdNMf.js +58 -0
  262. package/public/assets/marko-CPi9NSCl.js +1 -0
  263. package/public/assets/material-theme-D5KoaKCx.js +1 -0
  264. package/public/assets/material-theme-darker-BfHTSMKl.js +1 -0
  265. package/public/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  266. package/public/assets/material-theme-ocean-CyktbL80.js +1 -0
  267. package/public/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  268. package/public/assets/matlab-D7o27uSR.js +1 -0
  269. package/public/assets/mdc-DUICxH0z.js +1 -0
  270. package/public/assets/mdx-Cmh6b_Ma.js +1 -0
  271. package/public/assets/mermaid-DKYwYmdq.js +1 -0
  272. package/public/assets/min-dark-CafNBF8u.js +1 -0
  273. package/public/assets/min-light-CTRr51gU.js +1 -0
  274. package/public/assets/mipsasm-CKIfxQSi.js +1 -0
  275. package/public/assets/mojo-1DNp92w6.js +1 -0
  276. package/public/assets/monaco-viewer-9Byc1Kpy.js +26 -0
  277. package/public/assets/monokai-D4h5O-jR.js +1 -0
  278. package/public/assets/move-Bu9oaDYs.js +1 -0
  279. package/public/assets/narrat-DRg8JJMk.js +1 -0
  280. package/public/assets/nextflow-CUEJCptM.js +1 -0
  281. package/public/assets/nginx-DknmC5AR.js +1 -0
  282. package/public/assets/night-owl-C39BiMTA.js +1 -0
  283. package/public/assets/nim-CVrawwO9.js +1 -0
  284. package/public/assets/nix-BbRYJGeE.js +1 -0
  285. package/public/assets/nord-Ddv68eIx.js +1 -0
  286. package/public/assets/nushell-C-sUppwS.js +1 -0
  287. package/public/assets/objective-c-DXmwc3jG.js +1 -0
  288. package/public/assets/objective-cpp-CLxacb5B.js +1 -0
  289. package/public/assets/ocaml-C0hk2d4L.js +1 -0
  290. package/public/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  291. package/public/assets/one-light-PoHY5YXO.js +1 -0
  292. package/public/assets/pascal-D93ZcfNL.js +1 -0
  293. package/public/assets/perl-C0TMdlhV.js +1 -0
  294. package/public/assets/php-CDn_0X-4.js +1 -0
  295. package/public/assets/pkl-u5AG7uiY.js +1 -0
  296. package/public/assets/plastic-3e1v2bzS.js +1 -0
  297. package/public/assets/plsql-ChMvpjG-.js +1 -0
  298. package/public/assets/po-BTJTHyun.js +1 -0
  299. package/public/assets/poimandres-CS3Unz2-.js +1 -0
  300. package/public/assets/polar-C0HS_06l.js +1 -0
  301. package/public/assets/postcss-CXtECtnM.js +1 -0
  302. package/public/assets/powerquery-CEu0bR-o.js +1 -0
  303. package/public/assets/powershell-Dpen1YoG.js +1 -0
  304. package/public/assets/prisma-Dd19v3D-.js +1 -0
  305. package/public/assets/prolog-CbFg5uaA.js +1 -0
  306. package/public/assets/proto-DyJlTyXw.js +1 -0
  307. package/public/assets/pug-CGlum2m_.js +1 -0
  308. package/public/assets/puppet-BMWR74SV.js +1 -0
  309. package/public/assets/purescript-CklMAg4u.js +1 -0
  310. package/public/assets/python-B6aJPvgy.js +1 -0
  311. package/public/assets/qml-3beO22l8.js +1 -0
  312. package/public/assets/qmldir-C8lEn-DE.js +1 -0
  313. package/public/assets/qss-IeuSbFQv.js +1 -0
  314. package/public/assets/r-DiinP2Uv.js +1 -0
  315. package/public/assets/racket-BqYA7rlc.js +1 -0
  316. package/public/assets/raku-DXvB9xmW.js +1 -0
  317. package/public/assets/razor-WgofotgN.js +1 -0
  318. package/public/assets/red-bN70gL4F.js +1 -0
  319. package/public/assets/reg-C-SQnVFl.js +1 -0
  320. package/public/assets/regexp-CDVJQ6XC.js +1 -0
  321. package/public/assets/rel-C3B-1QV4.js +1 -0
  322. package/public/assets/riscv-BM1_JUlF.js +1 -0
  323. package/public/assets/rose-pine-BHrmToEH.js +1 -0
  324. package/public/assets/rose-pine-dawn-CnK8MTSM.js +1 -0
  325. package/public/assets/rose-pine-moon-NleAzG8P.js +1 -0
  326. package/public/assets/rosmsg-BJDFO7_C.js +1 -0
  327. package/public/assets/rst-B0xPkSld.js +1 -0
  328. package/public/assets/ruby-BvKwtOVI.js +1 -0
  329. package/public/assets/rust-B1yitclQ.js +1 -0
  330. package/public/assets/sas-cz2c8ADy.js +1 -0
  331. package/public/assets/sass-Cj5Yp3dK.js +1 -0
  332. package/public/assets/scala-C151Ov-r.js +1 -0
  333. package/public/assets/scheme-C98Dy4si.js +1 -0
  334. package/public/assets/scss-OYdSNvt2.js +1 -0
  335. package/public/assets/sdbl-DVxCFoDh.js +1 -0
  336. package/public/assets/shaderlab-Dg9Lc6iA.js +1 -0
  337. package/public/assets/shellscript-Yzrsuije.js +1 -0
  338. package/public/assets/shellsession-BADoaaVG.js +1 -0
  339. package/public/assets/slack-dark-BthQWCQV.js +1 -0
  340. package/public/assets/slack-ochin-DqwNpetd.js +1 -0
  341. package/public/assets/smalltalk-BERRCDM3.js +1 -0
  342. package/public/assets/snazzy-light-Bw305WKR.js +1 -0
  343. package/public/assets/solarized-dark-DXbdFlpD.js +1 -0
  344. package/public/assets/solarized-light-L9t79GZl.js +1 -0
  345. package/public/assets/solidity-BbcW6ACK.js +1 -0
  346. package/public/assets/soy-Brmx7dQM.js +1 -0
  347. package/public/assets/sparql-rVzFXLq3.js +1 -0
  348. package/public/assets/splunk-BtCnVYZw.js +1 -0
  349. package/public/assets/sql-BLtJtn59.js +1 -0
  350. package/public/assets/ssh-config-_ykCGR6B.js +1 -0
  351. package/public/assets/stata-BH5u7GGu.js +1 -0
  352. package/public/assets/stylus-BEDo0Tqx.js +1 -0
  353. package/public/assets/svelte-3Dk4HxPD.js +1 -0
  354. package/public/assets/swift-Dg5xB15N.js +1 -0
  355. package/public/assets/synthwave-84-CbfX1IO0.js +1 -0
  356. package/public/assets/system-verilog-CnnmHF94.js +1 -0
  357. package/public/assets/systemd-4A_iFExJ.js +1 -0
  358. package/public/assets/talonscript-CkByrt1z.js +1 -0
  359. package/public/assets/tasl-QIJgUcNo.js +1 -0
  360. package/public/assets/tcl-dwOrl1Do.js +1 -0
  361. package/public/assets/templ-W15q3VgB.js +1 -0
  362. package/public/assets/terraform-BETggiCN.js +1 -0
  363. package/public/assets/tex-Cppo0RY3.js +1 -0
  364. package/public/assets/todo-uxdyLWei.js +1 -0
  365. package/public/assets/tokyo-night-hegEt444.js +1 -0
  366. package/public/assets/toml-vGWfd6FD.js +1 -0
  367. package/public/assets/tool-call-C_JEoVSV.js +60 -0
  368. package/public/assets/ts-tags-zn1MmPIZ.js +1 -0
  369. package/public/assets/tsv-B_m7g4N7.js +1 -0
  370. package/public/assets/tsx-COt5Ahok.js +1 -0
  371. package/public/assets/turtle-BsS91CYL.js +1 -0
  372. package/public/assets/twig-CO9l9SDP.js +1 -0
  373. package/public/assets/typescript-BPQ3VLAy.js +1 -0
  374. package/public/assets/typespec-Df68jz8_.js +1 -0
  375. package/public/assets/typst-DHCkPAjA.js +1 -0
  376. package/public/assets/unified-picker-ePaJEYDm.js +1 -0
  377. package/public/assets/v-BcVCzyr7.js +1 -0
  378. package/public/assets/vala-CsfeWuGM.js +1 -0
  379. package/public/assets/vb-D17OF-Vu.js +1 -0
  380. package/public/assets/verilog-BQ8w6xss.js +1 -0
  381. package/public/assets/vesper-DU1UobuO.js +1 -0
  382. package/public/assets/vhdl-CeAyd5Ju.js +1 -0
  383. package/public/assets/viml-CJc9bBzg.js +1 -0
  384. package/public/assets/vitesse-black-Bkuqu6BP.js +1 -0
  385. package/public/assets/vitesse-dark-D0r3Knsf.js +1 -0
  386. package/public/assets/vitesse-light-CVO1_9PV.js +1 -0
  387. package/public/assets/vue-CCoi5OLL.js +1 -0
  388. package/public/assets/vue-html-DAAvJJDi.js +1 -0
  389. package/public/assets/vue-vine-_Ih-lPRR.js +1 -0
  390. package/public/assets/vyper-CDx5xZoG.js +1 -0
  391. package/public/assets/wasm-CG6Dc4jp.js +1 -0
  392. package/public/assets/wasm-MzD3tlZU.js +1 -0
  393. package/public/assets/wenyan-BV7otONQ.js +1 -0
  394. package/public/assets/wgsl-Dx-B1_4e.js +1 -0
  395. package/public/assets/wikitext-BhOHFoWU.js +1 -0
  396. package/public/assets/wit-5i3qLPDT.js +1 -0
  397. package/public/assets/wolfram-lXgVvXCa.js +1 -0
  398. package/public/assets/wrap-text-S8HH4qqP.js +1 -0
  399. package/public/assets/xml-sdJ4AIDG.js +1 -0
  400. package/public/assets/xsl-CtQFsRM5.js +1 -0
  401. package/public/assets/yaml-Buea-lGh.js +1 -0
  402. package/public/assets/zenscript-DVFEvuxE.js +1 -0
  403. package/public/assets/zig-VOosw3JB.js +1 -0
  404. package/public/favicon.ico +0 -0
  405. package/public/index.html +44 -0
  406. package/public/loading.html +33 -0
  407. package/public/logo.png +0 -0
  408. package/public/manifest.webmanifest +1 -0
  409. package/public/maskable-icon-512x512.png +0 -0
  410. package/public/monaco/vs/base/browser/ui/codicons/codicon/codicon.ttf +0 -0
  411. package/public/monaco/vs/base/worker/workerMain.js +31 -0
  412. package/public/monaco/vs/basic-languages/cpp/cpp.js +10 -0
  413. package/public/monaco/vs/basic-languages/kotlin/kotlin.js +10 -0
  414. package/public/monaco/vs/basic-languages/markdown/markdown.js +10 -0
  415. package/public/monaco/vs/basic-languages/python/python.js +10 -0
  416. package/public/monaco/vs/editor/editor.main.css +8 -0
  417. package/public/monaco/vs/editor/editor.main.js +798 -0
  418. package/public/monaco/vs/language/css/cssMode.js +13 -0
  419. package/public/monaco/vs/language/css/cssWorker.js +77 -0
  420. package/public/monaco/vs/language/html/htmlMode.js +13 -0
  421. package/public/monaco/vs/language/html/htmlWorker.js +454 -0
  422. package/public/monaco/vs/language/json/jsonMode.js +19 -0
  423. package/public/monaco/vs/language/json/jsonWorker.js +42 -0
  424. package/public/monaco/vs/language/typescript/tsMode.js +20 -0
  425. package/public/monaco/vs/language/typescript/tsWorker.js +51328 -0
  426. package/public/monaco/vs/loader.js +11 -0
  427. package/public/monaco.worker.js +7 -0
  428. package/public/pwa-192x192.png +0 -0
  429. package/public/pwa-512x512.png +0 -0
  430. package/public/pwa-64x64.png +0 -0
  431. package/public/registerSW.js +1 -0
  432. package/public/sw.js +1 -0
  433. package/public/ui-version.json +3 -0
  434. package/public/workbox-60d14903.js +1 -0
@@ -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,40 @@
1
+ export class PluginChannelManager {
2
+ constructor(logger) {
3
+ this.logger = logger;
4
+ this.clients = new Set();
5
+ }
6
+ register(workspaceId, reply) {
7
+ const connection = { workspaceId, reply };
8
+ this.clients.add(connection);
9
+ this.logger.debug({ workspaceId }, "Plugin SSE client connected");
10
+ let closed = false;
11
+ const close = () => {
12
+ if (closed)
13
+ return;
14
+ closed = true;
15
+ this.clients.delete(connection);
16
+ this.logger.debug({ workspaceId }, "Plugin SSE client disconnected");
17
+ };
18
+ return { close };
19
+ }
20
+ send(workspaceId, event) {
21
+ for (const client of this.clients) {
22
+ if (client.workspaceId !== workspaceId)
23
+ continue;
24
+ this.write(client.reply, event);
25
+ }
26
+ }
27
+ broadcast(event) {
28
+ for (const client of this.clients) {
29
+ this.write(client.reply, event);
30
+ }
31
+ }
32
+ write(reply, event) {
33
+ try {
34
+ reply.raw.write(`data: ${JSON.stringify(event)}\n\n`);
35
+ }
36
+ catch (error) {
37
+ this.logger.warn({ err: error }, "Failed to write plugin SSE event");
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,17 @@
1
+ export function handlePluginEvent(workspaceId, event, deps) {
2
+ switch (event.type) {
3
+ case "embeddedcowork.pong":
4
+ deps.logger.debug({ workspaceId, properties: event.properties }, "Plugin pong received");
5
+ return;
6
+ default:
7
+ deps.logger.debug({ workspaceId, eventType: event.type }, "Unhandled plugin event");
8
+ }
9
+ }
10
+ export function buildPingEvent() {
11
+ return {
12
+ type: "embeddedcowork.ping",
13
+ properties: {
14
+ ts: Date.now(),
15
+ },
16
+ };
17
+ }
@@ -0,0 +1,78 @@
1
+ export class VoiceModeManager {
2
+ constructor(options) {
3
+ this.options = options;
4
+ this.enabledConnectionsByInstance = new Map();
5
+ this.aggregateByInstance = new Map();
6
+ this.options.connections.subscribe((event) => {
7
+ if (event.type !== "disconnected")
8
+ return;
9
+ this.clearConnection(event.connection);
10
+ });
11
+ }
12
+ setEnabled(instanceId, connection, enabled) {
13
+ if (enabled && !this.options.connections.isConnected(connection)) {
14
+ this.options.logger.debug({ instanceId, clientId: connection.clientId, connectionId: connection.connectionId }, "Ignoring voice mode enable for disconnected client connection");
15
+ return false;
16
+ }
17
+ const key = getConnectionKey(connection);
18
+ const current = this.enabledConnectionsByInstance.get(instanceId) ?? new Set();
19
+ if (enabled) {
20
+ current.add(key);
21
+ this.enabledConnectionsByInstance.set(instanceId, current);
22
+ }
23
+ else if (current.delete(key)) {
24
+ if (current.size === 0) {
25
+ this.enabledConnectionsByInstance.delete(instanceId);
26
+ }
27
+ else {
28
+ this.enabledConnectionsByInstance.set(instanceId, current);
29
+ }
30
+ }
31
+ this.options.logger.debug({ instanceId, clientId: connection.clientId, connectionId: connection.connectionId, enabled }, "Voice mode updated for client connection");
32
+ this.publishIfChanged(instanceId);
33
+ return true;
34
+ }
35
+ syncInstance(instanceId) {
36
+ this.options.channel.send(instanceId, buildVoiceModeEvent(this.isEnabled(instanceId)));
37
+ }
38
+ isEnabled(instanceId) {
39
+ return this.aggregateByInstance.get(instanceId) === true;
40
+ }
41
+ clearConnection(connection) {
42
+ const key = getConnectionKey(connection);
43
+ for (const [instanceId, enabledConnections] of Array.from(this.enabledConnectionsByInstance.entries())) {
44
+ if (!enabledConnections.delete(key))
45
+ continue;
46
+ if (enabledConnections.size === 0) {
47
+ this.enabledConnectionsByInstance.delete(instanceId);
48
+ }
49
+ this.publishIfChanged(instanceId);
50
+ }
51
+ }
52
+ publishIfChanged(instanceId) {
53
+ const enabled = (this.enabledConnectionsByInstance.get(instanceId)?.size ?? 0) > 0;
54
+ const previous = this.aggregateByInstance.get(instanceId) === true;
55
+ if (enabled === previous)
56
+ return;
57
+ if (enabled) {
58
+ this.aggregateByInstance.set(instanceId, true);
59
+ }
60
+ else {
61
+ this.aggregateByInstance.delete(instanceId);
62
+ }
63
+ this.options.logger.debug({ instanceId, enabled }, "Broadcasting aggregate voice mode");
64
+ this.options.channel.send(instanceId, buildVoiceModeEvent(enabled));
65
+ }
66
+ }
67
+ function buildVoiceModeEvent(enabled) {
68
+ return {
69
+ type: "embeddedcowork.voiceMode",
70
+ properties: {
71
+ enabled,
72
+ formatVersion: "v1",
73
+ },
74
+ };
75
+ }
76
+ function getConnectionKey(connection) {
77
+ return `${connection.clientId}:${connection.connectionId}`;
78
+ }
@@ -0,0 +1,75 @@
1
+ import { fetch } from "undici";
2
+ import { compareVersionStrings, stripTagPrefix } from "./release-monitor";
3
+ const DEFAULT_POLL_INTERVAL_MS = 15 * 60 * 1000;
4
+ export function startDevReleaseMonitor(options) {
5
+ let stopped = false;
6
+ let timer = null;
7
+ const pollIntervalMs = Number.isFinite(options.pollIntervalMs) && (options.pollIntervalMs ?? 0) > 0
8
+ ? options.pollIntervalMs
9
+ : DEFAULT_POLL_INTERVAL_MS;
10
+ const refresh = async () => {
11
+ if (stopped)
12
+ return;
13
+ try {
14
+ const release = await fetchLatestPrerelease({
15
+ repo: options.repo,
16
+ currentVersion: options.currentVersion,
17
+ });
18
+ options.onUpdate(release);
19
+ }
20
+ catch (error) {
21
+ options.logger.debug({ err: error }, "Failed to refresh dev prerelease information");
22
+ }
23
+ };
24
+ void refresh();
25
+ timer = setInterval(() => void refresh(), pollIntervalMs);
26
+ return {
27
+ stop() {
28
+ stopped = true;
29
+ if (timer) {
30
+ clearInterval(timer);
31
+ timer = null;
32
+ }
33
+ },
34
+ };
35
+ }
36
+ async function fetchLatestPrerelease(args) {
37
+ const normalizedRepo = args.repo.trim();
38
+ if (!/^[^/\s]+\/[^/\s]+$/.test(normalizedRepo)) {
39
+ throw new Error(`Invalid GitHub repo: ${args.repo}`);
40
+ }
41
+ const apiUrl = `https://api.github.com/repos/${normalizedRepo}/releases?per_page=20`;
42
+ const response = await fetch(apiUrl, {
43
+ headers: {
44
+ Accept: "application/vnd.github+json",
45
+ "User-Agent": "EmbeddedCowork-CLI",
46
+ },
47
+ });
48
+ if (!response.ok) {
49
+ throw new Error(`GitHub releases API responded with ${response.status}`);
50
+ }
51
+ const list = (await response.json());
52
+ const latest = list.find((r) => r && r.prerelease === true && r.draft !== true);
53
+ if (!latest) {
54
+ return null;
55
+ }
56
+ const tag = latest.tag_name || latest.name;
57
+ if (!tag) {
58
+ return null;
59
+ }
60
+ const normalizedVersion = stripTagPrefix(tag);
61
+ if (!normalizedVersion) {
62
+ return null;
63
+ }
64
+ if (compareVersionStrings(normalizedVersion, args.currentVersion) <= 0) {
65
+ return null;
66
+ }
67
+ return {
68
+ version: normalizedVersion,
69
+ tag,
70
+ url: latest.html_url ?? `https://github.com/${normalizedRepo}/releases/tag/${encodeURIComponent(tag)}`,
71
+ channel: "dev",
72
+ publishedAt: latest.published_at ?? latest.created_at,
73
+ notes: latest.body,
74
+ };
75
+ }
@@ -0,0 +1,107 @@
1
+ import { fetch } from "undici";
2
+ const RELEASES_API_URL = "https://api.github.com/repos/vividcode-ai/EmbeddedCowork/releases/latest";
3
+ export function startReleaseMonitor(options) {
4
+ let stopped = false;
5
+ const refreshRelease = async () => {
6
+ if (stopped)
7
+ return;
8
+ try {
9
+ const release = await fetchLatestRelease(options);
10
+ options.onUpdate(release);
11
+ }
12
+ catch (error) {
13
+ options.logger.warn({ err: error }, "Failed to refresh release information");
14
+ }
15
+ };
16
+ void refreshRelease();
17
+ return {
18
+ stop() {
19
+ stopped = true;
20
+ },
21
+ };
22
+ }
23
+ export function compareVersionStrings(a, b) {
24
+ const left = parseVersion(a);
25
+ const right = parseVersion(b);
26
+ return compareVersions(left, right);
27
+ }
28
+ async function fetchLatestRelease(options) {
29
+ const response = await fetch(RELEASES_API_URL, {
30
+ headers: {
31
+ Accept: "application/vnd.github+json",
32
+ "User-Agent": "EmbeddedCowork-CLI",
33
+ },
34
+ });
35
+ if (!response.ok) {
36
+ throw new Error(`Release API responded with ${response.status}`);
37
+ }
38
+ const json = (await response.json());
39
+ const tagFromServer = json.tag_name || json.name;
40
+ if (!tagFromServer) {
41
+ return null;
42
+ }
43
+ const normalizedVersion = stripTagPrefix(tagFromServer);
44
+ if (!normalizedVersion) {
45
+ return null;
46
+ }
47
+ const current = parseVersion(options.currentVersion);
48
+ const remote = parseVersion(normalizedVersion);
49
+ if (compareVersions(remote, current) <= 0) {
50
+ return null;
51
+ }
52
+ return {
53
+ version: normalizedVersion,
54
+ tag: tagFromServer,
55
+ url: json.html_url ?? `https://github.com/vividcode-ai/EmbeddedCowork/releases/tag/${encodeURIComponent(tagFromServer)}`,
56
+ channel: json.prerelease || normalizedVersion.includes("-") ? "dev" : "stable",
57
+ publishedAt: json.published_at ?? json.created_at,
58
+ notes: json.body,
59
+ };
60
+ }
61
+ export function stripTagPrefix(tag) {
62
+ if (!tag)
63
+ return null;
64
+ const trimmed = tag.trim();
65
+ if (!trimmed)
66
+ return null;
67
+ return trimmed.replace(/^v/i, "");
68
+ }
69
+ function parseVersion(value) {
70
+ const normalized = stripTagPrefix(value) ?? "0.0.0";
71
+ const dashIndex = normalized.indexOf("-");
72
+ const core = dashIndex >= 0 ? normalized.slice(0, dashIndex) : normalized;
73
+ const prerelease = dashIndex >= 0 ? normalized.slice(dashIndex + 1) : null;
74
+ const [major = 0, minor = 0, patch = 0] = core.split(".").map((segment) => {
75
+ const parsed = Number.parseInt(segment, 10);
76
+ return Number.isFinite(parsed) ? parsed : 0;
77
+ });
78
+ return {
79
+ major,
80
+ minor,
81
+ patch,
82
+ prerelease,
83
+ };
84
+ }
85
+ function compareVersions(a, b) {
86
+ if (a.major !== b.major) {
87
+ return a.major > b.major ? 1 : -1;
88
+ }
89
+ if (a.minor !== b.minor) {
90
+ return a.minor > b.minor ? 1 : -1;
91
+ }
92
+ if (a.patch !== b.patch) {
93
+ return a.patch > b.patch ? 1 : -1;
94
+ }
95
+ const aPre = a.prerelease && a.prerelease.length > 0 ? a.prerelease : null;
96
+ const bPre = b.prerelease && b.prerelease.length > 0 ? b.prerelease : null;
97
+ if (aPre === bPre) {
98
+ return 0;
99
+ }
100
+ if (!aPre) {
101
+ return 1;
102
+ }
103
+ if (!bPre) {
104
+ return -1;
105
+ }
106
+ return aPre.localeCompare(bPre);
107
+ }
@@ -0,0 +1,67 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+ function safeModuleDir(importMetaUrl) {
5
+ try {
6
+ return path.dirname(fileURLToPath(importMetaUrl));
7
+ }
8
+ catch {
9
+ return null;
10
+ }
11
+ }
12
+ function firstExistingPath(candidates, predicate) {
13
+ for (const candidate of candidates) {
14
+ if (!candidate)
15
+ continue;
16
+ if (predicate(candidate)) {
17
+ return candidate;
18
+ }
19
+ }
20
+ return null;
21
+ }
22
+ export function getPackagedDistDir() {
23
+ return path.dirname(process.execPath);
24
+ }
25
+ export function resolveServerPackageRoot(importMetaUrl) {
26
+ const moduleDir = safeModuleDir(importMetaUrl);
27
+ const configuredRoot = process.env.EMBEDDEDCOWORK_SERVER_ROOT?.trim();
28
+ const candidates = [
29
+ configuredRoot ? path.resolve(configuredRoot) : null,
30
+ moduleDir ? path.resolve(moduleDir, "..") : null,
31
+ path.resolve(getPackagedDistDir(), ".."),
32
+ ];
33
+ return (firstExistingPath(candidates, (value) => fs.existsSync(path.join(value, "package.json"))) ??
34
+ candidates.find((value) => Boolean(value)) ??
35
+ process.cwd());
36
+ }
37
+ export function resolveServerPublicDir(importMetaUrl) {
38
+ const moduleDir = safeModuleDir(importMetaUrl);
39
+ const candidates = [moduleDir ? path.resolve(moduleDir, "../public") : null, path.join(resolveServerPackageRoot(importMetaUrl), "public")];
40
+ return firstExistingPath(candidates, (value) => fs.existsSync(value)) ?? candidates[candidates.length - 1];
41
+ }
42
+ export function resolveAuthTemplatePath(importMetaUrl, fileName) {
43
+ const moduleDir = safeModuleDir(importMetaUrl);
44
+ const distDir = getPackagedDistDir();
45
+ const candidates = [
46
+ moduleDir ? path.join(moduleDir, "auth-pages", fileName) : null,
47
+ path.join(distDir, "auth-pages", fileName),
48
+ path.join(distDir, "server", "routes", "auth-pages", fileName),
49
+ ];
50
+ return firstExistingPath(candidates, (value) => fs.existsSync(value)) ?? candidates[0];
51
+ }
52
+ export function resolveOpencodeTemplateDir(importMetaUrl) {
53
+ const moduleDir = safeModuleDir(importMetaUrl);
54
+ const resourcesPath = process.resourcesPath;
55
+ const candidates = [
56
+ moduleDir ? path.resolve(moduleDir, "../../opencode-config") : null,
57
+ resourcesPath ? path.resolve(resourcesPath, "opencode-config") : null,
58
+ moduleDir ? path.resolve(moduleDir, "opencode-config") : null,
59
+ path.join(getPackagedDistDir(), "opencode-config"),
60
+ ];
61
+ return firstExistingPath(candidates, (value) => fs.existsSync(value)) ?? candidates[candidates.length - 1];
62
+ }
63
+ export function readServerPackageVersion(importMetaUrl) {
64
+ const packageJsonPath = path.join(resolveServerPackageRoot(importMetaUrl), "package.json");
65
+ const parsed = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
66
+ return typeof parsed.version === "string" && parsed.version.trim().length > 0 ? parsed.version : "0.0.0";
67
+ }
@@ -0,0 +1,68 @@
1
+ import assert from "node:assert/strict";
2
+ import os from "node:os";
3
+ import { describe, it } from "node:test";
4
+ import { resolveNetworkAddresses, resolveRemoteAddresses } from "../network-addresses";
5
+ describe("resolveNetworkAddresses", () => {
6
+ it("preserves interface order among external addresses", () => {
7
+ const addresses = [
8
+ { address: "172.24.0.1", family: "IPv4", internal: false },
9
+ { address: "192.168.1.128", family: "IPv4", internal: false },
10
+ { address: "10.0.0.8", family: 4, internal: false },
11
+ { address: "127.0.0.1", family: "IPv4", internal: true },
12
+ { address: "169.254.10.20", family: "IPv4", internal: false },
13
+ ];
14
+ usingMockedNetworkInterfaces(addresses, () => {
15
+ const result = resolveNetworkAddresses({ host: "0.0.0.0", protocol: "https", port: 9898 });
16
+ assert.deepEqual(result.map((entry) => entry.ip), ["172.24.0.1", "192.168.1.128", "10.0.0.8", "169.254.10.20", "127.0.0.1"]);
17
+ });
18
+ });
19
+ });
20
+ describe("resolveRemoteAddresses", () => {
21
+ it("keeps all external addresses user-visible while preferring non-link-local addresses for the primary URL", () => {
22
+ const addresses = [
23
+ { address: "169.254.10.20", family: "IPv4", internal: false },
24
+ { address: "192.168.1.128", family: "IPv4", internal: false },
25
+ { address: "172.24.0.1", family: "IPv4", internal: false },
26
+ ];
27
+ usingMockedNetworkInterfaces(addresses, () => {
28
+ const result = resolveRemoteAddresses({ host: "0.0.0.0", protocol: "https", port: 9898 });
29
+ assert.deepEqual(result.userVisible.map((entry) => entry.ip), ["192.168.1.128", "172.24.0.1", "169.254.10.20"]);
30
+ assert.equal(result.primaryRemoteUrl, "https://192.168.1.128:9898");
31
+ });
32
+ });
33
+ it("prefers private LAN addresses over public addresses", () => {
34
+ const addresses = [
35
+ { address: "203.0.113.40", family: "IPv4", internal: false },
36
+ { address: "192.168.1.128", family: "IPv4", internal: false },
37
+ { address: "8.8.8.8", family: "IPv4", internal: false },
38
+ ];
39
+ usingMockedNetworkInterfaces(addresses, () => {
40
+ const result = resolveRemoteAddresses({ host: "0.0.0.0", protocol: "https", port: 9898 });
41
+ assert.deepEqual(result.userVisible.map((entry) => entry.ip), ["192.168.1.128", "203.0.113.40", "8.8.8.8"]);
42
+ assert.equal(result.primaryRemoteUrl, "https://192.168.1.128:9898");
43
+ });
44
+ });
45
+ it("uses a public address when no private LAN address is available", () => {
46
+ const addresses = [
47
+ { address: "169.254.10.20", family: "IPv4", internal: false },
48
+ { address: "203.0.113.40", family: "IPv4", internal: false },
49
+ ];
50
+ usingMockedNetworkInterfaces(addresses, () => {
51
+ const result = resolveRemoteAddresses({ host: "0.0.0.0", protocol: "https", port: 9898 });
52
+ assert.deepEqual(result.userVisible.map((entry) => entry.ip), ["203.0.113.40", "169.254.10.20"]);
53
+ assert.equal(result.primaryRemoteUrl, "https://203.0.113.40:9898");
54
+ });
55
+ });
56
+ });
57
+ function usingMockedNetworkInterfaces(addresses, callback) {
58
+ const original = os.networkInterfaces;
59
+ os.networkInterfaces = (() => ({
60
+ ethernet0: addresses,
61
+ }));
62
+ try {
63
+ callback();
64
+ }
65
+ finally {
66
+ os.networkInterfaces = original;
67
+ }
68
+ }