aiwf 0.3.14 → 0.3.16
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 +19 -10
- package/README.md +54 -9
- package/docs/AI-WORKFLOW.ko.md +1 -1
- package/docs/AI-WORKFLOW.md +1 -1
- package/docs/API_REFERENCE_FULL.ko.md +979 -0
- package/docs/API_REFERENCE_FULL.md +979 -0
- package/docs/ARCHITECTURE.ko.md +314 -0
- package/docs/ARCHITECTURE.md +314 -0
- package/docs/GETTING_STARTED.ko.md +219 -0
- package/docs/GETTING_STARTED.md +1 -2
- package/docs/PERFORMANCE_GUIDELINES.ko.md +388 -0
- package/docs/ROADMAP_v0.4.0.md +286 -0
- package/docs/TROUBLESHOOTING.ko.md +366 -0
- package/package.json +50 -2
- package/src/DEPENDENCY_MAP.md +90 -0
- package/src/cli/index.js +1 -1
- package/src/lib/installer.js +204 -15
- package/src/lib/resources/templates/api-server/template/src/controllers/aiwfController.ts +0 -14
- package/src/lib/resources/templates/api-server/template/src/routes/aiwf.ts +0 -11
- package/src/lib/resources/templates/web-app/template/src/pages/AiwfDashboard.tsx +2 -5
- package/src/lib/resources/utils/token-reporter.js +2 -3
- package/src/utils/checkpoint-manager.js +11 -1
- package/src/utils/engineering-guard.js +11 -1
- package/src/utils/messages.js +16 -0
- package/src/utils/paths.js +2 -2
- package/templates/api-server/template/src/controllers/aiwfController.ts +0 -14
- package/templates/api-server/template/src/routes/aiwf.ts +0 -11
- package/templates/web-app/template/src/pages/AiwfDashboard.tsx +2 -5
- package/docs/CLEANUP_RECOMMENDATIONS.md +0 -86
- package/docs/git-feature-integration-guide.md +0 -253
- package/docs/guides/feature-git-integration-guide-ko.md +0 -481
- package/docs/guides/feature-git-integration-guide.md +0 -481
- 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/src/commands/cache-templates.js +0 -209
- package/src/commands/create-offline.js +0 -86
- package/src/commands/state-refactored.js +0 -419
- package/src/lib/resources/commands/feature-ledger.js +0 -565
- package/src/lib/resources/commands/feature_commit_report.js +0 -370
- package/src/lib/resources/commands/scan_git_history.js +0 -234
- package/src/lib/resources/commands/sync_feature_commits.js +0 -154
- package/src/lib/resources/templates/web-app/template/src/components/aiwf/FeatureLedger.tsx +0 -93
- package/src/lib/resources/utils/feature-updater.js +0 -271
- package/src/utils/git-integration.js +0 -173
- package/templates/web-app/template/src/components/aiwf/FeatureLedger.tsx +0 -93
- /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
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# AIWF 모듈 의존성 매트릭스
|
|
2
|
+
|
|
3
|
+
## 📊 CLI 명령어별 의존성
|
|
4
|
+
|
|
5
|
+
| 명령어 | 직접 의존성 | 간접 의존성 | 특수 사용 |
|
|
6
|
+
|--------|-------------|-------------|-----------|
|
|
7
|
+
| `aiwf install` | installer.js | backup-manager.js, file-downloader.js, rollback-manager.js, validator.js | - |
|
|
8
|
+
| `aiwf persona` | persona.js, ai-persona-manager.js | context-engine.js, metrics-collector.js, task-analyzer.js, token-optimizer.js | - |
|
|
9
|
+
| `aiwf compress` | compress.js, resource-loader.js | - | - |
|
|
10
|
+
| `aiwf token` | token.js, resource-loader.js | - | - |
|
|
11
|
+
| `aiwf evaluate` | evaluate.js, resource-loader.js | - | - |
|
|
12
|
+
| `aiwf state` | state.js | - | - |
|
|
13
|
+
| `aiwf create-project` | create-project.js, resource-loader.js | - | - |
|
|
14
|
+
| `aiwf ai-tool` | ai-tool.js | - | - |
|
|
15
|
+
| `aiwf sprint-task` | sprint-task.js | - | - |
|
|
16
|
+
| `aiwf sprint` | sprint-independent.js | - | - |
|
|
17
|
+
| `aiwf yolo-config` | yolo-config.js | - | - |
|
|
18
|
+
| `aiwf checkpoint` | checkpoint-manager.js | - | ⚠️ YOLO 전용 |
|
|
19
|
+
| `aiwf-checkpoint` | checkpoint-manager.js | - | ⚠️ YOLO 전용 |
|
|
20
|
+
| `aiwf cache` | cache-cli.js | template-cache-system.js, offline-detector.js, template-downloader.js, template-version-manager.js | - |
|
|
21
|
+
| `aiwf github` | github-integration.js | state/state-index.js | - |
|
|
22
|
+
| `YOLO 모드` | engineering-guard.js | - | ⚠️ 동적 import |
|
|
23
|
+
|
|
24
|
+
## 🏗️ 모듈 분류
|
|
25
|
+
|
|
26
|
+
### 🔧 핵심 유틸리티 (삭제 금지)
|
|
27
|
+
- **paths.js** - 경로 관리 (8곳에서 사용)
|
|
28
|
+
- **messages.js** - 다국어 메시지 시스템 (5곳에서 사용)
|
|
29
|
+
- **language-utils.js** - 언어 설정 관리 (3곳에서 사용)
|
|
30
|
+
|
|
31
|
+
### 🚀 YOLO 시스템 (삭제 금지)
|
|
32
|
+
- **engineering-guard.js** - 오버엔지니어링 방지 ⚠️ 동적 로드
|
|
33
|
+
- **checkpoint-manager.js** - 체크포인트 관리
|
|
34
|
+
|
|
35
|
+
### 🎯 명령어별 전용 모듈
|
|
36
|
+
|
|
37
|
+
#### AI Persona 시스템
|
|
38
|
+
- **ai-persona-manager.js** → persona 명령어
|
|
39
|
+
- **context-engine.js** → ai-persona-manager가 사용
|
|
40
|
+
- **metrics-collector.js** → ai-persona-manager가 사용
|
|
41
|
+
- **task-analyzer.js** → ai-persona-manager가 사용
|
|
42
|
+
- **token-optimizer.js** → context-engine이 사용
|
|
43
|
+
|
|
44
|
+
#### 설치/백업 시스템
|
|
45
|
+
- **installer.js** → install 명령어
|
|
46
|
+
- **backup-manager.js** → installer가 사용
|
|
47
|
+
- **file-downloader.js** → installer가 사용
|
|
48
|
+
- **rollback-manager.js** → installer가 사용
|
|
49
|
+
- **validator.js** → installer가 사용
|
|
50
|
+
|
|
51
|
+
#### 캐시 시스템
|
|
52
|
+
- **template-cache-system.js** → cache 명령어
|
|
53
|
+
- **offline-detector.js** → cache 명령어
|
|
54
|
+
- **template-downloader.js** → cache 명령어
|
|
55
|
+
- **template-version-manager.js** → cache 명령어
|
|
56
|
+
|
|
57
|
+
#### GitHub 통합
|
|
58
|
+
- **github-integration.js** → github 명령어
|
|
59
|
+
- **state/state-index.js** → github-integration이 사용
|
|
60
|
+
|
|
61
|
+
#### 공통 리소스
|
|
62
|
+
- **resource-loader.js** → 5개 명령어에서 사용
|
|
63
|
+
|
|
64
|
+
## ⚠️ 삭제 위험 모듈
|
|
65
|
+
|
|
66
|
+
### 동적 로드 모듈 (CLI에서 직접 참조되지 않음)
|
|
67
|
+
- **engineering-guard.js** - YOLO 템플릿에서 `import()`로 로드
|
|
68
|
+
- **state/priority-calculator.js** - github-integration에서 사용
|
|
69
|
+
- **state/task-scanner.js** - github-integration에서 사용
|
|
70
|
+
|
|
71
|
+
### 간접 의존성 모듈
|
|
72
|
+
- AI Persona 시스템의 하위 모듈들
|
|
73
|
+
- 설치 시스템의 백업/복구 모듈들
|
|
74
|
+
|
|
75
|
+
## 🚨 삭제하기 전 확인사항
|
|
76
|
+
|
|
77
|
+
1. **이 파일에서 모듈 위치 확인**
|
|
78
|
+
2. **`@warning 삭제 금지` 주석 확인**
|
|
79
|
+
3. **YOLO 전용 모듈인지 확인**
|
|
80
|
+
4. **동적 import 사용 여부 확인**
|
|
81
|
+
5. **간접 의존성 체인 확인**
|
|
82
|
+
|
|
83
|
+
## 📁 미사용 모듈 (삭제 가능)
|
|
84
|
+
|
|
85
|
+
현재 완전히 미사용되는 모듈은 없습니다. 모든 모듈이 직간접적으로 CLI 시스템에서 사용됩니다.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
**마지막 업데이트**: 2024-01-27
|
|
90
|
+
**검증 방법**: `grep -r "모듈명" src/` 으로 사용처 확인
|
package/src/cli/index.js
CHANGED
|
@@ -35,7 +35,7 @@ program
|
|
|
35
35
|
program
|
|
36
36
|
.command('install')
|
|
37
37
|
.description('Install AIWF framework')
|
|
38
|
-
.option('-f, --force', 'Force
|
|
38
|
+
.option('-f, --force', 'Force complete reinstall without prompts')
|
|
39
39
|
.action((options) => installAIWF({ ...options, debugLog: true }));
|
|
40
40
|
|
|
41
41
|
// AI Tool command
|
package/src/lib/installer.js
CHANGED
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
TOOL_DIRS,
|
|
37
37
|
TEMP_DIRS,
|
|
38
38
|
AIWF_DIRS,
|
|
39
|
+
BASE_DIRS,
|
|
39
40
|
getAllAiwfDirectories,
|
|
40
41
|
getAllClaudeMdFiles
|
|
41
42
|
} from '../utils/paths.js';
|
|
@@ -52,6 +53,61 @@ async function checkExistingInstallation() {
|
|
|
52
53
|
return flagExists;
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Check if existing project files exist
|
|
58
|
+
* @returns {Promise<{hasProject: boolean, projectFiles: string[]}>} Project status
|
|
59
|
+
*/
|
|
60
|
+
async function checkExistingProject() {
|
|
61
|
+
const projectFiles = [];
|
|
62
|
+
let hasProject = false;
|
|
63
|
+
|
|
64
|
+
// Check for key project files
|
|
65
|
+
const keyFiles = [
|
|
66
|
+
FILES.PROJECT_MANIFEST,
|
|
67
|
+
path.join(AIWF_DIRS.PROJECT_DOCS, 'README.md'),
|
|
68
|
+
path.join(AIWF_DIRS.REQUIREMENTS, 'requirements.md'),
|
|
69
|
+
path.join(AIWF_DIRS.SPRINTS, 'sprint-01.md'),
|
|
70
|
+
path.join(AIWF_DIRS.GENERAL_TASKS, 'tasks.md'),
|
|
71
|
+
path.join(AIWF_DIRS.ARCHITECTURAL_DECISIONS, 'decisions.md'),
|
|
72
|
+
path.join(AIWF_DIRS.STATE_OF_PROJECT, 'current-state.md')
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
for (const file of keyFiles) {
|
|
76
|
+
try {
|
|
77
|
+
await fs.access(file);
|
|
78
|
+
projectFiles.push(file);
|
|
79
|
+
hasProject = true;
|
|
80
|
+
} catch (error) {
|
|
81
|
+
// File doesn't exist, continue
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Check for any .md files in project directories
|
|
86
|
+
const projectDirs = [
|
|
87
|
+
AIWF_DIRS.PROJECT_DOCS,
|
|
88
|
+
AIWF_DIRS.REQUIREMENTS,
|
|
89
|
+
AIWF_DIRS.SPRINTS,
|
|
90
|
+
AIWF_DIRS.GENERAL_TASKS,
|
|
91
|
+
AIWF_DIRS.ARCHITECTURAL_DECISIONS,
|
|
92
|
+
AIWF_DIRS.STATE_OF_PROJECT
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
for (const dir of projectDirs) {
|
|
96
|
+
try {
|
|
97
|
+
const files = await fs.readdir(dir);
|
|
98
|
+
const mdFiles = files.filter(file => file.endsWith('.md'));
|
|
99
|
+
if (mdFiles.length > 0) {
|
|
100
|
+
hasProject = true;
|
|
101
|
+
projectFiles.push(...mdFiles.map(file => path.join(dir, file)));
|
|
102
|
+
}
|
|
103
|
+
} catch (error) {
|
|
104
|
+
// Directory doesn't exist, continue
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return { hasProject, projectFiles };
|
|
109
|
+
}
|
|
110
|
+
|
|
55
111
|
/**
|
|
56
112
|
* Log with spinner for debug mode
|
|
57
113
|
* @param {Object} spinner - Ora spinner instance
|
|
@@ -146,34 +202,145 @@ async function selectLanguage(options) {
|
|
|
146
202
|
* Handle existing installation
|
|
147
203
|
* @param {Object} msg - Localized messages
|
|
148
204
|
* @param {Object} options - Installation options
|
|
149
|
-
* @returns {Promise<boolean>}
|
|
205
|
+
* @returns {Promise<{continue: boolean, installType: string, preserveProject: boolean}>} Installation decision
|
|
150
206
|
*/
|
|
151
207
|
async function handleExistingInstallation(msg, options) {
|
|
208
|
+
|
|
152
209
|
if (options.force) {
|
|
153
|
-
return true;
|
|
210
|
+
return { continue: true, installType: 'reinstall', preserveProject: false };
|
|
154
211
|
}
|
|
155
212
|
|
|
156
|
-
|
|
213
|
+
// First, ask about installation type
|
|
214
|
+
const installResponse = await prompts({
|
|
157
215
|
type: 'select',
|
|
158
216
|
name: 'action',
|
|
159
217
|
message: msg.existingDetected,
|
|
160
218
|
choices: [
|
|
161
219
|
{ title: msg.updateOption, value: 'update' },
|
|
220
|
+
{ title: msg.reinstallOption, value: 'reinstall' },
|
|
162
221
|
{ title: msg.skipOption, value: 'skip' },
|
|
163
222
|
{ title: msg.cancelOption, value: 'cancel' }
|
|
164
223
|
]
|
|
165
224
|
});
|
|
166
225
|
|
|
167
|
-
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
if (installResponse.action === 'skip' || installResponse.action === 'cancel') {
|
|
168
229
|
console.log(chalk.yellow(msg.installCancelled));
|
|
169
230
|
process.exit(0);
|
|
170
231
|
}
|
|
171
232
|
|
|
172
|
-
|
|
233
|
+
let preserveProject = true; // Default to preserve
|
|
234
|
+
|
|
235
|
+
// If reinstalling, don't preserve project (complete fresh install)
|
|
236
|
+
if (installResponse.action === 'reinstall') {
|
|
237
|
+
preserveProject = false;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Backup if updating
|
|
241
|
+
if (installResponse.action === 'update') {
|
|
173
242
|
await backupCommandsAndDocs(msg);
|
|
174
243
|
}
|
|
175
244
|
|
|
176
|
-
return
|
|
245
|
+
return {
|
|
246
|
+
continue: true,
|
|
247
|
+
installType: installResponse.action,
|
|
248
|
+
preserveProject
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Backup project files
|
|
254
|
+
* @param {string[]} projectFiles - List of project files to backup
|
|
255
|
+
* @param {Object} msg - Localized messages
|
|
256
|
+
* @returns {Promise<string>} Backup directory path
|
|
257
|
+
*/
|
|
258
|
+
async function backupProjectFiles(projectFiles, msg) {
|
|
259
|
+
if (projectFiles.length === 0) {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const backupDir = path.join(os.tmpdir(), `aiwf-project-backup-${Date.now()}`);
|
|
264
|
+
await fs.mkdir(backupDir, { recursive: true });
|
|
265
|
+
|
|
266
|
+
console.log(chalk.cyan('💾 Backing up project files...'));
|
|
267
|
+
|
|
268
|
+
for (const file of projectFiles) {
|
|
269
|
+
try {
|
|
270
|
+
const relativePath = path.relative(process.cwd(), file);
|
|
271
|
+
const backupPath = path.join(backupDir, relativePath);
|
|
272
|
+
const backupDirPath = path.dirname(backupPath);
|
|
273
|
+
|
|
274
|
+
await fs.mkdir(backupDirPath, { recursive: true });
|
|
275
|
+
await fs.copyFile(file, backupPath);
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.log(chalk.yellow(`Warning: Could not backup ${file}: ${error.message}`));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
console.log(chalk.green(`✅ Project files backed up to: ${backupDir}`));
|
|
282
|
+
return backupDir;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Restore project files from backup
|
|
287
|
+
* @param {string} backupDir - Backup directory path
|
|
288
|
+
* @param {Object} msg - Localized messages
|
|
289
|
+
*/
|
|
290
|
+
async function restoreProjectFiles(backupDir, msg) {
|
|
291
|
+
if (!backupDir) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
console.log(chalk.cyan('🔄 Restoring project files...'));
|
|
296
|
+
|
|
297
|
+
try {
|
|
298
|
+
const backupFiles = await fs.readdir(backupDir, { recursive: true });
|
|
299
|
+
|
|
300
|
+
for (const file of backupFiles) {
|
|
301
|
+
const backupFilePath = path.join(backupDir, file);
|
|
302
|
+
const stat = await fs.stat(backupFilePath);
|
|
303
|
+
|
|
304
|
+
if (stat.isFile()) {
|
|
305
|
+
const targetPath = path.join(process.cwd(), file);
|
|
306
|
+
const targetDir = path.dirname(targetPath);
|
|
307
|
+
|
|
308
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
309
|
+
await fs.copyFile(backupFilePath, targetPath);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
console.log(chalk.green(msg.projectPreserved));
|
|
314
|
+
|
|
315
|
+
// Clean up backup directory
|
|
316
|
+
await fs.rm(backupDir, { recursive: true, force: true });
|
|
317
|
+
} catch (error) {
|
|
318
|
+
console.log(chalk.yellow(`Warning: Could not restore some project files: ${error.message}`));
|
|
319
|
+
console.log(chalk.yellow(`Backup preserved at: ${backupDir}`));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Remove project files
|
|
325
|
+
* @param {string[]} projectFiles - List of project files to remove
|
|
326
|
+
* @param {Object} msg - Localized messages
|
|
327
|
+
*/
|
|
328
|
+
async function removeProjectFiles(projectFiles, msg) {
|
|
329
|
+
if (projectFiles.length === 0) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
console.log(chalk.cyan('🗑️ Removing existing project files...'));
|
|
334
|
+
|
|
335
|
+
for (const file of projectFiles) {
|
|
336
|
+
try {
|
|
337
|
+
await fs.unlink(file);
|
|
338
|
+
} catch (error) {
|
|
339
|
+
// File might already be deleted, continue
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
console.log(chalk.green(msg.projectOverwritten));
|
|
177
344
|
}
|
|
178
345
|
|
|
179
346
|
/**
|
|
@@ -609,9 +776,22 @@ export async function installAIWF(options = {}) {
|
|
|
609
776
|
// Check existing installation
|
|
610
777
|
const hasExisting = await checkExistingInstallation();
|
|
611
778
|
|
|
779
|
+
let installDecision = { continue: true, installType: 'fresh', preserveProject: false };
|
|
780
|
+
let projectBackupDir = null;
|
|
781
|
+
|
|
612
782
|
if (hasExisting) {
|
|
613
|
-
|
|
614
|
-
|
|
783
|
+
|
|
784
|
+
installDecision = await handleExistingInstallation(msg, options);
|
|
785
|
+
|
|
786
|
+
if (!installDecision.continue) return;
|
|
787
|
+
|
|
788
|
+
// If reinstalling and preserving project, backup project files
|
|
789
|
+
if (installDecision.installType === 'reinstall' && installDecision.preserveProject) {
|
|
790
|
+
const { hasProject, projectFiles } = await checkExistingProject();
|
|
791
|
+
if (hasProject) {
|
|
792
|
+
projectBackupDir = await backupProjectFiles(projectFiles, msg);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
615
795
|
}
|
|
616
796
|
|
|
617
797
|
const spinner = ora(msg.fetching).start();
|
|
@@ -620,16 +800,20 @@ export async function installAIWF(options = {}) {
|
|
|
620
800
|
// Create directory structure
|
|
621
801
|
await createDirectoryStructure();
|
|
622
802
|
|
|
623
|
-
// Download manifest (fresh installs only)
|
|
624
|
-
if (!hasExisting) {
|
|
803
|
+
// Download manifest (fresh installs only or complete reinstall)
|
|
804
|
+
if (!hasExisting || installDecision.installType === 'reinstall') {
|
|
625
805
|
await downloadManifest(languagePath, spinner, msg, debugLog);
|
|
626
806
|
}
|
|
627
807
|
|
|
628
|
-
// Download templates
|
|
629
|
-
|
|
808
|
+
// Download templates (fresh installs and complete reinstall only)
|
|
809
|
+
if (!hasExisting || installDecision.installType === 'reinstall') {
|
|
810
|
+
await downloadTemplates(languagePath, spinner, msg, debugLog);
|
|
811
|
+
}
|
|
630
812
|
|
|
631
|
-
// Update documentation
|
|
632
|
-
|
|
813
|
+
// Update documentation (fresh installs and complete reinstall only)
|
|
814
|
+
if (!hasExisting || installDecision.installType === 'reinstall') {
|
|
815
|
+
await updateDocumentation(languagePath, spinner, msg, debugLog);
|
|
816
|
+
}
|
|
633
817
|
|
|
634
818
|
// Update commands
|
|
635
819
|
await updateCommands(languagePath, spinner, msg, debugLog);
|
|
@@ -637,8 +821,13 @@ export async function installAIWF(options = {}) {
|
|
|
637
821
|
// Download and process rules
|
|
638
822
|
await downloadAndProcessRules(spinner, msg, debugLog);
|
|
639
823
|
|
|
824
|
+
// Restore project files if needed
|
|
825
|
+
if (projectBackupDir) {
|
|
826
|
+
await restoreProjectFiles(projectBackupDir, msg);
|
|
827
|
+
}
|
|
828
|
+
|
|
640
829
|
// Success
|
|
641
|
-
if (hasExisting) {
|
|
830
|
+
if (hasExisting && installDecision.installType === 'update') {
|
|
642
831
|
spinner.succeed(chalk.green(msg.updateSuccess));
|
|
643
832
|
} else {
|
|
644
833
|
spinner.succeed(chalk.green(msg.installSuccess));
|
|
@@ -3,20 +3,6 @@ import fs from 'fs/promises';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
|
|
5
5
|
export const aiwfController = {
|
|
6
|
-
getFeatures: async (req: Request, res: Response, next: NextFunction) => {
|
|
7
|
-
try {
|
|
8
|
-
const ledgerPath = path.join(process.cwd(), '.aiwf', 'feature-ledger.json');
|
|
9
|
-
const ledgerData = await fs.readFile(ledgerPath, 'utf-8');
|
|
10
|
-
const ledger = JSON.parse(ledgerData);
|
|
11
|
-
|
|
12
|
-
res.json({
|
|
13
|
-
success: true,
|
|
14
|
-
data: ledger,
|
|
15
|
-
});
|
|
16
|
-
} catch (error) {
|
|
17
|
-
next(error);
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
6
|
|
|
21
7
|
getTokenUsage: async (req: Request, res: Response, next: NextFunction) => {
|
|
22
8
|
try {
|
|
@@ -3,17 +3,6 @@ import { aiwfController } from '@controllers/aiwfController';
|
|
|
3
3
|
|
|
4
4
|
const router = Router();
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* @swagger
|
|
8
|
-
* /api/aiwf/features:
|
|
9
|
-
* get:
|
|
10
|
-
* summary: Feature Ledger 조회
|
|
11
|
-
* tags: [AIWF]
|
|
12
|
-
* responses:
|
|
13
|
-
* 200:
|
|
14
|
-
* description: Feature 목록
|
|
15
|
-
*/
|
|
16
|
-
router.get('/features', aiwfController.getFeatures);
|
|
17
6
|
|
|
18
7
|
/**
|
|
19
8
|
* @swagger
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import { useState, useEffect } from 'react'
|
|
2
2
|
import { useAiwfStore } from '@/stores/aiwfStore'
|
|
3
|
-
import FeatureLedger from '@/components/aiwf/FeatureLedger'
|
|
4
3
|
import TokenUsage from '@/components/aiwf/TokenUsage'
|
|
5
4
|
import ContextStatus from '@/components/aiwf/ContextStatus'
|
|
6
5
|
|
|
7
6
|
export default function AiwfDashboard() {
|
|
8
|
-
const {
|
|
9
|
-
const [activeTab, setActiveTab] = useState('
|
|
7
|
+
const { tokenUsage, contextStatus, loadDashboardData } = useAiwfStore()
|
|
8
|
+
const [activeTab, setActiveTab] = useState('tokens')
|
|
10
9
|
|
|
11
10
|
useEffect(() => {
|
|
12
11
|
loadDashboardData()
|
|
13
12
|
}, [loadDashboardData])
|
|
14
13
|
|
|
15
14
|
const tabs = [
|
|
16
|
-
{ id: 'features', name: 'Feature Ledger', icon: '📋' },
|
|
17
15
|
{ id: 'tokens', name: '토큰 사용량', icon: '🪙' },
|
|
18
16
|
{ id: 'context', name: 'Context 상태', icon: '📊' },
|
|
19
17
|
]
|
|
@@ -51,7 +49,6 @@ export default function AiwfDashboard() {
|
|
|
51
49
|
</div>
|
|
52
50
|
|
|
53
51
|
<div className="mt-8">
|
|
54
|
-
{activeTab === 'features' && <FeatureLedger features={features} />}
|
|
55
52
|
{activeTab === 'tokens' && <TokenUsage usage={tokenUsage} />}
|
|
56
53
|
{activeTab === 'context' && <ContextStatus status={contextStatus} />}
|
|
57
54
|
</div>
|
|
@@ -37,9 +37,8 @@ export class TokenReporter {
|
|
|
37
37
|
'.aiwf/02_REQUIREMENTS',
|
|
38
38
|
'.aiwf/03_SPRINTS',
|
|
39
39
|
'.aiwf/04_GENERAL_TASKS',
|
|
40
|
-
'.aiwf/
|
|
41
|
-
'.aiwf/
|
|
42
|
-
'.aiwf/07_AI_PERSONAS'
|
|
40
|
+
'.aiwf/05_ARCHITECTURAL_DECISIONS',
|
|
41
|
+
'.aiwf/10_STATE_OF_PROJECT'
|
|
43
42
|
];
|
|
44
43
|
|
|
45
44
|
// 각 디렉토리별 토큰 수 분석
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* YOLO 모드 체크포인트 매니저
|
|
2
|
+
* Checkpoint Manager - YOLO 모드 체크포인트 매니저
|
|
3
|
+
*
|
|
4
|
+
* @usage YOLO 모드 및 CLI 명령어에서 사용
|
|
5
|
+
* @used_by src/cli/index.js, src/cli/checkpoint-cli.js
|
|
6
|
+
* @commands aiwf checkpoint, aiwf-checkpoint
|
|
7
|
+
* @warning 삭제 금지 - YOLO 시스템 핵심 구성 요소
|
|
8
|
+
*
|
|
3
9
|
* 진행 상황을 저장하고 복구할 수 있는 시스템
|
|
10
|
+
* - 세션 상태 관리
|
|
11
|
+
* - 체크포인트 생성/복구
|
|
12
|
+
* - 진행률 추적
|
|
13
|
+
* - 복구 가능한 상태 유지
|
|
4
14
|
*/
|
|
5
15
|
|
|
6
16
|
import fs from 'fs/promises';
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 오버엔지니어링 방지 가드
|
|
2
|
+
* Engineering Guard - 오버엔지니어링 방지 가드
|
|
3
|
+
*
|
|
4
|
+
* @usage YOLO 모드 전용 - 동적 import로 사용됨
|
|
5
|
+
* @used_by /claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_yolo.md
|
|
6
|
+
* @phase 프로젝트 복잡도 모니터링 (5단계)
|
|
7
|
+
* @warning 삭제 금지 - YOLO 시스템 핵심 구성 요소
|
|
8
|
+
*
|
|
3
9
|
* YOLO 모드에서 과도한 복잡성을 방지하는 유틸리티
|
|
10
|
+
* - 초기 복잡도 측정
|
|
11
|
+
* - 사전 체크 및 실시간 모니터링
|
|
12
|
+
* - 태스크 완료 후 검증
|
|
13
|
+
* - 최종 보고서 생성
|
|
4
14
|
*/
|
|
5
15
|
|
|
6
16
|
import fs from 'fs/promises';
|
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
|
|
@@ -3,20 +3,6 @@ import fs from 'fs/promises';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
|
|
5
5
|
export const aiwfController = {
|
|
6
|
-
getFeatures: async (req: Request, res: Response, next: NextFunction) => {
|
|
7
|
-
try {
|
|
8
|
-
const ledgerPath = path.join(process.cwd(), '.aiwf', 'feature-ledger.json');
|
|
9
|
-
const ledgerData = await fs.readFile(ledgerPath, 'utf-8');
|
|
10
|
-
const ledger = JSON.parse(ledgerData);
|
|
11
|
-
|
|
12
|
-
res.json({
|
|
13
|
-
success: true,
|
|
14
|
-
data: ledger,
|
|
15
|
-
});
|
|
16
|
-
} catch (error) {
|
|
17
|
-
next(error);
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
6
|
|
|
21
7
|
getTokenUsage: async (req: Request, res: Response, next: NextFunction) => {
|
|
22
8
|
try {
|
|
@@ -3,17 +3,6 @@ import { aiwfController } from '@controllers/aiwfController';
|
|
|
3
3
|
|
|
4
4
|
const router = Router();
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* @swagger
|
|
8
|
-
* /api/aiwf/features:
|
|
9
|
-
* get:
|
|
10
|
-
* summary: Feature Ledger 조회
|
|
11
|
-
* tags: [AIWF]
|
|
12
|
-
* responses:
|
|
13
|
-
* 200:
|
|
14
|
-
* description: Feature 목록
|
|
15
|
-
*/
|
|
16
|
-
router.get('/features', aiwfController.getFeatures);
|
|
17
6
|
|
|
18
7
|
/**
|
|
19
8
|
* @swagger
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import { useState, useEffect } from 'react'
|
|
2
2
|
import { useAiwfStore } from '@/stores/aiwfStore'
|
|
3
|
-
import FeatureLedger from '@/components/aiwf/FeatureLedger'
|
|
4
3
|
import TokenUsage from '@/components/aiwf/TokenUsage'
|
|
5
4
|
import ContextStatus from '@/components/aiwf/ContextStatus'
|
|
6
5
|
|
|
7
6
|
export default function AiwfDashboard() {
|
|
8
|
-
const {
|
|
9
|
-
const [activeTab, setActiveTab] = useState('
|
|
7
|
+
const { tokenUsage, contextStatus, loadDashboardData } = useAiwfStore()
|
|
8
|
+
const [activeTab, setActiveTab] = useState('tokens')
|
|
10
9
|
|
|
11
10
|
useEffect(() => {
|
|
12
11
|
loadDashboardData()
|
|
13
12
|
}, [loadDashboardData])
|
|
14
13
|
|
|
15
14
|
const tabs = [
|
|
16
|
-
{ id: 'features', name: 'Feature Ledger', icon: '📋' },
|
|
17
15
|
{ id: 'tokens', name: '토큰 사용량', icon: '🪙' },
|
|
18
16
|
{ id: 'context', name: 'Context 상태', icon: '📊' },
|
|
19
17
|
]
|
|
@@ -51,7 +49,6 @@ export default function AiwfDashboard() {
|
|
|
51
49
|
</div>
|
|
52
50
|
|
|
53
51
|
<div className="mt-8">
|
|
54
|
-
{activeTab === 'features' && <FeatureLedger features={features} />}
|
|
55
52
|
{activeTab === 'tokens' && <TokenUsage usage={tokenUsage} />}
|
|
56
53
|
{activeTab === 'context' && <ContextStatus status={contextStatus} />}
|
|
57
54
|
</div>
|