Build complex CLIs with type safety and no dependencies
Exit code constants for process control.
const ExitCode = {
Success: 0, // Command executed successfully
CommandRunError: 1, // Command threw error
InternalError: -1, // Framework internal error
CommandLoadError: -2, // Failed to load command module
ContextLoadError: -3, // Failed to load command context
InvalidArgument: -4, // Invalid arguments provided
UnknownCommand: -5 // Command not found
}await run(app, process.argv.slice(2), { process });
// Check exit code
if (process.exitCode === ExitCode.Success) {
console.log("✓ Success");
} else if (process.exitCode === ExitCode.InvalidArgument) {
console.error("✗ Invalid arguments");
} else if (process.exitCode === ExitCode.UnknownCommand) {
console.error("✗ Command not found");
}class BusinessError extends Error {
constructor(message: string, public exitCode: number) {
super(message);
}
}
const app = buildApplication(command, {
name: "myapp",
determineExitCode: (exc) => {
if (exc instanceof BusinessError) return exc.exitCode;
if (exc instanceof Error && exc.message.includes("timeout")) return 124;
return ExitCode.CommandRunError;
}
});
// Command that uses custom exit codes
const command = buildCommand({
func: async function() {
throw new BusinessError("Payment failed", 10);
},
parameters: {},
docs: { brief: "Process payment" }
});
await run(app, [], { process });
// process.exitCode will be 10| Code | Scenario | Example |
|---|---|---|
| 0 | Success | Command completes without error |
| 1 | Command error | Command throws or returns Error |
| -1 | Internal error | Framework bug (rare) |
| -2 | Load error | loader: () => import("./nonexistent.js") |
| -3 | Context error | forCommand throws |
| -4 | Invalid args | --port abc when expecting number |
| -5 | Unknown command | myapp unknown-cmd |
// Skip version check
STRICLI_SKIP_VERSION_CHECK=1 myapp command
// Disable colors
STRICLI_NO_COLOR=1 myapp --help
// Both
STRICLI_SKIP_VERSION_CHECK=1 STRICLI_NO_COLOR=1 myapp commandVariables:
STRICLI_SKIP_VERSION_CHECK=1: Skip automatic version checkingSTRICLI_NO_COLOR=1: Disable ANSI color output// Disable colors and version checks in CI
const isCI = process.env.CI === "true";
if (isCI) {
process.env.STRICLI_SKIP_VERSION_CHECK = "1";
process.env.STRICLI_NO_COLOR = "1";
}
await run(app, process.argv.slice(2), { process });
process.exit(process.exitCode || 0);Install with Tessl CLI
npx tessl i tessl/npm-stricli--core