@bkm016/basalt 0.0.0-stage → 0.1.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 (252) hide show
  1. package/README.md +275 -2
  2. package/chunk-0hbjv3y6.js +11 -0
  3. package/chunk-0rya8cxe.js +3 -0
  4. package/chunk-0szjy61m.js +2 -0
  5. package/chunk-0tdv0t5q.js +3 -0
  6. package/chunk-1egbcp85.js +59 -0
  7. package/chunk-1fv27j4b.js +3 -0
  8. package/chunk-1yzt0qm0.js +2 -0
  9. package/chunk-2zqny2sy.js +2 -0
  10. package/chunk-32at88hc.js +3 -0
  11. package/chunk-356q8e0y.js +10 -0
  12. package/chunk-3jz9g8ab.js +10 -0
  13. package/chunk-3p7q2pyp.js +3 -0
  14. package/chunk-501zkf9b.js +3 -0
  15. package/chunk-58vz2qsq.js +2 -0
  16. package/chunk-5fdgy0q2.js +16 -0
  17. package/chunk-5wp4egky.js +7 -0
  18. package/chunk-665jzf2w.js +25 -0
  19. package/chunk-6gyhajhx.js +3 -0
  20. package/chunk-7yw8aa5j.js +31 -0
  21. package/chunk-8wjgbd9k.js +3 -0
  22. package/chunk-913tfr9c.js +2 -0
  23. package/chunk-97kjn55j.js +2 -0
  24. package/chunk-9y69ywyg.js +3 -0
  25. package/chunk-a6r4z44b.js +2 -0
  26. package/chunk-agntrqs9.js +2 -0
  27. package/chunk-b9bg5fhd.js +2 -0
  28. package/chunk-bj14jshr.js +3 -0
  29. package/chunk-c25s4w6a.js +5 -0
  30. package/chunk-d48bfd2e.js +3 -0
  31. package/chunk-d913kpyw.js +3 -0
  32. package/chunk-dakrpbe6.js +3 -0
  33. package/chunk-g2k3yhgh.js +12 -0
  34. package/chunk-hat3s3pr.js +3 -0
  35. package/chunk-hcn9cf6v.js +2 -0
  36. package/chunk-j2x0g1vg.js +2 -0
  37. package/chunk-k0t23cmx.js +2 -0
  38. package/chunk-k7w7ac9q.js +18 -0
  39. package/chunk-kgdrjqsy.js +3 -0
  40. package/chunk-kjr81mrd.js +9 -0
  41. package/chunk-m38ber71.js +2 -0
  42. package/chunk-n6e43rvk.js +3 -0
  43. package/chunk-qbf8x2ft.js +5 -0
  44. package/chunk-qcwnkr5y.js +2 -0
  45. package/chunk-qffb7een.js +3 -0
  46. package/chunk-qnr1f5pj.js +3 -0
  47. package/chunk-r9aatvwm.js +3 -0
  48. package/chunk-rad3dm0q.js +2 -0
  49. package/chunk-rjdhaasf.js +3 -0
  50. package/chunk-rm3kcxq9.js +20 -0
  51. package/chunk-rv06x0kn.js +7 -0
  52. package/chunk-sf13azm4.js +12 -0
  53. package/chunk-sytpmbfp.js +471 -0
  54. package/chunk-t057xfrt.js +5 -0
  55. package/chunk-tjpvayr1.js +2 -0
  56. package/chunk-tnrqkc7b.js +8 -0
  57. package/chunk-v9fea96h.js +3 -0
  58. package/chunk-ve7qx8wm.js +3 -0
  59. package/chunk-vkkj4awb.js +2 -0
  60. package/chunk-wc5j0hfw.js +39 -0
  61. package/chunk-wd9zxhza.js +2 -0
  62. package/chunk-wx7kdf0b.js +2 -0
  63. package/chunk-x9982ek7.js +25 -0
  64. package/chunk-xhk54h2q.js +7 -0
  65. package/chunk-xsbxykr4.js +2 -0
  66. package/chunk-y69ewdn2.js +3 -0
  67. package/chunk-y8ced1jm.js +5 -0
  68. package/chunk-y9xe9ct2.js +2 -0
  69. package/chunk-yb1jxgnk.js +2 -0
  70. package/chunk-zt1wvkyf.js +3 -0
  71. package/compiled.js +3773 -0
  72. package/icon-dp9pmcvp.png +0 -0
  73. package/package.json +20 -4
  74. package/ui-test-worker.js +226 -0
  75. package/web/KaTeX_AMS-Regular-n7eqehx2.woff2 +0 -0
  76. package/web/KaTeX_Caligraphic-Bold-20r3b6fv.woff2 +0 -0
  77. package/web/KaTeX_Caligraphic-Regular-kkjm8f18.woff2 +0 -0
  78. package/web/KaTeX_Fraktur-Bold-pz5vg4t0.woff2 +0 -0
  79. package/web/KaTeX_Fraktur-Regular-a1e9wkwk.woff2 +0 -0
  80. package/web/KaTeX_Main-Bold-mcp098h8.woff2 +0 -0
  81. package/web/KaTeX_Main-BoldItalic-fy74z249.woff2 +0 -0
  82. package/web/KaTeX_Main-Italic-hw2gxy7f.woff2 +0 -0
  83. package/web/KaTeX_Main-Regular-xvp1b75c.woff2 +0 -0
  84. package/web/KaTeX_Math-BoldItalic-mf5nf33d.woff2 +0 -0
  85. package/web/KaTeX_Math-Italic-ap60jrna.woff2 +0 -0
  86. package/web/KaTeX_SansSerif-Bold-we3bymb6.woff2 +0 -0
  87. package/web/KaTeX_SansSerif-Italic-ent92bjx.woff2 +0 -0
  88. package/web/KaTeX_SansSerif-Regular-0573pbz9.woff2 +0 -0
  89. package/web/KaTeX_Script-Regular-z2rtj6vq.woff2 +0 -0
  90. package/web/KaTeX_Size1-Regular-dfr3w1hv.woff2 +0 -0
  91. package/web/KaTeX_Size2-Regular-kted78zb.woff2 +0 -0
  92. package/web/KaTeX_Size3-Regular-e6k1k5jk.woff2 +0 -0
  93. package/web/KaTeX_Size4-Regular-abedc1pd.woff2 +0 -0
  94. package/web/KaTeX_Typewriter-Regular-scw9zx1z.woff2 +0 -0
  95. package/web/apple-touch-icon-7dkm33qp.png +0 -0
  96. package/web/apple-touch-icon.png +0 -0
  97. package/web/chunk-00mq7bhx.js +1 -0
  98. package/web/chunk-0atfn8jf.js +1 -0
  99. package/web/chunk-0k0hvh59.js +40 -0
  100. package/web/chunk-0mrkjnte.js +1 -0
  101. package/web/chunk-0pbjgdgp.js +2 -0
  102. package/web/chunk-0s80zw00.js +1 -0
  103. package/web/chunk-0xck277j.js +140 -0
  104. package/web/chunk-1t760bg0.js +1 -0
  105. package/web/chunk-1v3d60pp.js +217 -0
  106. package/web/chunk-1x8fn8w9.js +1 -0
  107. package/web/chunk-20q90epj.js +2 -0
  108. package/web/chunk-24mfx6w1.js +2 -0
  109. package/web/chunk-29e1trsq.js +78 -0
  110. package/web/chunk-2j4m0bh1.js +2 -0
  111. package/web/chunk-310yey4q.js +1 -0
  112. package/web/chunk-32ezm0ry.js +1136 -0
  113. package/web/chunk-3ahpr030.js +2 -0
  114. package/web/chunk-3bqh2dkw.js +7 -0
  115. package/web/chunk-3cfabjey.js +370 -0
  116. package/web/chunk-3hvgs5aw.js +1 -0
  117. package/web/chunk-3kh6zefg.js +1 -0
  118. package/web/chunk-3pf33xsm.js +98 -0
  119. package/web/chunk-3pm4645m.js +2 -0
  120. package/web/chunk-401v5ht6.js +8 -0
  121. package/web/chunk-4b5mt5pd.js +70 -0
  122. package/web/chunk-4gavbw65.js +1 -0
  123. package/web/chunk-4rm1vy7w.js +1 -0
  124. package/web/chunk-4wd9r73y.js +1 -0
  125. package/web/chunk-4y2td14d.js +24 -0
  126. package/web/chunk-54thej0t.js +2 -0
  127. package/web/chunk-55kw67nv.js +1 -0
  128. package/web/chunk-59kqahb3.js +1 -0
  129. package/web/chunk-5hex8g0y.js +24 -0
  130. package/web/chunk-5r5kv4gh.js +1 -0
  131. package/web/chunk-6atq9qtt.js +7 -0
  132. package/web/chunk-6beqrmtq.js +1 -0
  133. package/web/chunk-6m69hczt.js +2 -0
  134. package/web/chunk-6r912gfj.js +34 -0
  135. package/web/chunk-74j07k8k.js +2 -0
  136. package/web/chunk-7f0m2yrd.js +169 -0
  137. package/web/chunk-8g239029.js +1 -0
  138. package/web/chunk-942prjb6.js +332 -0
  139. package/web/chunk-95q1bwxn.js +1 -0
  140. package/web/chunk-9s7c178f.js +1 -0
  141. package/web/chunk-9v1f6yc8.js +1 -0
  142. package/web/chunk-a3xt6840.js +38 -0
  143. package/web/chunk-ad6x47yy.js +1 -0
  144. package/web/chunk-b5brnfv9.js +2 -0
  145. package/web/chunk-benmmqt2.js +1 -0
  146. package/web/chunk-bgqdcnke.js +1 -0
  147. package/web/chunk-bhe4jzha.js +1 -0
  148. package/web/chunk-bwyw10wx.js +39 -0
  149. package/web/chunk-c85wxnpw.js +292 -0
  150. package/web/chunk-canbct9d.js +55 -0
  151. package/web/chunk-cg3jterp.js +2 -0
  152. package/web/chunk-d18r4m14.js +141 -0
  153. package/web/chunk-d4d3mnak.js +84 -0
  154. package/web/chunk-dmqtdeb4.js +1 -0
  155. package/web/chunk-dy2gm1fs.js +1 -0
  156. package/web/chunk-e5rmr47n.js +2 -0
  157. package/web/chunk-ea9swkkt.js +1 -0
  158. package/web/chunk-ejd43q75.js +19 -0
  159. package/web/chunk-eqegxtdt.js +1 -0
  160. package/web/chunk-ev1g5cqw.js +2 -0
  161. package/web/chunk-ezyvv4ab.js +3 -0
  162. package/web/chunk-f91wzwtk.js +1 -0
  163. package/web/chunk-fdkp6tzq.js +36 -0
  164. package/web/chunk-g1ev11wx.js +1 -0
  165. package/web/chunk-g9qv15hq.js +41 -0
  166. package/web/chunk-ghxe4gam.js +2 -0
  167. package/web/chunk-gmfp7fg4.js +1 -0
  168. package/web/chunk-gxay64d5.js +1 -0
  169. package/web/chunk-gxn0bey7.js +142 -0
  170. package/web/chunk-haphmhz8.js +200 -0
  171. package/web/chunk-hejz98gw.js +1 -0
  172. package/web/chunk-hfaffkrh.js +1 -0
  173. package/web/chunk-hp167dbv.js +1 -0
  174. package/web/chunk-hryhthxr.js +16 -0
  175. package/web/chunk-j2vt8c8v.js +1 -0
  176. package/web/chunk-jg6nzn6q.js +1 -0
  177. package/web/chunk-jtwhjp20.js +303 -0
  178. package/web/chunk-jvhmna7z.js +89 -0
  179. package/web/chunk-ka3q31t1.js +1 -0
  180. package/web/chunk-kbtbbarw.js +2 -0
  181. package/web/chunk-ktqt87qw.js +1 -0
  182. package/web/chunk-kx2xk3bb.js +1 -0
  183. package/web/chunk-m2d1sp30.js +1 -0
  184. package/web/chunk-mdsgekpk.js +1 -0
  185. package/web/chunk-mq92vqb1.js +2 -0
  186. package/web/chunk-n1dmrz44.js +2 -0
  187. package/web/chunk-n5fn9khr.js +1 -0
  188. package/web/chunk-n90cqdvg.js +2 -0
  189. package/web/chunk-nerx2q12.js +139 -0
  190. package/web/chunk-ngpq43vn.js +1 -0
  191. package/web/chunk-nj0cv1cq.js +257 -0
  192. package/web/chunk-nzey7cpv.js +1 -0
  193. package/web/chunk-p8y0hjx9.js +2 -0
  194. package/web/chunk-pxe3vna4.js +1 -0
  195. package/web/chunk-pz934t6t.js +30 -0
  196. package/web/chunk-r1dnh0s8.js +1 -0
  197. package/web/chunk-r5eakmw6.js +1 -0
  198. package/web/chunk-rkesqprv.js +1 -0
  199. package/web/chunk-rsn8j7xv.js +120 -0
  200. package/web/chunk-rtf2zzzv.js +1 -0
  201. package/web/chunk-ry9256r7.js +1 -0
  202. package/web/chunk-rykfak98.js +2 -0
  203. package/web/chunk-rz6wwdd5.js +106 -0
  204. package/web/chunk-s8vapqgr.js +12 -0
  205. package/web/chunk-sc63gh9d.js +2 -0
  206. package/web/chunk-srrfphes.js +1 -0
  207. package/web/chunk-svdzmaxb.js +2 -0
  208. package/web/chunk-svmhj9hd.js +1 -0
  209. package/web/chunk-t6agpn2z.js +1 -0
  210. package/web/chunk-tfyxp2qs.js +89 -0
  211. package/web/chunk-ts7zrf5b.js +2 -0
  212. package/web/chunk-ttg6tbwx.js +2 -0
  213. package/web/chunk-v47rhg7b.js +1 -0
  214. package/web/chunk-v5cnt7c8.js +1 -0
  215. package/web/chunk-v6v831tc.js +214 -0
  216. package/web/chunk-vadqkz3x.js +99 -0
  217. package/web/chunk-vfqdy860.js +1 -0
  218. package/web/chunk-vfqe8298.js +1 -0
  219. package/web/chunk-vqjs551t.js +7 -0
  220. package/web/chunk-wtawdeej.css +1 -0
  221. package/web/chunk-x3zwjkwg.js +62 -0
  222. package/web/chunk-x59p8sg2.js +1 -0
  223. package/web/chunk-x9q4kh67.js +4 -0
  224. package/web/chunk-xet1jjy9.js +1 -0
  225. package/web/chunk-xzp7jf7e.js +2 -0
  226. package/web/chunk-y7z144e3.js +1 -0
  227. package/web/chunk-ydgqrfvw.js +2 -0
  228. package/web/chunk-ydtrc1ay.js +2 -0
  229. package/web/chunk-yj1a2d37.js +1 -0
  230. package/web/chunk-ykxpb3wv.js +2 -0
  231. package/web/chunk-ytpwz01r.js +291 -0
  232. package/web/chunk-z09emmrb.js +1 -0
  233. package/web/chunk-z1jtv4c0.js +2 -0
  234. package/web/chunk-zakv2xdf.js +1 -0
  235. package/web/chunk-zbj1trar.js +2 -0
  236. package/web/chunk-zk2f7x5e.js +4 -0
  237. package/web/icon-192.png +0 -0
  238. package/web/icon-512.png +0 -0
  239. package/web/icon-maskable-512.png +0 -0
  240. package/web/icon-yx2p2pye.svg +13 -0
  241. package/web/icon.svg +13 -0
  242. package/web/index.html +23 -0
  243. package/web/install.ps1 +91 -0
  244. package/web/install.sh +177 -0
  245. package/web/inter-latin-wght-normal-an0py913.woff2 +0 -0
  246. package/web/jetbrains-mono-latin-wght-normal-hj2e42wt.woff2 +0 -0
  247. package/web/manifest-txf6vfbq.webmanifest +35 -0
  248. package/web/manifest.webmanifest +35 -0
  249. package/web/source-serif-4-latin-wght-italic-ta5tqqvz.woff2 +0 -0
  250. package/web/source-serif-4-latin-wght-normal-1yyvbhsz.woff2 +0 -0
  251. package/web/sw.js +90 -0
  252. package/worker.js +2 -0
