@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
@@ -1,11 +1,14 @@
1
1
  import fs from 'fs-extra';
2
2
  import path from 'path';
3
3
  import chalk from 'chalk';
4
- import { getWorkspaceDir, isWorkspaceSetup, getTimestamp } from '../utils/files.js';
4
+ import inquirer from 'inquirer';
5
+ import { getWorkspaceDir, isWorkspaceSetup } from '../utils/files.js';
6
+ import { syncSprint, findActiveSprint, updateSprintMeta } from '../utils/sprintUtils.js';
7
+ import { normalizeTaskStatus } from '../utils/taskParser.js';
5
8
 
6
9
  /**
7
10
  * 스프린트 관리 명령어
8
- * @param {string} action - create / add / close / list
11
+ * @param {string} action - create / add / close / list / sync
9
12
  * @param {Array} args - 추가 인자
10
13
  */
11
14
  export default async function sprint(action, ...args) {
@@ -25,8 +28,11 @@ export default async function sprint(action, ...args) {
25
28
  case 'add':
26
29
  await addTasks(sprintsDir, args);
27
30
  break;
31
+ case 'sync':
32
+ await syncSprint(sprintsDir);
33
+ break;
28
34
  case 'close':
29
- await closeSprint(sprintsDir);
35
+ await closeSprint(sprintsDir, args);
30
36
  break;
31
37
  case 'list':
32
38
  await listSprints(sprintsDir);
@@ -35,10 +41,14 @@ export default async function sprint(action, ...args) {
35
41
  console.log(chalk.red('❌ 알 수 없는 명령어입니다.'));
36
42
  console.log('');
37
43
  console.log(chalk.cyan('사용법:'));
38
- console.log(chalk.gray(' ada sprint create - 새 스프린트 생성'));
39
- console.log(chalk.gray(' ada sprint add task-001 ... - Task 추가'));
40
- console.log(chalk.gray(' ada sprint close - 현재 스프린트 종료'));
41
- console.log(chalk.gray(' ada sprint list - 스프린트 목록'));
44
+ console.log(chalk.gray(' ada sprint create - 새 스프린트 생성'));
45
+ console.log(chalk.gray(' ada sprint add task-001 ... - Task 추가'));
46
+ console.log(chalk.gray(' ada sprint sync - meta.md 상태 동기화'));
47
+ console.log(chalk.gray(' ada sprint close - 스프린트 종료 (작업 파일 archive)'));
48
+ console.log(chalk.gray(' ada sprint close --auto - 스프린트 자동 종료 (회고 기본값)'));
49
+ console.log(chalk.gray(' ada sprint close --clean - 스프린트 종료 (작업 파일 삭제)'));
50
+ console.log(chalk.gray(' ada sprint close --keep-all - 스프린트 종료 (파일 유지)'));
51
+ console.log(chalk.gray(' ada sprint list - 스프린트 목록'));
42
52
  process.exit(1);
43
53
  }
44
54
  }
@@ -73,25 +83,37 @@ async function createSprint(sprintsDir) {
73
83
  const sprintName = `sprint-${nextNumber}`;
74
84
  const sprintPath = path.join(sprintsDir, sprintName);
75
85
 
76
- // 템플릿 복사
77
- const templatePath = path.join(sprintsDir, '_template');
78
- if (!fs.existsSync(templatePath)) {
79
- console.log(chalk.red('❌ 스프린트 템플릿이 없습니다.'));
80
- process.exit(1);
81
- }
82
-
83
- fs.copySync(templatePath, sprintPath);
86
+ // 스프린트 디렉토리 구조 생성
87
+ fs.ensureDirSync(path.join(sprintPath, 'tasks'));
88
+ fs.ensureDirSync(path.join(sprintPath, 'review-reports'));
89
+ fs.ensureDirSync(path.join(sprintPath, 'docs'));
84
90
 
85
- // meta.md 업데이트
91
+ // meta.md 생성 (간소화된 버전)
86
92
  const metaPath = path.join(sprintPath, 'meta.md');
87
- let metaContent = fs.readFileSync(metaPath, 'utf-8');
88
93
  const today = new Date().toISOString().slice(0, 10);
89
94
 
90
- metaContent = metaContent
91
- .replace(/스프린트 번호 \| N/, `스프린트 번호 | ${nextNumber}`)
92
- .replace(/상태 \| active \/ completed/, `상태 | active`)
93
- .replace(/시작일 \| YYYY-MM-DD/, `시작일 | ${today}`)
94
- .replace(/종료 예정 \| YYYY-MM-DD/, `종료 예정 | TBD`);
95
+ const metaContent = `# Sprint ${nextNumber} 메타정보
96
+
97
+ | 항목 | |
98
+ |------|-----|
99
+ | 스프린트 번호 | ${nextNumber} |
100
+ | 상태 | active |
101
+ | 시작일 | ${today} |
102
+ | 종료 예정 | TBD |
103
+
104
+ ## Task 목록
105
+
106
+ > Task는 \`ada sprint add task-NNN\` 명령어로 추가됩니다.
107
+ > 추가된 Task는 아래에 자동으로 나열됩니다.
108
+
109
+ (Task 없음)
110
+
111
+ ## 참고
112
+
113
+ - Task 상태: BACKLOG → IN_DEV → DONE
114
+ - 리뷰 결과: review-reports/ 참고
115
+ - 최종 문서: docs/ 참고
116
+ `;
95
117
 
96
118
  fs.writeFileSync(metaPath, metaContent);
97
119
 
@@ -109,29 +131,6 @@ async function createSprint(sprintsDir) {
109
131
  console.log('');
110
132
  }
111
133
 
112
- /**
113
- * 현재 활성 스프린트 찾기
114
- */
115
- function findActiveSprint(sprintsDir) {
116
- if (!fs.existsSync(sprintsDir)) return null;
117
-
118
- const sprints = fs.readdirSync(sprintsDir).filter(d => {
119
- return fs.statSync(path.join(sprintsDir, d)).isDirectory() && !d.startsWith('_');
120
- });
121
-
122
- for (const sprint of sprints) {
123
- const metaPath = path.join(sprintsDir, sprint, 'meta.md');
124
- if (fs.existsSync(metaPath)) {
125
- const content = fs.readFileSync(metaPath, 'utf-8');
126
- if (content.includes('상태 | active')) {
127
- return sprint;
128
- }
129
- }
130
- }
131
-
132
- return null;
133
- }
134
-
135
134
  /**
136
135
  * Task 추가
137
136
  */
@@ -158,7 +157,7 @@ async function addTasks(sprintsDir, taskIds) {
158
157
  }
159
158
 
160
159
  let addedCount = 0;
161
-
160
+
162
161
  for (const taskId of taskIds) {
163
162
  const taskFile = `${taskId}.md`;
164
163
  const sourcePath = path.join(backlogPath, taskFile);
@@ -181,17 +180,20 @@ async function addTasks(sprintsDir, taskIds) {
181
180
  console.log(chalk.green(`✅ ${taskId} 추가됨`));
182
181
  }
183
182
 
183
+ // meta.md 업데이트 (Sync 호출)
184
+ await syncSprint(sprintsDir, true);
185
+
184
186
  console.log('');
185
187
  console.log(chalk.cyan(`📊 ${addedCount}개 Task가 ${activeSprint}에 추가되었습니다.`));
186
188
  console.log('');
187
- console.log(chalk.gray(` meta.md를 업데이트하여 Task 목록을 갱신하세요.`));
188
- console.log('');
189
189
  }
190
190
 
191
191
  /**
192
192
  * 스프린트 종료
193
+ * @param {string} sprintsDir - 스프린트 디렉토리
194
+ * @param {Array} args - 옵션 (--clean, --keep-all, --auto)
193
195
  */
194
- async function closeSprint(sprintsDir) {
196
+ async function closeSprint(sprintsDir, args = []) {
195
197
  const activeSprint = findActiveSprint(sprintsDir);
196
198
  if (!activeSprint) {
197
199
  console.log(chalk.red('❌ 활성 스프린트가 없습니다.'));
@@ -201,6 +203,14 @@ async function closeSprint(sprintsDir) {
201
203
  const sprintPath = path.join(sprintsDir, activeSprint);
202
204
  const metaPath = path.join(sprintPath, 'meta.md');
203
205
 
206
+ // 옵션 파싱
207
+ const hasClean = args.includes('--clean');
208
+ const hasKeepAll = args.includes('--keep-all');
209
+ const isAuto = args.includes('--auto');
210
+
211
+ // 종료 전 마지막 동기화
212
+ await syncSprint(sprintsDir, true);
213
+
204
214
  // meta.md 업데이트 (active → completed)
205
215
  let metaContent = fs.readFileSync(metaPath, 'utf-8');
206
216
  const today = new Date().toISOString().slice(0, 10);
@@ -211,13 +221,93 @@ async function closeSprint(sprintsDir) {
211
221
 
212
222
  fs.writeFileSync(metaPath, metaContent);
213
223
 
224
+ // retrospective.md 생성
214
225
  console.log('');
215
- console.log(chalk.green(`✅ ${activeSprint}가 종료되었습니다!`));
226
+ console.log(chalk.cyan('📝 스프린트 회고 작성'));
227
+ console.log(chalk.gray('━'.repeat(50)));
228
+
229
+ let retrospectiveData;
230
+ if (isAuto) {
231
+ console.log(chalk.gray('🤖 자동 모드: 기본값으로 회고 작성'));
232
+ retrospectiveData = await getRetrospectiveDataAuto(sprintPath);
233
+ } else {
234
+ retrospectiveData = await promptRetrospective(sprintPath);
235
+ }
236
+
237
+ createRetrospective(sprintPath, activeSprint, today, retrospectiveData);
238
+
216
239
  console.log('');
217
- console.log(chalk.cyan('다음 단계:'));
218
- console.log(chalk.gray(` 1. meta.md 회고 섹션 작성`));
219
- console.log(chalk.gray(` 2. ada documenter [tool]로 문서 작성`));
220
- console.log(chalk.gray(` 3. ada sprint create로 다음 스프린트 시작`));
240
+ console.log(chalk.green(' 회고 작성 완료'));
241
+
242
+ // 작업 파일 정리
243
+ if (!hasKeepAll) {
244
+ const tasksDir = path.join(sprintPath, 'tasks');
245
+ const reviewReportsDir = path.join(sprintPath, 'review-reports');
246
+
247
+ if (hasClean) {
248
+ // --clean: 완전 삭제
249
+ console.log('');
250
+ console.log(chalk.yellow('🗑️ 작업 파일 삭제 중...'));
251
+
252
+ let deletedCount = 0;
253
+ if (fs.existsSync(tasksDir)) {
254
+ const taskFiles = fs.readdirSync(tasksDir).filter(f => !f.includes('template'));
255
+ taskFiles.forEach(f => fs.removeSync(path.join(tasksDir, f)));
256
+ deletedCount += taskFiles.length;
257
+ }
258
+ if (fs.existsSync(reviewReportsDir)) {
259
+ const reviewFiles = fs.readdirSync(reviewReportsDir).filter(f => !f.includes('template'));
260
+ reviewFiles.forEach(f => fs.removeSync(path.join(reviewReportsDir, f)));
261
+ deletedCount += reviewFiles.length;
262
+ }
263
+
264
+ console.log(chalk.gray(` ✓ ${deletedCount}개 파일 삭제됨`));
265
+ } else {
266
+ // 기본: archive/ 폴더로 이동
267
+ console.log('');
268
+ console.log(chalk.cyan('📦 작업 파일 보관 중...'));
269
+
270
+ const archiveDir = path.join(sprintPath, 'archive');
271
+ fs.ensureDirSync(archiveDir);
272
+
273
+ let archivedCount = 0;
274
+
275
+ // tasks/ 이동
276
+ if (fs.existsSync(tasksDir)) {
277
+ const taskFiles = fs.readdirSync(tasksDir).filter(f => !f.includes('template'));
278
+ if (taskFiles.length > 0) {
279
+ const archiveTasksDir = path.join(archiveDir, 'tasks');
280
+ fs.ensureDirSync(archiveTasksDir);
281
+ taskFiles.forEach(f => {
282
+ fs.moveSync(path.join(tasksDir, f), path.join(archiveTasksDir, f), { overwrite: true });
283
+ });
284
+ archivedCount += taskFiles.length;
285
+ }
286
+ }
287
+
288
+ // review-reports/ 이동
289
+ if (fs.existsSync(reviewReportsDir)) {
290
+ const reviewFiles = fs.readdirSync(reviewReportsDir).filter(f => !f.includes('template'));
291
+ if (reviewFiles.length > 0) {
292
+ const archiveReviewsDir = path.join(archiveDir, 'review-reports');
293
+ fs.ensureDirSync(archiveReviewsDir);
294
+ reviewFiles.forEach(f => {
295
+ fs.moveSync(path.join(reviewReportsDir, f), path.join(archiveReviewsDir, f), { overwrite: true });
296
+ });
297
+ archivedCount += reviewFiles.length;
298
+ }
299
+ }
300
+
301
+ if (archivedCount > 0) {
302
+ console.log(chalk.gray(` ✓ ${archivedCount}개 파일 → archive/`));
303
+ } else {
304
+ console.log(chalk.gray(` ✓ 정리할 파일 없음`));
305
+ }
306
+ }
307
+ }
308
+
309
+ console.log('');
310
+ console.log(chalk.green(`✅ ${activeSprint}가 종료되었습니다!`));
221
311
  console.log('');
222
312
  }
223
313
 
@@ -260,3 +350,154 @@ async function listSprints(sprintsDir) {
260
350
 
261
351
  console.log('');
262
352
  }
353
+
354
+ /**
355
+ * 회고 데이터 자동 생성 (Auto Mode)
356
+ */
357
+ async function getRetrospectiveDataAuto(sprintPath) {
358
+ const { completedTasks, incompleteTasks } = getTaskStatusForRetrospective(sprintPath);
359
+
360
+ return {
361
+ completedTasks,
362
+ incompleteTasks,
363
+ keep: '자동 완료됨',
364
+ problem: '-',
365
+ try: '-'
366
+ };
367
+ }
368
+
369
+ /**
370
+ * 회고 작성 프롬프트
371
+ */
372
+ async function promptRetrospective(sprintPath) {
373
+ const { completedTasks, incompleteTasks } = getTaskStatusForRetrospective(sprintPath);
374
+
375
+ console.log('');
376
+ console.log(chalk.white(`완료된 Task: ${completedTasks.length}개`));
377
+ console.log(chalk.white(`미완료 Task: ${incompleteTasks.length}개`));
378
+ console.log('');
379
+
380
+ const answers = await inquirer.prompt([
381
+ {
382
+ type: 'input',
383
+ name: 'keep',
384
+ message: '잘된 점 (Keep):',
385
+ default: '계획대로 진행됨'
386
+ },
387
+ {
388
+ type: 'input',
389
+ name: 'problem',
390
+ message: '개선할 점 (Problem):',
391
+ default: '-'
392
+ },
393
+ {
394
+ type: 'input',
395
+ name: 'try',
396
+ message: '시도할 것 (Try):',
397
+ default: '-'
398
+ }
399
+ ]);
400
+
401
+ return {
402
+ completedTasks,
403
+ incompleteTasks,
404
+ ...answers
405
+ };
406
+ }
407
+
408
+ /**
409
+ * 회고를 위한 Task 상태 분류 헬퍼
410
+ */
411
+ function getTaskStatusForRetrospective(sprintPath) {
412
+ // meta.md에서 Task 정보 읽기
413
+ const metaPath = path.join(sprintPath, 'meta.md');
414
+ const metaContent = fs.readFileSync(metaPath, 'utf-8');
415
+
416
+ // Task 목록/요약 파싱
417
+ const taskLines = metaContent
418
+ .split('\n')
419
+ .filter(line => line.trim().toLowerCase().startsWith('| task-'));
420
+ const knownStatuses = new Set(['BACKLOG', 'IN_DEV', 'IN_REVIEW', 'DONE', 'REJECT', 'REJECTED', 'BLOCKED']);
421
+
422
+ const completedTasks = [];
423
+ const incompleteTasks = [];
424
+
425
+ taskLines.forEach(line => {
426
+ const columns = line.split('|').map(col => col.trim()).filter(col => col.length > 0);
427
+ if (columns.length < 2) return;
428
+
429
+ const id = columns[0];
430
+ let status = null;
431
+
432
+ const candidate1 = normalizeTaskStatus(columns[1]);
433
+ if (knownStatuses.has(candidate1)) {
434
+ status = candidate1;
435
+ } else if (columns.length > 2) {
436
+ const candidate2 = normalizeTaskStatus(columns[2]);
437
+ if (knownStatuses.has(candidate2)) {
438
+ status = candidate2;
439
+ }
440
+ }
441
+
442
+ if (status === 'DONE') {
443
+ completedTasks.push(id);
444
+ } else {
445
+ incompleteTasks.push(id);
446
+ }
447
+ });
448
+
449
+ return { completedTasks, incompleteTasks };
450
+ }
451
+
452
+ /**
453
+ * retrospective.md 파일 생성
454
+ */
455
+ function createRetrospective(sprintPath, sprintName, endDate, data) {
456
+ const retrospectivePath = path.join(sprintPath, 'retrospective.md');
457
+
458
+ // 시작일은 meta.md에서 가져오기
459
+ const metaPath = path.join(sprintPath, 'meta.md');
460
+ const metaContent = fs.readFileSync(metaPath, 'utf-8');
461
+ const startDateMatch = metaContent.match(/시작일 \| ([\d-]+)/);
462
+ const startDate = startDateMatch ? startDateMatch[1] : endDate;
463
+
464
+ const sprintNumber = sprintName.replace('sprint-', '');
465
+ const totalTasks = data.completedTasks.length + data.incompleteTasks.length;
466
+ const completionRate = totalTasks > 0 ? Math.round((data.completedTasks.length / totalTasks) * 100) : 0;
467
+
468
+ const content = `# Sprint ${sprintNumber} 회고
469
+
470
+ ## 기간
471
+ - 시작: ${startDate}
472
+ - 종료: ${endDate}
473
+
474
+ ## 완료된 Task (${data.completedTasks.length}개)
475
+
476
+ ${data.completedTasks.map(t => `- ${t}`).join('\n') || '- (없음)'}
477
+
478
+ ## 미완료 Task (${data.incompleteTasks.length}개)
479
+
480
+ ${data.incompleteTasks.map(t => `- ${t}: 이월 필요`).join('\n') || '- (없음)'}
481
+
482
+ ## 잘된 점 (Keep)
483
+
484
+ - ${data.keep}
485
+
486
+ ## 개선할 점 (Problem)
487
+
488
+ - ${data.problem}
489
+
490
+ ## 시도할 것 (Try)
491
+
492
+ - ${data.try}
493
+
494
+ ## 메트릭
495
+
496
+ - 계획 Task 수: ${totalTasks}개
497
+ - 완료 Task 수: ${data.completedTasks.length}개
498
+ - 완료율: ${completionRate}%
499
+ - 이월 Task 수: ${data.incompleteTasks.length}개
500
+ `;
501
+
502
+ fs.writeFileSync(retrospectivePath, content);
503
+ }
@@ -4,7 +4,10 @@ import chalk from 'chalk';
4
4
  import {
5
5
  getWorkspaceDir,
6
6
  getCurrentTemplate,
7
- isWorkspaceSetup
7
+ isWorkspaceSetup,
8
+ getPackageVersion,
9
+ readVersion,
10
+ compareVersions
8
11
  } from '../utils/files.js';
9
12
 
10
13
  export async function status() {
@@ -30,6 +33,36 @@ export async function status() {
30
33
  const artifactsDir = path.join(workspace, 'artifacts');
31
34
  const rulesDir = path.join(workspace, 'rules');
32
35
 
36
+ // 버전 정보 확인
37
+ const packageVersion = getPackageVersion();
38
+ const versionInfo = readVersion();
39
+ const workspaceVersion = versionInfo ? (versionInfo.workspaceVersion || versionInfo.packageVersion) : null;
40
+
41
+ console.log(chalk.white.bold('버전:'));
42
+ console.log(chalk.gray(` 패키지: ${packageVersion}`));
43
+ if (workspaceVersion) {
44
+ console.log(chalk.gray(` 작업공간: ${workspaceVersion}`));
45
+
46
+ // 버전 비교
47
+ const versionDiff = compareVersions(packageVersion, workspaceVersion);
48
+ if (versionDiff > 0) {
49
+ console.log('');
50
+ console.log(chalk.yellow('⚠️ 새 버전이 있습니다!'));
51
+ console.log(chalk.gray(` 현재: ${workspaceVersion} → 최신: ${packageVersion}`));
52
+ console.log(chalk.gray(' 업그레이드하려면: ada upgrade'));
53
+ } else if (versionDiff < 0) {
54
+ console.log('');
55
+ console.log(chalk.yellow('⚠️ 작업공간 버전이 패키지 버전보다 높습니다.'));
56
+ console.log(chalk.gray(' 개발 버전이거나 패키지 다운그레이드됨'));
57
+ }
58
+ } else {
59
+ console.log(chalk.gray(` 작업공간: 버전 정보 없음`));
60
+ console.log('');
61
+ console.log(chalk.yellow('⚠️ 이전 버전에서 생성된 작업공간입니다.'));
62
+ console.log(chalk.gray(' 업그레이드 권장: ada upgrade'));
63
+ }
64
+ console.log('');
65
+
33
66
  // 템플릿 정보
34
67
  console.log(chalk.white.bold('템플릿:'), chalk.green(template || '알 수 없음'));
35
68
  console.log('');