scaffold-cli-command
정보
이 스킬은 구조화된 옵션, 액션 핸들러, 다중 출력 모드 지원을 갖춘 완전한 Commander.js CLI 명령어 스캐폴드를 생성합니다. 기존 CLI에 명령어를 추가하거나 새로운 도구를 생성하거나 프로젝트 전반에 걸쳐 패턴을 표준화하는 데 적합합니다. 스캐폴드에는 오류 처리, 공유 컨텍스트 패턴, 통합 테스트 가이드가 포함되어 있습니다.
빠른 설치
Claude Code
추천npx skills add pjt222/agent-almanac -a claude-code/plugin add https://github.com/pjt222/agent-almanacgit clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/scaffold-cli-commandClaude Code에서 이 명령을 복사하여 붙여넣어 스킬을 설치하세요
문서
Scaffold a CLI Command
Añadir un nuevo comando a una aplicación CLI Commander.js con manejo consistente de opciones, tres modos de salida y pruebas de integración.
Cuándo Usar
- Añadir un nuevo comando a una CLI Commander.js existente
- Diseñar una herramienta CLI multi-comando desde cero
- Estandarizar la estructura de comandos para que todos los comandos sigan los mismos patrones
- Añadir una variante "ceremonial" que reemplaza la salida de máquina con salida cálida y narrativa
Entradas
- Requerido: Nombre y verbo del comando (p. ej.,
gather,audit,sync) - Requerido: Lo que hace el comando (una oración)
- Requerido: Ruta al punto de entrada de la CLI (p. ej.,
cli/index.js) - Opcional: Si el comando necesita una variante ceremonial (salida narrativa cálida)
- Opcional: Opciones personalizadas más allá del conjunto estándar
- Opcional: Argumentos de subcomando (args posicionales como
<name>o[names...])
Procedimiento
Paso 1: Elegir el Nombre y Categoría del Comando
Seleccionar un verbo que comunique la acción del comando. Agrupar comandos en categorías:
| Categoría | Verbos | Patrón |
|---|---|---|
| CRUD | install, uninstall, list, search | Opera sobre contenido |
| Lifecycle | init, sync, audit | Gestiona el estado del proyecto |
| Ceremony | gather, scatter, tend, campfire | Salida narrativa cálida |
Convenciones de nombrado:
- Usar un solo verbo (no
install-skill— dejar que las opciones especifiquen qué) - Usar minúsculas, sin guiones en el nombre del comando mismo
- Args posicionales:
<required>o[optional]o[variadic...]
program
.command('gather <name>')
.description('Gather a team around the campfire')
Esperado: Un nombre de comando, descripción y args posicionales definidos.
En caso de fallo: Si el verbo se solapa con un comando existente, o componerlos (añadir una opción al comando existente) o diferenciarlos claramente en la descripción.
Paso 2: Definir Opciones
Cada comando debe soportar un conjunto estándar de opciones compartidas más las específicas del comando.
Opciones estándar (incluir según sea necesario):
.option('-n, --dry-run', 'Preview without making changes')
.option('-q, --quiet', 'Suppress human-readable output')
.option('--json', 'Output as JSON')
.option('-f, --framework <id>', 'Target specific framework')
.option('-g, --global', 'Use global scope')
.option('--scope <scope>', 'Scope: project, workspace, global', 'project')
.option('--source <path>', 'Path to tool root directory')
Opciones específicas del comando — añadir solo lo que el comando necesita:
.option('--ceremonial', 'Show each item arriving individually')
.option('--only <items>', 'Comma-separated subset to include')
.option('-y, --yes', 'Skip confirmation prompts')
Reglas de diseño:
- Flags cortos (
-n) para opciones usadas frecuentemente - Flags largos (
--dry-run) para claridad - Valores predeterminados como tercer argumento donde sea apropiado
- Flags booleanos (sin argumento) para toggles
Esperado: Una cadena completa de opciones con opciones estándar y personalizadas.
En caso de fallo: Si demasiadas opciones se acumulan (>8), considerar dividir en subcomandos o agrupar opciones relacionadas.
Paso 3: Implementar el Action Handler
El action handler sigue un patrón consistente:
.action(async (name, options) => {
// 1. Get shared context (registries, adapters, paths)
const ctx = getContext(options);
// 2. Resolve what to operate on
const items = resolveItems(ctx, name, options);
if (!items || items.length === 0) {
reporter.error('Nothing found.');
process.exit(1);
}
// 3. Preview if dry-run
if (options.dryRun) reporter.printDryRun();
// 4. Execute the operation
const results = await executeOperation(items, ctx, options);
// 5. Output results (3 modes)
if (options.json) {
console.log(JSON.stringify(results, null, 2));
} else if (options.quiet) {
reporter.printResults(results);
} else {
printHumanOutput(results, options);
}
})
El helper compartido getContext() centraliza:
- Detección del directorio raíz
- Carga del registry
- Detección de framework o selección explícita
- Resolución de scope
Esperado: Un action handler que sigue el patrón de 5 pasos: contexto → resolver → previsualizar → ejecutar → salida.
En caso de fallo: Si el comando no encaja en el patrón resolver-luego-ejecutar (p. ej., es puramente informacional como detect), simplificar a: contexto → calcular → salida.
Paso 4: Añadir los Tres Modos de Salida
Cada comando debe soportar tres modos de salida:
Predeterminado (legible para humanos):
Installing 3 item(s) to Claude Code...
+ create-skill [claude-code] .claude/skills/create-skill
+ write-tests [claude-code] .claude/skills/write-tests
= commit-changes [claude-code] (skipped)
2 installed, 1 skipped
Quiet (--quiet):
Salida estándar del reporter — líneas concisas con iconos de estado (+, -, =, !), sin ceremonia, sin decoración.
JSON (--json):
{
"command": "install",
"items": 3,
"installed": 2,
"skipped": 1,
"failed": 0
}
Patrón de implementación:
if (options.json) {
console.log(JSON.stringify(data, null, 2));
return;
}
if (options.quiet) {
reporter.printResults(results);
return;
}
// Default: human-readable output
printHumanReadable(results, options);
Esperado: Los tres modos producen salida útil. JSON es parseable. Quiet es conciso. Predeterminado es informativo.
En caso de fallo: Si el comando no tiene representación JSON significativa (p. ej., detect), saltar el modo JSON y documentar por qué.
Paso 5: Añadir Variante Ceremonial (Opcional)
Para comandos que se benefician de salida cálida y narrativa en lugar de reporte transaccional:
if (options.json) {
ceremonyReporter.printJson(data);
} else if (options.quiet) {
reporter.printResults(results);
} else {
ceremonyReporter.printArrival({
teamId: name,
agents,
results: { installed, skipped, failed },
ceremonial: options.ceremonial || false,
});
}
La salida ceremonial sigue las reglas de voz:
- Presente, voz activa ("mystic arrives", no "mystic was installed")
- Sin signos de exclamación
- La metáfora reemplaza la jerga ("practices" no "dependencies")
- Los fallos son honestos, no catastróficos ("a spark was lost")
- La línea de cierre refleja el estado ("The fire burns.")
- Sin emoji — usar glyphs Unicode (✦ ◉ ◎ ○ ✗)
- Cada palabra debe cargar información
Ver la habilidad design-cli-output para patrones detallados de salida de terminal.
Esperado: Salida ceremonial que sigue todas las reglas de voz y produce narrativas cálidas e informativas.
En caso de fallo: Si la salida ceremonial se siente forzada o no añade información más allá de la salida estándar, saltarla. No todo comando necesita una variante ceremonial.
Paso 6: Manejar Errores y Casos Límite
// Unknown item
if (!item) {
reporter.error(`Unknown: ${name}. Use 'tool list' to browse.`);
process.exit(1);
}
// Confirmation for destructive actions
if (!options.yes && !options.quiet && !options.dryRun) {
const answer = await askYesNo('Proceed?');
if (!answer) {
console.log(' Cancelled.');
return;
}
}
// State validation
if (!state.fires[name]) {
reporter.error(`Not active. Nothing to remove.`);
process.exit(1);
}
Principios de diseño de errores:
- Los mensajes de error sugieren la acción correctiva
process.exit(1)para errores irrecuperables- Prompts de confirmación para operaciones destructivas (saltar con
--yes) - Dry-run siempre tiene éxito (nunca bloquea en confirmación)
Esperado: Todos los caminos de error producen mensajes útiles. Las operaciones destructivas requieren confirmación.
En caso de fallo: Si los prompts de confirmación interfieren con scripting, asegurar que --yes y --quiet ambos los sorteen.
Paso 7: Escribir Pruebas de Integración
import { describe, it, after } from 'node:test';
import assert from 'node:assert/strict';
import { execSync } from 'child_process';
const CLI = 'node cli/index.js';
function run(args) {
return execSync(`${CLI} ${args}`, { encoding: 'utf8', timeout: 10000 });
}
describe('new-command', () => {
after(() => { /* cleanup created files/state */ });
it('dry-run shows preview', () => {
const out = run('new-command arg --dry-run');
assert.match(out, /DRY RUN/);
});
it('--json outputs valid JSON', () => {
const out = run('new-command arg --json');
const start = out.indexOf('{');
const data = JSON.parse(out.slice(start));
assert.equal(data.command, 'new-command');
});
it('rejects unknown input', () => {
assert.throws(() => run('new-command nonexistent'), /Unknown/);
});
});
Ver la habilidad test-cli-application para patrones comprensivos de pruebas de CLI.
Esperado: Al menos 3 pruebas: dry-run, salida JSON, caso de error. Más para comandos complejos.
En caso de fallo: Si execSync hace timeout, aumentar el timeout o verificar prompts interactivos bloqueando el comando.
Validación
- El comando está registrado en el punto de entrada de la CLI y aparece en
--help - Las opciones estándar (
--dry-run,--quiet,--json) funcionan correctamente - La salida predeterminada es legible para humanos e informativa
- La salida JSON es válida y parseable
- Los mensajes de error sugieren acciones correctivas
- Las operaciones destructivas requieren confirmación (sorteadas por
--yes) - Al menos 3 pruebas de integración pasan
- El comando sigue el patrón getContext → resolver → ejecutar → salida
Errores Comunes
- Olvidar el modo JSON: Los consumidores de máquina (scripts, CI) dependen de salida estructurada. Siempre implementar
--jsonincluso si el comando parece solo-interactivo. - Prompts de confirmación bloqueando scripts: Cualquier comando que pida entrada se colgará en contextos no-interactivos. Siempre proveer
--yespara comandos destructivos y asegurar que--quietsuprima prompts. - Códigos de salida de error inconsistentes: Usar
process.exit(1)para todos los errores. Las herramientas que parsean salida de CLI verifican códigos de salida primero. - Opciones sin predeterminados: Opciones como
--scopedeben tener predeterminados sensatos para que los usuarios no necesiten especificarlos cada vez. - Filtrar ceremonia al modo quiet: El flag
--quietsignifica "salida mínima para máquinas." Si el texto de ceremonia se filtra al modo quiet, los scripts se romperán por salida inesperada.
Habilidades Relacionadas
build-cli-plugin— construir el adaptador/plugin sobre el que operan los comandostest-cli-application— patrones comprensivos de pruebas de CLI más allá de los básicos en el Paso 7design-cli-output— diseño de salida de terminal para todos los niveles de verbosidadinstall-almanac-content— ejemplo de una habilidad de comando CLI bien estructurada
GitHub 저장소
연관 스킬
evaluating-llms-harness
테스팅이 Claude Skill은 MMLU, GSM8K를 포함한 60개 이상의 표준화된 학술 과제에서 LLM 성능을 벤치마크하기 위해 lm-evaluation-harness를 실행합니다. 개발자들이 모델 품질을 비교하고, 학습 진행 상황을 추적하거나 학술 결과를 보고할 수 있도록 설계되었습니다. 이 도구는 HuggingFace와 vLLM 모델을 포함한 다양한 백엔드를 지원합니다.
cloudflare-cron-triggers
테스팅이 스킬은 cron 표현식을 사용하여 Worker를 스케줄링하기 위한 Cloudflare Cron Triggers 구현에 관한 포괄적인 지식을 제공합니다. 주기적 작업, 유지보수 작업, 자동화된 워크플로우 설정 방법을 다루며, 잘못된 cron 표현식이나 시간대 문제 같은 일반적인 이슈들을 해결하는 방법을 포함합니다. 개발자들은 이를 통해 스케줄된 핸들러 구성, cron 트리거 테스트, Workflows 및 Green Compute와의 연동 작업을 수행할 수 있습니다.
webapp-testing
테스팅이 Claude Skill은 Python 스크립트를 통해 로컬 웹 애플리케이션을 테스트하기 위한 Playwright 기반 툴킷을 제공합니다. 프론트엔드 검증, UI 디버깅, 스크린샷 캡처, 로그 확인 기능을 지원하며 서버 라이프사이클을 관리합니다. 브라우저 자동화 작업에 사용하되 컨텍스트 오염을 방지하기 위해 소스 코드를 읽지 않고 스크립트를 직접 실행하세요.
finishing-a-development-branch
테스팅이 스킬은 테스트 통과를 확인한 후 체계적인 통합 옵션을 제시하여 개발자가 완성된 작업을 마무리하도록 돕습니다. 구현이 완료된 후 머지, PR 생성, 브랜치 정리와 같은 워크플로우를 안내합니다. 코드가 준비되고 테스트가 완료되었을 때 개발 프로세스를 체계적으로 마무리하기 위해 사용하세요.
