@bruc3van/dsh-doctor 0.5.5 → 0.5.7

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.
Files changed (30) hide show
  1. package/README.en.md +77 -181
  2. package/README.md +77 -181
  3. package/migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.2/packages.json +1 -3
  4. package/migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.2/symbols.json +8 -0
  5. package/migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.3/behavior.md +14 -0
  6. package/migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.3/config-rules.json +36 -0
  7. package/migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.3/manifest.json +19 -0
  8. package/migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.3/packages.json +74 -0
  9. package/migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.3/services.json +28 -0
  10. package/migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.3/symbols.json +134 -0
  11. package/package.json +1 -1
  12. package/skills/dsh-plugin-upgrade/SKILL.md +54 -23
  13. package/skills/dsh-plugin-upgrade/evals/evals.json +55 -0
  14. package/skills/dsh-plugin-upgrade/evals/files/import-move-plugin/README.md +5 -0
  15. package/skills/dsh-plugin-upgrade/evals/files/import-move-plugin/package.json +31 -0
  16. package/skills/dsh-plugin-upgrade/evals/files/import-move-plugin/src/index.ts +20 -0
  17. package/skills/dsh-plugin-upgrade/evals/files/import-move-plugin/src/stores.ts +15 -0
  18. package/skills/dsh-plugin-upgrade/evals/files/settings-plugin/README.md +7 -0
  19. package/skills/dsh-plugin-upgrade/evals/files/settings-plugin/package.json +20 -0
  20. package/skills/dsh-plugin-upgrade/evals/files/settings-plugin/src/index.ts +2 -0
  21. package/skills/dsh-plugin-upgrade/evals/files/settings-plugin/src/namespace-read.ts +6 -0
  22. package/skills/dsh-plugin-upgrade/evals/files/settings-plugin/src/settings.ts +21 -0
  23. package/skills/dsh-plugin-upgrade/evals/trigger-evals.json +22 -0
  24. package/skills/dsh-plugin-upgrade/references/cli-bootstrap.md +6 -4
  25. package/skills/dsh-plugin-upgrade/references/migration-map.md +5 -1
  26. package/skills/dsh-plugin-upgrade/references/source-investigation.md +2 -0
  27. package/skills/dsh-plugin-upgrade/references/verification.md +6 -0
  28. package/src/cli.mjs +7 -3
  29. package/src/migrate-verify.mjs +3 -2
  30. package/src/migrate.mjs +53 -22
