@bruc3van/dsh-doctor 0.1.5 → 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 +80 -84
- package/README.md +130 -82
- package/migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.2/behavior.md +12 -0
- package/migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.2/config-rules.json +36 -0
- package/migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.2/manifest.json +19 -0
- package/migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.2/packages.json +62 -0
- package/migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.2/services.json +28 -0
- package/migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.2/symbols.json +126 -0
- package/package.json +6 -3
- package/skills/dsh-plugin-upgrade/SKILL.md +98 -0
- package/skills/dsh-plugin-upgrade/evals/evals.json +36 -0
- package/skills/dsh-plugin-upgrade/references/migration-map.md +32 -0
- package/skills/dsh-plugin-upgrade/references/verification.md +27 -0
- package/src/baseline.mjs +69 -0
- package/src/cli.mjs +272 -85
- package/src/config-model.mjs +167 -0
- package/src/doctor.mjs +235 -31
- package/src/i18n.mjs +18 -0
- package/src/migrate-verify.mjs +195 -0
- package/src/migrate.mjs +418 -0
- package/src/migration-catalog.mjs +60 -0
- package/src/recovery.mjs +358 -0
- package/src/redact.mjs +46 -0
- package/src/registry.mjs +61 -0
- package/src/safe-write.mjs +50 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"removed": [
|
|
3
|
+
"@deepseek-ai/dsh-acp-demo",
|
|
4
|
+
"@deepseek-ai/dsh-acp-snapshot",
|
|
5
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
6
|
+
"@deepseek-ai/dsh-host-apiproxy",
|
|
7
|
+
"@deepseek-ai/dsh-sdk-jsonrpc-demo"
|
|
8
|
+
],
|
|
9
|
+
"added": [
|
|
10
|
+
"@deepseek-ai/dsh-acp-app",
|
|
11
|
+
"@deepseek-ai/dsh-api-session-controller",
|
|
12
|
+
"@deepseek-ai/dsh-api-settings-controller",
|
|
13
|
+
"@deepseek-ai/dsh-api-workspace-controller",
|
|
14
|
+
"@deepseek-ai/dsh-client-store",
|
|
15
|
+
"@deepseek-ai/dsh-client-ui-approval",
|
|
16
|
+
"@deepseek-ai/dsh-client-ui-chat",
|
|
17
|
+
"@deepseek-ai/dsh-client-ui-schedule",
|
|
18
|
+
"@deepseek-ai/dsh-client-ui-session",
|
|
19
|
+
"@deepseek-ai/dsh-deepseek-llm-api-extensions",
|
|
20
|
+
"@deepseek-ai/dsh-deque",
|
|
21
|
+
"@deepseek-ai/dsh-experimental-agent-team-profile",
|
|
22
|
+
"@deepseek-ai/dsh-experimental-agent-team-web-profile",
|
|
23
|
+
"@deepseek-ai/dsh-experimental-client-ui-agent-team",
|
|
24
|
+
"@deepseek-ai/dsh-experimental-inspector",
|
|
25
|
+
"@deepseek-ai/dsh-experimental-webworker-packer",
|
|
26
|
+
"@deepseek-ai/dsh-experimental-webworker-runtime",
|
|
27
|
+
"@deepseek-ai/dsh-plugin-package-inventory-deepseek",
|
|
28
|
+
"@deepseek-ai/dsh-sdk-app",
|
|
29
|
+
"@deepseek-ai/dsh-sdk-minimal",
|
|
30
|
+
"@deepseek-ai/dsh-session-log-deepseek",
|
|
31
|
+
"@deepseek-ai/dsh-session-snapshot",
|
|
32
|
+
"@deepseek-ai/dsh-util-crypto",
|
|
33
|
+
"@deepseek-ai/dsh-util-time",
|
|
34
|
+
"@deepseek-ai/dsh-util-values",
|
|
35
|
+
"@deepseek-ai/dsh-util-workspace-path",
|
|
36
|
+
"@deepseek-ai/dsh-webhook",
|
|
37
|
+
"@deepseek-ai/dsh-webhook-github",
|
|
38
|
+
"@deepseek-ai/dsh-win32-process"
|
|
39
|
+
],
|
|
40
|
+
"targetVersions": {
|
|
41
|
+
"@deepseek-ai/cordis": "4.0.2",
|
|
42
|
+
"@deepseek-ai/dsh-client-store": "0.1.2-alpha.2",
|
|
43
|
+
"@deepseek-ai/dsh-session": "0.1.2-alpha.2"
|
|
44
|
+
},
|
|
45
|
+
"semanticReplacements": {
|
|
46
|
+
"@deepseek-ai/dsh-client-runtime": [
|
|
47
|
+
"@deepseek-ai/dsh-api-session-controller",
|
|
48
|
+
"@deepseek-ai/dsh-api-workspace-controller",
|
|
49
|
+
"@deepseek-ai/dsh-client-store",
|
|
50
|
+
"@deepseek-ai/dsh-client-ui-session",
|
|
51
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
52
|
+
"@deepseek-ai/dsh-client-ui-chat",
|
|
53
|
+
"@deepseek-ai/dsh-client-ui-trajectory",
|
|
54
|
+
"@deepseek-ai/dsh-client-ui-approval",
|
|
55
|
+
"@deepseek-ai/dsh-client-ui-user-questions"
|
|
56
|
+
],
|
|
57
|
+
"@deepseek-ai/dsh-host-apiproxy": [
|
|
58
|
+
"@deepseek-ai/dsh-api-gateway",
|
|
59
|
+
"@deepseek-ai/dsh-api-remotes"
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"services": {
|
|
3
|
+
"sessions": {
|
|
4
|
+
"owner": "@deepseek-ai/dsh-api-session-controller/client",
|
|
5
|
+
"confidence": "semantic",
|
|
6
|
+
"note": "The service name survives, but Session snapshots no longer contain Conversation views or pending interactions."
|
|
7
|
+
},
|
|
8
|
+
"workspaces": {
|
|
9
|
+
"owner": "@deepseek-ai/dsh-api-workspace-controller/client",
|
|
10
|
+
"confidence": "semantic",
|
|
11
|
+
"note": "The service name survives, while cross-domain navigation belongs to ui-workspace."
|
|
12
|
+
},
|
|
13
|
+
"conversation": {
|
|
14
|
+
"owner": "@deepseek-ai/dsh-client-ui-conversation/client",
|
|
15
|
+
"confidence": "semantic",
|
|
16
|
+
"note": "Conversation assembly and input are independent of Session lifecycle snapshots."
|
|
17
|
+
},
|
|
18
|
+
"slots": {
|
|
19
|
+
"owner": "@deepseek-ai/dsh-client-ui-renderer/client",
|
|
20
|
+
"confidence": "semantic",
|
|
21
|
+
"note": "Slot declarations stay in ui-slots; runtime registration and binding belong to ui-renderer."
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"removedHostFacade": {
|
|
25
|
+
"package": "@deepseek-ai/dsh-host-apiproxy",
|
|
26
|
+
"replacementPolicy": "Use the natural business Remote owner through generated api-remotes contributions; there is no replacement facade."
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
{
|
|
2
|
+
"modules": {
|
|
3
|
+
"@deepseek-ai/dsh-client-runtime/client": {
|
|
4
|
+
"ClientContext": {
|
|
5
|
+
"toModule": "@deepseek-ai/cordis",
|
|
6
|
+
"toSymbol": "Context",
|
|
7
|
+
"confidence": "exact",
|
|
8
|
+
"reason": "ClientContext was a type alias of Cordis Context."
|
|
9
|
+
},
|
|
10
|
+
"createSnapshotStore": {
|
|
11
|
+
"toModule": "@deepseek-ai/dsh-client-store",
|
|
12
|
+
"toSymbol": "createSnapshotStore",
|
|
13
|
+
"confidence": "exact",
|
|
14
|
+
"reason": "The React-free store engine moved to client-store."
|
|
15
|
+
},
|
|
16
|
+
"defineStore": {
|
|
17
|
+
"toModule": "@deepseek-ai/dsh-client-store",
|
|
18
|
+
"toSymbol": "defineStore",
|
|
19
|
+
"confidence": "exact",
|
|
20
|
+
"reason": "The declarative store factory moved to client-store."
|
|
21
|
+
},
|
|
22
|
+
"ObservableSnapshot": {
|
|
23
|
+
"toModule": "@deepseek-ai/dsh-client-store",
|
|
24
|
+
"toSymbol": "ObservableSnapshot",
|
|
25
|
+
"confidence": "exact",
|
|
26
|
+
"reason": "The observable store contract moved to client-store."
|
|
27
|
+
},
|
|
28
|
+
"SnapshotStore": {
|
|
29
|
+
"toModule": "@deepseek-ai/dsh-client-store",
|
|
30
|
+
"toSymbol": "SnapshotStore",
|
|
31
|
+
"confidence": "exact",
|
|
32
|
+
"reason": "The writable store contract moved to client-store."
|
|
33
|
+
},
|
|
34
|
+
"shallowEqual": {
|
|
35
|
+
"toModule": "@deepseek-ai/dsh-client-store",
|
|
36
|
+
"toSymbol": "shallowEqual",
|
|
37
|
+
"confidence": "exact",
|
|
38
|
+
"reason": "The store equality helper moved to client-store."
|
|
39
|
+
},
|
|
40
|
+
"SessionId": {
|
|
41
|
+
"toModule": "@deepseek-ai/dsh-session/types",
|
|
42
|
+
"toSymbol": "SessionId",
|
|
43
|
+
"confidence": "exact",
|
|
44
|
+
"reason": "Session identity is owned by the Session domain."
|
|
45
|
+
},
|
|
46
|
+
"ISessions": {
|
|
47
|
+
"toModule": "@deepseek-ai/dsh-api-session-controller/client",
|
|
48
|
+
"toSymbol": "ISessions",
|
|
49
|
+
"confidence": "semantic",
|
|
50
|
+
"reason": "Session ownership moved to the Session Controller and its snapshots changed."
|
|
51
|
+
},
|
|
52
|
+
"Session": {
|
|
53
|
+
"toModule": "@deepseek-ai/dsh-api-session-controller/client",
|
|
54
|
+
"toSymbol": "Session",
|
|
55
|
+
"confidence": "semantic",
|
|
56
|
+
"reason": "The Client Session object and lifecycle moved to the Session Controller."
|
|
57
|
+
},
|
|
58
|
+
"SessionBinding": {
|
|
59
|
+
"toModule": "@deepseek-ai/dsh-api-session-controller/client",
|
|
60
|
+
"toSymbol": "SessionBinding",
|
|
61
|
+
"confidence": "semantic",
|
|
62
|
+
"reason": "Session bindings are now Controller-owned lifetimes."
|
|
63
|
+
},
|
|
64
|
+
"SessionListState": {
|
|
65
|
+
"toModule": "@deepseek-ai/dsh-api-session-controller/client",
|
|
66
|
+
"toSymbol": "SessionListState",
|
|
67
|
+
"confidence": "semantic",
|
|
68
|
+
"reason": "The list state moved and no longer owns Conversation or pending-interaction facts."
|
|
69
|
+
},
|
|
70
|
+
"SessionSummary": {
|
|
71
|
+
"toModule": "@deepseek-ai/dsh-api-session-controller/client",
|
|
72
|
+
"toSymbol": "SessionSummary",
|
|
73
|
+
"confidence": "semantic",
|
|
74
|
+
"reason": "The Session summary is now a Controller-owned control snapshot."
|
|
75
|
+
},
|
|
76
|
+
"UseProjection": {
|
|
77
|
+
"toModule": "@deepseek-ai/dsh-api-session-controller/client",
|
|
78
|
+
"toSymbol": "UseProjection",
|
|
79
|
+
"confidence": "semantic",
|
|
80
|
+
"reason": "Projection sources are now exposed by Session Controller bindings and adapted by ui-session."
|
|
81
|
+
},
|
|
82
|
+
"IWorkspaces": {
|
|
83
|
+
"toModule": "@deepseek-ai/dsh-api-workspace-controller/client",
|
|
84
|
+
"toSymbol": "IWorkspaces",
|
|
85
|
+
"confidence": "semantic",
|
|
86
|
+
"reason": "Workspace ownership moved to the Workspace Controller and navigation policy moved to ui-workspace."
|
|
87
|
+
},
|
|
88
|
+
"WorkspaceId": {
|
|
89
|
+
"toModule": "@deepseek-ai/dsh-api-workspace-controller/client",
|
|
90
|
+
"toSymbol": "WorkspaceId",
|
|
91
|
+
"confidence": "semantic",
|
|
92
|
+
"reason": "Workspace identity is re-exported by the Workspace Controller."
|
|
93
|
+
},
|
|
94
|
+
"WorkspaceView": {
|
|
95
|
+
"toModule": "@deepseek-ai/dsh-api-workspace-controller/client",
|
|
96
|
+
"toSymbol": "WorkspaceView",
|
|
97
|
+
"confidence": "semantic",
|
|
98
|
+
"reason": "Workspace snapshots are Controller-owned and their shape changed."
|
|
99
|
+
},
|
|
100
|
+
"ConversationNode": {
|
|
101
|
+
"toModule": "@deepseek-ai/dsh-client-ui-conversation/client",
|
|
102
|
+
"toSymbol": "ConversationNode",
|
|
103
|
+
"confidence": "semantic",
|
|
104
|
+
"reason": "Conversation assembly moved out of Session snapshots into ui-conversation."
|
|
105
|
+
},
|
|
106
|
+
"ConversationSnapshot": {
|
|
107
|
+
"toModule": "@deepseek-ai/dsh-client-ui-conversation/client",
|
|
108
|
+
"toSymbol": "ConversationSnapshot",
|
|
109
|
+
"confidence": "semantic",
|
|
110
|
+
"reason": "Conversation is now an independent target-neutral source."
|
|
111
|
+
},
|
|
112
|
+
"PendingInteraction": {
|
|
113
|
+
"toModule": "@deepseek-ai/dsh-client-ui-session/client",
|
|
114
|
+
"toSymbol": "SessionPendingInteraction",
|
|
115
|
+
"confidence": "semantic",
|
|
116
|
+
"reason": "Approval and Question now publish domain-owned pending interactions through ui-session."
|
|
117
|
+
},
|
|
118
|
+
"PendingWait": {
|
|
119
|
+
"toModule": "@deepseek-ai/dsh-client-ui-session/client",
|
|
120
|
+
"toSymbol": "SessionPendingInteraction",
|
|
121
|
+
"confidence": "semantic",
|
|
122
|
+
"reason": "The Runtime PendingWait aggregate was removed; pending domains own their payloads."
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bruc3van/dsh-doctor",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Diagnose DSH
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Diagnose DSH upgrades, migrate plugins with safe codemods, and verify recovery decisions",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
@@ -17,19 +17,22 @@
|
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"src",
|
|
20
|
+
"migrations",
|
|
21
|
+
"skills",
|
|
20
22
|
"README.md",
|
|
21
23
|
"README.en.md",
|
|
22
24
|
"LICENSE"
|
|
23
25
|
],
|
|
24
26
|
"scripts": {
|
|
25
27
|
"test": "node --test",
|
|
26
|
-
"check": "node --check src/cli.mjs && node --check src/doctor.mjs && node --check src/i18n.mjs && node --check src/repair.mjs && npm test",
|
|
28
|
+
"check": "node --check src/cli.mjs && node --check src/doctor.mjs && node --check src/i18n.mjs && node --check src/repair.mjs && node --check src/migration-catalog.mjs && node --check src/migrate.mjs && node --check src/migrate-verify.mjs && npm test",
|
|
27
29
|
"prepublishOnly": "npm run check"
|
|
28
30
|
},
|
|
29
31
|
"dependencies": {
|
|
30
32
|
"cross-spawn": "^7.0.6",
|
|
31
33
|
"js-yaml": "^4.2.0",
|
|
32
34
|
"semver": "^7.7.2",
|
|
35
|
+
"typescript": "^6.0.3",
|
|
33
36
|
"yaml": "^2.8.1"
|
|
34
37
|
},
|
|
35
38
|
"engines": {
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dsh-plugin-upgrade
|
|
3
|
+
description: Upgrade a DeepSeek Harness plugin from dsh-v0.1.1-rc.2 to dsh-v0.1.2-alpha.2 with dsh-doctor. Use when a plugin developer asks to migrate, assess compatibility, replace removed dsh-client-runtime or dsh-host-apiproxy APIs, update DSH peer dependencies, rebuild artifacts, or verify a plugin against DSH 0.1.2. Produces an evidence-backed staged report and applies only catalog-confirmed exact rewrites automatically.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# DSH plugin upgrade
|
|
7
|
+
|
|
8
|
+
Upgrade one plugin at a time. Treat source migration, artifact verification, runtime activation, and business behavior as separate gates.
|
|
9
|
+
This skill is intentionally bound to the `dsh-v0.1.1-rc.2` to `dsh-v0.1.2-alpha.2` catalog; do not reuse its mappings for another version pair.
|
|
10
|
+
|
|
11
|
+
## Inputs
|
|
12
|
+
|
|
13
|
+
Determine:
|
|
14
|
+
|
|
15
|
+
- the plugin repository root;
|
|
16
|
+
- the DSH Harness checkout when available;
|
|
17
|
+
- whether the developer authorizes writes and project command execution;
|
|
18
|
+
- the plugin's package manager and build scripts.
|
|
19
|
+
|
|
20
|
+
Use these fixed refs unless the user explicitly requests a supported alternative:
|
|
21
|
+
|
|
22
|
+
- source: `dsh-v0.1.1-rc.2`
|
|
23
|
+
- target: `dsh-v0.1.2-alpha.2`
|
|
24
|
+
|
|
25
|
+
Read [migration-map.md](references/migration-map.md) before making semantic changes. Read [verification.md](references/verification.md) before build or runtime verification.
|
|
26
|
+
|
|
27
|
+
Before touching the plugin, run `dsh-doctor migrations list` and confirm this exact version pair is present. If `dsh-doctor` is not on `PATH`, use `npx --package=@bruc3van/dsh-doctor dsh-doctor migrations list` and confirm the same catalog before continuing; never silently use an older CLI that lacks the migration.
|
|
28
|
+
|
|
29
|
+
## Phase 1: analyze
|
|
30
|
+
|
|
31
|
+
Run from any directory:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
dsh-doctor migrate analyze <plugin-root> \
|
|
35
|
+
--from dsh-v0.1.1-rc.2 \
|
|
36
|
+
--to dsh-v0.1.2-alpha.2 \
|
|
37
|
+
--json
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
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.
|
|
41
|
+
|
|
42
|
+
Group the result by:
|
|
43
|
+
|
|
44
|
+
1. errors blocking compatibility;
|
|
45
|
+
2. exact import moves eligible for safe codemods;
|
|
46
|
+
3. semantic tasks requiring developer judgment;
|
|
47
|
+
4. stale build artifacts;
|
|
48
|
+
5. required verification gates.
|
|
49
|
+
|
|
50
|
+
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.
|
|
51
|
+
|
|
52
|
+
## Phase 2: apply exact changes
|
|
53
|
+
|
|
54
|
+
Preview first:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
dsh-doctor migrate apply <plugin-root> --safe --harness-root <deepseek-harness-root> --json
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Review affected files and hashes. Apply only with explicit authorization:
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
dsh-doctor migrate apply <plugin-root> --safe --yes --harness-root <deepseek-harness-root> --json
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The CLI creates timestamped backups and refuses writes when a file changed after preview. It may split a mixed import: exact symbols move to their new owners while semantic symbols remain unresolved. It may pin non-removed DSH development dependencies and add dependencies required by exact symbol moves. It does not change the ranges of existing published peers automatically. Never mechanically replace the removed Client Runtime with one aggregate package; no such replacement exists.
|
|
67
|
+
|
|
68
|
+
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.
|
|
69
|
+
|
|
70
|
+
## Phase 3: verify
|
|
71
|
+
|
|
72
|
+
Run the gates in order:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
dsh-doctor migrate verify <plugin-root> --level static --harness-root <deepseek-harness-root> --json
|
|
76
|
+
dsh-doctor migrate verify <plugin-root> --level build --yes --harness-root <deepseek-harness-root> --json
|
|
77
|
+
dsh-doctor migrate verify <plugin-root> --level runtime --yes --harness-root <deepseek-harness-root> --json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Build and runtime levels execute plugin scripts and therefore require `--yes`. Runtime verification 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`.
|
|
81
|
+
|
|
82
|
+
Resolve every semantic task and rebuild stale artifacts before expecting static verification to pass. An `apply` exit code of 1 after successful writes means migration blockers remain in the follow-up analysis; inspect `mode`, `writes`, and `report` instead of treating it as a write failure.
|
|
83
|
+
|
|
84
|
+
On failure, preserve and report the temporary directory. On success, the CLI removes it unless `--keep-temp` is used.
|
|
85
|
+
|
|
86
|
+
Runtime activation is not business-behavior proof. Finish with targeted manual or automated checks for visible UI, service lifecycle, event subscriptions, cleanup, configuration, and plugin-specific workflows.
|
|
87
|
+
|
|
88
|
+
## Report the outcome
|
|
89
|
+
|
|
90
|
+
State the highest achieved gate exactly:
|
|
91
|
+
|
|
92
|
+
- `analyzed`
|
|
93
|
+
- `source-migrated`
|
|
94
|
+
- `artifact-verified`
|
|
95
|
+
- `runtime-verified`
|
|
96
|
+
- behavior verified separately with named evidence
|
|
97
|
+
|
|
98
|
+
Do not call the plugin compatible while errors, semantic tasks, stale artifacts, or required behavior checks remain. Include backups and retained temporary directories in the handoff.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "dsh-plugin-upgrade",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "检查这个只有后端 bundle 的 DSH 插件能否从 0.1.1-rc.2 升级到 0.1.2-alpha.2。它的 peerDependencies 仍是 ^0.1.1,不要改文件。",
|
|
7
|
+
"expected_output": "Runs read-only migrate analysis, identifies target range mismatch, and does not claim runtime compatibility.",
|
|
8
|
+
"expectations": [
|
|
9
|
+
"Uses migrate analyze before proposing edits",
|
|
10
|
+
"Reports the exact verification status as analyzed",
|
|
11
|
+
"Does not write files or execute build scripts"
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": 2,
|
|
16
|
+
"prompt": "把这个前端插件升级到 DSH 0.1.2。源码里有 import type { ClientContext, ISessions } from '@deepseek-ai/dsh-client-runtime/client',可以安全改的帮我改,其他的列出来。",
|
|
17
|
+
"expected_output": "Safely moves ClientContext to Cordis while leaving ISessions as an explicit semantic migration task, with backup evidence.",
|
|
18
|
+
"expectations": [
|
|
19
|
+
"Detects type-only imports from source rather than relying on the bundle",
|
|
20
|
+
"Uses migrate apply --safe and requires explicit confirmation for writes",
|
|
21
|
+
"Does not mechanically rewrite the semantic ISessions contract"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": 3,
|
|
26
|
+
"prompt": "完整升级这个混合前后端插件并验证,Harness 在 /workspace/deepseek-harness。构建失败也要把现场路径告诉我。",
|
|
27
|
+
"expected_output": "Performs analyze, safe apply, semantic work, build and isolated runtime gates; reports the highest proven status and retained failure workspace.",
|
|
28
|
+
"expectations": [
|
|
29
|
+
"Uses the exact Harness refs and verifies the catalog commits",
|
|
30
|
+
"Runs static, build, then runtime verification in order",
|
|
31
|
+
"Uses a temporary DSH_HOME and reports retained failure state",
|
|
32
|
+
"Keeps business behavior verification separate from activation smoke"
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Migration map
|
|
2
|
+
|
|
3
|
+
## Ownership split
|
|
4
|
+
|
|
5
|
+
`@deepseek-ai/dsh-client-runtime` was removed without an aggregate replacement.
|
|
6
|
+
|
|
7
|
+
| Old concern | 0.1.2 owner | Migration policy |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| store engine and equality helpers | `@deepseek-ai/dsh-client-store` | exact for catalog-listed symbols |
|
|
10
|
+
| Cordis client context type | `@deepseek-ai/cordis` `Context` | exact; preserve local aliases |
|
|
11
|
+
| session control/list/commands | `@deepseek-ai/dsh-api-session-controller/client` | semantic |
|
|
12
|
+
| workspace state/commands | `@deepseek-ai/dsh-api-workspace-controller/client` | semantic |
|
|
13
|
+
| conversation assembly | `@deepseek-ai/dsh-client-ui-conversation/client` | semantic |
|
|
14
|
+
| approval/questions pending state | domain UI packages aggregated by `ui-session` | semantic |
|
|
15
|
+
|
|
16
|
+
Session snapshots no longer own Conversation views or all pending-interaction facts. Workspace navigation policy is distinct from workspace state. Check callers and lifecycle rather than changing import paths alone.
|
|
17
|
+
|
|
18
|
+
## Host facade removal
|
|
19
|
+
|
|
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
|
+
|
|
22
|
+
## Client graph
|
|
23
|
+
|
|
24
|
+
- `dsh.client.inject` declares package dependency edges; Cordis service injection still controls activation.
|
|
25
|
+
- React, Cordis, client-store, ui-slots, and ui-primitives baseline modules are implicit and should not be repeated in `dsh.client.external`.
|
|
26
|
+
- A declared web client requires a published `exports["./client"]` artifact.
|
|
27
|
+
|
|
28
|
+
## Patch targets
|
|
29
|
+
|
|
30
|
+
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.
|
|
31
|
+
|
|
32
|
+
The machine-readable source of truth is the [versioned catalog](../../../migrations/dsh-v0.1.1-rc.2__dsh-v0.1.2-alpha.2/manifest.json).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Verification gates
|
|
2
|
+
|
|
3
|
+
## Static
|
|
4
|
+
|
|
5
|
+
Static analysis covers source/type imports, dependency ranges, client graph declarations, and generated artifacts. A pass means no known blocking finding; it does not execute project code.
|
|
6
|
+
|
|
7
|
+
## Build
|
|
8
|
+
|
|
9
|
+
The CLI selects the package manager from lockfiles and runs declared scripts in this order: `typecheck`, `build`, `test`, `pack:check`, stopping at the first failure. Artifact verification requires a successful `build` or `pack:check`; `typecheck`/`test` alone do not pass this gate.
|
|
10
|
+
|
|
11
|
+
## Runtime
|
|
12
|
+
|
|
13
|
+
Runtime verification:
|
|
14
|
+
|
|
15
|
+
1. packs the plugin from its repository;
|
|
16
|
+
2. creates a fresh temporary `DSH_HOME`;
|
|
17
|
+
3. initializes a web profile by adding the tarball through the target DSH CLI;
|
|
18
|
+
4. composes effective config with `--dump-config`;
|
|
19
|
+
5. performs a CLI activation smoke with `--help`.
|
|
20
|
+
|
|
21
|
+
The gate also checks the DSH CLI's exact target version, the created profile manifest, the installed package manifest, bundle activation, and the plugin's presence in the effective config. Successful exit codes alone are insufficient.
|
|
22
|
+
|
|
23
|
+
Use a built target Harness CLI through `--harness-root`, or pass `--dsh-command` explicitly. The temporary home is deleted only after a successful run unless `--keep-temp` is set.
|
|
24
|
+
|
|
25
|
+
## Behavior
|
|
26
|
+
|
|
27
|
+
Choose focused checks from the plugin contract: render the real UI, invoke each command, exercise settings, verify service availability, repeat activation/deactivation, check listener cleanup, and cover failure recovery. Record exact commands, screenshots, logs, or tests. This gate is deliberately not inferred by dsh-doctor.
|
package/src/baseline.mjs
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { join, resolve } from 'node:path'
|
|
3
|
+
import { atomicWrite, snapshotFile } from './safe-write.mjs'
|
|
4
|
+
import { redactSecrets } from './redact.mjs'
|
|
5
|
+
|
|
6
|
+
export function baselinePath(report, explicit) {
|
|
7
|
+
return explicit === undefined
|
|
8
|
+
? join(report.context.profileDir, '.dsh-doctor', 'baseline.json')
|
|
9
|
+
: resolve(explicit)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function baselineFromReport(report) {
|
|
13
|
+
const safeReport = redactSecrets(report)
|
|
14
|
+
return {
|
|
15
|
+
schemaVersion: 2,
|
|
16
|
+
createdAt: new Date().toISOString(),
|
|
17
|
+
profile: report.context.profile,
|
|
18
|
+
home: report.context.home,
|
|
19
|
+
harness: safeReport.context.harness,
|
|
20
|
+
packages: safeReport.context.packages.map(item => ({ name: item.name, version: item.version, compatibility: item.compatibility })),
|
|
21
|
+
configuration: {
|
|
22
|
+
layers: safeReport.context.configuration?.layers ?? [],
|
|
23
|
+
currentDefaultTree: safeReport.context.configuration?.currentDefaultTree ?? [],
|
|
24
|
+
currentEffectiveTree: safeReport.context.configuration?.currentEffectiveTree ?? [],
|
|
25
|
+
},
|
|
26
|
+
findingCodes: report.findings.map(item => item.code),
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function createBaseline(report, explicit) {
|
|
31
|
+
const file = baselinePath(report, explicit)
|
|
32
|
+
const snapshot = snapshotFile(file)
|
|
33
|
+
const baseline = baselineFromReport(report)
|
|
34
|
+
const written = atomicWrite(snapshot, `${JSON.stringify(baseline, null, 2)}\n`, { backup: snapshot.exists })
|
|
35
|
+
return { ...written, baseline }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function byName(values) {
|
|
39
|
+
return new Map(values.map(item => [item.name, item]))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function compareBaseline(report, explicit) {
|
|
43
|
+
const file = baselinePath(report, explicit)
|
|
44
|
+
if (!existsSync(file)) throw new Error(`baseline does not exist: ${file}`)
|
|
45
|
+
const baseline = JSON.parse(readFileSync(file, 'utf8'))
|
|
46
|
+
if (![1, 2].includes(baseline?.schemaVersion) || !Array.isArray(baseline.packages)) throw new Error(`unsupported baseline document: ${file}`)
|
|
47
|
+
const before = byName(baseline.packages)
|
|
48
|
+
const after = byName(report.context.packages)
|
|
49
|
+
const added = [...after.keys()].filter(name => !before.has(name)).sort()
|
|
50
|
+
const removed = [...before.keys()].filter(name => !after.has(name)).sort()
|
|
51
|
+
const changed = [...after.keys()].filter(name => before.has(name)).flatMap(name => {
|
|
52
|
+
const left = before.get(name)
|
|
53
|
+
const right = after.get(name)
|
|
54
|
+
const fields = ['version', 'compatibility'].filter(field => left[field] !== right[field])
|
|
55
|
+
return fields.length === 0 ? [] : [{ name, fields, before: left, after: right }]
|
|
56
|
+
})
|
|
57
|
+
const oldFindings = new Set(baseline.findingCodes ?? [])
|
|
58
|
+
const currentFindings = new Set(report.findings.map(item => item.code))
|
|
59
|
+
return {
|
|
60
|
+
file,
|
|
61
|
+
baselineCreatedAt: baseline.createdAt,
|
|
62
|
+
harness: { before: baseline.harness, after: report.context.harness },
|
|
63
|
+
packages: { added, removed, changed },
|
|
64
|
+
findings: {
|
|
65
|
+
introduced: [...currentFindings].filter(code => !oldFindings.has(code)).sort(),
|
|
66
|
+
resolved: [...oldFindings].filter(code => !currentFindings.has(code)).sort(),
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
}
|