garrytan/gstack · warning · Error

Usage: $B skill test <name>

Error message

Usage: $B skill test <name>

What it means

Thrown by handleTest when args[0] is falsy — `$B skill test` was invoked with no skill name. The guard fires before readBrowserSkill so no filesystem walk happens; same usage-error pattern as show/run.

Source

Thrown at browse/src/browser-skill-commands.ts:178

  if (result.exitCode !== 0 || result.timedOut || result.truncated) {
    const summary = result.truncated
      ? `truncated stdout at ${MAX_STDOUT_BYTES} bytes`
      : result.timedOut
        ? `timed out after ${timeoutSeconds}s`
        : `exit ${result.exitCode}`;
    const err = new Error(`Skill "${name}" failed: ${summary}\n--- stderr ---\n${result.stderr.slice(0, 4096)}`);
    (err as any).exitCode = result.exitCode || 1;
    throw err;
  }
  return result.stdout;
}

// ─── test ───────────────────────────────────────────────────────

async function handleTest(args: string[], ctx: SkillCommandContext): Promise<string> {
  const name = args[0];
  if (!name) throw new Error('Usage: $B skill test <name>');
  const tiers = ctx.tiers ?? defaultTierPaths();
  const skill = readBrowserSkill(name, tiers);
  if (!skill) throw new Error(`Skill "${name}" not found.`);

  const testFile = path.join(skill.dir, 'script.test.ts');
  if (!fs.existsSync(testFile)) {
    throw new Error(`Skill "${name}" has no script.test.ts at ${testFile}`);
  }

  const proc = Bun.spawn(['bun', 'test', testFile], {
    cwd: skill.dir,
    stdout: 'pipe',
    stderr: 'pipe',
    env: process.env,
  });
  const exitCode = await proc.exited;
  const stdout = proc.stdout ? await new Response(proc.stdout).text() : '';
  const stderr = proc.stderr ? await new Response(proc.stderr).text() : '';

View on GitHub (pinned to 94993f7401)

Solutions

  1. Re-run with a name: `$B skill test <name>`.
  2. Run `$B skill list` to enumerate skills that actually have test files.
  3. Confirm the target skill ships a script.test.ts (only skills authored with tests are testable).

Example fix

// before
$B skill test
// after
$B skill test hn-frontpage
Defensive patterns

Strategy: validation

Validate before calling

function requireTestName(args: string[]): string {
  const name = args[0];
  if (!name) throw new Error('Usage: $B skill test <name>');
  return name;
}

Prevention

When it happens

Trigger: handleSkillCommand(['test'], ctx) or ['test',''] — the subcommand resolves but no name follows. Distinct from the script.test.ts-missing error (which fires only after the skill is found).

Common situations: Incomplete command typed by an agent or user; programmatic caller forgets to append the name; CI harness issues `$B skill test` against a dynamically-resolved name that came back empty.

Related errors


AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12). Data as JSON: /api/errors/14aff7bdd9ea8302. Report an issue: GitHub.