@@ -0,0 +1,134 @@
1
+ {
2
+ "modules": {
3
+ "@deepseek-ai/dsh-settings": {
4
+ "settingsNamespace": {
5
+ "toModule": "@deepseek-ai/dsh-settings",
6
+ "toSymbol": "SettingsProvider.register",
7
+ "confidence": "semantic",
8
+ "reason": "The settingsNamespace factory was removed. Inject the settings Service and register the namespace through ctx.settings.register(name, schema)."
9
+ }
10
+ },
11
+ "@deepseek-ai/dsh-client-runtime/client": {
12
+ "ClientContext": {
13
+ "toModule": "@deepseek-ai/cordis",
14
+ "toSymbol": "Context",
15
+ "confidence": "exact",
16
+ "reason": "ClientContext was a type alias of Cordis Context."
17
+ },
18
+ "createSnapshotStore": {
19
+ "toModule": "@deepseek-ai/dsh-client-store",
20
+ "toSymbol": "createSnapshotStore",
21
+ "confidence": "exact",
22
+ "reason": "The React-free store engine moved to client-store."
23
+ },
24
+ "defineStore": {
25
+ "toModule": "@deepseek-ai/dsh-client-store",
26
+ "toSymbol": "defineStore",
27
+ "confidence": "exact",
28
+ "reason": "The declarative store factory moved to client-store."
29
+ },
30
+ "ObservableSnapshot": {
31
+ "toModule": "@deepseek-ai/dsh-client-store",
32
+ "toSymbol": "ObservableSnapshot",
33
+ "confidence": "exact",
34
+ "reason": "The observable store contract moved to client-store."
35
+ },
36
+ "SnapshotStore": {
37
+ "toModule": "@deepseek-ai/dsh-client-store",
38
+ "toSymbol": "SnapshotStore",
39
+ "confidence": "exact",
40
+ "reason": "The writable store contract moved to client-store."
41
+ },
42
+ "shallowEqual": {
43
+ "toModule": "@deepseek-ai/dsh-client-store",
44
+ "toSymbol": "shallowEqual",
45
+ "confidence": "exact",
46
+ "reason": "The store equality helper moved to client-store."
47
+ },
48
+ "SessionId": {
49
+ "toModule": "@deepseek-ai/dsh-session/types",
50
+ "toSymbol": "SessionId",
51
+ "confidence": "exact",
52
+ "reason": "Session identity is owned by the Session domain."
53
+ },
54
+ "ISessions": {
55
+ "toModule": "@deepseek-ai/dsh-api-session-controller/client",
56
+ "toSymbol": "ISessions",
57
+ "confidence": "semantic",
58
+ "reason": "Session ownership moved to the Session Controller and its snapshots changed."
59
+ },
60
+ "Session": {
61
+ "toModule": "@deepseek-ai/dsh-api-session-controller/client",
62
+ "toSymbol": "Session",
63
+ "confidence": "semantic",
64
+ "reason": "The Client Session object and lifecycle moved to the Session Controller."
65
+ },
66
+ "SessionBinding": {
67
+ "toModule": "@deepseek-ai/dsh-api-session-controller/client",
68
+ "toSymbol": "SessionBinding",
69
+ "confidence": "semantic",
70
+ "reason": "Session bindings are now Controller-owned lifetimes."
71
+ },
72
+ "SessionListState": {
73
+ "toModule": "@deepseek-ai/dsh-api-session-controller/client",
74
+ "toSymbol": "SessionListState",
75
+ "confidence": "semantic",
76
+ "reason": "The list state moved and no longer owns Conversation or pending-interaction facts."
77
+ },
78
+ "SessionSummary": {
79
+ "toModule": "@deepseek-ai/dsh-api-session-controller/client",
80
+ "toSymbol": "SessionSummary",
81
+ "confidence": "semantic",
82
+ "reason": "The Session summary is now a Controller-owned control snapshot."
83
+ },
84
+ "UseProjection": {
85
+ "toModule": "@deepseek-ai/dsh-api-session-controller/client",
86
+ "toSymbol": "UseProjection",
87
+ "confidence": "semantic",
88
+ "reason": "Projection sources are now exposed by Session Controller bindings and adapted by ui-session."
89
+ },
90
+ "IWorkspaces": {
91
+ "toModule": "@deepseek-ai/dsh-api-workspace-controller/client",
92
+ "toSymbol": "IWorkspaces",
93
+ "confidence": "semantic",
94
+ "reason": "Workspace ownership moved to the Workspace Controller and navigation policy moved to ui-workspace."
95
+ },
96
+ "WorkspaceId": {
97
+ "toModule": "@deepseek-ai/dsh-api-workspace-controller/client",
98
+ "toSymbol": "WorkspaceId",
99
+ "confidence": "semantic",
100
+ "reason": "Workspace identity is re-exported by the Workspace Controller."
101
+ },
102
+ "WorkspaceView": {
103
+ "toModule": "@deepseek-ai/dsh-api-workspace-controller/client",
104
+ "toSymbol": "WorkspaceView",
105
+ "confidence": "semantic",
106
+ "reason": "Workspace snapshots are Controller-owned and their shape changed."
107
+ },
108
+ "ConversationNode": {
109
+ "toModule": "@deepseek-ai/dsh-client-ui-conversation/client",
110
+ "toSymbol": "ConversationNode",
111
+ "confidence": "semantic",
112
+ "reason": "Conversation assembly moved out of Session snapshots into ui-conversation."
113
+ },
114
+ "ConversationSnapshot": {
115
+ "toModule": "@deepseek-ai/dsh-client-ui-conversation/client",
116
+ "toSymbol": "ConversationSnapshot",
117
+ "confidence": "semantic",
118
+ "reason": "Conversation is now an independent target-neutral source."
119
+ },
120
+ "PendingInteraction": {
121
+ "toModule": "@deepseek-ai/dsh-client-ui-session/client",
122
+ "toSymbol": "SessionPendingInteraction",
123
+ "confidence": "semantic",
124
+ "reason": "Approval and Question now publish domain-owned pending interactions through ui-session."
125
+ },
126
+ "PendingWait": {
127
+ "toModule": "@deepseek-ai/dsh-client-ui-session/client",
128
+ "toSymbol": "SessionPendingInteraction",
129
+ "confidence": "semantic",
130
+ "reason": "The Runtime PendingWait aggregate was removed; pending domains own their payloads."
131
+ }
132
+ }
133
+ }
134
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bruc3van/dsh-doctor",
3
- "version": "0.5.5",
3
+ "version": "0.5.7",
4
4
  "description": "Help agents diagnose and upgrade DeepSeek Harness plugins from DSH 0.1.1 to 0.1.2",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,13 +1,22 @@
1
1
  ---
2
2
  name: dsh-plugin-upgrade
3
- description: Help diagnose and upgrade a DeepSeek Harness plugin from DSH 0.1.1 to 0.1.2 with dsh-doctor, while deciding explicitly whether the upgraded release must remain compatible with DSH 0.1.1. Use when a plugin developer asks to assess compatibility, identify changed APIs, replace removed dsh-client-runtime or dsh-host-apiproxy usage, update DSH dependencies, modify plugin code, rebuild artifacts, or verify the plugin before releasing a new version. Apply only catalog-confirmed exact rewrites automatically, guide semantic code changes, and report what still needs developer verification. The current catalog uses dsh-v0.1.1-rc.2 and dsh-v0.1.2-alpha.2 as its reference points.
3
+ description: Help migrate a DeepSeek Harness (DSH) plugin from DSH 0.1.1 to 0.1.2 with the dsh-doctor CLI, deciding explicitly up front whether the upgraded release must stay compatible with DSH 0.1.1. Use when a plugin developer plans a migration or compatibility assessment: checking what changed between DSH versions, replacing imports of packages 0.1.2 removed (such as dsh-client-runtime or dsh-host-apiproxy), migrating settingsNamespace to the settings Service, updating DSH dependency ranges, or verifying and preparing a plugin release for 0.1.2. Applies only catalog-confirmed exact rewrites automatically and guides the semantic changes that need developer judgment. Not for debugging a plugin that already targets 0.1.2, general DSH usage or configuration questions, or developing the Harness itself.
4
4
  ---
5
5
 
6
6
  # Upgrade a DSH 0.1.1 plugin to 0.1.2
7
7
 
8
8
  Help the developer diagnose and modify one plugin at a time. Treat source migration, artifact verification, runtime activation, and business behavior as separate gates.
9
9
 
10
- The current migration knowledge covers the DSH 0.1.1 to 0.1.2 transition. Its CLI catalog records `dsh-v0.1.1-rc.2` and `dsh-v0.1.2-alpha.2` as the exact reference points used to derive and verify known changes. Use those refs in dsh-doctor commands, but first record the plugin's actual DSH ranges and requested target. When another patch or prerelease is involved, use the catalog for known changes only and report that the additional version difference still needs review. Do not claim that the catalog proves an unlisted version combination.
10
+ The migration knowledge covers the DSH 0.1.1 to 0.1.2 transition, derived and verified from one exact catalog version pair (declared below). Keep the skill's product scope at the release-line level (`0.1.1` to `0.1.2`), while keeping the catalog target exact. First record the plugin's actual DSH ranges and requested target. When a newer patch or prerelease appears, use the catalog for known changes only, inspect the additional interval, and report that it is not catalog-confirmed until the catalog and this skill are deliberately updated a pass for the catalog pair never proves an unlisted version combination.
11
+
12
+ ## Current catalog version pair
13
+
14
+ This block is the single source of truth for the exact refs. Every command below and every reference file defers to it; the references avoid repeating the literals on purpose. When the catalog advances, update this block, the `migrate analyze` example, and the shipped catalog together.
15
+
16
+ - source ref: `dsh-v0.1.1-rc.2`
17
+ - target ref: `dsh-v0.1.2-alpha.3`
18
+
19
+ Standard commands target this pair and need no `--target-version`. If the developer explicitly targets a newer 0.1.2 build before the catalog is updated, inspect that additional interval first (see [source-investigation.md](references/source-investigation.md)), then pass its exact version to every migration phase as `--target-version <actual-0.1.2-version>`. That changes dependency pins and runtime expectations only; the catalog's API claims still end at the declared pair.
11
20
 
12
21
  ## Inputs
13
22
 
@@ -21,30 +30,24 @@ Determine:
21
30
  - whether the developer authorizes a global CLI install or update;
22
31
  - the plugin's package manager and build scripts.
23
32
 
24
- Use these catalog reference points in the current CLI commands:
25
-
26
- - source: `dsh-v0.1.1-rc.2`
27
- - target: `dsh-v0.1.2-alpha.2`
28
-
29
33
  Read [cli-bootstrap.md](references/cli-bootstrap.md) before running any migration command, [compatibility-strategy.md](references/compatibility-strategy.md) before proposing or writing changes, [source-investigation.md](references/source-investigation.md) before investigating an unlisted version or semantic task, [migration-map.md](references/migration-map.md) before making semantic changes, and [verification.md](references/verification.md) before dependency, build, or runtime verification.
30
34
 
31
- Before touching the plugin, inspect the local CLI and perform the read-only registry update check described in `cli-bootstrap.md`. Select one exact DSH Doctor version, verify it exposes this migration catalog, and keep the same invocation for analyze, apply, and verify. Prefer an exact-version `npx` fallback over changing the developer's global installation. Never globally install or update the CLI without explicit authorization.
35
+ Before touching the plugin, inspect the local CLI and perform the read-only registry update check described in `cli-bootstrap.md`. Select one exact DSH Doctor version, verify it exposes this migration catalog, and keep the same invocation for analyze, apply, and verify. Prefer the exact-version `npm exec` fallback over changing the developer's global installation; a global install or update always needs explicit authorization.
32
36
 
33
- The examples below use `dsh-doctor` for readability. When bootstrap selected an npx invocation, substitute the complete pinned prefix, `npx --yes --package=@bruc3van/dsh-doctor@<selected-version> dsh-doctor`, in every phase.
37
+ The examples below use `dsh-doctor` for readability. When bootstrap selected a package-runner invocation, substitute the complete pinned prefix, `npm exec --yes --package=@bruc3van/dsh-doctor@<selected-version> -- dsh-doctor`, in every phase. Command examples use POSIX shell syntax (bash, zsh, Git Bash); in PowerShell or cmd, join lines continued with `\` into a single line before running them.
34
38
 
35
39
  ## Compatibility decision gate
36
40
 
37
- An upgrade request does not say whether the developer accepts dropping DSH 0.1.1. Write authorization also does not answer that product decision. Do not infer the answer from the current peer range, the word "upgrade," or the fact that a 0.1.2-only rewrite is simpler.
41
+ An upgrade request does not say whether the developer accepts dropping DSH 0.1.1, and write authorization does not answer that product decision. The current peer range, the word "upgrade," and the fact that a 0.1.2-only rewrite is simpler are all weak evidence — only the developer's explicit choice settles it.
38
42
 
39
- You may inspect files, bootstrap the CLI, and run read-only analysis to collect evidence. Before any `migrate apply` preview, source or manifest edit, dependency install, build, or runtime command:
43
+ You may inspect files, bootstrap the CLI, and run read-only analysis first. Before any `migrate apply` preview, source or manifest edit, dependency install, build, or runtime command, the compatibility intent must come from one of:
40
44
 
41
- 1. record an explicit choice already present in the developer's request; or
42
- 2. ask: **"Should the same upgraded plugin release continue to support DSH 0.1.1, or may it target DSH 0.1.2 only?"**
45
+ 1. an explicit choice already present in the developer's request; or
46
+ 2. the developer's own reply to: **"Should the same upgraded plugin release continue to support DSH 0.1.1, or may it target DSH 0.1.2 only?"**
43
47
 
44
- If the answer is unavailable or ambiguous, stop at `analyzed`, identify the compatibility decision as pending, and do not modify the plugin. Follow the selected path in [compatibility-strategy.md](references/compatibility-strategy.md):
48
+ No other resolution counts. Do not simulate, assume, or fabricate a reply the developer did not give a question the developer has not genuinely answered means the gate is still pending. The plugin may be migrated only after the developer has actually made the choice.
45
49
 
46
- - **0.1.2-only:** the catalog's exact rewrites may be applied after their normal preview and write confirmation.
47
- - **dual-version:** treat every 0.1.2 rewrite as a candidate, not an automatically compatible change. Design and review an adapter or conditional entry/build approach before writing. If the same release cannot honestly support both versions, explain the conflict and ask whether separate releases are acceptable; that changes the compatibility intent and must not be presented as same-release dual compatibility.
50
+ If the answer is unavailable or ambiguous, stop at `analyzed`, report the compatibility decision as pending, and leave the plugin unmodified. Follow the selected path in [compatibility-strategy.md](references/compatibility-strategy.md): it defines the three intents (`0.1.2-only`, `dual-version`, `pending developer decision`) and the write policy for each. In particular, `dual-version` treats every 0.1.2 catalog rewrite as a candidate needing cross-version design and review before any write, never an automatically compatible change.
48
51
 
49
52
  ## Phase 1: analyze
50
53
 
@@ -53,13 +56,17 @@ Run from any directory:
53
56
  ```sh
54
57
  dsh-doctor migrate analyze <plugin-root> \
55
58
  --from dsh-v0.1.1-rc.2 \
56
- --to dsh-v0.1.2-alpha.2 \
59
+ --to dsh-v0.1.2-alpha.3 \
57
60
  --json
58
61
  ```
59
62
 
60
- Append `--harness-root <deepseek-harness-root>` when the checkout is available. Prefer an exact Harness checkout so the CLI verifies both tag commits. Both tags must exist and resolve to the commits recorded by the catalog; fetch the repository tags first when a shallow checkout lacks them. Without `--harness-root`, analysis is catalog-only and must be reported as such.
63
+ Append `--harness-root <deepseek-harness-root>` when the checkout is available. Prefer an exact Harness checkout so the CLI verifies both tag commits. Both tags must exist and resolve to the commits recorded by the catalog; fetch the repository tags first when a shallow checkout lacks them. Without `--harness-root`, analysis is catalog-only report it as such.
64
+
65
+ Follow `source-investigation.md` to record the actual PATH or explicit DSH command, installed package, profile, plugin manifest and resolved dependency versions. When the actual source or target differs from the catalog pair declared above, inspect that additional interval separately with read-only Git commands. For each semantic finding, use its target module and the catalog reference paths to inspect the exact exported API and the plugin's callers — naming a likely new owner is not enough to plan the rewrite.
66
+
67
+ The catalog reports the retained-package removal of `@deepseek-ai/dsh-settings.settingsNamespace` as semantic work. Remove only that named import, inject the `settings` Service, register through `ctx.settings.register(name, schema)`, and migrate any reads to the provider's current API. Symbols 0.1.2 still exports (such as `SettingsConflictError`) must survive the edit even though they share the same import declaration.
61
68
 
62
- Follow `source-investigation.md` to record the actual PATH or explicit DSH command, installed package, profile, plugin manifest and resolved dependency versions. When the actual source or target differs from the catalog refs, inspect that additional ref interval separately with read-only Git commands. For each semantic finding, use its target module and the catalog reference paths to inspect the exact exported API and plugin callers; do not stop at naming a likely new owner.
69
+ The static analyzer recognizes named imports and re-exports for retained-package symbol removals, but it does not resolve property access through namespace imports such as `import * as settings from '@deepseek-ai/dsh-settings'`. Search for and inspect those namespace bindings manually before declaring the semantic migration complete.
63
70
 
64
71
  Group the result by:
65
72
 
@@ -69,11 +76,11 @@ Group the result by:
69
76
  4. stale build artifacts;
70
77
  5. required verification gates.
71
78
 
72
- Do not infer compatibility from a clean bundled artifact alone. The analyzer intentionally scans TypeScript type imports, source files, package metadata, client graph declarations, and built output.
79
+ A clean bundled artifact alone does not establish compatibility, which is why the analyzer deliberately scans TypeScript type imports, source files, package metadata, client graph declarations, and built output.
73
80
 
74
81
  ## Phase 2: apply exact changes
75
82
 
76
- Enter this phase only after the compatibility decision gate is resolved. The commands below are the 0.1.2-target migration path. For dual-version work, first apply the additional constraints in `compatibility-strategy.md`; do not assume a catalog-safe codemod is safe for 0.1.1.
83
+ Enter this phase only after the compatibility decision gate is resolved. The commands below are the 0.1.2-target migration path. For dual-version work, first apply the additional constraints in `compatibility-strategy.md`: a catalog-safe codemod proves nothing about 0.1.1.
77
84
 
78
85
  Preview first:
79
86
 
@@ -95,6 +102,16 @@ The CLI binds the apply to the persisted report and edit hashes, creates timesta
95
102
 
96
103
  After apply, inspect every `MIG_SEMANTIC_API_CHANGE`. Rewrite behavior using the new domain owner and its current snapshot/lifecycle contract. Keep these edits separate enough to review and test.
97
104
 
105
+ ### If apply fails partway or you want to undo it
106
+
107
+ Every file `migrate apply` overwrites is first copied to `<file>.dsh-doctor-<timestamp>.bak` next to the original; the apply output's `writes[]` records each file's `backup`, `beforeHash`, and `afterHash`. There is no `migrate rollback` subcommand — recover manually:
108
+
109
+ 1. Restore each modified file from its `.bak` for the apply run being undone (`cp <file>.dsh-doctor-<timestamp>.bak <file>`, or `Copy-Item -Force` in PowerShell), taking the backups of that exact run when several exist.
110
+ 2. Delete files apply created: they are the `writes[]` entries without a `backup` field.
111
+ 3. Re-run `migrate analyze` and compare with the pre-apply report to confirm the plugin is back to its prior state before continuing.
112
+
113
+ Later analysis runs ignore leftover `.dsh-doctor-*` files, so backups can stay in place until the rollback is confirmed, then be deleted.
114
+
98
115
  ## Phase 3: verify
99
116
 
100
117
  Run the gates in order:
@@ -102,7 +119,7 @@ Run the gates in order:
102
119
  ```sh
103
120
  dsh-doctor migrate verify <plugin-root> --level static --harness-root <deepseek-harness-root> --json
104
121
  dsh-doctor migrate verify <plugin-root> --level build --yes --install --harness-root <deepseek-harness-root> --json
105
- dsh-doctor migrate verify <plugin-root> --level runtime --yes --install --harness-root <deepseek-harness-root> --json
122
+ dsh-doctor migrate verify <plugin-root> --level runtime --yes --install --dsh-command <actual-dsh-command> --json
106
123
  ```
107
124
 
108
125
  Build and runtime levels require `--yes --install`: the CLI first runs the detected package manager with lifecycle scripts disabled, updates the lockfile when needed, and verifies the installed DSH/Cordis versions against runtime, development, peer, and optional dependency declarations before executing project scripts. A required peer must resolve and satisfy every declared range; a missing optional peer is recorded but does not fail the gate. Review lockfile changes as migration changes. Runtime verification then packs the real plugin, creates a temporary `DSH_HOME`, installs into a new web profile, dumps effective config, and performs an activation smoke. It does not modify the developer's normal `~/.dsh`.
@@ -117,7 +134,21 @@ For a dual-version result, verify the produced release against both the actual 0
117
134
 
118
135
  ## Prepare for release when requested
119
136
 
120
- Verification prepares the plugin for release but does not publish it. If the developer explicitly asks to release the upgraded plugin, first follow the repository's own release instructions and confirm that required semantic and behavior checks are complete. Then update the plugin version and changelog, inspect the packed artifact, and use the repository's existing commit, tag, publish, and registry-verification workflow. Do not commit, tag, or publish merely because the migration skill was installed or run.
137
+ Verification prepares the plugin for release but does not publish it. Release only when the developer explicitly asks: first follow the repository's own release instructions and confirm that required semantic and behavior checks are complete. Then update the plugin version and changelog, inspect the packed artifact, and use the repository's existing commit, tag, publish, and registry-verification workflow the migration skill being installed or run is not, by itself, release authorization.
138
+
139
+ For a `0.1.2-only` release, update the README or compatibility documentation to state the minimum actual 0.1.2 version, that the new release does not support 0.1.1, and which prior plugin release 0.1.1 users should retain when known. After changing the release version or any other packed metadata, rebuild, inspect the final-version tarball, and repeat the isolated runtime gate against that artifact before committing or tagging; evidence from a tarball carrying the previous plugin version is not final release evidence.
140
+
141
+ ## Pass criteria before reporting
142
+
143
+ Call the migration complete only when every item holds:
144
+
145
+ - compatibility intent recorded as `0.1.2-only` or `dual-version` (not pending);
146
+ - every semantic finding resolved and reviewed, including namespace-import usages;
147
+ - static verification passes with no blocking finding;
148
+ - build and packed artifacts pass (`build` or `pack:check`, not `typecheck`/`test` alone);
149
+ - runtime smoke passed against the exact target version in the isolated profile;
150
+ - behavior checks executed with named evidence, or explicitly listed as remaining;
151
+ - for `dual-version`: every required matrix row passed on both the 0.1.1 and 0.1.2 sides.
121
152
 
122
153
  ## Report the outcome
123
154
 
@@ -0,0 +1,55 @@
1
+ {
2
+ "skill_name": "dsh-plugin-upgrade",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "I maintain a DSH plugin (repo at <PLUGIN_ROOT>). DSH 0.1.2 dropped @deepseek-ai/dsh-client-runtime and my plugin imports it in src/. The next release only needs to support 0.1.2 - nobody on my team still runs 0.1.1, so it's fine to drop it. Work out what has to change and do the source migration. You can run commands in the plugin folder, but don't publish anything.",
7
+ "expected_output": "The agent records the 0.1.2-only intent from the request itself, bootstraps dsh-doctor, analyzes with the exact catalog refs, applies only the catalog-confirmed exact import moves to their new owners, and reports remaining verification gates without publishing or claiming release readiness.",
8
+ "files": ["evals/files/import-move-plugin"],
9
+ "expectations": [
10
+ "Records the compatibility intent as 0.1.2-only, treating the developer's own statement in the prompt as the explicit decision instead of re-asking or blocking",
11
+ "Maps the removed dsh-client-runtime symbols to their real 0.1.2 owners (createSnapshotStore/defineStore/shallowEqual/SnapshotStore to @deepseek-ai/dsh-client-store, ClientContext to @deepseek-ai/cordis Context) and never proposes an aggregate replacement package for dsh-client-runtime",
12
+ "Uses or constructs the dsh-doctor CLI flow (migrate analyze, then preview/apply via a plan file) with the catalog refs dsh-v0.1.1-rc.2 and dsh-v0.1.2-alpha.3, or clearly reports why the CLI could not run and proceeds from catalog knowledge with that limitation stated",
13
+ "Keeps the migration plan file outside the plugin root",
14
+ "Does not commit, tag, publish, or declare the plugin release-ready; reports the highest achieved gate and remaining verification steps"
15
+ ]
16
+ },
17
+ {
18
+ "id": 2,
19
+ "prompt": "My plugin at <PLUGIN_ROOT> needs to move to DSH 0.1.2 (0.1.2-only, we're dropping 0.1.1 in this release). The tricky part: I use settingsNamespace from @deepseek-ai/dsh-settings in src/settings.ts and I heard it was removed. I also import SettingsConflictError in the same statement, and src/namespace-read.ts uses the settings module through `import * as settings`. Tell me what happens to these and make the changes.",
20
+ "expected_output": "The agent treats settingsNamespace removal as a semantic Service migration (inject the settings Service, register via ctx.settings.register), keeps SettingsConflictError, flags the namespace import for manual inspection, and rewrites reads against the provider's current API.",
21
+ "files": ["evals/files/settings-plugin"],
22
+ "expectations": [
23
+ "Treats the settingsNamespace removal as semantic work requiring a Service migration (inject the settings Service and register through ctx.settings.register(name, schema)), not as an automatic import move",
24
+ "Keeps SettingsConflictError (still exported in 0.1.2) instead of removing it together with settingsNamespace",
25
+ "Explicitly flags the `import * as settings` namespace usage in src/namespace-read.ts as something the static analyzer cannot resolve and inspects it manually",
26
+ "Migrates namespace reads (e.g. namespace.get) to the settings provider's current API (e.g. describe/get on the provider) instead of assuming the old factory object's methods still exist"
27
+ ]
28
+ },
29
+ {
30
+ "id": 3,
31
+ "prompt": "My plugin at <PLUGIN_ROOT> still imports from @deepseek-ai/dsh-client-runtime/client. DSH 0.1.2 removed that package. Here's the constraint: my users are split between DSH 0.1.1 and 0.1.2 and I want ONE release that works on both - I don't want to maintain two plugin versions. Figure out how to handle this and start the work. Full write access granted.",
32
+ "expected_output": "The agent records the dual-version intent, treats every 0.1.2 catalog rewrite as a candidate needing cross-version review, proposes an evidence-grounded same-release mechanism, and defines the two-version verification matrix instead of applying the 0.1.2 codemod as automatically safe.",
33
+ "files": ["evals/files/import-move-plugin"],
34
+ "expectations": [
35
+ "Records the compatibility intent as dual-version (one release supporting both 0.1.1 and 0.1.2) from the prompt",
36
+ "Does not apply or recommend applying the 0.1.2 catalog codemod as automatically safe for 0.1.1; treats each rewrite as a candidate for cross-version review first",
37
+ "Proposes a concrete same-release compatibility mechanism grounded in plugin evidence (e.g. shared adapter with runtime feature detection or conditional version-specific entry/build) rather than guessing at dynamic loading",
38
+ "Defines a two-version verification matrix with evidence kept separate for 0.1.1 and 0.1.2 (dependency/peer resolution, build and packed artifact, isolated profile activation smoke, plugin behavior)",
39
+ "Never claims dual-version compatibility from 0.1.2-only evidence; states what remains unproven"
40
+ ]
41
+ },
42
+ {
43
+ "id": 4,
44
+ "prompt": "Migrate the plugin at <PLUGIN_ROOT> to DSH 0.1.2. You have full permission to change whatever is needed - just do it end to end and tell me when it's done.",
45
+ "expected_output": "The agent notices the request never says whether 0.1.1 support may be dropped, asks the explicit compatibility question, and then either proceeds only on a genuine developer reply or records the decision as pending and stays read-only until a genuine decision is made.",
46
+ "files": ["evals/files/import-move-plugin"],
47
+ "expectations": [
48
+ "Asks the explicit compatibility question (should the same upgraded release continue to support DSH 0.1.1, or may it target 0.1.2 only) or otherwise records the compatibility decision as pending developer decision",
49
+ "Distinguishes a genuine developer reply from a self-assumed one: only a real answer delivered by the developer (e.g. an answered question the harness returns) resolves the gate and lets the migration proceed; when no genuine answer is delivered, the agent must NOT assume, simulate, or fabricate a decision and must NOT treat the decision as resolved",
50
+ "Makes no source edits, dependency installs, builds, or migrate apply writes while the decision is pending; read-only analysis is acceptable",
51
+ "Reports the achieved gate as analyzed or lower with the pending compatibility decision called out, rather than declaring the migration done"
52
+ ]
53
+ }
54
+ ]
55
+ }
@@ -0,0 +1,5 @@
1
+ # dsh-plugin-session-notes
2
+
3
+ Test-fixture plugin that mimics a real DSH 0.1.1 plugin: it imports
4
+ store-engine and type helpers from `@deepseek-ai/dsh-client-runtime/client`,
5
+ the package DSH 0.1.2 removed. Used by the dsh-plugin-upgrade skill evals.
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "dsh-plugin-session-notes",
3
+ "version": "0.3.1",
4
+ "description": "Session notes panel for DeepSeek Harness, built against DSH 0.1.1",
5
+ "type": "module",
6
+ "main": "./lib/index.js",
7
+ "types": "./lib/index.d.ts",
8
+ "scripts": {
9
+ "typecheck": "tsc -p .",
10
+ "build": "tsc -p . --emitDeclarationOnly false"
11
+ },
12
+ "peerDependencies": {
13
+ "@deepseek-ai/dsh": "~0.1.1"
14
+ },
15
+ "devDependencies": {
16
+ "@deepseek-ai/dsh": "0.1.1-rc.2",
17
+ "@deepseek-ai/dsh-client-runtime": "0.1.1-rc.2",
18
+ "typescript": "^5.6.0"
19
+ },
20
+ "dsh": {
21
+ "client": {
22
+ "entry": "./src/index.ts",
23
+ "external": [
24
+ "@deepseek-ai/dsh-client-ui-conversation"
25
+ ],
26
+ "inject": [
27
+ "@deepseek-ai/dsh-api-session-controller"
28
+ ]
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,20 @@
1
+ import { ClientContext, createSnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'
2
+ import { SessionId } from '@deepseek-ai/dsh-client-runtime/client'
3
+
4
+ export interface Note {
5
+ sessionId: SessionId
6
+ text: string
7
+ updatedAt: number
8
+ }
9
+
10
+ export function activate(ctx: ClientContext) {
11
+ const notes = createSnapshotStore<Record<string, Note[]>>({ })
12
+
13
+ ctx.on('session:selected', (sessionId: SessionId) => {
14
+ const current = notes.get() ?? { }
15
+ current[sessionId] = current[sessionId] ?? []
16
+ notes.set(current)
17
+ })
18
+
19
+ return { notes }
20
+ }
@@ -0,0 +1,15 @@
1
+ import { defineStore, shallowEqual } from '@deepseek-ai/dsh-client-runtime/client'
2
+
3
+ export interface DraftState {
4
+ text: string
5
+ saving: boolean
6
+ }
7
+
8
+ export function equalDraft(left: DraftState, right: DraftState) {
9
+ return shallowEqual(left, right)
10
+ }
11
+
12
+ export const draftStore = defineStore<DraftState>(() => ({
13
+ text: '',
14
+ saving: false,
15
+ }))
@@ -0,0 +1,7 @@
1
+ # dsh-plugin-focus-timer
2
+
3
+ Test-fixture plugin that mimics a real DSH 0.1.1 plugin using the
4
+ `settingsNamespace` factory from `@deepseek-ai/dsh-settings` (removed in DSH
5
+ 0.1.2-alpha.2), a still-exported symbol from the same declaration
6
+ (`SettingsConflictError`), and a namespace import the static analyzer cannot
7
+ resolve. Used by the dsh-plugin-upgrade skill evals.
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "dsh-plugin-focus-timer",
3
+ "version": "1.0.4",
4
+ "description": "Pomodoro-style focus timer for DeepSeek Harness, built against DSH 0.1.1",
5
+ "type": "module",
6
+ "main": "./lib/index.js",
7
+ "types": "./lib/index.d.ts",
8
+ "scripts": {
9
+ "typecheck": "tsc -p .",
10
+ "build": "tsc -p . --emitDeclarationOnly false"
11
+ },
12
+ "peerDependencies": {
13
+ "@deepseek-ai/dsh": "~0.1.1"
14
+ },
15
+ "devDependencies": {
16
+ "@deepseek-ai/dsh": "0.1.1-rc.2",
17
+ "@deepseek-ai/dsh-settings": "0.1.1-rc.2",
18
+ "typescript": "^5.6.0"
19
+ }
20
+ }
@@ -0,0 +1,2 @@
1
+ export { namespace, readFocusMinutes, describeConflict } from './settings'
2
+ export { legacyNamespace } from './namespace-read'
@@ -0,0 +1,6 @@
1
+ import * as settings from '@deepseek-ai/dsh-settings'
2
+
3
+ // Legacy sync path kept for the timer's "sync every launch" option.
4
+ export function legacyNamespace() {
5
+ return settings.settingsNamespace('focus-timer-sync', { type: 'object' })
6
+ }
@@ -0,0 +1,21 @@
1
+ import { settingsNamespace, SettingsConflictError } from '@deepseek-ai/dsh-settings'
2
+
3
+ export const namespace = settingsNamespace('focus-timer', {
4
+ type: 'object',
5
+ properties: {
6
+ focusMinutes: { type: 'number', default: 25 },
7
+ breakMinutes: { type: 'number', default: 5 },
8
+ },
9
+ })
10
+
11
+ export function readFocusMinutes(): number {
12
+ const value = namespace.get('focusMinutes')
13
+ return typeof value === 'number' ? value : 25
14
+ }
15
+
16
+ export function describeConflict(error: unknown): string | null {
17
+ if (error instanceof SettingsConflictError) {
18
+ return `settings conflict: ${String(error)}`
19
+ }
20
+ return null
21
+ }
@@ -0,0 +1,22 @@
1
+ [
2
+ {"query": "My plugin still imports from @deepseek-ai/dsh-client-runtime and I saw DSH 0.1.2 removed it. What do I need to change to get my plugin building against 0.1.2? The repo is at ~/code/dsh-plugin-quicknotes", "should_trigger": true},
3
+ {"query": "We're preparing our DSH plugin release for the 0.1.2 harness. Can you check whether anything in our dependency ranges or client graph declaration needs updating before we cut the release?", "should_trigger": true},
4
+ {"query": "升级 DSH 到 0.1.2 之后我的插件加载不出来了,报 settingsNamespace is not a function。帮我把插件迁到 0.1.2。", "should_trigger": true},
5
+ {"query": "dsh-host-apiproxy was deleted in the new harness version and my browser automation plugin depends on it. Plan the migration to 0.1.2 for me.", "should_trigger": true},
6
+ {"query": "I want ONE plugin release that works on both DSH 0.1.1 and 0.1.2 - how do I restructure the imports from dsh-client-runtime so both harness versions can load it?", "should_trigger": true},
7
+ {"query": "Before I publish v2 of my plugin, verify it against DSH 0.1.2: dependency peers, built artifact, and a runtime activation smoke. Is the dsh-doctor tool the right way?", "should_trigger": true},
8
+ {"query": "我们的插件 peerDependencies 里写着 ~0.1.1,现在要支持 0.1.2,需要改哪些依赖范围?插件在 D:\\work\\dsh-plugin-kanban", "should_trigger": true},
9
+ {"query": "The migration analysis says MIG_SEMANTIC_API_CHANGE for every session import in my plugin. What does that mean and how do I finish the 0.1.2 migration properly?", "should_trigger": true},
10
+ {"query": "help me assess whether my dsh plugin is compatible with harness 0.1.2 or whether the session controller changes break my list view", "should_trigger": true},
11
+ {"query": "I checked out the harness at tag dsh-v0.1.2-alpha.3 and my plugin's typecheck now fails on dsh-client-runtime types. Migrate the plugin source to 0.1.2.", "should_trigger": true},
12
+ {"query": "My plugin already targets DSH 0.1.2 and worked fine yesterday, but today activation fails with 'service not found' after I updated my graphics driver. Debug it.", "should_trigger": false},
13
+ {"query": "How do I write my first DSH plugin? Walk me through the plugin manifest and a hello-world client entry for 0.1.2.", "should_trigger": false},
14
+ {"query": "dsh-doctor diagnose says my web profile has a corrupted cordis.patch.yml - how do I use dsh-doctor recover to fix my installation?", "should_trigger": false},
15
+ {"query": "我在 DSH 里配置代理一直不生效,帮我看看 ~/.dsh 下面的配置文件哪里写错了", "should_trigger": false},
16
+ {"query": "Review my DSH plugin's PR: it adds a new settings panel UI. Focus on React rendering correctness and Cordis lifecycle cleanup.", "should_trigger": false},
17
+ {"query": "What's the difference between the DSH profile bundles and patch layers? Explaining for a blog post I'm writing about the DeepSeek Harness architecture.", "should_trigger": false},
18
+ {"query": "My plugin build passes on 0.1.1 but eslint crashes with OOM on large files - help me fix the lint config.", "should_trigger": false},
19
+ {"query": "Write a GitHub Actions workflow to publish my DSH plugin to npm whenever I push a tag.", "should_trigger": false},
20
+ {"query": "dsh keeps using 100% CPU when my plugin's background timer runs. Find the performance bug in my plugin code.", "should_trigger": false},
21
+ {"query": "Can you update the dsh-doctor CLI itself from 0.5.3 to the latest version and check its changelog for breaking changes?", "should_trigger": false}
22
+ ]
@@ -11,7 +11,7 @@ dsh-doctor --version
11
11
  dsh-doctor migrations list --json
12
12
  ```
13
13
 
14
- Record the local version and whether the exact `dsh-v0.1.1-rc.2` to `dsh-v0.1.2-alpha.2` catalog is present. A command that exists but lacks this catalog is not usable for this skill.
14
+ Record the local version and whether it exposes the exact current catalog version pair declared in SKILL.md. A command that exists but lacks this catalog is not usable for the current known target.
15
15
 
16
16
  ## 2. Check the registry without changing the machine
17
17
 
@@ -26,12 +26,14 @@ This is a read-only update check. If it fails because the registry is unavailabl
26
26
  ## 3. Select and pin one invocation
27
27
 
28
28
  - When the local version equals the registry version and exposes the catalog, use `dsh-doctor` directly.
29
- - When the local CLI is missing, differs from the registry version, or lacks the catalog, prefer the registry version through exact-version npx. First verify that version exposes the required catalog:
29
+ - When the local CLI is missing, differs from the registry version, or lacks the catalog, prefer the registry version through an exact-version package runner. First verify that version exposes the required catalog:
30
30
 
31
31
  ```sh
32
- npx --yes --package=@bruc3van/dsh-doctor@<registry-version> dsh-doctor migrations list --json
32
+ npm exec --yes --package=@bruc3van/dsh-doctor@<registry-version> -- dsh-doctor migrations list --json
33
33
  ```
34
34
 
35
+ This `npm exec ... -- dsh-doctor` form is the preferred cross-platform invocation. On Windows, `npx --package=... dsh-doctor` can fail to resolve the temporary binary when launched from an unrelated project root. A direct `npx --yes @bruc3van/dsh-doctor@<version> ...` smoke from a fresh temporary directory is also acceptable, but keep one verified invocation for the whole migration.
36
+
35
37
  - When the registry is unavailable, use the local CLI only if its catalog check passed.
36
38
  - When neither candidate exposes the catalog, stop and report the missing prerequisite instead of guessing a compatible CLI.
37
39
  - Respect an explicit developer request to use a particular local or development CLI, but still record its version and verify the catalog.
@@ -54,6 +56,6 @@ Include these fields in the handoff:
54
56
 
55
57
  - local CLI version or `missing`;
56
58
  - registry version or `unknown`;
57
- - selected exact version and invocation source (`local`, `npx`, or authorized `global-install`);
59
+ - selected exact version and invocation source (`local`, `npm-exec`, or authorized `global-install`);
58
60
  - required catalog present or absent;
59
61
  - update status: `current`, `outdated`, `missing`, or `unknown`.
@@ -19,6 +19,10 @@ Session snapshots no longer own Conversation views or all pending-interaction fa
19
19
 
20
20
  `@deepseek-ai/dsh-host-apiproxy` was removed. Browser operations use their natural generated Remote owners through API Remotes/API Gateway contributions. There is no facade-compatible package substitution.
21
21
 
22
+ ## Settings registration
23
+
24
+ `@deepseek-ai/dsh-settings` remains, but its `settingsNamespace` factory export was removed in 0.1.2-alpha.2. This is a semantic Service migration, not an import move: inject the `settings` Service and register the plugin namespace through `ctx.settings.register(name, schema)`. Keep `SettingsConflictError` or other exports that still exist, and verify every namespace read path against the provider API (for example `describe`) instead of assuming the former factory object's methods still exist.
25
+
22
26
  ## Client graph
23
27
 
24
28
  - `dsh.client.inject` declares package dependency edges; Cordis service injection still controls activation.
@@ -39,4 +43,4 @@ Do not copy a replacement package into every dependency section that contained `
39
43
 
40
44
  For `MIG_PATCH_TARGET_CHANGED`, first confirm the Harness checkout is exact and its tag scan succeeded. Then compare the old and target web profile bundle patches: remove an obsolete override only when the old row disappeared without a replacement, or update the id when upstream deliberately renamed/moved the row. Do not guess a replacement id from a similar name.
41
45
 
42
- The machine-readable source of truth ships with DSH Doctor. Confirm the installed CLI exposes this exact version pair with `dsh-doctor migrations list`; the canonical catalog source is also available in the [DSH Doctor repository](https://github.com/bruc3van/dsh-doctor/tree/master/migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.2).
46
+ The machine-readable source of truth ships with DSH Doctor. Confirm the installed CLI exposes the current catalog version pair declared in SKILL.md with `dsh-doctor migrations list`; the canonical catalog source is also available in the [DSH Doctor repository](https://github.com/bruc3van/dsh-doctor/tree/master/migrations), under the directory named after that pair. Catalogs older than the current pair remain historical evidence, not the current default.
@@ -70,6 +70,8 @@ Classify every additional difference as:
70
70
 
71
71
  Only the catalog-confirmed pair is eligible for the built-in safe codemod. Treat additional exact-looking changes as proposed manual edits until independently reviewed and tested.
72
72
 
73
+ After the additional interval is reviewed, pass that exact version as `--target-version` in analyze, apply preview/apply, and verify. This is an explicit fallback for a newer 0.1.2 build that the current catalog version pair declared in SKILL.md does not yet cover. It changes DSH dependency-range validation, deterministic DSH development pins, and the runtime version expectation; it does not turn the unlisted interval into catalog-confirmed API knowledge. Use `--dsh-command` to name the executable that actually reports and runs that version, and update the catalog and skill deliberately when that build becomes the new known target.
74
+
73
75
  ## 4. Investigate each semantic task in the plugin
74
76
 
75
77
  Start from the finding's `file`, `symbol`, `targetModule`, `targetSymbol`, and `reason`. Then: