{"_id":"@async/witness","_rev":"5-61adae424817e6db1e0909240df37204","name":"@async/witness","dist-tags":{"latest":"0.9.0"},"versions":{"0.5.0":{"name":"@async/witness","version":"0.5.0","_id":"@async/witness@0.5.0","maintainers":[{"name":"jackshelton","email":"me@jackshelton.com"},{"name":"async-npm","email":"async.npm@gdi2290.com"},{"name":"patrickjs","email":"npm.patrickjs@gdi2290.com"}],"//":"generated from deno.json by scripts/generate-package-json.ts — do not edit, do not commit","bin":{"witness":"dist/witness.mjs"},"dist":{"shasum":"e707e8c263b05984e2e495dbca2dd68ebdf7c5d6","tarball":"https://registry.npmjs.org/@async/witness/-/witness-0.5.0.tgz","fileCount":7,"integrity":"sha512-eOF492ZunFfMaXusd7Rv9tDMq7U8qg3temMcf8OOf5YxRuyDqpjOAknMvjB0wFAfQ3OzT2F9X9MvUzPD2IaW6A==","signatures":[{"sig":"MEUCIETKeQRCQyzeKnouBYGfMjcJfvCWGf17qItfZTV+NvbvAiEAmVLiBCdPLnhthAg+svCVbCsSxxmqWB/Y7fMXxt1o0xE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":215697},"type":"module","exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./cli":"./dist/witness.mjs"},"gitHead":"7ede7bfd4d2e78c15675d6742eeb41e2f9068b0c","_npmUser":{"name":"jackshelton","email":"me@jackshelton.com"},"_npmVersion":"11.12.1","description":"**See what your Vite pipeline actually did — with receipts.**","directories":{},"_nodeVersion":"24.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"vite":"^8.0.0"},"_npmOperationalInternal":{"tmp":"tmp/witness_0.5.0_1781672311930_0.6926658941512547","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@async/witness","version":"0.6.0","_id":"@async/witness@0.6.0","maintainers":[{"name":"jackshelton","email":"me@jackshelton.com"},{"name":"async-npm","email":"async.npm@gdi2290.com"},{"name":"patrickjs","email":"npm.patrickjs@gdi2290.com"}],"homepage":"https://github.com/async/witness#readme","bugs":{"url":"https://github.com/async/witness/issues"},"bin":{"witness":"dist/witness.mjs"},"dist":{"shasum":"0eea0497b9190e499c7baf977e6d52b0bbef2b44","tarball":"https://registry.npmjs.org/@async/witness/-/witness-0.6.0.tgz","fileCount":7,"integrity":"sha512-AA+etpHTGnXrdBiicAhhS5zdZ7a4WWyvv2inzK0azbC7TAgX24kIZ38nijrHGsCdtwaLdsnsNGceQr7q1WfvjQ==","signatures":[{"sig":"MEUCIG2nHYtDksNesZm5ZTrn05p3/NDgTu6SW1cZp1nNOQwJAiEAjsBtjqIalaqYf5kyt+aAbGjoMY7r9UowUF+uqftDdJs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":216615},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./cli":{"types":"./dist/witness.d.mts","default":"./dist/witness.mjs"},"./package.json":"./package.json"},"gitHead":"fc00b0f2b08bc0150144488e9c59e5fe66a9a97b","scripts":{"cli":"node ./dist/witness.mjs","dev":"vp test watch","fmt":"vp fmt","lint":"vp lint","test":"vp test","build":"vp pack","check":"vp check && tsc --noEmit","release":"node ./scripts/release.mjs","fmt:check":"vp fmt --check","typecheck":"tsc --noEmit","test:watch":"vp test watch","prepublishOnly":"pnpm run build"},"_npmUser":{"name":"jackshelton","email":"me@jackshelton.com"},"repository":{"url":"git+https://github.com/async/witness.git","type":"git"},"_npmVersion":"11.12.1","description":"**See what your Vite pipeline actually did — with receipts.**","directories":{},"_nodeVersion":"24.15.0","dependencies":{"mitt":"^3.0.1","pathe":"^2.0.3","tinyglobby":"~0.2.17"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@10.33.2","devDependencies":{"vite":"8.0.16","bumpp":"11.1.0","vitest":"4.1.5","vite-plus":"0.1.20","typescript":"5.9.3","@types/node":"24.12.2","changelogen":"0.6.2"},"peerDependencies":{"vite":"^8.0.0"},"_npmOperationalInternal":{"tmp":"tmp/witness_0.6.0_1781740312076_0.3741439195758054","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"@async/witness","version":"0.7.0","_id":"@async/witness@0.7.0","maintainers":[{"name":"jackshelton","email":"me@jackshelton.com"},{"name":"async-npm","email":"async.npm@gdi2290.com"},{"name":"patrickjs","email":"npm.patrickjs@gdi2290.com"}],"homepage":"https://github.com/async/witness#readme","bugs":{"url":"https://github.com/async/witness/issues"},"bin":{"witness":"dist/witness.mjs"},"dist":{"shasum":"88e52cd5ba6345bee51ba495d9fef1c638fccd7b","tarball":"https://registry.npmjs.org/@async/witness/-/witness-0.7.0.tgz","fileCount":7,"integrity":"sha512-EYJ4RG8uMl4abIgGqg/NgIOakZZwmm5J1Jb6ady9M7nY47S0GCPniHs0G0/TFN/y8ZCypMkdQum0Nl3QKdMPqg==","signatures":[{"sig":"MEQCIGV+OxdKF+ve6Mb4ZQEaA8CCBxZ1A1DmdGsllEOXu9AUAiBVsYb8BGWx3dgE+8YKMxGa01fYp4hfAy26PJHYd39aTw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":222109},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./cli":{"types":"./dist/witness.d.mts","default":"./dist/witness.mjs"},"./package.json":"./package.json"},"gitHead":"d4d0a88177fb4483601c873031e777866d8a67e0","scripts":{"cli":"node ./dist/witness.mjs","dev":"vp test watch","fmt":"vp fmt","lint":"vp lint","test":"vp test","build":"vp pack","check":"vp check && tsc --noEmit","release":"node ./scripts/release.mjs","fmt:check":"vp fmt --check","typecheck":"tsc --noEmit","test:watch":"vp test watch","prepublishOnly":"pnpm run build"},"_npmUser":{"name":"jackshelton","email":"me@jackshelton.com"},"repository":{"url":"git+https://github.com/async/witness.git","type":"git"},"_npmVersion":"11.12.1","description":"**See what your Vite pipeline actually did — with receipts.**","directories":{},"_nodeVersion":"24.15.0","dependencies":{"mitt":"^3.0.1","pathe":"^2.0.3","tinyglobby":"~0.2.17"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@10.33.2","devDependencies":{"vite":"8.0.16","bumpp":"11.1.0","vitest":"4.1.5","vite-plus":"0.1.20","typescript":"5.9.3","@types/node":"24.12.2","changelogen":"0.6.2"},"peerDependencies":{"vite":"^8.0.0"},"_npmOperationalInternal":{"tmp":"tmp/witness_0.7.0_1782073971391_0.27738585164042107","host":"s3://npm-registry-packages-npm-production"}},"0.8.0":{"name":"@async/witness","version":"0.8.0","_id":"@async/witness@0.8.0","maintainers":[{"name":"jackshelton","email":"me@jackshelton.com"},{"name":"async-npm","email":"async.npm@gdi2290.com"},{"name":"patrickjs","email":"npm.patrickjs@gdi2290.com"}],"homepage":"https://github.com/async/witness#readme","bugs":{"url":"https://github.com/async/witness/issues"},"bin":{"witness":"dist/witness.mjs"},"dist":{"shasum":"522dad4faf205ba243f4914e7c6fa78ce986d98a","tarball":"https://registry.npmjs.org/@async/witness/-/witness-0.8.0.tgz","fileCount":7,"integrity":"sha512-UsrAQB3UzLtOMPPzCVIaLbQVEN+5ejZZV9mAMqcWHqBs2vdy4lr2TMe3r2aaKVb8wL7pAM+TVBxiqpcH3kR+iA==","signatures":[{"sig":"MEQCIC/sbfbSm/It/rW2r/oLeNiqGbe01EVvCrt9Fx2P14FbAiBiPsKfriCioy+79ncGiJRG3+wbvnnvRrMYYPMe/ghArw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@async%2fwitness@0.8.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":229569},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./cli":{"types":"./dist/witness.d.mts","default":"./dist/witness.mjs"},"./package.json":"./package.json"},"gitHead":"087ab904280cf98db07c806e9007cac4425641bb","scripts":{"cli":"node ./dist/witness.mjs","dev":"vp test watch","fmt":"vp fmt","lint":"vp lint","test":"vp test","build":"vp pack","check":"vp check . !.async/** !.async-pipeline/** !.github/async-pipeline.lock.json !.github/workflows/async-pipeline.yml && tsc --noEmit","fmt:check":"vp fmt --check","typecheck":"tsc --noEmit","pack:check":"npm --cache .async/npm-cache pack --dry-run","test:watch":"vp test watch","release:check":"pnpm run pipeline:verify:force","prepublishOnly":"pnpm run build","pipeline:verify":"async-pipeline run verify","pipeline:publish":"async-pipeline run publish","pipeline:snapshot":"async-pipeline run snapshot","pipeline:task:pack":"async-pipeline run-task pack","pipeline:task:test":"async-pipeline run-task test","pipeline:sync:check":"async-pipeline sync check","pipeline:task:build":"async-pipeline run-task build","pipeline:task:check":"async-pipeline run-task check","pipeline:publish:npm":"async-pipeline publish npm --package .","pipeline:github:check":"async-pipeline github check","pipeline:test-windows":"async-pipeline run test-windows","pipeline:verify:force":"async-pipeline run verify --force","pipeline:sync:generate":"async-pipeline sync generate","pipeline:release-doctor":"async-pipeline run release-doctor","pipeline:release:doctor":"async-pipeline release doctor --package .","pipeline:release:ensure":"async-pipeline release ensure --package .","pipeline:github:generate":"async-pipeline github generate","pipeline:task:sync.check":"async-pipeline run-task sync.check","pipeline:task:github.check":"async-pipeline run-task github.check","pipeline:publish:github:main":"async-pipeline publish github main --package .","pipeline:task:release.doctor":"async-pipeline run-task release.doctor","pipeline:publish:github:release":"async-pipeline publish github release --package ."},"_npmUser":{"name":"patrickjs","email":"npm.patrickjs@gdi2290.com"},"repository":{"url":"git+https://github.com/async/witness.git","type":"git"},"_npmVersion":"11.16.0","description":"**See what your Vite pipeline actually did — with receipts.**","directories":{},"_nodeVersion":"24.18.0","dependencies":{"mitt":"^3.0.1","pathe":"^2.0.3","tinyglobby":"~0.2.17"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@10.33.2","devDependencies":{"vite":"8.0.16","vitest":"4.1.5","vite-plus":"0.1.20","typescript":"5.9.3","@types/node":"24.12.2","@async/pipeline":"0.9.23"},"peerDependencies":{"vite":"^8.0.0"},"_npmOperationalInternal":{"tmp":"tmp/witness_0.8.0_1783048121901_0.5003269904482912","host":"s3://npm-registry-packages-npm-production"}},"0.9.0":{"name":"@async/witness","version":"0.9.0","homepage":"https://github.com/async/witness#readme","bugs":{"url":"https://github.com/async/witness/issues"},"repository":{"type":"git","url":"git+https://github.com/async/witness.git"},"bin":{"witness":"dist/witness.mjs"},"type":"module","exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./cli":{"types":"./dist/witness.d.mts","default":"./dist/witness.mjs"},"./package.json":"./package.json"},"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"vp check . !.async/** !.async-pipeline/** !.github/async-pipeline.lock.json !.github/workflows/async-pipeline.yml && tsc --noEmit","cli":"node ./dist/witness.mjs","dev":"vp test watch","fmt":"vp fmt","fmt:check":"vp fmt --check","lint":"vp lint","pack:check":"npm --cache .async/npm-cache pack --dry-run","pipeline:github:check":"async-pipeline github check","pipeline:github:generate":"async-pipeline github generate","pipeline:publish":"async-pipeline run publish","pipeline:publish:github:main":"async-pipeline publish github main --package .","pipeline:publish:github:release":"async-pipeline publish github release --package .","pipeline:publish:npm":"async-pipeline publish npm --package .","pipeline:release-doctor":"async-pipeline run release-doctor","pipeline:release:doctor":"async-pipeline release doctor --package .","pipeline:release:ensure":"async-pipeline release ensure --package .","pipeline:snapshot":"async-pipeline run snapshot","pipeline:sync:check":"async-pipeline sync check","pipeline:sync:generate":"async-pipeline sync generate","pipeline:task:build":"async-pipeline run-task build","pipeline:task:check":"async-pipeline run-task check","pipeline:task:github.check":"async-pipeline run-task github.check","pipeline:task:pack":"async-pipeline run-task pack","pipeline:task:release.doctor":"async-pipeline run-task release.doctor","pipeline:task:sync.check":"async-pipeline run-task sync.check","pipeline:task:test":"async-pipeline run-task test","pipeline:test-windows":"async-pipeline run test-windows","pipeline:verify":"async-pipeline run verify","pipeline:verify:force":"async-pipeline run verify --force","prepublishOnly":"pnpm run build","release:check":"pnpm run pipeline:verify:force","test":"vp test","test:watch":"vp test watch","typecheck":"tsc --noEmit"},"dependencies":{"mitt":"^3.0.1","pathe":"^2.0.3","tinyglobby":"~0.2.17"},"devDependencies":{"@async/pipeline":"0.9.23","@types/node":"24.12.2","typescript":"5.9.3","vite":"8.0.16","vite-plus":"0.1.20","vitest":"4.1.5"},"peerDependencies":{"vite":"^8.0.0"},"engines":{"node":">=22"},"packageManager":"pnpm@10.33.2","gitHead":"5fde464ed3cb3268efca82ee26e6bb45afb55c5a","_id":"@async/witness@0.9.0","description":"**See what your Vite pipeline actually did — with receipts.**","_nodeVersion":"24.19.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-NDCPV/0pdBe2LkSp53obN+QHSw7MtHbRT0lrSGDvx2g+6gX/kpD3ITlwPovsKY8NDQdOjzKtBCxYbkYzlRBZHw==","shasum":"c31e7bafa63c43f9baa7e83e5873caf977607b88","tarball":"https://registry.npmjs.org/@async/witness/-/witness-0.9.0.tgz","fileCount":7,"unpackedSize":249492,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@async%2fwitness@0.9.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHtfKv9G0HchiaBxsZ20U255KSg5lyoJK20K0WB8CIAWAiAzSrhvDZY3u35ZBaOpRCUIj6F/6HyDW5lT2NihSu6kmA=="}]},"_npmUser":{"name":"patrickjs","email":"npm.patrickjs@gdi2290.com"},"directories":{},"maintainers":[{"name":"jackshelton","email":"me@jackshelton.com"},{"name":"async-npm","email":"async.npm@gdi2290.com"},{"name":"patrickjs","email":"npm.patrickjs@gdi2290.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/witness_0.9.0_1787366918692_0.9463293256705887"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-17T04:58:31.706Z","modified":"2026-08-22T02:48:39.208Z","0.5.0":"2026-06-17T04:58:32.059Z","0.6.0":"2026-06-17T23:51:52.239Z","0.7.0":"2026-06-21T20:32:51.520Z","0.8.0":"2026-07-03T03:08:42.034Z","0.9.0":"2026-08-22T02:48:38.856Z"},"bugs":{"url":"https://github.com/async/witness/issues"},"homepage":"https://github.com/async/witness#readme","repository":{"type":"git","url":"git+https://github.com/async/witness.git"},"description":"**See what your Vite pipeline actually did — with receipts.**","maintainers":[{"name":"jackshelton","email":"me@jackshelton.com"},{"name":"async-npm","email":"async.npm@gdi2290.com"},{"name":"patrickjs","email":"npm.patrickjs@gdi2290.com"}],"readme":"# Async Witness\n\n**See what your Vite pipeline actually did — with receipts.**\n\nRestart, hard-refresh, `console.log`, pray 🙏 — Vite knew what happened the whole time, it\njust never told you. Async Witness runs your real pipeline and writes a **receipt** for every run:\nproof you, CI, or an AI agent can act on.\n\n> ⚠️ **Early release** — the [specs](./specs/README.md) are the product truth.\n> Designed by Jack, implemented by **Mythos**, reviewed by **Codex**.\n\n## A box in 30 seconds\n\nA **box** is a small file that runs inside your real Vite pipeline and asserts what the\npipeline did, in the pipeline's own vocabulary:\n\n```ts\nimport { box } from '@async/witness';\n\nexport default box('message updates without reload', async ({ browser, project, expect }) => {\n\t// Visit a real route — this auto-starts your real Vite dev server.\n\tconst page = await browser.visit('/demo');\n\n\t// Edit a real source file, like a developer saving in their editor.\n\tconst change = await project.edit('src/message.ts', {\n\t\treplace: ['before', 'after'],\n\t});\n\n\t// Declare what Vite should have done about it.\n\tawait expect.edit(change, {\n\t\tclient: { hmr: 'accepted' }, // hot update applied, no full reload\n\t});\n\n\t// Confirm the browser actually shows the new text.\n\tawait expect.page.text(page, '#message', 'after');\n});\n```\n\n```sh\nwitness hmr\n```\n\nAsync Witness runs the box, restores the edited file, and writes a receipt to `.witness/receipts/` —\npass or fail, human- and machine-readable. If the box fails, the receipt explains _why_ in\nVite's own terms: what payload Vite sent, whether the server restarted, what the console said.\n\n<p align=\"center\">\n  <img src=\"./assets/box-flow.svg\" alt=\"you edit src/message.ts → your real Vite pipeline (dev server, HMR, SSR, build) → receipt.json: hmr accepted, 0 reloads\" width=\"780\" />\n</p>\n\n## What a box can prove\n\n- A route renders with every asset loaded and a clean console\n- A user-made UI state — clicked, typed, hovered, key-pressed, dragged, or scrolled into — survives an edit, with every interaction recorded as receipt evidence\n- An edit hot-updated, full-reloaded, or silently did nothing — per environment\n- A server-only edit left the browser alone\n- A config edit restarted the server with the new plugin active\n- SSR renders and hydrates without console errors\n- The **built** app behaves like dev (build + preview parity)\n- Artifacts are right — manifest entries, no stale placeholders, no `node:fs` in worker bundles\n- A workflow stayed inside a performance budget\n\n## Every receipt has witnesses\n\nAssertions only answer the questions you thought to ask. The interesting failures live in what\nyou didn't ask about — the console error that didn't break your selector, the request that\ndied while the page still rendered, the full reload that happened to land on the right text\nanyway. Async Witness treats a box run like a case: the receipt is the case file, and everyone who\nobserved the run testifies in it.\n\nThree witnesses watch every browser box from different vantage points. The **pipeline**\nwitness is Vite's server side — it knows what hot payloads were actually sent, whether the\nserver restarted, what each environment did with your edit. The **client** witness is the page\nitself — its console, its uncaught errors, the custom events your framework fired. The\n**driver** witness watches from outside the page over CDP — failed requests with their real\n`net::ERR_*` reasons, navigations the page can't hide, the screenshots. None of them can see\nwhat the others see, which is the point: they corroborate or contradict each other\nindependently.\n\nEach witness gets a verdict on every box. When a box passes but a witness holds evidence\nagainst the run, the pass is marked **contested**:\n\n```\npass noisy page records console and network evidence  [pipeline+ client! driver!]  contested\n     client reported: 1 console error   driver reported: 1 failed request\n```\n\nEvery assertion passed here. The page also logged an error and a request died — facts no\nassertion asked about, preserved instead of swallowed. That's the gap between \"tests pass\" and\n\"the app is fine\", made visible on every run.\n\nCross-examine any box straight from a stored receipt:\n\n```sh\nwitness evidence 'noisy page'\n```\n\n```\ncrimes reported (2):\n  ! console error   Failed to load resource: net::ERR_ABORTED   — reported by client\n  ! request failed  GET http://127.0.0.1:5173/missing.js        — reported by driver\n```\n\nWitness identity and verdicts are plain data in the receipt JSON — stable, greppable, safe for\nCI and agents to consume. Color is just how your terminal paints them.\n\n## Why not Vitest / Playwright / Storybook?\n\nThey're great at what they own — but they see the **page**, not the **pipeline** that produced\nit. That gap is how \"all tests pass\" and \"the app is broken\" happen at the same time. Async Witness\nowns the pipeline: the chain from an edit to a Vite environment event to what you see, with a\nreceipt preserving the whole story.\n\nThere's no automation framework underneath, either. Async Witness drives the browser itself over the\nChrome DevTools Protocol — a couple thousand lines of WebSocket and JSON it owns outright,\nzero dependencies. One pooled browser serves the whole run and every box gets its own isolated\nbrowser context, the same architecture playwright uses internally, which is how witness ended\nup faster per test than playwright-core on every platform CI measures.\n\n## Bring your own browser\n\nAsync Witness drives a Chromium-family browser already on your machine over the Chrome DevTools\nProtocol — no playwright dependency, no download at install time. Discovery order:\n\n1. `WITNESS_BROWSER_PATH` — explicit override. If it's set but doesn't point at an executable,\n   discovery fails with an error instead of silently falling through to another browser.\n2. System installs of Chrome, Edge, or Chromium, in the usual per-OS locations.\n3. Playwright's browser cache as a courtesy fallback (`~/Library/Caches/ms-playwright` on\n   macOS, `$XDG_CACHE_HOME` or `~/.cache/ms-playwright` on Linux,\n   `%LOCALAPPDATA%\\ms-playwright` on Windows) — full `chromium-<revision>` downloads only,\n   newest first, the headless shell is skipped.\n\nmacOS, Linux, and Windows are all exercised in CI. When nothing is found, witness fails with\nthe exact paths it checked.\n\n## Docs\n\n- **[Specs](./specs/README.md)** — product direction and the source of truth\n\n## Status\n\nBuilt in slices. Box authoring, dev/build/preview runs, browser evidence, witness verdicts\nwith the `witness evidence` drill-down, the CLI, and JSON receipts work today. The\nstate-gallery UI, generated types, and receipt replay are coming.\n\n## Contributing\n\nThe workspace runs on **pnpm** (the library itself is runtime-agnostic — it runs wherever Vite\nruns):\n\n```sh\npnpm install        # install dependencies\npnpm run test       # run the test suite (drives real Vite pipelines)\npnpm run check      # format check + lint + typecheck\n```\n\nSee [CONTRIBUTING.md](./CONTRIBUTING.md) for the full setup. Start with\n[`specs/`](./specs/README.md) for intent, and `.ruler/` for the working agreements.\n","readmeFilename":"README.md"}