Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,10 @@ token-watcher extra-roots remove claude-code ~/mirror/home-pc/claude/projects

**Node ≥ 22.13**(`node:sqlite` 自该版本起免 `--experimental-sqlite` flag,零原生依赖)。

**dsh 源需要系统 `zstd`**(`brew install zstd`)。dsh 的会话快照是追加式多帧写入,
**dsh 源需要系统 `zstd`**。dsh 的会话快照是追加式多帧写入,必须用外部 zstd CLI 解压:
- macOS:`brew install zstd`
- Windows:`scoop install zstd` 或 `choco install zstd`,或从 [facebook/zstd releases](https://github.com/facebook/zstd/releases) 下载 `zstd.exe` 加入 PATH
- Linux:`apt-get install -y zstd` / `dnf install -y zstd` / `pacman -S zstd`
单个文件可达数千帧,而 Node 内置的 zstd 只解第一帧就结束且不报错,因此这里以外部
`zstd` 为准,仅在确认文件只含单帧时才回落内置实现。未安装且遇到多帧文件时,该源会在
健康自检里报错,而不是静默少算。其余数据源不需要它。
Expand Down
3 changes: 2 additions & 1 deletion src/doctor.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { join } from 'node:path';
import { homedir } from 'node:os';
import { SOURCES, DB_PATH, DATA_DIR, EXTRA_ROOTS, isOffline } from './config.js';
import { isUnderRoot } from './scanner.js';
import { zstdInstallHint } from './zstd.js';
import { computeHealth } from './server.js';
import { zcodeQuotaTargets } from './zcodeQuota.js';
import { readClaudeOauthToken } from './claudeUsage.js';
Expand Down Expand Up @@ -34,7 +35,7 @@ export async function runDoctor(store, scannerStats, { log = console.log } = {})
try { execFileSync('zstd', ['--version'], { stdio: 'ignore', timeout: 3000 }); return true; }
catch { return false; }
})();
log(` ${zstd ? '✓' : '⚠'} 系统 zstd(dsh 多帧会话必需):${zstd ? '可用' : '未找到,brew install zstd'}`);
log(` ${zstd ? '✓' : '⚠'} 系统 zstd(dsh 多帧会话必需):${zstd ? '可用' : '未找到,' + zstdInstallHint()}`);
}

log('数据库');
Expand Down
23 changes: 21 additions & 2 deletions src/zstd.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@ const execFileP = promisify(execFile);
const ZSTD_BINS = ['zstd', '/opt/homebrew/bin/zstd', '/usr/local/bin/zstd', '/usr/bin/zstd'];
const ZSTD_MAGIC = Buffer.from([0x28, 0xb5, 0x2f, 0xfd]);

/**
* 跨平台「如何安装 zstd」提示。dsh 多帧会话必须用外部 zstd CLI 解压,
* 但旧报错只给了 macOS 的 `brew install zstd`,Windows/Linux 用户无解。
* 这里按 process.platform 给出对应包管理器命令或官方二进制下载地址。
*/
export function zstdInstallHint() {
switch (process.platform) {
case 'win32':
return '请安装 zstd:scoop install zstd 或 choco install zstd;也可从 https://github.com/facebook/zstd/releases 下载 zstd.exe 并加入 PATH';
case 'darwin':
return '请安装 zstd:brew install zstd';
case 'linux':
return '请安装 zstd:apt-get install -y zstd(Debian/Ubuntu)| dnf install -y zstd(Fedora)| pacman -S zstd(Arch)';
default:
return '请通过系统包管理器安装 zstd';
}
}


/** Decompress a complete zstd stream, including concatenated frames. */
export async function decompressZstd(path, { bins = ZSTD_BINS } = {}) {
for (const bin of bins) {
Expand Down Expand Up @@ -35,11 +54,11 @@ export async function decompressZstd(path, { bins = ZSTD_BINS } = {}) {
} catch { /* A magic-like sequence inside the frame payload is not a frame boundary. */ }
idx = buf.indexOf(ZSTD_MAGIC, idx + 1);
}
if (multi) throw new Error(`${path} 含多个 zstd 帧,Node 内置实现只能解第一帧。请安装 zstd:brew install zstd`);
if (multi) throw new Error(`${path} 含多个 zstd 帧,Node 内置实现只能解第一帧。${zstdInstallHint()}`);
return zlib.zstdDecompressSync(buf);
}

throw new Error('zstd 不可用:PATH 与常见安装路径下均无 zstd,请执行 brew install zstd');
throw new Error(`zstd 不可用:PATH 与常见安装路径下均无 zstd。${zstdInstallHint()}`);
}

/**
Expand Down
Loading