@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,416 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
5
|
+
import {
|
|
6
|
+
getPackageRoot,
|
|
7
|
+
getWorkspaceDir,
|
|
8
|
+
getBackupDir,
|
|
9
|
+
getPackageVersion,
|
|
10
|
+
readVersion,
|
|
11
|
+
writeVersion,
|
|
12
|
+
compareVersions,
|
|
13
|
+
getCurrentTemplate,
|
|
14
|
+
isWorkspaceSetup,
|
|
15
|
+
copyDirMerge,
|
|
16
|
+
getTimestamp
|
|
17
|
+
} from '../utils/files.js';
|
|
18
|
+
|
|
19
|
+
export async function upgrade(options = {}) {
|
|
20
|
+
// 작업공간 확인
|
|
21
|
+
if (!isWorkspaceSetup()) {
|
|
22
|
+
console.log(chalk.red('❌ 작업공간이 세팅되어 있지 않습니다.'));
|
|
23
|
+
console.log(chalk.gray(' ada setup 명령어로 먼저 세팅하세요.'));
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const packageVersion = getPackageVersion();
|
|
28
|
+
let workspaceVersionInfo = readVersion();
|
|
29
|
+
const currentTemplate = getCurrentTemplate();
|
|
30
|
+
|
|
31
|
+
if (!workspaceVersionInfo) {
|
|
32
|
+
console.log(chalk.yellow('⚠️ 작업공간에 버전 정보가 없습니다.'));
|
|
33
|
+
console.log(chalk.gray(' 이전 버전에서 생성된 작업공간으로 추정됩니다.'));
|
|
34
|
+
console.log('');
|
|
35
|
+
|
|
36
|
+
if (!options.force) {
|
|
37
|
+
const answer = await inquirer.prompt([
|
|
38
|
+
{
|
|
39
|
+
type: 'confirm',
|
|
40
|
+
name: 'continue',
|
|
41
|
+
message: '업그레이드를 계속하시겠습니까?',
|
|
42
|
+
default: true
|
|
43
|
+
}
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
if (!answer.continue) {
|
|
47
|
+
console.log(chalk.gray('취소되었습니다.'));
|
|
48
|
+
process.exit(0);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 버전 정보 초기화
|
|
53
|
+
workspaceVersionInfo = {
|
|
54
|
+
packageVersion: '0.0.0',
|
|
55
|
+
workspaceVersion: '0.0.0',
|
|
56
|
+
template: currentTemplate,
|
|
57
|
+
lastUpgrade: null
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const workspaceVersion = workspaceVersionInfo.workspaceVersion || workspaceVersionInfo.packageVersion;
|
|
62
|
+
|
|
63
|
+
console.log('');
|
|
64
|
+
console.log(chalk.cyan('━'.repeat(50)));
|
|
65
|
+
console.log(chalk.cyan.bold('🔄 ada 업그레이드'));
|
|
66
|
+
console.log(chalk.cyan('━'.repeat(50)));
|
|
67
|
+
console.log('');
|
|
68
|
+
console.log(chalk.gray(`현재 작업공간 버전: ${workspaceVersion}`));
|
|
69
|
+
console.log(chalk.gray(`최신 패키지 버전: ${packageVersion}`));
|
|
70
|
+
console.log('');
|
|
71
|
+
|
|
72
|
+
// 버전 비교
|
|
73
|
+
const versionDiff = compareVersions(packageVersion, workspaceVersion);
|
|
74
|
+
|
|
75
|
+
if (versionDiff === 0) {
|
|
76
|
+
console.log(chalk.green('✅ 이미 최신 버전입니다.'));
|
|
77
|
+
process.exit(0);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (versionDiff < 0) {
|
|
81
|
+
console.log(chalk.yellow('⚠️ 작업공간 버전이 패키지 버전보다 높습니다.'));
|
|
82
|
+
console.log(chalk.gray(' 개발 중이거나 다운그레이드된 패키지일 수 있습니다.'));
|
|
83
|
+
|
|
84
|
+
if (!options.force) {
|
|
85
|
+
const answer = await inquirer.prompt([
|
|
86
|
+
{
|
|
87
|
+
type: 'confirm',
|
|
88
|
+
name: 'continue',
|
|
89
|
+
message: '그래도 업그레이드하시겠습니까?',
|
|
90
|
+
default: false
|
|
91
|
+
}
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
if (!answer.continue) {
|
|
95
|
+
console.log(chalk.gray('취소되었습니다.'));
|
|
96
|
+
process.exit(0);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 롤백 처리
|
|
102
|
+
if (options.rollback) {
|
|
103
|
+
await handleRollback();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Dry-run 모드
|
|
108
|
+
if (options.dryRun) {
|
|
109
|
+
await performDryRun(workspaceVersion, packageVersion);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 실제 업그레이드
|
|
114
|
+
await performUpgrade(workspaceVersion, packageVersion, options);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 롤백 처리
|
|
119
|
+
*/
|
|
120
|
+
async function handleRollback() {
|
|
121
|
+
const backupDir = getBackupDir();
|
|
122
|
+
|
|
123
|
+
if (!fs.existsSync(backupDir)) {
|
|
124
|
+
console.log(chalk.red('❌ 백업이 없습니다.'));
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const backups = fs.readdirSync(backupDir)
|
|
129
|
+
.filter(d => d.startsWith('upgrade-'))
|
|
130
|
+
.sort()
|
|
131
|
+
.reverse();
|
|
132
|
+
|
|
133
|
+
if (backups.length === 0) {
|
|
134
|
+
console.log(chalk.red('❌ 백업이 없습니다.'));
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
console.log(chalk.cyan('사용 가능한 백업:'));
|
|
139
|
+
backups.forEach((backup, index) => {
|
|
140
|
+
const backupPath = path.join(backupDir, backup);
|
|
141
|
+
const versionFile = path.join(backupPath, '.ada-version');
|
|
142
|
+
let versionInfo = 'unknown';
|
|
143
|
+
if (fs.existsSync(versionFile)) {
|
|
144
|
+
const info = JSON.parse(fs.readFileSync(versionFile, 'utf-8'));
|
|
145
|
+
versionInfo = info.workspaceVersion || info.packageVersion;
|
|
146
|
+
}
|
|
147
|
+
console.log(chalk.gray(` ${index + 1}. ${backup} (v${versionInfo})`));
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const answer = await inquirer.prompt([
|
|
151
|
+
{
|
|
152
|
+
type: 'list',
|
|
153
|
+
name: 'backup',
|
|
154
|
+
message: '복원할 백업을 선택하세요:',
|
|
155
|
+
choices: backups.map((b, i) => ({ name: `${i + 1}. ${b}`, value: b }))
|
|
156
|
+
}
|
|
157
|
+
]);
|
|
158
|
+
|
|
159
|
+
const selectedBackup = path.join(backupDir, answer.backup);
|
|
160
|
+
const workspace = getWorkspaceDir();
|
|
161
|
+
|
|
162
|
+
console.log('');
|
|
163
|
+
console.log(chalk.yellow('⚠️ 현재 작업공간을 백업으로 덮어씁니다.'));
|
|
164
|
+
|
|
165
|
+
const confirm = await inquirer.prompt([
|
|
166
|
+
{
|
|
167
|
+
type: 'confirm',
|
|
168
|
+
name: 'confirm',
|
|
169
|
+
message: '계속하시겠습니까?',
|
|
170
|
+
default: false
|
|
171
|
+
}
|
|
172
|
+
]);
|
|
173
|
+
|
|
174
|
+
if (!confirm.confirm) {
|
|
175
|
+
console.log(chalk.gray('취소되었습니다.'));
|
|
176
|
+
process.exit(0);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// 롤백 실행
|
|
180
|
+
console.log(chalk.gray('복원 중...'));
|
|
181
|
+
|
|
182
|
+
// roles, rules 복원
|
|
183
|
+
['roles', 'rules'].forEach(dir => {
|
|
184
|
+
const backupPath = path.join(selectedBackup, dir);
|
|
185
|
+
const workspacePath = path.join(workspace, dir);
|
|
186
|
+
|
|
187
|
+
if (fs.existsSync(backupPath)) {
|
|
188
|
+
fs.removeSync(workspacePath);
|
|
189
|
+
fs.copySync(backupPath, workspacePath);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// 버전 정보 복원
|
|
194
|
+
const backupVersionFile = path.join(selectedBackup, '.ada-version');
|
|
195
|
+
if (fs.existsSync(backupVersionFile)) {
|
|
196
|
+
fs.copyFileSync(backupVersionFile, path.join(workspace, '.ada-version'));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
console.log('');
|
|
200
|
+
console.log(chalk.green('✅ 롤백 완료!'));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Dry-run 수행
|
|
205
|
+
*/
|
|
206
|
+
async function performDryRun(workspaceVersion, packageVersion) {
|
|
207
|
+
const packageRoot = getPackageRoot();
|
|
208
|
+
const workspace = getWorkspaceDir();
|
|
209
|
+
const template = getCurrentTemplate();
|
|
210
|
+
|
|
211
|
+
console.log(chalk.cyan('🔍 변경 사항 미리보기 (실제 변경 없음)'));
|
|
212
|
+
console.log('');
|
|
213
|
+
|
|
214
|
+
const changes = [];
|
|
215
|
+
|
|
216
|
+
// roles 디렉토리 비교
|
|
217
|
+
const coreRoles = path.join(packageRoot, 'core', 'roles');
|
|
218
|
+
const templateRoles = path.join(packageRoot, 'templates', template, 'roles');
|
|
219
|
+
const workspaceRoles = path.join(workspace, 'roles');
|
|
220
|
+
|
|
221
|
+
if (fs.existsSync(coreRoles)) {
|
|
222
|
+
const coreFiles = fs.readdirSync(coreRoles).filter(f => f.endsWith('.md'));
|
|
223
|
+
coreFiles.forEach(file => {
|
|
224
|
+
const workspaceFile = path.join(workspaceRoles, file);
|
|
225
|
+
if (fs.existsSync(workspaceFile)) {
|
|
226
|
+
changes.push({ type: 'UPDATE', category: 'roles', file });
|
|
227
|
+
} else {
|
|
228
|
+
changes.push({ type: 'ADD', category: 'roles', file });
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (fs.existsSync(templateRoles)) {
|
|
234
|
+
const templateFiles = fs.readdirSync(templateRoles).filter(f => f.endsWith('.md'));
|
|
235
|
+
templateFiles.forEach(file => {
|
|
236
|
+
const workspaceFile = path.join(workspaceRoles, file);
|
|
237
|
+
if (fs.existsSync(workspaceFile)) {
|
|
238
|
+
changes.push({ type: 'UPDATE', category: 'roles', file });
|
|
239
|
+
} else {
|
|
240
|
+
changes.push({ type: 'ADD', category: 'roles', file });
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// rules 디렉토리 비교
|
|
246
|
+
const coreRules = path.join(packageRoot, 'core', 'rules');
|
|
247
|
+
const templateRules = path.join(packageRoot, 'templates', template, 'rules');
|
|
248
|
+
const workspaceRules = path.join(workspace, 'rules');
|
|
249
|
+
|
|
250
|
+
if (fs.existsSync(coreRules)) {
|
|
251
|
+
const coreFiles = fs.readdirSync(coreRules).filter(f => f.endsWith('.md'));
|
|
252
|
+
coreFiles.forEach(file => {
|
|
253
|
+
const workspaceFile = path.join(workspaceRules, file);
|
|
254
|
+
if (fs.existsSync(workspaceFile)) {
|
|
255
|
+
changes.push({ type: 'UPDATE', category: 'rules', file });
|
|
256
|
+
} else {
|
|
257
|
+
changes.push({ type: 'ADD', category: 'rules', file });
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (fs.existsSync(templateRules)) {
|
|
263
|
+
const templateFiles = fs.readdirSync(templateRules).filter(f => f.endsWith('.md'));
|
|
264
|
+
templateFiles.forEach(file => {
|
|
265
|
+
const workspaceFile = path.join(workspaceRules, file);
|
|
266
|
+
if (fs.existsSync(workspaceFile)) {
|
|
267
|
+
changes.push({ type: 'UPDATE', category: 'rules', file });
|
|
268
|
+
} else {
|
|
269
|
+
changes.push({ type: 'ADD', category: 'rules', file });
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// 중복 제거
|
|
275
|
+
const uniqueChanges = Array.from(
|
|
276
|
+
new Map(changes.map(c => [`${c.category}/${c.file}`, c])).values()
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
if (uniqueChanges.length === 0) {
|
|
280
|
+
console.log(chalk.gray('변경 사항이 없습니다.'));
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
console.log(chalk.white.bold('📋 변경될 파일:'));
|
|
285
|
+
console.log('');
|
|
286
|
+
|
|
287
|
+
const addedFiles = uniqueChanges.filter(c => c.type === 'ADD');
|
|
288
|
+
const updatedFiles = uniqueChanges.filter(c => c.type === 'UPDATE');
|
|
289
|
+
|
|
290
|
+
if (addedFiles.length > 0) {
|
|
291
|
+
console.log(chalk.green(' 추가될 파일:'));
|
|
292
|
+
addedFiles.forEach(c => {
|
|
293
|
+
console.log(chalk.gray(` + ${c.category}/${c.file}`));
|
|
294
|
+
});
|
|
295
|
+
console.log('');
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (updatedFiles.length > 0) {
|
|
299
|
+
console.log(chalk.yellow(' 업데이트될 파일:'));
|
|
300
|
+
updatedFiles.forEach(c => {
|
|
301
|
+
console.log(chalk.gray(` ↻ ${c.category}/${c.file}`));
|
|
302
|
+
});
|
|
303
|
+
console.log('');
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
console.log(chalk.gray(`총 ${uniqueChanges.length}개 파일이 변경됩니다.`));
|
|
307
|
+
console.log('');
|
|
308
|
+
console.log(chalk.cyan('실제 업그레이드를 실행하려면:'));
|
|
309
|
+
console.log(chalk.gray(' ada upgrade'));
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* 실제 업그레이드 수행
|
|
314
|
+
*/
|
|
315
|
+
async function performUpgrade(workspaceVersion, packageVersion, options) {
|
|
316
|
+
const packageRoot = getPackageRoot();
|
|
317
|
+
const workspace = getWorkspaceDir();
|
|
318
|
+
const template = getCurrentTemplate();
|
|
319
|
+
|
|
320
|
+
// 백업 생성
|
|
321
|
+
const backupId = `upgrade-${new Date().toISOString().slice(0, 19).replace(/[T:]/g, '-')}`;
|
|
322
|
+
const backupPath = path.join(getBackupDir(), backupId);
|
|
323
|
+
|
|
324
|
+
console.log(chalk.gray('📦 백업 생성 중...'));
|
|
325
|
+
fs.ensureDirSync(backupPath);
|
|
326
|
+
|
|
327
|
+
// roles, rules 백업
|
|
328
|
+
['roles', 'rules'].forEach(dir => {
|
|
329
|
+
const srcPath = path.join(workspace, dir);
|
|
330
|
+
const destPath = path.join(backupPath, dir);
|
|
331
|
+
if (fs.existsSync(srcPath)) {
|
|
332
|
+
fs.copySync(srcPath, destPath);
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// 버전 정보 백업
|
|
337
|
+
const versionFile = path.join(workspace, '.ada-version');
|
|
338
|
+
if (fs.existsSync(versionFile)) {
|
|
339
|
+
fs.copyFileSync(versionFile, path.join(backupPath, '.ada-version'));
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
console.log(chalk.green(`✅ 백업 완료: ${backupId}`));
|
|
343
|
+
console.log('');
|
|
344
|
+
|
|
345
|
+
// 업그레이드 실행
|
|
346
|
+
console.log(chalk.gray('🔄 업그레이드 중...'));
|
|
347
|
+
|
|
348
|
+
try {
|
|
349
|
+
// Core 파일 복사
|
|
350
|
+
const coreRoles = path.join(packageRoot, 'core', 'roles');
|
|
351
|
+
const coreRules = path.join(packageRoot, 'core', 'rules');
|
|
352
|
+
|
|
353
|
+
if (fs.existsSync(coreRoles)) {
|
|
354
|
+
copyDirMerge(coreRoles, path.join(workspace, 'roles'));
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (fs.existsSync(coreRules)) {
|
|
358
|
+
copyDirMerge(coreRules, path.join(workspace, 'rules'));
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Template 파일 복사
|
|
362
|
+
const templateRoles = path.join(packageRoot, 'templates', template, 'roles');
|
|
363
|
+
const templateRules = path.join(packageRoot, 'templates', template, 'rules');
|
|
364
|
+
const templateArtifacts = path.join(packageRoot, 'templates', template, 'artifacts');
|
|
365
|
+
|
|
366
|
+
if (fs.existsSync(templateRoles)) {
|
|
367
|
+
copyDirMerge(templateRoles, path.join(workspace, 'roles'));
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (fs.existsSync(templateRules)) {
|
|
371
|
+
copyDirMerge(templateRules, path.join(workspace, 'rules'));
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// 템플릿 아티팩트 (사용자 데이터 아닌 것만)
|
|
375
|
+
if (fs.existsSync(templateArtifacts)) {
|
|
376
|
+
const artifactFiles = fs.readdirSync(templateArtifacts).filter(f => f.endsWith('.md'));
|
|
377
|
+
artifactFiles.forEach(file => {
|
|
378
|
+
const srcFile = path.join(templateArtifacts, file);
|
|
379
|
+
const destFile = path.join(workspace, 'artifacts', file);
|
|
380
|
+
// 기존 사용자 데이터가 있으면 건너뜀
|
|
381
|
+
if (!fs.existsSync(destFile)) {
|
|
382
|
+
fs.copyFileSync(srcFile, destFile);
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// 버전 정보 업데이트
|
|
388
|
+
const newVersionInfo = {
|
|
389
|
+
packageVersion: packageVersion,
|
|
390
|
+
workspaceVersion: packageVersion,
|
|
391
|
+
template: template,
|
|
392
|
+
lastUpgrade: new Date().toISOString()
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
writeVersion(newVersionInfo);
|
|
396
|
+
|
|
397
|
+
console.log('');
|
|
398
|
+
console.log(chalk.green('✅ 업그레이드 완료!'));
|
|
399
|
+
console.log('');
|
|
400
|
+
console.log(chalk.gray(`${workspaceVersion} → ${packageVersion}`));
|
|
401
|
+
console.log('');
|
|
402
|
+
console.log(chalk.cyan('롤백이 필요한 경우:'));
|
|
403
|
+
console.log(chalk.gray(' ada upgrade --rollback'));
|
|
404
|
+
console.log('');
|
|
405
|
+
|
|
406
|
+
} catch (error) {
|
|
407
|
+
console.log('');
|
|
408
|
+
console.log(chalk.red('❌ 업그레이드 중 오류 발생!'));
|
|
409
|
+
console.log(chalk.red(error.message));
|
|
410
|
+
console.log('');
|
|
411
|
+
console.log(chalk.yellow('백업에서 복원하려면:'));
|
|
412
|
+
console.log(chalk.gray(' ada upgrade --rollback'));
|
|
413
|
+
console.log('');
|
|
414
|
+
process.exit(1);
|
|
415
|
+
}
|
|
416
|
+
}
|
package/src/commands/validate.js
CHANGED
|
@@ -229,11 +229,12 @@ export function validateSprint(artifactsDir) {
|
|
|
229
229
|
}
|
|
230
230
|
});
|
|
231
231
|
|
|
232
|
-
|
|
233
|
-
|
|
232
|
+
const hasTaskSection = content.includes('Task 요약') || content.includes('Task 목록');
|
|
233
|
+
if (hasTaskSection) {
|
|
234
|
+
logPass('Task 섹션 존재');
|
|
234
235
|
pass++;
|
|
235
236
|
} else {
|
|
236
|
-
logWarn('Task
|
|
237
|
+
logWarn('Task 섹션 미확인');
|
|
237
238
|
warn++;
|
|
238
239
|
}
|
|
239
240
|
|
package/src/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export { validate } from './commands/validate.js';
|
|
|
6
6
|
export { sessions } from './commands/sessions.js';
|
|
7
7
|
export { logs } from './commands/logs.js';
|
|
8
8
|
export { run } from './commands/run.js';
|
|
9
|
+
export { config } from './commands/config.js';
|
|
9
10
|
export { interactive } from './commands/interactive.js';
|
|
10
11
|
|
|
11
12
|
// Utils
|