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 CHANGED
@@ -20,5 +20,6 @@ __tests__
20
20
  .idea/deepdebug-local-agent.iml
21
21
  .idea/modules.xml
22
22
  node_modules/
23
+ package-lock.json
23
24
  src/.DS_Store
24
25
  src/analyzers/
package/bin/install.js CHANGED
@@ -1,419 +1,282 @@
1
1
  #!/usr/bin/env node
2
+
2
3
  /**
3
- * Insptech AI Local Agent — Installer
4
+ * deepdebug-local-agent CLI
4
5
  *
5
6
  * Usage:
6
- * npx @insptech/agent install
7
- *
8
- * What it does:
9
- * 1. Asks for API Key (ia_live_...)
10
- * 2. Validates the key against the platform
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 { writeFileSync, mkdirSync, existsSync } from 'fs';
18
- import { homedir, platform, hostname } from 'os';
19
- import { join } from 'path';
20
-
21
- const PLATFORM_URL = process.env.INSPTECH_URL || 'https://gateway.insptech.pt';
22
- const AGENT_PORT = process.env.AGENT_PORT || '5055';
23
- const VERSION = '1.0.0';
24
-
25
- // ============================================
26
- // COLOURS
27
- // ============================================
28
- const c = {
29
- reset: '\x1b[0m',
30
- bold: '\x1b[1m',
31
- green: '\x1b[32m',
32
- yellow: '\x1b[33m',
33
- blue: '\x1b[34m',
34
- red: '\x1b[31m',
35
- cyan: '\x1b[36m',
36
- grey: '\x1b[90m',
37
- };
38
-
39
- function log(msg) { console.log(msg); }
40
- function ok(msg) { console.log(`${c.green}${msg}${c.reset}`); }
41
- function warn(msg) { console.log(`${c.yellow}⚠️ ${msg}${c.reset}`); }
42
- function error(msg) { console.log(`${c.red}❌ ${msg}${c.reset}`); }
43
- function info(msg) { console.log(`${c.cyan}ℹ️ ${msg}${c.reset}`); }
44
- function step(n, msg){ console.log(`\n${c.bold}${c.blue}[${n}]${c.reset} ${c.bold}${msg}${c.reset}`); }
45
-
46
- // ============================================
47
- // PROMPT HELPER
48
- // ============================================
49
- function prompt(question, hidden = false) {
50
- return new Promise(resolve => {
51
- const rl = createInterface({
52
- input: process.stdin,
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
- // VALIDATE API KEY FORMAT
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
- const response = await fetch(`${PLATFORM_URL}/api/v1/agent/validate-key`, {
105
- method: 'POST',
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 (err) {
127
- // Network error — allow offline install with warning
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
- // SAVE CONFIG
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
- // INSTALL AS SERVICE
157
- // ============================================
158
- async function installService(apiKey, port) {
159
- const os = platform();
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 installLaunchd(apiKey, port) {
175
- try {
176
- const plistPath = join(homedir(), 'Library/LaunchAgents/pt.insptech.agent.plist');
177
- const nodePath = execSync('which node').toString().trim();
178
- const agentPath = new URL('../src/server.js', import.meta.url).pathname;
179
-
180
- const plist = `<?xml version="1.0" encoding="UTF-8"?>
181
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
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
- function installSystemd(apiKey, port) {
222
- try {
223
- const nodePath = execSync('which node').toString().trim();
224
- const agentPath = new URL('../src/server.js', import.meta.url).pathname;
225
- const serviceFile = `/etc/systemd/system/insptech-agent.service`;
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 installWindowsService(apiKey, port) {
103
+ function readPid() {
259
104
  try {
260
- const nodePath = execSync('where node').toString().trim().split('\n')[0];
261
- const agentPath = new URL('../src/server.js', import.meta.url).pathname.replace(/^\//, '');
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
- // MAIN
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
- if (command === 'start') {
284
- // Direct start (used by service managers)
285
- const { default: startServer } = await import('../src/server.js');
286
- return;
287
- }
114
+ // ─── Commands ─────────────────────────────────────────────────────────────────
288
115
 
289
- if (command !== 'install') {
290
- log(`\nUsage: npx @insptech/agent install\n`);
291
- process.exit(1);
292
- }
116
+ async function cmdInstall() {
117
+ printBanner();
118
+ log('Starting installation...');
119
+ console.log('');
293
120
 
294
- // ============================================
295
- // BANNER
296
- // ============================================
297
- log('');
298
- log(`${c.bold}${c.blue}╔════════════════════════════════════════╗${c.reset}`);
299
- log(`${c.bold}${c.blue}║ Insptech AI Local Agent ║${c.reset}`);
300
- log(`${c.bold}${c.blue}║ Installation Wizard ║${c.reset}`);
301
- log(`${c.bold}${c.blue}╚════════════════════════════════════════╝${c.reset}`);
302
- log(`${c.grey} version ${VERSION} · insptech.pt${c.reset}`);
303
- log('');
304
-
305
- // ============================================
306
- // STEP 1 CHECK NODE VERSION
307
- // ============================================
308
- step(1, 'Checking requirements');
309
- const nodeVersion = process.versions.node;
310
- const major = parseInt(nodeVersion.split('.')[0]);
311
- if (major < 18) {
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
- // STEP 2 — API KEY
320
- // ============================================
321
- step(2, 'API Key');
322
- log(`${c.grey} Get your key: app.insptech.pt → Settings → Agent → Generate API Key${c.reset}`);
323
- log('');
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
- let apiKey = '';
326
- let attempts = 0;
161
+ console.log('');
327
162
 
328
- while (attempts < 3) {
329
- apiKey = await prompt(' Enter your API Key: ', true);
163
+ // Start the agent
164
+ await cmdStart(cfg);
330
165
 
331
- if (!apiKey) {
332
- error('API Key cannot be empty.');
333
- attempts++;
334
- continue;
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
- if (!isValidKeyFormat(apiKey)) {
338
- error(`Invalid format. Key must start with "ia_live_" followed by 24+ characters.`);
339
- attempts++;
340
- continue;
341
- }
174
+ async function cmdStart(cfg) {
175
+ cfg = cfg || loadConfig();
342
176
 
343
- break;
177
+ const pid = readPid();
178
+ if (pid && isRunning(pid)) {
179
+ ok(`Agent is already running (PID ${pid})`);
180
+ return;
344
181
  }
345
182
 
346
- if (!apiKey || !isValidKeyFormat(apiKey)) {
347
- error('Installation cancelled: invalid API Key.');
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 validation = await validateApiKey(apiKey);
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
- if (!validation.valid) {
360
- log('');
361
- error(`API Key validation failed: ${validation.reason}`);
362
- info('Generate a new key at: app.insptech.pt → Settings → Agent');
363
- process.exit(1);
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
- log(` ${c.green}OK${c.reset}`);
208
+ // Save PID
209
+ if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true });
210
+ writeFileSync(getPidFile(), String(child.pid), 'utf8');
367
211
 
368
- if (!validation.offline) {
369
- if (validation.tenantName) ok(`Authenticated as: ${validation.tenantName}`);
370
- if (validation.workspaceName) info(`Workspace: ${validation.workspaceName}`);
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
- // STEP 4 — PORT
375
- // ============================================
376
- step(4, 'Configuration');
377
- const portAnswer = await prompt(` Agent port [${AGENT_PORT}]: `);
378
- const port = portAnswer || AGENT_PORT;
379
- ok(`Port: ${port}`);
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
- info(`To start manually: node src/server.js`);
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
- log('');
411
- log(`${c.grey} Platform: ${PLATFORM_URL}${c.reset}`);
412
- log(`${c.grey} Docs: https://docs.insptech.pt/agent${c.reset}`);
413
- log('');
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
- main().catch(err => {
417
- error(`Unexpected error: ${err.message}`);
418
- process.exit(1);
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.2",
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": "src/server.js",
6
+ "main": "server.js",
7
+ "bin": {
8
+ "deepdebug-local-agent": "./bin/install.js"
9
+ },
6
10
  "scripts": {
7
- "start": "node src/server.js",
8
- "dev": "NODE_ENV=development node src/server.js",
9
- "mcp": "node src/mcp-server.js"
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",