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,154 @@
1
+ import path from "path";
2
+ import { writeFile, readFile, exists } from "./fs-utils.js";
3
+ import pkg from "unidiff";
4
+
5
+ const { parsePatch, applyPatch } = pkg;
6
+
7
+ /**
8
+ * Aplica um unified diff ao arquivo alvo.
9
+ * VERSION 2: Melhor logging e fallback para replace direto.
10
+ */
11
+ export async function applyUnifiedDiff(root, diffText) {
12
+ console.log("đź”§ [patch_bkp.js] Applying unified diff...");
13
+ console.log("đź“‚ Root:", root);
14
+ console.log("đź“‹ Diff length:", diffText?.length || 0, "chars");
15
+
16
+ if (!diffText || diffText.trim() === "") {
17
+ throw new Error("Empty diff text provided");
18
+ }
19
+
20
+ // Log primeiras linhas do diff para debug
21
+ const diffLines = diffText.split("\n");
22
+ console.log("đź“‹ Diff preview:");
23
+ for (let i = 0; i < Math.min(10, diffLines.length); i++) {
24
+ console.log(` ${i + 1}: ${diffLines[i]}`);
25
+ }
26
+
27
+ // Parse o diff
28
+ let patches;
29
+ try {
30
+ patches = parsePatch(diffText);
31
+ console.log("âś… Parsed", patches.length, "patch(es)");
32
+ } catch (parseErr) {
33
+ console.error("❌ Failed to parse diff:", parseErr.message);
34
+ throw new Error("Failed to parse diff: " + parseErr.message);
35
+ }
36
+
37
+ if (!patches || patches.length === 0) {
38
+ throw new Error("No patches found in diff text");
39
+ }
40
+
41
+ const p = patches[0];
42
+ console.log("📦 Patch info:", {
43
+ oldFileName: p?.oldFileName,
44
+ newFileName: p?.newFileName,
45
+ hunks: p?.hunks?.length || 0
46
+ });
47
+
48
+ // Descobre path alvo a partir do patch
49
+ const targetRel =
50
+ p?.newFileName?.replace(/^b\//, "") ||
51
+ p?.oldFileName?.replace(/^a\//, "");
52
+
53
+ if (!targetRel) {
54
+ throw new Error("Could not infer target file from diff headers");
55
+ }
56
+
57
+ console.log("🎯 Target file:", targetRel);
58
+
59
+ const full = path.join(root, targetRel);
60
+ console.log("đź“„ Full path:", full);
61
+
62
+ // Verificar se arquivo existe
63
+ if (!(await exists(full))) {
64
+ throw new Error(`Target file not found: ${full}`);
65
+ }
66
+
67
+ // Ler arquivo original
68
+ let original;
69
+ try {
70
+ original = await readFile(full, "utf8");
71
+ console.log("đź“– Original file:", original.length, "chars,", original.split("\n").length, "lines");
72
+ } catch (readErr) {
73
+ throw new Error(`Failed to read target file: ${readErr.message}`);
74
+ }
75
+
76
+ // Tentar aplicar o patch
77
+ let result;
78
+ try {
79
+ result = applyPatch(original, p);
80
+ console.log("đź”§ applyPatch result:", result === false ? "FAILED" : `${result?.length} chars`);
81
+ } catch (applyErr) {
82
+ console.error("❌ applyPatch threw error:", applyErr.message);
83
+ throw new Error(`Patch application error: ${applyErr.message}`);
84
+ }
85
+
86
+ if (result === false) {
87
+ // Log mais detalhes sobre por que falhou
88
+ console.error("❌ Patch failed to apply. Possible reasons:");
89
+ console.error(" - Line numbers don't match current file");
90
+ console.error(" - Context lines don't match");
91
+ console.error(" - File was modified since diff was generated");
92
+
93
+ // Log hunks para debug
94
+ if (p.hunks) {
95
+ for (const hunk of p.hunks) {
96
+ console.error(` Hunk: @@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@`);
97
+ }
98
+ }
99
+
100
+ throw new Error("Patch failed to apply - context mismatch");
101
+ }
102
+
103
+ // Escrever resultado
104
+ try {
105
+ await writeFile(full, result, "utf8");
106
+ console.log("âś… Patch applied successfully!");
107
+ console.log(" Target:", targetRel);
108
+ console.log(" Bytes:", Buffer.byteLength(result, "utf8"));
109
+ } catch (writeErr) {
110
+ throw new Error(`Failed to write patched file: ${writeErr.message}`);
111
+ }
112
+
113
+ return {
114
+ target: targetRel,
115
+ bytes: Buffer.byteLength(result, "utf8"),
116
+ linesChanged: countChangedLines(p)
117
+ };
118
+ }
119
+
120
+ /**
121
+ * Conta quantas linhas foram alteradas
122
+ */
123
+ function countChangedLines(patch) {
124
+ if (!patch.hunks) return 0;
125
+ let count = 0;
126
+ for (const hunk of patch.hunks) {
127
+ if (hunk.lines) {
128
+ count += hunk.lines.filter(l => l.startsWith("+") || l.startsWith("-")).length;
129
+ }
130
+ }
131
+ return count;
132
+ }
133
+
134
+ /**
135
+ * Fallback: aplica substituição direta do arquivo
136
+ * Usado quando o patch unidiff falha mas temos o conteĂşdo completo
137
+ */
138
+ export async function applyDirectReplace(root, targetRel, newContent) {
139
+ console.log("🔄 [patch_bkp.js] Applying direct replace...");
140
+
141
+ const full = path.join(root, targetRel);
142
+
143
+ if (!(await exists(full))) {
144
+ throw new Error(`Target file not found: ${full}`);
145
+ }
146
+
147
+ await writeFile(full, newContent, "utf8");
148
+
149
+ return {
150
+ target: targetRel,
151
+ bytes: Buffer.byteLength(newContent, "utf8"),
152
+ method: "direct-replace"
153
+ };
154
+ }
package/src/ports.js ADDED
@@ -0,0 +1,69 @@
1
+ import path from "path";
2
+ import yaml from "js-yaml";
3
+ import PropertiesReader from "properties-reader";
4
+ import { exists, readFile } from "./fs-utils.js";
5
+
6
+ export async function detectPort(root) {
7
+ // Spring Boot
8
+ const ymlCandidates = [
9
+ "src/main/resources/application.yml",
10
+ "src/main/resources/application.yaml",
11
+ "application.yml",
12
+ "application.yaml"
13
+ ];
14
+ for (const rel of ymlCandidates) {
15
+ const full = path.join(root, rel);
16
+ if (await exists(full)) {
17
+ try {
18
+ const content = await readFile(full, "utf8");
19
+ const doc = yaml.load(content);
20
+
21
+ // Tentar pegar do objeto parseado
22
+ let port = doc?.server?.port ?? doc?.SERVER?.PORT;
23
+
24
+ // Se for string com ${PORT:8090}, extrair o valor padrĂŁo
25
+ if (typeof port === 'string') {
26
+ const match = port.match(/\$\{PORT:(\d+)\}/);
27
+ if (match) port = match[1];
28
+ }
29
+
30
+ if (port) return Number(port);
31
+ } catch {}
32
+ }
33
+ }
34
+
35
+ const propCandidates = [
36
+ "src/main/resources/application.properties",
37
+ "application.properties"
38
+ ];
39
+ for (const rel of propCandidates) {
40
+ const full = path.join(root, rel);
41
+ if (await exists(full)) {
42
+ try {
43
+ const props = PropertiesReader(full);
44
+ let port = props.get("server.port");
45
+
46
+ // Se for string com ${PORT:8090}, extrair o valor padrĂŁo
47
+ if (typeof port === 'string') {
48
+ const match = port.match(/\$\{PORT:(\d+)\}/);
49
+ if (match) port = match[1];
50
+ }
51
+
52
+ if (port) return Number(port);
53
+ } catch {}
54
+ }
55
+ }
56
+
57
+ // Node (com .env padrĂŁo)
58
+ const envCandidates = [".env", "src/.env"];
59
+ for (const rel of envCandidates) {
60
+ const full = path.join(root, rel);
61
+ if (await exists(full)) {
62
+ const content = await readFile(full, "utf8");
63
+ const m = content.match(/PORT\s*=\s*(\d+)/i);
64
+ if (m) return Number(m[1]);
65
+ }
66
+ }
67
+
68
+ return null;
69
+ }