@bruc3van/dsh-doctor 0.1.6 → 0.5.0

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.en.md CHANGED
@@ -2,142 +2,138 @@
2
2
 
3
3
  [中文](README.md) | English
4
4
 
5
- DSH Doctor helps DSH and plugin users quickly identify plugins that break startup or stop working after a DSH upgrade. It groups each plugin's problems, impact, and recommended actions, while also checking common profile configuration and version-drift issues. Diagnosis is read-only by default; repairs run only after you explicitly use `--fix`, review the exact plan, and confirm it. File edits are backed up first.
5
+ DSH Doctor is a diagnostic and recovery-decision tool for DSH upgrade incidents. For each plugin, it explains the incompatibility, the configuration layer that caused or amplified it, the preferred repair, and whether temporary isolation or removal can be proven safe enough to offer.
6
6
 
7
- This is a community-maintained third-party tool and is not an official DeepSeek project. It does not load or execute code from the plugins it inspects.
7
+ This is a community-maintained third-party tool, not an official DeepSeek project. Normal diagnosis is read-only and never loads or executes inspected plugin code.
8
8
 
9
- ## Installation
9
+ ## Install
10
10
 
11
11
  Node.js `22.19+` or `24+` is required:
12
12
 
13
13
  ```sh
14
14
  npm install --global @bruc3van/dsh-doctor
15
- dsh-doctor
15
+ dsh-doctor diagnose
16
16
  ```
17
17
 
18
- You can also run it without a global installation:
18
+ The default target is `$DSH_HOME/profiles/web`, falling back to `~/.dsh`. Use `--dsh-command /path/to/dsh` for a special installation or `--harness-root /path/to/deepseek-harness` for a source checkout.
19
+
20
+ ## Upgrade a plugin from 0.1.1 to 0.1.2
21
+
22
+ Doctor ships a versioned `dsh-v0.1.1-rc.2 → dsh-v0.1.2-alpha.2` migration catalog and exposes three auditable stages:
19
23
 
20
24
  ```sh
21
- npx @bruc3van/dsh-doctor
25
+ dsh-doctor migrate analyze /path/to/plugin --harness-root /path/to/deepseek-harness
26
+
27
+ dsh-doctor migrate apply /path/to/plugin --safe --harness-root /path/to/deepseek-harness
28
+ dsh-doctor migrate apply /path/to/plugin --safe --yes --harness-root /path/to/deepseek-harness
29
+
30
+ dsh-doctor migrate verify /path/to/plugin --level static --harness-root /path/to/deepseek-harness
31
+ dsh-doctor migrate verify /path/to/plugin --level build --yes --harness-root /path/to/deepseek-harness
32
+ dsh-doctor migrate verify /path/to/plugin --level runtime --yes --harness-root /path/to/deepseek-harness
22
33
  ```
23
34
 
24
- By default, Doctor checks `$DSH_HOME/profiles/web`. If `DSH_HOME` is unset, it uses `~/.dsh`.
35
+ Analysis uses the TypeScript AST and therefore sees type-only imports that disappear from JavaScript bundles. Safe apply only rewrites catalog-confirmed exact moves, pins non-removed DSH development dependencies to the target, and creates timestamped backups. It may add dependencies required by exact symbol moves, but it does not automatically change existing peer ranges. Session, Workspace, Conversation, and pending-interaction ownership changes remain explicit semantic tasks.
25
36
 
26
- Doctor does not require `dsh` to be installed as a global command. It searches, in order, an explicit `--dsh-command` or `DSH_DOCTOR_DSH_COMMAND`, the CLI under an explicit `--harness-root`, the shared profile installation or links left by the npx cache, the current project, PATH, and finally an automatically detected Harness source checkout. For a bundled DSH Desktop runtime or another custom installation, pass `--dsh-command /path/to/dsh`; the official package's `lib/bin.js` is also accepted. If no CLI can be found, Doctor still completes its read-only checks but does not offer or run command-based repairs that it cannot verify.
37
+ `artifact-verified` requires a successful `build` or `pack:check`; `test`/`typecheck` alone cannot prove a publishable artifact. Runtime verification packs the real plugin and installs it with the target DSH CLI under a temporary `DSH_HOME`; it verifies the CLI version, profile manifest, resolved installed package, activated bundle, effective config, and activation smoke, so a no-op command cannot claim success. It never touches the normal `~/.dsh`. Failed workspaces are retained and reported. `runtime-verified` still does not prove real UI, lifecycle, or business behavior.
27
38
 
28
- ## How it works
39
+ The package also includes the [`dsh-plugin-upgrade` skill](skills/dsh-plugin-upgrade/SKILL.md) so coding agents can drive this workflow without collapsing its safety gates.
29
40
 
30
- A complete diagnosis and repair flow has four steps:
41
+ ## Diagnosis model
31
42
 
32
- 1. `dsh-doctor` inspects the active DSH Home, profile, plugins, and Harness versions without making changes.
33
- 2. Doctor reports evidence and recommendations by severity and plugin compatibility state.
34
- 3. `dsh-doctor --fix` shows the exact file edits or DSH command plan and waits for confirmation.
35
- 4. After applying confirmed repairs, Doctor runs the full diagnosis again and determines the exit code from the final state.
43
+ Version 0.4.0 composes the configuration from an empty tree in the same order as current DSH:
36
44
 
