npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@heyhuynhgiabuu/pi-diff

v0.7.5

Published

Shiki-powered terminal diff renderer for pi — syntax-highlighted, word-level diffs in split and unified views.

Readme

pi-diff

npm version GitHub release

A pi extension that replaces the default write and edit tool output with Shiki-powered, syntax-highlighted diffs — side-by-side split view, unified stacked view, and word-level change emphasis, all rendered directly in your terminal.

Status: Early release.

Unified view — stacked single-column diff

Split view — side-by-side comparison

Features

  • Syntax-highlighted diffs — full Shiki grammar highlighting (190+ languages) composited with diff background colors
  • Split view — side-by-side comparison for edit tool, auto-falls back to unified on narrow terminals
  • Unified view — stacked single-column layout for write tool overwrites
  • Word-level emphasis — changed characters get brighter backgrounds so you see exactly what changed
  • New file preview — syntax-highlighted preview when creating files
  • Adaptive layout — auto-detects terminal width; wraps intelligently on wide terminals, truncates on narrow ones
  • LRU cache — singleton Shiki highlighter with 192-entry cache for fast re-renders
  • Large diff fallback — gracefully degrades (skips highlighting, still shows diff structure) for files > 80k chars
  • Fully customizable — every color and threshold is overridable via environment variables
  • Edit guard — blocks edit tool calls whose oldText is no longer in the target file, forcing the model to re-read before retrying (prevents stale-oldText retry loops)

Install

pi install npm:@heyhuynhgiabuu/pi-diff

Latest release: https://github.com/buddingnewinsights/pi-diff/releases/latest

Or load directly for development:

pi -e ./src/index.ts

How It Works

pi-diff wraps the built-in write and edit tools from the pi SDK, including single-edit and multi-edit edit calls. When the agent writes or edits a file:

  1. Before the write — reads the existing file content
  2. Delegates to the original SDK tool (file is actually written)
  3. After the write — computes a structured diff between old and new content
  4. Renders the diff with syntax highlighting and word-level emphasis

For edit calls, a tool_call handler runs before the tool executes and verifies that every oldText in the request is still present in the target file. If any oldText is missing, the call is blocked with a clear VERIFY before EDIT error, preventing the model from re-trying with stale text from a prior read.

The rendering pipeline:

Old content ──┐
              ├── diff (structuredPatch) ── parse ── highlight (Shiki → ANSI)
New content ──┘                                          │
                                                         ├── inject diff bg
                                                         ├── inject word-level bg
                                                         └── wrap/fit to terminal

Views

| View | Used by | Description | | ----------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Split | edit tool | Side-by-side with old on left, new on right. Diagonal stripes fill empty slots. Auto-falls back to unified when terminal < 150 cols or > 20% of lines would wrap. | | Unified | write tool | Single column with +/- gutter. Compact, works at any terminal width. |

Both views show:

  • Colored border bars () for changed lines
  • Line numbers in the gutter
  • Hunk separators (··· N unmodified lines ···)
  • Word-level emphasis on paired add/del lines

Configuration

Diff Theme Presets

pi-diff ships with built-in theme presets optimized for different terminal backgrounds. Add to your .pi/settings.json:

{
  "theme": "dark",
  "diffTheme": "midnight"
}

