dsh-calibguard 0.3.0 → 0.3.2

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.
package/README.en.md CHANGED
@@ -76,7 +76,7 @@ once (depends on network and pip mirror).
76
76
  > You can also pre-warm, or install offline, by running the same installer manually (idempotent):
77
77
  >
78
78
  > ```powershell
79
- > node setup.mjs # bundled engine → npm model shards → venv → deps → self-check
79
+ > node setup.mjs # bundled engine → model release asset → venv → deps → self-check
80
80
  > node setup.mjs --from D:\CalibGuard-GUI.zip # use an already-downloaded release zip (offline)
81
81
  > node setup.mjs --dest D:\CG_GUI # custom location (then configure engineRoot)
82
82
  > ```
package/README.md CHANGED
@@ -69,7 +69,7 @@
69
69
  > 想提前预热、或断网/锁网环境需要离线安装,也可以手动跑安装器(同一套逻辑,幂等):
70
70
  >
71
71
  > ```powershell
72
- > node setup.mjs # 一键:下载 → 解压 → venv → 依赖 → 自检
72
+ > node setup.mjs # 一键:内置引擎 → 下载模型 → venv → 依赖 → 自检
73
73
  > node setup.mjs --from D:\CalibGuard-GUI.zip # 用已下载的发行包,不联网
74
74
  > node setup.mjs --dest D:\CG_GUI # 装到自定义位置(之后配置 engineRoot)
75
75
  > ```
@@ -81,7 +81,7 @@
81
81
 
82
82
  1. **DSH**(DeepSeek Harness)0.1.5-rc.2 实测可用;
83
83
  2. **Python**:无需预装——没有 64 位 3.10–3.12 时安装器会自动下载便携版(缓存在 `~/.dsh/calibguard-tools`,可用 `--no-portable-python` 关闭);
84
- 3. **引擎**:插件自带;模型权重会自动从 npm 镜像下载。也可用 `--from` 指定 CG 发行包,或把 `engineRoot` 指向已有 `CG_GUI/`。
84
+ 3. **引擎**:插件自带;模型权重会自动从本仓库 Release 下载(自动镜像回退)。也可用 `--from` 指定 CG 发行包,或把 `engineRoot` 指向已有 `CG_GUI/`。
85
85
 
86
86
  ### 方式 0:桌面端「添加插件」(最省事,推荐)
87
87
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-calibguard",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -48,6 +48,7 @@
48
48
  }
49
49
  },
