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,666 @@
1
+ import { exec } from 'child_process';
2
+ import { promisify } from 'util';
3
+ import path from 'path';
4
+ import os from 'os';
5
+
6
+ const execAsync = promisify(exec);
7
+
8
+ /**
9
+ * EnvironmentDiagnostics
10
+ *
11
+ * Detecta automaticamente ferramentas de desenvolvimento instaladas no sistema.
12
+ * Útil para debugging e setup do ambiente.
13
+ */
14
+ export class EnvironmentDiagnostics {
15
+
16
+ constructor() {
17
+ this.cache = null;
18
+ this.cacheTime = 0;
19
+ this.cacheTTL = 60000; // 1 minuto
20
+ }
21
+
22
+ /**
23
+ * Executa diagnóstico completo do ambiente
24
+ */
25
+ async diagnose() {
26
+ // Usar cache se ainda válido
27
+ if (this.cache && (Date.now() - this.cacheTime) < this.cacheTTL) {
28
+ return this.cache;
29
+ }
30
+
31
+ const startTime = Date.now();
32
+
33
+ const [
34
+ system,
35
+ java,
36
+ maven,
37
+ gradle,
38
+ node,
39
+ npm,
40
+ yarn,
41
+ python,
42
+ pip,
43
+ go,
44
+ dotnet,
45
+ git,
46
+ docker
47
+ ] = await Promise.all([
48
+ this.getSystemInfo(),
49
+ this.detectJava(),
50
+ this.detectMaven(),
51
+ this.detectGradle(),
52
+ this.detectNode(),
53
+ this.detectNpm(),
54
+ this.detectYarn(),
55
+ this.detectPython(),
56
+ this.detectPip(),
57
+ this.detectGo(),
58
+ this.detectDotnet(),
59
+ this.detectGit(),
60
+ this.detectDocker()
61
+ ]);
62
+
63
+ const result = {
64
+ timestamp: new Date().toISOString(),
65
+ diagnosisTime: Date.now() - startTime,
66
+ system,
67
+ tools: {
68
+ java,
69
+ maven,
70
+ gradle,
71
+ node,
72
+ npm,
73
+ yarn,
74
+ python,
75
+ pip,
76
+ go,
77
+ dotnet,
78
+ git,
79
+ docker
80
+ },
81
+ summary: this.generateSummary({ java, maven, gradle, node, npm, yarn, python, go, dotnet }),
82
+ issues: this.detectIssues({ java, maven, gradle, node, npm, yarn, python, go, dotnet })
83
+ };
84
+
85
+ this.cache = result;
86
+ this.cacheTime = Date.now();
87
+
88
+ return result;
89
+ }
90
+
91
+ /**
92
+ * Informações do sistema
93
+ */
94
+ async getSystemInfo() {
95
+ return {
96
+ platform: os.platform(),
97
+ arch: os.arch(),
98
+ release: os.release(),
99
+ hostname: os.hostname(),
100
+ cpus: os.cpus().length,
101
+ memory: {
102
+ total: Math.round(os.totalmem() / 1024 / 1024 / 1024 * 100) / 100, // GB
103
+ free: Math.round(os.freemem() / 1024 / 1024 / 1024 * 100) / 100 // GB
104
+ },
105
+ uptime: Math.floor(os.uptime() / 3600), // hours
106
+ user: os.userInfo().username,
107
+ home: os.homedir(),
108
+ shell: process.env.SHELL || 'unknown'
109
+ };
110
+ }
111
+
112
+ /**
113
+ * Detecta Java
114
+ */
115
+ async detectJava() {
116
+ const result = {
117
+ installed: false,
118
+ version: null,
119
+ vendor: null,
120
+ javaHome: process.env.JAVA_HOME || null,
121
+ path: null
122
+ };
123
+
124
+ try {
125
+ // Tentar java -version
126
+ const { stderr } = await execAsync('java -version 2>&1');
127
+ const output = stderr || '';
128
+
129
+ result.installed = true;
130
+
131
+ // Extrair versão (ex: "openjdk version "17.0.1"")
132
+ const versionMatch = output.match(/version\s+"([^"]+)"/);
133
+ if (versionMatch) {
134
+ result.version = versionMatch[1];
135
+ }
136
+
137
+ // Extrair vendor
138
+ if (output.includes('OpenJDK')) {
139
+ result.vendor = 'OpenJDK';
140
+ } else if (output.includes('Oracle')) {
141
+ result.vendor = 'Oracle';
142
+ } else if (output.includes('Azul')) {
143
+ result.vendor = 'Azul Zulu';
144
+ } else if (output.includes('Amazon')) {
145
+ result.vendor = 'Amazon Corretto';
146
+ } else if (output.includes('Eclipse')) {
147
+ result.vendor = 'Eclipse Temurin';
148
+ }
149
+
150
+ // Encontrar path
151
+ const { stdout: whichOutput } = await execAsync('which java').catch(() => ({ stdout: '' }));
152
+ result.path = whichOutput.trim() || null;
153
+
154
+ } catch (err) {
155
+ result.error = err.message;
156
+ }
157
+
158
+ return result;
159
+ }
160
+
161
+ /**
162
+ * Detecta Maven
163
+ */
164
+ async detectMaven() {
165
+ const result = {
166
+ installed: false,
167
+ version: null,
168
+ path: null,
169
+ mavenHome: process.env.MAVEN_HOME || process.env.M2_HOME || null
170
+ };
171
+
172
+ try {
173
+ const { stdout } = await execAsync('mvn -version 2>&1');
174
+
175
+ result.installed = true;
176
+
177
+ // Extrair versão (ex: "Apache Maven 3.9.0")
178
+ const versionMatch = stdout.match(/Apache Maven (\d+\.\d+\.\d+)/);
179
+ if (versionMatch) {
180
+ result.version = versionMatch[1];
181
+ }
182
+
183
+ // Extrair Java version usado pelo Maven
184
+ const javaMatch = stdout.match(/Java version: ([^\n,]+)/);
185
+ if (javaMatch) {
186
+ result.javaVersion = javaMatch[1].trim();
187
+ }
188
+
189
+ // Encontrar path
190
+ const { stdout: whichOutput } = await execAsync('which mvn').catch(() => ({ stdout: '' }));
191
+ result.path = whichOutput.trim() || null;
192
+
193
+ } catch (err) {
194
+ result.error = err.message;
195
+ }
196
+
197
+ return result;
198
+ }
199
+
200
+ /**
201
+ * Detecta Gradle
202
+ */
203
+ async detectGradle() {
204
+ const result = {
205
+ installed: false,
206
+ version: null,
207
+ path: null,
208
+ gradleHome: process.env.GRADLE_HOME || null
209
+ };
210
+
211
+ try {
212
+ const { stdout } = await execAsync('gradle -version 2>&1');
213
+
214
+ result.installed = true;
215
+
216
+ // Extrair versão (ex: "Gradle 8.0")
217
+ const versionMatch = stdout.match(/Gradle (\d+\.\d+\.?\d*)/);
218
+ if (versionMatch) {
219
+ result.version = versionMatch[1];
220
+ }
221
+
222
+ // Encontrar path
223
+ const { stdout: whichOutput } = await execAsync('which gradle').catch(() => ({ stdout: '' }));
224
+ result.path = whichOutput.trim() || null;
225
+
226
+ } catch (err) {
227
+ result.error = err.message;
228
+ }
229
+
230
+ return result;
231
+ }
232
+
233
+ /**
234
+ * Detecta Node.js
235
+ */
236
+ async detectNode() {
237
+ const result = {
238
+ installed: false,
239
+ version: null,
240
+ path: null
241
+ };
242
+
243
+ try {
244
+ const { stdout } = await execAsync('node -version 2>&1');
245
+
246
+ result.installed = true;
247
+ result.version = stdout.trim().replace('v', '');
248
+
249
+ // Encontrar path
250
+ const { stdout: whichOutput } = await execAsync('which node').catch(() => ({ stdout: '' }));
251
+ result.path = whichOutput.trim() || null;
252
+
253
+ } catch (err) {
254
+ result.error = err.message;
255
+ }
256
+
257
+ return result;
258
+ }
259
+
260
+ /**
261
+ * Detecta npm
262
+ */
263
+ async detectNpm() {
264
+ const result = {
265
+ installed: false,
266
+ version: null,
267
+ path: null,
268
+ globalPrefix: null
269
+ };
270
+
271
+ try {
272
+ const { stdout } = await execAsync('npm -version 2>&1');
273
+
274
+ result.installed = true;
275
+ result.version = stdout.trim();
276
+
277
+ // Prefix global
278
+ const { stdout: prefixOutput } = await execAsync('npm config get prefix').catch(() => ({ stdout: '' }));
279
+ result.globalPrefix = prefixOutput.trim() || null;
280
+
281
+ // Encontrar path
282
+ const { stdout: whichOutput } = await execAsync('which npm').catch(() => ({ stdout: '' }));
283
+ result.path = whichOutput.trim() || null;
284
+
285
+ } catch (err) {
286
+ result.error = err.message;
287
+ }
288
+
289
+ return result;
290
+ }
291
+
292
+ /**
293
+ * Detecta Yarn
294
+ */
295
+ async detectYarn() {
296
+ const result = {
297
+ installed: false,
298
+ version: null,
299
+ path: null
300
+ };
301
+
302
+ try {
303
+ const { stdout } = await execAsync('yarn -version 2>&1');
304
+
305
+ result.installed = true;
306
+ result.version = stdout.trim();
307
+
308
+ // Encontrar path
309
+ const { stdout: whichOutput } = await execAsync('which yarn').catch(() => ({ stdout: '' }));
310
+ result.path = whichOutput.trim() || null;
311
+
312
+ } catch (err) {
313
+ result.error = err.message;
314
+ }
315
+
316
+ return result;
317
+ }
318
+
319
+ /**
320
+ * Detecta Python
321
+ */
322
+ async detectPython() {
323
+ const result = {
324
+ installed: false,
325
+ version: null,
326
+ path: null,
327
+ python3: false
328
+ };
329
+
330
+ try {
331
+ // Tentar python3 primeiro
332
+ const { stdout } = await execAsync('python3 --version 2>&1').catch(() =>
333
+ execAsync('python --version 2>&1')
334
+ );
335
+
336
+ result.installed = true;
337
+
338
+ // Extrair versão (ex: "Python 3.11.0")
339
+ const versionMatch = stdout.match(/Python (\d+\.\d+\.?\d*)/);
340
+ if (versionMatch) {
341
+ result.version = versionMatch[1];
342
+ result.python3 = result.version.startsWith('3');
343
+ }
344
+
345
+ // Encontrar path
346
+ const { stdout: whichOutput } = await execAsync('which python3 || which python').catch(() => ({ stdout: '' }));
347
+ result.path = whichOutput.trim() || null;
348
+
349
+ } catch (err) {
350
+ result.error = err.message;
351
+ }
352
+
353
+ return result;
354
+ }
355
+
356
+ /**
357
+ * Detecta pip
358
+ */
359
+ async detectPip() {
360
+ const result = {
361
+ installed: false,
362
+ version: null,
363
+ path: null
364
+ };
365
+
366
+ try {
367
+ const { stdout } = await execAsync('pip3 --version 2>&1').catch(() =>
368
+ execAsync('pip --version 2>&1')
369
+ );
370
+
371
+ result.installed = true;
372
+
373
+ // Extrair versão (ex: "pip 23.0.1")
374
+ const versionMatch = stdout.match(/pip (\d+\.\d+\.?\d*)/);
375
+ if (versionMatch) {
376
+ result.version = versionMatch[1];
377
+ }
378
+
379
+ // Encontrar path
380
+ const { stdout: whichOutput } = await execAsync('which pip3 || which pip').catch(() => ({ stdout: '' }));
381
+ result.path = whichOutput.trim() || null;
382
+
383
+ } catch (err) {
384
+ result.error = err.message;
385
+ }
386
+
387
+ return result;
388
+ }
389
+
390
+ /**
391
+ * Detecta Go
392
+ */
393
+ async detectGo() {
394
+ const result = {
395
+ installed: false,
396
+ version: null,
397
+ path: null,
398
+ gopath: process.env.GOPATH || null,
399
+ goroot: process.env.GOROOT || null
400
+ };
401
+
402
+ try {
403
+ const { stdout } = await execAsync('go version 2>&1');
404
+
405
+ result.installed = true;
406
+
407
+ // Extrair versão (ex: "go version go1.21.0 darwin/amd64")
408
+ const versionMatch = stdout.match(/go(\d+\.\d+\.?\d*)/);
409
+ if (versionMatch) {
410
+ result.version = versionMatch[1];
411
+ }
412
+
413
+ // Encontrar path
414
+ const { stdout: whichOutput } = await execAsync('which go').catch(() => ({ stdout: '' }));
415
+ result.path = whichOutput.trim() || null;
416
+
417
+ } catch (err) {
418
+ result.error = err.message;
419
+ }
420
+
421
+ return result;
422
+ }
423
+
424
+ /**
425
+ * Detecta .NET
426
+ */
427
+ async detectDotnet() {
428
+ const result = {
429
+ installed: false,
430
+ version: null,
431
+ sdks: [],
432
+ runtimes: [],
433
+ path: null
434
+ };
435
+
436
+ try {
437
+ const { stdout } = await execAsync('dotnet --version 2>&1');
438
+
439
+ result.installed = true;
440
+ result.version = stdout.trim();
441
+
442
+ // Listar SDKs
443
+ const { stdout: sdkOutput } = await execAsync('dotnet --list-sdks 2>&1').catch(() => ({ stdout: '' }));
444
+ result.sdks = sdkOutput.trim().split('\n').filter(Boolean);
445
+
446
+ // Listar Runtimes
447
+ const { stdout: runtimeOutput } = await execAsync('dotnet --list-runtimes 2>&1').catch(() => ({ stdout: '' }));
448
+ result.runtimes = runtimeOutput.trim().split('\n').filter(Boolean).slice(0, 5); // Limitar
449
+
450
+ // Encontrar path
451
+ const { stdout: whichOutput } = await execAsync('which dotnet').catch(() => ({ stdout: '' }));
452
+ result.path = whichOutput.trim() || null;
453
+
454
+ } catch (err) {
455
+ result.error = err.message;
456
+ }
457
+
458
+ return result;
459
+ }
460
+
461
+ /**
462
+ * Detecta Git
463
+ */
464
+ async detectGit() {
465
+ const result = {
466
+ installed: false,
467
+ version: null,
468
+ path: null,
469
+ user: null,
470
+ email: null
471
+ };
472
+
473
+ try {
474
+ const { stdout } = await execAsync('git --version 2>&1');
475
+
476
+ result.installed = true;
477
+
478
+ // Extrair versão (ex: "git version 2.39.0")
479
+ const versionMatch = stdout.match(/git version (\d+\.\d+\.?\d*)/);
480
+ if (versionMatch) {
481
+ result.version = versionMatch[1];
482
+ }
483
+
484
+ // User e email
485
+ const { stdout: userOutput } = await execAsync('git config --global user.name').catch(() => ({ stdout: '' }));
486
+ result.user = userOutput.trim() || null;
487
+
488
+ const { stdout: emailOutput } = await execAsync('git config --global user.email').catch(() => ({ stdout: '' }));
489
+ result.email = emailOutput.trim() || null;
490
+
491
+ // Encontrar path
492
+ const { stdout: whichOutput } = await execAsync('which git').catch(() => ({ stdout: '' }));
493
+ result.path = whichOutput.trim() || null;
494
+
495
+ } catch (err) {
496
+ result.error = err.message;
497
+ }
498
+
499
+ return result;
500
+ }
501
+
502
+ /**
503
+ * Detecta Docker
504
+ */
505
+ async detectDocker() {
506
+ const result = {
507
+ installed: false,
508
+ version: null,
509
+ running: false,
510
+ path: null
511
+ };
512
+
513
+ try {
514
+ const { stdout } = await execAsync('docker --version 2>&1');
515
+
516
+ result.installed = true;
517
+
518
+ // Extrair versão (ex: "Docker version 24.0.0, build xxx")
519
+ const versionMatch = stdout.match(/Docker version (\d+\.\d+\.?\d*)/);
520
+ if (versionMatch) {
521
+ result.version = versionMatch[1];
522
+ }
523
+
524
+ // Verificar se está rodando
525
+ try {
526
+ await execAsync('docker info 2>&1');
527
+ result.running = true;
528
+ } catch {
529
+ result.running = false;
530
+ }
531
+
532
+ // Encontrar path
533
+ const { stdout: whichOutput } = await execAsync('which docker').catch(() => ({ stdout: '' }));
534
+ result.path = whichOutput.trim() || null;
535
+
536
+ } catch (err) {
537
+ result.error = err.message;
538
+ }
539
+
540
+ return result;
541
+ }
542
+
543
+ /**
544
+ * Gera sumário das capacidades
545
+ */
546
+ generateSummary(tools) {
547
+ const capabilities = [];
548
+
549
+ if (tools.java?.installed && tools.maven?.installed) {
550
+ capabilities.push('java-maven');
551
+ }
552
+ if (tools.java?.installed && tools.gradle?.installed) {
553
+ capabilities.push('java-gradle');
554
+ }
555
+ if (tools.node?.installed && tools.npm?.installed) {
556
+ capabilities.push('node-npm');
557
+ }
558
+ if (tools.node?.installed && tools.yarn?.installed) {
559
+ capabilities.push('node-yarn');
560
+ }
561
+ if (tools.python?.installed) {
562
+ capabilities.push('python');
563
+ }
564
+ if (tools.go?.installed) {
565
+ capabilities.push('go');
566
+ }
567
+ if (tools.dotnet?.installed) {
568
+ capabilities.push('dotnet');
569
+ }
570
+
571
+ return {
572
+ capabilities,
573
+ canRunJava: tools.java?.installed && (tools.maven?.installed || tools.gradle?.installed),
574
+ canRunNode: tools.node?.installed && (tools.npm?.installed || tools.yarn?.installed),
575
+ canRunPython: tools.python?.installed,
576
+ canRunGo: tools.go?.installed,
577
+ canRunDotnet: tools.dotnet?.installed
578
+ };
579
+ }
580
+
581
+ /**
582
+ * Detecta problemas de configuração
583
+ */
584
+ detectIssues(tools) {
585
+ const issues = [];
586
+
587
+ // Java sem JAVA_HOME
588
+ if (tools.java?.installed && !process.env.JAVA_HOME) {
589
+ issues.push({
590
+ severity: 'warning',
591
+ tool: 'java',
592
+ message: 'JAVA_HOME não está configurado',
593
+ fix: 'export JAVA_HOME=$(/usr/libexec/java_home)'
594
+ });
595
+ }
596
+
597
+ // Java instalado mas Maven não
598
+ if (tools.java?.installed && !tools.maven?.installed) {
599
+ issues.push({
600
+ severity: 'info',
601
+ tool: 'maven',
602
+ message: 'Maven não está instalado (necessário para projetos Maven)',
603
+ fix: 'brew install maven'
604
+ });
605
+ }
606
+
607
+ // Node sem npm
608
+ if (tools.node?.installed && !tools.npm?.installed) {
609
+ issues.push({
610
+ severity: 'error',
611
+ tool: 'npm',
612
+ message: 'Node está instalado mas npm não foi encontrado',
613
+ fix: 'Reinstale o Node.js'
614
+ });
615
+ }
616
+
617
+ // Python 2 ao invés de 3
618
+ if (tools.python?.installed && !tools.python?.python3) {
619
+ issues.push({
620
+ severity: 'warning',
621
+ tool: 'python',
622
+ message: 'Python 2 detectado. Recomendado usar Python 3',
623
+ fix: 'brew install python3'
624
+ });
625
+ }
626
+
627
+ return issues;
628
+ }
629
+
630
+ /**
631
+ * Diagnóstico rápido apenas para uma linguagem
632
+ */
633
+ async diagnoseFor(language) {
634
+ switch (language) {
635
+ case 'java':
636
+ return {
637
+ java: await this.detectJava(),
638
+ maven: await this.detectMaven(),
639
+ gradle: await this.detectGradle()
640
+ };
641
+ case 'node':
642
+ return {
643
+ node: await this.detectNode(),
644
+ npm: await this.detectNpm(),
645
+ yarn: await this.detectYarn()
646
+ };
647
+ case 'python':
648
+ return {
649
+ python: await this.detectPython(),
650
+ pip: await this.detectPip()
651
+ };
652
+ case 'go':
653
+ return {
654
+ go: await this.detectGo()
655
+ };
656
+ case 'dotnet':
657
+ return {
658
+ dotnet: await this.detectDotnet()
659
+ };
660
+ default:
661
+ return await this.diagnose();
662
+ }
663
+ }
664
+ }
665
+
666
+ export default EnvironmentDiagnostics;