archicore 0.1.0

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 (118) hide show
  1. package/README.md +530 -0
  2. package/dist/analyzers/dead-code.d.ts +95 -0
  3. package/dist/analyzers/dead-code.js +327 -0
  4. package/dist/analyzers/duplication.d.ts +90 -0
  5. package/dist/analyzers/duplication.js +344 -0
  6. package/dist/analyzers/security.d.ts +79 -0
  7. package/dist/analyzers/security.js +484 -0
  8. package/dist/architecture/index.d.ts +35 -0
  9. package/dist/architecture/index.js +249 -0
  10. package/dist/cli/commands/analyzers.d.ts +6 -0
  11. package/dist/cli/commands/analyzers.js +431 -0
  12. package/dist/cli/commands/export.d.ts +6 -0
  13. package/dist/cli/commands/export.js +78 -0
  14. package/dist/cli/commands/index.d.ts +8 -0
  15. package/dist/cli/commands/index.js +8 -0
  16. package/dist/cli/commands/init.d.ts +26 -0
  17. package/dist/cli/commands/init.js +140 -0
  18. package/dist/cli/commands/interactive.d.ts +7 -0
  19. package/dist/cli/commands/interactive.js +522 -0
  20. package/dist/cli/commands/projects.d.ts +6 -0
  21. package/dist/cli/commands/projects.js +249 -0
  22. package/dist/cli/index.d.ts +7 -0
  23. package/dist/cli/index.js +7 -0
  24. package/dist/cli/ui/box.d.ts +17 -0
  25. package/dist/cli/ui/box.js +62 -0
  26. package/dist/cli/ui/colors.d.ts +49 -0
  27. package/dist/cli/ui/colors.js +86 -0
  28. package/dist/cli/ui/index.d.ts +9 -0
  29. package/dist/cli/ui/index.js +9 -0
  30. package/dist/cli/ui/prompt.d.ts +34 -0
  31. package/dist/cli/ui/prompt.js +122 -0
  32. package/dist/cli/ui/spinner.d.ts +29 -0
  33. package/dist/cli/ui/spinner.js +80 -0
  34. package/dist/cli/ui/table.d.ts +33 -0
  35. package/dist/cli/ui/table.js +84 -0
  36. package/dist/cli/utils/config.d.ts +23 -0
  37. package/dist/cli/utils/config.js +73 -0
  38. package/dist/cli/utils/index.d.ts +6 -0
  39. package/dist/cli/utils/index.js +6 -0
  40. package/dist/cli/utils/session.d.ts +27 -0
  41. package/dist/cli/utils/session.js +117 -0
  42. package/dist/cli.d.ts +8 -0
  43. package/dist/cli.js +295 -0
  44. package/dist/code-index/ast-parser.d.ts +16 -0
  45. package/dist/code-index/ast-parser.js +330 -0
  46. package/dist/code-index/dependency-graph.d.ts +16 -0
  47. package/dist/code-index/dependency-graph.js +161 -0
  48. package/dist/code-index/index.d.ts +44 -0
  49. package/dist/code-index/index.js +124 -0
  50. package/dist/code-index/symbol-extractor.d.ts +13 -0
  51. package/dist/code-index/symbol-extractor.js +150 -0
  52. package/dist/export/index.d.ts +92 -0
  53. package/dist/export/index.js +676 -0
  54. package/dist/github/github-service.d.ts +146 -0
  55. package/dist/github/github-service.js +609 -0
  56. package/dist/impact-engine/index.d.ts +25 -0
  57. package/dist/impact-engine/index.js +284 -0
  58. package/dist/index.d.ts +60 -0
  59. package/dist/index.js +149 -0
  60. package/dist/metrics/index.d.ts +136 -0
  61. package/dist/metrics/index.js +525 -0
  62. package/dist/orchestrator/deepseek-optimizer.d.ts +67 -0
  63. package/dist/orchestrator/deepseek-optimizer.js +320 -0
  64. package/dist/orchestrator/index.d.ts +34 -0
  65. package/dist/orchestrator/index.js +305 -0
  66. package/dist/pr-guardian/index.d.ts +143 -0
  67. package/dist/pr-guardian/index.js +553 -0
  68. package/dist/refactoring/index.d.ts +108 -0
  69. package/dist/refactoring/index.js +580 -0
  70. package/dist/rules-engine/index.d.ts +129 -0
  71. package/dist/rules-engine/index.js +482 -0
  72. package/dist/semantic-memory/embedding-service.d.ts +24 -0
  73. package/dist/semantic-memory/embedding-service.js +120 -0
  74. package/dist/semantic-memory/index.d.ts +45 -0
  75. package/dist/semantic-memory/index.js +206 -0
  76. package/dist/semantic-memory/vector-store.d.ts +27 -0
  77. package/dist/semantic-memory/vector-store.js +166 -0
  78. package/dist/server/index.d.ts +28 -0
  79. package/dist/server/index.js +141 -0
  80. package/dist/server/middleware/api-auth.d.ts +43 -0
  81. package/dist/server/middleware/api-auth.js +256 -0
  82. package/dist/server/routes/admin.d.ts +5 -0
  83. package/dist/server/routes/admin.js +123 -0
  84. package/dist/server/routes/api.d.ts +7 -0
  85. package/dist/server/routes/api.js +362 -0
  86. package/dist/server/routes/auth.d.ts +16 -0
  87. package/dist/server/routes/auth.js +191 -0
  88. package/dist/server/routes/developer.d.ts +8 -0
  89. package/dist/server/routes/developer.js +439 -0
  90. package/dist/server/routes/github.d.ts +7 -0
  91. package/dist/server/routes/github.js +495 -0
  92. package/dist/server/routes/upload.d.ts +7 -0
  93. package/dist/server/routes/upload.js +196 -0
  94. package/dist/server/services/api-key-service.d.ts +81 -0
  95. package/dist/server/services/api-key-service.js +281 -0
  96. package/dist/server/services/auth-service.d.ts +40 -0
  97. package/dist/server/services/auth-service.js +315 -0
  98. package/dist/server/services/project-service.d.ts +123 -0
  99. package/dist/server/services/project-service.js +533 -0
  100. package/dist/server/services/token-service.d.ts +107 -0
  101. package/dist/server/services/token-service.js +416 -0
  102. package/dist/server/services/upload-service.d.ts +93 -0
  103. package/dist/server/services/upload-service.js +464 -0
  104. package/dist/types/api.d.ts +188 -0
  105. package/dist/types/api.js +86 -0
  106. package/dist/types/github.d.ts +335 -0
  107. package/dist/types/github.js +5 -0
  108. package/dist/types/index.d.ts +265 -0
  109. package/dist/types/index.js +32 -0
  110. package/dist/types/user.d.ts +69 -0
  111. package/dist/types/user.js +42 -0
  112. package/dist/utils/file-utils.d.ts +20 -0
  113. package/dist/utils/file-utils.js +163 -0
  114. package/dist/utils/logger.d.ts +17 -0
  115. package/dist/utils/logger.js +41 -0
  116. package/dist/watcher/index.d.ts +125 -0
  117. package/dist/watcher/index.js +397 -0
  118. package/package.json +71 -0
