@openspecui/web 0.9.0

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 (463) hide show
  1. package/dist/assets/abap-BdImnpbu.js +1 -0
  2. package/dist/assets/actionscript-3-CfeIJUat.js +1 -0
  3. package/dist/assets/ada-bCR0ucgS.js +1 -0
  4. package/dist/assets/andromeeda-C-Jbm3Hp.js +1 -0
  5. package/dist/assets/angular-html-CU67Zn6k.js +1 -0
  6. package/dist/assets/angular-ts-BwZT4LLn.js +1 -0
  7. package/dist/assets/apache-Pmp26Uib.js +1 -0
  8. package/dist/assets/apex-DDbsPZ6N.js +1 -0
  9. package/dist/assets/apl-B4CMkyY2.js +1 -0
  10. package/dist/assets/apl-dKokRX4l.js +1 -0
  11. package/dist/assets/applescript-Co6uUVPk.js +1 -0
  12. package/dist/assets/ara-BRHolxvo.js +1 -0
  13. package/dist/assets/asciiarmor-Df11BRmG.js +1 -0
  14. package/dist/assets/asciidoc-Dv7Oe6Be.js +1 -0
  15. package/dist/assets/asm-D_Q5rh1f.js +1 -0
  16. package/dist/assets/asn1-EdZsLKOL.js +1 -0
  17. package/dist/assets/asterisk-B-8jnY81.js +1 -0
  18. package/dist/assets/astro-CbQHKStN.js +1 -0
  19. package/dist/assets/aurora-x-D-2ljcwZ.js +1 -0
  20. package/dist/assets/awk-DMzUqQB5.js +1 -0
  21. package/dist/assets/ayu-dark-Cv9koXgw.js +1 -0
  22. package/dist/assets/ballerina-BFfxhgS-.js +1 -0
  23. package/dist/assets/bat-BkioyH1T.js +1 -0
  24. package/dist/assets/beancount-k_qm7-4y.js +1 -0
  25. package/dist/assets/berry-uYugtg8r.js +1 -0
  26. package/dist/assets/bibtex-CHM0blh-.js +1 -0
  27. package/dist/assets/bicep-Bmn6On1c.js +1 -0
  28. package/dist/assets/blade-DVc8C-J4.js +1 -0
  29. package/dist/assets/brainfuck-C4LP7Hcl.js +1 -0
  30. package/dist/assets/bsl-BO_Y6i37.js +1 -0
  31. package/dist/assets/c-BIGW1oBm.js +1 -0
  32. package/dist/assets/cadence-Bv_4Rxtq.js +1 -0
  33. package/dist/assets/cairo-KRGpt6FW.js +1 -0
  34. package/dist/assets/catppuccin-frappe-DFWUc33u.js +1 -0
  35. package/dist/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
  36. package/dist/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
  37. package/dist/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
  38. package/dist/assets/clarity-D53aC0YG.js +1 -0
  39. package/dist/assets/clike-B9uivgTg.js +1 -0
  40. package/dist/assets/clojure-BMjYHr_A.js +1 -0
  41. package/dist/assets/clojure-P80f7IUj.js +1 -0
  42. package/dist/assets/cmake-BQqOBYOt.js +1 -0
  43. package/dist/assets/cmake-D1j8_8rp.js +1 -0
  44. package/dist/assets/cobol-CWcv1MsR.js +1 -0
  45. package/dist/assets/cobol-nwyudZeR.js +1 -0
  46. package/dist/assets/codeowners-Bp6g37R7.js +1 -0
  47. package/dist/assets/codeql-DsOJ9woJ.js +1 -0
  48. package/dist/assets/coffee-Ch7k5sss.js +1 -0
  49. package/dist/assets/coffeescript-S37ZYGWr.js +1 -0
  50. package/dist/assets/common-lisp-Cg-RD9OK.js +1 -0
  51. package/dist/assets/commonlisp-DBKNyK5s.js +1 -0
  52. package/dist/assets/coq-DkFqJrB1.js +1 -0
  53. package/dist/assets/cpp-CofmeUqb.js +1 -0
  54. package/dist/assets/crystal-SjHAIU92.js +1 -0
  55. package/dist/assets/crystal-tKQVLTB8.js +1 -0
  56. package/dist/assets/csharp-K5feNrxe.js +1 -0
  57. package/dist/assets/css-BnMrqG3P.js +1 -0
  58. package/dist/assets/css-DPfMkruS.js +1 -0
  59. package/dist/assets/csv-fuZLfV_i.js +1 -0
  60. package/dist/assets/cue-D82EKSYY.js +1 -0
  61. package/dist/assets/cypher-COkxafJQ.js +1 -0
  62. package/dist/assets/cypher-C_CwsFkJ.js +1 -0
  63. package/dist/assets/d-85-TOEBH.js +1 -0
  64. package/dist/assets/d-pRatUO7H.js +1 -0
  65. package/dist/assets/dark-plus-C3mMm8J8.js +1 -0
  66. package/dist/assets/dart-CF10PKvl.js +1 -0
  67. package/dist/assets/dax-CEL-wOlO.js +1 -0
  68. package/dist/assets/desktop-BmXAJ9_W.js +1 -0
  69. package/dist/assets/diff-D97Zzqfu.js +1 -0
  70. package/dist/assets/diff-DbItnlRl.js +1 -0
  71. package/dist/assets/docker-BcOcwvcX.js +1 -0
  72. package/dist/assets/dockerfile-BKs6k2Af.js +1 -0
  73. package/dist/assets/dotenv-Da5cRb03.js +1 -0
  74. package/dist/assets/dracula-BzJJZx-M.js +1 -0
  75. package/dist/assets/dracula-soft-BXkSAIEj.js +1 -0
  76. package/dist/assets/dream-maker-BtqSS_iP.js +1 -0
  77. package/dist/assets/dtd-DF_7sFjM.js +1 -0
  78. package/dist/assets/dylan-DwRh75JA.js +1 -0
  79. package/dist/assets/ebnf-CDyGwa7X.js +1 -0
  80. package/dist/assets/ecl-Cabwm37j.js +1 -0
  81. package/dist/assets/edge-BkV0erSs.js +1 -0
  82. package/dist/assets/eiffel-CnydiIhH.js +1 -0
  83. package/dist/assets/elixir-CDX3lj18.js +1 -0
  84. package/dist/assets/elm-DbKCFpqz.js +1 -0
  85. package/dist/assets/elm-vLlmbW-K.js +1 -0
  86. package/dist/assets/emacs-lisp-C9XAeP06.js +1 -0
  87. package/dist/assets/erb-BOJIQeun.js +1 -0
  88. package/dist/assets/erlang-BNw1qcRV.js +1 -0
  89. package/dist/assets/erlang-DsQrWhSR.js +1 -0
  90. package/dist/assets/everforest-dark-BgDCqdQA.js +1 -0
  91. package/dist/assets/everforest-light-C8M2exoo.js +1 -0
  92. package/dist/assets/factor-kuTfRLto.js +1 -0
  93. package/dist/assets/fcl-Kvtd6kyn.js +1 -0
  94. package/dist/assets/fennel-BYunw83y.js +1 -0
  95. package/dist/assets/fish-BvzEVeQv.js +1 -0
  96. package/dist/assets/fluent-C4IJs8-o.js +1 -0
  97. package/dist/assets/forth-Ffai-XNe.js +1 -0
  98. package/dist/assets/fortran-DYz_wnZ1.js +1 -0
  99. package/dist/assets/fortran-fixed-form-BZjJHVRy.js +1 -0
  100. package/dist/assets/fortran-free-form-D22FLkUw.js +1 -0
  101. package/dist/assets/fsharp-CXgrBDvD.js +1 -0
  102. package/dist/assets/gas-Bneqetm1.js +1 -0
  103. package/dist/assets/gdresource-B7Tvp0Sc.js +1 -0
  104. package/dist/assets/gdscript-DTMYz4Jt.js +1 -0
  105. package/dist/assets/gdshader-DkwncUOv.js +1 -0
  106. package/dist/assets/genie-D0YGMca9.js +1 -0
  107. package/dist/assets/gherkin-DyxjwDmM.js +1 -0
  108. package/dist/assets/gherkin-heZmZLOM.js +1 -0
  109. package/dist/assets/git-commit-F4YmCXRG.js +1 -0
  110. package/dist/assets/git-rebase-r7XF79zn.js +1 -0
  111. package/dist/assets/github-dark-DHJKELXO.js +1 -0
  112. package/dist/assets/github-dark-default-Cuk6v7N8.js +1 -0
  113. package/dist/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  114. package/dist/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  115. package/dist/assets/github-light-DAi9KRSo.js +1 -0
  116. package/dist/assets/github-light-default-D7oLnXFd.js +1 -0
  117. package/dist/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  118. package/dist/assets/gleam-BspZqrRM.js +1 -0
  119. package/dist/assets/glimmer-js-Rg0-pVw9.js +1 -0
  120. package/dist/assets/glimmer-ts-U6CK756n.js +1 -0
  121. package/dist/assets/glsl-DplSGwfg.js +1 -0
  122. package/dist/assets/gnuplot-DdkO51Og.js +1 -0
  123. package/dist/assets/go-Dn2_MT6a.js +1 -0
  124. package/dist/assets/graphql-ChdNCCLP.js +1 -0
  125. package/dist/assets/groovy-D9Dt4D0W.js +1 -0
  126. package/dist/assets/groovy-gcz8RCvz.js +1 -0
  127. package/dist/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  128. package/dist/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  129. package/dist/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  130. package/dist/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  131. package/dist/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  132. package/dist/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  133. package/dist/assets/hack-CaT9iCJl.js +1 -0
  134. package/dist/assets/haml-B8DHNrY2.js +1 -0
  135. package/dist/assets/handlebars-BL8al0AC.js +1 -0
  136. package/dist/assets/haskell-Cw1EW3IL.js +1 -0
  137. package/dist/assets/haskell-Df6bDoY_.js +1 -0
  138. package/dist/assets/haxe-CzTSHFRz.js +1 -0
  139. package/dist/assets/haxe-H-WmDvRZ.js +1 -0
  140. package/dist/assets/hcl-BWvSN4gD.js +1 -0
  141. package/dist/assets/hjson-D5-asLiD.js +1 -0
  142. package/dist/assets/hlsl-D3lLCCz7.js +1 -0
  143. package/dist/assets/houston-DnULxvSX.js +1 -0
  144. package/dist/assets/html-GMplVEZG.js +1 -0
  145. package/dist/assets/html-derivative-BFtXZ54Q.js +1 -0
  146. package/dist/assets/http-DBlCnlav.js +1 -0
  147. package/dist/assets/http-jrhK8wxY.js +1 -0
  148. package/dist/assets/hurl-irOxFIW8.js +1 -0
  149. package/dist/assets/hxml-Bvhsp5Yf.js +1 -0
  150. package/dist/assets/hy-DFXneXwc.js +1 -0
  151. package/dist/assets/idl-BEugSyMb.js +1 -0
  152. package/dist/assets/imba-DGztddWO.js +1 -0
  153. package/dist/assets/index-8c6bEJ99.js +1 -0
  154. package/dist/assets/index-AbWe21oh.js +2 -0
  155. package/dist/assets/index-ArhptQw0.js +1 -0
  156. package/dist/assets/index-B1hpa--1.js +3 -0
  157. package/dist/assets/index-Bafja8o4.js +1 -0
  158. package/dist/assets/index-Bp00uZNc.js +1 -0
  159. package/dist/assets/index-BsTieXqQ.js +1 -0
  160. package/dist/assets/index-BvGAWAqS.js +1 -0
  161. package/dist/assets/index-CCfVkFzN.js +1 -0
  162. package/dist/assets/index-D-Urq2hl.css +1 -0
  163. package/dist/assets/index-D3mXuuih.js +1 -0
  164. package/dist/assets/index-DFOLYN6W.js +1 -0
  165. package/dist/assets/index-DpxkOmNJ.js +7 -0
  166. package/dist/assets/index-YZ-iXB95.js +309 -0
  167. package/dist/assets/index-eA_XNQ_L.js +1 -0
  168. package/dist/assets/index-ftYom_wU.js +1 -0
  169. package/dist/assets/index-gvPT4BlL.js +1 -0
  170. package/dist/assets/ini-BEwlwnbL.js +1 -0
  171. package/dist/assets/java-CylS5w8V.js +1 -0
  172. package/dist/assets/javascript-iXu5QeM3.js +1 -0
  173. package/dist/assets/javascript-wDzz0qaB.js +1 -0
  174. package/dist/assets/jinja-4LBKfQ-Z.js +1 -0
  175. package/dist/assets/jison-wvAkD_A8.js +1 -0
  176. package/dist/assets/json-Cp-IABpG.js +1 -0
  177. package/dist/assets/json5-C9tS-k6U.js +1 -0
  178. package/dist/assets/jsonc-Des-eS-w.js +1 -0
  179. package/dist/assets/jsonl-DcaNXYhu.js +1 -0
  180. package/dist/assets/jsonnet-DFQXde-d.js +1 -0
  181. package/dist/assets/jssm-C2t-YnRu.js +1 -0
  182. package/dist/assets/jsx-g9-lgVsj.js +1 -0
  183. package/dist/assets/julia-C8NyazO9.js +1 -0
  184. package/dist/assets/julia-DuME0IfC.js +1 -0
  185. package/dist/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  186. package/dist/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  187. package/dist/assets/kanagawa-wave-DWedfzmr.js +1 -0
  188. package/dist/assets/kdl-DV7GczEv.js +1 -0
  189. package/dist/assets/kotlin-BdnUsdx6.js +1 -0
  190. package/dist/assets/kusto-BvAqAH-y.js +1 -0
  191. package/dist/assets/laserwave-DUszq2jm.js +1 -0
  192. package/dist/assets/latex-BdAV_C_H.js +1 -0
  193. package/dist/assets/lean-Bc6EcWN3.js +1 -0
  194. package/dist/assets/less-B1dDrJ26.js +1 -0
  195. package/dist/assets/light-plus-B7mTdjB0.js +1 -0
  196. package/dist/assets/liquid-DYVedYrR.js +1 -0
  197. package/dist/assets/livescript-BwQOo05w.js +1 -0
  198. package/dist/assets/llvm-BtvRca6l.js +1 -0
  199. package/dist/assets/log-2UxHyX5q.js +1 -0
  200. package/dist/assets/logo-BtOb2qkB.js +1 -0
  201. package/dist/assets/lua-BbnMAYS6.js +1 -0
  202. package/dist/assets/lua-BgMRiT3U.js +1 -0
  203. package/dist/assets/luau-CXu1NL6O.js +1 -0
  204. package/dist/assets/make-CHLpvVh8.js +1 -0
  205. package/dist/assets/markdown-Cvjx9yec.js +1 -0
  206. package/dist/assets/marko-CPi9NSCl.js +1 -0
  207. package/dist/assets/material-theme-D5KoaKCx.js +1 -0
  208. package/dist/assets/material-theme-darker-BfHTSMKl.js +1 -0
  209. package/dist/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  210. package/dist/assets/material-theme-ocean-CyktbL80.js +1 -0
  211. package/dist/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  212. package/dist/assets/mathematica-DTrFuWx2.js +1 -0
  213. package/dist/assets/matlab-D7o27uSR.js +1 -0
  214. package/dist/assets/mbox-CNhZ1qSd.js +1 -0
  215. package/dist/assets/mdc-DUICxH0z.js +1 -0
  216. package/dist/assets/mdx-Cmh6b_Ma.js +1 -0
  217. package/dist/assets/mermaid-DKYwYmdq.js +1 -0
  218. package/dist/assets/min-dark-CafNBF8u.js +1 -0
  219. package/dist/assets/min-light-CTRr51gU.js +1 -0
  220. package/dist/assets/mipsasm-CKIfxQSi.js +1 -0
  221. package/dist/assets/mirc-CjQqDB4T.js +1 -0
  222. package/dist/assets/mllike-CXdrOF99.js +1 -0
  223. package/dist/assets/modelica-Dc1JOy9r.js +1 -0
  224. package/dist/assets/mojo-1DNp92w6.js +1 -0
  225. package/dist/assets/monokai-D4h5O-jR.js +1 -0
  226. package/dist/assets/move-Bu9oaDYs.js +1 -0
  227. package/dist/assets/mscgen-BA5vi2Kp.js +1 -0
  228. package/dist/assets/mumps-BT43cFF4.js +1 -0
  229. package/dist/assets/narrat-DRg8JJMk.js +1 -0
  230. package/dist/assets/nextflow-BrzmwbiE.js +1 -0
  231. package/dist/assets/nginx-DdIZxoE0.js +1 -0
  232. package/dist/assets/nginx-DknmC5AR.js +1 -0
  233. package/dist/assets/night-owl-C39BiMTA.js +1 -0
  234. package/dist/assets/nim-CVrawwO9.js +1 -0
  235. package/dist/assets/nix-c8nO5XWb.js +1 -0
  236. package/dist/assets/nord-Ddv68eIx.js +1 -0
  237. package/dist/assets/nsis-LdVXkNf5.js +1 -0
  238. package/dist/assets/ntriples-BfvgReVJ.js +1 -0
  239. package/dist/assets/nushell-C-sUppwS.js +1 -0
  240. package/dist/assets/objective-c-DXmwc3jG.js +1 -0
  241. package/dist/assets/objective-cpp-CLxacb5B.js +1 -0
  242. package/dist/assets/ocaml-C0hk2d4L.js +1 -0
  243. package/dist/assets/octave-Ck1zUtKM.js +1 -0
  244. package/dist/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  245. package/dist/assets/one-light-PoHY5YXO.js +1 -0
  246. package/dist/assets/openscad-C4EeE6gA.js +1 -0
  247. package/dist/assets/oz-BzwKVEFT.js +1 -0
  248. package/dist/assets/pascal--L3eBynH.js +1 -0
  249. package/dist/assets/pascal-D93ZcfNL.js +1 -0
  250. package/dist/assets/perl-C0TMdlhV.js +1 -0
  251. package/dist/assets/perl-CdXCOZ3F.js +1 -0
  252. package/dist/assets/php-CDn_0X-4.js +1 -0
  253. package/dist/assets/pig-CevX1Tat.js +1 -0
  254. package/dist/assets/pkl-u5AG7uiY.js +1 -0
  255. package/dist/assets/plastic-3e1v2bzS.js +1 -0
  256. package/dist/assets/plsql-ChMvpjG-.js +1 -0
  257. package/dist/assets/po-BTJTHyun.js +1 -0
  258. package/dist/assets/poimandres-CS3Unz2-.js +1 -0
  259. package/dist/assets/polar-C0HS_06l.js +1 -0
  260. package/dist/assets/postcss-CXtECtnM.js +1 -0
  261. package/dist/assets/powerquery-CEu0bR-o.js +1 -0
  262. package/dist/assets/powershell-CFHJl5sT.js +1 -0
  263. package/dist/assets/powershell-Dpen1YoG.js +1 -0
  264. package/dist/assets/prisma-Dd19v3D-.js +1 -0
  265. package/dist/assets/prolog-CbFg5uaA.js +1 -0
  266. package/dist/assets/properties-C78fOPTZ.js +1 -0
  267. package/dist/assets/proto-DyJlTyXw.js +1 -0
  268. package/dist/assets/protobuf-ChK-085T.js +1 -0
  269. package/dist/assets/pug-CGlum2m_.js +1 -0
  270. package/dist/assets/pug-DeIclll2.js +1 -0
  271. package/dist/assets/puppet-BMWR74SV.js +1 -0
  272. package/dist/assets/puppet-DMA9R1ak.js +1 -0
  273. package/dist/assets/purescript-CklMAg4u.js +1 -0
  274. package/dist/assets/python-B6aJPvgy.js +1 -0
  275. package/dist/assets/python-BuPzkPfP.js +1 -0
  276. package/dist/assets/q-pXgVlZs6.js +1 -0
  277. package/dist/assets/qml-3beO22l8.js +1 -0
  278. package/dist/assets/qmldir-C8lEn-DE.js +1 -0
  279. package/dist/assets/qss-IeuSbFQv.js +1 -0
  280. package/dist/assets/r-B6wPVr8A.js +1 -0
  281. package/dist/assets/r-DiinP2Uv.js +1 -0
  282. package/dist/assets/racket-BqYA7rlc.js +1 -0
  283. package/dist/assets/raku-DXvB9xmW.js +1 -0
  284. package/dist/assets/razor-CE9lU5zL.js +1 -0
  285. package/dist/assets/red-bN70gL4F.js +1 -0
  286. package/dist/assets/reg-C-SQnVFl.js +1 -0
  287. package/dist/assets/regexp-CDVJQ6XC.js +1 -0
  288. package/dist/assets/rel-C3B-1QV4.js +1 -0
  289. package/dist/assets/riscv-BM1_JUlF.js +1 -0
  290. package/dist/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
  291. package/dist/assets/rose-pine-moon-D4_iv3hh.js +1 -0
  292. package/dist/assets/rose-pine-qdsjHGoJ.js +1 -0
  293. package/dist/assets/rosmsg-BJDFO7_C.js +1 -0
  294. package/dist/assets/rpm-CTu-6PCP.js +1 -0
  295. package/dist/assets/rst-B0xPkSld.js +1 -0
  296. package/dist/assets/ruby-B2Rjki9n.js +1 -0
  297. package/dist/assets/ruby-BvKwtOVI.js +1 -0
  298. package/dist/assets/rust-B1yitclQ.js +1 -0
  299. package/dist/assets/sas-B4kiWyti.js +1 -0
  300. package/dist/assets/sas-cz2c8ADy.js +1 -0
  301. package/dist/assets/sass-Cj5Yp3dK.js +1 -0
  302. package/dist/assets/scala-C151Ov-r.js +1 -0
  303. package/dist/assets/scheme-C41bIUwD.js +1 -0
  304. package/dist/assets/scheme-C98Dy4si.js +1 -0
  305. package/dist/assets/scss-OYdSNvt2.js +1 -0
  306. package/dist/assets/sdbl-DVxCFoDh.js +1 -0
  307. package/dist/assets/shaderlab-Dg9Lc6iA.js +1 -0
  308. package/dist/assets/shell-CjFT_Tl9.js +1 -0
  309. package/dist/assets/shellscript-Yzrsuije.js +1 -0
  310. package/dist/assets/shellsession-BADoaaVG.js +1 -0
  311. package/dist/assets/sieve-C3Gn_uJK.js +1 -0
  312. package/dist/assets/simple-mode-GW_nhZxv.js +1 -0
  313. package/dist/assets/slack-dark-BthQWCQV.js +1 -0
  314. package/dist/assets/slack-ochin-DqwNpetd.js +1 -0
  315. package/dist/assets/smalltalk-BERRCDM3.js +1 -0
  316. package/dist/assets/smalltalk-CnHTOXQT.js +1 -0
  317. package/dist/assets/snazzy-light-Bw305WKR.js +1 -0
  318. package/dist/assets/solarized-dark-DXbdFlpD.js +1 -0
  319. package/dist/assets/solarized-light-L9t79GZl.js +1 -0
  320. package/dist/assets/solidity-rGO070M0.js +1 -0
  321. package/dist/assets/solr-DehyRSwq.js +1 -0
  322. package/dist/assets/soy-Brmx7dQM.js +1 -0
  323. package/dist/assets/sparql-DkYu6x3z.js +1 -0
  324. package/dist/assets/sparql-rVzFXLq3.js +1 -0
  325. package/dist/assets/splunk-BtCnVYZw.js +1 -0
  326. package/dist/assets/spreadsheet-BCZA_wO0.js +1 -0
  327. package/dist/assets/sql-BLtJtn59.js +1 -0
  328. package/dist/assets/sql-D0XecflT.js +1 -0
  329. package/dist/assets/ssh-config-_ykCGR6B.js +1 -0
  330. package/dist/assets/stata-BH5u7GGu.js +1 -0
  331. package/dist/assets/stex-C3f8Ysf7.js +1 -0
  332. package/dist/assets/stylus-B533Al4x.js +1 -0
  333. package/dist/assets/stylus-BEDo0Tqx.js +1 -0
  334. package/dist/assets/svelte-3Dk4HxPD.js +1 -0
  335. package/dist/assets/swift-BzpIVaGY.js +1 -0
  336. package/dist/assets/swift-Dg5xB15N.js +1 -0
  337. package/dist/assets/synthwave-84-CbfX1IO0.js +1 -0
  338. package/dist/assets/system-verilog-CnnmHF94.js +1 -0
  339. package/dist/assets/systemd-4A_iFExJ.js +1 -0
  340. package/dist/assets/talonscript-CkByrt1z.js +1 -0
  341. package/dist/assets/tasl-QIJgUcNo.js +1 -0
  342. package/dist/assets/tcl-DVfN8rqt.js +1 -0
  343. package/dist/assets/tcl-dwOrl1Do.js +1 -0
  344. package/dist/assets/templ-W15q3VgB.js +1 -0
  345. package/dist/assets/terraform-BETggiCN.js +1 -0
  346. package/dist/assets/tex-CxkMU7Pf.js +1 -0
  347. package/dist/assets/textile-CnDTJFAw.js +1 -0
  348. package/dist/assets/tiddlywiki-DO-Gjzrf.js +1 -0
  349. package/dist/assets/tiki-DGYXhP31.js +1 -0
  350. package/dist/assets/tokyo-night-hegEt444.js +1 -0
  351. package/dist/assets/toml-Bm5Em-hy.js +1 -0
  352. package/dist/assets/toml-vGWfd6FD.js +1 -0
  353. package/dist/assets/troff-wAsdV37c.js +1 -0
  354. package/dist/assets/ts-tags-zn1MmPIZ.js +1 -0
  355. package/dist/assets/tsv-B_m7g4N7.js +1 -0
  356. package/dist/assets/tsx-COt5Ahok.js +1 -0
  357. package/dist/assets/ttcn-CfJYG6tj.js +1 -0
  358. package/dist/assets/ttcn-cfg-B9xdYoR4.js +1 -0
  359. package/dist/assets/turtle-B1tBg_DP.js +1 -0
  360. package/dist/assets/turtle-BsS91CYL.js +1 -0
  361. package/dist/assets/twig-CO9l9SDP.js +1 -0
  362. package/dist/assets/typescript-BPQ3VLAy.js +1 -0
  363. package/dist/assets/typespec-BGHnOYBU.js +1 -0
  364. package/dist/assets/typst-DHCkPAjA.js +1 -0
  365. package/dist/assets/v-BcVCzyr7.js +1 -0
  366. package/dist/assets/vala-CsfeWuGM.js +1 -0
  367. package/dist/assets/vb-CmGdzxic.js +1 -0
  368. package/dist/assets/vb-D17OF-Vu.js +1 -0
  369. package/dist/assets/vbscript-BuJXcnF6.js +1 -0
  370. package/dist/assets/velocity-D8B20fx6.js +1 -0
  371. package/dist/assets/verilog-BQ8w6xss.js +1 -0
  372. package/dist/assets/verilog-C6RDOZhf.js +1 -0
  373. package/dist/assets/vesper-DU1UobuO.js +1 -0
  374. package/dist/assets/vhdl-CeAyd5Ju.js +1 -0
  375. package/dist/assets/vhdl-lSbBsy5d.js +1 -0
  376. package/dist/assets/viml-CJc9bBzg.js +1 -0
  377. package/dist/assets/vitesse-black-Bkuqu6BP.js +1 -0
  378. package/dist/assets/vitesse-dark-D0r3Knsf.js +1 -0
  379. package/dist/assets/vitesse-light-CVO1_9PV.js +1 -0
  380. package/dist/assets/vue-DnHKYNfI.js +1 -0
  381. package/dist/assets/vue-html-CChd_i61.js +1 -0
  382. package/dist/assets/vue-vine-8moa0y9V.js +1 -0
  383. package/dist/assets/vyper-CDx5xZoG.js +1 -0
  384. package/dist/assets/wasm-CG6Dc4jp.js +1 -0
  385. package/dist/assets/wasm-MzD3tlZU.js +1 -0
  386. package/dist/assets/webidl-ZXfAyPTL.js +1 -0
  387. package/dist/assets/wenyan-BV7otONQ.js +1 -0
  388. package/dist/assets/wgsl-Dx-B1_4e.js +1 -0
  389. package/dist/assets/wikitext-BhOHFoWU.js +1 -0
  390. package/dist/assets/wit-5i3qLPDT.js +1 -0
  391. package/dist/assets/wolfram-lXgVvXCa.js +1 -0
  392. package/dist/assets/xml-sdJ4AIDG.js +1 -0
  393. package/dist/assets/xquery-DzFWVndE.js +1 -0
  394. package/dist/assets/xsl-CtQFsRM5.js +1 -0
  395. package/dist/assets/yacas-BJ4BC0dw.js +1 -0
  396. package/dist/assets/yaml-Buea-lGh.js +1 -0
  397. package/dist/assets/z80-Hz9HOZM7.js +1 -0
  398. package/dist/assets/zenscript-DVFEvuxE.js +1 -0
  399. package/dist/assets/zig-VOosw3JB.js +1 -0
  400. package/dist/index.html +47 -0
  401. package/dist/logo.svg +8 -0
  402. package/dist/openspec_pixel_dark.svg +89 -0
  403. package/dist/openspec_pixel_light.svg +89 -0
  404. package/index.html +46 -0
  405. package/package.json +66 -0
  406. package/src/App.tsx +124 -0
  407. package/src/components/StaticModeBanner.tsx +46 -0
  408. package/src/components/change-overview.tsx +156 -0
  409. package/src/components/cli-terminal.tsx +93 -0
  410. package/src/components/code-editor.tsx +232 -0
  411. package/src/components/copyable-path.tsx +44 -0
  412. package/src/components/dialog.tsx +193 -0
  413. package/src/components/folder-editor-viewer.tsx +411 -0
  414. package/src/components/global-archive-modal.tsx +205 -0
  415. package/src/components/layout/desktop-sidebar.tsx +48 -0
  416. package/src/components/layout/index.ts +6 -0
  417. package/src/components/layout/mobile-header.tsx +91 -0
  418. package/src/components/layout/mobile-tabbar.tsx +20 -0
  419. package/src/components/layout/nav-items.ts +33 -0
  420. package/src/components/layout/root-layout.tsx +67 -0
  421. package/src/components/layout/status-bar.tsx +69 -0
  422. package/src/components/markdown-content.tsx +104 -0
  423. package/src/components/markdown-viewer.tsx +415 -0
  424. package/src/components/path-marquee.tsx +104 -0
  425. package/src/components/tabs.tsx +151 -0
  426. package/src/components/tasks-view.test.tsx +45 -0
  427. package/src/components/tasks-view.tsx +209 -0
  428. package/src/components/toc-context.tsx +177 -0
  429. package/src/components/toc.tsx +290 -0
  430. package/src/entry-client.tsx +47 -0
  431. package/src/index.css +481 -0
  432. package/src/lib/api-config.ts +72 -0
  433. package/src/lib/archive-modal-context.tsx +45 -0
  434. package/src/lib/codemirror-markdown-preview.ts +494 -0
  435. package/src/lib/format-time.ts +51 -0
  436. package/src/lib/shiki-highlighter.ts +47 -0
  437. package/src/lib/static-data-provider.ts +386 -0
  438. package/src/lib/static-mode.ts +158 -0
  439. package/src/lib/trpc.ts +107 -0
  440. package/src/lib/use-cli-runner.tsx +433 -0
  441. package/src/lib/use-dark-mode.ts +28 -0
  442. package/src/lib/use-server-status.ts +208 -0
  443. package/src/lib/use-subscription.ts +375 -0
  444. package/src/lib/use-tabs-status-by-query.ts +78 -0
  445. package/src/main.tsx +9 -0
  446. package/src/routes/archive-list.tsx +65 -0
  447. package/src/routes/archive-view.tsx +116 -0
  448. package/src/routes/change-list.tsx +63 -0
  449. package/src/routes/change-view.tsx +188 -0
  450. package/src/routes/dashboard.tsx +204 -0
  451. package/src/routes/project.tsx +272 -0
  452. package/src/routes/settings.tsx +816 -0
  453. package/src/routes/spec-list.tsx +49 -0
  454. package/src/routes/spec-view.tsx +164 -0
  455. package/src/ssg/entry-server.tsx +111 -0
  456. package/src/ssg/index.ts +6 -0
  457. package/src/ssg/prerender.ts +111 -0
  458. package/src/ssg/static-data-context.tsx +49 -0
  459. package/src/ssg/types.ts +5 -0
  460. package/src/test/setup.ts +1 -0
  461. package/src/vite-env.d.ts +6 -0
  462. package/tsconfig.json +18 -0
  463. package/vite.config.ts +58 -0
