dsh-soul 0.6.0 → 0.6.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.
- package/README.md +18 -0
- package/README_EN.md +18 -0
- package/client/index.mjs +1 -1
- package/package.json +6 -5
- package/scripts/verify-compat.mjs +289 -0
package/README.md
CHANGED
|
@@ -46,6 +46,24 @@ dsh plugin --profile web update dsh-soul
|
|
|
46
46
|
name: dsh-soul
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
## 兼容性
|
|
50
|
+
|
|
51
|
+
插件不打包 DSH 运行时包,全部由宿主提供。DSH 会在装载前校验 `peerDependencies`,**比较对象是 DSH 运行时版本**(`@deepseek-ai/dsh-app-boot` 的 version),而不是这些包各自的版本:
|
|
52
|
+
|
|
53
|
+
| 包 | 范围 |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| `@deepseek-ai/dsh-llm` | `>=0.1.1-rc.2 <0.3.0-0` |
|
|
56
|
+
| `@deepseek-ai/dsh-tools` | `>=0.1.0-rc.6 <0.3.0-0` |
|
|
57
|
+
| `@deepseek-ai/cordis` | `^4.0.1 \|\| ^4.0.5-alpha.1` |
|
|
58
|
+
|
|
59
|
+
即支持 DSH **0.1.x 与 0.2.x**(含 prerelease 版本)。可用 `npm run verify:compat` 在当前环境确认声明是否成立。
|
|
60
|
+
|
|
61
|
+
若 DSH 提示「dsh-soul@x.y.z 与 DSH a.b.c 不兼容」,说明插件版本早于该 DSH 版本,升级插件即可:
|
|
62
|
+
|
|
63
|
+
```powershell
|
|
64
|
+
dsh plugin --profile web update dsh-soul
|
|
65
|
+
```
|
|
66
|
+
|
|
49
67
|
## 截图
|
|
50
68
|
|
|
51
69
|
**设置页(关于你 + 特质)**
|
package/README_EN.md
CHANGED
|
@@ -46,6 +46,24 @@ The plugin is registered via `cordis.patch.yml`:
|
|
|
46
46
|
name: dsh-soul
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
## Compatibility
|
|
50
|
+
|
|
51
|
+
The plugin ships no DSH runtime packages; the host provides them all. DSH validates `peerDependencies` before loading, comparing against the **DSH runtime version** (the version of `@deepseek-ai/dsh-app-boot`), not the individual packages' versions:
|
|
52
|
+
|
|
53
|
+
| Package | Range |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| `@deepseek-ai/dsh-llm` | `>=0.1.1-rc.2 <0.3.0-0` |
|
|
56
|
+
| `@deepseek-ai/dsh-tools` | `>=0.1.0-rc.6 <0.3.0-0` |
|
|
57
|
+
| `@deepseek-ai/cordis` | `^4.0.1 \|\| ^4.0.5-alpha.1` |
|
|
58
|
+
|
|
59
|
+
So DSH **0.1.x and 0.2.x** are supported, prereleases included. Run `npm run verify:compat` to check the declaration against your environment.
|
|
60
|
+
|
|
61
|
+
If DSH reports "dsh-soul@x.y.z is incompatible with DSH a.b.c", the plugin predates that DSH version — updating it is enough:
|
|
62
|
+
|
|
63
|
+
```powershell
|
|
64
|
+
dsh plugin --profile web update dsh-soul
|
|
65
|
+
```
|
|
66
|
+
|
|
49
67
|
## Screenshots
|
|
50
68
|
|
|
51
69
|
**Settings page (About you + Traits)**
|
package/client/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-soul",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "为 DeepSeek Harness 添加个性化设置",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"type": "module",
|
|
18
18
|
"main": "index.mjs",
|
|
19
19
|
"scripts": {
|
|
20
|
-
"verify": "node scripts/verify-config.mjs"
|
|
20
|
+
"verify": "node scripts/verify-config.mjs && node scripts/verify-compat.mjs",
|
|
21
|
+
"verify:compat": "node scripts/verify-compat.mjs"
|
|
21
22
|
},
|
|
22
23
|
"license": "MIT",
|
|
23
24
|
"repository": {
|
|
@@ -25,9 +26,9 @@
|
|
|
25
26
|
"url": "git+https://github.com/Aliuyanfeng/dsh-soul.git"
|
|
26
27
|
},
|
|
27
28
|
"peerDependencies": {
|
|
28
|
-
"@deepseek-ai/cordis": "^4.0.1",
|
|
29
|
-
"@deepseek-ai/dsh-llm": "
|
|
30
|
-
"@deepseek-ai/dsh-tools": "
|
|
29
|
+
"@deepseek-ai/cordis": "^4.0.1 || ^4.0.5-alpha.1",
|
|
30
|
+
"@deepseek-ai/dsh-llm": ">=0.1.1-rc.2 <0.3.0-0",
|
|
31
|
+
"@deepseek-ai/dsh-tools": ">=0.1.0-rc.6 <0.3.0-0"
|
|
31
32
|
},
|
|
32
33
|
"dsh": {
|
|
33
34
|
"bundle": {
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 校验本插件的 peerDependencies 是否与当前 DSH 运行时兼容。
|
|
4
|
+
*
|
|
5
|
+
* DSH 装载插件前会做同一件事(见 @deepseek-ai/dsh-app-boot 的 evaluatePluginCompatibility):
|
|
6
|
+
*
|
|
7
|
+
* 1. 只校验 peerDependencies 里名字等于 `@deepseek-ai/dsh` 或以 `@deepseek-ai/dsh-` 开头的条目;
|
|
8
|
+
* 其余(例如 `@deepseek-ai/cordis`)不参与判定。
|
|
9
|
+
* 2. 被比较的一方是 **DSH 运行时版本**(取自 `@deepseek-ai/dsh-app-boot/package.json` 的 version),
|
|
10
|
+
* 而不是插件真正 import 到的那个包的版本。
|
|
11
|
+
* 3. 用 `semver.satisfies(runtimeVersion, range, { includePrerelease: true })` 判定。
|
|
12
|
+
* `includePrerelease` 带来两个后果:
|
|
13
|
+
* - `^0.1.1-rc.2` 的隐含上界是 `<0.2.0-0`,因此**挡不住** 0.2.x 线;
|
|
14
|
+
* - range 必须显式覆盖对方的 [major,minor,patch],否则同线上的 prerelease 也不匹配。
|
|
15
|
+
*
|
|
16
|
+
* 不通过时 DSH 会拒绝装载,并在插件管理器里给出
|
|
17
|
+
* 「{插件} 与 DSH {版本} 不兼容(要求 {peer})」。因此 DSH 升级后应重跑本脚本。
|
|
18
|
+
*
|
|
19
|
+
* 用法:
|
|
20
|
+
* node scripts/verify-compat.mjs # 自动定位 DSH
|
|
21
|
+
* node scripts/verify-compat.mjs --dsh <目录> # 指定 DSH 安装目录(含 @deepseek-ai 或 @deepseek-ai/dsh)
|
|
22
|
+
* node scripts/verify-compat.mjs --runtime <版本> # 直接指定运行时版本,跳过定位
|
|
23
|
+
*
|
|
24
|
+
* 退出码:0 = 兼容,或无法定位运行时(跳过);1 = 存在不兼容的 peer。
|
|
25
|
+
*/
|
|
26
|
+
import { createRequire } from 'node:module'
|
|
27
|
+
import { readFileSync, existsSync, readdirSync } from 'node:fs'
|
|
28
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
29
|
+
import { dirname, join, resolve } from 'node:path'
|
|
30
|
+
import { homedir } from 'node:os'
|
|
31
|
+
|
|
32
|
+
const HERE = dirname(fileURLToPath(import.meta.url))
|
|
33
|
+
const PKG_DIR = resolve(HERE, '..')
|
|
34
|
+
const MANIFEST = JSON.parse(readFileSync(join(PKG_DIR, 'package.json'), 'utf8'))
|
|
35
|
+
const APP_BOOT = '@deepseek-ai/dsh-app-boot'
|
|
36
|
+
|
|
37
|
+
// ==================== 最小 semver 实现(仅在借不到宿主 semver 时使用)====================
|
|
38
|
+
|
|
39
|
+
function parseVersion(input) {
|
|
40
|
+
const m = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(String(input).trim())
|
|
41
|
+
if (!m) return null
|
|
42
|
+
return { nums: [Number(m[1]), Number(m[2]), Number(m[3])], pre: m[4] ? m[4].split('.') : [] }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function comparePre(a, b) {
|
|
46
|
+
if (a.length === 0 || b.length === 0) return a.length === b.length ? 0 : a.length === 0 ? 1 : -1
|
|
47
|
+
const len = Math.max(a.length, b.length)
|
|
48
|
+
for (let i = 0; i < len; i++) {
|
|
49
|
+
const x = a[i]
|
|
50
|
+
const y = b[i]
|
|
51
|
+
if (x === undefined) return -1
|
|
52
|
+
if (y === undefined) return 1
|
|
53
|
+
const xn = /^\d+$/.test(x)
|
|
54
|
+
const yn = /^\d+$/.test(y)
|
|
55
|
+
if (xn && yn) {
|
|
56
|
+
if (Number(x) !== Number(y)) return Number(x) < Number(y) ? -1 : 1
|
|
57
|
+
} else if (xn !== yn) {
|
|
58
|
+
return xn ? -1 : 1
|
|
59
|
+
} else if (x !== y) {
|
|
60
|
+
return x < y ? -1 : 1
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return 0
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function compareVersions(a, b) {
|
|
67
|
+
const pa = parseVersion(a)
|
|
68
|
+
const pb = parseVersion(b)
|
|
69
|
+
if (!pa || !pb) return NaN
|
|
70
|
+
for (let i = 0; i < 3; i++) if (pa.nums[i] !== pb.nums[i]) return pa.nums[i] < pb.nums[i] ? -1 : 1
|
|
71
|
+
return comparePre(pa.pre, pb.pre)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** 计算 ^ 与 ~ 的隐式上界,规则与 node-semver 一致(目标带 prerelease 时上界加 `-0`)。 */
|
|
75
|
+
function upperBound(op, t) {
|
|
76
|
+
let cap
|
|
77
|
+
if (op === '^') {
|
|
78
|
+
if (t.nums[0] !== 0) cap = [t.nums[0] + 1, 0, 0]
|
|
79
|
+
else if (t.nums[1] !== 0) cap = [0, t.nums[1] + 1, 0]
|
|
80
|
+
else cap = [0, 0, t.nums[2] + 1]
|
|
81
|
+
} else {
|
|
82
|
+
if (t.nums[0] !== 0) cap = [t.nums[0], t.nums[1] + 1, 0]
|
|
83
|
+
else cap = [0, t.nums[1] + 1, 0]
|
|
84
|
+
}
|
|
85
|
+
return `${cap[0]}.${cap[1]}.${cap[2]}${t.pre.length > 0 ? '-0' : ''}`
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function testComparator(version, comparator) {
|
|
89
|
+
const m = /^(>=|<=|>|<|=|\^|~)?\s*(.+)$/.exec(comparator.trim())
|
|
90
|
+
if (!m) return false
|
|
91
|
+
const op = m[1] || '='
|
|
92
|
+
const raw = m[2]
|
|
93
|
+
if (!parseVersion(raw) || !parseVersion(version)) return false
|
|
94
|
+
const c = compareVersions(version, raw)
|
|
95
|
+
switch (op) {
|
|
96
|
+
case '>=': return c >= 0
|
|
97
|
+
case '<=': return c <= 0
|
|
98
|
+
case '>': return c > 0
|
|
99
|
+
case '<': return c < 0
|
|
100
|
+
case '=': return c === 0
|
|
101
|
+
case '^':
|
|
102
|
+
case '~': return c >= 0 && compareVersions(version, upperBound(op, parseVersion(raw))) < 0
|
|
103
|
+
default: return false
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** 等价于 semver.satisfies(v, r, { includePrerelease: true }),仅覆盖本项目用到的语法。 */
|
|
108
|
+
export function satisfiesFallback(version, range) {
|
|
109
|
+
return String(range)
|
|
110
|
+
.split('||')
|
|
111
|
+
.some((alt) => alt.trim().split(/\s+/).filter(Boolean).every((c) => testComparator(version, c)))
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ==================== 定位 DSH 运行时 ====================
|
|
115
|
+
|
|
116
|
+
const argv = process.argv.slice(2)
|
|
117
|
+
const argValue = (flag) => {
|
|
118
|
+
const i = argv.indexOf(flag)
|
|
119
|
+
return i >= 0 && argv[i + 1] ? argv[i + 1] : undefined
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function anchors() {
|
|
123
|
+
const list = [process.cwd(), PKG_DIR, join(PKG_DIR, 'node_modules')]
|
|
124
|
+
const explicit = argValue('--dsh') || process.env.DSH_INSTALL_DIR || process.env.DSH_APP_BOOT_DIR
|
|
125
|
+
if (explicit) list.unshift(resolve(explicit))
|
|
126
|
+
const dshHome = process.env.DSH_HOME || join(homedir(), '.dsh')
|
|
127
|
+
const profiles = join(dshHome, 'profiles')
|
|
128
|
+
if (existsSync(profiles)) {
|
|
129
|
+
try {
|
|
130
|
+
for (const p of readdirSync(profiles)) list.push(join(profiles, p))
|
|
131
|
+
} catch { /* 忽略 */ }
|
|
132
|
+
}
|
|
133
|
+
return list
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function loadModule(anchorsList, spec) {
|
|
137
|
+
for (const anchor of anchorsList) {
|
|
138
|
+
try {
|
|
139
|
+
const req = createRequire(join(anchor, 'noop.js'))
|
|
140
|
+
const resolved = req.resolve(spec)
|
|
141
|
+
const mod = await import(pathToFileURL(resolved).href)
|
|
142
|
+
return { mod, resolved }
|
|
143
|
+
} catch { /* 换下一个 */ }
|
|
144
|
+
}
|
|
145
|
+
return null
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function locateAppBoot() {
|
|
149
|
+
const explicit = argValue('--dsh') || process.env.DSH_INSTALL_DIR || process.env.DSH_APP_BOOT_DIR
|
|
150
|
+
if (explicit) {
|
|
151
|
+
const base = resolve(explicit)
|
|
152
|
+
for (const p of [join(base, 'node_modules', APP_BOOT), join(base, APP_BOOT), base]) {
|
|
153
|
+
const pj = join(p, 'package.json')
|
|
154
|
+
if (!existsSync(pj)) continue
|
|
155
|
+
try {
|
|
156
|
+
if (JSON.parse(readFileSync(pj, 'utf8')).name === APP_BOOT) return p
|
|
157
|
+
} catch { /* 继续 */ }
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
for (const anchor of anchors()) {
|
|
161
|
+
try {
|
|
162
|
+
const req = createRequire(join(anchor, 'noop.js'))
|
|
163
|
+
return dirname(req.resolve(`${APP_BOOT}/package.json`))
|
|
164
|
+
} catch { /* 换下一个 */ }
|
|
165
|
+
}
|
|
166
|
+
return null
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const isCheckedPeer = (name) => name === '@deepseek-ai/dsh' || name.startsWith('@deepseek-ai/dsh-')
|
|
170
|
+
|
|
171
|
+
// ==================== 主流程 ====================
|
|
172
|
+
|
|
173
|
+
async function main() {
|
|
174
|
+
console.log(`dsh-soul v${MANIFEST.version} — DSH 兼容性自检`)
|
|
175
|
+
console.log('')
|
|
176
|
+
|
|
177
|
+
const peers = MANIFEST.peerDependencies || {}
|
|
178
|
+
console.log('peerDependencies')
|
|
179
|
+
for (const [name, range] of Object.entries(peers)) {
|
|
180
|
+
console.log(` ${isCheckedPeer(name) ? '· 校验' : '· 忽略'} ${name.padEnd(30)} ${range}`)
|
|
181
|
+
}
|
|
182
|
+
console.log('')
|
|
183
|
+
|
|
184
|
+
const appBootDir = locateAppBoot()
|
|
185
|
+
const searchAnchors = []
|
|
186
|
+
if (appBootDir) searchAnchors.push(appBootDir, join(appBootDir, '..'), join(appBootDir, '..', '..'), join(appBootDir, '..', '..', '..'))
|
|
187
|
+
searchAnchors.push(...anchors())
|
|
188
|
+
|
|
189
|
+
let runtimeVersion = argValue('--runtime') || null
|
|
190
|
+
let evalFn = null
|
|
191
|
+
if (appBootDir) {
|
|
192
|
+
const boot = await loadModule([appBootDir], APP_BOOT)
|
|
193
|
+
if (boot) {
|
|
194
|
+
const mod = boot.mod
|
|
195
|
+
// 仅在未显式指定 --runtime 时采用宿主自报的版本(否则会把用户指定的版本覆盖掉)
|
|
196
|
+
if (runtimeVersion === null && typeof mod.getDshRuntimeVersion === 'function') {
|
|
197
|
+
try { runtimeVersion = mod.getDshRuntimeVersion() } catch { /* 回退到文件读取 */ }
|
|
198
|
+
}
|
|
199
|
+
if (typeof mod.evaluatePluginCompatibility === 'function') evalFn = mod.evaluatePluginCompatibility
|
|
200
|
+
}
|
|
201
|
+
if (!runtimeVersion) {
|
|
202
|
+
try {
|
|
203
|
+
runtimeVersion = JSON.parse(readFileSync(join(appBootDir, 'package.json'), 'utf8')).version
|
|
204
|
+
} catch { /* 保持 null */ }
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (!runtimeVersion) {
|
|
209
|
+
console.log('跳过:未能定位 DSH 运行时。')
|
|
210
|
+
console.log('可用 --dsh <目录> 指定 DSH 安装目录,或用 --runtime <版本> 直接给出运行时版本。')
|
|
211
|
+
process.exit(0)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
console.log(`DSH 运行时版本:${runtimeVersion}`)
|
|
215
|
+
console.log(`定位来源:${appBootDir || '(--runtime 指定)'}`)
|
|
216
|
+
console.log('')
|
|
217
|
+
|
|
218
|
+
// semver 优先借宿主的;借不到用内置最小实现
|
|
219
|
+
let satisfies = null
|
|
220
|
+
const sem = await loadModule(searchAnchors, 'semver')
|
|
221
|
+
if (sem) {
|
|
222
|
+
const m = sem.mod.satisfies ? sem.mod : sem.mod.default
|
|
223
|
+
if (typeof m?.satisfies === 'function') satisfies = (v, r) => m.satisfies(v, r, { includePrerelease: true })
|
|
224
|
+
}
|
|
225
|
+
const mode = evalFn ? 'DSH 原生 evaluatePluginCompatibility' : satisfies ? '宿主 semver' : '内置最小实现'
|
|
226
|
+
|
|
227
|
+
console.log('判定')
|
|
228
|
+
const failures = []
|
|
229
|
+
for (const [name, range] of Object.entries(peers)) {
|
|
230
|
+
if (!isCheckedPeer(name)) {
|
|
231
|
+
console.log(` – 忽略 ${name.padEnd(30)} ${range} (DSH 不校验此类 peer)`)
|
|
232
|
+
continue
|
|
233
|
+
}
|
|
234
|
+
let ok
|
|
235
|
+
if (evalFn) {
|
|
236
|
+
const issue = evalFn({ name: MANIFEST.name, version: MANIFEST.version, peerDependencies: { [name]: range } }, {}, runtimeVersion)
|
|
237
|
+
ok = issue === undefined
|
|
238
|
+
} else {
|
|
239
|
+
ok = satisfies ? satisfies(runtimeVersion, range) : satisfiesFallback(runtimeVersion, range)
|
|
240
|
+
}
|
|
241
|
+
console.log(` ${ok ? '✓ 通过' : '✗ 不通过'} ${name.padEnd(30)} ${range}`)
|
|
242
|
+
if (!ok) failures.push([name, range])
|
|
243
|
+
}
|
|
244
|
+
console.log(` (判定方式:${mode})`)
|
|
245
|
+
|
|
246
|
+
console.log('')
|
|
247
|
+
console.log('运行时符号抽查(DSH 不做这层校验,仅作预警)')
|
|
248
|
+
let symbolMissing = 0
|
|
249
|
+
const audits = [
|
|
250
|
+
['@deepseek-ai/dsh-llm', ['createUserMessage']],
|
|
251
|
+
['@deepseek-ai/dsh-tools', ['defineTool', 'TOOL_RUNTIME_SCHEDULER']]
|
|
252
|
+
]
|
|
253
|
+
for (const [spec, symbols] of audits) {
|
|
254
|
+
const hit = await loadModule(searchAnchors, spec)
|
|
255
|
+
if (!hit) { console.log(` – ${spec}:未解析到,跳过`); continue }
|
|
256
|
+
const missing = symbols.filter((s) => !(s in hit.mod))
|
|
257
|
+
if (missing.length) symbolMissing += missing.length
|
|
258
|
+
console.log(` ${missing.length ? '✗' : '✓'} ${spec}:${missing.length ? '缺少 ' + missing.join(', ') : '符号齐备'}`)
|
|
259
|
+
}
|
|
260
|
+
for (const spec of MANIFEST.dsh?.client?.inject || []) {
|
|
261
|
+
const hit = await loadModule(searchAnchors, spec)
|
|
262
|
+
console.log(` ${hit ? '✓' : '–'} ${spec}:${hit ? '已解析' : '未解析到,跳过'}`)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
console.log('')
|
|
266
|
+
if (failures.length === 0) {
|
|
267
|
+
console.log('结果:兼容。')
|
|
268
|
+
if (symbolMissing > 0) console.log(`注意:仍有 ${symbolMissing} 个运行时符号缺失,需同步适配代码。`)
|
|
269
|
+
process.exit(0)
|
|
270
|
+
}
|
|
271
|
+
console.log(`结果:不兼容 —— DSH ${runtimeVersion} 不落在以下 peer 范围内:`)
|
|
272
|
+
for (const [name, range] of failures) console.log(` ${name} ${range}`)
|
|
273
|
+
console.log('')
|
|
274
|
+
console.log('处理方式:')
|
|
275
|
+
console.log(' 1. 放宽 package.json 的 peer 范围使其覆盖该运行时版本,然后升版本重新发布;')
|
|
276
|
+
console.log(' 2. 或让用户升级插件到已声明支持该 DSH 版本的版本。')
|
|
277
|
+
if (symbolMissing > 0) console.log(` 另:抽查到 ${symbolMissing} 个运行时符号缺失,说明不只是声明过期,代码也需适配。`)
|
|
278
|
+
process.exit(1)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const invokedDirectly = process.argv[1] !== undefined &&
|
|
282
|
+
import.meta.url === pathToFileURL(resolve(process.argv[1])).href
|
|
283
|
+
|
|
284
|
+
if (invokedDirectly) {
|
|
285
|
+
main().catch((error) => {
|
|
286
|
+
console.error('自检脚本异常:', error)
|
|
287
|
+
process.exit(1)
|
|
288
|
+
})
|
|
289
|
+
}
|