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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (462) hide show
  1. package/README.md +126 -0
  2. package/dist/api-types.js +1 -0
  3. package/dist/auth/auth-store.js +134 -0
  4. package/dist/auth/http-auth.js +37 -0
  5. package/dist/auth/manager.js +128 -0
  6. package/dist/auth/password-hash.js +32 -0
  7. package/dist/auth/session-manager.js +17 -0
  8. package/dist/auth/token-manager.js +27 -0
  9. package/dist/background-processes/manager.js +437 -0
  10. package/dist/bin.js +24 -0
  11. package/dist/config/binaries.js +148 -0
  12. package/dist/config/location.js +57 -0
  13. package/dist/config/schema.js +70 -0
  14. package/dist/config/store.js +200 -0
  15. package/dist/events/bus.js +41 -0
  16. package/dist/filesystem/__tests__/search-cache.test.js +40 -0
  17. package/dist/filesystem/browser.js +285 -0
  18. package/dist/filesystem/search-cache.js +43 -0
  19. package/dist/filesystem/search.js +135 -0
  20. package/dist/index.js +410 -0
  21. package/dist/integrations/github/bot-signature.js +11 -0
  22. package/dist/integrations/github/git-ops.js +133 -0
  23. package/dist/integrations/github/github-types.js +1 -0
  24. package/dist/integrations/github/job-runner.js +608 -0
  25. package/dist/integrations/github/octokit.js +58 -0
  26. package/dist/integrations/github/sanitize-webhook.js +42 -0
  27. package/dist/integrations/github/webhook-verify.js +21 -0
  28. package/dist/integrations/github/workspace-context.js +10 -0
  29. package/dist/integrations/github/worktree-context.js +15 -0
  30. package/dist/launcher.js +149 -0
  31. package/dist/loader.js +21 -0
  32. package/dist/logger.js +109 -0
  33. package/dist/opencode/request-context.js +39 -0
  34. package/dist/opencode/worktree-directory.js +42 -0
  35. package/dist/opencode-config/README.md +32 -0
  36. package/dist/opencode-config/opencode.jsonc +3 -0
  37. package/dist/opencode-config/package.json +9 -0
  38. package/dist/opencode-config/plugin/codenomad.ts +32 -0
  39. package/dist/opencode-config/plugin/lib/background-process.ts +253 -0
  40. package/dist/opencode-config/plugin/lib/client.ts +133 -0
  41. package/dist/opencode-config/plugin/lib/request.ts +214 -0
  42. package/dist/opencode-config-template/README.md +32 -0
  43. package/dist/opencode-config-template/opencode.jsonc +3 -0
  44. package/dist/opencode-config-template/plugin/codenomad.ts +40 -0
  45. package/dist/opencode-config-template/plugin/lib/background-process.ts +160 -0
  46. package/dist/opencode-config-template/plugin/lib/client.ts +165 -0
  47. package/dist/opencode-config.js +26 -0
  48. package/dist/plugins/channel.js +40 -0
  49. package/dist/plugins/handlers.js +17 -0
  50. package/dist/releases/dev-release-monitor.js +75 -0
  51. package/dist/releases/release-monitor.js +107 -0
  52. package/dist/server/http-server.js +547 -0
  53. package/dist/server/network-addresses.js +72 -0
  54. package/dist/server/routes/auth-pages/login.html +134 -0
  55. package/dist/server/routes/auth-pages/token.html +93 -0
  56. package/dist/server/routes/auth.js +134 -0
  57. package/dist/server/routes/background-processes.js +60 -0
  58. package/dist/server/routes/config.js +59 -0
  59. package/dist/server/routes/events.js +43 -0
  60. package/dist/server/routes/filesystem.js +43 -0
  61. package/dist/server/routes/github-plugin.js +215 -0
  62. package/dist/server/routes/github-webhook.js +32 -0
  63. package/dist/server/routes/meta.js +47 -0
  64. package/dist/server/routes/plugin.js +52 -0
  65. package/dist/server/routes/storage.js +52 -0
  66. package/dist/server/routes/workspaces.js +89 -0
  67. package/dist/server/routes/worktrees.js +156 -0
  68. package/dist/server/tls.js +224 -0
  69. package/dist/storage/instance-store.js +56 -0
  70. package/dist/ui/__tests__/remote-ui.test.js +46 -0
  71. package/dist/ui/remote-ui.js +462 -0
  72. package/dist/workspaces/git-worktrees.js +199 -0
  73. package/dist/workspaces/instance-events.js +180 -0
  74. package/dist/workspaces/manager.js +375 -0
  75. package/dist/workspaces/opencode-auth.js +16 -0
  76. package/dist/workspaces/runtime.js +346 -0
  77. package/dist/workspaces/worktree-map.js +116 -0
  78. package/package.json +49 -0
  79. package/public/apple-touch-icon-180x180.png +0 -0
  80. package/public/assets/CodeNomad-Icon-bmTWNPXy.png +0 -0
  81. package/public/assets/abap-BdImnpbu.js +1 -0
  82. package/public/assets/actionscript-3-CfeIJUat.js +1 -0
  83. package/public/assets/ada-bCR0ucgS.js +1 -0
  84. package/public/assets/andromeeda-C-Jbm3Hp.js +1 -0
  85. package/public/assets/angular-html-CU67Zn6k.js +1 -0
  86. package/public/assets/angular-ts-BwZT4LLn.js +1 -0
  87. package/public/assets/apache-Pmp26Uib.js +1 -0
  88. package/public/assets/apex-DhZLUxFE.js +1 -0
  89. package/public/assets/apl-dKokRX4l.js +1 -0
  90. package/public/assets/applescript-Co6uUVPk.js +1 -0
  91. package/public/assets/ara-BRHolxvo.js +1 -0
  92. package/public/assets/asciidoc-Dv7Oe6Be.js +1 -0
  93. package/public/assets/asm-D_Q5rh1f.js +1 -0
  94. package/public/assets/astro-CbQHKStN.js +1 -0
  95. package/public/assets/aurora-x-D-2ljcwZ.js +1 -0
  96. package/public/assets/awk-DMzUqQB5.js +1 -0
  97. package/public/assets/ayu-dark-Cv9koXgw.js +1 -0
  98. package/public/assets/ballerina-BFfxhgS-.js +1 -0
  99. package/public/assets/bat-BkioyH1T.js +1 -0
  100. package/public/assets/beancount-k_qm7-4y.js +1 -0
  101. package/public/assets/berry-D08WgyRC.js +1 -0
  102. package/public/assets/bibtex-CHM0blh-.js +1 -0
  103. package/public/assets/bicep-Bmn6On1c.js +1 -0
  104. package/public/assets/blade-DVc8C-J4.js +1 -0
  105. package/public/assets/bsl-BO_Y6i37.js +1 -0
  106. package/public/assets/c-BIGW1oBm.js +1 -0
  107. package/public/assets/cadence-Bv_4Rxtq.js +1 -0
  108. package/public/assets/cairo-KRGpt6FW.js +1 -0
  109. package/public/assets/catppuccin-frappe-DFWUc33u.js +1 -0
  110. package/public/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
  111. package/public/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
  112. package/public/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
  113. package/public/assets/clarity-D53aC0YG.js +1 -0
  114. package/public/assets/clojure-P80f7IUj.js +1 -0
  115. package/public/assets/cmake-D1j8_8rp.js +1 -0
  116. package/public/assets/cobol-nwyudZeR.js +1 -0
  117. package/public/assets/codeowners-Bp6g37R7.js +1 -0
  118. package/public/assets/codeql-DsOJ9woJ.js +1 -0
  119. package/public/assets/coffee-Ch7k5sss.js +1 -0
  120. package/public/assets/common-lisp-Cg-RD9OK.js +1 -0
  121. package/public/assets/coq-DkFqJrB1.js +1 -0
  122. package/public/assets/core-BSTVzpXI.js +1 -0
  123. package/public/assets/cpp-CofmeUqb.js +1 -0
  124. package/public/assets/crystal-tKQVLTB8.js +1 -0
  125. package/public/assets/csharp-CX12Zw3r.js +1 -0
  126. package/public/assets/css-DPfMkruS.js +1 -0
  127. package/public/assets/csv-fuZLfV_i.js +1 -0
  128. package/public/assets/cue-D82EKSYY.js +1 -0
  129. package/public/assets/cypher-COkxafJQ.js +1 -0
  130. package/public/assets/d-85-TOEBH.js +1 -0
  131. package/public/assets/dark-plus-eOWES_5F.js +1 -0
  132. package/public/assets/dart-CF10PKvl.js +1 -0
  133. package/public/assets/dax-CEL-wOlO.js +1 -0
  134. package/public/assets/desktop-BmXAJ9_W.js +1 -0
  135. package/public/assets/diff-D97Zzqfu.js +1 -0
  136. package/public/assets/docker-BcOcwvcX.js +1 -0
  137. package/public/assets/dotenv-Da5cRb03.js +1 -0
  138. package/public/assets/dracula-BzJJZx-M.js +1 -0
  139. package/public/assets/dracula-soft-BXkSAIEj.js +1 -0
  140. package/public/assets/dream-maker-BtqSS_iP.js +1 -0
  141. package/public/assets/edge-BkV0erSs.js +1 -0
  142. package/public/assets/elixir-CDX3lj18.js +1 -0
  143. package/public/assets/elm-DbKCFpqz.js +1 -0
  144. package/public/assets/emacs-lisp-C9XAeP06.js +1 -0
  145. package/public/assets/erb-BOJIQeun.js +1 -0
  146. package/public/assets/erlang-DsQrWhSR.js +1 -0
  147. package/public/assets/everforest-dark-BgDCqdQA.js +1 -0
  148. package/public/assets/everforest-light-C8M2exoo.js +1 -0
  149. package/public/assets/fennel-BYunw83y.js +1 -0
  150. package/public/assets/fish-BvzEVeQv.js +1 -0
  151. package/public/assets/fluent-C4IJs8-o.js +1 -0
  152. package/public/assets/fortran-fixed-form-BZjJHVRy.js +1 -0
  153. package/public/assets/fortran-free-form-D22FLkUw.js +1 -0
  154. package/public/assets/fsharp-CXgrBDvD.js +1 -0
  155. package/public/assets/gdresource-B7Tvp0Sc.js +1 -0
  156. package/public/assets/gdscript-DTMYz4Jt.js +1 -0
  157. package/public/assets/gdshader-DkwncUOv.js +1 -0
  158. package/public/assets/genie-D0YGMca9.js +1 -0
  159. package/public/assets/gherkin-DyxjwDmM.js +1 -0
  160. package/public/assets/git-commit-F4YmCXRG.js +1 -0
  161. package/public/assets/git-rebase-r7XF79zn.js +1 -0
  162. package/public/assets/github-dark-DHJKELXO.js +1 -0
  163. package/public/assets/github-dark-default-Cuk6v7N8.js +1 -0
  164. package/public/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  165. package/public/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  166. package/public/assets/github-light-DAi9KRSo.js +1 -0
  167. package/public/assets/github-light-default-D7oLnXFd.js +1 -0
  168. package/public/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  169. package/public/assets/gleam-BspZqrRM.js +1 -0
  170. package/public/assets/glimmer-js-Rg0-pVw9.js +1 -0
  171. package/public/assets/glimmer-ts-U6CK756n.js +1 -0
  172. package/public/assets/glsl-DplSGwfg.js +1 -0
  173. package/public/assets/gnuplot-DdkO51Og.js +1 -0
  174. package/public/assets/go-Dn2_MT6a.js +1 -0
  175. package/public/assets/graphql-ChdNCCLP.js +1 -0
  176. package/public/assets/groovy-gcz8RCvz.js +1 -0
  177. package/public/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  178. package/public/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  179. package/public/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  180. package/public/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  181. package/public/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  182. package/public/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  183. package/public/assets/hack-CaT9iCJl.js +1 -0
  184. package/public/assets/haml-B8DHNrY2.js +1 -0
  185. package/public/assets/handlebars-BL8al0AC.js +1 -0
  186. package/public/assets/haskell-Df6bDoY_.js +1 -0
  187. package/public/assets/haxe-CzTSHFRz.js +1 -0
  188. package/public/assets/hcl-BWvSN4gD.js +1 -0
  189. package/public/assets/hjson-D5-asLiD.js +1 -0
  190. package/public/assets/hlsl-D3lLCCz7.js +1 -0
  191. package/public/assets/houston-DnULxvSX.js +1 -0
  192. package/public/assets/html-GMplVEZG.js +1 -0
  193. package/public/assets/html-derivative-BFtXZ54Q.js +1 -0
  194. package/public/assets/http-jrhK8wxY.js +1 -0
  195. package/public/assets/hurl-irOxFIW8.js +1 -0
  196. package/public/assets/hxml-Bvhsp5Yf.js +1 -0
  197. package/public/assets/hy-DFXneXwc.js +1 -0
  198. package/public/assets/imba-DGztddWO.js +1 -0
  199. package/public/assets/index-D4PT0yE4.js +1 -0
  200. package/public/assets/index-DN20ggb1.js +1 -0
  201. package/public/assets/index-DdQ7zIzB.js +1 -0
  202. package/public/assets/index-Dl-rJJuP.js +1 -0
  203. package/public/assets/index-Dlo2gDiy.css +1 -0
  204. package/public/assets/ini-BEwlwnbL.js +1 -0
  205. package/public/assets/java-CylS5w8V.js +1 -0
  206. package/public/assets/javascript-wDzz0qaB.js +1 -0
  207. package/public/assets/jinja-4LBKfQ-Z.js +1 -0
  208. package/public/assets/jison-wvAkD_A8.js +1 -0
  209. package/public/assets/json-Cp-IABpG.js +1 -0
  210. package/public/assets/json5-C9tS-k6U.js +1 -0
  211. package/public/assets/jsonc-Des-eS-w.js +1 -0
  212. package/public/assets/jsonl-DcaNXYhu.js +1 -0
  213. package/public/assets/jsonnet-DFQXde-d.js +1 -0
  214. package/public/assets/jssm-C2t-YnRu.js +1 -0
  215. package/public/assets/jsx-g9-lgVsj.js +1 -0
  216. package/public/assets/julia-C8NyazO9.js +1 -0
  217. package/public/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  218. package/public/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  219. package/public/assets/kanagawa-wave-DWedfzmr.js +1 -0
  220. package/public/assets/kdl-DV7GczEv.js +1 -0
  221. package/public/assets/kotlin-BdnUsdx6.js +1 -0
  222. package/public/assets/kusto-BvAqAH-y.js +1 -0
  223. package/public/assets/laserwave-DUszq2jm.js +1 -0
  224. package/public/assets/latex-BUKiar2Z.js +1 -0
  225. package/public/assets/lean-DP1Csr6i.js +1 -0
  226. package/public/assets/less-B1dDrJ26.js +1 -0
  227. package/public/assets/light-plus-B7mTdjB0.js +1 -0
  228. package/public/assets/liquid-DYVedYrR.js +1 -0
  229. package/public/assets/llvm-BtvRca6l.js +1 -0
  230. package/public/assets/loading-CmEVQgyj.css +1 -0
  231. package/public/assets/loading-DgqIiz-T.js +1 -0
  232. package/public/assets/log-2UxHyX5q.js +1 -0
  233. package/public/assets/logo-BtOb2qkB.js +1 -0
  234. package/public/assets/lua-BbnMAYS6.js +1 -0
  235. package/public/assets/luau-CXu1NL6O.js +1 -0
  236. package/public/assets/main-CSlDZj4f.js +188 -0
  237. package/public/assets/main-HAZkIolJ.css +19 -0
  238. package/public/assets/make-CHLpvVh8.js +1 -0
  239. package/public/assets/markdown-Cvjx9yec.js +1 -0
  240. package/public/assets/marko-CPi9NSCl.js +1 -0
  241. package/public/assets/material-theme-D5KoaKCx.js +1 -0
  242. package/public/assets/material-theme-darker-BfHTSMKl.js +1 -0
  243. package/public/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  244. package/public/assets/material-theme-ocean-CyktbL80.js +1 -0
  245. package/public/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  246. package/public/assets/matlab-D7o27uSR.js +1 -0
  247. package/public/assets/mdc-DUICxH0z.js +1 -0
  248. package/public/assets/mdx-Cmh6b_Ma.js +1 -0
  249. package/public/assets/mermaid-DKYwYmdq.js +1 -0
  250. package/public/assets/min-dark-CafNBF8u.js +1 -0
  251. package/public/assets/min-light-CTRr51gU.js +1 -0
  252. package/public/assets/mipsasm-CKIfxQSi.js +1 -0
  253. package/public/assets/mojo-1DNp92w6.js +1 -0
  254. package/public/assets/monokai-D4h5O-jR.js +1 -0
  255. package/public/assets/move-Bu9oaDYs.js +1 -0
  256. package/public/assets/narrat-DRg8JJMk.js +1 -0
  257. package/public/assets/nextflow-CUEJCptM.js +1 -0
  258. package/public/assets/nginx-DknmC5AR.js +1 -0
  259. package/public/assets/night-owl-C39BiMTA.js +1 -0
  260. package/public/assets/nim-CVrawwO9.js +1 -0
  261. package/public/assets/nix-BbRYJGeE.js +1 -0
  262. package/public/assets/nord-Ddv68eIx.js +1 -0
  263. package/public/assets/nushell-C-sUppwS.js +1 -0
  264. package/public/assets/objective-c-DXmwc3jG.js +1 -0
  265. package/public/assets/objective-cpp-CLxacb5B.js +1 -0
  266. package/public/assets/ocaml-C0hk2d4L.js +1 -0
  267. package/public/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  268. package/public/assets/one-light-PoHY5YXO.js +1 -0
  269. package/public/assets/pascal-D93ZcfNL.js +1 -0
  270. package/public/assets/perl-C0TMdlhV.js +1 -0
  271. package/public/assets/php-CDn_0X-4.js +1 -0
  272. package/public/assets/pkl-u5AG7uiY.js +1 -0
  273. package/public/assets/plastic-3e1v2bzS.js +1 -0
  274. package/public/assets/plsql-ChMvpjG-.js +1 -0
  275. package/public/assets/po-BTJTHyun.js +1 -0
  276. package/public/assets/poimandres-CS3Unz2-.js +1 -0
  277. package/public/assets/polar-C0HS_06l.js +1 -0
  278. package/public/assets/postcss-CXtECtnM.js +1 -0
  279. package/public/assets/powerquery-CEu0bR-o.js +1 -0
  280. package/public/assets/powershell-Dpen1YoG.js +1 -0
  281. package/public/assets/prisma-Dd19v3D-.js +1 -0
  282. package/public/assets/prolog-CbFg5uaA.js +1 -0
  283. package/public/assets/proto-DyJlTyXw.js +1 -0
  284. package/public/assets/pug-CGlum2m_.js +1 -0
  285. package/public/assets/puppet-BMWR74SV.js +1 -0
  286. package/public/assets/purescript-CklMAg4u.js +1 -0
  287. package/public/assets/python-B6aJPvgy.js +1 -0
  288. package/public/assets/qml-3beO22l8.js +1 -0
  289. package/public/assets/qmldir-C8lEn-DE.js +1 -0
  290. package/public/assets/qss-IeuSbFQv.js +1 -0
  291. package/public/assets/r-DiinP2Uv.js +1 -0
  292. package/public/assets/racket-BqYA7rlc.js +1 -0
  293. package/public/assets/raku-DXvB9xmW.js +1 -0
  294. package/public/assets/razor-WgofotgN.js +1 -0
  295. package/public/assets/red-bN70gL4F.js +1 -0
  296. package/public/assets/reg-C-SQnVFl.js +1 -0
  297. package/public/assets/regexp-CDVJQ6XC.js +1 -0
  298. package/public/assets/rel-C3B-1QV4.js +1 -0
  299. package/public/assets/riscv-BM1_JUlF.js +1 -0
  300. package/public/assets/rose-pine-BHrmToEH.js +1 -0
  301. package/public/assets/rose-pine-dawn-CnK8MTSM.js +1 -0
  302. package/public/assets/rose-pine-moon-NleAzG8P.js +1 -0
  303. package/public/assets/rosmsg-BJDFO7_C.js +1 -0
  304. package/public/assets/rst-B0xPkSld.js +1 -0
  305. package/public/assets/ruby-BvKwtOVI.js +1 -0
  306. package/public/assets/rust-B1yitclQ.js +1 -0
  307. package/public/assets/sas-cz2c8ADy.js +1 -0
  308. package/public/assets/sass-Cj5Yp3dK.js +1 -0
  309. package/public/assets/scala-C151Ov-r.js +1 -0
  310. package/public/assets/scheme-C98Dy4si.js +1 -0
  311. package/public/assets/scss-OYdSNvt2.js +1 -0
  312. package/public/assets/sdbl-DVxCFoDh.js +1 -0
  313. package/public/assets/shaderlab-Dg9Lc6iA.js +1 -0
  314. package/public/assets/shellscript-Yzrsuije.js +1 -0
  315. package/public/assets/shellsession-BADoaaVG.js +1 -0
  316. package/public/assets/slack-dark-BthQWCQV.js +1 -0
  317. package/public/assets/slack-ochin-DqwNpetd.js +1 -0
  318. package/public/assets/smalltalk-BERRCDM3.js +1 -0
  319. package/public/assets/snazzy-light-Bw305WKR.js +1 -0
  320. package/public/assets/solarized-dark-DXbdFlpD.js +1 -0
  321. package/public/assets/solarized-light-L9t79GZl.js +1 -0
  322. package/public/assets/solidity-BbcW6ACK.js +1 -0
  323. package/public/assets/soy-Brmx7dQM.js +1 -0
  324. package/public/assets/sparql-rVzFXLq3.js +1 -0
  325. package/public/assets/splunk-BtCnVYZw.js +1 -0
  326. package/public/assets/sql-BLtJtn59.js +1 -0
  327. package/public/assets/ssh-config-_ykCGR6B.js +1 -0
  328. package/public/assets/stata-BH5u7GGu.js +1 -0
  329. package/public/assets/stylus-BEDo0Tqx.js +1 -0
  330. package/public/assets/svelte-3Dk4HxPD.js +1 -0
  331. package/public/assets/swift-Dg5xB15N.js +1 -0
  332. package/public/assets/synthwave-84-CbfX1IO0.js +1 -0
  333. package/public/assets/system-verilog-CnnmHF94.js +1 -0
  334. package/public/assets/systemd-4A_iFExJ.js +1 -0
  335. package/public/assets/talonscript-CkByrt1z.js +1 -0
  336. package/public/assets/tasl-QIJgUcNo.js +1 -0
  337. package/public/assets/tcl-dwOrl1Do.js +1 -0
  338. package/public/assets/templ-W15q3VgB.js +1 -0
  339. package/public/assets/terraform-BETggiCN.js +1 -0
  340. package/public/assets/tex-Cppo0RY3.js +1 -0
  341. package/public/assets/tokyo-night-hegEt444.js +1 -0
  342. package/public/assets/toml-vGWfd6FD.js +1 -0
  343. package/public/assets/ts-tags-zn1MmPIZ.js +1 -0
  344. package/public/assets/tsv-B_m7g4N7.js +1 -0
  345. package/public/assets/tsx-COt5Ahok.js +1 -0
  346. package/public/assets/turtle-BsS91CYL.js +1 -0
  347. package/public/assets/twig-CO9l9SDP.js +1 -0
  348. package/public/assets/typescript-BPQ3VLAy.js +1 -0
  349. package/public/assets/typespec-Df68jz8_.js +1 -0
  350. package/public/assets/typst-DHCkPAjA.js +1 -0
  351. package/public/assets/v-BcVCzyr7.js +1 -0
  352. package/public/assets/vala-CsfeWuGM.js +1 -0
  353. package/public/assets/vb-D17OF-Vu.js +1 -0
  354. package/public/assets/verilog-BQ8w6xss.js +1 -0
  355. package/public/assets/vesper-DU1UobuO.js +1 -0
  356. package/public/assets/vhdl-CeAyd5Ju.js +1 -0
  357. package/public/assets/viml-CJc9bBzg.js +1 -0
  358. package/public/assets/vitesse-black-Bkuqu6BP.js +1 -0
  359. package/public/assets/vitesse-dark-D0r3Knsf.js +1 -0
  360. package/public/assets/vitesse-light-CVO1_9PV.js +1 -0
  361. package/public/assets/vue-CCoi5OLL.js +1 -0
  362. package/public/assets/vue-html-DAAvJJDi.js +1 -0
  363. package/public/assets/vue-vine-_Ih-lPRR.js +1 -0
  364. package/public/assets/vyper-CDx5xZoG.js +1 -0
  365. package/public/assets/wasm-CG6Dc4jp.js +1 -0
  366. package/public/assets/wasm-MzD3tlZU.js +1 -0
  367. package/public/assets/wenyan-BV7otONQ.js +1 -0
  368. package/public/assets/wgsl-Dx-B1_4e.js +1 -0
  369. package/public/assets/wikitext-BhOHFoWU.js +1 -0
  370. package/public/assets/wit-5i3qLPDT.js +1 -0
  371. package/public/assets/wolfram-lXgVvXCa.js +1 -0
  372. package/public/assets/xml-sdJ4AIDG.js +1 -0
  373. package/public/assets/xsl-CtQFsRM5.js +1 -0
  374. package/public/assets/yaml-Buea-lGh.js +1 -0
  375. package/public/assets/zenscript-DVFEvuxE.js +1 -0
  376. package/public/assets/zig-VOosw3JB.js +1 -0
  377. package/public/favicon.ico +0 -0
  378. package/public/index.html +38 -0
  379. package/public/loading.html +28 -0
  380. package/public/logo.png +0 -0
  381. package/public/manifest.webmanifest +1 -0
  382. package/public/maskable-icon-512x512.png +0 -0
  383. package/public/monaco/vs/base/browser/ui/codicons/codicon/codicon.ttf +0 -0
  384. package/public/monaco/vs/base/worker/workerMain.js +31 -0
  385. package/public/monaco/vs/basic-languages/cpp/cpp.js +10 -0
  386. package/public/monaco/vs/basic-languages/kotlin/kotlin.js +10 -0
  387. package/public/monaco/vs/basic-languages/markdown/markdown.js +10 -0
  388. package/public/monaco/vs/basic-languages/python/python.js +10 -0
  389. package/public/monaco/vs/editor/editor.main.css +8 -0
  390. package/public/monaco/vs/editor/editor.main.js +798 -0
  391. package/public/monaco/vs/language/css/cssMode.js +13 -0
  392. package/public/monaco/vs/language/css/cssWorker.js +77 -0
  393. package/public/monaco/vs/language/html/htmlMode.js +13 -0
  394. package/public/monaco/vs/language/html/htmlWorker.js +454 -0
  395. package/public/monaco/vs/language/json/jsonMode.js +19 -0
  396. package/public/monaco/vs/language/json/jsonWorker.js +42 -0
  397. package/public/monaco/vs/language/typescript/tsMode.js +20 -0
  398. package/public/monaco/vs/language/typescript/tsWorker.js +51328 -0
  399. package/public/monaco/vs/loader.js +11 -0
  400. package/public/monaco.worker.js +7 -0
  401. package/public/pwa-192x192.png +0 -0
  402. package/public/pwa-512x512.png +0 -0
  403. package/public/pwa-64x64.png +0 -0
  404. package/public/registerSW.js +1 -0
  405. package/public/sw.js +1 -0
  406. package/public/ui-version.json +3 -0
  407. package/public/workbox-60d14903.js +1 -0
  408. package/scripts/copy-auth-pages.mjs +22 -0
  409. package/scripts/copy-opencode-config.mjs +61 -0
  410. package/scripts/copy-ui-dist.mjs +21 -0
  411. package/src/api-types.ts +326 -0
  412. package/src/auth/auth-store.ts +175 -0
  413. package/src/auth/http-auth.ts +38 -0
  414. package/src/auth/manager.ts +163 -0
  415. package/src/auth/password-hash.ts +49 -0
  416. package/src/auth/session-manager.ts +23 -0
  417. package/src/auth/token-manager.ts +32 -0
  418. package/src/background-processes/manager.ts +519 -0
  419. package/src/bin.ts +29 -0
  420. package/src/config/binaries.ts +192 -0
  421. package/src/config/location.ts +78 -0
  422. package/src/config/schema.ts +104 -0
  423. package/src/config/store.ts +244 -0
  424. package/src/events/bus.ts +45 -0
  425. package/src/filesystem/__tests__/search-cache.test.ts +61 -0
  426. package/src/filesystem/browser.ts +353 -0
  427. package/src/filesystem/search-cache.ts +66 -0
  428. package/src/filesystem/search.ts +184 -0
  429. package/src/index.ts +540 -0
  430. package/src/launcher.ts +177 -0
  431. package/src/loader.ts +21 -0
  432. package/src/logger.ts +133 -0
  433. package/src/opencode-config.ts +31 -0
  434. package/src/plugins/channel.ts +55 -0
  435. package/src/plugins/handlers.ts +36 -0
  436. package/src/releases/dev-release-monitor.ts +118 -0
  437. package/src/releases/release-monitor.ts +149 -0
  438. package/src/server/http-server.ts +693 -0
  439. package/src/server/network-addresses.ts +75 -0
  440. package/src/server/routes/auth-pages/login.html +134 -0
  441. package/src/server/routes/auth-pages/token.html +93 -0
  442. package/src/server/routes/auth.ts +164 -0
  443. package/src/server/routes/background-processes.ts +85 -0
  444. package/src/server/routes/config.ts +76 -0
  445. package/src/server/routes/events.ts +61 -0
  446. package/src/server/routes/filesystem.ts +54 -0
  447. package/src/server/routes/meta.ts +58 -0
  448. package/src/server/routes/plugin.ts +75 -0
  449. package/src/server/routes/storage.ts +66 -0
  450. package/src/server/routes/workspaces.ts +113 -0
  451. package/src/server/routes/worktrees.ts +195 -0
  452. package/src/server/tls.ts +283 -0
  453. package/src/storage/instance-store.ts +64 -0
  454. package/src/ui/__tests__/remote-ui.test.ts +58 -0
  455. package/src/ui/remote-ui.ts +571 -0
  456. package/src/workspaces/git-worktrees.ts +241 -0
  457. package/src/workspaces/instance-events.ts +226 -0
  458. package/src/workspaces/manager.ts +493 -0
  459. package/src/workspaces/opencode-auth.ts +22 -0
  460. package/src/workspaces/runtime.ts +428 -0
  461. package/src/workspaces/worktree-map.ts +129 -0
  462. package/tsconfig.json +17 -0
