dsh-crossterm 0.8.11 → 0.8.12

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/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # dsh-crossterm 变更记录
2
2
 
3
+ ## 0.8.12 — 2026-10-20
4
+
5
+ ### 修复:更新链路在 pnpm 11 上必定失败;latest 被镜像滞后带偏
6
+
7
+ 来源:跨设备邮件(YOCE_C 经「同端多会话2」转发,2026-10-20T06:20:28Z)—— 0.8.11 复测报告。
8
+
9
+ - **`--prefer-online` 是 pnpm 11 的非法选项**:0.8.11 把它拼进了 dsh / cli / pnpm 三级兜底,
10
+ B 机实测 `[ERROR] Unknown option: 'prefer-online'`,exit 1 ⇒ 三条路一起挂。
11
+ 现在只给 pnpm 那步加它认识的 `--config.prefer-offline=false`;dsh / cli 两条路不加附加项。
12
+ - **24h 发布年龄策略**:新版本发布不到 24 小时会被 `minimumReleaseAge` 拒装
13
+ (`ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION`)。失败输出命中该关键字时,用
14
+ `--config.minimumReleaseAge=0` 重试一次,并把「已临时放宽」记进 `logs/update.log`。
15
+ - **`latestVersion()` 取最大版本**:原来「第一个能返回的 registry 就用」,而顺序是 npmmirror 优先,
16
+ 镜像滞后时会把 0.8.11 读成 0.8.10(钉版本也会钉到旧号)。现在两源都问、取最大版本,
17
+ 请求带 `cache-control: no-cache`。
18
+ - 探针 `probe-0811.mjs` 扩到 **25 项全 PASS**(新增「pnpm 合法选项」「不再出现 --prefer-online 参数」
19
+ 「minimumReleaseAge 重试」「两源取最大」四项,替换掉原来断言 --prefer-online 的两项)。
20
+
3
21
  ## 0.8.11 — 2026-10-20
4
22
 
5
23
  ### 更新不再把版本装低(YOCE_C 实测事故)
package/README.md CHANGED
@@ -28,23 +28,22 @@ A 终端看不到 B 终端里有哪个会话、在干什么,也没法把一条
28
28
  > `locatePkgJson()` 对子路径行返回 undefined),而插件页顶部标题与这一行共用同一份 `locale/zh.json` 的 meta,
29
29
  > 所以它单独做入口(配置卡片 + 自动更新开关),标题带「(自更新)」;卡片头用 `shortTitle` 显示短名「跨端互通」。
30
30
 
