@rsktash/beads-ui 0.1.50 → 0.10.3

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 (336) hide show
  1. package/README.md +85 -144
  2. package/bin/bd-web +94 -0
  3. package/dist/assets/index-BBVIMXaM.js +73 -0
  4. package/dist/assets/index-SUXI6Mzt.css +1 -0
  5. package/dist/bd-favicon-16.svg +6 -0
  6. package/dist/bd-favicon-32.svg +6 -0
  7. package/dist/bd-logo-512.svg +6 -0
  8. package/dist/favicon.ico +0 -0
  9. package/dist/icon-180.png +0 -0
  10. package/dist/icon-192.png +0 -0
  11. package/dist/icon-512.png +0 -0
  12. package/dist/index.html +8 -5
  13. package/package.json +39 -29
  14. package/server/auth.js +68 -87
  15. package/server/db.js +91 -134
  16. package/server/dsn.js +130 -0
  17. package/server/index.js +151 -87
  18. package/server/queries.js +247 -0
  19. package/server/routes/auth.js +27 -0
  20. package/server/routes/issues.js +120 -0
  21. package/server/routes/stream.js +111 -0
  22. package/server/types.js +83 -0
  23. package/app/protocol.js +0 -216
  24. package/bin/bd-grep +0 -121
  25. package/bin/bd-ui +0 -19
  26. package/dist/assets/abap-DsBKuouk.js +0 -1
  27. package/dist/assets/actionscript-3-D_z4Izcz.js +0 -1
  28. package/dist/assets/ada-727ZlQH0.js +0 -1
  29. package/dist/assets/andromeeda-C3khCPGq.js +0 -1
  30. package/dist/assets/angular-html-LfdN0zeE.js +0 -1
  31. package/dist/assets/angular-ts-CKsD7JZE.js +0 -1
  32. package/dist/assets/apache-Dn00JSTd.js +0 -1
  33. package/dist/assets/apex-COJ4H7py.js +0 -1
  34. package/dist/assets/apl-BBq3IX1j.js +0 -1
  35. package/dist/assets/applescript-Bu5BbsvL.js +0 -1
  36. package/dist/assets/ara-7O62HKoU.js +0 -1
  37. package/dist/assets/asciidoc-BPT9niGB.js +0 -1
  38. package/dist/assets/asm-Dhn9LcZ4.js +0 -1
  39. package/dist/assets/astro-CqkE3fuf.js +0 -1
  40. package/dist/assets/aurora-x-D-2ljcwZ.js +0 -1
  41. package/dist/assets/awk-eg146-Ew.js +0 -1
  42. package/dist/assets/ayu-dark-Cv9koXgw.js +0 -1
  43. package/dist/assets/ballerina-Du268qiB.js +0 -1
  44. package/dist/assets/bat-fje9CFhw.js +0 -1
  45. package/dist/assets/beancount-BwXTMy5W.js +0 -1
  46. package/dist/assets/berry-3xVqZejG.js +0 -1
  47. package/dist/assets/bibtex-xW4inM5L.js +0 -1
  48. package/dist/assets/bicep-DHo0CJ0O.js +0 -1
  49. package/dist/assets/blade-a8OxSdnT.js +0 -1
  50. package/dist/assets/bsl-Dgyn0ogV.js +0 -1
  51. package/dist/assets/c-C3t2pwGQ.js +0 -1
  52. package/dist/assets/cadence-DNquZEk8.js +0 -1
  53. package/dist/assets/cairo--RitsXJZ.js +0 -1
  54. package/dist/assets/catppuccin-frappe-CD_QflpE.js +0 -1
  55. package/dist/assets/catppuccin-latte-DRW-0cLl.js +0 -1
  56. package/dist/assets/catppuccin-macchiato-C-_shW-Y.js +0 -1
  57. package/dist/assets/catppuccin-mocha-LGGdnPYs.js +0 -1
  58. package/dist/assets/clarity-BHOwM8T6.js +0 -1
  59. package/dist/assets/clojure-DxSadP1t.js +0 -1
  60. package/dist/assets/cmake-DbXoA79R.js +0 -1
  61. package/dist/assets/cobol-PTqiYgYu.js +0 -1
  62. package/dist/assets/codeowners-Bp6g37R7.js +0 -1
  63. package/dist/assets/codeql-sacFqUAJ.js +0 -1
  64. package/dist/assets/coffee-dyiR41kL.js +0 -1
  65. package/dist/assets/common-lisp-C7gG9l05.js +0 -1
  66. package/dist/assets/coq-Dsg_Bt_b.js +0 -1
  67. package/dist/assets/cpp-BksuvNSY.js +0 -1
  68. package/dist/assets/crystal-DtDmRg-F.js +0 -1
  69. package/dist/assets/csharp-D9R-vmeu.js +0 -1
  70. package/dist/assets/css-BPhBrDlE.js +0 -1
  71. package/dist/assets/csv-B0qRVHPH.js +0 -1
  72. package/dist/assets/cue-DtFQj3wx.js +0 -1
  73. package/dist/assets/cypher-m2LEI-9-.js +0 -1
  74. package/dist/assets/d-BoXegm-a.js +0 -1
  75. package/dist/assets/dark-plus-C3mMm8J8.js +0 -1
  76. package/dist/assets/dart-B9wLZaAG.js +0 -1
  77. package/dist/assets/dax-ClGRhx96.js +0 -1
  78. package/dist/assets/desktop-DEIpsLCJ.js +0 -1
  79. package/dist/assets/diff-BgYniUM_.js +0 -1
  80. package/dist/assets/docker-COcR7UxN.js +0 -1
  81. package/dist/assets/dotenv-BjQB5zDj.js +0 -1
  82. package/dist/assets/dracula-BzJJZx-M.js +0 -1
  83. package/dist/assets/dracula-soft-BXkSAIEj.js +0 -1
  84. package/dist/assets/dream-maker-C-nORZOA.js +0 -1
  85. package/dist/assets/edge-D5gP-w-T.js +0 -1
  86. package/dist/assets/elixir-CLiX3zqd.js +0 -1
  87. package/dist/assets/elm-CmHSxxaM.js +0 -1
  88. package/dist/assets/emacs-lisp-BX77sIaO.js +0 -1
  89. package/dist/assets/erb-BYTLMnw6.js +0 -1
  90. package/dist/assets/erlang-B-DoSBHF.js +0 -1
  91. package/dist/assets/everforest-dark-BgDCqdQA.js +0 -1
  92. package/dist/assets/everforest-light-C8M2exoo.js +0 -1
  93. package/dist/assets/fennel-bCA53EVm.js +0 -1
  94. package/dist/assets/fish-w-ucz2PV.js +0 -1
  95. package/dist/assets/fluent-Dayu4EKP.js +0 -1
  96. package/dist/assets/fortran-fixed-form-TqA4NnZg.js +0 -1
  97. package/dist/assets/fortran-free-form-DKXYxT9g.js +0 -1
  98. package/dist/assets/fsharp-XplgxFYe.js +0 -1
  99. package/dist/assets/gdresource-BHYsBjWJ.js +0 -1
  100. package/dist/assets/gdscript-DfxzS6Rs.js +0 -1
  101. package/dist/assets/gdshader-SKMF96pI.js +0 -1
  102. package/dist/assets/genie-ajMbGru0.js +0 -1
  103. package/dist/assets/gherkin--30QC5Em.js +0 -1
  104. package/dist/assets/git-commit-i4q6IMui.js +0 -1
  105. package/dist/assets/git-rebase-B-v9cOL2.js +0 -1
  106. package/dist/assets/github-dark-DHJKELXO.js +0 -1
  107. package/dist/assets/github-dark-default-Cuk6v7N8.js +0 -1
  108. package/dist/assets/github-dark-dimmed-DH5Ifo-i.js +0 -1
  109. package/dist/assets/github-dark-high-contrast-E3gJ1_iC.js +0 -1
  110. package/dist/assets/github-light-DAi9KRSo.js +0 -1
  111. package/dist/assets/github-light-default-D7oLnXFd.js +0 -1
  112. package/dist/assets/github-light-high-contrast-BfjtVDDH.js +0 -1
  113. package/dist/assets/gleam-B430Bg39.js +0 -1
  114. package/dist/assets/glimmer-js-D-cwc0-E.js +0 -1
  115. package/dist/assets/glimmer-ts-pgjy16dm.js +0 -1
  116. package/dist/assets/glsl-DBO2IWDn.js +0 -1
  117. package/dist/assets/gnuplot-CM8KxXT1.js +0 -1
  118. package/dist/assets/go-B1SYOhNW.js +0 -1
  119. package/dist/assets/graphql-cDcHW_If.js +0 -1
  120. package/dist/assets/groovy-DkBy-JyN.js +0 -1
  121. package/dist/assets/hack-D1yCygmZ.js +0 -1
  122. package/dist/assets/haml-B2EZWmdv.js +0 -1
  123. package/dist/assets/handlebars-BQGss363.js +0 -1
  124. package/dist/assets/haskell-BILxekzW.js +0 -1
  125. package/dist/assets/haxe-C5wWYbrZ.js +0 -1
  126. package/dist/assets/hcl-HzYwdGDm.js +0 -1
  127. package/dist/assets/hjson-T-Tgc4AT.js +0 -1
  128. package/dist/assets/hlsl-ifBTmRxC.js +0 -1
  129. package/dist/assets/houston-DnULxvSX.js +0 -1
  130. package/dist/assets/html-C2L_23MC.js +0 -1
  131. package/dist/assets/html-derivative-CSfWNPLT.js +0 -1
  132. package/dist/assets/http-FRrOvY1W.js +0 -1
  133. package/dist/assets/hxml-TIA70rKU.js +0 -1
  134. package/dist/assets/hy-BMj5Y0dO.js +0 -1
  135. package/dist/assets/imba-bv_oIlVt.js +0 -1
  136. package/dist/assets/index-BuQ1xTdM.css +0 -1
  137. package/dist/assets/index-DclShbpd.js +0 -125
  138. package/dist/assets/ini-BjABl1g7.js +0 -1
  139. package/dist/assets/java-xI-RfyKK.js +0 -1
  140. package/dist/assets/javascript-ySlJ1b_l.js +0 -1
  141. package/dist/assets/jinja-DGy0s7-h.js +0 -1
  142. package/dist/assets/jison-BqZprYcd.js +0 -1
  143. package/dist/assets/json-BQoSv7ci.js +0 -1
  144. package/dist/assets/json5-w8dY5SsB.js +0 -1
  145. package/dist/assets/jsonc-TU54ms6u.js +0 -1
  146. package/dist/assets/jsonl-DREVFZK8.js +0 -1
  147. package/dist/assets/jsonnet-BfivnA6A.js +0 -1
  148. package/dist/assets/jssm-P4WzXJd0.js +0 -1
  149. package/dist/assets/jsx-BAng5TT0.js +0 -1
  150. package/dist/assets/julia-BBuGR-5E.js +0 -1
  151. package/dist/assets/kanagawa-dragon-CkXjmgJE.js +0 -1
  152. package/dist/assets/kanagawa-lotus-CfQXZHmo.js +0 -1
  153. package/dist/assets/kanagawa-wave-DWedfzmr.js +0 -1
  154. package/dist/assets/kotlin-B5lbUyaz.js +0 -1
  155. package/dist/assets/kusto-mebxcVVE.js +0 -1
  156. package/dist/assets/laserwave-DUszq2jm.js +0 -1
  157. package/dist/assets/latex-C-cWTeAZ.js +0 -1
  158. package/dist/assets/lean-XBlWyCtg.js +0 -1
  159. package/dist/assets/less-BfCpw3nA.js +0 -1
  160. package/dist/assets/light-plus-B7mTdjB0.js +0 -1
  161. package/dist/assets/liquid-D3W5UaiH.js +0 -1
  162. package/dist/assets/log-Cc5clBb7.js +0 -1
  163. package/dist/assets/logo-IuBKFhSY.js +0 -1
  164. package/dist/assets/lua-CvWAzNxB.js +0 -1
  165. package/dist/assets/luau-Du5NY7AG.js +0 -1
  166. package/dist/assets/make-Bvotw-X0.js +0 -1
  167. package/dist/assets/markdown-UIAJJxZW.js +0 -1
  168. package/dist/assets/marko-z0MBrx5-.js +0 -1
  169. package/dist/assets/material-theme-D5KoaKCx.js +0 -1
  170. package/dist/assets/material-theme-darker-BfHTSMKl.js +0 -1
  171. package/dist/assets/material-theme-lighter-B0m2ddpp.js +0 -1
  172. package/dist/assets/material-theme-ocean-CyktbL80.js +0 -1
  173. package/dist/assets/material-theme-palenight-Csfq5Kiy.js +0 -1
  174. package/dist/assets/matlab-D9-PGadD.js +0 -1
  175. package/dist/assets/mdc-DB_EDNY_.js +0 -1
  176. package/dist/assets/mdx-sdHcTMYB.js +0 -1
  177. package/dist/assets/mermaid-Ci6OQyBP.js +0 -1
  178. package/dist/assets/min-dark-CafNBF8u.js +0 -1
  179. package/dist/assets/min-light-CTRr51gU.js +0 -1
  180. package/dist/assets/mipsasm-BC5c_5Pe.js +0 -1
  181. package/dist/assets/mojo-Tz6hzZYG.js +0 -1
  182. package/dist/assets/monokai-D4h5O-jR.js +0 -1
  183. package/dist/assets/move-DB_GagMm.js +0 -1
  184. package/dist/assets/narrat-DLbgOhZU.js +0 -1
  185. package/dist/assets/nextflow-B0XVJmRM.js +0 -1
  186. package/dist/assets/nginx-D_VnBJ67.js +0 -1
  187. package/dist/assets/night-owl-C39BiMTA.js +0 -1
  188. package/dist/assets/nim-ZlGxZxc3.js +0 -1
  189. package/dist/assets/nix-shcSOmrb.js +0 -1
  190. package/dist/assets/nord-Ddv68eIx.js +0 -1
  191. package/dist/assets/nushell-D4Tzg5kh.js +0 -1
  192. package/dist/assets/objective-c-Deuh7S70.js +0 -1
  193. package/dist/assets/objective-cpp-BUEGK8hf.js +0 -1
  194. package/dist/assets/ocaml-BNioltXt.js +0 -1
  195. package/dist/assets/one-dark-pro-GBQ2dnAY.js +0 -1
  196. package/dist/assets/one-light-PoHY5YXO.js +0 -1
  197. package/dist/assets/pascal-JqZropPD.js +0 -1
  198. package/dist/assets/perl-CHQXSrWU.js +0 -1
  199. package/dist/assets/php-B5ebYQev.js +0 -1
  200. package/dist/assets/plastic-3e1v2bzS.js +0 -1
  201. package/dist/assets/plsql-LKU2TuZ1.js +0 -1
  202. package/dist/assets/po-BFLt1xDp.js +0 -1
  203. package/dist/assets/poimandres-CS3Unz2-.js +0 -1
  204. package/dist/assets/polar-DKykz6zU.js +0 -1
  205. package/dist/assets/postcss-B3ZDOciz.js +0 -1
  206. package/dist/assets/powerquery-CSHBycmS.js +0 -1
  207. package/dist/assets/powershell-BIEUsx6d.js +0 -1
  208. package/dist/assets/prisma-B48N-Iqd.js +0 -1
  209. package/dist/assets/prolog-BY-TUvya.js +0 -1
  210. package/dist/assets/proto-zocC4JxJ.js +0 -1
  211. package/dist/assets/pug-CM9l7STV.js +0 -1
  212. package/dist/assets/puppet-Cza_XSSt.js +0 -1
  213. package/dist/assets/purescript-Bg-kzb6g.js +0 -1
  214. package/dist/assets/python-DhUJRlN_.js +0 -1
  215. package/dist/assets/qml-D8XfuvdV.js +0 -1
  216. package/dist/assets/qmldir-C8lEn-DE.js +0 -1
  217. package/dist/assets/qss-DhMKtDLN.js +0 -1
  218. package/dist/assets/r-CwjWoCRV.js +0 -1
  219. package/dist/assets/racket-CzouJOBO.js +0 -1
  220. package/dist/assets/raku-B1bQXN8T.js +0 -1
  221. package/dist/assets/razor-CNLDkMZG.js +0 -1
  222. package/dist/assets/red-bN70gL4F.js +0 -1
  223. package/dist/assets/reg-5LuOXUq_.js +0 -1
  224. package/dist/assets/regexp-DWJ3fJO_.js +0 -1
  225. package/dist/assets/rel-DJlmqQ1C.js +0 -1
  226. package/dist/assets/riscv-QhoSD0DR.js +0 -1
  227. package/dist/assets/rose-pine-CmCqftbK.js +0 -1
  228. package/dist/assets/rose-pine-dawn-Ds-gbosJ.js +0 -1
  229. package/dist/assets/rose-pine-moon-CjDtw9vr.js +0 -1
  230. package/dist/assets/rst-4NLicBqY.js +0 -1
  231. package/dist/assets/ruby-DeZ3UC14.js +0 -1
  232. package/dist/assets/rust-Be6lgOlo.js +0 -1
  233. package/dist/assets/sas-BmTFh92c.js +0 -1
  234. package/dist/assets/sass-BJ4Li9vH.js +0 -1
  235. package/dist/assets/scala-DQVVAn-B.js +0 -1
  236. package/dist/assets/scheme-BJGe-b2p.js +0 -1
  237. package/dist/assets/scss-C31hgJw-.js +0 -1
  238. package/dist/assets/sdbl-BLhTXw86.js +0 -1
  239. package/dist/assets/shaderlab-B7qAK45m.js +0 -1
  240. package/dist/assets/shellscript-atvbtKCR.js +0 -1
  241. package/dist/assets/shellsession-C_rIy8kc.js +0 -1
  242. package/dist/assets/slack-dark-BthQWCQV.js +0 -1
  243. package/dist/assets/slack-ochin-DqwNpetd.js +0 -1
  244. package/dist/assets/smalltalk-DkLiglaE.js +0 -1
  245. package/dist/assets/snazzy-light-Bw305WKR.js +0 -1
  246. package/dist/assets/solarized-dark-DXbdFlpD.js +0 -1
  247. package/dist/assets/solarized-light-L9t79GZl.js +0 -1
  248. package/dist/assets/solidity-C1w2a3ep.js +0 -1
  249. package/dist/assets/soy-C-lX7w71.js +0 -1
  250. package/dist/assets/sparql-bYkjHRlG.js +0 -1
  251. package/dist/assets/splunk-Cf8iN4DR.js +0 -1
  252. package/dist/assets/sql-COK4E0Yg.js +0 -1
  253. package/dist/assets/ssh-config-BknIz3MU.js +0 -1
  254. package/dist/assets/stata-DorPZHa4.js +0 -1
  255. package/dist/assets/stylus-BeQkCIfX.js +0 -1
  256. package/dist/assets/svelte-MSaWC3Je.js +0 -1
  257. package/dist/assets/swift-BSxZ-RaX.js +0 -1
  258. package/dist/assets/synthwave-84-CbfX1IO0.js +0 -1
  259. package/dist/assets/system-verilog-C7L56vO4.js +0 -1
  260. package/dist/assets/systemd-CUnW07Te.js +0 -1
  261. package/dist/assets/talonscript-C1XDQQGZ.js +0 -1
  262. package/dist/assets/tasl-CQjiPCtT.js +0 -1
  263. package/dist/assets/tcl-DQ1-QYvQ.js +0 -1
  264. package/dist/assets/templ-dwX3ZSMB.js +0 -1
  265. package/dist/assets/terraform-BbSNqyBO.js +0 -1
  266. package/dist/assets/tex-rYs2v40G.js +0 -1
  267. package/dist/assets/tokyo-night-DBQeEorK.js +0 -1
  268. package/dist/assets/toml-CB2ApiWb.js +0 -1
  269. package/dist/assets/ts-tags-CipyTH0X.js +0 -1
  270. package/dist/assets/tsv-B_m7g4N7.js +0 -1
  271. package/dist/assets/tsx-B6W0miNI.js +0 -1
  272. package/dist/assets/turtle-BMR_PYu6.js +0 -1
  273. package/dist/assets/twig-NC5TFiHP.js +0 -1
  274. package/dist/assets/typescript-Dj6nwHGl.js +0 -1
  275. package/dist/assets/typespec-BpWG_bgh.js +0 -1
  276. package/dist/assets/typst-BVUVsWT6.js +0 -1
  277. package/dist/assets/v-CAQ2eGtk.js +0 -1
  278. package/dist/assets/vala-BFOHcciG.js +0 -1
  279. package/dist/assets/vb-CdO5JTpU.js +0 -1
  280. package/dist/assets/verilog-CJaU5se_.js +0 -1
  281. package/dist/assets/vesper-BEBZ7ncR.js +0 -1
  282. package/dist/assets/vhdl-DYoNaHQp.js +0 -1
  283. package/dist/assets/viml-m4uW47V2.js +0 -1
  284. package/dist/assets/vitesse-black-Bkuqu6BP.js +0 -1
  285. package/dist/assets/vitesse-dark-D0r3Knsf.js +0 -1
  286. package/dist/assets/vitesse-light-CVO1_9PV.js +0 -1
  287. package/dist/assets/vue-BuYVFjOK.js +0 -1
  288. package/dist/assets/vue-html-xdeiXROB.js +0 -1
  289. package/dist/assets/vyper-nyqBNV6O.js +0 -1
  290. package/dist/assets/wasm-C6j12Q_x.js +0 -1
  291. package/dist/assets/wasm-CG6Dc4jp.js +0 -1
  292. package/dist/assets/wenyan-7A4Fjokl.js +0 -1
  293. package/dist/assets/wgsl-CB0Krxn9.js +0 -1
  294. package/dist/assets/wikitext-DCE3LsBG.js +0 -1
  295. package/dist/assets/wolfram-C3FkfJm5.js +0 -1
  296. package/dist/assets/xml-e3z08dGr.js +0 -1
  297. package/dist/assets/xsl-Dd0NUgwM.js +0 -1
  298. package/dist/assets/yaml-CVw76BM1.js +0 -1
  299. package/dist/assets/zenscript-HnGAYVZD.js +0 -1
  300. package/dist/assets/zig-BVz_zdnA.js +0 -1
  301. package/server/app.js +0 -165
  302. package/server/app.test.js +0 -30
  303. package/server/bd.js +0 -227
  304. package/server/bd.test.js +0 -194
  305. package/server/cli/cli.test.js +0 -207
  306. package/server/cli/commands.integration.test.js +0 -148
  307. package/server/cli/commands.js +0 -285
  308. package/server/cli/commands.unit.test.js +0 -408
  309. package/server/cli/daemon.js +0 -340
  310. package/server/cli/daemon.test.js +0 -31
  311. package/server/cli/index.js +0 -135
  312. package/server/cli/open.js +0 -178
  313. package/server/cli/open.test.js +0 -26
  314. package/server/cli/usage.js +0 -49
  315. package/server/config.js +0 -36
  316. package/server/db.test.js +0 -169
  317. package/server/dolt-pool.js +0 -313
  318. package/server/dolt-queries.js +0 -764
  319. package/server/list-adapters.js +0 -421
  320. package/server/list-adapters.test.js +0 -208
  321. package/server/logging.js +0 -23
  322. package/server/registry-watcher.js +0 -200
  323. package/server/subscriptions.js +0 -299
  324. package/server/subscriptions.test.js +0 -128
  325. package/server/validators.js +0 -124
  326. package/server/watcher.js +0 -139
  327. package/server/watcher.test.js +0 -120
  328. package/server/ws.comments.test.js +0 -262
  329. package/server/ws.delete.test.js +0 -119
  330. package/server/ws.js +0 -1329
  331. package/server/ws.labels.test.js +0 -95
  332. package/server/ws.list-refresh.coalesce.test.js +0 -95
  333. package/server/ws.list-subscriptions.test.js +0 -403
  334. package/server/ws.mutation-window.test.js +0 -147
  335. package/server/ws.mutations.test.js +0 -389
  336. package/server/ws.test.js +0 -52
