701 lines
23 KiB
JavaScript
701 lines
23 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* 인터랙티브 CLI - 단계별 승인 기능
|
||
* 각 에이전트 실행 전 사용자 확인을 받고 진행
|
||
*/
|
||
import 'dotenv/config';
|
||
import * as readline from 'readline';
|
||
import Anthropic from '@anthropic-ai/sdk';
|
||
import { agentDefinitions } from './agents/definitions.js';
|
||
import type { WorkflowResult, WorkflowStep, AgentType, AgentResult } from './types/index.js';
|
||
|
||
const PROJECT_ROOT = process.env.G7_PROJECT_ROOT || '.';
|
||
|
||
// 색상 코드
|
||
const colors = {
|
||
reset: '\x1b[0m',
|
||
bright: '\x1b[1m',
|
||
dim: '\x1b[2m',
|
||
red: '\x1b[31m',
|
||
green: '\x1b[32m',
|
||
yellow: '\x1b[33m',
|
||
blue: '\x1b[34m',
|
||
magenta: '\x1b[35m',
|
||
cyan: '\x1b[36m',
|
||
white: '\x1b[37m',
|
||
bgBlue: '\x1b[44m',
|
||
bgGreen: '\x1b[42m',
|
||
bgYellow: '\x1b[43m',
|
||
bgRed: '\x1b[41m',
|
||
};
|
||
|
||
// 에이전트별 색상
|
||
const agentColors: Record<string, string> = {
|
||
backend: colors.blue,
|
||
frontend: colors.magenta,
|
||
layout: colors.cyan,
|
||
template: colors.yellow,
|
||
reviewer: colors.green,
|
||
coordinator: colors.white,
|
||
};
|
||
|
||
/**
|
||
* 인터랙티브 세션 클래스
|
||
*/
|
||
class InteractiveSession {
|
||
private rl: readline.Interface;
|
||
private client: Anthropic;
|
||
private result: WorkflowResult;
|
||
private currentStep: number = 0;
|
||
|
||
constructor() {
|
||
this.rl = readline.createInterface({
|
||
input: process.stdin,
|
||
output: process.stdout,
|
||
});
|
||
|
||
this.client = new Anthropic({
|
||
apiKey: process.env.ANTHROPIC_API_KEY,
|
||
});
|
||
|
||
this.result = {
|
||
success: false,
|
||
steps: [],
|
||
totalCost: 0,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 세션 시작
|
||
*/
|
||
async start(): Promise<void> {
|
||
this.printBanner();
|
||
this.promptUser();
|
||
}
|
||
|
||
/**
|
||
* 배너 출력
|
||
*/
|
||
private printBanner(): void {
|
||
console.log(`
|
||
${colors.bgBlue}${colors.bright} ${colors.reset}
|
||
${colors.bgBlue}${colors.bright} 그누보드7 Multi-Agent Interactive System v1.0.0 ${colors.reset}
|
||
${colors.bgBlue}${colors.bright} ${colors.reset}
|
||
|
||
${colors.cyan}사용 가능한 명령어:${colors.reset}
|
||
${colors.yellow}/feature${colors.reset} <설명> - 기능 개발 (단계별 승인)
|
||
${colors.yellow}/bugfix${colors.reset} <설명> - 버그 수정 (단계별 승인)
|
||
${colors.yellow}/quick${colors.reset} <요청> - 빠른 실행 (승인 없이)
|
||
${colors.yellow}/agents${colors.reset} - 에이전트 목록
|
||
${colors.yellow}/help${colors.reset} - 도움말
|
||
${colors.yellow}/exit${colors.reset} - 종료
|
||
|
||
${colors.dim}또는 자유롭게 요청을 입력하세요. (단계별 승인 모드)${colors.reset}
|
||
`);
|
||
}
|
||
|
||
/**
|
||
* 사용자 입력 대기
|
||
*/
|
||
private promptUser(): void {
|
||
this.rl.question(`\n${colors.green}🤖 >${colors.reset} `, async (input) => {
|
||
const trimmedInput = input.trim();
|
||
|
||
if (!trimmedInput) {
|
||
this.promptUser();
|
||
return;
|
||
}
|
||
|
||
await this.handleInput(trimmedInput);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 입력 처리
|
||
*/
|
||
private async handleInput(input: string): Promise<void> {
|
||
// 종료
|
||
if (input === '/exit' || input === 'exit') {
|
||
console.log(`\n${colors.cyan}👋 안녕히 가세요!${colors.reset}`);
|
||
this.rl.close();
|
||
return;
|
||
}
|
||
|
||
// 도움말
|
||
if (input === '/help') {
|
||
this.showHelp();
|
||
this.promptUser();
|
||
return;
|
||
}
|
||
|
||
// 에이전트 목록
|
||
if (input === '/agents') {
|
||
this.showAgents();
|
||
this.promptUser();
|
||
return;
|
||
}
|
||
|
||
// 기능 개발
|
||
if (input.startsWith('/feature ')) {
|
||
const description = input.substring(9);
|
||
await this.runFeatureWorkflow(description);
|
||
this.promptUser();
|
||
return;
|
||
}
|
||
|
||
// 버그 수정
|
||
if (input.startsWith('/bugfix ')) {
|
||
const description = input.substring(8);
|
||
await this.runBugfixWorkflow(description);
|
||
this.promptUser();
|
||
return;
|
||
}
|
||
|
||
// 빠른 실행 (승인 없이)
|
||
if (input.startsWith('/quick ')) {
|
||
const prompt = input.substring(7);
|
||
await this.runQuickMode(prompt);
|
||
this.promptUser();
|
||
return;
|
||
}
|
||
|
||
// 자유 형식 (단계별 승인)
|
||
await this.runWithApproval(input);
|
||
this.promptUser();
|
||
}
|
||
|
||
/**
|
||
* 기능 개발 워크플로우 (단계별 승인)
|
||
*/
|
||
private async runFeatureWorkflow(description: string): Promise<void> {
|
||
console.log(`\n${colors.bgGreen}${colors.bright} 기능 개발 워크플로우 ${colors.reset}`);
|
||
console.log(`${colors.dim}설명: ${description}${colors.reset}\n`);
|
||
|
||
this.result = { success: false, steps: [], totalCost: 0 };
|
||
|
||
// 워크플로우 단계 정의
|
||
const workflow: Array<{ agent: AgentType; task: string }> = [
|
||
{ agent: 'backend', task: `백엔드 구현: ${description}` },
|
||
{ agent: 'layout', task: `레이아웃 JSON 작성: ${description}` },
|
||
{ agent: 'frontend', task: `프론트엔드 컴포넌트 개발 (필요시): ${description}` },
|
||
{ agent: 'template', task: `템플릿 빌드 및 컴포넌트 등록: ${description}` },
|
||
{ agent: 'reviewer', task: `코드 검수: ${description}` },
|
||
];
|
||
|
||
// 워크플로우 개요 표시
|
||
this.printWorkflowPlan(workflow);
|
||
|
||
// 각 단계 실행
|
||
for (let i = 0; i < workflow.length; i++) {
|
||
const step = workflow[i];
|
||
const approved = await this.requestApproval(i + 1, workflow.length, step.agent, step.task);
|
||
|
||
if (!approved) {
|
||
console.log(`\n${colors.yellow}⏭️ ${step.agent} 단계를 건너뜁니다.${colors.reset}`);
|
||
this.result.steps.push({
|
||
agent: step.agent,
|
||
task: step.task,
|
||
status: 'skipped',
|
||
});
|
||
continue;
|
||
}
|
||
|
||
await this.executeAgent(step.agent, step.task);
|
||
}
|
||
|
||
this.printFinalResult();
|
||
}
|
||
|
||
/**
|
||
* 버그 수정 워크플로우 (단계별 승인)
|
||
*/
|
||
private async runBugfixWorkflow(description: string): Promise<void> {
|
||
console.log(`\n${colors.bgYellow}${colors.bright} 버그 수정 워크플로우 ${colors.reset}`);
|
||
console.log(`${colors.dim}설명: ${description}${colors.reset}\n`);
|
||
|
||
this.result = { success: false, steps: [], totalCost: 0 };
|
||
|
||
// 1단계: 분석
|
||
console.log(`${colors.cyan}📋 버그 영향 영역을 분석합니다...${colors.reset}\n`);
|
||
|
||
const analysisPrompt = `
|
||
다음 버그 설명을 분석하고, 영향 받는 영역을 판단해주세요:
|
||
|
||
버그 설명: ${description}
|
||
|
||
그누보드7 프로젝트의 영역:
|
||
- backend: Service, Repository, Controller, FormRequest 등 PHP 코드
|
||
- frontend: TSX 컴포넌트, React 코드
|
||
- layout: 레이아웃 JSON 파일
|
||
- template: 템플릿 설정, 빌드
|
||
|
||
어떤 영역이 영향 받는지 알려주세요. 답변 형식:
|
||
영향 영역: [backend/frontend/layout/template] (쉼표로 구분)
|
||
분석 근거: [간단한 설명]
|
||
`;
|
||
|
||
const analysis = await this.callClaude(analysisPrompt);
|
||
console.log(`${colors.dim}${analysis}${colors.reset}\n`);
|
||
|
||
// 영역 추출 (간단한 파싱)
|
||
const affectedAreas: AgentType[] = [];
|
||
const lowerAnalysis = analysis.toLowerCase();
|
||
if (lowerAnalysis.includes('backend')) affectedAreas.push('backend');
|
||
if (lowerAnalysis.includes('frontend')) affectedAreas.push('frontend');
|
||
if (lowerAnalysis.includes('layout')) affectedAreas.push('layout');
|
||
if (lowerAnalysis.includes('template')) affectedAreas.push('template');
|
||
|
||
if (affectedAreas.length === 0) {
|
||
affectedAreas.push('backend'); // 기본값
|
||
}
|
||
|
||
// 워크플로우 구성
|
||
const workflow: Array<{ agent: AgentType; task: string }> = [];
|
||
|
||
// 트러블슈팅 가이드 참조 단계
|
||
workflow.push({
|
||
agent: 'reviewer',
|
||
task: `트러블슈팅 가이드에서 유사 사례 확인: ${description}`,
|
||
});
|
||
|
||
// 영향 받는 영역별 수정
|
||
for (const area of affectedAreas) {
|
||
workflow.push({
|
||
agent: area,
|
||
task: `버그 수정 (TDD 방식): ${description}`,
|
||
});
|
||
}
|
||
|
||
// 최종 검수
|
||
workflow.push({
|
||
agent: 'reviewer',
|
||
task: `테스트 통과 확인 및 최종 검수: ${description}`,
|
||
});
|
||
|
||
// 워크플로우 개요 표시
|
||
this.printWorkflowPlan(workflow);
|
||
|
||
// 각 단계 실행
|
||
for (let i = 0; i < workflow.length; i++) {
|
||
const step = workflow[i];
|
||
const approved = await this.requestApproval(i + 1, workflow.length, step.agent, step.task);
|
||
|
||
if (!approved) {
|
||
console.log(`\n${colors.yellow}⏭️ ${step.agent} 단계를 건너뜁니다.${colors.reset}`);
|
||
this.result.steps.push({
|
||
agent: step.agent,
|
||
task: step.task,
|
||
status: 'skipped',
|
||
});
|
||
continue;
|
||
}
|
||
|
||
await this.executeAgent(step.agent, step.task);
|
||
}
|
||
|
||
this.printFinalResult();
|
||
}
|
||
|
||
/**
|
||
* 단계별 승인 모드로 자유 형식 요청 실행
|
||
*/
|
||
private async runWithApproval(prompt: string): Promise<void> {
|
||
console.log(`\n${colors.bgBlue}${colors.bright} 요청 처리 ${colors.reset}`);
|
||
console.log(`${colors.dim}${prompt}${colors.reset}\n`);
|
||
|
||
this.result = { success: false, steps: [], totalCost: 0 };
|
||
|
||
// 요청 분석
|
||
console.log(`${colors.cyan}📋 요청을 분석하고 워크플로우를 계획합니다...${colors.reset}\n`);
|
||
|
||
const planPrompt = `
|
||
다음 요청을 분석하고 실행 계획을 세워주세요:
|
||
|
||
요청: ${prompt}
|
||
|
||
그누보드7 프로젝트의 에이전트:
|
||
- backend: 백엔드 개발 (Service, Repository, Controller, FormRequest, Migration)
|
||
- frontend: 프론트엔드 개발 (TSX 컴포넌트, 상태 관리)
|
||
- layout: 레이아웃 개발 (JSON 스키마, 데이터 바인딩)
|
||
- template: 템플릿 개발 (빌드, 컴포넌트 등록)
|
||
- reviewer: 코드 검수 (규정 준수, 테스트)
|
||
|
||
어떤 에이전트가 어떤 순서로 작업해야 하는지 계획해주세요.
|
||
|
||
답변 형식 (JSON):
|
||
{
|
||
"steps": [
|
||
{ "agent": "backend", "task": "구체적인 작업 내용" },
|
||
{ "agent": "layout", "task": "구체적인 작업 내용" }
|
||
]
|
||
}
|
||
`;
|
||
|
||
const planResponse = await this.callClaude(planPrompt);
|
||
|
||
// JSON 파싱 시도
|
||
let workflow: Array<{ agent: AgentType; task: string }> = [];
|
||
try {
|
||
const jsonMatch = planResponse.match(/\{[\s\S]*\}/);
|
||
if (jsonMatch) {
|
||
const plan = JSON.parse(jsonMatch[0]);
|
||
workflow = plan.steps || [];
|
||
}
|
||
} catch {
|
||
// 파싱 실패 시 기본 워크플로우
|
||
console.log(`${colors.dim}${planResponse}${colors.reset}\n`);
|
||
workflow = [{ agent: 'backend', task: prompt }];
|
||
}
|
||
|
||
if (workflow.length === 0) {
|
||
workflow = [{ agent: 'backend', task: prompt }];
|
||
}
|
||
|
||
// 워크플로우 개요 표시
|
||
this.printWorkflowPlan(workflow);
|
||
|
||
// 각 단계 실행
|
||
for (let i = 0; i < workflow.length; i++) {
|
||
const step = workflow[i];
|
||
const validAgent = this.validateAgent(step.agent);
|
||
const approved = await this.requestApproval(i + 1, workflow.length, validAgent, step.task);
|
||
|
||
if (!approved) {
|
||
console.log(`\n${colors.yellow}⏭️ ${validAgent} 단계를 건너뜁니다.${colors.reset}`);
|
||
this.result.steps.push({
|
||
agent: validAgent,
|
||
task: step.task,
|
||
status: 'skipped',
|
||
});
|
||
continue;
|
||
}
|
||
|
||
await this.executeAgent(validAgent, step.task);
|
||
}
|
||
|
||
this.printFinalResult();
|
||
}
|
||
|
||
/**
|
||
* 빠른 모드 (승인 없이)
|
||
*/
|
||
private async runQuickMode(prompt: string): Promise<void> {
|
||
console.log(`\n${colors.bgBlue}${colors.bright} 빠른 실행 ${colors.reset}`);
|
||
console.log(`${colors.dim}승인 없이 자동으로 실행됩니다.${colors.reset}\n`);
|
||
|
||
this.result = { success: false, steps: [], totalCost: 0 };
|
||
|
||
// 단일 에이전트로 빠른 실행
|
||
await this.executeAgent('backend', prompt);
|
||
this.printFinalResult();
|
||
}
|
||
|
||
/**
|
||
* 워크플로우 계획 출력
|
||
*/
|
||
private printWorkflowPlan(workflow: Array<{ agent: AgentType; task: string }>): void {
|
||
console.log(`${colors.bright}📊 실행 계획:${colors.reset}\n`);
|
||
|
||
workflow.forEach((step, index) => {
|
||
const agentColor = agentColors[step.agent] || colors.white;
|
||
console.log(` ${colors.dim}${index + 1}.${colors.reset} ${agentColor}[${step.agent}]${colors.reset} ${step.task}`);
|
||
});
|
||
|
||
console.log('');
|
||
}
|
||
|
||
/**
|
||
* 승인 요청
|
||
*/
|
||
private async requestApproval(
|
||
current: number,
|
||
total: number,
|
||
agent: AgentType,
|
||
task: string
|
||
): Promise<boolean> {
|
||
const agentColor = agentColors[agent] || colors.white;
|
||
|
||
console.log(`\n${colors.bright}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`);
|
||
console.log(`${colors.bright}단계 ${current}/${total}${colors.reset}`);
|
||
console.log(`${colors.bright}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`);
|
||
console.log(`\n${agentColor}🤖 에이전트: ${agent}${colors.reset}`);
|
||
console.log(`${colors.dim}📋 작업: ${task}${colors.reset}\n`);
|
||
|
||
// 에이전트 설명 표시
|
||
const agentDef = agentDefinitions[agent];
|
||
if (agentDef) {
|
||
console.log(`${colors.dim}ℹ️ ${agentDef.description}${colors.reset}\n`);
|
||
}
|
||
|
||
return new Promise((resolve) => {
|
||
this.rl.question(
|
||
`${colors.yellow}실행하시겠습니까? ${colors.reset}[${colors.green}Y${colors.reset}es/${colors.red}N${colors.reset}o/${colors.cyan}S${colors.reset}kip all] `,
|
||
(answer) => {
|
||
const lowerAnswer = answer.toLowerCase().trim();
|
||
|
||
if (lowerAnswer === 'n' || lowerAnswer === 'no') {
|
||
resolve(false);
|
||
} else if (lowerAnswer === 's' || lowerAnswer === 'skip') {
|
||
// Skip all은 모든 후속 단계를 건너뜀
|
||
resolve(false);
|
||
} else {
|
||
resolve(true);
|
||
}
|
||
}
|
||
);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 에이전트 실행
|
||
*/
|
||
private async executeAgent(agent: AgentType, task: string): Promise<void> {
|
||
const agentColor = agentColors[agent] || colors.white;
|
||
const agentDef = agentDefinitions[agent];
|
||
|
||
console.log(`\n${agentColor}▶ ${agent} 에이전트 실행 중...${colors.reset}\n`);
|
||
|
||
const step: WorkflowStep = {
|
||
agent,
|
||
task,
|
||
status: 'running',
|
||
};
|
||
this.result.steps.push(step);
|
||
|
||
try {
|
||
// 에이전트 시스템 프롬프트 + 작업
|
||
const systemPrompt = agentDef?.prompt || '';
|
||
const fullPrompt = `
|
||
${systemPrompt}
|
||
|
||
## 현재 작업
|
||
${task}
|
||
|
||
## 프로젝트 경로
|
||
${PROJECT_ROOT}
|
||
|
||
## 지시사항
|
||
1. 위 작업을 수행하세요.
|
||
2. 필요한 파일을 읽고 수정하세요.
|
||
3. 작업 완료 후 결과를 요약해주세요.
|
||
`;
|
||
|
||
const response = await this.callClaude(fullPrompt);
|
||
|
||
step.status = 'completed';
|
||
step.result = {
|
||
success: true,
|
||
agent: agent,
|
||
task: task,
|
||
output: response,
|
||
};
|
||
|
||
// 결과 출력 (요약)
|
||
console.log(`${colors.dim}─────────────────────────────────────────────${colors.reset}`);
|
||
const summary = response.length > 500 ? response.substring(0, 500) + '...' : response;
|
||
console.log(`${colors.dim}${summary}${colors.reset}`);
|
||
console.log(`${colors.dim}─────────────────────────────────────────────${colors.reset}`);
|
||
|
||
console.log(`\n${colors.green}✅ ${agent} 완료${colors.reset}`);
|
||
|
||
} catch (error: any) {
|
||
step.status = 'failed';
|
||
step.result = {
|
||
success: false,
|
||
agent: agent,
|
||
task: task,
|
||
output: '',
|
||
errors: [error.message],
|
||
};
|
||
|
||
console.log(`\n${colors.red}❌ ${agent} 실패: ${error.message}${colors.reset}`);
|
||
this.result.errors = this.result.errors || [];
|
||
this.result.errors.push(`[${agent}] ${error.message}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* AI API 호출
|
||
*/
|
||
private async callClaude(prompt: string): Promise<string> {
|
||
const response = await this.client.messages.create({
|
||
model: 'claude-sonnet-4-20250514',
|
||
max_tokens: 4096,
|
||
messages: [
|
||
{ role: 'user', content: prompt },
|
||
],
|
||
});
|
||
|
||
// 비용 계산 (대략적)
|
||
const inputTokens = response.usage?.input_tokens || 0;
|
||
const outputTokens = response.usage?.output_tokens || 0;
|
||
const cost = (inputTokens * 0.003 + outputTokens * 0.015) / 1000;
|
||
this.result.totalCost += cost;
|
||
|
||
const textContent = response.content.find((c: { type: string }) => c.type === 'text') as { type: 'text'; text: string } | undefined;
|
||
return textContent?.text || '';
|
||
}
|
||
|
||
/**
|
||
* 에이전트 타입 검증
|
||
*/
|
||
private validateAgent(agent: string): AgentType {
|
||
const validAgents: AgentType[] = ['backend', 'frontend', 'layout', 'template', 'reviewer'];
|
||
if (validAgents.includes(agent as AgentType)) {
|
||
return agent as AgentType;
|
||
}
|
||
return 'backend'; // 기본값
|
||
}
|
||
|
||
/**
|
||
* 최종 결과 출력
|
||
*/
|
||
private printFinalResult(): void {
|
||
const completedSteps = this.result.steps.filter(s => s.status === 'completed').length;
|
||
const totalSteps = this.result.steps.length;
|
||
|
||
this.result.success = completedSteps > 0 && !this.result.errors?.length;
|
||
|
||
console.log(`\n${colors.bright}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`);
|
||
console.log(`${colors.bright} 최종 결과 ${colors.reset}`);
|
||
console.log(`${colors.bright}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}\n`);
|
||
|
||
if (this.result.success) {
|
||
console.log(`${colors.green}✅ 작업 완료${colors.reset}\n`);
|
||
} else {
|
||
console.log(`${colors.red}❌ 작업 실패${colors.reset}\n`);
|
||
}
|
||
|
||
// 단계별 결과
|
||
console.log(`${colors.bright}📊 실행 단계 (${completedSteps}/${totalSteps}):${colors.reset}\n`);
|
||
|
||
this.result.steps.forEach((step, index) => {
|
||
const agentColor = agentColors[step.agent] || colors.white;
|
||
let statusIcon: string;
|
||
let statusColor: string;
|
||
|
||
switch (step.status) {
|
||
case 'completed':
|
||
statusIcon = '✅';
|
||
statusColor = colors.green;
|
||
break;
|
||
case 'failed':
|
||
statusIcon = '❌';
|
||
statusColor = colors.red;
|
||
break;
|
||
case 'skipped':
|
||
statusIcon = '⏭️';
|
||
statusColor = colors.yellow;
|
||
break;
|
||
default:
|
||
statusIcon = '⏳';
|
||
statusColor = colors.dim;
|
||
}
|
||
|
||
console.log(` ${statusIcon} ${agentColor}[${step.agent}]${colors.reset} ${statusColor}${step.task}${colors.reset}`);
|
||
});
|
||
|
||
// 오류
|
||
if (this.result.errors?.length) {
|
||
console.log(`\n${colors.red}⚠️ 오류:${colors.reset}`);
|
||
this.result.errors.forEach(e => {
|
||
console.log(` ${colors.red}- ${e}${colors.reset}`);
|
||
});
|
||
}
|
||
|
||
// 비용
|
||
console.log(`\n${colors.cyan}💰 총 비용: $${this.result.totalCost.toFixed(4)}${colors.reset}`);
|
||
console.log(`${colors.bright}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`);
|
||
}
|
||
|
||
/**
|
||
* 에이전트 목록 표시
|
||
*/
|
||
private showAgents(): void {
|
||
console.log(`\n${colors.bright}🤖 사용 가능한 에이전트:${colors.reset}\n`);
|
||
|
||
Object.entries(agentDefinitions).forEach(([name, def]) => {
|
||
const agentColor = agentColors[name] || colors.white;
|
||
console.log(` ${agentColor}${name}${colors.reset}`);
|
||
console.log(` ${colors.dim}${def.description}${colors.reset}`);
|
||
console.log(` ${colors.dim}도구: ${(def.tools || []).join(', ')}${colors.reset}`);
|
||
console.log('');
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 도움말 표시
|
||
*/
|
||
private showHelp(): void {
|
||
console.log(`
|
||
${colors.bright}📖 그누보드7 Multi-Agent Interactive System 도움말${colors.reset}
|
||
|
||
${colors.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}
|
||
|
||
${colors.bright}🔧 워크플로우 명령어 (단계별 승인):${colors.reset}
|
||
|
||
${colors.yellow}/feature${colors.reset} <설명>
|
||
새로운 기능을 개발합니다.
|
||
각 단계 실행 전 승인을 요청합니다.
|
||
${colors.dim}예: /feature 상품 할인 기능 추가${colors.reset}
|
||
|
||
${colors.yellow}/bugfix${colors.reset} <설명>
|
||
버그를 수정합니다. 영향 영역을 분석하고 TDD 방식으로 진행합니다.
|
||
${colors.dim}예: /bugfix Form 저장 시 데이터가 사라지는 문제${colors.reset}
|
||
|
||
${colors.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}
|
||
|
||
${colors.bright}⚡ 빠른 실행:${colors.reset}
|
||
|
||
${colors.yellow}/quick${colors.reset} <요청>
|
||
승인 없이 빠르게 실행합니다.
|
||
${colors.dim}예: /quick package.json 파일 분석해줘${colors.reset}
|
||
|
||
${colors.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}
|
||
|
||
${colors.bright}📚 자유 형식 요청:${colors.reset}
|
||
|
||
명령어 없이 자유롭게 입력하면 요청을 분석하여
|
||
워크플로우를 자동으로 구성하고 단계별 승인을 받습니다.
|
||
|
||
${colors.dim}예: "ProductService의 할인 로직을 구현해줘"${colors.reset}
|
||
|
||
${colors.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}
|
||
|
||
${colors.bright}⌨️ 승인 옵션:${colors.reset}
|
||
|
||
${colors.green}Y${colors.reset}/yes - 실행
|
||
${colors.red}N${colors.reset}/no - 건너뛰기
|
||
${colors.cyan}S${colors.reset}/skip - 이후 모든 단계 건너뛰기
|
||
|
||
${colors.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}
|
||
|
||
${colors.bright}⌨️ 기타 명령어:${colors.reset}
|
||
|
||
${colors.yellow}/agents${colors.reset} - 에이전트 목록
|
||
${colors.yellow}/help${colors.reset} - 이 도움말
|
||
${colors.yellow}/exit${colors.reset} - 종료
|
||
|
||
${colors.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}
|
||
`);
|
||
}
|
||
}
|
||
|
||
// 메인 실행
|
||
async function main() {
|
||
// API 키 확인
|
||
if (!process.env.ANTHROPIC_API_KEY) {
|
||
console.error(`${colors.red}❌ ANTHROPIC_API_KEY가 설정되지 않았습니다.${colors.reset}`);
|
||
console.error(`${colors.dim}.env 파일에 API 키를 설정해주세요.${colors.reset}`);
|
||
process.exit(1);
|
||
}
|
||
|
||
const session = new InteractiveSession();
|
||
await session.start();
|
||
}
|
||
|
||
main().catch((error) => {
|
||
console.error(`${colors.red}❌ 오류: ${error.message}${colors.reset}`);
|
||
process.exit(1);
|
||
});
|