{"record":{"id":"14aff7bdd9ea8302","repo":"garrytan/gstack","slug":"usage-b-skill-test-name","errorCode":null,"errorMessage":"Usage: $B skill test <name>","messagePattern":"Usage: \\$B skill test <name>","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"browse/src/browser-skill-commands.ts","lineNumber":178,"sourceCode":"\n  if (result.exitCode !== 0 || result.timedOut || result.truncated) {\n    const summary = result.truncated\n      ? `truncated stdout at ${MAX_STDOUT_BYTES} bytes`\n      : result.timedOut\n        ? `timed out after ${timeoutSeconds}s`\n        : `exit ${result.exitCode}`;\n    const err = new Error(`Skill \"${name}\" failed: ${summary}\\n--- stderr ---\\n${result.stderr.slice(0, 4096)}`);\n    (err as any).exitCode = result.exitCode || 1;\n    throw err;\n  }\n  return result.stdout;\n}\n\n// ─── test ───────────────────────────────────────────────────────\n\nasync function handleTest(args: string[], ctx: SkillCommandContext): Promise<string> {\n  const name = args[0];\n  if (!name) throw new Error('Usage: $B skill test <name>');\n  const tiers = ctx.tiers ?? defaultTierPaths();\n  const skill = readBrowserSkill(name, tiers);\n  if (!skill) throw new Error(`Skill \"${name}\" not found.`);\n\n  const testFile = path.join(skill.dir, 'script.test.ts');\n  if (!fs.existsSync(testFile)) {\n    throw new Error(`Skill \"${name}\" has no script.test.ts at ${testFile}`);\n  }\n\n  const proc = Bun.spawn(['bun', 'test', testFile], {\n    cwd: skill.dir,\n    stdout: 'pipe',\n    stderr: 'pipe',\n    env: process.env,\n  });\n  const exitCode = await proc.exited;\n  const stdout = proc.stdout ? await new Response(proc.stdout).text() : '';\n  const stderr = proc.stderr ? await new Response(proc.stderr).text() : '';","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/browser-skill-commands.ts#L160-L196","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Re-run with a name: `$B skill test <name>`.","Run `$B skill list` to enumerate skills that actually have test files.","Confirm the target skill ships a script.test.ts (only skills authored with tests are testable)."],"exampleFix":"// before\n$B skill test\n// after\n$B skill test hn-frontpage","handlingStrategy":"validation","validationCode":"function requireTestName(args: string[]): string {\n  const name = args[0];\n  if (!name) throw new Error('Usage: $B skill test <name>');\n  return name;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only testable skills have script.test.ts — check with `$B skill list` first.","Pass the name as args[0], separate from any flags.","Programmatic callers should validate args.length > 0 before dispatching."],"tags":["cli-usage","skill-management","testing","gstack"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}