@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
package/dist/logger.js ADDED
@@ -0,0 +1,109 @@
1
+ import { Transform } from "node:stream";
2
+ import pino from "pino";
3
+ const LEVEL_LABELS = {
4
+ 10: "trace",
5
+ 20: "debug",
6
+ 30: "info",
7
+ 40: "warn",
8
+ 50: "error",
9
+ 60: "fatal",
10
+ };
11
+ const LIFECYCLE_COMPONENTS = new Set(["app", "workspace"]);
12
+ const OMITTED_FIELDS = new Set(["time", "msg", "level", "component", "module"]);
13
+ export function createLogger(options = {}) {
14
+ const level = (options.level ?? process.env.CLI_LOG_LEVEL ?? "info").toLowerCase();
15
+ const destination = options.destination ?? process.env.CLI_LOG_DESTINATION ?? "stdout";
16
+ const baseComponent = options.component ?? "app";
17
+ const loggerOptions = {
18
+ level,
19
+ base: { component: baseComponent },
20
+ timestamp: false,
21
+ };
22
+ if (destination && destination !== "stdout") {
23
+ const stream = pino.destination({ dest: destination, mkdir: true, sync: false });
24
+ return pino(loggerOptions, stream);
25
+ }
26
+ const lifecycleStream = new LifecycleLogStream({ restrictInfoToLifecycle: level === "info" });
27
+ lifecycleStream.pipe(process.stdout);
28
+ return pino(loggerOptions, lifecycleStream);
29
+ }
30
+ class LifecycleLogStream extends Transform {
31
+ constructor(options) {
32
+ super();
33
+ this.options = options;
34
+ this.buffer = "";
35
+ }
36
+ _transform(chunk, _encoding, callback) {
37
+ this.buffer += chunk.toString();
38
+ let newlineIndex = this.buffer.indexOf("\n");
39
+ while (newlineIndex >= 0) {
40
+ const line = this.buffer.slice(0, newlineIndex);
41
+ this.buffer = this.buffer.slice(newlineIndex + 1);
42
+ this.pushFormatted(line);
43
+ newlineIndex = this.buffer.indexOf("\n");
44
+ }
45
+ callback();
46
+ }
47
+ _flush(callback) {
48
+ if (this.buffer.length > 0) {
49
+ this.pushFormatted(this.buffer);
50
+ this.buffer = "";
51
+ }
52
+ callback();
53
+ }
54
+ pushFormatted(line) {
55
+ if (!line.trim()) {
56
+ return;
57
+ }
58
+ let entry;
59
+ try {
60
+ entry = JSON.parse(line);
61
+ }
62
+ catch {
63
+ return;
64
+ }
65
+ const levelNumber = typeof entry.level === "number" ? entry.level : 30;
66
+ const levelLabel = LEVEL_LABELS[levelNumber] ?? "info";
67
+ const component = entry.component ?? entry.module ?? "app";
68
+ if (this.options.restrictInfoToLifecycle && levelNumber <= 30 && !LIFECYCLE_COMPONENTS.has(component)) {
69
+ return;
70
+ }
71
+ const message = typeof entry.msg === "string" ? entry.msg : "";
72
+ const metadata = this.formatMetadata(entry);
73
+ const formatted = metadata.length > 0 ? `[${levelLabel.toUpperCase()}] [${component}] ${message} ${metadata}` : `[${levelLabel.toUpperCase()}] [${component}] ${message}`;
74
+ this.push(`${formatted}\n`);
75
+ }
76
+ formatMetadata(entry) {
77
+ const pairs = [];
78
+ for (const [key, value] of Object.entries(entry)) {
79
+ if (OMITTED_FIELDS.has(key)) {
80
+ continue;
81
+ }
82
+ if (key === "err" && value && typeof value === "object") {
83
+ const err = value;
84
+ const errLabel = err.type ?? "Error";
85
+ const errMessage = err.message ? `: ${err.message}` : "";
86
+ pairs.push(`err=${errLabel}${errMessage}`);
87
+ if (err.stack) {
88
+ pairs.push(`stack="${err.stack}"`);
89
+ }
90
+ continue;
91
+ }
92
+ pairs.push(`${key}=${this.stringifyValue(value)}`);
93
+ }
94
+ return pairs.join(" ").trim();
95
+ }
96
+ stringifyValue(value) {
97
+ if (value === undefined)
98
+ return "undefined";
99
+ if (value === null)
100
+ return "null";
101
+ if (typeof value === "string")
102
+ return value;
103
+ if (typeof value === "number" || typeof value === "boolean")
104
+ return String(value);
105
+ if (value instanceof Error)
106
+ return value.message ?? value.name;
107
+ return JSON.stringify(value);
108
+ }
109
+ }
@@ -0,0 +1,32 @@
1
+ # opencode-config
2
+
3
+ ## TLDR
4
+ Template config + plugins injected into every OpenCode instance that EmbeddedCowork launches. It provides an EmbeddedCowork bridge plugin for local event exchange between the CLI server and opencode.
5
+
6
+ ## What it is
7
+ A packaged config directory that EmbeddedCowork copies into `~/.config/embeddedcowork/opencode-config` for production builds or uses directly in dev. OpenCode autoloads any `plugin/*.ts` or `plugin/*.js` from this directory.
8
+
9
+ ## How it works
10
+ - EmbeddedCowork sets `OPENCODE_CONFIG_DIR` when spawning each opencode instance (`packages/server/src/workspaces/manager.ts`).
11
+ - This template is synced from `packages/opencode-config` (`packages/server/src/opencode-config.ts`, `packages/server/scripts/copy-opencode-config.mjs`).
12
+ - OpenCode autoloads plugins from `plugin/` (`packages/opencode-config/plugin/embeddedcowork.ts`).
13
+ - The `EmbeddedCoworkPlugin` reads `EMBEDDEDCOWORK_INSTANCE_ID` + `EMBEDDEDCOWORK_BASE_URL`, connects to `GET /workspaces/:id/plugin/events`, and posts to `POST /workspaces/:id/plugin/event` (`packages/opencode-config/plugin/lib/client.ts`).
14
+ - The server exposes the plugin routes and maps events into the UI SSE pipeline (`packages/server/src/server/routes/plugin.ts`, `packages/server/src/plugins/handlers.ts`).
15
+
16
+ ## Expectations
17
+ - Local-only bridge (no auth/token yet).
18
+ - Plugin must fail startup if it cannot connect after 3 retries.
19
+ - Keep plugin entrypoints thin; put shared logic under `plugin/lib/` to avoid autoloaded helpers.
20
+ - Keep event shapes small and explicit; use `type` + `properties` only.
21
+
22
+ ## Ideas
23
+ - Add feature modules under `plugin/lib/features/` (tool lifecycle, permission prompts, custom commands).
24
+ - Expand `/workspaces/:id/plugin/*` with dedicated endpoints as needed.
25
+ - Promote stable event shapes and version tags once the protocol settles.
26
+
27
+ ## Pointers
28
+ - Plugin entry: `packages/opencode-config/plugin/embeddedcowork.ts`
29
+ - Plugin client: `packages/opencode-config/plugin/lib/client.ts`
30
+ - Plugin server routes: `packages/server/src/server/routes/plugin.ts`
31
+ - Plugin event handling: `packages/server/src/plugins/handlers.ts`
32
+ - Workspace env injection: `packages/server/src/workspaces/manager.ts`
@@ -0,0 +1,3 @@
1
+ {
2
+ "$schema": "https://opencode.ai/config.json"
3
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "@embeddedcowork/opencode-config",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "license": "MIT",
6
+ "dependencies": {
7
+ "@opencode-ai/plugin": "1.14.28"
8
+ }
9
+ }
@@ -0,0 +1,62 @@
1
+ import type { PluginInput } from "@opencode-ai/plugin"
2
+ import { createEmbeddedCoworkClient, getEmbeddedCoworkConfig } from "./lib/client"
3
+ import { createBackgroundProcessTools } from "./lib/background-process"
4
+
5
+ let voiceModeEnabled = false
6
+
7
+ export async function EmbeddedCoworkPlugin(input: PluginInput) {
8
+ const config = getEmbeddedCoworkConfig()
9
+ const client = createEmbeddedCoworkClient(config)
10
+ const backgroundProcessTools = createBackgroundProcessTools(config, { baseDir: input.directory })
11
+
12
+ await client.startEvents((event) => {
13
+ if (event.type === "embeddedcowork.ping") {
14
+ void client.postEvent({
15
+ type: "embeddedcowork.pong",
16
+ properties: {
17
+ ts: Date.now(),
18
+ pingTs: (event.properties as any)?.ts,
19
+ },
20
+ }).catch(() => {})
21
+ return
22
+ }
23
+
24
+ if (event.type === "embeddedcowork.voiceMode") {
25
+ voiceModeEnabled = Boolean((event.properties as { enabled?: unknown } | undefined)?.enabled)
26
+ }
27
+ })
28
+
29
+ return {
30
+ tool: {
31
+ ...backgroundProcessTools,
32
+ },
33
+ async "chat.message"(_input: { sessionID: string }, output: { message: { system?: string } }) {
34
+ if (!voiceModeEnabled) {
35
+ return
36
+ }
37
+
38
+ output.message.system = [output.message.system, buildVoiceModePrompt()].filter(Boolean).join("\n\n")
39
+ },
40
+ async event(input: { event: any }) {
41
+ const opencodeEvent = input?.event
42
+ if (!opencodeEvent || typeof opencodeEvent !== "object") return
43
+
44
+ },
45
+ }
46
+ }
47
+
48
+ function buildVoiceModePrompt(): string {
49
+ return [
50
+ "Voice conversation mode is enabled.",
51
+ "Prepend your reply with a fenced code block using language `spoken`.",
52
+ "The `spoken` block should be the natural conversational reply you would say out loud to the user. It should be a concise spoken gist of the full response in 2 to 4 natural sentences.",
53
+ "In the spoken block, summarize the main outcome, recommendation, or next step. Sound conversational and natural, not like a document summary.",
54
+ "Do not include code, bullet lists, markdown formatting, or long technical detail in the spoken block.",
55
+ "Do not add generic phrases about whether the user should read more.",
56
+ "Only mention additional written detail when there is something specific that may matter for the user's next response, such as a tradeoff, caveat, risk, open question, exact diff, or test result.",
57
+ "When referring to that written detail, say `below` or `in the message` rather than `detailed section`.",
58
+ "After the `spoken` block, continue with your normal detailed response.",
59
+ "Example:",
60
+ "```spoken\nI implemented the relay-based voice-mode flow and it works with the current plugin bridge. The reconnect caveat is explained below.\n```",
61
+ ].join("\n\n")
62
+ }
@@ -0,0 +1,265 @@
1
+ import path from "path"
2
+ import { tool } from "@opencode-ai/plugin/tool"
3
+ import { createEmbeddedCoworkRequester, type EmbeddedCoworkConfig } from "./request"
4
+
5
+ type BackgroundProcess = {
6
+ id: string
7
+ title: string
8
+ command: string
9
+ status: "running" | "stopped" | "error"
10
+ startedAt: string
11
+ stoppedAt?: string
12
+ exitCode?: number
13
+ outputSizeBytes?: number
14
+ }
15
+
16
+ type BackgroundProcessNotificationRequest = {
17
+ sessionID: string
18
+ directory: string
19
+ }
20
+
21
+ type BackgroundProcessOptions = {
22
+ baseDir: string
23
+ }
24
+
25
+ type ParsedCommand = {
26
+ head: string
27
+ args: string[]
28
+ }
29
+
30
+ export function createBackgroundProcessTools(config: EmbeddedCoworkConfig, options: BackgroundProcessOptions) {
31
+ const requester = createEmbeddedCoworkRequester(config)
32
+
33
+ const request = async <T>(path: string, init?: RequestInit): Promise<T> => {
34
+ return requester.requestJson<T>(`/background-processes${path}`, init)
35
+ }
36
+
37
+ return {
38
+ run_background_process: tool({
39
+ description:
40
+ "Run a long-lived background process (dev servers, DBs, watchers) so it keeps running while you do other tasks. Use it for running processes that timeout otherwise or produce a lot of output.",
41
+ args: {
42
+ title: tool.schema.string().describe("Short label for the process (e.g. Dev server, DB server)"),
43
+ command: tool.schema.string().describe("Shell command to run in the workspace"),
44
+ notify: tool.schema.boolean().optional().describe("Notify the current session when the process ends"),
45
+ },
46
+ async execute(args, context) {
47
+ assertCommandWithinBase(args.command, options.baseDir)
48
+ const notification: BackgroundProcessNotificationRequest | undefined = args.notify
49
+ ? {
50
+ sessionID: context.sessionID,
51
+ directory: context.directory,
52
+ }
53
+ : undefined
54
+ const process = await request<BackgroundProcess>("", {
55
+ method: "POST",
56
+ body: JSON.stringify({ title: args.title, command: args.command, notify: args.notify, notification }),
57
+ })
58
+
59
+ return `Started background process ${process.id} (${process.title})\nStatus: ${process.status}\nCommand: ${process.command}`
60
+ },
61
+ }),
62
+ list_background_processes: tool({
63
+ description: "List background processes running for this workspace.",
64
+ args: {},
65
+ async execute() {
66
+ const response = await request<{ processes: BackgroundProcess[] }>("")
67
+ if (response.processes.length === 0) {
68
+ return "No background processes running."
69
+ }
70
+
71
+ return response.processes
72
+ .map((process) => {
73
+ const status = process.status === "running" ? "running" : process.status
74
+ const exit = process.exitCode !== undefined ? ` (exit ${process.exitCode})` : ""
75
+ const size =
76
+ typeof process.outputSizeBytes === "number" ? ` | ${Math.round(process.outputSizeBytes / 1024)}KB` : ""
77
+ return `- ${process.id} | ${process.title} | ${status}${exit}${size}\n ${process.command}`
78
+ })
79
+ .join("\n")
80
+ },
81
+ }),
82
+ read_background_process_output: tool({
83
+ description: "Read output from a background process. Use full, grep, head, or tail.",
84
+ args: {
85
+ id: tool.schema.string().describe("Background process ID"),
86
+ method: tool.schema
87
+ .enum(["full", "grep", "head", "tail"])
88
+ .default("full")
89
+ .describe("Method to read output"),
90
+ pattern: tool.schema.string().optional().describe("Pattern for grep method"),
91
+ lines: tool.schema.number().optional().describe("Number of lines for head/tail methods"),
92
+ },
93
+ async execute(args) {
94
+ if (args.method === "grep" && !args.pattern) {
95
+ return "Pattern is required for grep method."
96
+ }
97
+
98
+ const params = new URLSearchParams({ method: args.method })
99
+ if (args.pattern) {
100
+ params.set("pattern", args.pattern)
101
+ }
102
+ if (args.lines) {
103
+ params.set("lines", String(args.lines))
104
+ }
105
+
106
+ const response = await request<{ id: string; content: string; truncated: boolean; sizeBytes: number }>(
107
+ `/${args.id}/output?${params.toString()}`,
108
+ )
109
+
110
+ const header = response.truncated
111
+ ? `Output (truncated, ${Math.round(response.sizeBytes / 1024)}KB):`
112
+ : `Output (${Math.round(response.sizeBytes / 1024)}KB):`
113
+
114
+ return `${header}\n\n${response.content}`
115
+ },
116
+ }),
117
+ stop_background_process: tool({
118
+ description: "Stop a background process (SIGTERM) but keep its output and entry.",
119
+ args: {
120
+ id: tool.schema.string().describe("Background process ID"),
121
+ },
122
+ async execute(args) {
123
+ const process = await request<BackgroundProcess>(`/${args.id}/stop`, { method: "POST" })
124
+ return `Stopped background process ${process.id} (${process.title}). Status: ${process.status}`
125
+ },
126
+ }),
127
+ terminate_background_process: tool({
128
+ description: "Terminate a background process and delete its output + entry.",
129
+ args: {
130
+ id: tool.schema.string().describe("Background process ID"),
131
+ },
132
+ async execute(args) {
133
+ await request<void>(`/${args.id}/terminate`, { method: "POST" })
134
+ return `Terminated background process ${args.id} and removed its output.`
135
+ },
136
+ }),
137
+ }
138
+ }
139
+
140
+ const FILE_COMMANDS = new Set(["cd", "rm", "cp", "mv", "mkdir", "touch", "chmod", "chown"])
141
+ const EXPANSION_CHARS = /[~*$?\[\]`$]/
142
+
143
+ function assertCommandWithinBase(command: string, baseDir: string) {
144
+ const normalizedBase = path.resolve(baseDir)
145
+ const commands = splitCommands(command)
146
+
147
+ for (const item of commands) {
148
+ if (!FILE_COMMANDS.has(item.head)) {
149
+ continue
150
+ }
151
+
152
+ for (const arg of item.args) {
153
+ if (!arg) continue
154
+ if (arg.startsWith("-") || (item.head === "chmod" && arg.startsWith("+"))) continue
155
+
156
+ const literalArg = unquote(arg)
157
+ if (EXPANSION_CHARS.test(literalArg)) {
158
+ throw new Error(`Background process commands may only reference paths within ${normalizedBase}.`)
159
+ }
160
+
161
+ const resolved = path.isAbsolute(literalArg) ? path.normalize(literalArg) : path.resolve(normalizedBase, literalArg)
162
+ if (!isWithinBase(normalizedBase, resolved)) {
163
+ throw new Error(`Background process commands may only reference paths within ${normalizedBase}.`)
164
+ }
165
+ }
166
+ }
167
+ }
168
+
169
+ function splitCommands(command: string): ParsedCommand[] {
170
+ const tokens = tokenize(command)
171
+ const commands: ParsedCommand[] = []
172
+ let current: string[] = []
173
+
174
+ for (const token of tokens) {
175
+ if (isSeparator(token)) {
176
+ if (current.length > 0) {
177
+ commands.push({ head: current[0], args: current.slice(1) })
178
+ current = []
179
+ }
180
+ continue
181
+ }
182
+ current.push(token)
183
+ }
184
+
185
+ if (current.length > 0) {
186
+ commands.push({ head: current[0], args: current.slice(1) })
187
+ }
188
+
189
+ return commands
190
+ }
191
+
192
+ function tokenize(input: string): string[] {
193
+ const tokens: string[] = []
194
+ let current = ""
195
+ let quote: "'" | '"' | null = null
196
+ let escape = false
197
+
198
+ const flush = () => {
199
+ if (current.length > 0) {
200
+ tokens.push(current)
201
+ current = ""
202
+ }
203
+ }
204
+
205
+ for (let index = 0; index < input.length; index += 1) {
206
+ const char = input[index]
207
+
208
+ if (escape) {
209
+ current += char
210
+ escape = false
211
+ continue
212
+ }
213
+
214
+ if (char === "\\" && quote !== "'") {
215
+ escape = true
216
+ continue
217
+ }
218
+
219
+ if (quote) {
220
+ current += char
221
+ if (char === quote) {
222
+ quote = null
223
+ }
224
+ continue
225
+ }
226
+
227
+ if (char === "'" || char === '"') {
228
+ quote = char
229
+ current += char
230
+ continue
231
+ }
232
+
233
+ if (char === " " || char === "\n" || char === "\t") {
234
+ flush()
235
+ continue
236
+ }
237
+
238
+ if (char === "|" || char === "&" || char === ";") {
239
+ flush()
240
+ tokens.push(char)
241
+ continue
242
+ }
243
+
244
+ current += char
245
+ }
246
+
247
+ flush()
248
+ return tokens
249
+ }
250
+
251
+ function isSeparator(token: string): boolean {
252
+ return token === "|" || token === "&" || token === ";"
253
+ }
254
+
255
+ function unquote(token: string): string {
256
+ if ((token.startsWith('"') && token.endsWith('"')) || (token.startsWith("'") && token.endsWith("'"))) {
257
+ return token.slice(1, -1)
258
+ }
259
+ return token
260
+ }
261
+
262
+ function isWithinBase(base: string, candidate: string): boolean {
263
+ const relative = path.relative(base, candidate)
264
+ return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative))
265
+ }
@@ -0,0 +1,133 @@
1
+ import { createEmbeddedCoworkRequester, type EmbeddedCoworkConfig, type PluginEvent } from "./request"
2
+
3
+ export { getEmbeddedCoworkConfig, type EmbeddedCoworkConfig, type PluginEvent } from "./request"
4
+
5
+ export function createEmbeddedCoworkClient(config: EmbeddedCoworkConfig) {
6
+ const requester = createEmbeddedCoworkRequester(config)
7
+
8
+ return {
9
+ postEvent: (event: PluginEvent) =>
10
+ requester.requestVoid("/event", {
11
+ method: "POST",
12
+ body: JSON.stringify(event),
13
+ }),
14
+ startEvents: (onEvent: (event: PluginEvent) => void) => startPluginEvents(requester, onEvent),
15
+ }
16
+ }
17
+
18
+ function delay(ms: number) {
19
+ return new Promise<void>((resolve) => setTimeout(resolve, ms))
20
+ }
21
+
22
+ async function startPluginEvents(
23
+ requester: ReturnType<typeof createEmbeddedCoworkRequester>,
24
+ onEvent: (event: PluginEvent) => void,
25
+ ) {
26
+ // Fail plugin startup if we cannot establish the initial connection.
27
+ const initialBody = await connectWithRetries(requester, 3)
28
+
29
+ // After startup, keep reconnecting; throw after 3 consecutive failures.
30
+ void consumeWithReconnect(requester, onEvent, initialBody)
31
+ }
32
+
33
+ async function connectWithRetries(requester: ReturnType<typeof createEmbeddedCoworkRequester>, maxAttempts: number) {
34
+ let lastError: unknown
35
+
36
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
37
+ try {
38
+ return await requester.requestSseBody("/events")
39
+ } catch (error) {
40
+ lastError = error
41
+ await delay(500 * attempt)
42
+ }
43
+ }
44
+
45
+ const reason = lastError instanceof Error ? lastError.message : String(lastError)
46
+ const url = requester.buildUrl("/events")
47
+ throw new Error(`[EmbeddedCoworkPlugin] Failed to connect to EmbeddedCowork at ${url} after ${maxAttempts} retries: ${reason}`)
48
+ }
49
+
50
+ async function consumeWithReconnect(
51
+ requester: ReturnType<typeof createEmbeddedCoworkRequester>,
52
+ onEvent: (event: PluginEvent) => void,
53
+ initialBody: ReadableStream<Uint8Array>,
54
+ ) {
55
+ let consecutiveFailures = 0
56
+ let body: ReadableStream<Uint8Array> | null = initialBody
57
+
58
+ while (true) {
59
+ try {
60
+ if (!body) {
61
+ body = await connectWithRetries(requester, 3)
62
+ }
63
+
64
+ await consumeSseBody(body, onEvent)
65
+ body = null
66
+ consecutiveFailures = 0
67
+ } catch (error) {
68
+ body = null
69
+ consecutiveFailures += 1
70
+ if (consecutiveFailures >= 3) {
71
+ const reason = error instanceof Error ? error.message : String(error)
72
+ throw new Error(`[EmbeddedCoworkPlugin] Plugin event stream failed after 3 retries: ${reason}`)
73
+ }
74
+ await delay(500 * consecutiveFailures)
75
+ }
76
+ }
77
+ }
78
+
79
+ async function consumeSseBody(body: ReadableStream<Uint8Array>, onEvent: (event: PluginEvent) => void) {
80
+ const reader = body.getReader()
81
+ const decoder = new TextDecoder()
82
+ let buffer = ""
83
+
84
+ while (true) {
85
+ const { done, value } = await reader.read()
86
+ if (done || !value) {
87
+ break
88
+ }
89
+
90
+ buffer += decoder.decode(value, { stream: true })
91
+
92
+ let separatorIndex = buffer.indexOf("\n\n")
93
+ while (separatorIndex >= 0) {
94
+ const chunk = buffer.slice(0, separatorIndex)
95
+ buffer = buffer.slice(separatorIndex + 2)
96
+ separatorIndex = buffer.indexOf("\n\n")
97
+
98
+ const event = parseSseChunk(chunk)
99
+ if (event) {
100
+ onEvent(event)
101
+ }
102
+ }
103
+ }
104
+
105
+ throw new Error("SSE stream ended")
106
+ }
107
+
108
+ function parseSseChunk(chunk: string): PluginEvent | null {
109
+ const lines = chunk.split(/\r?\n/)
110
+ const dataLines: string[] = []
111
+
112
+ for (const line of lines) {
113
+ if (line.startsWith(":")) continue
114
+ if (line.startsWith("data:")) {
115
+ dataLines.push(line.slice(5).trimStart())
116
+ }
117
+ }
118
+
119
+ if (dataLines.length === 0) return null
120
+
121
+ const payload = dataLines.join("\n").trim()
122
+ if (!payload) return null
123
+
124
+ try {
125
+ const parsed = JSON.parse(payload)
126
+ if (!parsed || typeof parsed !== "object" || typeof (parsed as any).type !== "string") {
127
+ return null
128
+ }
129
+ return parsed as PluginEvent
130
+ } catch {
131
+ return null
132
+ }
133
+ }