37
- Doctor never loads inspected plugins and does not modify configuration during a normal diagnosis. Operations without one deterministic answer—such as guessing credentials, rewriting damaged YAML, or removing a plugin—remain recommendations only.
45
+ ```text
46
+ bundle layers → profile cordis.patch.yml → home cordis.patch.yml → CLI overlays
47
+ ```
48
+
49
+ The JSON report retains `currentDefaultTree`, `currentEffectiveTree`, field-level provenance, replaced sources, and paths removed by whole-`config` replacement. It diagnoses stale patches, duplicate ids and mounts, higher-layer disabling or replacement, bundle/profile conflicts, plugin versions and artifacts, client contracts, dependencies, and runtime issues.
50
+
51
+ Every `pluginDiagnoses[]` object keeps current `status` separate from `recovery`. Being removable does not make an incompatible plugin compatible.
52
+
53
+ ```sh
54
+ dsh-doctor diagnose
55
+ dsh-doctor diagnose --json
56
+ dsh-doctor diagnose --check-updates
57
+ ```
38
58
 
39
- ## Output language
59
+ Only `--check-updates` and `recover` contact the npm registry. Offline diagnosis reports `update.status: "not-checked"`; it never turns “not checked” into “no compatible version.”
40
60
 
41
- Text output supports English and Chinese. Doctor resolves the language in this order:
61
+ ## Compatible-version search
42
62
 
43
- 1. `--lang zh|en`
44
- 2. `DSH_DOCTOR_LANG`
45
- 3. `locale.preference` in the active DSH Home's `settings.yaml`
46
- 4. Terminal or system locale
63
+ Doctor checks all published manifests instead of trusting `latest`, then selects the highest version whose declared peer ranges accept the resolvable active DSH packages. This is only a manifest-declared candidate, not proof from a real startup or UI test.
47
64
 
48
65
  ```sh
49
- dsh-doctor --lang zh
50
- dsh-doctor --lang en
51
- DSH_DOCTOR_LANG=zh dsh-doctor
66
+ dsh-doctor recover @scope/plugin --action check-update
67
+ dsh-doctor recover @scope/plugin --action update # preview
68
+ dsh-doctor recover @scope/plugin --action update --yes # exact version
52
69
  ```
53
70
 
54
- `--json` always keeps stable English messages and diagnostic codes so language changes do not break automation.
71
+ ## Quarantine
55
72
 
56
- ## Common commands
73
+ When no compatible release is available, generate and test a temporary overlay first:
57
74
 
58
75
  ```sh
59
- # Read-only diagnosis
60
- dsh-doctor
61
- dsh-doctor --profile web
62
- dsh-doctor --home /path/to/.dsh
63
- dsh-doctor --dsh-command /path/to/@deepseek-ai/dsh/lib/bin.js
76
+ dsh-doctor recover @scope/plugin --action quarantine
77
+ dsh-doctor recover @scope/plugin --action quarantine --output ./plugin-quarantine.yml
78
+ dsh --profile web --patch ./plugin-quarantine.yml
79
+ ```
64
80
 
65
- # Machine-readable read-only report with no prompts
66
- dsh-doctor --json
81
+ Doctor only generates it when every active entry is mapped precisely, has a unique non-empty id and an exact name assertion, and the bundle does not rewrite entries owned by another layer. Core bundles, declared client dependents, and plugins statically detected as runtime Service providers with unproven dependents require manual review.
67
82
 
68
- # Show a repair plan, apply it after confirmation, and diagnose again
69
- dsh-doctor --fix
83
+ After testing the overlay, persistence is separately gated:
70
84
 
71
- # Explicitly confirm the current plan in automation
72
- dsh-doctor --fix --yes --json
85
+ ```sh
86
+ dsh-doctor recover @scope/plugin --action persist-quarantine --verified
87
+ dsh-doctor recover @scope/plugin --action persist-quarantine --verified --yes
73
88
  ```
74
89
 
75
- `--repair` is an alias for `--fix`. `--yes` is valid only together with `--fix`.
90
+ Persistence appends the final winning profile-layer disable override and refuses the write when a home or CLI overlay would still outrank it. It then recomposes the configuration and verifies every exact target is disabled; failed verification returns a nonzero exit code. The write rechecks SHA-256 and atomically replaces the profile patch. An existing patch gets a `.dsh-doctor-<timestamp>.bak`; a first-time file gets a `.rollback.json` containing its target and created-content hash, allowing deletion rollback only while the file is unchanged.
76
91
 
77
- ## Plugin compatibility after a DSH upgrade
92
+ Preview and explicitly restore that backup or rollback record with `recover <package> --action rollback-quarantine --backup <path>`, adding `--yes` to apply it. Doctor only accepts timestamped recovery files belonging to the selected profile patch.
78
93
 
79
- After DSH is updated, Doctor assigns every direct profile plugin one explicit state and summarizes the result in both text and JSON reports:
94
+ ## Safe removal
80
95
 
81
- - `incompatible`: Doctor found an error that can prevent the plugin or Harness from loading, such as a missing plugin or an injection targeting a removed client runtime.
82
- - `risk`: Doctor found a current-version risk, such as a Harness peer range that rejects the new version, a dependency on a removed DSH package, an unsupported Node.js version, or installation drift.
83
- - `unknown`: The plugin does not declare a Harness compatibility range through `peerDependencies`, or the active package version for a declared peer cannot be resolved. Doctor cannot prove it supports the upgraded DSH, but does not report uncertainty as a failure.
84
- - `compatible`: The declared compatibility ranges accept the active Harness and no plugin-related errors or warnings were found.
96
+ Removal is always explicit and can never be inferred by legacy `--fix --yes`:
85
97
 
