deepdebug-local-agent 1.0.18 → 1.0.20

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/Dockerfile CHANGED
@@ -2,7 +2,7 @@
2
2
  # ║ DeepDebug Local Agent - Enterprise Docker ║
3
3
  # ║ ║
4
4
  # ║ Security-hardened container for enterprise deployments ║
5
- # ║ Supports: Kubernetes, OpenShift, Docker Compose
5
+ # ║ Supports: Cloud Run with NFS (GCP Filestore)
6
6
  # ╚══════════════════════════════════════════════════════════════╝
7
7
 
8
8
  # ===========================================
@@ -12,14 +12,9 @@ FROM node:20-alpine AS builder
12
12
 
13
13
  WORKDIR /build
14
14
 
15
- # Copy package files first (better cache)
16
15
  COPY package*.json ./
17
-
18
- # Install dependencies (production only)
19
- # Using npm install instead of npm ci for repos without package-lock.json
20
16
  RUN npm install --omit=dev && npm cache clean --force
21
17
 
22
- # Copy source code
23
18
  COPY src/ ./src/
24
19
 
25
20
  # ===========================================
@@ -27,48 +22,69 @@ COPY src/ ./src/
27
22
  # ===========================================
28
23
  FROM node:20-alpine AS production
29
24
 
30
- # Security: Add labels for compliance
31
25
  LABEL org.opencontainers.image.title="DeepDebug Local Agent"
32
26
  LABEL org.opencontainers.image.description="Enterprise debugging agent for code analysis"
33
27
  LABEL org.opencontainers.image.vendor="InspTech AI"
34
- LABEL org.opencontainers.image.version="1.0.0"
28
+ LABEL org.opencontainers.image.version="1.2.0"
35
29
  LABEL org.opencontainers.image.licenses="Proprietary"
36
30
  LABEL security.scan.required="true"
37
31
 
38
- # Security: Create non-root user
32
+ # Create non-root user
39
33
  RUN addgroup -g 1001 -S deepdebug && \
40
34
  adduser -u 1001 -S deepdebug -G deepdebug
41
35
 
42
- # Security: Install security updates
36
+ # Install dependencies including Java 17 for Maven wrapper support
43
37
  RUN apk update && \
44
38
  apk upgrade --no-cache && \
45
39
  apk add --no-cache \
46
40
  dumb-init \
47
41
  git \
48
42
  curl \
