affaan-m/ECC · error · Error

${normalizePath(path.relative(ROOT, outputPath))} is out of

Error message

${normalizePath(path.relative(ROOT, outputPath))} is out of date; run npm run command-registry:write

What it means

`checkRegistry` reads docs/COMMAND-REGISTRY.json and string-compares it to `formatRegistry(registry)` (the freshly-generated, pretty-printed JSON). If they differ by even one character, it throws `docs/COMMAND-REGISTRY.json is out of date; run npm run command-registry:write`. The registry is deterministic (sorted keys, 2-space indent, trailing newline), so any drift is real.

Source

Thrown at scripts/ci/generate-command-registry.js:227

}

function writeRegistry(registry, outputPath = DEFAULT_OUTPUT_PATH) {
  fs.mkdirSync(path.dirname(outputPath), { recursive: true });
  fs.writeFileSync(outputPath, formatRegistry(registry), 'utf8');
}

function checkRegistry(registry, outputPath = DEFAULT_OUTPUT_PATH) {
  const expected = formatRegistry(registry);
  let current;

  try {
    current = fs.readFileSync(outputPath, 'utf8');
  } catch (error) {
    throw new Error(`Failed to read ${normalizePath(path.relative(ROOT, outputPath))}: ${error.message}`);
  }

  if (current !== expected) {
    throw new Error(`${normalizePath(path.relative(ROOT, outputPath))} is out of date; run npm run command-registry:write`);
  }
}

function formatTextSummary(registry) {
  const lines = [
    'Command registry statistics',
    '',
    `Total commands: ${registry.totalCommands}`,
    '',
    'By type:',
  ];

  for (const [type, count] of Object.entries(registry.statistics.byType)) {
    lines.push(`  ${type}: ${count}`);
  }

  lines.push('', 'Top agents:');
  for (const { agent, count } of registry.statistics.topAgents) {

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Run `node scripts/ci/generate-command-registry.js --write` (or `npm run command-registry:write`) to regenerate the artifact, then commit it.
  2. If you believe the diff is spurious, check formatting: the file must use 2-space indent, sorted object keys, and a single trailing newline.
  3. Add the write step to your pre-commit flow so command edits automatically refresh the registry.
  4. Re-run `--check` to confirm zero diff.

Example fix

// before — added commands/my-command.md, did not regenerate registry
node scripts/ci/generate-command-registry.js --check
// -> docs/COMMAND-REGISTRY.json is out of date; run npm run command-registry:write

// after
node scripts/ci/generate-command-registry.js --write
git add docs/COMMAND-REGISTRY.json
git commit -m "chore: regenerate command registry"
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs');
const { generateRegistry, formatRegistry } = require('./scripts/ci/generate-command-registry.js');
const expected = formatRegistry(generateRegistry());
const current = fs.readFileSync('docs/COMMAND-REGISTRY.json', 'utf8');
if (current !== expected) {
  console.error('docs/COMMAND-REGISTRY.json is stale. Run: npm run command-registry:write');
  process.exit(1);
}

Type guard

function registryIsUpToDate(root, outputPath) {
  const { generateRegistry, formatRegistry } = require('./scripts/ci/generate-command-registry.js');
  const expected = formatRegistry(generateRegistry({ root }));
  try {
    return fs.readFileSync(outputPath, 'utf8') === expected;
  } catch { return false; }
}

Try / catch

try {
  run(['--check']);
} catch (error) {
  if (/is out of date/i.test(error.message)) {
    console.error('Regenerate: node scripts/ci/generate-command-registry.js --write && git add docs/COMMAND-REGISTRY.json');
  }
  throw error;
}

Prevention

When it happens

Trigger: Triggered by `--check` when a command file was added, removed, renamed, or edited (description/type/agent/skill references changed) without regenerating docs/COMMAND-REGISTRY.json. Also fires if the file's formatting (indent, trailing newline, key order) was altered by an editor or different Node version.

Common situations: A contributor adds a new command .md but forgets to run the write step. A command's frontmatter description is tweaked. A command file is renamed. Someone reformats the JSON with prettier (different indent). CI runs --check on a PR that touched commands/.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/fb1981aa068c401b. Report an issue: GitHub.