86
- Compatibility checks cover every direct profile plugin, not only frontend plugins with `dsh.client`. References to removed Harness APIs in bundle-only or server-side plugins are reported as well. After upgrading DSH, run `dsh-doctor` first, review the exact update recommendations, and then decide whether to continue with `dsh-doctor --fix`.
98
+ ```sh
99
+ dsh-doctor recover @scope/plugin --action remove # impact preview
100
+ dsh-doctor recover @scope/plugin --action remove --yes
101
+ ```
87
102
 
88
- ## Current checks
103
+ Automatic removal requires a direct profile dependency, a readable lockfile, a non-core bundle, no manual mount or dangling patch that would remain, and a working current DSH CLI. Before the official `dsh plugin --profile <name> remove <package>` command runs, Doctor saves a redacted diagnostic snapshot and quarantine overlay. It then re-diagnoses dependency, bundle-layer, and active-entry absence and reports the exact rollback install command.
89
104
 
90
- - JSON root structure, dependency maps, bundle lists, and reload lifecycle in the profile `package.json`
91
- - Syntax and top-level structure of profile, home, and bundle `cordis.patch.yml` files, including `!!js` expressions
92
- - Safe structural checks for `settings.yaml` and `.credentials.yaml`; credential diagnostics never expose secret values
93
- - Presence of profile dependencies, bundle declarations, patch files, and client bundles
94
- - Consistency among the profile `package.json`, the `pnpm-lock.yaml` importer, and installed versions
95
- - Node.js `engines`, Harness peer ranges, and obsolete DSH dependencies for all direct plugins, including bundle-only and server-side plugins
96
- - Version drift and stale top-level `@deepseek-ai/dsh-*` packages across the active DSH CLI, Harness workspace, and profile
97
- - The `platform`, `immediately`, `inject`, `external`, and `./client` export contract for `dsh.client`
98
- - Consistency between literal `require()` calls in client bundles and external or module suppliers
99
- - References to removed Harness client packages
100
- - Third-party plugin peer ranges against actual active Harness versions
101
- - Real resolution precedence where the Harness installation wins over a profile-local bundle with the same name
102
- - Static composition of bundle, profile, and home patches in official Harness order, including missing targets, invalid group inserts, and name assertions, without loading plugins
105
+ Static analysis cannot prove the absence of dynamic Service dependencies, external data, or regressions in every real workflow. Restart the profile and validate its main functions after any bundle update or removal.
103
106
 
104
- ## Repair safety
107
+ ## Baselines
105
108
 
106
- Every executable repair has a stable ID, risk level, description, and exact target:
109
+ ```sh
110
+ dsh-doctor baseline create
111
+ dsh-doctor baseline compare
112
+ dsh-doctor baseline create --output ./before-upgrade.json
113
+ ```
107
114
 
108
- - File repairs show their paths before confirmation and verify the SHA-256 fingerprint again before writing.
109
- - Doctor creates a `.dsh-doctor-<timestamp>.bak` backup before replacing a file atomically through a temporary file in the same directory.
110
- - External commands use fixed argument arrays and never construct shell commands.
111
- - `--json --fix --yes` captures subprocess output in the repair result so stdout remains exactly one valid JSON document.
112
- - Command repairs bind the diagnosed `DSH_HOME` and show the resolved CLI path instead of assuming `dsh` exists on PATH.
113
- - Each command repair has a 10-minute limit; a timeout terminates that action and marks subsequent actions as skipped.
114
- - A failed repair stops later actions and preserves backups already created.
115
- - Doctor runs every diagnostic again after repairs and uses the final state for its exit code.
115
+ The default baseline is `.dsh-doctor/baseline.json` inside the profile. It compares Harness state, package versions and compatibility, and introduced or resolved finding codes. It supplements current evidence; it is never required for diagnosis.
116
116
 
117
- The initial release automatically performs only deterministic operations, such as restoring an installed bundle to the manifest list or running an exact profile install or update command. Damaged JSON or YAML, credential values, and plugin removal remain recommendations because Doctor cannot safely guess the intended result.
117
+ ## Legacy confirmed repairs
118
118
 
119
- ## Exit codes
119
+ `--fix` and `--repair` remain compatible with deterministic 0.1.x install, update, and bundle-manifest repairs. They never quarantine or remove a plugin. File actions are hash-checked, backed up, and atomically replaced; commands use fixed argv and the selected `DSH_HOME`.
120
120
 
121
- - `0`: No blocking errors were found; warnings may still be present
122
- - `1`: Doctor found a problem that may prevent Harness from starting
123
- - `2`: Invalid arguments, an operational failure, or a failed repair
121
+ ## Output, exit codes, and boundaries
124
122
 
125
- ## Current limitations
123
+ Text output supports Chinese and English. `--json` keeps stable English codes and complete non-secret evidence; plugin `config` values and other common secret fields are replaced with `[REDACTED]`.
126
124
 
