dsh-paoding 0.3.5 → 0.3.6
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 +4 -4
- package/README_en.md +4 -4
- package/docs/architecture.md +1 -1
- package/docs/architecture_en.md +1 -1
- package/docs/installation.md +5 -5
- package/docs/installation_en.md +5 -5
- package/icon.svg +8 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +6 -2
- package/plugins/paoding-config-ui/index.mjs +4 -3
- package/plugins/paoding-config-ui/lib/base.css +28 -0
- package/plugins/paoding-config-ui/lib/client.js +38 -4
- package/plugins/paoding-config-ui/package.json +1 -1
- package/tools/lib/upgrade.mjs +13 -7
- package/tools/lib/version.mjs +58 -30
package/README.md
CHANGED
|
@@ -17,9 +17,9 @@ dsh-paoding(中文品牌「庖丁」,典出《庄子》——庖丁顺纹理
|
|
|
17
17
|
- **装了什么都能认出来**:MCP 服务器、本地插件、已装技能,安装与配置时全程检测;默认只装 dsh 基础工具,检测到的 host 工具在「庖丁配置」里按需勾选;停用哪个,重新应用后相关工具自动剔除。
|
|
18
18
|
- **按工作区各有各的班底**:不同项目可以配不同的主/子 agent——「庖丁配置」里选定工作区单独配置,每个工作区生成自己的预设(`orchestrator-<目录名>`),新建会话时选对应预设即可,全局默认不受影响。
|
|
19
19
|
- **图形界面配置**:不习惯改配置文件的话,点开左侧栏底部动作条(设置行上方)的「庖丁配置」入口,整页点选即可,「保存并应用」即时重生成预设——与首装自动化同一条生成管线。
|
|
20
|
-
- **版本更新有提醒,面板一键升级**:面板会对比 npm registry(GitHub release
|
|
20
|
+
- **版本更新有提醒,面板一键升级**:面板会对比 npm registry(npmmirror 镜像、GitHub release 依次兜底)上的最新版本,发现新版就地提示并附上发布页链接;点「升级」就地执行 `dsh plugin update dsh-paoding`(profile 自动探测)换上新版,重启 DSH 后生效,编排预设会在重启时按新版自动重生成。开发检出的 link 形态无法就地升级,面板会提示切回 registry 版的办法;检测失败时页头留一行「版本检测失败 · 重试」(完整原因与代理排查提示在悬浮提示里),不弹窗打扰。
|
|
21
21
|
- **来去自由**:不改 DSH 一行源码;装完新会话即用,卸载即删目录。
|
|
22
|
-
- **两代宿主都兼容**:DSH 0.1.5 / 0.1.6 / 0.1.7-rc.1 全支持——两代宿主发现预设的机制不同(目录扫描 vs patch 声明行),安装器自动检测宿主版本选对落点,宿主升级、降级后的首次保存/自愈自动迁移,全程无感。
|
|
22
|
+
- **两代宿主都兼容**:DSH 0.1.5 / 0.1.6 / 0.1.7-rc.1 / 0.1.7-rc.2 全支持——两代宿主发现预设的机制不同(目录扫描 vs patch 声明行),安装器自动检测宿主版本选对落点,宿主升级、降级后的首次保存/自愈自动迁移,全程无感。
|
|
23
23
|
|
|
24
24
|
## 插件截图
|
|
25
25
|
|
|
@@ -27,7 +27,7 @@ dsh-paoding(中文品牌「庖丁」,典出《庄子》——庖丁顺纹理
|
|
|
27
27
|
|
|
28
28
|
## 快速开始
|
|
29
29
|
|
|
30
|
-
前置:**Node.js ≥ 18**、**pnpm** 与一台已装好的 DSH host(**@deepseek-ai/dsh 0.1.5 – 0.1.7-rc.
|
|
30
|
+
前置:**Node.js ≥ 18**、**pnpm** 与一台已装好的 DSH host(**@deepseek-ai/dsh 0.1.5 – 0.1.7-rc.2** 全支持,预设落点自动适配两代宿主机制)。
|
|
31
31
|
|
|
32
32
|
**官方插件通道(唯一安装入口)**——不用克隆仓库,一条命令,装完重启即用:
|
|
33
33
|
|
|
@@ -80,7 +80,7 @@ dsh plugin --profile web add link:"$PWD/dsh-paoding"
|
|
|
80
80
|
| 文档 | 内容 |
|
|
81
81
|
|---|---|
|
|
82
82
|
| [架构](docs/architecture.md) | 为什么这样设计——概述、成本账、角色与工具、对应 DSH 原生机制、Token 治理、已知边界。 |
|
|
83
|
-
| [安装](docs/installation.md) | 官方插件通道一条命令安装、版本支持与预设落点双轨(DSH 0.1.5 – 0.1.7-rc.
|
|
83
|
+
| [安装](docs/installation.md) | 官方插件通道一条命令安装、版本支持与预设落点双轨(DSH 0.1.5 – 0.1.7-rc.2)、首装自动化与版本标记、升级、开发检出自装、host patch 检测机制、庖丁配置面板、卸载、排查。 |
|
|
84
84
|
| [编排](docs/orchestration.md) | 编排总览、失败如何呈现与三层处理、one-shot vs continuable、上下文隔离。 |
|
|
85
85
|
| [配置](docs/configuration.md) | 配置键全参考、内置角色微调、主 agent 工具与技能、自定义角色、按角色分模型、角色会话模式。 |
|
|
86
86
|
|
package/README_en.md
CHANGED
|
@@ -17,9 +17,9 @@ dsh-paoding (Chinese brand 「庖丁」/ Pao Ding, from the Zhuangzi parable of
|
|
|
17
17
|
- **Whatever you've installed, it's recognized**: MCP servers, local plugins, installed skills — detected throughout install and configuration; the default install carries only DSH base tools, and detected host tools are opted into per tool in **Paoding Config**; disable one, re-apply, and its tools drop out on their own.
|
|
18
18
|
- **A different lineup per workspace**: each project can carry its own main/sub-agent setup — pick the workspace in 庖丁配置, configure it separately, and it gets its own preset (`orchestrator-<basename>`); choose that preset when starting a session. The global default stays untouched.
|
|
19
19
|
- **A visual configurator**: prefer clicking to editing YAML? the 庖丁配置 (Paoding Config) entry in the sidebar bottom action bar (above the Settings row) covers everything; Save & Apply regenerates the preset on the spot — the same generation pipeline as first-install automation.
|
|
20
|
-
- **Notified of new releases, one-click upgrade in the panel**: the panel compares your local version against the latest npm registry publish (GitHub release as
|
|
20
|
+
- **Notified of new releases, one-click upgrade in the panel**: the panel compares your local version against the latest npm registry publish (npmmirror and GitHub release as successive fallbacks) and points to the release page when a newer one is out. The Upgrade button runs `dsh plugin update dsh-paoding` in place (profile auto-detected) to swap in the new version; a DSH restart applies it, and the orchestrator preset regenerates itself against the new version on startup. A dev checkout in link: form cannot be upgraded in place — the panel tells you how to switch back to the registry version. If the check fails (offline, rate-limited), a subdued "version check failed · retry" row stays in the header (full causes and proxy hints in its tooltip) without popping anything up.
|
|
21
21
|
- **Installs and uninstalls cleanly**: no DSH source changes; active in a new session right after install, gone when you delete one directory.
|
|
22
|
-
- **Works on both host generations**: DSH 0.1.5 / 0.1.6 / 0.1.7-rc.1 are all supported — the two generations discover presets differently (directory scan vs patch declaration rows), and the installer picks the right landing automatically, then migrates on the first save/self-heal after a host upgrade or downgrade, all without user action.
|
|
22
|
+
- **Works on both host generations**: DSH 0.1.5 / 0.1.6 / 0.1.7-rc.1 / 0.1.7-rc.2 are all supported — the two generations discover presets differently (directory scan vs patch declaration rows), and the installer picks the right landing automatically, then migrates on the first save/self-heal after a host upgrade or downgrade, all without user action.
|
|
23
23
|
|
|
24
24
|
## Screenshots
|
|
25
25
|
|
|
@@ -27,7 +27,7 @@ dsh-paoding (Chinese brand 「庖丁」/ Pao Ding, from the Zhuangzi parable of
|
|
|
27
27
|
|
|
28
28
|
## Quick Start
|
|
29
29
|
|
|
30
|
-
Prerequisites: **Node.js ≥ 18**, **pnpm**, and a working DSH host (**@deepseek-ai/dsh 0.1.5 – 0.1.7-rc.
|
|
30
|
+
Prerequisites: **Node.js ≥ 18**, **pnpm**, and a working DSH host (**@deepseek-ai/dsh 0.1.5 – 0.1.7-rc.2**, all supported — the preset landing adapts to the host generation automatically).
|
|
31
31
|
|
|
32
32
|
**The official plugin channel (the only install route)** — no clone needed; one command, then a restart:
|
|
33
33
|
|
|
@@ -80,7 +80,7 @@ All preferences live in `~/.dsh/dsh-paoding.config.yml`: role add/remove/tweak,
|
|
|
80
80
|
| Document | Contents |
|
|
81
81
|
|---|---|
|
|
82
82
|
| [Architecture](docs/architecture_en.md) | Why it is designed this way — overview, the cost ledger, roles and tools, mapping to DSH's native mechanisms, token governance, known limits. |
|
|
83
|
-
| [Installation](docs/installation_en.md) | The single official channel (`dsh plugin add`), version support and the dual preset landing (DSH 0.1.5 – 0.1.7-rc.
|
|
83
|
+
| [Installation](docs/installation_en.md) | The single official channel (`dsh plugin add`), version support and the dual preset landing (DSH 0.1.5 – 0.1.7-rc.2), first-install automation and the version marker, upgrading, dev-checkout install, host patch detection, the Paoding Config panel, uninstalling, troubleshooting. |
|
|
84
84
|
| [Orchestration](docs/orchestration_en.md) | Orchestration overview, how failures surface and the three recovery layers, one-shot vs continuable, context isolation. |
|
|
85
85
|
| [Configuration](docs/configuration_en.md) | The full key reference, tuning built-in roles, main-agent tools and skills, custom roles, per-role models, per-role session modes. |
|
|
86
86
|
|
package/docs/architecture.md
CHANGED
|
@@ -269,7 +269,7 @@ grep inline cap 与对照同设计)后,根因锁定为:**默认压缩从
|
|
|
269
269
|
触发),配合 retainRatio 默认保留约 16% 尾部(≈42K)+ 摘要 checkpoint,稳态平均回落到 ~80K 量级。
|
|
270
270
|
压缩每次触发调用一次 LLM 摘要——复用前缀缓存,成本极低——因此触发频繁一点也几乎不额外花钱;
|
|
271
271
|
0.45 是「省 token 与不频繁摘要」之间的平衡点。compaction-basic 另显式钉了 `maxTokens: 8192`:
|
|
272
|
-
DSH 0.1.7 起宿主默认升到 65536,显式值让 0.1.5 – 0.1.7-rc.
|
|
272
|
+
DSH 0.1.7 起宿主默认升到 65536,显式值让 0.1.5 – 0.1.7-rc.2 全系的摘要预算行为保持一致。
|
|
273
273
|
|
|
274
274
|
**参数与效果。**
|
|
275
275
|
|
package/docs/architecture_en.md
CHANGED
|
@@ -352,7 +352,7 @@ performs one LLM summarization call that reuses the prefix cache, so its cost is
|
|
|
352
352
|
somewhat more often costs almost nothing extra; 0.45 is the balance point between saving tokens and not
|
|
353
353
|
summarizing too frequently. compaction-basic also pins `maxTokens: 8192` explicitly: from DSH 0.1.7 the host
|
|
354
354
|
default rises to 65536, and the explicit value keeps the summary-budget behavior identical across
|
|
355
|
-
0.1.5 – 0.1.7-rc.
|
|
355
|
+
0.1.5 – 0.1.7-rc.2.
|
|
356
356
|
|
|
357
357
|
**Parameters and effect.**
|
|
358
358
|
|
package/docs/installation.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
- **Node.js ≥ 18**。DSH host 与插件链路都跑在 Node 上;版本过低时 `dsh` 本身就起不来。可用 `node --version` 自查。
|
|
14
14
|
- **pnpm 可用**。`dsh plugin` 是 pnpm 的透明转发器:插件包装进 profile 时由 pnpm 完成。缺失时安装命令会报 pnpm 相关错误,装好 pnpm(`npm i -g pnpm` 或 `corepack enable`)后重试。
|
|
15
|
-
- **已安装 DSH host**(`dsh` 可用,含其 Web/agent 运行时;**@deepseek-ai/dsh 0.1.5 – 0.1.7-rc.
|
|
15
|
+
- **已安装 DSH host**(`dsh` 可用,含其 Web/agent 运行时;**@deepseek-ai/dsh 0.1.5 – 0.1.7-rc.2** 全支持,安装器自动适配两代预设机制,详见第 2 节「版本支持与预设落点双轨」)。本插件不改 DSH 源码,只往 DSH 的 preset roster 写入编排预设、并把「庖丁配置」面板挂进 Web 左侧栏,因此先要有可用的 DSH 家目录。
|
|
16
16
|
- **路径事实**(生成管线内建常量,写死前先了解它们):
|
|
17
17
|
|
|
18
18
|
| 项 | 默认值 | 说明 |
|
|
@@ -50,9 +50,9 @@ dsh plugin --profile web add dsh-paoding
|
|
|
50
50
|
|
|
51
51
|
`--profile web` 决定插件装进哪个 profile:「庖丁配置」面板只在以该 profile 启动的 DSH Web 里出现。`web` 是 `dsh web` 的默认 profile,多数机器无需改动;多 profile 用户对每个需要的 profile 各执行一次 `dsh plugin add`。编排预设本体落在 `$DSH_HOME/.agent-presets/`,全机共享、不随 profile 走——DSH ≥ 0.1.7 的声明行写在 home 层 `$DSH_HOME/cordis.patch.yml`,同样与 profile 无关——在任何 profile 的面板里「保存并应用」,写的都是同一份预设。
|
|
52
52
|
|
|
53
|
-
### 版本支持与预设落点双轨(DSH 0.1.5 – 0.1.7-rc.
|
|
53
|
+
### 版本支持与预设落点双轨(DSH 0.1.5 – 0.1.7-rc.2)
|
|
54
54
|
|
|
55
|
-
本插件兼容两代宿主:**DSH 0.1.5 / 0.1.6 / 0.1.7-rc.1 全部支持**,安装与使用流程完全一致。插件 0.3.4 起,package.json 显式声明 `peerDependencies: @deepseek-ai/dsh >= 0.1.5`——0.1.7 起宿主装插件前做兼容性预检,无声明等于默认放行,显式声明后按真实兼容面把关;0.1.5 / 0.1.6 不读这个字段,声明纯属元数据,不影响安装。
|
|
55
|
+
本插件兼容两代宿主:**DSH 0.1.5 / 0.1.6 / 0.1.7-rc.1 / 0.1.7-rc.2 全部支持**,安装与使用流程完全一致。插件 0.3.4 起,package.json 显式声明 `peerDependencies: @deepseek-ai/dsh >= 0.1.5`——0.1.7 起宿主装插件前做兼容性预检,无声明等于默认放行,显式声明后按真实兼容面把关;0.1.5 / 0.1.6 不读这个字段,声明纯属元数据,不影响安装。
|
|
56
56
|
|
|
57
57
|
两代宿主发现「本地 authored preset」的机制不同,安装器据此分双轨落点,宿主检测全自动、用户无感:
|
|
58
58
|
|
|
@@ -108,7 +108,7 @@ dsh plugin --profile web add dsh-paoding
|
|
|
108
108
|
|
|
109
109
|
## 3. 升级
|
|
110
110
|
|
|
111
|
-
**面板一键升级(推荐)**:面板自动对比 npm registry 上的最新版本(GitHub release
|
|
111
|
+
**面板一键升级(推荐)**:面板自动对比 npm registry 上的最新版本(npmmirror 镜像、GitHub release 依次兜底),发现新版就地提示并附上发布页链接。点「升级」按钮,面板就地执行:
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
114
|
dsh plugin --profile <name> update dsh-paoding
|
|
@@ -120,7 +120,7 @@ dsh plugin --profile <name> update dsh-paoding
|
|
|
120
120
|
|
|
121
121
|
**开发 link 形态**(见第 4 节)版本比较照常(更新卡有新版照常提示),但无法就地升级——升级器要求包真实装在某个 profile 的 node_modules 下,link 直连仓库匹配不到;点「升级」会如实报这一点,并提示手动跑 `dsh plugin add dsh-paoding@latest` 切回 registry 版。
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
检测失败(断网、限流、代理不可用)时页头会留一行弱化的「版本检测失败 · 重试」,完整原因(npm registry / npmmirror / GitHub 三路各自的错误,以及代理排查提示)在悬浮提示里,不弹窗打扰;检测成功且确无新版时不显示任何内容。常见误区:浏览器能打开 npm 页面不代表 DSH 进程检测也能通——DSH 遵循启动环境里的 `HTTPS_PROXY` / `HTTP_PROXY` 等代理变量,浏览器不走它们;若靠代理上网,请确认代理可用后重启 DSH 再试。
|
|
124
124
|
|
|
125
125
|
## 4. 开发自装(link: 形态)
|
|
126
126
|
|
package/docs/installation_en.md
CHANGED
|
@@ -12,7 +12,7 @@ Check the following before installing:
|
|
|
12
12
|
|
|
13
13
|
- **Node.js ≥ 18**. The DSH host and the plugin chain both run on Node; with an older version `dsh` won't start in the first place. Check with `node --version`.
|
|
14
14
|
- **pnpm available**. `dsh plugin` is a transparent pass-through to pnpm: installing a plugin package into a profile is done by pnpm. If pnpm is missing the install command fails with a pnpm error — install pnpm (`npm i -g pnpm` or `corepack enable`) and retry.
|
|
15
|
-
- **A working DSH host** (the `dsh` command, including its Web/agent runtime; **@deepseek-ai/dsh 0.1.5 – 0.1.7-rc.
|
|
15
|
+
- **A working DSH host** (the `dsh` command, including its Web/agent runtime; **@deepseek-ai/dsh 0.1.5 – 0.1.7-rc.2**, all supported — the installer adapts to the two preset mechanisms automatically; see §2 "Version support and the dual preset landing"). This plugin does not modify DSH source code; it only writes the orchestrator preset into DSH's preset roster and mounts the Paoding Config page into the Web sidebar, so a usable DSH home directory must exist first.
|
|
16
16
|
- **Path facts** (constants built into the generation pipeline; know them before customizing):
|
|
17
17
|
|
|
18
18
|
| Item | Default | Description |
|
|
@@ -50,9 +50,9 @@ The orchestrator preset needs no separate install — the plugin fills it in aut
|
|
|
50
50
|
|
|
51
51
|
`--profile web` decides which profile the plugin is installed into: the Paoding Config page appears only in a DSH Web launched with that profile. `web` is the default profile of `dsh web`, so most machines need no change; multi-profile users run `dsh plugin add` once per profile they want it in. The orchestrator preset itself lives under `$DSH_HOME/.agent-presets/` and is shared machine-wide, independent of profiles — under DSH ≥ 0.1.7 the declaration rows go into the home-layer `$DSH_HOME/cordis.patch.yml`, equally profile-independent — Save & Apply from any profile's panel writes the same preset.
|
|
52
52
|
|
|
53
|
-
### Version support and the dual preset landing (DSH 0.1.5 – 0.1.7-rc.
|
|
53
|
+
### Version support and the dual preset landing (DSH 0.1.5 – 0.1.7-rc.2)
|
|
54
54
|
|
|
55
|
-
The plugin supports two host generations: **DSH 0.1.5 / 0.1.6 / 0.1.7-rc.1 are all supported**, with an identical install and usage flow. As of plugin 0.3.4, package.json declares `peerDependencies: @deepseek-ai/dsh >= 0.1.5` explicitly — from 0.1.7 the host runs a plugin-compatibility precheck before installing: no declaration meant a default pass, an explicit one gets checked against the real compatibility surface; 0.1.5 / 0.1.6 never read the field, where the declaration is pure metadata and changes nothing about the install.
|
|
55
|
+
The plugin supports two host generations: **DSH 0.1.5 / 0.1.6 / 0.1.7-rc.1 / 0.1.7-rc.2 are all supported**, with an identical install and usage flow. As of plugin 0.3.4, package.json declares `peerDependencies: @deepseek-ai/dsh >= 0.1.5` explicitly — from 0.1.7 the host runs a plugin-compatibility precheck before installing: no declaration meant a default pass, an explicit one gets checked against the real compatibility surface; 0.1.5 / 0.1.6 never read the field, where the declaration is pure metadata and changes nothing about the install.
|
|
56
56
|
|
|
57
57
|
The two generations discover "local authored presets" differently, so the installer maintains a dual landing, detecting the host automatically — nothing for the user to do:
|
|
58
58
|
|
|
@@ -108,7 +108,7 @@ Once installed:
|
|
|
108
108
|
|
|
109
109
|
## 3. Upgrading
|
|
110
110
|
|
|
111
|
-
**One-click upgrade in the panel (recommended)**: the panel compares your local version against the latest npm registry publish (GitHub release as
|
|
111
|
+
**One-click upgrade in the panel (recommended)**: the panel compares your local version against the latest npm registry publish (npmmirror and GitHub release as successive fallbacks) and points to the release page when a newer one is out. Click the Upgrade button and the panel runs this in place:
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
114
|
dsh plugin --profile <name> update dsh-paoding
|
|
@@ -120,7 +120,7 @@ Manual equivalent: run the `dsh plugin update` command above yourself, restart,
|
|
|
120
120
|
|
|
121
121
|
A **dev link: checkout** (see §4) still gets version checks (the update card appears when a newer version exists) but cannot be upgraded in place — the upgrader requires the package to really live under a profile's node_modules, which a link straight into the repo never matches. Hitting Upgrade reports exactly that and suggests running `dsh plugin add dsh-paoding@latest` to switch back to the registry version.
|
|
122
122
|
|
|
123
|
-
If the check fails (offline, rate-limited),
|
|
123
|
+
If the check fails (offline, rate-limited, proxy down), a subdued "version check failed · retry" row stays in the panel header with the full causes (per-source errors across npm registry / npmmirror / GitHub, plus proxy troubleshooting hints) in its tooltip; a successful check with no new version shows nothing. Common pitfall: being able to open the npm page in a browser does not mean the DSH process can reach it — DSH honors HTTPS_PROXY / HTTP_PROXY from its launch environment while browsers do not. If you rely on a proxy, make sure it is up and restart DSH before retrying.
|
|
124
124
|
|
|
125
125
|
## 4. Dev-checkout install (link: form)
|
|
126
126
|
|
package/icon.svg
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
|
2
|
+
<rect width="64" height="64" rx="14" fill="#4D6BFE"/>
|
|
3
|
+
<g transform="rotate(-45 32 32)">
|
|
4
|
+
<rect x="14" y="11" width="32" height="22" rx="3" fill="#FFFFFF"/>
|
|
5
|
+
<circle cx="41" cy="16.5" r="2" fill="#4D6BFE"/>
|
|
6
|
+
<rect x="44" y="17" width="13" height="10" rx="4" fill="#FFFFFF" opacity="0.85"/>
|
|
7
|
+
</g>
|
|
8
|
+
</svg>
|
package/locale/en.json
ADDED
package/locale/zh.json
ADDED
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-paoding",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "庖丁 — DSH (DeepSeek Harness) 编排模式安装器:host 感知的角色工具过滤 + Web 设置页可视化配置器",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"icon": "./icon.svg",
|
|
7
8
|
"files": [
|
|
8
9
|
"bin/",
|
|
9
10
|
"tools/",
|
|
@@ -11,6 +12,8 @@
|
|
|
11
12
|
"plugins/",
|
|
12
13
|
"!plugins/paoding-config-ui/src",
|
|
13
14
|
"docs/",
|
|
15
|
+
"locale/",
|
|
16
|
+
"icon.svg",
|
|
14
17
|
"README.md",
|
|
15
18
|
"README_en.md",
|
|
16
19
|
"LICENSE",
|
|
@@ -43,7 +46,8 @@
|
|
|
43
46
|
"exports": {
|
|
44
47
|
".": "./plugins/paoding-config-ui/index.mjs",
|
|
45
48
|
"./client": "./plugins/paoding-config-ui/lib/client.js",
|
|
46
|
-
"./package.json": "./package.json"
|
|
49
|
+
"./package.json": "./package.json",
|
|
50
|
+
"./locale/*.json": "./locale/*.json"
|
|
47
51
|
},
|
|
48
52
|
"dsh": {
|
|
49
53
|
"client": {
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* upgrade/preview/apply/rescan + client.css 静态样式),经
|
|
7
7
|
* ./api-core.mjs 复用 tools/install.mjs 的检测与生成管线;workspaces 直连
|
|
8
8
|
* 宿主 workspaceRegistry 服务(list / create,幂等);version
|
|
9
|
-
* 复用 tools/lib/version.mjs 的版本检测(npm registry
|
|
10
|
-
*
|
|
9
|
+
* 复用 tools/lib/version.mjs 的版本检测(npm registry 优先,npmmirror
|
|
10
|
+
* 镜像、GitHub release 依次兜底);upgrade 经 tools/lib/upgrade.mjs
|
|
11
|
+
* spawn `dsh plugin update` 完成
|
|
11
12
|
* 一键升级。首装 / 升级后 preset 自动重生成(ensurePresetInstalled,等价
|
|
12
13
|
* install --auto 语义)在路由注册完成后异步触发,不阻塞启动。
|
|
13
14
|
* - Client 侧:lib/client.js 经宿主 sidebar.footer.action 键控槽在左侧栏
|
|
@@ -530,7 +531,7 @@ export function apply(ctx) {
|
|
|
530
531
|
}
|
|
531
532
|
|
|
532
533
|
if (route === 'version' && req.method === 'GET') {
|
|
533
|
-
// 版本提示:npm registry
|
|
534
|
+
// 版本提示:npm registry 优先,npmmirror / GitHub 依次兜底(version.mjs,
|
|
534
535
|
// 带 1 小时内存缓存,命中不发外网请求)。绝不 5xx——检测失败也回
|
|
535
536
|
// 200 + error 字段,面板据此静默降级(不打扰使用)。timeoutMs 3000:
|
|
536
537
|
// 检测只是锦上添花,不值得让面板等更久。layout 告知客户端挂载形态
|
|
@@ -149,6 +149,34 @@
|
|
|
149
149
|
|
|
150
150
|
.omd-upgradeBtn:focus-visible { outline: 2px solid var(--dsw-alias-border-l4); outline-offset: 1px; }
|
|
151
151
|
|
|
152
|
+
/* 版本检测失败行(弱化):比更新警示卡低一档的存在感——三级文字色小字
|
|
153
|
+
⚠ + 重试小 pill,常态(检测成功且无新版)不渲染。完整失败原因(三路源
|
|
154
|
+
各自错误与代理排查提示)收在行上的 title 悬浮提示,不占版面。 */
|
|
155
|
+
.omd-versionFail { gap: 4px; }
|
|
156
|
+
|
|
157
|
+
.omd-retryBtn {
|
|
158
|
+
flex: none;
|
|
159
|
+
padding: 1px 10px;
|
|
160
|
+
border: 1px solid var(--dsw-alias-border-l3);
|
|
161
|
+
border-radius: 999px;
|
|
162
|
+
background: transparent;
|
|
163
|
+
color: var(--dsw-alias-label-secondary);
|
|
164
|
+
font: inherit;
|
|
165
|
+
font-size: 11px;
|
|
166
|
+
line-height: 16px;
|
|
167
|
+
cursor: pointer;
|
|
168
|
+
transition: color 0.12s ease, border-color 0.12s ease;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.omd-retryBtn:hover:not(:disabled) {
|
|
172
|
+
color: var(--dsw-alias-label-primary);
|
|
173
|
+
border-color: var(--dsw-alias-border-l4);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.omd-retryBtn:disabled { opacity: 0.6; cursor: default; }
|
|
177
|
+
|
|
178
|
+
.omd-retryBtn:focus-visible { outline: 2px solid var(--dsw-alias-border-l4); outline-offset: 1px; }
|
|
179
|
+
|
|
152
180
|
/* 升级进行中的补充说明(分钟级操作,管理预期)。 */
|
|
153
181
|
.omd-upgradeHint {
|
|
154
182
|
flex: none;
|
|
@@ -236,8 +236,8 @@ window.__ModuleLoader__.load({
|
|
|
236
236
|
// 版本提示(渲染在页头标题旁,由 PageShell 持有):常态版本号不进正文;
|
|
237
237
|
// updateAvailable 时这里渲染醒目提示卡:releaseUrl 新标签页打开 release 页、
|
|
238
238
|
// 「升级」按钮走 onUpgrade(一键 dsh plugin update 自升级),并保留当前版本号。
|
|
239
|
-
// latest 为 null
|
|
240
|
-
//
|
|
239
|
+
// latest 为 null 一律不显示新版部分;检测失败(error 非空)改渲染弱化失败行
|
|
240
|
+
// (⚠ 版本检测失败 · 重试,完整原因在 title 悬浮提示),不再整行静默。
|
|
241
241
|
// opts(可省):busy/busyOp 复用面板级互斥(任何操作进行中都禁用升级,
|
|
242
242
|
// 升级进行中也反过来禁用其他按钮),onUpgrade 为点击回调。
|
|
243
243
|
// ── 服务端 API 助手(PageShell 与 ConfigPanel 共用)──────────────────────
|
|
@@ -325,9 +325,28 @@ window.__ModuleLoader__.load({
|
|
|
325
325
|
// 渲染并持有升级动作,面板正文不再重复版本信息;当前版本号就在旁边的
|
|
326
326
|
// pd-versionTag 上,卡内不再赘述「(当前 vX)」。note / error 为升级
|
|
327
327
|
// 反馈行(成功提示 / 失败原因,含子进程输出尾部),也收在卡内。
|
|
328
|
+
// 检测失败(v.error 非空且无新版信息)不再全静默:弱化小字「版本检测
|
|
329
|
+
// 失败 · 重试」——否则「没新版」与「没测出来」无从区分(真实事故:用户
|
|
330
|
+
// 端 0.3.2 对 0.3.5 迟迟看不到升级卡,只能靠作者远程猜)。检测成功且确
|
|
331
|
+
// 无新版仍静默(常态不打扰)。完整失败原因(三路源各自错误 + 代理提示)
|
|
332
|
+
// 收在 title 悬浮提示里,不占版面。
|
|
328
333
|
function versionRowOf(v, opts) {
|
|
329
334
|
if (!v || typeof v.current !== "string" || !v.current) return null;
|
|
330
|
-
if (!(v.updateAvailable && v.latest))
|
|
335
|
+
if (!(v.updateAvailable && v.latest)) {
|
|
336
|
+
if (typeof v.error !== "string" || !v.error) return null;
|
|
337
|
+
var retryBusy = !!(opts && opts.retryBusy);
|
|
338
|
+
return h("span", { className: "omd-versionRow omd-versionFail", title: v.error },
|
|
339
|
+
h("span", { className: "omd-versionIcon" }, "⚠"),
|
|
340
|
+
h("span", { className: "omd-versionText" }, "版本检测失败"),
|
|
341
|
+
typeof (opts && opts.onRetry) === "function"
|
|
342
|
+
? h("button", {
|
|
343
|
+
type: "button",
|
|
344
|
+
className: "omd-retryBtn",
|
|
345
|
+
disabled: retryBusy,
|
|
346
|
+
onClick: opts.onRetry,
|
|
347
|
+
}, retryBusy ? "检测中…" : "重试")
|
|
348
|
+
: null);
|
|
349
|
+
}
|
|
331
350
|
var busy = !!opts && !!opts.busy;
|
|
332
351
|
var note = (opts && opts.note) || "";
|
|
333
352
|
var error = (opts && opts.error) || "";
|
|
@@ -3042,11 +3061,26 @@ window.__ModuleLoader__.load({
|
|
|
3042
3061
|
var _ub = useState(false), upgBusy = _ub[0], setUpgBusy = _ub[1];
|
|
3043
3062
|
var _un = useState(""), upgNote = _un[0], setUpgNote = _un[1];
|
|
3044
3063
|
var _ue = useState(""), upgErr = _ue[0], setUpgErr = _ue[1];
|
|
3064
|
+
// 版本检测重试进行中(页头失败行的「重试」按钮禁用态):与升级三态分开,
|
|
3065
|
+
// 检测失败重试不该锁升级(升级预检在服务端另做一次,不依赖这份 verInfo)。
|
|
3066
|
+
var _vb = useState(false), verRetryBusy = _vb[0], setVerRetryBusy = _vb[1];
|
|
3045
3067
|
|
|
3046
3068
|
// 一键升级逻辑在共享的 runUpgradeFlow(页头更新卡统一走这一份)。
|
|
3047
3069
|
function doUpgrade() {
|
|
3048
3070
|
runUpgradeFlow(verInfo, setVerInfo, setUpgBusy, setUpgNote, setUpgErr);
|
|
3049
3071
|
}
|
|
3072
|
+
|
|
3073
|
+
// 检测失败重试:直接再拉一次 /api/paoding/version(服务端失败结果不进
|
|
3074
|
+
// 缓存,重试即真实检测;成功则 error 随新响应自然清空)。仍失败维持
|
|
3075
|
+
// 原提示——失败行常驻,重试按钮永远可用。
|
|
3076
|
+
function doRetryVersion() {
|
|
3077
|
+
setVerRetryBusy(true);
|
|
3078
|
+
paodingApi("version").then(function (d) {
|
|
3079
|
+
if (d && typeof d.current === "string" && d.current) setVerInfo(d);
|
|
3080
|
+
}).catch(function () { /* 仍不通:维持失败行,不额外打扰 */ }).finally(function () {
|
|
3081
|
+
setVerRetryBusy(false);
|
|
3082
|
+
});
|
|
3083
|
+
}
|
|
3050
3084
|
useEffect(function () {
|
|
3051
3085
|
var onKey = function (e) {
|
|
3052
3086
|
if (e && e.key === "Escape" && typeof onClose === "function") onClose();
|
|
@@ -3064,7 +3098,7 @@ window.__ModuleLoader__.load({
|
|
|
3064
3098
|
verInfo && typeof verInfo.current === "string" && verInfo.current
|
|
3065
3099
|
? h("span", { className: "pd-versionTag" }, versionTagOf(verInfo.current))
|
|
3066
3100
|
: null),
|
|
3067
|
-
versionRowOf(verInfo, { busy: upgBusy, onUpgrade: doUpgrade, note: upgNote, error: upgErr })),
|
|
3101
|
+
versionRowOf(verInfo, { busy: upgBusy, onUpgrade: doUpgrade, note: upgNote, error: upgErr, onRetry: doRetryVersion, retryBusy: verRetryBusy })),
|
|
3068
3102
|
h("p", { className: "pd-pageSubtitle" },
|
|
3069
3103
|
"为主 agent 与子 agent 编排工具、技能与角色,预览并应用生成的 agent.cordis.yml。")),
|
|
3070
3104
|
h("button", {
|
package/tools/lib/upgrade.mjs
CHANGED
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
* 开发 link: 直连形态的真实路径在仓库里、匹配不到,如实报「无法就地升级」。
|
|
11
11
|
*
|
|
12
12
|
* 零依赖纯 Node(>=18):目标版本复用 version.mjs 的 fetchLatestFromRegistry
|
|
13
|
-
*
|
|
13
|
+
* / fetchLatestFromMirror(官方源失败再走 npmmirror 镜像——点「升级」的用户
|
|
14
|
+
* 网络本来就在出状况,多一路快路能实打实救回一次升级),子进程、时钟全部
|
|
15
|
+
* 可注入便于单测。升级后不做磁盘后验
|
|
14
16
|
* ——本进程代码不随升级变化,无从对账;成功与否以 dsh 子进程退出码为准,
|
|
15
17
|
* 新版本在重启 DSH 后生效(preset 由新包的启动自愈钩子自动重生成)。
|
|
16
18
|
*
|
|
@@ -22,7 +24,7 @@ import os from 'node:os'
|
|
|
22
24
|
import { spawn } from 'node:child_process'
|
|
23
25
|
import { realpath } from 'node:fs/promises'
|
|
24
26
|
import { fileURLToPath } from 'node:url'
|
|
25
|
-
import { currentVersion, compareVersions, fetchLatestFromRegistry } from './version.mjs'
|
|
27
|
+
import { currentVersion, compareVersions, fetchLatestFromMirror, fetchLatestFromRegistry } from './version.mjs'
|
|
26
28
|
|
|
27
29
|
// 子进程输出上限:合并 stdout+stderr 后只保留最后 ~8KB(安装进度刷屏无排障
|
|
28
30
|
// 价值,报错结论都在尾部);累积过程中超过 1MB 就先截一版,防止异常刷爆内存。
|
|
@@ -124,13 +126,17 @@ async function doRunUpgrade({ profile, fetchImpl, spawnImpl, timeoutMs, now }) {
|
|
|
124
126
|
const elapsedMs = () =>
|
|
125
127
|
Math.max(0, (typeof now === 'function' ? now() : typeof now === 'number' ? now : Date.now()) - startedAt)
|
|
126
128
|
|
|
127
|
-
// ① 版本预检:拿不到
|
|
128
|
-
//
|
|
129
|
-
//
|
|
129
|
+
// ① 版本预检:拿不到 latest 就不做半截升级(宁可不动现有安装)。官方源
|
|
130
|
+
// 失败再试 npmmirror 镜像。超时给 10s:面板静默检测用 3s 够了,这里是
|
|
131
|
+
// 用户显式点了「升级」、本来就要等,多花几秒换一次成功率是划算的;
|
|
132
|
+
// 仍超时就如实报失败。
|
|
130
133
|
const { version: current } = await currentVersion()
|
|
131
134
|
const reg = await fetchLatestFromRegistry({ fetchImpl, timeoutMs: 10000 })
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
const manifest = reg.ok ? reg : await fetchLatestFromMirror({ fetchImpl, timeoutMs: 10000 })
|
|
136
|
+
if (!manifest.ok) {
|
|
137
|
+
return { ok: false, error: `无法确定最新版本:官方源 ${reg.error};镜像 ${manifest.error}` }
|
|
138
|
+
}
|
|
139
|
+
const target = manifest.latest // 形如 v0.2.3
|
|
134
140
|
if (compareVersions(target, current) <= 0) return { ok: true, upToDate: true, current }
|
|
135
141
|
const targetVersion = target.replace(/^v/, '')
|
|
136
142
|
|
package/tools/lib/version.mjs
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 版本提示 —— 检测线上是否有比本地更新的版本(Web 面板 + CLI 共用)。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* 可见,不像 GitHub release 需要另行打 tag
|
|
4
|
+
* 检测源三级:npm registry 的 dist-tags/latest 优先(无认证无限流,发布即
|
|
5
|
+
* 可见,不像 GitHub release 需要另行打 tag);失败再试 npmmirror 镜像(数据
|
|
6
|
+
* 同步自 npm registry,官方源超时 / 被墙时国内几秒内可达,分钟级同步延迟对
|
|
7
|
+
* 「有没有新版」这个判断无伤大雅);最后 GitHub releases/latest 兜底。
|
|
6
8
|
*
|
|
7
9
|
* 零依赖纯 Node(>=18):不引 cordis / npm 依赖,fetch 可注入(缺省用
|
|
8
10
|
* globalThis.fetch),超时用 AbortSignal.timeout()。所有失败路径都不抛错,
|
|
@@ -22,6 +24,9 @@ const RELEASE_API = 'https://api.github.com/repos/lifangjin/dsh-paoding/releases
|
|
|
22
24
|
const RELEASE_PAGE = 'https://github.com/lifangjin/dsh-paoding/releases/latest'
|
|
23
25
|
// npm registry 的 latest 元数据端点(等价 dist-tags.latest,无认证无限流)。
|
|
24
26
|
const REGISTRY_LATEST = 'https://registry.npmjs.org/dsh-paoding/latest'
|
|
27
|
+
// npmmirror 镜像的同名端点:manifest 形状与官方源一致(顶层 version 即
|
|
28
|
+
// latest),同步自 npm registry,官方源不可达时的国内快路。
|
|
29
|
+
const MIRROR_LATEST = 'https://registry.npmmirror.com/dsh-paoding/latest'
|
|
25
30
|
|
|
26
31
|
// 读不到 package.json 时的版本兜底。当前版本不可知(source: 'fallback')时
|
|
27
32
|
// updateAvailable 恒 false —— 拿「0.0.0 恒小于任何真实版本」去比较,反而必然
|
|
@@ -141,65 +146,87 @@ export async function fetchLatestRelease({ fetchImpl, timeoutMs = 3000 } = {}) {
|
|
|
141
146
|
}
|
|
142
147
|
|
|
143
148
|
/**
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
149
|
+
* 请求一个 npm 系 manifest 端点(官方源与 npmmirror 镜像共用同一形状:完整
|
|
150
|
+
* manifest,顶层 version 即 latest)。任何失败(网络 / 超时 / 解析 / 形状不对)
|
|
151
|
+
* 都不抛出,返回 { ok: false, error };成功返回 { ok: true, latest: 'vX.Y.Z',
|
|
152
|
+
* releaseUrl, source }(端点的 version 不带 v 前缀,这里统一补齐,与 GitHub
|
|
153
|
+
* tag 的显示口径一致)。
|
|
148
154
|
*/
|
|
149
|
-
|
|
155
|
+
async function fetchLatestManifest(url, label, source, { fetchImpl, timeoutMs = 3000 } = {}) {
|
|
150
156
|
const doFetch = typeof fetchImpl === 'function' ? fetchImpl : globalThis.fetch
|
|
151
157
|
if (typeof doFetch !== 'function') return { ok: false, error: 'fetch 不可用(当前运行时无 fetch 实现)' }
|
|
152
158
|
try {
|
|
153
|
-
const res = await doFetch(
|
|
159
|
+
const res = await doFetch(url, {
|
|
154
160
|
headers: { accept: 'application/vnd.npm+json' },
|
|
155
161
|
signal: AbortSignal.timeout(timeoutMs),
|
|
156
162
|
})
|
|
157
|
-
if (!res.ok) return { ok: false, error:
|
|
163
|
+
if (!res.ok) return { ok: false, error: `${label} HTTP ${res.status}` }
|
|
158
164
|
let data = null
|
|
159
165
|
try {
|
|
160
166
|
data = await res.json()
|
|
161
167
|
} catch (err) {
|
|
162
|
-
return { ok: false, error:
|
|
168
|
+
return { ok: false, error: `${label} 响应解析失败: ${err?.message ?? err}` }
|
|
163
169
|
}
|
|
164
170
|
// /<name>/latest 返回该版本的完整 manifest,顶层 version 即 latest 版本号;
|
|
165
|
-
// CDN
|
|
171
|
+
// CDN 缓存抖动可能回形状不对的正文,按失败处理走下一级检测源。
|
|
166
172
|
const ver = typeof data?.version === 'string' && data.version !== '' ? data.version : null
|
|
167
|
-
if (!ver) return { ok: false, error:
|
|
168
|
-
return { ok: true, latest: `v${ver}`, releaseUrl: RELEASE_PAGE, source
|
|
173
|
+
if (!ver) return { ok: false, error: `${label} 响应缺少 version` }
|
|
174
|
+
return { ok: true, latest: `v${ver}`, releaseUrl: RELEASE_PAGE, source }
|
|
169
175
|
} catch (err) {
|
|
170
176
|
return { ok: false, error: String(err?.message ?? err) }
|
|
171
177
|
}
|
|
172
178
|
}
|
|
173
179
|
|
|
180
|
+
/**
|
|
181
|
+
* 请求 npm registry(官方源)的 latest 元数据——版本检测首选源,runUpgrade
|
|
182
|
+
* 的目标版本解析也复用。
|
|
183
|
+
*/
|
|
184
|
+
export async function fetchLatestFromRegistry(opts) {
|
|
185
|
+
return await fetchLatestManifest(REGISTRY_LATEST, 'npm registry', 'npm', opts)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* 请求 npmmirror 镜像的 latest 元数据——官方源不可达(超时 / 被墙 / 代理
|
|
190
|
+
* 黑洞)时的国内快路:manifest 形状与官方源一致,同步延迟分钟级,对「有
|
|
191
|
+
* 没有新版」这个判断无伤大雅。
|
|
192
|
+
*/
|
|
193
|
+
export async function fetchLatestFromMirror(opts) {
|
|
194
|
+
return await fetchLatestManifest(MIRROR_LATEST, 'npmmirror', 'mirror', opts)
|
|
195
|
+
}
|
|
196
|
+
|
|
174
197
|
/**
|
|
175
198
|
* 组合结果(面板路由与 CLI 收尾共用):带 1 小时内存缓存,过期才重新请求;
|
|
176
199
|
* 请求失败时若上次成功结果在 lastGood 窗口(7 天,见 LASTGOOD_TTL_MS)内则
|
|
177
200
|
* 原样复用(stale-if-error),否则返回带 error 的降级结果(latest 置 null、
|
|
178
201
|
* updateAvailable 恒 false——调用方静默)。当前版本不可知(FALLBACK_VERSION
|
|
179
202
|
* 兜底)时 updateAvailable 恒 false:0.0.0 对任何 latest 都「更小」,比较必
|
|
180
|
-
*
|
|
181
|
-
* release
|
|
182
|
-
*
|
|
203
|
+
* 误报新版,升级提示整体抑制。检测源三级:npm registry 优先,失败再试
|
|
204
|
+
* npmmirror 镜像,最后 GitHub release;三路皆败才算本次检测失败,error 里
|
|
205
|
+
* 带上各路失败原因与代理排查提示便于排障。成功结果的 source 字段记录命中源。
|
|
183
206
|
* @param {{fetchImpl?: Function, timeoutMs?: number, now?: Function|number}} opts
|
|
184
207
|
* now 可注入函数或时间戳(测试用);缺省 Date.now()。
|
|
185
208
|
* @returns {Promise<{current: string, latest: string|null, updateAvailable: boolean,
|
|
186
209
|
* releaseUrl: string|null, checkedAt: string, error: string|null,
|
|
187
|
-
* source: 'npm'|'github'|null}>}
|
|
210
|
+
* source: 'npm'|'mirror'|'github'|null}>}
|
|
188
211
|
*/
|
|
189
212
|
export async function getVersionInfo({ fetchImpl, timeoutMs = 3000, now } = {}) {
|
|
190
213
|
const nowMs = typeof now === 'function' ? now() : typeof now === 'number' ? now : Date.now()
|
|
191
214
|
if (cache.info && nowMs - cache.at < CACHE_TTL_MS) return cache.info
|
|
192
215
|
const { version: current, source: currentSource } = await currentVersion()
|
|
193
|
-
//
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
let
|
|
197
|
-
if (
|
|
198
|
-
hit
|
|
199
|
-
|
|
216
|
+
// 三级链:① npm registry(官方源);② npmmirror 镜像(官方源不可达时的
|
|
217
|
+
// 国内快路);③ GitHub releases/latest(镜像也挂时的独立数据源)。
|
|
218
|
+
const failures = []
|
|
219
|
+
let hit = await fetchLatestFromRegistry({ fetchImpl, timeoutMs })
|
|
220
|
+
if (!hit.ok) {
|
|
221
|
+
failures.push(hit.error)
|
|
222
|
+
hit = await fetchLatestFromMirror({ fetchImpl, timeoutMs })
|
|
223
|
+
}
|
|
224
|
+
if (!hit.ok) {
|
|
225
|
+
failures.push(hit.error)
|
|
200
226
|
const rel = await fetchLatestRelease({ fetchImpl, timeoutMs })
|
|
201
|
-
|
|
202
|
-
|
|
227
|
+
hit = rel.ok
|
|
228
|
+
? { ok: true, latest: rel.tag, releaseUrl: rel.url, source: 'github' }
|
|
229
|
+
: { ok: false, error: rel.error }
|
|
203
230
|
}
|
|
204
231
|
if (hit && hit.ok) {
|
|
205
232
|
const info = {
|
|
@@ -216,10 +243,11 @@ export async function getVersionInfo({ fetchImpl, timeoutMs = 3000, now } = {})
|
|
|
216
243
|
cache = { at: nowMs, info }
|
|
217
244
|
return info
|
|
218
245
|
}
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
|
|
246
|
+
// 三路皆败:优先复用 lastGood 窗口(7 天)内的上次成功结果;超窗才给降级
|
|
247
|
+
// 结果(不写缓存)。error 把各路原因都带上(谁挂了一目了然),并附代理排查
|
|
248
|
+
// 提示——最常见的「浏览器能上网、DSH 进程检测失败」是启动环境的代理变量
|
|
249
|
+
// 指向了不可用的代理(DSH 遵循 HTTPS_PROXY 等变量,浏览器不走它们)。
|
|
250
|
+
const combined = `三路检测均失败(npm registry: ${failures[0]};npmmirror: ${failures[1]};GitHub: ${hit.error})。若本机经代理访问外网,请确认代理可用后重启 DSH 再试——DSH 进程遵循 HTTPS_PROXY / HTTP_PROXY 环境变量,浏览器不走它们,两者连通性可能不同`
|
|
223
251
|
if (cache.info && nowMs - cache.at < LASTGOOD_TTL_MS) return cache.info
|
|
224
252
|
return {
|
|
225
253
|
current,
|