pbakaus/impeccable · error

usage: surface-brief.mjs write <primary-target> <body-file>

Error message

usage: surface-brief.mjs write <primary-target> <body-file>

What it means

Thrown by main() in surface-brief.mjs when the 'write' subcommand is invoked without either the primary target or the body-file argument. The write command persists a brief to disk and needs both: the target names the surface the brief describes, and bodyFile is the file whose contents become the brief text (read via fs.readFileSync). Missing either, there is nothing deterministic to write.

Source

Thrown at skill/scripts/surface-brief.mjs:45

    if (!filePath) throw new Error('surface brief path requires a concrete target');
    process.stdout.write(`${path.relative(process.cwd(), filePath) || filePath}\n`);
    return;
  }
  if (command === 'list') {
    process.stdout.write(`${JSON.stringify(listSurfaceBriefs(projectRoot).map((brief) => summary(brief, projectRoot)), null, 2)}\n`);
    return;
  }
  if (command === 'read') {
    const result = resolveSurfaceBrief(projectRoot, target || null);
    if (result.brief) {
      process.stdout.write(result.brief.text);
      return;
    }
    if (result.candidates.length) process.stderr.write(`${JSON.stringify(result.candidates.map((brief) => summary(brief, projectRoot)), null, 2)}\n`);
    process.exit(2);
  }
  if (command === 'write') {
    if (!target || !bodyFile) throw new Error('usage: surface-brief.mjs write <primary-target> <body-file>');
    const filePath = writeSurfaceBrief({
      projectRoot,
      primaryTarget: target,
      relatedTargets,
      body: fs.readFileSync(bodyFile, 'utf-8'),
    });
    process.stdout.write(`${path.relative(process.cwd(), filePath) || filePath}\n`);
    return;
  }
  throw new Error('usage: surface-brief.mjs <path|list|read|write> [target] [body-file] [related-target ...]');
}

function isMainModule() {
  if (!process.argv[1]) return false;
  try {
    return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(process.argv[1]);
  } catch {
    return import.meta.url === pathToFileURL(process.argv[1]).href;

View on GitHub (pinned to d14711ae3d)

Solutions

  1. Supply both: 'surface-brief.mjs write src/components/Header.jsx ./brief.md'.
  2. Create the body file first (e.g. echo, $EDITOR) so readFileSync succeeds.
  3. Re-read the usage message: write <primary-target> <body-file> [related-target ...].

Example fix

# before
node surface-brief.mjs write src/components/Header.jsx
# after
node surface-brief.mjs write src/components/Header.jsx ./header-brief.md
Defensive patterns

Strategy: validation

Validate before calling

if (command === 'write' && (!target || !bodyFile)) {
  throw new Error('write needs both <primary-target> and <body-file>');
}
if (!fs.existsSync(bodyFile)) throw new Error('body file not found: ' + bodyFile);

Prevention

When it happens

Trigger: The script is run as 'surface-brief.mjs write <target>' with bodyFile omitted, or 'surface-brief.mjs write' with neither. argv destructuring puts argv[2] in target and argv[3] in bodyFile; the guard is !target || !bodyFile.

Common situations: User forgets the body file argument expecting an editor to open; passes only the target; the body path variable was unset in a wrapper; misread the usage line and supplied related-targets before the body file.

Related errors


AI-assisted analysis of pbakaus/impeccable@d14711ae3d (2026-08-13). Data as JSON: /api/errors/9da980399716324a. Report an issue: GitHub.