why-broke Causal Debugger
why-broke is a command-line utility designed for causal debugging of build failures in JavaScript/TypeScript projects. It tackles the common problem of "it worked yesterday, but not today" by detecting subtle environmental and dependency changes that conventional version control systems like Git might miss. The tool operates by taking a "good state" snapshot of the system, which includes critical factors like Node.js version, operating system, lockfile hashes, package manifest versions, key configuration files (e.g., `tsconfig`, `webpack`), and essential environment variable keys. When a build subsequently fails, why-broke compares the current "bad state" against the last known good state to pinpoint the root cause, such as silent dependency updates, missing environment variables, or unexpected Node.js version discrepancies. As of version 1.4.2, it incorporates a causal inference engine with specialized detectors for runtime, dependencies, configuration, environment, and Git status. The package is actively maintained and appears to follow a typical semantic versioning release cadence based on its version history. Its primary differentiator is its focus on diagnosing *why* a build failed rather than merely *where* it failed, offering actionable fixes.
Common errors
-
command not found: why-broke
cause The `why-broke` package is not installed globally or locally, or `npx` cannot locate it in the current environment's PATH.fixInstall `why-broke` globally via `npm install -g why-broke` or as a dev dependency with `npm install --save-dev why-broke`. Ensure `npx` is available and in your system's PATH. -
✖ Command failed. Diagnosing cause... (followed by an empty or unhelpful report)
cause The previously recorded "good state" baseline is missing, corrupted, or was set when the project was already in a problematic state, preventing meaningful comparison.fixRun `npx why-broke record` when your project is in a verified working condition to establish a fresh, reliable baseline for future comparisons. -
Error: EACCES: permission denied, open '.why-broke.json'
cause The user executing `why-broke` does not have sufficient file system write permissions to create or modify the `.why-broke.json` file in the project's root directory.fixEnsure the user has write permissions in the project root. Avoid running `npm` or `npx` commands with `sudo` unless absolutely necessary, as this can lead to incorrect file ownership and permissions.
Warnings
- gotcha The `.why-broke.json` snapshot file stores local environmental state and should never be committed to version control. Committing it can lead to confusing or incorrect diagnostics when shared across different machines or environments.
- gotcha `why-broke`'s accuracy heavily depends on a reliable "good state" baseline. If this baseline is outdated, corrupted, or was recorded during a temporarily broken state, subsequent diagnostic reports may be misleading or inaccurate.
- gotcha The `GitDetector` within `why-broke` provides change reports with `LOW` confidence for aspects like Git history or dirty working directories. These reports are less definitive than `HIGH` confidence reports from other detectors.
Install
-
npm install why-broke -
yarn add why-broke -
pnpm add why-broke
Imports
- init
const init = require('why-broke').init;import { init } from 'why-broke'; - record
import record from 'why-broke';
import { record } from 'why-broke'; - check
const check = require('why-broke');import { check } from 'why-broke';
Quickstart
import { exec } from 'child_process';
import path from 'path';
// This script demonstrates common why-broke usages programmatically,
// often seen in build scripts or advanced CI/CD setups where shell commands
// are orchestrated via Node.js.
const projectRoot = process.cwd(); // Assumes script is run from project root
async function setupAndRunWhyBroke() {
console.log('1. Installing why-broke as a dev dependency...');
// Ensure why-broke is available. In a real scenario, this might be in package.json.
await new Promise<void>((resolve, reject) => {
exec('npm install --save-dev why-broke', { cwd: projectRoot }, (err, stdout, stderr) => {
if (err) {
console.error(`Installation failed: ${stderr}`);
return reject(err);
}
console.log(stdout);
resolve();
});
});
console.log('\n2. Initializing why-broke in the project...');
// This sets up automatic state recording on 'npm install'
await new Promise<void>((resolve, reject) => {
exec('npx why-broke init', { cwd: projectRoot }, (err, stdout, stderr) => {
if (err) {
console.error(`Init failed: ${stderr}`);
return reject(err);
}
console.log(stdout);
resolve();
});
});
console.log('\n3. Attempting a wrapped build with why-broke...');
// why-broke will record a "good state" if this build succeeds,
// or diagnose if it fails.
await new Promise<void>((resolve, reject) => {
exec('npx why-broke "npm run build"', { cwd: projectRoot }, (err, stdout, stderr) => {
console.log(stdout); // why-broke's diagnostic output will be here
if (stderr) {
console.error(stderr);
}
if (err) {
console.error(`\nBuild command failed with exit code ${err.code}.`);
console.error('why-broke should have provided a diagnosis above.');
return reject(err);
}
console.log('\nBuild succeeded. why-broke might have recorded a new good state.');
resolve();
});
});
console.log('\nDemonstration complete.');
}
setupAndRunWhyBroke().catch(error => {
console.error('An error occurred during the why-broke demonstration:', error);
process.exit(1);
});