aiwf 0.3.19 → 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/package.json +3 -5
- package/src/cli/index.js +7 -546
- package/ai-tools/README.md +0 -105
- package/ai-tools/augment/README.md +0 -371
- package/ai-tools/augment/config.json +0 -30
- package/ai-tools/augment/template/.augment/aiwf-integration.md +0 -387
- package/ai-tools/augment/template/.augment/augment.yaml +0 -347
- package/ai-tools/augment/template/augment.config.json +0 -64
- package/ai-tools/claude-code/README.md +0 -151
- package/ai-tools/claude-code/config.json +0 -28
- package/ai-tools/claude-code/template/CLAUDE.md +0 -91
- package/ai-tools/cursor/README.md +0 -314
- package/ai-tools/cursor/config.json +0 -29
- package/ai-tools/cursor/template/.cursorrules +0 -362
- package/ai-tools/github-copilot/README.md +0 -195
- package/ai-tools/github-copilot/config.json +0 -24
- package/ai-tools/github-copilot/template/.github/copilot-instructions.md +0 -202
- package/ai-tools/windsurf/README.md +0 -355
- package/ai-tools/windsurf/config.json +0 -29
- package/ai-tools/windsurf/template/.windsurf/aiwf-rules.md +0 -260
- package/ai-tools/windsurf/template/.windsurf/windsurf.config.js +0 -312
- package/ai-tools/windsurf/template/windsurf.config.json +0 -63
package/package.json
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiwf",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.20",
|
|
4
4
|
"description": "AI Workflow Framework for Claude Code with multi-language support (Korean/English)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"aiwf": "./src/cli/index.js",
|
|
9
9
|
"aiwf-lang": "./src/cli/language-cli.js",
|
|
10
|
-
"aiwf-sprint": "./src/cli/sprint-cli.js"
|
|
11
|
-
"aiwf-checkpoint": "./src/cli/checkpoint-cli.js",
|
|
12
|
-
"aiwf-cache": "./src/cli/cache-cli.js"
|
|
10
|
+
"aiwf-sprint": "./src/cli/sprint-cli.js"
|
|
13
11
|
},
|
|
14
12
|
"scripts": {
|
|
15
13
|
"test": "node --experimental-vm-modules node_modules/.bin/jest",
|
|
@@ -133,4 +131,4 @@
|
|
|
133
131
|
"utils/engineering-guard.js"
|
|
134
132
|
]
|
|
135
133
|
}
|
|
136
|
-
}
|
|
134
|
+
}
|
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
|
-
});
|
|
241
|
-
|
|
242
|
-
// Context compression command
|
|
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
|
-
});
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
// Token tracking commands
|
|
258
|
-
const token = program.command('token');
|
|
259
|
-
token.description('Manage token usage tracking / 토큰 사용량 추적 관리');
|
|
260
|
-
|
|
261
|
-
token
|
|
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
|
-
});
|
|
96
|
+
// (removed) create-project command
|
|
303
97
|
|
|
304
|
-
//
|
|
305
|
-
const evaluate = program.command('evaluate');
|
|
306
|
-
evaluate.description('Evaluate AI responses and code quality / AI 응답 및 코드 품질 평가');
|
|
98
|
+
// (removed) compress command
|
|
307
99
|
|
|
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
100
|
|
|
316
|
-
|
|
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
|
-
});
|
|
101
|
+
// (removed) token command group
|
|
323
102
|
|
|
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,303 +260,7 @@ yoloConfig
|
|
|
503
260
|
}
|
|
504
261
|
});
|
|
505
262
|
|
|
506
|
-
//
|
|
507
|
-
const checkpoint = program.command('checkpoint');
|
|
508
|
-
checkpoint.description('YOLO checkpoint management / YOLO 체크포인트 관리');
|
|
509
|
-
|
|
510
|
-
checkpoint
|
|
511
|
-
.command('list')
|
|
512
|
-
.alias('ls')
|
|
513
|
-
.description('List available checkpoints / 사용 가능한 체크포인트 목록')
|
|
514
|
-
.option('--limit <n>', 'Limit number of checkpoints / 체크포인트 수 제한', '10')
|
|
515
|
-
.action(async (options) => {
|
|
516
|
-
try {
|
|
517
|
-
// 프로젝트 루트 찾기
|
|
518
|
-
const fs = await import('fs/promises');
|
|
519
|
-
const path = await import('path');
|
|
520
|
-
let currentDir = process.cwd();
|
|
521
|
-
|
|
522
|
-
while (currentDir !== path.parse(currentDir).root) {
|
|
523
|
-
try {
|
|
524
|
-
await fs.access(path.join(currentDir, '.aiwf'));
|
|
525
|
-
break;
|
|
526
|
-
} catch {
|
|
527
|
-
currentDir = path.dirname(currentDir);
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
const manager = new CheckpointManager(currentDir);
|
|
532
|
-
const checkpoints = await manager.listCheckpoints();
|
|
533
|
-
|
|
534
|
-
console.log(chalk.bold('📊 체크포인트 목록:'));
|
|
535
|
-
console.log('');
|
|
536
|
-
|
|
537
|
-
if (checkpoints.length === 0) {
|
|
538
|
-
console.log(chalk.yellow('📭 체크포인트가 없습니다.'));
|
|
539
|
-
return;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
const limit = parseInt(options.limit);
|
|
543
|
-
const limitedCheckpoints = checkpoints.slice(0, limit);
|
|
544
|
-
|
|
545
|
-
for (const cp of limitedCheckpoints) {
|
|
546
|
-
const typeIcon = cp.type === 'session_start' ? '🚀' :
|
|
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)}개 완료`);
|
|
550
|
-
console.log('');
|
|
551
|
-
}
|
|
552
|
-
} catch (error) {
|
|
553
|
-
console.error(chalk.red('❌ 체크포인트 목록 조회 실패:'), error.message);
|
|
554
|
-
process.exit(1);
|
|
555
|
-
}
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
checkpoint
|
|
559
|
-
.command('add [type]')
|
|
560
|
-
.alias('create')
|
|
561
|
-
.description('Create a checkpoint / 체크포인트 생성')
|
|
562
|
-
.option('-m, --message <text>', 'Description for the checkpoint / 체크포인트 설명')
|
|
563
|
-
.option('--meta <json>', 'Additional metadata as JSON / 추가 메타데이터(JSON)')
|
|
564
|
-
.option('--cleanup <n>', 'Keep only last N checkpoints after creating / 생성 후 최근 N개만 보존')
|
|
565
|
-
.action(async (type, options) => {
|
|
566
|
-
try {
|
|
567
|
-
const fs = await import('fs/promises');
|
|
568
|
-
const path = await import('path');
|
|
569
|
-
let currentDir = process.cwd();
|
|
570
|
-
|
|
571
|
-
// 프로젝트 루트 탐색 (.aiwf 기준)
|
|
572
|
-
while (currentDir !== path.parse(currentDir).root) {
|
|
573
|
-
try {
|
|
574
|
-
await fs.access(path.join(currentDir, '.aiwf'));
|
|
575
|
-
break;
|
|
576
|
-
} catch {
|
|
577
|
-
currentDir = path.dirname(currentDir);
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
const manager = new CheckpointManager(currentDir);
|
|
582
|
-
await manager.initialize();
|
|
583
|
-
|
|
584
|
-
// 메타데이터 구성
|
|
585
|
-
const metadata = {};
|
|
586
|
-
if (options.message) metadata.message = options.message;
|
|
587
|
-
if (options.meta) {
|
|
588
|
-
try {
|
|
589
|
-
const parsed = JSON.parse(options.meta);
|
|
590
|
-
Object.assign(metadata, parsed);
|
|
591
|
-
} catch (e) {
|
|
592
|
-
console.error(chalk.red('❌ --meta 값이 올바른 JSON 형식이 아닙니다.'));
|
|
593
|
-
process.exit(1);
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
const cpType = type || 'manual';
|
|
598
|
-
const checkpointId = await manager.createCheckpoint(cpType, metadata);
|
|
599
|
-
|
|
600
|
-
console.log(chalk.green('✅ 체크포인트 생성 완료!'));
|
|
601
|
-
console.log(` ID: ${chalk.cyan(checkpointId)} 유형: ${chalk.yellow(cpType)}`);
|
|
602
|
-
if (metadata.message) {
|
|
603
|
-
console.log(` 메시지: ${chalk.blue(metadata.message)}`);
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
if (options.cleanup) {
|
|
607
|
-
const keep = parseInt(options.cleanup, 10);
|
|
608
|
-
if (!Number.isNaN(keep) && keep > 0) {
|
|
609
|
-
await manager.cleanup(keep);
|
|
610
|
-
console.log(`🧹 최근 ${chalk.cyan(keep)}개만 보존하도록 정리했습니다.`);
|
|
611
|
-
} else {
|
|
612
|
-
console.log(chalk.yellow('⚠️ --cleanup 값이 유효하지 않아 정리를 건너뜁니다. 정수로 입력하세요.'));
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
} catch (error) {
|
|
616
|
-
console.error(chalk.red('❌ 체크포인트 생성 실패:'), error.message);
|
|
617
|
-
process.exit(1);
|
|
618
|
-
}
|
|
619
|
-
});
|
|
620
|
-
|
|
621
|
-
checkpoint
|
|
622
|
-
.command('restore <checkpointId>')
|
|
623
|
-
.description('Restore from checkpoint / 체크포인트에서 복구')
|
|
624
|
-
.action(async (checkpointId) => {
|
|
625
|
-
try {
|
|
626
|
-
const fs = await import('fs/promises');
|
|
627
|
-
const path = await import('path');
|
|
628
|
-
let currentDir = process.cwd();
|
|
629
|
-
|
|
630
|
-
while (currentDir !== path.parse(currentDir).root) {
|
|
631
|
-
try {
|
|
632
|
-
await fs.access(path.join(currentDir, '.aiwf'));
|
|
633
|
-
break;
|
|
634
|
-
} catch {
|
|
635
|
-
currentDir = path.dirname(currentDir);
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
const manager = new CheckpointManager(currentDir);
|
|
640
|
-
await manager.initialize();
|
|
641
|
-
|
|
642
|
-
console.log(chalk.blue(`🔄 체크포인트 ${checkpointId}에서 복구 중...`));
|
|
643
|
-
|
|
644
|
-
const result = await manager.restoreFromCheckpoint(checkpointId);
|
|
645
|
-
|
|
646
|
-
if (result.success) {
|
|
647
|
-
console.log(chalk.green('✅ 체크포인트 복구 성공!'));
|
|
648
|
-
console.log(` 세션 ID: ${chalk.cyan(result.checkpoint.state_snapshot.session_id)}`);
|
|
649
|
-
console.log(` 스프린트: ${chalk.blue(result.checkpoint.state_snapshot.sprint_id || 'N/A')}`);
|
|
650
|
-
console.log('');
|
|
651
|
-
console.log(chalk.green('🚀 복구 완료! YOLO 모드를 다시 실행할 수 있습니다.'));
|
|
652
|
-
}
|
|
653
|
-
} catch (error) {
|
|
654
|
-
console.error(chalk.red('❌ 체크포인트 복구 실패:'), error.message);
|
|
655
|
-
process.exit(1);
|
|
656
|
-
}
|
|
657
|
-
});
|
|
658
|
-
|
|
659
|
-
checkpoint
|
|
660
|
-
.command('status')
|
|
661
|
-
.description('Show current YOLO session status / 현재 YOLO 세션 상태')
|
|
662
|
-
.action(async () => {
|
|
663
|
-
try {
|
|
664
|
-
const fs = await import('fs/promises');
|
|
665
|
-
const path = await import('path');
|
|
666
|
-
let currentDir = process.cwd();
|
|
667
|
-
|
|
668
|
-
while (currentDir !== path.parse(currentDir).root) {
|
|
669
|
-
try {
|
|
670
|
-
await fs.access(path.join(currentDir, '.aiwf'));
|
|
671
|
-
break;
|
|
672
|
-
} catch {
|
|
673
|
-
currentDir = path.dirname(currentDir);
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
const manager = new CheckpointManager(currentDir);
|
|
678
|
-
await manager.loadState();
|
|
679
|
-
|
|
680
|
-
console.log(chalk.bold('📊 YOLO 세션 상태:'));
|
|
681
|
-
console.log('');
|
|
682
|
-
|
|
683
|
-
if (!manager.currentState.session_id) {
|
|
684
|
-
console.log(chalk.yellow('📭 활성 YOLO 세션이 없습니다.'));
|
|
685
|
-
return;
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
console.log(`세션 ID: ${chalk.cyan(manager.currentState.session_id)}`);
|
|
689
|
-
console.log(`스프린트: ${chalk.blue(manager.currentState.sprint_id || 'N/A')}`);
|
|
690
|
-
console.log(`완료된 태스크: ${chalk.green(manager.currentState.completed_tasks.length)}개`);
|
|
691
|
-
console.log(`체크포인트: ${chalk.blue(manager.currentState.checkpoints.length)}개`);
|
|
692
|
-
} catch (error) {
|
|
693
|
-
console.error(chalk.red('❌ 상태 확인 실패:'), error.message);
|
|
694
|
-
process.exit(1);
|
|
695
|
-
}
|
|
696
|
-
});
|
|
697
|
-
|
|
698
|
-
// 체크포인트 리포트 생성
|
|
699
|
-
checkpoint
|
|
700
|
-
.command('report')
|
|
701
|
-
.description('Generate progress report / 진행 상황 리포트 생성')
|
|
702
|
-
.action(async () => {
|
|
703
|
-
try {
|
|
704
|
-
const fs = await import('fs/promises');
|
|
705
|
-
const path = await import('path');
|
|
706
|
-
let currentDir = process.cwd();
|
|
707
|
-
|
|
708
|
-
while (currentDir !== path.parse(currentDir).root) {
|
|
709
|
-
try {
|
|
710
|
-
await fs.access(path.join(currentDir, '.aiwf'));
|
|
711
|
-
break;
|
|
712
|
-
} catch {
|
|
713
|
-
currentDir = path.dirname(currentDir);
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
const manager = new CheckpointManager(currentDir);
|
|
718
|
-
await manager.loadState();
|
|
719
|
-
|
|
720
|
-
console.log(chalk.blue('📊 진행 상황 리포트 생성 중...'));
|
|
721
|
-
console.log('');
|
|
722
|
-
|
|
723
|
-
const report = await manager.generateProgressReport();
|
|
724
|
-
|
|
725
|
-
console.log(chalk.bold('🎯 YOLO 세션 리포트'));
|
|
726
|
-
console.log(''.padEnd(50, '='));
|
|
727
|
-
console.log('');
|
|
728
|
-
|
|
729
|
-
// 세션 정보
|
|
730
|
-
console.log(chalk.bold('📋 세션 정보:'));
|
|
731
|
-
console.log(` ID: ${chalk.cyan(report.session.id)}`);
|
|
732
|
-
console.log(` 시작: ${chalk.gray(new Date(report.session.started).toLocaleString())}`);
|
|
733
|
-
console.log(` 스프린트: ${chalk.blue(report.session.sprint || 'N/A')}`);
|
|
734
|
-
console.log('');
|
|
735
|
-
|
|
736
|
-
// 진행 상황
|
|
737
|
-
console.log(chalk.bold('📈 진행 상황:'));
|
|
738
|
-
console.log(` 완료: ${chalk.green(report.progress.completed)}개`);
|
|
739
|
-
console.log(` 실패: ${chalk.red(report.progress.failed)}개`);
|
|
740
|
-
console.log(` 건너뜀: ${chalk.yellow(report.progress.skipped)}개`);
|
|
741
|
-
console.log('');
|
|
742
|
-
|
|
743
|
-
// 성능 지표
|
|
744
|
-
console.log(chalk.bold('⏱️ 성능 지표:'));
|
|
745
|
-
console.log(` 총 시간: ${chalk.blue(report.performance.total_time)}`);
|
|
746
|
-
console.log(` 평균 태스크 시간: ${chalk.blue(report.performance.avg_task_time)}`);
|
|
747
|
-
console.log(` 성공률: ${chalk.green(report.performance.success_rate)}`);
|
|
748
|
-
|
|
749
|
-
} catch (error) {
|
|
750
|
-
console.error(chalk.red('❌ 리포트 생성 실패:'), error.message);
|
|
751
|
-
process.exit(1);
|
|
752
|
-
}
|
|
753
|
-
});
|
|
754
|
-
|
|
755
|
-
// 체크포인트 정리
|
|
756
|
-
checkpoint
|
|
757
|
-
.command('clean')
|
|
758
|
-
.description('Clean old checkpoints / 오래된 체크포인트 정리')
|
|
759
|
-
.option('--keep <n>', 'Number of checkpoints to keep / 유지할 체크포인트 수', '10')
|
|
760
|
-
.option('--dry-run', 'Preview without deletion / 실제 삭제 없이 미리보기')
|
|
761
|
-
.action(async (options) => {
|
|
762
|
-
try {
|
|
763
|
-
const fs = await import('fs/promises');
|
|
764
|
-
const path = await import('path');
|
|
765
|
-
let currentDir = process.cwd();
|
|
766
|
-
|
|
767
|
-
while (currentDir !== path.parse(currentDir).root) {
|
|
768
|
-
try {
|
|
769
|
-
await fs.access(path.join(currentDir, '.aiwf'));
|
|
770
|
-
break;
|
|
771
|
-
} catch {
|
|
772
|
-
currentDir = path.dirname(currentDir);
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
const manager = new CheckpointManager(currentDir);
|
|
777
|
-
const keepLast = parseInt(options.keep);
|
|
778
|
-
|
|
779
|
-
console.log(chalk.blue(`🧹 체크포인트 정리 중... (최근 ${keepLast}개 유지)`));
|
|
780
|
-
|
|
781
|
-
if (options.dryRun) {
|
|
782
|
-
console.log(chalk.yellow('🔍 드라이런 모드: 실제 삭제는 수행하지 않습니다.'));
|
|
783
|
-
const checkpoints = await manager.listCheckpoints();
|
|
784
|
-
if (checkpoints.length <= keepLast) {
|
|
785
|
-
console.log(chalk.green('✅ 정리할 체크포인트가 없습니다.'));
|
|
786
|
-
} else {
|
|
787
|
-
const toDelete = checkpoints.slice(keepLast);
|
|
788
|
-
console.log(chalk.yellow(`삭제 예정 체크포인트 (${toDelete.length}개):`));
|
|
789
|
-
for (const cp of toDelete) {
|
|
790
|
-
console.log(` ${chalk.red('🗑️')} ${chalk.cyan(cp.id)}`);
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
} else {
|
|
794
|
-
await manager.cleanup(keepLast);
|
|
795
|
-
console.log(chalk.green('✅ 체크포인트 정리 완료!'));
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
} catch (error) {
|
|
799
|
-
console.error(chalk.red('❌ 체크포인트 정리 실패:'), error.message);
|
|
800
|
-
process.exit(1);
|
|
801
|
-
}
|
|
802
|
-
});
|
|
263
|
+
// (removed) checkpoint command group
|
|
803
264
|
|
|
804
265
|
// Engineering Guard commands (오버엔지니어링 방지)
|
|
805
266
|
const guard = program.command('guard');
|