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,645 +0,0 @@
1
- import { TokenCounter } from './token-counter.js';
2
-
3
- /**
4
- * 중요도 분류 및 점수 계산 시스템
5
- */
6
- export class ImportanceClassifier {
7
- constructor() {
8
- this.tokenCounter = new TokenCounter();
9
- this.initializeWeights();
10
- }
11
-
12
- /**
13
- * 가중치 및 기준을 초기화합니다
14
- */
15
- initializeWeights() {
16
- // 중요도 레벨 정의
17
- this.importanceLevels = {
18
- critical: { weight: 1.0, threshold: 8 },
19
- high: { weight: 0.8, threshold: 5 },
20
- medium: { weight: 0.6, threshold: 3 },
21
- low: { weight: 0.4, threshold: 0 }
22
- };
23
-
24
- // 키워드 가중치
25
- this.keywordWeights = {
26
- critical: {
27
- keywords: ['urgent', 'critical', 'blocking', 'error', 'failed', 'must', 'required', 'essential'],
28
- weight: 5,
29
- multiplier: 1.5
30
- },
31
- high: {
32
- keywords: ['important', 'priority', 'deadline', 'milestone', 'goal', 'objective', 'key', 'main'],
33
- weight: 4,
34
- multiplier: 1.3
35
- },
36
- medium: {
37
- keywords: ['enhancement', 'improvement', 'optimize', 'should', 'planned', 'task', 'feature'],
38
- weight: 3,
39
- multiplier: 1.1
40
- },
41
- low: {
42
- keywords: ['nice-to-have', 'future', 'consider', 'optional', 'example', 'note'],
43
- weight: 2,
44
- multiplier: 1.0
45
- }
46
- };
47
-
48
- // 한국어 키워드 가중치
49
- this.koreanKeywordWeights = {
50
- critical: {
51
- keywords: ['긴급', '중대', '차단', '오류', '실패', '필수', '요구', '필수적'],
52
- weight: 5,
53
- multiplier: 1.5
54
- },
55
- high: {
56
- keywords: ['중요', '우선순위', '마감일', '마일스톤', '목표', '목적', '핵심', '주요'],
57
- weight: 4,
58
- multiplier: 1.3
59
- },
60
- medium: {
61
- keywords: ['개선', '향상', '최적화', '해야', '계획된', '태스크', '기능'],
62
- weight: 3,
63
- multiplier: 1.1
64
- },
65
- low: {
66
- keywords: ['좋으면', '미래', '고려', '선택적', '예시', '참고'],
67
- weight: 2,
68
- multiplier: 1.0
69
- }
70
- };
71
-
72
- // 섹션 타입 가중치
73
- this.sectionWeights = {
74
- critical: {
75
- sections: ['subtasks', 'acceptance criteria', 'requirements', 'goal', 'objectives', 'current sprint', 'active tasks'],
76
- weight: 5
77
- },
78
- high: {
79
- sections: ['description', 'specifications', 'architecture', 'implementation', 'planned tasks'],
80
- weight: 4
81
- },
82
- medium: {
83
- sections: ['testing', 'documentation', 'notes', 'examples', 'guidelines'],
84
- weight: 3
85
- },
86
- low: {
87
- sections: ['output log', 'history', 'templates', 'completed tasks', 'old logs'],
88
- weight: 2
89
- }
90
- };
91
-
92
- // 구조적 가중치
93
- this.structuralWeights = {
94
- header: {
95
- levels: {
96
- 1: 5, // # 메인 헤더
97
- 2: 4, // ## 섹션 헤더
98
- 3: 3, // ### 서브섹션
99
- 4: 2, // #### 세부사항
100
- 5: 1, // ##### 최하위
101
- 6: 1 // ###### 최하위
102
- }
103
- },
104
- list: {
105
- checkbox_unchecked: 4, // - [ ] 미완료 체크박스
106
- checkbox_checked: 2, // - [x] 완료 체크박스
107
- bullet: 2, // - 불릿 포인트
108
- numbered: 2 // 1. 번호 목록
109
- },
110
- emphasis: {
111
- bold: 2, // **굵게**
112
- italic: 1, // *기울임*
113
- code: 1, // `코드`
114
- link: 1 // [링크]
115
- }
116
- };
117
-
118
- // 위치 가중치
119
- this.positionWeights = {
120
- start: 1.2, // 문서 시작 부분
121
- middle: 1.0, // 문서 중간 부분
122
- end: 0.8 // 문서 끝 부분
123
- };
124
-
125
- // 길이 가중치
126
- this.lengthWeights = {
127
- optimal: { min: 30, max: 150, weight: 1.2 },
128
- acceptable: { min: 15, max: 300, weight: 1.0 },
129
- penalty: { min: 0, max: 500, weight: 0.8 }
130
- };
131
- }
132
-
133
- /**
134
- * 콘텐츠의 중요도를 분석합니다
135
- * @param {string} content - 분석할 콘텐츠
136
- * @param {Object} options - 분석 옵션
137
- * @returns {Object} 중요도 분석 결과
138
- */
139
- analyzeImportance(content, options = {}) {
140
- const {
141
- preserveStructure = true,
142
- includeMetadata = true,
143
- detailedScoring = false
144
- } = options;
145
-
146
- const sections = this.parseContentSections(content);
147
- const analyzedSections = sections.map((section, index) => {
148
- const score = this.calculateSectionScore(section, index, sections.length);
149
- const importance = this.scoreToImportance(score);
150
-
151
- return {
152
- ...section,
153
- score,
154
- importance,
155
- tokens: this.tokenCounter.countTokens(section.content),
156
- ...(detailedScoring && { scoreBreakdown: this.getScoreBreakdown(section, index, sections.length) })
157
- };
158
- });
159
-
160
- // 중요도별 정렬
161
- const sortedSections = analyzedSections.sort((a, b) => b.score - a.score);
162
-
163
- const result = {
164
- sections: preserveStructure ? analyzedSections : sortedSections,
165
- summary: this.generateImportanceSummary(analyzedSections),
166
- recommendations: this.generateRecommendations(analyzedSections)
167
- };
168
-
169
- if (includeMetadata) {
170
- result.metadata = this.generateMetadata(analyzedSections, content);
171
- }
172
-
173
- return result;
174
- }
175
-
176
- /**
177
- * 콘텐츠를 섹션으로 파싱합니다
178
- * @param {string} content - 파싱할 콘텐츠
179
- * @returns {Array<Object>} 섹션 배열
180
- */
181
- parseContentSections(content) {
182
- const sections = [];
183
- const lines = content.split('\n');
184
- let currentSection = null;
185
- let currentContent = [];
186
- let currentLevel = 0;
187
-
188
- for (let i = 0; i < lines.length; i++) {
189
- const line = lines[i];
190
- const headerMatch = line.match(/^(#{1,6})\s+(.+)$/);
191
-
192
- if (headerMatch) {
193
- // 이전 섹션 저장
194
- if (currentSection) {
195
- sections.push({
196
- name: currentSection,
197
- level: currentLevel,
198
- content: currentContent.join('\n').trim(),
199
- type: this.identifySectionType(currentSection),
200
- startLine: i - currentContent.length,
201
- endLine: i - 1
202
- });
203
- }
204
-
205
- // 새 섹션 시작
206
- currentLevel = headerMatch[1].length;
207
- currentSection = headerMatch[2].trim();
208
- currentContent = [line];
209
- } else {
210
- if (currentSection) {
211
- currentContent.push(line);
212
- } else {
213
- // 헤더가 없는 초기 콘텐츠
214
- if (line.trim()) {
215
- if (!currentSection) {
216
- currentSection = 'Introduction';
217
- currentLevel = 1;
218
- currentContent = [];
219
- }
220
- currentContent.push(line);
221
- }
222
- }
223
- }
224
- }
225
-
226
- // 마지막 섹션 저장
227
- if (currentSection) {
228
- sections.push({
229
- name: currentSection,
230
- level: currentLevel,
231
- content: currentContent.join('\n').trim(),
232
- type: this.identifySectionType(currentSection),
233
- startLine: lines.length - currentContent.length,
234
- endLine: lines.length - 1
235
- });
236
- }
237
-
238
- return sections;
239
- }
240
-
241
- /**
242
- * 섹션 타입을 식별합니다
243
- * @param {string} sectionName - 섹션 이름
244
- * @returns {string} 섹션 타입
245
- */
246
- identifySectionType(sectionName) {
247
- const lowerName = sectionName.toLowerCase();
248
-
249
- for (const [importance, config] of Object.entries(this.sectionWeights)) {
250
- for (const sectionType of config.sections) {
251
- if (lowerName.includes(sectionType.toLowerCase())) {
252
- return sectionType;
253
- }
254
- }
255
- }
256
-
257
- return 'general';
258
- }
259
-
260
- /**
261
- * 섹션의 점수를 계산합니다
262
- * @param {Object} section - 섹션 객체
263
- * @param {number} index - 섹션 인덱스
264
- * @param {number} totalSections - 전체 섹션 수
265
- * @returns {number} 점수
266
- */
267
- calculateSectionScore(section, index, totalSections) {
268
- let score = 0;
269
- const content = section.content;
270
- const lowerContent = content.toLowerCase();
271
-
272
- // 1. 키워드 기반 점수
273
- score += this.calculateKeywordScore(lowerContent);
274
-
275
- // 2. 섹션 타입 기반 점수
276
- score += this.calculateSectionTypeScore(section.type);
277
-
278
- // 3. 구조적 점수
279
- score += this.calculateStructuralScore(content);
280
-
281
- // 4. 위치 기반 점수
282
- score += this.calculatePositionScore(index, totalSections);
283
-
284
- // 5. 길이 기반 점수
285
- score += this.calculateLengthScore(content);
286
-
287
- // 6. 헤더 레벨 점수
288
- score += this.calculateHeaderLevelScore(section.level);
289
-
290
- // 7. 특수 패턴 점수
291
- score += this.calculateSpecialPatternScore(content);
292
-
293
- return Math.max(0, score);
294
- }
295
-
296
- /**
297
- * 키워드 기반 점수를 계산합니다
298
- * @param {string} content - 콘텐츠
299
- * @returns {number} 키워드 점수
300
- */
301
- calculateKeywordScore(content) {
302
- let score = 0;
303
-
304
- // 영어 키워드 점수
305
- for (const [level, config] of Object.entries(this.keywordWeights)) {
306
- for (const keyword of config.keywords) {
307
- const regex = new RegExp(`\\b${keyword}\\b`, 'gi');
308
- const matches = content.match(regex);
309
- if (matches) {
310
- score += matches.length * config.weight * config.multiplier;
311
- }
312
- }
313
- }
314
-
315
- // 한국어 키워드 점수
316
- for (const [level, config] of Object.entries(this.koreanKeywordWeights)) {
317
- for (const keyword of config.keywords) {
318
- const regex = new RegExp(keyword, 'gi');
319
- const matches = content.match(regex);
320
- if (matches) {
321
- score += matches.length * config.weight * config.multiplier;
322
- }
323
- }
324
- }
325
-
326
- return score;
327
- }
328
-
329
- /**
330
- * 섹션 타입 기반 점수를 계산합니다
331
- * @param {string} sectionType - 섹션 타입
332
- * @returns {number} 섹션 타입 점수
333
- */
334
- calculateSectionTypeScore(sectionType) {
335
- for (const [importance, config] of Object.entries(this.sectionWeights)) {
336
- if (config.sections.includes(sectionType)) {
337
- return config.weight;
338
- }
339
- }
340
- return 1; // 기본 점수
341
- }
342
-
343
- /**
344
- * 구조적 점수를 계산합니다
345
- * @param {string} content - 콘텐츠
346
- * @returns {number} 구조적 점수
347
- */
348
- calculateStructuralScore(content) {
349
- let score = 0;
350
-
351
- // 체크박스 점수
352
- const uncheckedCheckboxes = content.match(/- \[ \]/g);
353
- if (uncheckedCheckboxes) {
354
- score += uncheckedCheckboxes.length * this.structuralWeights.list.checkbox_unchecked;
355
- }
356
-
357
- const checkedCheckboxes = content.match(/- \[x\]/gi);
358
- if (checkedCheckboxes) {
359
- score += checkedCheckboxes.length * this.structuralWeights.list.checkbox_checked;
360
- }
361
-
362
- // 불릿 포인트 점수
363
- const bulletPoints = content.match(/^\s*[-*+]\s+/gm);
364
- if (bulletPoints) {
365
- score += bulletPoints.length * this.structuralWeights.list.bullet;
366
- }
367
-
368
- // 번호 목록 점수
369
- const numberedLists = content.match(/^\s*\d+\.\s+/gm);
370
- if (numberedLists) {
371
- score += numberedLists.length * this.structuralWeights.list.numbered;
372
- }
373
-
374
- // 강조 표시 점수
375
- const boldText = content.match(/\*\*[^*]+\*\*/g);
376
- if (boldText) {
377
- score += boldText.length * this.structuralWeights.emphasis.bold;
378
- }
379
-
380
- const italicText = content.match(/\*[^*]+\*/g);
381
- if (italicText) {
382
- score += italicText.length * this.structuralWeights.emphasis.italic;
383
- }
384
-
385
- const codeText = content.match(/`[^`]+`/g);
386
- if (codeText) {
387
- score += codeText.length * this.structuralWeights.emphasis.code;
388
- }
389
-
390
- const links = content.match(/\[[^\]]+\]\([^)]+\)/g);
391
- if (links) {
392
- score += links.length * this.structuralWeights.emphasis.link;
393
- }
394
-
395
- return score;
396
- }
397
-
398
- /**
399
- * 위치 기반 점수를 계산합니다
400
- * @param {number} index - 섹션 인덱스
401
- * @param {number} totalSections - 전체 섹션 수
402
- * @returns {number} 위치 점수
403
- */
404
- calculatePositionScore(index, totalSections) {
405
- const relativePosition = index / totalSections;
406
-
407
- if (relativePosition < 0.3) {
408
- return this.positionWeights.start;
409
- } else if (relativePosition > 0.7) {
410
- return this.positionWeights.end;
411
- } else {
412
- return this.positionWeights.middle;
413
- }
414
- }
415
-
416
- /**
417
- * 길이 기반 점수를 계산합니다
418
- * @param {string} content - 콘텐츠
419
- * @returns {number} 길이 점수
420
- */
421
- calculateLengthScore(content) {
422
- const length = content.length;
423
-
424
- if (length >= this.lengthWeights.optimal.min && length <= this.lengthWeights.optimal.max) {
425
- return this.lengthWeights.optimal.weight;
426
- } else if (length >= this.lengthWeights.acceptable.min && length <= this.lengthWeights.acceptable.max) {
427
- return this.lengthWeights.acceptable.weight;
428
- } else {
429
- return this.lengthWeights.penalty.weight;
430
- }
431
- }
432
-
433
- /**
434
- * 헤더 레벨 점수를 계산합니다
435
- * @param {number} level - 헤더 레벨
436
- * @returns {number} 헤더 레벨 점수
437
- */
438
- calculateHeaderLevelScore(level) {
439
- return this.structuralWeights.header.levels[level] || 1;
440
- }
441
-
442
- /**
443
- * 특수 패턴 점수를 계산합니다
444
- * @param {string} content - 콘텐츠
445
- * @returns {number} 특수 패턴 점수
446
- */
447
- calculateSpecialPatternScore(content) {
448
- let score = 0;
449
-
450
- // 날짜 패턴 (최신성)
451
- const recentDates = content.match(/2025-\d{2}-\d{2}/g);
452
- if (recentDates) {
453
- score += recentDates.length * 2;
454
- }
455
-
456
- // 상태 패턴
457
- const statusPatterns = {
458
- 'in_progress': 4,
459
- 'pending': 3,
460
- 'completed': 1,
461
- 'planned': 2,
462
- 'blocked': 5
463
- };
464
-
465
- for (const [status, weight] of Object.entries(statusPatterns)) {
466
- if (content.includes(status)) {
467
- score += weight;
468
- }
469
- }
470
-
471
- // 수치 패턴 (메트릭, 통계)
472
- const numberPatterns = content.match(/\d+%|\d+\/\d+|\d+\.\d+/g);
473
- if (numberPatterns) {
474
- score += Math.min(numberPatterns.length * 0.5, 3); // 최대 3점
475
- }
476
-
477
- // 질문 패턴
478
- const questions = content.match(/\?/g);
479
- if (questions) {
480
- score += questions.length * 0.5;
481
- }
482
-
483
- return score;
484
- }
485
-
486
- /**
487
- * 점수를 중요도 레벨로 변환합니다
488
- * @param {number} score - 점수
489
- * @returns {string} 중요도 레벨
490
- */
491
- scoreToImportance(score) {
492
- if (score >= this.importanceLevels.critical.threshold) {
493
- return 'critical';
494
- } else if (score >= this.importanceLevels.high.threshold) {
495
- return 'high';
496
- } else if (score >= this.importanceLevels.medium.threshold) {
497
- return 'medium';
498
- } else {
499
- return 'low';
500
- }
501
- }
502
-
503
- /**
504
- * 점수 세부 분석을 제공합니다
505
- * @param {Object} section - 섹션 객체
506
- * @param {number} index - 섹션 인덱스
507
- * @param {number} totalSections - 전체 섹션 수
508
- * @returns {Object} 점수 세부 분석
509
- */
510
- getScoreBreakdown(section, index, totalSections) {
511
- const content = section.content;
512
- const lowerContent = content.toLowerCase();
513
-
514
- return {
515
- keyword: this.calculateKeywordScore(lowerContent),
516
- sectionType: this.calculateSectionTypeScore(section.type),
517
- structural: this.calculateStructuralScore(content),
518
- position: this.calculatePositionScore(index, totalSections),
519
- length: this.calculateLengthScore(content),
520
- headerLevel: this.calculateHeaderLevelScore(section.level),
521
- specialPattern: this.calculateSpecialPatternScore(content)
522
- };
523
- }
524
-
525
- /**
526
- * 중요도 요약을 생성합니다
527
- * @param {Array<Object>} sections - 분석된 섹션 배열
528
- * @returns {Object} 중요도 요약
529
- */
530
- generateImportanceSummary(sections) {
531
- const summary = {
532
- total: sections.length,
533
- critical: 0,
534
- high: 0,
535
- medium: 0,
536
- low: 0,
537
- averageScore: 0,
538
- maxScore: 0,
539
- minScore: Infinity,
540
- totalTokens: 0
541
- };
542
-
543
- let totalScore = 0;
544
-
545
- sections.forEach(section => {
546
- summary[section.importance]++;
547
- summary.totalTokens += section.tokens;
548
- totalScore += section.score;
549
- summary.maxScore = Math.max(summary.maxScore, section.score);
550
- summary.minScore = Math.min(summary.minScore, section.score);
551
- });
552
-
553
- summary.averageScore = totalScore / sections.length;
554
- summary.minScore = summary.minScore === Infinity ? 0 : summary.minScore;
555
-
556
- // 백분율 계산
557
- summary.percentages = {
558
- critical: (summary.critical / summary.total) * 100,
559
- high: (summary.high / summary.total) * 100,
560
- medium: (summary.medium / summary.total) * 100,
561
- low: (summary.low / summary.total) * 100
562
- };
563
-
564
- return summary;
565
- }
566
-
567
- /**
568
- * 압축 권장사항을 생성합니다
569
- * @param {Array<Object>} sections - 분석된 섹션 배열
570
- * @returns {Object} 압축 권장사항
571
- */
572
- generateRecommendations(sections) {
573
- const recommendations = {
574
- compressionStrategy: '',
575
- preserveSections: [],
576
- removeSections: [],
577
- compressSections: [],
578
- estimatedSavings: 0
579
- };
580
-
581
- const criticalSections = sections.filter(s => s.importance === 'critical');
582
- const highSections = sections.filter(s => s.importance === 'high');
583
- const mediumSections = sections.filter(s => s.importance === 'medium');
584
- const lowSections = sections.filter(s => s.importance === 'low');
585
-
586
- // 압축 전략 결정
587
- const totalTokens = sections.reduce((sum, s) => sum + s.tokens, 0);
588
- const lowTokens = lowSections.reduce((sum, s) => sum + s.tokens, 0);
589
- const mediumTokens = mediumSections.reduce((sum, s) => sum + s.tokens, 0);
590
-
591
- if (lowTokens / totalTokens > 0.4) {
592
- recommendations.compressionStrategy = 'aggressive';
593
- recommendations.preserveSections = [...criticalSections, ...highSections];
594
- recommendations.removeSections = lowSections;
595
- recommendations.compressSections = mediumSections;
596
- recommendations.estimatedSavings = (lowTokens + mediumTokens * 0.5) / totalTokens * 100;
597
- } else if (lowTokens / totalTokens > 0.2) {
598
- recommendations.compressionStrategy = 'balanced';
599
- recommendations.preserveSections = [...criticalSections, ...highSections, ...mediumSections];
600
- recommendations.removeSections = lowSections;
601
- recommendations.compressSections = [];
602
- recommendations.estimatedSavings = lowTokens / totalTokens * 100;
603
- } else {
604
- recommendations.compressionStrategy = 'minimal';
605
- recommendations.preserveSections = sections;
606
- recommendations.removeSections = [];
607
- recommendations.compressSections = [];
608
- recommendations.estimatedSavings = 10; // 기본 포맷 정리
609
- }
610
-
611
- return recommendations;
612
- }
613
-
614
- /**
615
- * 메타데이터를 생성합니다
616
- * @param {Array<Object>} sections - 분석된 섹션 배열
617
- * @param {string} content - 원본 콘텐츠
618
- * @returns {Object} 메타데이터
619
- */
620
- generateMetadata(sections, content) {
621
- return {
622
- analysisDate: new Date().toISOString(),
623
- totalSections: sections.length,
624
- totalTokens: this.tokenCounter.countTokens(content),
625
- averageScore: sections.reduce((sum, s) => sum + s.score, 0) / sections.length,
626
- scoreRange: {
627
- min: Math.min(...sections.map(s => s.score)),
628
- max: Math.max(...sections.map(s => s.score))
629
- },
630
- importanceDistribution: this.generateImportanceSummary(sections),
631
- processingTime: Date.now() - this.startTime || 0
632
- };
633
- }
634
-
635
- /**
636
- * 리소스를 정리합니다
637
- */
638
- cleanup() {
639
- if (this.tokenCounter) {
640
- this.tokenCounter.cleanup();
641
- }
642
- }
643
- }
644
-
645
- export default ImportanceClassifier;