@@ -1,49 +0,0 @@
1
- /**
2
- * Print CLI usage to a stream-like target.
3
- *
4
- * @param {{ write: (chunk: string) => any }} out_stream
5
- */
6
- export function printUsage(out_stream) {
7
- const lines = [
8
- 'Usage: bdui <command> [options]',
9
- '',
10
- 'Commands:',
11
- ' start Start the UI server',
12
- ' stop Stop the UI server',
13
- ' restart Restart the UI server',
14
- '',
15
- 'Options:',
16
- ' -h, --help Show this help message',
17
- ' -v, --version Show the CLI version',
18
- ' -d, --debug Enable debug logging',
19
- ' --open Open the browser after start/restart',
20
- ' --host <addr> Bind to a specific host (default: 127.0.0.1)',
21
- ' --port <num> Bind to a specific port (default: 3000)',
22
- '',
23
- 'Environment variables:',
24
- ' PORT Server port (default: 3333)',
25
- ' HOST Bind address (default: 127.0.0.1)',
26
- ' BEADS_DOLT_PASSWORD Password for remote Dolt server',
27
- ' FILE_ATTACHMENT_BASE_URL Base URL for attach:// URIs in markdown',
28
- '',
29
- 'Dolt modes:',
30
- ' Embedded (default): spawns a local dolt sql-server from .beads/embeddeddolt/',
31
- ' Remote server: set dolt_mode: "server" in .beads/metadata.json with',
32
- ' dolt_server_host, dolt_server_port, dolt_server_user, dolt_database.',
33
- ' Password is read from BEADS_DOLT_PASSWORD env var.',
34
- '',
35
- 'Attachments:',
36
- ' Markdown content can use attach://<path> URIs for portable file references.',
37
- ' Set FILE_ATTACHMENT_BASE_URL to resolve them at render time.',
38
- ' Example: attach://bead-42/shot.png becomes',
39
- ' ${FILE_ATTACHMENT_BASE_URL}/bead-42/shot.png',
40
- '',
41
- 'Issue mentions:',
42
- ' Use #issue-id to mention issues in markdown (e.g., #yuklar-985).',
43
- ' These are auto-linked to the issue detail page.',
44
- ''
45
- ];
46
- for (const line of lines) {
47
- out_stream.write(line + '\n');
48
- }
49
- }
package/server/config.js DELETED
@@ -1,36 +0,0 @@
1
- import path from 'node:path';
2
- import { fileURLToPath } from 'node:url';
3
-
4
- /**
5
- * Resolve runtime configuration for the server.
6
- * Notes:
7
- * - `app_dir` is resolved relative to the installed package location.
8
- * - `root_dir` represents the directory where the process was invoked
9
- * (i.e., the current working directory) so DB resolution follows the
10
- * caller's context rather than the install location.
11
- *
12
- * @returns {{ host: string, port: number, app_dir: string, root_dir: string, url: string }}
13
- */
14
- export function getConfig() {
15
- const this_file = fileURLToPath(new URL(import.meta.url));
16
- const server_dir = path.dirname(this_file);
17
- const package_root = path.resolve(server_dir, '..');
18
- // Always reflect the directory from which the process was started
19
- const root_dir = process.cwd();
20
-
21
- let port_value = Number.parseInt(process.env.PORT || '', 10);
22
- if (!Number.isFinite(port_value)) {
23
- port_value = 3333;
24
- }
25
-
26
- const host_env = process.env.HOST;
27
- const host_value = host_env && host_env.length > 0 ? host_env : '127.0.0.1';
28
-
29
- return {
30
- host: host_value,
31
- port: port_value,
32
- app_dir: path.resolve(package_root, 'app'),
33
- root_dir,
34
- url: `http://${host_value}:${port_value}`
35
- };
36
- }
package/server/db.test.js DELETED
@@ -1,169 +0,0 @@
1
- import fs from 'node:fs';
2
- import os from 'node:os';
3
- import path from 'node:path';
4
- import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
5
- import {
6
- findNearestBeadsDb,
7
- findNearestBeadsMetadata,
8
- resolveDbPath,
9
- resolveWorkspaceDatabase
10
- } from './db.js';
11
-
12
- /** @type {string[]} */
13
- const tmps = [];
14
-
15
- function mkdtemp() {
16
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'beads-ui-test-'));
17
- tmps.push(dir);
18
- return dir;
19
- }
20
-
21
- beforeEach(() => {
22
- vi.resetModules();
23
- });
24
-
25
- afterEach(() => {
26
- for (const d of tmps.splice(0)) {
27
- try {
28
- fs.rmSync(d, { recursive: true, force: true });
29
- } catch {
30
- // ignore cleanup errors
31
- }
32
- }
33
- });
34
-
35
- describe('resolveDbPath', () => {
36
- test('uses explicit_db when provided', () => {
37
- const res = resolveDbPath({ cwd: '/x', explicit_db: './my.db', env: {} });
38
- expect(res.path.endsWith('/x/my.db')).toBe(true);
39
- expect(res.source).toBe('flag');
40
- });
41
-
42
- test('uses BEADS_DB from env when set', () => {
43
- const res = resolveDbPath({ cwd: '/x', env: { BEADS_DB: '/abs/env.db' } });
44
- expect(res.path).toBe('/abs/env.db');
45
- expect(res.source).toBe('env');
46
- });
47
-
48
- test('finds nearest .beads/ui.db walking up', () => {
49
- const root = mkdtemp();
50
- const nested = path.join(root, 'a', 'b', 'c');
51
- fs.mkdirSync(nested, { recursive: true });
52
- const beads = path.join(root, '.beads');
53
- fs.mkdirSync(beads);
54
- const ui_db = path.join(beads, 'ui.db');
55
- fs.writeFileSync(ui_db, '');
56
-
57
- const found = findNearestBeadsDb(nested);
58
- expect(found).toBe(ui_db);
59
-
60
- const res = resolveDbPath({ cwd: nested, env: {} });
61
- expect(res.path).toBe(ui_db);
62
- expect(res.source).toBe('nearest');
63
- });
64
-
65
- test('falls back to ~/.beads/default.db when none found', async () => {
66
- // Mock os.homedir to a deterministic location using spy
67
- const home = mkdtemp();
68
- vi.spyOn(os, 'homedir').mockReturnValue(home);
69
- const mod = await import('./db.js');
70
- const res = mod.resolveDbPath({ cwd: '/no/db/here', env: {} });
71
- expect(res.path).toBe(path.join(home, '.beads', 'default.db'));
72
- expect(res.source).toBe('home-default');
73
- });
74
-
75
- test('treats ~/.beads/default.db as fallback, not nearest workspace db', async () => {
76
- const home = mkdtemp();
77
- const nested = path.join(home, 'projects', 'repo', 'deep');
78
- fs.mkdirSync(nested, { recursive: true });
79
- const home_beads = path.join(home, '.beads');
80
- fs.mkdirSync(home_beads, { recursive: true });
81
- fs.writeFileSync(path.join(home_beads, 'default.db'), '');
82
- vi.spyOn(os, 'homedir').mockReturnValue(home);
83
- const mod = await import('./db.js');
84
-
85
- const res = mod.resolveDbPath({ cwd: nested, env: {} });
86
-
87
- expect(res.path).toBe(path.join(home, '.beads', 'default.db'));
88
- expect(res.source).toBe('home-default');
89
- });
90
- });
91
-
92
- describe('findNearestBeadsMetadata', () => {
93
- test('finds nearest metadata walking up', () => {
94
- const root = mkdtemp();
95
- const nested = path.join(root, 'a', 'b', 'c');
96
- fs.mkdirSync(nested, { recursive: true });
97
- const beads_dir = path.join(root, '.beads');
98
- fs.mkdirSync(beads_dir, { recursive: true });
99
- const metadata = path.join(beads_dir, 'metadata.json');
100
- fs.writeFileSync(metadata, '{}');
101
-
102
- const found = findNearestBeadsMetadata(nested);
103
-
104
- expect(found).toBe(metadata);
105
- });
106
-
107
- test('returns null when metadata is missing', () => {
108
- const root = mkdtemp();
109
-
110
- const found = findNearestBeadsMetadata(root);
111
-
112
- expect(found).toBeNull();
113
- });
114
- });
115
-
116
- describe('resolveWorkspaceDatabase', () => {
117
- test('uses metadata directory for non-SQLite workspace', () => {
118
- const root = mkdtemp();
119
- const nested = path.join(root, 'workspace', 'nested');
120
- fs.mkdirSync(nested, { recursive: true });
121
- const beads_dir = path.join(root, '.beads');
122
- fs.mkdirSync(beads_dir, { recursive: true });
123
- fs.writeFileSync(path.join(beads_dir, 'metadata.json'), '{}');
124
-
125
- const found = resolveWorkspaceDatabase({ cwd: nested, env: {} });
126
-
127
- expect(found.path).toBe(beads_dir);
128
- expect(found.source).toBe('metadata');
129
- expect(found.exists).toBe(true);
130
- });
131
-
132
- test('prefers metadata workspace when home default db exists', async () => {
133
- const home = mkdtemp();
134
- const root = path.join(home, 'project');
135
- const nested = path.join(root, 'workspace', 'nested');
136
- fs.mkdirSync(nested, { recursive: true });
137
- const home_beads = path.join(home, '.beads');
138
- fs.mkdirSync(home_beads, { recursive: true });
139
- fs.writeFileSync(path.join(home_beads, 'default.db'), '');
140
- const beads_dir = path.join(root, '.beads');
141
- fs.mkdirSync(beads_dir, { recursive: true });
142
- fs.writeFileSync(path.join(beads_dir, 'metadata.json'), '{}');
143
- vi.spyOn(os, 'homedir').mockReturnValue(home);
144
- const mod = await import('./db.js');
145
-
146
- const found = mod.resolveWorkspaceDatabase({ cwd: nested, env: {} });
147
-
148
- expect(found.path).toBe(beads_dir);
149
- expect(found.source).toBe('metadata');
150
- expect(found.exists).toBe(true);
151
- });
152
-
153
- test('prefers nearest sqlite database when present', () => {
154
- const root = mkdtemp();
155
- const nested = path.join(root, 'workspace', 'nested');
156
- fs.mkdirSync(nested, { recursive: true });
157
- const beads_dir = path.join(root, '.beads');
158
- fs.mkdirSync(beads_dir, { recursive: true });
159
- fs.writeFileSync(path.join(beads_dir, 'metadata.json'), '{}');
160
- const sqlite_db = path.join(beads_dir, 'workspace.db');
161
- fs.writeFileSync(sqlite_db, '');
162
-
163
- const found = resolveWorkspaceDatabase({ cwd: nested, env: {} });
164
-
165
- expect(found.path).toBe(sqlite_db);
166
- expect(found.source).toBe('nearest');
167
- expect(found.exists).toBe(true);
168
- });
169
- });
@@ -1,313 +0,0 @@
1
- import { spawn } from 'node:child_process';
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
- import mysql from 'mysql2/promise';
5
- import { findNearestBeadsMetadata } from './db.js';
6
- import { debug } from './logging.js';
7
-
8
- const log = debug('dolt-pool');
9
-
10
- const DOLT_PORT = 3307;
11
- const DOLT_SOCK = '/tmp/bdui-dolt.sock';
12
-
13
- /** @type {import('mysql2/promise').Pool | null} */
14
- let pool = null;
15
-
16
- /** @type {import('node:child_process').ChildProcess | null} */
17
- let serverProcess = null;
18
-
19
- /** @type {string | null} */
20
- let currentDataDir = null;
21
-
22
- /** @type {'embedded' | 'server' | null} */
23
- let currentMode = null;
24
-
25
- /**
26
- * @typedef {{ mode: 'embedded', dataDir: string, database: string }} EmbeddedDoltInfo
27
- * @typedef {{ mode: 'server', host: string, port: number, user: string, password: string, database: string }} ServerDoltInfo
28
- * @typedef {EmbeddedDoltInfo | ServerDoltInfo} DoltInfo
29
- */
30
-
31
- /**
32
- * Resolve Dolt connection info from the workspace root.
33
- * Walks up from cwd to find .beads/metadata.json, then returns either
34
- * embedded or server connection info depending on dolt_mode.
35
- *
36
- * @param {string} cwd
37
- * @returns {DoltInfo | null}
38
- */
39
- export function resolveDoltDir(cwd) {
40
- const metadataPath = findNearestBeadsMetadata(cwd);
41
- if (!metadataPath) return null;
42
-
43
- const beadsDir = path.dirname(metadataPath);
44
- let metadata;
45
- try {
46
- metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
47
- } catch {
48
- return null;
49
- }
50
-
51
- if (metadata.backend !== 'dolt' && metadata.database !== 'dolt') return null;
52
-
53
- const database = metadata.dolt_database || 'default';
54
-
55
- if (metadata.dolt_mode === 'server') {
56
- return {
57
- mode: 'server',
58
- host: metadata.dolt_server_host || '127.0.0.1',
59
- port: metadata.dolt_server_port || 3306,
60
- user: metadata.dolt_server_user || 'root',
61
- password: process.env.BEADS_DOLT_PASSWORD || '',
62
- database
63
- };
64
- }
65
-
66
- const dataDir = path.join(beadsDir, 'embeddeddolt', database);
67
-
68
- try {
69
- fs.accessSync(path.join(dataDir, '.dolt'), fs.constants.F_OK);
70
- } catch {
71
- return null;
72
- }
73
-
74
- return { mode: 'embedded', dataDir, database };
75
- }
76
-
77
- /**
78
- * Start the Dolt SQL server and create a connection pool.
79
- * Idempotent — returns existing pool if already running for the same dataDir.
80
- *
81
- * @param {string} cwd - Workspace root directory
82
- * @returns {Promise<import('mysql2/promise').Pool | null>}
83
- */
84
- export async function startDoltServer(cwd) {
85
- const resolved = resolveDoltDir(cwd);
86
- if (!resolved) {
87
- log('no Dolt database found for %s', cwd);
88
- return null;
89
- }
90
-
91
- // Server mode — connect directly, no child process
92
- if (resolved.mode === 'server') {
93
- const { host, port, user, password, database } = resolved;
94
-
95
- // Already connected to this server
96
- if (pool && currentMode === 'server') {
97
- return pool;
98
- }
99
-
100
- await stopDoltServer();
101
-
102
- log('connecting to remote dolt server at %s:%d (database=%s)', host, port, database);
103
- currentMode = 'server';
104
-
105
- try {
106
- pool = await createPool({ host, port, user, password, database });
107
- log('connected to remote dolt server at %s:%d', host, port);
108
- ensureIndexes(pool).catch((err) => log('ensureIndexes error: %o', err));
109
- return pool;
110
- } catch (err) {
111
- log('failed to connect to remote dolt server: %o', err);
112
- pool = null;
113
- currentMode = null;
114
- return null;
115
- }
116
- }
117
-
118
- // Embedded mode — spawn local dolt sql-server
119
- const { dataDir, database } = resolved;
120
-
121
- // Already running for this data dir
122
- if (pool && currentDataDir === dataDir && serverProcess && !serverProcess.killed) {
123
- return pool;
124
- }
125
-
126
- // Clean up any previous server
127
- await stopDoltServer();
128
-
129
- log('starting dolt sql-server at %s (database=%s)', dataDir, database);
130
-
131
- // Clean up stale socket
132
- try { fs.unlinkSync(DOLT_SOCK); } catch { /* ignore */ }
133
-
134
- currentDataDir = dataDir;
135
- currentMode = 'embedded';
136
-
137
- return new Promise((resolve) => {
138
- const child = spawn('dolt', [
139
- 'sql-server',
140
- '-P', String(DOLT_PORT),
141
- '--socket', DOLT_SOCK,
142
- '-l', 'warning'
143
- ], {
144
- cwd: dataDir,
145
- stdio: ['ignore', 'pipe', 'pipe'],
146
- detached: false
147
- });
148
-
149
- serverProcess = child;
150
-
151
- let resolved_already = false;
152
-
153
- child.stderr?.setEncoding('utf8');
154
- child.stderr?.on('data', (chunk) => {
155
- // Log warnings/errors from dolt
156
- if (chunk.trim()) log('dolt: %s', chunk.trim());
157
- });
158
-
159
- child.on('error', (err) => {
160
- log('dolt sql-server spawn error: %o', err);
161
- if (!resolved_already) {
162
- resolved_already = true;
163
- resolve(null);
164
- }
165
- });
166
-
167
- child.on('exit', (code) => {
168
- log('dolt sql-server exited with code %d', code);
169
- pool = null;
170
- serverProcess = null;
171
- currentDataDir = null;
172
- currentMode = null;
173
- if (!resolved_already) {
174
- resolved_already = true;
175
- resolve(null);
176
- }
177
- });
178
-
179
- // Poll for connectivity instead of parsing stdout
180
- let attempts = 0;
181
- const maxAttempts = 50; // 50 * 100ms = 5s max
182
- const pollInterval = setInterval(async () => {
183
- attempts++;
184
- if (resolved_already) {
185
- clearInterval(pollInterval);
186
- return;
187
- }
188
- if (attempts > maxAttempts) {
189
- clearInterval(pollInterval);
190
- if (!resolved_already) {
191
- resolved_already = true;
192
- log('dolt sql-server start timeout after %d attempts', attempts);
193
- resolve(null);
194
- }
195
- return;
196
- }
197
- try {
198
- const p = await createPool({ host: '127.0.0.1', port: DOLT_PORT, user: 'root', database });
199
- clearInterval(pollInterval);
200
- if (!resolved_already) {
201
- resolved_already = true;
202
- pool = p;
203
- log('dolt sql-server ready on port %d (after %d polls)', DOLT_PORT, attempts);
204
- ensureIndexes(p).catch((err) => log('ensureIndexes error: %o', err));
205
- resolve(pool);
206
- } else {
207
- // Pool created after we already resolved (race); close it
208
- try { await p.end(); } catch { /* ignore */ }
209
- }
210
- } catch (poolErr) {
211
- // Not ready yet, retry. Clean up any partial pool.
212
- if (poolErr && typeof /** @type {any} */ (poolErr).pool?.end === 'function') {
213
- try { await /** @type {any} */ (poolErr).pool.end(); } catch { /* ignore */ }
214
- }
215
- }
216
- }, 100);
217
- });
218
- }
219
-
220
- /**
221
- * Create a mysql2 connection pool.
222
- *
223
- * @param {{ host: string, port: number, user: string, password?: string, database: string }} opts
224
- * @returns {Promise<import('mysql2/promise').Pool>}
225
- */
226
- async function createPool(opts) {
227
- const p = mysql.createPool({
228
- host: opts.host,
229
- port: opts.port,
230
- user: opts.user,
231
- password: opts.password || undefined,
232
- database: opts.database,
233
- waitForConnections: true,
234
- connectionLimit: 10,
235
- queueLimit: 50,
236
- enableKeepAlive: true,
237
- keepAliveInitialDelay: 10000,
238
- // Dolt dates come as strings; avoid extra parsing
239
- dateStrings: true
240
- });
241
-
242
- // Verify connectivity
243
- const conn = await p.getConnection();
244
- conn.release();
245
- return p;
246
- }
247
-
248
- /**
249
- * Ensure required indexes exist. Idempotent — skips if already present.
250
- *
251
- * @param {import('mysql2/promise').Pool} p
252
- */
253
- async function ensureIndexes(p) {
254
- const [rows] = await p.query(
255
- `SELECT 1 FROM information_schema.statistics
256
- WHERE table_schema = DATABASE() AND table_name = 'issues'
257
- AND index_name = 'idx_ft_issues_title_desc' LIMIT 1`
258
- );
259
- if (/** @type {any[]} */ (rows).length > 0) {
260
- log('FULLTEXT index already exists');
261
- return;
262
- }
263
- log('creating FULLTEXT index on issues(title, description)');
264
- await p.query(`ALTER TABLE issues ADD FULLTEXT idx_ft_issues_title_desc (title, description)`);
265
- await p.query(`CALL dolt_commit('-Am', 'add FULLTEXT index on issues(title, description)')`);
266
- log('FULLTEXT index created');
267
- }
268
-
269
- /**
270
- * Get the current pool, or null if not started.
271
- *
272
- * @returns {import('mysql2/promise').Pool | null}
273
- */
274
- export function getPool() {
275
- return pool;
276
- }
277
-
278
- /**
279
- * Stop the Dolt SQL server and close the pool.
280
- */
281
- export async function stopDoltServer() {
282
- if (pool) {
283
- try { await pool.end(); } catch { /* ignore */ }
284
- pool = null;
285
- }
286
- if (serverProcess && !serverProcess.killed) {
287
- serverProcess.kill('SIGTERM');
288
- serverProcess = null;
289
- }
290
- currentDataDir = null;
291
- currentMode = null;
292
- }
293
-
294
- /**
295
- * Rebind to a new workspace directory (e.g., after workspace switch).
296
- *
297
- * @param {string} cwd
298
- * @returns {Promise<import('mysql2/promise').Pool | null>}
299
- */
300
- export async function rebindDoltServer(cwd) {
301
- const resolved = resolveDoltDir(cwd);
302
- if (!resolved) {
303
- await stopDoltServer();
304
- return null;
305
- }
306
- if (resolved.mode === 'server' && pool && currentMode === 'server') {
307
- return pool;
308
- }
309
- if (resolved.mode === 'embedded' && resolved.dataDir === currentDataDir && pool && serverProcess && !serverProcess.killed) {
310
- return pool;
311
- }
312
- return startDoltServer(cwd);
313
- }