ygc-dsh-plugin-autoupdate 1.1.1 → 1.2.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 +56 -1
- package/client.js +183 -18
- package/index.js +302 -19
- package/lib/api.js +149 -10
- package/lib/core.js +111 -6
- package/lib/gitref.js +74 -0
- package/lib/origin.js +196 -0
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -5,10 +5,12 @@
|
|
|
5
5
|
- **定时检查**:间隔自己设(最短 5 分钟,默认 360 分钟)
|
|
6
6
|
- **逐个插件定策略**:某个插件可以「发布后立即更新」,也可以「发布后等 N 小时」(默认 2 小时)
|
|
7
7
|
- **更新完是否自动重启**:独立开关,可设「只在没有会话跑的时候重启」和「重启前等待秒数」
|
|
8
|
+
- **本地装的插件也能更新**(1.2.0):本机是 `file:` 装的、上游其实是 GitHub 仓库的包,识别出来一起检查
|
|
8
9
|
|
|
9
10
|
## 打开位置
|
|
10
11
|
|
|
11
|
-
侧栏图标「插件自动更新」→
|
|
12
|
+
侧栏图标「插件自动更新」→ 主面板。面板分六块:总开关与频率、默认策略、
|
|
13
|
+
本地装的插件的 Git 上游识别、插件列表、重启设置、最近记录。
|
|
12
14
|
|
|
13
15
|
## 怎么判断「等够时间了」
|
|
14
16
|
|
|
@@ -20,6 +22,59 @@
|
|
|
20
22
|
发布时间从 npm registry 的 packument `time[version]` 取;取不到才退回「本次检查时间」。
|
|
21
23
|
本地路径(`file:`)和 Git 来源的包不参与检查 —— 它们没有「发布」这个概念。
|
|
22
24
|
|
|
25
|
+
> **1.2.0 起改了这一条**:本地装、但上游其实是 Git 仓库的包,现在也会联网检查。
|
|
26
|
+
> 见下面「本地装的插件,上游在 GitHub」一节。
|
|
27
|
+
|
|
28
|
+
## 本地装的插件,上游在 GitHub(1.2.0)
|
|
29
|
+
|
|
30
|
+
### 为什么会有这一条
|
|
31
|
+
|
|
32
|
+
`dsh-knowledge-wiki`、`dsh-purge-community` 这类包在本机是用本地 tgz 装的:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
"dsh-knowledge-wiki": "file:C:/DSH-Work/local-plugins/dsh-knowledge-wiki-0.39.1.tgz"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
来源判定只看这个写法 → 判成 `local` → **不检查、不更新**,面板上只写一句
|
|
39
|
+
「本地路径来源,不参与版本检查」。可它们的仓库在 GitHub 上有 tag,
|
|
40
|
+
`dsh-purge` 甚至自己就会检查更新。结果就是「能更新的插件永远停在装机那天」。
|
|
41
|
+
|
|
42
|
+
### 怎么识别的(判据只有一条是不放宽的)
|
|
43
|
+
|
|
44
|
+
1. 从**已装副本**的 `package.json` 里读 `repository` / `homepage`,解析出 `owner/repo`;
|
|
45
|
+
2. 到远端核实「仓库根就是这个包」——**远端 `package.json` 的 `name` 必须与本地包名逐字相同**。
|
|
46
|
+
仓库名与包名常常不一样(`dsh-knowledge-wiki` 的仓库叫 `dsh-knowledge-base`),
|
|
47
|
+
所以既不能靠仓库名,也不能靠「名字像不像」。放宽这一条会立刻误认一堆无关仓库;
|
|
48
|
+
3. 取远端最新版本:优先 semver tag(`v0.43.1` → `0.43.1`),没有 tag 才退回 HEAD 的 `version`。
|
|
49
|
+
|
|
50
|
+
核实通过后,`updateKind()` 把这类包判成 **`git-local`**:参与联网检查、出现在
|
|
51
|
+
「已装插件」那一组,面板标「Git 上游·本地装」。
|
|
52
|
+
|
|
53
|
+
### 检查与升级各做什么
|
|
54
|
+
|
|
55
|
+
| 阶段 | 做什么 |
|
|
56
|
+
|---|---|
|
|
57
|
+
| 检查 | 比**版本号**(本机 `0.39.1` vs 上游 tag `0.43.1`)。本机是 tgz 装出来的,没有 commit 可比 |
|
|
58
|
+
| 升级(手动点) | 把依赖写法换成 `github:owner/repo#v0.43.1`,走 `installSpec` 装;装不成**原样还原**写法 |
|
|
59
|
+
| 升级(定时任务) | **默认不自动装**,只报到面板。要自动就在设置里开「定时任务也自动装这类更新」 |
|
|
60
|
+
|
|
61
|
+
为什么定时默认不装:这一步会改 profile 的 `package.json`,属于「换安装方式」而不只是升版本。
|
|
62
|
+
装出来的那份可能不再带本机的定制,也可能缺 peer 依赖。换成功之后这个包就变成正常的
|
|
63
|
+
`git` 来源(此后比 commit),不再是 `git-local`。
|
|
64
|
+
|
|
65
|
+
### 面板上的开关
|
|
66
|
+
|
|
67
|
+
- **识别本地来源的 Git 上游**(默认开):关掉即回到旧行为,本地来源一律不查;
|
|
68
|
+
- **定时任务也自动装这类更新**(默认关):见上表;
|
|
69
|
+
- 每个识别结果都能单独「停用」(回到本地来源)或「恢复」;
|
|
70
|
+
- 「重新识别上游」强制重探(忽略 24 小时缓存)。
|
|
71
|
+
|
|
72
|
+
### 为什么识别结果要落盘
|
|
73
|
+
|
|
74
|
+
探测是联网动作(`git ls-remote` + 一个 `raw.githubusercontent.com` 请求)。
|
|
75
|
+
结果存进 `~/.dsh/storages/plugin-autoupdate.json` 的 `gitOrigins`,带 `checkedAt`,
|
|
76
|
+
24 小时内不重复打网络;重启 DSH 也不会把识别结果丢掉。
|
|
77
|
+
|
|
23
78
|
## 更新怎么执行
|
|
24
79
|
|
|
25
80
|
1. 先把 profile 的 `package.json` / `pnpm-lock.yaml` / `pnpm-workspace.yaml` 快照到
|
package/client.js
CHANGED
|
@@ -176,7 +176,13 @@ function makePanel(React) {
|
|
|
176
176
|
const registryPlugins = managed.filter((p) => p.kind === 'registry');
|
|
177
177
|
// git 与 registry 一样参与自动更新,只是比的是 commit 而不是版本号
|
|
178
178
|
const gitPlugins = managed.filter((p) => p.kind === 'git');
|
|
179
|
-
|
|
179
|
+
// git-local:本机是 file: 装的,但上游核实过就是这个包的 GitHub 仓库。
|
|
180
|
+
// 它和 registry / git 一样参与联网检查(比 tag 版本号),所以归进「已装插件」那一组;
|
|
181
|
+
// 区别只在于升级时会把依赖写法换成 github:owner/repo#tag。
|
|
182
|
+
const gitLocalPlugins = managed.filter((p) => p.kind === 'git-local');
|
|
183
|
+
const otherPlugins = managed.filter(
|
|
184
|
+
(p) => p.kind !== 'registry' && p.kind !== 'git' && p.kind !== 'git-local',
|
|
185
|
+
);
|
|
180
186
|
const available = plugins.filter((p) => p.updateAvailable);
|
|
181
187
|
const ready = available.filter((p) => !p.waitMs);
|
|
182
188
|
// 被隐藏的本体插件数量:宿主报了就用宿主的,没报就按本地筛掉的差值兜底。
|
|
@@ -319,8 +325,137 @@ function makePanel(React) {
|
|
|
319
325
|
),
|
|
320
326
|
);
|
|
321
327
|
|
|
328
|
+
/**
|
|
329
|
+
* 「本地装、上游是 Git」识别卡片。
|
|
330
|
+
*
|
|
331
|
+
* 为什么要有它:这类包(dsh-knowledge-wiki、dsh-purge-community)以前被判成
|
|
332
|
+
* local 之后既不显示、也不检查,用户完全看不到原因。这里把识别结果摊开:
|
|
333
|
+
* 认出了哪个仓库、最新是哪个 tag、认不出来的那句 error 也照实写。
|
|
334
|
+
*/
|
|
335
|
+
const origins = Array.isArray(snap.gitOrigins) ? snap.gitOrigins : [];
|
|
336
|
+
const originCard = h(
|
|
337
|
+
'div',
|
|
338
|
+
{ className: 'pau-card' },
|
|
339
|
+
h(
|
|
340
|
+
'div',
|
|
341
|
+
{ className: 'pau-card-h' },
|
|
342
|
+
h('h3', { className: 'pau-card-t' }, '本地装的插件 · Git 上游识别'),
|
|
343
|
+
h(
|
|
344
|
+
'span',
|
|
345
|
+
{ className: snap.detectGitOrigins ? 'pau-tag pau-tag-ok' : 'pau-tag' },
|
|
346
|
+
snap.detectGitOrigins ? '已开启' : '已关闭',
|
|
347
|
+
),
|
|
348
|
+
),
|
|
349
|
+
h(
|
|
350
|
+
'p',
|
|
351
|
+
{ className: 'pau-sub' },
|
|
352
|
+
'有些插件本机是用本地 tgz 装的,但上游其实在 GitHub 发 tag。开启后会对这类插件核对仓库,识别成功的按 Git 参与联网检查与升级(升级时依赖写法会换成 github: 地址)。',
|
|
353
|
+
),
|
|
354
|
+
h(
|
|
355
|
+
'label',
|
|
356
|
+
{ className: 'pau-switch' },
|
|
357
|
+
h('input', {
|
|
358
|
+
type: 'checkbox',
|
|
359
|
+
checked: !!snap.detectGitOrigins,
|
|
360
|
+
onChange: (e) => patchSettings({ detectGitOrigins: e.target.checked }),
|
|
361
|
+
}),
|
|
362
|
+
'识别本地来源的 Git 上游',
|
|
363
|
+
),
|
|
364
|
+
h(
|
|
365
|
+
'label',
|
|
366
|
+
{ className: 'pau-switch' },
|
|
367
|
+
h('input', {
|
|
368
|
+
type: 'checkbox',
|
|
369
|
+
disabled: !snap.detectGitOrigins,
|
|
370
|
+
checked: !!snap.autoApplyGitLocal,
|
|
371
|
+
onChange: (e) => patchSettings({ autoApplyGitLocal: e.target.checked }),
|
|
372
|
+
}),
|
|
373
|
+
'定时任务也自动装这类更新(默认只提示,因为升级会把依赖写法从 file: 换成 github:)',
|
|
374
|
+
),
|
|
375
|
+
h(
|
|
376
|
+
'div',
|
|
377
|
+
{ className: 'pau-field' },
|
|
378
|
+
h(
|
|
379
|
+
'button',
|
|
380
|
+
{
|
|
381
|
+
className: 'pau-btn',
|
|
382
|
+
disabled: !!busy || !snap.detectGitOrigins,
|
|
383
|
+
onClick: () =>
|
|
384
|
+
run('origins', async () => {
|
|
385
|
+
const next = await call('/origins/refresh', { force: true });
|
|
386
|
+
const n = next.result && next.result.changed;
|
|
387
|
+
setNote(n ? `已重新识别 ${n} 个本地来源` : '没有需要重新识别的本地来源');
|
|
388
|
+
return next;
|
|
389
|
+
}),
|
|
390
|
+
},
|
|
391
|
+
busy === 'origins' ? '识别中…' : '重新识别上游',
|
|
392
|
+
),
|
|
393
|
+
h(
|
|
394
|
+
'span',
|
|
395
|
+
{ className: 'pau-row-d' },
|
|
396
|
+
origins.length ? `已记录 ${origins.length} 个候选(含识别失败的)` : '还没有识别记录',
|
|
397
|
+
),
|
|
398
|
+
),
|
|
399
|
+
origins.length
|
|
400
|
+
? h(
|
|
401
|
+
'div',
|
|
402
|
+
{ className: 'pau-scroll' },
|
|
403
|
+
origins.map((item) =>
|
|
404
|
+
h(
|
|
405
|
+
'div',
|
|
406
|
+
{ className: 'pau-other', key: item.name },
|
|
407
|
+
h(
|
|
408
|
+
'div',
|
|
409
|
+
{ className: 'pau-other-main' },
|
|
410
|
+
h(
|
|
411
|
+
'div',
|
|
412
|
+
{ className: 'pau-row-t' },
|
|
413
|
+
h('span', { className: 'pau-mono' }, item.name),
|
|
414
|
+
item.ok
|
|
415
|
+
? h('span', { className: 'pau-tag pau-tag-ok' }, '已识别')
|
|
416
|
+
: h('span', { className: 'pau-tag pau-tag-err' }, '未识别'),
|
|
417
|
+
item.disabled ? h('span', { className: 'pau-tag' }, '已停用') : null,
|
|
418
|
+
item.ok && item.latestRef ? h('span', { className: 'pau-tag' }, item.latestRef) : null,
|
|
419
|
+
),
|
|
420
|
+
h(
|
|
421
|
+
'div',
|
|
422
|
+
{ className: 'pau-row-d' },
|
|
423
|
+
item.ok
|
|
424
|
+
? `${item.owner}/${item.repo}${item.latest ? ` · 最新 v${item.latest}` : ' · 上游没打版本 tag(只比 commit)'}`
|
|
425
|
+
: item.error || '未识别',
|
|
426
|
+
),
|
|
427
|
+
),
|
|
428
|
+
item.ok
|
|
429
|
+
? h(
|
|
430
|
+
'button',
|
|
431
|
+
{
|
|
432
|
+
className: 'pau-btn pau-btn-sm',
|
|
433
|
+
disabled: !!busy,
|
|
434
|
+
title: item.disabled ? '重新参与检查' : '停用后这个包回到「本地来源」,不再联网检查',
|
|
435
|
+
onClick: () =>
|
|
436
|
+
run(`origin-toggle:${item.name}`, async () => {
|
|
437
|
+
const next = await call('/origins/toggle', {
|
|
438
|
+
name: item.name,
|
|
439
|
+
disabled: !item.disabled,
|
|
440
|
+
});
|
|
441
|
+
setNote(`${item.name} 上游识别已${item.disabled ? '恢复' : '停用'}`);
|
|
442
|
+
return next;
|
|
443
|
+
}),
|
|
444
|
+
},
|
|
445
|
+
busy === `origin-toggle:${item.name}` ? '处理中…' : item.disabled ? '恢复' : '停用',
|
|
446
|
+
)
|
|
447
|
+
: null,
|
|
448
|
+
),
|
|
449
|
+
),
|
|
450
|
+
)
|
|
451
|
+
: null,
|
|
452
|
+
);
|
|
453
|
+
|
|
322
454
|
const pluginRow = (plugin) => {
|
|
323
455
|
const isGit = plugin.kind === 'git';
|
|
456
|
+
// git-local:本机 file: 装着,但上游核实过就是这个包的 GitHub 仓库。
|
|
457
|
+
// 参与联网检查(比 tag 版本号),升级时把依赖写法换成 github:owner/repo#tag。
|
|
458
|
+
const isGitLocal = plugin.kind === 'git-local';
|
|
324
459
|
// 三种特殊行,各自的状态文案必须诚实:
|
|
325
460
|
// system —— 随 DSH 安装(本体插件已整组隐藏,这里只作兜底)
|
|
326
461
|
// missing —— 宿主知道但没装,不是「已是最新」
|
|
@@ -346,17 +481,24 @@ function makePanel(React) {
|
|
|
346
481
|
: plugin.latestError
|
|
347
482
|
? '查询失败'
|
|
348
483
|
: '已是最新';
|
|
349
|
-
// git 来源没有版本号可比:当前版本只认 commit,「最新」也只写短 sha
|
|
484
|
+
// git 来源没有版本号可比:当前版本只认 commit,「最新」也只写短 sha。
|
|
485
|
+
// git-local 反而是靠版本号比的(本机是 tag 打出来的 tgz),
|
|
486
|
+
// 所以它的「最新」写成 tag 更直观:最新 v0.43.1。
|
|
350
487
|
const currentCommit = plugin.git && plugin.git.commit ? String(plugin.git.commit).slice(0, 10) : '';
|
|
351
488
|
const showLatest = isGit
|
|
352
489
|
? Boolean(plugin.latest && plugin.latest !== currentCommit)
|
|
353
490
|
: Boolean(plugin.latest && plugin.latest !== plugin.version);
|
|
354
|
-
const latestLabel = isGit
|
|
355
|
-
|
|
491
|
+
const latestLabel = isGit
|
|
492
|
+
? `远端 ${plugin.latest}`
|
|
493
|
+
: isGitLocal && plugin.latestTag
|
|
494
|
+
? `最新 ${plugin.latestTag}`
|
|
495
|
+
: `最新 v${plugin.latest}`;
|
|
496
|
+
// npm 上有同名包才算「能切换」;查不到就明确说没有,免得用户反复猜。
|
|
497
|
+
// git / git-local 一律不给这个按钮:它们已经能联网更新了,切 npm 只会丢掉信息。
|
|
356
498
|
const migration = plugin.npmMigration;
|
|
357
|
-
const canMigrate = !isGit && plugin.kind === 'local' && migration && migration.available;
|
|
499
|
+
const canMigrate = !isGit && !isGitLocal && plugin.kind === 'local' && migration && migration.available;
|
|
358
500
|
const migrationNote =
|
|
359
|
-
!isGit && plugin.kind === 'local' && migration
|
|
501
|
+
!isGit && !isGitLocal && plugin.kind === 'local' && migration
|
|
360
502
|
? migration.available
|
|
361
503
|
? `npm 上有同名包 ${migration.latest}${migration.upgradable ? '(更高)' : ''},可切换来源`
|
|
362
504
|
: 'npm 上没有同名包,保持原来源'
|
|
@@ -372,6 +514,8 @@ function makePanel(React) {
|
|
|
372
514
|
{ className: 'pau-row-t' },
|
|
373
515
|
h('span', { className: 'pau-mono' }, plugin.name),
|
|
374
516
|
isGit ? h('span', { className: 'pau-tag' }, 'Git') : null,
|
|
517
|
+
// git-local 要标出来:不然用户看到「本地 tgz 装的包也会联网检查」会以为是 bug
|
|
518
|
+
isGitLocal ? h('span', { className: 'pau-tag pau-tag-mine' }, 'Git 上游·本地装') : null,
|
|
375
519
|
h('span', { className: 'pau-tag' }, plugin.version ? `v${plugin.version}` : '未装'),
|
|
376
520
|
isGit && currentCommit ? h('span', { className: 'pau-tag' }, currentCommit) : null,
|
|
377
521
|
showLatest ? h('span', { className: 'pau-tag' }, latestLabel) : null,
|
|
@@ -381,11 +525,22 @@ function makePanel(React) {
|
|
|
381
525
|
? h('div', { className: 'pau-row-d' }, `查询失败:${plugin.latestError}`)
|
|
382
526
|
: isGit && plugin.latestMessage
|
|
383
527
|
? h('div', { className: 'pau-row-d' }, `${plugin.latestTag ? `${plugin.latestTag} · ` : ''}${plugin.latestMessage}`)
|
|
384
|
-
:
|
|
385
|
-
? h(
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
528
|
+
: isGitLocal
|
|
529
|
+
? h(
|
|
530
|
+
'div',
|
|
531
|
+
{ className: 'pau-row-d' },
|
|
532
|
+
`Git 上游 ${plugin.origin && plugin.origin.owner ? `${plugin.origin.owner}/${plugin.origin.repo}` : '(已识别)'}` +
|
|
533
|
+
`${plugin.origin && plugin.origin.latestRef ? ` · 最新 ${plugin.origin.latestRef}` : ''}` +
|
|
534
|
+
`${plugin.origin && plugin.origin.latest ? `(v${plugin.origin.latest})` : ''}` +
|
|
535
|
+
' · 升级时依赖写法会换成 github: 地址',
|
|
536
|
+
)
|
|
537
|
+
: migrationNote
|
|
538
|
+
? h('div', { className: 'pau-row-d' }, migrationNote)
|
|
539
|
+
: plugin.originError && plugin.kind === 'local'
|
|
540
|
+
? h('div', { className: 'pau-row-d' }, `上游识别:${plugin.originError}`)
|
|
541
|
+
: plugin.description
|
|
542
|
+
? h('div', { className: 'pau-row-d' }, plugin.description.slice(0, 160))
|
|
543
|
+
: null,
|
|
389
544
|
),
|
|
390
545
|
// 系统插件 / 未安装 / 直链来源的策略与「立即更新」都是假的:
|
|
391
546
|
// 一个版本跟桌面端走,一个根本没装,一个没有版本号可比。
|
|
@@ -431,7 +586,11 @@ function makePanel(React) {
|
|
|
431
586
|
{
|
|
432
587
|
className: 'pau-btn pau-btn-sm',
|
|
433
588
|
disabled: !!busy || !plugin.updateAvailable,
|
|
434
|
-
title:
|
|
589
|
+
title: isGitLocal
|
|
590
|
+
? `切到 Git 上游 ${plugin.latestTag || plugin.latest || ''}(会把依赖写法换成 github: 地址)`
|
|
591
|
+
: isGit
|
|
592
|
+
? '安装远端最新提交'
|
|
593
|
+
: '安装最新版本',
|
|
435
594
|
onClick: () =>
|
|
436
595
|
run(`update:${plugin.name}`, async () => {
|
|
437
596
|
const body = isGit
|
|
@@ -541,14 +700,19 @@ function makePanel(React) {
|
|
|
541
700
|
h(
|
|
542
701
|
'h3',
|
|
543
702
|
{ className: 'pau-card-t' },
|
|
544
|
-
// 只数「真正参与自动更新」的(registry + git
|
|
545
|
-
//
|
|
546
|
-
|
|
703
|
+
// 只数「真正参与自动更新」的(registry + git + git-local)。
|
|
704
|
+
// local / 直链 / 系统 / 未装各自单列,混进这个数字会让「已装插件(N)」
|
|
705
|
+
// 与实际能自动更新的数量不符。
|
|
706
|
+
`已装插件(${registryPlugins.length + gitPlugins.length + gitLocalPlugins.length})`,
|
|
707
|
+
),
|
|
708
|
+
h(
|
|
709
|
+
'span',
|
|
710
|
+
{ className: 'pau-row-d' },
|
|
711
|
+
available.length ? `${available.length} 个可更新` : '全部最新',
|
|
547
712
|
),
|
|
548
|
-
h('span', { className: 'pau-row-d' }, available.length ? `${available.length} 个可更新` : '全部最新'),
|
|
549
713
|
),
|
|
550
|
-
registryPlugins.length + gitPlugins.length
|
|
551
|
-
? registryPlugins.concat(gitPlugins).map(pluginRow)
|
|
714
|
+
registryPlugins.length + gitPlugins.length + gitLocalPlugins.length
|
|
715
|
+
? registryPlugins.concat(gitPlugins).concat(gitLocalPlugins).map(pluginRow)
|
|
552
716
|
: h('div', { className: 'pau-empty' }, '没有可联网检查的插件'),
|
|
553
717
|
otherPlugins.length
|
|
554
718
|
? h(
|
|
@@ -689,6 +853,7 @@ function makePanel(React) {
|
|
|
689
853
|
: null,
|
|
690
854
|
masterCard,
|
|
691
855
|
policyCard,
|
|
856
|
+
originCard,
|
|
692
857
|
pluginsCard,
|
|
693
858
|
restartCard,
|
|
694
859
|
historyCard,
|