DeepSeek Harness Plugin

ygcdsj/dsh-home-migrate

Stars ★ 3 Category Workflow & Automation Added 2026-08-21

Export and import DeepSeek Harness configuration across machines as same-OS .dshmig archives, with credential redaction, verification and rollback.

Install

# from a prebuilt release tarball

dsh plugin --profile web add "https://github.com/ygcdsj/dsh-home-migrate/releases/download/v0.0.9/dsh-migrate-0.0.9.tgz"

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:ygcdsj/dsh-home-migrate

Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).

README

experimental — DSH configuration migration: export/package → restore on another machine → verify + rollback.

中文

Pack configuration from any DSH install, restore it into a NEW profile on the target machine, with verification at every step and automatic rollback on failure. No cloud, no history, no cross-brand imports.

Workflow

dsh-migrate migration flow overview

Why not just use X?

Project Purpose Our boundary
dshmarket (dsh-market) Backup & Restore In-market profile plugin-layer backup/restore We don't touch the plugin market; dsh-migrate covers vendor/ link dirs, .agent-presets, settings.yaml, credential redaction — archive-format interop is a v2 goal
dsh-backup-sync Local snapshots + WebDAV cross-machine sync Backup/sync ≠ migration; we do the full "package → restore" loop
dsh-backup One-command backup + rotation Same as above
dsh-session-sync Session-library git mirror Sessions are explicitly out of MVP scope
dsh-movein / DSH-Portable Claude Code → DSH import / portable builds Reverse direction or different shape

Features (MVP)

  • Export: scans ~/.dsh (profile configs, settings.yaml, .agent-presets, vendor/ link dirs); hard-excludes .credentials.yaml, .env*, .pnpm-store, sessions, storages, node_modules, …; field-level credential scanning + redaction for settings/presets, with a secretReport in the manifest
  • Packaging: single .dshmig (zip) with a manifest (version, platform, file list, sha256 checksums, link mapping)
  • Import: preflight (same OS, dsh version) → backup target → NEW profile by default (<name>-migrated, auto-incremented) → link: path rewrite → vendor/presets/settings restore → pnpm install → verification chain (link resolution → dsh --dump-config) → automatic rollback on failure
  • Verification chain: L1 pnpm install / L2 link resolution (junction realpath) / L3 dsh --dump-config
  • UI: "Migration" section in Settings (export wizard + import wizard); host tools dsh_migrate_export / dsh_migrate_import callable by agents

Explicitly out of MVP scope (v2 or ecosystem)

Sessions/storages migration, WebDAV/Gist sync, cross-brand imports, portability, cross-OS migration, overwriting existing profiles, unattended migration, credential management (exclude + redact + re-configure guidance only).

Install

After npm release:

# inside the profile directory
dsh plugin --profile web add dsh-migrate

Local development (requires dsh-super-injector):

npm install --legacy-peer-deps --no-audit --no-fund
npm run build          # falls back to the _npx official package tree when no bash/checkout exists
# inside the injector environment:
dev_inject_plugin <this directory>

Full migration walkthrough (first-time users)

  1. Export on the source machine: Settings → Migration → Export → ① Preview export → ② Run export
  2. Get the artifact: a .dshmig file lands in ~/dsh-migrate-exports/dsh-migrate-<profile>-<timestamp>.dshmig — a zip containing the manifest (checksums), profile configs, settings.yaml (redacted), .agent-presets, and vendor/ link packages; credentials are best-effort excluded/redacted (secretReport includes an unscannedFiles list — review it before transferring)
  3. Transfer it: USB / cloud / scp — redaction is best-effort; rely on secretReport
  4. Import on the target: DSH → Settings → Migration → Import → paste the .dshmig path → ① Preflight (per-item ✓/✗) → confirm the step list → ② Run import
  5. Wait for verification: pnpm install + verification chain run automatically (L1 install / L2 link resolution / L3 dsh --dump-config); the import only finishes when all pass
  6. Switch to it: the import creates a NEW profile (<name>-migrated); switch the default profile manually after verification, then clean up ~/.dsh/.dshmig-backup/ once confirmed

Launching the migrated profile (important): dsh web is an alias of dsh --profile web and always boots the pristine web profile — the migration lives in the NEW <name>-migrated profile, so you must name it explicitly:

dsh --profile web-migrated      # boot the migrated profile (GUI)

Running dsh web opens the untouched native environment, so migrated plugins/skins/settings won't show up there — that is expected, not a fault. web is a hardcoded alias in the dsh CLI (dsh web ≡ dsh --profile web); DSH has no default-profile mechanism and no switch command. The only way to make dsh web boot the migrated environment is to rename the profile directory: once verified, retire/move the old web directory, then rename <name>-migrated to web (both live under $DSH_HOME/profiles/). Until then, keep launching explicitly with dsh --profile <name>-migrated. ⚠ After renaming the directory, pnpm may fail with ERR_PNPM_UNEXPECTED_VIRTUAL_STORE (virtual-store path mismatch, a known pnpm behavior) — see the FAQ for the fix.

Import never overwrites your existing profile; any failure rolls back automatically.

Usage