@@ -0,0 +1,177 @@
1
+ import { spawn } from "child_process"
2
+ import os from "os"
3
+ import path from "path"
4
+ import type { Logger } from "./logger"
5
+
6
+ interface BrowserCandidate {
7
+ name: string
8
+ command: string
9
+ args: (url: string) => string[]
10
+ }
11
+
12
+ const APP_ARGS = (url: string) => [`--app=${url}`, "--new-window"]
13
+
14
+ export async function launchInBrowser(url: string, logger: Logger): Promise<boolean> {
15
+ const { platform, candidates, manualExamples } = buildPlatformCandidates(url)
16
+
17
+ console.log(`Attempting to launch browser (${platform}) using:`)
18
+ candidates.forEach((candidate) => console.log(` - ${candidate.name}: ${candidate.command}`))
19
+
20
+ for (const candidate of candidates) {
21
+ const success = await tryLaunch(candidate, url, logger)
22
+ if (success) {
23
+ return true
24
+ }
25
+ }
26
+
27
+ console.error(
28
+ "No supported browser found to launch. Run without --launch and use one of the commands below or install a compatible browser.",
29
+ )
30
+ if (manualExamples.length > 0) {
31
+ console.error("Manual launch commands:")
32
+ manualExamples.forEach((line) => console.error(` ${line}`))
33
+ }
34
+
35
+ return false
36
+ }
37
+
38
+ async function tryLaunch(candidate: BrowserCandidate, url: string, logger: Logger): Promise<boolean> {
39
+ return new Promise((resolve) => {
40
+ let resolved = false
41
+ try {
42
+ const args = candidate.args(url)
43
+ const child = spawn(candidate.command, args, { stdio: "ignore", detached: true })
44
+
45
+ child.once("error", (error) => {
46
+ if (resolved) return
47
+ resolved = true
48
+ logger.debug({ err: error, candidate: candidate.name, command: candidate.command, args }, "Browser launch failed")
49
+ resolve(false)
50
+ })
51
+
52
+ child.once("spawn", () => {
53
+ if (resolved) return
54
+ resolved = true
55
+ logger.info(
56
+ {
57
+ browser: candidate.name,
58
+ command: candidate.command,
59
+ args,
60
+ fullCommand: [candidate.command, ...args].join(" "),
61
+ },
62
+ "Launched browser in app mode",
63
+ )
64
+ child.unref()
65
+ resolve(true)
66
+ })
67
+ } catch (error) {
68
+ if (resolved) return
69
+ resolved = true
70
+ logger.debug({ err: error, candidate: candidate.name, command: candidate.command }, "Browser spawn threw")
71
+ resolve(false)
72
+ }
73
+ })
74
+ }
75
+
76
+ function buildPlatformCandidates(url: string) {
77
+ switch (os.platform()) {
78
+ case "darwin":
79
+ return {
80
+ platform: "macOS",
81
+ candidates: buildMacCandidates(),
82
+ manualExamples: buildMacManualExamples(url),
83
+ }
84
+ case "win32":
85
+ return {
86
+ platform: "Windows",
87
+ candidates: buildWindowsCandidates(),
88
+ manualExamples: buildWindowsManualExamples(url),
89
+ }
90
+ default:
91
+ return {
92
+ platform: "Linux",
93
+ candidates: buildLinuxCandidates(),
94
+ manualExamples: buildLinuxManualExamples(url),
95
+ }
96
+ }
97
+ }
98
+
99
+ function buildMacCandidates(): BrowserCandidate[] {
100
+ const apps = [
101
+ { name: "Google Chrome", path: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" },
102
+ { name: "Google Chrome Canary", path: "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary" },
103
+ { name: "Microsoft Edge", path: "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge" },
104
+ { name: "Brave Browser", path: "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser" },
105
+ { name: "Chromium", path: "/Applications/Chromium.app/Contents/MacOS/Chromium" },
106
+ { name: "Vivaldi", path: "/Applications/Vivaldi.app/Contents/MacOS/Vivaldi" },
107
+ { name: "Arc", path: "/Applications/Arc.app/Contents/MacOS/Arc" },
108
+ ]
109
+
110
+ return apps.map((entry) => ({ name: entry.name, command: entry.path, args: APP_ARGS }))
111
+ }
112
+
113
+ function buildWindowsCandidates(): BrowserCandidate[] {
114
+ const programFiles = process.env["ProgramFiles"]
115
+ const programFilesX86 = process.env["ProgramFiles(x86)"]
116
+ const localAppData = process.env["LocalAppData"]
117
+
118
+ const paths = [
119
+ [programFiles, "Google/Chrome/Application/chrome.exe", "Google Chrome"],
120
+ [programFilesX86, "Google/Chrome/Application/chrome.exe", "Google Chrome (x86)"],
121
+ [localAppData, "Google/Chrome/Application/chrome.exe", "Google Chrome (User)"],
122
+ [programFiles, "Microsoft/Edge/Application/msedge.exe", "Microsoft Edge"],
123
+ [programFilesX86, "Microsoft/Edge/Application/msedge.exe", "Microsoft Edge (x86)"],
124
+ [localAppData, "Microsoft/Edge/Application/msedge.exe", "Microsoft Edge (User)"],
125
+ [programFiles, "BraveSoftware/Brave-Browser/Application/brave.exe", "Brave"],
126
+ [localAppData, "BraveSoftware/Brave-Browser/Application/brave.exe", "Brave (User)"],
127
+ [programFiles, "Chromium/Application/chromium.exe", "Chromium"],
128
+ ] as const
129
+
130
+ return paths
131
+ .filter(([root]) => Boolean(root))
132
+ .map(([root, rel, name]) => ({
133
+ name,
134
+ command: path.join(root as string, rel),
135
+ args: APP_ARGS,
136
+ }))
137
+ }
138
+
139
+ function buildLinuxCandidates(): BrowserCandidate[] {
140
+ const names = [
141
+ "google-chrome",
142
+ "google-chrome-stable",
143
+ "chromium",
144
+ "chromium-browser",
145
+ "brave-browser",
146
+ "microsoft-edge",
147
+ "microsoft-edge-stable",
148
+ "vivaldi",
149
+ ]
150
+
151
+ return names.map((name) => ({ name, command: name, args: APP_ARGS }))
152
+ }
153
+
154
+ function buildMacManualExamples(url: string) {
155
+ return [
156
+ `"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --app="${url}" --new-window`,
157
+ `"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge" --app="${url}" --new-window`,
158
+ `"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser" --app="${url}" --new-window`,
159
+ ]
160
+ }
161
+
162
+ function buildWindowsManualExamples(url: string) {
163
+ return [
164
+ `"%ProgramFiles%\\Google\\Chrome\\Application\\chrome.exe" --app="${url}" --new-window`,
165
+ `"%ProgramFiles%\\Microsoft\\Edge\\Application\\msedge.exe" --app="${url}" --new-window`,
166
+ `"%ProgramFiles%\\BraveSoftware\\Brave-Browser\\Application\\brave.exe" --app="${url}" --new-window`,
167
+ ]
168
+ }
169
+
170
+ function buildLinuxManualExamples(url: string) {
171
+ return [
172
+ `google-chrome --app="${url}" --new-window`,
173
+ `chromium --app="${url}" --new-window`,
174
+ `brave-browser --app="${url}" --new-window`,
175
+ `microsoft-edge --app="${url}" --new-window`,
176
+ ]
177
+ }
package/src/loader.ts ADDED
@@ -0,0 +1,21 @@
1
+ export async function resolve(specifier: string, context: any, defaultResolve: any) {
2
+ try {
3
+ return await defaultResolve(specifier, context, defaultResolve)
4
+ } catch (error: any) {
5
+ if (shouldRetry(specifier, error)) {
6
+ const retried = specifier.endsWith(".js") ? specifier : `${specifier}.js`
7
+ return defaultResolve(retried, context, defaultResolve)
8
+ }
9
+ throw error
10
+ }
11
+ }
12
+
13
+ function shouldRetry(specifier: string, error: any) {
14
+ if (!error || error.code !== "ERR_MODULE_NOT_FOUND") {
15
+ return false
16
+ }
17
+ if (specifier.startsWith("./") || specifier.startsWith("../")) {
18
+ return true
19
+ }
20
+ return false
21
+ }
package/src/logger.ts ADDED
@@ -0,0 +1,133 @@
1
+ import { Transform } from "node:stream"
2
+ import pino, { Logger as PinoLogger } from "pino"
3
+
4
+ export type Logger = PinoLogger
5
+
6
+ interface LoggerOptions {
7
+ level?: string
8
+ destination?: string
9
+ component?: string
10
+ }
11
+
12
+ const LEVEL_LABELS: Record<number, string> = {
13
+ 10: "trace",
14
+ 20: "debug",
15
+ 30: "info",
16
+ 40: "warn",
17
+ 50: "error",
18
+ 60: "fatal",
19
+ }
20
+
21
+ const LIFECYCLE_COMPONENTS = new Set(["app", "workspace"])
22
+ const OMITTED_FIELDS = new Set(["time", "msg", "level", "component", "module"])
23
+
24
+ export function createLogger(options: LoggerOptions = {}): Logger {
25
+ const level = (options.level ?? process.env.CLI_LOG_LEVEL ?? "info").toLowerCase()
26
+ const destination = options.destination ?? process.env.CLI_LOG_DESTINATION ?? "stdout"
27
+ const baseComponent = options.component ?? "app"
28
+ const loggerOptions = {
29
+ level,
30
+ base: { component: baseComponent },
31
+ timestamp: false,
32
+ } as const
33
+
34
+ if (destination && destination !== "stdout") {
35
+ const stream = pino.destination({ dest: destination, mkdir: true, sync: false })
36
+ return pino(loggerOptions, stream)
37
+ }
38
+
39
+ const lifecycleStream = new LifecycleLogStream({ restrictInfoToLifecycle: level === "info" })
40
+ lifecycleStream.pipe(process.stdout)
41
+ return pino(loggerOptions, lifecycleStream)
42
+ }
43
+
44
+ interface LifecycleStreamOptions {
45
+ restrictInfoToLifecycle: boolean
46
+ }
47
+
48
+ class LifecycleLogStream extends Transform {
49
+ private buffer = ""
50
+
51
+ constructor(private readonly options: LifecycleStreamOptions) {
52
+ super()
53
+ }
54
+
55
+ _transform(chunk: Buffer, _encoding: BufferEncoding, callback: () => void) {
56
+ this.buffer += chunk.toString()
57
+ let newlineIndex = this.buffer.indexOf("\n")
58
+ while (newlineIndex >= 0) {
59
+ const line = this.buffer.slice(0, newlineIndex)
60
+ this.buffer = this.buffer.slice(newlineIndex + 1)
61
+ this.pushFormatted(line)
62
+ newlineIndex = this.buffer.indexOf("\n")
63
+ }
64
+ callback()
65
+ }
66
+
67
+ _flush(callback: () => void) {
68
+ if (this.buffer.length > 0) {
69
+ this.pushFormatted(this.buffer)
70
+ this.buffer = ""
71
+ }
72
+ callback()
73
+ }
74
+
75
+ private pushFormatted(line: string) {
76
+ if (!line.trim()) {
77
+ return
78
+ }
79
+
80
+ let entry: Record<string, unknown>
81
+ try {
82
+ entry = JSON.parse(line)
83
+ } catch {
84
+ return
85
+ }
86
+
87
+ const levelNumber = typeof entry.level === "number" ? entry.level : 30
88
+ const levelLabel = LEVEL_LABELS[levelNumber] ?? "info"
89
+ const component = (entry.component as string | undefined) ?? (entry.module as string | undefined) ?? "app"
90
+
91
+ if (this.options.restrictInfoToLifecycle && levelNumber <= 30 && !LIFECYCLE_COMPONENTS.has(component)) {
92
+ return
93
+ }
94
+
95
+ const message = typeof entry.msg === "string" ? entry.msg : ""
96
+ const metadata = this.formatMetadata(entry)
97
+ const formatted = metadata.length > 0 ? `[${levelLabel.toUpperCase()}] [${component}] ${message} ${metadata}` : `[${levelLabel.toUpperCase()}] [${component}] ${message}`
98
+ this.push(`${formatted}\n`)
99
+ }
100
+
101
+ private formatMetadata(entry: Record<string, unknown>): string {
102
+ const pairs: string[] = []
103
+ for (const [key, value] of Object.entries(entry)) {
104
+ if (OMITTED_FIELDS.has(key)) {
105
+ continue
106
+ }
107
+
108
+ if (key === "err" && value && typeof value === "object") {
109
+ const err = value as { type?: string; message?: string; stack?: string }
110
+ const errLabel = err.type ?? "Error"
111
+ const errMessage = err.message ? `: ${err.message}` : ""
112
+ pairs.push(`err=${errLabel}${errMessage}`)
113
+ if (err.stack) {
114
+ pairs.push(`stack="${err.stack}"`)
115
+ }
116
+ continue
117
+ }
118
+
119
+ pairs.push(`${key}=${this.stringifyValue(value)}`)
120
+ }
121
+
122
+ return pairs.join(" ").trim()
123
+ }
124
+
125
+ private stringifyValue(value: unknown): string {
126
+ if (value === undefined) return "undefined"
127
+ if (value === null) return "null"
128
+ if (typeof value === "string") return value
129
+ if (typeof value === "number" || typeof value === "boolean") return String(value)
130
+ if (value instanceof Error) return value.message ?? value.name
131
+ return JSON.stringify(value)
132
+ }
133
+ }
@@ -0,0 +1,31 @@
1
+ import { existsSync } from "fs"
2
+ import path from "path"
3
+ import { fileURLToPath } from "url"
4
+ import { createLogger } from "./logger"
5
+
6
+ const log = createLogger({ component: "opencode-config" })
7
+ const __filename = fileURLToPath(import.meta.url)
8
+ const __dirname = path.dirname(__filename)
9
+ const devTemplateDir = path.resolve(__dirname, "../../opencode-config")
10
+ const resourcesPath = (process as NodeJS.Process & { resourcesPath?: string }).resourcesPath
11
+ const prodTemplateDirs = [
12
+ resourcesPath ? path.resolve(resourcesPath, "opencode-config") : undefined,
13
+ path.resolve(__dirname, "opencode-config"),
14
+ ].filter((dir): dir is string => Boolean(dir))
15
+
16
+ const isDevBuild = Boolean(process.env.CODENOMAD_DEV ?? process.env.CLI_UI_DEV_SERVER) || existsSync(devTemplateDir)
17
+ const templateDir = isDevBuild
18
+ ? devTemplateDir
19
+ : prodTemplateDirs.find((dir) => existsSync(dir)) ?? prodTemplateDirs[0]
20
+
21
+ export function getOpencodeConfigDir(): string {
22
+ if (!existsSync(templateDir)) {
23
+ throw new Error(`CodeNomad Opencode config template missing at ${templateDir}`)
24
+ }
25
+
26
+ if (isDevBuild) {
27
+ log.debug({ templateDir }, "Using Opencode config template directly (dev mode)")
28
+ }
29
+
30
+ return templateDir
31
+ }
@@ -0,0 +1,55 @@
1
+ import type { FastifyReply } from "fastify"
2
+ import type { Logger } from "../logger"
3
+
4
+ export interface PluginOutboundEvent {
5
+ type: string
6
+ properties?: Record<string, unknown>
7
+ }
8
+
9
+ interface ClientConnection {
10
+ reply: FastifyReply
11
+ workspaceId: string
12
+ }
13
+
14
+ export class PluginChannelManager {
15
+ private readonly clients = new Set<ClientConnection>()
16
+
17
+ constructor(private readonly logger: Logger) {}
18
+
19
+ register(workspaceId: string, reply: FastifyReply) {
20
+ const connection: ClientConnection = { workspaceId, reply }
21
+ this.clients.add(connection)
22
+ this.logger.debug({ workspaceId }, "Plugin SSE client connected")
23
+
24
+ let closed = false
25
+ const close = () => {
26
+ if (closed) return
27
+ closed = true
28
+ this.clients.delete(connection)
29
+ this.logger.debug({ workspaceId }, "Plugin SSE client disconnected")
30
+ }
31
+
32
+ return { close }
33
+ }
34
+
35
+ send(workspaceId: string, event: PluginOutboundEvent) {
36
+ for (const client of this.clients) {
37
+ if (client.workspaceId !== workspaceId) continue
38
+ this.write(client.reply, event)
39
+ }
40
+ }
41
+
42
+ broadcast(event: PluginOutboundEvent) {
43
+ for (const client of this.clients) {
44
+ this.write(client.reply, event)
45
+ }
46
+ }
47
+
48
+ private write(reply: FastifyReply, event: PluginOutboundEvent) {
49
+ try {
50
+ reply.raw.write(`data: ${JSON.stringify(event)}\n\n`)
51
+ } catch (error) {
52
+ this.logger.warn({ err: error }, "Failed to write plugin SSE event")
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,36 @@
1
+ import type { EventBus } from "../events/bus"
2
+ import type { WorkspaceManager } from "../workspaces/manager"
3
+ import type { Logger } from "../logger"
4
+ import type { PluginOutboundEvent } from "./channel"
5
+
6
+ export interface PluginInboundEvent {
7
+ type: string
8
+ properties?: Record<string, unknown>
9
+ }
10
+
11
+ interface HandlerDeps {
12
+ workspaceManager: WorkspaceManager
13
+ eventBus: EventBus
14
+ logger: Logger
15
+ }
16
+
17
+ export function handlePluginEvent(workspaceId: string, event: PluginInboundEvent, deps: HandlerDeps) {
18
+ switch (event.type) {
19
+ case "codenomad.pong":
20
+ deps.logger.debug({ workspaceId, properties: event.properties }, "Plugin pong received")
21
+ return
22
+
23
+ default:
24
+ deps.logger.debug({ workspaceId, eventType: event.type }, "Unhandled plugin event")
25
+ }
26
+ }
27
+
28
+ export function buildPingEvent(): PluginOutboundEvent {
29
+
30
+ return {
31
+ type: "codenomad.ping",
32
+ properties: {
33
+ ts: Date.now(),
34
+ },
35
+ }
36
+ }
@@ -0,0 +1,118 @@
1
+ import { fetch } from "undici"
2
+ import type { LatestReleaseInfo } from "../api-types"
3
+ import type { Logger } from "../logger"
4
+ import { compareVersionStrings, stripTagPrefix } from "./release-monitor"
5
+
6
+ interface DevReleaseMonitorOptions {
7
+ /** Current running server version (from package.json). */
8
+ currentVersion: string
9
+ /** GitHub repo in the form "owner/name". */
10
+ repo: string
11
+ logger: Logger
12
+ onUpdate: (release: LatestReleaseInfo | null) => void
13
+ pollIntervalMs?: number
14
+ }
15
+
16
+ interface GithubReleaseListItem {
17
+ tag_name?: string
18
+ name?: string
19
+ html_url?: string
20
+ body?: string
21
+ published_at?: string
22
+ created_at?: string
23
+ prerelease?: boolean
24
+ draft?: boolean
25
+ }
26
+
27
+ export interface DevReleaseMonitor {
28
+ stop(): void
29
+ }
30
+
31
+ const DEFAULT_POLL_INTERVAL_MS = 15 * 60 * 1000
32
+
33
+ export function startDevReleaseMonitor(options: DevReleaseMonitorOptions): DevReleaseMonitor {
34
+ let stopped = false
35
+ let timer: ReturnType<typeof setInterval> | null = null
36
+
37
+ const pollIntervalMs =
38
+ Number.isFinite(options.pollIntervalMs) && (options.pollIntervalMs ?? 0) > 0
39
+ ? (options.pollIntervalMs as number)
40
+ : DEFAULT_POLL_INTERVAL_MS
41
+
42
+ const refresh = async () => {
43
+ if (stopped) return
44
+ try {
45
+ const release = await fetchLatestPrerelease({
46
+ repo: options.repo,
47
+ currentVersion: options.currentVersion,
48
+ })
49
+ options.onUpdate(release)
50
+ } catch (error) {
51
+ options.logger.debug({ err: error }, "Failed to refresh dev prerelease information")
52
+ }
53
+ }
54
+
55
+ void refresh()
56
+ timer = setInterval(() => void refresh(), pollIntervalMs)
57
+
58
+ return {
59
+ stop() {
60
+ stopped = true
61
+ if (timer) {
62
+ clearInterval(timer)
63
+ timer = null
64
+ }
65
+ },
66
+ }
67
+ }
68
+
69
+ async function fetchLatestPrerelease(args: {
70
+ repo: string
71
+ currentVersion: string
72
+ }): Promise<LatestReleaseInfo | null> {
73
+ const normalizedRepo = args.repo.trim()
74
+ if (!/^[^/\s]+\/[^/\s]+$/.test(normalizedRepo)) {
75
+ throw new Error(`Invalid GitHub repo: ${args.repo}`)
76
+ }
77
+
78
+ const apiUrl = `https://api.github.com/repos/${normalizedRepo}/releases?per_page=20`
79
+ const response = await fetch(apiUrl, {
80
+ headers: {
81
+ Accept: "application/vnd.github+json",
82
+ "User-Agent": "CodeNomad-CLI",
83
+ },
84
+ })
85
+
86
+ if (!response.ok) {
87
+ throw new Error(`GitHub releases API responded with ${response.status}`)
88
+ }
89
+
90
+ const list = (await response.json()) as GithubReleaseListItem[]
91
+ const latest = list.find((r) => r && r.prerelease === true && r.draft !== true)
92
+ if (!latest) {
93
+ return null
94
+ }
95
+
96
+ const tag = latest.tag_name || latest.name
97
+ if (!tag) {
98
+ return null
99
+ }
100
+
101
+ const normalizedVersion = stripTagPrefix(tag)
102
+ if (!normalizedVersion) {
103
+ return null
104
+ }
105
+
106
+ if (compareVersionStrings(normalizedVersion, args.currentVersion) <= 0) {
107
+ return null
108
+ }
109
+
110
+ return {
111
+ version: normalizedVersion,
112
+ tag,
113
+ url: latest.html_url ?? `https://github.com/${normalizedRepo}/releases/tag/${encodeURIComponent(tag)}`,
114
+ channel: "dev",
115
+ publishedAt: latest.published_at ?? latest.created_at,
116
+ notes: latest.body,
117
+ }
118
+ }