Vai al contenuto principale
D

dsh-repot

daoyan2142/dsh-repot

Carries a DSH environment between machines through one private GitHub or Gitee repository: third-party plugins (reinstalled from a version, or carried as a tarball or source tree), the four profile configuration files, and folder snapshots. A restore resolves each folder through an absolute path, a registered root, or a confirmed new path, compares file by file, leaves locally edited files alone, backs up anything it replaces, and refuses writes that escape a root, cross a junction, or land on a directory the plugin does not own. Configuration files and folder contents are uploaded as they are (no secret scrubbing) and the plugin does not check that the repository is private; the access token stays in the credentials service, and on first start a GIT_SYNC_* token left by dsh-plugin-git-sync is copied over. Needs Node 22.12 or later.

Installazione

dsh plugin --profile web add github:daoyan2142/dsh-repot

README

dsh-repot

Carry a DSH environment from one machine to another.

The name is "repot": lift the plant with its root ball intact into a new pot. Plugins, configuration and folders travel through one private GitHub / Gitee repository; on the way back, every write must land on the expected path or it is refused.

中文说明 · Install · First run · Why paths cannot drift · Limitations


What it carries

CategoryCarriedHow
Plugins (registry install)yesname@version only by default; reinstall on restore, tarball optional
Plugins (file: linked source)yesthe source tree travels, restored as a relative spec
Plugins (file: pointing at a tgz)yesthe tarball travels as-is
Configurationyescordis.patch.yml / package.json / pnpm-lock.yaml / pnpm-workspace.yaml
Foldersyesa snapshot of the chosen directories, with a path anchor
Sessions / tasksnosessions are zstd-appended logs; wrong shape and size for git
Credentialsnothe PAT never leaves the local credentials service
Runtimesnodsh-runtimes is per-machine
Cachesnostorages, .plugin-manager/asar-out are rebuildable

Commits, branches and graphs are not here — better-sidebar's Git tab owns those.

Install

dsh plugin --profile <your profile> add dsh-repot

Or install from the marketplace and restart DSH.

Two entry points appear:

  • Settings → Environment carry — platform, token, repository, sync roots
  • Sidebar → Repot — upload / compare / apply

Without better-sidebar the settings page also hosts the actions.

First run

  1. Create a repository (private is fine) and fill in owner/repo and the branch. All three sets use it by default; to split them (plugins on Gitee, files on GitHub) name a per-set repository under Per-set repositories and leave the rest empty to inherit.
  2. Paste a Personal Access Token. Not your DSH password. GitHub needs repo; Gitee needs repository read/write. It is stored in the credentials service and never read back over HTTP.
  3. Register sync roots — the anchors that survive a machine change:
idpath
workD:\work
pluginsC:\Users\you\.dsh\plugins

At most three, never a drive root (D:\), the folder must exist, and roots may not nest. The id stays; the path is re-pointed on the new machine — that is the only thing you re-enter.

  1. Pick what to carry in the sidebar and press Upload.
  2. On the other machine: install the plugin, enter the same repository and token, register roots, press Compare, then Apply.

The three buttons

ButtonEffectRisk
Uploadwrites the selected content to the repository, one commitremote only
Comparereads the remote manifest and diffs it against this machineread-only
Applywrites to this machinechanges local files, needs confirmation

Folder restores raise a preflight dialog that lists every absolute path about to be written.

Why paths cannot drift

Each folder entry records three things:

absPath   D:/work/notes       absolute path on the source machine
rootId    work                a registered root
relPath   notes               path inside that root

Restore resolves in order:

LevelConditionBehaviour
1absPath exists hereuse it
2rootId + relPath exists hererelocate
3neither existscreate, after you confirm it

Every level then faces four hard refusals:

  1. the target must be inside a registered root — blocks .. escapes
  2. the nearest existing ancestor must still realpath inside that root — blocks junction escapes
  3. an existing target without this plugin's marker is refused — a directory you filled yourself is never eaten
  4. a content hash mismatch is refused

Pruning only removes files recorded by the previous marker, so your own additions survive. Before anything is overwritten or deleted, the previous content is copied to <profile>/.repot/backup/<stamp>/files/<id>/, and a file you edited since the last restore is never overwritten and never pruned — it is reported as a conflict and left exactly as you left it.

Folder diffs

A folder has no version number, so identity is the hash of its files. Two layers:

  • the manifest records one tree hash per folder, which is what "same or different" compares
  • every folder index (files/<id>/.repot-index.json) records a hash per file, which is what "which file" answers

Comparison therefore lists the actual files:

notes          +2 ~0 −0
  + plan.md
  + src/todo.ts
assets         +0 ~2 −1
  ~ logo.svg
  ~ tokens/colors.json
  − old-banner.png

+ the remote added it, ~ both have it with different content, − the remote no longer has it (a restore removes it, unless you edited it locally).

Indexes written by an older version have no per-file hashes; those folders fall back to the tree-level verdict and say so.

Three plugin shapes

ShapeStoredRestored by
registryname@version (default, near zero bytes)installBundle('name@version')
registry + carrythe tarballdownload, then installBundle(tgz)
file: sourcethe source treematerialise under <profile>/plugins/<name>

Anything above 20 MB defaults to reinstall; dsh-boot-suite ships tens of megabytes of video and audio, so carrying it is a choice, not a default.

file:D:/... specs are rewritten to file:./plugins/<name> on restore.

Safety boundaries

  • The PAT lives only in the credentials service; not in settings, responses, or commit messages.
  • Every request passes ctx.connection.requestRejection; cross-origin calls get 403.
  • Configuration restores back up the previous file to <profile>/.repot/backup/<stamp>/; folder restores do the same for every file they replace or delete, under backup/<stamp>/files/<id>/.
  • A file whose content no longer matches what this plugin last wrote is treated as yours: the restore skips it and reports it instead of reverting your edit.
  • Remote branch updates use force: false; a moved branch is reported, not overwritten.

Limitations

  • No session/task sync — wrong shape and size for git.
  • Gitee writes file-by-file — no dependable tree endpoint, so large sets are slow and deletions cannot ride the same commit.
  • No three-way merge — conflicts are refused and reported, never guessed. Fix a conflict by taking the local file out of the way (or restoring it) and comparing again.
  • A folder is all-or-nothing — the list shows individual files, but the tick is per folder; there is no "apply just this one file".
  • Comparison reads the folder — hashes come from the bytes, so comparing a 500 MB folder costs 500 MB of reads (it does not hold them in memory).
  • No multi-repository parallel work, submodules, or LFS.
  • The marketplace requires a repository at least one day old; a brand-new repository is held, not rejected.

Relationship to dsh-plugin-git-sync

dsh-repot supersedes it. On first start it reads <profile>/.git-sync/settings.json and the GIT_SYNC_* credentials once, migrates them, and leaves the old files untouched so a rollback still works. Do not enable both.

License

MIT

Plugin correlati