@bruc3van/dsh-doctor 0.1.6 → 0.5.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.en.md CHANGED
@@ -2,142 +2,250 @@
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
+ Or run without installing:
19
19
 
20
20
  ```sh
21
- npx @bruc3van/dsh-doctor
21
+ npx @bruc3van/dsh-doctor diagnose
22
22
  ```
23
23
 
24
- By default, Doctor checks `$DSH_HOME/profiles/web`. If `DSH_HOME` is unset, it uses `~/.dsh`.
24
+ 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.
25
25
 
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.
26
+ ---
27
27
 
28
- ## How it works
28
+ ## Plugin migration: 0.1.1 → 0.1.2
29
29
 
30
- A complete diagnosis and repair flow has four steps:
30
+ ### migrate commands
31
31
 
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.
32
+ Doctor ships a versioned `dsh-v0.1.1-rc.2 dsh-v0.1.2-alpha.2` migration catalog and exposes three auditable stages:
36
33
 
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.
34
+ ```sh
35
+ # Stage 1: read-only analysis of source, type imports, manifest, client graph, and build artifacts
36
+ dsh-doctor migrate analyze /path/to/plugin \
37
+ --from dsh-v0.1.1-rc.2 \
38
+ --to dsh-v0.1.2-alpha.2 \
39
+ --harness-root /path/to/deepseek-harness
40
+
41
+ # Stage 2: preview exact rewrites; add --yes to write and create timestamped backups
42
+ dsh-doctor migrate apply /path/to/plugin --safe \
43
+ --harness-root /path/to/deepseek-harness
44
+ dsh-doctor migrate apply /path/to/plugin --safe --yes \
45
+ --harness-root /path/to/deepseek-harness
46
+
47
+ # Stage 3: static, build, and isolated runtime verification in order
48
+ dsh-doctor migrate verify /path/to/plugin --level static \
49
+ --harness-root /path/to/deepseek-harness
50
+ dsh-doctor migrate verify /path/to/plugin --level build --yes \
51
+ --harness-root /path/to/deepseek-harness
52
+ dsh-doctor migrate verify /path/to/plugin --level runtime --yes \
53
+ --harness-root /path/to/deepseek-harness
54
+ ```
55
+
56
+ Run `dsh-doctor migrations list` to confirm the CLI contains this exact version pair before starting. Without a local install, `npx --package=@bruc3van/dsh-doctor dsh-doctor migrations list` works the same.
57
+
58
+ ### Stage details
59
+
60
+ **analyze**: Uses the TypeScript AST so it sees type-only imports that disappear from JavaScript bundles. Also checks package metadata, client graph declarations, and build artifacts. A clean bundle alone does not imply compatibility.
61
+
62
+ **apply --safe**: Rewrites only catalog-confirmed exact-equivalent symbols, pins non-removed DSH development dependencies to the target version, and creates timestamped backups. It may add dependencies required by exact symbol moves but does not automatically change existing peer ranges. Session, Workspace, Conversation, and pending-interaction ownership changes are left as `MIG_SEMANTIC_API_CHANGE` and are never mechanically replaced.
63
+
64
+ **verify**:
65
+
66
+ | Level | What it does |
67
+ |---|---|
68
+ | `static` | Uses the TypeScript AST to inspect source/imports, manifest, client graph, and build artifacts without running project scripts |
69
+ | `build` | Executes plugin build scripts and verifies the artifact (`build` or `pack:check` must succeed; `test`/`typecheck` alone is insufficient proof of a publishable artifact) |
70
+ | `runtime` | Packs the real plugin tarball, installs it under a temporary `DSH_HOME` via the target CLI into a fresh web profile, verifies CLI version, profile manifest, installed package, activated bundle, effective config, and performs an activation smoke; never touches the normal `~/.dsh` |
38
71
 
39
- ## Output language
72
+ The highest achievable gate is `analyzed` → `source-migrated` → `artifact-verified` → `runtime-verified`. `runtime-verified` still does not prove real UI, lifecycle, or business behavior. Failed workspaces are retained and reported; successful ones are cleaned up by default.
40
73
 
