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

vite-plugin-agent-quiet

v1.0.0

Published

Pause Vite's HMR during AI-agent edit bursts. Coalesce many edits into one reload.

Readme

vite-plugin-agent-quiet

Pause Vite's HMR during AI-agent edit bursts. Coalesce many edits into one reload.

npm version npm downloads CI license

Status: v1. Plugin is small (~110 LOC core) and stable. Claude Code hooks are tested; Cursor and Aider configs are community-contributed placeholders.


The problem

AI coding agents (Claude Code, Cursor, Aider, Codex, Continue) edit codebases in bursts — often 5 to 20 writes within a few seconds. Vite's HMR was designed for a human cadence: one save, an incremental update, a stable intermediate state. When edits arrive faster than HMR can settle, the dev server runs overlapping cycles against a temporarily inconsistent dependency graph.

Concretely, here's a 4-file 2-second agent burst on a vanilla Vite setup:

t=0.0s   Edit Button.tsx     → HMR cycle 1
t=0.4s   Edit Modal.tsx      → HMR cycle 2
t=0.9s   Edit store.ts       → HMR cycle 3 (full reload — store edit)
t=1.3s   Edit hooks.ts       → HMR cycle 4
                             ↳ flashing errors, lost component state, wasted rebuild work

Four reload cycles for one logical change. The middle cycles fire while the graph is half-rewritten — the kind of state a human editor never produces, so HMR has no special handling for it.

The solution

A filesystem sentinel acts as a mutex between the agent and Vite. The agent creates .agent-editing before its first write and removes it after its last. The plugin watches that file and pauses HMR while it exists.

The same burst with the plugin installed:

t=0.0s   sentinel up, edits 1–4 swallowed and queued
t=2.0s   sentinel down → 1 full-reload, queue drained

One reload, applied to a stable post-burst snapshot. No flashing, no half-state.

The mechanism is small on purpose. The plugin watches for one file, polls every 250ms, and emits exactly one full-reload when the file disappears. Stale sentinels are auto-recovered after a configurable timeout.

Install

yarn add -D vite-plugin-agent-quiet
// vite.config.ts
import { defineConfig } from 'vite';
import agentQuiet from 'vite-plugin-agent-quiet';

export default defineConfig({
  plugins: [agentQuiet()],
});

That's the whole plugin install. The agent side needs hooks — see the next section.

Minimal setup

Plugin only

The snippet above. The plugin is a no-op in build mode (apply: 'serve'), so it ships zero overhead to production.

With Claude Code

Drop the examples/claude-code/.claude/settings.json into your project root and add .agent-editing to .gitignore. The example's README walks through verification.

Agent hook examples

| Agent | Example | Status | |---|---|---| | Claude Code | examples/claude-code/ | Tested. Three-hook config covers PreToolUse, Stop, SubagentStop. | | Cursor | examples/cursor/ | Placeholder. PRs welcome. | | Aider | examples/aider/ | Placeholder. PRs welcome. | | Custom / shell wrapper | examples/manual/ | Tested pattern with trap ... EXIT for signal-safe cleanup. |

The plugin itself is agent-agnostic. As long as something creates the sentinel before the burst and removes it after, the plugin works.

How it works

The plugin maintains a small state machine around one filesystem primitive: the sentinel file.

  1. Agent hooks create .agent-editing before the burst (touch .agent-editing) and remove it after (rm -f .agent-editing).
  2. handleHotUpdate sees the sentinel and returns [], which tells Vite to skip HMR for that file. The changed path is added to an in-memory Set so we don't double-count repeated edits to the same file.
  3. A 250ms poller watches for the sentinel's removal. When it disappears, the plugin emits exactly one { type: 'full-reload' } over the dev server's WebSocket and clears the queue.
  4. Staleness is tracked via mtime. If the sentinel sits longer than staleMs (default 60s) without being touched, it's treated as abandoned: the plugin unlinks it and flushes whatever was queued. This is the recovery path for crashed or interrupted agents.

The whole thing is about 110 lines. See src/index.ts if you want the full picture.

Options

| Option | Default | Description | |---|---|---| | sentinel | .agent-editing | Sentinel filename, resolved relative to Vite root. | | staleMs | 60_000 | Treat the sentinel as dead after this many ms without modification. | | log | true | Print one line per resume: [agent-quiet] coalesced N edits → 1 reload. |

agentQuiet({
  sentinel: '.my-agent.lock',
  staleMs: 30_000,
  log: false,
});

FAQ

Why a file instead of an IPC socket or in-process API? A sentinel file is agent-agnostic and has zero coupling. Any agent or shell script that can run touch and rm works — no plugin-specific protocol, no version-matching, no language bindings. Sockets and named pipes would lock the plugin to one ecosystem.

Why not just use server.watch.ignored? That ignores files permanently. We need dynamic pause/resume — HMR works normally while you edit by hand, and only pauses during agent bursts.

What if my agent crashes mid-edit? The staleMs timeout (default 60s) takes over: the next poll tick unlinks the abandoned sentinel and flushes any queued edits with one full-reload.

Does this affect production builds? No. The plugin is apply: 'serve', so it isn't even loaded during vite build.

Does it work with Next.js / Remix / SvelteKit? Only with Vite-based setups currently. Next.js uses Turbopack/Webpack; Remix has both Vite and non-Vite variants. The plugin hooks into Vite's handleHotUpdate, so anything not built on Vite is out of scope.

Will this slow down normal HMR when no agent is editing? The only added work is one statSync call per HMR event. Sub-millisecond. The poller is a 250ms setInterval that does one statSync per tick.

What about my framework's HMR (Vue / Svelte / React Fast Refresh)? Works fine. The plugin intercepts at Vite's level, before framework-specific HMR runs. Framework HMR happens downstream of handleHotUpdate, so when the plugin passes through, the framework's machinery is untouched.

What about monorepos? The sentinel is resolved relative to each Vite root, so if you run multiple Vite servers in one repo each gets its own sentinel — but the agent hooks touch only one filename. Either set sentinel per-package (e.g. .agent-editing-web, .agent-editing-admin) and use multiple hook entries, or accept that one touch pauses all of them simultaneously. The second option is usually fine and is what we run.

Benchmarks

Workload: 8 file edits over 1.1 seconds (mimicking an agent burst), then a 2-second settle window. Cycles are counted by spying on server.ws.send for update and full-reload payloads.

| | Without plugin | With plugin | |---|---|---| | HMR cycles | 8 | 1 |

One reload instead of eight, for the same set of edits. Run it yourself with yarn benchmark — the script is at benchmark/hmr-cycles.ts. Measured on Node 23, macOS, Vite 6.4. Numbers will vary by host.

Comparison

| Approach | Coalesces edits | Auto-recovers | Works during agent turn | Setup | |---|---|---|---|---| | vite-plugin-agent-quiet | ✅ | ✅ | ✅ | One plugin + agent hooks | | server.watch.ignored | ❌ permanently | n/a | ❌ | Vite config edit | | server.hmr: false | ❌ entirely | n/a | ❌ | Vite config edit | | Do nothing | ❌ | n/a | ❌ | n/a |

Contributing

Bug reports and PRs are welcome. The Cursor and Aider example folders are placeholders — if you use those tools and get a config working, please open a PR.

  • Commits follow Conventional Commits (feat:, fix:, docs:, etc.).
  • Run yarn test before pushing. Unit + integration tests should be green.
  • For non-trivial changes, open an issue first to align on scope before writing code.

License

MIT