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

edit-o-matic

v1.1.0

Published

Whitespace-tolerant edit fallback for Pi — fail-closed relative-indent matching, match-failure diagnostics, dry-run preview, correct indent-unit detection, Myers line diffs, multi-edit hardening, backups, atomic writes, and remapped Python syntax errors.

Readme

editomatic

Whitespace-tolerant edit fallback for Pi — for local/quantized LLM users who also use gentle-pi.

Upgrade to 1.1.0+ (diagnostics + dry-run)

Versions before 1.0.5 could silently corrupt indent-sensitive files (especially Python) when aggressive fallback matching flattened indentation and rewrote the wrong region.

1.0.5+ fail-closed matching · 1.0.6+ backups + atomic write · 1.0.7 multi-edit hardening · 1.0.8 Myers line diffs · 1.1.0 match-failure diagnostics, dry-run preview, correct indent-unit detection, remapped Python syntax errors.

Full details: CHANGELOG.md · lockdown: EDITOMATIC_STRICT=1

editomatic is not a replacement for Pi's built-in edit tool. It is a fallback for models that struggle with exact text matching due to indentation drift, trailing whitespace, or Unicode normalization differences — common failure modes of local and quantized language models.

The problem

Pi's built-in edit tool uses exact string matching. When a model's output contains different indentation levels, trailing spaces, or Unicode smart quotes, the edit fails. Quantized models (4-bit, 8-bit) are especially prone to these drift patterns.

# What the model sends:
{ "oldText": "function hello() {}" }

# What the file actually has:
"    function hello() {\n      // does nothing\n    }"

# Result: edit fails, model has to guess again

editomatic handles this with progressive fallback matching and fail-closed safety so it never silently destroys structure.

How it works

Matching strategies (first success wins):

| Strategy | What it does | Speed | |---|---|---| | Exact | Byte-perfect indexOf match | Fastest | | Fuzzy | Strips trailing whitespace, normalizes Unicode; always replaces at line level | Fast | | Relative-indent | Same content after fuzzy normalization, with matching relative indentation between lines (absolute indent may differ) | Medium |

Pure “strip all leading whitespace and hope” is not used. Two blocks that only look identical after flattening structure are rejected or treated as ambiguous.

Replacement preserves:

  • Original BOM and line endings (CRLF vs LF)
  • Unchanged lines outside the match
  • Tab/space convention and relative indent structure
  • Trailing newlines when intentional in newText

Write safety

Every successful write:

  1. Saves previous content to yourfile.ext.editomatic-bak
  2. Writes new content to a temp file, then renames (atomic on the same filesystem)
  3. For Python paths, runs best-effort python -m py_compile before overwrite when an interpreter is available (errors cite the real path and proposed-file line numbers, not a temp path)

Dry-run preview

{ "path": "app.py", "dryRun": true, "edits": [{ "oldText": "...", "newText": "..." }] }

Matches and builds the same Myers diff (and Python syntax gate) but does not write or create a backup. Use when verifying a large newText before committing the change.

Match-failure diagnostics

When oldText is not found, the error includes the closest candidate region, the first differing line (expected vs actual), and whether the drift is whitespace-only. That saves a full re-read when a successive edit used stale text.

Emergency lockdown

export EDITOMATIC_STRICT=1   # exact + fuzzy only

Install

pi install npm:edit-o-matic

Project-local:

pi install npm:edit-o-matic -l

Confirm 1.1.0 or later. See CHANGELOG.md.

Recovery from backup

cp path/to/file.py.editomatic-bak path/to/file.py

| Variable | Effect | |----------|--------| | EDITOMATIC_STRICT=1 | Exact + fuzzy matching only | | EDITOMATIC_NO_BACKUP=1 | Skip sidecar backup | | EDITOMATIC_SKIP_PYTHON_CHECK=1 | Skip py_compile for .py files |

Usage

The tool registers as editomatic in Pi's tool registry.

Parameters

{
  path: string;          // Path to file (relative or absolute)
  edits: Array<{
    oldText: string;     // Text to find (whitespace-tolerant)
    newText: string;     // Replacement text ("" = delete)
  }>;
  dryRun?: boolean;      // Preview diff + syntax check; no write
}

Tips

  • Keep oldText small and unique — ambiguous matches are rejected; not-found errors include first-diff diagnostics
  • One call, multiple edits — searched against original content; applied bottom-up safely
  • After a successful edit, re-read or use updated text for further edits to the same region
  • Preserve relative indentation in multi-line blocks (critical for Python)
  • dryRun: true — verify large replacements before writing
  • Deletion — empty newText deletes matched lines; "\n" inserts a blank line

When to use editomatic vs built-in edit

| Situation | Use | |---|---| | Standard edit on well-formatted files | Built-in edit | | Models that produce indentation drift | editomatic | | Mixed tab/space files | editomatic | | Unicode drift (smart quotes, special dashes) | editomatic | | Quantized or local models | editomatic |

Indentation context injection

On before_agent_start, editomatic injects per-file indent style, short indent examples, and a Python-specific reminder that indentation is syntax. That reduces how often fallback matching is needed.

Package contents

| Path | Purpose | |---|---| | index.ts | Extension entry point | | smart-edit.ts | Matching engine + reindent | | write-safety.ts | Backup, atomic write, Python syntax gate | | test/ | Unit tests (matching, corruption regressions, write-safety) | | CHANGELOG.md | Version history and integrity notices |

Changelog

See CHANGELOG.md.

Building

npm install
npm run build
npm run check
npm test

License

MIT — LICENSE