41
- Text output supports English and Chinese. Doctor resolves the language in this order:
74
+ ### Key API changes
42
75
 
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
76
+ `@deepseek-ai/dsh-client-runtime` was removed with **no aggregate replacement**. Capabilities migrate to:
77
+
78
+ | Concern | 0.1.2 owner | Migration |
79
+ |---|---|---|
80
+ | store engine and equality helpers | `dsh-client-store` | exact (catalog-listed symbols) |
81
+ | Cordis client context type | `@deepseek-ai/cordis` `Context` | exact; preserve local aliases |
82
+ | session control / list / commands | `dsh-api-session-controller/client` | semantic (developer judgment required) |
83
+ | workspace state / commands | `dsh-api-workspace-controller/client` | semantic |
84
+ | conversation assembly | `dsh-client-ui-conversation/client` | semantic |
85
+ | pending-interaction state | domain UI packages aggregated by `ui-session` | semantic |
86
+
87
+ `@deepseek-ai/dsh-host-apiproxy` was also removed with no compatible substitute. Browser operations use their natural generated Remote owners through API Remotes/API Gateway contributions.
88
+
89
+ ### dsh-plugin-upgrade skill
90
+
91
+ The package ships the [`dsh-plugin-upgrade` skill](skills/dsh-plugin-upgrade/SKILL.md) so coding agents (such as Claude Code) can drive the full migration workflow without collapsing any safety gate. The skill triggers when a plugin developer asks for migration, compatibility assessment, API replacement, peer dependency updates, artifact rebuilds, or DSH 0.1.2 runtime verification.
92
+
93
+ Install it directly from the GitHub repository into a supported coding agent:
47
94
 
48
95
  ```sh
49
- dsh-doctor --lang zh
50
- dsh-doctor --lang en
51
- DSH_DOCTOR_LANG=zh dsh-doctor
96
+ npx skills add bruc3van/dsh-doctor
52
97
  ```
53
98
 
54
- `--json` always keeps stable English messages and diagnostic codes so language changes do not break automation.
99
+ The repository currently exposes one skill, so the `skills` CLI discovers and installs `dsh-plugin-upgrade`; add `--skill dsh-plugin-upgrade` to select it explicitly. This installs the agent skill, not a global DSH Doctor CLI. The skill uses an existing `dsh-doctor` command when available and falls back to the matching `npx @bruc3van/dsh-doctor` workflow when it is not installed.
100
+
101
+ ---
102
+
103
+ ## Diagnosis
104
+
105
+ ### Diagnosis model
55
106
 
56
- ## Common commands
107
+ `diagnose` composes the configuration from an empty tree in the same order as current DSH:
108
+
109
+ ```text
110
+ bundle layers → profile cordis.patch.yml → home cordis.patch.yml → CLI overlays
111
+ ```
112
+
113
+ The JSON report retains `currentDefaultTree`, `currentEffectiveTree`, field-level provenance, replaced sources, and paths removed by whole-`config` replacement. It diagnoses:
114
+
115
+ - stale patches, missing targets, wrong name assertions;
116
+ - duplicate entry ids and duplicate plugin mounts;
117
+ - higher-layer disabling, structural replacement, whole group/config overrides;
118
+ - bundle declaration conflicts with profile activation state;
119
+ - plugin versions, artifacts, client contracts, dependencies, and runtime issues.
120
+
121
+ Every `pluginDiagnoses[]` object keeps current `status` separate from `recovery`. Being removable does not make an incompatible plugin compatible.
57
122
 
58
123
  ```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
124
+ dsh-doctor diagnose
125
+ dsh-doctor diagnose --json
126
+ dsh-doctor diagnose --check-updates
127
+ ```
64
128
 
65
- # Machine-readable read-only report with no prompts
66
- dsh-doctor --json
129
+ Only `--check-updates` and `recover` contact the npm registry. Offline diagnosis reports `update.status: "not-checked"` and never turns "not checked" into "no compatible version."
67
130
 
68
- # Show a repair plan, apply it after confirmation, and diagnose again
69
- dsh-doctor --fix
131
+ ---
70
132
 
71
- # Explicitly confirm the current plan in automation
72
- dsh-doctor --fix --yes --json
133
+ ## Recovery decisions
134
+
135
+ ### Compatible-version search
136
+
137
+ 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 a manifest-declared candidate only, not proof from a real startup or UI test.
138
+
139
+ ```sh
140
+ dsh-doctor recover @scope/plugin --action check-update
141
+ dsh-doctor recover @scope/plugin --action update # preview
142
+ dsh-doctor recover @scope/plugin --action update --yes # exact version
143
+ ```
144
+
145
+ ### Quarantine
146
+
147
+ When no compatible release is available, generate and test a temporary overlay first:
148
+
149
+ ```sh
150
+ dsh-doctor recover @scope/plugin --action quarantine
151
+ dsh-doctor recover @scope/plugin --action quarantine --output ./plugin-quarantine.yml
152
+ dsh --profile web --patch ./plugin-quarantine.yml
153
+ ```
154
+
155
+ Doctor only generates an overlay when every active entry is precisely mapped, 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. The overlay disables all known active entries, causing both host and client sources to exit composition.
156
+
157
+ After testing the overlay, persistence is separately gated:
158
+
159
+ ```sh
160
+ # Preview the exact diff first
161
+ dsh-doctor recover @scope/plugin --action persist-quarantine --verified
162
+
163
+ # Write to profile/cordis.patch.yml after explicit confirmation
164
+ dsh-doctor recover @scope/plugin --action persist-quarantine --verified --yes
73
165
  ```
