@silbaram/artifact-driven-agent 0.1.6 → 0.1.9

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.
Files changed (80) hide show
  1. package/README.md +709 -516
  2. package/ai-dev-team/.ada-status.json +10 -0
  3. package/ai-dev-team/.ada-version +6 -0
  4. package/ai-dev-team/.current-template +1 -0
  5. package/ai-dev-team/.sessions/logs/20260124-014551-00f04724.log +5 -0
  6. package/ai-dev-team/.sessions/logs/20260124-014623-cb2b1d44.log +5 -0
  7. package/ai-dev-team/ada.config.json +15 -0
  8. package/ai-dev-team/artifacts/api.md +212 -0
  9. package/ai-dev-team/artifacts/decision.md +72 -0
  10. package/ai-dev-team/artifacts/improvement-reports/IMP-0000-template.md +57 -0
  11. package/ai-dev-team/artifacts/plan.md +187 -0
  12. package/ai-dev-team/artifacts/project.md +193 -0
  13. package/ai-dev-team/artifacts/sprints/_template/docs/release-notes.md +37 -0
  14. package/ai-dev-team/artifacts/sprints/_template/meta.md +54 -0
  15. package/ai-dev-team/artifacts/sprints/_template/retrospective.md +50 -0
  16. package/ai-dev-team/artifacts/sprints/_template/review-reports/review-template.md +49 -0
  17. package/ai-dev-team/artifacts/sprints/_template/tasks/task-template.md +43 -0
  18. package/ai-dev-team/artifacts/ui.md +104 -0
  19. package/ai-dev-team/roles/analyzer.md +265 -0
  20. package/ai-dev-team/roles/developer.md +222 -0
  21. package/ai-dev-team/roles/documenter.md +715 -0
  22. package/ai-dev-team/roles/improver.md +461 -0
  23. package/ai-dev-team/roles/manager.md +544 -0
  24. package/ai-dev-team/roles/planner.md +398 -0
  25. package/ai-dev-team/roles/reviewer.md +294 -0
  26. package/ai-dev-team/rules/api-change.md +198 -0
  27. package/ai-dev-team/rules/document-priority.md +199 -0
  28. package/ai-dev-team/rules/escalation.md +172 -0
  29. package/ai-dev-team/rules/iteration.md +236 -0
  30. package/ai-dev-team/rules/rfc.md +31 -0
  31. package/ai-dev-team/rules/rollback.md +218 -0
  32. package/bin/cli.js +49 -5
  33. package/core/artifacts/sprints/_template/meta.md +4 -4
  34. package/core/docs-templates/mkdocs/docs/architecture/overview.md +29 -0
  35. package/core/docs-templates/mkdocs/docs/changelog.md +36 -0
  36. package/core/docs-templates/mkdocs/docs/contributing/contributing.md +60 -0
  37. package/core/docs-templates/mkdocs/docs/getting-started/configuration.md +51 -0
  38. package/core/docs-templates/mkdocs/docs/getting-started/installation.md +41 -0
  39. package/core/docs-templates/mkdocs/docs/getting-started/quick-start.md +56 -0
  40. package/core/docs-templates/mkdocs/docs/guides/api-reference.md +83 -0
  41. package/core/docs-templates/mkdocs/docs/index.md +32 -0
  42. package/core/docs-templates/mkdocs/mkdocs.yml +86 -0
  43. package/core/roles/analyzer.md +32 -10
  44. package/core/roles/developer.md +222 -223
  45. package/core/roles/documenter.md +592 -170
  46. package/core/roles/improver.md +461 -0
  47. package/core/roles/manager.md +4 -1
  48. package/core/roles/planner.md +160 -10
  49. package/core/roles/reviewer.md +31 -3
  50. package/core/rules/document-priority.md +2 -1
  51. package/core/rules/rollback.md +3 -3
  52. package/package.json +1 -1
  53. package/src/commands/config.js +371 -0
  54. package/src/commands/docs.js +502 -0
  55. package/src/commands/interactive.js +324 -33
  56. package/src/commands/monitor.js +236 -0
  57. package/src/commands/run.js +360 -122
  58. package/src/commands/sessions.js +270 -70
  59. package/src/commands/setup.js +22 -1
  60. package/src/commands/sprint.js +295 -54
  61. package/src/commands/status.js +34 -1
  62. package/src/commands/upgrade.js +416 -0
  63. package/src/commands/validate.js +4 -3
  64. package/src/index.js +1 -0
  65. package/src/ui/dashboard.js +518 -0
  66. package/src/ui/keyHandler.js +147 -0
  67. package/src/ui/quickActions.js +111 -0
  68. package/src/utils/config.js +74 -0
  69. package/src/utils/files.js +70 -3
  70. package/src/utils/sessionState.js +472 -328
  71. package/src/utils/sessionState.process.test.js +101 -0
  72. package/src/utils/sessionState.test.js +183 -0
  73. package/src/utils/sprintUtils.js +134 -0
  74. package/src/utils/taskParser.js +134 -0
  75. package/src/utils/taskParser.test.js +76 -0
  76. package/ai-dev-team/artifacts/features/_template/qa.md +0 -16
  77. package/examples/todo-app/README.md +0 -23
  78. package/examples/todo-app/artifacts/backlog.md +0 -23
  79. package/examples/todo-app/artifacts/plan.md +0 -23
  80. package/examples/todo-app/artifacts/project.md +0 -23
