@silbaram/artifact-driven-agent 0.1.7 → 0.2.3

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 (189) hide show
  1. package/README.md +510 -60
  2. package/ai-dev-team/.ada-status.template.json +10 -10
  3. package/ai-dev-team/README.md +39 -44
  4. package/ai-dev-team/ada.config.json +15 -0
  5. package/ai-dev-team/artifacts/api.md +2 -0
  6. package/ai-dev-team/artifacts/features/_template/api.md +19 -19
  7. package/ai-dev-team/artifacts/features/_template/review.md +14 -14
  8. package/ai-dev-team/artifacts/features/_template/spec.md +28 -28
  9. package/ai-dev-team/artifacts/features/_template/ui.md +14 -14
  10. package/ai-dev-team/artifacts/improvement-reports/IMP-0000-template.md +57 -0
  11. package/ai-dev-team/artifacts/project.md +2 -0
  12. package/ai-dev-team/artifacts/rfc/RFC-0000-template.md +49 -49
  13. package/core/artifacts/decision.md +72 -72
  14. package/core/artifacts/plan.md +187 -187
  15. package/core/artifacts/project.md +193 -193
  16. package/core/artifacts/sprints/_template/docs/release-notes.md +37 -37
  17. package/core/artifacts/sprints/_template/meta.md +54 -54
  18. package/core/artifacts/sprints/_template/retrospective.md +50 -50
  19. package/core/artifacts/sprints/_template/review-reports/review-template.md +49 -49
  20. package/core/artifacts/sprints/_template/tasks/task-template.md +43 -43
  21. package/core/docs-templates/mkdocs/docs/architecture/overview.md +29 -0
  22. package/core/docs-templates/mkdocs/docs/changelog.md +36 -0
  23. package/core/docs-templates/mkdocs/docs/contributing/contributing.md +60 -0
  24. package/core/docs-templates/mkdocs/docs/getting-started/configuration.md +51 -0
  25. package/core/docs-templates/mkdocs/docs/getting-started/installation.md +41 -0
  26. package/core/docs-templates/mkdocs/docs/getting-started/quick-start.md +56 -0
  27. package/core/docs-templates/mkdocs/docs/guides/api-reference.md +83 -0
  28. package/core/docs-templates/mkdocs/docs/index.md +32 -0
  29. package/core/docs-templates/mkdocs/mkdocs.yml +86 -0
  30. package/core/roles/analyzer.md +265 -243
  31. package/core/roles/developer.md +227 -223
  32. package/core/roles/documenter.md +226 -293
  33. package/core/roles/improver.md +461 -0
  34. package/core/roles/manager.md +574 -541
  35. package/core/roles/planner.md +398 -248
  36. package/core/roles/reviewer.md +294 -266
  37. package/core/rules/document-priority.md +199 -198
  38. package/core/rules/escalation.md +172 -172
  39. package/core/rules/iteration.md +236 -236
  40. package/core/rules/rfc.md +31 -31
  41. package/core/rules/rollback.md +218 -218
  42. package/core/skills/_template/SKILL.md +50 -0
  43. package/core/skills/clean-code/SKILL.md +177 -0
  44. package/core/skills/code-review-checklist/SKILL.md +125 -0
  45. package/core/skills/error-handling/SKILL.md +155 -0
  46. package/core/skills/talk-game-dot-design/SKILL.md +85 -0
  47. package/core/skills/talk-game-dot-design/references/asset-specs.md +57 -0
  48. package/core/skills/talk-game-dot-design/references/review-checklist.md +34 -0
  49. package/core/skills/task-writing/SKILL.md +166 -0
  50. package/core/skills/testing-patterns/SKILL.md +140 -0
  51. package/dist/bin/cli.d.ts +2 -0
  52. package/dist/bin/cli.js +121 -0
  53. package/dist/bin/cli.js.map +1 -0
  54. package/dist/src/commands/config.d.ts +4 -0
  55. package/dist/src/commands/config.js +427 -0
  56. package/dist/src/commands/config.js.map +1 -0
  57. package/dist/src/commands/docs.d.ts +12 -0
  58. package/dist/src/commands/docs.js +453 -0
  59. package/dist/src/commands/docs.js.map +1 -0
  60. package/dist/src/commands/interactive.d.ts +4 -0
  61. package/dist/src/commands/interactive.js +380 -0
  62. package/dist/src/commands/interactive.js.map +1 -0
  63. package/dist/src/commands/logs.d.ts +1 -0
  64. package/dist/src/commands/logs.js +76 -0
  65. package/dist/src/commands/logs.js.map +1 -0
  66. package/dist/src/commands/monitor.d.ts +6 -0
  67. package/dist/src/commands/monitor.js +216 -0
  68. package/dist/src/commands/monitor.js.map +1 -0
  69. package/dist/src/commands/reset.d.ts +4 -0
  70. package/dist/src/commands/reset.js +57 -0
  71. package/dist/src/commands/reset.js.map +1 -0
  72. package/dist/src/commands/run.d.ts +45 -0
  73. package/dist/src/commands/run.js +421 -0
  74. package/dist/src/commands/run.js.map +1 -0
  75. package/dist/src/commands/sessions.d.ts +5 -0
  76. package/dist/src/commands/sessions.js +563 -0
  77. package/dist/src/commands/sessions.js.map +1 -0
  78. package/dist/src/commands/setup.d.ts +1 -0
  79. package/dist/src/commands/setup.js +132 -0
  80. package/dist/src/commands/setup.js.map +1 -0
  81. package/dist/src/commands/skills.d.ts +4 -0
  82. package/dist/src/commands/skills.js +748 -0
  83. package/dist/src/commands/skills.js.map +1 -0
  84. package/dist/src/commands/sprint.d.ts +4 -0
  85. package/dist/src/commands/sprint.js +434 -0
  86. package/dist/src/commands/sprint.js.map +1 -0
  87. package/dist/src/commands/status.d.ts +1 -0
  88. package/dist/src/commands/status.js +97 -0
  89. package/dist/src/commands/status.js.map +1 -0
  90. package/dist/src/commands/upgrade.d.ts +6 -0
  91. package/dist/src/commands/upgrade.js +350 -0
  92. package/dist/src/commands/upgrade.js.map +1 -0
  93. package/dist/src/commands/validate.d.ts +8 -0
  94. package/dist/src/commands/validate.js +260 -0
  95. package/dist/src/commands/validate.js.map +1 -0
  96. package/dist/src/commands/validate.test.d.ts +1 -0
  97. package/dist/src/commands/validate.test.js +74 -0
  98. package/dist/src/commands/validate.test.js.map +1 -0
  99. package/{src/index.js → dist/src/index.d.ts} +2 -3
  100. package/dist/src/index.js +15 -0
  101. package/dist/src/index.js.map +1 -0
  102. package/dist/src/types/common.d.ts +31 -0
  103. package/dist/src/types/common.js +2 -0
  104. package/dist/src/types/common.js.map +1 -0
  105. package/dist/src/types/config.d.ts +46 -0
  106. package/dist/src/types/config.js +2 -0
  107. package/dist/src/types/config.js.map +1 -0
  108. package/dist/src/types/index.d.ts +53 -0
  109. package/dist/src/types/index.js +2 -0
  110. package/dist/src/types/index.js.map +1 -0
  111. package/dist/src/types/session.d.ts +87 -0
  112. package/dist/src/types/session.js +2 -0
  113. package/dist/src/types/session.js.map +1 -0
  114. package/dist/src/types/task.d.ts +32 -0
  115. package/dist/src/types/task.js +2 -0
  116. package/dist/src/types/task.js.map +1 -0
  117. package/dist/src/ui/dashboard.d.ts +9 -0
  118. package/dist/src/ui/dashboard.js +468 -0
  119. package/dist/src/ui/dashboard.js.map +1 -0
  120. package/dist/src/ui/keyHandler.d.ts +47 -0
  121. package/dist/src/ui/keyHandler.js +132 -0
  122. package/dist/src/ui/keyHandler.js.map +1 -0
  123. package/dist/src/ui/quickActions.d.ts +25 -0
  124. package/dist/src/ui/quickActions.js +106 -0
  125. package/dist/src/ui/quickActions.js.map +1 -0
  126. package/dist/src/utils/config.d.ts +33 -0
  127. package/dist/src/utils/config.js +135 -0
  128. package/dist/src/utils/config.js.map +1 -0
  129. package/dist/src/utils/files.d.ts +84 -0
  130. package/dist/src/utils/files.js +202 -0
  131. package/dist/src/utils/files.js.map +1 -0
  132. package/dist/src/utils/promptBuilder.d.ts +39 -0
  133. package/dist/src/utils/promptBuilder.js +726 -0
  134. package/dist/src/utils/promptBuilder.js.map +1 -0
  135. package/dist/src/utils/sessionState.d.ts +83 -0
  136. package/dist/src/utils/sessionState.js +466 -0
  137. package/dist/src/utils/sessionState.js.map +1 -0
  138. package/dist/src/utils/sessionState.process.test.d.ts +1 -0
  139. package/dist/src/utils/sessionState.process.test.js +93 -0
  140. package/dist/src/utils/sessionState.process.test.js.map +1 -0
  141. package/dist/src/utils/sessionState.test.d.ts +1 -0
  142. package/dist/src/utils/sessionState.test.js +150 -0
  143. package/dist/src/utils/sessionState.test.js.map +1 -0
  144. package/dist/src/utils/sprintUtils.d.ts +13 -0
  145. package/dist/src/utils/sprintUtils.js +129 -0
  146. package/dist/src/utils/sprintUtils.js.map +1 -0
  147. package/dist/src/utils/taskParser.d.ts +9 -0
  148. package/dist/src/utils/taskParser.js +122 -0
  149. package/dist/src/utils/taskParser.js.map +1 -0
  150. package/dist/src/utils/taskParser.test.d.ts +1 -0
  151. package/dist/src/utils/taskParser.test.js +69 -0
  152. package/dist/src/utils/taskParser.test.js.map +1 -0
  153. package/package.json +62 -47
  154. package/templates/cli/artifacts/commands.md +262 -262
  155. package/templates/cli/artifacts/output-format.md +298 -298
  156. package/templates/cli/rules/command-change.md +225 -225
  157. package/templates/game/artifacts/assets.md +148 -148
  158. package/templates/game/artifacts/game-systems.md +217 -217
  159. package/templates/game/artifacts/hud.md +199 -199
  160. package/templates/game/rules/system-change.md +184 -184
  161. package/templates/library/artifacts/changelog.md +84 -84
  162. package/templates/library/artifacts/examples.md +157 -157
  163. package/templates/library/artifacts/public-api.md +197 -197
  164. package/templates/library/rules/versioning.md +186 -186
  165. package/templates/web-dev/artifacts/api.md +212 -212
  166. package/templates/web-dev/artifacts/ui.md +104 -104
  167. package/templates/web-dev/rules/api-change.md +198 -198
  168. package/ai-dev-team/.gitkeep +0 -0
  169. package/ai-dev-team/artifacts/.gitkeep +0 -0
  170. package/ai-dev-team/artifacts/features/_template/qa.md +0 -16
  171. package/ai-dev-team/roles/.gitkeep +0 -0
  172. package/ai-dev-team/rules/.gitkeep +0 -0
  173. package/bin/cli.js +0 -83
  174. package/examples/todo-app/README.md +0 -23
  175. package/examples/todo-app/artifacts/backlog.md +0 -23
  176. package/examples/todo-app/artifacts/plan.md +0 -23
  177. package/examples/todo-app/artifacts/project.md +0 -23
  178. package/src/commands/interactive.js +0 -101
  179. package/src/commands/logs.js +0 -81
  180. package/src/commands/reset.js +0 -66
  181. package/src/commands/run.js +0 -554
  182. package/src/commands/sessions.js +0 -707
  183. package/src/commands/setup.js +0 -128
  184. package/src/commands/sprint.js +0 -262
  185. package/src/commands/status.js +0 -76
  186. package/src/commands/validate.js +0 -288
  187. package/src/commands/validate.test.js +0 -84
  188. package/src/utils/files.js +0 -134
  189. package/src/utils/sessionState.js +0 -379
