# Contributing

Thanks for considering a contribution to dsh-checkpoint-diff. This project is
small on purpose — a focused read-only diff view over
[dsh-checkpoint-rewind](https://github.com/PerryLink/dsh-checkpoint-rewind)
checkpoints — so a few conventions keep it maintainable.

## Ground rules

- **Read-only by design, with one explicit exception — rollback.** The plugin
  must never write to snapshot storage, git, or sessions, and never fork
  sessions. The single write path is user-invoked rollback
  (`/rollback` / `POST /api/rollback` / panel Restore row): it restores
  snapshot file contents into the session workspace — overwrite only, never
  deletes, workspace-root confined, `.git`/`.dsh` refused, read-only git
  primitives (no `git restore`). Every new write-like behavior must first
  extend that exception explicitly in `AGENTS.md`/`SECURITY.md`; anything
  else belongs in the producer (rewind) instead.
- **Pure functions where possible.** Timeline extraction, addressing, and
  output formatting live in `lib/checkpoints.mjs` as pure functions; the diff
  engine in `lib/diff/engine.mjs` is dependency-free; rollback planning lives
  in `lib/rollback.mjs` as pure functions plus low-level fs helpers. Keep it
  that way.
- **Security boundaries are load-bearing.** Refs are validated (git 40/64-hex,
  copy UUID) and relative paths reject `..` and absolute paths before any
  filesystem or git access; restore targets additionally refuse `.git`/`.dsh`
  segments and symlink escapes. Tests must cover the degradation paths
  (missing records, pruned snapshots, missing objects, mixed providers) and
  the rollback refusal paths (traversal, protected paths, absent files,
  method gates).

## Development setup

```bash
pnpm install                 # zod, esbuild, jsdom + react for tests
pnpm test                    # unit tests (node --test, in-process isolation)
pnpm test:integration        # headless integration vs. real dsh-checkpoint-rewind
pnpm build:client            # rebuild the browser bundle -> lib/client.js
```

The integration suite assembles the real rewind plugin against the **local
harness deployment** (`$DSH_HOME/profiles/node_modules`, rc.5) because
dsh-checkpoint-rewind is not published to npm and rc.5 packages are not on the
registry either. `scripts/link-profile-deps.mjs` junctions those packages into
this repo's `node_modules`; run `pnpm test:integration` on a machine with the
harness installed (or with `DSH_HOME` pointed at one). The unit suite has no
such dependency and runs anywhere.

Sandbox notes (Windows): `node --test` child-process spawning and esbuild's
binary service may be blocked under restricted sandbox modes — unit tests use
`--test-isolation=none`, and building the client bundle may require
full-access once.

## Structure

- `index.mjs` — host plugin entry (config, domain acquisition, `/diff` and `/rollback` incl. `--project`, API route)
- `lib/` — host logic: `constants`, `domain` (zod spec), `workspace`,
  `checkpoints` (timeline/format), `project` (cross-session merge/lineage),
  `labels` (snapshot intent naming), `service` (DiffService + HTTP handler),
  `rollback` (restore planning + fs helpers), `diff/engine|git|copy`
- `src/client/` — browser half: `index` (slot registration), `store`, `api`,
  `tree` (collapsible directory tree), `DiffTrigger`, `DiffPanel` (incl.
  restore row), `style` (theme tokens)
- `scripts/` — `build-client.mjs` (esbuild), `link-profile-deps.mjs` (test deps)
- `test/` — unit tests, jsdom panel smoke tests, `integration/diff-headless.mjs`
- `docs/` — design documents (`timeline-design.md`: cross-session timelines, implemented in 0.2.0)

## Pull request checklist

- [ ] `pnpm test` passes
- [ ] `pnpm test:integration` passes (or is documented as environment-limited)
- [ ] `pnpm build:client` and the built bundle was committed if client code changed
- [ ] CHANGELOG updated (Added / Fixed sections)
- [ ] New behavior covered by a test; degradation paths included

## License

By contributing you agree that your contributions are licensed under the
Apache-2.0 terms of this repository.
