deepdebug-local-agent 1.0.20 → 1.0.22

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
@@ -1,14 +1,14 @@
1
1
  # ╔══════════════════════════════════════════════════════════════╗
2
2
  # ║ DeepDebug Local Agent - Enterprise Docker ║
3
3
  # ║ ║
4
- # ║ Security-hardened container for enterprise deployments ║
4
+ # ║ Multi-language agent: Java, Node, Python, Go, Swift, Kotlin ║
5
5
  # ║ Supports: Cloud Run with NFS (GCP Filestore) ║
6
6
  # ╚══════════════════════════════════════════════════════════════╝
7
7
 
8
8
  # ===========================================
9
- # Stage 1: Build
9
+ # Stage 1: Build (Node dependencies)
10
10
  # ===========================================
11
- FROM node:20-alpine AS builder
11
+ FROM node:20-bookworm-slim AS builder
12
12
 
13
13
  WORKDIR /build
14
14
 
@@ -20,36 +20,73 @@ COPY src/ ./src/
20
20
  # ===========================================
21
21
  # Stage 2: Production
22
22
  # ===========================================
23
- FROM node:20-alpine AS production
23
+ FROM node:20-bookworm-slim AS production
24
24
 
25
25
  LABEL org.opencontainers.image.title="DeepDebug Local Agent"
26
26
  LABEL org.opencontainers.image.description="Enterprise debugging agent for code analysis"
27
27
  LABEL org.opencontainers.image.vendor="InspTech AI"
28
- LABEL org.opencontainers.image.version="1.2.0"
28
+ LABEL org.opencontainers.image.version="2.0.0"
29
29
  LABEL org.opencontainers.image.licenses="Proprietary"
30
30
  LABEL security.scan.required="true"
31
31
 
32
32
  # Create non-root user
33
- RUN addgroup -g 1001 -S deepdebug && \
34
- adduser -u 1001 -S deepdebug -G deepdebug
33
+ RUN groupadd -g 1001 deepdebug && \
34
+ useradd -u 1001 -g deepdebug -m deepdebug
35
35
 
36
- # Install dependencies including Java 17 for Maven wrapper support
37
- RUN apk update && \
38
- apk upgrade --no-cache && \
39
- apk add --no-cache \
36
+ # Install system dependencies: git, curl, Java 17, Maven, Python 3, NFS, dumb-init
37
+ RUN apt-get update && \
38
+ apt-get install -y --no-install-recommends \
40
39
  dumb-init \
41
40
  git \
42
41
  curl \