Settings wizards (recommended)

  1. Export: Settings → Migration → Preview export (file list/size/excluded/credential hits) → Run export → artifact in ~/dsh-migrate-exports/*.dshmig
  2. Import: Settings → Migration on the target → enter the .dshmig path → Preflight (per-item ✓/✗) → confirm the step list → Run import → review verification results and backup dir
  3. Switch the default profile manually after verification; clean up .dshmig-backup/ once confirmed

Host tools

dsh_migrate_export { dryRun: true } (preview) / { dryRun: false, outDir } (package); dsh_migrate_import { archive, dryRun: true } (preflight) / { archive } (import, auto-rollback on failure).

Security boundary

dsh-migrate import security gates

  • Credentials are best-effort excluded/redacted, not guaranteed: .credentials.yaml and .env* are hard-excluded; suspected credential fields in settings/presets/vendor config files are redacted (<redacted>) and recorded in secretReport; an unscanned-files list (unscannedFiles) ships with the report — review it before transferring
  • Credentials inside vendor config files are redacted in place: the inevitable cost of not migrating credentials — if a migrated vendor package depends on a redacted value (e.g. an API token), reconfigure it on the target; the README/export report calls this out
  • Importing executes code from the archive: import runs pnpm install (default --ignore-scripts) and parses bundle plugins, and starting the profile later executes them — only import archives from sources you trust (the UI confirm dialog warns about this)
  • Artifacts are generated locally only; transferring them is your responsibility
  • link: targets are asserted inside <home>/vendor; manifest path fields (files/links/profiles) are allow-listed + landing-path asserted (anti path-traversal writes)
  • HTTP API is loopback-only (Host allow-list) + CSRF token + Origin same-origin + Sec-Fetch-Site checks; exposing DSH web to a LAN means anyone can import arbitrary archives (an RCE surface)
  • A symlinked settings.yaml is refused for overwrite (no write-through); concurrent imports use separate staging subdirs and never clean each other's

FAQ

Will import overwrite my current config? No. MVP only creates a new profile (<name>-migrated); settings.yaml is overwritten after backup (uncheck it before importing if unwanted).

Why can't I see the migrated plugins with dsh web? dsh web is a hardcoded alias of dsh --profile web and boots the pristine web profile; the migration tool never overwrites your existing profile, so everything lives in the NEW <name>-migrated profile. Boot it with dsh --profile <name>-migrated. Once verified, retire the old profile and rename <name>-migrated to web (rename the directory under $DSH_HOME/profiles/; DSH has no default-profile mechanism) so dsh web boots the migrated environment.

Cross-OS migration? MVP is same-OS only; cross-OS is rejected at preflight.

Can I import into a machine that's already been used (plugins/skins installed)? Yes. Import only creates a NEW profile (<name>-migrated) and never touches your existing profiles; settings.yaml is backed up before being overwritten (uncheck it before importing if unwanted); same-name vendor packages are skipped or verified identical, conflicts are reported only. The target-used preflight item shows a warning (⚠) describing the target state (vendor packages / non-default profiles / migration history) but does not block the import; for strict mode ("target must be pristine"), pass requireFresh: true to the host tool.

dsh plugin fails with ERR_PNPM_UNEXPECTED_VIRTUAL_STORE after renaming a profile directory? pnpm records the virtual store's absolute path in node_modules/.modules.yaml (virtualStoreDir); renaming/copying the profile directory makes that path stale and pnpm refuses any mutation — a known pnpm behavior, unrelated to this tool (dsh web still boots because runtime loading follows the links, it does not check this field). Fix: stop dsh → delete the profile's node_modules (pnpm-lock.yaml stays in the profile dir) → re-run dsh plugin --profile <name> add <pkg> (or pnpm install in that directory) to rebuild everything from the lockfile.

Will the migration archive carry dsh-migrate itself? Since 0.0.9, yes: on export the tool automatically appends itself to the archived profiles (dependencies gains dsh-migrate@^<version> and dsh.profile.bundles is extended), so the target has the migration tool right after import — no manual install needed (idempotent: skipped when the profile already declares it; the import installs it from npm, so network is required). Older versions (≤0.0.8) did not: migration only carries a profile's declared content, and a tool mounted via runtime injection (super-injector) is not a profile dependency — in that case install it on the target manually: dsh plugin --profile <name> add dsh-migrate.

What about git: dependencies (skins)? Not packaged; re-fetched by pnpm install on the target (network/credentials required; preflight warns).

Is import safe? Import executes code inside the archive (pnpm install scripts + bundle plugin parsing; starting the profile later runs the plugins), so only import archives from sources you trust. --ignore-scripts is on by default; path fields are allow-listed with landing assertions; the HTTP API is loopback-only + token-gated.

What if import fails? Config-level rollback is complete (remove created paths + restore snapshot); dependency-level is best-effort; .dshmig-backup/ preserves the scene — never silent.

Development & tests

npm test             # smoke (export → import → rewrite/restore/increment/fault injection), sandbox-safe
npm run test:install # full chain (pnpm install + dump-config, needs full permissions)

Spec and design decisions: docs/DEVELOPMENT.md (machine-verified baselines, ecosystem conventions, survey findings, risk register).

Security review & fix records: the original review report is docs/SECURITY_REVIEW.md; verification and fix evidence is in docs/VERIFICATION.md.

Roadmap (v2)

  • Sessions/storages migration (dsh-session-sync git-mirror approach)
  • Archive-format interop with dshmarket backups
  • WebDAV/Gist sync
  • Cross-OS (implementation is already cross-OS-friendly; promises stay conservative)

License

MIT © 2026 dsh-migrate contributors

Credits

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →

Community comments

Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.