-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
DXChanges that improve developer experienceChanges that improve developer experiencefeatureNew functionalityNew functionality
Description
Implement CLI binary for command-line usage and configure dual-format (ESM + CJS) build output.
Rationale
The CLI enables:
- Quick dice rolls from terminal
- Scripting and automation
- Testing reproducible rolls with seeds
Dual-format build ensures compatibility with:
- Modern ESM consumers (Next.js, Vite, etc.)
- Legacy CJS consumers (older Node.js, some bundlers)
References
- PRD.md Section 6 — Project structure
- PLAN.md Phase 6 — CLI implementation details
- Bun Build docs — Dual-format bundling
Things to Consider
- Shebang: CLI needs
#!/usr/bin/env bunfor direct execution - Exit codes: 0 for success, 1 for parse errors, 2 for usage errors
- Verbose output: Show dice breakdown, not just total
- package.json bin: Must point to built CLI, not source
Implementation
Important
This is not a step-by-step guide — it's a functional checklist ordered logically.
Files to Create
-
/src/cli/args.ts— Argument parsing:interface CLIOptions { notation?: string; verbose: boolean; help: boolean; version: boolean; seed?: string; } function parseArgs(args: string[]): CLIOptions
-
/src/cli/index.ts— CLI entry point:#!/usr/bin/env bun import { parseArgs } from './args'; import { roll } from '../index'; const options = parseArgs(process.argv.slice(2)); // Handle --help, --version, then roll
-
/bin/roll-parser.ts— Bin wrapper (thin shim)
CLI Usage
# Basic usage
roll-parser 2d6+3
# Output: 11
# Verbose output
roll-parser 2d6+3 --verbose
# Output: 2d6[3,5] + 3 = 11
# Reproducible roll
roll-parser 4d6dl1 --seed "character-str"
# Output: 13
# Help
roll-parser --help
# Output: Usage: roll-parser <notation> [options]
# Options:
# --verbose, -v Show detailed roll breakdown
# --seed <seed> Use seed for reproducible rolls
# --help, -h Show this help message
# --version Show version number
# Version
roll-parser --version
# Output: 3.0.0Build Configuration
Build output structure:
dist/
├── index.mjs # ESM entry
├── index.js # CJS entry
├── index.d.ts # TypeScript declarations
└── cli.js # CLI bundle (standalone)
package.json configuration:
{
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
}
},
"bin": {
"roll-parser": "./dist/cli.js"
}
}CLI Tests
describe('CLI', () => {
it('should roll dice from argument', async () => {
const proc = Bun.spawn(['bun', 'run', 'dist/cli.js', '2d6']);
const output = await new Response(proc.stdout).text();
expect(output.trim()).toMatch(/^\d+$/);
});
it('should show verbose output with --verbose', async () => {
const proc = Bun.spawn(['bun', 'run', 'dist/cli.js', '2d6', '--verbose']);
const output = await new Response(proc.stdout).text();
expect(output).toMatch(/2d6\[.*\]/);
});
it('should produce same result with same seed', async () => {
const run = () => Bun.spawn(['bun', 'run', 'dist/cli.js', '4d6', '--seed', 'test']);
const out1 = await new Response(run().stdout).text();
const out2 = await new Response(run().stdout).text();
expect(out1).toBe(out2);
});
it('should show help with --help', async () => {
const proc = Bun.spawn(['bun', 'run', 'dist/cli.js', '--help']);
const output = await new Response(proc.stdout).text();
expect(output).toContain('Usage:');
});
it('should show version with --version', async () => {
const proc = Bun.spawn(['bun', 'run', 'dist/cli.js', '--version']);
const output = await new Response(proc.stdout).text();
expect(output.trim()).toMatch(/^\d+\.\d+\.\d+/);
});
it('should exit with code 1 on parse error', async () => {
const proc = Bun.spawn(['bun', 'run', 'dist/cli.js', 'invalid@dice']);
await proc.exited;
expect(proc.exitCode).toBe(1);
});
});Acceptance Criteria
- CLI binary works:
roll-parser 2d6 -
--help/-hshows usage information -
--versionshows package version -
--verbose/-vshows detailed roll breakdown -
--seedenables reproducible rolls - Exit code 0 on success, 1 on parse error, 2 on usage error
- Build produces ESM (
index.mjs) + CJS (index.js) + types (index.d.ts) - Package exports configured correctly for both ESM and CJS consumers
-
binfield points to working CLI - CI smoke test passes (existing workflow)
Drafted with AI assistance
Metadata
Metadata
Assignees
Labels
DXChanges that improve developer experienceChanges that improve developer experiencefeatureNew functionalityNew functionality