@bro-code/cli
v2026.6.0
Published
A CLI toolkit for orchestrating Node.js monorepo projects — dependency management, dev servers, database operations, environment setup, and more.
Maintainers
Readme
@bro-code/cli
A CLI toolkit for orchestrating Node.js monorepo projects — dependency management, dev servers, database operations, environment setup, and more. Powered by @bro-code/tasks and @bro-code/logger.
Installation
npm install @bro-code/cliPrerequisites
Optional external tools that enable specific features:
SSL Certificate Generation
mkcert — Required for bc ssl, and for SSL setup in bc dev/bc setup when cli.ssl.enabled is true.
SSL is off by default: bc dev/bc setup only make certificates for apps that set cli.ssl.enabled: true, and if mkcert is not installed then, they skip it with a warning. bc ssl always makes them.
Installation:
- Windows (Chocolatey):
choco install mkcert - macOS (Homebrew):
brew install mkcert - Linux: See mkcert installation docs
Database Operations
pg — Required for PostgreSQL database operations (bc db, database creation in setup).
Install in your project:
npm install pgUsing the CLI
After installing, the package provides two binary commands: bro and bc (shorthand). Both are identical.
Via npm scripts (recommended)
Add commands to your project's package.json:
{
"scripts": {
"dev": "bro dev",
"clean": "bro clean",
"setup": "bro setup",
"migrate": "bro migrate"
}
}Then run them with npm run:
npm run dev
npm run clean
npm run setupnpm automatically resolves bro from node_modules/.bin when running scripts.
Via npx
npx bro dev
npx bc clean server clientGlobal install
Install globally to use bro and bc anywhere without npx:
npm install -g @bro-code/cli
bro dev
bro clean server
bc migrate deployTo update a global install:
npm update -g @bro-code/cliBuilt-in Commands
bro setup [projects...] Full project setup (deps, env, ssl, db, migrate)
bro install [projects...] [d=pkg1,pkg2] [D=dev] Install dependencies across projects
bro uninstall [projects...] d=pkg1,pkg2 Remove dependencies from projects
bro clean [projects...] Remove node_modules and lock files
bro kill [--inside|--outside] [port=<n>[,<n>]] Kill Node.js processes with their process trees
bro wipe Wipe infrastructure (db, .env, ssl, migrations)
bro nuke [dev] Clean and wipe everything, optionally run dev
bro dev [server] [client] [client=N] Run setup then start dev servers
bro dev [args...] With cli.dev.command: run setup, then the command with args
bro fresh [projects...] Clean everything and run dev from scratch
bro start [server] [client] [client=N] Start dev servers with staggered startup
bro start [args...] With cli.dev.command: run the command with args, no setup
bro env Generate a .env file interactively
bro ssl Generate local SSL certificates via mkcert
bro db [drop] Create or drop the project database
bro migrate <add|deploy|generate|seed|reset|status> [name] Run Prisma migrations
bro exec <command> [args...] Run a command and print its output
bro run <command> [args...] Run an interactive command
bro list List discovered workspace projects
bro tree Generate a file tree of the workspace
bro create [name] [--dir=path] [--yes] [--overwrite] [--recipe-file=path] Scaffold a new Node.js project
bro --help Show all commands
bro --version Show versionProgrammatic API
All tools are also available as importable functions for building custom CLIs:
import { Cli, discover, clean, install, dev, setup, migrate, wipe, tree } from '@bro-code/cli';
const cli = new Cli({
name: 'bro-creation',
version: '1.0.0',
description: 'My project CLI',
});
cli
.command('dev', 'Start development servers', (args) => dev(args))
.command('clean', 'Clean project artifacts', (args) => clean(args))
.command('load', 'Install dependencies', (args) => install(args))
.command('setup', 'Full project setup', (args) => setup(args))
.command('migrate', 'Run database migrations', (args) => migrate(args));
await cli.run();Tools
The package is organized into focused, composable tools:
Cli — Command Framework
const cli = new Cli({ name: 'bro-creation', version: '1.0.0' });
cli.command('build', 'Build everything', handler);
cli.command('test', 'Run tests', handler);
await cli.run(); // parse process.argv
await cli.run(['build']); // or pass args directly
cli.help(); // print help textdiscover — Project Discovery
Finds sub-project directories in a workspace root. Only directories containing a package.json are included. Respects ignore lists and priority ordering from bro.config.json.
import { discover, resolveDir } from '@bro-code/cli';
const workspace = discover(); // uses cwd
const workspace = discover('/my/repo'); // explicit root
workspace.root; // '/my/repo'
workspace.projects; // ['.', 'shared', 'server', 'client']
resolveDir(workspace, 'server'); // '/my/repo/server'parseArgs — Argument Parsing
import { parseArgs } from '@bro-code/cli';
const parsed = parseArgs(['server', 'd=express,cors', 'D=vitest', '--force']);
parsed.projects; // ['server']
parsed.deps; // ['express', 'cors']
parsed.devDeps; // ['vitest']
parsed.flags; // { force: true }
parsed.positional; // []install / uninstall — Dependency Management
Installs root dependencies first (priority), then remaining projects in parallel.
import { install, uninstall } from '@bro-code/cli';
await install(); // npm install in all projects
await install(['server', 'client']); // specific projects
await install(['d=express,cors']); // add deps to all projects
await install(['server', 'D=vitest']); // add dev dep to server only
await uninstall(['d=lodash']); // remove from all projectsclean / kill — Cleanup
import { clean, kill } from '@bro-code/cli';
await clean(); // remove node_modules + lock files
await clean(['server', 'client']); // specific projects
await kill(); // every node process, with its tree (Windows)
await kill(['--outside']); // spare this workspace's processes
await kill(['--inside']); // only this workspace's processes
await kill(['port=5173']); // only the Node process listening on 5173kill (Windows only) ends each Node.js process with its whole process tree (taskkill /F /T), so the tools a dev server started (esbuild, a shell) go with it:
| Command | Kills |
|---------|-------|
| bro kill | Every node.exe |
| bro kill --outside | Every node.exe whose command line does not point inside the current workspace |
| bro kill --inside | Only the node.exe processes whose command line points inside the current workspace |
| bro kill port=5173 | Only the Node process listening on each port (port=5173,8080 for several, like d=pkg1,pkg2); a port held by something that is not Node is named (image and PID) and left alone |
--inside / --outside can be combined with port=. bro itself and every process above it (npm, which is itself node.exe, a terminal, an editor task) are always spared, so npm run kill finishes. A process whose tree holds a spared process is spared too, so --outside does not end an outside npm that is running this workspace's dev server. Processes are read with Get-CimInstance Win32_Process and ports with Get-NetTCPConnection.
"Inside" means the process's command line contains the workspace root (case and / vs \ ignored) followed by a separator, a quote, a space or the end, so ...\app does not match ...\app-engines. A process started with a relative path (node ./index.js) shows no workspace path and counts as outside, as does a process whose command line Windows does not show (another user's or an elevated one). Each killed process is listed (name, PID, command line, how many processes went with it), followed by a count of those spared, by reason.
wipe — Infrastructure Wipe
Removes project infrastructure: database (when DATABASE_URL is set), .env, SSL certificates, and migration directories. Configurable protection via bro.config.json.
import { wipe } from '@bro-code/cli';
await wipe(); // wipe all unprotected targets
await wipe({ db: false }); // skip database drop
await wipe({ ssl: false, env: false }); // keep ssl and envtree — File Tree Generation
Generates a file tree of the workspace and writes it to a file. Ignores directories configured in cli.tree.ignore.
import { tree } from '@bro-code/cli';
await tree(); // uses config defaults
await tree({ output: './docs/tree.txt' }); // custom output path
await tree({ ignore: ['node_modules', '.git'] }); // custom ignore listdev / start — Dev Server Orchestration
dev runs full setup first (deps, env, ssl, db, migrations) then starts servers.start just spawns the dev processes without setup.
cli.dev.serverReadyUrl replaces the fixed serverDelay with a readiness check: after starting server, start requests the URL and starts clients once it answers with a 2xx status. ${ENV_VAR} placeholders in the URL are filled from the process environment and the .env file at cli.dev.envPath. A non-2xx response or a connection failure is retried every half second until cli.dev.serverReadyTimeout (default 30 seconds) runs out, and then startup fails without starting clients. It fails before starting anything when a placeholder's variable is not set or the server folder is missing. The check runs only when server is started (bro start client skips it), and not with cli.dev.command. Without a URL, serverDelay controls the wait.
import { dev, start } from '@bro-code/cli';
await dev(); // setup + start server + client
await dev(['server']); // setup + server only
await dev(['client=2']); // setup + two client instances
await start(); // start server + client (no setup)
await start(['server']); // server only
await start(['client=2']); // two client instancesdev runs npm install in each project it sets up. Set cli.dev.install: false to skip it; bro fresh and bro nuke dev always install, because they have just deleted node_modules.
Single project
A repo with one project at its root (a Vite app, for example) sets cli.dev.command instead of having server/ and client/ folders:
{ "cli": { "dev": { "command": "vite" } } }dev then sets up the root project only and runs the command in the workspace root with the terminal attached, so the command's own keys and colours work. node_modules/.bin goes first on PATH, as under npm run, and the .env file is loaded into its environment. Every argument after dev / start goes to the command, with a leading -- dropped, so both of these run vite --mode debug:
bro dev --mode debug
bro dev -- --mode debugnpm run dev -- --host with "dev": "bro dev" reaches the command as --host the same way. bro exits with the command's exit code. server / client arguments mean nothing in this mode; bro warns and passes them on like any other argument.
exec / execInteractive — Command Execution
import { exec, execWithContext, execInteractive } from '@bro-code/cli';
const version = await exec('node', ['--version']);
await execInteractive('npx', ['prisma', 'studio']);
// Within a Task step:
await task.step('Build', async (ctx) => {
await execWithContext('npm', ['run', 'build'], ctx, { cwd: './server' });
});createEnv / loadEnv — Environment Management
import { createEnv, loadEnv, checkEnv } from '@bro-code/cli';
// Check if .env exists
checkEnv(); // boolean
// Interactive .env generation from a schema
await createEnv({
variables: [
{ key: 'PORT', label: 'Server Port', default: 3000 },
{ key: 'DB_HOST', label: 'Database Host', default: 'localhost' },
{ key: 'DB_PASS', label: 'Database Password', isString: true, required: true, encode: true },
{ key: 'JWT', label: 'JWT Secret', generate: 'base64' },
],
composites: [
{
key: 'DATABASE_URL',
template: 'postgresql://postgres:{DB_PASS}@{DB_HOST}:5432/mydb?schema=public',
isString: true,
},
],
});
// Parse .env into object
const env = loadEnv('.env');createSsl — SSL Certificate Generation
createSsl (and bc ssl) always creates certificates when the folder is missing, whatever cli.ssl.enabled says; the setting only decides whether setup and dev create them.
import { createSsl, checkSsl } from '@bro-code/cli';
if (!checkSsl()) {
await createSsl({ hosts: ['localhost', '127.0.0.1'] });
}checkDb / createDb / dropDb / hasDatabase — Database Operations
Requires pg package: npm install pg
A database is configured when DATABASE_URL is set in the environment or the .env file (hasDatabase()). Without one, setup leaves out its "Create database" step, and bc db and bc migrate print one line saying there is nothing to do.
import { checkDb, createDb, dropDb, hasDatabase } from '@bro-code/cli';
if (!hasDatabase()) return; // no DATABASE_URL
const exists = await checkDb();
if (!exists) await createDb();
// Dangerous!
await dropDb();migrate / massMigrate — Prisma Migrations
import { migrate, massMigrate } from '@bro-code/cli';
await migrate(['generate']); // regenerate client
await migrate(['add', 'init']); // create migration
await migrate(['deploy']); // apply pending
await migrate(['seed']); // seed database
await migrate(['status']); // check status
await massMigrate(true); // deploy → generate → seedsetup — Full Project Setup
Orchestrates the entire setup pipeline. SSL certificates are made only when cli.ssl.enabled is true (and skipped with a warning if mkcert is not installed), the database is created only when DATABASE_URL is set, and the "Setting up project" task is left out when it has nothing to do.
import { setup } from '@bro-code/cli';
await setup(['.', 'shared', 'server', 'client']);
// 1. Install deps → 2. Create .env → 3. SSL (if enabled) → 4. Database (if DATABASE_URL) → 5. Migrationsprompt / select / confirm — Interactive Prompts
import { prompt, select, confirm } from '@bro-code/cli';
const name = await prompt('Project name');
const env = await select('Environment', ['development', 'staging', 'production']);
const proceed = await confirm('Continue?');create — Scaffold a fresh Node.js project
Generates a brand-new project from a recipe. The CLI command (bro create) walks the user through a colourful interactive menu; the programmatic API lets you bypass prompts entirely.
CLI usage:
bro create # fully interactive
bro create bro-creation # pre-fill the project name
bro create bro-creation --yes # use defaults for everything
bro create bro-creation --dir=./apps # create inside ./apps/bro-creation
bro create bro-creation --overwrite # replace an existing target dir
bro create bro-creation --kind=server # pre-fill any single recipe field
bro create bro-creation --yes --kind=cli-tool --language=javascript
bro create bro-creation --yes --recipe='{"kind":"client"}' # pre-fill fields from JSON
bro create bro-creation --yes --recipe-file=./recipe.json # the same, from a JSON file--recipe-file=<path> (relative to the current directory) reads the same JSON as --recipe=; use it from Windows PowerShell 5.1, which strips the double quotes inside --recipe=<json>. A byte order mark (as Out-File -Encoding utf8 writes) is ignored. Give server, client and shared as whole objects: a sub-object replaces the default one rather than merging with it. With --yes, the defaults' server, client and shared are dropped when the kind has no such folder, as the interactive menu does.
The generated project always includes a bro.config.json and the standard scripts (bc dev, bc setup, bc clean, bc fresh) so it is immediately usable with the rest of the toolkit. It starts at version <current year>.0.0, and its root package.json also gets:
buildandtest, which run each sub-project's script in priority order (npm run build --prefix shared && npm run build --prefix server && ...), leaving out a sub-project without that script;echo "no build"/echo "no tests"when none has one, sonpm testexits 0. Acli-toolkeeps its ownbuild(tsc).postinstall: bc install <sub-projects>, sonpm installat the root installsshared,serverandclienttoo, andnpm run build/npm testwork right after it. Whenbcitself runs the root'snpm install(asbc devandbc setupdo), it tells the nestedbc installwhich projects it is already installing (theBRO_CLI_INSTALLINGenvironment variable), so they are not installed twice.
Recipes with a server get "ssl": { "enabled": true } in bro.config.json, since SSL is opt-in.
What the menu covers
| Category | Choices |
|---|---|
| Project kind | fullstack, server, client, cli-tool, monorepo |
| Language | typescript, javascript (+ strict/recommended/loose tsconfig) |
| Module | esm, cjs, dual |
| Server framework | express, fastify, koa, hono, nestjs, none |
| Database | postgresql, mysql, sqlite, mongodb, redis, none |
| ORM | prisma, drizzle, typeorm, mongoose, raw |
| Authentication | jwt, passport, session, none |
| WebSocket | socket.io, ws, none |
| Validation | zod, joi, yup, none |
| Frontend framework | vue, react, angular, svelte, solid, none |
| Bundler / meta | vite, next, nuxt, sveltekit, remix, none |
| State management | pinia, vuex, redux, zustand, mobx, jotai, none |
| UI library | vuetify, mui, chakra, antd, shadcn, tailwind, none |
| Styling | css-modules, styled-components, sass, tailwind, plain |
| Testing | vitest, jest, mocha, none |
| Linter / formatter | eslint/biome/none · prettier/biome/none |
| CI | azure-pipelines, github-actions, gitlab-ci, circleci, none |
| Extras | git init · Docker / docker-compose · LICENSE · README · .env template |
Programmatic API:
import {
scaffold,
pickRecipe,
runCreate,
buildFiles,
recipeOptions,
DEFAULT_RECIPE,
} from '@bro-code/cli';
import type { Recipe } from '@bro-code/cli';
// 1. Run the full interactive flow (prompts → confirm → scaffold).
await runCreate({ dir: './apps' });
// 2. Pre-fill some fields and let the user pick the rest.
await runCreate({
name: 'my-api',
recipe: { kind: 'server', websocket: 'none', server: { tech: 'fastify', database: 'postgresql', orm: 'prisma', auth: 'jwt', validation: 'zod' } },
});
// 3. Skip prompts entirely with --yes equivalent.
await runCreate({ name: 'speedy', yes: true, recipe: { kind: 'cli-tool' } });
// 4. Fully programmatic — no prompts, no console output.
const recipe: Recipe = { ...DEFAULT_RECIPE, name: 'lib', kind: 'cli-tool', server: undefined, client: undefined, shared: undefined };
await scaffold({ recipe, dir: './packages', silent: true });
// 5. Inspect what would be generated without writing anything.
const files = buildFiles(recipe);
console.log(files.map(f => f.path));
// 6. Build your own picker UI from the registry.
console.log(recipeOptions.serverTech.map(c => c.label));Helper functions:
import { hasServer, hasClient, hasShared, createCommand } from '@bro-code/cli';
// Check which sub-projects a recipe kind includes
hasServer('fullstack'); // true
hasClient('server'); // false
hasShared('cli-tool'); // false
// Parse argv for the bro create command (used internally by the CLI)
await createCommand(['my-project', '--yes', '--kind=server']);Configuration
Add a cli section to your bro.config.json:
{
"cli": {
"ignore": ["node_modules", ".git", "scripts", ".vscode"],
"priority": [".", "shared", "server", "client"],
"clean": {
"targets": ["node_modules", "package-lock.json", "dist"]
},
"dev": {
"serverDelay": 5000,
"serverReadyUrl": "http://localhost:${PORT}/health",
"serverReadyTimeout": 30000,
"clientDelay": 500,
"envPath": ".env"
},
"env": {
"variables": [
{ "key": "PORT", "label": "Server Port", "default": 3000 },
{ "key": "DB_USER", "label": "Database User", "default": "postgres", "encode": true },
{ "key": "DB_PASSWORD", "label": "Database Password", "isString": true, "required": true, "encode": true },
{ "key": "DB_HOST", "label": "Database Host", "default": "localhost" },
{ "key": "DB_PORT", "label": "Database Port", "default": 5432 },
{ "key": "DB_NAME", "label": "Database Name", "default": "mydb", "space": true },
{ "key": "JWT", "label": "JWT Secret", "comment": "Security", "generate": "base64", "bytes": 64 },
{ "key": "ENCRYPTION_KEY", "label": "Encryption Key", "generate": "hex", "bytes": 32 }
],
"composites": [
{
"key": "DATABASE_URL",
"comment": "Prisma",
"template": "postgresql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}?schema=public",
"isString": true
}
]
},
"ssl": {
"enabled": true,
"dir": ".ssl",
"hosts": ["localhost"],
"keyFile": "server.key",
"certFile": "server.cert"
},
"db": {
"envPrefix": "DATABASE"
},
"migrate": {
"cwd": "./server",
"schemaPath": "./prisma/schema.prisma",
"configPath": "./prisma/prisma.config.ts"
},
"wipe": {
"disabled": false,
"protect": ["db"]
},
"tree": {
"ignore": ["node_modules", ".git", ".vs", ".vscode", "dist", "coverage"],
"output": ".logs/file-tree.txt"
}
}
}Configuration Reference
cli.ignore
Directory names to skip during project discovery.
cli.priority
Preferred project ordering. Earlier entries have higher priority (e.g., root installs before server/client).
cli.clean
| Option | Type | Default | Description |
|-----------|------------|-----------------------------------------|----------------------------------------|
| targets | string[] | ["node_modules", "package-lock.json"] | File/directory names to remove per project |
| ignore | string[] | [] | Names from targets to keep (e.g. ["package-lock.json"] for a pipeline that runs npm ci). Separate from the top-level cli.ignore, which is for project discovery |
cli.dev
| Option | Type | Default | Description |
|---------------------|----------|----------|------------------------------------------------------|
| serverDelay | number | 5000 | Milliseconds to wait after server before starting clients when no readiness URL is set |
| serverReadyUrl | string | unset | URL polled before starting clients; supports ${ENV_VAR} placeholders |
| serverReadyTimeout| number | 30000 | Maximum milliseconds to wait for the readiness URL |
| clientDelay | number | 500 | Milliseconds between client instance starts |
| envPath | string | ".env" | Path to the .env file (relative to workspace root) |
| command | string | unset | Command to run in the workspace root instead of starting server / client (see Single project) |
| install | boolean| true | Run npm install before starting (fresh and nuke dev always install) |
cli.env
| Option | Type | Default | Description |
|--------------|------------------|---------|----------------------------------------------------|
| variables | EnvVariable[] | [] | Variable definitions for interactive .env generation |
| composites | EnvComposite[] | [] | Composite variables built from other variable values |
| path | string | ".env" | Path to the .env file |
| overwrite | boolean | false | Overwrite an existing .env file |
| interactive| boolean | true | Enable interactive prompts |
EnvVariable fields:
| Field | Type | Description |
|------------|----------|----------------------------------------------------------------|
| key | string | Environment variable key (e.g. DATABASE_HOST) |
| label | string | Human-readable label shown during prompts |
| comment | string | Section comment header (e.g. "Database") |
| default | string \| number | Default value used when user skips the prompt |
| required | boolean| Whether a value is required (no empty string allowed) |
| space | boolean| Add a blank line after this variable |
| isString | boolean| Wrap the value in double quotes |
| generate | string | Auto-generate: "base64", "hex", or "uuid" |
| bytes | number | Number of random bytes (default: 64 for base64, 32 for hex) |
| encode | boolean| URL-encode this value when substituting into composite templates|
EnvComposite fields:
| Field | Type | Description |
|------------|----------|----------------------------------------------------------------|
| key | string | Environment variable key (e.g. DATABASE_URL) |
| comment | string | Section comment header |
| template | string | Template string with {KEY} placeholders |
| isString | boolean| Wrap the value in double quotes |
| space | boolean| Add a blank line after this variable |
cli.ssl
| Option | Type | Default | Description |
|------------|------------|------------------|----------------------------------|
| enabled | boolean | false | Create certificates during setup / dev (bc ssl always creates them) |
| dir | string | ".ssl" | Directory for certificate files |
| hosts | string[] | ["localhost"] | Hostnames for the certificate |
| keyFile | string | "server.key" | Key filename |
| certFile | string | "server.cert" | Certificate filename |
cli.db
| Option | Type | Default | Description |
|-------------|----------|--------------|------------------------------------------|
| envPrefix | string | "DATABASE" | Prefix for database env variables (reads <PREFIX>_USER, _PASSWORD, _HOST, _PORT, _NAME) |
cli.migrate
| Option | Type | Default | Description |
|--------------|----------|---------------------------------|--------------------------------|
| cwd | string | "./server" | Working directory for Prisma |
| schemaPath | string | "./prisma/schema.prisma" | Path to the Prisma schema file |
| configPath | string | "./prisma/prisma.config.ts" | Path to the Prisma config file |
cli.wipe
| Option | Type | Default | Description |
|------------|------------|---------|--------------------------------------------------------------|
| disabled | boolean | false | Disable the wipe command entirely |
| protect | string[] | [] | Targets to protect from wiping: "db", "env", "ssl", "migrations" |
cli.tree
| Option | Type | Default | Description |
|----------|------------|----------------------------------|--------------------------------------------|
| ignore | string[] | ["node_modules", ".git", ...] | Directory/file names to skip during walk |
| output | string | ".logs/file-tree.txt" | Output file path (relative to workspace root) |
Reading the config in code
getCliConfig(cwd?) returns the cli section of bro.config.json (or bro.config.js / .cjs) in cwd (default: the current directory), merged with the defaults above. The result is cached after the first call, so a later cwd is ignored until the cache is cleared.
import { getCliConfig, resetCliConfigCache } from '@bro-code/cli';
import { resetConfigCache } from '@bro-code/logger';
const cfg = getCliConfig();
cfg.dev.serverReadyTimeout; // 30000 unless set
// Re-read bro.config.json on the next call (e.g. between tests).
// @bro-code/logger caches the file, so clear both.
resetConfigCache();
resetCliConfigCache();API
Full TypeScript types are exported for all options, configs, and tool parameters. See the types source for complete documentation.
License
MIT © Bro Code Technologies
Changelog
[2026.6.0] - 2026-10-21
Added
cli.dev.serverReadyUrlandcli.dev.serverReadyTimeout(default30000):devandstartwait for the server to answer a readiness URL with a 2xx status before starting clients, instead of waiting a fixedserverDelay. The URL takes${ENV_VAR}placeholders from the environment and.env. Startup fails without starting clients when the timeout runs out, and before starting anything when a placeholder's variable is not set or theserverfolder is missing. Without a URL,serverDelayworks as before.
Documentation
- Documented
getCliConfig()andresetCliConfigCache(), which were exported but not described.
[2026.5.0] - 2026-10-14
Added
cli.dev.command:devandstartrun one project in the workspace root (e.g."vite") with the terminal attached,node_modules/.binonPATH, the.envloaded, and every argument passed on (a leading--dropped).broexits with the command's code. Without it,server/clientstart as before.cli.dev.install(defaulttrue):falseskipsnpm installwhendevstarts.freshandnuke devalways install.SetupOptions.skipInstallskips the install step ofsetup.cli.clean.ignore: names fromcli.clean.targetsthatcleankeeps (e.g.package-lock.json).hasDatabase(): whetherDATABASE_URLis set in the environment or.env.bro kill --inside/--outsidekill only the Node processes inside / outside the current workspace, andbro kill port=<n>[,<n>...]kills only the Node process listening on each port, naming and leaving alone a holder that is not Node.EnvCompositetype is exported from the package entry point.EnvOptions.compositesalready used it, but it could not be imported.bro create --recipe-file=<path>reads the recipe JSON from a file (for Windows PowerShell 5.1, which strips the quotes in--recipe=<json>).- Projects from
bro createget rootbuildandtestscripts that run each sub-project's script, and apostinstallthat installs the sub-projects, sonpm install,npm run buildandnpm testwork from the root.installpassesBRO_CLI_INSTALLINGto the root'snpm installso that postinstall does not install the same projects twice.
Changed
- SSL is opt-in.
setupanddevonly create certificates whencli.ssl.enabledistrue(defaultfalse), and with it off they skip the mkcert check and its warning too. Apps that relied on certificates being made without saying so must set"ssl": { "enabled": true }.bc sslalways creates them. setupadds its "Create database" step only whenDATABASE_URLis set, and leaves out the "Setting up project" task when it has no steps.bro dbandbro migratewith noDATABASE_URLprint one line saying there is nothing to do, instead of doing nothing silently or failing in Prisma.bro killends each Node process with its whole process tree (taskkill /T) and sparesbroand every process above it (npm, a terminal, an editor task), sonpm run killfinishes; it lists what it killed and counts what it spared.killmoved fromclean.tsto its own module and takes the command's arguments (kill(args)); it is still exported askill.bro createstarts projects at version<current year>.0.0instead of0.0.0, and gives recipes with a server"ssl": { "enabled": true }.
Fixed
bro execprints the command's output (it was captured and dropped), andbro envsays when there is nothing to write (nocli.env.variables, or the.envalready exists) instead of exiting silently.bro wipeadds its "Drop database" step only whenDATABASE_URLis set (without a.envthe step used to fail even in apps with no database), and says "Nothing to wipe" when no step applies.bro create --yeswith a partial recipe no longer keeps the defaults'server,clientandsharedfolders when thekindhas none (aclientrecipe gotserver/andshared/that its config and scripts left out).
[2026.4.0] - 2026-04-27
Added
bro create/bc createcommand — scaffold a brand-new Node.js project from an interactive menu. Supports five project kinds (fullstack, server, client, cli-tool, monorepo) with ~20 customization axes covering framework, database, ORM, authentication, frontend, testing, CI, and more.
Fixed
setup,db, andmigratetools now work across every database / ORM combination supported bybro create. Previously these tools were hard-wired around PostgreSQL + Prisma; they now route to the correct admin connection, schema location, and migration runner for MySQL, SQLite, MongoDB, Redis, Drizzle, TypeORM, Mongoose, and the raw-driver paths.
[2026.3.8] - 2026-04-23
Fixed
- CJS build:
tsconfig.cjs.jsoncorrected to emit real CommonJS output. The previousmodule: Node16setting combined with"type": "module"caused TypeScript to emit ESM syntax (export {) intodist/cjs/, which brokerequire()in Node.js environments.
[2026.3.7] - 2026-04-22
Fixed
migratecommand now loads environment variables from the .env file before running any Prisma commands, ensuring thatDATABASE_URLand other variables are available to Prisma during generate, deploy, and seed steps. This fixes "datasource.url property is required" errors when runningbc migratewithout a pre-existingDATABASE_URLin the environment.
[2026.3.6] - 2026-04-20
Fixed
nukecommand now runswipebeforecleanto ensure the database is dropped before the root is cleaned.
[2026.3.5] - 2026-04-20
Fixed
wipeDrop database step now checks for.envbefore attempting drop — shows ❌ with "No .env file — cannot resolve database credentials" instead of silently succeeding- Uses
ctx.log()instead oflogger.warn()so the message is visible under the task renderer
[2026.3.4] - 2026-04-20
Fixed
dropDbdepends on the presence of the.envfile.
[2026.3.3] - 2026-04-20
Fixed
dropDbno longer depends oncheckDb— connects directly to thepostgresadmin database and runsDROP DATABASE IF EXISTS, fixing silent no-op whencheckDbreturned falsecheckDbnow queriespg_databasefrom the admin database instead of connecting to the target database, avoiding false negatives from auth or connection issueswipeno longer swallowsdropDberrors — failures now propagate as step failures with visible error output
[2026.3.2] - 2026-04-20
Fixed
wipenow logs the actual error message whendropDbthrows instead of silently swallowing exceptions
[2026.3.1] - 2026-04-19
Fixed
massMigratenow usesstopOnFail: trueso Generate and Seed are skipped when Deploy fails, instead of running all steps regardless- Bumped
@bro-code/tasksto2026.2.0(fixes multi-line error messages breaking the animation loop)
[2026.3.0] - 2026-04-19
Added
wipecommand — drops database, removes.env,.ssl, and migration directories with config-based protection (cli.wipe.protectandcli.wipe.disabled)nukecommand — runscleanthenwipe, optionally followed bydev(bc nuke dev)freshcommand — runscleanthendevfrom scratchtreecommand — generates a file tree of the workspace, writing to.logs/file-tree.txtwith configurable ignore list (cli.tree.ignore)- mkcert availability check —
bc sslnow throws a helpful error with install instructions if mkcert is not found;setup/devskip SSL gracefully with a warning
Changed
massMigratenow usestask.set()with a conditionally-built steps array instead of sequentialtask.step()callssetupnow inlines SSL steps directly into the setup Task instead of delegating tocreateSsl(), eliminating duplicate SSL output
[2026.2.5] - 2026-04-19
Fixed
bc envstandalone command now readscli.envconfiguration frombro.config.jsonand passes variables tocreateEnv(previously passed no variables and did nothing)setupnow creates.envoutside of the Task animation to prevent readline/stdout conflicts that causedbc devto hang on the env step
[2026.2.4] - 2026-04-19
Fixed
setupnow reads env variable definitions fromcli.envinbro.config.jsonand passes them tocreateEnv, fixing the empty.envfile issuesetupreloads.envintoprocess.envafter creating it so database and migration steps haveDATABASE_URL- Added composite variable support (
EnvComposite) for buildingDATABASE_URLfrom individual parts with{KEY}template placeholders andencodesupport for URL-encoding cleannow runs projects in parallel usingtask.set()instead of sequentialtask.step()calls
[2026.2.3] - 2026-04-19
Fixed
setupnow loads.envintoprocess.envbefore running infrastructure checks and migrations, fixing "datasource.url property is required" errors when runningprisma migrate deploymassMigratenow stops execution after deploy failure instead of continuing to generate and seed
[2026.2.2] - 2026-04-19
Changed
- Replaced all
console.log/console.errorwith@bro-code/loggeracross the entire package
[2026.2.1] - 2026-04-19
Fixed
devnow always includes.andsharedin setup regardless of args (bc dev= all four,bc dev server= root + shared + server, etc.)massMigrateno longer creates nested Tasks causing duplicate generate output — runs prisma commands inline within a single Task- Server
[INFO]output lines now display in cyan - "Starting" message now uses
@bro-code/loggerinstead of rawconsole.log
[2026.2.0] - 2026-04-19
Added
startcommand — start dev servers without running setup firstdevnow runssetupfirst, then starts servers
Fixed
- Database commands (
db,setup) now resolvepgpackage from workspace root instead of CLI install location, fixing "Cannot find module 'pg'" errors when CLI is installed globally or in root node_modules
[2026.1.2] - 2026-04-19
Fixed
devcommand now loads the root.envfile before spawning child processes, so server/client inherit workspace environment variables
[2026.1.1] - 2026-04-19
Fixed
- Fix DEP0190 deprecation warning in
devcommand by joining shell command and args into a single string
[2026.1.0] - 2026-04-19
Changed
discover()now only includes directories that contain apackage.jsoninstall()/uninstall()now run in parallel with root project as a priority step (installs root first, then rest simultaneously)
[2026.0.0] - 2026-04-19
Added
Cliclass — lightweight command framework with help and version supportdiscover()— workspace project discovery with configurable ignore/priorityparseArgs()— structured CLI argument parsing (projects, deps, flags)install()/uninstall()— dependency management across projectsclean()/kill()— artifact cleanup and process managementdev()— multi-project dev server orchestration with staggered startupexec()/execWithContext()/execInteractive()— command executioncreateEnv()/loadEnv()/checkEnv()— .env file managementcreateSsl()/checkSsl()— mkcert SSL certificate generationcheckDb()/createDb()/dropDb()— PostgreSQL database managementmigrate()/massMigrate()— Prisma migration commandssetup()— full project setup pipelinewipe()— infrastructure wipe (db, env, ssl, migrations)tree()— file tree generationprompt()/select()/confirm()— interactive terminal promptsbro.config.jsonintegration for all tool defaultsbroandbcCLI binaries with all built-in commands
