docs(skills): one canonical resolution, no DSH_SOURCE
DSH_SOURCE is an install-time shell variable the installer never exports, so
a skill reading ${DSH_SOURCE} at runtime reads nothing. Verified unset in a
running dsh process.
Git resolves the main clone identically for every install, so the curl-vs-
adopted distinction was never a branch point in these workflows. Verified
one launcher-then-Git recipe against three shapes: a curl install cloning
into the container, an adopted clone nested far outside any container, and
a custom DSH_SOURCE container.
dsh-customize now states that single procedure and warns off the installer
variables. dsh-upgrade's Layout describes what the resolution finds rather
than a path convention, and no longer teaches install shapes as cases.
This commit is contained in:
@@ -12,7 +12,9 @@ Make personal DSH changes in task worktrees and integrate them under the staging
|
||||
Do not assume a path or branch name. DSH is usually installed from source with a personal staging branch; create one for the user only when none exists.
|
||||
|
||||
1. Inspect `command -v dsh` in the user's launch environment before resolving symlinks.
|
||||
2. Follow the launcher through the full symlink chain to identify the source checkout. The standard [`scripts/install.sh`](../../scripts/install.sh) keeps staging checkouts under one container `${DSH_SOURCE}` (default `~/.dsh/source`), each a git worktree `${DSH_SOURCE}/staging-<timestamp>`. The main clone — the one real clone whose object store every worktree shares — is at `${DSH_SOURCE}/master` for a `curl` install, but installing from an existing clone adopts that clone wherever it lives, so never assume it sits in the container or on any particular branch. Resolve it from the checkout: `git -C <checkout> rev-parse --git-common-dir` gives the shared git directory (a linked worktree reports the real clone's, not its own), and its parent is the main clone. That answer is relative for a plain clone, so anchor it against the checkout before use, and resolve it physically — comparing a resolved path against an unresolved one silently misidentifies the clone, since macOS reaches `/var` through a symlink to `/private/var`. `${DSH_BIN_DIR}/dsh` links to `${DSH_SOURCE}/current/bin/dsh`, and the stable `current` symlink points at the active staging worktree, so resolve `current` to reach the real checkout. All paths are configurable; an older install may link PATH straight at a worktree (no `current`) or use scattered sibling clones — follow the launcher rather than assuming a layout.
|
||||
2. Follow the launcher through the full symlink chain to reach the source checkout, then ask Git for everything else. The `dsh` on PATH is a symlink, usually through a stable `current` symlink into the active staging worktree; resolve the chain physically and take the launcher's parent directory as the checkout. Derive the rest from that checkout rather than from any path convention: `git -C <checkout> rev-parse --show-toplevel` confirms the checkout root, and `git -C <checkout> rev-parse --git-common-dir` gives the shared git directory — a linked worktree reports the real clone's, not its own — whose parent is the main clone, the one real clone whose object store every worktree shares. `--git-common-dir` answers relatively for a plain clone, so anchor it against the checkout before use, and resolve it physically: comparing a resolved path against an unresolved one silently misidentifies the clone, since macOS reaches `/var` through a symlink to `/private/var`. `git -C <main clone> worktree list` then enumerates every checkout sharing it.
|
||||
|
||||
This one procedure covers every install. [`scripts/install.sh`](../../scripts/install.sh) puts staging worktrees and `current` under a container directory (default `~/.dsh/source`), and a `curl` install also clones into that container while installing from an existing clone adopts that clone where it already lives — but nothing in this workflow depends on which happened, on the container's path, or on the main clone's branch. `DSH_SOURCE` and the installer's other variables exist only while the installer runs; they are never exported, so never read them here. An older install may link PATH straight at a worktree with no `current`, which the same launcher-then-Git procedure resolves unchanged.
|
||||
3. Verify the checkout with Git, then record its branch, tip, status, remotes, worktrees, in-progress operations, and applicable `AGENTS.md` files.
|
||||
4. Treat the launcher checkout's branch as staging unless the user says otherwise. The installed launcher must resolve to a staging worktree on a staging branch, never the main clone or a task, preparation, review, publication, or detached checkout. Ask if the launcher, checkout, or branch ownership is ambiguous; warn explicitly for a detached HEAD, the main clone, or a non-staging branch.
|
||||
|
||||
|
||||
@@ -9,7 +9,9 @@ Prepare and validate the upgrade in a fresh staging worktree of the main clone,
|
||||
|
||||
## Layout
|
||||
|
||||
A source-installed DSH keeps its staging checkouts and `current` under one container directory `<source>` (default `~/.dsh/source`): each staging checkout is a git worktree `<source>/staging-<timestamp>` on branch `dsh-staging/<timestamp>`. The main clone — the one real clone holding the object store every worktree shares, and never a launcher target — is at `<source>/master` for a `curl` install, but the container owns worktrees rather than the repository: installing from an existing clone adopts that clone wherever it already lives, so resolve it from the staging worktree by the procedure in [`dsh-customize`](../dsh-customize/SKILL.md) instead of assuming a path. Do not assume the main clone sits on `master` or that its `origin` is authoritative upstream — an adopted clone keeps whatever branch and remotes it had, and may point at a fork. The upgrade fetches upstream separately, per step 1. The stable symlink `<source>/current` points at the active staging worktree, and the PATH launcher links to `<source>/current/bin/dsh`, so the launcher resolves PATH -> `current` -> staging worktree. Cutover repoints `current` alone; the PATH launcher is written once at install and never moves. All worktrees share the main clone's single `.git` object store; the main clone's `.git/info/exclude` is inherited by every linked worktree, so one `.agents/merge.lock` entry there excludes the lock in all of them. An older install may link PATH straight at a worktree (no `current`) or use scattered sibling clones; if so, follow the recorded launcher checkout rather than assuming this layout, treat that sibling clone as its own main clone, and create `current` and repoint PATH to `current/bin/dsh` as a one-time migration at cutover.
|
||||
Resolve the layout, never assume it. [`dsh-customize`](../dsh-customize/SKILL.md) owns the procedure: follow the PATH launcher to the staging worktree, then derive the main clone from that checkout with Git. It resolves every install the same way, so this workflow needs no special case for how DSH was installed and never reads the installer's variables, which exist only while the installer runs.
|
||||
|
||||
The resolved layout is one container directory `<source>` holding each staging checkout as a git worktree `<source>/staging-<timestamp>` on branch `dsh-staging/<timestamp>`, plus the stable symlink `<source>/current` pointing at the active one; the PATH launcher links to `<source>/current/bin/dsh`, so it resolves PATH -> `current` -> staging worktree. The main clone is the one real clone whose object store every worktree shares, and is never a launcher target. It may live inside `<source>` or anywhere else on disk, on any branch, with remotes that may point at a fork — so treat it strictly as the object store and worktree host, and take authoritative upstream from step 1 instead. Cutover repoints `current` alone; the PATH launcher is written once at install and never moves. The main clone's `.git/info/exclude` is inherited by every linked worktree, so one `.agents/merge.lock` entry there excludes the lock in all of them. An older install may link PATH straight at a worktree with no `current`; the same resolution finds it, and cutover then creates `current` and repoints PATH to `current/bin/dsh` as a one-time migration.
|
||||
|
||||
## Names
|
||||
|
||||
|
||||
Reference in New Issue
Block a user