74
166
 
75
- `--repair` is an alias for `--fix`. `--yes` is valid only together with `--fix`.
167
+ 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, enabling deletion rollback only while the file is unchanged.
76
168
 
77
- ## Plugin compatibility after a DSH upgrade
169
+ Preview and explicitly restore that backup or rollback record:
78
170
 
79
- After DSH is updated, Doctor assigns every direct profile plugin one explicit state and summarizes the result in both text and JSON reports:
171
+ ```sh
172
+ dsh-doctor recover @scope/plugin --action rollback-quarantine \
173
+ --backup /path/to/cordis.patch.yml.dsh-doctor-...bak
174
+ dsh-doctor recover @scope/plugin --action rollback-quarantine \
175
+ --backup /path/to/cordis.patch.yml.dsh-doctor-...bak --yes
176
+ ```
80
177
 
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.
178
+ Doctor only accepts timestamped recovery files belonging to the selected profile patch.
85
179
 
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`.
180
+ ### Safe removal
87
181
 
88
- ## Current checks
182
+ Removal is always explicit and can never be inferred by legacy `--fix --yes`:
89
183
 
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
184
+ ```sh
185
+ dsh-doctor recover @scope/plugin --action remove # impact preview
186
+ dsh-doctor recover @scope/plugin --action remove --yes
187
+ ```
103
188
 
104
- ## Repair safety
189
+ 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 command runs, Doctor saves a redacted diagnostic snapshot and quarantine overlay:
105
190
 
106
- Every executable repair has a stable ID, risk level, description, and exact target:
191
+ ```sh
192
+ dsh plugin --profile web remove @scope/plugin
193
+ ```
107
194
 
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.
195
+ It then re-diagnoses dependency, bundle-layer, and active-entry absence and reports the exact rollback install command. 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.
116
196
 
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.
197
+ ---
118
198
 
119
- ## Exit codes
199
+ ## Baselines
120
200
 
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
201
+ Save a baseline before upgrading, then compare plugin versions, compatibility state, Harness state, and finding changes afterwards:
124
202
 
125
- ## Current limitations
203
+ ```sh
204
+ dsh-doctor baseline create
205
+ dsh-doctor baseline compare
126
206
 
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.
207
+ # Custom path
208
+ dsh-doctor baseline create --output ./before-upgrade.json
209
+ dsh-doctor baseline compare --output ./before-upgrade.json
210
+ ```
211
+
212
+ The default baseline is `.dsh-doctor/baseline.json` inside the profile. It supplements current evidence and is never required for diagnosis.
213
+
214
+ ## Legacy confirmed repairs
215
+
216
+ `--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`.
217
+
218
+ ```sh
219
+ dsh-doctor --fix
220
+ dsh-doctor --fix --yes --json
221
+ ```
222
+
223
+ ---
224
+
225
+ ## Output and exit codes
226
+
227
+ 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]`.
228
+
229
+ | Exit code | Meaning |
230
+ |---|---|
231
+ | `0` | No blocking error, or an explicit action passed static verification |
232
+ | `1` | A possible startup blocker remains, or recovery verification is incomplete |
233
+ | `2` | Argument, environment, or action execution failure |
234
+
235
+ ## Security boundaries
236
+
237
+ - Does not execute third-party plugins or evaluate `!!js`; diagnosis 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.
238
+ - Registry compatibility is declarative only; it does not prove a real startup or UI test.
239
+ - Dynamic Service dependencies, external side effects, real UI behavior, and business workflows require user validation.
240
+ - Precise patch edits only operate on structures Doctor can safely parse and locate; ambiguous cases are refused automatically.
241
+ - After adding, updating, or removing a bundle, a running profile does not automatically change its bundle set — a restart is required.
132
242
 
133
243
  ## Development
134
244
 
135
245
  ```sh
136
246
  npm install
137
247
  npm run check
138
- node src/cli.mjs --help
248
+ npm pack --dry-run
139
249
  ```
140
250
 
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.
251
+ Publishing uses GitHub Actions OIDC and npm provenance. Local implementation and verification do not commit, tag, or publish automatically.