dshbase

Plugin directory / Developer / dsh-checkout-guard

dsh-checkout-guard

Verified · install-tested on dsh LeslieWylie

✓ Actively maintained Builds on 2 official DSH packages

View on GitHub ↗ ← Back to plugin directory

0Stars
0Forks
0Open issues
—Language
2026-08-18Last push
Cross-platformPlatform

What it does

Pre-flight guard for git working copies: is the checkout you are about to write to the one you think it is? Branch identity, drift from the remote and how stale that figure is, the identity your next commit will carry, work already in the index, and duplicate clones. Read-only, offline by default.

✅
Our take
Works — verified, early-stage project

Pre-flight guard for git working copies: is the checkout you are about to write to the one you think it is? Branch identity, drift from the remote and how stale that figure is, the identity your next commit will carry, work already in the index, and duplicate clones. Read-only, offline by default. It installs cleanly and boots without issues in our testing. It's early-stage but functional.

“Verified” means our automated CI actually ran dsh plugin add in a clean profile and it booted — nothing more. Feature descriptions and version compatibility are the author’s claims. This is not a security audit and not an endorsement of third-party code.

README

dsh-checkout-guard

Is the working copy you are about to write to the one you think it is?

A DSH plugin that answers that before you edit, commit, or push — not after. It
reads a git checkout and tells you where it sits relative to its remote, how
stale that answer is, who your next commit will be attributed to, what work is
already sitting in the index, and whether another clone of the same repository
on this machine has moved ahead of the one you are in.

Read-only. Offline unless you ask for a fetch. Never takes the index lock.


Why

Every check here exists because a specific mistake actually happened, usually to
an agent working across many repositories at once:

What goes wrong What you see afterwards
You edit a checkout that is 8 commits behind Your "fix" reverts work, or your push is rejected after the fact
Two clones of one repository, you are in the stale one Changes vanish; the repo on the forge never shows them
A concurrent process moved HEAD to another branch Your commit lands on a branch you have never heard of
Something was already staged before you ran git add Your commit packages somebody else's work in progress
No repository-local user.email A work address is permanently attached to a public commit
Detached HEAD The commits exist, then don't, and nothing warned you

None of these throw. Git does exactly what you asked; you asked in a state you
had misread. That is the entire problem space this plugin covers.

Install

npm install dsh-checkout-guard

Then append to your profile's cordis.yml:

- id: checkout-guard
  name: 'dsh-checkout-guard'

Node 22.19+ or 24+. The only runtime requirement is git on PATH.

Tools

checkout_guard — one working copy, in depth

{ "path": "/abs/path/to/repo", "expectBranch": "main" }
{
  "branch":  { "current": "main", "detached": false, "upstream": "origin/main", "linkedWorktree": false },
  "sync":    { "ahead": 1, "behind": 1, "fetchAgeSeconds": 255600, "fetchedNow": false },
  "remote":  { "normalized": "github.com/acme/widget", "host": "github.com", "publicForge": true },
  "identity":{ "email": "[email protected]", "source": "global", "repositoryOverride": false },
  "workingTree": { "staged": [], "unstaged": ["package.json"], "untracked": [], "clean": false },
  "duplicateCheckouts": [ { "path": "/elsewhere/widget", "branch": "main", "ahead": 3, "aheadOfThisOne": true } ],
  "blockers": [
    "diverged from origin/main by 1 commit(s) (and 1 ahead); you are reading code the remote has already moved past, and a push will be rejected",
    "another checkout of the same remote is ahead of this one: /elsewhere/widget (main, 3 ahead vs 1); you may be editing the stale copy"
  ],
  "warnings": [
    "remote refs were last updated 71h ago; ahead/behind is computed from that snapshot, not from the remote as it is now (re-run with fetch: true)"
  ],
  "verdict": "blocked",
  "safeToWrite": false
}

safeToWrite is the one field a caller needs. blockers are states where
proceeding loses or misplaces work; warnings are things worth knowing that
are not automatically wrong.

