aiwf 0.3.21 → 0.3.23

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.
Files changed (140) hide show
  1. package/package.json +3 -2
  2. package/src/cli/index.js +39 -336
  3. package/src/lib/installer.js +310 -90
  4. package/src/utils/messages.js +24 -0
  5. package/src/DEPENDENCY_MAP.md +0 -90
  6. package/src/cli/cache-cli.js +0 -459
  7. package/src/cli/checkpoint-cli.js +0 -417
  8. package/src/cli/language-cli.js +0 -286
  9. package/src/cli/sprint-cli.js +0 -287
  10. package/src/commands/ai-tool.js +0 -383
  11. package/src/commands/compress.js +0 -60
  12. package/src/commands/create-project.js +0 -160
  13. package/src/commands/evaluate.js +0 -459
  14. package/src/commands/persona.js +0 -309
  15. package/src/commands/sprint-task.js +0 -262
  16. package/src/commands/token.js +0 -312
  17. package/src/lib/ai-persona-manager.js +0 -711
  18. package/src/lib/cache-system.js +0 -332
  19. package/src/lib/context-engine.js +0 -568
  20. package/src/lib/github-integration.js +0 -402
  21. package/src/lib/memory-profiler.js +0 -471
  22. package/src/lib/metrics-collector.js +0 -885
  23. package/src/lib/offline-detector.js +0 -386
  24. package/src/lib/resource-loader-enhanced.js +0 -399
  25. package/src/lib/resource-loader.js +0 -250
  26. package/src/lib/resources/commands/ai-persona.js +0 -602
  27. package/src/lib/resources/commands/compress-context.js +0 -389
  28. package/src/lib/resources/commands/evaluate.js +0 -246
  29. package/src/lib/resources/commands/persona-context-apply.js +0 -562
  30. package/src/lib/resources/commands/token-tracking.js +0 -443
  31. package/src/lib/resources/config/commit-patterns.js +0 -103
  32. package/src/lib/resources/config/language.json +0 -6
  33. package/src/lib/resources/personas/PERSONA_INDEX.md +0 -57
  34. package/src/lib/resources/personas/analyst.json +0 -44
  35. package/src/lib/resources/personas/architect/best_practices.md +0 -136
  36. package/src/lib/resources/personas/architect/knowledge_base.md +0 -377
  37. package/src/lib/resources/personas/architect.json +0 -44
  38. package/src/lib/resources/personas/backend/best_practices.md +0 -766
  39. package/src/lib/resources/personas/backend/knowledge_base.md +0 -1070
  40. package/src/lib/resources/personas/data_analyst/best_practices.md +0 -594
  41. package/src/lib/resources/personas/data_analyst/knowledge_base.md +0 -1057
  42. package/src/lib/resources/personas/developer.json +0 -44
  43. package/src/lib/resources/personas/developer.md +0 -37
  44. package/src/lib/resources/personas/evaluation_criteria.json +0 -137
  45. package/src/lib/resources/personas/frontend/best_practices.md +0 -445
  46. package/src/lib/resources/personas/frontend/knowledge_base.md +0 -729
  47. package/src/lib/resources/personas/persona-index.json +0 -31
  48. package/src/lib/resources/personas/reviewer.json +0 -44
  49. package/src/lib/resources/personas/security/best_practices.md +0 -307
  50. package/src/lib/resources/personas/security/knowledge_base.md +0 -498
  51. package/src/lib/resources/personas/tester.json +0 -44
  52. package/src/lib/resources/templates/README.md +0 -78
  53. package/src/lib/resources/templates/api-server/config.json +0 -64
  54. package/src/lib/resources/templates/api-server/template/.aiwf/config.json +0 -56
  55. package/src/lib/resources/templates/api-server/template/.aiwf/feature-ledger.json +0 -42
  56. package/src/lib/resources/templates/api-server/template/.aiwf/personas/backend-engineer.json +0 -40
  57. package/src/lib/resources/templates/api-server/template/.aiwf/scripts/cli.js +0 -111
  58. package/src/lib/resources/templates/api-server/template/.env.example +0 -29
  59. package/src/lib/resources/templates/api-server/template/.eslintrc.json +0 -23
  60. package/src/lib/resources/templates/api-server/template/README.md +0 -171
  61. package/src/lib/resources/templates/api-server/template/jest.config.js +0 -26
  62. package/src/lib/resources/templates/api-server/template/nodemon.json +0 -9
  63. package/src/lib/resources/templates/api-server/template/package.json +0 -61
  64. package/src/lib/resources/templates/api-server/template/src/app.ts +0 -60
  65. package/src/lib/resources/templates/api-server/template/src/config/swagger.ts +0 -38
  66. package/src/lib/resources/templates/api-server/template/src/controllers/aiwfController.ts +0 -54
  67. package/src/lib/resources/templates/api-server/template/src/controllers/authController.ts +0 -128
  68. package/src/lib/resources/templates/api-server/template/src/controllers/statusController.ts +0 -28
  69. package/src/lib/resources/templates/api-server/template/src/index.ts +0 -28
  70. package/src/lib/resources/templates/api-server/template/src/middleware/aiwfMiddleware.ts +0 -50
  71. package/src/lib/resources/templates/api-server/template/src/middleware/authMiddleware.ts +0 -41
  72. package/src/lib/resources/templates/api-server/template/src/middleware/errorHandler.ts +0 -42
  73. package/src/lib/resources/templates/api-server/template/src/middleware/notFoundHandler.ts +0 -14
  74. package/src/lib/resources/templates/api-server/template/src/middleware/requestLogger.ts +0 -20
  75. package/src/lib/resources/templates/api-server/template/src/routes/aiwf.ts +0 -31
  76. package/src/lib/resources/templates/api-server/template/src/routes/index.ts +0 -13
  77. package/src/lib/resources/templates/api-server/template/src/routes/v1/index.ts +0 -67
  78. package/src/lib/resources/templates/api-server/template/src/utils/logger.ts +0 -37
  79. package/src/lib/resources/templates/api-server/template/tests/app.test.ts +0 -40
  80. package/src/lib/resources/templates/api-server/template/tsconfig.json +0 -43
  81. package/src/lib/resources/templates/npm-library/config.json +0 -61
  82. package/src/lib/resources/templates/npm-library/template/LICENSE +0 -21
  83. package/src/lib/resources/templates/npm-library/template/README.md +0 -201
  84. package/src/lib/resources/templates/npm-library/template/package.json +0 -78
  85. package/src/lib/resources/templates/web-app/config.json +0 -53
  86. package/src/lib/resources/templates/web-app/template/.aiwf/config.json +0 -54
  87. package/src/lib/resources/templates/web-app/template/.aiwf/feature-ledger.json +0 -37
  88. package/src/lib/resources/templates/web-app/template/.aiwf/personas/fullstack-developer.json +0 -40
  89. package/src/lib/resources/templates/web-app/template/.aiwf/scripts/cli.js +0 -110
  90. package/src/lib/resources/templates/web-app/template/.eslintrc.cjs +0 -20
  91. package/src/lib/resources/templates/web-app/template/README.md +0 -151
  92. package/src/lib/resources/templates/web-app/template/index.html +0 -14
  93. package/src/lib/resources/templates/web-app/template/package.json +0 -44
  94. package/src/lib/resources/templates/web-app/template/postcss.config.js +0 -6
  95. package/src/lib/resources/templates/web-app/template/public/vite.svg +0 -1
  96. package/src/lib/resources/templates/web-app/template/src/App.tsx +0 -21
  97. package/src/lib/resources/templates/web-app/template/src/components/Layout.tsx +0 -57
  98. package/src/lib/resources/templates/web-app/template/src/components/aiwf/ContextStatus.tsx +0 -107
  99. package/src/lib/resources/templates/web-app/template/src/components/aiwf/TokenUsage.tsx +0 -71
  100. package/src/lib/resources/templates/web-app/template/src/index.css +0 -60
  101. package/src/lib/resources/templates/web-app/template/src/main.tsx +0 -10
  102. package/src/lib/resources/templates/web-app/template/src/pages/AiwfDashboard.tsx +0 -57
  103. package/src/lib/resources/templates/web-app/template/src/pages/HomePage.tsx +0 -89
  104. package/src/lib/resources/templates/web-app/template/src/pages/NotFound.tsx +0 -25
  105. package/src/lib/resources/templates/web-app/template/src/stores/aiwfStore.ts +0 -126
  106. package/src/lib/resources/templates/web-app/template/src/types/global.d.ts +0 -9
  107. package/src/lib/resources/templates/web-app/template/src/vite-env.d.ts +0 -1
  108. package/src/lib/resources/templates/web-app/template/tailwind.config.js +0 -30
  109. package/src/lib/resources/templates/web-app/template/tsconfig.json +0 -37
  110. package/src/lib/resources/templates/web-app/template/tsconfig.node.json +0 -10
  111. package/src/lib/resources/templates/web-app/template/vite.config.ts +0 -23
  112. package/src/lib/resources/utils/background-monitor.js +0 -223
  113. package/src/lib/resources/utils/compression-metrics.js +0 -1031
  114. package/src/lib/resources/utils/compression-strategies.js +0 -557
  115. package/src/lib/resources/utils/content-normalizer.js +0 -455
  116. package/src/lib/resources/utils/context-compressor.js +0 -583
  117. package/src/lib/resources/utils/context-rule-parser.js +0 -180
  118. package/src/lib/resources/utils/context-token-monitor.js +0 -463
  119. package/src/lib/resources/utils/context-update-manager.js +0 -502
  120. package/src/lib/resources/utils/git-utils.js +0 -220
  121. package/src/lib/resources/utils/importance-classifier.js +0 -645
  122. package/src/lib/resources/utils/information-filter.js +0 -710
  123. package/src/lib/resources/utils/persona-aware-compressor.js +0 -598
  124. package/src/lib/resources/utils/prompt-injector.js +0 -242
  125. package/src/lib/resources/utils/simplified-evaluator.js +0 -119
  126. package/src/lib/resources/utils/text-summarizer.js +0 -492
  127. package/src/lib/resources/utils/token-counter.js +0 -177
  128. package/src/lib/resources/utils/token-monitor.js +0 -484
  129. package/src/lib/resources/utils/token-reporter.js +0 -452
  130. package/src/lib/resources/utils/token-storage.js +0 -433
  131. package/src/lib/resources/utils/token-tracker.js +0 -283
  132. package/src/lib/state/priority-calculator.js +0 -217
  133. package/src/lib/state/state-index.js +0 -155
  134. package/src/lib/state/task-scanner.js +0 -328
  135. package/src/lib/task-analyzer.js +0 -599
  136. package/src/lib/template-cache-system.js +0 -559
  137. package/src/lib/template-downloader.js +0 -467
  138. package/src/lib/template-version-manager.js +0 -491
  139. package/src/lib/token-optimizer.js +0 -517
  140. package/src/utils/engineering-guard.js +0 -399
