deepdebug-local-agent 0.3.1

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 (50) hide show
  1. package/.dockerignore +24 -0
  2. package/.idea/deepdebug-local-agent.iml +12 -0
  3. package/.idea/modules.xml +8 -0
  4. package/.idea/vcs.xml +6 -0
  5. package/Dockerfile +46 -0
  6. package/cloudbuild.yaml +42 -0
  7. package/index.js +42 -0
  8. package/mcp-server.js +533 -0
  9. package/package.json +22 -0
  10. package/src/ai-engine.js +861 -0
  11. package/src/analyzers/config-analyzer.js +446 -0
  12. package/src/analyzers/controller-analyzer.js +429 -0
  13. package/src/analyzers/dto-analyzer.js +455 -0
  14. package/src/detectors/build-tool-detector.js +0 -0
  15. package/src/detectors/framework-detector.js +91 -0
  16. package/src/detectors/language-detector.js +89 -0
  17. package/src/detectors/multi-project-detector.js +191 -0
  18. package/src/detectors/service-detector.js +244 -0
  19. package/src/detectors.js +30 -0
  20. package/src/exec-utils.js +215 -0
  21. package/src/fs-utils.js +34 -0
  22. package/src/git/base-git-provider.js +384 -0
  23. package/src/git/git-provider-registry.js +110 -0
  24. package/src/git/github-provider.js +502 -0
  25. package/src/mcp-http-server.js +313 -0
  26. package/src/patch/patch-engine.js +339 -0
  27. package/src/patch-manager.js +816 -0
  28. package/src/patch.js +607 -0
  29. package/src/patch_bkp.js +154 -0
  30. package/src/ports.js +69 -0
  31. package/src/routes/workspace.route.js +528 -0
  32. package/src/runtimes/base-runtime.js +290 -0
  33. package/src/runtimes/java/gradle-runtime.js +378 -0
  34. package/src/runtimes/java/java-integrations.js +339 -0
  35. package/src/runtimes/java/maven-runtime.js +418 -0
  36. package/src/runtimes/node/node-integrations.js +247 -0
  37. package/src/runtimes/node/npm-runtime.js +466 -0
  38. package/src/runtimes/node/yarn-runtime.js +354 -0
  39. package/src/runtimes/runtime-registry.js +256 -0
  40. package/src/server-local.js +576 -0
  41. package/src/server.js +4565 -0
  42. package/src/utils/environment-diagnostics.js +666 -0
  43. package/src/utils/exec-utils.js +264 -0
  44. package/src/utils/fs-utils.js +218 -0
  45. package/src/workspace/detect-port.js +176 -0
  46. package/src/workspace/file-reader.js +54 -0
  47. package/src/workspace/git-client.js +0 -0
  48. package/src/workspace/process-manager.js +619 -0
  49. package/src/workspace/scanner.js +72 -0
  50. package/src/workspace-manager.js +172 -0