31
- **本版更新(0.8.11)**
32
-
33
- - **更新不再把版本装低**:点「更新」时钉死 `dsh-crossterm@<npm 最新版>` 并加 `--prefer-online`
34
- (以前 `@latest` 会命中 pnpm 缓存里的旧 packument,实测把 0.8.2 装成 0.6.1 还判成功);
35
- 装完必须**等于**最新版才算成功,装低了会自动回滚到原版本并报错。
36
- - **同 id 邮件副本不再各自重投**:一份邮件投递失败时,同 id 的其他副本直接归档,不会最后重复投递。
37
- - 本机是 `link:` 源码版,点更新仍会提示「改源码后重启」;以上对用 npm 安装的其他设备生效。
38
-
39
- **上一版(0.8.10)**
40
-
41
- - **云端设备显示规则调整**:每台设备显示 `名称(权限) · 在线状态`,例如 `YOCE_C(成员) · 3 小时前`;
42
- 版本号**只在它与本机版本不一致时**才显示(如 ` · v0.8.2`),与本机一致的设备不再挂版本号。
43
- - 只改客户端渲染,接口与数据不变;升级后刷新卡片即生效。
44
-
45
- - **第一个组件从「总开关」改成「自更新开关」**:关掉它只失去卡片与自动更新,跨会话 / 跨终端 / 跨设备 / 跨账号 各自独立。
46
- - **自动更新默认关**:卡片「自动更新」一行 + 开关,默认每 6 小时检查一次并自动安装,装完提示重启、不自动重启。
47
- - **服务注入拆掉**:五行都只 `inject(['agents'])`,不再 provide/inject 连锁。
31
+ **本版更新(0.8.12)**
32
+
33
+ - **修「点更新必定失败」**:0.8.11 给三级兜底都加了 `--prefer-online`,而这是 pnpm 11 的**非法选项**
34
+ (`[ERROR] Unknown option`),三条路会一起挂。现在只给 pnpm 那步加它认识的
35
+ `--config.prefer-offline=false`。
36
+ - **新版本发布不到 24h 也能装**:撞 `minimumReleaseAge` 策略(`ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION`)时,
37
+ 自动用 `--config.minimumReleaseAge=0` 重试一次,并在 `logs/update.log` 记一笔「临时放宽」。
38
+ - **npm 最新版读得准了**:原来「第一个能返回的镜像就用」(npmmirror 优先),镜像滞后时会把 0.8.12 读成旧号,
39
+ 钉版本也钉错。现在两个源都问、取最大版本。
40
+ - 本机是 `link:` 源码版,点更新仍提示「改源码后重启」;以上对用 npm 安装的其他设备生效。
41
+
42
+ **上一版(0.8.11)**
43
+
44
+ - **更新不再把版本装低**:钉死 `dsh-crossterm@<npm 最新版>`(原来是 `@latest`,会命中 pnpm 缓存的旧 packument,
45
+ 实测把 0.8.2 装成 0.6.1 还判成功);装完必须**等于**最新版才算成功,装低了自动回滚并报错。
46
+ - **同 id 邮件副本不再各自重投**:一份投递失败时,同 id 的其他副本直接归档。
48
47
 
49
48
  **更早(0.8.8 / 0.8.7 / 0.8.6 / 0.8.5 / 0.8.2 / 0.8.0)**
50
49
 
package/lib/bus.js CHANGED
@@ -23,7 +23,7 @@ import path from 'node:path'
23
23
  import crypto from 'node:crypto'
24
24
  import { rotateIfNeeded } from './logs.js'
25
25
 
26
- export const VERSION = '0.8.11'
26
+ export const VERSION = '0.8.12'
27
27
 
28
28
  /** DSH 的家目录:与宿主其它状态(sessions / profiles)同一个根,多终端天然共享 */
