why-broke Causal Debugger

1.4.2 · active · verified Sun Apr 19

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

Warnings

Install

Imports

Quickstart

This TypeScript example demonstrates installing, initializing, and using `why-broke` to wrap a build command programmatically, typical for CI/CD pipelines or automated development scripts.

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);
});

view raw JSON →