@@ -1,389 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { ContextCompressor } from '../utils/context-compressor.js';
4
- import { PersonaAwareCompressor } from '../utils/persona-aware-compressor.js';
5
- import { getBackgroundMonitor } from '../utils/background-monitor.js';
6
- import { TokenCounter } from '../utils/token-counter.js';
7
- import { CompressionMetrics } from '../utils/compression-metrics.js';
8
- import fs from 'fs/promises';
9
- import path from 'path';
10
- import chalk from 'chalk';
11
- import ora from 'ora';
12
- import { fileURLToPath } from 'url';
13
- import { dirname } from 'path';
14
-
15
- const __filename = fileURLToPath(import.meta.url);
16
- const __dirname = dirname(__filename);
17
-
18
- /**
19
- * compress-context 명령어 실행
20
- */
21
- export async function executeCompressContext(args = []) {
22
- const spinner = ora('Context 압축 준비 중...').start();
23
-
24
- try {
25
- // 파라미터 파싱
26
- const { mode, targetPath, usePersona } = parseArguments(args);
27
-
28
- spinner.text = '압축 대상 분석 중...';
29
-
30
- // 대상 경로 결정
31
- const resolvedPath = await resolveTargetPath(targetPath);
32
- const files = await collectMarkdownFiles(resolvedPath);
33
-
34
- if (files.length === 0) {
35
- spinner.fail('압축할 마크다운 파일이 없습니다.');
36
- return;
37
- }
38
-
39
- // 압축 전 통계
40
- spinner.text = '원본 토큰 수 계산 중...';
41
- const beforeStats = await calculateStats(files);
42
-
43
- // 압축 시작
44
- console.log('');
45
- console.log(chalk.cyan('🗜️ Context 압축 시작'));
46
- console.log(chalk.gray('━'.repeat(50)));
47
- console.log(`압축 모드: ${chalk.yellow(mode)}`);
48
- console.log(`대상: ${chalk.yellow(resolvedPath)}`);
49
- console.log(`페르소나 연동: ${chalk.yellow(usePersona ? '활성화' : '비활성화')}`);
50
- console.log('');
51
-
52
- console.log(chalk.cyan('📊 압축 전 통계:'));
53
- console.log(`- 총 파일 수: ${files.length}`);
54
- console.log(`- 원본 토큰: ${chalk.red(beforeStats.totalTokens.toLocaleString())}`);
55
- console.log(`- 원본 크기: ${(beforeStats.totalSize / 1024).toFixed(1)} KB`);
56
- console.log('');
57
-
58
- spinner.text = '압축 진행 중...';
59
-
60
- // 압축 수행
61
- const compressor = usePersona
62
- ? new PersonaAwareCompressor(mode)
63
- : new ContextCompressor(mode);
64
- const compressionResults = [];
65
- const startTime = Date.now();
66
-
67
- console.log(chalk.cyan('⚙️ 압축 진행 중...'));
68
-
69
- for (const file of files) {
70
- const fileName = path.basename(file);
71
- const content = await fs.readFile(file, 'utf8');
72
-
73
- const result = await compressor.compress(content, {
74
- strategy: mode,
75
- preserveStructure: true,
76
- enableSummarization: mode === 'aggressive',
77
- enableNormalization: true,
78
- enableFiltering: mode !== 'minimal'
79
- });
80
-
81
- if (result.success) {
82
- const savedTokens = result.originalTokens - result.compressedTokens;
83
- const ratio = result.compressionRatio.toFixed(1);
84
-
85
- console.log(chalk.green(`✓ ${fileName} (${result.originalTokens.toLocaleString()} → ${result.compressedTokens.toLocaleString()} 토큰, -${ratio}%)`));
86
-
87
- compressionResults.push({
88
- filePath: file,
89
- fileName,
90
- ...result
91
- });
92
- } else {
93
- console.log(chalk.red(`✗ ${fileName} (압축 실패: ${result.error})`));
94
- }
95
- }
96
-
97
- const processingTime = Date.now() - startTime;
98
-
99
- // 압축 후 통계
100
- const afterStats = calculateCompressedStats(compressionResults);
101
- const totalSaved = beforeStats.totalTokens - afterStats.totalTokens;
102
- const overallRatio = ((totalSaved / beforeStats.totalTokens) * 100).toFixed(1);
103
-
104
- // 압축된 파일 저장
105
- spinner.text = '압축된 파일 저장 중...';
106
- const outputDir = await saveCompressedFiles(compressionResults, resolvedPath);
107
-
108
- // 압축 보고서 생성
109
- await generateReport(compressionResults, {
110
- mode,
111
- targetPath: resolvedPath,
112
- outputDir,
113
- beforeStats,
114
- afterStats,
115
- processingTime
116
- });
117
-
118
- spinner.stop();
119
-
120
- // 결과 출력
121
- console.log('');
122
- console.log(chalk.cyan('📊 압축 후 통계:'));
123
- console.log(`- 압축된 토큰: ${chalk.green(afterStats.totalTokens.toLocaleString())}`);
124
- console.log(`- 절약된 토큰: ${chalk.green(totalSaved.toLocaleString())}`);
125
- console.log(`- 토큰 절약률: ${chalk.green(overallRatio + '%')}`);
126
- console.log(`- 압축 시간: ${(processingTime / 1000).toFixed(1)}초`);
127
-
128
- // 평균 품질 점수 계산
129
- const avgQuality = compressionResults.reduce((sum, r) => {
130
- return sum + (r.metadata?.validation?.qualityScore || 0);
131
- }, 0) / compressionResults.length;
132
-
133
- console.log(`- 품질 점수: ${chalk.green(avgQuality.toFixed(0) + '/100')}`);
134
-
135
- // 페르소나 정보 출력
136
- if (usePersona && compressor.currentPersona) {
137
- console.log(`- 활성 페르소나: ${chalk.cyan(compressor.currentPersona)}`);
138
- }
139
-
140
- console.log('');
141
-
142
- console.log(chalk.green('✅ 압축 완료!'));
143
- console.log(`압축된 파일 위치: ${chalk.yellow(outputDir)}`);
144
-
145
- // 페르소나 인식 압축인 경우 백그라운드 품질 체크
146
- if (usePersona && compressor.currentPersona) {
147
- const monitor = getBackgroundMonitor();
148
-
149
- // 압축된 내용의 샘플로 품질 체크 (비차단)
150
- const sampleResult = compressionResults[0];
151
- if (sampleResult) {
152
- monitor.monitorResponse(
153
- sampleResult.compressed.substring(0, 1000), // 샘플만
154
- compressor.currentPersona,
155
- { silent: false }
156
- ).then(feedback => {
157
- if (feedback && feedback.feedback) {
158
- console.log('');
159
- console.log(feedback.feedback);
160
- }
161
- }).catch(() => {}); // 에러 무시
162
- }
163
- }
164
-
165
- // 목표 달성 여부 확인
166
- const targetRange = getTargetRange(mode);
167
- if (parseFloat(overallRatio) < targetRange.min) {
168
- console.log('');
169
- console.log(chalk.yellow(`⚠️ 경고: 압축률이 목표 범위(${targetRange.min}-${targetRange.max}%)에 미달했습니다.`));
170
- console.log('더 높은 압축률이 필요하면 aggressive 모드를 시도해보세요.');
171
- }
172
-
173
- // 리소스 정리
174
- compressor.cleanup();
175
-
176
- } catch (error) {
177
- spinner.fail(`압축 실패: ${error.message}`);
178
- console.error(error);
179
- }
180
- }
181
-
182
- /**
183
- * 명령어 인자를 파싱합니다
184
- * @param {Array<string>} args - 인자 배열
185
- * @returns {Object} 파싱된 옵션
186
- */
187
- function parseArguments(args) {
188
- let mode = 'balanced';
189
- let targetPath = null;
190
- let usePersona = false;
191
-
192
- for (const arg of args) {
193
- if (['aggressive', 'balanced', 'minimal'].includes(arg)) {
194
- mode = arg;
195
- } else if (arg === '--persona' || arg === '-p') {
196
- usePersona = true;
197
- } else if (arg && !arg.startsWith('-')) {
198
- targetPath = arg;
199
- }
200
- }
201
-
202
- return { mode, targetPath, usePersona };
203
- }
204
-
205
- /**
206
- * 대상 경로를 결정합니다
207
- * @param {string} targetPath - 사용자 지정 경로
208
- * @returns {string} 결정된 경로
209
- */
210
- async function resolveTargetPath(targetPath) {
211
- if (targetPath) {
212
- // 절대 경로가 아니면 현재 디렉토리 기준으로 변환
213
- if (!path.isAbsolute(targetPath)) {
214
- targetPath = path.join(process.cwd(), targetPath);
215
- }
216
- return targetPath;
217
- }
218
-
219
- // 기본값: 프로젝트의 .aiwf 디렉토리
220
- const aiwfPath = path.join(process.cwd(), '.aiwf');
221
- try {
222
- await fs.access(aiwfPath);
223
- return aiwfPath;
224
- } catch {
225
- // .aiwf가 없으면 현재 디렉토리
226
- return process.cwd();
227
- }
228
- }
229
-
230
- /**
231
- * 마크다운 파일들을 수집합니다
232
- * @param {string} targetPath - 대상 경로
233
- * @returns {Array<string>} 파일 경로 배열
234
- */
235
- async function collectMarkdownFiles(targetPath) {
236
- const files = [];
237
-
238
- try {
239
- const stats = await fs.stat(targetPath);
240
-
241
- if (stats.isFile() && targetPath.endsWith('.md')) {
242
- files.push(targetPath);
243
- } else if (stats.isDirectory()) {
244
- await collectFromDirectory(targetPath, files);
245
- }
246
- } catch (error) {
247
- console.error(`경로 접근 오류: ${targetPath}`);
248
- }
249
-
250
- return files;
251
- }
252
-
253
- /**
254
- * 디렉토리에서 마크다운 파일을 재귀적으로 수집합니다
255
- * @param {string} dirPath - 디렉토리 경로
256
- * @param {Array<string>} files - 파일 배열
257
- */
258
- async function collectFromDirectory(dirPath, files) {
259
- const entries = await fs.readdir(dirPath, { withFileTypes: true });
260
-
261
- for (const entry of entries) {
262
- const fullPath = path.join(dirPath, entry.name);
263
-
264
- if (entry.isDirectory() && !entry.name.startsWith('.')) {
265
- await collectFromDirectory(fullPath, files);
266
- } else if (entry.isFile() && entry.name.endsWith('.md')) {
267
- files.push(fullPath);
268
- }
269
- }
270
- }
271
-
272
- /**
273
- * 파일 통계를 계산합니다
274
- * @param {Array<string>} files - 파일 경로 배열
275
- * @returns {Object} 통계 정보
276
- */
277
- async function calculateStats(files) {
278
- const tokenCounter = new TokenCounter();
279
- let totalTokens = 0;
280
- let totalSize = 0;
281
-
282
- for (const file of files) {
283
- const content = await fs.readFile(file, 'utf8');
284
- totalTokens += tokenCounter.countTokens(content);
285
- totalSize += Buffer.byteLength(content, 'utf8');
286
- }
287
-
288
- tokenCounter.cleanup();
289
-
290
- return { totalTokens, totalSize };
291
- }
292
-
293
- /**
294
- * 압축된 통계를 계산합니다
295
- * @param {Array<Object>} results - 압축 결과 배열
296
- * @returns {Object} 통계 정보
297
- */
298
- function calculateCompressedStats(results) {
299
- const totalTokens = results.reduce((sum, r) => sum + r.compressedTokens, 0);
300
- const totalSize = results.reduce((sum, r) => sum + Buffer.byteLength(r.compressed, 'utf8'), 0);
301
-
302
- return { totalTokens, totalSize };
303
- }
304
-
305
- /**
306
- * 압축된 파일들을 저장합니다
307
- * @param {Array<Object>} results - 압축 결과 배열
308
- * @param {string} targetPath - 원본 경로
309
- * @returns {string} 출력 디렉토리
310
- */
311
- async function saveCompressedFiles(results, targetPath) {
312
- const timestamp = new Date().toISOString().slice(0, 19).replace(/:/g, '-');
313
- const outputDir = path.join(path.dirname(targetPath), `.aiwf_compressed`, timestamp);
314
-
315
- await fs.mkdir(outputDir, { recursive: true });
316
-
317
- for (const result of results) {
318
- const outputPath = path.join(outputDir, result.fileName);
319
- await fs.writeFile(outputPath, result.compressed);
320
- }
321
-
322
- return outputDir;
323
- }
324
-
325
- /**
326
- * 압축 보고서를 생성합니다
327
- * @param {Array<Object>} results - 압축 결과 배열
328
- * @param {Object} stats - 통계 정보
329
- */
330
- async function generateReport(results, stats) {
331
- const report = [];
332
-
333
- report.push('# Context 압축 보고서');
334
- report.push('');
335
- report.push(`**생성 시간**: ${new Date().toISOString()}`);
336
- report.push(`**압축 모드**: ${stats.mode}`);
337
- report.push(`**대상 경로**: ${stats.targetPath}`);
338
- report.push(`**출력 경로**: ${stats.outputDir}`);
339
- report.push('');
340
-
341
- report.push('## 전체 통계');
342
- report.push(`- **파일 수**: ${results.length}`);
343
- report.push(`- **원본 토큰**: ${stats.beforeStats.totalTokens.toLocaleString()}`);
344
- report.push(`- **압축 토큰**: ${stats.afterStats.totalTokens.toLocaleString()}`);
345
- report.push(`- **절약 토큰**: ${(stats.beforeStats.totalTokens - stats.afterStats.totalTokens).toLocaleString()}`);
346
- report.push(`- **전체 압축률**: ${((stats.beforeStats.totalTokens - stats.afterStats.totalTokens) / stats.beforeStats.totalTokens * 100).toFixed(1)}%`);
347
- report.push(`- **처리 시간**: ${(stats.processingTime / 1000).toFixed(1)}초`);
348
- report.push('');
349
-
350
- report.push('## 파일별 상세');
351
- report.push('');
352
- report.push('| 파일명 | 원본 토큰 | 압축 토큰 | 압축률 | 품질 점수 |');
353
- report.push('|--------|-----------|-----------|--------|-----------|');
354
-
355
- for (const result of results) {
356
- const qualityScore = result.metadata?.validation?.qualityScore || 0;
357
- report.push(
358
- `| ${result.fileName} | ${result.originalTokens.toLocaleString()} | ` +
359
- `${result.compressedTokens.toLocaleString()} | ${result.compressionRatio}% | ` +
360
- `${qualityScore}/100 |`
361
- );
362
- }
363
-
364
- const reportPath = path.join(stats.outputDir, 'compression-report.md');
365
- await fs.writeFile(reportPath, report.join('\n'));
366
- }
367
-
368
- /**
369
- * 압축 모드별 목표 범위를 반환합니다
370
- * @param {string} mode - 압축 모드
371
- * @returns {Object} 목표 범위
372
- */
373
- function getTargetRange(mode) {
374
- const ranges = {
375
- aggressive: { min: 50, max: 70 },
376
- balanced: { min: 30, max: 50 },
377
- minimal: { min: 10, max: 30 }
378
- };
379
-
380
- return ranges[mode] || { min: 0, max: 100 };
381
- }
382
-
383
- // CLI로 직접 실행하는 경우
384
- if (import.meta.url === `file://${process.argv[1]}`) {
385
- const args = process.argv.slice(2);
386
- executeCompressContext(args);
387
- }
388
-
389
- export default executeCompressContext;
@@ -1,246 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * 경량화된 평가 명령어
5
- * 선택적으로 사용할 수 있는 간단한 평가 도구
6
- */
7
-
8
- import { SimplifiedEvaluator } from '../utils/simplified-evaluator.js';
9
- import { getBackgroundMonitor } from '../utils/background-monitor.js';
10
- import fs from 'fs/promises';
11
- import path from 'path';
12
- import chalk from 'chalk';
13
- import { fileURLToPath } from 'url';
14
-
15
- const __filename = fileURLToPath(import.meta.url);
16
- const __dirname = path.dirname(__filename);
17
-
18
- /**
19
- * evaluate 명령어 실행
20
- */
21
- export async function executeEvaluate(args = []) {
22
- const option = args[0];
23
-
24
- try {
25
- switch (option) {
26
- case '--detailed':
27
- case '-d':
28
- return await detailedEvaluation();
29
-
30
- case '--history':
31
- case '-h':
32
- return await showHistory();
33
-
34
- case '--stats':
35
- case '-s':
36
- return await showStats();
37
-
38
- default:
39
- return await quickEvaluation();
40
- }
41
- } catch (error) {
42
- console.error(chalk.red('오류:'), error.message);
43
- }
44
- }
45
-
46
- /**
47
- * 빠른 평가 (기본)
48
- */
49
- async function quickEvaluation() {
50
- console.log(chalk.cyan('🔍 최근 응답 평가'));
51
- console.log(chalk.gray('━'.repeat(50)));
52
-
53
- // 현재 페르소나 확인
54
- const currentPersona = await getCurrentPersona();
55
- if (!currentPersona) {
56
- console.log(chalk.yellow('활성화된 페르소나가 없습니다.'));
57
- console.log('페르소나를 먼저 활성화하세요: aiwf persona [architect|security|frontend|backend|data_analyst]');
58
- return;
59
- }
60
-
61
- console.log(`현재 페르소나: ${chalk.yellow(currentPersona)}`);
62
-
63
- // 최근 통계 표시
64
- const monitor = getBackgroundMonitor();
65
- const stats = monitor.getRecentStats(currentPersona);
66
-
67
- if (stats.message) {
68
- console.log(stats.message);
69
- return;
70
- }
71
-
72
- console.log(`평균 점수: ${chalk.green(stats.averageScore)}`);
73
- console.log(`평가 횟수: ${stats.totalEvaluations}`);
74
- console.log(`추세: ${getTrendEmoji(stats.trend)} ${getKoreanTrend(stats.trend)}`);
75
-
76
- // 간단한 팁
77
- if (parseFloat(stats.averageScore) < 0.6) {
78
- console.log('');
79
- console.log(chalk.yellow('💡 팁: 페르소나 특성을 더 활용해보세요!'));
80
- } else if (parseFloat(stats.averageScore) > 0.8) {
81
- console.log('');
82
- console.log(chalk.green('🎉 훌륭해요! 페르소나를 잘 활용하고 있습니다.'));
83
- }
84
- }
85
-
86
- /**
87
- * 상세 평가
88
- */
89
- async function detailedEvaluation() {
90
- console.log(chalk.cyan('📊 상세 평가 분석'));
91
- console.log(chalk.gray('━'.repeat(50)));
92
-
93
- const monitor = getBackgroundMonitor();
94
- const stats = monitor.getRecentStats();
95
-
96
- if (stats.message) {
97
- console.log(stats.message);
98
- return;
99
- }
100
-
101
- console.log(chalk.white('전체 통계:'));
102
- console.log(`- 총 평가: ${stats.totalEvaluations}회`);
103
- console.log(`- 평균 점수: ${stats.averageScore}`);
104
- console.log(`- 추세: ${getTrendEmoji(stats.trend)} ${getKoreanTrend(stats.trend)}`);
105
-
106
- console.log('');
107
- console.log(chalk.white('페르소나별 성과:'));
108
-
109
- Object.entries(stats.personaStats).forEach(([persona, data]) => {
110
- const score = parseFloat(data.avgScore);
111
- const scoreColor = score >= 0.8 ? 'green' : score >= 0.6 ? 'yellow' : 'red';
112
-
113
- console.log(`- ${getKoreanPersonaName(persona)}: ${chalk[scoreColor](data.avgScore)} (${data.count}회)`);
114
- });
115
-
116
- // 개선 제안
117
- console.log('');
118
- console.log(chalk.white('개선 제안:'));
119
-
120
- Object.entries(stats.personaStats).forEach(([persona, data]) => {
121
- if (parseFloat(data.avgScore) < 0.6) {
122
- const evaluator = new SimplifiedEvaluator();
123
- const feedback = evaluator.getGentleFeedback(persona, parseFloat(data.avgScore));
124
- if (feedback) {
125
- console.log(feedback);
126
- }
127
- }
128
- });
129
- }
130
-
131
- /**
132
- * 평가 히스토리
133
- */
134
- async function showHistory() {
135
- console.log(chalk.cyan('📈 평가 히스토리'));
136
- console.log(chalk.gray('━'.repeat(50)));
137
-
138
- const monitor = getBackgroundMonitor();
139
- const history = monitor.recentEvaluations.slice(-10); // 최근 10개
140
-
141
- if (history.length === 0) {
142
- console.log('평가 기록이 없습니다.');
143
- return;
144
- }
145
-
146
- history.forEach((eval, index) => {
147
- const date = new Date(eval.timestamp);
148
- const timeStr = `${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}`;
149
- const scoreColor = eval.score >= 0.8 ? 'green' : eval.score >= 0.6 ? 'yellow' : 'red';
150
-
151
- console.log(`${timeStr} | ${getKoreanPersonaName(eval.persona)} | ${chalk[scoreColor](eval.score.toFixed(2))}`);
152
- });
153
- }
154
-
155
- /**
156
- * 주간 통계
157
- */
158
- async function showStats() {
159
- console.log(chalk.cyan('📊 주간 통계'));
160
- console.log(chalk.gray('━'.repeat(50)));
161
-
162
- const monitor = getBackgroundMonitor();
163
- const summary = monitor.getWeeklySummary();
164
-
165
- if (summary.message) {
166
- console.log(summary.message);
167
- return;
168
- }
169
-
170
- console.log(`평가 횟수: ${summary.evaluationCount}회`);
171
- console.log(`평균 점수: ${summary.averageScore}`);
172
- console.log(`추세: ${getTrendEmoji(summary.trend)} ${getKoreanTrend(summary.trend)}`);
173
-
174
- if (summary.personaStats) {
175
- console.log('');
176
- console.log('페르소나별 활용도:');
177
-
178
- const sorted = Object.entries(summary.personaStats)
179
- .sort((a, b) => b[1].count - a[1].count);
180
-
181
- sorted.forEach(([persona, data]) => {
182
- const bar = '█'.repeat(Math.floor(data.count / 2));
183
- console.log(`${getKoreanPersonaName(persona).padEnd(10)} ${bar} ${data.count}회`);
184
- });
185
- }
186
- }
187
-
188
- /**
189
- * 현재 페르소나 가져오기
190
- */
191
- async function getCurrentPersona() {
192
- try {
193
- const personaPath = path.join(process.cwd(), '.aiwf', 'current_persona.json');
194
- const data = await fs.readFile(personaPath, 'utf8');
195
- const personaData = JSON.parse(data);
196
- return personaData.persona;
197
- } catch {
198
- return null;
199
- }
200
- }
201
-
202
- /**
203
- * 페르소나 이름 한글화
204
- */
205
- function getKoreanPersonaName(persona) {
206
- const names = {
207
- architect: '아키텍트',
208
- security: '보안 전문가',
209
- frontend: '프론트엔드',
210
- backend: '백엔드',
211
- data_analyst: '데이터 분석가'
212
- };
213
- return names[persona] || persona;
214
- }
215
-
216
- /**
217
- * 추세 이모지
218
- */
219
- function getTrendEmoji(trend) {
220
- const emojis = {
221
- improving: '📈',
222
- declining: '📉',
223
- stable: '➡️'
224
- };
225
- return emojis[trend] || '❓';
226
- }
227
-
228
- /**
229
- * 추세 한글화
230
- */
231
- function getKoreanTrend(trend) {
232
- const trends = {
233
- improving: '개선 중',
234
- declining: '하락 중',
235
- stable: '안정적'
236
- };
237
- return trends[trend] || trend;
238
- }
239
-
240
- // CLI로 직접 실행하는 경우
241
- if (import.meta.url === `file://${process.argv[1]}`) {
242
- const args = process.argv.slice(2);
243
- executeEvaluate(args);
244
- }
245
-
246
- export default executeEvaluate;