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/CLAUDE_CODE_AGENT_INFINITE.md +623 -0
- package/Dockerfile +57 -20
- package/Dockerfile.full +63 -0
- package/cloudbuild-agent-staging.yaml +40 -0
- package/local-agent-source.tar.gz +0 -0
- package/package.json +4 -3
- package/src/detectors/framework-detector.js +33 -0
- package/src/detectors/language-detector.js +54 -12
- package/src/detectors.js +291 -8
- package/src/exec-utils.js +201 -16
- package/src/local-agent-source.tar.gz +0 -0
- package/src/runtimes/java/maven-runtime.js +4 -3
- package/src/server.js +729 -4
- package/src/utils/exec-utils.js +8 -4
package/Dockerfile
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# ╔══════════════════════════════════════════════════════════════╗
|
|
2
2
|
# ║ DeepDebug Local Agent - Enterprise Docker ║
|
|
3
3
|
# ║ ║
|
|
4
|
-
# ║
|
|
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-
|
|
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-
|
|
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="
|
|
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
|
|
34
|
-
|
|
33
|
+
RUN groupadd -g 1001 deepdebug && \
|
|
34
|
+
useradd -u 1001 -g deepdebug -m deepdebug
|
|
35
35
|
|
|
36
|
-
# Install dependencies
|
|
37
|
-
RUN
|
|
38
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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"]
|
package/Dockerfile.full
ADDED
|
@@ -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.
|
|
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
|
-
"
|
|
49
|
-
"
|
|
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
|
|
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
|
-
//
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
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:
|
|
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);
|
|
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;
|
|
129
|
+
return 0.7;
|
|
88
130
|
}
|
|
89
|
-
}
|
|
131
|
+
}
|