Skip to content

Script Basics

This is the core concept of Bunmagic: All the utilities documented below are available as global variables in your scripts. You don’t need to import anything - just use them directly!

// No imports needed! Just use the globals:
const files = await glob("*.ts")
const choice = await select("Pick one:", files)
await $`echo "You picked ${choice}"`

All argument parsing utilities are available as global variables:

Type: string[]

Array containing all non-flag arguments passed to the script.

Examples:

// Running: my-script file1.txt file2.txt --verbose
console.log(args) // ["file1.txt", "file2.txt"]
// Accessing specific arguments
const [inputFile, outputFile] = args

Type: Record<string, string | boolean | number>

Object containing all flag arguments passed to the script.

Examples:

// Running: my-script --name=value --verbose -n 5
console.log(flags) // { name: "value", verbose: true, n: 5 }
// Conditional logic based on flags
if (flags.verbose) {
console.log("Running in verbose mode")
}

Type: { _: string[], [key: string]: any }

Combined object containing both arguments and flags in a minimist-like format.

Examples:

// Running: my-script file1.txt file2.txt --verbose
console.log(argv) // { _: ["file1.txt", "file2.txt"], verbose: true }

Usage: notMinimist(input: string[]): { flags: Record<string, string | number | boolean | undefined>, args: string[] }

Parses command line arguments into structured format with flags and arguments. Used internally to generate the global args, flags, and argv variables.

Parameters:

  • input - Array of command line argument strings

Returns:

  • Object with flags property containing parsed flags and args property containing non-flag arguments

Behavior:

  • Supports short flags (-v) and long flags (--verbose)
  • Handles flag values with equals syntax (--name=value)
  • Handles flag values with space syntax (--port 3000)
  • Automatically type casts values (strings “true”/“false” become booleans, numeric strings become integers)
  • Flags without values default to true

Examples:

// Basic flag parsing
const result = notMinimist(["--verbose", "-n", "5", "file.txt"])
console.log(result)
// { flags: { verbose: true, n: 5 }, args: ["file.txt"] }
// Equals syntax for values
const result = notMinimist(["--name=john", "--debug", "input.txt"])
console.log(result)
// { flags: { name: "john", debug: true }, args: ["input.txt"] }
// Type casting
const result = notMinimist(["--count=10", "--enabled=true", "--disabled=false"])
console.log(result)
// { flags: { count: 10, enabled: true, disabled: false }, args: [] }
// Mixed arguments and flags
const result = notMinimist(["file1.txt", "--output", "result.txt", "file2.txt", "--verbose"])
console.log(result)
// { flags: { output: "result.txt", verbose: true }, args: ["file1.txt", "file2.txt"] }

Bunmagic scripts can provide automatic help documentation using JSDoc comments. This makes your scripts self-documenting and provides built-in --help support.

Add @autohelp to your script’s JSDoc comment to enable automatic --help handling. When users run your script with the --help flag, they’ll see formatted documentation instead of the script executing.

Example:

/**
* Process and transform data files
* @autohelp
* @usage my-script <input-file> [output-file] [options]
* @flag --format <type> Output format (json, csv, xml)
* @flag --verbose Show detailed processing information
* @flag --dry-run Preview changes without writing files
* @alias transform
*/
export default async function() {
// When @autohelp is present, running "my-script --help"
// will display the documentation instead of executing this code
const [input, output = "output.json"] = args
if (flags.verbose) {
console.log(`Processing ${input}...`)
}
// ... rest of script
}
  • @autohelp - Enable automatic —help handling for the script
  • @usage <example> - Show usage examples in help output
  • @flag <name> <description> - Document command-line flags
  • @alias <name> - Create command aliases (can be used multiple times)

Type: Function

Display help information for the current script programmatically. Useful when you want custom help behavior or need to show help in response to specific conditions.

Examples:

/**
* Advanced file processor
* @usage processor <command> [options]
* @flag --config <path> Configuration file path
*/
export default async function() {
// Custom help logic
if (args.length === 0 || flags.help) {
await showHelp()
throw new Exit(0)
}
// Show help for unknown commands
const command = args[0]
if (!['process', 'validate', 'convert'].includes(command)) {
console.error(`Unknown command: ${command}\n`)
await showHelp()
throw new Exit(1)
}
// ... rest of script
}

When help is displayed (either via @autohelp or showHelp()), it shows:

  1. Script name - The command name in bold
  2. Description - Main script description from JSDoc
  3. Usage - Usage examples from @usage tags
  4. Flags - All documented flags from @flag tags
  5. Aliases - Alternative command names from @alias tags

Example output:

my-script
Process and transform data files
Usage:
my-script <input-file> [output-file] [options]
Flags:
--format <type> - Output format (json, csv, xml)
--verbose - Show detailed processing information
--dry-run - Preview changes without writing files
Aliases: transform

Type: Function

Bun’s shell API is available globally as $, allowing you to execute shell commands directly from your scripts.

Returns:

  • Promise resolving to the command output

Examples:

// Basic command execution
await $`ls -la`
// Capturing command output
const gitStatus = await $`git status`.text()
console.log(gitStatus)
// Handling command errors
try {
await $`command-that-might-fail`
} catch (error) {
console.error(`Command failed: ${error.message}`)
}
// Piping commands
await $`find . -type f -name "*.ts" | grep -v "node_modules"`

Usage: $get(...properties: Parameters<typeof $>): Promise<string>

Runs a shell command and returns the result as text, even if the command fails. Unlike the regular $ command which throws on errors, $get always returns a string containing either stdout or stderr.

Parameters:

  • ...properties - Same parameters as the $ command (template literal or command string)

Returns:

  • Promise resolving to stdout text if command succeeds, or stderr text if command fails

Examples:

// Get command output without error handling
const gitBranch = await $get`git branch --show-current`
console.log(`Current branch: ${gitBranch.trim()}`)
// Handle commands that might fail
const result = await $get`ls nonexistent-directory`
console.log(result) // Will contain error message instead of throwing
// Compare with regular $ command
try {
await $`command-that-fails` // This throws an error
} catch (error) {
console.error("Command failed")
}
// $get doesn't throw - always returns text
const output = await $get`command-that-fails` // Returns error text
console.log("Command output:", output)
// Useful for checking command availability
const which = await $get`which docker`
if (which.includes("not found")) {
console.log("Docker is not installed")
} else {
console.log(`Docker found at: ${which.trim()}`)
}

Type: class

Utility for cleanly exiting a script with an optional message.

Examples:

// Exit with a message
throw new Exit("Operation completed successfully")
// Exit with a status code
throw new Exit("Configuration error", 1)
// Exit when a condition is met
if (!await isDirectory(targetDir)) {
throw new Exit("Target directory doesn't exist")
}

Type: Function

Shorthand utility to exit with an error message.

Examples:

// Simple error exit
die("Fatal error occurred")
// Conditional exit
if (!configFile) {
die("Missing configuration file")
}
// With dynamic message
const missing = checkMissingDependencies()
if (missing.length > 0) {
die(`Missing dependencies: ${missing.join(", ")}`)
}