Dev Tooling
package.json scripts fallback
3va <name> runs package.json.scripts.<name> (via the project’s actual
package manager — pnpm/yarn/bun/npm, detected by lockfile) whenever
<name> isn’t one of 3va’s own subcommands — the same convention
npm run <name> / pnpm <name> follow:
3va build # not a 3va subcommand → runs `pnpm run build` (or npm/yarn/bun)Built-in subcommands always win: 3va dev / 3va test / etc. run 3va’s own
implementation, never a same-named script.
This is not sandboxed — the delegated script is a real external process
(the actual package manager, running arbitrary shell), completely outside
the permissions system’s capability model (which only governs JS executed
inside 3va’s own V8 engine; internally this lives in the vvva_permissions
crate). Consistent with 3va install never running postinstall scripts,
running it requires explicit consent: a [y/N] prompt in a TTY, --yes to
skip it, "3va": { "no-prompt": true } in package.json to skip it
permanently, or a hard deny with no prompt at all outside a TTY (CI, pipes).
Test runner
Jest-compatible. No configuration required.
3va test
3va test tests/unit
3va test --watch
3va test --coverage
3va test --update-snapshotsSupports describe, test, expect, watch mode, coverage reporting, and
these matchers: toBe, toEqual, toStrictEqual, toBeNull,
toBeUndefined, toBeDefined, toBeTruthy, toBeFalsy,
toBeGreaterThan(OrEqual), toBeLessThan(OrEqual), toContain,
toHaveLength, toMatch, toThrow, toMatchSnapshot, and
toMatchInlineSnapshot. Implemented in the vvva_test crate — no Jest
install needed.
Not implemented: mocks/spies (jest.fn(), toHaveBeenCalled(With)),
toBeCloseTo, toMatchObject, toHaveProperty, toBeInstanceOf,
toBeNaN, toContainEqual, and resolves/rejects. If your test suite
depends on mocking, it isn’t portable to 3va test yet.
Bundler
3va bundle src/index.ts
3va bundle src/index.ts -o dist/bundle.js --minifyWalks the real import graph from the entry — project files, node_modules
(both ESM and CommonJS packages), .json, and .css — and inlines
everything into one self-contained file, runnable standalone via
3va run dist/bundle.js or in a browser <script> tag. .css imports
inject a <style> tag when a DOM is present (browser) and no-op otherwise
(CLI/server); asset imports (images, fonts) embed the original path as a
string, not a copied/hashed file — there’s no production asset pipeline yet.
The output directory is created automatically if it doesn’t exist.
--minify works. --source-map and --split are not implemented for
this path — see Roadmap. For automatic rebuilds on change, use
3va dev (watches and rebuilds with a 300 ms debounce) — it also serves the
project directly via on-demand transpilation without needing a full bundle
at all.
Dev server with HMR
3va dev
3va dev --port 3000 --host 0.0.0.0 --openAutomatically detects the project framework (Next.js, Astro, Nuxt, SvelteKit, Remix, Gatsby, SolidStart, Qwik, RedwoodJS) and delegates to its native dev server. For custom/unrecognized setups, runs a built-in dev server:
- On-demand ESM serving (Vite-style) — a root-level
index.htmlreferencing<script type="module" src="/src/main.jsx">works directly:.js/.jsx/.ts/.tsxfiles are transpiled per request (JSX/TS stripped via oxc) and their import specifiers rewritten so the browser’s native ES module loader can resolve them — project-relative imports stay project-relative, bare specifiers ("react") and anything undernode_modulesresolve to/@fs/<path>.import "./x.css"is wrapped in a tiny style-injecting module;.cssrequested directly (a<link>tag) is served as-is. - A full bundle to
dist/bundle.jsstill runs on start and on every source change (300 ms debounce) — served at/bundle.js, useful for a hand-rolledpublic/index.htmlthat references it directly. - SPA fallback checks
public/index.html, then a root-levelindex.html, then a built-in default page.
HMR is full-page reload via Server-Sent Events (/__hmr), not granular
per-module hot replacement — see Roadmap. Two Ctrl+C within the
30s drain window force an immediate shutdown, useful since a browser tab’s
open /__hmr connection otherwise keeps the server “draining” for the full
timeout.
CPU profiler
3va run app.ts --prof # writes profile.cpuprofile
3va run app.ts --prof --flamegraph=flame.svg # also emit SVG flamegraph
3va prof profile.cpuprofile --top 20 # post-hoc analysisOutput is V8-compatible .cpuprofile JSON, loadable in Chrome DevTools and
speedscope.app . Flamegraphs use the Inferno
format.
Debugger
3va run app.ts --inspect # CDP on 127.0.0.1:9229
3va run app.ts --inspect=0.0.0.0:9230Opens a WebSocket CDP server. Connect via chrome://inspect or any
DAP-compatible IDE. debugger; statements pause execution and emit
Debugger.paused CDP events.
Interactive sandbox
3va sandboxREPL with permission management. Inside the session: .allow-read=PATH,
.allow-write=PATH, .allow-net=HOST, .allow-env, and .permissions to
list current grants. Leave with exit, quit, or ^D.
Other commands
3va doctor # environment health check
3va --accessible # EN 301 549 mode: no ANSI, no animations, screen-reader friendly