@noob-stupid/dsh-plugin-console 0.5.20 → 0.5.21
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/lib/client.js
CHANGED
|
@@ -5217,7 +5217,7 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
|
|
|
5217
5217
|
phase: done?.ok === true ? "done" : "error",
|
|
5218
5218
|
text: parts.join(" · "),
|
|
5219
5219
|
level: done?.ok === true ? null : "warn",
|
|
5220
|
-
title: [done?.command, done?.stdout, raw].filter((s) => typeof s === "string" && s !== "").join("\n") || null,
|
|
5220
|
+
title: [done?.command, typeof done?.exitCode === "number" ? "exitCode=" + done.exitCode : null, done?.stdout, raw].filter((s) => typeof s === "string" && s !== "").join("\n") || null,
|
|
5221
5221
|
closed: false,
|
|
5222
5222
|
});
|
|
5223
5223
|
},
|
|
@@ -34,6 +34,19 @@ const PROBE_TIMEOUT_MS = 8000
|
|
|
34
34
|
const REPAIR_TIMEOUT_MS = 180000
|
|
35
35
|
const DEP_SECTIONS = ['dependencies', 'devDependencies', 'optionalDependencies']
|
|
36
36
|
|
|
37
|
+
/**
|
|
38
|
+
* spec 是不是**非 registry 来源**(`link:` / `file:` / `workspace:` / `portal:` / URL / git / 别名)。
|
|
39
|
+
* 2026-09-27 改错(与 0.5.20 的写回规则配套):这类依赖**不经 registry 解析**,所以"registry 上 404"
|
|
40
|
+
* 对它们毫无信息量 —— 体检不能拿它判问题,重建更不能被它拦下。真实现场:desktop profile 的两个
|
|
41
|
+
* `@dsh-external/*` 按新规则钉成 `link:` 之后,体检仍按包名去 registry 探,报 `fetch-404` 并把重建
|
|
42
|
+
* **永久**挡在门外(`repair.applicable=false`),而 lock 其实完全一致。
|
|
43
|
+
* 与 `specSatisfiedBy` 共用同一份判据(唯一真源,避免两处各写一条正则)。
|
|
44
|
+
*/
|
|
45
|
+
function isSourceSpec(spec) {
|
|
46
|
+
return typeof spec === 'string'
|
|
47
|
+
&& /^(?:link|file|workspace|portal|npm|git\+|git:|github:|gitlab:|bitbucket:|https?:)/iu.test(spec.trim())
|
|
48
|
+
}
|
|
49
|
+
|
|
37
50
|
/** 重建 lock 的 argv(纯函数,唯一产出点):只重写 lock,不碰 node_modules;
|
|
38
51
|
* `--no-frozen-lockfile` 是必需的(我们的 pnpm env 带 CI=true,pnpm 在 CI 下默认 frozen-lockfile,
|
|
39
52
|
* 不加它就只会得到 `ERR_PNPM_OUTDATED_LOCKFILE` —— 正是要修的那个症状)。
|
|
@@ -111,7 +124,7 @@ function parseLockImporters(lockText) {
|
|
|
111
124
|
* · 非 registry 来源(link:/file:/git+/http…)→ 交给 specifier 相等判定,这里恒 true。 */
|
|
112
125
|
function specSatisfiedBy(spec, version) {
|
|
113
126
|
if (typeof spec !== 'string' || spec === '') return true
|
|
114
|
-
if (
|
|
127
|
+
if (isSourceSpec(spec)) return true
|
|
115
128
|
if (typeof version !== 'string' || version === '') return false
|
|
116
129
|
if (/^[\^~]?\d/u.test(spec) || /^(?:>=|>|=|<=|<)\s*\d/u.test(spec)) return semverRangeMatch(version, spec)
|
|
117
130
|
return version === spec
|
|
@@ -151,7 +164,9 @@ function diffLockfile({ manifestText, lockText, installed = {} } = {}) {
|
|
|
151
164
|
state = 'version-mismatch'
|
|
152
165
|
}
|
|
153
166
|
const onDisk = installed[dep.name] ?? null
|
|
154
|
-
|
|
167
|
+
// 来源型 spec(link:/file:/URL/git)没有"版本号相等"可比:按盘上版本号与 lock 里的
|
|
168
|
+
// `link:../../…` 比,必然"漂移"(假阳性)。两个方向都判来源(spec 或 lock 解析任一是来源)。
|
|
169
|
+
if (onDisk !== null && locked.version !== null && !isSourceSpec(dep.spec) && !isSourceSpec(locked.version) && onDisk !== locked.version) {
|
|
155
170
|
drift.push({ name: dep.name, installed: onDisk, lockVersion: locked.version })
|
|
156
171
|
}
|
|
157
172
|
deps.push({ name: dep.name, spec: dep.spec, section: dep.section, lockSpecifier: locked.specifier, lockVersion: locked.version, state })
|
|
@@ -250,8 +265,10 @@ async function runLockfileCheck({
|
|
|
250
265
|
const diff = diffLockfile({ manifestText: manifestText ?? '', lockText, installed })
|
|
251
266
|
const manifest = readManifestDeps(manifestText ?? '')
|
|
252
267
|
|
|
253
|
-
// ① 依赖能不能在 registry 上解析(404 要点名;不可达与 404
|
|
254
|
-
|
|
268
|
+
// ① 依赖能不能在 registry 上解析(404 要点名;不可达与 404 分开说)。
|
|
269
|
+
// **来源型 spec 跳过探测**(2026-09-27 改错):link:/file:/URL/git 本来就不经 registry 解析。
|
|
270
|
+
const sourceSpecDeps = (manifest.ok ? manifest.deps : []).filter((dep) => isSourceSpec(dep.spec)).map((dep) => dep.name)
|
|
271
|
+
const probes = await Promise.all((manifest.ok ? manifest.deps : []).filter((dep) => !isSourceSpec(dep.spec)).map(async (dep) => {
|
|
255
272
|
const result = await probe(dep.name, probeList, {
|
|
256
273
|
version: exactVersionOf(dep.spec),
|
|
257
274
|
timeoutMs: PROBE_TIMEOUT_MS,
|
|
@@ -316,6 +333,8 @@ async function runLockfileCheck({
|
|
|
316
333
|
lockfile: { present: diff.lockfilePresent, parsed: diff.lockfileParsed, entries: diff.deps.filter((d) => d.lockVersion !== null).length },
|
|
317
334
|
problems,
|
|
318
335
|
packages404: name404,
|
|
336
|
+
// 非 registry 来源的依赖(link:/file:/URL/git):明确列出来,说明"为什么没探测它们"
|
|
337
|
+
sourceLinked: sourceSpecDeps,
|
|
319
338
|
outdated: {
|
|
320
339
|
lockfileMissing: !diff.lockfilePresent,
|
|
321
340
|
missing: diff.missing,
|
|
@@ -422,6 +441,7 @@ export {
|
|
|
422
441
|
diffLockfile,
|
|
423
442
|
exactVersionOf,
|
|
424
443
|
freshReleases,
|
|
444
|
+
isSourceSpec,
|
|
425
445
|
parseLockImporters,
|
|
426
446
|
problemLines,
|
|
427
447
|
probeVerdict,
|
|
@@ -177,9 +177,15 @@ async function runSuggestedAction({ body, profileDir, registries = [], deps = {}
|
|
|
177
177
|
const manifests = { before, after, changed: before !== after, planned: pinned.spec, pinned: pinnedOk }
|
|
178
178
|
const notes = []
|
|
179
179
|
if (run.relaxedReleaseAge) notes.push('本机 pnpm 的 24h 供应链闸(minimumReleaseAge)拦下了这次 lock 校验,已**仅对这一条命令**追加 --config.minimumReleaseAge=0 重试一次(有安全代价,未写进任何配置文件)。')
|
|
180
|
-
|
|
181
|
-
//
|
|
182
|
-
if (!run.ok
|
|
180
|
+
// 三种"pnpm 那一步没跑成"的形态都如实记一句(2026-09-27 真机桌面端实例实测:corepack 在该进程里
|
|
181
|
+
// 解析不到 → pnpm 那一步失败,而清单/lock 其实已达成目标;只留 stderr 会让用户自己猜发生了什么)
|
|
182
|
+
if (!run.ok) {
|
|
183
|
+
notes.push(manifests.pinned
|
|
184
|
+
? (lockSynced
|
|
185
|
+
? `pnpm 那一步没跑完(exitCode=${run.exitCode},原始输出见 stderr):清单与 lock 已经是 link:,目标状态已达成。`
|
|
186
|
+
: `清单已钉住(下次 pnpm 操作不会再 404),但 lock 没能对齐(exitCode=${run.exitCode}):见 stderr。`)
|
|
187
|
+
: `清单与 lock 都没改成功(exitCode=${run.exitCode}):见 stderr(原始输出已原样回显)。`)
|
|
188
|
+
}
|
|
183
189
|
return {
|
|
184
190
|
...base,
|
|
185
191
|
// 只有"清单真的是 link: **且** lock 里也有这条 link"才算成功;只成一半时 partial=true 并如实说明
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noob-stupid/dsh-plugin-console",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.21",
|
|
4
4
|
"description": "DSH 框架升级安全与插件升级门控:一键升级、失败自动回滚、升级后回滚上版、旧插件不适配自动禁用;内置多源插件市场为发现层,插件源全部可自定义,可指向公司内网私有源 / 私有索引 / 本地 Git 仓库,纯内网离线可用 | Framework upgrade safety & plugin version gating for DSH, with a customizable multi-source plugin market: point every source at internal mirrors or a local file:// repo for intranet-only, offline installs.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|