43
+ nfs-utils \
44
+ openjdk17-jdk \
49
45
  && rm -rf /var/cache/apk/*
50
46
 
47
+ # Set JAVA_HOME so ./mvnw can find Java
48
+ # Alpine stores JVM under java-17-openjdk with arch suffix - use readlink to resolve
49
+ RUN ln -sf $(dirname $(dirname $(readlink -f $(which java)))) /usr/local/java-home
50
+ ENV JAVA_HOME=/usr/local/java-home
51
+ ENV PATH="$JAVA_HOME/bin:$PATH"
52
+
53
+ # Create NFS mount point with correct ownership
54
+ RUN mkdir -p /mnt/workspaces && \
55
+ chown deepdebug:deepdebug /mnt/workspaces
56
+
57
+ # Install cloudflared for tunnel support (Vibe preview)
58
+ RUN wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 \
59
+ -O /usr/local/bin/cloudflared && \
60
+ chmod +x /usr/local/bin/cloudflared && \
61
+ cloudflared --version
62
+
63
+ # Install GitHub CLI (gh) for PR creation
64
+ RUN wget -q https://github.com/cli/cli/releases/download/v2.63.2/gh_2.63.2_linux_amd64.tar.gz \
65
+ -O /tmp/gh.tar.gz && \
66
+ tar -xzf /tmp/gh.tar.gz -C /tmp && \
67
+ mv /tmp/gh_2.63.2_linux_amd64/bin/gh /usr/local/bin/gh && \
68
+ chmod +x /usr/local/bin/gh && \
69
+ rm -rf /tmp/gh* && \
70
+ gh --version
71
+
51
72
  WORKDIR /app
52
73
 
53
- # Copy from builder with correct ownership
54
74
  COPY --from=builder --chown=deepdebug:deepdebug /build/node_modules ./node_modules
55
75
  COPY --from=builder --chown=deepdebug:deepdebug /build/src ./src
56
76
  COPY --chown=deepdebug:deepdebug package*.json ./
57
77
 
58
- # Security: Switch to non-root user
59
78
  USER deepdebug
60
79
 
61
- # Health check
62
80
  HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
63
81
  CMD curl -f http://localhost:5055/health || exit 1
64
82
 
65
- # Environment
66
83
  ENV NODE_ENV=production
67
84
  ENV PORT=5055
85
+ ENV WORKSPACES_MOUNT=/mnt/workspaces
68
86
 
69
- # Expose port
70
87
  EXPOSE 5055
71
88
 
72
- # Security: Use dumb-init to handle signals properly
73
89
  ENTRYPOINT ["dumb-init", "--"]
74
90
  CMD ["node", "src/server.js"]
@@ -0,0 +1,43 @@
1
+ steps:
2
+ # Step 1: Build Docker image
3
+ - name: 'gcr.io/cloud-builders/docker'
4
+ args:
5
+ - 'build'
6
+ - '--platform=linux/amd64'
7
+ - '-t'
8
+ - 'us-central1-docker.pkg.dev/insptechai/deepdebug-docker/local-agent-qa:latest'
9
+ - '.'
10
+ timeout: '600s'
11
+
12
+ # Step 2: Push to Artifact Registry
13
+ - name: 'gcr.io/cloud-builders/docker'
14
+ args:
15
+ - 'push'
16
+ - 'us-central1-docker.pkg.dev/insptechai/deepdebug-docker/local-agent-qa:latest'
17
+
18
+ # Step 3: Deploy to Cloud Run QA
19
+ - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
20
+ entrypoint: 'gcloud'
21
+ args:
22
+ - 'run'
23
+ - 'deploy'
24
+ - 'deepdebug-local-agent-qa'
25
+ - '--image=us-central1-docker.pkg.dev/insptechai/deepdebug-docker/local-agent-qa:latest'
26
+ - '--region=us-central1'
27
+ - '--platform=managed'
28
+ - '--allow-unauthenticated'
29
+ - '--memory=1Gi'
30
+ - '--cpu=1'
31
+ - '--min-instances=1'
32
+ - '--max-instances=3'
33
+ - '--port=5055'
34
+ - '--timeout=300'
35
+ - '--update-env-vars=NODE_ENV=qa'
36
+
37
+ images:
38
+ - 'us-central1-docker.pkg.dev/insptechai/deepdebug-docker/local-agent-qa:latest'
39
+
40
+ options:
41
+ logging: CLOUD_LOGGING_ONLY
42
+
43
+ timeout: '1200s'
@@ -52,8 +52,8 @@ services:
52
52
  # Volumes
53
53
  # ─────────────────────────────────────────
54
54
  volumes:
55
- # Project source code (read-only for security)
56
- - ${PROJECT_PATH:-/path/to/projects}:/workspace:ro
55
+ # Project source code - writable so agent can apply patches
56
+ - /Users/macintosh/IdeaProjects:/workspace
57
57
  # Temp directory for container writes
58
58
  - agent-tmp:/tmp
59
59
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepdebug-local-agent",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "description": "DeepDebug Local Agent - AI-powered code debugging assistant",
5
5
  "private": false,
6
6
  "type": "module",
package/src/exec-utils.js CHANGED
@@ -1,10 +1,12 @@
1
1
  import { spawn } from "child_process";
2
2
  import stripAnsi from "strip-ansi";
3
3
 
4
- export function run(cmd, args, cwd, timeoutMs = 10 * 60 * 1000) {
4
+ export function run(cmd, args, cwd, timeoutMs = 10 * 60 * 1000, env = null) {
5
5
  return new Promise((resolve) => {
6
6
  const start = Date.now();
7
- const child = spawn(cmd, args, { cwd, shell: true });
7
+ const spawnOpts = { cwd, shell: true };
8
+ if (env) spawnOpts.env = env;
9
+ const child = spawn(cmd, args, spawnOpts);
8
10
  let stdout = "";
9
11
  let stderr = "";
10
12
  const timer = setTimeout(() => {
@@ -47,20 +49,121 @@ export function run(cmd, args, cwd, timeoutMs = 10 * 60 * 1000) {
47
49
  * @returns {Promise<{code: number, stdout: string, stderr: string, duration: number}>}
48
50
  */
