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,433 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
-
4
- /**
5
- * 토큰 사용량 데이터를 저장하고 관리하는 클래스
6
- */
7
- export class TokenStorage {
8
- constructor(baseDir = '.aiwf/token-data') {
9
- this.baseDir = baseDir;
10
- this.dataFile = path.join(baseDir, 'token-usage.json');
11
- this.sessionDir = path.join(baseDir, 'sessions');
12
- this.reportsDir = path.join(baseDir, 'reports');
13
-
14
- this.ensureDirectories();
15
- this.loadData();
16
- }
17
-
18
- /**
19
- * 필요한 디렉토리를 생성합니다
20
- */
21
- ensureDirectories() {
22
- try {
23
- const dirs = [this.baseDir, this.sessionDir, this.reportsDir];
24
- for (const dir of dirs) {
25
- if (!fs.existsSync(dir)) {
26
- fs.mkdirSync(dir, { recursive: true });
27
- }
28
- }
29
- } catch (error) {
30
- console.error('디렉토리 생성 중 오류 발생:', error);
31
- }
32
- }
33
-
34
- /**
35
- * 토큰 사용량 데이터를 로드합니다
36
- */
37
- loadData() {
38
- try {
39
- if (fs.existsSync(this.dataFile)) {
40
- const data = JSON.parse(fs.readFileSync(this.dataFile, 'utf8'));
41
- this.data = {
42
- totalTokens: 0,
43
- sessionsCount: 0,
44
- lastUpdated: Date.now(),
45
- dailyUsage: {},
46
- commandStats: {},
47
- compressionStats: {
48
- totalOriginal: 0,
49
- totalCompressed: 0,
50
- totalSaved: 0,
51
- avgRatio: 0
52
- },
53
- ...data
54
- };
55
- } else {
56
- this.data = {
57
- totalTokens: 0,
58
- sessionsCount: 0,
59
- lastUpdated: Date.now(),
60
- dailyUsage: {},
61
- commandStats: {},
62
- compressionStats: {
63
- totalOriginal: 0,
64
- totalCompressed: 0,
65
- totalSaved: 0,
66
- avgRatio: 0
67
- }
68
- };
69
- }
70
- } catch (error) {
71
- console.error('데이터 로드 중 오류 발생:', error);
72
- this.data = this.getDefaultData();
73
- }
74
- }
75
-
76
- /**
77
- * 기본 데이터 구조를 반환합니다
78
- * @returns {Object} 기본 데이터 구조
79
- */
80
- getDefaultData() {
81
- return {
82
- totalTokens: 0,
83
- sessionsCount: 0,
84
- lastUpdated: Date.now(),
85
- dailyUsage: {},
86
- commandStats: {},
87
- compressionStats: {
88
- totalOriginal: 0,
89
- totalCompressed: 0,
90
- totalSaved: 0,
91
- avgRatio: 0
92
- }
93
- };
94
- }
95
-
96
- /**
97
- * 데이터를 저장합니다
98
- */
99
- saveData() {
100
- try {
101
- this.data.lastUpdated = Date.now();
102
- fs.writeFileSync(this.dataFile, JSON.stringify(this.data, null, 2));
103
- } catch (error) {
104
- console.error('데이터 저장 중 오류 발생:', error);
105
- }
106
- }
107
-
108
- /**
109
- * 세션 토큰 사용량을 기록합니다
110
- * @param {Object} sessionData - 세션 데이터
111
- */
112
- recordSessionUsage(sessionData) {
113
- try {
114
- const today = new Date().toISOString().split('T')[0];
115
-
116
- // 총 토큰 수 업데이트
117
- this.data.totalTokens += sessionData.totalTokens;
118
- this.data.sessionsCount++;
119
-
120
- // 일일 사용량 업데이트
121
- if (!this.data.dailyUsage[today]) {
122
- this.data.dailyUsage[today] = {
123
- tokens: 0,
124
- sessions: 0,
125
- commands: 0
126
- };
127
- }
128
-
129
- this.data.dailyUsage[today].tokens += sessionData.totalTokens;
130
- this.data.dailyUsage[today].sessions++;
131
- this.data.dailyUsage[today].commands += sessionData.commands.length;
132
-
133
- // 명령어별 통계 업데이트
134
- for (const command of sessionData.commands) {
135
- if (!this.data.commandStats[command.command]) {
136
- this.data.commandStats[command.command] = {
137
- count: 0,
138
- totalTokens: 0,
139
- avgTokens: 0
140
- };
141
- }
142
-
143
- const stats = this.data.commandStats[command.command];
144
- stats.count++;
145
- stats.totalTokens += command.totalTokens;
146
- stats.avgTokens = Math.round(stats.totalTokens / stats.count);
147
- }
148
-
149
- // 압축 통계 업데이트
150
- if (sessionData.compressions) {
151
- for (const compression of sessionData.compressions) {
152
- this.data.compressionStats.totalOriginal += compression.originalTokens;
153
- this.data.compressionStats.totalCompressed += compression.compressedTokens;
154
- this.data.compressionStats.totalSaved += compression.savedTokens;
155
- }
156
-
157
- // 평균 압축률 계산
158
- if (this.data.compressionStats.totalOriginal > 0) {
159
- this.data.compressionStats.avgRatio =
160
- (this.data.compressionStats.totalSaved / this.data.compressionStats.totalOriginal) * 100;
161
- }
162
- }
163
-
164
- this.saveData();
165
- } catch (error) {
166
- console.error('세션 사용량 기록 중 오류 발생:', error);
167
- }
168
- }
169
-
170
- /**
171
- * 토큰 사용량 보고서를 생성합니다
172
- * @param {string} type - 보고서 타입 ('daily', 'weekly', 'monthly')
173
- * @returns {Object} 보고서 데이터
174
- */
175
- generateUsageReport(type = 'daily') {
176
- try {
177
- const report = {
178
- type,
179
- generatedAt: Date.now(),
180
- period: this.getPeriod(type),
181
- summary: {
182
- totalTokens: this.data.totalTokens,
183
- totalSessions: this.data.sessionsCount,
184
- avgTokensPerSession: this.data.sessionsCount > 0 ?
185
- Math.round(this.data.totalTokens / this.data.sessionsCount) : 0
186
- },
187
- dailyUsage: this.getDailyUsageForPeriod(type),
188
- topCommands: this.getTopCommands(10),
189
- compressionStats: this.data.compressionStats,
190
- trends: this.calculateTrends(type)
191
- };
192
-
193
- // 보고서 저장
194
- const reportFile = path.join(this.reportsDir, `${type}_report_${Date.now()}.json`);
195
- fs.writeFileSync(reportFile, JSON.stringify(report, null, 2));
196
-
197
- return report;
198
- } catch (error) {
199
- console.error('보고서 생성 중 오류 발생:', error);
200
- return null;
201
- }
202
- }
203
-
204
- /**
205
- * 기간에 따른 일일 사용량을 조회합니다
206
- * @param {string} type - 기간 타입
207
- * @returns {Object} 일일 사용량 데이터
208
- */
209
- getDailyUsageForPeriod(type) {
210
- const days = type === 'weekly' ? 7 : type === 'monthly' ? 30 : 1;
211
- const result = {};
212
-
213
- for (let i = 0; i < days; i++) {
214
- const date = new Date();
215
- date.setDate(date.getDate() - i);
216
- const dateStr = date.toISOString().split('T')[0];
217
-
218
- result[dateStr] = this.data.dailyUsage[dateStr] || {
219
- tokens: 0,
220
- sessions: 0,
221
- commands: 0
222
- };
223
- }
224
-
225
- return result;
226
- }
227
-
228
- /**
229
- * 가장 많이 사용된 명령어를 조회합니다
230
- * @param {number} limit - 조회할 명령어 수
231
- * @returns {Array<Object>} 상위 명령어 목록
232
- */
233
- getTopCommands(limit = 10) {
234
- try {
235
- return Object.entries(this.data.commandStats)
236
- .sort((a, b) => b[1].totalTokens - a[1].totalTokens)
237
- .slice(0, limit)
238
- .map(([command, stats]) => ({
239
- command,
240
- count: stats.count,
241
- totalTokens: stats.totalTokens,
242
- avgTokens: stats.avgTokens
243
- }));
244
- } catch (error) {
245
- console.error('상위 명령어 조회 중 오류 발생:', error);
246
- return [];
247
- }
248
- }
249
-
250
- /**
251
- * 사용량 트렌드를 계산합니다
252
- * @param {string} type - 기간 타입
253
- * @returns {Object} 트렌드 데이터
254
- */
255
- calculateTrends(type) {
256
- try {
257
- const dailyUsage = this.getDailyUsageForPeriod(type);
258
- const values = Object.values(dailyUsage).map(day => day.tokens);
259
-
260
- if (values.length < 2) {
261
- return { trend: 'insufficient_data', change: 0 };
262
- }
263
-
264
- const recent = values.slice(0, Math.floor(values.length / 2));
265
- const older = values.slice(Math.floor(values.length / 2));
266
-
267
- const recentAvg = recent.reduce((sum, val) => sum + val, 0) / recent.length;
268
- const olderAvg = older.reduce((sum, val) => sum + val, 0) / older.length;
269
-
270
- const change = olderAvg > 0 ? ((recentAvg - olderAvg) / olderAvg) * 100 : 0;
271
-
272
- return {
273
- trend: change > 10 ? 'increasing' : change < -10 ? 'decreasing' : 'stable',
274
- change: Math.round(change),
275
- recentAvg: Math.round(recentAvg),
276
- olderAvg: Math.round(olderAvg)
277
- };
278
- } catch (error) {
279
- console.error('트렌드 계산 중 오류 발생:', error);
280
- return { trend: 'error', change: 0 };
281
- }
282
- }
283
-
284
- /**
285
- * 기간 정보를 반환합니다
286
- * @param {string} type - 기간 타입
287
- * @returns {Object} 기간 정보
288
- */
289
- getPeriod(type) {
290
- const now = new Date();
291
- const start = new Date(now);
292
-
293
- switch (type) {
294
- case 'weekly':
295
- start.setDate(now.getDate() - 7);
296
- break;
297
- case 'monthly':
298
- start.setMonth(now.getMonth() - 1);
299
- break;
300
- default:
301
- start.setDate(now.getDate() - 1);
302
- }
303
-
304
- return {
305
- start: start.toISOString().split('T')[0],
306
- end: now.toISOString().split('T')[0]
307
- };
308
- }
309
-
310
- /**
311
- * 임계값을 확인합니다
312
- * @param {Object} thresholds - 임계값 설정
313
- * @returns {Array<Object>} 임계값 위반 목록
314
- */
315
- checkThresholds(thresholds) {
316
- const violations = [];
317
- const today = new Date().toISOString().split('T')[0];
318
- const todayUsage = this.data.dailyUsage[today] || { tokens: 0, sessions: 0 };
319
-
320
- try {
321
- // 일일 토큰 한도 확인
322
- if (thresholds.dailyTokenLimit && todayUsage.tokens > thresholds.dailyTokenLimit) {
323
- violations.push({
324
- type: 'daily_token_limit',
325
- threshold: thresholds.dailyTokenLimit,
326
- current: todayUsage.tokens,
327
- message: `일일 토큰 한도(${thresholds.dailyTokenLimit})를 초과했습니다: ${todayUsage.tokens}`
328
- });
329
- }
330
-
331
- // 일일 세션 한도 확인
332
- if (thresholds.dailySessionLimit && todayUsage.sessions > thresholds.dailySessionLimit) {
333
- violations.push({
334
- type: 'daily_session_limit',
335
- threshold: thresholds.dailySessionLimit,
336
- current: todayUsage.sessions,
337
- message: `일일 세션 한도(${thresholds.dailySessionLimit})를 초과했습니다: ${todayUsage.sessions}`
338
- });
339
- }
340
-
341
- // 경고 임계값 확인
342
- if (thresholds.warningThreshold) {
343
- const warningLimit = thresholds.dailyTokenLimit * (thresholds.warningThreshold / 100);
344
- if (todayUsage.tokens > warningLimit) {
345
- violations.push({
346
- type: 'warning_threshold',
347
- threshold: warningLimit,
348
- current: todayUsage.tokens,
349
- message: `경고 임계값(${Math.round(warningLimit)})을 초과했습니다: ${todayUsage.tokens}`
350
- });
351
- }
352
- }
353
- } catch (error) {
354
- console.error('임계값 확인 중 오류 발생:', error);
355
- }
356
-
357
- return violations;
358
- }
359
-
360
- /**
361
- * 저장된 보고서 목록을 조회합니다
362
- * @returns {Array<Object>} 보고서 목록
363
- */
364
- getReportsList() {
365
- try {
366
- const reports = [];
367
- const files = fs.readdirSync(this.reportsDir);
368
-
369
- for (const file of files) {
370
- if (file.endsWith('.json')) {
371
- const filePath = path.join(this.reportsDir, file);
372
- const stats = fs.statSync(filePath);
373
-
374
- reports.push({
375
- filename: file,
376
- path: filePath,
377
- size: stats.size,
378
- created: stats.birthtime,
379
- modified: stats.mtime
380
- });
381
- }
382
- }
383
-
384
- return reports.sort((a, b) => b.created - a.created);
385
- } catch (error) {
386
- console.error('보고서 목록 조회 중 오류 발생:', error);
387
- return [];
388
- }
389
- }
390
-
391
- /**
392
- * 오래된 보고서를 정리합니다
393
- * @param {number} daysToKeep - 보관할 일수
394
- */
395
- cleanupOldReports(daysToKeep = 30) {
396
- try {
397
- const cutoffTime = Date.now() - (daysToKeep * 24 * 60 * 60 * 1000);
398
- const files = fs.readdirSync(this.reportsDir);
399
- let deletedCount = 0;
400
-
401
- for (const file of files) {
402
- if (file.endsWith('.json')) {
403
- const filePath = path.join(this.reportsDir, file);
404
- const stats = fs.statSync(filePath);
405
-
406
- if (stats.birthtime.getTime() < cutoffTime) {
407
- fs.unlinkSync(filePath);
408
- deletedCount++;
409
- }
410
- }
411
- }
412
-
413
- console.log(`${deletedCount}개의 오래된 보고서를 정리했습니다.`);
414
- } catch (error) {
415
- console.error('보고서 정리 중 오류 발생:', error);
416
- }
417
- }
418
-
419
- /**
420
- * 모든 데이터를 초기화합니다
421
- */
422
- resetData() {
423
- try {
424
- this.data = this.getDefaultData();
425
- this.saveData();
426
- console.log('토큰 사용량 데이터가 초기화되었습니다.');
427
- } catch (error) {
428
- console.error('데이터 초기화 중 오류 발생:', error);
429
- }
430
- }
431
- }
432
-
433
- export default TokenStorage;
@@ -1,283 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { TokenCounter } from './token-counter.js';
4
-
5
- /**
6
- * 세션별 토큰 사용량을 추적하는 클래스
7
- */
8
- export class TokenTracker {
9
- constructor(sessionDir = '.aiwf/sessions') {
10
- this.sessionDir = sessionDir;
11
- this.sessionId = this.generateSessionId();
12
- this.counter = new TokenCounter();
13
- this.usage = {
14
- total: 0,
15
- compressed: 0,
16
- saved: 0,
17
- ratio: 0
18
- };
19
- this.sessionData = {
20
- sessionId: this.sessionId,
21
- startTime: Date.now(),
22
- totalTokens: 0,
23
- commands: [],
24
- lastUpdated: Date.now()
25
- };
26
-
27
- this.ensureSessionDirectory();
28
- this.loadSession();
29
- }
30
-
31
- /**
32
- * 세션 ID를 생성합니다
33
- * @returns {string} 세션 ID
34
- */
35
- generateSessionId() {
36
- const timestamp = Date.now();
37
- const random = Math.random().toString(36).substr(2, 9);
38
- return `session_${timestamp}_${random}`;
39
- }
40
-
41
- /**
42
- * 세션 디렉토리를 생성합니다
43
- */
44
- ensureSessionDirectory() {
45
- try {
46
- if (!fs.existsSync(this.sessionDir)) {
47
- fs.mkdirSync(this.sessionDir, { recursive: true });
48
- }
49
- } catch (error) {
50
- console.error('세션 디렉토리 생성 중 오류 발생:', error);
51
- }
52
- }
53
-
54
- /**
55
- * 세션 데이터를 로드합니다
56
- */
57
- loadSession() {
58
- try {
59
- const sessionFile = path.join(this.sessionDir, `${this.sessionId}.json`);
60
-
61
- if (fs.existsSync(sessionFile)) {
62
- const data = JSON.parse(fs.readFileSync(sessionFile, 'utf8'));
63
- this.sessionData = { ...this.sessionData, ...data };
64
- }
65
- } catch (error) {
66
- console.error('세션 로드 중 오류 발생:', error);
67
- }
68
- }
69
-
70
- /**
71
- * 세션 데이터를 저장합니다
72
- */
73
- saveSession() {
74
- try {
75
- const sessionFile = path.join(this.sessionDir, `${this.sessionId}.json`);
76
- this.sessionData.lastUpdated = Date.now();
77
-
78
- fs.writeFileSync(sessionFile, JSON.stringify(this.sessionData, null, 2));
79
- } catch (error) {
80
- console.error('세션 저장 중 오류 발생:', error);
81
- }
82
- }
83
-
84
- /**
85
- * 명령어 실행 토큰 사용량을 추적합니다
86
- * @param {string} command - 실행된 명령어
87
- * @param {string} input - 입력 텍스트
88
- * @param {string} output - 출력 텍스트
89
- */
90
- trackCommand(command, input = '', output = '') {
91
- try {
92
- const inputTokens = this.counter.countTokens(input);
93
- const outputTokens = this.counter.countTokens(output);
94
- const totalTokens = inputTokens + outputTokens;
95
-
96
- const commandEntry = {
97
- timestamp: Date.now(),
98
- command,
99
- inputTokens,
100
- outputTokens,
101
- totalTokens
102
- };
103
-
104
- this.sessionData.commands.push(commandEntry);
105
- this.sessionData.totalTokens += totalTokens;
106
-
107
- this.saveSession();
108
-
109
- return commandEntry;
110
- } catch (error) {
111
- console.error('명령어 토큰 추적 중 오류 발생:', error);
112
- return null;
113
- }
114
- }
115
-
116
- /**
117
- * 압축 전후 토큰 수를 기록합니다
118
- * @param {number} originalTokens - 원본 토큰 수
119
- * @param {number} compressedTokens - 압축된 토큰 수
120
- */
121
- trackCompression(originalTokens, compressedTokens) {
122
- try {
123
- this.usage.total = originalTokens;
124
- this.usage.compressed = compressedTokens;
125
- this.usage.saved = originalTokens - compressedTokens;
126
- this.usage.ratio = originalTokens > 0 ? (this.usage.saved / originalTokens) * 100 : 0;
127
-
128
- // 세션 데이터에 압축 정보 추가
129
- if (!this.sessionData.compressions) {
130
- this.sessionData.compressions = [];
131
- }
132
-
133
- this.sessionData.compressions.push({
134
- timestamp: Date.now(),
135
- originalTokens,
136
- compressedTokens,
137
- savedTokens: this.usage.saved,
138
- ratio: this.usage.ratio
139
- });
140
-
141
- this.saveSession();
142
- } catch (error) {
143
- console.error('압축 토큰 추적 중 오류 발생:', error);
144
- }
145
- }
146
-
147
- /**
148
- * 토큰 사용량 보고서를 생성합니다
149
- * @returns {Object} 토큰 사용량 보고서
150
- */
151
- generateReport() {
152
- try {
153
- const sessionDuration = Date.now() - this.sessionData.startTime;
154
- const avgTokensPerCommand = this.sessionData.commands.length > 0
155
- ? this.sessionData.totalTokens / this.sessionData.commands.length
156
- : 0;
157
-
158
- return {
159
- sessionId: this.sessionId,
160
- sessionDuration: this.formatDuration(sessionDuration),
161
- totalCommands: this.sessionData.commands.length,
162
- totalTokens: this.sessionData.totalTokens,
163
- avgTokensPerCommand: Math.round(avgTokensPerCommand),
164
- compressionStats: this.usage.total > 0 ? {
165
- originalTokens: this.usage.total,
166
- compressedTokens: this.usage.compressed,
167
- savedTokens: this.usage.saved,
168
- compressionRatio: this.usage.ratio.toFixed(2) + '%',
169
- efficiency: this.usage.ratio >= 50 ? 'High' : this.usage.ratio >= 25 ? 'Medium' : 'Low'
170
- } : null,
171
- recentCommands: this.sessionData.commands.slice(-5),
172
- startTime: new Date(this.sessionData.startTime).toLocaleString(),
173
- lastUpdated: new Date(this.sessionData.lastUpdated).toLocaleString()
174
- };
175
- } catch (error) {
176
- console.error('보고서 생성 중 오류 발생:', error);
177
- return null;
178
- }
179
- }
180
-
181
- /**
182
- * 시간 간격을 사람이 읽기 쉬운 형태로 변환합니다
183
- * @param {number} ms - 밀리초
184
- * @returns {string} 포맷된 시간
185
- */
186
- formatDuration(ms) {
187
- const seconds = Math.floor(ms / 1000);
188
- const minutes = Math.floor(seconds / 60);
189
- const hours = Math.floor(minutes / 60);
190
-
191
- if (hours > 0) {
192
- return `${hours}시간 ${minutes % 60}분`;
193
- } else if (minutes > 0) {
194
- return `${minutes}분 ${seconds % 60}초`;
195
- } else {
196
- return `${seconds}초`;
197
- }
198
- }
199
-
200
- /**
201
- * 세션 통계를 조회합니다
202
- * @returns {Object} 세션 통계
203
- */
204
- getSessionStats() {
205
- try {
206
- return {
207
- sessionId: this.sessionId,
208
- totalTokens: this.sessionData.totalTokens,
209
- commandCount: this.sessionData.commands.length,
210
- sessionDuration: Date.now() - this.sessionData.startTime,
211
- lastActivity: this.sessionData.lastUpdated
212
- };
213
- } catch (error) {
214
- console.error('세션 통계 조회 중 오류 발생:', error);
215
- return null;
216
- }
217
- }
218
-
219
- /**
220
- * 모든 세션 데이터를 조회합니다
221
- * @returns {Array<Object>} 세션 목록
222
- */
223
- getAllSessions() {
224
- try {
225
- const sessions = [];
226
- const files = fs.readdirSync(this.sessionDir);
227
-
228
- for (const file of files) {
229
- if (file.endsWith('.json')) {
230
- const sessionData = JSON.parse(
231
- fs.readFileSync(path.join(this.sessionDir, file), 'utf8')
232
- );
233
- sessions.push(sessionData);
234
- }
235
- }
236
-
237
- return sessions.sort((a, b) => b.startTime - a.startTime);
238
- } catch (error) {
239
- console.error('세션 목록 조회 중 오류 발생:', error);
240
- return [];
241
- }
242
- }
243
-
244
- /**
245
- * 오래된 세션을 정리합니다
246
- * @param {number} daysToKeep - 보관할 일수 (기본: 7일)
247
- */
248
- cleanupOldSessions(daysToKeep = 7) {
249
- try {
250
- const cutoffTime = Date.now() - (daysToKeep * 24 * 60 * 60 * 1000);
251
- const files = fs.readdirSync(this.sessionDir);
252
- let deletedCount = 0;
253
-
254
- for (const file of files) {
255
- if (file.endsWith('.json')) {
256
- const filePath = path.join(this.sessionDir, file);
257
- const sessionData = JSON.parse(fs.readFileSync(filePath, 'utf8'));
258
-
259
- if (sessionData.startTime < cutoffTime) {
260
- fs.unlinkSync(filePath);
261
- deletedCount++;
262
- }
263
- }
264
- }
265
-
266
- console.log(`${deletedCount}개의 오래된 세션을 정리했습니다.`);
267
- } catch (error) {
268
- console.error('세션 정리 중 오류 발생:', error);
269
- }
270
- }
271
-
272
- /**
273
- * 리소스를 정리합니다
274
- */
275
- cleanup() {
276
- this.saveSession();
277
- if (this.counter) {
278
- this.counter.cleanup();
279
- }
280
- }
281
- }
282
-
283
- export default TokenTracker;