aiwf 0.3.18 → 0.3.20
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 +84 -0
- package/README.md +87 -0
- package/docs/CODE_CLEANUP_GUIDE.ko.md +415 -0
- package/docs/CODE_CLEANUP_GUIDE.md +415 -0
- package/docs/VALIDATOR_API.ko.md +324 -0
- package/docs/VALIDATOR_API.md +324 -0
- package/package.json +3 -4
- package/src/cli/index.js +134 -335
- package/src/lib/backup-manager.js +4 -3
- package/src/lib/installer.js +126 -3
- package/src/lib/validator.js +78 -313
- package/src/utils/messages.js +16 -2
- package/src/utils/paths.js +1 -20
package/src/cli/index.js
CHANGED
|
@@ -4,16 +4,9 @@ import { program } from 'commander';
|
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import { installAIWF } from '../lib/installer.js';
|
|
6
6
|
import AIToolCommand from '../commands/ai-tool.js';
|
|
7
|
-
import PersonaCommand from '../commands/persona.js';
|
|
8
|
-
import { CacheCLI } from './cache-cli.js';
|
|
9
7
|
import { addTaskToSprint } from '../commands/sprint-task.js';
|
|
10
|
-
import CompressCommand from '../commands/compress.js';
|
|
11
|
-
import TokenCommand from '../commands/token.js';
|
|
12
|
-
import EvaluateCommand from '../commands/evaluate.js';
|
|
13
|
-
import { createProject } from '../commands/create-project.js';
|
|
14
8
|
import StateCommand from '../commands/state.js';
|
|
15
9
|
import { createIndependentSprint } from '../commands/sprint-independent.js';
|
|
16
|
-
import { CheckpointManager } from '../utils/checkpoint-manager.js';
|
|
17
10
|
import { createYoloConfig, createInteractiveYoloConfig, showYoloConfig } from '../commands/yolo-config.js';
|
|
18
11
|
|
|
19
12
|
// Parse version from package.json
|
|
@@ -50,94 +43,7 @@ program
|
|
|
50
43
|
});
|
|
51
44
|
|
|
52
45
|
// Cache management commands
|
|
53
|
-
|
|
54
|
-
cache.description('Manage offline template cache');
|
|
55
|
-
|
|
56
|
-
cache
|
|
57
|
-
.command('download')
|
|
58
|
-
.description('Download templates for offline use')
|
|
59
|
-
.option('--all', 'Download all templates')
|
|
60
|
-
.option('--type <type>', 'Download specific type (ai-tools, projects)')
|
|
61
|
-
.action(async (options) => {
|
|
62
|
-
const cacheCLI = new CacheCLI();
|
|
63
|
-
try {
|
|
64
|
-
await cacheCLI.init();
|
|
65
|
-
await cacheCLI.downloadCommand(options);
|
|
66
|
-
} catch (error) {
|
|
67
|
-
console.error(chalk.red('Cache download failed:', error.message));
|
|
68
|
-
process.exit(1);
|
|
69
|
-
} finally {
|
|
70
|
-
await cacheCLI.cleanup();
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
cache
|
|
75
|
-
.command('list')
|
|
76
|
-
.description('List cached templates')
|
|
77
|
-
.option('--type <type>', 'Filter by type (ai-tools, projects)')
|
|
78
|
-
.action(async (options) => {
|
|
79
|
-
const cacheCLI = new CacheCLI();
|
|
80
|
-
try {
|
|
81
|
-
await cacheCLI.init();
|
|
82
|
-
await cacheCLI.listCommand(options);
|
|
83
|
-
} catch (error) {
|
|
84
|
-
console.error(chalk.red('Cache list failed:', error.message));
|
|
85
|
-
process.exit(1);
|
|
86
|
-
} finally {
|
|
87
|
-
await cacheCLI.cleanup();
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
cache
|
|
92
|
-
.command('clean')
|
|
93
|
-
.description('Clean up cached templates')
|
|
94
|
-
.option('--all', 'Clear all cached templates')
|
|
95
|
-
.option('--max-age <days>', 'Maximum age in days (default: 7)', '7')
|
|
96
|
-
.action(async (options) => {
|
|
97
|
-
const cacheCLI = new CacheCLI();
|
|
98
|
-
try {
|
|
99
|
-
await cacheCLI.init();
|
|
100
|
-
await cacheCLI.cleanCommand(options);
|
|
101
|
-
} catch (error) {
|
|
102
|
-
console.error(chalk.red('Cache clean failed:', error.message));
|
|
103
|
-
process.exit(1);
|
|
104
|
-
} finally {
|
|
105
|
-
await cacheCLI.cleanup();
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
cache
|
|
110
|
-
.command('update')
|
|
111
|
-
.description('Check for template updates')
|
|
112
|
-
.option('--install', 'Install available updates')
|
|
113
|
-
.action(async (options) => {
|
|
114
|
-
const cacheCLI = new CacheCLI();
|
|
115
|
-
try {
|
|
116
|
-
await cacheCLI.init();
|
|
117
|
-
await cacheCLI.updateCommand(options);
|
|
118
|
-
} catch (error) {
|
|
119
|
-
console.error(chalk.red('Cache update failed:', error.message));
|
|
120
|
-
process.exit(1);
|
|
121
|
-
} finally {
|
|
122
|
-
await cacheCLI.cleanup();
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
cache
|
|
127
|
-
.command('status')
|
|
128
|
-
.description('Show cache system status')
|
|
129
|
-
.action(async () => {
|
|
130
|
-
const cacheCLI = new CacheCLI();
|
|
131
|
-
try {
|
|
132
|
-
await cacheCLI.init();
|
|
133
|
-
await cacheCLI.statusCommand();
|
|
134
|
-
} catch (error) {
|
|
135
|
-
console.error(chalk.red('Cache status failed:', error.message));
|
|
136
|
-
process.exit(1);
|
|
137
|
-
} finally {
|
|
138
|
-
await cacheCLI.cleanup();
|
|
139
|
-
}
|
|
140
|
-
});
|
|
46
|
+
// (removed) cache command group
|
|
141
47
|
|
|
142
48
|
// Language management commands
|
|
143
49
|
const lang = program.command('lang');
|
|
@@ -171,45 +77,7 @@ lang
|
|
|
171
77
|
await resetLanguage();
|
|
172
78
|
});
|
|
173
79
|
|
|
174
|
-
//
|
|
175
|
-
const persona = program.command('persona');
|
|
176
|
-
persona.description('Manage AI personas / AI 페르소나 관리');
|
|
177
|
-
|
|
178
|
-
persona
|
|
179
|
-
.command('status')
|
|
180
|
-
.alias('s')
|
|
181
|
-
.description('Show current persona status / 현재 페르소나 상태 표시')
|
|
182
|
-
.action(async () => {
|
|
183
|
-
const personaCmd = new PersonaCommand();
|
|
184
|
-
await personaCmd.showStatus();
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
persona
|
|
188
|
-
.command('list')
|
|
189
|
-
.alias('ls')
|
|
190
|
-
.description('List available personas / 사용 가능한 페르소나 목록')
|
|
191
|
-
.action(async () => {
|
|
192
|
-
const personaCmd = new PersonaCommand();
|
|
193
|
-
await personaCmd.listPersonas();
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
persona
|
|
197
|
-
.command('set <persona-name>')
|
|
198
|
-
.alias('switch')
|
|
199
|
-
.description('Switch to specific persona / 특정 페르소나로 전환')
|
|
200
|
-
.action(async (personaName) => {
|
|
201
|
-
const personaCmd = new PersonaCommand();
|
|
202
|
-
await personaCmd.setPersona(personaName);
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
persona
|
|
206
|
-
.command('reset')
|
|
207
|
-
.alias('r')
|
|
208
|
-
.description('Reset to default persona / 기본 페르소나로 리셋')
|
|
209
|
-
.action(async () => {
|
|
210
|
-
const personaCmd = new PersonaCommand();
|
|
211
|
-
await personaCmd.resetPersona();
|
|
212
|
-
});
|
|
80
|
+
// (removed) persona command group
|
|
213
81
|
|
|
214
82
|
// Sprint task management command
|
|
215
83
|
program
|
|
@@ -225,125 +93,14 @@ program
|
|
|
225
93
|
}
|
|
226
94
|
});
|
|
227
95
|
|
|
228
|
-
//
|
|
229
|
-
program
|
|
230
|
-
.command('create-project')
|
|
231
|
-
.alias('create')
|
|
232
|
-
.description('Create a new AIWF project / 새 AIWF 프로젝트 생성')
|
|
233
|
-
.action(async () => {
|
|
234
|
-
try {
|
|
235
|
-
await createProject();
|
|
236
|
-
} catch (error) {
|
|
237
|
-
console.error(chalk.red(`오류: ${error.message}`));
|
|
238
|
-
process.exit(1);
|
|
239
|
-
}
|
|
240
|
-
});
|
|
96
|
+
// (removed) create-project command
|
|
241
97
|
|
|
242
|
-
//
|
|
243
|
-
program
|
|
244
|
-
.command('compress [mode] [path]')
|
|
245
|
-
.description('Compress context for token optimization / 토큰 최적화를 위한 컨텍스트 압축')
|
|
246
|
-
.option('--persona, -p', 'Enable persona-aware compression / 페르소나 인식 압축 활성화')
|
|
247
|
-
.action(async (mode, path, options) => {
|
|
248
|
-
const compressCmd = new CompressCommand();
|
|
249
|
-
const args = [];
|
|
250
|
-
if (mode) args.push(mode);
|
|
251
|
-
if (path) args.push(path);
|
|
252
|
-
if (options.persona) args.push('--persona');
|
|
253
|
-
await compressCmd.execute(args);
|
|
254
|
-
});
|
|
98
|
+
// (removed) compress command
|
|
255
99
|
|
|
256
100
|
|
|
257
|
-
//
|
|
258
|
-
const token = program.command('token');
|
|
259
|
-
token.description('Manage token usage tracking / 토큰 사용량 추적 관리');
|
|
101
|
+
// (removed) token command group
|
|
260
102
|
|
|
261
|
-
|
|
262
|
-
.command('status')
|
|
263
|
-
.alias('s')
|
|
264
|
-
.description('Show token usage status / 토큰 사용 현황 표시')
|
|
265
|
-
.action(async () => {
|
|
266
|
-
const tokenCmd = new TokenCommand();
|
|
267
|
-
await tokenCmd.execute(['status']);
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
token
|
|
271
|
-
.command('report [period]')
|
|
272
|
-
.description('Generate usage report / 사용 리포트 생성')
|
|
273
|
-
.action(async (period) => {
|
|
274
|
-
const tokenCmd = new TokenCommand();
|
|
275
|
-
const args = ['report'];
|
|
276
|
-
if (period) args.push(period);
|
|
277
|
-
await tokenCmd.execute(args);
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
token
|
|
281
|
-
.command('track <input> <output>')
|
|
282
|
-
.description('Manually track token usage / 토큰 사용량 수동 기록')
|
|
283
|
-
.action(async (input, output) => {
|
|
284
|
-
const tokenCmd = new TokenCommand();
|
|
285
|
-
await tokenCmd.execute(['track', input, output]);
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
token
|
|
289
|
-
.command('limit <type> <value>')
|
|
290
|
-
.description('Set usage limits / 사용 한도 설정')
|
|
291
|
-
.action(async (type, value) => {
|
|
292
|
-
const tokenCmd = new TokenCommand();
|
|
293
|
-
await tokenCmd.execute(['limit', type, value]);
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
token
|
|
297
|
-
.command('reset')
|
|
298
|
-
.description('Reset tracking data / 추적 데이터 초기화')
|
|
299
|
-
.action(async () => {
|
|
300
|
-
const tokenCmd = new TokenCommand();
|
|
301
|
-
await tokenCmd.execute(['reset']);
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
// Evaluation commands
|
|
305
|
-
const evaluate = program.command('evaluate');
|
|
306
|
-
evaluate.description('Evaluate AI responses and code quality / AI 응답 및 코드 품질 평가');
|
|
307
|
-
|
|
308
|
-
evaluate
|
|
309
|
-
.command('response <file>')
|
|
310
|
-
.description('Evaluate AI response quality / AI 응답 품질 평가')
|
|
311
|
-
.action(async (file) => {
|
|
312
|
-
const evaluateCmd = new EvaluateCommand();
|
|
313
|
-
await evaluateCmd.execute(['response', file]);
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
evaluate
|
|
317
|
-
.command('code <file>')
|
|
318
|
-
.description('Evaluate code quality / 코드 품질 평가')
|
|
319
|
-
.action(async (file) => {
|
|
320
|
-
const evaluateCmd = new EvaluateCommand();
|
|
321
|
-
await evaluateCmd.execute(['code', file]);
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
evaluate
|
|
325
|
-
.command('persona <file> <persona>')
|
|
326
|
-
.description('Evaluate persona appropriateness / 페르소나 적합성 평가')
|
|
327
|
-
.action(async (file, persona) => {
|
|
328
|
-
const evaluateCmd = new EvaluateCommand();
|
|
329
|
-
await evaluateCmd.execute(['persona', file, persona]);
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
evaluate
|
|
333
|
-
.command('report')
|
|
334
|
-
.description('Generate evaluation report / 평가 리포트 생성')
|
|
335
|
-
.action(async () => {
|
|
336
|
-
const evaluateCmd = new EvaluateCommand();
|
|
337
|
-
await evaluateCmd.execute(['report']);
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
evaluate
|
|
341
|
-
.command('criteria')
|
|
342
|
-
.description('Show evaluation criteria / 평가 기준 표시')
|
|
343
|
-
.action(async () => {
|
|
344
|
-
const evaluateCmd = new EvaluateCommand();
|
|
345
|
-
await evaluateCmd.execute(['criteria']);
|
|
346
|
-
});
|
|
103
|
+
// (removed) evaluate command group
|
|
347
104
|
|
|
348
105
|
// State management commands
|
|
349
106
|
const state = program.command('state');
|
|
@@ -503,131 +260,173 @@ yoloConfig
|
|
|
503
260
|
}
|
|
504
261
|
});
|
|
505
262
|
|
|
506
|
-
//
|
|
507
|
-
const checkpoint = program.command('checkpoint');
|
|
508
|
-
checkpoint.description('YOLO checkpoint management / YOLO 체크포인트 관리');
|
|
263
|
+
// (removed) checkpoint command group
|
|
509
264
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
.
|
|
265
|
+
// Engineering Guard commands (오버엔지니어링 방지)
|
|
266
|
+
const guard = program.command('guard');
|
|
267
|
+
guard.description('Engineering guard for overengineering prevention / 오버엔지니어링 방지 가드');
|
|
268
|
+
|
|
269
|
+
guard
|
|
270
|
+
.command('check [path]')
|
|
271
|
+
.description('Check project complexity / 프로젝트 복잡도 검사')
|
|
272
|
+
.option('--config <path>', 'YOLO config file path / YOLO 설정 파일 경로', '.aiwf/yolo-config.yaml')
|
|
273
|
+
.action(async (targetPath, options) => {
|
|
516
274
|
try {
|
|
517
|
-
|
|
518
|
-
const
|
|
519
|
-
const path = await import('path');
|
|
520
|
-
let currentDir = process.cwd();
|
|
275
|
+
const { EngineeringGuard } = await import('../utils/engineering-guard.js');
|
|
276
|
+
const guard = new EngineeringGuard();
|
|
521
277
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
await fs.access(path.join(currentDir, '.aiwf'));
|
|
525
|
-
break;
|
|
526
|
-
} catch {
|
|
527
|
-
currentDir = path.dirname(currentDir);
|
|
528
|
-
}
|
|
529
|
-
}
|
|
278
|
+
// 설정 파일 로드
|
|
279
|
+
await guard.loadConfig(options.config);
|
|
530
280
|
|
|
531
|
-
const
|
|
532
|
-
|
|
281
|
+
const checkPath = targetPath || process.cwd();
|
|
282
|
+
console.log(chalk.blue(`🔍 복잡도 검사 중: ${checkPath}`));
|
|
283
|
+
console.log('');
|
|
284
|
+
|
|
285
|
+
const report = await guard.checkProject(checkPath);
|
|
533
286
|
|
|
534
|
-
|
|
287
|
+
// 결과 출력
|
|
288
|
+
console.log(chalk.bold('📊 복잡도 분석 결과:'));
|
|
289
|
+
console.log(` 총 위반사항: ${chalk.yellow(report.summary.total_violations)}`);
|
|
290
|
+
console.log(` 높은 심각도: ${chalk.red(report.summary.high_severity)}`);
|
|
291
|
+
console.log(` 중간 심각도: ${chalk.yellow(report.summary.medium_severity)}`);
|
|
292
|
+
console.log(` 경고사항: ${chalk.blue(report.summary.warnings)}`);
|
|
535
293
|
console.log('');
|
|
536
294
|
|
|
537
|
-
if (
|
|
538
|
-
console.log(chalk.
|
|
539
|
-
|
|
295
|
+
if (report.violations && report.violations.length > 0) {
|
|
296
|
+
console.log(chalk.bold('🚨 위반사항:'));
|
|
297
|
+
for (const violation of report.violations.slice(0, 10)) {
|
|
298
|
+
const icon = violation.severity === 'high' ? '❌' :
|
|
299
|
+
violation.severity === 'medium' ? '⚠️' : '💡';
|
|
300
|
+
console.log(` ${icon} ${chalk.cyan(violation.type)}: ${violation.file || violation.message}`);
|
|
301
|
+
if (violation.details) {
|
|
302
|
+
console.log(` ${chalk.gray(violation.details)}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
console.log('');
|
|
540
306
|
}
|
|
541
307
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
cp.type === 'task_complete' ? '✅' : '🔄';
|
|
548
|
-
console.log(`${typeIcon} ${chalk.cyan(cp.id)} - ${chalk.yellow(cp.type)}`);
|
|
549
|
-
console.log(` 태스크: ${chalk.blue(cp.tasks_completed)}개 완료`);
|
|
308
|
+
if (report.recommendations && report.recommendations.length > 0) {
|
|
309
|
+
console.log(chalk.bold('💡 권장사항:'));
|
|
310
|
+
for (const rec of report.recommendations) {
|
|
311
|
+
console.log(` • ${chalk.green(rec)}`);
|
|
312
|
+
}
|
|
550
313
|
console.log('');
|
|
551
314
|
}
|
|
315
|
+
|
|
316
|
+
// 통과/실패 판정
|
|
317
|
+
if (report.passed) {
|
|
318
|
+
console.log(chalk.green('✅ 복잡도 기준 통과'));
|
|
319
|
+
} else {
|
|
320
|
+
console.log(chalk.red('❌ 복잡도 기준 초과 - 리팩토링 필요'));
|
|
321
|
+
}
|
|
322
|
+
|
|
552
323
|
} catch (error) {
|
|
553
|
-
console.error(chalk.red('❌
|
|
324
|
+
console.error(chalk.red('❌ 복잡도 검사 실패:'), error.message);
|
|
554
325
|
process.exit(1);
|
|
555
326
|
}
|
|
556
327
|
});
|
|
557
328
|
|
|
558
|
-
|
|
559
|
-
.command('
|
|
560
|
-
.description('
|
|
561
|
-
.action(async (
|
|
329
|
+
guard
|
|
330
|
+
.command('quick [path]')
|
|
331
|
+
.description('Quick complexity check / 빠른 복잡도 체크')
|
|
332
|
+
.action(async (targetPath) => {
|
|
562
333
|
try {
|
|
563
|
-
const
|
|
564
|
-
const path = await import('path');
|
|
565
|
-
let currentDir = process.cwd();
|
|
566
|
-
|
|
567
|
-
while (currentDir !== path.parse(currentDir).root) {
|
|
568
|
-
try {
|
|
569
|
-
await fs.access(path.join(currentDir, '.aiwf'));
|
|
570
|
-
break;
|
|
571
|
-
} catch {
|
|
572
|
-
currentDir = path.dirname(currentDir);
|
|
573
|
-
}
|
|
574
|
-
}
|
|
334
|
+
const { quickCheck } = await import('../utils/engineering-guard.js');
|
|
575
335
|
|
|
576
|
-
const
|
|
577
|
-
|
|
336
|
+
const checkPath = targetPath || process.cwd();
|
|
337
|
+
console.log(chalk.blue(`⚡ 빠른 복잡도 체크: ${checkPath}`));
|
|
578
338
|
|
|
579
|
-
|
|
339
|
+
const report = await quickCheck(checkPath);
|
|
580
340
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
console.log(
|
|
586
|
-
console.log(` 스프린트: ${chalk.blue(result.checkpoint.state_snapshot.sprint_id || 'N/A')}`);
|
|
587
|
-
console.log('');
|
|
588
|
-
console.log(chalk.green('🚀 복구 완료! YOLO 모드를 다시 실행할 수 있습니다.'));
|
|
341
|
+
if (report.summary.high_severity > 0) {
|
|
342
|
+
console.log(chalk.red('⚠️ 오버엔지니어링 위험 감지!'));
|
|
343
|
+
console.log('권장사항:', report.recommendations.join(', '));
|
|
344
|
+
} else {
|
|
345
|
+
console.log(chalk.green('✅ 복잡도 양호'));
|
|
589
346
|
}
|
|
347
|
+
|
|
590
348
|
} catch (error) {
|
|
591
|
-
console.error(chalk.red('❌
|
|
349
|
+
console.error(chalk.red('❌ 빠른 체크 실패:'), error.message);
|
|
592
350
|
process.exit(1);
|
|
593
351
|
}
|
|
594
352
|
});
|
|
595
353
|
|
|
596
|
-
|
|
597
|
-
.command('
|
|
598
|
-
.description('
|
|
354
|
+
guard
|
|
355
|
+
.command('init')
|
|
356
|
+
.description('Initialize YOLO config with guard settings / YOLO 설정 초기화')
|
|
599
357
|
.action(async () => {
|
|
600
358
|
try {
|
|
601
359
|
const fs = await import('fs/promises');
|
|
602
360
|
const path = await import('path');
|
|
603
|
-
|
|
361
|
+
const yaml = await import('js-yaml');
|
|
604
362
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
363
|
+
const configPath = path.join(process.cwd(), '.aiwf', 'yolo-config.yaml');
|
|
364
|
+
|
|
365
|
+
// 기본 설정 생성
|
|
366
|
+
const defaultConfig = {
|
|
367
|
+
engineering_level: 'minimal',
|
|
368
|
+
focus_rules: ['requirement_first', 'simple_solution', 'no_gold_plating', 'stay_on_track'],
|
|
369
|
+
overengineering_prevention: {
|
|
370
|
+
max_file_lines: 300,
|
|
371
|
+
max_function_lines: 50,
|
|
372
|
+
max_nesting_depth: 4,
|
|
373
|
+
max_abstraction_layers: 3,
|
|
374
|
+
limit_design_patterns: true,
|
|
375
|
+
no_future_proofing: true,
|
|
376
|
+
enforce_yagni: true
|
|
611
377
|
}
|
|
612
|
-
}
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
// .aiwf 디렉토리 생성
|
|
381
|
+
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
|
382
|
+
|
|
383
|
+
// 설정 파일 쓰기
|
|
384
|
+
await fs.writeFile(configPath, yaml.dump(defaultConfig), 'utf-8');
|
|
385
|
+
|
|
386
|
+
console.log(chalk.green('✅ YOLO 설정 파일 생성 완료!'));
|
|
387
|
+
console.log(` 경로: ${chalk.cyan(configPath)}`);
|
|
388
|
+
console.log('');
|
|
389
|
+
console.log(chalk.bold('🛡️ 오버엔지니어링 방지 설정:'));
|
|
390
|
+
console.log(` 파일 크기 제한: ${chalk.yellow('300')}줄`);
|
|
391
|
+
console.log(` 함수 크기 제한: ${chalk.yellow('50')}줄`);
|
|
392
|
+
console.log(` 중첩 깊이 제한: ${chalk.yellow('4')}레벨`);
|
|
393
|
+
console.log(` YAGNI 원칙: ${chalk.green('적용')}`);
|
|
394
|
+
|
|
395
|
+
} catch (error) {
|
|
396
|
+
console.error(chalk.red('❌ 설정 초기화 실패:'), error.message);
|
|
397
|
+
process.exit(1);
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
guard
|
|
402
|
+
.command('feedback [area]')
|
|
403
|
+
.description('Get engineering feedback for area / 특정 영역 피드백 받기')
|
|
404
|
+
.action(async (area) => {
|
|
405
|
+
try {
|
|
406
|
+
const { EngineeringGuard } = await import('../utils/engineering-guard.js');
|
|
407
|
+
const guard = new EngineeringGuard();
|
|
613
408
|
|
|
614
|
-
|
|
615
|
-
await
|
|
409
|
+
// 설정 파일 로드 시도
|
|
410
|
+
await guard.loadConfig('.aiwf/yolo-config.yaml');
|
|
616
411
|
|
|
617
|
-
|
|
412
|
+
const targetArea = area || 'current_task_area';
|
|
413
|
+
console.log(chalk.blue(`💡 엔지니어링 피드백 제공: ${targetArea}`));
|
|
618
414
|
console.log('');
|
|
619
415
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
416
|
+
const feedback = await guard.provideFeedback(targetArea);
|
|
417
|
+
|
|
418
|
+
if (feedback && feedback.length > 0) {
|
|
419
|
+
for (const item of feedback) {
|
|
420
|
+
const icon = item.level === 'error' ? '❌' :
|
|
421
|
+
item.level === 'warning' ? '⚠️' : '💡';
|
|
422
|
+
console.log(`${icon} ${item.message}`);
|
|
423
|
+
}
|
|
424
|
+
} else {
|
|
425
|
+
console.log(chalk.green('✅ 현재 영역은 복잡도 기준을 만족합니다.'));
|
|
623
426
|
}
|
|
624
427
|
|
|
625
|
-
console.log(`세션 ID: ${chalk.cyan(manager.currentState.session_id)}`);
|
|
626
|
-
console.log(`스프린트: ${chalk.blue(manager.currentState.sprint_id || 'N/A')}`);
|
|
627
|
-
console.log(`완료된 태스크: ${chalk.green(manager.currentState.completed_tasks.length)}개`);
|
|
628
|
-
console.log(`체크포인트: ${chalk.blue(manager.currentState.checkpoints.length)}개`);
|
|
629
428
|
} catch (error) {
|
|
630
|
-
console.error(chalk.red('❌
|
|
429
|
+
console.error(chalk.red('❌ 피드백 생성 실패:'), error.message);
|
|
631
430
|
process.exit(1);
|
|
632
431
|
}
|
|
633
432
|
});
|
|
@@ -5,8 +5,7 @@ import chalk from 'chalk';
|
|
|
5
5
|
import {
|
|
6
6
|
TOOL_DIRS,
|
|
7
7
|
AIWF_DIRS,
|
|
8
|
-
FILES
|
|
9
|
-
getBackupDirName as getBackupDirNamePath
|
|
8
|
+
FILES
|
|
10
9
|
} from '../utils/paths.js';
|
|
11
10
|
|
|
12
11
|
let BACKUP_DIR = null;
|
|
@@ -16,7 +15,9 @@ let BACKUP_DIR = null;
|
|
|
16
15
|
* @returns {string} Backup directory name
|
|
17
16
|
*/
|
|
18
17
|
function getBackupDirName() {
|
|
19
|
-
|
|
18
|
+
const now = new Date();
|
|
19
|
+
const timestamp = now.toISOString().replace(/[:.]/g, '-').slice(0, -5);
|
|
20
|
+
return `backup-${timestamp}`;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
/**
|