@anvil-di/anvil-cli
v0.0.4
Published
Native binary launcher for the anvil codegen CLI. Resolves the right per-platform package at runtime; mirrors esbuild's distribution model.
Readme
@msulak/anvil-cli
Native binary launcher for @msulak/anvil — installs the right prebuilt CLI for your platform, exposes it as an anvil command, and provides a programmatic API for tooling that needs to invoke codegen (like @msulak/anvil-unplugin).
Install
npm install -D @msulak/anvil-cli # adds the launcher + npm picks one platform package
pnpm add -D @msulak/anvil-cli # pnpm honors optionalDependencies by default
yarn add -D @msulak/anvil-cli # yarn honors optionalDependencies by defaultThe @msulak/anvil-cli package itself ships zero binaries. Its optionalDependencies field lists every supported platform; npm's os/cpu filtering installs exactly one of them (the one matching your machine). The CLI binary lives inside that platform package.
Use as a command
npx anvil build --entry src/app-component.ts
npx anvil check --entry src/app-component.ts
npx anvil watch --entry src/app-component.ts
npx anvil explain --entry src/app-component.tsThe anvil shim in node_modules/.bin resolves the per-platform package, then spawnSyncs the real binary with your argv pass-through.
Use programmatically
import { resolveBinaryPath, unresolvableBinaryError } from "@msulak/anvil-cli";
const binary = resolveBinaryPath();
if (binary === null) {
throw new Error(unresolvableBinaryError());
}
// `binary` is an absolute path you can pass to execFile / spawn.This is what @msulak/anvil-unplugin uses by default. Any tooling that needs the same "find my platform's binary" lookup can use the same API.
Resolution order
resolveBinaryPath() checks, in order:
ANVIL_CLI_BINenv var — if it points at an existing file, that file wins. Useful for tests, monorepo dev (point attarget/release/anvil), and CI that builds from source.require.resolve("@msulak/anvil-cli-<platform>-<arch>")— the per-platform npm package corresponding to the current Node process.
If neither resolves, the function returns null and unresolvableBinaryError() produces a human-readable message diagnosing why (unsupported platform, optional deps skipped during install, etc.).
Supported platforms
| Platform | Arch | Package |
|---|---|---|
| Linux | x64 | @msulak/anvil-cli-linux-x64 |
| Linux | arm64 | @msulak/anvil-cli-linux-arm64 |
| macOS | x64 (Intel) | @msulak/anvil-cli-darwin-x64 |
| macOS | arm64 (Apple Silicon) | @msulak/anvil-cli-darwin-arm64 |
| Windows | x64 | @msulak/anvil-cli-win32-x64 |
Need another? Open an issue, or build from source:
git clone https://github.com/msulak13/tsdi
cd tsdi
cargo build --release -p anvil-cli
export ANVIL_CLI_BIN=$PWD/target/release/anvilHow releases work
The repo's release-cli.yml GitHub Actions workflow builds the binary on each native runner (linux-x64, linux-arm64 via cross, macos-13, macos-14, windows-latest) and publishes the matching @msulak/anvil-cli-<platform>-<arch> package along with the launcher. The launcher's optionalDependencies are pinned to the same version, so a single npm install @msulak/anvil-cli@<version> always pulls a coherent set.
Why this layout
esbuild popularized this pattern because it sidesteps every alternative's failure modes:
- No
postinstallbuild step — no Rust toolchain on user machines, no opaque "compiling…" delay duringnpm install. - No giant universal binary in the launcher —
npm install @msulak/anvil-clidownloads ~4MB, not ~25MB times five. - No conditional logic in the launcher's
package.json— npm does the platform filtering for us viaos/cpu. - Hash-pinned reproducibility — every install gets the exact binary CI built; nothing is recompiled on the user's machine.