49
51
  export async function compileAndTest({ language, buildTool, cwd, skipTests = false }) {
50
- console.log(`🔨 [COMPILE] Language: ${language}, BuildTool: ${buildTool}, SkipTests: ${skipTests}`);
52
+ console.log(`[BUILD] [COMPILE] Language: ${language}, BuildTool: ${buildTool}, SkipTests: ${skipTests}`);
51
53
 
52
54
  let result;
53
55
  const start = Date.now();
54
56
 
55
57
  try {
56
58
  if (language === "java" && buildTool === "maven") {
57
- // Maven: clean install (skip tests if requested)
59
+ // Prefer ./mvnw wrapper over system mvn
60
+ const fs = await import("fs");
61
+ const path = await import("path");
62
+ const hasMvnw = fs.existsSync(path.join(cwd, "mvnw"));
63
+ const mvnCmd = hasMvnw ? "./mvnw" : "mvn";
64
+
65
+ // Verify build tool is available before attempting
66
+ if (!hasMvnw) {
67
+ const check = await run("which mvn", [], cwd);
68
+ if (check.code !== 0) {
69
+ return {
70
+ code: 1,
71
+ stdout: "",
72
+ stderr: "Maven not found: neither ./mvnw nor mvn is available in this environment.",
73
+ duration: Date.now() - start
74
+ };
75
+ }
76
+ }
77
+
78
+ // Fix for maven-compiler-plugin 3.8.1 + Java 17:
79
+ // plexus-compiler-javac 2.8.4 does not support --release 17.
80
+ // Workaround: disable the --release flag entirely and use -source/-target instead.
81
+ // Also pass JAVA_HOME explicitly so mvnw uses the correct JDK.
82
+ // Dynamically prepare Maven environment and fix common Java version issues
83
+ const fs2 = await import("fs");
84
+ const path2 = await import("path");
85
+
86
+ // 1. Detect Java version available
87
+ const javaHome = process.env.JAVA_HOME || "/usr/local/java-home";
88
+ const javacPath = `${javaHome}/bin/javac`;
89
+ const hasJavac = fs2.existsSync(javacPath);
90
+ const mavenEnv = {
91
+ ...process.env,
92
+ JAVA_HOME: javaHome,
93
+ PATH: `${javaHome}/bin:${process.env.PATH}`
94
+ };
95
+ console.log(`[BUILD] JAVA_HOME=${javaHome}, javac available=${hasJavac}`);
96
+
97
+ // 2. Detect Java version from javac
98
+ let javaVersion = 11; // default fallback
99
+ try {
100
+ const versionResult = await run(`${javaHome}/bin/java`, ["-version"], cwd, 5000, mavenEnv);
101
+ const versionOutput = versionResult.stdout + versionResult.stderr;
102
+ const match = versionOutput.match(/version "(\d+)/);
103
+ if (match) javaVersion = parseInt(match[1]);
104
+ console.log(`[BUILD] Detected Java version: ${javaVersion}`);
105
+ } catch {}
106
+
107
+ // 3. Patch pom.xml dynamically based on what's in it
108
+ const pomPath = path2.join(cwd, "pom.xml");
109
+ const javaCompatFlags = [];
110
+ if (fs2.existsSync(pomPath)) {
111
+ try {
112
+ let pomContent = fs2.readFileSync(pomPath, "utf8");
113
+ let patched = pomContent;
114
+
115
+ // Detect configured java version in pom
116
+ const javaVersionMatch = pomContent.match(/<java\.version>(\d+)<\/java\.version>/);
117
+ const pomJavaVersion = javaVersionMatch ? parseInt(javaVersionMatch[1]) : javaVersion;
118
+ console.log(`[BUILD] pom.xml java.version=${pomJavaVersion}`);
119
+
120
+ // Detect maven-compiler-plugin version
121
+ const compilerVersionMatch = pomContent.match(/<artifactId>maven-compiler-plugin<\/artifactId>\s*<version>([^<]+)<\/version>/);
122
+ const compilerVersion = compilerVersionMatch ? compilerVersionMatch[1] : "unknown";
123
+ console.log(`[BUILD] maven-compiler-plugin version=${compilerVersion}`);
124
+
125
+ // If compiler plugin < 3.10 and java >= 17: upgrade to 3.11.0
126
+ // (3.8.x uses plexus-compiler-javac 2.8.4 which doesn't support --release 17)
127
+ const [compMajor, compMinor] = compilerVersion.split(".").map(Number);
128
+ if (!isNaN(compMajor) && (compMajor < 3 || (compMajor === 3 && compMinor < 10)) && pomJavaVersion >= 17) {
129
+ patched = patched.replace(
130
+ new RegExp("(<artifactId>maven-compiler-plugin<\/artifactId>\\s*<version>)[^<]+(<\/version>)"),
131
+ "$1" + "3.11.0" + "$2"
132
+ );
133
+ console.log(`[BUILD] Patched: maven-compiler-plugin ${compilerVersion} -> 3.11.0`);
134
+ }
135
+
136
+ // If pom uses <release> tag that might fail, replace with <source>/<target>
137
+ if (pomContent.includes("<release>") && pomJavaVersion >= 17) {
138
+ patched = patched.replace(
139
+ /<release>\d+<\/release>/g,
140
+ `<source>${pomJavaVersion}</source>
141
+ <target>${pomJavaVersion}</target>`
142
+ );
143
+ console.log(`[BUILD] Patched: replaced <release> with <source>/<target> for Java ${pomJavaVersion}`);
144
+ }
145
+
146
+ if (patched !== pomContent) {
147
+ fs2.writeFileSync(pomPath, patched, "utf8");
148
+ console.log("[BUILD] pom.xml patched successfully");
149
+ } else {
150
+ console.log("[BUILD] pom.xml no patches needed");
151
+ }
152
+ } catch (patchErr) {
153
+ console.warn("[BUILD] Could not patch pom.xml:", patchErr.message);
154
+ }
155
+ }
156
+
58
157
  const args = skipTests
59
- ? ["clean", "install", "-DskipTests", "-q"]
60
- : ["clean", "install", "-q"];
158
+ ? ["compile", "-DskipTests", ...javaCompatFlags]
159
+ : ["test", ...javaCompatFlags];
61
160
 
62
- console.log(`🔨 [COMPILE] Running: mvn ${args.join(" ")}`);
63
- result = await run("mvn", args, cwd);
161
+ console.log(`[BUILD] [COMPILE] Running: ${mvnCmd} ${args.join(" ")}`);
162
+ result = await run(mvnCmd, args, cwd, 10 * 60 * 1000, mavenEnv);
163
+ if (result.code !== 0) {
164
+ console.error("[ERR] [COMPILE] stdout:", result.stdout.substring(0, 2000));
165
+ console.error("[ERR] [COMPILE] stderr:", result.stderr.substring(0, 2000));
166
+ }
64
167
  }
65
168
  else if (language === "java" && buildTool === "gradle") {
66
169
  // Gradle: clean build
@@ -68,12 +171,12 @@ export async function compileAndTest({ language, buildTool, cwd, skipTests = fal
68
171
  ? ["clean", "build", "-x", "test"]
69
172
  : ["clean", "build"];
70
173
 
71
- console.log(`🔨 [COMPILE] Running: ./gradlew ${args.join(" ")}`);
174
+ console.log(`[BUILD] [COMPILE] Running: ./gradlew ${args.join(" ")}`);
72
175
  result = await run("./gradlew", args, cwd);
73
176
  }
74
177
  else if (language === "node" || buildTool === "npm") {
75
178
  // Node/npm: install and optionally test
76
- console.log(`🔨 [COMPILE] Running: npm install`);
179
+ console.log(`[BUILD] [COMPILE] Running: npm install`);
77
180
  const installResult = await run("npm", ["install", "--silent"], cwd);
78
181
 
79
182
  if (installResult.code !== 0) {
@@ -81,7 +184,7 @@ export async function compileAndTest({ language, buildTool, cwd, skipTests = fal
81
184
  }
82
185
 
83
186
  if (!skipTests) {
84
- console.log(`🔨 [COMPILE] Running: npm test`);
187
+ console.log(`[BUILD] [COMPILE] Running: npm test`);
85
188
  result = await run("npm", ["test", "--silent"], cwd);
86
189
  } else {
87
190
  result = installResult;
@@ -89,7 +192,7 @@ export async function compileAndTest({ language, buildTool, cwd, skipTests = fal
89
192
  }
90
193
  else if (language === "node" || buildTool === "yarn") {
91
194
  // Yarn
92
- console.log(`🔨 [COMPILE] Running: yarn install`);
195
+ console.log(`[BUILD] [COMPILE] Running: yarn install`);
93
196
  const installResult = await run("yarn", ["install", "--silent"], cwd);
94
197
 
95
198
  if (installResult.code !== 0) {
@@ -97,7 +200,7 @@ export async function compileAndTest({ language, buildTool, cwd, skipTests = fal
97
200
  }
98
201
 
99
202
  if (!skipTests) {
100
- console.log(`🔨 [COMPILE] Running: yarn test`);
203
+ console.log(`[BUILD] [COMPILE] Running: yarn test`);
101
204
  result = await run("yarn", ["test", "--silent"], cwd);
102
205
  } else {
103
206
  result = installResult;
@@ -106,7 +209,7 @@ export async function compileAndTest({ language, buildTool, cwd, skipTests = fal
106
209
  else if (language === "python") {
107
210
  // Python: pytest
108
211
  if (!skipTests) {
109
- console.log(`🔨 [COMPILE] Running: pytest`);
212
+ console.log(`[BUILD] [COMPILE] Running: pytest`);
110
213
  result = await run("pytest", [], cwd);
111
214
  } else {
112
215
  // Python doesn't have a compile step, just return success
@@ -115,7 +218,7 @@ export async function compileAndTest({ language, buildTool, cwd, skipTests = fal
115
218
  }
116
219
  else if (language === "go") {
117
220
  // Go: build and optionally test
118
- console.log(`🔨 [COMPILE] Running: go build ./...`);
221
+ console.log(`[BUILD] [COMPILE] Running: go build ./...`);
119
222
  const buildResult = await run("go", ["build", "./..."], cwd);
120
223
 
121
224
  if (buildResult.code !== 0) {
@@ -123,7 +226,7 @@ export async function compileAndTest({ language, buildTool, cwd, skipTests = fal
123
226
  }
124
227
 
125
228
  if (!skipTests) {
126
- console.log(`🔨 [COMPILE] Running: go test ./...`);
229
+ console.log(`[BUILD] [COMPILE] Running: go test ./...`);
127
230
  result = await run("go", ["test", "./..."], cwd);
128
231
  } else {
129
232
  result = buildResult;
@@ -131,7 +234,7 @@ export async function compileAndTest({ language, buildTool, cwd, skipTests = fal
131
234
  }
132
235
  else if (language === ".net" || language === "dotnet") {
133
236
  // .NET: build and optionally test
134
- console.log(`🔨 [COMPILE] Running: dotnet build`);
237
+ console.log(`[BUILD] [COMPILE] Running: dotnet build`);
135
238
  const buildResult = await run("dotnet", ["build"], cwd);
136
239
 
137
240
  if (buildResult.code !== 0) {
@@ -139,14 +242,14 @@ export async function compileAndTest({ language, buildTool, cwd, skipTests = fal
139
242
  }
140
243
 
141
244
  if (!skipTests) {
142
- console.log(`🔨 [COMPILE] Running: dotnet test`);
245
+ console.log(`[BUILD] [COMPILE] Running: dotnet test`);
143
246
  result = await run("dotnet", ["test"], cwd);
144
247
  } else {
145
248
  result = buildResult;
146
249
  }
147
250
  }
148
251
  else {
149
- console.error(`❌ [COMPILE] Unsupported: ${language}/${buildTool}`);
252
+ console.error(`[ERR] [COMPILE] Unsupported: ${language}/${buildTool}`);
150
253
  return {
151
254
  code: 1,
152
255
  stdout: "",
@@ -157,18 +260,18 @@ export async function compileAndTest({ language, buildTool, cwd, skipTests = fal
157
260
 
158
261
  // Log result
159
262
  if (result.code === 0) {
160
- console.log(`✅ [COMPILE] Success in ${result.duration}ms`);
263
+ console.log(`[OK] [COMPILE] Success in ${result.duration}ms`);
161
264
  } else {
162
- console.error(`❌ [COMPILE] Failed with code ${result.code}`);
265
+ console.error(`[ERR] [COMPILE] Failed with code ${result.code}`);
163
266
  if (result.stderr) {
164
- console.error(`❌ [COMPILE] Error: ${result.stderr.substring(0, 500)}`);
267
+ console.error(`[ERR] [COMPILE] Error: ${result.stderr.substring(0, 500)}`);
165
268
  }
166
269
  }
167
270
 
168
271
  return result;
169
272
 
170
273
  } catch (err) {
171
- console.error(`❌ [COMPILE] Exception: ${err.message}`);
274
+ console.error(`[ERR] [COMPILE] Exception: ${err.message}`);
172
275
  return {
173
276
  code: 1,
174
277
  stdout: "",