| Preset | Best for | Description | | ---------- | -------------------------------- | --------------------------------------------------------- | | default | Dark theme bases (~#1e1e2e) | Original pi-diff colors — balanced contrast | | midnight | Pure black (#000000) terminals | Subtle tints that don't overwhelm on black | | subtle | Any dark theme | Minimal backgrounds — barely-there tints for a clean look | | neon | Low-contrast displays | Higher contrast backgrounds for better visibility |

Per-Color Overrides

Override individual diff colors in .pi/settings.json using hex #RRGGBB values:

{
  "theme": "dark",
  "diffTheme": "midnight",
  "diffColors": {
    "bgAdd": "#0d1a12",
    "bgDel": "#1a0d0d",
    "bgAddHighlight": "#1a3825",
    "bgDelHighlight": "#381a1a",
    "bgGutterAdd": "#091208",
    "bgGutterDel": "#120908",
    "bgEmpty": "#080808",
    "fgAdd": "#64b478",
    "fgDel": "#c86464",
    "fgDim": "#404040",
    "fgLnum": "#505050",
    "fgRule": "#282828",
    "fgStripe": "#1e1e1e",
    "fgSafeMuted": "#8b949e",
    "shikiTheme": "github-dark"
  }
}

diffColors overrides take priority over diffTheme presets, so you can start from a preset and tweak individual colors.

Auto-Derive (Default Behavior)

When no diffTheme or diffColors is set, pi-diff automatically derives background colors from your pi theme's diff foreground colors and tool-state backgrounds. Added/context surfaces use toolSuccessBg; removed surfaces use toolErrorBg. This ensures diffs look good with any pi theme and terminal background — no configuration needed.

The auto-derive uses different intensity levels:

  • Line backgrounds: 8–10% of the theme's diff fg color mixed into the matching tool-state background (subtle tint)
  • Word highlights: 20–22% (more visible for changed characters)
  • Gutters: 5–6% (subtler than line backgrounds)

Color Resolution Order

For each color, pi-diff checks (highest priority first):

  1. Environment variable — e.g. DIFF_BG_ADD="#1a3320" (backward compatible)
  2. diffColors from .pi/settings.json (per-color hex overrides)
  3. diffTheme preset from .pi/settings.json (named preset bundle)
  4. Auto-derived from pi theme's toolDiffAdded/toolDiffRemoved colors
  5. Hardcoded fallback (original defaults)

Environment Variables

All settings are also controllable via environment variables. Add them to your shell profile or .envrc:

Theme

| Variable | Default | Description | | ------------ | ------------- | ---------------------------------------------------------------------- | | DIFF_THEME | github-dark | Shiki theme name (e.g., dracula, one-dark-pro, catppuccin-mocha) |

Colors

Override any diff color with hex #RRGGBB format:

| Variable | Default | Description | | -------------------- | --------- | ------------------------------------------- | | DIFF_BG_ADD | #162620 | Background for added lines | | DIFF_BG_DEL | #2d1919 | Background for removed lines | | DIFF_BG_ADD_HL | #234b32 | Word-level emphasis on added text | | DIFF_BG_DEL_HL | #502323 | Word-level emphasis on removed text | | DIFF_BG_GUTTER_ADD | #12201a | Gutter background for added lines | | DIFF_BG_GUTTER_DEL | #261616 | Gutter background for removed lines | | DIFF_FG_ADD | #64b478 | Foreground for + signs and add indicators | | DIFF_FG_DEL | #c86464 | Foreground for - signs and del indicators |

Layout

| Variable | Default | Description | | --------------------------- | ------- | ------------------------------------------- | | DIFF_SPLIT_MIN_WIDTH | 150 | Minimum terminal columns to use split view | | DIFF_SPLIT_MIN_CODE_WIDTH | 60 | Minimum code columns per side in split view |

Example .envrc

# Use a different Shiki theme
export DIFF_THEME="catppuccin-mocha"

# Brighter add backgrounds
export DIFF_BG_ADD="#1a3a25"
export DIFF_BG_ADD_HL="#2d6040"

# Allow split view on narrower terminals
export DIFF_SPLIT_MIN_WIDTH=120

Architecture

src/
├── index.ts            # Extension entry point — wraps write/edit tools with diff rendering
├── edit-guard.ts       # tool_call handler that blocks stale oldText in edit calls
├── edit-guard.test.ts  # Unit tests for the edit guard
├── core/               # Pure data layer: diff parsing, conflict detection, line resolution
│   ├── config.ts
│   ├── conflicts.ts
│   ├── diff.ts         # parseDiff, parsePatchFiles, resolveSepStyle
│   ├── replace.ts      # safe in-place text replacement
│   ├── resolve-lines.ts
│   └── *.test.ts
└── review/             # Shared diff-rendering primitives used by the main extension
    ├── git.ts          # read git diffs from disk (execFileSync)
    └── hunk-preview.ts # renderSplit, renderUnified, theme helpers (re-exported via __testing)

Key internals

All listed symbols are exposed under the __testing export for unit tests:

| Symbol | Source | Purpose | | -------------------------- | ----------------------- | ----------------------------------------------------------------------- | | parseDiff() | core/diff.ts | Convert old/new content to structured DiffLine[] (added/removed/chars) | | parsePatchFiles() | core/diff.ts | Parse a full git apply patch into per-file diff objects | | resolveSepStyle() | core/diff.ts | Pick the per-side separator style ( vs ) for split view | | getSepStyle() | review/hunk-preview.ts| Same as above for the shared rendering layer | | computeHunkBlocks() | review/hunk-preview.ts| Build add/remove/modify line blocks with column ranges for split view | | renderSplit() | review/hunk-preview.ts| Side-by-side renderer with diagonal stripe fillers | | renderUnified() | review/hunk-preview.ts| Stacked single-column renderer | | normalizeShikiContrast() | review/hunk-preview.ts | Lighten/darken Shiki output to match the surrounding TUI theme |

Rendering constants

| Constant | Value | Description | | ------------------- | ------ | ------------------------------------------ | | MAX_PREVIEW_LINES | 60 | Max lines in edit preview (split view) | | MAX_RENDER_LINES | 150 | Max lines in write result (unified view) | | MAX_HL_CHARS | 80,000 | Skip syntax highlighting above this | | CACHE_LIMIT | 192 | LRU cache entries for highlighted blocks | | WORD_DIFF_MIN_SIM | 0.15 | Minimum similarity for word-level emphasis |

Exports

The extension exports a __testing object for unit testing:

import { __testing } from "@heyhuynhgiabuu/pi-diff";

const { parseDiff, renderSplit, renderUnified, normalizeShikiContrast } =
  __testing;

Development

git clone https://github.com/buddingnewinsights/pi-diff.git
cd pi-diff
npm install
npm run typecheck   # TypeScript validation
npm run lint        # Biome linting
npm test            # Run tests

Load in pi for testing

# From the pi-diff directory
pi -e ./src/index.ts

# Or install globally
pi install .

How pi Extensions Work

pi-diff is a pi extension — a TypeScript file that exports a default function receiving the pi API:

import { registerEditGuard } from "./edit-guard.js";

export default function piDiffExtension(pi: ExtensionAPI): void {
  // Wrap the built-in write/edit tools with diff rendering
  const origWrite = createWriteTool(cwd);
  const origEdit = createEditTool(cwd);

  pi.registerTool({
    ...origWrite,
    name: "write",
    execute: async (...) => { /* wrap + diff */ },
    renderCall: (...) => { /* preview */ },
    renderResult: (...) => { /* render diff */ },
  });

  // Block stale-oldText edit calls before they run
  registerEditGuard(pi);
}

Extensions can:

  • Register toolspi.registerTool(definition)
  • Listen to eventspi.on("session_start" | "input" | "tool_call" | "session_shutdown" | ...)
    • tool_call handlers can block: true to prevent the call from running
  • Register commandspi.registerCommand("/name", handler)

See the pi docs for the full extension API.

Design notes

How hashline (hashline_read, hashline_edit, edit hashlineChanges) relates to Pi’s stock edit tool (exact edits[], bounded fuzzy match, loud failures) is documented in .pi/artifacts/DECISIONS.md (ADR-001). Summary: stock edit stays the portable default; hashline is an opt-in strict anchor path for agents that adopt it.

License

MIT — huynhgiabuu