127
- - Static scanning recognizes only literal `require("package")` calls. Dynamic dependencies require a future bundle metadata contract.
128
- - Configuration checks cover syntax and structures that Doctor can align deterministically. Patch composition follows the current Harness algorithm, but Doctor does not evaluate `!!js` or load third-party plugins.
129
- - Version compatibility is based on plugin `peerDependencies` and resolvable active Harness package versions. A plugin without a declared range, or whose corresponding active version cannot be resolved, can receive only structural checks and an `unknown` compatibility state.
130
- - Lockfile checks deterministically cross-check the direct profile importer only; they do not recursively scan the complete npm dependency graph.
131
- - A runtime startup probe is not enabled. Even a copied `DSH_HOME` would not make arbitrary third-party plugin code side-effect-free because it could access the network, absolute paths, or external processes.
125
+ - `0`: no blocking error, or an explicit action passed static verification;
126
+ - `1`: a possible startup blocker remains, or recovery verification is incomplete;
127
+ - `2`: argument, environment, or action execution failure.
128
+
129
+ Doctor does not execute third-party plugins or evaluate `!!js`. It parses configuration structure, but redacts every plugin `config` value plus other common secret fields from JSON, baselines, and recovery snapshots; text reports do not print configuration values. Registry compatibility is declarative only. Dynamic services, external side effects, real UI behavior, and business workflows require real user validation. Ambiguous YAML or plugin ownership causes an automatic action to be refused.
132
130
 
133
131
  ## Development
134
132
 
135
133
  ```sh
136
134
  npm install
137
135
  npm run check
138
- node src/cli.mjs --help
136
+ npm pack --dry-run
139
137
  ```
140
138
 
141
- The first publication of a new package must be performed by the npm account that owns the `@bruc3van` scope with `npm publish --access public`. Then configure a GitHub Actions Trusted Publisher in the npm package settings with Organization or user `bruc3van`, Repository `dsh-doctor`, Workflow filename `release.yml`, no Environment, and only the `npm publish` allowed action.
142
-
143
- Before each later release, add a Chinese `## vX.Y.Z` entry matching the version tag to `CHANGELOG.md`. Pushing a tag that matches `package.json` makes the workflow publish through OIDC with npm provenance and automatically create or update the GitHub Release from that Chinese entry. The release fails if the entry is missing or contains no Chinese text. No long-lived npm token is required.
139
+ Publishing uses GitHub Actions OIDC and npm provenance. Local implementation and verification do not commit, tag, or publish automatically.
package/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  中文 | [English](README.en.md)
4
4
 
5
- DSH Doctor 面向 DSH 与插件使用者,帮助快速找出导致 DSH 启动异常或升级后不可用的插件,集中说明每个插件的问题、影响与处理方式,并检查常见的 profile 配置和版本漂移。诊断默认完全只读;只有显式使用 `--fix`、核对并确认精确的修复计划后才会执行,文件修改会先创建备份。
5
+ DSH Doctor 是面向 DSH 升级事故的诊断与恢复决策工具。它按插件回答:哪里不兼容、哪层配置造成或放大问题、首选修复是什么,以及暂时修不好时能否安全隔离或删除。
6
6
 
7
- 这是社区维护的第三方工具,不属于 DeepSeek 官方项目。它不会加载或执行待检查插件的代码。
7
+ 这是社区维护的第三方工具,不属于 DeepSeek 官方项目。普通诊断完全只读,也不会加载或执行待检查插件的代码。
8
8
 
9
9
  ## 安装
10
10
 
@@ -12,132 +12,180 @@ DSH Doctor 面向 DSH 与插件使用者,帮助快速找出导致 DSH 启动
12
12
 
13
13
  ```sh
14
14
  npm install --global @bruc3van/dsh-doctor
15
- dsh-doctor
15
+ dsh-doctor diagnose
16
16
  ```
17
17
 
18
18
  也可以临时运行:
19
19
 
20
20
  ```sh
21
- npx @bruc3van/dsh-doctor
21
+ npx @bruc3van/dsh-doctor diagnose
22
22
  ```
23
23
 
24
- 默认检查 `$DSH_HOME/profiles/web`;未设置 `DSH_HOME` 时使用 `~/.dsh`。
24
+ 默认检查 `$DSH_HOME/profiles/web`;未设置 `DSH_HOME` 时使用 `~/.dsh`。特殊安装可用 `--dsh-command /path/to/dsh` 指定实际 CLI,源码工作区可用 `--harness-root /path/to/deepseek-harness`。
25
25
 
26
- Doctor 不要求 `dsh` 必须是全局命令。它会按顺序查找 `--dsh-command` 或 `DSH_DOCTOR_DSH_COMMAND` 指定的命令、显式 `--harness-root` 中的 CLI、profile 共享安装或 npx 缓存留下的链接、当前项目安装、PATH,最后是自动识别出的 Harness 源码工作区。DSH Desktop 内置运行时或其他特殊安装可以通过 `--dsh-command /path/to/dsh`(也接受官方包的 `lib/bin.js`)明确指定。找不到 CLI 时仍会完成只读诊断,但不会提供或执行无法验证的命令型修复。
26
+ ## 插件从 0.1.1 升级到 0.1.2
27
27
 
28
- ## 工作方式
28
+ Doctor 内置 `dsh-v0.1.1-rc.2 → dsh-v0.1.2-alpha.2` 的版本化迁移目录,并把升级拆成三个可审计阶段:
29
29
 
