Skip to main content Accueil Créateurs joelhooks swarm-tools cli-builder
cli-builder Guide for building TypeScript CLIs with Bun. Use when creating command-line tools, adding subcommands to existing CLIs, or building developer tooling. Covers argument parsing, subcommand patterns, output formatting, and distribution.
Aller à l'installation Skills Marketplace Découvrez et explorez les compétences IA créées par la communauté.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Copier le promptAfficher les détails du prompt Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
npx skills add https://github.com/joelhooks/swarm-tools --skill cli-builderLa commande reste sur une seule ligne. Faites défiler horizontalement pour la vérifier avant de la copier.
Vous préférez une copie locale ? Téléchargez les fichiers actuellement disponibles dans SkillsMP.
Télécharger Zip Téléchargement... Send messages, system events, and agent notifications through the openclaw CLI. Use when an agent needs to notify a user (Telegram, Slack, Discord), trigger another agent, broadcast updates, send system events, or coordinate agent-to-agent communication via swarmmail. Covers all three messaging layers - external channels, agent invocation, and internal swarmmail.
Handles version bumps and npm releases for the swarm-tools monorepo (opencode-swarm-plugin,
claude-code-swarm-plugin, swarm-mail, swarm-queue). Use when: creating changesets, bumping
versions, preparing releases, checking release status, debugging publish failures, verifying
npm packages, or merging release PRs.
Triggers: "release", "publish", "changeset", "bump version", "ship it", "new version",
"create a release", "check npm", "verify publish", "/release"
Métiers associés SOC
Basé sur la classification professionnelle SOC
Explorateur de fichiers
2 fichiers name cli-builder description Guide for building TypeScript CLIs with Bun. Use when creating command-line tools, adding subcommands to existing CLIs, or building developer tooling. Covers argument parsing, subcommand patterns, output formatting, and distribution. tags ["cli","typescript","bun","tooling"]
CLI Builder
Build TypeScript command-line tools with Bun.
When to Build a CLI
CLIs are ideal for:
Developer tools and automation
Project-specific commands (swarm, bd, etc.)
Scripts that need arguments/flags
Tools that compose with shell pipelines
Quick Start
Minimal CLI
#!/usr/bin/env bun
const args = process.argv .slice (2 );
const command = args[0 ];
if (!command || command === "help" ) {
console .log (`
Usage: my-tool <command>
Commands:
hello Say hello
help Show this message
` );
process.exit (0 );
}
if (command === "hello" ) {
. ( );
}
console
log
"Hello, world!"
Run with: bun scripts/my-tool.ts hello
With Argument Parsing Use parseArgs from Node's util module (works in Bun):
#!/usr/bin/env bun
import { parseArgs } from "util" ;
const { values, positionals } = parseArgs ({
args : process.argv .slice (2 ),
options : {
name : { type : "string" , short : "n" },
verbose : { type : "boolean" , short : "v" , default : false },
help : { type : "boolean" , short : "h" , default : false },
},
allowPositionals : true ,
});
if (values.help ) {
console .log (`
Usage: greet [options] <message>
Options:
-n, --name <name> Name to greet
-v, --verbose Verbose output
-h, --help Show help
` );
process.exit (0 );
}
const message = positionals[0 ] || "Hello" ;
const name = values.name || "World" ;
console .log (`${message} , ${name} !` );
if (values.verbose ) {
console .log (` (greeted at ${new Date ().toISOString()} )` );
}
Subcommand Pattern For CLIs with multiple commands, use a command registry:
#!/usr/bin/env bun
import { parseArgs } from "util" ;
type Command = {
description : string ;
run : (args : string [] ) => Promise <void >;
};
const commands : Record <string , Command > = {
init : {
description : "Initialize a new project" ,
run : async (args) => {
const { values } = parseArgs ({
args,
options : {
template : { type : "string" , short : "t" , default : "default" },
},
});
console .log (`Initializing with template: ${values.template} ` );
},
},
build : {
description : "Build the project" ,
run : async (args) => {
const { values } = parseArgs ({
args,
options : {
watch : { type : "boolean" , short : "w" , default : false },
},
});
console .log (`Building...${values.watch ? " (watch mode)" : "" } ` );
},
},
};
function showHelp ( ) {
console .log (`
Usage: mytool <command> [options]
Commands:` );
for (const [name, cmd] of Object .entries (commands)) {
console .log (` ${name.padEnd(12 )} ${cmd.description} ` );
}
console .log (`
Run 'mytool <command> --help' for command-specific help.
` );
}
const [command, ...args] = process.argv .slice (2 );
if (!command || command === "help" || command === "--help" ) {
showHelp ();
process.exit (0 );
}
const cmd = commands[command];
if (!cmd) {
console .error (`Unknown command: ${command} ` );
showHelp ();
process.exit (1 );
}
await cmd.run (args);
Output Formatting
Colors (without dependencies) const colors = {
reset : "\x1b[0m" ,
red : "\x1b[31m" ,
green : "\x1b[32m" ,
yellow : "\x1b[33m" ,
blue : "\x1b[34m" ,
dim : "\x1b[2m" ,
bold : "\x1b[1m" ,
};
function success (msg : string ) {
console .log (`${colors.green} ✓${colors.reset} ${msg} ` );
}
function error (msg : string ) {
console .error (`${colors.red} ✗${colors.reset} ${msg} ` );
}
function warn (msg : string ) {
console .log (`${colors.yellow} ⚠${colors.reset} ${msg} ` );
}
function info (msg : string ) {
console .log (`${colors.blue} ℹ${colors.reset} ${msg} ` );
}
JSON Output Mode Support --json for scriptable output:
const { values } = parseArgs ({
args : process.argv .slice (2 ),
options : {
json : { type : "boolean" , default : false },
},
allowPositionals : true ,
});
const result = { status : "ok" , items : ["a" , "b" , "c" ] };
if (values.json ) {
console .log (JSON .stringify (result, null , 2 ));
} else {
console .log ("Status:" , result.status );
console .log ("Items:" , result.items .join (", " ));
}
Progress Indicators function spinner (message : string ) {
const frames = ["⠋" , "⠙" , "⠹" , "⠸" , "⠼" , "⠴" , "⠦" , "⠧" , "⠇" , "⠏" ];
let i = 0 ;
const id = setInterval (() => {
process.stdout .write (`\r${frames[i++ % frames.length]} ${message} ` );
}, 80 );
return {
stop : (finalMessage ?: string ) => {
clearInterval (id);
process.stdout .write (`\r${finalMessage || message} \n` );
},
};
}
const spin = spinner ("Loading..." );
await someAsyncWork ();
spin.stop ("✓ Done!" );
File System Operations import { readFile, writeFile, mkdir, readdir } from "fs/promises" ;
import { existsSync } from "fs" ;
import { join, dirname } from "path" ;
async function writeFileWithDir (path : string , content : string ) {
await mkdir (dirname (path), { recursive : true });
await writeFile (path, content);
}
async function readJsonFile<T>(path : string , defaults : T): Promise <T> {
if (!existsSync (path)) return defaults;
const content = await readFile (path, "utf-8" );
return { ...defaults, ...JSON .parse (content) };
}
Shell Execution import { $ } from "bun" ;
const result = await $`git status` .text ();
try {
await $`npm test` .quiet ();
console .log ("Tests passed!" );
} catch (error) {
console .error ("Tests failed" );
process.exit (1 );
}
const branch = await $`git branch --show-current` .text ();
console .log (`Current branch: ${branch.trim()} ` );
Error Handling class CLIError extends Error {
constructor (message : string , public exitCode = 1 ) {
super (message);
this .name = "CLIError" ;
}
}
async function main ( ) {
try {
await runCommand ();
} catch (error) {
if (error instanceof CLIError ) {
console .error (`Error: ${error.message} ` );
process.exit (error.exitCode );
}
throw error;
}
}
main ();
Distribution
package.json bin field {
"name" : "my-cli" ,
"bin" : {
"mycli" : "./dist/cli.js"
} ,
"scripts" : {
"build" : "bun build ./src/cli.ts --outfile ./dist/cli.js --target node"
}
}
Shebang for direct execution Make executable: chmod +x scripts/my-cli.ts
Best Practices
Always provide --help - Users expect it
Exit codes matter - 0 for success, non-zero for errors
Support --json - For scriptability and piping
Fail fast - Validate inputs early
Be quiet by default - Use --verbose for noise
Respect NO_COLOR - Check process.env.NO_COLOR
Stream large output - Don't buffer everything in memory