This skill does only one thing
Split "adapting a plugin to the new DSH" into four steps, one script per step, each runnable on its own; two optional steps complete "verify as soon as it's built, optimize along the way during upgrades":
| Step | Script | What it answers |
|---|---|---|
| ★ One-command full chain (recommended entry point) | scripts/run.mjs |
Environment→version pinning→guide→scan→health check→smoke test→typecheck in a single command, produces a unified report and writes a local run log |
| 0 Build skeleton (optional) | scripts/scaffold.mjs |
Build a plugin from scratch: one command produces a smoke-testable skeleton in five forms, validated on generation |
| 1 Probe environment | scripts/env-doctor.mjs |
Which version of DSH is installed locally? Are there stale packages in the overlay layer? Are there dangling symlinks in the shared farm? Were both patch layers read? Which plugins are installed? Are the plugins enabled and ready? |
| 2 Pin version | scripts/guide-sync.mjs |
What is the latest official version? Should the local install follow it? Which one? |
| 3 Fetch differences | scripts/guide-sync.mjs --clone |
Between the local version and the target version, which breaking changes does the official source list? |
| 4 Check hits | scripts/code-scan.mjs |
Which of those does the local plugin code hit? What fix does the official source give? |
| ★ Seam query | scripts/seams.mjs |
Dual-source conclusion for a given package/API symbol across the official guide and the local host ("removed" is only concluded when both sources agree) |
| 5 5-second verify (optional) | scripts/quick-smoke.mjs |
After the changes, can the plugin still load, apply, and register tools? Will access to host services not declared in inject be blocked? |
| 6 Health check (optional) | scripts/plugin-audit.mjs |
How does the plugin score on performance, resilience, context budget, and lifecycle? Which optimizations should be done for the new version? How should the peer be changed? |
| ★ Log diagnosis | scripts/log-doctor.mjs |
~/.dsh/logs/ What is the root cause of the host startup failure (port in use/undeclared inject/dead client entry link)? |
| ★ Downstream sync | scripts/sync-skill.mjs |
Has the skill surface of the standalone repo drifted from the downstream skill directory? |
Does not depend on any manually maintained knowledge cards. The only two authoritative sources are: version information from the npm registry, and the deepseek-harness repository's docs/upgrade-guide/. So the moment upstream releases a new version, this skill automatically keeps up—there is no "card lag" problem. It also does not mirror the full official documentation or build a manually maintained issue library—such knowledge snapshots are bound to lag (upstream pre-release cadence is one every 1.7-2.8 days), and the key determination (whether a package still exists) is more solid when tested directly against the host's node_modules.
How to use
Step one: get a clear picture of the local environment
node scripts/env-doctor.mjs <插件目录>
Outputs JSON; focus on six sections:
globalDsh: the globally installed DSH version and locationoverlayFindings: packages in the profiles overlay layer that are out of sync with the main install, with severity and reasonsharedFarmFindings: dangling symlinks in the shared node_modules farm (~/.dsh/profiles/node_modules), withbrokenCount/hostBackedBroken(those pointing into the host install tree are the "package removed after host upgrade" kind, marked critical)runningProcesses: The running DSH host process (must be restarted after changing Host-side code)target.peerWindows: The peer version window declared by the plugin under inspection itselfactivation: Plugin enablement readiness — whether build artifacts exist, whether each profile has mounted it, and whether the declared inject services have provider signatures in that profile (Cordis silent-pending risk); when the target is not in plugin form (package.json has nodshnamespace, no@deepseek-ai/*dependency) recordN/Aas not checked — running plugin rules against a pure tool repo falsely reports "no main entry" as ERROR (2026-10-25 self-review record). Entry resolution follows Node semantics (exports['.']takes precedence overmain), packages with nomainbut with the entry written inexportswill no longer be falsely reported as ERROR (2026-10-26 measured@local/dsh-env-sweeper)activation.client: Client side (dsh.client) three-layer determination — declaration shape (composer boot throws immediately), ./client artifacts (reports client bundles not found), inject target roster dead links (entry stuck loading, the whole web boot fails). The web profile and the desktop APP share the same platform:web frontend, both are treated the same. Roster evidence is graded strong/weak: host built-in / bundles column names / overlay mount behavior as strong evidence pass directly; packages present in dependencies but with no row evidence are reported at the info weak tier for confirmation (whether the host auto-mounts cannot be determined by static analysis). 2026-10-25 record: the host side smoke test was all green but the desktop APP would not start — the real culprit was the client-side dead injection
overlayFindings When non-empty, handle the overlay first before discussing adaptation. This is the class of incident in issue #263: after a host upgrade, old packages remain in the overlay, and old packages resolving with priority cause runtime load conflicts, and merely swapping files without restarting the host reproduces it. If an upstream-removed package is explicitly re-mounted by the overlay (- insert: line), downgrade to info — that is a deliberately retained compatibility shim, not an accidental leftover; tearing it out directly would break old plugins that still require it (clean up only after confirming all consumers have been migrated away).
overlayFindings Only look at each profile's own overlay directory; the shared farm is another layer. ~/.dsh/profiles/node_modules is a symlink farm pointing at the host installation (@deepseek-ai/* plus transitive dependencies such as react-dom/express); after a host upgrade removes packages, dangling symlinks remain, and any plugin that requires it ends with ERR_MODULE_NOT_FOUND (2026-10-26 measured 209 entries; in the host startup log, client-runtime/orca-agent-hooks two lines of load failure, while overlayFindings reports 0 locations). This layer env-heal is not handled and must be cleaned up manually.
Both patch layers must be checked. Besides each profile's own cordis.patch.yml, there is also the global ~/.dsh/cordis.patch.yml——dsh --dump-config which shows it is appended as the last layer of every profile. Reading only the former misses it entirely: on this machine the global layer is written by Orca with a orca-agent-hooks line referencing @deepseek-ai/dsh-hooks-claude-code which is not installed, reporting 1 entry did not activateon every startup, while the tool reports 0 locations (2026-10-26 measured).installedPlugins[].patchEntries already merges the two layers, andregistered/disabled determination applies to both layers.
node scripts/env-heal.mjs # dry-run,只报告
node scripts/env-heal.mjs --apply # 真的移动(移到 ~/.dsh/.trash/<日期>/,不删除)
Step 2: Determine the target version
node scripts/guide-sync.mjs <本机版本>
Upstream watch (--check):node scripts/guide-sync.mjs --check with no arguments can be plugged directly into cron/launchd/agent polling — it automatically detects the local host version, exit codes are semantic (1 = a new upstream version exists, 0 = no action needed, 2 = determination failed), and when a new version exists it also prefetches that version's official guide into the cache (next run.mjs has zero wait). The tool does not include a timer; wiring is up to the user.
It reads npm's dist-tags(latest / next / alpha), then determines where the local machine sits in the official channel:
| Determination | Meaning | Next |
|---|---|---|
upgrade-available |
A channel version is newer than the local machine | Take target(the highest version across all official channels) and continue |
up-to-date-on-channel |
The local machine is already the latest version of some channel | No adaptation needed, done |
ahead-of-upstream |
The local machine is newer than all official channels | No adaptation needed, done |
unknown-local |
No local version detected | Default to following latest, but requires manual confirmation |
Do not blindly take latest。 The local machine may well be running on next production, one version newer than latest ; at that point, reporting "recommend upgrading to latest" is a regression.
When there is target , take the official upgrade guide for that version:
node scripts/guide-sync.mjs <本机版本> --clone
Prefer reusing the existing harness clone on the local machine (auto-discovered at ~/Documents/*/deepseek-harness, or specified with DSH_HARNESS_CLONE ); only if absent, sparse clone to ~/.cache/dsh-plugin-fast-adapt/。
Version anchor (2026-10-25 field review): when the local machine is already the latest version of an official channel, resolution.target is null, so the old implementation could not obtain the guide corpus, andrun.mjs 's scan stage silently skipped (the scan corridor (peerFloor, hostVersion] clearly had content yet reported "no guide root or no window"). Now the version anchor falls back to the local version (target || localVersion || dist-tags.latest), and the corridor is scanned as usual.
The window start only recognizes the host package (2026-10-25 dsh-image-gen record): the start takes the peer lower bound declared by the plugin on the host package (@deepseek-ai/dsh and the dsh-* suite subpackages); the same-scope @deepseek-ai/cordis(4.x)、@deepseek-ai/schemastery(3.x) is a library on an independent version line and does not count as a host package—mixing it in pushes the start up to a high position like 3.18.4, and after the window inverts, the scan silently skips. Now an inversion (start > end) falls back to the host version and leaves a trace in window.fallback ,window.source records the start source (flag/peer/host), and the stderr summary raises a synchronized warning, no longer silently.
Step 3: Check which changes the plugin has hit
node scripts/code-scan.mjs <插件目录> <upgrade-guide 目录> <本机版本> <目标版本>
<upgrade-guide 目录> is the official guide root directory, e.g. ~/layerfs-lab/deepseek-harness/docs/upgrade-guide, or the ~/.cache/dsh-plugin-fast-adapt/harness-dsh-v<version>/docs/upgrade-guide。
output has three sections:
findingsByGuide: hits grouped by official change entry, each withguide、title、migrationmigration: the original fix text given officially (relevant steps extracted from the Migration section of that guide)findingCount/guidesConsidered: the number of hits and the number of guides referenced
Each hit carries a source anchor guideFile/guideLine(relative path within the guide + heading line number), so conclusions can be traced back to the official original text location without searching for headings again in the guide directory.
Hits are divided into three categories and carry severity:package(imported a removed or renamed package, critical, will definitely crash on load),member(called a removed method or field, high, crashes at runtime),code(a changed error code or event name appears in a string, medium, most likely to collide with the same name). Findings are sorted first by severity then by file line number; each carries evidence(the original text of the hit line). Package name anchors have a semantic gate: they become anchors only when in the same sentence as a removal/rename verb; contextual references do not count.
Scan roots (2026-10-25 field review):pickScanRoots takes the union of source roots—src(client/web are often embedded inside src) and the sibling client/web/ui are scanned together;lib/dist is a build artifact, synonymous with src, and is only fallen back to when there is no source root at all; otherwise the same hit would be reported twice as two files.
Seam queries (seams)
node scripts/seams.mjs <包名或符号> [--guide <guide-root>] [--host <版本>]
Answer "does this seam still exist in my target host" with dual-source synthesis: guide source (anchor table covering all corridors, which version claimed it was removed/renamed, the exact line in the original text, official fix) × host source (packages checked live in node_modules, symbols matched against host suite source text—weak evidence, labeled as such). Bare dsh-* names are auto-normalized to @deepseek-ai/ scope before lookup. Honest three states: only when both sources say absent do we conclude "removed"; if the guide says absent but the host has it, report the disagreement rather than deciding for the user; when neither source has a record, explicitly say "the guide not mentioning it does not mean the API doesn't exist." Zero network by default (guide root uses cache).
One-click orchestration and run log (run.mjs)
node scripts/run.mjs <插件目录> [--target <版本>] [--from <版本>] [--no-clone] [--no-smoke] [--no-typecheck] [--no-log] [--real-smoke]
Run the above flow in order: environment, version pinning, guide, scan, health check, smoke, typecheck (executes the plugin's own typecheck script, same trust level as smoke), and output a unified JSON report; the scan window automatically takes the corridor from "the peer lower bound declared by the plugin on the host package → host version" (--from/--target can override; inversion auto-falls back and leaves a trace).--real-smoke is off by default; when explicitly enabled, it bridges the original repo's plugin-upgrade verify-runtime.mjs: clean profile install→startup→four categories of attribution (plugin code/dependency resolution/profile config/host runtime), fail counts toward exit code 2; when the script is not on this machine (probes sibling repo dsh-plugin-upgrade-skill, or PFA_VERIFY_RUNTIME points to the path) it honestly skips and gives remediation; on Windows it skips per the POSIX-only declaration. Exit codes: 0 clean, 2 when there are critical/high hits, typecheck is red, or a real cold start fails.
Each run writes a local log (~/.cache/dsh-plugin-fast-adapt/runs/, one self-contained JSON per run + one summary line in index.jsonl), recording the tool version and commit—a lesson from a 2026-10-25 real-world test: running a stale copy produced 4 false positives that had already been fixed, and without logs there was no way to observe "which version of the tool was run." The index summary carries phases three states (scan/smoke/typecheck/realSmoke each ok|skipped|fail|error) and the toolDirty asterisk (the tool repo had uncommitted changes at the time, so version number and commit may not pair up)—a scan that didn't run is no longer conflated on the same line with a "perfect health score" (dsh-image-gen real record: scan skipped, auditScore still recorded as 100). Run logs are retained for 90 days, with expired files and corresponding index lines lazily cleaned up on write.
node scripts/run-log.mjs list [--limit 20] # 最近运行一览(含工具版本@commit)
node scripts/run-log.mjs show <id|--latest> # 单次全文
node scripts/run-log.mjs sanitize <id|--latest> [--out 文件] # 脱敏后才可外发
node scripts/run-log.mjs doctor [--logs <目录>] # 运行日志 × 宿主启动日志交叉核对
doctor cross-check(first stop for plugin errors / installed but not taking effect): the run log gives code-side status (phases/hits/health check), while the host startup log's failedPlugins/waitingForServices gives load-side status—one command puts evidence from both sides side by side. Three-state determination: host log clean → states consistent; host reports it but the most recent scan is clean → suspicion lies in loading/mounting/environment (switch to env-doctor to look at both halves of activation); problems on both sides → first clear code according to run's hits.
Logs never leave the local machine; before giving external feedback you must first sanitize(home prefix→~, username→, machine name→, email→; directory structure preserved).--offline skips guide-sync (for self-check with zero network).
Step five (optional): instant verification after fixing
node scripts/quick-smoke.mjs <插件目录>
Purely in-memory simulation of the Cordis context, dynamically loading the plugin entry, verifying in milliseconds to seconds: the module can load, theapply contract can execute, tools can register. After changing code, run it first; if it breaks, fix it immediately—no need to wait for a real host cold start.
Boundaries: smoke passing ≠ host compatibility. The mock only covers common surfaces such as logger/tools/effect/on; the output's mockFallbacks Lists the properties the plugin touched but the Mock did not provide (including facets in built-in mixins that the Mock does not fully faithfully implement) — the longer this list is, the lower the confidence in this result.
Contract validation (measured retrospective on 2026-10-25): previously the Mock returned a fallback proxy for any unknown property, so when the plugin accessedan undeclared inject host service (real Cordis directly throws cannot get property "X" without inject, and loading crashes immediately), the smoke test silently passed — in historical startup logs, failed to register /llm-verifier rpc fallback: cannot get property "webServer" without inject is exactly this category. Now it is judged by the real contract:
- a service declaring
injectthat the Mock does not provide → fallback and disclose (a Mock gap, not the plugin's fault); - an undeclared non-built-in property → throws a
inject_contractphase error (same shape as the real host).
The criteria are taken from cordis/lib/index.js 's ReflectService construction and LoggerService assembly, not fabricated. Real cold-start verification still uses the original repository plugin-upgrade's verify-runtime.mjs。
Step 6 (optional): also perform a performance and architecture health check during the upgrade
node scripts/plugin-audit.mjs <插件目录> # 纯四维审计
node scripts/plugin-audit.mjs <插件目录> --guide <guide-root> <本机版本> <目标版本> # 叠加官方指南交叉
Points are deducted from 100 across four dimensions: performance (synchronous I/O, unbounded reads), resilience (hard dependencies on removed packages), context budget (tool Schema size), lifecycle (listener and timer cleanup). Detection uses a scanner state machine; same-named words in comments and strings do not count as hits. The report carries targetForm(plugin/tool): whether the target is a DSH plugin is determined by ecosystem signals (package.json's dsh namespace,@deepseek-ai/* dependency); tool repositories skip the lifecycle dimension — for ordinary Node scripts, suggesting ctx.effect is noise from a shape mismatch (2026-10-25 self-review retrospective). Three INFO-level hints do not deduct points: import type references a removed package (a compile-time risk, not runtime), the peer window under strict semver does not include the target host (bundle installation in this ecosystem does not enforce peer, it is a declarative convention; it is recommended to self-verify via satisfiesRange before outputting), the host path convention in the tool description has zero hits in the host code (possibly an old-version convention that has died out, such as .dsh-filess, requiring manual confirmation).
When --guide is present, cross-reference with code-scan from the same source: package hits are first verified by actual host testing (package still in the target host → downgrade to info as disproven; genuinely absent → HIGH deduction with the official fix attached); before the hits are cleared, performance optimization is not recommended first. The seams introduced by the new version (weak dependency ctx.get() replacing a hard import, peer range syntax) are exactly the basis for "making architectural adjustments according to the new dependency".
peer patch suggestion: for peer ranges that do not include the target host,peerPatch gives a replacement syntax of "a caret line with the same triple as the target", and each one is first self-verified with satisfiesRange to cover the target (syntaxes that fail verification are not given). Generated only for @deepseek-ai/dsh and its dsh-* suite subpackages — libraries in the same scope (@deepseek-ai/schemastery、@deepseek-ai/cordis) have their own version lines, and applying the host version to their peer would give wildly wrong suggestions.Generate only, do not auto-modify the package: modifying the user's package.json is an irreversible write;--peer-patch prints it and applies only after manual confirmation.
One-click host log diagnosis (log-doctor)
node scripts/log-doctor.mjs [--logs <目录>] [--limit 5] [--pattern '^startup-']
Host startup failures (StartupError, port in use, undeclared inject, dead client entry links) previously required manually grepping ~/.dsh/logs/startup-*.logone by one, then extracting failedPlugins and waitingForServices. This script cements that troubleshooting path: parse each startup log's header metadata and multi-line error blocks, message arrays (tolerating the host's [length]: N pseudo-array markers), extract preset signals, and aggregate them into diagnostics grouped by root cause with executable actions.
Output:runs(each log's meta/failedPlugins/waitingForServices/signals),signalSummary(signals sorted by occurrence count + actions),verdict(clean/warnings/host-failure). Non-startup logs (maintain/env-sweeper/web-restart) only have signals scanned across the full text.Boundary: logs are JS literals written by the host (not JSON), so only line-level heuristic parsing is done; fields that cannot be parsed are left as null without guessing; signals are text hits, and actions are the first step of "how to confirm/how to fix", not a decision made for the user.
Downstream skill sync (sync-skill)
node scripts/sync-skill.mjs --dest <下游技能目录> --check # 只查漂移(退出码 1 = 有漂移)
node scripts/sync-skill.mjs --dest <下游技能目录> # 同步
After the standalone repo split,dsh-plugin-upgrade-skill/skills/plugin-fast-adapt kept a static copy; when both are real files, downstream silently lags (measured 2026-10-25: main repo already added client half three-layer detection, downstream still lacks lib/client-graph.mjs、SKILL.md and is also stale), and when the lagging copy is mistakenly run, new problems cannot be detected. The sync surface is fixed to the files skill readers will actually use:SKILL.md、README.md、README.en.md、references/**、scripts/**(package.json not included in the skill surface).--check reports missing files and content drift,--dry-run only prints without writing to disk. After sync completes, print the suggested mirror repo commit command (only add sync paths to prevent smuggling, commit subject carries the true-source short commit; realpath both paths first to prevent macOS /var symlink prefix misalignment), without auto-committing.
Creating a plugin: from scratch
The first step uses this skill's scaffold to produce a smoke-testable skeleton in one command:
node scripts/scaffold.mjs <namespace>/<name> --form tool|hook|service|config|llm-adapter [--out <目录>] [--harness <版本>] [--no-smoke]
It only does deterministic things and does not touch discretion:
- Five-piece generation: package.json (build-free pure ESM invariants:
type: module, main and exports both point tolib/index.js, files includes the mount layer), a minimal runnable entry per form (tool registers with raw JSON Schema, hook goes through waterfall and explicitlynext(), service/config/llm-adapter use the host base-class form),cordis.patch.ymlminimal mount entry (without it, installing has no effect; this is the layer env-doctor's activation checks),dsh-plugin.naming.json、README+.gitignore - Naming projection: loader id/service/tool/command/skill/event/route are all derived from the coordinate per the upstream naming-conventions collision-resistant rules; generated artifacts have passed upstream validate-names'
--strictcheck (0 errors, 0 warnings) - Verify on the spot: tool/hook forms smoke directly with zero dependencies (generation is verification of registration); service/config/llm-adapter depend on the host
@deepseek-ai/*base class, so honestly skip smoke and note to run manually after installing packages; the llm-adapter base class import source is not pinned down in upstream docs, so the skeleton has a TODO placeholder and after generation it must be checked against the target host checkout for names
Refuse if the target directory is non-empty (don't touch user files); reject invalid coordinates before writing to disk. The skeleton only guarantees structural and naming compliance; capability implementation still follows the true-source docs:
| Requirement | Go to where |
|---|---|
| Complete contract for five forms (execute obligations, waterfall semantics, Schema rules, protocol obligation list) | Original repo plugin-write skill five form references |
| Common naming conventions and registry conflict checks | plugin-write's naming-conventions and registry-check reference (the two scripts validate-names / query-registry) |
| Cordis tutorial, API, cookbook | official repository deepseek-harness/docs/ 's cordis-tutorial, cordis-api, cookbook |
| After building it | pass the health-check gate with one command:node scripts/write-gate.mjs <插件目录> — smoke test + enablement readiness + four-dimension audit + official guide check produce a "birth certificate" report (or run them separately: quick-smoke for a quick verification → env-doctor for enablement readiness → plugin-audit for the audit → code-scan to check against the target version) |
Verdict layering of the health-check gate (write-gate)
There are only three hard gates; any fail means exit code 1: entry artifact exists, smoke test passes, zero critical hits against the official guide. Everything else is only passed through, never decided — the audit's four-dimension scores and MEDIUM list, scan's high/medium hits (with evidence), mockFallbacks, the fact that a profile is not yet mounted, all go into the discretion section marked "manual discretion", because plugin-audit's honest reservation signals (e.g. under the host contract, synchronous is the only legal way to write it) and env-doctor's pending-semantics WARN — deciding "qualified" for the user would be disguising a discretion question as a verdict question. Guide auto-discovery: explicit --guide takes priority; otherwise look up the guide-sync cache (zero network) using the local host version; if neither exists, honestly skip and give a remediation. The new-plugin check surface is the entire historical corridor (localVersion=null window allows all guides): new code should not import any package that has been removed, regardless of which version removed it. Right after scaffolding, add --skip-smoke to avoid a duplicate smoke test.
Batch scenario: host upgrade inspection of an entire batch of installed plugins
This skill deeply inspects one plugin at a time. When the host has just been upgraded and you want to run the whole batch of installed plugins through a full pass, first use the original repository's plugin-fleet-sweep for batch screening, then take the problematic plugins it finds and return them one by one to this skill's six-step pipeline for a deep check — batch handles breadth, this skill handles depth.
Old plugins: when the official guide does not cover them
The official upgrade-guide only goes back as far as dsh-v0.1.7-rc.2. When the plugin is older, the target version is older, or the span crosses a long historical corridor,code-scan will report guidesConsidered = 0— at that point switch to the old-plugin migration SOP: use the original repository's plugin-upgrade skill manual card corridor (19 edges since dsh-v0.1.0-rc.8 + version-skip cards) as the source of diffs, and follow the seven-phase checklist: determine mode → read-only preparation → ghost host check → assemble corridor → seven contact types → plan confirmation → six-layer verification. A quick reference for the division of labor between the two tool sets is also in the SOP: for segments with a guide, use this skill's code-scan; for segments without a guide, use the original version's plan-migration.mjs and cards; for runtime verification, use the original version's verify-runtime.mjs。
How to read the results
Zero hits does not mean there is no problem; it means "no hits within the scope covered by the official guide". The guide only records breaking changes that the official team considers worth notifying, and does not cover every possibility.
For a hit, look more carefully at whether it is a false positive. This skill's anchor matching has several layers of noise reduction (see references/heuristics.md), but symbols with the same name can still collide, for example the plugin's path.resolve() and the guide's runtime.resolve(). How to judge: look at the code context at the hit location and confirm whether that symbol really comes from the host API.
member will not appear among the hits, if the symbol is the guide's "migration target". The plugin uses the new API, which means it has already been adapted; the reported warning is just noise.
Security boundaries
- Primarily read-only。
env-doctor、code-scan、plugin-auditDoes not write files at all. quick-smokeWill execute plugin code(dynamically import the entry module). Use it only for your own plugins or code you have reviewed; do not run it on directories of unknown origin. Execution is confined to the Node process, but plugin code can in theory do anything Node can do.- Self-healing defaults to dry-run。
env-healWithout adding--applyit only reports; even when added, it is a "move" rather than a delete, into~/.dsh/.trash/<日期>/。 - Does not modify DSH itself. It only reads environment information and does not touch the configuration and profile declarations under
~/.dsh. - Does not automatically modify plugin code. It only reports matches and official fixes; whether and how to change them is up to a human;
plugin-audit --peer-patchalso only prints suggestions and does not writepackage.json。 sync-skillexplicitly writes to the downstream directory, copying only the fixed skill surface (SKILL.md/README*/references/scripts),--check/--dry-runfor confirmation first; what is changed is the downstream copy, and the main repository is not touched.- Network is used only when
--cloneuse for. Both the npm registry and git clone have timeouts; failures report an explicit error rather than silently skipping; dist-tags have a 1-hour cache, and on network failure it degrades to the old cache and marks it as stale. - Logs are written only locally. The run log of run.mjs is written to
~/.cache/dsh-plugin-fast-adapt/runs/, containing local paths and usernames; before sending externally you mustrun-log.mjs sanitize。
Self-check
npm test
130 assertions, covering: scanner does not produce false positives (same-named words in comments and strings do not count as hits), does not miss true positives, real semver range determination (prerelease tuple rules, this round with 30 anchor regression cases cross-checked against the host's built-in semver), scan window computation (host package peer exact matching, cordis/schemastery version lines are not mixed in, inverted guard fallback leaves a trace), target shape determination (dsh namespace/ecosystem dependency evidence, non-plugin N/A, tool repos skip the Cordis lifecycle), import type distinction, host measured verification grading, description drift detection, guide source anchor points (guideFile/guideLine persisted round-trip), seam query dual-source conclusions (consistent already removed/host still reporting a divergence/no record stated truthfully/host undetectable and not fabricated), run log × host log cross-check, --real-smoke bridge tier (fail→exit code 2, tail attribution passthrough, failure points the way), one-click orchestration and run log (write/index/desensitization round-trip, phases three states, dirty marker, 90-day retention cleanup), upstream watch exit codes (upgrade-available→1, others→0), suggested sync commit command (git repos get a command that only adds sync paths, non-git silently skipped), version heuristics, replacement pair identification, end-to-end hit, SOP reference completeness, dist-tags cache three states, smoke verification (including interception of undeclared inject contracts and disclosure of Mock gaps), four-dimensional audit (including peer patch suggestions), enablement diagnostics (host half Silent Pending + client half three-layer determination: declaration/artifact/injection roster dead links), three environment-layer blind spots (critical/info grading of dangling symlinks in the shared node_modules farm, the global patch layer takes effect for all profiles and disabled ones also participate in determination, entry resolution prioritizes exports over main to prevent packages without main from being falsely reported as ERROR), authoring scaffold (five-form generation and smoke closed loop, naming projection syntax, mount layer identifiable, rejection of illegal input and non-empty directories), authoring health check gate (hard gate interception, soft metrics do not overstep to judge red, skip semantics, scaffold connection), log diagnostics (startup header/failed plugins/waiting services/signals/cross-file aggregation), downstream sync drift check +real-machine zero-drift interception, self-test size gate (red when over 2200 lines), cross-platform simulation (Windows root detection and cache isolation), documentation assertion count anti-drift, scan performance regression gate. Zero network, zero external dependencies, runs on any machine (the Windows branch has been simulation-verified, real-machine verification pending).
Pre-commit gate:git config core.hooksPath .githooks(one-time) enable the pre-commit hook, and this self-check runs automatically at commit time — forgetting to run sync-skill after changing the source of truth gets caught at this moment, without waiting for someone to run npm test.
Script list
| Script | Responsibility |
|---|---|
scripts/run.mjs |
One-click orchestration of the full workflow + write local run log |
scripts/run-log.mjs |
Run log viewing (list/show) and desensitized export (sanitize) |
scripts/env-doctor.mjs |
Probe the local DSH environment (version, overlay layers, dangling symlinks in the shared farm, two-layer patch, plugins, processes, host-half + client-half enablement readiness) |
scripts/env-heal.mjs |
Overlay stale package self-healing (dry-run by default) |
scripts/guide-sync.mjs |
Determine target version + fetch the official upgrade guide (dist-tags with 1-hour cache, fall back to old cache on failure) |
scripts/code-scan.mjs |
Scan plugin code, match official change anchors (findings carry guide file + line number source) |
scripts/seams.mjs |
Seam query: dual-source conclusion for a package name/API symbol in the guide anchor table and the local host |
scripts/quick-smoke.mjs |
Instant verification after fixes (in-memory Cordis smoke, including Mock fallback disclosure) |
scripts/plugin-audit.mjs |
Four-dimensional performance architecture checkup, cross-referenceable with official guides;--peer-patch print verified peer patch suggestions |
scripts/log-doctor.mjs |
One-click parse ~/.dsh/logs/ host failures (startup headers/failed plugins/waiting services/signal summary) |
scripts/sync-skill.mjs |
Sync the skill surface to downstream skill directories,--check check for drift |
scripts/self-test.mjs |
Self-check |
scripts/lib/scanner.mjs |
Lexical scanner and version comparison (zero dependencies) |
scripts/lib/guide-parser.mjs |
Official guide parsing and anchor extraction (including removal-verb semantic gate) |
scripts/lib/runlog.mjs |
Run log writing, indexing, and desensitization |
scripts/lib/client-graph.mjs |
Client half three-layer determination: dsh.client declaration validation, ./client artifact parsing, injected roster dead links (strong/weak evidence grading) |
references/legacy-migration-sop.md |
Legacy plugin migration SOP (reference manual for cases not covered by official guides) |
references/ci-snippet.md |
Plugin repository CI gate template (move "plugin errors after upgrade" earlier to commit time: smoke/typecheck hard gate + checkup soft gate) |