30
- 一次完整流程分为四步:
30
+ ```sh
31
+ # 1. 只读分析源码、类型导入、manifest、client graph 与构建产物
32
+ dsh-doctor migrate analyze /path/to/plugin \
33
+ --harness-root /path/to/deepseek-harness
34
+
35
+ # 2. 预览 catalog 确认为 exact 的改写;加入 --yes 才写入并创建备份
36
+ dsh-doctor migrate apply /path/to/plugin --safe \
37
+ --harness-root /path/to/deepseek-harness
38
+ dsh-doctor migrate apply /path/to/plugin --safe --yes \
39
+ --harness-root /path/to/deepseek-harness
40
+
41
+ # 3. 依次完成静态、构建和隔离运行时验证
42
+ dsh-doctor migrate verify /path/to/plugin --level static \
43
+ --harness-root /path/to/deepseek-harness
44
+ dsh-doctor migrate verify /path/to/plugin --level build --yes \
45
+ --harness-root /path/to/deepseek-harness
46
+ dsh-doctor migrate verify /path/to/plugin --level runtime --yes \
47
+ --harness-root /path/to/deepseek-harness
48
+ ```
49
+
50
+ `analyze` 使用 TypeScript AST,因此能识别不会出现在 JavaScript bundle 中的 `import type`。`apply --safe` 只迁移 catalog 标记为精确等价的符号,并把非移除的 DSH 开发依赖固定到目标版本;例如 store 工具迁往 `dsh-client-store`,`ClientContext` 迁往 Cordis `Context` 并保留本地别名。它可能补充精确符号迁移需要的新依赖,但不会自动修改已有 peer 的版本范围。Session、Workspace、Conversation 和 pending interaction 属于所有权及生命周期变化,会保留为 `MIG_SEMANTIC_API_CHANGE`,不会被机械替换。
51
+
52
+ `artifact-verified` 至少要求成功执行 `build` 或 `pack:check`,仅有 `test`/`typecheck` 不足以证明发布产物。`runtime` 会从插件仓库打真实 tarball,在临时 `DSH_HOME` 中通过目标 DSH CLI 安装到全新 web profile、组合配置并做激活 smoke,不触碰普通用户的 `~/.dsh`;它还会核验目标 CLI 版本、profile manifest、安装后的包、bundle 激活和有效配置证据,不能由一个只返回成功码的空脚本伪造。失败现场会保留并报告路径;成功后默认清理。最高状态分为 `analyzed`、`source-migrated`、`artifact-verified` 和 `runtime-verified`;真实 UI、生命周期与业务行为仍需单独验证。
53
+
54
+ 仓库还随包提供 [`dsh-plugin-upgrade` skill](skills/dsh-plugin-upgrade/SKILL.md),用于指导编码 Agent 严格按上述阶段帮助插件开发者升级。
31
55
 
32
- 1. `dsh-doctor` 只读检查当前 DSH Home、profile、插件和 Harness 版本。
33
- 2. Doctor 按错误、警告和插件兼容状态展示证据与建议。
34
- 3. `dsh-doctor --fix` 先展示精确的文件修改或 DSH 命令计划,并等待用户确认。
35
- 4. 修复完成后自动重新诊断,以最终状态决定退出码。
56
+ ## 0.4.0 的诊断模型
36
57
 
37
- Doctor 不会加载待检查插件,也不会在普通诊断时修改配置。无法确定正确结果的操作,例如猜测凭据、重写损坏 YAML 或直接移除插件,只会给出建议。
58
+ `diagnose` 从空树开始,按当前 DSH 的正式顺序组合:
38
59
 
39
- ## 输出语言
60
+ ```text
61
+ bundle layers → profile cordis.patch.yml → home cordis.patch.yml → CLI overlays
62
+ ```
63
+
64
+ JSON 同时保留 `currentDefaultTree`、`currentEffectiveTree`、字段级来源、被替换来源和 `config` 整体替换时丢失的字段路径。重点识别:
40
65
 
41
- 文本输出支持中文和英文。默认依次读取:
66
+ - 旧 patch、缺失 target、错误 name assertion;
67
+ - 重复 entry id、重复插件 mount;
68
+ - 高层禁用、结构替换、group/config 整体覆盖;
69
+ - bundle 声明与 profile 激活状态冲突;
70
+ - 插件版本、产物、client contract、依赖与运行环境问题。
42
71
 
43
- 1. `--lang zh|en`
44
- 2. `DSH_DOCTOR_LANG`
45
- 3. 当前 DSH Home 中 `settings.yaml` 的 `locale.preference`
46
- 4. 终端或系统 locale
72
+ 每个 `pluginDiagnoses[]` 都把当前 `status` 与可选 `recovery` 分开。插件即使能够隔离或删除,也不会因此被标记为已经兼容。
47
73
 
48
74
  ```sh
49
- dsh-doctor --lang zh
50
- dsh-doctor --lang en
51
- DSH_DOCTOR_LANG=zh dsh-doctor
75
+ dsh-doctor diagnose
76
+ dsh-doctor diagnose --json
77
+ dsh-doctor diagnose --check-updates
52
78
  ```
53
79
 
54
- `--json` 始终保留稳定的英文消息与诊断 code,避免语言变化破坏脚本。
80
+ 只有 `--check-updates` `recover` 会访问 npm registry。离线诊断只报告 `update.status: "not-checked"`,绝不会把“未检查”写成“没有兼容版本”。
55
81
 
56
- ## DSH 升级后的插件兼容性
82
+ ## 兼容版本检查
57
83
 
58
- DSH 更新后,Doctor 会把每个 profile 插件归入一个明确状态,并在文本与 JSON 报告中汇总:
84
+ Doctor 会检查所有已发布版本的 manifest,而不是只看 `latest`,并选出声明兼容当前可解析 DSH package 版本的最高版本。结论仅表示“manifest 声明兼容的候选版本”,不代表已经通过真实启动或 UI 验证。更新始终绑定精确版本:
59
85
 