50
50
  "scripts": {
51
+ "prepack": "node -e \"const fs=require('fs');for(const d of ['bridge','engine']){if(!fs.existsSync(d))continue;for(const f of fs.readdirSync(d,{withFileTypes:true})){if(f.isDirectory()&&f.name==='__pycache__')fs.rmSync(d+'/'+f.name,{recursive:true,force:true});else if(f.isFile()&&f.name.endsWith('.pyc'))fs.rmSync(d+'/'+f.name,{force:true});}}\"",
51
52
  "test": "node --test",
52
53
  "setup": "node setup.mjs",
53
54
  "link-dsh": "node scripts/link-dsh.mjs",
package/setup.mjs CHANGED
@@ -35,7 +35,7 @@ const PY_MIN = 10
35
35
  const PY_MAX = 12
36
36
 
37
37
  /** 引擎下载的镜像前缀:GitHub 直连失败时依次重试。 */
38
- const ENGINE_MIRRORS = ['https://ghproxy.cn/', 'https://gh-proxy.com/', 'https://ghfast.top/']
38
+ const ENGINE_MIRRORS = ['https://gh-proxy.com/', 'https://ghfast.top/', 'https://ghproxy.cn/']
39
39
  /** pip 索引:默认清华镜像,失败回退官方 PyPI。 */
40
40
  const DEFAULT_PIP_INDEX = 'https://pypi.tuna.tsinghua.edu.cn/simple'
41
41
  const OFFICIAL_PIP_INDEX = 'https://pypi.org/simple'
@@ -86,6 +86,9 @@ const MODEL_URL = 'https://github.com/maomitgd2006/dsh-CalibGuard/releases/downl
86
86
  /** 完整模型的 SHA-256(与 CG 发行包里的 model.safetensors 完全一致)。 */
87
87
  const MODEL_SHA256 = '2f088a00c1a08c9331a58de2b9adc9bb7ace8f28a2491ee7b699f41c7b7efc65'
88
88
 
89
+ /** 模型压缩包的合理大小下限(防止镜像返回错误页被当成压缩包)。 */
90
+ const MODEL_ZIP_MIN_BYTES = 400 * 1024 ** 2
91
+
89
92
  /** 文件 SHA-256(流式,避免大文件占内存)。 */
90
93
  function sha256File(file) {
91
94
  return new Promise((resolvePromise, rejectPromise) => {
@@ -98,9 +101,9 @@ function sha256File(file) {
98
101
  }
99
102
 
100
103
  /**
101
- * 准备模型权重:下载本仓库 Release 里的模型压缩包 → 校验 SHA-256 → 缓存到
104
+ * 准备模型权重:下载本仓库 Release 里的模型压缩包 → 校验尺寸/SHA-256 → 缓存到
102
105
  * `~/.dsh/calibguard-tools/model-cache` → 复制进引擎目录。
103
- * 支持断点续传、ghproxy 镜像;已缓存时秒级完成。
106
+ * 每个镜像都会完整尝试(下载 → 解压 → 校验),坏镜像不会污染结果;已缓存时秒级完成。
104
107
  */
105
108
  async function fetchModelWeights(dest) {
106
109
  const cacheDir = join(toolsDir(), 'model-cache')
@@ -114,42 +117,48 @@ async function fetchModelWeights(dest) {
114
117
  modelFile = cachedModel
115
118
  } else {
116
119
  const zipPath = join(cacheDir, 'calibguard-model-1.0.0.zip')
120
+ const unpacked = join(cacheDir, 'unpacked')
117
121
  let lastError = null
118
122
  for (const url of mirroredUrls(MODEL_URL)) {
119
123
  try {
120
124
  log(`下载模型权重(约 442 MB):${url}`)
121
125
  await download(url, zipPath)
126
+ const size = statSync(zipPath).size
127
+ if (size < MODEL_ZIP_MIN_BYTES) {
128
+ throw new SetupError(`下载内容异常(${bytes(size)},预期约 442 MB,可能是镜像错误页)`)
129
+ }
130
+ rmSync(unpacked, { recursive: true, force: true })
131
+ mkdirSync(unpacked, { recursive: true })
132
+ extract(zipPath, unpacked)
133
+ const found = findBinary(unpacked, 'model.safetensors')
134
+ if (!found) throw new SetupError('模型压缩包里没有 model.safetensors')
135
+ const actual = await sha256File(found)
136
+ if (actual !== MODEL_SHA256) throw new SetupError(`模型 SHA-256 不匹配:${actual}`)
137
+ deleteFile(cachedModel)
138
+ try {
139
+ renameSync(found, cachedModel)
140
+ } catch {
141
+ copyFileSync(found, cachedModel)
142
+ }
143
+ rmSync(unpacked, { recursive: true, force: true })
144
+ deleteFile(zipPath)
145
+ modelFile = cachedModel
122
146
  lastError = null
147
+ log(`✓ 模型已缓存:${cachedModel}`)
123
148
  break
124
149
  } catch (error) {
125
150
  lastError = error
126
- warn(`下载源失败:${String(error.message).split('\n')[0]}`)
151
+ warn(`下载源失败:${String(error.message).split('\n')[0]},换下一个源…`)
152
+ deleteFile(zipPath)
127
153
  deleteFile(`${zipPath}.part`)
154
+ rmSync(unpacked, { recursive: true, force: true })
128
155
  }
129
156
  }
130
- if (lastError) {
131
- throw new SetupError(`模型下载失败:${lastError.message}\n`
157
+ if (!modelFile) {
158
+ throw new SetupError(`模型下载失败:${lastError?.message ?? '未知错误'}\n`
132
159
  + `可以重试(支持断点续传),或手动下载后放到:${cachedModel}\n`
133
160
  + '(下载地址:https://github.com/maomitgd2006/dsh-CalibGuard/releases/tag/model-v1.0.0)')
134
161
  }
135
- const unpacked = join(cacheDir, 'unpacked')
136
- rmSync(unpacked, { recursive: true, force: true })
137
- mkdirSync(unpacked, { recursive: true })
138
- extract(zipPath, unpacked)
139
- const found = findBinary(unpacked, 'model.safetensors')
140
- if (!found) throw new SetupError(`模型压缩包里没有 model.safetensors:${unpacked}`)
141
- const actual = await sha256File(found)
142
- if (actual !== MODEL_SHA256) throw new SetupError(`模型 SHA-256 不匹配:${actual}`)
143
- deleteFile(cachedModel)
144
- try {
145
- renameSync(found, cachedModel)
146
- } catch {
147
- copyFileSync(found, cachedModel)
148
- }
149
- rmSync(unpacked, { recursive: true, force: true })
150
- deleteFile(zipPath)
151
- modelFile = cachedModel
152
- log(`✓ 模型已缓存:${cachedModel}`)
153
162
  }
154
163
 
155
164
  log(`写入引擎目录:${finalPath}`)
@@ -680,11 +689,15 @@ async function main() {
680
689
  for (const candidate of candidates) {
681
690
  try {
682
691
  await download(candidate, downloadedZip)
692
+ if (statSync(downloadedZip).size < 100 * 1024 ** 2) {
693
+ throw new SetupError('下载内容明显偏小,可能是镜像错误页')
694
+ }
683
695
  lastError = null
684
696
  break
685
697
  } catch (error) {
686
698
  lastError = error
687
699
  warn(`下载源失败:${String(error.message).split('\n')[0]}`)
700
+ rmSync(downloadedZip, { force: true })
688
701
  rmSync(`${downloadedZip}.part`, { force: true })
689
702
  }
690
703
  }