@su-record/vibe 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +448 -0
- package/agents/backend-python-expert.md +453 -0
- package/agents/database-postgres-expert.md +538 -0
- package/agents/frontend-flutter-expert.md +487 -0
- package/agents/frontend-react-expert.md +424 -0
- package/agents/quality-reviewer.md +542 -0
- package/agents/specification-agent.md +505 -0
- package/bin/sutory +332 -0
- package/bin/vibe +338 -0
- package/mcp/dist/__tests__/complexity.test.js +126 -0
- package/mcp/dist/__tests__/memory.test.js +120 -0
- package/mcp/dist/__tests__/python-dart-complexity.test.js +146 -0
- package/mcp/dist/index.js +230 -0
- package/mcp/dist/lib/ContextCompressor.js +305 -0
- package/mcp/dist/lib/MemoryManager.js +334 -0
- package/mcp/dist/lib/ProjectCache.js +126 -0
- package/mcp/dist/lib/PythonParser.js +241 -0
- package/mcp/dist/tools/browser/browserPool.js +76 -0
- package/mcp/dist/tools/browser/browserUtils.js +135 -0
- package/mcp/dist/tools/browser/inspectNetworkRequests.js +140 -0
- package/mcp/dist/tools/browser/monitorConsoleLogs.js +97 -0
- package/mcp/dist/tools/convention/analyzeComplexity.js +248 -0
- package/mcp/dist/tools/convention/applyQualityRules.js +102 -0
- package/mcp/dist/tools/convention/checkCouplingCohesion.js +233 -0
- package/mcp/dist/tools/convention/complexityMetrics.js +133 -0
- package/mcp/dist/tools/convention/dartComplexity.js +117 -0
- package/mcp/dist/tools/convention/getCodingGuide.js +64 -0
- package/mcp/dist/tools/convention/languageDetector.js +50 -0
- package/mcp/dist/tools/convention/pythonComplexity.js +109 -0
- package/mcp/dist/tools/convention/suggestImprovements.js +257 -0
- package/mcp/dist/tools/convention/validateCodeQuality.js +177 -0
- package/mcp/dist/tools/memory/autoSaveContext.js +79 -0
- package/mcp/dist/tools/memory/database.js +123 -0
- package/mcp/dist/tools/memory/deleteMemory.js +39 -0
- package/mcp/dist/tools/memory/listMemories.js +38 -0
- package/mcp/dist/tools/memory/memoryConfig.js +27 -0
- package/mcp/dist/tools/memory/memorySQLite.js +138 -0
- package/mcp/dist/tools/memory/memoryUtils.js +34 -0
- package/mcp/dist/tools/memory/migrate.js +113 -0
- package/mcp/dist/tools/memory/prioritizeMemory.js +109 -0
- package/mcp/dist/tools/memory/recallMemory.js +40 -0
- package/mcp/dist/tools/memory/restoreSessionContext.js +69 -0
- package/mcp/dist/tools/memory/saveMemory.js +34 -0
- package/mcp/dist/tools/memory/searchMemories.js +37 -0
- package/mcp/dist/tools/memory/startSession.js +100 -0
- package/mcp/dist/tools/memory/updateMemory.js +46 -0
- package/mcp/dist/tools/planning/analyzeRequirements.js +166 -0
- package/mcp/dist/tools/planning/createUserStories.js +119 -0
- package/mcp/dist/tools/planning/featureRoadmap.js +202 -0
- package/mcp/dist/tools/planning/generatePrd.js +156 -0
- package/mcp/dist/tools/prompt/analyzePrompt.js +145 -0
- package/mcp/dist/tools/prompt/enhancePrompt.js +105 -0
- package/mcp/dist/tools/semantic/findReferences.js +195 -0
- package/mcp/dist/tools/semantic/findSymbol.js +200 -0
- package/mcp/dist/tools/thinking/analyzeProblem.js +50 -0
- package/mcp/dist/tools/thinking/breakDownProblem.js +140 -0
- package/mcp/dist/tools/thinking/createThinkingChain.js +39 -0
- package/mcp/dist/tools/thinking/formatAsPlan.js +73 -0
- package/mcp/dist/tools/thinking/stepByStepAnalysis.js +58 -0
- package/mcp/dist/tools/thinking/thinkAloudProcess.js +75 -0
- package/mcp/dist/tools/time/getCurrentTime.js +61 -0
- package/mcp/dist/tools/ui/previewUiAscii.js +232 -0
- package/mcp/dist/types/tool.js +2 -0
- package/mcp/package.json +53 -0
- package/package.json +49 -0
- package/scripts/install-mcp.js +48 -0
- package/scripts/install.sh +70 -0
- package/skills/core/communication-guide.md +104 -0
- package/skills/core/development-philosophy.md +53 -0
- package/skills/core/quick-start.md +121 -0
- package/skills/languages/dart-flutter.md +509 -0
- package/skills/languages/python-fastapi.md +386 -0
- package/skills/languages/typescript-nextjs.md +441 -0
- package/skills/languages/typescript-react-native.md +446 -0
- package/skills/languages/typescript-react.md +525 -0
- package/skills/quality/checklist.md +276 -0
- package/skills/quality/testing-strategy.md +437 -0
- package/skills/standards/anti-patterns.md +369 -0
- package/skills/standards/code-structure.md +291 -0
- package/skills/standards/complexity-metrics.md +312 -0
- package/skills/standards/naming-conventions.md +198 -0
- package/skills/tools/mcp-hi-ai-guide.md +665 -0
- package/skills/tools/mcp-workflow.md +51 -0
- package/templates/constitution-template.md +193 -0
- package/templates/plan-template.md +237 -0
- package/templates/spec-template.md +142 -0
- package/templates/tasks-template.md +132 -0
package/bin/sutory
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* sutory CLI
|
|
5
|
+
* Your story becomes code
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
|
|
11
|
+
// 명령어 목록
|
|
12
|
+
const commands = {
|
|
13
|
+
init: 'Initialize sutory in current project',
|
|
14
|
+
story: 'Create/manage SPEC documents',
|
|
15
|
+
plan: 'Create technical implementation plan',
|
|
16
|
+
tasks: 'Break down SPEC into actionable tasks',
|
|
17
|
+
run: 'Run task implementation (with auto guide generation)',
|
|
18
|
+
implement: 'Start implementation with AI agents (deprecated, use run)',
|
|
19
|
+
verify: 'Verify implementation against SPEC',
|
|
20
|
+
agents: 'List available agents',
|
|
21
|
+
skills: 'List installed skills',
|
|
22
|
+
update: 'Update sutory framework',
|
|
23
|
+
help: 'Show help message'
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const args = process.argv.slice(2);
|
|
27
|
+
const command = args[0];
|
|
28
|
+
|
|
29
|
+
// 도움말 출력
|
|
30
|
+
function showHelp() {
|
|
31
|
+
console.log(`
|
|
32
|
+
📖 sutory - Your story becomes code
|
|
33
|
+
|
|
34
|
+
Usage:
|
|
35
|
+
sutory <command> [options]
|
|
36
|
+
|
|
37
|
+
Commands:
|
|
38
|
+
init Initialize sutory in current project
|
|
39
|
+
story create <name> Create new SPEC through Q&A
|
|
40
|
+
story list List all SPECs
|
|
41
|
+
story show <name> Show SPEC content
|
|
42
|
+
plan <name> Create implementation plan from SPEC
|
|
43
|
+
tasks <name> Generate tasks from SPEC + PLAN
|
|
44
|
+
|
|
45
|
+
🆕 run <task-id> Run specific task (auto-generates guide + implements)
|
|
46
|
+
🆕 run --phase <N> Run all tasks in Phase N
|
|
47
|
+
🆕 run --all Run all tasks sequentially
|
|
48
|
+
|
|
49
|
+
verify <name> Verify against SPEC requirements
|
|
50
|
+
agents List available agents
|
|
51
|
+
skills List installed skills
|
|
52
|
+
update Update sutory framework
|
|
53
|
+
help Show this message
|
|
54
|
+
|
|
55
|
+
Workflow:
|
|
56
|
+
1. sutory spec "기능명" → SPEC 작성 (Q&A)
|
|
57
|
+
2. sutory plan "기능명" → PLAN 작성 (기술 계획)
|
|
58
|
+
3. sutory tasks "기능명" → TASKS 생성 (19개 Task)
|
|
59
|
+
4. sutory run "Task 1-1" → Task 구현 (가이드 생성 + 코드 작성)
|
|
60
|
+
5. sutory verify "기능명" → SPEC 검증
|
|
61
|
+
|
|
62
|
+
Examples:
|
|
63
|
+
$ sutory init
|
|
64
|
+
$ sutory story create "푸시 알림 설정"
|
|
65
|
+
$ sutory plan "푸시 알림 설정"
|
|
66
|
+
$ sutory tasks "푸시 알림 설정"
|
|
67
|
+
$ sutory run "Task 1-1" # 개별 Task 실행
|
|
68
|
+
$ sutory run --phase 1 # Phase 1 전체 실행
|
|
69
|
+
$ sutory run --all # 전체 실행
|
|
70
|
+
|
|
71
|
+
More info:
|
|
72
|
+
https://github.com/your-username/sutory
|
|
73
|
+
`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 버전 정보
|
|
77
|
+
function showVersion() {
|
|
78
|
+
const packageJson = require('../package.json');
|
|
79
|
+
console.log(`sutory v${packageJson.version}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 프로젝트 초기화
|
|
83
|
+
function init() {
|
|
84
|
+
const sutoryDir = path.join(process.cwd(), '.sutory');
|
|
85
|
+
|
|
86
|
+
if (fs.existsSync(sutoryDir)) {
|
|
87
|
+
console.log('❌ .sutory/ 폴더가 이미 존재합니다.');
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 폴더 생성
|
|
92
|
+
fs.mkdirSync(sutoryDir);
|
|
93
|
+
fs.mkdirSync(path.join(sutoryDir, 'specs'));
|
|
94
|
+
fs.mkdirSync(path.join(sutoryDir, 'plans'));
|
|
95
|
+
fs.mkdirSync(path.join(sutoryDir, 'tasks'));
|
|
96
|
+
|
|
97
|
+
// constitution.md 템플릿 복사
|
|
98
|
+
const templatePath = path.join(__dirname, '../templates/constitution-template.md');
|
|
99
|
+
const constitutionPath = path.join(sutoryDir, 'constitution.md');
|
|
100
|
+
|
|
101
|
+
if (fs.existsSync(templatePath)) {
|
|
102
|
+
fs.copyFileSync(templatePath, constitutionPath);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// config.json 생성 (언어 설정 포함)
|
|
106
|
+
const configPath = path.join(sutoryDir, 'config.json');
|
|
107
|
+
const config = {
|
|
108
|
+
language: 'ko', // 기본 한국어
|
|
109
|
+
agents: {
|
|
110
|
+
default: 'backend-python-expert'
|
|
111
|
+
},
|
|
112
|
+
mcp: {
|
|
113
|
+
enabled: true,
|
|
114
|
+
servers: ['hi-ai', 'context-7']
|
|
115
|
+
},
|
|
116
|
+
quality: {
|
|
117
|
+
strict: true,
|
|
118
|
+
autoVerify: true
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
122
|
+
|
|
123
|
+
console.log(`
|
|
124
|
+
✅ sutory 초기화 완료!
|
|
125
|
+
|
|
126
|
+
생성된 구조:
|
|
127
|
+
.sutory/
|
|
128
|
+
├── config.json # 프로젝트 설정 (언어: 한국어)
|
|
129
|
+
├── constitution.md # 프로젝트 원칙
|
|
130
|
+
├── specs/ # SPEC 문서들
|
|
131
|
+
├── plans/ # 기술 계획들
|
|
132
|
+
└── tasks/ # 작업 목록들
|
|
133
|
+
|
|
134
|
+
언어 변경:
|
|
135
|
+
.sutory/config.json에서 "language"를 "en" 또는 "ko"로 변경
|
|
136
|
+
|
|
137
|
+
다음 단계:
|
|
138
|
+
sutory story create "기능명" - 새 기능 스토리 작성
|
|
139
|
+
`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 에이전트 목록
|
|
143
|
+
function listAgents() {
|
|
144
|
+
const agentsDir = path.join(__dirname, '../agents');
|
|
145
|
+
const agents = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md'));
|
|
146
|
+
|
|
147
|
+
console.log('\n🤖 사용 가능한 에이전트:\n');
|
|
148
|
+
agents.forEach((agent, i) => {
|
|
149
|
+
const name = agent.replace('.md', '');
|
|
150
|
+
console.log(` ${i + 1}. ${name}`);
|
|
151
|
+
});
|
|
152
|
+
console.log('');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// 스킬 목록
|
|
156
|
+
function listSkills() {
|
|
157
|
+
const skillsDir = path.join(__dirname, '../skills');
|
|
158
|
+
const categories = fs.readdirSync(skillsDir).filter(f => {
|
|
159
|
+
return fs.statSync(path.join(skillsDir, f)).isDirectory();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
console.log('\n📚 설치된 스킬:\n');
|
|
163
|
+
categories.forEach(category => {
|
|
164
|
+
const skills = fs.readdirSync(path.join(skillsDir, category))
|
|
165
|
+
.filter(f => f.endsWith('.md'));
|
|
166
|
+
console.log(` ${category}/`);
|
|
167
|
+
skills.forEach(skill => {
|
|
168
|
+
console.log(` - ${skill.replace('.md', '')}`);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
console.log('');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Claude Code와 통합 (추후 구현)
|
|
175
|
+
function delegateToClaudeCode(command, args) {
|
|
176
|
+
console.log(`
|
|
177
|
+
⚠️ 이 명령어는 Claude Code와 통합이 필요합니다.
|
|
178
|
+
|
|
179
|
+
지금은 수동으로 Claude Code를 열고 다음과 같이 요청하세요:
|
|
180
|
+
|
|
181
|
+
"${command} ${args.join(' ')}"
|
|
182
|
+
|
|
183
|
+
향후 업데이트에서 자동화될 예정입니다.
|
|
184
|
+
`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// 메인 라우터
|
|
188
|
+
switch (command) {
|
|
189
|
+
case 'init':
|
|
190
|
+
init();
|
|
191
|
+
break;
|
|
192
|
+
|
|
193
|
+
case 'agents':
|
|
194
|
+
listAgents();
|
|
195
|
+
break;
|
|
196
|
+
|
|
197
|
+
case 'skills':
|
|
198
|
+
listSkills();
|
|
199
|
+
break;
|
|
200
|
+
|
|
201
|
+
case 'version':
|
|
202
|
+
case '-v':
|
|
203
|
+
case '--version':
|
|
204
|
+
showVersion();
|
|
205
|
+
break;
|
|
206
|
+
|
|
207
|
+
case 'help':
|
|
208
|
+
case '-h':
|
|
209
|
+
case '--help':
|
|
210
|
+
case undefined:
|
|
211
|
+
showHelp();
|
|
212
|
+
break;
|
|
213
|
+
|
|
214
|
+
// sutory run 명령어 (새로운 구현 워크플로우)
|
|
215
|
+
case 'run':
|
|
216
|
+
handleRunCommand(args.slice(1));
|
|
217
|
+
break;
|
|
218
|
+
|
|
219
|
+
// Claude Code 위임이 필요한 명령어들
|
|
220
|
+
case 'story':
|
|
221
|
+
case 'plan':
|
|
222
|
+
case 'tasks':
|
|
223
|
+
case 'implement':
|
|
224
|
+
case 'verify':
|
|
225
|
+
delegateToClaudeCode(command, args.slice(1));
|
|
226
|
+
break;
|
|
227
|
+
|
|
228
|
+
default:
|
|
229
|
+
console.log(`❌ 알 수 없는 명령어: ${command}`);
|
|
230
|
+
console.log('사용법을 보려면: sutory help');
|
|
231
|
+
process.exit(1);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// sutory run 명령어 핸들러
|
|
235
|
+
function handleRunCommand(args) {
|
|
236
|
+
const option = args[0];
|
|
237
|
+
|
|
238
|
+
if (!option) {
|
|
239
|
+
console.log(`
|
|
240
|
+
❌ 사용법: sutory run <task-id> | --phase <N> | --all
|
|
241
|
+
|
|
242
|
+
예시:
|
|
243
|
+
sutory run "Task 1-1" # 특정 Task 실행
|
|
244
|
+
sutory run --phase 1 # Phase 1 전체 실행
|
|
245
|
+
sutory run --all # 모든 Task 실행
|
|
246
|
+
`);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// --all 플래그 처리
|
|
251
|
+
if (option === '--all') {
|
|
252
|
+
console.log(`
|
|
253
|
+
🚀 전체 Task 실행 시작...
|
|
254
|
+
|
|
255
|
+
Claude Code에 다음과 같이 요청하세요:
|
|
256
|
+
|
|
257
|
+
"sutory run --all 실행해줘. TASKS 문서의 의존성 순서대로 19개 Task를 모두 구현해줘."
|
|
258
|
+
|
|
259
|
+
작업 순서:
|
|
260
|
+
Phase 1 (Backend) → Task 1-1 ~ 1-8
|
|
261
|
+
Phase 2 (Frontend) → Task 2-1 ~ 2-8
|
|
262
|
+
Phase 3 (FCM) → Task 3-1 ~ 3-3
|
|
263
|
+
|
|
264
|
+
⚠️ 주의: 전체 실행은 약 24시간 소요됩니다.
|
|
265
|
+
`);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// --phase 플래그 처리
|
|
270
|
+
if (option === '--phase') {
|
|
271
|
+
const phaseNumber = args[1];
|
|
272
|
+
if (!phaseNumber) {
|
|
273
|
+
console.log(`❌ Phase 번호를 지정하세요: sutory run --phase <1|2|3>`);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
console.log(`
|
|
278
|
+
🚀 Phase ${phaseNumber} 실행 시작...
|
|
279
|
+
|
|
280
|
+
Claude Code에 다음과 같이 요청하세요:
|
|
281
|
+
|
|
282
|
+
"sutory run --phase ${phaseNumber} 실행해줘. TASKS 문서의 Phase ${phaseNumber} Task들을 순차적으로 구현해줘."
|
|
283
|
+
|
|
284
|
+
Phase ${phaseNumber} 작업 목록:
|
|
285
|
+
${getPhaseTaskList(phaseNumber)}
|
|
286
|
+
|
|
287
|
+
예상 시간: ${getPhaseEstimatedTime(phaseNumber)}
|
|
288
|
+
`);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// 특정 Task 실행
|
|
293
|
+
const taskId = option;
|
|
294
|
+
console.log(`
|
|
295
|
+
🚀 Task 실행: "${taskId}"
|
|
296
|
+
|
|
297
|
+
Claude Code에 다음과 같이 요청하세요:
|
|
298
|
+
|
|
299
|
+
"sutory run '${taskId}' 실행해줘. 다음 순서로 진행해줘:
|
|
300
|
+
|
|
301
|
+
1. TASKS 문서에서 '${taskId}' 찾기
|
|
302
|
+
2. 구현 가이드 생성 (.sutory/guides/${taskId}.md)
|
|
303
|
+
3. 가이드에 따라 코드 구현
|
|
304
|
+
4. Acceptance Criteria 검증
|
|
305
|
+
5. Task 상태를 ✅ 완료로 업데이트"
|
|
306
|
+
|
|
307
|
+
구현 가이드 생성 위치:
|
|
308
|
+
.sutory/guides/${taskId.replace(/\s+/g, '-').toLowerCase()}.md
|
|
309
|
+
|
|
310
|
+
검증 명령어는 TASKS 문서 참고
|
|
311
|
+
`);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Phase별 Task 목록 (하드코딩 - 추후 TASKS 파일에서 파싱)
|
|
315
|
+
function getPhaseTaskList(phase) {
|
|
316
|
+
const phases = {
|
|
317
|
+
'1': 'Task 1-1 ~ 1-8 (Backend 개발)',
|
|
318
|
+
'2': 'Task 2-1 ~ 2-8 (Frontend 개발)',
|
|
319
|
+
'3': 'Task 3-1 ~ 3-3 (FCM 연동 및 테스트)'
|
|
320
|
+
};
|
|
321
|
+
return phases[phase] || '알 수 없는 Phase';
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Phase별 예상 시간
|
|
325
|
+
function getPhaseEstimatedTime(phase) {
|
|
326
|
+
const times = {
|
|
327
|
+
'1': '8시간 (1일)',
|
|
328
|
+
'2': '12시간 (1.5일)',
|
|
329
|
+
'3': '4시간 (0.5일)'
|
|
330
|
+
};
|
|
331
|
+
return times[phase] || '알 수 없음';
|
|
332
|
+
}
|
package/bin/vibe
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* vibe CLI
|
|
5
|
+
* Vibe Development - SPEC-driven AI coding framework
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
|
|
11
|
+
// 명령어 목록
|
|
12
|
+
const commands = {
|
|
13
|
+
init: 'Initialize vibe in current project',
|
|
14
|
+
spec: 'Create/manage SPEC documents',
|
|
15
|
+
plan: 'Create technical implementation plan',
|
|
16
|
+
tasks: 'Break down SPEC into actionable tasks',
|
|
17
|
+
run: 'Run task implementation (with auto guide generation)',
|
|
18
|
+
verify: 'Verify implementation against SPEC',
|
|
19
|
+
analyze: 'Analyze project (code quality, architecture, dependencies)',
|
|
20
|
+
ui: 'Preview UI with ASCII art',
|
|
21
|
+
diagram: 'Generate diagrams (architecture, ERD, flow)',
|
|
22
|
+
agents: 'List available agents',
|
|
23
|
+
skills: 'List installed skills',
|
|
24
|
+
help: 'Show help message'
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const args = process.argv.slice(2);
|
|
28
|
+
const command = args[0];
|
|
29
|
+
|
|
30
|
+
// 도움말 출력
|
|
31
|
+
function showHelp() {
|
|
32
|
+
console.log(`
|
|
33
|
+
📖 vibe - Your story becomes code
|
|
34
|
+
|
|
35
|
+
Usage:
|
|
36
|
+
vibe <command> [options]
|
|
37
|
+
|
|
38
|
+
Commands:
|
|
39
|
+
init Initialize vibe in current project
|
|
40
|
+
spec <name> Create SPEC through 6-question Q&A
|
|
41
|
+
plan <name> Create implementation plan from SPEC
|
|
42
|
+
tasks <name> Generate tasks from SPEC + PLAN
|
|
43
|
+
run <task-id> Run task (auto-guide + implement)
|
|
44
|
+
run --phase <N> Run all tasks in Phase N
|
|
45
|
+
run --all Run all tasks sequentially
|
|
46
|
+
verify <name> Verify against SPEC requirements
|
|
47
|
+
|
|
48
|
+
analyze Analyze project (code/deps/arch)
|
|
49
|
+
analyze --code Code quality analysis
|
|
50
|
+
analyze --deps Dependency analysis
|
|
51
|
+
ui <description> Preview UI with ASCII art
|
|
52
|
+
diagram Generate architecture diagram
|
|
53
|
+
diagram --er Generate ERD diagram
|
|
54
|
+
|
|
55
|
+
agents List available agents
|
|
56
|
+
skills List installed skills
|
|
57
|
+
help Show this message
|
|
58
|
+
|
|
59
|
+
Workflow:
|
|
60
|
+
1. vibe spec "기능명" → SPEC 작성 (Q&A)
|
|
61
|
+
2. vibe plan "기능명" → PLAN 작성 (기술 계획)
|
|
62
|
+
3. vibe tasks "기능명" → TASKS 생성 (19개 Task)
|
|
63
|
+
4. vibe run "Task 1-1" → Task 구현 (가이드 생성 + 코드 작성)
|
|
64
|
+
5. vibe verify "기능명" → SPEC 검증
|
|
65
|
+
|
|
66
|
+
Examples:
|
|
67
|
+
$ vibe init
|
|
68
|
+
$ vibe story create "푸시 알림 설정"
|
|
69
|
+
$ vibe plan "푸시 알림 설정"
|
|
70
|
+
$ vibe tasks "푸시 알림 설정"
|
|
71
|
+
$ vibe run "Task 1-1" # 개별 Task 실행
|
|
72
|
+
$ vibe run --phase 1 # Phase 1 전체 실행
|
|
73
|
+
$ vibe run --all # 전체 실행
|
|
74
|
+
|
|
75
|
+
More info:
|
|
76
|
+
https://github.com/your-username/vibe
|
|
77
|
+
`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 버전 정보
|
|
81
|
+
function showVersion() {
|
|
82
|
+
const packageJson = require('../package.json');
|
|
83
|
+
console.log(`vibe v${packageJson.version}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 프로젝트 초기화
|
|
87
|
+
function init() {
|
|
88
|
+
const vibeDir = path.join(process.cwd(), '.vibe');
|
|
89
|
+
|
|
90
|
+
if (fs.existsSync(vibeDir)) {
|
|
91
|
+
console.log('❌ .vibe/ 폴더가 이미 존재합니다.');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 폴더 생성
|
|
96
|
+
fs.mkdirSync(vibeDir);
|
|
97
|
+
fs.mkdirSync(path.join(vibeDir, 'specs'));
|
|
98
|
+
fs.mkdirSync(path.join(vibeDir, 'plans'));
|
|
99
|
+
fs.mkdirSync(path.join(vibeDir, 'tasks'));
|
|
100
|
+
|
|
101
|
+
// constitution.md 템플릿 복사
|
|
102
|
+
const templatePath = path.join(__dirname, '../templates/constitution-template.md');
|
|
103
|
+
const constitutionPath = path.join(vibeDir, 'constitution.md');
|
|
104
|
+
|
|
105
|
+
if (fs.existsSync(templatePath)) {
|
|
106
|
+
fs.copyFileSync(templatePath, constitutionPath);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// config.json 생성 (언어 설정 포함)
|
|
110
|
+
const configPath = path.join(vibeDir, 'config.json');
|
|
111
|
+
const config = {
|
|
112
|
+
language: 'ko', // 기본 한국어
|
|
113
|
+
agents: {
|
|
114
|
+
default: 'backend-python-expert'
|
|
115
|
+
},
|
|
116
|
+
mcp: {
|
|
117
|
+
enabled: true,
|
|
118
|
+
servers: ['hi-ai', 'context-7']
|
|
119
|
+
},
|
|
120
|
+
quality: {
|
|
121
|
+
strict: true,
|
|
122
|
+
autoVerify: true
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
126
|
+
|
|
127
|
+
console.log(`
|
|
128
|
+
✅ vibe 초기화 완료!
|
|
129
|
+
|
|
130
|
+
생성된 구조:
|
|
131
|
+
.vibe/
|
|
132
|
+
├── config.json # 프로젝트 설정 (언어: 한국어)
|
|
133
|
+
├── constitution.md # 프로젝트 원칙
|
|
134
|
+
├── specs/ # SPEC 문서들
|
|
135
|
+
├── plans/ # 기술 계획들
|
|
136
|
+
└── tasks/ # 작업 목록들
|
|
137
|
+
|
|
138
|
+
언어 변경:
|
|
139
|
+
.vibe/config.json에서 "language"를 "en" 또는 "ko"로 변경
|
|
140
|
+
|
|
141
|
+
다음 단계:
|
|
142
|
+
vibe story create "기능명" - 새 기능 스토리 작성
|
|
143
|
+
`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// 에이전트 목록
|
|
147
|
+
function listAgents() {
|
|
148
|
+
const agentsDir = path.join(__dirname, '../agents');
|
|
149
|
+
const agents = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md'));
|
|
150
|
+
|
|
151
|
+
console.log('\n🤖 사용 가능한 에이전트:\n');
|
|
152
|
+
agents.forEach((agent, i) => {
|
|
153
|
+
const name = agent.replace('.md', '');
|
|
154
|
+
console.log(` ${i + 1}. ${name}`);
|
|
155
|
+
});
|
|
156
|
+
console.log('');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 스킬 목록
|
|
160
|
+
function listSkills() {
|
|
161
|
+
const skillsDir = path.join(__dirname, '../skills');
|
|
162
|
+
const categories = fs.readdirSync(skillsDir).filter(f => {
|
|
163
|
+
return fs.statSync(path.join(skillsDir, f)).isDirectory();
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
console.log('\n📚 설치된 스킬:\n');
|
|
167
|
+
categories.forEach(category => {
|
|
168
|
+
const skills = fs.readdirSync(path.join(skillsDir, category))
|
|
169
|
+
.filter(f => f.endsWith('.md'));
|
|
170
|
+
console.log(` ${category}/`);
|
|
171
|
+
skills.forEach(skill => {
|
|
172
|
+
console.log(` - ${skill.replace('.md', '')}`);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
console.log('');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Claude Code와 통합 (추후 구현)
|
|
179
|
+
function delegateToClaudeCode(command, args) {
|
|
180
|
+
console.log(`
|
|
181
|
+
⚠️ 이 명령어는 Claude Code와 통합이 필요합니다.
|
|
182
|
+
|
|
183
|
+
지금은 수동으로 Claude Code를 열고 다음과 같이 요청하세요:
|
|
184
|
+
|
|
185
|
+
"${command} ${args.join(' ')}"
|
|
186
|
+
|
|
187
|
+
향후 업데이트에서 자동화될 예정입니다.
|
|
188
|
+
`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// 메인 라우터
|
|
192
|
+
switch (command) {
|
|
193
|
+
case 'init':
|
|
194
|
+
init();
|
|
195
|
+
break;
|
|
196
|
+
|
|
197
|
+
case 'agents':
|
|
198
|
+
listAgents();
|
|
199
|
+
break;
|
|
200
|
+
|
|
201
|
+
case 'skills':
|
|
202
|
+
listSkills();
|
|
203
|
+
break;
|
|
204
|
+
|
|
205
|
+
case 'version':
|
|
206
|
+
case '-v':
|
|
207
|
+
case '--version':
|
|
208
|
+
showVersion();
|
|
209
|
+
break;
|
|
210
|
+
|
|
211
|
+
case 'help':
|
|
212
|
+
case '-h':
|
|
213
|
+
case '--help':
|
|
214
|
+
case undefined:
|
|
215
|
+
showHelp();
|
|
216
|
+
break;
|
|
217
|
+
|
|
218
|
+
// vibe run 명령어 (새로운 구현 워크플로우)
|
|
219
|
+
case 'run':
|
|
220
|
+
handleRunCommand(args.slice(1));
|
|
221
|
+
break;
|
|
222
|
+
|
|
223
|
+
// Claude Code 위임이 필요한 명령어들
|
|
224
|
+
case 'spec':
|
|
225
|
+
case 'plan':
|
|
226
|
+
case 'tasks':
|
|
227
|
+
case 'verify':
|
|
228
|
+
case 'analyze':
|
|
229
|
+
case 'ui':
|
|
230
|
+
case 'diagram':
|
|
231
|
+
delegateToClaudeCode(command, args.slice(1));
|
|
232
|
+
break;
|
|
233
|
+
|
|
234
|
+
default:
|
|
235
|
+
console.log(`❌ 알 수 없는 명령어: ${command}`);
|
|
236
|
+
console.log('사용법을 보려면: vibe help');
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// vibe run 명령어 핸들러
|
|
241
|
+
function handleRunCommand(args) {
|
|
242
|
+
const option = args[0];
|
|
243
|
+
|
|
244
|
+
if (!option) {
|
|
245
|
+
console.log(`
|
|
246
|
+
❌ 사용법: vibe run <task-id> | --phase <N> | --all
|
|
247
|
+
|
|
248
|
+
예시:
|
|
249
|
+
vibe run "Task 1-1" # 특정 Task 실행
|
|
250
|
+
vibe run --phase 1 # Phase 1 전체 실행
|
|
251
|
+
vibe run --all # 모든 Task 실행
|
|
252
|
+
`);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// --all 플래그 처리
|
|
257
|
+
if (option === '--all') {
|
|
258
|
+
console.log(`
|
|
259
|
+
🚀 전체 Task 실행 시작...
|
|
260
|
+
|
|
261
|
+
Claude Code에 다음과 같이 요청하세요:
|
|
262
|
+
|
|
263
|
+
"vibe run --all 실행해줘. TASKS 문서의 의존성 순서대로 19개 Task를 모두 구현해줘."
|
|
264
|
+
|
|
265
|
+
작업 순서:
|
|
266
|
+
Phase 1 (Backend) → Task 1-1 ~ 1-8
|
|
267
|
+
Phase 2 (Frontend) → Task 2-1 ~ 2-8
|
|
268
|
+
Phase 3 (FCM) → Task 3-1 ~ 3-3
|
|
269
|
+
|
|
270
|
+
⚠️ 주의: 전체 실행은 약 24시간 소요됩니다.
|
|
271
|
+
`);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// --phase 플래그 처리
|
|
276
|
+
if (option === '--phase') {
|
|
277
|
+
const phaseNumber = args[1];
|
|
278
|
+
if (!phaseNumber) {
|
|
279
|
+
console.log(`❌ Phase 번호를 지정하세요: vibe run --phase <1|2|3>`);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
console.log(`
|
|
284
|
+
🚀 Phase ${phaseNumber} 실행 시작...
|
|
285
|
+
|
|
286
|
+
Claude Code에 다음과 같이 요청하세요:
|
|
287
|
+
|
|
288
|
+
"vibe run --phase ${phaseNumber} 실행해줘. TASKS 문서의 Phase ${phaseNumber} Task들을 순차적으로 구현해줘."
|
|
289
|
+
|
|
290
|
+
Phase ${phaseNumber} 작업 목록:
|
|
291
|
+
${getPhaseTaskList(phaseNumber)}
|
|
292
|
+
|
|
293
|
+
예상 시간: ${getPhaseEstimatedTime(phaseNumber)}
|
|
294
|
+
`);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// 특정 Task 실행
|
|
299
|
+
const taskId = option;
|
|
300
|
+
console.log(`
|
|
301
|
+
🚀 Task 실행: "${taskId}"
|
|
302
|
+
|
|
303
|
+
Claude Code에 다음과 같이 요청하세요:
|
|
304
|
+
|
|
305
|
+
"vibe run '${taskId}' 실행해줘. 다음 순서로 진행해줘:
|
|
306
|
+
|
|
307
|
+
1. TASKS 문서에서 '${taskId}' 찾기
|
|
308
|
+
2. 구현 가이드 생성 (.vibe/guides/${taskId}.md)
|
|
309
|
+
3. 가이드에 따라 코드 구현
|
|
310
|
+
4. Acceptance Criteria 검증
|
|
311
|
+
5. Task 상태를 ✅ 완료로 업데이트"
|
|
312
|
+
|
|
313
|
+
구현 가이드 생성 위치:
|
|
314
|
+
.vibe/guides/${taskId.replace(/\s+/g, '-').toLowerCase()}.md
|
|
315
|
+
|
|
316
|
+
검증 명령어는 TASKS 문서 참고
|
|
317
|
+
`);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Phase별 Task 목록 (하드코딩 - 추후 TASKS 파일에서 파싱)
|
|
321
|
+
function getPhaseTaskList(phase) {
|
|
322
|
+
const phases = {
|
|
323
|
+
'1': 'Task 1-1 ~ 1-8 (Backend 개발)',
|
|
324
|
+
'2': 'Task 2-1 ~ 2-8 (Frontend 개발)',
|
|
325
|
+
'3': 'Task 3-1 ~ 3-3 (FCM 연동 및 테스트)'
|
|
326
|
+
};
|
|
327
|
+
return phases[phase] || '알 수 없는 Phase';
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Phase별 예상 시간
|
|
331
|
+
function getPhaseEstimatedTime(phase) {
|
|
332
|
+
const times = {
|
|
333
|
+
'1': '8시간 (1일)',
|
|
334
|
+
'2': '12시간 (1.5일)',
|
|
335
|
+
'3': '4시간 (0.5일)'
|
|
336
|
+
};
|
|
337
|
+
return times[phase] || '알 수 없음';
|
|
338
|
+
}
|