60
- - `incompatible`:已经发现会阻断插件加载或 Harness 启动的错误,例如插件未安装,或注入了已删除的 client runtime。
61
- - `risk`:发现当前版本风险,例如 Harness peer range 不接受新版本、仍依赖已删除的 DSH 包、Node.js 不兼容,或安装版本发生漂移。
62
- - `unknown`:插件没有通过 `peerDependencies` 声明 Harness 兼容范围,或声明对应的当前 package 版本无法解析;Doctor 无法证明它支持升级后的 DSH,但不会把未知误报成故障。
63
- - `compatible`:插件声明的兼容范围接受当前 Harness,且没有发现插件相关错误或警告。
86
+ ```sh
87
+ dsh-doctor recover @scope/plugin --action check-update
88
+ dsh-doctor recover @scope/plugin --action update # 只预览
89
+ dsh-doctor recover @scope/plugin --action update --yes # 执行精确版本
90
+ ```
64
91
 
65
- 兼容性检查覆盖所有 profile 直接插件,不再只检查带 `dsh.client` 的前端插件;纯 bundle 或服务端插件引用旧 Harness API 也会被报告。建议 DSH 升级后先运行一次 `dsh-doctor`,再根据精确的 update 建议决定是否执行 `dsh-doctor --fix`。
92
+ ## 临时与持久隔离
66
93
 
67
- ## 常用命令
94
+ 没有兼容版本时,默认先生成临时 overlay,再用实际 profile 验证其余功能:
68
95
 
69
96
  ```sh
70
- # 只读诊断
71
- dsh-doctor
72
- dsh-doctor --profile web
73
- dsh-doctor --home /path/to/.dsh
74
- dsh-doctor --dsh-command /path/to/@deepseek-ai/dsh/lib/bin.js
97
+ dsh-doctor recover @scope/plugin --action quarantine
98
+ dsh-doctor recover @scope/plugin --action quarantine --output ./plugin-quarantine.yml
99
+ dsh --profile web --patch ./plugin-quarantine.yml
100
+ ```
75
101
 
76
- # 机器可读的只读报告,不显示提示
77
- dsh-doctor --json
102
+ 只有所有活跃 entry 均能精确定位、都有唯一非空 id、name assertion 明确,且 bundle 没有改写其他来源 entry 时,Doctor 才会生成 overlay。核心 bundle、存在 client 依赖者或静态检测到提供运行时 Service 但无法证明依赖关系的插件都要求人工审查。overlay 会禁用插件所有已知活跃 entry,使 host 与 client 来源同时退出组合。
78
103
 
79
- # 展示修复计划,确认后实施并重新诊断
80
- dsh-doctor --fix
104
+ 验证完成后才可持久化:
81
105
 
82
- # 自动化环境中显式确认当前计划
83
- dsh-doctor --fix --yes --json
106
+ ```sh
107
+ # 先预览精确差异
108
+ dsh-doctor recover @scope/plugin --action persist-quarantine --verified
109
+
110
+ # 明确确认后写入 profile/cordis.patch.yml
111
+ dsh-doctor recover @scope/plugin --action persist-quarantine --verified --yes
84
112
  ```
85
113
 
86
- `--repair` `--fix` 的别名。`--yes` 只有和 `--fix` 一起使用才有效。
114
+ 持久写入会追加 profile 层最终生效的禁用覆盖;如果 home CLI overlay 等更高层仍会覆盖它,Doctor 会在写入前拒绝。写入后重新组合配置并逐个验证目标 entry 确实处于 disabled 状态;验证失败会返回非零退出码。写入前重新校验 SHA-256 并原子替换文件。已有 patch 会创建 `.dsh-doctor-<timestamp>.bak`;首次新建 patch 会创建 `.rollback.json`,其中记录目标文件和创建内容哈希,以便只在文件未被再次修改时执行删除式回滚。旧的 `disabled: true` 不会自动过期,所以插件升级后应重新诊断并决定是否撤销。
87
115
 
88
- ## 当前检查范围
116
+ 可先预览并显式恢复该次备份或回滚记录;Doctor 只接受属于当前 profile patch 的时间戳恢复文件:
89
117
 
90
- - profile `package.json` 的 JSON 根结构、依赖表、bundle 列表和 reload 生命周期
91
- - profile、home bundle `cordis.patch.yml` 语法与顶层结构,包括 `!!js` 表达式
92
- - `settings.yaml` `.credentials.yaml` 的安全结构检查;凭据诊断不输出秘密值
93
- - profile 依赖、bundle 声明、patch 文件和 client bundle 是否存在
94
- - profile `package.json`、`pnpm-lock.yaml` importer 与实际安装版本是否一致
95
- - 所有直接插件(包括纯 bundle/服务端插件)的 Node.js `engines`、Harness peer range、旧 DSH 依赖与当前运行时是否兼容
96
- - 当前 DSH CLI、Harness 工作区和 profile 顶层 `@deepseek-ai/dsh-*` 包是否发生版本漂移或残留
97
- - `dsh.client` 的 `platform`、`immediately`、`inject`、`external` 和 `./client` export contract
98
- - client bundle 中字面量 `require()` 与 external/module supplier 的一致性
99
- - 已删除的 Harness client package 引用
100
- - 第三方插件 peer range 与当前 Harness 实际版本的兼容性
101
- - Harness installation 优先于 profile 同名 bundle 的真实解析顺序
102
- - 按 Harness 官方层级顺序静态组合 bundle、profile 和 home patch,检查缺失 target、错误 group insert 与 name assertion;不会加载插件
118
+ ```sh
119
+ dsh-doctor recover @scope/plugin --action rollback-quarantine --backup /path/to/cordis.patch.yml.dsh-doctor-...bak
120
+ dsh-doctor recover @scope/plugin --action rollback-quarantine --backup /path/to/cordis.patch.yml.dsh-doctor-...bak --yes
121
+ # 首次新建时,把上面的 .bak 换成命令返回的 .rollback.json
122
+ ```
103
123
 
