@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.
- package/README.md +709 -516
- package/ai-dev-team/.ada-status.json +10 -0
- package/ai-dev-team/.ada-version +6 -0
- package/ai-dev-team/.current-template +1 -0
- package/ai-dev-team/.sessions/logs/20260124-014551-00f04724.log +5 -0
- package/ai-dev-team/.sessions/logs/20260124-014623-cb2b1d44.log +5 -0
- package/ai-dev-team/ada.config.json +15 -0
- package/ai-dev-team/artifacts/api.md +212 -0
- package/ai-dev-team/artifacts/decision.md +72 -0
- package/ai-dev-team/artifacts/improvement-reports/IMP-0000-template.md +57 -0
- package/ai-dev-team/artifacts/plan.md +187 -0
- package/ai-dev-team/artifacts/project.md +193 -0
- package/ai-dev-team/artifacts/sprints/_template/docs/release-notes.md +37 -0
- package/ai-dev-team/artifacts/sprints/_template/meta.md +54 -0
- package/ai-dev-team/artifacts/sprints/_template/retrospective.md +50 -0
- package/ai-dev-team/artifacts/sprints/_template/review-reports/review-template.md +49 -0
- package/ai-dev-team/artifacts/sprints/_template/tasks/task-template.md +43 -0
- package/ai-dev-team/artifacts/ui.md +104 -0
- package/ai-dev-team/roles/analyzer.md +265 -0
- package/ai-dev-team/roles/developer.md +222 -0
- package/ai-dev-team/roles/documenter.md +715 -0
- package/ai-dev-team/roles/improver.md +461 -0
- package/ai-dev-team/roles/manager.md +544 -0
- package/ai-dev-team/roles/planner.md +398 -0
- package/ai-dev-team/roles/reviewer.md +294 -0
- package/ai-dev-team/rules/api-change.md +198 -0
- package/ai-dev-team/rules/document-priority.md +199 -0
- package/ai-dev-team/rules/escalation.md +172 -0
- package/ai-dev-team/rules/iteration.md +236 -0
- package/ai-dev-team/rules/rfc.md +31 -0
- package/ai-dev-team/rules/rollback.md +218 -0
- package/bin/cli.js +49 -5
- package/core/artifacts/sprints/_template/meta.md +4 -4
- package/core/docs-templates/mkdocs/docs/architecture/overview.md +29 -0
- package/core/docs-templates/mkdocs/docs/changelog.md +36 -0
- package/core/docs-templates/mkdocs/docs/contributing/contributing.md +60 -0
- package/core/docs-templates/mkdocs/docs/getting-started/configuration.md +51 -0
- package/core/docs-templates/mkdocs/docs/getting-started/installation.md +41 -0
- package/core/docs-templates/mkdocs/docs/getting-started/quick-start.md +56 -0
- package/core/docs-templates/mkdocs/docs/guides/api-reference.md +83 -0
- package/core/docs-templates/mkdocs/docs/index.md +32 -0
- package/core/docs-templates/mkdocs/mkdocs.yml +86 -0
- package/core/roles/analyzer.md +32 -10
- package/core/roles/developer.md +222 -223
- package/core/roles/documenter.md +592 -170
- package/core/roles/improver.md +461 -0
- package/core/roles/manager.md +4 -1
- package/core/roles/planner.md +160 -10
- package/core/roles/reviewer.md +31 -3
- package/core/rules/document-priority.md +2 -1
- package/core/rules/rollback.md +3 -3
- package/package.json +1 -1
- package/src/commands/config.js +371 -0
- package/src/commands/docs.js +502 -0
- package/src/commands/interactive.js +324 -33
- package/src/commands/monitor.js +236 -0
- package/src/commands/run.js +360 -122
- package/src/commands/sessions.js +270 -70
- package/src/commands/setup.js +22 -1
- package/src/commands/sprint.js +295 -54
- package/src/commands/status.js +34 -1
- package/src/commands/upgrade.js +416 -0
- package/src/commands/validate.js +4 -3
- package/src/index.js +1 -0
- package/src/ui/dashboard.js +518 -0
- package/src/ui/keyHandler.js +147 -0
- package/src/ui/quickActions.js +111 -0
- package/src/utils/config.js +74 -0
- package/src/utils/files.js +70 -3
- package/src/utils/sessionState.js +472 -328
- package/src/utils/sessionState.process.test.js +101 -0
- package/src/utils/sessionState.test.js +183 -0
- package/src/utils/sprintUtils.js +134 -0
- package/src/utils/taskParser.js +134 -0
- package/src/utils/taskParser.test.js +76 -0
- package/ai-dev-team/artifacts/features/_template/qa.md +0 -16
- package/examples/todo-app/README.md +0 -23
- package/examples/todo-app/artifacts/backlog.md +0 -23
- package/examples/todo-app/artifacts/plan.md +0 -23
- 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
|
+
}
|