dsh-plugin-upgrade 0.1.3 → 2.0.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/AGENTS.md +146 -47
- package/CHANGELOG.md +106 -31
- package/README-es.md +241 -0
- package/README-hi.md +241 -0
- package/README-pt.md +241 -0
- package/README-zh.md +241 -0
- package/README.md +115 -46
- package/SECURITY.md +1 -1
- package/THIRD_PARTY_NOTICES.md +3 -3
- package/cordis.patch.yml +6 -6
- package/docs/EVIDENCE.md +423 -0
- package/index.mjs +21 -17
- package/lib/route.mjs +112 -0
- package/lib/scan-0.1.6.mjs +310 -0
- package/lib/scan.mjs +264 -31
- package/package.json +55 -10
- package/scripts/changelog-section.mjs +1 -0
- package/scripts/check-readme-sync.mjs +4 -1
- package/scripts/scan-0.1.5.mjs +20 -6
- package/scripts/sweep-all.mjs +6 -2
- package/scripts/verify-artifacts.mjs +44 -14
- package/scripts/verify-self-contained.mjs +13 -3
- package/skills/plugin-upgrade/SKILL.md +88 -0
- package/skills/plugin-upgrade/references/v0.1.3-alpha.1-to-v0.1.5-rc.1.md +421 -0
- package/skills/plugin-upgrade/references/v0.1.5-rc.2-to-v0.1.6-alpha.2.md +75 -0
- package/skills/plugin-upgrade/scripts/scan-0.1.5.mjs +29 -0
- package/types.d.ts +39 -7
- package/README.es.md +0 -172
- package/README.hi.md +0 -172
- package/README.pt.md +0 -172
- package/README.zh.md +0 -172
- package/skills/plugin-upgrade-015/SKILL.md +0 -38
- package/skills/plugin-upgrade-015/references/v0.1.3-alpha.1-to-v0.1.5-alpha.1.md +0 -90
- package/skills/plugin-upgrade-015/scripts/scan-0.1.5.mjs +0 -14
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
2
|
// verify-artifacts: pack the package into a temp directory and prove the published
|
|
2
3
|
// tarball carries the plugin entry, the skill bundle, the CLI and the patch layer,
|
|
3
|
-
// and that the entry
|
|
4
|
+
// that dev-only content (tests, fixtures, CI) is excluded, and that the entry
|
|
5
|
+
// imports under plain Node.
|
|
4
6
|
// Usage: node scripts/verify-artifacts.mjs
|
|
5
7
|
import { execFileSync } from 'node:child_process'
|
|
6
8
|
import { mkdtempSync, readdirSync, rmSync, existsSync, readFileSync, symlinkSync, mkdirSync, writeFileSync } from 'node:fs'
|
|
@@ -15,25 +17,31 @@ try {
|
|
|
15
17
|
execFileSync('npm', ['pack', '--pack-destination', staging], { cwd: root, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true, shell: true })
|
|
16
18
|
const tgz = readdirSync(staging).find(f => f.endsWith('.tgz'))
|
|
17
19
|
if (!tgz) throw new Error('npm pack produced no tarball')
|
|
18
|
-
const extract = join(staging, 'x')
|
|
19
20
|
execFileSync('tar', ['-xzf', join(staging, tgz), '-C', staging], { stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true })
|
|
20
21
|
const pkgRoot = join(staging, 'package')
|
|
21
|
-
if (!existsSync(pkgRoot))
|
|
22
|
+
if (!existsSync(pkgRoot)) failures.push('tarball has no package/ root')
|
|
22
23
|
|
|
23
24
|
const required = [
|
|
24
25
|
'index.mjs',
|
|
26
|
+
'types.d.ts',
|
|
25
27
|
'cordis.patch.yml',
|
|
26
28
|
'lib/scan.mjs',
|
|
27
29
|
'scripts/scan-0.1.5.mjs',
|
|
28
|
-
'skills/plugin-upgrade
|
|
29
|
-
'skills/plugin-upgrade
|
|
30
|
-
'skills/plugin-upgrade
|
|
30
|
+
'skills/plugin-upgrade/SKILL.md',
|
|
31
|
+
'skills/plugin-upgrade/scripts/scan-0.1.5.mjs',
|
|
32
|
+
'skills/plugin-upgrade/references/v0.1.3-alpha.1-to-v0.1.5-rc.1.md',
|
|
33
|
+
'docs/EVIDENCE.md',
|
|
31
34
|
'README.md',
|
|
32
35
|
'CHANGELOG.md',
|
|
33
36
|
'LICENSE',
|
|
34
37
|
]
|
|
35
38
|
for (const rel of required) if (!existsSync(join(pkgRoot, rel))) failures.push(`tarball is missing ${rel}`)
|
|
36
39
|
|
|
40
|
+
// Dev-only content must never ship: tests, fixtures and CI configuration.
|
|
41
|
+
for (const rel of ['test', 'fixtures', '.github', 'pnpm-workspace.yaml', 'pnpm-lock.yaml']) {
|
|
42
|
+
if (existsSync(join(pkgRoot, rel))) failures.push(`tarball ships dev-only content: ${rel}`)
|
|
43
|
+
}
|
|
44
|
+
|
|
37
45
|
// The packaged entry must import without the harness present. It imports the
|
|
38
46
|
// declared peer @deepseek-ai/schemastery, so lend the extracted tree this
|
|
39
47
|
// repo's installed peers through a directory link instead of reinstalling.
|
|
@@ -46,12 +54,17 @@ try {
|
|
|
46
54
|
const out = execFileSync(process.execPath, ['-e', `import(${JSON.stringify(entryUrl)}).then(m => console.log('exports:' + ['name','inject','Config','apply'].filter(k => k in m).join(',')))`], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true })
|
|
47
55
|
if (!/exports:name,inject,Config,apply/.test(out)) failures.push(`entry export surface unexpected: ${out.trim()}`)
|
|
48
56
|
} catch (error) {
|
|
49
|
-
|
|
57
|
+
// `execFileSync` attaches the failed child's stderr, which `Error` does not
|
|
58
|
+
// declare: narrow with `in` instead of casting so the message stays identical.
|
|
59
|
+
const stderr = error instanceof Error && 'stderr' in error ? error.stderr : undefined
|
|
60
|
+
const detail = error instanceof Error ? String(stderr || error.message) : String(error)
|
|
61
|
+
failures.push(`packaged entry failed to import: ${detail.slice(0, 200)}`)
|
|
50
62
|
}
|
|
51
63
|
|
|
52
|
-
// The packaged SKILL.md must keep its corridor frontmatter.
|
|
53
|
-
const skill = readFileSync(join(pkgRoot, 'skills/plugin-upgrade
|
|
54
|
-
if (!/^name:\s*plugin-upgrade
|
|
64
|
+
// The packaged SKILL.md must keep its merged-corridor frontmatter.
|
|
65
|
+
const skill = readFileSync(join(pkgRoot, 'skills/plugin-upgrade/SKILL.md'), 'utf8')
|
|
66
|
+
if (!/^name:\s*plugin-upgrade\s*$/m.test(skill)) failures.push('packaged SKILL.md lost its frontmatter name')
|
|
67
|
+
if (!/^ corridor:\s*"0\.1\.3-alpha\.1 -> 0\.1\.5-rc\.1"\s*$/m.test(skill)) failures.push('packaged SKILL.md lost its merged corridor frontmatter')
|
|
55
68
|
|
|
56
69
|
// cordis.patch.yml must stay a top-level YAML ARRAY of loader patch entries:
|
|
57
70
|
// a mapping (`insert:` at column 0) mounts nothing and dsh reports
|
|
@@ -66,20 +79,37 @@ try {
|
|
|
66
79
|
// the skill body resolves `./scripts/...` against the skill directory.
|
|
67
80
|
const probe = join(staging, 'bad-probe')
|
|
68
81
|
mkdirSync(probe, { recursive: true })
|
|
69
|
-
writeFileSync(join(probe, 'index.ts'), "ctx.
|
|
82
|
+
writeFileSync(join(probe, 'index.ts'), "ctx.slots.inject('conversation', () => {})\n")
|
|
70
83
|
try {
|
|
71
|
-
execFileSync(process.execPath, [join(pkgRoot, 'skills/plugin-upgrade
|
|
72
|
-
failures.push('packaged skill-relative scanner exited 0 on a real seam')
|
|
84
|
+
execFileSync(process.execPath, [join(pkgRoot, 'skills/plugin-upgrade/scripts/scan-0.1.5.mjs'), '--repo', probe, '--quiet'], { stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true })
|
|
85
|
+
failures.push('packaged skill-relative scanner exited 0 on a real seam (C1)')
|
|
73
86
|
} catch (error) {
|
|
74
87
|
if (error.status !== 1) failures.push(`packaged skill-relative scanner exited ${error.status}, expected 1`)
|
|
75
88
|
}
|
|
76
89
|
|
|
90
|
+
// A leg-A seam must fail the same scanner from the tarball: the merged
|
|
91
|
+
// catalog, not the rc.1-only one, is what ships. The probe stays import-free
|
|
92
|
+
// so this file keeps no dependency edge the package does not declare.
|
|
93
|
+
const legAProbe = join(staging, 'leg-a-probe')
|
|
94
|
+
mkdirSync(legAProbe, { recursive: true })
|
|
95
|
+
writeFileSync(join(legAProbe, 'index.ts'), [
|
|
96
|
+
'declare const SystemPrompt: any',
|
|
97
|
+
"export const mount = (ctx: any) => ctx.plugin(SystemPrompt, { persona: '' })",
|
|
98
|
+
'',
|
|
99
|
+
].join('\n'))
|
|
100
|
+
try {
|
|
101
|
+
execFileSync(process.execPath, [join(pkgRoot, 'skills/plugin-upgrade/scripts/scan-0.1.5.mjs'), '--repo', legAProbe, '--quiet', '--seams', 'S9'], { stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true })
|
|
102
|
+
failures.push('packaged skill-relative scanner exited 0 on a leg-A seam (S9)')
|
|
103
|
+
} catch (error) {
|
|
104
|
+
if (error.status !== 1) failures.push(`packaged skill-relative scanner exited ${error.status} on the leg-A probe, expected 1`)
|
|
105
|
+
}
|
|
106
|
+
|
|
77
107
|
if (failures.length) {
|
|
78
108
|
console.error('artifacts: FAIL')
|
|
79
109
|
for (const f of failures) console.error(' ' + f)
|
|
80
110
|
process.exitCode = 1
|
|
81
111
|
} else {
|
|
82
|
-
console.log(`artifacts: OK (${required.length} required files present, entry imports, skill frontmatter intact)`)
|
|
112
|
+
console.log(`artifacts: OK (${required.length} required files present, dev-only content excluded, entry imports, skill frontmatter intact, CLI fails a real seam)`)
|
|
83
113
|
}
|
|
84
114
|
} finally {
|
|
85
115
|
rmSync(staging, { recursive: true, force: true })
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
2
|
// verify-self-contained: every bare import in this package must resolve from the
|
|
2
3
|
// declared dependency set, and no import may point outside the package root.
|
|
3
4
|
// Usage: node scripts/verify-self-contained.mjs
|
|
4
|
-
import { readFileSync, readdirSync, existsSync
|
|
5
|
+
import { readFileSync, readdirSync, existsSync } from 'node:fs'
|
|
5
6
|
import { dirname, join, resolve, relative, isAbsolute } from 'node:path'
|
|
6
7
|
import { fileURLToPath } from 'node:url'
|
|
7
8
|
|
|
@@ -16,6 +17,11 @@ const declared = new Set([
|
|
|
16
17
|
const BUILTIN = /^(node:|[a-z]+$)/
|
|
17
18
|
const SKIP = new Set(['node_modules', '.git', 'fixtures'])
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Yield every source file under `dir`, skipping the package's own exclusions.
|
|
22
|
+
* @param {string} dir
|
|
23
|
+
* @returns {Generator<string, void, void>}
|
|
24
|
+
*/
|
|
19
25
|
function* walk(dir) {
|
|
20
26
|
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
21
27
|
if (e.isDirectory()) { if (!SKIP.has(e.name)) yield* walk(join(dir, e.name)) }
|
|
@@ -46,8 +52,12 @@ for (const file of walk(root)) {
|
|
|
46
52
|
}
|
|
47
53
|
}
|
|
48
54
|
|
|
49
|
-
// The packaged skill and its
|
|
50
|
-
for (const required of [
|
|
55
|
+
// The packaged skill bundle and its assets must exist for the plugin to mount.
|
|
56
|
+
for (const required of [
|
|
57
|
+
'skills/plugin-upgrade/SKILL.md',
|
|
58
|
+
'skills/plugin-upgrade/references/v0.1.3-alpha.1-to-v0.1.5-rc.1.md',
|
|
59
|
+
'cordis.patch.yml',
|
|
60
|
+
]) {
|
|
51
61
|
if (!existsSync(join(root, required))) problems.push(`missing packaged asset: ${required}`)
|
|
52
62
|
}
|
|
53
63
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plugin-upgrade
|
|
3
|
+
description: Migrate a DeepSeek Harness plugin repo across the merged 0.1.3-alpha.1 -> 0.1.5-rc.1 corridor. Runs a zero-dependency seam scanner over one 20-seam catalog — leg A (V3 session format, assistant/message.stream, SessionHandleReadResult, ctx.agent, Inbox, SubprocessHandle.pid, SystemPrompt persona, PTC rename, EpochHeader.system, and the tsconfig stale-path false green) plus leg B (the removed bare `conversation` client slot, the sidebar textpreview -> documentpreview package rename, the stale-type-line false green, the new global main-panel model and usePanelInfo standard prop, the new `present` tool key, two new session event types, and the peer-range trap) — then walks the fix-and-verify loop with a real-host smoke, a resume round-trip for log writers and a real browser assertion for a client half.
|
|
4
|
+
whenToUse: Use when a DSH plugin must reach the DeepSeek Harness 0.1.5-rc.1 line (or any host line in >=0.1.2-rc.1 <0.2.0) while keeping the older peer band working. Read leg A first if the peer band is below 0.1.5-alpha.1 or the target is 0.1.5-alpha.1; read leg B if the target is 0.1.5-rc.1 or the plugin has a client/browser half. Not for 0.1.1 -> 0.1.2 migrations (use the community convergence skill), not for a hop after 0.1.5-rc.1 (a new corridor is a new package) and not for the DSH user-facing upgrade/repair path.
|
|
5
|
+
metadata:
|
|
6
|
+
corridor: "0.1.3-alpha.1 -> 0.1.5-rc.1"
|
|
7
|
+
legs: "leg A 0.1.3-alpha.1 -> 0.1.5-alpha.1 (S1-S10, M1) · leg B 0.1.5-alpha.1 -> 0.1.5-rc.1 (C1, C2, C4, C5, H1-H4, P1); leg B's C3 is leg A's M1"
|
|
8
|
+
host-baseline: "0.1.5-rc.1 (tag dsh-v0.1.5-rc.1 = 183f08e9c6dde7e36cd2318eaee70b0da08fb35e); leg A baseline 0.1.5-alpha.1 (tag dsh-v0.1.5-alpha.1 = 5dda764ed3aa172535a7967b06ff95d9cbfe536a, checkout 19d2e38480)"
|
|
9
|
+
evidence: "leg A: 2026-09-09 wave over 40 plugin repos · leg B: tag-range diff + public slot/service catalogs re-read 2026-09-10; family workspace sweep (15 repos with a client half, 8 slot keys). Both recorded in docs/EVIDENCE.md"
|
|
10
|
+
status: "published"
|
|
11
|
+
supersedes: "the version-locked packages dsh-plugin-upgrade (leg A) and dsh-plugin-upgrade-rc1 (leg B)"
|
|
12
|
+
user-invocable: true
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Plugin upgrade · 0.1.3-alpha.1 → 0.1.5-rc.1 (one package, two legs)
|
|
16
|
+
|
|
17
|
+
You are migrating **one plugin repository** across the merged DSH span `0.1.3-alpha.1 → 0.1.5-rc.1`. The goal is not "make typecheck pass" — it is "prove the plugin still works on the target host". Local gates are necessary but not sufficient, and two classes of failure survive a green gate: **stale-type false green** (the local gate compiles an old type line) and **silent non-mount** (the host drops a contribution with no error, no log line and no failed build). Read the leg that matches your peer band; both legs share one scanner and one catalog.
|
|
18
|
+
|
|
19
|
+
## 1. Locate your leg first
|
|
20
|
+
|
|
21
|
+
| Your situation | Read |
|
|
22
|
+
|---|---|
|
|
23
|
+
| Target host is `0.1.5-alpha.1`, or your peer band is below `0.1.5-alpha.1`, or you are bringing a repo up from the `0.1.3-alpha.1` line | **Leg A** — card §1, seams `S1`–`S10` + `M1` |
|
|
24
|
+
| Target host is `0.1.5-rc.1`, or the repo has a client/browser half, or its peer band already sits on `>=0.1.2-rc.1 <0.2.0` | **Leg B** — card §2, seams `C1`, `C2`, `C4`, `C5`, `H1`–`H4`, `P1` |
|
|
25
|
+
| A full `0.1.3-alpha.1 → 0.1.5-rc.1` upgrade | both legs, **A first then B**; card §1 then §2 |
|
|
26
|
+
| Your peer band is below `0.1.5-alpha.1` and you only need `0.1.5-alpha.1` | leg A only — do **not** apply leg B's rc.1 slot-catalog work |
|
|
27
|
+
| Target is a hop after `0.1.5-rc.1` | **Leg C** — `./references/v0.1.5-rc.2-to-v0.1.6-alpha.2.md`, seams `E1`–`E5` |
|
|
28
|
+
|
|
29
|
+
**One package, one corridor index (owner decision, 2026-09-19).** The earlier rule "a hop after 0.1.5-rc.1 is a new package" is superseded: this package carries a corridor index (`lib/route.mjs`) and the CLI routes to the matching corridor automatically. It reads the target repository's declared dsh band (`engines.dsh`, the `@deepseek-ai/dsh*` ranges) and `--span legAB|legC` overrides the guess; an undeclared band falls back to the older corridor. Each corridor keeps its **own** catalog and evidence — the seam arrays are never merged, so every card claim stays traceable to its measurement.
|
|
30
|
+
|
|
31
|
+
**Before you pick a corridor, establish which line is newest.** That lookup is yours, not the scanner's: it is read-only, dependency-free and offline by contract. Read the harness's published line (npm `@deepseek-ai/dsh` dist-tags, or the repository's releases/tags), compare it with the target band, and state the target line in your plan. If the newest line is past every corridor here, say so plainly rather than stretching a card.
|
|
32
|
+
|
|
33
|
+
The card is `./references/v0.1.3-alpha.1-to-v0.1.5-rc.1.md`. It is one document: a preamble with the corridor and how to read it, **§1 = Leg A's full card**, **§2 = Leg B's full card**, **§3 = the merged 20-seam index**. Each leg keeps its own evidence, `path:line` citations, fixtures and rollback path, so one leg can be rolled back without touching the other.
|
|
34
|
+
|
|
35
|
+
**`C3` no longer exists as a seam.** Leg B's card spelled the stale-type-line false green `C3`; it is the same defect as leg A's `M1` and is folded into it, so `M1` now carries both causes (a stale `0.1.5-alpha.*` dev/test pin and an unresolvable `tsconfig` `paths` alias). The card records the old spelling where it applies. Do not pass `C3` to `--seams`.
|
|
36
|
+
|
|
37
|
+
### Routing hints carried over from the two legs' frontmatter
|
|
38
|
+
|
|
39
|
+
Both legs' frontmatter `whenToUse` were routing hints; they cannot both live in one frontmatter, so they are preserved verbatim here — they are still the sharpest statement of each leg's boundary.
|
|
40
|
+
|
|
41
|
+
- **Leg A** (`0.1.3-alpha.1 → 0.1.5-alpha.1`): "Use when a DSH plugin must support @deepseek-ai/dsh 0.1.5-alpha.1 (or any host line in >=0.1.3-alpha.1 <0.1.5-alpha.2) while keeping the 0.1.2-rc.1 peer band working. Not for 0.1.1→0.1.2 migrations (use the community convergence skill) and not for the DSH user-facing upgrade/repair path."
|
|
42
|
+
- **Leg B** (`0.1.5-alpha.1 → 0.1.5-rc.1`): "Use when a DSH plugin must support the 0.1.5-rc.1 host line (or any host line in >=0.1.2-rc.1 <0.2.0) while keeping the older peer band working, especially when the plugin has a client/browser half. Not for 0.1.3-alpha.1 -> 0.1.5-alpha.1 migrations (use the sibling corridor dsh-plugin-upgrade) and not for the DSH user-facing upgrade/repair path."
|
|
43
|
+
- **Merged-world correction:** the "sibling corridor dsh-plugin-upgrade" that hint points at is now **this same package's Leg A** — read card §1. There is no second package to install.
|
|
44
|
+
|
|
45
|
+
## 2. Hard rules
|
|
46
|
+
|
|
47
|
+
1. **Run the scanner first.** `node ./scripts/scan-0.1.5.mjs --repo <repo>` — it prints `file:line` facts. Clear `M1` (stale type line) and `P1` (peer band) before trusting anything else: a fake green and a mis-edited peer range make every later signal meaningless.
|
|
48
|
+
2. **`M1` is a blocker, not a warning.** Two independent causes, either one enough: a `tsconfig` `paths` alias that resolves to a missing directory (TypeScript silently falls back to the published types), or dev/test types pinned at `0.1.5-alpha.*` (the local gate compiles the old slot catalog). Fix the paths and the pin, then re-run — new red is real signal.
|
|
49
|
+
3. **`P1` is a blocker.** Never collapse the peer range to `>=0.1.2-rc.1 <0.2.0`: under npm semver's prerelease-tuple rule it rejects `0.1.5-rc.1` (measured `false` on semver 7.8.5). rc.1 adaptation does **not** change the peer range.
|
|
50
|
+
4. **`C1` is an error, never a warning.** The bare `conversation` client slot was deleted with no alias, and `ctx.slots.inject()` only runs its callback when the declaration exists — the plugin's UI disappears with no error, no log line and no failed build.
|
|
51
|
+
5. **Only adapt what the card says changed.** Do not refactor beyond the card, and do not re-litigate the other leg: on leg B the session-format seams (`assistant/message.stream`, `SessionHandleReadResult`, `EpochHeader.system`, `ctx.agent`, `Inbox`, `SystemPrompt.persona`, the V3 log generation) are unchanged in that hop and belong to leg A; on leg A the repo must still boot on `0.1.2-rc.1`, so keep the old peer band working.
|
|
52
|
+
6. **A client half needs a browser assertion.** `conversation`'s removal is not detectable at build time. For every `C1` / `C2` / `C5` / `H2` hit, confirm in a real page that the plugin's UI actually appears. A clean scan and a green `typecheck` are **not** evidence.
|
|
53
|
+
7. **Behavior change ⇒ test change ⇒ docs change, in one commit.** Five-language READMEs and CHANGELOG move with the code.
|
|
54
|
+
8. **Real-host smoke is the exit criterion.** Temp `DSH_HOME` (mkdtemp) + target CLI + `dsh plugin --profile web add <tarball>` + `--dump-config`. Never touch the user's real `~/.dsh`. Leg A adds a **resume round-trip** for anything that writes session logs (`S3`); leg B adds the **real browser assertion** for a client half.
|
|
55
|
+
|
|
56
|
+
## 3. Loop (both legs)
|
|
57
|
+
|
|
58
|
+
1. **Identify** — record: repo, current version, peer band, target host tag, node/pnpm, and whether the repo has a client half / tracked `lib/`.
|
|
59
|
+
2. **Baseline** — run the repo's own gate chain and *record pre-existing failures*; never let them be counted as migration regressions.
|
|
60
|
+
3. **Scan** — run `./scripts/scan-0.1.5.mjs`; load only the version-card facts that hit. **Locate the leg** (§1 above) before planning: a leg-A-only repo must not be planned against leg B's catalog, and vice versa.
|
|
61
|
+
4. **Plan** — group by the leg's own axes — leg A: session log / host vocabulary / config / distribution; leg B: client slot / package rename / type line / host vocabulary / config — list files, why they change, tests, rollback point. Get confirmation before editing.
|
|
62
|
+
5. **Adapt + verify per module** — fix, run the module's tests, keep commits conventional and independently revertable.
|
|
63
|
+
6. **Prove** — full gate chain + real-host smoke + (leg A) the resume round-trip for log writers + (leg B) a real browser assertion for a client half. Report done / not-hit / pre-existing / unverified / rollback, and say **which leg** each finding came from.
|
|
64
|
+
|
|
65
|
+
## 4. Leg-specific guidance
|
|
66
|
+
|
|
67
|
+
**Leg A (`0.1.3-alpha.1 → 0.1.5-alpha.1`, seams `S1`–`S10` + `M1`)**
|
|
68
|
+
|
|
69
|
+
- The four seams no community PR covered are the high-value ones: `S3` (an `assistant/message` written without the V3 required `stream` field), `S8` (`SessionHandle.read()` now returns `{ eventState, events }`), `S9` (`SystemPrompt` `persona` → `personaPrefix` / `personaSuffix`), and `M1`.
|
|
70
|
+
- `S3`'s failure shape is worse than a red gate: the log write succeeds and `Session.fromRestore` then refuses to resume the session.
|
|
71
|
+
- `S9`: do **not** substitute `includeHarnessIdentity: false` — it deletes the harness identity block, which is not equivalent.
|
|
72
|
+
- `S7` / `S1` / `S2` / `S10` are advisory leads for manual review; they have legitimate matches.
|
|
73
|
+
- The exit criterion is a temp-`DSH_HOME` smoke plus the `S3` resume round-trip where applicable.
|
|
74
|
+
|
|
75
|
+
**Leg B (`0.1.5-alpha.1 → 0.1.5-rc.1`, seams `C1`, `C2`, `C4`, `C5`, `H1`–`H4`, `P1`)**
|
|
76
|
+
|
|
77
|
+
- Rewrite `inject('conversation')` to `main.conversation` (the conversation content seat) or to `main` with your own `key` (a global central panel); card §2 §3.4 has the full recipe. Do **not** "rename to the nearest key" (`conversation.session` and its siblings are different seats).
|
|
78
|
+
- `C2` is a package rename with no shim: `@deepseek-ai/dsh-client-ui-sidebar-textpreview` → `…-sidebar-documentpreview`.
|
|
79
|
+
- `C4` / `C5` / `H1` / `H2` / `H4` are advisory leads; `H3` is card-only and deliberately has no detector.
|
|
80
|
+
- `P1` is about `package.json` peers **only**. `dshWorkshop.compatibility.dshVersions` is a different field: there, replace `0.1.5-alpha.1` with the line you target — do not append.
|
|
81
|
+
- Honest sizing: the family's own client halves use 8 slot keys that all survive rc.1, so for them this leg is latent breakage. Third-party halves that targeted the bare `conversation` key are the ones that break, and they break quietly.
|
|
82
|
+
|
|
83
|
+
## 5. Reference
|
|
84
|
+
|
|
85
|
+
- `./references/v0.1.3-alpha.1-to-v0.1.5-rc.1.md` — the merged version card: preamble, **§1 Leg A** (10 seams with host path + commit + minimal fix + regression, and the 4 that no community PR covers yet), **§2 Leg B** (the from→to mapping, the `conversation` → `main.conversation` rewrite recipe, the boundary list), **§3 the 20-seam merged index**.
|
|
86
|
+
- `./scripts/scan-0.1.5.mjs` — the detector (zero dependency, `file:line`, exit 1 on error-severity hits, `--seams` to filter). It is a thin wrapper over the package's own `lib/scan.mjs`, shipped inside the skill directory so relative paths resolve.
|
|
87
|
+
- The package's own test suite (`node --test`) — synthetic bad/good fixtures **for both legs** (`fixtures/leg-a-*` for leg A, `fixtures/bad-repo` / `fixtures/good-repo` for leg B), a card↔catalog id-parity gate, and a live negative on a family repo.
|
|
88
|
+
- `docs/EVIDENCE.md` — the command→output record behind every card claim (§A is leg A's provenance, §1–§10 the leg-B records).
|