104
- ## 修复安全边界
124
+ ## 安全删除
105
125
 
106
- 每条可执行修复都包含稳定 ID、风险级别、说明和精确目标:
126
+ 删除是独立动作,永远不会由通用 `--fix --yes` 推断:
107
127
 
108
- - 文件修复在确认前展示路径,确认后再次校验 SHA-256 指纹。
109
- - 写入前创建 `.dsh-doctor-<timestamp>.bak` 备份,再通过同目录临时文件原子替换。
110
- - 外部命令使用固定 argv 调用,不拼接 shell 命令。
111
- - `--json --fix --yes` 会捕获子命令输出并放入修复结果,保证 stdout 始终只有一个合法 JSON 文档。
112
- - 命令修复绑定当前诊断的 `DSH_HOME`,并展示解析出的真实 CLI 路径;不会假定 PATH 中存在 `dsh`。
113
- - 单个命令修复最长运行 10 分钟,超时会终止该动作并把后续动作标记为跳过。
114
- - 任一步失败即停止后续修复,并保留已经创建的备份。
115
- - 完成后重新运行全部诊断,以最终状态决定退出码。
128
+ ```sh
129
+ dsh-doctor recover @scope/plugin --action remove # 只做影响预检
130
+ dsh-doctor recover @scope/plugin --action remove --yes # 显式执行
131
+ ```
116
132
 
117
- 首期只自动处理确定性操作,例如把已安装 bundle 恢复到 manifest 列表,或运行明确的 profile install/update。损坏 JSON/YAML、凭据值和插件移除只给建议,不猜测应该删除或改成什么。
133
+ 自动删除要求插件是 profile 直接依赖、不是模板/内置核心 bundle、lockfile 可读、没有会残留的手工 mount dangling patch,并且当前 DSH CLI 可用。执行前会保存已脱敏的诊断快照和临时 quarantine overlay,再调用官方命令:
118
134
 
119
- ## 退出码
135
+ ```sh
136
+ dsh plugin --profile web remove @scope/plugin
137
+ ```
120
138
 
121
- - `0`:没有阻断错误;warning 仍会显示
122
- - `1`:发现可能阻断 Harness 启动的问题
123
- - `2`:参数、运行环境或修复执行失败
139
+ 成功后重新诊断并分别验证 dependency、bundle layer 和活跃 entry 已消失,同时保留原版本的精确回滚安装命令。静态检查无法证明不存在动态 Service 依赖、外部数据残留或所有真实业务流程都正常;完成后仍须重启 profile 并验证主要功能。
124
140
 
125
- ## 当前限制
141
+ ## 历史基线
126
142
 
127
- - 静态扫描只识别代码中的字面量 `require("package")`;动态依赖需要未来的 bundle 元数据协议。
128
- - 配置检查覆盖语法和 Doctor 能稳定对齐的结构,并按当前 Harness patch 算法做无执行组合检查;不会求值 `!!js`,也不会加载第三方插件。
129
- - 版本兼容以插件 `peerDependencies` 和当前可解析 Harness package 版本为依据;未声明兼容范围或无法解析对应当前版本的插件只能做结构检查。
130
- - lockfile 检查只对 profile 的直接依赖 importer 做确定性交叉验证,不递归扫描整个 npm 依赖树。
131
- - 真实启动探针尚未启用;即使复制 `DSH_HOME`,第三方插件仍可能访问网络、绝对路径或启动外部进程,不能宣称无副作用。
143
+ 升级前保存基线,升级后比较插件版本、兼容状态、Harness finding 变化:
144
+
145
+ ```sh
146
+ dsh-doctor baseline create
147
+ dsh-doctor baseline compare
148
+
149
+ # 自定义基线路径
150
+ dsh-doctor baseline create --output ./before-upgrade.json
151
+ dsh-doctor baseline compare --output ./before-upgrade.json
152
+ ```
153
+
154
+ 默认基线位于 profile 的 `.dsh-doctor/baseline.json`。基线用于差异归因,不是当前诊断的前提,也不会覆盖当前现场证据。
155
+
156
+ ## 旧版确认式修复
157
+
158
+ `--fix` / `--repair` 继续兼容 0.1.x 的确定性 install、update 与 bundle manifest 修复:
159
+
160
+ ```sh
161
+ dsh-doctor --fix
162
+ dsh-doctor --fix --yes --json
163
+ ```
164
+
165
+ 它不会触发 quarantine、持久化隔离或删除。文件动作展示路径并创建备份,命令使用固定 argv、绑定当前 `DSH_HOME`,任一步失败都会停止后续动作。
166
+
167
+ ## 输出与退出码
168
+
169
+ 文本支持中文和英文,优先级为 `--lang`、`DSH_DOCTOR_LANG`、DSH 设置和系统 locale。`--json` 始终保留稳定英文 code 和完整的非秘密证据;插件 `config` 值和其他常见秘密字段会替换为 `[REDACTED]`。
170
+
171
+ - `0`:没有阻断错误,或显式动作成功且静态验证通过;
172
+ - `1`:仍有可能阻断启动的问题,或恢复后静态状态不完整;
173
+ - `2`:参数、运行环境或动作执行失败。
174
+
175
+ ## 安全边界
176
+
177
+ - 不执行第三方插件,不求值 `!!js`;诊断会解析配置结构,但 JSON、baseline 和恢复快照会脱敏所有插件 `config` 值及其他常见秘密字段,文本报告也不打印配置值;
178
+ - registry 结果只证明 manifest 声明,不证明真实运行兼容;
179
+ - 动态 Service 依赖、外部副作用、真实 UI 和业务流程需要用户验证;
180
+ - patch 精确编辑只处理 Doctor 能安全解析和定位的结构;有歧义时拒绝自动操作;
181
+ - 添加、更新或删除 bundle 后,运行中的 profile 不会自动改变 bundle 集合,必须重启。
132
182
 