@@ -0,0 +1,502 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+ import inquirer from 'inquirer';
5
+ import { spawn } from 'child_process';
6
+ import { getPackageRoot, getWorkspaceDir, isWorkspaceSetup } from '../utils/files.js';
7
+
8
+ /**
9
+ * 문서 관리 명령어
10
+ * @param {string} action - init / generate / publish / serve
11
+ * @param {Object} options - 명령어 옵션
12
+ */
13
+ export default async function docs(action, options = {}) {
14
+ if (!isWorkspaceSetup() && action !== 'init') {
15
+ console.log(chalk.red('❌ 워크스페이스가 설정되지 않았습니다.'));
16
+ console.log(chalk.gray(' ada setup [template]을 먼저 실행하세요.'));
17
+ process.exit(1);
18
+ }
19
+
20
+ switch (action) {
21
+ case 'init':
22
+ await initDocs(options);
23
+ break;
24
+ case 'generate':
25
+ await generateDocs(options);
26
+ break;
27
+ case 'publish':
28
+ await publishDocs(options);
29
+ break;
30
+ case 'serve':
31
+ await serveDocs(options);
32
+ break;
33
+ default:
34
+ console.log(chalk.red('❌ 알 수 없는 명령어입니다.'));
35
+ console.log('');
36
+ console.log(chalk.cyan('사용법:'));
37
+ console.log(chalk.gray(' ada docs init - 문서 구조 초기화'));
38
+ console.log(chalk.gray(' ada docs generate - 문서 생성/업데이트 (Documenter 실행)'));
39
+ console.log(chalk.gray(' ada docs publish - GitHub Pages 배포'));
40
+ console.log(chalk.gray(' ada docs serve - 로컬 문서 서버 실행'));
41
+ process.exit(1);
42
+ }
43
+ }
44
+
45
+ /**
46
+ * 문서 구조 초기화
47
+ */
48
+ async function initDocs(options) {
49
+ const projectRoot = process.cwd();
50
+ const docsDir = path.join(projectRoot, 'docs');
51
+
52
+ console.log('');
53
+ console.log(chalk.cyan('━'.repeat(60)));
54
+ console.log(chalk.cyan.bold('📚 문서 구조 초기화'));
55
+ console.log(chalk.cyan('━'.repeat(60)));
56
+ console.log('');
57
+
58
+ // 이미 docs/ 디렉토리가 있는지 확인
59
+ if (fs.existsSync(docsDir)) {
60
+ const answer = await inquirer.prompt([
61
+ {
62
+ type: 'confirm',
63
+ name: 'overwrite',
64
+ message: 'docs/ 디렉토리가 이미 존재합니다. 덮어쓰시겠습니까?',
65
+ default: false
66
+ }
67
+ ]);
68
+
69
+ if (!answer.overwrite) {
70
+ console.log(chalk.yellow('⚠️ 초기화가 취소되었습니다.'));
71
+ return;
72
+ }
73
+
74
+ // 백업 생성
75
+ const backupDir = path.join(projectRoot, `docs-backup-${Date.now()}`);
76
+ fs.moveSync(docsDir, backupDir);
77
+ console.log(chalk.yellow(`📦 기존 문서를 백업했습니다: ${path.basename(backupDir)}`));
78
+ console.log('');
79
+ }
80
+
81
+ // 생성기 선택
82
+ let generator = options.generator;
83
+ if (!generator) {
84
+ const answer = await inquirer.prompt([
85
+ {
86
+ type: 'list',
87
+ name: 'generator',
88
+ message: '문서 생성기를 선택하세요:',
89
+ choices: [
90
+ { name: 'MkDocs Material (추천) - 강력한 검색, 다국어, 버전 관리', value: 'mkdocs' },
91
+ { name: 'Jekyll - GitHub Pages 기본 지원', value: 'jekyll' }
92
+ ],
93
+ default: 'mkdocs'
94
+ }
95
+ ]);
96
+ generator = answer.generator;
97
+ }
98
+
99
+ // 템플릿 복사
100
+ const packageRoot = getPackageRoot();
101
+ const templateDir = path.join(packageRoot, 'core', 'docs-templates', generator);
102
+
103
+ if (!fs.existsSync(templateDir)) {
104
+ console.log(chalk.red(`❌ 템플릿을 찾을 수 없습니다: ${generator}`));
105
+ process.exit(1);
106
+ }
107
+
108
+ console.log(chalk.gray(`📁 ${generator} 템플릿 복사 중...`));
109
+ fs.copySync(templateDir, docsDir);
110
+
111
+ // mkdocs.yml 또는 _config.yml 업데이트 (프로젝트 이름)
112
+ let configFile;
113
+ if (generator === 'mkdocs') {
114
+ configFile = path.join(docsDir, 'mkdocs.yml');
115
+ } else if (generator === 'jekyll') {
116
+ configFile = path.join(docsDir, '_config.yml');
117
+ }
118
+
119
+ if (configFile && fs.existsSync(configFile)) {
120
+ const packageJson = path.join(projectRoot, 'package.json');
121
+ if (fs.existsSync(packageJson)) {
122
+ const pkg = JSON.parse(fs.readFileSync(packageJson, 'utf-8'));
123
+ let config = fs.readFileSync(configFile, 'utf-8');
124
+
125
+ if (generator === 'mkdocs') {
126
+ config = config.replace('site_name: Project Documentation', `site_name: ${pkg.name || 'Project'} Documentation`);
127
+ config = config.replace('site_description: Project documentation powered by ADA',
128
+ `site_description: ${pkg.description || 'Project documentation'}`);
129
+
130
+ if (pkg.repository && pkg.repository.url) {
131
+ const repoUrl = pkg.repository.url.replace(/^git\+/, '').replace(/\.git$/, '');
132
+ config = config.replace('repo_url: https://github.com/username/repo', `repo_url: ${repoUrl}`);
133
+
134
+ const repoName = repoUrl.split('github.com/')[1];
135
+ if (repoName) {
136
+ config = config.replace('repo_name: username/repo', `repo_name: ${repoName}`);
137
+ }
138
+ }
139
+ }
140
+
141
+ fs.writeFileSync(configFile, config);
142
+ }
143
+ }
144
+
145
+ // README.md 생성
146
+ const readmeFile = path.join(docsDir, 'README.md');
147
+ const readmeContent = `# Documentation
148
+
149
+ This directory contains the project documentation.
150
+
151
+ ## Building Documentation
152
+
153
+ ### MkDocs
154
+
155
+ \`\`\`bash
156
+ # 가상환경 생성 및 활성화 (권장)
157
+ python -m venv venv
158
+ venv\\Scripts\\activate # Windows
159
+ source venv/bin/activate # macOS/Linux
160
+
161
+ # MkDocs 설치
162
+ pip install mkdocs mkdocs-material
163
+
164
+ # Serve locally
165
+ mkdocs serve
166
+
167
+ # Build static site
168
+ mkdocs build
169
+ \`\`\`
170
+
171
+ ### Deploy to GitHub Pages
172
+
173
+ \`\`\`bash
174
+ # Using CLI
175
+ ada docs publish
176
+
177
+ # Or manually
178
+ mkdocs gh-deploy
179
+ \`\`\`
180
+
181
+ ## Documentation Structure
182
+
183
+ - \`getting-started/\` - Installation and quick start guides
184
+ - \`guides/\` - User and developer guides
185
+ - \`architecture/\` - Architecture documentation
186
+ - \`contributing/\` - Contributing guidelines
187
+ - \`changelog.md\` - Project changelog
188
+
189
+ ## Updating Documentation
190
+
191
+ Use the Documenter role to update documentation:
192
+
193
+ \`\`\`bash
194
+ ada documenter claude
195
+ \`\`\`
196
+ `;
197
+
198
+ fs.writeFileSync(readmeFile, readmeContent);
199
+
200
+ console.log('');
201
+ console.log(chalk.green('✅ 문서 구조 초기화 완료!'));
202
+ console.log('');
203
+ console.log(chalk.cyan('📂 생성된 구조:'));
204
+ console.log(chalk.gray(' docs/'));
205
+ console.log(chalk.gray(' ├── index.md # 홈페이지'));
206
+ console.log(chalk.gray(' ├── getting-started/ # 시작 가이드'));
207
+ console.log(chalk.gray(' ├── guides/ # 사용 가이드'));
208
+ console.log(chalk.gray(' ├── architecture/ # 아키텍처 문서'));
209
+ console.log(chalk.gray(' ├── contributing/ # 기여 가이드'));
210
+ console.log(chalk.gray(` └── ${generator === 'mkdocs' ? 'mkdocs.yml' : '_config.yml'} # 설정 파일`));
211
+ console.log('');
212
+ console.log(chalk.cyan('다음 단계:'));
213
+ console.log(chalk.gray(' 1. ada documenter claude # 문서 내용 생성'));
214
+ console.log(chalk.gray(' 2. ada docs serve # 로컬 미리보기'));
215
+ console.log(chalk.gray(' 3. ada docs publish # GitHub Pages 배포'));
216
+ console.log('');
217
+
218
+ // .gitignore 업데이트
219
+ const gitignorePath = path.join(projectRoot, '.gitignore');
220
+ if (fs.existsSync(gitignorePath)) {
221
+ let gitignore = fs.readFileSync(gitignorePath, 'utf-8');
222
+ if (!gitignore.includes('site/')) {
223
+ gitignore += '\n# MkDocs build output\nsite/\n';
224
+ fs.writeFileSync(gitignorePath, gitignore);
225
+ console.log(chalk.gray('✓ .gitignore 업데이트됨'));
226
+ console.log('');
227
+ }
228
+ }
229
+ }
230
+
231
+ /**
232
+ * 문서 생성 (Documenter 역할 실행)
233
+ */
234
+ async function generateDocs(options) {
235
+ console.log('');
236
+ console.log(chalk.cyan('━'.repeat(60)));
237
+ console.log(chalk.cyan.bold('📝 문서 생성'));
238
+ console.log(chalk.cyan('━'.repeat(60)));
239
+ console.log('');
240
+
241
+ // Documenter 역할 실행을 위한 안내
242
+ console.log(chalk.yellow('💡 문서를 생성하려면 Documenter 역할을 실행하세요:'));
243
+ console.log('');
244
+ console.log(chalk.cyan(' ada documenter claude'));
245
+ console.log('');
246
+ console.log(chalk.gray('Documenter가 다음 작업을 수행합니다:'));
247
+ console.log(chalk.gray(' - 프로젝트 전체 분석'));
248
+ console.log(chalk.gray(' - docs/ 문서 생성/업데이트'));
249
+ console.log(chalk.gray(' - API 레퍼런스 자동 생성'));
250
+ console.log(chalk.gray(' - Changelog 업데이트'));
251
+ console.log('');
252
+ }
253
+
254
+ /**
255
+ * GitHub Pages 배포
256
+ */
257
+ async function publishDocs(options) {
258
+ const projectRoot = process.cwd();
259
+ const docsDir = path.join(projectRoot, 'docs');
260
+
261
+ console.log('');
262
+ console.log(chalk.cyan('━'.repeat(60)));
263
+ console.log(chalk.cyan.bold('🚀 GitHub Pages 배포'));
264
+ console.log(chalk.cyan('━'.repeat(60)));
265
+ console.log('');
266
+
267
+ // docs/ 디렉토리 확인
268
+ if (!fs.existsSync(docsDir)) {
269
+ console.log(chalk.red('❌ docs/ 디렉토리가 없습니다.'));
270
+ console.log(chalk.gray(' 먼저 ada docs init을 실행하세요.'));
271
+ process.exit(1);
272
+ }
273
+
274
+ // MkDocs인지 Jekyll인지 확인
275
+ const isMkDocs = fs.existsSync(path.join(docsDir, 'mkdocs.yml'));
276
+ const isJekyll = fs.existsSync(path.join(docsDir, '_config.yml'));
277
+
278
+ if (isMkDocs) {
279
+ console.log(chalk.cyan('📘 MkDocs 문서 배포'));
280
+
281
+ // 배포 확인
282
+ const answer = await inquirer.prompt([
283
+ {
284
+ type: 'confirm',
285
+ name: 'confirm',
286
+ message: 'GitHub Pages에 문서를 배포하시겠습니까? (gh-pages 브랜치에 푸시됩니다)',
287
+ default: false
288
+ }
289
+ ]);
290
+
291
+ if (!answer.confirm) {
292
+ console.log(chalk.yellow('⚠️ 배포가 취소되었습니다.'));
293
+ return;
294
+ }
295
+
296
+ // 가상환경 내의 mkdocs 실행 파일 확인 (venv 및 .venv 지원)
297
+ const venvCandidates = [
298
+ path.join(projectRoot, 'venv', 'Scripts', 'mkdocs.exe'), // Windows venv
299
+ path.join(projectRoot, 'venv', 'bin', 'mkdocs'), // Unix venv
300
+ path.join(projectRoot, '.venv', 'Scripts', 'mkdocs.exe'), // Windows .venv
301
+ path.join(projectRoot, '.venv', 'bin', 'mkdocs') // Unix .venv
302
+ ];
303
+
304
+ let mkdocsCmd = 'mkdocs';
305
+ let usingVenv = false;
306
+ for (const candidate of venvCandidates) {
307
+ if (fs.existsSync(candidate)) {
308
+ mkdocsCmd = candidate;
309
+ usingVenv = true;
310
+ break;
311
+ }
312
+ }
313
+
314
+ if (usingVenv) {
315
+ console.log(chalk.gray(` 가상환경 사용: ${mkdocsCmd}`));
316
+ } else {
317
+ console.log(chalk.gray(' 시스템 전역 mkdocs 사용 시도...'));
318
+ }
319
+ console.log('');
320
+
321
+ // mkdocs gh-deploy 실행
322
+ const mkdocs = spawn(mkdocsCmd, ['gh-deploy'], {
323
+ cwd: docsDir,
324
+ stdio: 'inherit',
325
+ shell: true
326
+ });
327
+
328
+ mkdocs.on('error', (err) => {
329
+ console.log('');
330
+ console.log(chalk.red('❌ MkDocs 실행 실패'));
331
+ console.log(chalk.yellow('💡 MkDocs가 설치되어 있는지 확인하세요.'));
332
+ process.exit(1);
333
+ });
334
+
335
+ mkdocs.on('close', (code) => {
336
+ if (code === 0) {
337
+ console.log('');
338
+ console.log(chalk.green('✅ 배포가 완료되었습니다!'));
339
+ console.log(chalk.gray(' 잠시 후 GitHub Pages 설정된 주소에서 확인할 수 있습니다.'));
340
+ } else {
341
+ console.log('');
342
+ console.log(chalk.red(`❌ 배포 중 오류가 발생했습니다 (코드: ${code})`));
343
+ }
344
+ });
345
+
346
+ } else if (isJekyll) {
347
+ console.log(chalk.cyan('📗 Jekyll 문서 배포'));
348
+ console.log('');
349
+ console.log(chalk.yellow('GitHub Pages 설정:'));
350
+ console.log('');
351
+ console.log(chalk.white(' 1. GitHub 저장소 설정으로 이동'));
352
+ console.log(chalk.white(' 2. Pages 섹션에서 "Branch" 선택'));
353
+ console.log(chalk.white(' 3. "main" 브랜치의 "/docs" 폴더 선택'));
354
+ console.log(chalk.white(' 4. Save'));
355
+ console.log('');
356
+ } else {
357
+ console.log(chalk.yellow('⚠️ 문서 생성기를 인식할 수 없습니다.'));
358
+ }
359
+
360
+ // 기존에는 여기서 함수가 끝났지만, spawn은 비동기이므로
361
+ // MkDocs의 경우 이벤트 핸들러에서 처리가 완료됩니다.
362
+ }
363
+
364
+ /**
365
+ * 로컬 문서 서버 실행
366
+ */
367
+ async function serveDocs(options) {
368
+ const projectRoot = process.cwd();
369
+ const docsDir = path.join(projectRoot, 'docs');
370
+
371
+ console.log('');
372
+ console.log(chalk.cyan('━'.repeat(60)));
373
+ console.log(chalk.cyan.bold('🌐 로컬 문서 서버'));
374
+ console.log(chalk.cyan('━'.repeat(60)));
375
+ console.log('');
376
+
377
+ if (!fs.existsSync(docsDir)) {
378
+ console.log(chalk.red('❌ docs/ 디렉토리가 없습니다.'));
379
+ console.log(chalk.gray(' 먼저 ada docs init을 실행하세요.'));
380
+ process.exit(1);
381
+ }
382
+
383
+ const isMkDocs = fs.existsSync(path.join(docsDir, 'mkdocs.yml'));
384
+ const isJekyll = fs.existsSync(path.join(docsDir, '_config.yml'));
385
+
386
+ if (isMkDocs) {
387
+ console.log(chalk.cyan('📘 MkDocs 서버 시작 중...'));
388
+
389
+ // 가상환경 내의 mkdocs 실행 파일 확인 (venv 및 .venv 지원)
390
+ const venvCandidates = [
391
+ path.join(projectRoot, 'venv', 'Scripts', 'mkdocs.exe'), // Windows venv
392
+ path.join(projectRoot, 'venv', 'bin', 'mkdocs'), // Unix venv
393
+ path.join(projectRoot, '.venv', 'Scripts', 'mkdocs.exe'), // Windows .venv
394
+ path.join(projectRoot, '.venv', 'bin', 'mkdocs') // Unix .venv
395
+ ];
396
+
397
+ let mkdocsCmd = 'mkdocs';
398
+ for (const candidate of venvCandidates) {
399
+ if (fs.existsSync(candidate)) {
400
+ mkdocsCmd = candidate;
401
+ console.log(chalk.gray(` 가상환경 사용: ${mkdocsCmd}`));
402
+ break;
403
+ }
404
+ }
405
+
406
+ console.log(chalk.gray(' 문서: http://127.0.0.1:8000'));
407
+ console.log(chalk.gray(' 종료: Ctrl+C'));
408
+ console.log('');
409
+
410
+ // mkdocs serve 실행
411
+ const mkdocs = spawn(mkdocsCmd, ['serve'], {
412
+ cwd: docsDir,
413
+ stdio: 'inherit',
414
+ shell: true
415
+ });
416
+
417
+ mkdocs.on('error', (err) => {
418
+ console.log('');
419
+ console.log(chalk.red('❌ MkDocs 실행 실패'));
420
+ console.log(chalk.yellow('💡 MkDocs가 설치되어 있는지 확인하세요:'));
421
+ console.log('');
422
+ console.log(chalk.gray('가상환경을 사용하여 설치하세요 (권장):'));
423
+ console.log('');
424
+ console.log(chalk.white(' python -m venv venv'));
425
+ console.log(chalk.white(' venv\\Scripts\\activate # Windows'));
426
+ console.log(chalk.white(' source venv/bin/activate # macOS/Linux'));
427
+ console.log(chalk.white(' pip install mkdocs mkdocs-material'));
428
+ console.log('');
429
+ process.exit(1);
430
+ });
431
+
432
+ mkdocs.on('close', (code) => {
433
+ if (code === 127) {
434
+ // command not found
435
+ console.log('');
436
+ console.log(chalk.red('❌ MkDocs가 설치되어 있지 않습니다.'));
437
+ console.log('');
438
+ console.log(chalk.yellow('💡 가상환경을 사용하여 설치하세요 (권장):'));
439
+ console.log('');
440
+ console.log(chalk.white(' python -m venv venv'));
441
+ console.log(chalk.white(' venv\\Scripts\\activate # Windows'));
442
+ console.log(chalk.white(' source venv/bin/activate # macOS/Linux'));
443
+ console.log(chalk.white(' pip install mkdocs mkdocs-material'));
444
+ console.log('');
445
+ console.log(chalk.gray('Python 3.x가 설치되지 않았다면 먼저 설치하세요:'));
446
+ console.log(chalk.gray(' Windows: https://www.python.org/downloads/'));
447
+ console.log(chalk.gray(' macOS: brew install python'));
448
+ console.log('');
449
+ process.exit(1);
450
+ } else if (code !== 0 && code !== null) {
451
+ console.log('');
452
+ console.log(chalk.yellow(`⚠️ 서버가 종료되었습니다 (코드: ${code})`));
453
+ }
454
+ });
455
+
456
+ } else if (isJekyll) {
457
+ console.log(chalk.cyan('📗 Jekyll 서버 시작 중...'));
458
+ console.log(chalk.gray(' 종료: Ctrl+C'));
459
+ console.log('');
460
+
461
+ // bundle exec jekyll serve 실행
462
+ const jekyll = spawn('bundle', ['exec', 'jekyll', 'serve'], {
463
+ cwd: docsDir,
464
+ stdio: 'inherit',
465
+ shell: true
466
+ });
467
+
468
+ jekyll.on('error', (err) => {
469
+ console.log('');
470
+ console.log(chalk.red('❌ Jekyll 실행 실패'));
471
+ console.log(chalk.yellow('💡 Jekyll이 설치되어 있는지 확인하세요:'));
472
+ console.log('');
473
+ console.log(chalk.white(' gem install bundler jekyll'));
474
+ console.log(chalk.white(' cd docs && bundle install'));
475
+ console.log('');
476
+ process.exit(1);
477
+ });
478
+
479
+ jekyll.on('close', (code) => {
480
+ if (code === 127) {
481
+ // command not found
482
+ console.log('');
483
+ console.log(chalk.red('❌ Jekyll이 설치되어 있지 않습니다.'));
484
+ console.log('');
485
+ console.log(chalk.yellow('💡 다음 명령어로 설치하세요:'));
486
+ console.log('');
487
+ console.log(chalk.white(' gem install bundler jekyll'));
488
+ console.log(chalk.white(' cd docs && bundle install'));
489
+ console.log('');
490
+ process.exit(1);
491
+ } else if (code !== 0 && code !== null) {
492
+ console.log('');
493
+ console.log(chalk.yellow(`⚠️ 서버가 종료되었습니다 (코드: ${code})`));
494
+ }
495
+ });
496
+
497
+ } else {
498
+ console.log(chalk.yellow('⚠️ 문서 생성기를 인식할 수 없습니다.'));
499
+ console.log(chalk.gray(' mkdocs.yml 또는 _config.yml 파일이 필요합니다.'));
500
+ console.log('');
501
+ }
502
+ }