@@ -0,0 +1,375 @@
1
+ import type { ArchiveMeta, Change, ChangeFile, ChangeMeta, Spec, SpecMeta } from '@openspecui/core'
2
+ import { useEffect, useRef, useState } from 'react'
3
+ import * as StaticProvider from './static-data-provider'
4
+ import { isStaticMode } from './static-mode'
5
+ import { trpcClient } from './trpc'
6
+
7
+ /** 订阅状态 */
8
+ export interface SubscriptionState<T> {
9
+ data: T | undefined
10
+ isLoading: boolean
11
+ error: Error | null
12
+ }
13
+
14
+ /** Dashboard 数据类型 */
15
+ export interface DashboardData {
16
+ specs: Spec[]
17
+ changes: Change[]
18
+ archivedCount: number
19
+ summary: {
20
+ specCount: number
21
+ requirementCount: number
22
+ activeChangeCount: number
23
+ archivedChangeCount: number
24
+ totalTasks: number
25
+ completedTasks: number
26
+ progressPercent: number
27
+ }
28
+ }
29
+
30
+ /** 订阅回调 */
31
+ interface SubscriptionCallbacks<T> {
32
+ onData: (data: T) => void
33
+ onError: (err: Error) => void
34
+ }
35
+
36
+ /** 可取消订阅的对象 */
37
+ interface Unsubscribable {
38
+ unsubscribe: () => void
39
+ }
40
+
41
+ /**
42
+ * 通用订阅 Hook (支持静态模式)
43
+ *
44
+ * 替代 useQuery,直接从 WebSocket 获取数据。
45
+ * 当订阅的数据变更时,自动更新组件。
46
+ * 在静态模式下,从 data.json 加载数据。
47
+ *
48
+ * @param subscribe 订阅函数
49
+ * @param staticLoader 静态数据加载函数(静态模式下使用)
50
+ * @param deps 依赖数组
51
+ */
52
+ export function useSubscription<T>(
53
+ subscribe: (callbacks: SubscriptionCallbacks<T>) => Unsubscribable,
54
+ staticLoader?: () => Promise<T>,
55
+ deps: unknown[] = []
56
+ ): SubscriptionState<T> {
57
+ const [state, setState] = useState<SubscriptionState<T>>({
58
+ data: undefined,
59
+ isLoading: true,
60
+ error: null,
61
+ })
62
+
63
+ const subscriptionRef = useRef<Unsubscribable | null>(null)
64
+ const inStaticMode = isStaticMode()
65
+
66
+ useEffect(() => {
67
+ // 清理之前的订阅
68
+ subscriptionRef.current?.unsubscribe()
69
+
70
+ // 重置状态
71
+ setState((prev) => ({ ...prev, isLoading: true, error: null }))
72
+
73
+ // 静态模式:从 data.json 加载数据
74
+ if (inStaticMode) {
75
+ if (staticLoader) {
76
+ staticLoader()
77
+ .then((data) => {
78
+ setState({ data, isLoading: false, error: null })
79
+ })
80
+ .catch((error) => {
81
+ console.error('Static data loading error:', error)
82
+ setState((prev) => ({ ...prev, isLoading: false, error }))
83
+ })
84
+ } else {
85
+ console.warn('No static loader provided for subscription in static mode')
86
+ setState((prev) => ({
87
+ ...prev,
88
+ isLoading: false,
89
+ error: new Error('Static loader not available'),
90
+ }))
91
+ }
92
+ return
93
+ }
94
+
95
+ // 动态模式:创建 WebSocket 订阅
96
+ const subscription = subscribe({
97
+ onData: (data) => {
98
+ setState({ data, isLoading: false, error: null })
99
+ },
100
+ onError: (error) => {
101
+ console.error('Subscription error:', error)
102
+ setState((prev) => ({ ...prev, isLoading: false, error }))
103
+ },
104
+ })
105
+
106
+ subscriptionRef.current = subscription
107
+
108
+ return () => {
109
+ subscription.unsubscribe()
110
+ }
111
+ // eslint-disable-next-line react-hooks/exhaustive-deps
112
+ }, [inStaticMode, ...deps])
113
+
114
+ return state
115
+ }
116
+
117
+ // =====================
118
+ // Dashboard subscriptions
119
+ // =====================
120
+
121
+ export function useDashboardSubscription(): SubscriptionState<DashboardData> {
122
+ return useSubscription<DashboardData>(
123
+ (callbacks) =>
124
+ trpcClient.dashboard.subscribe.subscribe(undefined, {
125
+ onData: callbacks.onData,
126
+ onError: callbacks.onError,
127
+ }),
128
+ async () => {
129
+ const data = await StaticProvider.getDashboardData()
130
+ if (!data) throw new Error('Failed to load dashboard data')
131
+ return data
132
+ },
133
+ []
134
+ )
135
+ }
136
+
137
+ export function useInitializedSubscription(): SubscriptionState<boolean> {
138
+ return useSubscription<boolean>(
139
+ (callbacks) =>
140
+ trpcClient.dashboard.subscribeInitialized.subscribe(undefined, {
141
+ onData: callbacks.onData,
142
+ onError: callbacks.onError,
143
+ }),
144
+ StaticProvider.getInitialized,
145
+ []
146
+ )
147
+ }
148
+
149
+ // =====================
150
+ // Spec subscriptions
151
+ // =====================
152
+
153
+ export function useSpecsSubscription(): SubscriptionState<SpecMeta[]> {
154
+ return useSubscription<SpecMeta[]>(
155
+ (callbacks) =>
156
+ trpcClient.spec.subscribe.subscribe(undefined, {
157
+ onData: callbacks.onData,
158
+ onError: callbacks.onError,
159
+ }),
160
+ StaticProvider.getSpecs,
161
+ []
162
+ )
163
+ }
164
+
165
+ export function useSpecSubscription(id: string): SubscriptionState<Spec | null> {
166
+ return useSubscription<Spec | null>(
167
+ (callbacks) =>
168
+ trpcClient.spec.subscribeOne.subscribe(
169
+ { id },
170
+ {
171
+ onData: callbacks.onData,
172
+ onError: callbacks.onError,
173
+ }
174
+ ),
175
+ () => StaticProvider.getSpec(id),
176
+ [id]
177
+ )
178
+ }
179
+
180
+ export function useSpecRawSubscription(id: string): SubscriptionState<string | null> {
181
+ return useSubscription<string | null>(
182
+ (callbacks) =>
183
+ trpcClient.spec.subscribeRaw.subscribe(
184
+ { id },
185
+ {
186
+ onData: callbacks.onData,
187
+ onError: callbacks.onError,
188
+ }
189
+ ),
190
+ () => StaticProvider.getSpecRaw(id),
191
+ [id]
192
+ )
193
+ }
194
+
195
+ // =====================
196
+ // Change subscriptions
197
+ // =====================
198
+
199
+ export function useChangesSubscription(): SubscriptionState<ChangeMeta[]> {
200
+ return useSubscription<ChangeMeta[]>(
201
+ (callbacks) =>
202
+ trpcClient.change.subscribe.subscribe(undefined, {
203
+ onData: callbacks.onData,
204
+ onError: callbacks.onError,
205
+ }),
206
+ StaticProvider.getChanges,
207
+ []
208
+ )
209
+ }
210
+
211
+ export function useChangeSubscription(id: string): SubscriptionState<Change | null> {
212
+ return useSubscription<Change | null>(
213
+ (callbacks) =>
214
+ trpcClient.change.subscribeOne.subscribe(
215
+ { id },
216
+ {
217
+ onData: callbacks.onData,
218
+ onError: callbacks.onError,
219
+ }
220
+ ),
221
+ () => StaticProvider.getChange(id),
222
+ [id]
223
+ )
224
+ }
225
+
226
+ export function useChangeFilesSubscription(id: string): SubscriptionState<ChangeFile[]> {
227
+ return useSubscription<ChangeFile[]>(
228
+ (callbacks) =>
229
+ trpcClient.change.subscribeFiles.subscribe(
230
+ { id },
231
+ {
232
+ onData: callbacks.onData,
233
+ onError: callbacks.onError,
234
+ }
235
+ ),
236
+ () => StaticProvider.getChangeFiles(id),
237
+ [id]
238
+ )
239
+ }
240
+
241
+ /** Change 原始文件内容 */
242
+ export interface ChangeRaw {
243
+ proposal: string
244
+ tasks?: string
245
+ }
246
+
247
+ export function useChangeRawSubscription(id: string): SubscriptionState<ChangeRaw | null> {
248
+ return useSubscription<ChangeRaw | null>(
249
+ (callbacks) =>
250
+ trpcClient.change.subscribeRaw.subscribe(
251
+ { id },
252
+ {
253
+ onData: callbacks.onData,
254
+ onError: callbacks.onError,
255
+ }
256
+ ),
257
+ () => StaticProvider.getChangeRaw(id),
258
+ [id]
259
+ )
260
+ }
261
+
262
+ // =====================
263
+ // Archive subscriptions
264
+ // =====================
265
+
266
+ export function useArchivesSubscription(): SubscriptionState<ArchiveMeta[]> {
267
+ return useSubscription<ArchiveMeta[]>(
268
+ (callbacks) =>
269
+ trpcClient.archive.subscribe.subscribe(undefined, {
270
+ onData: callbacks.onData,
271
+ onError: callbacks.onError,
272
+ }),
273
+ StaticProvider.getArchives,
274
+ []
275
+ )
276
+ }
277
+
278
+ /** Archived change 数据类型 (与 Change 相同结构) */
279
+ export type ArchivedChange = Change
280
+
281
+ export function useArchiveSubscription(id: string): SubscriptionState<ArchivedChange | null> {
282
+ return useSubscription<ArchivedChange | null>(
283
+ (callbacks) =>
284
+ trpcClient.archive.subscribeOne.subscribe(
285
+ { id },
286
+ {
287
+ onData: callbacks.onData,
288
+ onError: callbacks.onError,
289
+ }
290
+ ),
291
+ () => StaticProvider.getArchive(id),
292
+ [id]
293
+ )
294
+ }
295
+
296
+ export function useArchiveFilesSubscription(id: string): SubscriptionState<ChangeFile[]> {
297
+ return useSubscription<ChangeFile[]>(
298
+ (callbacks) =>
299
+ trpcClient.archive.subscribeFiles.subscribe(
300
+ { id },
301
+ {
302
+ onData: callbacks.onData,
303
+ onError: callbacks.onError,
304
+ }
305
+ ),
306
+ () => StaticProvider.getArchiveFiles(id),
307
+ [id]
308
+ )
309
+ }
310
+
311
+ // =====================
312
+ // Project subscriptions
313
+ // =====================
314
+
315
+ export function useProjectMdSubscription(): SubscriptionState<string | null> {
316
+ return useSubscription<string | null>(
317
+ (callbacks) =>
318
+ trpcClient.project.subscribeProjectMd.subscribe(undefined, {
319
+ onData: callbacks.onData,
320
+ onError: callbacks.onError,
321
+ }),
322
+ StaticProvider.getProjectMd,
323
+ []
324
+ )
325
+ }
326
+
327
+ export function useAgentsMdSubscription(): SubscriptionState<string | null> {
328
+ return useSubscription<string | null>(
329
+ (callbacks) =>
330
+ trpcClient.project.subscribeAgentsMd.subscribe(undefined, {
331
+ onData: callbacks.onData,
332
+ onError: callbacks.onError,
333
+ }),
334
+ StaticProvider.getAgentsMd,
335
+ []
336
+ )
337
+ }
338
+
339
+ // =====================
340
+ // Config subscriptions
341
+ // =====================
342
+
343
+ /** OpenSpecUI 配置类型 */
344
+ export interface OpenSpecUIConfig {
345
+ cli: { command?: string }
346
+ ui: { theme: 'light' | 'dark' | 'system' }
347
+ }
348
+
349
+ export function useConfigSubscription(): SubscriptionState<OpenSpecUIConfig> {
350
+ return useSubscription<OpenSpecUIConfig>(
351
+ (callbacks) =>
352
+ trpcClient.config.subscribe.subscribe(undefined, {
353
+ onData: callbacks.onData,
354
+ onError: callbacks.onError,
355
+ }),
356
+ StaticProvider.getConfig,
357
+ []
358
+ )
359
+ }
360
+
361
+ // =====================
362
+ // CLI subscriptions
363
+ // =====================
364
+
365
+ export function useConfiguredToolsSubscription(): SubscriptionState<string[]> {
366
+ return useSubscription<string[]>(
367
+ (callbacks) =>
368
+ trpcClient.cli.subscribeConfiguredTools.subscribe(undefined, {
369
+ onData: callbacks.onData,
370
+ onError: callbacks.onError,
371
+ }),
372
+ StaticProvider.getConfiguredTools,
373
+ []
374
+ )
375
+ }
@@ -0,0 +1,78 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react'
2
+
3
+ interface UseTabsStatusByQueryParams {
4
+ tabsId: string
5
+ tabs: Array<{ id: string }>
6
+ initialTab?: string
7
+ }
8
+
9
+ export function useTabsStatusByQuery({ tabsId, tabs, initialTab }: UseTabsStatusByQueryParams) {
10
+ const validIds = useMemo(() => new Set(tabs.map((t) => t.id)), [tabs])
11
+
12
+ const readFromUrl = useCallback(() => {
13
+ if (typeof window === 'undefined') return null
14
+ const params = new URLSearchParams(window.location.search)
15
+ const value = params.get(tabsId)
16
+ return value && validIds.has(value) ? value : null
17
+ }, [tabsId, validIds])
18
+
19
+ const pickInitial = useCallback(() => {
20
+ return readFromUrl() ?? initialTab ?? tabs[0]?.id ?? ''
21
+ }, [readFromUrl, initialTab, tabs])
22
+
23
+ const [selectedTab, setSelectedTab] = useState<string>(pickInitial)
24
+
25
+ const writeToUrl = useCallback(
26
+ (id: string) => {
27
+ if (typeof window === 'undefined') return
28
+ const url = new URL(window.location.href)
29
+ url.searchParams.set(tabsId, id)
30
+ window.history.replaceState(null, '', url.toString())
31
+ },
32
+ [tabsId]
33
+ )
34
+
35
+ const setBoth = useCallback(
36
+ (id: string) => {
37
+ if (!validIds.has(id)) return
38
+ setSelectedTab(id)
39
+ writeToUrl(id)
40
+ },
41
+ [validIds, writeToUrl]
42
+ )
43
+
44
+ // keep in sync when tabs or URL change
45
+ useEffect(() => {
46
+ const fromUrl = readFromUrl()
47
+ const candidate = fromUrl ?? initialTab ?? tabs[0]?.id ?? ''
48
+ if (candidate && candidate !== selectedTab && validIds.has(candidate)) {
49
+ setSelectedTab(candidate)
50
+ } else if (!validIds.has(selectedTab) && candidate) {
51
+ setSelectedTab(candidate)
52
+ }
53
+ }, [readFromUrl, initialTab, tabs, selectedTab, validIds])
54
+
55
+ // respond to browser navigation
56
+ useEffect(() => {
57
+ if (typeof window === 'undefined') return
58
+ const handler = () => {
59
+ const next = readFromUrl()
60
+ if (next && validIds.has(next)) {
61
+ setSelectedTab((prev) => (prev === next ? prev : next))
62
+ }
63
+ }
64
+ window.addEventListener('popstate', handler)
65
+ return () => window.removeEventListener('popstate', handler)
66
+ }, [readFromUrl, validIds])
67
+
68
+ // reflect current selection into URL
69
+ useEffect(() => {
70
+ if (!validIds.has(selectedTab) || typeof window === 'undefined') return
71
+ const current = readFromUrl()
72
+ if (current === selectedTab) return
73
+ writeToUrl(selectedTab)
74
+ }, [selectedTab, validIds, writeToUrl, readFromUrl])
75
+
76
+ return { selectedTab, setSelectedTab: setBoth }
77
+ }
78
+
package/src/main.tsx ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Main entry point - re-exports from entry-client
3
+ *
4
+ * This file exists for backwards compatibility with Vite's default entry.
5
+ */
6
+ export * from './entry-client'
7
+
8
+ // Import to trigger side effects (the actual app initialization)
9
+ import './entry-client'
@@ -0,0 +1,65 @@
1
+ import { formatRelativeTime } from '@/lib/format-time'
2
+ import { useArchivesSubscription } from '@/lib/use-subscription'
3
+ import { Link } from '@tanstack/react-router'
4
+ import { Archive, ChevronRight } from 'lucide-react'
5
+ import { useEffect, useState } from 'react'
6
+
7
+ export function ArchiveList() {
8
+ const { data: archived, isLoading } = useArchivesSubscription()
9
+
10
+ const [firstFrameLoading, setFirstFrameLoading] = useState(true)
11
+ useEffect(() => {
12
+ const id = requestAnimationFrame(() => setFirstFrameLoading(false))
13
+ return () => cancelAnimationFrame(id)
14
+ }, [])
15
+
16
+ if (firstFrameLoading || (isLoading && !archived)) {
17
+ return <div className="route-loading animate-pulse">Loading archived changes...</div>
18
+ }
19
+
20
+ return (
21
+ <div className="space-y-6">
22
+ <h1 className="font-nav flex items-center gap-2 text-2xl font-bold">
23
+ <Archive className="h-6 w-6 shrink-0" />
24
+ Archive
25
+ </h1>
26
+
27
+ <p className="text-muted-foreground">
28
+ Completed changes that have been archived after implementation.
29
+ </p>
30
+
31
+ <div className="border-border divide-border divide-y rounded-lg border">
32
+ {archived?.map((change) => (
33
+ <Link
34
+ key={change.id}
35
+ to="/archive/$changeId"
36
+ params={{ changeId: change.id }}
37
+ className="hover:bg-muted/50 flex items-center justify-between p-4"
38
+ >
39
+ <div className="flex items-center gap-3">
40
+ <Archive className="text-muted-foreground h-5 w-5" />
41
+ <div>
42
+ <div className="font-medium">{change.name}</div>
43
+ <div className="text-muted-foreground text-sm">
44
+ {change.id}
45
+ {change.updatedAt > 0 && <> · {formatRelativeTime(change.updatedAt)}</>}
46
+ </div>
47
+ </div>
48
+ </div>
49
+ <ChevronRight className="text-muted-foreground h-4 w-4" />
50
+ </Link>
51
+ ))}
52
+ {archived?.length === 0 && (
53
+ <div className="text-muted-foreground p-8 text-center">
54
+ <Archive className="mx-auto mb-4 h-12 w-12 opacity-50" />
55
+ <p>No archived changes yet.</p>
56
+ <p className="mt-2 text-sm">
57
+ Changes are archived after implementation using{' '}
58
+ <code className="bg-muted rounded px-1">openspec archive</code>
59
+ </p>
60
+ </div>
61
+ )}
62
+ </div>
63
+ </div>
64
+ )
65
+ }
@@ -0,0 +1,116 @@
1
+ import { ChangeOverview } from '@/components/change-overview'
2
+ import { FolderEditorViewer } from '@/components/folder-editor-viewer'
3
+ import { Tabs, type Tab } from '@/components/tabs'
4
+ import { useTabsStatusByQuery } from '@/lib/use-tabs-status-by-query'
5
+ import { TasksView } from '@/components/tasks-view'
6
+ import { useArchiveSubscription } from '@/lib/use-subscription'
7
+ import { getRouteApi, Link } from '@tanstack/react-router'
8
+ import { Archive, ArrowLeft, CheckCircle, FileText, FolderTree, ListChecks } from 'lucide-react'
9
+ import { useEffect, useMemo, useState } from 'react'
10
+
11
+ const route = getRouteApi('/archive/$changeId')
12
+
13
+ export function ArchiveView() {
14
+ const { changeId } = route.useParams()
15
+
16
+ const { data: change } = useArchiveSubscription(changeId)
17
+ const [loading, setLoading] = useState(true)
18
+ useEffect(() => {
19
+ const id = requestAnimationFrame(() => setLoading(false))
20
+ return () => cancelAnimationFrame(id)
21
+ }, [])
22
+
23
+ const tabs = useMemo<Tab[]>(() => {
24
+ if (!change) return []
25
+
26
+ const result: Tab[] = [
27
+ {
28
+ id: 'overview',
29
+ label: 'Overview',
30
+ icon: <FileText className="h-4 w-4" />,
31
+ content: <ChangeOverview change={change} />,
32
+ },
33
+ ]
34
+
35
+ if (change.tasks.length > 0) {
36
+ result.push({
37
+ id: 'tasks',
38
+ label: `Tasks (${change.progress.completed}/${change.progress.total})`,
39
+ icon: <ListChecks className="h-4 w-4" />,
40
+ content: (
41
+ <div className="border-border h-full overflow-auto rounded-lg border p-4">
42
+ <TasksView tasks={change.tasks} progress={change.progress} readonly />
43
+ </div>
44
+ ),
45
+ })
46
+ }
47
+
48
+ result.push({
49
+ id: 'folder',
50
+ label: 'Folder',
51
+ icon: <FolderTree className="h-4 w-4" />,
52
+ content: <FolderEditorViewer changeId={changeId} archived />,
53
+ })
54
+
55
+ return result
56
+ }, [change, changeId])
57
+
58
+ const { selectedTab, setSelectedTab } = useTabsStatusByQuery({
59
+ tabsId: 'archiveTab',
60
+ tabs,
61
+ initialTab: tabs[0]?.id,
62
+ })
63
+
64
+ if (loading) {
65
+ return <div className="route-loading animate-pulse">Loading archived change...</div>
66
+ }
67
+
68
+ if (!change) {
69
+ return (
70
+ <div className="py-12 text-center">
71
+ <p className="text-muted-foreground">Archived change not found: {changeId}</p>
72
+ <Link to="/archive" className="text-primary mt-4 inline-block hover:underline">
73
+ Back to Archive
74
+ </Link>
75
+ </div>
76
+ )
77
+ }
78
+
79
+ return (
80
+ <div className="flex min-h-0 flex-1 flex-col gap-6">
81
+ {/* Header */}
82
+ <div className="flex items-center gap-4">
83
+ <Link
84
+ to="/archive"
85
+ className="hover:bg-muted rounded-md p-2 transition-colors"
86
+ title="Back to Archive"
87
+ >
88
+ <ArrowLeft className="h-5 w-5" />
89
+ </Link>
90
+ <div>
91
+ <h1 className="font-nav flex items-center gap-2 text-2xl font-bold">
92
+ <Archive className="h-6 w-6 shrink-0" />
93
+ {change.name}
94
+ </h1>
95
+ <p className="text-muted-foreground text-sm">{changeId}</p>
96
+ </div>
97
+ </div>
98
+
99
+ {/* Progress */}
100
+ <div className="flex items-center gap-2 text-sm">
101
+ <CheckCircle className="h-4 w-4 text-green-500" />
102
+ <span className="text-green-600">
103
+ Completed: {change.progress.completed}/{change.progress.total} tasks
104
+ </span>
105
+ </div>
106
+
107
+ {/* Tabs with Activity for state preservation */}
108
+ <Tabs
109
+ tabs={tabs}
110
+ selectedTab={selectedTab}
111
+ onTabChange={setSelectedTab}
112
+ className="min-h-0 flex-1 gap-6"
113
+ />
114
+ </div>
115
+ )
116
+ }
@@ -0,0 +1,63 @@
1
+ import { formatRelativeTime } from '@/lib/format-time'
2
+ import { useChangesSubscription } from '@/lib/use-subscription'
3
+ import { Link } from '@tanstack/react-router'
4
+ import { ChevronRight, GitBranch } from 'lucide-react'
5
+ import { useEffect, useState } from 'react'
6
+
7
+ export function ChangeList() {
8
+ const { data: changes, isLoading } = useChangesSubscription()
9
+ const [firstFrameLoading, setFirstFrameLoading] = useState(true)
10
+ useEffect(() => {
11
+ const id = requestAnimationFrame(() => setFirstFrameLoading(false))
12
+ return () => cancelAnimationFrame(id)
13
+ }, [])
14
+
15
+ if (firstFrameLoading || (isLoading && !changes)) {
16
+ return <div className="route-loading animate-pulse">Loading changes...</div>
17
+ }
18
+
19
+ return (
20
+ <div className="space-y-6">
21
+ <h1 className="font-nav flex items-center gap-2 text-2xl font-bold">
22
+ <GitBranch className="h-6 w-6 shrink-0" />
23
+ Changes
24
+ </h1>
25
+
26
+ <p className="text-muted-foreground">
27
+ Active change proposals. Completed changes are moved to{' '}
28
+ <Link to="/archive" className="text-primary hover:underline">
29
+ Archive
30
+ </Link>
31
+ .
32
+ </p>
33
+
34
+ <div className="border-border divide-border divide-y rounded-lg border">
35
+ {changes?.map((change) => (
36
+ <Link
37
+ key={change.id}
38
+ to="/changes/$changeId"
39
+ params={{ changeId: change.id }}
40
+ className="hover:bg-muted/50 flex items-center justify-between p-4"
41
+ >
42
+ <div className="flex items-center gap-3">
43
+ <GitBranch className="text-muted-foreground h-5 w-5" />
44
+ <div>
45
+ <div className="font-medium">{change.name}</div>
46
+ <div className="text-muted-foreground text-sm">
47
+ {change.progress.completed}/{change.progress.total} tasks
48
+ {change.updatedAt > 0 && <> · {formatRelativeTime(change.updatedAt)}</>}
49
+ </div>
50
+ </div>
51
+ </div>
52
+ <ChevronRight className="text-muted-foreground h-4 w-4" />
53
+ </Link>
54
+ ))}
55
+ {changes?.length === 0 && (
56
+ <div className="text-muted-foreground p-4 text-center">
57
+ No active changes. Create one in <code>openspec/changes/</code>
58
+ </div>
59
+ )}
60
+ </div>
61
+ </div>
62
+ )
63
+ }