@@ -0,0 +1,525 @@
1
+ /**
2
+ * Code Metrics Module
3
+ *
4
+ * Вычисление метрик качества кода:
5
+ * - Цикломатическая сложность
6
+ * - Когнитивная сложность
7
+ * - Связанность (Coupling)
8
+ * - Связность (Cohesion)
9
+ * - Maintainability Index
10
+ * - Lines of Code метрики
11
+ */
12
+ import { SymbolKind } from '../types/index.js';
13
+ import { Logger } from '../utils/logger.js';
14
+ export class MetricsCalculator {
15
+ COMPLEXITY_THRESHOLD = 10;
16
+ COGNITIVE_THRESHOLD = 15;
17
+ COUPLING_THRESHOLD = 10;
18
+ LOC_THRESHOLD = 500;
19
+ NESTING_THRESHOLD = 4;
20
+ /**
21
+ * Вычислить метрики для всего проекта
22
+ */
23
+ async calculateProjectMetrics(graph, symbols, fileContents, asts) {
24
+ Logger.progress('Calculating code metrics...');
25
+ const fileMetrics = [];
26
+ for (const [filePath, content] of fileContents) {
27
+ const ast = asts.get(filePath);
28
+ const metrics = this.calculateFileMetrics(filePath, content, ast, graph, symbols);
29
+ fileMetrics.push(metrics);
30
+ }
31
+ const summary = this.calculateSummary(fileMetrics);
32
+ const hotspots = this.identifyHotspots(fileMetrics);
33
+ Logger.success(`Metrics calculated for ${fileMetrics.length} files`);
34
+ return {
35
+ summary,
36
+ files: fileMetrics,
37
+ hotspots
38
+ };
39
+ }
40
+ /**
41
+ * Вычислить метрики для одного файла
42
+ */
43
+ calculateFileMetrics(filePath, content, ast, graph, symbols) {
44
+ const loc = this.calculateLOC(content);
45
+ const complexity = this.calculateComplexity(content, ast, symbols, filePath);
46
+ const coupling = this.calculateCoupling(filePath, graph);
47
+ const maintainability = this.calculateMaintainability(loc, complexity, coupling);
48
+ const issues = this.identifyIssues(loc, complexity, coupling, maintainability);
49
+ return {
50
+ filePath,
51
+ loc,
52
+ complexity,
53
+ coupling,
54
+ maintainability,
55
+ issues
56
+ };
57
+ }
58
+ /**
59
+ * Подсчёт строк кода
60
+ */
61
+ calculateLOC(content) {
62
+ const lines = content.split('\n');
63
+ let code = 0;
64
+ let comments = 0;
65
+ let blank = 0;
66
+ let inBlockComment = false;
67
+ for (const line of lines) {
68
+ const trimmed = line.trim();
69
+ if (trimmed === '') {
70
+ blank++;
71
+ continue;
72
+ }
73
+ // Block comments
74
+ if (trimmed.startsWith('/*')) {
75
+ inBlockComment = true;
76
+ comments++;
77
+ if (trimmed.endsWith('*/')) {
78
+ inBlockComment = false;
79
+ }
80
+ continue;
81
+ }
82
+ if (inBlockComment) {
83
+ comments++;
84
+ if (trimmed.endsWith('*/') || trimmed.includes('*/')) {
85
+ inBlockComment = false;
86
+ }
87
+ continue;
88
+ }
89
+ // Line comments
90
+ if (trimmed.startsWith('//') || trimmed.startsWith('#')) {
91
+ comments++;
92
+ continue;
93
+ }
94
+ code++;
95
+ }
96
+ return {
97
+ total: lines.length,
98
+ code,
99
+ comments,
100
+ blank,
101
+ ratio: code > 0 ? comments / code : 0
102
+ };
103
+ }
104
+ /**
105
+ * Вычисление сложности
106
+ */
107
+ calculateComplexity(content, _ast, symbols, filePath) {
108
+ // Цикломатическая сложность
109
+ const cyclomatic = this.calculateCyclomaticComplexity(content);
110
+ // Когнитивная сложность
111
+ const cognitive = this.calculateCognitiveComplexity(content);
112
+ // Halstead метрики
113
+ const halstead = this.calculateHalsteadMetrics(content);
114
+ // Максимальная вложенность
115
+ const maxNesting = this.calculateMaxNesting(content);
116
+ // Средняя сложность функций
117
+ const fileFunctions = Array.from(symbols.values()).filter(s => (s.kind === SymbolKind.Function) && s.location.filePath === filePath);
118
+ const avgFunctionComplexity = fileFunctions.length > 0
119
+ ? cyclomatic / fileFunctions.length
120
+ : cyclomatic;
121
+ return {
122
+ cyclomatic,
123
+ cognitive,
124
+ halstead,
125
+ maxNesting,
126
+ avgFunctionComplexity
127
+ };
128
+ }
129
+ /**
130
+ * Цикломатическая сложность (McCabe)
131
+ */
132
+ calculateCyclomaticComplexity(content) {
133
+ let complexity = 1; // Базовая сложность
134
+ // Ключевые слова, увеличивающие сложность
135
+ const patterns = [
136
+ /\bif\b/g,
137
+ /\belse\s+if\b/g,
138
+ /\bfor\b/g,
139
+ /\bwhile\b/g,
140
+ /\bcase\b/g,
141
+ /\bcatch\b/g,
142
+ /\b\?\s*[^:]+\s*:/g, // Тернарный оператор
143
+ /&&/g,
144
+ /\|\|/g,
145
+ /\?\?/g // Nullish coalescing
146
+ ];
147
+ for (const pattern of patterns) {
148
+ const matches = content.match(pattern);
149
+ if (matches) {
150
+ complexity += matches.length;
151
+ }
152
+ }
153
+ return complexity;
154
+ }
155
+ /**
156
+ * Когнитивная сложность (SonarSource)
157
+ */
158
+ calculateCognitiveComplexity(content) {
159
+ let complexity = 0;
160
+ let nestingLevel = 0;
161
+ const lines = content.split('\n');
162
+ for (const line of lines) {
163
+ const trimmed = line.trim();
164
+ // Увеличиваем вложенность
165
+ if (trimmed.match(/\b(if|for|while|switch|try)\b.*{/)) {
166
+ complexity += 1 + nestingLevel;
167
+ nestingLevel++;
168
+ }
169
+ // else if добавляет только 1
170
+ else if (trimmed.match(/\belse\s+if\b/)) {
171
+ complexity += 1;
172
+ }
173
+ // else добавляет 1
174
+ else if (trimmed.match(/\belse\b.*{/)) {
175
+ complexity += 1;
176
+ }
177
+ // catch добавляет 1 + вложенность
178
+ else if (trimmed.match(/\bcatch\b/)) {
179
+ complexity += 1 + nestingLevel;
180
+ }
181
+ // Логические операторы в условиях
182
+ else if (trimmed.match(/(&&|\|\|)/)) {
183
+ complexity += (trimmed.match(/(&&|\|\|)/g) || []).length;
184
+ }
185
+ // break/continue с меткой
186
+ else if (trimmed.match(/\b(break|continue)\s+\w+/)) {
187
+ complexity += 1;
188
+ }
189
+ // Рекурсия (упрощённо)
190
+ else if (trimmed.match(/\bfunction\s+(\w+).*\1\s*\(/)) {
191
+ complexity += 1;
192
+ }
193
+ // Закрытие блока
194
+ if (trimmed.includes('}') && nestingLevel > 0) {
195
+ nestingLevel--;
196
+ }
197
+ }
198
+ return complexity;
199
+ }
200
+ /**
201
+ * Halstead метрики
202
+ */
203
+ calculateHalsteadMetrics(content) {
204
+ // Операторы
205
+ const operators = new Set();
206
+ const operatorCounts = {};
207
+ const operatorPatterns = [
208
+ '+', '-', '*', '/', '%', '=', '==', '===', '!=', '!==',
209
+ '<', '>', '<=', '>=', '&&', '||', '!', '&', '|', '^',
210
+ '~', '<<', '>>', '>>>', '++', '--', '+=', '-=', '*=',
211
+ '/=', '%=', '&=', '|=', '^=', '<<=', '>>=', '>>>=',
212
+ '?', ':', '=>', '...', '.', '?.', '??'
213
+ ];
214
+ // Операнды (идентификаторы и литералы)
215
+ const operands = new Set();
216
+ const operandCounts = {};
217
+ // Подсчёт операторов
218
+ for (const op of operatorPatterns) {
219
+ const escaped = op.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
220
+ const matches = content.match(new RegExp(escaped, 'g'));
221
+ if (matches && matches.length > 0) {
222
+ operators.add(op);
223
+ operatorCounts[op] = matches.length;
224
+ }
225
+ }
226
+ // Подсчёт операндов (идентификаторы)
227
+ const identifierMatches = content.match(/\b[a-zA-Z_]\w*\b/g) || [];
228
+ for (const id of identifierMatches) {
229
+ // Исключаем ключевые слова
230
+ const keywords = ['if', 'else', 'for', 'while', 'do', 'switch', 'case', 'break',
231
+ 'continue', 'return', 'function', 'class', 'const', 'let', 'var', 'new',
232
+ 'this', 'true', 'false', 'null', 'undefined', 'typeof', 'instanceof',
233
+ 'import', 'export', 'default', 'async', 'await', 'try', 'catch', 'finally',
234
+ 'throw', 'extends', 'implements', 'interface', 'type', 'enum', 'public',
235
+ 'private', 'protected', 'static', 'readonly'];
236
+ if (!keywords.includes(id)) {
237
+ operands.add(id);
238
+ operandCounts[id] = (operandCounts[id] || 0) + 1;
239
+ }
240
+ }
241
+ const n1 = operators.size; // Уникальные операторы
242
+ const n2 = operands.size; // Уникальные операнды
243
+ const N1 = Object.values(operatorCounts).reduce((a, b) => a + b, 0); // Всего операторов
244
+ const N2 = Object.values(operandCounts).reduce((a, b) => a + b, 0); // Всего операндов
245
+ const vocabulary = n1 + n2;
246
+ const length = N1 + N2;
247
+ const volume = length * Math.log2(Math.max(vocabulary, 1));
248
+ const difficulty = n2 > 0 ? (n1 / 2) * (N2 / n2) : 0;
249
+ const effort = difficulty * volume;
250
+ const time = effort / 18;
251
+ const bugs = volume / 3000;
252
+ return {
253
+ vocabulary,
254
+ length,
255
+ volume: Math.round(volume * 100) / 100,
256
+ difficulty: Math.round(difficulty * 100) / 100,
257
+ effort: Math.round(effort * 100) / 100,
258
+ time: Math.round(time * 100) / 100,
259
+ bugs: Math.round(bugs * 1000) / 1000
260
+ };
261
+ }
262
+ /**
263
+ * Максимальная вложенность
264
+ */
265
+ calculateMaxNesting(content) {
266
+ let maxNesting = 0;
267
+ let currentNesting = 0;
268
+ for (const char of content) {
269
+ if (char === '{') {
270
+ currentNesting++;
271
+ maxNesting = Math.max(maxNesting, currentNesting);
272
+ }
273
+ else if (char === '}') {
274
+ currentNesting = Math.max(0, currentNesting - 1);
275
+ }
276
+ }
277
+ return maxNesting;
278
+ }
279
+ /**
280
+ * Вычисление связанности
281
+ */
282
+ calculateCoupling(filePath, graph) {
283
+ // Находим node для файла
284
+ let nodeId = '';
285
+ for (const [id, node] of graph.nodes) {
286
+ if (node.filePath === filePath) {
287
+ nodeId = id;
288
+ break;
289
+ }
290
+ }
291
+ if (!nodeId) {
292
+ return {
293
+ afferentCoupling: 0,
294
+ efferentCoupling: 0,
295
+ instability: 0.5,
296
+ abstractness: 0,
297
+ distance: 0.5
298
+ };
299
+ }
300
+ // Efferent (исходящие)
301
+ const efferent = (graph.edges.get(nodeId) || []).length;
302
+ // Afferent (входящие)
303
+ let afferent = 0;
304
+ for (const [, edges] of graph.edges) {
305
+ for (const edge of edges) {
306
+ if (edge.to === nodeId) {
307
+ afferent++;
308
+ }
309
+ }
310
+ }
311
+ const total = afferent + efferent;
312
+ const instability = total > 0 ? efferent / total : 0.5;
313
+ // Abstractness (упрощённо - соотношение интерфейсов/абстрактных классов)
314
+ const abstractness = 0; // TODO: вычислять из символов
315
+ const distance = Math.abs(abstractness + instability - 1);
316
+ return {
317
+ afferentCoupling: afferent,
318
+ efferentCoupling: efferent,
319
+ instability: Math.round(instability * 100) / 100,
320
+ abstractness,
321
+ distance: Math.round(distance * 100) / 100
322
+ };
323
+ }
324
+ /**
325
+ * Индекс поддерживаемости (Maintainability Index)
326
+ * Формула Microsoft: MI = MAX(0, (171 - 5.2 * ln(V) - 0.23 * G - 16.2 * ln(LOC)) * 100 / 171)
327
+ */
328
+ calculateMaintainability(loc, complexity, _coupling) {
329
+ const V = complexity.halstead.volume || 1;
330
+ const G = complexity.cyclomatic;
331
+ const LOC = Math.max(loc.code, 1);
332
+ let mi = 171 - 5.2 * Math.log(V) - 0.23 * G - 16.2 * Math.log(LOC);
333
+ // Учитываем комментарии (бонус)
334
+ const commentRatio = loc.ratio;
335
+ mi = mi + 50 * Math.sin(Math.sqrt(2.4 * commentRatio));
336
+ // Нормализуем 0-100
337
+ mi = Math.max(0, Math.min(100, mi * 100 / 171));
338
+ return Math.round(mi);
339
+ }
340
+ /**
341
+ * Выявление проблем
342
+ */
343
+ identifyIssues(loc, complexity, coupling, maintainability) {
344
+ const issues = [];
345
+ // Проблемы сложности
346
+ if (complexity.cyclomatic > this.COMPLEXITY_THRESHOLD * 2) {
347
+ issues.push({
348
+ type: 'complexity',
349
+ severity: 'high',
350
+ message: `Very high cyclomatic complexity: ${complexity.cyclomatic}`,
351
+ suggestion: 'Разбейте на несколько функций, упростите условия'
352
+ });
353
+ }
354
+ else if (complexity.cyclomatic > this.COMPLEXITY_THRESHOLD) {
355
+ issues.push({
356
+ type: 'complexity',
357
+ severity: 'medium',
358
+ message: `High cyclomatic complexity: ${complexity.cyclomatic}`,
359
+ suggestion: 'Рассмотрите рефакторинг сложных условий'
360
+ });
361
+ }
362
+ if (complexity.cognitive > this.COGNITIVE_THRESHOLD * 2) {
363
+ issues.push({
364
+ type: 'complexity',
365
+ severity: 'high',
366
+ message: `Very high cognitive complexity: ${complexity.cognitive}`,
367
+ suggestion: 'Упростите логику, избегайте глубокой вложенности'
368
+ });
369
+ }
370
+ else if (complexity.cognitive > this.COGNITIVE_THRESHOLD) {
371
+ issues.push({
372
+ type: 'complexity',
373
+ severity: 'medium',
374
+ message: `High cognitive complexity: ${complexity.cognitive}`,
375
+ suggestion: 'Уменьшите вложенность, используйте early returns'
376
+ });
377
+ }
378
+ if (complexity.maxNesting > this.NESTING_THRESHOLD) {
379
+ issues.push({
380
+ type: 'complexity',
381
+ severity: complexity.maxNesting > 6 ? 'high' : 'medium',
382
+ message: `Deep nesting: ${complexity.maxNesting} levels`,
383
+ suggestion: 'Используйте guard clauses и early returns'
384
+ });
385
+ }
386
+ // Проблемы размера
387
+ if (loc.code > this.LOC_THRESHOLD * 2) {
388
+ issues.push({
389
+ type: 'size',
390
+ severity: 'high',
391
+ message: `Very large file: ${loc.code} lines`,
392
+ suggestion: 'Разделите файл на модули по функциональности'
393
+ });
394
+ }
395
+ else if (loc.code > this.LOC_THRESHOLD) {
396
+ issues.push({
397
+ type: 'size',
398
+ severity: 'medium',
399
+ message: `Large file: ${loc.code} lines`,
400
+ suggestion: 'Рассмотрите разделение на несколько файлов'
401
+ });
402
+ }
403
+ // Проблемы связанности
404
+ if (coupling.efferentCoupling > this.COUPLING_THRESHOLD * 2) {
405
+ issues.push({
406
+ type: 'coupling',
407
+ severity: 'high',
408
+ message: `Very high coupling: ${coupling.efferentCoupling} dependencies`,
409
+ suggestion: 'Используйте dependency injection, создайте фасад'
410
+ });
411
+ }
412
+ else if (coupling.efferentCoupling > this.COUPLING_THRESHOLD) {
413
+ issues.push({
414
+ type: 'coupling',
415
+ severity: 'medium',
416
+ message: `High coupling: ${coupling.efferentCoupling} dependencies`,
417
+ suggestion: 'Уменьшите количество зависимостей'
418
+ });
419
+ }
420
+ // Maintainability
421
+ if (maintainability < 20) {
422
+ issues.push({
423
+ type: 'maintainability',
424
+ severity: 'high',
425
+ message: `Very low maintainability: ${maintainability}`,
426
+ suggestion: 'Требуется серьёзный рефакторинг'
427
+ });
428
+ }
429
+ else if (maintainability < 40) {
430
+ issues.push({
431
+ type: 'maintainability',
432
+ severity: 'medium',
433
+ message: `Low maintainability: ${maintainability}`,
434
+ suggestion: 'Добавьте комментарии, упростите логику'
435
+ });
436
+ }
437
+ return issues;
438
+ }
439
+ /**
440
+ * Сводка по проекту
441
+ */
442
+ calculateSummary(files) {
443
+ const totalFiles = files.length;
444
+ const totalLOC = files.reduce((sum, f) => sum + f.loc.code, 0);
445
+ const avgComplexity = files.length > 0
446
+ ? files.reduce((sum, f) => sum + f.complexity.cyclomatic, 0) / files.length
447
+ : 0;
448
+ const avgMaintainability = files.length > 0
449
+ ? files.reduce((sum, f) => sum + f.maintainability, 0) / files.length
450
+ : 100;
451
+ const avgCoupling = files.length > 0
452
+ ? files.reduce((sum, f) => sum + f.coupling.efferentCoupling, 0) / files.length
453
+ : 0;
454
+ // Технический долг (упрощённо: 30 мин на каждую проблему высокой важности)
455
+ const highIssues = files.reduce((sum, f) => sum + f.issues.filter(i => i.severity === 'high').length, 0);
456
+ const mediumIssues = files.reduce((sum, f) => sum + f.issues.filter(i => i.severity === 'medium').length, 0);
457
+ const technicalDebtHours = (highIssues * 0.5 + mediumIssues * 0.25);
458
+ // Оценка
459
+ let grade;
460
+ if (avgMaintainability >= 80 && avgComplexity <= 5) {
461
+ grade = 'A';
462
+ }
463
+ else if (avgMaintainability >= 60 && avgComplexity <= 10) {
464
+ grade = 'B';
465
+ }
466
+ else if (avgMaintainability >= 40 && avgComplexity <= 15) {
467
+ grade = 'C';
468
+ }
469
+ else if (avgMaintainability >= 20) {
470
+ grade = 'D';
471
+ }
472
+ else {
473
+ grade = 'F';
474
+ }
475
+ return {
476
+ totalFiles,
477
+ totalLOC,
478
+ avgComplexity: Math.round(avgComplexity * 10) / 10,
479
+ avgMaintainability: Math.round(avgMaintainability),
480
+ avgCoupling: Math.round(avgCoupling * 10) / 10,
481
+ technicalDebtHours: Math.round(technicalDebtHours * 10) / 10,
482
+ grade
483
+ };
484
+ }
485
+ /**
486
+ * Определение "горячих точек"
487
+ */
488
+ identifyHotspots(files) {
489
+ const hotspots = [];
490
+ for (const file of files) {
491
+ const reasons = [];
492
+ let score = 0;
493
+ // Сложность
494
+ if (file.complexity.cyclomatic > this.COMPLEXITY_THRESHOLD) {
495
+ score += (file.complexity.cyclomatic - this.COMPLEXITY_THRESHOLD) * 2;
496
+ reasons.push(`High complexity (${file.complexity.cyclomatic})`);
497
+ }
498
+ // Размер
499
+ if (file.loc.code > this.LOC_THRESHOLD) {
500
+ score += (file.loc.code - this.LOC_THRESHOLD) / 50;
501
+ reasons.push(`Large file (${file.loc.code} LOC)`);
502
+ }
503
+ // Связанность
504
+ if (file.coupling.efferentCoupling > this.COUPLING_THRESHOLD) {
505
+ score += (file.coupling.efferentCoupling - this.COUPLING_THRESHOLD) * 3;
506
+ reasons.push(`High coupling (${file.coupling.efferentCoupling})`);
507
+ }
508
+ // Maintainability
509
+ if (file.maintainability < 40) {
510
+ score += (40 - file.maintainability);
511
+ reasons.push(`Low maintainability (${file.maintainability})`);
512
+ }
513
+ if (reasons.length > 0) {
514
+ hotspots.push({
515
+ filePath: file.filePath,
516
+ score: Math.min(100, Math.round(score)),
517
+ reasons
518
+ });
519
+ }
520
+ }
521
+ // Сортируем по score
522
+ return hotspots.sort((a, b) => b.score - a.score).slice(0, 20);
523
+ }
524
+ }
525
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,67 @@
1
+ /**
2
+ * DeepSeek Optimizer
3
+ *
4
+ * Оптимизирует промпты и контекст специально для DeepSeek,
5
+ * чтобы минимизировать ошибки и получать точные ответы.
6
+ */
7
+ import { LLMPrompt } from '../types/index.js';
8
+ export interface OptimizationConfig {
9
+ maxContextLength: number;
10
+ simplifyPrompts: boolean;
11
+ useEnglish: boolean;
12
+ reduceExamples: boolean;
13
+ structuredOutput: boolean;
14
+ }
15
+ export declare class DeepSeekOptimizer {
16
+ private config;
17
+ constructor(config?: Partial<OptimizationConfig>);
18
+ /**
19
+ * Оптимизирует промпт для DeepSeek
20
+ */
21
+ optimizePrompt(prompt: LLMPrompt): LLMPrompt;
22
+ /**
23
+ * Упрощает системный промпт
24
+ */
25
+ private simplifySystemPrompt;
26
+ /**
27
+ * Упрощает пользовательский промпт
28
+ */
29
+ private simplifyUserPrompt;
30
+ /**
31
+ * Сокращает контекст до самого важного
32
+ */
33
+ private reduceContext;
34
+ /**
35
+ * Добавляет требование структурированного вывода
36
+ */
37
+ private addStructuredOutputRequest;
38
+ /**
39
+ * Упрощенный перевод ключевых терминов на английский
40
+ */
41
+ private translateToEnglish;
42
+ /**
43
+ * Проверяет, в основном ли текст на русском
44
+ */
45
+ private isMostlyRussian;
46
+ /**
47
+ * Обрезает текст до максимальной длины
48
+ */
49
+ private truncateText;
50
+ /**
51
+ * Разбивает сложную задачу на простые подзадачи
52
+ */
53
+ splitComplexTask(task: string): string[];
54
+ /**
55
+ * Валидирует и очищает ответ от DeepSeek
56
+ */
57
+ validateAndCleanResponse(response: string): string;
58
+ /**
59
+ * Создает retry-стратегию с упрощением
60
+ */
61
+ createRetryStrategy(originalPrompt: LLMPrompt, attemptNumber: number): LLMPrompt;
62
+ }
63
+ /**
64
+ * Создает оптимизированный промпт для простых задач DeepSeek
65
+ */
66
+ export declare function createSimplePrompt(task: string, context?: string): LLMPrompt;
67
+ //# sourceMappingURL=deepseek-optimizer.d.ts.map