@@ -0,0 +1,339 @@
1
+ import path from 'path';
2
+ import { readFile, readdir, stat } from '../../utils/fs-utils.js';
3
+
4
+ /**
5
+ * JavaIntegrationAnalyzer
6
+ *
7
+ * Analisa código Java para encontrar integrações HTTP:
8
+ * - RestTemplate
9
+ * - WebClient
10
+ * - FeignClient
11
+ * - HttpClient (Java 11+)
12
+ * - OkHttp
13
+ * - Retrofit
14
+ */
15
+ export class JavaIntegrationAnalyzer {
16
+
17
+ constructor(workspacePath) {
18
+ this.workspacePath = workspacePath;
19
+ this.integrations = [];
20
+ }
21
+
22
+ /**
23
+ * Encontra todas as integrações no workspace
24
+ * @returns {Promise<Integration[]>}
25
+ */
26
+ async findAll() {
27
+ this.integrations = [];
28
+
29
+ const srcPath = path.join(this.workspacePath, 'src/main/java');
30
+ await this.scanDirectory(srcPath);
31
+
32
+ return this.integrations;
33
+ }
34
+
35
+ /**
36
+ * Escaneia diretório recursivamente
37
+ */
38
+ async scanDirectory(dir) {
39
+ try {
40
+ const entries = await readdir(dir, { withFileTypes: true });
41
+
42
+ for (const entry of entries) {
43
+ const fullPath = path.join(dir, entry.name);
44
+
45
+ if (entry.isDirectory()) {
46
+ await this.scanDirectory(fullPath);
47
+ } else if (entry.name.endsWith('.java')) {
48
+ await this.analyzeFile(fullPath);
49
+ }
50
+ }
51
+ } catch (e) {
52
+ // Diretório não existe ou erro de leitura
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Analisa um arquivo Java
58
+ */
59
+ async analyzeFile(filePath) {
60
+ try {
61
+ const content = await readFile(filePath, 'utf8');
62
+ const relativePath = path.relative(this.workspacePath, filePath);
63
+ const lines = content.split('\n');
64
+
65
+ // Analisar cada tipo de integração
66
+ this.findRestTemplate(content, relativePath, lines);
67
+ this.findWebClient(content, relativePath, lines);
68
+ this.findFeignClient(content, relativePath, lines);
69
+ this.findHttpClient(content, relativePath, lines);
70
+ this.findKafka(content, relativePath, lines);
71
+ this.findRabbitMQ(content, relativePath, lines);
72
+
73
+ } catch (e) {
74
+ // Erro ao ler arquivo
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Encontra uso de RestTemplate
80
+ */
81
+ findRestTemplate(content, filePath, lines) {
82
+ // Padrões de RestTemplate
83
+ const patterns = [
84
+ // Injeção
85
+ { regex: /@Autowired\s*\n?\s*(?:private|protected|public)?\s*RestTemplate\s+\w+/g, type: 'injection' },
86
+ { regex: /private\s+(?:final\s+)?RestTemplate\s+\w+/g, type: 'field' },
87
+
88
+ // Chamadas HTTP
89
+ { regex: /restTemplate\.(getForObject|getForEntity|postForObject|postForEntity|exchange|put|delete)\s*\(/gi, type: 'call' },
90
+
91
+ // Criação
92
+ { regex: /new\s+RestTemplate\s*\(/g, type: 'instantiation' },
93
+ { regex: /RestTemplateBuilder/g, type: 'builder' }
94
+ ];
95
+
96
+ for (const pattern of patterns) {
97
+ let match;
98
+ while ((match = pattern.regex.exec(content)) !== null) {
99
+ const line = this.getLineNumber(content, match.index);
100
+ const url = this.extractUrl(content, match.index);
101
+ const method = this.extractHttpMethod(match[0]);
102
+
103
+ this.integrations.push({
104
+ type: 'rest-template',
105
+ subType: pattern.type,
106
+ file: filePath,
107
+ line,
108
+ targetUrl: url,
109
+ method,
110
+ snippet: lines[line - 1]?.trim() || match[0]
111
+ });
112
+ }
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Encontra uso de WebClient (Spring WebFlux)
118
+ */
119
+ findWebClient(content, filePath, lines) {
120
+ const patterns = [
121
+ { regex: /WebClient\.builder\(\)/g, type: 'builder' },
122
+ { regex: /WebClient\.create\s*\(/g, type: 'create' },
123
+ { regex: /\.get\(\)\s*\.uri\s*\(/g, type: 'get' },
124
+ { regex: /\.post\(\)\s*\.uri\s*\(/g, type: 'post' },
125
+ { regex: /\.put\(\)\s*\.uri\s*\(/g, type: 'put' },
126
+ { regex: /\.delete\(\)\s*\.uri\s*\(/g, type: 'delete' },
127
+ { regex: /\.patch\(\)\s*\.uri\s*\(/g, type: 'patch' }
128
+ ];
129
+
130
+ for (const pattern of patterns) {
131
+ let match;
132
+ while ((match = pattern.regex.exec(content)) !== null) {
133
+ const line = this.getLineNumber(content, match.index);
134
+ const url = this.extractUrl(content, match.index);
135
+
136
+ this.integrations.push({
137
+ type: 'web-client',
138
+ subType: pattern.type,
139
+ file: filePath,
140
+ line,
141
+ targetUrl: url,
142
+ method: pattern.type.toUpperCase(),
143
+ snippet: lines[line - 1]?.trim() || match[0]
144
+ });
145
+ }
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Encontra FeignClient
151
+ */
152
+ findFeignClient(content, filePath, lines) {
153
+ // @FeignClient annotation
154
+ const feignRegex = /@FeignClient\s*\(\s*(?:name\s*=\s*)?["']?([^"'\s,)]+)["']?/g;
155
+
156
+ let match;
157
+ while ((match = feignRegex.exec(content)) !== null) {
158
+ const line = this.getLineNumber(content, match.index);
159
+ const serviceName = match[1];
160
+
161
+ // Extrair URL se especificada
162
+ const urlMatch = content.substring(match.index, match.index + 200)
163
+ .match(/url\s*=\s*["']([^"']+)["']/);
164
+
165
+ this.integrations.push({
166
+ type: 'feign-client',
167
+ subType: 'declaration',
168
+ file: filePath,
169
+ line,
170
+ targetUrl: urlMatch ? urlMatch[1] : null,
171
+ serviceName,
172
+ method: null,
173
+ snippet: lines[line - 1]?.trim() || match[0]
174
+ });
175
+ }
176
+
177
+ // Métodos do FeignClient
178
+ const methodPatterns = [
179
+ { regex: /@GetMapping\s*\(?\s*["']?([^"'\s)]*)/g, method: 'GET' },
180
+ { regex: /@PostMapping\s*\(?\s*["']?([^"'\s)]*)/g, method: 'POST' },
181
+ { regex: /@PutMapping\s*\(?\s*["']?([^"'\s)]*)/g, method: 'PUT' },
182
+ { regex: /@DeleteMapping\s*\(?\s*["']?([^"'\s)]*)/g, method: 'DELETE' },
183
+ { regex: /@PatchMapping\s*\(?\s*["']?([^"'\s)]*)/g, method: 'PATCH' }
184
+ ];
185
+
186
+ // Só procurar métodos se arquivo tem @FeignClient
187
+ if (content.includes('@FeignClient')) {
188
+ for (const pattern of methodPatterns) {
189
+ let methodMatch;
190
+ while ((methodMatch = pattern.regex.exec(content)) !== null) {
191
+ const line = this.getLineNumber(content, methodMatch.index);
192
+
193
+ this.integrations.push({
194
+ type: 'feign-client',
195
+ subType: 'method',
196
+ file: filePath,
197
+ line,
198
+ targetUrl: methodMatch[1] || '/',
199
+ method: pattern.method,
200
+ snippet: lines[line - 1]?.trim() || methodMatch[0]
201
+ });
202
+ }
203
+ }
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Encontra Java HttpClient (11+)
209
+ */
210
+ findHttpClient(content, filePath, lines) {
211
+ const patterns = [
212
+ { regex: /HttpClient\.newBuilder\(\)/g, type: 'builder' },
213
+ { regex: /HttpClient\.newHttpClient\(\)/g, type: 'create' },
214
+ { regex: /HttpRequest\.newBuilder\(\)/g, type: 'request' }
215
+ ];
216
+
217
+ for (const pattern of patterns) {
218
+ let match;
219
+ while ((match = pattern.regex.exec(content)) !== null) {
220
+ const line = this.getLineNumber(content, match.index);
221
+ const url = this.extractUrl(content, match.index);
222
+
223
+ this.integrations.push({
224
+ type: 'http-client',
225
+ subType: pattern.type,
226
+ file: filePath,
227
+ line,
228
+ targetUrl: url,
229
+ method: null,
230
+ snippet: lines[line - 1]?.trim() || match[0]
231
+ });
232
+ }
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Encontra integrações Kafka
238
+ */
239
+ findKafka(content, filePath, lines) {
240
+ const patterns = [
241
+ { regex: /@KafkaListener\s*\(\s*topics\s*=\s*["']([^"']+)["']/g, type: 'consumer' },
242
+ { regex: /kafkaTemplate\.send\s*\(\s*["']([^"']+)["']/gi, type: 'producer' },
243
+ { regex: /@SendTo\s*\(\s*["']([^"']+)["']\s*\)/g, type: 'reply' }
244
+ ];
245
+
246
+ for (const pattern of patterns) {
247
+ let match;
248
+ while ((match = pattern.regex.exec(content)) !== null) {
249
+ const line = this.getLineNumber(content, match.index);
250
+
251
+ this.integrations.push({
252
+ type: 'kafka',
253
+ subType: pattern.type,
254
+ file: filePath,
255
+ line,
256
+ topic: match[1],
257
+ snippet: lines[line - 1]?.trim() || match[0]
258
+ });
259
+ }
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Encontra integrações RabbitMQ
265
+ */
266
+ findRabbitMQ(content, filePath, lines) {
267
+ const patterns = [
268
+ { regex: /@RabbitListener\s*\(\s*queues\s*=\s*["']([^"']+)["']/g, type: 'consumer' },
269
+ { regex: /rabbitTemplate\.convertAndSend\s*\(/gi, type: 'producer' },
270
+ { regex: /@RabbitHandler/g, type: 'handler' }
271
+ ];
272
+
273
+ for (const pattern of patterns) {
274
+ let match;
275
+ while ((match = pattern.regex.exec(content)) !== null) {
276
+ const line = this.getLineNumber(content, match.index);
277
+
278
+ this.integrations.push({
279
+ type: 'rabbitmq',
280
+ subType: pattern.type,
281
+ file: filePath,
282
+ line,
283
+ queue: match[1] || null,
284
+ snippet: lines[line - 1]?.trim() || match[0]
285
+ });
286
+ }
287
+ }
288
+ }
289
+
290
+ // ==========================================
291
+ // HELPERS
292
+ // ==========================================
293
+
294
+ /**
295
+ * Obtém número da linha a partir do índice
296
+ */
297
+ getLineNumber(content, index) {
298
+ return content.substring(0, index).split('\n').length;
299
+ }
300
+
301
+ /**
302
+ * Tenta extrair URL do contexto
303
+ */
304
+ extractUrl(content, startIndex) {
305
+ // Procurar URL nos próximos 500 caracteres
306
+ const context = content.substring(startIndex, startIndex + 500);
307
+
308
+ // Padrões de URL
309
+ const urlPatterns = [
310
+ /"(https?:\/\/[^"]+)"/,
311
+ /'(https?:\/\/[^']+)'/,
312
+ /\$\{([^}]+)\}/, // Property placeholder
313
+ /"([^"]*\/api\/[^"]+)"/,
314
+ /"(\/[a-zA-Z][a-zA-Z0-9/\-_{}]+)"/
315
+ ];
316
+
317
+ for (const pattern of urlPatterns) {
318
+ const match = context.match(pattern);
319
+ if (match) return match[1];
320
+ }
321
+
322
+ return null;
323
+ }
324
+
325
+ /**
326
+ * Extrai método HTTP da chamada
327
+ */
328
+ extractHttpMethod(snippet) {
329
+ if (/getFor|\.get\(/i.test(snippet)) return 'GET';
330
+ if (/postFor|\.post\(/i.test(snippet)) return 'POST';
331
+ if (/\.put\(/i.test(snippet)) return 'PUT';
332
+ if (/\.delete\(/i.test(snippet)) return 'DELETE';
333
+ if (/\.patch\(/i.test(snippet)) return 'PATCH';
334
+ if (/exchange/i.test(snippet)) return 'EXCHANGE';
335
+ return null;
336
+ }
337
+ }
338
+
339
+ export default JavaIntegrationAnalyzer;