deepdebug-local-agent 0.3.2 → 0.3.4
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 +1 -0
- package/bin/install.js +228 -365
- package/package.json +23 -5
package/.dockerignore
CHANGED
package/bin/install.js
CHANGED
|
@@ -1,419 +1,282 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
+
* deepdebug-local-agent CLI
|
|
4
5
|
*
|
|
5
6
|
* Usage:
|
|
6
|
-
* npx
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* 3. Installs the agent as a background service
|
|
12
|
-
* 4. Registers the machine on the platform
|
|
7
|
+
* npx deepdebug-local-agent install — installs and starts the agent as a service
|
|
8
|
+
* npx deepdebug-local-agent start — starts the agent
|
|
9
|
+
* npx deepdebug-local-agent stop — stops the agent
|
|
10
|
+
* npx deepdebug-local-agent status — shows agent status
|
|
11
|
+
* npx deepdebug-local-agent run — runs the agent in the foreground (dev mode)
|
|
13
12
|
*/
|
|
14
13
|
|
|
15
|
-
import { createInterface } from 'readline';
|
|
16
14
|
import { execSync, spawn } from 'child_process';
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
output: process.stdout,
|
|
54
|
-
terminal: true
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
if (hidden) {
|
|
58
|
-
process.stdout.write(question);
|
|
59
|
-
process.stdin.setRawMode?.(true);
|
|
60
|
-
let input = '';
|
|
61
|
-
process.stdin.once('data', function handler(chunk) {
|
|
62
|
-
const char = chunk.toString();
|
|
63
|
-
if (char === '\r' || char === '\n') {
|
|
64
|
-
process.stdin.setRawMode?.(false);
|
|
65
|
-
process.stdout.write('\n');
|
|
66
|
-
rl.close();
|
|
67
|
-
resolve(input);
|
|
68
|
-
} else if (char === '\u0003') {
|
|
69
|
-
process.exit();
|
|
70
|
-
} else if (char === '\u007f') {
|
|
71
|
-
if (input.length > 0) {
|
|
72
|
-
input = input.slice(0, -1);
|
|
73
|
-
process.stdout.write('\b \b');
|
|
74
|
-
}
|
|
75
|
-
} else {
|
|
76
|
-
input += char;
|
|
77
|
-
process.stdout.write('*');
|
|
78
|
-
}
|
|
79
|
-
if (char !== '\r' && char !== '\n') {
|
|
80
|
-
process.stdin.once('data', handler);
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
} else {
|
|
84
|
-
rl.question(question, answer => {
|
|
85
|
-
rl.close();
|
|
86
|
-
resolve(answer.trim());
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
});
|
|
15
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
16
|
+
import { join, dirname } from 'path';
|
|
17
|
+
import { fileURLToPath } from 'url';
|
|
18
|
+
import os from 'os';
|
|
19
|
+
import readline from 'readline';
|
|
20
|
+
|
|
21
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
22
|
+
const __dirname = dirname(__filename);
|
|
23
|
+
const ROOT_DIR = join(__dirname, '..');
|
|
24
|
+
|
|
25
|
+
const CONFIG_DIR = join(os.homedir(), '.deepdebug');
|
|
26
|
+
const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
27
|
+
const DEFAULT_PORT = 5055;
|
|
28
|
+
const DEFAULT_GATEWAY = 'https://gateway.insptech.pt';
|
|
29
|
+
const AGENT_NAME = 'deepdebug-agent';
|
|
30
|
+
|
|
31
|
+
const BLUE = '\x1b[34m';
|
|
32
|
+
const GREEN = '\x1b[32m';
|
|
33
|
+
const YELLOW = '\x1b[33m';
|
|
34
|
+
const RED = '\x1b[31m';
|
|
35
|
+
const BOLD = '\x1b[1m';
|
|
36
|
+
const RESET = '\x1b[0m';
|
|
37
|
+
|
|
38
|
+
const log = (msg) => console.log(`${BLUE}[DeepDebug]${RESET} ${msg}`);
|
|
39
|
+
const ok = (msg) => console.log(`${GREEN}✓${RESET} ${msg}`);
|
|
40
|
+
const warn = (msg) => console.log(`${YELLOW}⚠${RESET} ${msg}`);
|
|
41
|
+
const err = (msg) => console.log(`${RED}✗${RESET} ${msg}`);
|
|
42
|
+
const bold = (msg) => `${BOLD}${msg}${RESET}`;
|
|
43
|
+
|
|
44
|
+
function printBanner() {
|
|
45
|
+
console.log('');
|
|
46
|
+
console.log(`${BLUE}${BOLD}╔═══════════════════════════════════════╗${RESET}`);
|
|
47
|
+
console.log(`${BLUE}${BOLD}║ Insptech AI — DeepDebug Agent ║${RESET}`);
|
|
48
|
+
console.log(`${BLUE}${BOLD}║ deepdebug-local-agent ║${RESET}`);
|
|
49
|
+
console.log(`${BLUE}${BOLD}╚═══════════════════════════════════════╝${RESET}`);
|
|
50
|
+
console.log('');
|
|
90
51
|
}
|
|
91
52
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
function isValidKeyFormat(key) {
|
|
96
|
-
return /^ia_live_[a-zA-Z0-9]{24,}$/.test(key);
|
|
53
|
+
function ask(question) {
|
|
54
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
55
|
+
return new Promise(resolve => rl.question(question, ans => { rl.close(); resolve(ans.trim()); }));
|
|
97
56
|
}
|
|
98
57
|
|
|
99
|
-
|
|
100
|
-
// VALIDATE API KEY AGAINST PLATFORM
|
|
101
|
-
// ============================================
|
|
102
|
-
async function validateApiKey(apiKey) {
|
|
58
|
+
function loadConfig() {
|
|
103
59
|
try {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
headers: {
|
|
107
|
-
'Content-Type': 'application/json',
|
|
108
|
-
'X-Agent-Key': apiKey
|
|
109
|
-
},
|
|
110
|
-
body: JSON.stringify({
|
|
111
|
-
hostname: hostname(),
|
|
112
|
-
platform: platform(),
|
|
113
|
-
version: VERSION
|
|
114
|
-
}),
|
|
115
|
-
signal: AbortSignal.timeout(10000)
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
if (response.ok) {
|
|
119
|
-
const data = await response.json();
|
|
120
|
-
return { valid: true, tenantName: data.tenantName, workspaceName: data.workspaceName };
|
|
121
|
-
} else if (response.status === 401) {
|
|
122
|
-
return { valid: false, reason: 'Invalid API key' };
|
|
123
|
-
} else {
|
|
124
|
-
return { valid: false, reason: `Server returned ${response.status}` };
|
|
60
|
+
if (existsSync(CONFIG_FILE)) {
|
|
61
|
+
return JSON.parse(readFileSync(CONFIG_FILE, 'utf8'));
|
|
125
62
|
}
|
|
126
|
-
} catch
|
|
127
|
-
|
|
128
|
-
warn(`Could not reach platform (${err.message}). Continuing with offline install.`);
|
|
129
|
-
return { valid: true, offline: true };
|
|
130
|
-
}
|
|
63
|
+
} catch {}
|
|
64
|
+
return {};
|
|
131
65
|
}
|
|
132
66
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
function saveConfig(apiKey, port) {
|
|
137
|
-
const configDir = join(homedir(), '.insptech');
|
|
138
|
-
const configFile = join(configDir, 'agent.json');
|
|
139
|
-
|
|
140
|
-
if (!existsSync(configDir)) mkdirSync(configDir, { recursive: true });
|
|
141
|
-
|
|
142
|
-
const config = {
|
|
143
|
-
apiKey,
|
|
144
|
-
port,
|
|
145
|
-
platformUrl: PLATFORM_URL,
|
|
146
|
-
hostname: hostname(),
|
|
147
|
-
installedAt: new Date().toISOString(),
|
|
148
|
-
version: VERSION
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
writeFileSync(configFile, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
152
|
-
return configFile;
|
|
67
|
+
function saveConfig(cfg) {
|
|
68
|
+
if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true });
|
|
69
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2), 'utf8');
|
|
153
70
|
}
|
|
154
71
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if (os === 'darwin') {
|
|
162
|
-
return installLaunchd(apiKey, port);
|
|
163
|
-
} else if (os === 'linux') {
|
|
164
|
-
return installSystemd(apiKey, port);
|
|
165
|
-
} else if (os === 'win32') {
|
|
166
|
-
return installWindowsService(apiKey, port);
|
|
167
|
-
} else {
|
|
168
|
-
warn(`Unsupported OS (${os}). Agent will not be installed as a service.`);
|
|
169
|
-
info(`To start manually: npx @insptech/agent start --api-key ${apiKey}`);
|
|
170
|
-
return false;
|
|
72
|
+
function checkNodeVersion() {
|
|
73
|
+
const major = parseInt(process.version.slice(1).split('.')[0]);
|
|
74
|
+
if (major < 18) {
|
|
75
|
+
err(`Node.js ${process.version} detected. Version 18 or higher is required.`);
|
|
76
|
+
err('Download: https://nodejs.org');
|
|
77
|
+
process.exit(1);
|
|
171
78
|
}
|
|
79
|
+
ok(`Node.js ${process.version} detected`);
|
|
172
80
|
}
|
|
173
81
|
|
|
174
|
-
function
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
<plist version="1.0">
|
|
183
|
-
<dict>
|
|
184
|
-
<key>Label</key>
|
|
185
|
-
<string>pt.insptech.agent</string>
|
|
186
|
-
<key>ProgramArguments</key>
|
|
187
|
-
<array>
|
|
188
|
-
<string>${nodePath}</string>
|
|
189
|
-
<string>${agentPath}</string>
|
|
190
|
-
</array>
|
|
191
|
-
<key>EnvironmentVariables</key>
|
|
192
|
-
<dict>
|
|
193
|
-
<key>INSPTECH_API_KEY</key>
|
|
194
|
-
<string>${apiKey}</string>
|
|
195
|
-
<key>AGENT_PORT</key>
|
|
196
|
-
<string>${port}</string>
|
|
197
|
-
<key>GATEWAY_URL</key>
|
|
198
|
-
<string>${PLATFORM_URL}</string>
|
|
199
|
-
</dict>
|
|
200
|
-
<key>RunAtLoad</key>
|
|
201
|
-
<true/>
|
|
202
|
-
<key>KeepAlive</key>
|
|
203
|
-
<true/>
|
|
204
|
-
<key>StandardOutPath</key>
|
|
205
|
-
<string>${homedir()}/.insptech/agent.log</string>
|
|
206
|
-
<key>StandardErrorPath</key>
|
|
207
|
-
<string>${homedir()}/.insptech/agent-error.log</string>
|
|
208
|
-
</dict>
|
|
209
|
-
</plist>`;
|
|
210
|
-
|
|
211
|
-
writeFileSync(plistPath, plist);
|
|
212
|
-
execSync(`launchctl load ${plistPath}`);
|
|
213
|
-
ok(`macOS LaunchAgent installed: ${plistPath}`);
|
|
214
|
-
return true;
|
|
215
|
-
} catch (err) {
|
|
216
|
-
warn(`Could not install as service: ${err.message}`);
|
|
217
|
-
return false;
|
|
82
|
+
function getServerScript() {
|
|
83
|
+
// Try common locations
|
|
84
|
+
const candidates = [
|
|
85
|
+
join(ROOT_DIR, 'server.js'),
|
|
86
|
+
join(ROOT_DIR, 'src', 'server.js'),
|
|
87
|
+
];
|
|
88
|
+
for (const c of candidates) {
|
|
89
|
+
if (existsSync(c)) return c;
|
|
218
90
|
}
|
|
91
|
+
// Fallback: server.js next to bin/
|
|
92
|
+
return join(ROOT_DIR, 'server.js');
|
|
219
93
|
}
|
|
220
94
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
const service = `[Unit]
|
|
228
|
-
Description=Insptech AI Local Agent
|
|
229
|
-
After=network.target
|
|
230
|
-
|
|
231
|
-
[Service]
|
|
232
|
-
Type=simple
|
|
233
|
-
ExecStart=${nodePath} ${agentPath}
|
|
234
|
-
Environment=INSPTECH_API_KEY=${apiKey}
|
|
235
|
-
Environment=AGENT_PORT=${port}
|
|
236
|
-
Environment=GATEWAY_URL=${PLATFORM_URL}
|
|
237
|
-
Restart=on-failure
|
|
238
|
-
RestartSec=10
|
|
239
|
-
StandardOutput=journal
|
|
240
|
-
StandardError=journal
|
|
241
|
-
|
|
242
|
-
[Install]
|
|
243
|
-
WantedBy=multi-user.target
|
|
244
|
-
`;
|
|
245
|
-
writeFileSync(serviceFile, service);
|
|
246
|
-
execSync('systemctl daemon-reload');
|
|
247
|
-
execSync('systemctl enable insptech-agent');
|
|
248
|
-
execSync('systemctl start insptech-agent');
|
|
249
|
-
ok('systemd service installed and started: insptech-agent');
|
|
250
|
-
return true;
|
|
251
|
-
} catch (err) {
|
|
252
|
-
warn(`Could not install systemd service: ${err.message}`);
|
|
253
|
-
info('Try running with sudo for system-wide service installation.');
|
|
254
|
-
return false;
|
|
255
|
-
}
|
|
95
|
+
// ─── Platform detection ───────────────────────────────────────────────────────
|
|
96
|
+
|
|
97
|
+
const platform = os.platform(); // 'win32' | 'darwin' | 'linux'
|
|
98
|
+
|
|
99
|
+
function getPidFile() {
|
|
100
|
+
return join(CONFIG_DIR, 'agent.pid');
|
|
256
101
|
}
|
|
257
102
|
|
|
258
|
-
function
|
|
103
|
+
function readPid() {
|
|
259
104
|
try {
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
// Use sc.exe to create Windows Service
|
|
264
|
-
const cmd = `sc create "Insptech AI Agent" binPath= "${nodePath} ${agentPath}" start= auto DisplayName= "Insptech AI Agent"`;
|
|
265
|
-
execSync(cmd, { shell: 'cmd.exe' });
|
|
266
|
-
execSync('sc start "Insptech AI Agent"', { shell: 'cmd.exe' });
|
|
267
|
-
ok('Windows Service installed: "Insptech AI Agent" (visible in services.msc)');
|
|
268
|
-
return true;
|
|
269
|
-
} catch (err) {
|
|
270
|
-
warn(`Could not install Windows Service: ${err.message}`);
|
|
271
|
-
info('Try running PowerShell as Administrator.');
|
|
272
|
-
return false;
|
|
273
|
-
}
|
|
105
|
+
const pid = parseInt(readFileSync(getPidFile(), 'utf8').trim());
|
|
106
|
+
return isNaN(pid) ? null : pid;
|
|
107
|
+
} catch { return null; }
|
|
274
108
|
}
|
|
275
109
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
async function main() {
|
|
280
|
-
const args = process.argv.slice(2);
|
|
281
|
-
const command = args[0] || 'install';
|
|
110
|
+
function isRunning(pid) {
|
|
111
|
+
try { process.kill(pid, 0); return true; } catch { return false; }
|
|
112
|
+
}
|
|
282
113
|
|
|
283
|
-
|
|
284
|
-
// Direct start (used by service managers)
|
|
285
|
-
const { default: startServer } = await import('../src/server.js');
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
114
|
+
// ─── Commands ─────────────────────────────────────────────────────────────────
|
|
288
115
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
116
|
+
async function cmdInstall() {
|
|
117
|
+
printBanner();
|
|
118
|
+
log('Starting installation...');
|
|
119
|
+
console.log('');
|
|
293
120
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
//
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
error(`Node.js 18+ required. Current: ${nodeVersion}`);
|
|
313
|
-
info('Download from: https://nodejs.org');
|
|
314
|
-
process.exit(1);
|
|
121
|
+
checkNodeVersion();
|
|
122
|
+
|
|
123
|
+
// Read or create config
|
|
124
|
+
let cfg = loadConfig();
|
|
125
|
+
|
|
126
|
+
// Prompt for API Key if not set
|
|
127
|
+
if (!cfg.apiKey) {
|
|
128
|
+
console.log(`${YELLOW}You need an API Key from the Insptech AI platform.${RESET}`);
|
|
129
|
+
console.log(`Open ${bold('https://app.insptech.pt')} → Settings → Agent → Generate API Key`);
|
|
130
|
+
console.log('');
|
|
131
|
+
const key = await ask(' Enter your API Key: ');
|
|
132
|
+
if (!key || key.length < 10) {
|
|
133
|
+
err('Invalid API Key. Installation aborted.');
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
cfg.apiKey = key;
|
|
137
|
+
} else {
|
|
138
|
+
ok('API Key already configured');
|
|
315
139
|
}
|
|
316
|
-
ok(`Node.js ${nodeVersion}`);
|
|
317
140
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
141
|
+
if (!cfg.gatewayUrl) cfg.gatewayUrl = DEFAULT_GATEWAY;
|
|
142
|
+
if (!cfg.port) cfg.port = DEFAULT_PORT;
|
|
143
|
+
|
|
144
|
+
saveConfig(cfg);
|
|
145
|
+
ok(`Configuration saved to ${CONFIG_FILE}`);
|
|
146
|
+
|
|
147
|
+
// Install npm dependencies if needed
|
|
148
|
+
const nodeModules = join(ROOT_DIR, 'node_modules');
|
|
149
|
+
if (!existsSync(nodeModules)) {
|
|
150
|
+
log('Installing dependencies...');
|
|
151
|
+
try {
|
|
152
|
+
execSync('npm install --production', { cwd: ROOT_DIR, stdio: 'inherit' });
|
|
153
|
+
ok('Dependencies installed');
|
|
154
|
+
} catch (e) {
|
|
155
|
+
warn('Could not install dependencies automatically. Run: npm install');
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
ok('Dependencies already installed');
|
|
159
|
+
}
|
|
324
160
|
|
|
325
|
-
|
|
326
|
-
let attempts = 0;
|
|
161
|
+
console.log('');
|
|
327
162
|
|
|
328
|
-
|
|
329
|
-
|
|
163
|
+
// Start the agent
|
|
164
|
+
await cmdStart(cfg);
|
|
330
165
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
166
|
+
console.log('');
|
|
167
|
+
ok(bold('Agent registered successfully'));
|
|
168
|
+
console.log('');
|
|
169
|
+
log(`Health check: ${bold(`http://localhost:${cfg.port}/health`)}`);
|
|
170
|
+
log(`Platform: ${bold('https://app.insptech.pt')}`);
|
|
171
|
+
console.log('');
|
|
172
|
+
}
|
|
336
173
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
attempts++;
|
|
340
|
-
continue;
|
|
341
|
-
}
|
|
174
|
+
async function cmdStart(cfg) {
|
|
175
|
+
cfg = cfg || loadConfig();
|
|
342
176
|
|
|
343
|
-
|
|
177
|
+
const pid = readPid();
|
|
178
|
+
if (pid && isRunning(pid)) {
|
|
179
|
+
ok(`Agent is already running (PID ${pid})`);
|
|
180
|
+
return;
|
|
344
181
|
}
|
|
345
182
|
|
|
346
|
-
|
|
347
|
-
|
|
183
|
+
const serverScript = getServerScript();
|
|
184
|
+
if (!existsSync(serverScript)) {
|
|
185
|
+
err(`Server script not found: ${serverScript}`);
|
|
348
186
|
process.exit(1);
|
|
349
187
|
}
|
|
350
188
|
|
|
351
|
-
|
|
352
|
-
// STEP 3 — VALIDATE KEY
|
|
353
|
-
// ============================================
|
|
354
|
-
step(3, 'Validating API Key');
|
|
355
|
-
process.stdout.write(' Connecting to Insptech AI platform...');
|
|
189
|
+
log(`Starting agent on port ${cfg.port || DEFAULT_PORT}...`);
|
|
356
190
|
|
|
357
|
-
const
|
|
191
|
+
const env = {
|
|
192
|
+
...process.env,
|
|
193
|
+
NODE_ENV: 'production',
|
|
194
|
+
PORT: String(cfg.port || DEFAULT_PORT),
|
|
195
|
+
DEEPDEBUG_API_KEY: cfg.apiKey || '',
|
|
196
|
+
GATEWAY_URL: cfg.gatewayUrl || DEFAULT_GATEWAY,
|
|
197
|
+
};
|
|
358
198
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
}
|
|
199
|
+
const child = spawn(process.execPath, [serverScript], {
|
|
200
|
+
env,
|
|
201
|
+
detached: true,
|
|
202
|
+
stdio: 'ignore',
|
|
203
|
+
cwd: ROOT_DIR,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
child.unref();
|
|
365
207
|
|
|
366
|
-
|
|
208
|
+
// Save PID
|
|
209
|
+
if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true });
|
|
210
|
+
writeFileSync(getPidFile(), String(child.pid), 'utf8');
|
|
367
211
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
212
|
+
// Wait a moment and verify
|
|
213
|
+
await new Promise(r => setTimeout(r, 1500));
|
|
214
|
+
|
|
215
|
+
if (isRunning(child.pid)) {
|
|
216
|
+
ok(`Agent started (PID ${child.pid})`);
|
|
217
|
+
} else {
|
|
218
|
+
warn('Agent may have failed to start. Check logs or run in foreground: npx deepdebug-local-agent run');
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function cmdStop() {
|
|
223
|
+
const pid = readPid();
|
|
224
|
+
if (!pid) { warn('No PID file found. Agent may not be running.'); return; }
|
|
225
|
+
if (!isRunning(pid)) { warn(`No process with PID ${pid}. Agent is not running.`); return; }
|
|
226
|
+
try {
|
|
227
|
+
process.kill(pid, 'SIGTERM');
|
|
228
|
+
ok(`Agent stopped (PID ${pid})`);
|
|
229
|
+
} catch (e) {
|
|
230
|
+
err(`Failed to stop agent: ${e.message}`);
|
|
371
231
|
}
|
|
232
|
+
}
|
|
372
233
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
// STEP 5 — SAVE CONFIG
|
|
383
|
-
// ============================================
|
|
384
|
-
step(5, 'Saving configuration');
|
|
385
|
-
const configFile = saveConfig(apiKey, port);
|
|
386
|
-
ok(`Config saved: ${configFile}`);
|
|
387
|
-
|
|
388
|
-
// ============================================
|
|
389
|
-
// STEP 6 — INSTALL SERVICE
|
|
390
|
-
// ============================================
|
|
391
|
-
step(6, 'Installing service');
|
|
392
|
-
const serviceInstalled = await installService(apiKey, port);
|
|
393
|
-
|
|
394
|
-
// ============================================
|
|
395
|
-
// DONE
|
|
396
|
-
// ============================================
|
|
397
|
-
log('');
|
|
398
|
-
log(`${c.bold}${c.green}╔════════════════════════════════════════╗${c.reset}`);
|
|
399
|
-
log(`${c.bold}${c.green}║ Installation Complete! 🎉 ║${c.reset}`);
|
|
400
|
-
log(`${c.bold}${c.green}╚════════════════════════════════════════╝${c.reset}`);
|
|
401
|
-
log('');
|
|
402
|
-
|
|
403
|
-
if (serviceInstalled) {
|
|
404
|
-
ok(`Agent is running on port ${port}`);
|
|
405
|
-
info(`Logs: ${homedir()}/.insptech/agent.log`);
|
|
234
|
+
function cmdStatus() {
|
|
235
|
+
const cfg = loadConfig();
|
|
236
|
+
const pid = readPid();
|
|
237
|
+
const port = cfg.port || DEFAULT_PORT;
|
|
238
|
+
console.log('');
|
|
239
|
+
console.log(`${BOLD}DeepDebug Local Agent — Status${RESET}`);
|
|
240
|
+
console.log('─'.repeat(40));
|
|
241
|
+
if (pid && isRunning(pid)) {
|
|
242
|
+
console.log(` Process : ${GREEN}Running${RESET} (PID ${pid})`);
|
|
406
243
|
} else {
|
|
407
|
-
|
|
244
|
+
console.log(` Process : ${RED}Not running${RESET}`);
|
|
408
245
|
}
|
|
246
|
+
console.log(` Port : ${port}`);
|
|
247
|
+
console.log(` Config : ${CONFIG_FILE}`);
|
|
248
|
+
console.log(` Gateway : ${cfg.gatewayUrl || DEFAULT_GATEWAY}`);
|
|
249
|
+
console.log(` Health : http://localhost:${port}/health`);
|
|
250
|
+
console.log('');
|
|
251
|
+
}
|
|
409
252
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
253
|
+
function cmdRun() {
|
|
254
|
+
// Foreground mode — useful for debugging
|
|
255
|
+
const cfg = loadConfig();
|
|
256
|
+
const serverScript = getServerScript();
|
|
257
|
+
const env = {
|
|
258
|
+
...process.env,
|
|
259
|
+
NODE_ENV: 'development',
|
|
260
|
+
PORT: String(cfg.port || DEFAULT_PORT),
|
|
261
|
+
DEEPDEBUG_API_KEY: cfg.apiKey || '',
|
|
262
|
+
GATEWAY_URL: cfg.gatewayUrl || DEFAULT_GATEWAY,
|
|
263
|
+
};
|
|
264
|
+
log(`Running in foreground on port ${cfg.port || DEFAULT_PORT} (Ctrl+C to stop)...`);
|
|
265
|
+
const child = spawn(process.execPath, [serverScript], { env, stdio: 'inherit', cwd: ROOT_DIR });
|
|
266
|
+
child.on('exit', code => process.exit(code || 0));
|
|
414
267
|
}
|
|
415
268
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
269
|
+
// ─── Entry point ──────────────────────────────────────────────────────────────
|
|
270
|
+
|
|
271
|
+
const command = process.argv[2] || 'install';
|
|
272
|
+
|
|
273
|
+
switch (command) {
|
|
274
|
+
case 'install': cmdInstall().catch(e => { err(e.message); process.exit(1); }); break;
|
|
275
|
+
case 'start': cmdStart().catch(e => { err(e.message); process.exit(1); }); break;
|
|
276
|
+
case 'stop': cmdStop(); break;
|
|
277
|
+
case 'status': cmdStatus(); break;
|
|
278
|
+
case 'run': cmdRun(); break;
|
|
279
|
+
default:
|
|
280
|
+
console.log(`Usage: npx deepdebug-local-agent [install|start|stop|status|run]`);
|
|
281
|
+
process.exit(1);
|
|
282
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deepdebug-local-agent",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
|
+
"description": "Insptech AI — DeepDebug Local Agent. Autonomous code debugging agent for production environments.",
|
|
4
5
|
"type": "module",
|
|
5
|
-
"main": "
|
|
6
|
+
"main": "server.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"deepdebug-local-agent": "./bin/install.js"
|
|
9
|
+
},
|
|
6
10
|
"scripts": {
|
|
7
|
-
"start": "node
|
|
8
|
-
"dev": "NODE_ENV=development node
|
|
9
|
-
"mcp": "node
|
|
11
|
+
"start": "node server.js",
|
|
12
|
+
"dev": "NODE_ENV=development node server.js",
|
|
13
|
+
"mcp": "node mcp-server.js"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"deepdebug",
|
|
17
|
+
"insptech",
|
|
18
|
+
"debugging",
|
|
19
|
+
"ai",
|
|
20
|
+
"autonomous",
|
|
21
|
+
"agent"
|
|
22
|
+
],
|
|
23
|
+
"author": "Insptech AI <contacto@insptech.pt>",
|
|
24
|
+
"license": "UNLICENSED",
|
|
25
|
+
"homepage": "https://deepdebug.ai",
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18.0.0"
|
|
10
28
|
},
|
|
11
29
|
"dependencies": {
|
|
12
30
|
"@modelcontextprotocol/sdk": "^1.26.0",
|