43
- nfs-utils \
44
- openjdk17-jdk \
45
- && rm -rf /var/cache/apk/*
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
42
+ wget \
43
+ ca-certificates \
44
+ nfs-common \
45
+ openjdk-17-jdk-headless \
46
+ maven \
47
+ python3 \
48
+ python3-pip \
49
+ binutils \
50
+ libc6-dev \
51
+ libcurl4-openssl-dev \
52
+ libedit2 \
53
+ libgcc-s1 \
54
+ libpython3.11 \
55
+ libsqlite3-0 \
56
+ libstdc++6 \
57
+ libxml2 \
58
+ libz3-4 \
59
+ pkg-config \
60
+ zlib1g-dev \
61
+ libncurses6 \
62
+ gcc \
63
+ g++ \
64
+ && rm -rf /var/lib/apt/lists/*
65
+
66
+ # Set JAVA_HOME
67
+ ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
51
68
  ENV PATH="$JAVA_HOME/bin:$PATH"
52
69
 
70
+ # ==========================================
71
+ # Install Swift 6.0.3 (Linux x86_64)
72
+ # This enables REAL compilation for iOS/Swift projects:
73
+ # - `swift build` for SPM projects
74
+ # - `swiftc -typecheck` for syntax validation of any .swift file
75
+ # - Full Foundation/Dispatch/XCTest on Linux
76
+ # ==========================================
77
+ ARG SWIFT_VERSION=5.10.1
78
+ RUN SWIFT_URL="https://download.swift.org/swift-${SWIFT_VERSION}-release/ubuntu2204/swift-${SWIFT_VERSION}-RELEASE/swift-${SWIFT_VERSION}-RELEASE-ubuntu22.04.tar.gz" && \
79
+ echo "Downloading Swift ${SWIFT_VERSION} for Ubuntu 22.04 (glibc compat with Bookworm)..." && \
80
+ wget -q "${SWIFT_URL}" -O /tmp/swift.tar.gz && \
81
+ mkdir -p /usr/share/swift && \
82
+ tar -xzf /tmp/swift.tar.gz -C /usr/share/swift --strip-components=2 && \
83
+ rm /tmp/swift.tar.gz && \
84
+ export PATH="/usr/share/swift/bin:$PATH" && \
85
+ swift --version && \
86
+ echo "Swift installed successfully"
87
+
88
+ ENV PATH="/usr/share/swift/bin:$PATH"
89
+
53
90
  # Create NFS mount point with correct ownership
54
91
  RUN mkdir -p /mnt/workspaces && \
55
92
  chown deepdebug:deepdebug /mnt/workspaces
@@ -87,4 +124,4 @@ ENV WORKSPACES_MOUNT=/mnt/workspaces
87
124
  EXPOSE 5055
88
125
 
89
126
  ENTRYPOINT ["dumb-init", "--"]
90
- CMD ["node", "src/server.js"]
127
+ CMD ["node", "src/server.js"]
@@ -0,0 +1,63 @@
1
+ # ================================================================
2
+ # DeepDebug Local Agent - Full Stack (with build tools)
3
+ # ================================================================
4
+ # This image includes Java 17, Maven, Node.js, Python, and Git
5
+ # for compilation and testing in Cloud Engineer provisioned
6
+ # environments. Used when the client has OAuth connected and
7
+ # we provision a compilation container in their cloud.
8
+ # ================================================================
9
+
10
+ # Stage 1: Build Node.js agent
11
+ FROM node:20-slim AS builder
12
+
13
+ WORKDIR /build
14
+ COPY package*.json ./
15
+ RUN npm install --omit=dev && npm cache clean --force
16
+ COPY src/ ./src/
17
+
18
+ # Stage 2: Full runtime with build tools
19
+ FROM node:20-slim
20
+
21
+ # Install Java 17 + Maven for Spring Boot projects
22
+ RUN apt-get update && \
23
+ apt-get install -y --no-install-recommends \
24
+ openjdk-17-jdk-headless \
25
+ maven \
26
+ git \
27
+ curl \
28
+ openssh-client \
29
+ python3 \
30
+ python3-pip \
31
+ && rm -rf /var/lib/apt/lists/*
32
+
33
+ ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
34
+ ENV PATH=$PATH:$JAVA_HOME/bin:/usr/share/maven/bin
35
+
36
+ # Verify all tools are installed
37
+ RUN java -version && mvn -version && node -v && git --version
38
+
39
+ # Git safe directory for NFS mounted workspaces
40
+ RUN git config --global --add safe.directory '*'
41
+
42
+ # Create non-root user
43
+ RUN groupadd -r deepdebug && useradd -r -g deepdebug -m deepdebug
44
+
45
+ WORKDIR /app
46
+
47
+ # Copy built Node.js agent
48
+ COPY --from=builder /build/node_modules ./node_modules
49
+ COPY --from=builder /build/src ./src
50
+ COPY --from=builder /build/package*.json ./
51
+
52
+ # Maven dependencies cache directory
53
+ RUN mkdir -p /home/deepdebug/.m2 && chown -R deepdebug:deepdebug /home/deepdebug
54
+
55
+ # Workspace mount point
56
+ RUN mkdir -p /mnt/workspaces && chown -R deepdebug:deepdebug /mnt/workspaces
57
+
58
+ EXPOSE 8080
59
+
60
+ ENV NODE_ENV=production
61
+ ENV PORT=8080
62
+
63
+ CMD ["node", "src/server.js"]
@@ -0,0 +1,40 @@
1
+ steps:
2
+ - name: 'gcr.io/cloud-builders/docker'
3
+ args:
4
+ - 'build'
5
+ - '--platform=linux/amd64'
6
+ - '-t'
7
+ - 'us-central1-docker.pkg.dev/insptechai/deepdebug-docker/local-agent-staging:latest'
8
+ - '.'
9
+ timeout: '600s'
10
+
11
+ - name: 'gcr.io/cloud-builders/docker'
12
+ args:
13
+ - 'push'
14
+ - 'us-central1-docker.pkg.dev/insptechai/deepdebug-docker/local-agent-staging:latest'
15
+
16
+ - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
17
+ entrypoint: 'gcloud'
18
+ args:
19
+ - 'run'
20
+ - 'deploy'
21
+ - 'deepdebug-local-agent-staging'
22
+ - '--image=us-central1-docker.pkg.dev/insptechai/deepdebug-docker/local-agent-staging:latest'
23
+ - '--region=us-central1'
24
+ - '--platform=managed'
25
+ - '--allow-unauthenticated'
26
+ - '--memory=1Gi'
27
+ - '--cpu=1'
28
+ - '--min-instances=1'
29
+ - '--max-instances=3'
30
+ - '--port=5055'
31
+ - '--timeout=300'
32
+ - '--update-env-vars=NODE_ENV=staging'
33
+
34
+ images:
35
+ - 'us-central1-docker.pkg.dev/insptechai/deepdebug-docker/local-agent-staging:latest'
36
+
37
+ options:
38
+ logging: CLOUD_LOGGING_ONLY
39
+
40
+ timeout: '1200s'
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepdebug-local-agent",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
4
4
  "description": "DeepDebug Local Agent - AI-powered code debugging assistant",
5
5
  "private": false,
6
6
  "type": "module",
@@ -37,6 +37,7 @@
37
37
  "cors": "^2.8.5",
38
38
  "express": "^4.19.2",
39
39
  "js-yaml": "^4.1.0",
40
+ "pg": "^8.20.0",
40
41
  "pidusage": "^3.0.2",
41
42
  "properties-reader": "^2.3.0",
42
43
  "strip-ansi": "^7.1.0",
@@ -45,8 +46,8 @@
45
46
  },
46
47
  "devDependencies": {
47
48
  "esbuild": "^0.20.0",
48
- "pkg": "^5.8.1",
49
- "eslint": "^8.57.0"
49
+ "eslint": "^8.57.0",
50
+ "pkg": "^5.8.1"
50
51
  },
51
52
  "engines": {
52
53
  "node": ">=18.0.0"
@@ -17,11 +17,44 @@ export class FrameworkDetector {
17
17
  return { framework: 'dotnet', version: null, buildTool: 'dotnet' };
18
18
  case 'go':
19
19
  return { framework: 'go', version: null, buildTool: 'go' };
20
+ case 'ios':
21
+ return this.detectSwiftFramework();
22
+ case 'kotlin':
23
+ return this.detectKotlinFramework();
20
24
  default:
21
25
  return { framework: 'unknown', version: null, buildTool: null };
22
26
  }
23
27
  }
24
28
 
29
+ async detectSwiftFramework() {
30
+ for (const f of this.files) {
31
+ if (!f.name.endsWith('.swift')) continue;
32
+ try {
33
+ const c = await this.fileReader.read(f.path);
34
+ if (c.content && c.content.includes('import SwiftUI')) {
35
+ return { framework: 'swiftui', version: null, buildTool: 'xcodebuild' };
36
+ }
37
+ if (c.content && c.content.includes('import UIKit')) {
38
+ return { framework: 'uikit', version: null, buildTool: 'xcodebuild' };
39
+ }
40
+ } catch (_) {}
41
+ }
42
+ return { framework: 'swift-plain', version: null, buildTool: 'xcodebuild' };
43
+ }
44
+
45
+ async detectKotlinFramework() {
46
+ for (const f of this.files) {
47
+ if (!f.name.endsWith('.kt')) continue;
48
+ try {
49
+ const c = await this.fileReader.read(f.path);
50
+ if (c.content && c.content.includes('androidx.compose')) {
51
+ return { framework: 'jetpack-compose', version: null, buildTool: 'gradle' };
52
+ }
53
+ } catch (_) {}
54
+ }
55
+ return { framework: 'android-xml', version: null, buildTool: 'gradle' };
56
+ }
57
+
25
58
  async detectJavaFramework() {
26
59
  const pomFile = this.files.find(f => f.name === 'pom.xml');
27
60
  if (pomFile) {
@@ -16,13 +16,28 @@ export class LanguageDetector {
16
16
 
17
17
  findMarkers() {
18
18
  const markers = {
19
+ // iOS/Swift (highest priority when BOTH iOS and Java exist, per product rule:
20
+ // "Swift wins — it means the dev copied iOS files into a Java repo").
21
+ ios: this.files.some(f =>
22
+ f.name === 'Package.swift' ||
23
+ f.name === 'Podfile' ||
24
+ f.name === 'Podfile.lock' ||
25
+ f.name === 'Cartfile' ||
26
+ (f.name && (f.name.endsWith('.xcodeproj') || f.name.endsWith('.xcworkspace')))
27
+ ),
19
28
  java: this.files.some(f => f.name === 'pom.xml' || f.name === 'build.gradle'),
29
+ kotlin: this.files.some(f => f.name === 'build.gradle.kts'),
20
30
  node: this.files.some(f => f.name === 'package.json'),
21
31
  python: this.files.some(f => f.name === 'requirements.txt' || f.name === 'pyproject.toml'),
22
- dotnet: this.files.some(f => f.name.endsWith('.csproj') || f.name.endsWith('.sln')),
32
+ dotnet: this.files.some(f => f.name?.endsWith('.csproj') || f.name?.endsWith('.sln')),
23
33
  go: this.files.some(f => f.name === 'go.mod'),
24
34
  php: this.files.some(f => f.name === 'composer.json'),
25
- ruby: this.files.some(f => f.name === 'Gemfile')
35
+ ruby: this.files.some(f => f.name === 'Gemfile' || f.name === 'Rakefile'),
36
+ rust: this.files.some(f => f.name === 'Cargo.toml'),
37
+ dart: this.files.some(f => f.name === 'pubspec.yaml'),
38
+ elixir: this.files.some(f => f.name === 'mix.exs'),
39
+ docker: this.files.some(f => f.name === 'Dockerfile'),
40
+ static: this.files.some(f => f.name === 'index.html'),
26
41
  };
27
42
  return markers;
28
43
  }
@@ -37,20 +52,38 @@ export class LanguageDetector {
37
52
  }
38
53
 
39
54
  determinePrimaryLanguage(markers, extensions) {
40
- // Prioridade: markers > extensões
41
55
  const detected = Object.entries(markers)
42
56
  .filter(([_, exists]) => exists)
43
57
  .map(([lang]) => lang);
44
58
 
59
+ // Priority rule: iOS wins over anything else when its strong markers are present.
60
+ // Rationale: if a repo has BOTH Package.swift/Podfile/xcodeproj AND pom.xml, the
61
+ // developer copied iOS files into a Java repo (or vice versa) - the iOS app is
62
+ // the shipping artifact.
63
+ if (markers.ios) return 'ios';
64
+ // Even without strong iOS markers, a repo dominated by .swift source files is iOS.
65
+ const swiftCount = extensions['.swift'] || 0;
66
+ const totalCode = Object.entries(extensions)
67
+ .filter(([k]) => ['.swift','.m','.mm','.h','.java','.kt','.js','.ts','.py','.go','.rb','.cs','.php'].includes(k))
68
+ .reduce((s, [,v]) => s + v, 0);
69
+ if (swiftCount > 0 && (totalCode === swiftCount || swiftCount / Math.max(totalCode,1) >= 0.5)) {
70
+ return 'ios';
71
+ }
72
+
45
73
  if (detected.length === 1) return detected[0];
46
74
  if (detected.length > 1) {
47
- // Múltiplas linguagens, escolhe por extensões
48
- const sortedExts = Object.entries(extensions)
49
- .sort((a, b) => b[1] - a[1]);
50
- return this.mapExtToLang(sortedExts[0]?.[0]);
75
+ // Filter out meta-markers (docker, static) if real languages exist
76
+ const realLangs = detected.filter(l => l !== 'docker' && l !== 'static');
77
+ if (realLangs.length === 1) return realLangs[0];
78
+ if (realLangs.length > 1) {
79
+ const sortedExts = Object.entries(extensions)
80
+ .sort((a, b) => b[1] - a[1]);
81
+ return this.mapExtToLang(sortedExts[0]?.[0]) || realLangs[0];
82
+ }
83
+ return detected[0];
51
84
  }
52
85
 
53
- // Fallback: extensão mais comum
86
+ // Fallback: most common extension
54
87
  const sortedExts = Object.entries(extensions)
55
88
  .sort((a, b) => b[1] - a[1]);
56
89
  return this.mapExtToLang(sortedExts[0]?.[0]) || 'unknown';
@@ -59,6 +92,7 @@ export class LanguageDetector {
59
92
  mapExtToLang(ext) {
60
93
  const map = {
61
94
  '.java': 'java',
95
+ '.kt': 'kotlin',
62
96
  '.js': 'node',
63
97
  '.ts': 'node',
64
98
  '.jsx': 'node',
@@ -67,7 +101,15 @@ export class LanguageDetector {
67
101
  '.cs': 'dotnet',
68
102
  '.go': 'go',
69
103
  '.php': 'php',
70
- '.rb': 'ruby'
104
+ '.rb': 'ruby',
105
+ '.rs': 'rust',
106
+ '.dart': 'dart',
107
+ '.ex': 'elixir',
108
+ '.exs': 'elixir',
109
+ '.swift': 'ios',
110
+ '.m': 'ios',
111
+ '.mm': 'ios',
112
+ '.scala': 'scala',
71
113
  };
72
114
  return map[ext] || null;
73
115
  }
@@ -77,13 +119,13 @@ export class LanguageDetector {
77
119
  return Object.keys(extensions)
78
120
  .map(ext => this.mapExtToLang(ext))
79
121
  .filter(lang => lang && lang !== primary)
80
- .filter((v, i, a) => a.indexOf(v) === i); // unique
122
+ .filter((v, i, a) => a.indexOf(v) === i);
81
123
  }
82
124
 
83
125
  calculateConfidence(markers) {
84
126
  const markerCount = Object.values(markers).filter(Boolean).length;
85
127
  if (markerCount === 0) return 0.3;
86
128
  if (markerCount === 1) return 0.9;
87
- return 0.7; // Múltiplos markers = projeto polyglot
129
+ return 0.7;
88
130
  }
89
- }
131
+ }