@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
@@ -126,7 +126,7 @@ v[Major].[Minor]
126
126
 
127
127
  - 작업 시작 전 문서 확인 시
128
128
  - 작업 중 참조 문서 확인 시
129
- - 리뷰/QA 중 기준 확인 시
129
+ - 리뷰 중 기준 확인 시
130
130
 
131
131
  ### 7.2 충돌 보고 형식
132
132
 
@@ -196,3 +196,4 @@ Task 파일과 충돌?
196
196
  ├── Yes → Task 파일 따름
197
197
  └── No → 하위 문서 기준으로 판단
198
198
  ```
199
+
@@ -73,13 +73,13 @@ Developer: 수정된 설계로 재구현
73
73
  ```
74
74
  Reviewer REJECT
75
75
 
76
- Task 상태: IN_QA → IN_DEV
76
+ Task 상태: IN_REVIEW → IN_DEV
77
77
 
78
78
  review-report.md에 FAIL 사유 기록
79
79
 
80
80
  원인에 따라 담당자 결정
81
81
 
82
- 수정 후 재리뷰 → 재QA
82
+ 수정 후 재리뷰
83
83
  ```
84
84
 
85
85
  ---
@@ -143,7 +143,7 @@ Task 상태 복원 → 재진행
143
143
 
144
144
  Task 상태에 따른 처리:
145
145
  ├── DONE → 재검증 필요 여부 판단
146
- ├── IN_QA/IN_REVIEW → 재검증
146
+ ├── IN_REVIEW → 재검증
147
147
  ├── IN_DEV → 수정 반영
148
148
  └── IN_SPRINT/READY → 문서만 갱신
149
149
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@silbaram/artifact-driven-agent",
3
- "version": "0.1.6",
3
+ "version": "0.1.9",
4
4
  "description": "CLI 기반 멀티 AI 에이전트 개발 프레임워크 - AI가 규칙을 어기지 못하게 하는 문서 기반 개발",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,371 @@
1
+ import chalk from 'chalk';
2
+ import inquirer from 'inquirer';
3
+ import { readConfig, writeConfig, getConfigPath } from '../utils/config.js';
4
+
5
+ /**
6
+ * [CLI] 설정 관리 명령어
7
+ */
8
+ export async function config(action, key, value) {
9
+ const configPath = getConfigPath();
10
+ const currentConfig = readConfig();
11
+
12
+ // 1. 인자 없이 실행 → 대화형 모드
13
+ if (!action) {
14
+ await runInteractiveSet(currentConfig);
15
+ return;
16
+ }
17
+
18
+ // 2. 설정 조회 (List/Show)
19
+ if (action === 'list' || action === 'show') {
20
+ console.log(chalk.cyan('━'.repeat(60)));
21
+ console.log(chalk.cyan.bold('⚙️ ADA Configuration'));
22
+ console.log(chalk.gray(` Path: ${configPath}`));
23
+ console.log(chalk.cyan('━'.repeat(60)));
24
+ console.log('');
25
+ console.log(JSON.stringify(currentConfig, null, 2));
26
+ return;
27
+ }
28
+
29
+ // 2. 설정 값 확인 (Get)
30
+ if (action === 'get') {
31
+ if (!key) {
32
+ // 키 입력이 없으면 목록에서 선택하게 할 수도 있음 (여기선 생략)
33
+ console.error(chalk.red('❌ 조회할 설정 키를 입력하세요. (예: roles.manager)'));
34
+ process.exit(1);
35
+ }
36
+ const val = getValue(currentConfig, key);
37
+ console.log(val);
38
+ return;
39
+ }
40
+
41
+ // 3. 설정 변경 (Set)
42
+ if (action === 'set') {
43
+ // 인자가 부족하면 대화형 모드로 진입
44
+ if (!key || !value) {
45
+ await runInteractiveSet(currentConfig);
46
+ return;
47
+ }
48
+
49
+ // 인자가 있으면 바로 변경
50
+ updateConfig(currentConfig, key, value);
51
+ return;
52
+ }
53
+
54
+ console.error(chalk.red(`❌ 알 수 없는 명령입니다: ${action}`));
55
+ console.log(chalk.gray('사용 가능: list, get, set'));
56
+ }
57
+
58
+ /**
59
+ * 대화형 설정 변경 (개선된 버전)
60
+ */
61
+ async function runInteractiveSet(currentConfig) {
62
+ console.log(chalk.cyan('\n🛠️ 설정 변경 마법사'));
63
+ console.log(chalk.gray(' 역할별 AI 도구를 설정합니다.\n'));
64
+
65
+ const tools = ['claude', 'gemini', 'gpt', 'codex', 'copilot'];
66
+ const pendingChanges = {}; // 변경 예정 사항 추적
67
+
68
+ // 메인 루프
69
+ while (true) {
70
+ // 현재 설정 상태 표시
71
+ printCurrentSettings(currentConfig, pendingChanges);
72
+
73
+ // 메인 메뉴
74
+ const { action } = await inquirer.prompt([{
75
+ type: 'list',
76
+ name: 'action',
77
+ message: '무엇을 하시겠습니까?',
78
+ choices: [
79
+ { name: '📝 역할별 도구 설정', value: 'set_role' },
80
+ { name: '🔧 기본 도구 변경', value: 'set_default' },
81
+ { name: '📦 프리셋 적용', value: 'preset' },
82
+ new inquirer.Separator(),
83
+ { name: '💾 저장하고 종료', value: 'save' },
84
+ { name: '❌ 변경 취소', value: 'cancel' }
85
+ ]
86
+ }]);
87
+
88
+ if (action === 'set_role') {
89
+ await setRoleTool(currentConfig, pendingChanges, tools);
90
+ } else if (action === 'set_default') {
91
+ await setDefaultTool(currentConfig, pendingChanges, tools);
92
+ } else if (action === 'preset') {
93
+ await applyPreset(currentConfig, pendingChanges);
94
+ } else if (action === 'save') {
95
+ if (Object.keys(pendingChanges).length === 0) {
96
+ console.log(chalk.yellow('\n변경 사항이 없습니다.'));
97
+ } else {
98
+ // 변경 사항 적용
99
+ for (const [key, value] of Object.entries(pendingChanges)) {
100
+ setValue(currentConfig, key, value);
101
+ }
102
+ writeConfig(currentConfig);
103
+ console.log(chalk.green('\n✅ 설정이 저장되었습니다.'));
104
+ printChangeSummary(pendingChanges);
105
+ }
106
+ break;
107
+ } else if (action === 'cancel') {
108
+ if (Object.keys(pendingChanges).length > 0) {
109
+ const { confirmCancel } = await inquirer.prompt([{
110
+ type: 'confirm',
111
+ name: 'confirmCancel',
112
+ message: '변경 사항이 있습니다. 정말 취소하시겠습니까?',
113
+ default: false
114
+ }]);
115
+ if (!confirmCancel) continue;
116
+ }
117
+ console.log(chalk.gray('\n취소되었습니다.'));
118
+ break;
119
+ }
120
+ }
121
+ }
122
+
123
+ /**
124
+ * 현재 설정 상태 출력
125
+ */
126
+ function printCurrentSettings(config, pendingChanges) {
127
+ console.log(chalk.cyan('\n┌─────────────────────────────────────────┐'));
128
+ console.log(chalk.cyan('│') + chalk.bold(' 현재 설정 상태 ') + chalk.cyan('│'));
129
+ console.log(chalk.cyan('├─────────────────────────────────────────┤'));
130
+
131
+ // 기본 도구
132
+ const defaultTool = pendingChanges['defaults.tool'] || config.defaults?.tool || 'claude';
133
+ const defaultChanged = pendingChanges['defaults.tool'] ? chalk.yellow(' (변경됨)') : '';
134
+ console.log(chalk.cyan('│') + ` 기본 도구: ${chalk.bold(defaultTool)}${defaultChanged}`.padEnd(48) + chalk.cyan('│'));
135
+
136
+ console.log(chalk.cyan('├─────────────────────────────────────────┤'));
137
+
138
+ // 역할별 설정
139
+ const roles = Object.keys(config.roles || {});
140
+ roles.forEach(role => {
141
+ const currentValue = pendingChanges[`roles.${role}`] || config.roles[role];
142
+ const changed = pendingChanges[`roles.${role}`] ? chalk.yellow(' *') : '';
143
+ const line = ` ${role.padEnd(12)}: ${currentValue}${changed}`;
144
+ console.log(chalk.cyan('│') + line.padEnd(48) + chalk.cyan('│'));
145
+ });
146
+
147
+ console.log(chalk.cyan('└─────────────────────────────────────────┘'));
148
+
149
+ if (Object.keys(pendingChanges).length > 0) {
150
+ console.log(chalk.yellow(` (* 저장되지 않은 변경 ${Object.keys(pendingChanges).length}개)`));
151
+ }
152
+ console.log('');
153
+ }
154
+
155
+ /**
156
+ * 역할별 도구 설정
157
+ */
158
+ async function setRoleTool(config, pendingChanges, tools) {
159
+ const roles = Object.keys(config.roles || {});
160
+
161
+ const { selectedRole } = await inquirer.prompt([{
162
+ type: 'list',
163
+ name: 'selectedRole',
164
+ message: '설정할 역할을 선택하세요:',
165
+ choices: [
166
+ ...roles.map(role => {
167
+ const current = pendingChanges[`roles.${role}`] || config.roles[role];
168
+ return { name: `${role} (현재: ${current})`, value: role };
169
+ }),
170
+ new inquirer.Separator(),
171
+ { name: '↩️ 뒤로가기', value: '__back__' }
172
+ ]
173
+ }]);
174
+
175
+ if (selectedRole === '__back__') return;
176
+
177
+ const currentTool = pendingChanges[`roles.${selectedRole}`] || config.roles[selectedRole];
178
+
179
+ const { selectedTool } = await inquirer.prompt([{
180
+ type: 'list',
181
+ name: 'selectedTool',
182
+ message: `${selectedRole}에 사용할 도구를 선택하세요:`,
183
+ choices: [
184
+ ...tools.map(tool => ({
185
+ name: tool === currentTool ? `${tool} (현재)` : tool,
186
+ value: tool
187
+ })),
188
+ new inquirer.Separator(),
189
+ { name: '↩️ 뒤로가기', value: '__back__' }
190
+ ],
191
+ default: currentTool
192
+ }]);
193
+
194
+ if (selectedTool === '__back__') return;
195
+
196
+ if (selectedTool !== config.roles[selectedRole]) {
197
+ pendingChanges[`roles.${selectedRole}`] = selectedTool;
198
+ console.log(chalk.green(`\n ✓ ${selectedRole}: ${config.roles[selectedRole]} → ${selectedTool}`));
199
+ } else {
200
+ // 원래 값으로 돌아간 경우 pending에서 제거
201
+ delete pendingChanges[`roles.${selectedRole}`];
202
+ }
203
+ }
204
+
205
+ /**
206
+ * 기본 도구 설정
207
+ */
208
+ async function setDefaultTool(config, pendingChanges, tools) {
209
+ const currentDefault = pendingChanges['defaults.tool'] || config.defaults?.tool || 'claude';
210
+
211
+ const { selectedTool } = await inquirer.prompt([{
212
+ type: 'list',
213
+ name: 'selectedTool',
214
+ message: '기본 도구를 선택하세요:',
215
+ choices: [
216
+ ...tools.map(tool => ({
217
+ name: tool === currentDefault ? `${tool} (현재)` : tool,
218
+ value: tool
219
+ })),
220
+ new inquirer.Separator(),
221
+ { name: '↩️ 뒤로가기', value: '__back__' }
222
+ ],
223
+ default: currentDefault
224
+ }]);
225
+
226
+ if (selectedTool === '__back__') return;
227
+
228
+ const originalDefault = config.defaults?.tool || 'claude';
229
+ if (selectedTool !== originalDefault) {
230
+ pendingChanges['defaults.tool'] = selectedTool;
231
+ console.log(chalk.green(`\n ✓ 기본 도구: ${originalDefault} → ${selectedTool}`));
232
+ } else {
233
+ delete pendingChanges['defaults.tool'];
234
+ }
235
+ }
236
+
237
+ /**
238
+ * 프리셋 적용
239
+ */
240
+ async function applyPreset(config, pendingChanges) {
241
+ const presets = {
242
+ 'all_claude': {
243
+ name: '🔵 All Claude',
244
+ description: '모든 역할에 Claude 사용',
245
+ settings: { default: 'claude', roles: {} }
246
+ },
247
+ 'all_gemini': {
248
+ name: '🟢 All Gemini',
249
+ description: '모든 역할에 Gemini 사용',
250
+ settings: { default: 'gemini', roles: {} }
251
+ },
252
+ 'mixed_optimal': {
253
+ name: '🎨 Mixed Optimal',
254
+ description: 'Planner/Reviewer: Claude, Developer: Gemini',
255
+ settings: {
256
+ default: 'claude',
257
+ roles: {
258
+ planner: 'claude',
259
+ developer: 'gemini',
260
+ reviewer: 'claude',
261
+ documenter: 'claude',
262
+ manager: 'claude',
263
+ improver: 'claude',
264
+ analyzer: 'claude'
265
+ }
266
+ }
267
+ },
268
+ 'dev_gemini': {
269
+ name: '⚡ Dev Gemini + Review Claude',
270
+ description: '개발은 Gemini, 리뷰는 Claude',
271
+ settings: {
272
+ default: 'claude',
273
+ roles: {
274
+ developer: 'gemini'
275
+ }
276
+ }
277
+ }
278
+ };
279
+
280
+ const { selectedPreset } = await inquirer.prompt([{
281
+ type: 'list',
282
+ name: 'selectedPreset',
283
+ message: '적용할 프리셋을 선택하세요:',
284
+ choices: [
285
+ ...Object.entries(presets).map(([key, preset]) => ({
286
+ name: `${preset.name} - ${chalk.gray(preset.description)}`,
287
+ value: key
288
+ })),
289
+ new inquirer.Separator(),
290
+ { name: '↩️ 뒤로가기', value: '__back__' }
291
+ ]
292
+ }]);
293
+
294
+ if (selectedPreset === '__back__') return;
295
+
296
+ const preset = presets[selectedPreset];
297
+ const roles = Object.keys(config.roles || {});
298
+
299
+ // 기본 도구 설정
300
+ if (preset.settings.default) {
301
+ const originalDefault = config.defaults?.tool || 'claude';
302
+ if (preset.settings.default !== originalDefault) {
303
+ pendingChanges['defaults.tool'] = preset.settings.default;
304
+ }
305
+ }
306
+
307
+ // 역할별 설정
308
+ roles.forEach(role => {
309
+ let newValue;
310
+ if (preset.settings.roles && preset.settings.roles[role]) {
311
+ newValue = preset.settings.roles[role];
312
+ } else {
313
+ newValue = preset.settings.default || 'claude';
314
+ }
315
+
316
+ if (newValue !== config.roles[role]) {
317
+ pendingChanges[`roles.${role}`] = newValue;
318
+ } else {
319
+ delete pendingChanges[`roles.${role}`];
320
+ }
321
+ });
322
+
323
+ console.log(chalk.green(`\n ✓ 프리셋 '${preset.name}' 적용됨 (저장 필요)`));
324
+ }
325
+
326
+ /**
327
+ * 변경 사항 요약 출력
328
+ */
329
+ function printChangeSummary(changes) {
330
+ console.log(chalk.cyan('\n변경 내역:'));
331
+ for (const [key, value] of Object.entries(changes)) {
332
+ console.log(chalk.gray(` - ${key}: ${value}`));
333
+ }
334
+ }
335
+
336
+ /**
337
+ * 설정 업데이트 및 저장 공통 로직
338
+ */
339
+ function updateConfig(config, key, value) {
340
+ const validTools = ['claude', 'gemini', 'gpt', 'codex', 'copilot'];
341
+
342
+ // 유효성 검사
343
+ if (key.startsWith('roles.') || key === 'defaults.tool') {
344
+ if (!validTools.includes(value)) {
345
+ console.warn(chalk.yellow(`⚠️ 경고: '${value}'는 알려진 도구 목록(${validTools.join(', ')})에 없습니다.`));
346
+ }
347
+ }
348
+
349
+ setValue(config, key, value);
350
+ writeConfig(config);
351
+
352
+ console.log(chalk.green(`\n✅ 설정이 변경되었습니다: ${key} = ${value}`));
353
+ }
354
+
355
+ // ----------------------------------------------------------------------
356
+ // 헬퍼 함수: 점(.)으로 구분된 키로 객체 접근 (Lodash get/set 대용)
357
+ // ----------------------------------------------------------------------
358
+
359
+ function getValue(obj, path) {
360
+ return path.split('.').reduce((acc, part) => acc && acc[part], obj);
361
+ }
362
+
363
+ function setValue(obj, path, value) {
364
+ const parts = path.split('.');
365
+ const last = parts.pop();
366
+ const target = parts.reduce((acc, part) => {
367
+ if (!acc[part]) acc[part] = {};
368
+ return acc[part];
369
+ }, obj);
370
+ target[last] = value;
371
+ }