@@ -0,0 +1,4 @@
1
+ import{z,o,g,i,a,v,t,n,_,V,li,bo,Hi,Mr,tr,xo,Yi,_o,Jr,ea,Pn,ci,ui}from"./chunk-32ezm0ry.js";var M={sealed:"已封存",folded:"已折叠",archived:"已移出"},T=["bg-accent","bg-accent-strong","bg-warning","bg-success"];function P(e,d){if(e.startsWith("recent-"))return"json";let c=d.trimStart();if(!c)return"markdown";if(c.startsWith("{")||c.startsWith("["))return"json";if(/^<[a-zA-Z_][\w.-]*(?:\s+[^>]*)?>/.test(c))return"xml";return"markdown"}function W(e){if(!e||e.length>32000)return e;if(!e.trimStart().startsWith("<"))return e;let c=[],m=0,s=(p)=>" ".repeat(p),l=/(<([a-zA-Z_][\w.-]*)(?:\s+[^>]*)?>([^\r\n<]*)<\/\2>)|(<\/[a-zA-Z_][\w.-]*>)|(<[a-zA-Z_][\w.-]*(?:\s+[^>]*)?\/>)|(<[a-zA-Z_][\w.-]*(?:\s+[^>]*)?>)|([^<]+)/g,u;while((u=l.exec(e))!==null){let[,p,,,f,r,x,y]=u;if(p)c.push(`${s(m)}${p.trim()}`);else if(f)m=Math.max(0,m-1),c.push(`${s(m)}${f.trim()}`);else if(x)c.push(`${s(m)}${x.trim()}`),m++;else if(r)c.push(`${s(m)}${r.trim()}`);else if(y){let h=y.trim();if(h)for(let w of h.split(/\r?\n/)){let E=w.trim();if(E)c.push(`${s(m)}${E}`)}}}return c.length>0?c.join(`
2
+ `):e}function R(){return n("div",{role:"status","aria-busy":"true","aria-label":"正在加载上下文",className:"space-y-2 animate-pulse",children:[t("div",{className:"h-10 rounded-xl border border-line bg-panel/40"}),t("div",{className:"h-10 rounded-xl border border-line bg-panel/40"}),t("div",{className:"h-10 rounded-xl border border-line bg-panel/40"})]})}function k(e){let{style:d}=_();return t("p",{className:d("surface.empty"),children:e.children})}function B(e){let{cn:d}=_();if(!e.items.length)return t(k,{children:"新会话还没有上下文。发送第一条消息后,这里会显示构成。"});let c=e.items.reduce((m,s)=>m+s.tokens,0)||1;return n("div",{className:"space-y-2.5",children:[t("div",{className:"flex h-2 overflow-hidden rounded-full bg-raised",children:e.items.map((m,s)=>t("span",{className:d(T[s%T.length],"transition-[width] duration-300 ease-out-quint"),title:`${m.label}:${m.tokens.toLocaleString()} token`,style:{width:`${m.tokens/c*100}%`}},m.id))}),t("div",{className:"space-y-1.5",children:e.items.map((m,s)=>t(Z,{item:m,total:c,index:s,color:T[s%T.length]??"bg-accent"},m.id))})]})}function Z(e){let{cn:d,Chevron:c,CopyButton:m,Code:s,style:l,useTheme:u}=_();u();let[p,f]=a(!1),r=(e.item.tokens/e.total*100).toFixed(1),x=g(()=>p&&e.item.detail?tr(e.item.detail):"",[p,e.item.detail]),y=g(()=>x?P(e.item.id,x):"markdown",[x,e.item.id]),h=g(()=>{if(!x)return"";return y==="xml"?W(x):x},[x,y]);return n("div",{"data-state":p?"open":"closed",className:l("surface.interactive","group/collapsible"),children:[n("button",{type:"button","aria-expanded":p,onClick:()=>f((w)=>!w),className:"flex w-full items-center gap-2 px-3 py-2 text-left text-xs",children:[t("span",{className:d("size-2 shrink-0 rounded-full",e.color),"aria-hidden":!0}),t("span",{className:"min-w-0 flex-1 truncate font-medium text-ink",children:e.item.label}),e.item.state&&t("span",{className:l("control.badge","text-[10px]"),children:M[e.item.state]}),t("span",{className:"font-mono tabular-nums text-dim",children:e.item.tokens.toLocaleString()}),n("span",{className:"w-10 text-right font-mono text-[11px] tabular-nums text-faint",children:[r,"%"]}),t(c,{className:"-rotate-90 text-faint group-data-[state=open]/collapsible:rotate-90"})]}),p&&n("div",{className:"border-t border-line/60 bg-raised/20 px-3 py-2 text-xs text-dim",children:[t("div",{className:"mb-2 h-1 overflow-hidden rounded-full bg-raised",children:t("div",{className:d("h-full",e.color),style:{width:`${r}%`}})}),h?n("div",{className:l("surface.subtle","group/detail relative overflow-hidden rounded-lg bg-panel/70 p-2.5"),children:[t("div",{className:"absolute right-1.5 top-1.5 z-10",children:t(m,{text:e.item.detail,size:"icon-xs",className:"bg-raised/60 hover:bg-raised text-faint hover:text-ink backdrop-blur-sm"})}),t("div",{className:"max-h-80 overflow-y-auto pr-6 text-dim",children:t(s,{code:h,lang:y,className:"text-[11px]! leading-relaxed! [&_pre]:whitespace-pre-wrap [&_pre]:break-words [&_pre]:[overflow-wrap:anywhere]"})})]}):t("p",{className:"py-2 text-center text-xs text-faint",children:"(空)"})]})]})}var I=40,K={accent:"bg-accent/15 text-accent",success:"bg-success/15 text-success",warning:"bg-warning/15 text-warning",danger:"bg-danger/15 text-danger",neutral:"bg-raised text-dim"};function A(e){let{Button:d,CopyButton:c,style:m,useTheme:s}=_();s();let[l,u]=a(I),p=i(null),f=l<e.entries.length;o(()=>{let x=p.current;if(!x||!f||typeof IntersectionObserver>"u")return;let y=new IntersectionObserver((h)=>{if(h.some((w)=>w.isIntersecting))u((w)=>Math.min(e.entries.length,w+I))},{rootMargin:"480px"});return y.observe(x),()=>y.disconnect()},[f,e.entries.length]);let r=g(()=>e.entries.slice(-l).reverse(),[e.entries,l]);if(!e.entries.length)return t(k,{children:"还没有消息。"});return n("div",{className:"space-y-1.5",children:[n("div",{className:m("surface.subtle","flex items-center justify-between px-3 py-1.5 text-xs text-faint"),children:[n("span",{children:["共 ",e.entries.length," 条记录"]}),t(c,{text:()=>e.entries.map((x)=>JSON.stringify(x,null,2)).join(`
3
+
4
+ `),size:"icon-xs",label:"复制全部原始 JSON",className:"hover:bg-raised text-faint hover:text-ink"})]}),r.map((x)=>t(H,{entry:x},x.seq)),f&&n("div",{ref:p,className:m("surface.subtle","flex items-center justify-between bg-panel/40 px-3 py-2 text-xs text-faint"),children:[n("span",{children:["已显示 ",r.length," / ",e.entries.length," 条"]}),n("div",{className:"flex items-center gap-1.5",children:[t(d,{size:"sm",variant:"ghost",onClick:()=>u((x)=>Math.min(e.entries.length,x+I)),children:"加载更多"}),t(d,{size:"sm",variant:"ghost",onClick:()=>u(e.entries.length),children:"显示全部"})]})]})]})}var H=z(function(d){let{Chevron:c,CopyButton:m,style:s,useTheme:l}=_();l();let[u,p]=a(!1),f=xo(d.entry),r=g(()=>bo(d.entry.time),[d.entry.time]);return n("div",{"data-state":u?"open":"closed",className:s("surface.interactive","group/collapsible"),children:[n("button",{type:"button","aria-expanded":u,onClick:()=>p((x)=>!x),className:"flex w-full items-center gap-2 px-3 py-2 text-left text-xs",children:[n("span",{className:"shrink-0 font-mono text-[10.5px] tabular-nums text-faint",children:["#",d.entry.seq]}),t("span",{className:s("control.badge","shrink-0 font-medium text-[10px]",K[f.tone]),children:f.badge}),t("span",{className:"min-w-0 flex-1 truncate text-ink",children:f.title}),f.meta&&t("span",{className:s("control.badge","shrink-0 font-mono text-[10px] text-faint"),children:f.meta}),t("span",{className:"shrink-0 font-mono text-[10.5px] tabular-nums text-faint",children:r}),t(c,{className:"-rotate-90 text-faint group-data-[state=open]/collapsible:rotate-90"})]}),u&&t("div",{className:"border-t border-line/60 bg-raised/20 px-3 py-2.5 text-xs text-dim",children:n("div",{className:"space-y-2",children:[n("div",{className:"flex items-center justify-between text-[11px] text-faint",children:[n("span",{className:"font-mono",children:[d.entry.type," · #",d.entry.seq]}),t(m,{text:()=>JSON.stringify(d.entry,null,2),size:"icon-xs",label:"复制此条 JSON",className:"bg-raised/60 hover:bg-raised text-faint hover:text-ink"})]}),t(X,{entry:d.entry})]})})]})});function X(e){let{Code:d,style:c,useTheme:m}=_();m();let s=e.entry;if(s.type==="user")return n("div",{className:"space-y-2",children:[s.text&&t("pre",{className:c("surface.subtle","max-h-72 overflow-y-auto p-2.5 font-sans text-xs leading-relaxed text-ink whitespace-pre-wrap break-words [overflow-wrap:anywhere]"),children:Mr(s.text)}),s.attachments&&s.attachments.length>0&&n("div",{className:"space-y-1",children:[n("div",{className:"text-[10.5px] font-medium text-faint",children:["附件(",s.attachments.length,")"]}),t("div",{className:"flex flex-wrap gap-1.5",children:s.attachments.map((l,u)=>{let p=l.kind==="image"?Math.floor(l.data.length*0.75):l.data.length;return n("div",{className:c("surface.subtle","inline-flex items-center gap-1.5 px-2 py-1 text-[11px]"),children:[t("span",{className:c("control.badge","text-[10px] text-faint"),children:l.kind==="image"?"图片":l.kind==="path"?"路径":"文本"}),t("span",{className:"max-w-40 truncate font-medium text-ink",children:l.name}),n("span",{className:"font-mono text-[10px] text-faint",children:[l.mimeType," · ",Hi(p)]})]},`${l.name}-${u}`)})})]}),s.notices&&s.notices.length>0&&n("div",{className:"space-y-1",children:[n("div",{className:"text-[10.5px] font-medium text-faint",children:["通知来源(",s.notices.length,")"]}),s.notices.map((l)=>n("div",{className:c("surface.subtle","flex items-center justify-between px-2.5 py-1.5 font-mono text-[11px]"),children:[n("span",{className:"truncate text-ink",children:[l.sourceKind,"/",l.sourceID]}),t("span",{className:"text-faint",children:l.state})]},l.dedupeKey))]})]});if(s.type==="assistant")return n("div",{className:"space-y-2",children:[n("div",{className:"font-mono text-[11px] text-faint",children:["模型:",s.model]}),s.error&&t("div",{className:"rounded-lg border border-danger/30 bg-danger/8 px-2.5 py-2 text-xs text-danger",children:s.error}),s.parts.map((l,u)=>{if(l.type==="thinking")return n("div",{className:c("surface.subtle","p-2.5 space-y-1"),children:[t("div",{className:"text-[10.5px] font-medium text-faint",children:"思考"}),t("pre",{className:"max-h-60 overflow-y-auto font-sans text-xs italic leading-relaxed text-dim whitespace-pre-wrap break-words [overflow-wrap:anywhere]",children:Mr(l.text)})]},`thinking-${u}`);if(l.type==="text")return n("div",{className:c("surface.subtle","p-2.5 space-y-1"),children:[t("div",{className:"text-[10.5px] font-medium text-faint",children:"回复"}),t("pre",{className:"max-h-60 overflow-y-auto font-sans text-xs leading-relaxed text-ink whitespace-pre-wrap break-words [overflow-wrap:anywhere]",children:Mr(l.text)})]},`text-${u}`);return n("div",{className:c("surface.subtle","p-2.5 space-y-1.5"),children:[n("div",{className:"flex items-center justify-between gap-2 text-[11px]",children:[n("span",{className:"font-mono font-medium text-ink",children:["工具调用 · ",l.name]}),t("span",{className:"truncate font-mono text-[10px] text-faint",children:l.id})]}),t("div",{className:"max-h-60 overflow-y-auto text-dim",children:t(d,{code:tr(JSON.stringify(l.input,Yi,2)),lang:"json",className:"text-[11px]! leading-relaxed! [&_pre]:whitespace-pre-wrap [&_pre]:break-words [&_pre]:[overflow-wrap:anywhere]"})})]},l.id||`tool-${u}`)})]});if(s.type==="tool_result")return n("div",{className:"space-y-2",children:[n("div",{className:"flex flex-wrap items-center gap-2 font-mono text-[11px] text-faint",children:[t("span",{className:"text-ink",children:s.name}),t("span",{children:"·"}),t("span",{className:"truncate",children:s.callID}),t("span",{className:c("control.badge","ml-auto font-sans text-[10px]",s.isError?"bg-danger/15 text-danger":"text-dim"),children:s.isError?"执行失败":"执行完成"})]}),s.images&&s.images.length>0&&t("div",{className:"flex flex-wrap gap-1.5",children:s.images.map((l,u)=>n("span",{className:c("surface.subtle","px-2 py-1 font-mono text-[10.5px] text-faint"),children:["图片 #",u+1," · ",l.mimeType," · ",Hi(Math.floor(l.data.length*0.75))]},`${l.mimeType}-${u}`))}),li(s.output)?t("pre",{className:c("surface.subtle","max-h-72 overflow-y-auto p-2.5 font-mono text-[11px] leading-relaxed whitespace-pre-wrap break-words [overflow-wrap:anywhere]",s.isError?"text-danger":"text-dim"),children:Mr(s.output)}):t("p",{className:"py-1 text-faint",children:"(无文本输出)"})]});return t("pre",{className:c("surface.subtle","max-h-72 overflow-y-auto p-2.5 font-mono text-[11px] leading-relaxed text-dim whitespace-pre-wrap break-words [overflow-wrap:anywhere]"),children:_o(s)})}function L(e){let{cn:d,style:c,useTheme:m}=_();if(m(),!e.todos.length)return t(k,{children:"暂无待办。"});return t("ul",{className:"space-y-1.5",children:e.todos.map((s)=>n("li",{className:c("surface.interactive","flex items-start gap-2.5 px-3 py-2 text-xs"),children:[n("span",{className:d("mt-0.5 flex size-4 shrink-0 items-center justify-center rounded-full border transition-colors duration-300",s.status==="completed"&&"border-success bg-success text-panel",s.status==="in_progress"&&"border-accent",s.status==="pending"&&"border-line-strong"),children:[s.status==="completed"&&t(V,{className:"size-2.5 animate-pop",strokeWidth:3.5}),s.status==="in_progress"&&t("span",{className:"size-1.5 animate-pulse rounded-full bg-accent"})]}),t("span",{className:d("min-w-0 flex-1 break-words leading-relaxed [overflow-wrap:anywhere]",s.status==="completed"&&"text-faint line-through decoration-faint/60",s.status==="in_progress"&&"font-medium text-ink",s.status==="pending"&&"text-dim"),children:s.content})]},`${s.status}-${s.content}`))})}function O(e){let{cn:d,style:c,useTheme:m}=_();m();let[s,l]=a("all"),u=g(()=>e.tools.filter((r)=>r.deferred).length,[e.tools]),p=e.tools.length-u,f=g(()=>{if(s==="deferred")return e.tools.filter((r)=>r.deferred);if(s==="active")return e.tools.filter((r)=>!r.deferred);return e.tools},[e.tools,s]);if(!e.tools.length)return t(k,{children:"当前会话没有可用工具。"});return n("div",{className:"space-y-2",children:[u>0&&n("div",{className:"flex items-center gap-1 text-[11px]",children:[n("button",{type:"button",onClick:()=>l("all"),className:d("rounded-lg px-2 py-1 transition-colors",s==="all"?"bg-raised font-medium text-ink":"text-faint hover:text-dim"),children:["全部 (",e.tools.length,")"]}),n("button",{type:"button",onClick:()=>l("active"),className:d("rounded-lg px-2 py-1 transition-colors",s==="active"?"bg-raised font-medium text-ink":"text-faint hover:text-dim"),children:["常驻 (",p,")"]}),n("button",{type:"button",onClick:()=>l("deferred"),className:d("rounded-lg px-2 py-1 transition-colors",s==="deferred"?"bg-raised font-medium text-ink":"text-faint hover:text-dim"),children:["延迟加载 (",u,")"]})]}),t("div",{className:"space-y-1.5",children:f.map((r)=>t(G,{tool:r},`${r.group}-${r.name}`))})]})}function G(e){let{Chevron:d,CopyButton:c,Code:m,style:s,useTheme:l}=_();l();let[u,p]=a(!1),f=g(()=>u?JSON.stringify(e.tool.schema,null,2):"",[u,e.tool.schema]);return n("div",{"data-state":u?"open":"closed",className:s("surface.interactive","group/collapsible"),children:[n("button",{type:"button","aria-expanded":u,onClick:()=>p((r)=>!r),className:"flex w-full items-center justify-between px-3 py-2 text-left text-xs",children:[n("div",{className:"flex min-w-0 flex-1 items-center gap-1.5 truncate font-mono text-ink",children:[t("span",{className:"truncate",children:e.tool.name}),e.tool.group&&t("span",{className:s("control.badge","font-sans text-[10px]"),children:e.tool.group}),e.tool.deferred&&t("span",{className:s("control.badge","font-sans text-[10px]"),children:"延迟加载"})]}),t(d,{className:"-rotate-90 text-faint group-data-[state=open]/collapsible:rotate-90"})]}),u&&n("div",{className:"border-t border-line/60 bg-raised/20 px-3 py-2 text-xs text-dim",children:[e.tool.deferred&&t("div",{className:s("surface.subtle","mb-2 px-2.5 py-1.5 text-[11px] text-faint"),children:"延迟加载:此工具默认以精简描述挂载,模型通过 toolsearch 取回定义后才向上下文注入完整参数 Schema。"}),e.tool.description&&t("pre",{className:"mb-2 max-h-60 overflow-y-auto font-sans text-xs leading-relaxed text-dim whitespace-pre-wrap break-words [overflow-wrap:anywhere]",children:tr(e.tool.description)}),n("div",{className:s("surface.subtle","group/schema relative overflow-hidden rounded-lg p-2.5"),children:[t("div",{className:"absolute right-1.5 top-1.5 z-10",children:t(c,{text:f,size:"icon-xs",className:"bg-raised/60 hover:bg-raised text-faint hover:text-ink backdrop-blur-sm"})}),t("div",{className:"max-h-72 overflow-y-auto pr-6 text-dim",children:t(m,{code:tr(f),lang:"json",className:"text-[11px]! leading-relaxed! [&_pre]:whitespace-pre-wrap [&_pre]:break-words [&_pre]:[overflow-wrap:anywhere]"})})]})]})]})}function Q(){try{let e=localStorage.getItem("basalt.contextSidebar.tab");if(e==="tools"||e==="todos"||e==="raw")return e}catch{}return"breakdown"}function Y(e){let{style:d,useTheme:c}=_();return c(),n("div",{className:d("surface.panel","bg-panel/70 px-3 py-2"),children:[t("div",{className:"text-[10px] font-medium uppercase tracking-wider text-faint",children:e.label}),t("div",{className:"mt-0.5 truncate font-mono text-xs font-semibold tabular-nums text-ink",children:e.value})]})}function Pe(e){let{Button:d,StatusChip:c,Segmented:m,cn:s,style:l,useTheme:u}=_();u();let[p,f]=a(Q),[r,x]=a(()=>Pn.get(e.session.id)),[y,h]=a(!1),[w,E]=a(0),[D,j]=a(!1);o(()=>{let b=setTimeout(()=>j(!0),140);return()=>clearTimeout(b)},[]),o(()=>{let b=Pn.get(e.session.id);if(b)x(b);return ci((C,F)=>{if(C===e.session.id)x(F)})},[e.session.id]),o(()=>{let b=new AbortController;return h(!1),e.connection.request(`/api/sessions/${encodeURIComponent(e.session.id)}/context`,{signal:AbortSignal.any([b.signal,AbortSignal.timeout(15000)])}).then((C)=>{if(!b.signal.aborted)ui(e.session.id,C),x(C)},()=>{if(!b.signal.aborted)h(!0)}),()=>b.abort()},[e.connection,e.session.id,e.session.updated,e.entries.length,w]);let N=Jr(r?.items??[],r?.usableWindow,r?.calibratedTokens,r?.lastInputTokens,r?.hasPendingOutput),S=ea(N.percent),U=(b)=>{f(b);try{localStorage.setItem("basalt.contextSidebar.tab",b)}catch{}},J=[{value:"breakdown",label:"构成"},{value:"tools",label:n("span",{className:"inline-flex items-center gap-1",children:["工具",r&&t("span",{className:"text-[10px] text-faint tabular-nums",children:r.tools.length})]})},{value:"todos",label:n("span",{className:"inline-flex items-center gap-1",children:["待办",e.session.todos.length>0&&t("span",{className:"text-[10px] text-faint tabular-nums",children:e.session.todos.length})]})},{value:"raw",label:"原始消息"}],q=n("div",{className:"border-b border-line px-3.5 py-3",children:[n("div",{className:"flex items-start justify-between gap-3",children:[n("div",{children:[t("div",{className:"text-[10.5px] font-medium uppercase tracking-wider text-faint",children:"上下文用量"}),n("div",{className:"mt-0.5 flex items-baseline gap-1.5",children:[t("span",{className:"font-mono text-xl font-semibold tabular-nums text-ink",children:r?N.totalTokens.toLocaleString():"—"}),n("span",{className:"font-mono text-xs text-dim",children:["/ ",r?.usableWindow.toLocaleString()??"—"]})]})]}),t(c,{tone:S==="overflow"||S==="near_limit"?"danger":S==="sealing"?"warning":"success",children:S==="overflow"?"预计超限":S==="near_limit"?"接近上限":S==="sealing"?"接近封存":"正常"})]}),N.percent!==null&&t("meter",{className:"sr-only","aria-label":"可用上下文窗口占比",min:0,max:100,value:Math.min(100,N.percent)}),t("div",{"aria-hidden":!0,className:s("relative mt-2.5 h-2 w-full overflow-hidden rounded-full bg-raised",!r&&"animate-pulse"),children:t("div",{className:"h-full rounded-full bg-accent transition-[width] duration-500 ease-out-quint",style:{width:`${Math.min(100,N.percent??0)}%`}})}),n("div",{className:"mt-2 flex items-center justify-between text-[11px]",children:[t("span",{className:"text-dim",children:N.percent===null?"暂无窗口数据":`${N.percent.toFixed(1)}% 可用窗口`}),n("span",{className:"text-faint",children:["总窗口 ",r?.contextWindow.toLocaleString()??"—"," · 80% 封存 · 97% 折叠"]})]}),r?.usage&&(r.usage.input>0||r.usage.output>0||r.usage.cacheRead>0||r.usage.cacheWrite>0||r.usage.cost>0)&&t("div",{className:"mt-3 grid grid-cols-2 gap-2",children:[["Input",r.usage.input.toLocaleString()],["Output",r.usage.output.toLocaleString()],["Cache",`${r.usage.cacheRead.toLocaleString()} / ${r.usage.cacheWrite.toLocaleString()}`],["平均 TPS",r.usage.tps!==void 0?`${r.usage.tps.toFixed(1)} tok/s`:"—"]].map(([b,C])=>t(Y,{label:b,value:C},b))})]});return n(v,{children:[q,t("div",{className:"border-b border-line px-3 py-2",children:t(m,{value:p,onChange:U,options:J,className:"w-full grid grid-cols-4"})}),n("div",{className:"min-h-0 flex-1 overflow-y-auto px-3 py-3",children:[y&&!r&&n("div",{role:"alert",className:"flex items-center justify-between rounded-xl border border-danger/30 bg-danger/8 px-3 py-2 text-xs text-danger",children:[t("span",{children:"上下文加载失败。"}),t(d,{size:"sm",variant:"ghost",onClick:()=>E((b)=>b+1),children:"重试"})]}),t("div",{children:!D?t(R,{}):n(v,{children:[p==="raw"&&t(A,{entries:e.entries}),p==="todos"&&t(L,{todos:e.session.todos}),p==="breakdown"&&(r?t(B,{items:N.items}):!y?t(R,{}):null),p==="tools"&&(r?t(O,{tools:r.tools??[]}):!y?t(R,{}):null)]})},p)]})]})}export{Pe as ContextSidebar};
Binary file
Binary file
Binary file
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="none">
2
+ <title>Basalt</title>
3
+ <style>
4
+ .a { fill: #2D343A } .b { fill: #4C525A } .c { fill: #22272A }
5
+ @media (prefers-color-scheme: dark) { .a { fill: #AAB2B9 } .b { fill: #DFE3E6 } .c { fill: #858E96 } }
6
+ </style>
7
+ <g transform="translate(-566 -72)">
8
+ <path class="a" d="M608 369 641 220Q644 201 661 192L802 124Q819 115 836 124L949 181Q956 184 952 192L897 302Q895 307 890 312L806 387Q802 391 797 394L677 463Q672 467 668 462L618 400Q605 386 608 369Z"/>
9
+ <path class="b" d="M967 198Q969 192 975 195L1015 217Q1028 224 1029 239L1031 300Q1031 306 1025 306H922Q914 306 918 298Z"/>
10
+ <path class="c" d="M908 321H1028Q1034 321 1034 327L1035 394Q1036 405 1029 414L927 530Q922 536 917 530L822 404Q818 398 824 393L901 324Q904 321 908 321Z"/>
11
+ <path class="c" d="M800 410Q805 406 809 411L899 529Q903 536 896 537H748Q729 537 718 524L686 486Q681 479 689 475Z"/>
12
+ </g>
13
+ </svg>
package/web/icon.svg ADDED
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="none">
2
+ <title>Basalt</title>
3
+ <style>
4
+ .a { fill: #2D343A } .b { fill: #4C525A } .c { fill: #22272A }
5
+ @media (prefers-color-scheme: dark) { .a { fill: #AAB2B9 } .b { fill: #DFE3E6 } .c { fill: #858E96 } }
6
+ </style>
7
+ <g transform="translate(-566 -72)">
8
+ <path class="a" d="M608 369 641 220Q644 201 661 192L802 124Q819 115 836 124L949 181Q956 184 952 192L897 302Q895 307 890 312L806 387Q802 391 797 394L677 463Q672 467 668 462L618 400Q605 386 608 369Z"/>
9
+ <path class="b" d="M967 198Q969 192 975 195L1015 217Q1028 224 1029 239L1031 300Q1031 306 1025 306H922Q914 306 918 298Z"/>
10
+ <path class="c" d="M908 321H1028Q1034 321 1034 327L1035 394Q1036 405 1029 414L927 530Q922 536 917 530L822 404Q818 398 824 393L901 324Q904 321 908 321Z"/>
11
+ <path class="c" d="M800 410Q805 406 809 411L899 529Q903 536 896 537H748Q729 537 718 524L686 486Q681 479 689 475Z"/>
12
+ </g>
13
+ </svg>
package/web/index.html ADDED
@@ -0,0 +1,23 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content" />
6
+ <meta name="theme-color" content="#1d1f21" media="(prefers-color-scheme: dark)" />
7
+ <meta name="theme-color" content="#f9f9f8" media="(prefers-color-scheme: light)" />
8
+ <meta name="mobile-web-app-capable" content="yes" />
9
+ <meta name="apple-mobile-web-app-capable" content="yes" />
10
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
11
+ <meta name="apple-mobile-web-app-title" content="Basalt" />
12
+ <base href="/" />
13
+ <title>Basalt</title>
14
+ <link rel="manifest" href="/manifest.webmanifest" />
15
+ <link rel="icon" href="./icon-yx2p2pye.svg" type="image/svg+xml" />
16
+ <link rel="apple-touch-icon" href="./apple-touch-icon-7dkm33qp.png" />
17
+
18
+ <link rel="stylesheet" crossorigin href="./chunk-wtawdeej.css"><script type="module" crossorigin src="./chunk-32ezm0ry.js"></script></head>
19
+ <body>
20
+ <div id="root"></div>
21
+
22
+ </body>
23
+ </html>
@@ -0,0 +1,91 @@
1
+ # Basalt 一键安装(Windows):
2
+ # irm https://basalt.work/install.ps1 | iex
3
+ #
4
+ # 可选环境变量(在同一个 PowerShell 窗口里先设置):
5
+ # $env:BASALT_VERSION = "0.2.0" 安装指定版本(默认最新)
6
+ # $env:BASALT_INSTALL_DIR = "<目录>" 安装位置(默认 %LOCALAPPDATA%\Programs\Basalt)
7
+ # $env:BASALT_AUTOSTART = "1" 登录后自动启动
8
+ # $env:BASALT_NO_START = "1" 装完不启动
9
+ # $env:BASALT_DOWNLOAD_URL = "<地址>" 从镜像下载(目录里要有发布产物和 SHA256SUMS)
10
+ $ErrorActionPreference = "Stop"
11
+ $ProgressPreference = "SilentlyContinue" # 进度条会让 Invoke-WebRequest 慢几十倍
12
+
13
+ $Repo = "Bkm016/Basalt"
14
+ $Asset = "basalt-windows-x64.exe"
15
+ $InstallDir = if ($env:BASALT_INSTALL_DIR) { $env:BASALT_INSTALL_DIR } else { Join-Path $env:LOCALAPPDATA "Programs\Basalt" }
16
+ $Exe = Join-Path $InstallDir "basalt.exe"
17
+
18
+ if (-not [Environment]::Is64BitOperatingSystem) { throw "Basalt 只支持 64 位 Windows" }
19
+ # 旧版 PowerShell 默认不启用 TLS 1.2,连不上 GitHub
20
+ [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
21
+
22
+ $Base = if ($env:BASALT_DOWNLOAD_URL) {
23
+ $env:BASALT_DOWNLOAD_URL.TrimEnd('/')
24
+ } elseif ($env:BASALT_VERSION) {
25
+ "https://github.com/$Repo/releases/download/v$($env:BASALT_VERSION.TrimStart('v'))"
26
+ } else {
27
+ "https://github.com/$Repo/releases/latest/download"
28
+ }
29
+
30
+ $Temp = Join-Path ([IO.Path]::GetTempPath()) ("basalt-" + [Guid]::NewGuid())
31
+ New-Item -ItemType Directory -Force $Temp | Out-Null
32
+ try {
33
+ Write-Host "下载 $Asset ..."
34
+ Invoke-WebRequest -UseBasicParsing "$Base/$Asset" -OutFile (Join-Path $Temp $Asset)
35
+ Invoke-WebRequest -UseBasicParsing "$Base/SHA256SUMS" -OutFile (Join-Path $Temp "SHA256SUMS")
36
+
37
+ $Expected = Get-Content (Join-Path $Temp "SHA256SUMS") |
38
+ ForEach-Object { $Parts = $_ -split '\s+\*?'; if ($Parts[1] -eq $Asset) { $Parts[0] } } |
39
+ Select-Object -First 1
40
+ $Actual = (Get-FileHash -Algorithm SHA256 (Join-Path $Temp $Asset)).Hash
41
+ if (-not $Expected -or $Expected -ne $Actual.ToLower()) { throw "$Asset 校验失败,已停止安装" }
42
+
43
+ New-Item -ItemType Directory -Force $InstallDir | Out-Null
44
+ # 正在运行的 exe 不能覆盖但能改名:旧版本挪开,新版本启动后会删掉它
45
+ if (Test-Path $Exe) {
46
+ $Old = Join-Path $InstallDir "basalt.old.exe"
47
+ Remove-Item -Force -ErrorAction SilentlyContinue $Old
48
+ Move-Item -Force $Exe $Old
49
+ }
50
+ Move-Item -Force (Join-Path $Temp $Asset) $Exe
51
+ } finally {
52
+ Remove-Item -Recurse -Force -ErrorAction SilentlyContinue $Temp
53
+ }
54
+ Write-Host "已安装 Basalt 到 $Exe"
55
+
56
+ # ---------- PATH ----------
57
+
58
+ $UserPath = [Environment]::GetEnvironmentVariable("Path", "User")
59
+ if (-not (($UserPath -split ';') -contains $InstallDir)) {
60
+ [Environment]::SetEnvironmentVariable("Path", (@($UserPath, $InstallDir) | Where-Object { $_ }) -join ';', "User")
61
+ $env:Path = "$env:Path;$InstallDir"
62
+ Write-Host "已把 $InstallDir 加入用户 PATH,新开终端后可直接运行 basalt"
63
+ }
64
+
65
+ # ---------- 快捷方式 ----------
66
+
67
+ function New-Shortcut($Path) {
68
+ $Shell = New-Object -ComObject WScript.Shell
69
+ $Link = $Shell.CreateShortcut($Path)
70
+ $Link.TargetPath = $Exe
71
+ $Link.WorkingDirectory = $InstallDir
72
+ $Link.Description = "Basalt"
73
+ $Link.Save()
74
+ }
75
+ $Programs = [Environment]::GetFolderPath("Programs")
76
+ New-Shortcut (Join-Path $Programs "Basalt.lnk")
77
+ Write-Host "已添加开始菜单快捷方式"
78
+ if ($env:BASALT_AUTOSTART) {
79
+ New-Shortcut (Join-Path ([Environment]::GetFolderPath("Startup")) "Basalt.lnk")
80
+ Write-Host "已设置登录后自动启动"
81
+ }
82
+
83
+ # ---------- 启动 ----------
84
+
85
+ if ($env:BASALT_NO_START) {
86
+ Write-Host "从开始菜单打开 Basalt,或运行 basalt --open"
87
+ return
88
+ }
89
+ # --replace:升级时接替旧版本进程;--open:打开带配对链接的工作台。托盘图标常驻右下角
90
+ Start-Process -FilePath $Exe -ArgumentList "--open", "--replace" -WorkingDirectory $InstallDir
91
+ Write-Host "Basalt 已启动,浏览器会打开工作台;之后可以从托盘图标或开始菜单再次打开。"
package/web/install.sh ADDED
@@ -0,0 +1,177 @@
1
+ #!/bin/sh
2
+ # Basalt 一键安装(Linux / macOS):
3
+ # curl -fsSL https://basalt.work/install.sh | sh
4
+ #
5
+ # 可选环境变量:
6
+ # BASALT_VERSION=0.2.0 安装指定版本(默认最新)
7
+ # BASALT_INSTALL_DIR=<目录> 安装位置(默认 ~/.basalt/bin)
8
+ # BASALT_AUTOSTART=1 登录后自动启动(macOS LaunchAgent / Linux systemd 用户服务)
9
+ # BASALT_NO_START=1 装完不启动
10
+ # BASALT_NO_MODIFY_PATH=1 不改 shell 配置文件
11
+ # BASALT_DOWNLOAD_URL=<地址> 从镜像下载(目录里要有发布产物和 SHA256SUMS)
12
+ set -eu
13
+
14
+ REPO="Bkm016/Basalt"
15
+ INSTALL_DIR="${BASALT_INSTALL_DIR:-$HOME/.basalt/bin}"
16
+ LOG_DIR="$HOME/.basalt"
17
+
18
+ info() { printf '%s\n' "$*"; }
19
+ fail() {
20
+ printf '错误:%s\n' "$*" >&2
21
+ exit 1
22
+ }
23
+
24
+ case "$(uname -s)" in
25
+ Linux) os=linux ;;
26
+ Darwin) os=darwin ;;
27
+ MINGW* | MSYS* | CYGWIN*) fail "Windows 请在 PowerShell 里运行:irm https://basalt.work/install.ps1 | iex" ;;
28
+ *) fail "不支持的系统:$(uname -s)" ;;
29
+ esac
30
+ case "$(uname -m)" in
31
+ x86_64 | amd64) arch=x64 ;;
32
+ arm64 | aarch64) arch=arm64 ;;
33
+ *) fail "不支持的架构:$(uname -m)" ;;
34
+ esac
35
+ # Rosetta 下的终端会报告 x86_64,Apple Silicon 应该装原生版
36
+ if [ "$os" = darwin ] && [ "$arch" = x64 ] && [ "$(sysctl -n sysctl.proc_translated 2> /dev/null || echo 0)" = 1 ]; then
37
+ arch=arm64
38
+ fi
39
+
40
+ asset="basalt-$os-$arch.tar.gz"
41
+ if [ -n "${BASALT_DOWNLOAD_URL:-}" ]; then
42
+ base="${BASALT_DOWNLOAD_URL%/}"
43
+ elif [ -n "${BASALT_VERSION:-}" ]; then
44
+ base="https://github.com/$REPO/releases/download/v${BASALT_VERSION#v}"
45
+ else
46
+ base="https://github.com/$REPO/releases/latest/download"
47
+ fi
48
+
49
+ download() {
50
+ if command -v curl > /dev/null 2>&1; then
51
+ curl -fL --progress-bar -o "$2" "$1"
52
+ elif command -v wget > /dev/null 2>&1; then
53
+ wget -q --show-progress -O "$2" "$1"
54
+ else
55
+ fail "需要 curl 或 wget"
56
+ fi
57
+ }
58
+
59
+ tmp=$(mktemp -d)
60
+ trap 'rm -rf "$tmp"' EXIT
61
+
62
+ info "下载 $asset …"
63
+ download "$base/$asset" "$tmp/$asset" || fail "下载失败:$base/$asset"
64
+ download "$base/SHA256SUMS" "$tmp/SHA256SUMS" || fail "下载校验文件失败"
65
+
66
+ expected=$(awk -v name="$asset" '$2 == name || $2 == "*" name { print $1 }' "$tmp/SHA256SUMS")
67
+ if command -v sha256sum > /dev/null 2>&1; then
68
+ actual=$(sha256sum "$tmp/$asset" | awk '{ print $1 }')
69
+ else
70
+ actual=$(shasum -a 256 "$tmp/$asset" | awk '{ print $1 }')
71
+ fi
72
+ [ -n "$expected" ] && [ "$expected" = "$actual" ] || fail "$asset 校验失败,已停止安装"
73
+
74
+ tar -xzf "$tmp/$asset" -C "$tmp"
75
+ mkdir -p "$INSTALL_DIR"
76
+ # 先放到同一目录再改名:覆盖正在运行的旧版本也不会损坏它
77
+ mv "$tmp/basalt" "$INSTALL_DIR/.basalt.new"
78
+ chmod 755 "$INSTALL_DIR/.basalt.new"
79
+ mv "$INSTALL_DIR/.basalt.new" "$INSTALL_DIR/basalt"
80
+ bin="$INSTALL_DIR/basalt"
81
+ info "已安装 Basalt $("$bin" --version) 到 $bin"
82
+
83
+ # ---------- PATH ----------
84
+
85
+ if [ -z "${BASALT_NO_MODIFY_PATH:-}" ]; then
86
+ case ":$PATH:" in
87
+ *":$INSTALL_DIR:"*) ;;
88
+ *)
89
+ line="export PATH=\"$INSTALL_DIR:\$PATH\""
90
+ case "$(basename "${SHELL:-sh}")" in
91
+ zsh) rc="${ZDOTDIR:-$HOME}/.zshrc" ;;
92
+ bash) [ "$os" = darwin ] && rc="$HOME/.bash_profile" || rc="$HOME/.bashrc" ;;
93
+ fish)
94
+ rc="$HOME/.config/fish/conf.d/basalt.fish"
95
+ line="fish_add_path \"$INSTALL_DIR\""
96
+ mkdir -p "$(dirname "$rc")"
97
+ ;;
98
+ *) rc="$HOME/.profile" ;;
99
+ esac
100
+ if ! grep -qsF "$line" "$rc"; then
101
+ printf '\n# Basalt\n%s\n' "$line" >> "$rc"
102
+ info "已把 $INSTALL_DIR 加入 PATH($rc),新开终端后可直接运行 basalt"
103
+ fi
104
+ ;;
105
+ esac
106
+ fi
107
+
108
+ # ---------- 开机自启 ----------
109
+
110
+ if [ -n "${BASALT_AUTOSTART:-}" ]; then
111
+ mkdir -p "$LOG_DIR"
112
+ if [ "$os" = darwin ]; then
113
+ plist="$HOME/Library/LaunchAgents/work.basalt.plist"
114
+ mkdir -p "$(dirname "$plist")"
115
+ cat > "$plist" << EOF
116
+ <?xml version="1.0" encoding="UTF-8"?>
117
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
118
+ <plist version="1.0">
119
+ <dict>
120
+ <key>Label</key><string>work.basalt</string>
121
+ <key>ProgramArguments</key><array><string>$bin</string></array>
122
+ <key>RunAtLoad</key><true/>
123
+ <key>StandardOutPath</key><string>$LOG_DIR/basalt.log</string>
124
+ <key>StandardErrorPath</key><string>$LOG_DIR/basalt.log</string>
125
+ </dict>
126
+ </plist>
127
+ EOF
128
+ info "已设置登录后自动启动($plist)"
129
+ elif command -v systemctl > /dev/null 2>&1; then
130
+ unit="$HOME/.config/systemd/user/basalt.service"
131
+ mkdir -p "$(dirname "$unit")"
132
+ cat > "$unit" << EOF
133
+ [Unit]
134
+ Description=Basalt
135
+
136
+ [Service]
137
+ ExecStart=$bin
138
+ Restart=on-failure
139
+
140
+ [Install]
141
+ WantedBy=default.target
142
+ EOF
143
+ # 只 enable 不 --now:这次由下面直接启动并打开浏览器,下次登录再由 systemd 接手
144
+ systemctl --user daemon-reload && systemctl --user enable basalt.service > /dev/null 2>&1 &&
145
+ info "已设置登录后自动启动(systemd 用户服务 basalt)" ||
146
+ info "设置 systemd 自启失败,可以稍后手动运行 basalt"
147
+ else
148
+ info "没有 systemd,跳过自动启动设置"
149
+ fi
150
+ fi
151
+
152
+ # ---------- 启动 ----------
153
+
154
+ if [ -n "${BASALT_NO_START:-}" ]; then
155
+ info "运行 basalt --open 启动并打开工作台"
156
+ exit 0
157
+ fi
158
+
159
+ mkdir -p "$LOG_DIR"
160
+ log="$LOG_DIR/basalt.log"
161
+ : > "$log"
162
+ # --replace:升级时接替旧版本进程;--open:打开带配对链接的工作台
163
+ nohup "$bin" --open --replace > "$log" 2>&1 < /dev/null &
164
+ info "正在启动 Basalt …"
165
+ # 没有图形界面(如 SSH)时浏览器打不开,把配对信息打印出来
166
+ i=0
167
+ while [ $i -lt 50 ] && ! grep -qE '配对码|认证已关闭|已在运行' "$log" 2> /dev/null; do
168
+ sleep 0.2
169
+ i=$((i + 1))
170
+ done
171
+ if grep -q '配对码' "$log"; then
172
+ sed -n '/配对码/,$p' "$log"
173
+ info "已在浏览器打开工作台;打不开时访问上面的链接,或在工作台里输入配对码。"
174
+ else
175
+ cat "$log"
176
+ fi
177
+ info "日志:$log"
@@ -0,0 +1,35 @@
1
+ {
2
+ "id": "/",
3
+ "name": "Basalt",
4
+ "short_name": "Basalt",
5
+ "description": "Basalt 工作台",
6
+ "lang": "zh-CN",
7
+ "start_url": "/",
8
+ "scope": "/",
9
+ "display": "standalone",
10
+ "background_color": "#1d1f21",
11
+ "theme_color": "#1d1f21",
12
+ "launch_handler": {
13
+ "client_mode": ["navigate-existing", "auto"]
14
+ },
15
+ "icons": [
16
+ {
17
+ "src": "/icon-192.png",
18
+ "sizes": "192x192",
19
+ "type": "image/png",
20
+ "purpose": "any"
21
+ },
22
+ {
23
+ "src": "/icon-512.png",
24
+ "sizes": "512x512",
25
+ "type": "image/png",
26
+ "purpose": "any"
27
+ },
28
+ {
29
+ "src": "/icon-maskable-512.png",
30
+ "sizes": "512x512",
31
+ "type": "image/png",
32
+ "purpose": "maskable"
33
+ }
34
+ ]
35
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "id": "/",
3
+ "name": "Basalt",
4
+ "short_name": "Basalt",
5
+ "description": "Basalt 工作台",
6
+ "lang": "zh-CN",
7
+ "start_url": "/",
8
+ "scope": "/",
9
+ "display": "standalone",
10
+ "background_color": "#1d1f21",
11
+ "theme_color": "#1d1f21",
12
+ "launch_handler": {
13
+ "client_mode": ["navigate-existing", "auto"]
14
+ },
15
+ "icons": [
16
+ {
17
+ "src": "/icon-192.png",
18
+ "sizes": "192x192",
19
+ "type": "image/png",
20
+ "purpose": "any"
21
+ },
22
+ {
23
+ "src": "/icon-512.png",
24
+ "sizes": "512x512",
25
+ "type": "image/png",
26
+ "purpose": "any"
27
+ },
28
+ {
29
+ "src": "/icon-maskable-512.png",
30
+ "sizes": "512x512",
31
+ "type": "image/png",
32
+ "purpose": "maskable"
33
+ }
34
+ ]
35
+ }
package/web/sw.js ADDED
@@ -0,0 +1,90 @@
1
+ const CACHE_NAME = "basalt-shell-v1"
2
+ const PRECACHE_URLS = ["/", "/manifest.webmanifest", "/icon-192.png", "/icon-512.png", "/icon-maskable-512.png"]
3
+
4
+ self.addEventListener("install", (event) => {
5
+ self.skipWaiting()
6
+ event.waitUntil(
7
+ caches
8
+ .open(CACHE_NAME)
9
+ .then((cache) => cache.addAll(PRECACHE_URLS))
10
+ .catch(() => undefined),
11
+ )
12
+ })
13
+
14
+ self.addEventListener("activate", (event) => {
15
+ event.waitUntil(
16
+ (async () => {
17
+ const keys = await caches.keys()
18
+ await Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key)))
19
+ await self.clients.claim()
20
+ })(),
21
+ )
22
+ })
23
+
24
+ function isImmutableChunk(pathname) {
25
+ return /^\/chunk-[a-z0-9]+\.(js|css)$/i.test(pathname) || /-[a-z0-9]{8}\.(woff2|png|svg|webmanifest)$/i.test(pathname)
26
+ }
27
+
28
+ self.addEventListener("fetch", (event) => {
29
+ const { request } = event
30
+ if (request.method !== "GET") return
31
+
32
+ const url = new URL(request.url)
33
+ // 跨源请求(如 https://basalt.work 访问本机 http://127.0.0.1:7420)与 API/HMR 请求直通浏览器原生网络栈,不经过 SW 拦截
34
+ if (url.origin !== self.location.origin || url.pathname.startsWith("/api/") || url.pathname.startsWith("/_bun/")) {
35
+ return
36
+ }
37
+
38
+ if (request.mode === "navigate") {
39
+ event.respondWith(
40
+ (async () => {
41
+ try {
42
+ const response = await fetch(request)
43
+ if (response.ok) {
44
+ const cache = await caches.open(CACHE_NAME)
45
+ void cache.put("/", response.clone())
46
+ }
47
+ return response
48
+ } catch {
49
+ const cached = (await caches.match(request)) ?? (await caches.match("/"))
50
+ if (cached) return cached
51
+ throw new Error("Offline")
52
+ }
53
+ })(),
54
+ )
55
+ return
56
+ }
57
+
58
+ if (isImmutableChunk(url.pathname)) {
59
+ event.respondWith(
60
+ (async () => {
61
+ const cached = await caches.match(request)
62
+ if (cached) return cached
63
+ const response = await fetch(request)
64
+ if (response.ok) {
65
+ const cache = await caches.open(CACHE_NAME)
66
+ void cache.put(request, response.clone())
67
+ }
68
+ return response
69
+ })(),
70
+ )
71
+ return
72
+ }
73
+
74
+ event.respondWith(
75
+ (async () => {
76
+ try {
77
+ const response = await fetch(request)
78
+ if (response.ok) {
79
+ const cache = await caches.open(CACHE_NAME)
80
+ void cache.put(request, response.clone())
81
+ }
82
+ return response
83
+ } catch {
84
+ const cached = await caches.match(request)
85
+ if (cached) return cached
86
+ throw new Error("Offline")
87
+ }
88
+ })(),
89
+ )
90
+ })
package/worker.js ADDED
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{$e,Tt,Kr,Ht,Si,Ho,Go}from"./chunk-x9982ek7.js";var S="backfill";function c(t){return t.query("SELECT sum((SELECT max(seq) FROM store.entries WHERE session_id = sessions.id)) AS n FROM store.sessions").get()?.n??0}function k(t){let e=Kr(t,S);return e?JSON.parse(e):void 0}function y(t,e){Ht(t,S,JSON.stringify(e))}class b{db;indexer;batch;todo;page;state;constructor(t,e,s=500){this.db=t;this.indexer=e;this.batch=s;this.todo=t.query("SELECT session_id FROM main.backfill_todo WHERE ord = ?"),this.page=t.query("SELECT seq, time, body FROM store.entries WHERE session_id = ? AND seq > ? ORDER BY seq LIMIT ?"),this.state=k(t)}get running(){return this.state?.state==="running"}begin(t){this.db.transaction(()=>{let e=this.db.query("SELECT max(id) AS id FROM store.search_queue").get()?.id??0;Ht(this.db,"queue_done",e),this.db.run("DELETE FROM main.backfill_todo"),this.db.run("INSERT INTO main.backfill_todo (ord, session_id) SELECT row_number() OVER (ORDER BY updated DESC, id), id FROM store.sessions");let s=this.db.query("SELECT count(*) AS n FROM main.backfill_todo").get()?.n??0,r=c(this.db);this.state={state:s?"running":"done",reason:t,ord:1,seq:-1,total:r,sessionsTotal:s,done:0,sessionsDone:0,startedAt:Date.now()},y(this.db,this.state)})()}step(t){let e=this.state;if(e?.state!=="running")return!1;let s={...e};return this.db.transaction(()=>{let r=this.batch;while(r>0&&s.state==="running"){let n=this.todo.get(s.ord)?.session_id;if(n===void 0){s.state="done",this.db.run("DELETE FROM main.backfill_todo");break}if(s.seq<0)this.indexer.reindex(n,0),s.seq=0;let a=this.page.all(n,s.seq,r);for(let i of a)if(this.indexer.indexRow(n,i.seq,i.time,i.body),s.seq=i.seq,s.done++,r--,performance.now()>t){r=0;break}if(r>0)s.ord++,s.seq=-1,s.sessionsDone++;if(performance.now()>t)break}y(this.db,s)})(),this.state=s,!0}}var T=2000,M=30000;class E{options;db;layout;reset;indexer;backfill;terms;queueRows;queueMax;sliceMs;backfillSliceMs;queueBatch;termRefreshMs;queueDone;termCursor;termStale;lastTermRefresh=Number.NEGATIVE_INFINITY;rateStart;estimate;closed=!1;constructor(t){this.options=t;let e=Si(t.indexPath,t.storePath,t.features);if(this.db=e.db,this.layout=e.layout,this.reset=e.reset,this.sliceMs=t.sliceMs??20,this.backfillSliceMs=t.backfillSliceMs??200,this.queueBatch=t.queueBatch??200,this.termRefreshMs=t.termRefreshMs??60000,this.indexer=new Ho(this.db,this.layout),this.terms=new Go(this.db),this.backfill=new b(this.db,this.indexer,t.batch??500),this.queueRows=this.db.query("SELECT id, session_id, seq FROM store.search_queue WHERE id > ? ORDER BY id LIMIT ?"),this.queueMax=this.db.query("SELECT max(id) AS id FROM store.search_queue"),!this.backfill.state)this.backfill.begin(this.reset?"rebuild":"initial");this.queueDone=Number(Kr(this.db,"queue_done")??0),this.termStale=Number(Kr(this.db,"term_stale")??0)===1}step(t){if(this.closed)return!1;if(this.drainQueue(t??performance.now()+this.sliceMs))return!0;if(this.backfill.running){this.rateStart??={time:performance.now(),done:this.backfill.state?.done??0};let e=this.indexer.outChanges;if(this.backfill.step(t??performance.now()+this.backfillSliceMs),this.markTerms(e),!this.backfill.running)this.lastTermRefresh=Number.NEGATIVE_INFINITY;return!0}return this.refreshTerms(t??performance.now()+this.sliceMs)}drain(){while(this.step());}drainQueue(t){let e=!1;return this.db.transaction(()=>{let s=this.queueRows.all(this.queueDone,this.queueBatch);if(!s.length)return;e=!0;let r=this.indexer.outChanges,n=new Set,a=this.queueDone;for(let i of s){let h=`${i.seq}\x00${i.session_id}`;if(!n.has(h))n.add(h),this.indexer.reindex(i.session_id,i.seq);if(a=i.id,performance.now()>t)break}Ht(this.db,"queue_done",a),this.markTerms(r),this.queueDone=a})(),e}markTerms(t){if(this.indexer.outChanges===t||this.termStale)return;this.termStale=!0,Ht(this.db,"term_stale",1)}refreshTerms(t){if(this.termCursor===void 0){if(!this.termStale||performance.now()-this.lastTermRefresh<this.termRefreshMs)return!1;this.termCursor="",this.termStale=!1,this.indexer.outChanges=0,Ht(this.db,"term_stale",0)}while(this.termCursor!==void 0&&performance.now()<=t){let e=this.termCursor;this.db.transaction(()=>{this.termCursor=this.terms.step(e,T)})()}if(this.termCursor===void 0)this.lastTermRefresh=performance.now();return!0}status(){let t=this.queueMax.get()?.id??this.queueDone,e=this.backfill.state,s;if(e?.state==="running"&&this.rateStart){let n=(performance.now()-this.rateStart.time)/1000,a=(e.done-this.rateStart.done)/n;if(n>0.5&&a>0)s=Math.max(0,Math.round(Math.max(0,e.total-e.done)/a))}let r=e?{state:e.state,reason:e.reason,total:e.total,done:e.done,sessionsTotal:e.sessionsTotal,sessionsDone:e.sessionsDone,startedAt:e.startedAt}:void 0;if(!this.estimate||performance.now()-this.estimate.time>M)this.estimate={time:performance.now(),entries:c(this.db)};return{queueDone:this.queueDone,lag:Math.max(0,t-this.queueDone),entries:this.estimate.entries,...r?{backfill:r}:{},...s!==void 0?{etaSec:s}:{},layout:this.layout,reset:this.reset}}withIndex(t){return t(this.db)}close(){if(this.closed)return;this.closed=!0,this.db.close()}}var g=1000,x=100;function R(t){let e,s,r,n=!1,a=!1,i=0,h=[],l=(u)=>t.postMessage(u),d=(u)=>{if(a)return;if(r)clearTimeout(r);r=setTimeout(q,u)},p=()=>{if(!s||Atomics.load(s,$e)!==1)return;Atomics.store(s,Tt,1),Atomics.notify(s,Tt);while(Atomics.load(s,$e)===1)Atomics.wait(s,$e,1,1e4);Atomics.store(s,Tt,0)};function q(){if(r=void 0,a||!e)return;p();let u=!1;try{u=e.step()}catch(f){l({type:"error",message:f instanceof Error?f.message:String(f),fatal:!1}),n=!1,d(g);return}let o=performance.now();if(u){if(n=!0,o-i>=x)i=o,l({type:"status",status:e.status()});d(0);return}n=!1,i=o;let m=e.status();l({type:"status",status:m});for(let f of h.splice(0))l({type:"flushed",id:f,status:m});d(g)}t.onmessage=(u)=>{let o=u.data;if(o.type==="init"){s=new Int32Array(o.flags);try{e=new E(o.options)}catch(m){l({type:"error",message:m instanceof Error?m.message:String(m),fatal:!0});return}l({type:"status",status:e.status()}),d(0)}else if(o.type==="dirty"){if(!n)d(0)}else if(o.type==="pause")p();else if(o.type==="flush"){if(h.push(o.id),!n)d(0)}else if(o.type==="stop"){if(a=!0,r)clearTimeout(r);e?.close(),l({type:"stopped"})}}}if(!Bun.isMainThread)R(globalThis);export{E as SearchEngine};