aiwf 0.3.13 → 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 +229 -16
- package/src/utils/messages.js +16 -0
- package/src/utils/paths.js +3 -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
|
/**
|
|
@@ -190,6 +356,7 @@ async function createDirectoryStructure() {
|
|
|
190
356
|
// Create tool-specific directories
|
|
191
357
|
await fs.mkdir(TOOL_DIRS.CURSOR_RULES, { recursive: true });
|
|
192
358
|
await fs.mkdir(TOOL_DIRS.WINDSURF_RULES, { recursive: true });
|
|
359
|
+
await fs.mkdir(TOOL_DIRS.CLAUDE_AGENTS, { recursive: true });
|
|
193
360
|
}
|
|
194
361
|
|
|
195
362
|
/**
|
|
@@ -285,7 +452,7 @@ async function updateDocumentation(languagePath, spinner, msg, debugLog) {
|
|
|
285
452
|
}
|
|
286
453
|
|
|
287
454
|
/**
|
|
288
|
-
* Update commands
|
|
455
|
+
* Update Claude commands and agents
|
|
289
456
|
* @param {string} languagePath - Language path
|
|
290
457
|
* @param {Object} spinner - Ora spinner instance
|
|
291
458
|
* @param {Object} msg - Localized messages
|
|
@@ -298,7 +465,14 @@ async function updateCommands(languagePath, spinner, msg, debugLog) {
|
|
|
298
465
|
await fs.rm(TOOL_DIRS.CLAUDE_COMMANDS, { recursive: true, force: true });
|
|
299
466
|
}
|
|
300
467
|
|
|
468
|
+
// Delete existing agents folder if it exists
|
|
469
|
+
if (await fs.access(TOOL_DIRS.CLAUDE_AGENTS).then(() => true).catch(() => false)) {
|
|
470
|
+
logWithSpinner(spinner, 'Deleting old agents...', debugLog);
|
|
471
|
+
await fs.rm(TOOL_DIRS.CLAUDE_AGENTS, { recursive: true, force: true });
|
|
472
|
+
}
|
|
473
|
+
|
|
301
474
|
await fs.mkdir(TOOL_DIRS.CLAUDE_COMMANDS, { recursive: true });
|
|
475
|
+
await fs.mkdir(TOOL_DIRS.CLAUDE_AGENTS, { recursive: true });
|
|
302
476
|
|
|
303
477
|
// Download commands
|
|
304
478
|
logWithSpinner(spinner, msg.downloadingCommands, debugLog);
|
|
@@ -314,11 +488,28 @@ async function updateCommands(languagePath, spinner, msg, debugLog) {
|
|
|
314
488
|
} catch (error) {
|
|
315
489
|
logWithSpinner(spinner, msg.commandsNotFound, debugLog);
|
|
316
490
|
}
|
|
491
|
+
|
|
492
|
+
// Download agents
|
|
493
|
+
logWithSpinner(spinner, 'Downloading agents...', debugLog);
|
|
494
|
+
try {
|
|
495
|
+
await downloadDirectory(
|
|
496
|
+
`${GITHUB_CONTENT_PREFIX}/${languagePath}/${TOOL_DIRS.CLAUDE_AGENTS}`,
|
|
497
|
+
TOOL_DIRS.CLAUDE_AGENTS,
|
|
498
|
+
spinner,
|
|
499
|
+
msg,
|
|
500
|
+
languagePath,
|
|
501
|
+
false // agents도 기존 방식 유지 (파일 리스트 사용)
|
|
502
|
+
);
|
|
503
|
+
logWithSpinner(spinner, 'Successfully downloaded agents', debugLog);
|
|
504
|
+
} catch (error) {
|
|
505
|
+
logWithSpinner(spinner, 'Agents not found or failed to download', debugLog);
|
|
506
|
+
}
|
|
317
507
|
}
|
|
318
508
|
|
|
319
509
|
/**
|
|
320
510
|
* Download and process rules
|
|
321
511
|
* @param {Object} spinner - Ora spinner instance
|
|
512
|
+
{{ ... }}
|
|
322
513
|
* @param {Object} msg - Localized messages
|
|
323
514
|
* @param {boolean} debugLog - Debug mode flag
|
|
324
515
|
*/
|
|
@@ -584,9 +775,22 @@ export async function installAIWF(options = {}) {
|
|
|
584
775
|
// Check existing installation
|
|
585
776
|
const hasExisting = await checkExistingInstallation();
|
|
586
777
|
|
|
778
|
+
let installDecision = { continue: true, installType: 'fresh', preserveProject: false };
|
|
779
|
+
let projectBackupDir = null;
|
|
780
|
+
|
|
587
781
|
if (hasExisting) {
|
|
588
|
-
|
|
589
|
-
|
|
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
|
+
}
|
|
590
794
|
}
|
|
591
795
|
|
|
592
796
|
const spinner = ora(msg.fetching).start();
|
|
@@ -595,16 +799,20 @@ export async function installAIWF(options = {}) {
|
|
|
595
799
|
// Create directory structure
|
|
596
800
|
await createDirectoryStructure();
|
|
597
801
|
|
|
598
|
-
// Download manifest (fresh installs only)
|
|
599
|
-
if (!hasExisting) {
|
|
802
|
+
// Download manifest (fresh installs only or complete reinstall)
|
|
803
|
+
if (!hasExisting || installDecision.installType === 'reinstall') {
|
|
600
804
|
await downloadManifest(languagePath, spinner, msg, debugLog);
|
|
601
805
|
}
|
|
602
806
|
|
|
603
|
-
// Download templates
|
|
604
|
-
|
|
807
|
+
// Download templates (fresh installs and complete reinstall only)
|
|
808
|
+
if (!hasExisting || installDecision.installType === 'reinstall') {
|
|
809
|
+
await downloadTemplates(languagePath, spinner, msg, debugLog);
|
|
810
|
+
}
|
|
605
811
|
|
|
606
|
-
// Update documentation
|
|
607
|
-
|
|
812
|
+
// Update documentation (fresh installs and complete reinstall only)
|
|
813
|
+
if (!hasExisting || installDecision.installType === 'reinstall') {
|
|
814
|
+
await updateDocumentation(languagePath, spinner, msg, debugLog);
|
|
815
|
+
}
|
|
608
816
|
|
|
609
817
|
// Update commands
|
|
610
818
|
await updateCommands(languagePath, spinner, msg, debugLog);
|
|
@@ -612,8 +820,13 @@ export async function installAIWF(options = {}) {
|
|
|
612
820
|
// Download and process rules
|
|
613
821
|
await downloadAndProcessRules(spinner, msg, debugLog);
|
|
614
822
|
|
|
823
|
+
// Restore project files if needed
|
|
824
|
+
if (projectBackupDir) {
|
|
825
|
+
await restoreProjectFiles(projectBackupDir, msg);
|
|
826
|
+
}
|
|
827
|
+
|
|
615
828
|
// Success
|
|
616
|
-
if (hasExisting) {
|
|
829
|
+
if (hasExisting && installDecision.installType === 'update') {
|
|
617
830
|
spinner.succeed(chalk.green(msg.updateSuccess));
|
|
618
831
|
} else {
|
|
619
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'),
|
|
@@ -37,6 +37,7 @@ export const AIWF_DIRS = {
|
|
|
37
37
|
// Tool-specific directories
|
|
38
38
|
export const TOOL_DIRS = {
|
|
39
39
|
CLAUDE_COMMANDS: path.join(BASE_DIRS.CLAUDE, 'commands', 'aiwf'),
|
|
40
|
+
CLAUDE_AGENTS: path.join(BASE_DIRS.CLAUDE, 'agents'),
|
|
40
41
|
GEMINI_PROMPTS: path.join(BASE_DIRS.GEMINI, 'prompts', 'aiwf'),
|
|
41
42
|
CURSOR_RULES: path.join(BASE_DIRS.CURSOR, 'rules'),
|
|
42
43
|
WINDSURF_RULES: path.join(BASE_DIRS.WINDSURF, 'rules')
|
|
@@ -76,7 +77,7 @@ export function getAllAiwfDirectories() {
|
|
|
76
77
|
AIWF_DIRS.REQUIREMENTS,
|
|
77
78
|
AIWF_DIRS.SPRINTS,
|
|
78
79
|
AIWF_DIRS.GENERAL_TASKS,
|
|
79
|
-
AIWF_DIRS.
|
|
80
|
+
AIWF_DIRS.ARCHITECTURAL_DECISIONS,
|
|
80
81
|
AIWF_DIRS.STATE_OF_PROJECT,
|
|
81
82
|
AIWF_DIRS.PROMPTS,
|
|
82
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** (장기): 전체 구조 최적화
|