@bkm016/basalt 0.0.0-stage → 0.1.1

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 (256) hide show
  1. package/README.md +275 -2
  2. package/chunk-09vr609h.js +2 -0
  3. package/chunk-0hbjv3y6.js +11 -0
  4. package/chunk-0qqb6v41.js +3753 -0
  5. package/chunk-0szjy61m.js +2 -0
  6. package/chunk-0yytz0r1.js +59 -0
  7. package/chunk-1aspj1hn.js +3 -0
  8. package/chunk-1b7gbe8g.js +10 -0
  9. package/chunk-1v7st27a.js +25 -0
  10. package/chunk-1yzt0qm0.js +2 -0
  11. package/chunk-2bb01ddq.js +16 -0
  12. package/chunk-2wkaw73s.js +9 -0
  13. package/chunk-2zqny2sy.js +2 -0
  14. package/chunk-32at88hc.js +3 -0
  15. package/chunk-3m7qwfm3.js +7 -0
  16. package/chunk-44ek81ad.js +3 -0
  17. package/chunk-45cz26ap.js +39 -0
  18. package/chunk-501zkf9b.js +3 -0
  19. package/chunk-58vz2qsq.js +2 -0
  20. package/chunk-6e49xsf5.js +3 -0
  21. package/chunk-6qertm2t.js +3 -0
  22. package/chunk-8dxzqwq3.js +2 -0
  23. package/chunk-9mmz6wt3.js +2 -0
  24. package/chunk-a3tqx584.js +10 -0
  25. package/chunk-a6r4z44b.js +2 -0
  26. package/chunk-a8nyk4k9.js +2 -0
  27. package/chunk-agntrqs9.js +2 -0
  28. package/chunk-bhqyxyap.js +3 -0
  29. package/chunk-bpw6q7g0.js +3 -0
  30. package/chunk-c25s4w6a.js +5 -0
  31. package/chunk-cv5wsd9m.js +8 -0
  32. package/chunk-d48bfd2e.js +3 -0
  33. package/chunk-dakrpbe6.js +3 -0
  34. package/chunk-dhm42y04.js +7 -0
  35. package/chunk-exnn1867.js +2 -0
  36. package/chunk-f7egr55n.js +31 -0
  37. package/chunk-g2t6t8fk.js +3 -0
  38. package/chunk-h6sw8fbt.js +5 -0
  39. package/chunk-hat3s3pr.js +3 -0
  40. package/chunk-hcn9cf6v.js +2 -0
  41. package/chunk-jhd54p1b.js +3 -0
  42. package/chunk-k7w7ac9q.js +18 -0
  43. package/chunk-kf8hq21a.js +25 -0
  44. package/chunk-kfq8wyd3.js +3 -0
  45. package/chunk-n6e43rvk.js +3 -0
  46. package/chunk-nt2gntad.js +2 -0
  47. package/chunk-pmc3y1z8.js +2 -0
  48. package/chunk-pvncysbb.js +3 -0
  49. package/chunk-q8zx3kt6.js +2 -0
  50. package/chunk-qczbfccb.js +12 -0
  51. package/chunk-qnr1f5pj.js +3 -0
  52. package/chunk-qx0m82rw.js +2 -0
  53. package/chunk-r9aatvwm.js +3 -0
  54. package/chunk-rm3kcxq9.js +20 -0
  55. package/chunk-rv06x0kn.js +7 -0
  56. package/chunk-ry0z4ev6.js +2 -0
  57. package/chunk-s37s3k24.js +12 -0
  58. package/chunk-sh74qzvt.js +5 -0
  59. package/chunk-szat3vp4.js +3 -0
  60. package/chunk-t057xfrt.js +5 -0
  61. package/chunk-tvm4zmgj.js +3 -0
  62. package/chunk-v9fea96h.js +3 -0
  63. package/chunk-vgvq3q12.js +3 -0
  64. package/chunk-vkkj4awb.js +2 -0
  65. package/chunk-vv7fp27r.js +3 -0
  66. package/chunk-wjd9fr23.js +2 -0
  67. package/chunk-wx7kdf0b.js +2 -0
  68. package/chunk-x3dnb9sz.js +3 -0
  69. package/chunk-xsbxykr4.js +2 -0
  70. package/chunk-xysny0ve.js +3 -0
  71. package/chunk-y69ewdn2.js +3 -0
  72. package/chunk-yskm0hsy.js +2 -0
  73. package/chunk-zef13k3h.js +471 -0
  74. package/cli.js +89 -0
  75. package/compiled.js +23 -0
  76. package/icon-dp9pmcvp.png +0 -0
  77. package/package.json +21 -4
  78. package/ui-test-worker.js +226 -0
  79. package/web/KaTeX_AMS-Regular-n7eqehx2.woff2 +0 -0
  80. package/web/KaTeX_Caligraphic-Bold-20r3b6fv.woff2 +0 -0
  81. package/web/KaTeX_Caligraphic-Regular-kkjm8f18.woff2 +0 -0
  82. package/web/KaTeX_Fraktur-Bold-pz5vg4t0.woff2 +0 -0
  83. package/web/KaTeX_Fraktur-Regular-a1e9wkwk.woff2 +0 -0
  84. package/web/KaTeX_Main-Bold-mcp098h8.woff2 +0 -0
  85. package/web/KaTeX_Main-BoldItalic-fy74z249.woff2 +0 -0
  86. package/web/KaTeX_Main-Italic-hw2gxy7f.woff2 +0 -0
  87. package/web/KaTeX_Main-Regular-xvp1b75c.woff2 +0 -0
  88. package/web/KaTeX_Math-BoldItalic-mf5nf33d.woff2 +0 -0
  89. package/web/KaTeX_Math-Italic-ap60jrna.woff2 +0 -0
  90. package/web/KaTeX_SansSerif-Bold-we3bymb6.woff2 +0 -0
  91. package/web/KaTeX_SansSerif-Italic-ent92bjx.woff2 +0 -0
  92. package/web/KaTeX_SansSerif-Regular-0573pbz9.woff2 +0 -0
  93. package/web/KaTeX_Script-Regular-z2rtj6vq.woff2 +0 -0
  94. package/web/KaTeX_Size1-Regular-dfr3w1hv.woff2 +0 -0
  95. package/web/KaTeX_Size2-Regular-kted78zb.woff2 +0 -0
  96. package/web/KaTeX_Size3-Regular-e6k1k5jk.woff2 +0 -0
  97. package/web/KaTeX_Size4-Regular-abedc1pd.woff2 +0 -0
  98. package/web/KaTeX_Typewriter-Regular-scw9zx1z.woff2 +0 -0
  99. package/web/apple-touch-icon-7dkm33qp.png +0 -0
  100. package/web/apple-touch-icon.png +0 -0
  101. package/web/chunk-05w4fyzc.js +1 -0
  102. package/web/chunk-0mrkjnte.js +1 -0
  103. package/web/chunk-0pbjgdgp.js +2 -0
  104. package/web/chunk-0s80zw00.js +1 -0
  105. package/web/chunk-0vt9fg48.js +2 -0
  106. package/web/chunk-20q90epj.js +2 -0
  107. package/web/chunk-22a4ety5.js +1 -0
  108. package/web/chunk-24mfx6w1.js +2 -0
  109. package/web/chunk-2j4m0bh1.js +2 -0
  110. package/web/chunk-2m12wyrb.js +16 -0
  111. package/web/chunk-2msj52w6.js +1 -0
  112. package/web/chunk-2ps6mepk.js +120 -0
  113. package/web/chunk-2pver6r4.js +1 -0
  114. package/web/chunk-2scce33n.js +1 -0
  115. package/web/chunk-37ajk6zg.js +2 -0
  116. package/web/chunk-3ee04tmm.js +200 -0
  117. package/web/chunk-3jhyzmnf.js +292 -0
  118. package/web/chunk-45fzdcgz.js +30 -0
  119. package/web/chunk-4gavbw65.js +1 -0
  120. package/web/chunk-4ks96e4r.js +1 -0
  121. package/web/chunk-4rm1vy7w.js +1 -0
  122. package/web/chunk-4v8en1yw.js +40 -0
  123. package/web/chunk-4wd9r73y.js +1 -0
  124. package/web/chunk-4wkm9fda.js +1 -0
  125. package/web/chunk-54thej0t.js +2 -0
  126. package/web/chunk-59kqahb3.js +1 -0
  127. package/web/chunk-5vw9rs4r.js +4 -0
  128. package/web/chunk-6beqrmtq.js +1 -0
  129. package/web/chunk-6m69hczt.js +2 -0
  130. package/web/chunk-70qwwwak.js +2 -0
  131. package/web/chunk-74j07k8k.js +2 -0
  132. package/web/chunk-8g239029.js +1 -0
  133. package/web/chunk-8p4tc9f4.js +70 -0
  134. package/web/chunk-90kp4pnz.js +2 -0
  135. package/web/chunk-9an7cjd9.js +291 -0
  136. package/web/chunk-9dxjafp2.js +78 -0
  137. package/web/chunk-9p12mgs6.js +2 -0
  138. package/web/chunk-9v1f6yc8.js +1 -0
  139. package/web/chunk-9yakxvjb.js +2 -0
  140. package/web/chunk-a1z5qx1r.js +36 -0
  141. package/web/chunk-a3verqw9.js +214 -0
  142. package/web/chunk-a5x2zveg.js +7 -0
  143. package/web/chunk-ad6x47yy.js +1 -0
  144. package/web/chunk-amzgyy1k.js +1 -0
  145. package/web/chunk-b1pe46zz.js +2 -0
  146. package/web/chunk-b4wbk7vc.js +217 -0
  147. package/web/chunk-bc78qf1m.js +7 -0
  148. package/web/chunk-bgnnrpna.js +89 -0
  149. package/web/chunk-bj90t5gh.js +99 -0
  150. package/web/chunk-bjkc94mv.js +1 -0
  151. package/web/chunk-ca682sm6.js +370 -0
  152. package/web/chunk-cff5hcm8.js +8 -0
  153. package/web/chunk-cg3jterp.js +2 -0
  154. package/web/chunk-d18r4m14.js +141 -0
  155. package/web/chunk-dmqtdeb4.js +1 -0
  156. package/web/chunk-dt462hk9.js +332 -0
  157. package/web/chunk-dy2gm1fs.js +1 -0
  158. package/web/chunk-dzwxgqgm.js +39 -0
  159. package/web/chunk-e32y85kx.js +1 -0
  160. package/web/chunk-e53wfgb8.js +1 -0
  161. package/web/chunk-e6jxqbv7.js +3 -0
  162. package/web/chunk-esp1mmgr.js +1 -0
  163. package/web/chunk-ew3cgdtd.js +1 -0
  164. package/web/chunk-f26smjjf.js +2 -0
  165. package/web/chunk-f91wzwtk.js +1 -0
  166. package/web/chunk-fk0dh93x.js +89 -0
  167. package/web/chunk-fm2ybfj5.js +98 -0
  168. package/web/chunk-fscafg24.js +34 -0
  169. package/web/chunk-fz06t6km.js +55 -0
  170. package/web/chunk-g1ev11wx.js +1 -0
  171. package/web/chunk-g4azyef7.js +106 -0
  172. package/web/chunk-gjq1pxw3.js +1 -0
  173. package/web/chunk-gqw3f02j.js +140 -0
  174. package/web/chunk-h5ejbf6e.js +1 -0
  175. package/web/chunk-hev4hq89.js +2 -0
  176. package/web/chunk-hfaffkrh.js +1 -0
  177. package/web/chunk-hp167dbv.js +1 -0
  178. package/web/chunk-j2vt8c8v.js +1 -0
  179. package/web/chunk-jjh5jvva.js +1 -0
  180. package/web/chunk-jrcyc9s9.js +38 -0
  181. package/web/chunk-jwzd9tzk.js +24 -0
  182. package/web/chunk-k5btcvbg.js +1 -0
  183. package/web/chunk-ka3q31t1.js +1 -0
  184. package/web/chunk-kdyjnwdx.js +2 -0
  185. package/web/chunk-kpvgecwy.js +1 -0
  186. package/web/chunk-kq40ss39.js +1 -0
  187. package/web/chunk-m2d1sp30.js +1 -0
  188. package/web/chunk-n1dmrz44.js +2 -0
  189. package/web/chunk-n90cqdvg.js +2 -0
  190. package/web/chunk-nj0cv1cq.js +257 -0
  191. package/web/chunk-nzey7cpv.js +1 -0
  192. package/web/chunk-p3b9crsa.js +2 -0
  193. package/web/chunk-pf2ab8p8.js +1 -0
  194. package/web/chunk-pxe3vna4.js +1 -0
  195. package/web/chunk-q0p5xqe1.js +84 -0
  196. package/web/chunk-q5ke7a33.js +24 -0
  197. package/web/chunk-q7dsnvpf.js +1 -0
  198. package/web/chunk-qd8bxxdj.js +1 -0
  199. package/web/chunk-qefasa1j.js +2 -0
  200. package/web/chunk-qh7265qw.js +4 -0
  201. package/web/chunk-qnaqf0cr.js +1 -0
  202. package/web/chunk-r1dnh0s8.js +1 -0
  203. package/web/chunk-r5eakmw6.js +1 -0
  204. package/web/chunk-rg426vkf.js +1 -0
  205. package/web/chunk-rpmpttbk.js +12 -0
  206. package/web/chunk-rtf2zzzv.js +1 -0
  207. package/web/chunk-ry9256r7.js +1 -0
  208. package/web/chunk-rykfak98.js +2 -0
  209. package/web/chunk-scpwc9ev.js +1 -0
  210. package/web/chunk-srrfphes.js +1 -0
  211. package/web/chunk-ss1bcb0n.js +2 -0
  212. package/web/chunk-ssy07dd2.js +1 -0
  213. package/web/chunk-t6agpn2z.js +1 -0
  214. package/web/chunk-taynqrgq.js +142 -0
  215. package/web/chunk-tgpbhzn9.js +1 -0
  216. package/web/chunk-tmvakq7n.js +19 -0
  217. package/web/chunk-tqmwd9qp.js +139 -0
  218. package/web/chunk-ts7zrf5b.js +2 -0
  219. package/web/chunk-ttg6tbwx.js +2 -0
  220. package/web/chunk-v28fx2nd.js +1 -0
  221. package/web/chunk-v5cnt7c8.js +1 -0
  222. package/web/chunk-vt40e1kp.js +1136 -0
  223. package/web/chunk-w53rba6g.js +1 -0
  224. package/web/chunk-w86n42dy.js +1 -0
  225. package/web/chunk-w880psmw.js +1 -0
  226. package/web/chunk-wptv8atc.js +2 -0
  227. package/web/chunk-wtawdeej.css +1 -0
  228. package/web/chunk-xbty0rv7.js +41 -0
  229. package/web/chunk-xet1jjy9.js +1 -0
  230. package/web/chunk-xjxv8dg8.js +169 -0
  231. package/web/chunk-xrxne80b.js +62 -0
  232. package/web/chunk-xzp7jf7e.js +2 -0
  233. package/web/chunk-y0m8hrwz.js +303 -0
  234. package/web/chunk-y49fhfda.js +7 -0
  235. package/web/chunk-yd46jhqv.js +1 -0
  236. package/web/chunk-ydtrc1ay.js +2 -0
  237. package/web/chunk-z09emmrb.js +1 -0
  238. package/web/chunk-z7dcbxws.js +1 -0
  239. package/web/chunk-zbj1trar.js +2 -0
  240. package/web/chunk-zde7mj43.js +1 -0
  241. package/web/icon-192.png +0 -0
  242. package/web/icon-512.png +0 -0
  243. package/web/icon-maskable-512.png +0 -0
  244. package/web/icon-yx2p2pye.svg +13 -0
  245. package/web/icon.svg +13 -0
  246. package/web/index.html +23 -0
  247. package/web/install.ps1 +91 -0
  248. package/web/install.sh +177 -0
  249. package/web/inter-latin-wght-normal-an0py913.woff2 +0 -0
  250. package/web/jetbrains-mono-latin-wght-normal-hj2e42wt.woff2 +0 -0
  251. package/web/manifest-txf6vfbq.webmanifest +35 -0
  252. package/web/manifest.webmanifest +35 -0
  253. package/web/source-serif-4-latin-wght-italic-ta5tqqvz.woff2 +0 -0
  254. package/web/source-serif-4-latin-wght-normal-1yyvbhsz.woff2 +0 -0
  255. package/web/sw.js +90 -0
  256. package/worker.js +2 -0
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-vt40e1kp.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,wi,Ho,Go}from"./chunk-kf8hq21a.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=wi(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};