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,598 +0,0 @@
1
- /**
2
- * 페르소나 인식 컨텍스트 압축기
3
- * 현재 활성화된 페르소나에 따라 압축 전략을 조정합니다
4
- */
5
-
6
- import { ContextCompressor } from './context-compressor.js';
7
- import fs from 'fs';
8
- import path from 'path';
9
- import { fileURLToPath } from 'url';
10
-
11
- const __filename = fileURLToPath(import.meta.url);
12
- const __dirname = path.dirname(__filename);
13
-
14
- export class PersonaAwareCompressor extends ContextCompressor {
15
- constructor(mode = 'balanced') {
16
- super(mode);
17
- this.currentPersona = null;
18
- this.personaStrategies = this.initializePersonaStrategies();
19
- }
20
-
21
- /**
22
- * 페르소나별 압축 전략 초기화
23
- */
24
- initializePersonaStrategies() {
25
- return {
26
- architect: {
27
- preservePatterns: [
28
- '시스템', '아키텍처', '설계', '구조', '패턴', '확장성',
29
- 'API', 'interface', 'component', 'module', 'layer'
30
- ],
31
- focusAreas: ['system_design', 'architecture', 'patterns'],
32
- compressionWeights: {
33
- implementation_details: 0.3, // 구현 세부사항은 적게
34
- design_concepts: 0.9, // 설계 개념은 많이 보존
35
- code_examples: 0.5, // 코드 예제는 중간
36
- theoretical_content: 0.8 // 이론적 내용은 많이 보존
37
- },
38
- summarizationFocus: 'high-level structure and design patterns'
39
- },
40
-
41
- security: {
42
- preservePatterns: [
43
- '보안', '취약점', '위협', '암호화', '인증', '권한',
44
- 'vulnerability', 'threat', 'attack', 'defense', 'exploit'
45
- ],
46
- focusAreas: ['security_threats', 'vulnerabilities', 'mitigation'],
47
- compressionWeights: {
48
- security_warnings: 1.0, // 보안 경고는 모두 보존
49
- vulnerability_details: 1.0, // 취약점 세부사항 모두 보존
50
- general_info: 0.4, // 일반 정보는 압축
51
- examples: 0.6 // 예제는 중간 정도 보존
52
- },
53
- summarizationFocus: 'security implications and mitigation strategies'
54
- },
55
-
56
- frontend: {
57
- preservePatterns: [
58
- 'UI', 'UX', '사용자', '화면', '컴포넌트', '스타일',
59
- 'react', 'vue', 'component', 'style', 'responsive', 'accessibility'
60
- ],
61
- focusAreas: ['user_interface', 'user_experience', 'visual_design'],
62
- compressionWeights: {
63
- visual_descriptions: 0.8, // 시각적 설명 많이 보존
64
- code_snippets: 0.7, // 코드 스니펫 보존
65
- backend_details: 0.2, // 백엔드 세부사항은 압축
66
- styling_info: 0.9 // 스타일링 정보 많이 보존
67
- },
68
- summarizationFocus: 'UI components and user interaction flows'
69
- },
70
-
71
- backend: {
72
- preservePatterns: [
73
- 'API', '데이터베이스', '서버', '성능', '트랜잭션', '캐시',
74
- 'endpoint', 'database', 'query', 'performance', 'optimization'
75
- ],
76
- focusAreas: ['api_design', 'data_processing', 'performance'],
77
- compressionWeights: {
78
- api_specifications: 0.9, // API 명세 많이 보존
79
- database_schemas: 0.8, // DB 스키마 보존
80
- frontend_details: 0.2, // 프론트엔드 세부사항 압축
81
- performance_metrics: 0.9 // 성능 지표 많이 보존
82
- },
83
- summarizationFocus: 'API endpoints and data flow'
84
- },
85
-
86
- data_analyst: {
87
- preservePatterns: [
88
- '데이터', '분석', '통계', '지표', '시각화', '인사이트',
89
- 'data', 'analysis', 'statistics', 'metrics', 'visualization'
90
- ],
91
- focusAreas: ['data_analysis', 'insights', 'visualization'],
92
- compressionWeights: {
93
- data_descriptions: 0.9, // 데이터 설명 많이 보존
94
- analysis_methods: 0.8, // 분석 방법 보존
95
- raw_data: 0.3, // 원시 데이터는 압축
96
- insights: 1.0, // 인사이트는 모두 보존
97
- visualizations: 0.7 // 시각화 정보 보존
98
- },
99
- summarizationFocus: 'data patterns and analytical insights'
100
- }
101
- };
102
- }
103
-
104
- /**
105
- * 현재 페르소나 로드
106
- */
107
- loadCurrentPersona() {
108
- try {
109
- const projectRoot = this.findProjectRoot();
110
- const personaPath = path.join(projectRoot, '.aiwf', 'current_persona.json');
111
-
112
- if (fs.existsSync(personaPath)) {
113
- const personaData = JSON.parse(fs.readFileSync(personaPath, 'utf8'));
114
- this.currentPersona = personaData.persona;
115
- return personaData;
116
- }
117
- } catch (error) {
118
- console.warn('페르소나 정보를 로드할 수 없습니다:', error.message);
119
- }
120
-
121
- return null;
122
- }
123
-
124
- /**
125
- * 프로젝트 루트 찾기
126
- */
127
- findProjectRoot() {
128
- let currentDir = process.cwd();
129
-
130
- while (currentDir !== path.dirname(currentDir)) {
131
- if (fs.existsSync(path.join(currentDir, '.aiwf'))) {
132
- return currentDir;
133
- }
134
- currentDir = path.dirname(currentDir);
135
- }
136
-
137
- return process.cwd();
138
- }
139
-
140
- /**
141
- * 페르소나 인식 압축 수행
142
- */
143
- async compress(content, options = {}) {
144
- // 현재 페르소나 로드
145
- const personaData = this.loadCurrentPersona();
146
-
147
- if (!personaData || !this.personaStrategies[personaData.persona]) {
148
- // 페르소나가 없으면 기본 압축 수행
149
- return super.compress(content, options);
150
- }
151
-
152
- // 페르소나별 전략 적용
153
- const strategy = this.personaStrategies[personaData.persona];
154
- const enhancedOptions = {
155
- ...options,
156
- personaStrategy: strategy,
157
- currentPersona: personaData.persona,
158
- preservePatterns: [
159
- ...(options.preservePatterns || []),
160
- ...strategy.preservePatterns
161
- ]
162
- };
163
-
164
- // 압축 수행
165
- const result = await this.performPersonaAwareCompression(content, enhancedOptions);
166
-
167
- // 페르소나 메타데이터 추가
168
- if (result.success) {
169
- result.metadata = {
170
- ...result.metadata,
171
- persona: personaData.persona,
172
- personaStrategy: {
173
- focusAreas: strategy.focusAreas,
174
- summarizationFocus: strategy.summarizationFocus
175
- }
176
- };
177
- }
178
-
179
- return result;
180
- }
181
-
182
- /**
183
- * 페르소나 인식 압축 수행
184
- */
185
- async performPersonaAwareCompression(content, options) {
186
- const { personaStrategy, currentPersona } = options;
187
-
188
- try {
189
- // 1. 컨텐츠 분석
190
- const contentAnalysis = this.analyzeContent(content, personaStrategy);
191
-
192
- // 2. 페르소나별 중요도 점수 계산
193
- const importanceScores = this.calculateImportanceScores(
194
- contentAnalysis,
195
- personaStrategy
196
- );
197
-
198
- // 3. 선택적 압축
199
- let compressed = content;
200
-
201
- // 섹션별 압축
202
- if (contentAnalysis.sections.length > 0) {
203
- compressed = this.compressSectionsByImportance(
204
- contentAnalysis.sections,
205
- importanceScores,
206
- personaStrategy
207
- );
208
- }
209
-
210
- // 4. 페르소나 특화 요약
211
- if (options.strategy === 'aggressive') {
212
- const summary = await this.generatePersonaFocusedSummary(
213
- compressed,
214
- personaStrategy
215
- );
216
-
217
- if (summary) {
218
- compressed = this.integratePersonaSummary(compressed, summary, currentPersona);
219
- }
220
- }
221
-
222
- // 5. 토큰 수 계산
223
- const originalTokens = this.tokenCounter.countTokens(content);
224
- const compressedTokens = this.tokenCounter.countTokens(compressed);
225
-
226
- return {
227
- success: true,
228
- original: content,
229
- compressed: compressed,
230
- originalTokens: originalTokens,
231
- compressedTokens: compressedTokens,
232
- compressionRatio: ((originalTokens - compressedTokens) / originalTokens * 100).toFixed(1),
233
- metadata: {
234
- validation: this.validateCompression(content, compressed),
235
- contentAnalysis: contentAnalysis,
236
- importanceScores: importanceScores,
237
- personaFocus: personaStrategy.summarizationFocus
238
- }
239
- };
240
-
241
- } catch (error) {
242
- return {
243
- success: false,
244
- error: error.message,
245
- original: content,
246
- compressed: content
247
- };
248
- }
249
- }
250
-
251
- /**
252
- * 컨텐츠 분석
253
- */
254
- analyzeContent(content, strategy) {
255
- const lines = content.split('\n');
256
- const sections = [];
257
- let currentSection = null;
258
-
259
- lines.forEach((line, index) => {
260
- // 섹션 헤더 감지
261
- if (line.match(/^#+\s/)) {
262
- if (currentSection) {
263
- sections.push(currentSection);
264
- }
265
- currentSection = {
266
- header: line,
267
- startLine: index,
268
- content: [],
269
- relevanceScore: 0
270
- };
271
- } else if (currentSection) {
272
- currentSection.content.push(line);
273
- }
274
- });
275
-
276
- if (currentSection) {
277
- sections.push(currentSection);
278
- }
279
-
280
- // 각 섹션의 관련성 점수 계산
281
- sections.forEach(section => {
282
- section.relevanceScore = this.calculateSectionRelevance(
283
- section,
284
- strategy
285
- );
286
- });
287
-
288
- return {
289
- sections,
290
- totalLines: lines.length,
291
- hasCode: content.includes('```'),
292
- hasTables: content.includes('|'),
293
- hasLists: /^[-*]\s/.test(content)
294
- };
295
- }
296
-
297
- /**
298
- * 섹션 관련성 점수 계산
299
- */
300
- calculateSectionRelevance(section, strategy) {
301
- const fullText = section.header + '\n' + section.content.join('\n');
302
- let score = 0;
303
-
304
- // 보존 패턴 매칭
305
- strategy.preservePatterns.forEach(pattern => {
306
- const regex = new RegExp(pattern, 'gi');
307
- const matches = fullText.match(regex);
308
- if (matches) {
309
- score += matches.length * 2;
310
- }
311
- });
312
-
313
- // 포커스 영역 확인
314
- strategy.focusAreas.forEach(area => {
315
- if (fullText.toLowerCase().includes(area.replace('_', ' '))) {
316
- score += 5;
317
- }
318
- });
319
-
320
- // 섹션 헤더 레벨에 따른 가중치
321
- const headerLevel = (section.header.match(/^#+/) || [''])[0].length;
322
- score *= (5 - Math.min(headerLevel, 4)) / 4;
323
-
324
- return score;
325
- }
326
-
327
- /**
328
- * 중요도 점수 계산
329
- */
330
- calculateImportanceScores(analysis, strategy) {
331
- const scores = {};
332
-
333
- analysis.sections.forEach((section, index) => {
334
- // 기본 점수
335
- let importance = section.relevanceScore;
336
-
337
- // 컨텐츠 타입별 가중치 적용
338
- const sectionText = section.content.join('\n');
339
-
340
- if (sectionText.includes('```') && strategy.compressionWeights.code_examples) {
341
- importance *= strategy.compressionWeights.code_examples;
342
- }
343
-
344
- if (section.header.toLowerCase().includes('security') &&
345
- strategy.compressionWeights.security_warnings) {
346
- importance *= strategy.compressionWeights.security_warnings;
347
- }
348
-
349
- scores[index] = importance;
350
- });
351
-
352
- return scores;
353
- }
354
-
355
- /**
356
- * 중요도에 따른 섹션 압축
357
- */
358
- compressSectionsByImportance(sections, importanceScores, strategy) {
359
- const compressed = [];
360
-
361
- // 중요도 순으로 정렬
362
- const sortedIndices = Object.keys(importanceScores)
363
- .sort((a, b) => importanceScores[b] - importanceScores[a]);
364
-
365
- // 평균 중요도 계산
366
- const avgImportance = Object.values(importanceScores)
367
- .reduce((sum, score) => sum + score, 0) / Object.keys(importanceScores).length;
368
-
369
- sections.forEach((section, index) => {
370
- const importance = importanceScores[index];
371
-
372
- // 중요도가 평균 이상이면 전체 보존
373
- if (importance >= avgImportance * 1.2) {
374
- compressed.push(section.header);
375
- compressed.push(...section.content);
376
- }
377
- // 중요도가 낮으면 요약
378
- else if (importance < avgImportance * 0.5) {
379
- compressed.push(section.header);
380
- compressed.push(this.summarizeSection(section, strategy));
381
- }
382
- // 중간이면 부분 압축
383
- else {
384
- compressed.push(section.header);
385
- const compressedContent = this.partiallyCompressSection(section, strategy);
386
- compressed.push(...compressedContent);
387
- }
388
-
389
- compressed.push(''); // 섹션 구분
390
- });
391
-
392
- return compressed.join('\n');
393
- }
394
-
395
- /**
396
- * 섹션 요약
397
- */
398
- summarizeSection(section, strategy) {
399
- const content = section.content.join(' ');
400
- const sentences = content.split(/[.!?]+/).filter(s => s.trim());
401
-
402
- if (sentences.length <= 2) {
403
- return content;
404
- }
405
-
406
- // 페르소나 관련 문장 우선 선택
407
- const relevantSentences = sentences.filter(sentence => {
408
- return strategy.preservePatterns.some(pattern =>
409
- sentence.toLowerCase().includes(pattern.toLowerCase())
410
- );
411
- });
412
-
413
- if (relevantSentences.length > 0) {
414
- return `[요약] ${relevantSentences.slice(0, 2).join('. ')}.`;
415
- }
416
-
417
- // 첫 문장과 마지막 문장
418
- return `[요약] ${sentences[0]}... ${sentences[sentences.length - 1]}.`;
419
- }
420
-
421
- /**
422
- * 부분 압축
423
- */
424
- partiallyCompressSection(section, strategy) {
425
- const compressed = [];
426
- let skipNext = false;
427
-
428
- section.content.forEach((line, index) => {
429
- // 빈 줄은 유지
430
- if (!line.trim()) {
431
- compressed.push(line);
432
- return;
433
- }
434
-
435
- // 중요 패턴이 포함된 줄은 유지
436
- const hasImportantPattern = strategy.preservePatterns.some(pattern =>
437
- line.toLowerCase().includes(pattern.toLowerCase())
438
- );
439
-
440
- if (hasImportantPattern) {
441
- compressed.push(line);
442
- skipNext = false;
443
- } else if (!skipNext) {
444
- // 일반 줄은 2줄 중 1줄만 유지
445
- compressed.push(line);
446
- skipNext = true;
447
- } else {
448
- skipNext = false;
449
- }
450
- });
451
-
452
- return compressed;
453
- }
454
-
455
- /**
456
- * 페르소나 중심 요약 생성
457
- */
458
- async generatePersonaFocusedSummary(content, strategy) {
459
- try {
460
- // 여기서는 간단한 추출 기반 요약 구현
461
- // 실제로는 AI 기반 요약을 사용할 수 있습니다
462
-
463
- const sentences = content.split(/[.!?]+/).filter(s => s.trim());
464
- const scoredSentences = [];
465
-
466
- sentences.forEach(sentence => {
467
- let score = 0;
468
-
469
- // 페르소나 패턴 점수
470
- strategy.preservePatterns.forEach(pattern => {
471
- if (sentence.toLowerCase().includes(pattern.toLowerCase())) {
472
- score += 3;
473
- }
474
- });
475
-
476
- // 포커스 영역 점수
477
- strategy.focusAreas.forEach(area => {
478
- if (sentence.toLowerCase().includes(area.replace('_', ' '))) {
479
- score += 2;
480
- }
481
- });
482
-
483
- if (score > 0) {
484
- scoredSentences.push({ sentence, score });
485
- }
486
- });
487
-
488
- // 점수 순으로 정렬하고 상위 문장 선택
489
- const topSentences = scoredSentences
490
- .sort((a, b) => b.score - a.score)
491
- .slice(0, 5)
492
- .map(item => item.sentence);
493
-
494
- if (topSentences.length > 0) {
495
- return `주요 내용 (${strategy.summarizationFocus}):\n` +
496
- topSentences.map(s => `- ${s.trim()}`).join('\n');
497
- }
498
-
499
- return null;
500
-
501
- } catch (error) {
502
- console.error('요약 생성 실패:', error);
503
- return null;
504
- }
505
- }
506
-
507
- /**
508
- * 페르소나 요약 통합
509
- */
510
- integratePersonaSummary(content, summary, persona) {
511
- const personaNames = {
512
- architect: 'Architect',
513
- security: 'Security Expert',
514
- frontend: 'Frontend Developer',
515
- backend: 'Backend Developer',
516
- data_analyst: 'Data Analyst'
517
- };
518
-
519
- const header = `\n\n---\n### ${personaNames[persona]} 관점 요약\n\n`;
520
-
521
- return content + header + summary + '\n---\n';
522
- }
523
-
524
- /**
525
- * 압축 결과 검증
526
- */
527
- validateCompression(original, compressed) {
528
- const validation = super.validateCompression(original, compressed);
529
-
530
- // 페르소나별 추가 검증
531
- if (this.currentPersona) {
532
- const strategy = this.personaStrategies[this.currentPersona];
533
-
534
- // 중요 패턴 보존율 확인
535
- let preservedPatterns = 0;
536
- let totalPatterns = 0;
537
-
538
- strategy.preservePatterns.forEach(pattern => {
539
- const originalCount = (original.match(new RegExp(pattern, 'gi')) || []).length;
540
- const compressedCount = (compressed.match(new RegExp(pattern, 'gi')) || []).length;
541
-
542
- totalPatterns += originalCount;
543
- preservedPatterns += Math.min(originalCount, compressedCount);
544
- });
545
-
546
- validation.patternPreservationRate = totalPatterns > 0
547
- ? (preservedPatterns / totalPatterns * 100).toFixed(1)
548
- : 100;
549
-
550
- validation.personaAligned = validation.patternPreservationRate > 70;
551
- }
552
-
553
- return validation;
554
- }
555
-
556
- /**
557
- * 페르소나별 압축 통계
558
- */
559
- getPersonaCompressionStats() {
560
- return {
561
- currentPersona: this.currentPersona,
562
- strategy: this.currentPersona ? this.personaStrategies[this.currentPersona] : null,
563
- compressionHistory: this.compressionHistory || [],
564
- averageRatioByPersona: this.calculateAverageRatioByPersona()
565
- };
566
- }
567
-
568
- /**
569
- * 페르소나별 평균 압축률 계산
570
- */
571
- calculateAverageRatioByPersona() {
572
- if (!this.compressionHistory || this.compressionHistory.length === 0) {
573
- return {};
574
- }
575
-
576
- const ratiosByPersona = {};
577
-
578
- this.compressionHistory.forEach(record => {
579
- const persona = record.metadata?.persona || 'unknown';
580
-
581
- if (!ratiosByPersona[persona]) {
582
- ratiosByPersona[persona] = [];
583
- }
584
-
585
- ratiosByPersona[persona].push(parseFloat(record.compressionRatio));
586
- });
587
-
588
- const averages = {};
589
- Object.keys(ratiosByPersona).forEach(persona => {
590
- const ratios = ratiosByPersona[persona];
591
- averages[persona] = (ratios.reduce((sum, r) => sum + r, 0) / ratios.length).toFixed(1);
592
- });
593
-
594
- return averages;
595
- }
596
- }
597
-
598
- export default PersonaAwareCompressor;