@@ -0,0 +1,726 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { parseTaskMetadata, normalizeTaskStatus } from './taskParser.js';
4
+ // ============================================================================
5
+ // 역할별 콘텐츠 설정 (제약 조건 유지가 핵심!)
6
+ // ============================================================================
7
+ /**
8
+ * 역할별 문서 포함 레벨 설정
9
+ *
10
+ * 제약 조건 원칙:
11
+ * 1. Developer는 project.md 전체 필요 (기술 제약)
12
+ * 2. Reviewer는 코드 리뷰를 위해 Task와 Interface 필요 (개발은 못함)
13
+ * 3. Planner는 plan.md 전체 필요 (요구사항 관리)
14
+ * 4. 모든 역할은 decision.md 전체 필요 (최우선 결정)
15
+ * 5. 현재 스프린트 meta.md는 항상 포함 (범위 제한)
16
+ */
17
+ const ROLE_CONTENT_CONFIG = {
18
+ developer: {
19
+ plan: 'summary', // 현재 스프린트 관련 요약 (전체는 너무 김)
20
+ project: 'full', // 기술 기준 전체 필수 (제약!)
21
+ decision: 'full', // 최우선 결정 필수
22
+ tasks: {
23
+ inDev: 'full', // 작업 중인 Task 전체 (현재 작업)
24
+ backlog: 'summary', // 제목 + 수용조건 (다음 작업 파악)
25
+ done: 'list', // 제목만 (완료된 건 상세 불필요)
26
+ reject: 'list', // 제목만
27
+ inReview: 'list', // 리뷰 중인 건 제목만
28
+ },
29
+ interface: 'full', // API/UI 문서 전체 (구현 기준)
30
+ rules: 'full', // 규칙 전체 (제약!)
31
+ skills: 'full', // 스킬 전체 (코딩 패턴)
32
+ },
33
+ reviewer: {
34
+ plan: 'summary', // 요구사항 요약 (리뷰 기준)
35
+ project: 'summary', // 코딩 규칙 섹션만 (리뷰 기준)
36
+ decision: 'full', // 최우선 결정 필수
37
+ tasks: {
38
+ inDev: 'full', // 리뷰 대상 Task 전체
39
+ backlog: 'none', // 백로그는 리뷰 대상 아님
40
+ done: 'summary', // 최근 완료된 것 요약 (참고용)
41
+ reject: 'full', // 반려 사유 확인 필요
42
+ inReview: 'full', // 리뷰 중인 Task 전체
43
+ },
44
+ interface: 'full', // API 계약 확인 필요
45
+ rules: 'full', // 규칙 전체 (리뷰 기준!)
46
+ skills: 'summary', // 스킬 요약 (패턴 확인)
47
+ },
48
+ planner: {
49
+ plan: 'full', // 전체 요구사항 필수 (기획!)
50
+ project: 'summary', // 기술 스택 요약
51
+ decision: 'full', // 최우선 결정 필수
52
+ tasks: {
53
+ inDev: 'list', // 진행 상황 파악
54
+ backlog: 'full', // 백로그 관리 (기획!)
55
+ done: 'list', // 완료 현황 파악
56
+ reject: 'summary', // 반려 사유 파악
57
+ inReview: 'list', // 리뷰 현황 파악
58
+ },
59
+ interface: 'list', // 인터페이스 목록만
60
+ rules: 'full', // 규칙 전체
61
+ skills: 'summary', // 스킬 안내 (Task 작성 패턴)
62
+ },
63
+ improver: {
64
+ plan: 'full', // 개선 대상 파악
65
+ project: 'summary', // 기술 스택 요약
66
+ decision: 'full', // 최우선 결정 필수
67
+ tasks: {
68
+ inDev: 'summary', // 진행 중인 작업 파악
69
+ backlog: 'summary', // 개선 대상 파악
70
+ done: 'summary', // 완료된 기능 분석
71
+ reject: 'full', // 반려 사유 분석 (개선 포인트)
72
+ inReview: 'list',
73
+ },
74
+ interface: 'summary', // 인터페이스 요약
75
+ rules: 'full',
76
+ skills: 'summary', // 스킬 안내 (개선 Task 작성 패턴)
77
+ },
78
+ documenter: {
79
+ plan: 'summary', // 문서화할 기능 파악
80
+ project: 'summary', // 기술 스택 요약
81
+ decision: 'full', // 최우선 결정 필수
82
+ tasks: {
83
+ inDev: 'list', // 진행 상황 파악
84
+ backlog: 'none', // 백로그 불필요
85
+ done: 'summary', // 문서화 대상 (완료된 기능)
86
+ reject: 'none',
87
+ inReview: 'list',
88
+ },
89
+ interface: 'full', // API 문서화 필요
90
+ rules: 'summary', // 규칙 요약
91
+ skills: 'none',
92
+ },
93
+ analyzer: {
94
+ plan: 'summary', // 분석 범위 파악
95
+ project: 'full', // 기술 스택 전체 분석
96
+ decision: 'full', // 최우선 결정 필수
97
+ tasks: {
98
+ inDev: 'list',
99
+ backlog: 'list',
100
+ done: 'list',
101
+ reject: 'list',
102
+ inReview: 'list',
103
+ },
104
+ interface: 'full', // 인터페이스 분석
105
+ rules: 'full',
106
+ skills: 'none',
107
+ },
108
+ manager: {
109
+ plan: 'summary', // 프로젝트 현황 파악
110
+ project: 'summary', // 기술 스택 요약
111
+ decision: 'full', // 최우선 결정 필수
112
+ tasks: {
113
+ inDev: 'summary', // 진행 현황
114
+ backlog: 'summary', // 대기 현황
115
+ done: 'summary', // 완료 현황
116
+ reject: 'summary', // 이슈 파악
117
+ inReview: 'summary', // 리뷰 현황
118
+ },
119
+ interface: 'list',
120
+ rules: 'full',
121
+ skills: 'none',
122
+ },
123
+ };
124
+ /**
125
+ * 기본 콘텐츠 설정 (정의되지 않은 역할용)
126
+ */
127
+ const DEFAULT_CONTENT_CONFIG = {
128
+ plan: 'summary',
129
+ project: 'summary',
130
+ decision: 'full',
131
+ tasks: {
132
+ inDev: 'summary',
133
+ backlog: 'summary',
134
+ done: 'list',
135
+ reject: 'list',
136
+ inReview: 'summary',
137
+ },
138
+ interface: 'summary',
139
+ rules: 'full',
140
+ skills: 'summary',
141
+ };
142
+ // ============================================================================
143
+ // 역할별 규칙 (기존 유지 - 제약 조건!)
144
+ // ============================================================================
145
+ const ROLE_RULES = {
146
+ planner: ['iteration.md', 'escalation.md', 'document-priority.md'],
147
+ improver: ['iteration.md', 'escalation.md', 'document-priority.md', 'rfc.md'],
148
+ developer: ['iteration.md', 'escalation.md', 'rollback.md', 'document-priority.md', 'rfc.md'],
149
+ reviewer: ['iteration.md', 'rollback.md', 'escalation.md', 'document-priority.md'],
150
+ documenter: ['escalation.md', 'document-priority.md'],
151
+ analyzer: ['escalation.md', 'document-priority.md'],
152
+ manager: ['escalation.md', 'document-priority.md', 'rfc.md'],
153
+ };
154
+ // ============================================================================
155
+ // 메인 함수
156
+ // ============================================================================
157
+ /**
158
+ * 최적화된 시스템 프롬프트 생성
159
+ */
160
+ export function buildOptimizedSystemPrompt(workspace, role, roleContent) {
161
+ const artifactsDir = path.join(workspace, 'artifacts');
162
+ const rulesDir = path.join(workspace, 'rules');
163
+ const skillsDir = path.join(workspace, 'skills');
164
+ const config = ROLE_CONTENT_CONFIG[role] || DEFAULT_CONTENT_CONFIG;
165
+ const sections = [];
166
+ // ========================================
167
+ // 1. Role 정의 (항상 전체 - 제약 필수!)
168
+ // ========================================
169
+ sections.push(`# Role: ${role}\n\n${roleContent}`);
170
+ // ========================================
171
+ // 2. Rules (역할별 필수 규칙)
172
+ // ========================================
173
+ const rulesSection = buildRulesSection(rulesDir, role, config.rules);
174
+ if (rulesSection)
175
+ sections.push(rulesSection);
176
+ // ========================================
177
+ // 3. Skills (역할에 지정된 스킬)
178
+ // ========================================
179
+ const skillsSection = buildSkillsSection(skillsDir, role, config.skills);
180
+ if (skillsSection)
181
+ sections.push(skillsSection);
182
+ // ========================================
183
+ // 4. 핵심 산출물 (decision, project, plan)
184
+ // ========================================
185
+ const coreArtifactsSection = buildCoreArtifactsSection(artifactsDir, config);
186
+ if (coreArtifactsSection)
187
+ sections.push(coreArtifactsSection);
188
+ // ========================================
189
+ // 5. 현재 스프린트 정보 (항상 meta.md 포함!)
190
+ // ========================================
191
+ const sprintSection = buildSprintSection(artifactsDir, role, config.tasks);
192
+ if (sprintSection)
193
+ sections.push(sprintSection);
194
+ // ========================================
195
+ // 6. 인터페이스 문서
196
+ // ========================================
197
+ const interfaceSection = buildInterfaceSection(artifactsDir, config.interface);
198
+ if (interfaceSection)
199
+ sections.push(interfaceSection);
200
+ // ========================================
201
+ // 7. 기타 산출물 (항상 목록만)
202
+ // ========================================
203
+ const otherArtifactsSection = buildOtherArtifactsSection(artifactsDir);
204
+ if (otherArtifactsSection)
205
+ sections.push(otherArtifactsSection);
206
+ // ========================================
207
+ // 8. 작업 지침 (역할별 차별화)
208
+ // ========================================
209
+ const instructionsSection = buildInstructionsSection(role);
210
+ sections.push(instructionsSection);
211
+ return sections.join('\n\n---\n\n');
212
+ }
213
+ // ============================================================================
214
+ // 섹션 빌더 함수들
215
+ // ============================================================================
216
+ /**
217
+ * Rules 섹션 생성
218
+ */
219
+ function buildRulesSection(rulesDir, role, level) {
220
+ const requiredRules = ROLE_RULES[role] || [];
221
+ if (requiredRules.length === 0)
222
+ return null;
223
+ let section = '# 규칙 (Rules)\n\n';
224
+ section += `**이 역할의 필수 규칙:** ${requiredRules.join(', ')}\n\n`;
225
+ if (!fs.existsSync(rulesDir)) {
226
+ section += '(rules 디렉토리 없음)\n';
227
+ return section;
228
+ }
229
+ for (const ruleFile of requiredRules) {
230
+ const rulePath = path.join(rulesDir, ruleFile);
231
+ if (!fs.existsSync(rulePath)) {
232
+ section += `## ${ruleFile} (파일 없음)\n\n`;
233
+ continue;
234
+ }
235
+ try {
236
+ const content = fs.readFileSync(rulePath, 'utf-8');
237
+ section += `## ${ruleFile}\n\n`;
238
+ if (level === 'full') {
239
+ section += content + '\n';
240
+ }
241
+ else {
242
+ // summary: 첫 번째 섹션만 또는 요약
243
+ section += extractDocumentSummary(content, 30) + '\n';
244
+ }
245
+ }
246
+ catch {
247
+ section += `## ${ruleFile} (읽기 실패)\n\n`;
248
+ }
249
+ }
250
+ return section;
251
+ }
252
+ /**
253
+ * Skills 섹션 생성 (네이티브 방식 안내)
254
+ *
255
+ * 스킬은 각 AI 도구의 네이티브 경로에서 자동 로드됩니다:
256
+ * - Claude Code: .claude/skills/
257
+ * - Gemini CLI: .gemini/skills/
258
+ * - Codex: .agents/skills/
259
+ *
260
+ * `ada skills apply <name>` 명령으로 스킬을 네이티브 경로에 배포하세요.
261
+ */
262
+ function buildSkillsSection(_skillsDir, _role, level) {
263
+ if (level === 'none')
264
+ return null;
265
+ // 네이티브 방식에서는 스킬 내용을 시스템 프롬프트에 포함하지 않음
266
+ // AI 도구가 자체 스킬 탐색 경로에서 자동으로 로드함
267
+ let section = '# 전문 스킬 (Specialized Skills)\n\n';
268
+ section += '스킬은 AI 도구의 네이티브 스킬 시스템으로 로드됩니다.\n\n';
269
+ section += '**스킬 탐색 경로:**\n';
270
+ section += '- Claude Code: `.claude/skills/`\n';
271
+ section += '- Gemini CLI: `.gemini/skills/`\n';
272
+ section += '- Codex: `.agents/skills/`\n\n';
273
+ section += '**중요:** 적용된 스킬의 패턴과 규칙을 정확히 따르세요.\n';
274
+ return section;
275
+ }
276
+ /**
277
+ * 핵심 산출물 섹션 생성 (decision, project, plan)
278
+ */
279
+ function buildCoreArtifactsSection(artifactsDir, config) {
280
+ let section = '# 핵심 산출물 (Core Artifacts)\n\n';
281
+ // decision.md (항상 전체 - 최우선 문서)
282
+ section += buildArtifactContent(path.join(artifactsDir, 'decision.md'), 'decision.md', config.decision);
283
+ // project.md (역할별 차등)
284
+ section += buildArtifactContent(path.join(artifactsDir, 'project.md'), 'project.md', config.project, ['## 기술 스택', '## 코딩 규칙', '## 프로젝트 구조'] // summary용 섹션
285
+ );
286
+ // plan.md (역할별 차등)
287
+ section += buildArtifactContent(path.join(artifactsDir, 'plan.md'), 'plan.md', config.plan, ['## 핵심 요구사항', '## 현재 목표', '## 우선순위'] // summary용 섹션
288
+ );
289
+ return section;
290
+ }
291
+ /**
292
+ * 개별 산출물 콘텐츠 생성
293
+ */
294
+ function buildArtifactContent(filePath, fileName, level, summarySections) {
295
+ if (level === 'none')
296
+ return '';
297
+ if (!fs.existsSync(filePath)) {
298
+ return `## ${fileName} (아직 작성되지 않음)\n\n`;
299
+ }
300
+ try {
301
+ const content = fs.readFileSync(filePath, 'utf-8');
302
+ let result = `## ${fileName}\n\n`;
303
+ if (level === 'full') {
304
+ result += content + '\n';
305
+ }
306
+ else if (level === 'summary') {
307
+ if (summarySections && summarySections.length > 0) {
308
+ result += extractSections(content, summarySections) + '\n';
309
+ }
310
+ else {
311
+ result += extractDocumentSummary(content, 50) + '\n';
312
+ }
313
+ }
314
+ else if (level === 'list') {
315
+ // 제목만 추출
316
+ const titleMatch = content.match(/^#\s+(.+)$/m);
317
+ const title = titleMatch ? titleMatch[1] : fileName;
318
+ result += `- ${title}\n`;
319
+ result += ` (전체 내용은 파일을 읽어서 확인: artifacts/${fileName})\n\n`;
320
+ }
321
+ return result;
322
+ }
323
+ catch {
324
+ return `## ${fileName} (읽기 실패)\n\n`;
325
+ }
326
+ }
327
+ /**
328
+ * 스프린트 섹션 생성 (핵심 최적화!)
329
+ */
330
+ function buildSprintSection(artifactsDir, role, taskConfig) {
331
+ let section = '# 현재 스프린트 정보\n\n';
332
+ const sprintsDir = path.join(artifactsDir, 'sprints');
333
+ if (!fs.existsSync(sprintsDir)) {
334
+ section += '## ⚠️ sprints 디렉토리 없음\n\n';
335
+ section += '`ada sprint create` 명령으로 스프린트를 생성하세요.\n';
336
+ return section;
337
+ }
338
+ // 가장 최근 스프린트 찾기
339
+ const sprints = fs.readdirSync(sprintsDir, { withFileTypes: true })
340
+ .filter(d => d.isDirectory() && /^sprint-\d+$/.test(d.name))
341
+ .map(d => d.name)
342
+ .sort((a, b) => parseInt(b.split('-')[1]) - parseInt(a.split('-')[1]));
343
+ const activeSprint = sprints[0];
344
+ if (!activeSprint) {
345
+ section += '## ⚠️ 현재 활성 스프린트 없음\n\n';
346
+ section += '`ada sprint create` 명령으로 스프린트를 생성하세요.\n';
347
+ return section;
348
+ }
349
+ // meta.md는 항상 전체 포함 (범위 제한 필수!)
350
+ const metaPath = path.join(sprintsDir, activeSprint, 'meta.md');
351
+ if (fs.existsSync(metaPath)) {
352
+ try {
353
+ const metaContent = fs.readFileSync(metaPath, 'utf-8');
354
+ section += `## 현재 스프린트: ${activeSprint}/meta.md\n\n`;
355
+ section += metaContent + '\n\n';
356
+ }
357
+ catch {
358
+ section += `## ${activeSprint}/meta.md (읽기 실패)\n\n`;
359
+ }
360
+ }
361
+ // Task 파일들 (상태별 차등 포함!)
362
+ const tasksDir = path.join(sprintsDir, activeSprint, 'tasks');
363
+ if (fs.existsSync(tasksDir)) {
364
+ const taskFiles = fs.readdirSync(tasksDir)
365
+ .filter(f => f.endsWith('.md') && !f.includes('template'));
366
+ if (taskFiles.length > 0) {
367
+ section += buildTasksContent(tasksDir, taskFiles, taskConfig);
368
+ }
369
+ else {
370
+ section += '## ⚠️ 스프린트에 Task 없음\n\n';
371
+ section += '`ada sprint add task-001` 명령으로 Task를 추가하세요.\n';
372
+ }
373
+ }
374
+ // Backlog 목록 (항상 목록만 - Planner만 상세 필요)
375
+ const backlogDir = path.join(artifactsDir, 'backlog');
376
+ if (fs.existsSync(backlogDir)) {
377
+ const backlogFiles = fs.readdirSync(backlogDir)
378
+ .filter(f => f.endsWith('.md') && f.startsWith('task-'));
379
+ if (backlogFiles.length > 0) {
380
+ section += '\n## Backlog Task 목록\n\n';
381
+ if (taskConfig.backlog === 'full') {
382
+ // Planner용: 백로그 전체 내용
383
+ for (const f of backlogFiles) {
384
+ const taskPath = path.join(backlogDir, f);
385
+ try {
386
+ const content = fs.readFileSync(taskPath, 'utf-8');
387
+ section += `### ${f}\n\n${content}\n\n`;
388
+ }
389
+ catch {
390
+ section += `### ${f} (읽기 실패)\n\n`;
391
+ }
392
+ }
393
+ }
394
+ else {
395
+ // 목록만
396
+ section += '필요시 파일을 읽어서 확인하세요:\n';
397
+ for (const f of backlogFiles) {
398
+ section += `- backlog/${f}\n`;
399
+ }
400
+ section += '\n';
401
+ }
402
+ }
403
+ }
404
+ return section;
405
+ }
406
+ /**
407
+ * Task 콘텐츠 생성 (상태별 차등!)
408
+ */
409
+ function buildTasksContent(tasksDir, taskFiles, config) {
410
+ // 상태별로 Task 분류
411
+ const tasksByStatus = {
412
+ IN_DEV: [],
413
+ IN_REVIEW: [],
414
+ BACKLOG: [],
415
+ DONE: [],
416
+ REJECT: [],
417
+ OTHER: [],
418
+ };
419
+ for (const file of taskFiles) {
420
+ const filePath = path.join(tasksDir, file);
421
+ try {
422
+ const content = fs.readFileSync(filePath, 'utf-8');
423
+ const metadata = parseTaskMetadata(content, file);
424
+ const status = normalizeTaskStatus(metadata.status);
425
+ const category = tasksByStatus[status] ? status : 'OTHER';
426
+ tasksByStatus[category].push({ file, content, metadata });
427
+ }
428
+ catch {
429
+ tasksByStatus['OTHER'].push({
430
+ file,
431
+ content: '',
432
+ metadata: { id: file, title: file, status: 'UNKNOWN', priority: 'P2', size: 'M', assignee: '-', hasReviewReport: false }
433
+ });
434
+ }
435
+ }
436
+ let section = '## 현재 스프린트 Task\n\n';
437
+ // 상태별 콘텐츠 생성
438
+ section += buildTaskStatusSection('작업 중 (IN_DEV)', tasksByStatus['IN_DEV'], config.inDev);
439
+ section += buildTaskStatusSection('리뷰 중 (IN_REVIEW)', tasksByStatus['IN_REVIEW'], config.inReview);
440
+ section += buildTaskStatusSection('대기 (BACKLOG)', tasksByStatus['BACKLOG'], config.backlog);
441
+ section += buildTaskStatusSection('완료 (DONE)', tasksByStatus['DONE'], config.done);
442
+ section += buildTaskStatusSection('반려 (REJECT)', tasksByStatus['REJECT'], config.reject);
443
+ if (tasksByStatus['OTHER'].length > 0) {
444
+ section += buildTaskStatusSection('기타', tasksByStatus['OTHER'], 'list');
445
+ }
446
+ return section;
447
+ }
448
+ /**
449
+ * 상태별 Task 섹션 생성
450
+ */
451
+ function buildTaskStatusSection(title, tasks, level) {
452
+ if (tasks.length === 0 || level === 'none')
453
+ return '';
454
+ let section = `### ${title} (${tasks.length}개)\n\n`;
455
+ for (const task of tasks) {
456
+ if (level === 'full') {
457
+ section += `#### ${task.file}\n\n`;
458
+ section += task.content + '\n\n';
459
+ }
460
+ else if (level === 'summary') {
461
+ section += `#### ${task.file}: ${task.metadata.title}\n\n`;
462
+ // 수용 조건 섹션만 추출
463
+ const acceptanceCriteria = extractSection(task.content, '## 수용 조건') ||
464
+ extractSection(task.content, '## Acceptance Criteria') ||
465
+ extractSection(task.content, '## 작업 내용');
466
+ if (acceptanceCriteria) {
467
+ section += acceptanceCriteria + '\n\n';
468
+ }
469
+ else {
470
+ section += extractDocumentSummary(task.content, 20) + '\n\n';
471
+ }
472
+ }
473
+ else if (level === 'list') {
474
+ section += `- **${task.file}**: ${task.metadata.title} [${task.metadata.status}]\n`;
475
+ }
476
+ }
477
+ if (level === 'list')
478
+ section += '\n';
479
+ return section;
480
+ }
481
+ /**
482
+ * 인터페이스 문서 섹션 생성
483
+ */
484
+ function buildInterfaceSection(artifactsDir, level) {
485
+ if (level === 'none')
486
+ return null;
487
+ const interfaceFiles = [
488
+ 'api.md', 'ui.md', 'public-api.md', 'commands.md',
489
+ 'output-format.md', 'game-systems.md', 'assets.md',
490
+ 'hud.md', 'examples.md', 'changelog.md'
491
+ ];
492
+ const existingFiles = [];
493
+ for (const file of interfaceFiles) {
494
+ if (fs.existsSync(path.join(artifactsDir, file))) {
495
+ existingFiles.push(file);
496
+ }
497
+ }
498
+ if (existingFiles.length === 0)
499
+ return null;
500
+ let section = '# 인터페이스 산출물 (Interface Artifacts)\n\n';
501
+ if (level === 'list') {
502
+ section += '다음 인터페이스 문서를 필요시 읽어서 확인하세요:\n';
503
+ for (const file of existingFiles) {
504
+ section += `- artifacts/${file}\n`;
505
+ }
506
+ return section;
507
+ }
508
+ for (const file of existingFiles) {
509
+ const filePath = path.join(artifactsDir, file);
510
+ try {
511
+ const content = fs.readFileSync(filePath, 'utf-8');
512
+ section += `## ${file}\n\n`;
513
+ if (level === 'full') {
514
+ section += content + '\n';
515
+ }
516
+ else {
517
+ section += extractDocumentSummary(content, 40) + '\n';
518
+ }
519
+ }
520
+ catch {
521
+ section += `## ${file} (읽기 실패)\n\n`;
522
+ }
523
+ }
524
+ return section;
525
+ }
526
+ /**
527
+ * 기타 산출물 섹션 (항상 목록만)
528
+ */
529
+ function buildOtherArtifactsSection(artifactsDir) {
530
+ if (!fs.existsSync(artifactsDir))
531
+ return null;
532
+ const coreFiles = ['decision.md', 'project.md', 'plan.md'];
533
+ const interfaceFiles = [
534
+ 'api.md', 'ui.md', 'public-api.md', 'commands.md',
535
+ 'output-format.md', 'game-systems.md', 'assets.md',
536
+ 'hud.md', 'examples.md', 'changelog.md'
537
+ ];
538
+ const excludeFiles = [...coreFiles, ...interfaceFiles];
539
+ const allFiles = fs.readdirSync(artifactsDir, { withFileTypes: true });
540
+ const otherFiles = allFiles
541
+ .filter(d => d.isFile() && d.name.endsWith('.md') && !excludeFiles.includes(d.name))
542
+ .map(d => d.name);
543
+ if (otherFiles.length === 0)
544
+ return null;
545
+ let section = '# 기타 산출물 (목록)\n\n';
546
+ section += '필요시 파일을 읽어서 확인하세요:\n';
547
+ for (const file of otherFiles) {
548
+ section += `- artifacts/${file}\n`;
549
+ }
550
+ // Features 디렉토리
551
+ const featuresDir = path.join(artifactsDir, 'features');
552
+ if (fs.existsSync(featuresDir)) {
553
+ const features = fs.readdirSync(featuresDir, { withFileTypes: true })
554
+ .filter(d => d.isDirectory() && !d.name.startsWith('_'))
555
+ .map(d => d.name);
556
+ if (features.length > 0) {
557
+ section += '\n**Features:**\n';
558
+ for (const f of features) {
559
+ section += `- features/${f}/\n`;
560
+ }
561
+ }
562
+ }
563
+ // RFC 디렉토리
564
+ const rfcDir = path.join(artifactsDir, 'rfc');
565
+ if (fs.existsSync(rfcDir)) {
566
+ const rfcs = fs.readdirSync(rfcDir).filter(f => f.endsWith('.md') && !f.includes('template'));
567
+ if (rfcs.length > 0) {
568
+ section += '\n**RFC:**\n';
569
+ for (const rfc of rfcs) {
570
+ section += `- rfc/${rfc}\n`;
571
+ }
572
+ }
573
+ }
574
+ return section;
575
+ }
576
+ /**
577
+ * 작업 지침 섹션 (역할별 차별화)
578
+ */
579
+ function buildInstructionsSection(role) {
580
+ let section = '# 작업 지침\n\n';
581
+ // 공통 지침
582
+ section += '## 필수 준수 사항\n\n';
583
+ section += '- **문서 기준 판단**: 위에 포함된 문서 내용을 기준으로 판단\n';
584
+ section += '- **추측 금지**: 문서에 없는 내용은 사용자에게 에스컬레이션\n';
585
+ section += '- **규칙 준수**: 모든 규칙(Rules)을 반드시 따름\n';
586
+ section += '- **현재 범위**: 현재 스프린트 Task만 작업 (범위 초과 금지)\n';
587
+ section += '- **우선순위**: 문서 충돌 시 document-priority.md 따름\n\n';
588
+ // 의사결정 권한 (Manager 이외 역할에 대해 명시)
589
+ if (role !== 'manager') {
590
+ section += '## 의사결정 권한 제한 (CRITICAL)\n\n';
591
+ section += '- 스프린트 생성/종료/승인: **Manager(사용자)만 가능**\n';
592
+ section += '- Task 상태 전환 승인 (→ DONE): **Manager만 가능**\n';
593
+ section += '- decision.md 기록: **Manager만 가능**\n';
594
+ section += '- 최종 의사결정/승인: **Manager(사용자)만 가능**\n';
595
+ section += '- 당신의 역할: 분석/제안/실행만 가능, 결정/승인 권한 없음\n';
596
+ section += '- 결정이 필요한 상황: 사용자에게 에스컬레이션\n\n';
597
+ }
598
+ // 역할별 제약 명시
599
+ section += '## 역할별 제약 (CRITICAL)\n\n';
600
+ const roleConstraints = {
601
+ developer: [
602
+ '✅ 현재 스프린트의 IN_DEV Task만 구현',
603
+ '✅ project.md 기술 기준 절대 준수',
604
+ '✅ Interface 문서(api.md, ui.md) 계약 준수',
605
+ '❌ DONE/REJECT Task 수정 금지',
606
+ '❌ 스프린트 범위 외 작업 금지',
607
+ '❌ project.md에 없는 기술 추가 금지',
608
+ '❌ 기획 문서 작성 금지 (Planner 역할)',
609
+ '❌ 코드 리뷰 수행 금지 (Reviewer 역할)',
610
+ '❌ 아키텍처/기술 스택 결정 금지',
611
+ ],
612
+ reviewer: [
613
+ '✅ IN_DEV/IN_REVIEW Task 코드 리뷰',
614
+ '✅ project.md 코딩 규칙 기준으로 판정',
615
+ '✅ PASS/REJECT 판정 및 사유 기록',
616
+ '❌ 직접 코드 수정 금지 (리뷰만!)',
617
+ '❌ 기능 추가/변경 금지',
618
+ '❌ 범위 외 리뷰 금지',
619
+ '❌ 기획 작업 금지 (Planner 역할)',
620
+ '❌ 구현 작업 금지 (Developer 역할)',
621
+ ],
622
+ planner: [
623
+ '✅ 요구사항 수집 및 plan.md 작성',
624
+ '✅ backlog/ Task 생성 및 관리',
625
+ '✅ Task 우선순위/크기 산정',
626
+ '❌ 직접 코드 작성 금지 (절대 금지)',
627
+ '❌ 소스 파일 생성/수정 금지 (절대 금지)',
628
+ '❌ project.md 기술 결정 금지 (제안만)',
629
+ '❌ 스프린트 진행 중 Task 변경 금지',
630
+ '❌ 기술 스택 선택/아키텍처 결정 금지',
631
+ '❌ 개발 일정 추정 금지',
632
+ ],
633
+ improver: [
634
+ '✅ 기존 기능 개선점 분석',
635
+ '✅ improvement-reports/ 작성',
636
+ '✅ 개선 Task를 backlog/에 생성',
637
+ '❌ 직접 코드 수정/구현 금지 (절대 금지)',
638
+ '❌ 신규 기능 기획 금지 (Planner 역할)',
639
+ '❌ 코드 리뷰 수행 금지 (Reviewer 역할)',
640
+ '❌ 기술 스택 독단 결정 금지 (사용자 승인 필수)',
641
+ '❌ 다른 기능까지 확장 분석 금지 (범위 준수)',
642
+ ],
643
+ documenter: [
644
+ '✅ DONE Task 기반 문서 작성',
645
+ '✅ Release Notes, API Changelog 작성',
646
+ '✅ docs/ 디렉토리 문서 업데이트',
647
+ '❌ 코드 직접 수정 금지',
648
+ '❌ 미완료 Task 문서화 금지',
649
+ '❌ 존재하지 않는 기능 문서화 금지',
650
+ '❌ 빈 페이지 생성 금지 (내용 없으면 파일 만들지 않음)',
651
+ '❌ 추측으로 문서 작성 금지 (반드시 코드 확인 후)',
652
+ '❌ 개발/기획/리뷰 작업 금지 (다른 역할의 영역)',
653
+ ],
654
+ analyzer: [
655
+ '✅ 코드베이스 분석 및 project.md 역생성',
656
+ '✅ 기술 스택/패턴 파악',
657
+ '❌ 코드 수정/구현 금지 (절대 금지)',
658
+ '❌ 기존 코드 삭제/변경 금지 (절대 금지)',
659
+ '❌ 요구사항 정의 금지 (분석만)',
660
+ '❌ plan.md 작성 금지 (Planner 역할)',
661
+ '❌ backlog/ Task 파일 작성 금지 (Planner 역할)',
662
+ '❌ 분석 없이 가정으로 문서 작성 금지',
663
+ ],
664
+ };
665
+ const constraints = roleConstraints[role] || [
666
+ '✅ 역할에 정의된 책임만 수행',
667
+ '❌ 다른 역할의 책임 침범 금지',
668
+ ];
669
+ for (const constraint of constraints) {
670
+ section += `${constraint}\n`;
671
+ }
672
+ section += '\n## 멀티 세션 상태 관리\n\n';
673
+ section += '상태 공유: `ai-dev-team/.ada-status.json`\n';
674
+ section += '- Task 진행 상황 업데이트\n';
675
+ section += '- 질문은 pendingQuestions에 추가\n';
676
+ section += '- 알림은 notifications에 추가\n';
677
+ return section;
678
+ }
679
+ // ============================================================================
680
+ // 유틸리티 함수
681
+ // ============================================================================
682
+ /**
683
+ * 문서에서 특정 섹션 추출 (## 제목 기준)
684
+ */
685
+ function extractSection(content, sectionTitle) {
686
+ const escapedTitle = sectionTitle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
687
+ const regex = new RegExp(`(${escapedTitle}[\\s\\S]*?)(?=\\n## |$)`, 'i');
688
+ const match = content.match(regex);
689
+ return match ? match[1].trim() : null;
690
+ }
691
+ /**
692
+ * 문서에서 여러 섹션 추출
693
+ */
694
+ function extractSections(content, sectionTitles) {
695
+ const results = [];
696
+ for (const title of sectionTitles) {
697
+ const section = extractSection(content, title);
698
+ if (section) {
699
+ results.push(section);
700
+ }
701
+ }
702
+ if (results.length === 0) {
703
+ // 섹션을 찾지 못하면 요약 반환
704
+ return extractDocumentSummary(content, 30);
705
+ }
706
+ return results.join('\n\n');
707
+ }
708
+ /**
709
+ * 문서 요약 추출 (첫 N줄)
710
+ */
711
+ function extractDocumentSummary(content, maxLines) {
712
+ const lines = content.split('\n');
713
+ const summaryLines = lines.slice(0, maxLines);
714
+ let summary = summaryLines.join('\n');
715
+ if (lines.length > maxLines) {
716
+ summary += `\n\n... (${lines.length - maxLines}줄 생략, 전체 내용은 파일 읽기)`;
717
+ }
718
+ return summary;
719
+ }
720
+ /**
721
+ * 콘텐츠 레벨 가져오기 (외부 사용)
722
+ */
723
+ export function getRoleContentConfig(role) {
724
+ return ROLE_CONTENT_CONFIG[role] || DEFAULT_CONTENT_CONFIG;
725
+ }
726
+ //# sourceMappingURL=promptBuilder.js.map