Crust logoCrust

Development

Build your CLI with fast Bun loops, linked installs, and install-like smoke tests.

Use three loops while building a Crust CLI:

  1. run the source entry for fast iteration
  2. use bun link to test the installed command name
  3. pack and install the publish artifact to mimic a real install

Fast Local Loop

For day-to-day work, run the source entry directly:

bun run src/cli.ts --help
bun run src/cli.ts greet world
bun run check:types

If you used create-crust, bun run dev already points at src/cli.ts.

Also test the built resolver:

bun run build
./dist/cli --help

Also test the built entry:

bun run build
bun run dist/cli.js --help

Register your CLI once from the project root:

bun link

Then link it into a separate scratch project:

mkdir -p ../my-cli-smoke
cd ../my-cli-smoke
bun init -y
bun link my-cli
my-cli --help
my-cli greet world

To mimic a global command install while still pointing at your local package, use Bun's global link mode:

bun link -g my-cli
my-cli --help

bun link -g makes the command available from Bun's global bin directory, which you can inspect with bun pm bin -g.

Keep the scratch project outside your CLI repo. That helps catch accidental reliance on workspace paths or source-tree-only files.

bun link is for command ergonomics, not release validation:

  • It uses a symlink to your source tree, not the packed files users will install.
  • It can hide missing files, bin, or build output problems.
  • It does not validate staged dist/npm/ packages.

Mimic a Real Install

Use bun pm pack to test the artifact you actually plan to publish.

Pack the root package and install it into a throwaway project:

bun run build
TARBALL="$(pwd)/$(bun pm pack 2>/dev/null | tail -1)"

mkdir -p ../my-cli-install
cd ../my-cli-install
bun init -y
bun add "$TARBALL"

./node_modules/.bin/my-cli --help

To mimic a global install instead:

bun add -g "$TARBALL"
my-cli --help

If you distribute raw binaries directly, test the built resolver:

bun run build
./dist/cli --help
./dist/cli greet world

If you also publish the root package to npm, pack and install it the same way as the Bun runtime package example.

If your publish flow is crust build --package, the publish artifact is dist/npm/, not the repo root:

crust build --package
cd dist/npm/root
ROOT_TGZ="$(pwd)/$(bun pm pack 2>/dev/null | tail -1)"

cd ../darwin-arm64  # replace with your platform from dist/npm/manifest.json

echo "Root:     $ROOT_TGZ"
echo "Platform: $PLATFORM_TGZ"

Install both tarballs into a throwaway project. Replace the file: paths below with the values printed above:

mkdir -p ../my-cli-smoke
cd ../my-cli-smoke

Use the platform directory that matches your host, as listed in dist/npm/manifest.json.

  1. Write and iterate with bun run src/cli.ts ...
  2. Run bun run check:types
  3. Test the command name with bun link or bun link -g
  4. Smoke test the publish artifact with bun pm pack or staged dist/npm/ packages

On this page