29
29
  export function dshHome() {
package/lib/web.js CHANGED
@@ -205,6 +205,10 @@ function compareVersion(a, b) {
205
205
  }
206
206
 
207
207
  async function latestVersion() {
208
+ // 0.8.12:原来「第一个能返回的 registry 就用」+ 顺序是 npmmirror 优先 → 镜像滞后时
209
+ // 会把 0.8.11 读成 0.8.10,钉版本也钉到旧号(YOCE_C 2026-10-20 实测)。
210
+ // 现在两源都问,取最大的那个版本;单源失败不影响。
211
+ const found = []
208
212
  let last = ''
209
213
  for (const registry of NPM_REGISTRIES) {
210
214
  const ctrl = new AbortController()
@@ -212,14 +216,17 @@ async function latestVersion() {
212
216
  try {
213
217
  const res = await fetch(`${registry}/${PKG}/latest`, {
214
218
  signal: ctrl.signal,
215
- headers: { accept: 'application/json' },
219
+ headers: { accept: 'application/json', 'cache-control': 'no-cache' },
216
220
  })
217
221
  if (!res.ok) {
218
222
  last = `HTTP ${res.status}`
219
223
  continue
220
224
  }
221
225
  const doc = await res.json()
222
- if (doc && typeof doc.version === 'string') return doc.version
226
+ if (doc && typeof doc.version === 'string') {
227
+ found.push(doc.version)
228
+ continue
229
+ }
223
230
  last = 'no version field'
224
231
  } catch (error) {
225
232
  last = String((error && error.message) || error)
@@ -227,6 +234,7 @@ async function latestVersion() {
227
234
  clearTimeout(timer)
228
235
  }
229
236
  }
237
+ if (found.length > 0) return found.sort(compareVersion).pop()
230
238
  throw new Error(last || 'unknown')
231
239
  }
232
240
 
@@ -369,7 +377,9 @@ function appendUpdateLog(cfg, record) {
369
377
  */
370
378
  async function updatePlugin(term, info, latest) {
371
379
  // 0.8.11:不再用 @latest —— pnpm 可能拿缓存里的旧 packument,把机器「更新」成老版本
372
- // (YOCE_C 实测 0.8.2 → 0.6.1,还判成功)。已知确切版本就钉版本号,并加 --prefer-online。
380
+ // (YOCE_C 实测 0.8.2 → 0.6.1,还判成功)。已知确切版本就钉版本号。
381
+ // 0.8.12:--prefer-online 是 pnpm 11 的非法选项([ERROR] Unknown option),
382
+ // 三级兜底会一起挂;pnpm 只认 --config.prefer-offline=false,所以改成只给 pnpm 步加这条。
373
383
  const pin = latest ? `${PKG}@${latest}` : ''
374
384
  const target = pin || `${PKG}@latest`
375
385
  const before = installedVersion(info)
@@ -408,23 +418,33 @@ async function updatePlugin(term, info, latest) {
408
418
 
409
419
  const { cmd: node, env } = nodeTool(term.cfg)
410
420
  const cli = cliScript()
411
- const flags = pin ? ['--prefer-online'] : []
412
- const plan = [{ label: 'dsh', cmd: 'dsh', args: ['plugin', '--profile', info.name, 'add', target, ...flags], opts: {} }]
421
+ // pnpm 11:--prefer-online 不是合法选项;prefer-offline 只能通过 --config. 前缀关掉。
422
+ // 新版本发布不到 24h 还会撞 minimumReleaseAge 策略,失败时用 policyArgs 重试一次并记日志。
423
+ const pnpmFlags = ['--config.prefer-offline=false']
424
+ const policyArgs = ['--config.minimumReleaseAge=0']
425
+ const policyRe = /minimum[-_]?release[-_]?age/i
426
+ const plan = [{ label: 'dsh', cmd: 'dsh', args: ['plugin', '--profile', info.name, 'add', target], opts: {} }]
413
427
  if (fs.existsSync(cli)) {
414
428
  plan.push({
415
429
  label: 'cli',
416
430
  cmd: process.execPath,
417
- args: ['--expose-internals', cli, 'plugin', '--profile', info.name, 'add', target, ...flags],
431
+ args: ['--expose-internals', cli, 'plugin', '--profile', info.name, 'add', target],
418
432
  opts: { shell: false, env: { ELECTRON_RUN_AS_NODE: '1' } },
419
433
  })
420
434
  }
421
435
  for (const pnpm of pnpmCandidates(term.cfg)) {
422
- plan.push({ label: 'pnpm', cmd: node, args: [pnpm, 'add', target, ...flags], opts: { shell: false, env } })
436
+ plan.push({ label: 'pnpm', cmd: node, args: [pnpm, 'add', target, ...pnpmFlags], opts: { shell: false, env } })
423
437
  }
424
438
 
425
439
  let last = null
426
- for (const step of plan) {
427
- const res = await record(step.label, step.cmd, step.args, step.opts)
440
+ for (const base of plan) {
441
+ let step = base
442
+ let res = await record(step.label, step.cmd, step.args, step.opts)
443
+ if (res.code !== 0 && policyRe.test(res.out || '')) {
444
+ const args = [...step.args, ...policyArgs]
445
+ res = await record(`${step.label}+release-age`, step.cmd, args, step.opts)
446
+ step = { ...step, args }
447
+ }
428
448
  last = res
429
449
  if (res.code !== 0) continue
430
450
  const result = await settle(step.label, step)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-crossterm",
3
- "version": "0.8.11",
3
+ "version": "0.8.12",
4
4
  "description": "跨端互通:同一 DSH 账号下的会话、终端、设备之间互通 —— 特征码链、内联邮件、云端中转站与自动备份",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",