133
183
  ## 从源码开发
134
184
 
135
185
  ```sh
136
186
  npm install
137
187
  npm run check
138
- node src/cli.mjs --help
188
+ npm pack --dry-run
139
189
  ```
140
190
 
141
- 新包需要先由 `@bruc3van` 对应的 npm 账号完成一次 `npm publish --access public`,创建公开包页面。然后在 npm 包设置中添加 GitHub Actions Trusted Publisher:Organization or user `bruc3van`,Repository 为 `dsh-doctor`,Workflow filename 为 `release.yml`,Environment 留空,Allowed actions 只启用 `npm publish`。
142
-
143
- 后续发布前,需要在 `CHANGELOG.md` 中增加与版本 tag 同名的中文 `## vX.Y.Z` 条目。推送与 `package.json` 版本一致的 tag 后,workflow 会通过 OIDC 发布 npm 包、生成 provenance,并自动用该中文条目创建或更新 GitHub Release;缺少中文条目时发布流程会失败。不需要保存长期 npm token。
191
+ 发布仍使用 GitHub Actions OIDC npm provenance;本地实现和验证不会自动提交、打 tag 或发布。
@@ -0,0 +1,12 @@
1
+ # DSH 0.1.1-rc.2 to 0.1.2-alpha.2 behavior migration
2
+
3
+ The old Client Runtime was split by ownership. There is no aggregate replacement package.
4
+
5
+ - Session control, list state, commands, projections, queue and event windows belong to `api-session-controller/client`.
6
+ - Workspace state and commands belong to `api-workspace-controller/client`; navigation policy belongs to `ui-workspace`.
7
+ - Conversation assembly belongs to `ui-conversation`; Chat and Trajectory own their respective projections.
8
+ - Approval and Question own their pending objects; `ui-session` only aggregates domain publications.
9
+ - The store engine belongs to `client-store`; React hook synthesis belongs to the renderer.
10
+ - The Host API Proxy was removed. Unary browser operations live on their natural Remote service owners.
11
+
12
+ An import move is safe only when the catalog marks it `exact`. A `semantic` mapping identifies the new owner but still requires the plugin developer to rewrite behavior and verify the real lifecycle.
@@ -0,0 +1,36 @@
1
+ {
2
+ "platformModules": [
3
+ "react",
4
+ "react/jsx-runtime",
5
+ "react-dom",
6
+ "react-dom/client",
7
+ "@deepseek-ai/cordis",
8
+ "@deepseek-ai/dsh-client-store",
9
+ "@deepseek-ai/dsh-client-ui-slots",
10
+ "@deepseek-ai/dsh-client-ui-primitives"
11
+ ],
12
+ "profilePatchPaths": {
13
+ "web": [
14
+ "packages/bundle/base/cordis.patch.yml",
15
+ "packages/bundle/web-app/cordis.patch.yml"
16
+ ]
17
+ },
18
+ "rules": [
19
+ {
20
+ "id": "client-inject-is-informational",
21
+ "note": "dsh.client.inject lists package dependency edges; Cordis service inject controls activation."
22
+ },
23
+ {
24
+ "id": "baseline-external-is-implicit",
25
+ "note": "Platform modules are implicit and must not be repeated in dsh.client.external."
26
+ },
27
+ {
28
+ "id": "feature-values-use-services-or-slots",
29
+ "note": "Feature plugins must not use dsh.client.external as a feature-to-feature value dependency mechanism."
30
+ },
31
+ {
32
+ "id": "client-export-required",
33
+ "note": "A web dsh.client declaration requires a published exports[\"./client\"] artifact."
34
+ }
35
+ ]
36
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.2",
4
+ "from": {
5
+ "ref": "dsh-v0.1.1-rc.2",
6
+ "commit": "b150a551b8d465e31e418e1b2eaf5e79bbb7d28e"
7
+ },
8
+ "to": {
9
+ "ref": "dsh-v0.1.2-alpha.2",
10
+ "commit": "0a53fb55bea101816fa226bb964ae2bed71c343b",
11
+ "version": "0.1.2-alpha.2"
12
+ },
13
+ "description": "DeepSeek Harness 0.1.1-rc.2 to 0.1.2-alpha.2 plugin migration",
14
+ "references": {
15
+ "ownership": ".agents/notes/implemented/architecture/2026-08-20-client-session-conversation-ownership.md",
16
+ "remoteMigration": ".agents/notes/implemented/architecture/2026-08-10-unary-apiproxy-remote-migration.md",
17
+ "clientRules": "packages/client/AGENTS.md"
18
+ }
19
+ }