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.
- package/.dockerignore +24 -0
- package/.idea/deepdebug-local-agent.iml +12 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/Dockerfile +46 -0
- package/cloudbuild.yaml +42 -0
- package/index.js +42 -0
- package/mcp-server.js +533 -0
- package/package.json +22 -0
- package/src/ai-engine.js +861 -0
- package/src/analyzers/config-analyzer.js +446 -0
- package/src/analyzers/controller-analyzer.js +429 -0
- package/src/analyzers/dto-analyzer.js +455 -0
- package/src/detectors/build-tool-detector.js +0 -0
- package/src/detectors/framework-detector.js +91 -0
- package/src/detectors/language-detector.js +89 -0
- package/src/detectors/multi-project-detector.js +191 -0
- package/src/detectors/service-detector.js +244 -0
- package/src/detectors.js +30 -0
- package/src/exec-utils.js +215 -0
- package/src/fs-utils.js +34 -0
- package/src/git/base-git-provider.js +384 -0
- package/src/git/git-provider-registry.js +110 -0
- package/src/git/github-provider.js +502 -0
- package/src/mcp-http-server.js +313 -0
- package/src/patch/patch-engine.js +339 -0
- package/src/patch-manager.js +816 -0
- package/src/patch.js +607 -0
- package/src/patch_bkp.js +154 -0
- package/src/ports.js +69 -0
- package/src/routes/workspace.route.js +528 -0
- package/src/runtimes/base-runtime.js +290 -0
- package/src/runtimes/java/gradle-runtime.js +378 -0
- package/src/runtimes/java/java-integrations.js +339 -0
- package/src/runtimes/java/maven-runtime.js +418 -0
- package/src/runtimes/node/node-integrations.js +247 -0
- package/src/runtimes/node/npm-runtime.js +466 -0
- package/src/runtimes/node/yarn-runtime.js +354 -0
- package/src/runtimes/runtime-registry.js +256 -0
- package/src/server-local.js +576 -0
- package/src/server.js +4565 -0
- package/src/utils/environment-diagnostics.js +666 -0
- package/src/utils/exec-utils.js +264 -0
- package/src/utils/fs-utils.js +218 -0
- package/src/workspace/detect-port.js +176 -0
- package/src/workspace/file-reader.js +54 -0
- package/src/workspace/git-client.js +0 -0
- package/src/workspace/process-manager.js +619 -0
- package/src/workspace/scanner.js +72 -0
- package/src/workspace-manager.js +172 -0
package/src/patch_bkp.js
ADDED
|
@@ -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
|
+
}
|