Parameter Effect
path (required) Absolute path to the working copy, or any directory inside it
fetch Contact the remote first so ahead/behind is current. The only networked option, default false
expectBranch The branch you believe you are on. A mismatch is a blocker
expectIdentity The email you expect to author with. A mismatch is a blocker
remote Remote to compare against (default origin)
staleAfterHours When remote refs count as stale (default 24)
findDuplicates / duplicateRoots / maxDepth / maxRepos Control the search for other clones

expectBranch and expectIdentity are how you turn a report into an assertion.
Without them the plugin describes; with them it refuses.

checkout_guard_scan — every working copy under a root

{ "roots": ["/abs/path/to/projects"], "maxDepth": 3 }

Returns one row per checkout — branch, upstream, ahead/behind, uncommitted
counts, fetch age — plus:

  • needsAttention: the ones that are behind, diverged, detached, or have no upstream
  • duplicateRemotes: paths grouped by remote, so two clones of one repository are visible at a glance

Run this first to find out which checkouts deserve a closer look, then hand
those paths to checkout_guard.

What it deliberately does not do

  • It does not tell you a remote is archived. That needs the forge's API, and
    this plugin does not make authenticated HTTP calls. remote.normalized gives
    you host/owner/repo to check yourself.
  • It does not fix anything. No pull, no rebase, no stash, no checkout. The
    recovery for "behind" and the recovery for "diverged" are different, and
    picking between them is not a decision a guard should make for you.
  • It does not judge your identity. It reports which config your author line
    comes from, and warns only when a public forge is involved and the repository
    has no local override. If you pass expectIdentity, it compares against
    exactly what you named — it never guesses what your address should be.

Safety properties

  • No writes to any repository. The only command that can modify anything is
    git fetch --dry-run, which runs only when fetch: true and touches nothing
    but FETCH_HEAD.
  • GIT_OPTIONAL_LOCKS=0 on every call. Ordinary git status refreshes and
    rewrites the index, taking .git/index.lock. A guard whose whole premise is
    "another agent may be in this checkout right now" must not be able to block
    that agent.
  • GIT_TERMINAL_PROMPT=0, empty GIT_ASKPASS. A fetch against a private
    remote fails fast instead of parking on a credential prompt nobody can see.
  • Credentials are stripped during URL normalization, before a remote can
    reach a result object or a log line.
  • Path allowlist. Both sides are realpath'd, so a symlink planted inside
    an allowed root cannot read outside it.

Configuration

- id: checkout-guard
  name: 'dsh-checkout-guard'
  config:
    roots:
      - /Users/you/projects

roots bounds everything the plugin will look at. Unset, it defaults to your
home directory.

Development

npm install
npm test          # unit tests against real git repos in a temp dir
npm run test:boot # loads the plugin into a real cordis Context

There is no build step. src/index.js is the published entry point, byte
for byte. Plugins that compile to lib/ and commit the output have to keep the
two in sync forever, and every test that imports src/ passes while the
artifact an installer runs is stale. Removing the build removes the whole class.

The unit tests create real repositories — real remotes, real pushes, real
divergence — rather than stubbing git. A hand-written double answers the way its
author expects, and the author's expectation about repository state is precisely
what is under test.

tests/boot.test.mjs exits 0 with a SKIP from a bare clone so contributors are
not blocked, and exits 1 under DSH_BOOT_STRICT=1, which CI sets. A skipped
integration test reported as green is worse than no test at all.

中文 · MIT

Install

🧩 Let your agent install it (recommended)

Install the catalog once, then DeepSeek Harness can find and install any plugin from this site automatically:

dsh plugin add dshbase-catalog

Then say "install dsh-checkout-guard for me" — your agent finds it in the directory and installs it. Docs: dshbase-catalog · verified packs.

This plugin is GitHub source (not published to npm) — install it straight from the repo:

Web profile:

dsh plugin --profile web add github:LeslieWylie/dsh-checkout-guard

Headless (CLI) profile:

dsh plugin --profile headless add github:LeslieWylie/dsh-checkout-guard

Test report

Verified: L1 install + L2 load + L3 runtime from GitHub source on dsh 0.1.0-rc.6.

Security: not yet scanned — our daily static scan will cover it shortly.

Share this badge

More in Developer

Browse all 7819 plugins →