📝 docs: 여러 문서 및 파일 삭제
This commit is contained in:
275
.claude/skills/squad-orchestration/scripts/squad-orchestrator.js
Executable file
275
.claude/skills/squad-orchestration/scripts/squad-orchestrator.js
Executable file
@@ -0,0 +1,275 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* squad-orchestrator.js - AI 개발 스쿼드(Squad) 오케스트레이터
|
||||
*
|
||||
* 하나의 컴포넌트/피처 요건을 입력받아 3가지 전문 에이전트 역할군으로 작업을 쪼개고,
|
||||
* 각 에이전트에 줄 지시서와 전체 프로세스를 시뮬레이션/오케스트레이션하는 마스터 러너 파일을 생성합니다.
|
||||
*
|
||||
* 에이전트 스쿼드 구성:
|
||||
* 1. UI/마크업 스페셜리스트 (Markup Specialist): 구조 설계, 렌더링, Tailwind CSS 스타일링 및 기본 상태 바인딩.
|
||||
* 2. 웹 접근성 스페셜리스트 (A11y/UX Specialist): WCAG 2.1 AA 기준 준수, ARIA 레이블링, 키보드 인터랙션 강화.
|
||||
* 3. QA/유닛 테스트 스페셜리스트 (Testing Specialist): Vitest 기반 유닛 테스트 스위트 작성 및 품질 보증.
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const readline = require('readline');
|
||||
|
||||
const CWD = process.cwd();
|
||||
const SQUAD_ROOT = path.join(CWD, 'squad');
|
||||
|
||||
// 헬퍼: 디렉토리 자동 생성
|
||||
function ensureDirectory(dirPath) {
|
||||
if (!fs.existsSync(dirPath)) {
|
||||
fs.mkdirSync(dirPath, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
// 헬퍼: 파일 작성
|
||||
function writeFile(filePath, content) {
|
||||
const dir = path.dirname(filePath);
|
||||
ensureDirectory(dir);
|
||||
fs.writeFileSync(filePath, content, 'utf8');
|
||||
}
|
||||
|
||||
// CLI 인자 파싱
|
||||
function parseArgs() {
|
||||
const args = process.argv.slice(2);
|
||||
const result = { name: '', spec: '' };
|
||||
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
if (args[i] === '--name' || args[i] === '-n') {
|
||||
result.name = args[i + 1] || '';
|
||||
i++;
|
||||
} else if (args[i] === '--spec' || args[i] === '-s') {
|
||||
result.spec = args[i + 1] || '';
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// 지시서 생성 로직
|
||||
function generateSquadTasks(componentName, specification) {
|
||||
const lowercaseName = componentName.toLowerCase();
|
||||
const componentPath = `components/${componentName}.vue`;
|
||||
const testPath = `components/${componentName}.spec.ts`;
|
||||
const taskDir = path.join(SQUAD_ROOT, componentName);
|
||||
|
||||
// 1. Markup Specialist 지시서
|
||||
const markupTask = `# 🎨 Role 1: UI/마크업 스페셜리스트 지시서
|
||||
|
||||
## 목표
|
||||
- 요구사항에 맞는 컴포넌트 구조(Vue 3 / SFC)를 생성하고 Tailwind CSS를 이용해 아름답고 완벽한 반응형 UI를 스타일링합니다.
|
||||
- 복잡하지 않은 수준에서 데이터 수신을 위한 Props 정의 및 이벤트를 내보내기 위한 Emits를 설계합니다.
|
||||
|
||||
## 개발 대상 파일
|
||||
- \`${componentPath}\`
|
||||
|
||||
## 기술 요건 (framework-rules.md 준수)
|
||||
- \`<script setup lang="ts">\` 형식을 완벽히 준수해야 합니다.
|
||||
- Tailwind CSS의 유틸리티 클래스 위주로 스타일링하며, 조건부 렌더링 시 가독성 높은 클래스 바인딩을 적용하세요.
|
||||
- 비즈니스 상태가 필요한 경우, 템플릿 코드에 가짜(mock) 반응형 데이터(\`ref\`, \`computed\`)를 연결하여 상태를 구성합니다.
|
||||
|
||||
## 개발 요구사항
|
||||
${specification}
|
||||
|
||||
---
|
||||
|
||||
## 작업 지시 사항
|
||||
1. \`${componentPath}\` 파일을 신규 생성합니다.
|
||||
2. 컴포넌트가 정상적으로 렌더링되고 기본적인 반응형 동작(클릭 이벤트, 폼 입력 바인딩 등)이 원활하게 흐르는지 확인하는 모드에서 코드를 작성하세요.
|
||||
3. 작업 완료 후, 생성된 코드를 출력하여 다음 단계(A11y 검증)로 전달할 수 있게 준비하세요.
|
||||
`;
|
||||
|
||||
// 2. A11y Specialist 지시서
|
||||
const a11yTask = `# ♿ Role 2: 웹 접근성(A11y) 스페셜리스트 지시서
|
||||
|
||||
## 목표
|
||||
- UI 마크업 스페셜리스트가 구현한 \`${componentPath}\` 파일을 검토 및 개선합니다.
|
||||
- WCAG 2.1 AA 및 접근성 검증 지침(\`verify-a11y\`)에 맞춰 전 세계 모든 사용자(스크린 리더 사용자, 키보드 단독 사용자 등)가 사용에 제약이 없도록 인터랙션을 강화합니다.
|
||||
|
||||
## 대상 파일
|
||||
- \`${componentPath}\` (기존 마크업 위에서 수정)
|
||||
|
||||
## 접근성 필수 강화 체크리스트
|
||||
- **시각 대체 수단:** 모든 아이콘 단독 버튼이나 이미지에 적절한 대체 텍스트(\`aria-label\` 또는 \`alt\`)를 적용합니다.
|
||||
- **키보드 내비게이션:** 모든 상호작용 요소에 키보드 포커스가 잡히고(\`tabindex\`), 스페이스 및 엔터 키 입력 시 적절한 동작이 수행되어야 합니다. 모달이나 레이어 팝업이 뜰 경우 탭 인덱스 포커스 트랩(Focus Trap)이 동작해야 합니다.
|
||||
- **의미론적 마크업:** 적절한 HTML5 시맨틱 태그 및 WAI-ARIA 속성(\`role\`, \`aria-expanded\`, \`aria-haspopup\`, \`aria-controls\` 등)을 사용합니다.
|
||||
- **포커스 링 가시성:** 모든 인터랙티브 요소는 포커스를 받았을 때 아웃라인(\`:focus-visible\`)이 명확하게 나타나야 합니다.
|
||||
|
||||
---
|
||||
|
||||
## 작업 지시 사항
|
||||
1. UI 마크업 스페셜리스트가 작성한 \`${componentPath}\` 파일을 상세 분석합니다.
|
||||
2. 접근성 상의 미비점(예: 키보드 미지원 드롭다운, 라벨링이 누락된 버튼 등)을 발견하면 원본 코드의 핵심 구조를 깨지 않는 선에서 **Surgical Changes(최소한의 정밀 수정)**로 접근성 강화 코드를 삽입하세요.
|
||||
3. 주석을 통해 어떤 부분이 접근성 보장을 위해 개선되었는지 기록하세요.
|
||||
`;
|
||||
|
||||
// 3. QA/Testing Specialist 지시서
|
||||
const testingTask = `# 🧪 Role 3: QA/유닛 테스트 스페셜리스트 지시서
|
||||
|
||||
## 목표
|
||||
- 완성된 \`${componentPath}\`에 대해 완벽한 유닛 테스트 케이스를 생성합니다.
|
||||
- 컴포넌트의 비즈니스 반응형 흐름, 엣지 케이스, 이벤트 방출, 컴포넌트 마운트 상태, 그리고 접근성 레이블들의 존재성까지 종합 검증합니다.
|
||||
|
||||
## 대상 파일
|
||||
- \`${testPath}\` (신규 생성)
|
||||
|
||||
## 테스트 시나리오 설계 요건
|
||||
- **마운트 상태 검증:** 기본 props를 전달했을 때 컴포넌트가 깨짐 없이 정상 마운트되고 지정된 요소들이 화면에 나오는지 확인.
|
||||
- **인터랙션/상태 변경 테스트:** 사용자가 클릭, 입력 등을 수행할 때 로컬 상태가 정확히 변하고, 부모 컴포넌트로 적절한 \`emit\`이 전달되는지 검증.
|
||||
- **경계 조건(Edge Cases):** Props 값이 비어있거나, 최대 길이 초과 등 예외 상황에서 에러 메시지가 렌더링되거나 방어 동작이 작동하는지 검증.
|
||||
- **접근성(A11y) 속성 검증:** 주요 클릭 타깃의 \`aria-label\` 유효성, 상태 전이에 따른 \`aria-expanded\`의 동적 변경 값 검증.
|
||||
|
||||
---
|
||||
|
||||
## 작업 지시 사항
|
||||
1. Vitest 및 \`@vue/test-utils\` 조합으로 \`${testPath}\` 파일을 작성합니다.
|
||||
2. 테스트를 실행하여 모든 케이스가 초록색(PASS)을 반환하는지 수동 또는 자동으로 검증하세요.
|
||||
3. 테스트 코드는 가독성이 뛰어나야 하며, 복잡한 상태 관리가 사용된다면 Mocking을 적극적으로 활용하세요.
|
||||
`;
|
||||
|
||||
// 4. Master Run Orchestrator Script (run-squad.js)
|
||||
const masterRunScript = `const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
const COMPONENT_NAME = "${componentName}";
|
||||
const COMPONENT_PATH = "${componentPath}";
|
||||
const TEST_PATH = "${testPath}";
|
||||
|
||||
console.log(\`🚀 [Squad Run] \${COMPONENT_NAME} 스쿼드 개발 자동화 파이프라인 가동!\\n\`);
|
||||
|
||||
function runCommand(command) {
|
||||
try {
|
||||
console.log(\`👉 실행 중: \${command}\`);
|
||||
execSync(command, { stdio: 'inherit' });
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(\`❌ 에러 발생: \${command}\`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 1: Markup Specialist 실행
|
||||
console.log('----------------------------------------------------');
|
||||
console.log('🎨 Phase 1: 마크업 & UI 구현 (Role 1)');
|
||||
console.log('----------------------------------------------------');
|
||||
const markupPrompt = \`squad/\${COMPONENT_NAME}/tasks/01_markup_agent.md 지시서에 명시된 목표와 프레임워크 규칙에 맞추어 \${COMPONENT_PATH} 파일을 먼저 구현해 주세요. 작업을 마친 후에는 코드만 마크다운 파일 등에 별도로 복사해 두는 것이 아니라, 실제 파일로 저장한 다음 상태를 알려주세요.\`;
|
||||
runCommand(\`claude -p "\${markupPrompt}"\`);
|
||||
|
||||
// Phase 2: A11y Specialist 실행
|
||||
console.log('\\n----------------------------------------------------');
|
||||
console.log('♿ Phase 2: WCAG 2.1 AA 웹 접근성 개선 (Role 2)');
|
||||
console.log('----------------------------------------------------');
|
||||
const a11yPrompt = \`squad/\${COMPONENT_NAME}/tasks/02_a11y_agent.md 지시서를 기반으로, 앞서 생성된 \${COMPONENT_PATH} 파일의 코드를 검토하여 접근성을 강화해 주세요. Surgical Changes 원칙에 따라 핵심 마크업은 보존하고 ARIA 속성, 대체 텍스트, 키보드 핸들링만 지능적으로 주입 및 수정한 뒤 저장해 주세요.\`;
|
||||
runCommand(\`claude -p "\${a11yPrompt}"\`);
|
||||
|
||||
// Phase 3: Testing Specialist 실행
|
||||
console.log('\\n----------------------------------------------------');
|
||||
console.log('🧪 Phase 3: QA 및 유닛 테스트 케이스 구축 (Role 3)');
|
||||
console.log('----------------------------------------------------');
|
||||
const testingPrompt = \`squad/\${COMPONENT_NAME}/tasks/03_test_agent.md 지시서에 맞춰 \${TEST_PATH} 유닛 테스트 파일을 생성하고 Vitest를 기반으로 작성해 주세요.\`;
|
||||
runCommand(\`claude -p "\${testingPrompt}"\`);
|
||||
|
||||
// Phase 4: 최종 테스트 검증 및 코드 정리
|
||||
console.log('\\n----------------------------------------------------');
|
||||
console.log('🏁 Phase 4: 전체 스쿼드 통합 테스트 및 코드 정리');
|
||||
console.log('----------------------------------------------------');
|
||||
if (fs.existsSync(TEST_PATH)) {
|
||||
console.log('🔬 Vitest 테스트 실행으로 품질 최종 점검...');
|
||||
runCommand('npx vitest run ' + TEST_PATH);
|
||||
} else {
|
||||
console.log('⚠️ 테스트 파일이 생성되지 않았습니다.');
|
||||
}
|
||||
|
||||
console.log('\\n✨ 모든 에이전트의 스쿼드 협업을 통해 초고품질 컴포넌트가 빌드되었습니다!');
|
||||
console.log(\`📍 컴포넌트 위치: \${COMPONENT_PATH}\`);
|
||||
console.log(\`📍 테스트 파일: \${TEST_PATH}\`);
|
||||
`;
|
||||
|
||||
// 5. Squad Readme
|
||||
const squadReadme = `# 🚀 AI 개발 스쿼드 (Squad) 오케스트레이션 가이드: ${componentName}
|
||||
|
||||
이 폴더는 고품질의 프론트엔드 컴포넌트 개발을 위해 **3가지 전문화된 AI 역할군**을 정의하고 작업을 위임하는 오케스트레이션 패키지입니다.
|
||||
|
||||
## 📁 파일 구조
|
||||
- \`tasks/01_markup_agent.md\`: UI 레이아웃, 마크업 및 기본 구조 설계 지시서
|
||||
- \`tasks/02_a11y_agent.md\`: WCAG 2.1 AA 및 키보드 접근성 개선 지시서
|
||||
- \`tasks/03_test_agent.md\`: Vitest 기반 유닛 테스트 코드 작성 지시서
|
||||
- \`run-squad.js\`: 로컬의 Claude Code를 활용해 세 단계를 연속/자동으로 가동시키는 마스터 오케스트레이터 스크립트
|
||||
|
||||
## 🛠 실행 방법
|
||||
|
||||
### 방법 A: 전체 자동 가동 (Claude Code CLI 이용)
|
||||
프로젝트 루트에서 다음 노드 명령어를 실행하면 세 가지 에이전트 작업이 순차적으로 트리거되고 최종 유닛 테스트 검증까지 완벽히 오토파일럿으로 수행됩니다:
|
||||
|
||||
\`\`\`bash
|
||||
node squad/${componentName}/run-squad.js
|
||||
\`\`\`
|
||||
|
||||
### 방법 B: 수동 협업 가동 (각 전문 에이전트 수동 프롬프트)
|
||||
만약 Claude Code 세션을 단계별로 수동 제어하고 싶다면, 아래 순서대로 각 지시서 파일을 Claude에게 먹여서 진행할 수도 있습니다:
|
||||
|
||||
1. **Step 1:** \`squad/${componentName}/tasks/01_markup_agent.md\` 지시 내용을 Claude에게 전달 후 UI 마크업 파일 생성.
|
||||
2. **Step 2:** \`squad/${componentName}/tasks/02_a11y_agent.md\` 지시 내용을 전달하여 기존 UI 마크업 파일에 접근성 코드 주입.
|
||||
3. **Step 3:** \`squad/${componentName}/tasks/03_test_agent.md\` 지시 내용을 전달하여 Vitest 테스트 세트 확보.
|
||||
4. **Step 4:** 터미널에서 \`npx vitest run components/${componentName}.spec.ts\` 실행 및 검증 완료!
|
||||
`;
|
||||
|
||||
// 파일들 쓰기
|
||||
writeFile(path.join(taskDir, 'tasks/01_markup_agent.md'), markupTask);
|
||||
writeFile(path.join(taskDir, 'tasks/02_a11y_agent.md'), a11yTask);
|
||||
writeFile(path.join(taskDir, 'tasks/03_test_agent.md'), testingTask);
|
||||
writeFile(path.join(taskDir, 'run-squad.js'), masterRunScript);
|
||||
writeFile(path.join(taskDir, 'README.md'), squadReadme);
|
||||
|
||||
return taskDir;
|
||||
}
|
||||
|
||||
// 메인 비화 및 입력 대기 제어
|
||||
function run() {
|
||||
const args = parseArgs();
|
||||
|
||||
if (args.name && args.spec) {
|
||||
console.log(`🤖 전달받은 CLI 아규먼트로 스쿼드를 즉시 세팅합니다...`);
|
||||
const path = generateSquadTasks(args.name, args.spec);
|
||||
console.log(`\n🎉 에이전트 스쿼드가 성공적으로 정렬되었습니다!`);
|
||||
console.log(`📍 위치: ${path}`);
|
||||
console.log(`💬 'node ${path}/run-squad.js' 명령으로 전체 프로세스를 가동하거나 가이드 문서를 읽어보세요.`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// 대화형 질문으로 수행
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
console.log('👥 [Squad Orchestrator] 새로운 고품질 피처 개발을 위해 스쿼드를 조직합니다.');
|
||||
|
||||
rl.question('💬 개발할 컴포넌트/피처 이름을 작성해 주세요 (예: GameScoreBoard): ', (name) => {
|
||||
if (!name.trim()) {
|
||||
console.log('❌ 컴포넌트 이름은 필수입니다. 중단되었습니다.');
|
||||
rl.close();
|
||||
return;
|
||||
}
|
||||
|
||||
rl.question('💬 구현할 세부 요건/기능 스펙을 적어주세요:\n> ', (spec) => {
|
||||
if (!spec.trim()) {
|
||||
spec = '기본적인 반응형 디자인과 상태 데이터 흐름을 갖춘 고품질 컴포넌트 설계';
|
||||
}
|
||||
|
||||
const path = generateSquadTasks(name.trim(), spec.trim());
|
||||
console.log(`\n🎉 에이전트 스쿼드가 성공적으로 정렬되었습니다!`);
|
||||
console.log(`📍 위치: ${path}`);
|
||||
console.log(`💬 'node ${path}/run-squad.js' 명령으로 전체 프로세스를 가동하거나 가이드 문서를 읽어보세요.`);
|
||||
|
||||
rl.close();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
run();
|
||||
Reference in New Issue
Block a user