English | νκ΅μ΄ | ζ₯ζ¬θͺ | δΈζ | EspaΓ±ol
A local diff viewer, built on a vendored fork of Pierre's @pierre/diffs and @pierre/trees.
diffdeck is the local diff viewer originally embedded in cc-statusline, extracted into its own product. Instead of depending on the upstream Pierre packages β which move fast (@pierre/diffs churns heavily; @pierre/trees is pre-1.0 beta) and whose internal markup we had already coupled to heavily β diffdeck recovers the original TypeScript from the packages' source maps and vendors it, so we own the rendering engine outright.
The result is a Bun-workspace monorepo where a commodity-hard, framework-agnostic diff engine (Pierre's CodeView, the ~29.5k lines of packages/diffs) is kept as-is, while the parts we customize live in our own code.
What the diff-rendering engine provides:
- Syntax-highlighted diffs via Shiki with TextMate themes (light + dark).
- Full old/new file diffs, not just patches β so unchanged context can be collapsed and expanded on demand.
- Unified and split layouts.
- File-tree sidebar with git-status badges, natural sort, and flatten (compacting single-child folder chains).
- Image diffs β changed binary images render inline with old/new panels.
- Virtualized rendering that stays smooth on large diffs, with sticky file headers.
- Shadow-DOM encapsulation per file, so the viewer's styles never leak into the page.
The interactive viewer chrome that wraps this engine β click-to-fold, copy-path, in-app search, watch/auto-refresh, and working-tree-vs-base modes β comes from the cc-statusline viewer and now lives in diffdeck's apps/viewer/.
Select code in the diff and a prompt box opens right where you released the drag. Press Enter and diffdeck copies one block to your clipboard β the file reference, the exact lines you picked, and your prompt β ready to paste into Claude Code, Codex, or any chat.
Two ways in: drag the code text, or use the gutter's line selection and its + button. A text drag copies exactly the characters you highlighted; the gutter path takes whole lines. Either way the highlight shows precisely what will be copied.
What lands on your clipboard:
```
diffdeck selection
File: apps/viewer/browser/main.ts
Lines: 84-85 (new side, working diff)
if (a) return;
const b = 1;
```
why was this needed?
Run it on demand β no install needed:
bunx @say8425/diffdeckOr install it globally to get the diffdeck command:
bun install -g @say8425/diffdeckRequires Bun; git (and gh for branch-vs-base detection) on your PATH.
Run it in any git repository to view its diff:
bunx @say8425/diffdeck # or `diffdeck` if installed globallyThis starts a local server on 127.0.0.1:49573 (override with --port) and opens
the viewer in your browser.
Options:
| Flag | Description |
|---|---|
--port <n> |
Port to serve on (default: $DIFFDECK_PORT or 49573) |
--no-open |
Do not open a browser automatically (prints the URL) |
--untracked |
Start with untracked files included |
--watch |
Start with watch (auto-refresh) on |
--no-flatten |
Start with the file tree un-flattened (flatten is on by default) |
--tree-right |
Start with the file tree on the right |
--split |
Start in split view (unified is the default) |
--hide-tree |
Start with the file tree hidden |
--fold-with-tree |
Start with sidebar directory collapse synced to diff folds |
-h, --help |
Show help |
-v, --version |
Show version |
These view flags set the initial state for this launch only β they don't change your saved preferences, and the in-app toggles reflect the launched state.
Environment: DIFFDECK_PORT sets the default port. The token is cached under
$XDG_CACHE_HOME/diffdeck/, or ~/.cache/diffdeck/ when that is unset.
diffdeck ships an agent skill (a single skills/diffdeck/SKILL.md) so an AI
coding agent can open the diff viewer in your browser when a change is easier to
see than to read. Install it into your agent through one of the channels below.
The plugin and npx skills channels fetch from GitHub, so they need the
repository to be public and diffdeck published to npm (so the skill's
bunx @say8425/diffdeck resolves). The self-contained diffdeck install-skill
works from any local install.
Plugin:
/plugin marketplace add say8425/diffdeck
/plugin install diffdeck@diffdeck
Or self-contained (writes ~/.claude/skills/diffdeck/):
diffdeck install-skill # --project installs into the current repo insteadPlugin:
codex plugin marketplace add say8425/diffdeck
codex plugin add diffdeck@diffdeck
Or self-contained (writes ~/.claude/skills/diffdeck/ and ~/.agents/skills/diffdeck/):
diffdeck install-skill --codexInstall into any supported agent with the
skills CLI:
npx skills add say8425/diffdeckThe codex / npx skills subcommands are young β check codex plugin --help /
npx skills --help for your version.
packages/
path-store/ @diffdeck/path-store pure tree logic (flatten, sort, projection, store)
theming/ @diffdeck/theming theme system + 10 vendored shiki theme JSONs
diffs/ @diffdeck/diffs CodeView diff-rendering engine
trees/ @diffdeck/trees FileTree engine (vanilla render)
apps/viewer/ @say8425/diffdeck β CLI + diff-server (data API) + browser viewer
skills/ the agent skill (SKILL.md), copied into the package at build time
scripts/ source-map extraction tool, css-inline Bun plugin, render-parity harness
docs/ README translations and screenshots
Dependency graph: path-store (no deps) β trees; theming (shiki) β diffs, trees. Runtime externals: shiki + @shikijs/*, diff, hast-util-to-html, lru_map β these are the packages' own dependencies; the published CLI bundles everything, so nothing is resolved at install time.
Requires Bun.
bun install
bun run typecheck # per-package tsc
bun test
bun run lint # oxlint
bun run format # oxfmtThree lanes:
bun testβ unit/integration tests, fast.*.e2e.tsspecs are excluded from collection, so this never launches a browser.bun run test:coverageβ the same suite with a 100% coverage gate on diffdeck's owned runtime code (apps/viewer/{browser,cli,server}). Intentionally out of the gate: the vendoredpackages/*, the tooling underscripts/, the browser entrymain.ts(integration entry β exercised by the e2e suite instead, not in-process),build.ts, and the specs themselves (*.test.ts,e2e/**).bun run test:e2eβ the Playwright real-browser suite (apps/viewer/e2e/). Drives the system Google Chrome viachannel: "chrome"(no Chromium download) and coversmain.tsand the vendored render paths end-to-end.
Confirms the forked CodeView + FileTree actually render:
bun run scripts/parity/build.ts
cd scripts/parity && python3 -m http.server 8099
# open http://127.0.0.1:8099/index.htmlApache-2.0. diffdeck vendors source derived from Pierre's @pierre/* packages (Apache-2.0, Β© The Pierre Computer Company), modified under the @diffdeck/* namespace. See NOTICE and each package's LICENSE for full attribution and the required notice of modification.


