aiwf 0.3.14 → 0.3.15
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.ko.md +16 -6
- package/README.md +16 -6
- package/docs/AI-WORKFLOW.ko.md +1 -1
- package/docs/AI-WORKFLOW.md +1 -1
- package/docs/GETTING_STARTED.md +1 -1
- package/docs/ROADMAP_v0.4.0.md +286 -0
- package/package.json +1 -1
- package/src/cli/index.js +1 -1
- package/src/lib/installer.js +203 -15
- package/src/utils/messages.js +16 -0
- package/src/utils/paths.js +2 -2
- package/docs/CLEANUP_RECOMMENDATIONS.md +0 -86
- package/docs/git-feature-integration-guide.md +0 -253
- package/docs/lightweight-evaluation.md +0 -198
- package/docs/performance-benchmark-report.md +0 -159
- package/docs/reports/S02-sprint-report.md +0 -190
- package/docs/usability-test-report.md +0 -170
- /package/docs/{AI_PERSONA_SYSTEM_DESIGN.md → designs/AI_PERSONA_SYSTEM_DESIGN.md} +0 -0
- /package/docs/{API_DOCUMENTATION.md → designs/API_DOCUMENTATION.md} +0 -0
- /package/docs/{API_REFERENCE.md → designs/API_REFERENCE.md} +0 -0
- /package/docs/{Enhanced_Installation_Flow_Design.md → designs/Enhanced_Installation_Flow_Design.md} +0 -0
- /package/docs/{moonklabs-metadata-system-prd.md → designs/aiwf-metadata-system-prd.md} +0 -0
- /package/docs/{offline-template-cache.md → designs/offline-template-cache.md} +0 -0
- /package/docs/{persona-aware-compression.md → designs/persona-aware-compression.md} +0 -0
package/src/lib/installer.js
CHANGED
|
@@ -52,6 +52,61 @@ async function checkExistingInstallation() {
|
|
|
52
52
|
return flagExists;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Check if existing project files exist
|
|
57
|
+
* @returns {Promise<{hasProject: boolean, projectFiles: string[]}>} Project status
|
|
58
|
+
*/
|
|
59
|
+
async function checkExistingProject() {
|
|
60
|
+
const projectFiles = [];
|
|
61
|
+
let hasProject = false;
|
|
62
|
+
|
|
63
|
+
// Check for key project files
|
|
64
|
+
const keyFiles = [
|
|
65
|
+
FILES.PROJECT_MANIFEST,
|
|
66
|
+
path.join(AIWF_DIRS.PROJECT_DOCS, 'README.md'),
|
|
67
|
+
path.join(AIWF_DIRS.REQUIREMENTS, 'requirements.md'),
|
|
68
|
+
path.join(AIWF_DIRS.SPRINTS, 'sprint-01.md'),
|
|
69
|
+
path.join(AIWF_DIRS.GENERAL_TASKS, 'tasks.md'),
|
|
70
|
+
path.join(AIWF_DIRS.ARCHITECTURAL_DECISIONS, 'decisions.md'),
|
|
71
|
+
path.join(AIWF_DIRS.STATE_OF_PROJECT, 'current-state.md')
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
for (const file of keyFiles) {
|
|
75
|
+
try {
|
|
76
|
+
await fs.access(file);
|
|
77
|
+
projectFiles.push(file);
|
|
78
|
+
hasProject = true;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
// File doesn't exist, continue
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Check for any .md files in project directories
|
|
85
|
+
const projectDirs = [
|
|
86
|
+
AIWF_DIRS.PROJECT_DOCS,
|
|
87
|
+
AIWF_DIRS.REQUIREMENTS,
|
|
88
|
+
AIWF_DIRS.SPRINTS,
|
|
89
|
+
AIWF_DIRS.GENERAL_TASKS,
|
|
90
|
+
AIWF_DIRS.ARCHITECTURAL_DECISIONS,
|
|
91
|
+
AIWF_DIRS.STATE_OF_PROJECT
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
for (const dir of projectDirs) {
|
|
95
|
+
try {
|
|
96
|
+
const files = await fs.readdir(dir);
|
|
97
|
+
const mdFiles = files.filter(file => file.endsWith('.md'));
|
|
98
|
+
if (mdFiles.length > 0) {
|
|
99
|
+
hasProject = true;
|
|
100
|
+
projectFiles.push(...mdFiles.map(file => path.join(dir, file)));
|
|
101
|
+
}
|
|
102
|
+
} catch (error) {
|
|
103
|
+
// Directory doesn't exist, continue
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return { hasProject, projectFiles };
|
|
108
|
+
}
|
|
109
|
+
|
|
55
110
|
/**
|
|
56
111
|
* Log with spinner for debug mode
|
|
57
112
|
* @param {Object} spinner - Ora spinner instance
|
|
@@ -146,34 +201,145 @@ async function selectLanguage(options) {
|
|
|
146
201
|
* Handle existing installation
|
|
147
202
|
* @param {Object} msg - Localized messages
|
|
148
203
|
* @param {Object} options - Installation options
|
|
149
|
-
* @returns {Promise<boolean>}
|
|
204
|
+
* @returns {Promise<{continue: boolean, installType: string, preserveProject: boolean}>} Installation decision
|
|
150
205
|
*/
|
|
151
206
|
async function handleExistingInstallation(msg, options) {
|
|
207
|
+
|
|
152
208
|
if (options.force) {
|
|
153
|
-
return true;
|
|
209
|
+
return { continue: true, installType: 'reinstall', preserveProject: false };
|
|
154
210
|
}
|
|
155
211
|
|
|
156
|
-
|
|
212
|
+
// First, ask about installation type
|
|
213
|
+
const installResponse = await prompts({
|
|
157
214
|
type: 'select',
|
|
158
215
|
name: 'action',
|
|
159
216
|
message: msg.existingDetected,
|
|
160
217
|
choices: [
|
|
161
218
|
{ title: msg.updateOption, value: 'update' },
|
|
219
|
+
{ title: msg.reinstallOption, value: 'reinstall' },
|
|
162
220
|
{ title: msg.skipOption, value: 'skip' },
|
|
163
221
|
{ title: msg.cancelOption, value: 'cancel' }
|
|
164
222
|
]
|
|
165
223
|
});
|
|
166
224
|
|
|
167
|
-
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
if (installResponse.action === 'skip' || installResponse.action === 'cancel') {
|
|
168
228
|
console.log(chalk.yellow(msg.installCancelled));
|
|
169
229
|
process.exit(0);
|
|
170
230
|
}
|
|
171
231
|
|
|
172
|
-
|
|
232
|
+
let preserveProject = true; // Default to preserve
|
|
233
|
+
|
|
234
|
+
// If reinstalling, don't preserve project (complete fresh install)
|
|
235
|
+
if (installResponse.action === 'reinstall') {
|
|
236
|
+
preserveProject = false;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Backup if updating
|
|
240
|
+
if (installResponse.action === 'update') {
|
|
173
241
|
await backupCommandsAndDocs(msg);
|
|
174
242
|
}
|
|
175
243
|
|
|
176
|
-
return
|
|
244
|
+
return {
|
|
245
|
+
continue: true,
|
|
246
|
+
installType: installResponse.action,
|
|
247
|
+
preserveProject
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Backup project files
|
|
253
|
+
* @param {string[]} projectFiles - List of project files to backup
|
|
254
|
+
* @param {Object} msg - Localized messages
|
|
255
|
+
* @returns {Promise<string>} Backup directory path
|
|
256
|
+
*/
|
|
257
|
+
async function backupProjectFiles(projectFiles, msg) {
|
|
258
|
+
if (projectFiles.length === 0) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const backupDir = path.join(os.tmpdir(), `aiwf-project-backup-${Date.now()}`);
|
|
263
|
+
await fs.mkdir(backupDir, { recursive: true });
|
|
264
|
+
|
|
265
|
+
console.log(chalk.cyan('💾 Backing up project files...'));
|
|
266
|
+
|
|
267
|
+
for (const file of projectFiles) {
|
|
268
|
+
try {
|
|
269
|
+
const relativePath = path.relative(process.cwd(), file);
|
|
270
|
+
const backupPath = path.join(backupDir, relativePath);
|
|
271
|
+
const backupDirPath = path.dirname(backupPath);
|
|
272
|
+
|
|
273
|
+
await fs.mkdir(backupDirPath, { recursive: true });
|
|
274
|
+
await fs.copyFile(file, backupPath);
|
|
275
|
+
} catch (error) {
|
|
276
|
+
console.log(chalk.yellow(`Warning: Could not backup ${file}: ${error.message}`));
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
console.log(chalk.green(`✅ Project files backed up to: ${backupDir}`));
|
|
281
|
+
return backupDir;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Restore project files from backup
|
|
286
|
+
* @param {string} backupDir - Backup directory path
|
|
287
|
+
* @param {Object} msg - Localized messages
|
|
288
|
+
*/
|
|
289
|
+
async function restoreProjectFiles(backupDir, msg) {
|
|
290
|
+
if (!backupDir) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
console.log(chalk.cyan('🔄 Restoring project files...'));
|
|
295
|
+
|
|
296
|
+
try {
|
|
297
|
+
const backupFiles = await fs.readdir(backupDir, { recursive: true });
|
|
298
|
+
|
|
299
|
+
for (const file of backupFiles) {
|
|
300
|
+
const backupFilePath = path.join(backupDir, file);
|
|
301
|
+
const stat = await fs.stat(backupFilePath);
|
|
302
|
+
|
|
303
|
+
if (stat.isFile()) {
|
|
304
|
+
const targetPath = path.join(process.cwd(), file);
|
|
305
|
+
const targetDir = path.dirname(targetPath);
|
|
306
|
+
|
|
307
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
308
|
+
await fs.copyFile(backupFilePath, targetPath);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
console.log(chalk.green(msg.projectPreserved));
|
|
313
|
+
|
|
314
|
+
// Clean up backup directory
|
|
315
|
+
await fs.rm(backupDir, { recursive: true, force: true });
|
|
316
|
+
} catch (error) {
|
|
317
|
+
console.log(chalk.yellow(`Warning: Could not restore some project files: ${error.message}`));
|
|
318
|
+
console.log(chalk.yellow(`Backup preserved at: ${backupDir}`));
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Remove project files
|
|
324
|
+
* @param {string[]} projectFiles - List of project files to remove
|
|
325
|
+
* @param {Object} msg - Localized messages
|
|
326
|
+
*/
|
|
327
|
+
async function removeProjectFiles(projectFiles, msg) {
|
|
328
|
+
if (projectFiles.length === 0) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
console.log(chalk.cyan('🗑️ Removing existing project files...'));
|
|
333
|
+
|
|
334
|
+
for (const file of projectFiles) {
|
|
335
|
+
try {
|
|
336
|
+
await fs.unlink(file);
|
|
337
|
+
} catch (error) {
|
|
338
|
+
// File might already be deleted, continue
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
console.log(chalk.green(msg.projectOverwritten));
|
|
177
343
|
}
|
|
178
344
|
|
|
179
345
|
/**
|
|
@@ -609,9 +775,22 @@ export async function installAIWF(options = {}) {
|
|
|
609
775
|
// Check existing installation
|
|
610
776
|
const hasExisting = await checkExistingInstallation();
|
|
611
777
|
|
|
778
|
+
let installDecision = { continue: true, installType: 'fresh', preserveProject: false };
|
|
779
|
+
let projectBackupDir = null;
|
|
780
|
+
|
|
612
781
|
if (hasExisting) {
|
|
613
|
-
|
|
614
|
-
|
|
782
|
+
|
|
783
|
+
installDecision = await handleExistingInstallation(msg, options);
|
|
784
|
+
|
|
785
|
+
if (!installDecision.continue) return;
|
|
786
|
+
|
|
787
|
+
// If reinstalling and preserving project, backup project files
|
|
788
|
+
if (installDecision.installType === 'reinstall' && installDecision.preserveProject) {
|
|
789
|
+
const { hasProject, projectFiles } = await checkExistingProject();
|
|
790
|
+
if (hasProject) {
|
|
791
|
+
projectBackupDir = await backupProjectFiles(projectFiles, msg);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
615
794
|
}
|
|
616
795
|
|
|
617
796
|
const spinner = ora(msg.fetching).start();
|
|
@@ -620,16 +799,20 @@ export async function installAIWF(options = {}) {
|
|
|
620
799
|
// Create directory structure
|
|
621
800
|
await createDirectoryStructure();
|
|
622
801
|
|
|
623
|
-
// Download manifest (fresh installs only)
|
|
624
|
-
if (!hasExisting) {
|
|
802
|
+
// Download manifest (fresh installs only or complete reinstall)
|
|
803
|
+
if (!hasExisting || installDecision.installType === 'reinstall') {
|
|
625
804
|
await downloadManifest(languagePath, spinner, msg, debugLog);
|
|
626
805
|
}
|
|
627
806
|
|
|
628
|
-
// Download templates
|
|
629
|
-
|
|
807
|
+
// Download templates (fresh installs and complete reinstall only)
|
|
808
|
+
if (!hasExisting || installDecision.installType === 'reinstall') {
|
|
809
|
+
await downloadTemplates(languagePath, spinner, msg, debugLog);
|
|
810
|
+
}
|
|
630
811
|
|
|
631
|
-
// Update documentation
|
|
632
|
-
|
|
812
|
+
// Update documentation (fresh installs and complete reinstall only)
|
|
813
|
+
if (!hasExisting || installDecision.installType === 'reinstall') {
|
|
814
|
+
await updateDocumentation(languagePath, spinner, msg, debugLog);
|
|
815
|
+
}
|
|
633
816
|
|
|
634
817
|
// Update commands
|
|
635
818
|
await updateCommands(languagePath, spinner, msg, debugLog);
|
|
@@ -637,8 +820,13 @@ export async function installAIWF(options = {}) {
|
|
|
637
820
|
// Download and process rules
|
|
638
821
|
await downloadAndProcessRules(spinner, msg, debugLog);
|
|
639
822
|
|
|
823
|
+
// Restore project files if needed
|
|
824
|
+
if (projectBackupDir) {
|
|
825
|
+
await restoreProjectFiles(projectBackupDir, msg);
|
|
826
|
+
}
|
|
827
|
+
|
|
640
828
|
// Success
|
|
641
|
-
if (hasExisting) {
|
|
829
|
+
if (hasExisting && installDecision.installType === 'update') {
|
|
642
830
|
spinner.succeed(chalk.green(msg.updateSuccess));
|
|
643
831
|
} else {
|
|
644
832
|
spinner.succeed(chalk.green(msg.installSuccess));
|
package/src/utils/messages.js
CHANGED
|
@@ -11,8 +11,16 @@ export const messages = {
|
|
|
11
11
|
english: 'English',
|
|
12
12
|
existingDetected: '기존 AIWF 설치가 감지되었습니다. 무엇을 하시겠습니까?',
|
|
13
13
|
updateOption: '업데이트 (명령어와 문서만 업데이트하고 작업 내용은 보존)',
|
|
14
|
+
reinstallOption: '완전 재설치 (모든 내용을 새로 설치, 기존 프로젝트 덮어쓰기)',
|
|
14
15
|
skipOption: '설치 건너뛰기',
|
|
15
16
|
cancelOption: '취소',
|
|
17
|
+
projectDetected: '기존 프로젝트가 감지되었습니다. 프로젝트 파일을 어떻게 처리하시겠습니까?',
|
|
18
|
+
preserveProject: '프로젝트 보존 (기존 프로젝트 파일 유지)',
|
|
19
|
+
overwriteProject: '덮어쓰기 (새로 설치하고 기존 프로젝트 삭제)',
|
|
20
|
+
checkingProject: '기존 프로젝트 확인 중...',
|
|
21
|
+
projectFound: '기존 프로젝트가 발견되었습니다:',
|
|
22
|
+
projectPreserved: '💾 프로젝트가 보존되었습니다.',
|
|
23
|
+
projectOverwritten: '🔄 프로젝트가 새로 설치되었습니다.',
|
|
16
24
|
installCancelled: '\n설치가 취소되었습니다.',
|
|
17
25
|
backingUp: '기존 명령어 및 문서 백업 중...',
|
|
18
26
|
fetching: 'GitHub에서 AIWF 프레임워크를 가져오는 중...',
|
|
@@ -72,8 +80,16 @@ export const messages = {
|
|
|
72
80
|
english: 'English',
|
|
73
81
|
existingDetected: 'Existing AIWF installation detected. What would you like to do?',
|
|
74
82
|
updateOption: 'Update (Update commands and docs only, preserve work content)',
|
|
83
|
+
reinstallOption: 'Complete reinstall (Install everything fresh, overwrite existing project)',
|
|
75
84
|
skipOption: 'Skip installation',
|
|
76
85
|
cancelOption: 'Cancel',
|
|
86
|
+
projectDetected: 'Existing project detected. How would you like to handle project files?',
|
|
87
|
+
preserveProject: 'Preserve project (Keep existing project files)',
|
|
88
|
+
overwriteProject: 'Overwrite (Fresh install and remove existing project)',
|
|
89
|
+
checkingProject: 'Checking for existing project...',
|
|
90
|
+
projectFound: 'Existing project found:',
|
|
91
|
+
projectPreserved: '💾 Project has been preserved.',
|
|
92
|
+
projectOverwritten: '🔄 Project has been freshly installed.',
|
|
77
93
|
installCancelled: '\nInstallation cancelled.',
|
|
78
94
|
backingUp: 'Backing up existing commands and documents...',
|
|
79
95
|
fetching: 'Fetching AIWF framework from GitHub...',
|
package/src/utils/paths.js
CHANGED
|
@@ -22,7 +22,7 @@ export const AIWF_DIRS = {
|
|
|
22
22
|
REQUIREMENTS: path.join(BASE_DIRS.AIWF, '02_REQUIREMENTS'),
|
|
23
23
|
SPRINTS: path.join(BASE_DIRS.AIWF, '03_SPRINTS'),
|
|
24
24
|
GENERAL_TASKS: path.join(BASE_DIRS.AIWF, '04_GENERAL_TASKS'),
|
|
25
|
-
|
|
25
|
+
ARCHITECTURAL_DECISIONS: path.join(BASE_DIRS.AIWF, '05_ARCHITECTURAL_DECISIONS'),
|
|
26
26
|
STATE_OF_PROJECT: path.join(BASE_DIRS.AIWF, '10_STATE_OF_PROJECT'),
|
|
27
27
|
PROMPTS: path.join(BASE_DIRS.AIWF, '98_PROMPTS'),
|
|
28
28
|
TEMPLATES: path.join(BASE_DIRS.AIWF, '99_TEMPLATES'),
|
|
@@ -77,7 +77,7 @@ export function getAllAiwfDirectories() {
|
|
|
77
77
|
AIWF_DIRS.REQUIREMENTS,
|
|
78
78
|
AIWF_DIRS.SPRINTS,
|
|
79
79
|
AIWF_DIRS.GENERAL_TASKS,
|
|
80
|
-
AIWF_DIRS.
|
|
80
|
+
AIWF_DIRS.ARCHITECTURAL_DECISIONS,
|
|
81
81
|
AIWF_DIRS.STATE_OF_PROJECT,
|
|
82
82
|
AIWF_DIRS.PROMPTS,
|
|
83
83
|
AIWF_DIRS.TEMPLATES
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
# AIWF 프로젝트 정리 권장사항
|
|
2
|
-
|
|
3
|
-
## ✅ 완료된 작업
|
|
4
|
-
|
|
5
|
-
1. **import 경로 수정**
|
|
6
|
-
- index.js의 잘못된 경로 수정 완료
|
|
7
|
-
- `./src/commands/ai-tool.js` → `./commands/ai-tool.js`
|
|
8
|
-
|
|
9
|
-
2. **미사용 파일 삭제** (4개 파일, 1,734줄 제거)
|
|
10
|
-
- lib/file-batch-processor.js
|
|
11
|
-
- lib/performance-benchmark.js
|
|
12
|
-
- lib/template-manager.js
|
|
13
|
-
- lib/cache-integration.js
|
|
14
|
-
|
|
15
|
-
## 📋 추가 권장사항
|
|
16
|
-
|
|
17
|
-
### 1. 코드 구조 개선
|
|
18
|
-
|
|
19
|
-
#### index.js 모듈화 (1,950줄 → 여러 모듈로 분리)
|
|
20
|
-
```
|
|
21
|
-
index.js
|
|
22
|
-
├── lib/installer.js # 설치 로직
|
|
23
|
-
├── lib/validator.js # 검증 로직
|
|
24
|
-
├── lib/backup-manager.js # 백업/복원 로직
|
|
25
|
-
└── lib/github-client.js # GitHub API 통신
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
#### 토큰 관리 시스템 통합
|
|
29
|
-
현재 8개 파일에 분산된 토큰 기능을 2개로 통합:
|
|
30
|
-
- `lib/token-manager.js` - 핵심 토큰 관리
|
|
31
|
-
- `commands/token-tracking.js` - CLI 명령어
|
|
32
|
-
|
|
33
|
-
### 2. 파일명 일관성
|
|
34
|
-
|
|
35
|
-
스네이크 케이스를 케밥 케이스로 통일:
|
|
36
|
-
```bash
|
|
37
|
-
# 변경 필요
|
|
38
|
-
sync-feature-commits.js → sync-feature-commits.js ✓ (완료)
|
|
39
|
-
feature-commit-report.js → feature-commit-report.js ✓ (완료)
|
|
40
|
-
scan-git-history.js → scan-git-history.js ✓ (완료)
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### 3. 중복 기능 통합
|
|
44
|
-
|
|
45
|
-
#### 압축 시스템 (4개 → 2개)
|
|
46
|
-
- 유지: `utils/context-compressor.js`, `commands/compress-context.js`
|
|
47
|
-
- 통합: `compression-strategies.js`, `persona-aware-compressor.js`
|
|
48
|
-
|
|
49
|
-
### 4. 문서 정리
|
|
50
|
-
|
|
51
|
-
중복되거나 오래된 문서 통합:
|
|
52
|
-
- PRD.md와 PRD.ko.md의 정보 동기화
|
|
53
|
-
- 여러 개의 가이드 문서를 하나로 통합
|
|
54
|
-
- 사용되지 않는 문서에서만 참조되는 기능 제거
|
|
55
|
-
|
|
56
|
-
### 5. 테스트 개선
|
|
57
|
-
|
|
58
|
-
- 큰 테스트 파일 분리 (compression-test-suite.js: 1,251줄)
|
|
59
|
-
- 주석 처리된 테스트 코드 정리
|
|
60
|
-
- 실제 사용되는 유틸리티에 대한 테스트 추가
|
|
61
|
-
|
|
62
|
-
### 6. 성능 최적화
|
|
63
|
-
|
|
64
|
-
- 복잡한 메트릭 수집 간소화 (metrics-collector.js: 884줄)
|
|
65
|
-
- 불필요한 추상화 레벨 제거
|
|
66
|
-
- 캐시 시스템 단순화
|
|
67
|
-
|
|
68
|
-
## 🎯 예상 효과
|
|
69
|
-
|
|
70
|
-
- **코드 감소**: 약 20-30% 코드량 감소
|
|
71
|
-
- **유지보수성**: 파일 구조 명확화로 이해도 향상
|
|
72
|
-
- **성능**: 불필요한 추상화 제거로 성능 개선
|
|
73
|
-
- **일관성**: 명명 규칙 통일로 개발 경험 개선
|
|
74
|
-
|
|
75
|
-
## ⚠️ 주의사항
|
|
76
|
-
|
|
77
|
-
1. **Git 통합 파일들은 유지**: 실제로 활발히 사용 중
|
|
78
|
-
2. **페르소나 시스템 유지**: Claude Code 통합에 필수
|
|
79
|
-
3. **변경 시 테스트 필수**: 기능 손상 방지
|
|
80
|
-
|
|
81
|
-
## 🔄 단계별 진행
|
|
82
|
-
|
|
83
|
-
1. **Phase 1** (즉시): ✅ 미사용 파일 제거 (완료)
|
|
84
|
-
2. **Phase 2** (단기): 파일명 통일, 중복 통합
|
|
85
|
-
3. **Phase 3** (중기): index.js 모듈화, 테스트 개선
|
|
86
|
-
4. **Phase 4** (장기): 전체 구조 최적화
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
# Git-Feature 통합 가이드
|
|
2
|
-
|
|
3
|
-
이 문서는 AIWF의 Git 연동 Feature 추적 시스템 사용법을 설명합니다.
|
|
4
|
-
|
|
5
|
-
## 개요
|
|
6
|
-
|
|
7
|
-
Git-Feature 통합 시스템은 Git 커밋과 Feature Ledger를 자동으로 연결하여, 개발 진행 상황을 효과적으로 추적할 수 있게 합니다.
|
|
8
|
-
|
|
9
|
-
## 주요 기능
|
|
10
|
-
|
|
11
|
-
1. **커밋 메시지 파싱**: 다양한 형식의 Feature ID 자동 인식
|
|
12
|
-
2. **자동 동기화**: Git hooks를 통한 실시간 Feature 업데이트
|
|
13
|
-
3. **히스토리 스캔**: 기존 커밋 히스토리와 Feature 연결
|
|
14
|
-
4. **리포트 생성**: Feature-커밋 매핑 리포트 자동 생성
|
|
15
|
-
|
|
16
|
-
## 커밋 메시지 규칙
|
|
17
|
-
|
|
18
|
-
### 지원하는 Feature ID 형식
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
# 직접 참조
|
|
22
|
-
git commit -m "FL001 사용자 인증 기능 구현"
|
|
23
|
-
|
|
24
|
-
# 대괄호 참조
|
|
25
|
-
git commit -m "[FL001] 로그인 폼 스타일 수정"
|
|
26
|
-
|
|
27
|
-
# Conventional Commit 형식
|
|
28
|
-
git commit -m "feat(FL001): JWT 토큰 발급 로직 추가"
|
|
29
|
-
git commit -m "fix(FL001): 로그인 오류 수정"
|
|
30
|
-
|
|
31
|
-
# 해시 참조
|
|
32
|
-
git commit -m "Update authentication flow #FL001"
|
|
33
|
-
|
|
34
|
-
# 여러 Feature 참조
|
|
35
|
-
git commit -m "FL001, FL002 관련 공통 유틸리티 추가"
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### 브랜치 명명 규칙
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
# Feature 브랜치 형식
|
|
42
|
-
git checkout -b feature/FL001-user-authentication
|
|
43
|
-
git checkout -b feature/FL002-dashboard-redesign
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## 명령어 사용법
|
|
47
|
-
|
|
48
|
-
### 1. sync_feature_commits - Feature 동기화
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
# 특정 Feature 동기화
|
|
52
|
-
node claude-code/aiwf/ko/commands/sync_feature_commits.js FL001
|
|
53
|
-
|
|
54
|
-
# 모든 활성 Feature 동기화
|
|
55
|
-
node claude-code/aiwf/ko/commands/sync_feature_commits.js --all
|
|
56
|
-
|
|
57
|
-
# 최근 100개 커밋에서 Feature 찾기
|
|
58
|
-
node claude-code/aiwf/ko/commands/sync_feature_commits.js --recent 100
|
|
59
|
-
|
|
60
|
-
# 특정 날짜 이후 커밋 검색
|
|
61
|
-
node claude-code/aiwf/ko/commands/sync_feature_commits.js --since 2025-01-01
|
|
62
|
-
|
|
63
|
-
# 상세 로그 출력
|
|
64
|
-
node claude-code/aiwf/ko/commands/sync_feature_commits.js --verbose
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### 2. scan_git_history - 히스토리 스캔
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
# 기본 스캔 (2025-01-01부터)
|
|
71
|
-
node claude-code/aiwf/ko/commands/scan_git_history.js
|
|
72
|
-
|
|
73
|
-
# 날짜 범위 지정
|
|
74
|
-
node claude-code/aiwf/ko/commands/scan_git_history.js --since 2024-01-01 --until 2024-12-31
|
|
75
|
-
|
|
76
|
-
# 특정 Feature만 스캔
|
|
77
|
-
node claude-code/aiwf/ko/commands/scan_git_history.js --feature FL001
|
|
78
|
-
|
|
79
|
-
# Dry-run 모드 (실제 업데이트 없음)
|
|
80
|
-
node claude-code/aiwf/ko/commands/scan_git_history.js --dry-run
|
|
81
|
-
|
|
82
|
-
# 누락된 Feature 파일 자동 생성
|
|
83
|
-
node claude-code/aiwf/ko/commands/scan_git_history.js --create-missing
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### 3. feature_commit_report - 리포트 생성
|
|
87
|
-
|
|
88
|
-
```bash
|
|
89
|
-
# 기본 Markdown 리포트 생성
|
|
90
|
-
node claude-code/aiwf/ko/commands/feature_commit_report.js
|
|
91
|
-
|
|
92
|
-
# 특정 Feature 리포트
|
|
93
|
-
node claude-code/aiwf/ko/commands/feature_commit_report.js --feature FL001
|
|
94
|
-
|
|
95
|
-
# 활성 Feature만 포함
|
|
96
|
-
node claude-code/aiwf/ko/commands/feature_commit_report.js --status active
|
|
97
|
-
|
|
98
|
-
# JSON 형식으로 출력
|
|
99
|
-
node claude-code/aiwf/ko/commands/feature_commit_report.js --format json --output report.json
|
|
100
|
-
|
|
101
|
-
# HTML 형식 + 상세 정보
|
|
102
|
-
node claude-code/aiwf/ko/commands/feature_commit_report.js --format html --detailed --output report.html
|
|
103
|
-
|
|
104
|
-
# 타임라인 뷰 포함
|
|
105
|
-
node claude-code/aiwf/ko/commands/feature_commit_report.js --timeline
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
## Git Hooks 설정
|
|
109
|
-
|
|
110
|
-
### 자동 설치
|
|
111
|
-
|
|
112
|
-
```bash
|
|
113
|
-
# 설치 스크립트 실행
|
|
114
|
-
./claude-code/aiwf/ko/hooks/install-hooks.sh
|
|
115
|
-
|
|
116
|
-
# 환경 변수 설정 (활성화)
|
|
117
|
-
export AIWF_HOOKS_ENABLED=true
|
|
118
|
-
|
|
119
|
-
# 상세 로그 활성화 (선택사항)
|
|
120
|
-
export AIWF_HOOKS_VERBOSE=true
|
|
121
|
-
|
|
122
|
-
# 영구 설정 (~/.bashrc 또는 ~/.zshrc에 추가)
|
|
123
|
-
echo 'export AIWF_HOOKS_ENABLED=true' >> ~/.bashrc
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### 수동 설치
|
|
127
|
-
|
|
128
|
-
```bash
|
|
129
|
-
# post-commit hook 복사
|
|
130
|
-
cp claude-code/aiwf/ko/hooks/post-commit .git/hooks/
|
|
131
|
-
chmod +x .git/hooks/post-commit
|
|
132
|
-
|
|
133
|
-
# 환경 변수 설정
|
|
134
|
-
export AIWF_HOOKS_ENABLED=true
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### Hook 동작 확인
|
|
138
|
-
|
|
139
|
-
```bash
|
|
140
|
-
# Feature ID를 포함한 커밋 생성
|
|
141
|
-
git add .
|
|
142
|
-
git commit -m "feat(FL001): 새로운 기능 추가"
|
|
143
|
-
|
|
144
|
-
# 콘솔에 다음과 같은 메시지가 표시됩니다:
|
|
145
|
-
# 🔄 AIWF Feature Ledger 동기화 중...
|
|
146
|
-
# ✅ Feature ID 발견: FL001
|
|
147
|
-
# 📝 FL001 동기화 중...
|
|
148
|
-
# ✅ FL001 동기화 완료
|
|
149
|
-
# ✨ Feature Ledger 동기화 완료!
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
## 워크플로우 예시
|
|
153
|
-
|
|
154
|
-
### 1. 새 Feature 시작
|
|
155
|
-
|
|
156
|
-
```bash
|
|
157
|
-
# 1. Feature Ledger 생성
|
|
158
|
-
/project:aiwf:create_feature_ledger "User Authentication"
|
|
159
|
-
|
|
160
|
-
# 2. Feature 브랜치 생성
|
|
161
|
-
git checkout -b feature/FL001-user-authentication
|
|
162
|
-
|
|
163
|
-
# 3. 개발 및 커밋
|
|
164
|
-
git add src/auth/*
|
|
165
|
-
git commit -m "feat(FL001): 사용자 인증 모듈 구현"
|
|
166
|
-
|
|
167
|
-
# 4. Feature 자동 업데이트 확인
|
|
168
|
-
cat .aiwf/06_FEATURE_LEDGERS/active/FL001_User_Authentication.md
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
### 2. 기존 프로젝트에 적용
|
|
172
|
-
|
|
173
|
-
```bash
|
|
174
|
-
# 1. Git 히스토리 스캔
|
|
175
|
-
node claude-code/aiwf/ko/commands/scan_git_history.js --since 2024-01-01
|
|
176
|
-
|
|
177
|
-
# 2. 누락된 Feature 확인 및 생성
|
|
178
|
-
node claude-code/aiwf/ko/commands/scan_git_history.js --create-missing
|
|
179
|
-
|
|
180
|
-
# 3. 리포트 생성
|
|
181
|
-
node claude-code/aiwf/ko/commands/feature_commit_report.js --detailed
|
|
182
|
-
|
|
183
|
-
# 4. Git hooks 설치
|
|
184
|
-
./claude-code/aiwf/ko/hooks/install-hooks.sh
|
|
185
|
-
export AIWF_HOOKS_ENABLED=true
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### 3. 진행 상황 모니터링
|
|
189
|
-
|
|
190
|
-
```bash
|
|
191
|
-
# 전체 Feature 상태 확인
|
|
192
|
-
node claude-code/aiwf/ko/commands/feature_commit_report.js
|
|
193
|
-
|
|
194
|
-
# 특정 Feature 상세 정보
|
|
195
|
-
node claude-code/aiwf/ko/commands/sync_feature_commits.js FL001 --verbose
|
|
196
|
-
|
|
197
|
-
# 최근 활동 확인
|
|
198
|
-
node claude-code/aiwf/ko/commands/sync_feature_commits.js --recent 50 --verbose
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
## 문제 해결
|
|
202
|
-
|
|
203
|
-
### Git hooks가 실행되지 않음
|
|
204
|
-
|
|
205
|
-
```bash
|
|
206
|
-
# 환경 변수 확인
|
|
207
|
-
echo $AIWF_HOOKS_ENABLED
|
|
208
|
-
|
|
209
|
-
# Hook 파일 권한 확인
|
|
210
|
-
ls -la .git/hooks/post-commit
|
|
211
|
-
|
|
212
|
-
# 수동으로 동기화 실행
|
|
213
|
-
node claude-code/aiwf/ko/commands/sync_feature_commits.js --all
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### Feature ID가 인식되지 않음
|
|
217
|
-
|
|
218
|
-
```bash
|
|
219
|
-
# 커밋 메시지 패턴 확인
|
|
220
|
-
git log --oneline | grep "FL[0-9]\{3\}"
|
|
221
|
-
|
|
222
|
-
# 지원하는 형식 사용
|
|
223
|
-
git commit -m "feat(FL001): 기능 설명" # 권장
|
|
224
|
-
git commit -m "[FL001] 기능 설명" # 가능
|
|
225
|
-
git commit -m "FL001 기능 설명" # 가능
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
### 동기화 오류
|
|
229
|
-
|
|
230
|
-
```bash
|
|
231
|
-
# Feature 파일 존재 확인
|
|
232
|
-
find .aiwf/06_FEATURE_LEDGERS -name "FL001*"
|
|
233
|
-
|
|
234
|
-
# 수동으로 Feature 파일 생성
|
|
235
|
-
/project:aiwf:create_feature_ledger "Feature Name"
|
|
236
|
-
|
|
237
|
-
# 다시 동기화 시도
|
|
238
|
-
node claude-code/aiwf/ko/commands/sync_feature_commits.js FL001
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
## 모범 사례
|
|
242
|
-
|
|
243
|
-
1. **일관된 커밋 메시지**: Conventional Commit 형식 사용 권장
|
|
244
|
-
2. **브랜치 전략**: Feature별 브랜치 생성 및 명명 규칙 준수
|
|
245
|
-
3. **정기적 동기화**: 주기적으로 `--all` 옵션으로 전체 동기화
|
|
246
|
-
4. **리포트 활용**: 스프린트 종료 시 리포트 생성하여 진행 상황 공유
|
|
247
|
-
5. **Hook 활성화**: 팀 전체가 Git hooks를 활성화하여 일관성 유지
|
|
248
|
-
|
|
249
|
-
## 추가 리소스
|
|
250
|
-
|
|
251
|
-
- [Feature Ledger 시스템 사양](/.aiwf/02_REQUIREMENTS/M02_Context_Engineering_Enhancement/SPECS_Feature_Ledger_System.md)
|
|
252
|
-
- [Git 통합 사양](/.aiwf/06_FEATURE_LEDGERS/FEATURE_GIT_INTEGRATION.md)
|
|
253
|
-
- [통합 가이드](/.aiwf/06_FEATURE_LEDGERS/FEATURE_INTEGRATION_GUIDE.md)
|