agenthub-multiagent-mcp 1.10.4 → 1.10.5

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.
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * AgentHub Setup Wizard — one-click worker configuration
4
+ *
5
+ * Detects API key from existing claude settings, scans for projects,
6
+ * writes config file, and installs startup script.
7
+ *
8
+ * Usage: agenthub-setup
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG"}
package/dist/setup.js ADDED
@@ -0,0 +1,424 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * AgentHub Setup Wizard — one-click worker configuration
4
+ *
5
+ * Detects API key from existing claude settings, scans for projects,
6
+ * writes config file, and installs startup script.
7
+ *
8
+ * Usage: agenthub-setup
9
+ */
10
+ import * as fs from "fs";
11
+ import * as path from "path";
12
+ import * as os from "os";
13
+ import * as readline from "readline";
14
+ const CONFIG_DIR = path.join(os.homedir(), ".agenthub");
15
+ const CONFIG_FILE = path.join(CONFIG_DIR, "worker.json");
16
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
17
+ function ask(question, defaultVal) {
18
+ const suffix = defaultVal ? ` [${defaultVal}]` : "";
19
+ return new Promise((resolve) => {
20
+ rl.question(`${question}${suffix}: `, (answer) => {
21
+ resolve(answer.trim() || defaultVal || "");
22
+ });
23
+ });
24
+ }
25
+ function print(msg) {
26
+ console.log(msg);
27
+ }
28
+ // =============================================================================
29
+ // Step 1: Detect API key
30
+ // =============================================================================
31
+ function detectApiKey() {
32
+ // Check env var first
33
+ if (process.env.AGENTHUB_API_KEY) {
34
+ return process.env.AGENTHUB_API_KEY;
35
+ }
36
+ // Check existing config
37
+ if (fs.existsSync(CONFIG_FILE)) {
38
+ try {
39
+ const config = JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
40
+ if (config.api_key)
41
+ return config.api_key;
42
+ }
43
+ catch { /* ignore */ }
44
+ }
45
+ // Check claude global settings for agenthub MCP server config
46
+ const claudeSettings = path.join(os.homedir(), ".claude", "settings.json");
47
+ if (fs.existsSync(claudeSettings)) {
48
+ try {
49
+ const settings = JSON.parse(fs.readFileSync(claudeSettings, "utf-8"));
50
+ const mcpServers = settings.mcpServers || {};
51
+ for (const [, server] of Object.entries(mcpServers)) {
52
+ const env = server.env || {};
53
+ if (env.AGENTHUB_API_KEY) {
54
+ return env.AGENTHUB_API_KEY;
55
+ }
56
+ }
57
+ }
58
+ catch { /* ignore */ }
59
+ }
60
+ return "";
61
+ }
62
+ // =============================================================================
63
+ // Step 2: Detect server URL
64
+ // =============================================================================
65
+ function detectServerUrl() {
66
+ if (process.env.AGENTHUB_URL)
67
+ return process.env.AGENTHUB_URL;
68
+ if (fs.existsSync(CONFIG_FILE)) {
69
+ try {
70
+ const config = JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
71
+ if (config.server)
72
+ return config.server;
73
+ }
74
+ catch { /* ignore */ }
75
+ }
76
+ const claudeSettings = path.join(os.homedir(), ".claude", "settings.json");
77
+ if (fs.existsSync(claudeSettings)) {
78
+ try {
79
+ const settings = JSON.parse(fs.readFileSync(claudeSettings, "utf-8"));
80
+ const mcpServers = settings.mcpServers || {};
81
+ for (const [, server] of Object.entries(mcpServers)) {
82
+ const env = server.env || {};
83
+ if (env.AGENTHUB_URL)
84
+ return env.AGENTHUB_URL;
85
+ }
86
+ }
87
+ catch { /* ignore */ }
88
+ }
89
+ return "https://agenthub.contetial.com";
90
+ }
91
+ // =============================================================================
92
+ // Step 3: Scan for projects
93
+ // =============================================================================
94
+ function scanForProjects() {
95
+ const found = [];
96
+ const seen = new Set();
97
+ // Directories to scan
98
+ const scanRoots = [];
99
+ if (process.platform === "win32") {
100
+ // Windows: scan common dev directories
101
+ scanRoots.push(path.join(os.homedir(), "projects"), path.join(os.homedir(), "code"), path.join(os.homedir(), "dev"), "D:\\projects", "D:\\code", "D:\\dev",
102
+ // Check known KrishiAI locations
103
+ "D:\\Krishi_AI");
104
+ }
105
+ else {
106
+ // macOS/Linux
107
+ scanRoots.push(path.join(os.homedir(), "projects"), path.join(os.homedir(), "code"), path.join(os.homedir(), "dev"), path.join(os.homedir(), "work"));
108
+ }
109
+ for (const root of scanRoots) {
110
+ if (!fs.existsSync(root))
111
+ continue;
112
+ try {
113
+ // Check root itself
114
+ if (isProject(root)) {
115
+ const norm = root.replace(/\\/g, "/");
116
+ if (!seen.has(norm)) {
117
+ seen.add(norm);
118
+ found.push({ dir: norm, name: path.basename(root) });
119
+ }
120
+ }
121
+ // Check one level deep
122
+ const entries = fs.readdirSync(root, { withFileTypes: true });
123
+ for (const entry of entries) {
124
+ if (!entry.isDirectory() || entry.name.startsWith(".") || entry.name === "node_modules")
125
+ continue;
126
+ const fullPath = path.join(root, entry.name);
127
+ if (isProject(fullPath)) {
128
+ const norm = fullPath.replace(/\\/g, "/");
129
+ if (!seen.has(norm)) {
130
+ seen.add(norm);
131
+ found.push({ dir: norm, name: entry.name });
132
+ }
133
+ }
134
+ }
135
+ }
136
+ catch { /* permission error, skip */ }
137
+ }
138
+ return found;
139
+ }
140
+ function isProject(dir) {
141
+ return (fs.existsSync(path.join(dir, ".claude")) ||
142
+ fs.existsSync(path.join(dir, "CLAUDE.md")) ||
143
+ fs.existsSync(path.join(dir, ".agenthub")));
144
+ }
145
+ // =============================================================================
146
+ // Step 4: Fetch registered agents
147
+ // =============================================================================
148
+ async function fetchAgents(apiKey, serverUrl) {
149
+ try {
150
+ const resp = await fetch(`${serverUrl}/api/agents`, {
151
+ headers: { "X-API-Key": apiKey },
152
+ });
153
+ if (!resp.ok)
154
+ return [];
155
+ const data = await resp.json();
156
+ return data.agents || [];
157
+ }
158
+ catch {
159
+ return [];
160
+ }
161
+ }
162
+ // =============================================================================
163
+ // Step 5: Install startup script
164
+ // =============================================================================
165
+ function installStartupScript(config) {
166
+ const platform = process.platform;
167
+ if (platform === "win32") {
168
+ return installWindowsStartup(config);
169
+ }
170
+ else if (platform === "darwin") {
171
+ return installMacStartup();
172
+ }
173
+ else {
174
+ return installLinuxStartup();
175
+ }
176
+ }
177
+ function installWindowsStartup(config) {
178
+ const startupDir = path.join(process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming"), "Microsoft", "Windows", "Start Menu", "Programs", "Startup");
179
+ // Find worker.js path
180
+ const thisDir = path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/, "$1"));
181
+ const workerJs = path.join(thisDir, "worker.js").replace(/\\/g, "\\\\");
182
+ // Smart bat script: check before start, no zombie loop
183
+ const batContent = `@echo off
184
+ :: AgentHub Worker — auto-starts on login, checks before spawning
185
+ set AGENTHUB_API_KEY=${config.api_key}
186
+ set AGENTHUB_URL=${config.server}
187
+
188
+ :check
189
+ :: Check if worker is already running
190
+ set PID_FILE=%TEMP%\\agenthub-workers\\worker.pid
191
+ if exist "%PID_FILE%" (
192
+ for /f %%i in (%PID_FILE%) do (
193
+ tasklist /fi "PID eq %%i" 2>nul | find "node" >nul 2>&1
194
+ if not errorlevel 1 (
195
+ timeout /t 60 /nobreak >nul
196
+ goto check
197
+ )
198
+ )
199
+ )
200
+ :: Start worker
201
+ node "${workerJs}"
202
+ :: Worker exited, wait and retry
203
+ timeout /t 10 /nobreak >nul
204
+ goto check
205
+ `;
206
+ const batPath = path.join(startupDir, "agenthub-worker.bat");
207
+ fs.writeFileSync(batPath, batContent);
208
+ // VBS to run bat hidden
209
+ const vbsContent = `' Start AgentHub Worker hidden (no console window)
210
+ Set WshShell = CreateObject("WScript.Shell")
211
+ WshShell.Run """${batPath.replace(/\\/g, "\\\\")}""", 0, False
212
+ `;
213
+ const vbsPath = path.join(startupDir, "AgentHub-Worker.vbs");
214
+ fs.writeFileSync(vbsPath, vbsContent);
215
+ // Remove old daemon startup files if they exist
216
+ const oldBat = path.join(startupDir, "agenthub-daemon.bat");
217
+ const oldVbs = path.join(startupDir, "AgentHub-Daemon.vbs");
218
+ try {
219
+ if (fs.existsSync(oldBat))
220
+ fs.unlinkSync(oldBat);
221
+ }
222
+ catch { /* ignore */ }
223
+ try {
224
+ if (fs.existsSync(oldVbs))
225
+ fs.unlinkSync(oldVbs);
226
+ }
227
+ catch { /* ignore */ }
228
+ return vbsPath;
229
+ }
230
+ function installMacStartup() {
231
+ const plistDir = path.join(os.homedir(), "Library", "LaunchAgents");
232
+ const thisDir = path.dirname(new URL(import.meta.url).pathname);
233
+ const workerJs = path.join(thisDir, "worker.js");
234
+ const plist = `<?xml version="1.0" encoding="UTF-8"?>
235
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
236
+ <plist version="1.0">
237
+ <dict>
238
+ <key>Label</key>
239
+ <string>com.agenthub.worker</string>
240
+ <key>ProgramArguments</key>
241
+ <array>
242
+ <string>node</string>
243
+ <string>${workerJs}</string>
244
+ </array>
245
+ <key>RunAtLoad</key>
246
+ <true/>
247
+ <key>KeepAlive</key>
248
+ <true/>
249
+ <key>StandardOutPath</key>
250
+ <string>${path.join(CONFIG_DIR, "worker.log")}</string>
251
+ <key>StandardErrorPath</key>
252
+ <string>${path.join(CONFIG_DIR, "worker.log")}</string>
253
+ </dict>
254
+ </plist>`;
255
+ try {
256
+ fs.mkdirSync(plistDir, { recursive: true });
257
+ }
258
+ catch { /* exists */ }
259
+ const plistPath = path.join(plistDir, "com.agenthub.worker.plist");
260
+ fs.writeFileSync(plistPath, plist);
261
+ return plistPath;
262
+ }
263
+ function installLinuxStartup() {
264
+ const thisDir = path.dirname(new URL(import.meta.url).pathname);
265
+ const workerJs = path.join(thisDir, "worker.js");
266
+ const serviceContent = `[Unit]
267
+ Description=AgentHub Worker
268
+ After=network.target
269
+
270
+ [Service]
271
+ ExecStart=/usr/bin/node ${workerJs}
272
+ Restart=always
273
+ RestartSec=10
274
+
275
+ [Install]
276
+ WantedBy=default.target
277
+ `;
278
+ const serviceDir = path.join(os.homedir(), ".config", "systemd", "user");
279
+ try {
280
+ fs.mkdirSync(serviceDir, { recursive: true });
281
+ }
282
+ catch { /* exists */ }
283
+ const servicePath = path.join(serviceDir, "agenthub-worker.service");
284
+ fs.writeFileSync(servicePath, serviceContent);
285
+ return servicePath;
286
+ }
287
+ // =============================================================================
288
+ // Main wizard
289
+ // =============================================================================
290
+ async function main() {
291
+ print("");
292
+ print(" ╔═══════════════════════════════════╗");
293
+ print(" ║ AgentHub Worker Setup Wizard ║");
294
+ print(" ╚═══════════════════════════════════╝");
295
+ print("");
296
+ // Step 1: API Key
297
+ print("Step 1/4: API Key");
298
+ let apiKey = detectApiKey();
299
+ if (apiKey) {
300
+ print(` Auto-detected: ${apiKey.slice(0, 8)}...${apiKey.slice(-4)}`);
301
+ const confirm = await ask(" Use this key? (y/n)", "y");
302
+ if (confirm.toLowerCase() !== "y") {
303
+ apiKey = await ask(" Enter API key");
304
+ }
305
+ }
306
+ else {
307
+ print(" No API key found in env or claude settings.");
308
+ apiKey = await ask(" Enter API key");
309
+ }
310
+ if (!apiKey) {
311
+ print("Error: API key is required.");
312
+ process.exit(1);
313
+ }
314
+ print("");
315
+ // Step 2: Server URL
316
+ print("Step 2/4: Server");
317
+ const serverUrl = await ask(" Server URL", detectServerUrl());
318
+ print("");
319
+ // Step 3: Projects
320
+ print("Step 3/4: Project Discovery");
321
+ print(" Scanning for projects...");
322
+ const discovered = scanForProjects();
323
+ // Also fetch registered agents to help with matching
324
+ print(" Fetching registered agents...");
325
+ const agents = await fetchAgents(apiKey, serverUrl);
326
+ const projects = {};
327
+ if (discovered.length > 0) {
328
+ print(` Found ${discovered.length} project(s):`);
329
+ for (const p of discovered) {
330
+ print(` - ${p.name} (${p.dir})`);
331
+ }
332
+ print("");
333
+ // Try to match with registered agents
334
+ for (const p of discovered) {
335
+ const dirLower = p.dir.toLowerCase();
336
+ const nameLower = p.name.toLowerCase();
337
+ // Match by working_dir
338
+ const matchByDir = agents.find((a) => a.working_dir && dirLower.includes(a.working_dir.toLowerCase().replace(/\\/g, "/")));
339
+ // Match by name similarity
340
+ const matchByName = agents.find((a) => a.id.toLowerCase().includes(nameLower) || nameLower.includes(a.id.toLowerCase()));
341
+ const bestMatch = matchByDir || matchByName;
342
+ if (bestMatch) {
343
+ const confirm = await ask(` Map "${p.name}" → agent "${bestMatch.id}"? (y/n)`, "y");
344
+ if (confirm.toLowerCase() === "y") {
345
+ projects[bestMatch.id] = p.dir;
346
+ }
347
+ }
348
+ else {
349
+ const agentId = await ask(` Agent ID for "${p.name}" (skip = leave empty)`);
350
+ if (agentId) {
351
+ projects[agentId] = p.dir;
352
+ }
353
+ }
354
+ }
355
+ }
356
+ else {
357
+ print(" No projects found automatically.");
358
+ print(" You can add them manually to ~/.agenthub/worker.json later.");
359
+ }
360
+ print("");
361
+ // Step 4: Slots
362
+ print("Step 4/4: Configuration");
363
+ const slotsStr = await ask(" Concurrent slots", "3");
364
+ const slots = parseInt(slotsStr, 10) || 3;
365
+ // Write config
366
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
367
+ const configData = {
368
+ api_key: apiKey,
369
+ server: serverUrl,
370
+ slots,
371
+ projects,
372
+ };
373
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(configData, null, 2));
374
+ print(` Config saved: ${CONFIG_FILE}`);
375
+ // Install startup
376
+ print("");
377
+ const installStartup = await ask(" Install auto-start on login? (y/n)", "y");
378
+ if (installStartup.toLowerCase() === "y") {
379
+ const startupPath = installStartupScript(configData);
380
+ print(` Startup installed: ${startupPath}`);
381
+ }
382
+ // Start worker now?
383
+ print("");
384
+ const startNow = await ask(" Start worker now? (y/n)", "y");
385
+ if (startNow.toLowerCase() === "y") {
386
+ const { spawn } = await import("child_process");
387
+ const thisDir = path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/, "$1"));
388
+ const workerJs = path.join(thisDir, "worker.js");
389
+ // Stop existing worker first
390
+ const PID_FILE = path.join(os.tmpdir(), "agenthub-workers", "worker.pid");
391
+ if (fs.existsSync(PID_FILE)) {
392
+ const oldPid = parseInt(fs.readFileSync(PID_FILE, "utf-8").trim(), 10);
393
+ try {
394
+ process.kill(oldPid, "SIGTERM");
395
+ }
396
+ catch { /* not running */ }
397
+ }
398
+ const child = spawn("node", [workerJs], {
399
+ detached: true,
400
+ stdio: "ignore",
401
+ env: { ...process.env, AGENTHUB_API_KEY: apiKey, AGENTHUB_URL: serverUrl },
402
+ });
403
+ child.unref();
404
+ print(` Worker started (PID ${child.pid})`);
405
+ }
406
+ print("");
407
+ print(" Setup complete!");
408
+ print("");
409
+ print(" Commands:");
410
+ print(" agenthub-worker Start worker (foreground)");
411
+ print(" agenthub-worker status Check if running");
412
+ print(" agenthub-worker stop Stop worker");
413
+ print(" agenthub-worker logs View recent logs");
414
+ print("");
415
+ print(` Dashboard: ${serverUrl}`);
416
+ print(` Config: ${CONFIG_FILE}`);
417
+ print("");
418
+ rl.close();
419
+ }
420
+ main().catch((err) => {
421
+ console.error("Setup failed:", err);
422
+ process.exit(1);
423
+ });
424
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
package/dist/worker.js CHANGED
@@ -21,39 +21,149 @@ import * as path from "path";
21
21
  import * as os from "os";
22
22
  import { fileURLToPath } from "url";
23
23
  // =============================================================================
24
- // CLI arguments
24
+ // Config: file (~/.agenthub/worker.json) → env vars → CLI args
25
25
  // =============================================================================
26
- const args = process.argv.slice(2);
27
- function getArg(name) {
28
- const idx = args.indexOf(`--${name}`);
29
- return idx !== -1 && idx + 1 < args.length ? args[idx + 1] : undefined;
26
+ const CONFIG_DIR = path.join(os.homedir(), ".agenthub");
27
+ const CONFIG_FILE = path.join(CONFIG_DIR, "worker.json");
28
+ const LOG_FILE = path.join(CONFIG_DIR, "worker.log");
29
+ function loadConfig() {
30
+ // Defaults
31
+ const config = {
32
+ api_key: "",
33
+ server: "https://agenthub.contetial.com",
34
+ slots: 3,
35
+ projects: {},
36
+ };
37
+ // Layer 1: Config file
38
+ if (fs.existsSync(CONFIG_FILE)) {
39
+ try {
40
+ const file = JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
41
+ if (file.api_key)
42
+ config.api_key = file.api_key;
43
+ if (file.server)
44
+ config.server = file.server;
45
+ if (file.slots)
46
+ config.slots = file.slots;
47
+ if (file.projects)
48
+ config.projects = file.projects;
49
+ if (file.worker_id)
50
+ config.worker_id = file.worker_id;
51
+ if (file.claude_cmd)
52
+ config.claude_cmd = file.claude_cmd;
53
+ }
54
+ catch { /* ignore bad config */ }
55
+ }
56
+ // Layer 2: Environment variables (override config file)
57
+ if (process.env.AGENTHUB_API_KEY)
58
+ config.api_key = process.env.AGENTHUB_API_KEY;
59
+ if (process.env.AGENTHUB_URL)
60
+ config.server = process.env.AGENTHUB_URL;
61
+ // Layer 3: CLI args (override everything)
62
+ const args = process.argv.slice(2);
63
+ function getArg(name) {
64
+ const idx = args.indexOf(`--${name}`);
65
+ return idx !== -1 && idx + 1 < args.length ? args[idx + 1] : undefined;
66
+ }
67
+ if (getArg("slots"))
68
+ config.slots = parseInt(getArg("slots"), 10);
69
+ if (getArg("worker-id"))
70
+ config.worker_id = getArg("worker-id");
71
+ if (getArg("claude-cmd"))
72
+ config.claude_cmd = getArg("claude-cmd");
73
+ const projectsArg = getArg("projects") || "";
74
+ if (projectsArg) {
75
+ for (const entry of projectsArg.split(",")) {
76
+ const [agentId, ...dirParts] = entry.split("=");
77
+ if (agentId && dirParts.length > 0) {
78
+ config.projects[agentId.trim()] = dirParts.join("=").trim();
79
+ }
80
+ }
81
+ }
82
+ return config;
30
83
  }
31
- const SLOTS = parseInt(getArg("slots") || "3", 10);
32
- const WORKER_ID = getArg("worker-id") || `${os.hostname()}-${process.pid}`;
33
- const API_KEY = process.env.AGENTHUB_API_KEY || "";
34
- const API_URL = process.env.AGENTHUB_URL || "https://agenthub.contetial.com";
35
- const WS_URL = API_URL.replace(/^https:/, "wss:").replace(/^http:/, "ws:");
36
- const CLAUDE_CMD = getArg("claude-cmd") || "claude";
37
- // Parse projects: --projects "krishi-dev=/path,algo-agent=/other"
38
- const projectsArg = getArg("projects") || "";
39
- const PROJECTS = {};
40
- if (projectsArg) {
41
- for (const entry of projectsArg.split(",")) {
42
- const [agentId, ...dirParts] = entry.split("=");
43
- if (agentId && dirParts.length > 0) {
44
- PROJECTS[agentId.trim()] = dirParts.join("=").trim();
84
+ // =============================================================================
85
+ // Subcommands: status, stop, logs
86
+ // =============================================================================
87
+ const subcommand = process.argv[2];
88
+ if (subcommand === "status" || subcommand === "stop" || subcommand === "logs") {
89
+ const PID_DIR = path.join(os.tmpdir(), "agenthub-workers");
90
+ const PID_FILE = path.join(PID_DIR, "worker.pid");
91
+ if (subcommand === "status") {
92
+ if (!fs.existsSync(PID_FILE)) {
93
+ console.log("Worker: not running");
94
+ process.exit(1);
95
+ }
96
+ const pid = parseInt(fs.readFileSync(PID_FILE, "utf-8").trim(), 10);
97
+ try {
98
+ process.kill(pid, 0);
99
+ console.log(`Worker: running (PID ${pid})`);
100
+ if (fs.existsSync(CONFIG_FILE)) {
101
+ const cfg = JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
102
+ console.log(` Slots: ${cfg.slots || 3}`);
103
+ console.log(` Projects: ${Object.keys(cfg.projects || {}).join(", ") || "(none)"}`);
104
+ console.log(` Server: ${cfg.server || "default"}`);
105
+ }
106
+ }
107
+ catch {
108
+ console.log(`Worker: not running (stale PID ${pid})`);
109
+ process.exit(1);
110
+ }
111
+ process.exit(0);
112
+ }
113
+ if (subcommand === "stop") {
114
+ if (!fs.existsSync(PID_FILE)) {
115
+ console.log("Worker: not running");
116
+ process.exit(0);
117
+ }
118
+ const pid = parseInt(fs.readFileSync(PID_FILE, "utf-8").trim(), 10);
119
+ try {
120
+ process.kill(pid, "SIGTERM");
121
+ console.log(`Worker stopped (PID ${pid})`);
122
+ }
123
+ catch {
124
+ console.log("Worker: not running");
45
125
  }
126
+ try {
127
+ fs.unlinkSync(PID_FILE);
128
+ }
129
+ catch { /* ignore */ }
130
+ process.exit(0);
131
+ }
132
+ if (subcommand === "logs") {
133
+ if (!fs.existsSync(LOG_FILE)) {
134
+ console.log("No log file found at", LOG_FILE);
135
+ process.exit(1);
136
+ }
137
+ // Print last 50 lines
138
+ const content = fs.readFileSync(LOG_FILE, "utf-8");
139
+ const lines = content.split("\n");
140
+ console.log(lines.slice(-50).join("\n"));
141
+ process.exit(0);
46
142
  }
47
143
  }
144
+ // =============================================================================
145
+ // Load config and validate
146
+ // =============================================================================
147
+ const config = loadConfig();
148
+ const SLOTS = config.slots;
149
+ const WORKER_ID = config.worker_id || `${os.hostname()}-${process.pid}`;
150
+ const API_KEY = config.api_key;
151
+ const API_URL = config.server;
152
+ const WS_URL = API_URL.replace(/^https:/, "wss:").replace(/^http:/, "ws:");
153
+ const CLAUDE_CMD = config.claude_cmd || "claude";
154
+ const PROJECTS = config.projects;
48
155
  if (!API_KEY) {
49
- console.error("Error: AGENTHUB_API_KEY environment variable required");
156
+ console.error("Error: No API key found.");
157
+ console.error(" Set AGENTHUB_API_KEY env var, or run: agenthub-setup");
158
+ console.error(" Config file: " + CONFIG_FILE);
50
159
  process.exit(1);
51
160
  }
52
161
  // =============================================================================
53
162
  // PID file — ensures only one worker per machine
54
163
  // =============================================================================
55
164
  const PID_DIR = path.join(os.tmpdir(), "agenthub-workers");
56
- const PID_FILE = path.join(PID_DIR, `${WORKER_ID}.pid`);
165
+ // Use fixed filename so ANY new worker kills the previous one on this machine
166
+ const PID_FILE = path.join(PID_DIR, "worker.pid");
57
167
  function acquirePidLock() {
58
168
  try {
59
169
  fs.mkdirSync(PID_DIR, { recursive: true });
@@ -136,11 +246,22 @@ let ws = null;
136
246
  let reconnectAttempts = 0;
137
247
  let activeSlots = 0;
138
248
  let isShuttingDown = false;
249
+ // Log to both console and file
250
+ let logStream = null;
251
+ try {
252
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
253
+ logStream = fs.createWriteStream(LOG_FILE, { flags: "a" });
254
+ }
255
+ catch { /* ignore */ }
139
256
  function log(msg, ...extra) {
140
- console.log(`[${new Date().toISOString()}] [worker] ${msg}`, ...extra);
257
+ const line = `[${new Date().toISOString()}] [worker] ${msg}`;
258
+ console.log(line, ...extra);
259
+ logStream?.write(line + (extra.length ? " " + extra.map(String).join(" ") : "") + "\n");
141
260
  }
142
261
  function logError(msg, ...extra) {
143
- console.error(`[${new Date().toISOString()}] [worker] ${msg}`, ...extra);
262
+ const line = `[${new Date().toISOString()}] [worker] ${msg}`;
263
+ console.error(line, ...extra);
264
+ logStream?.write(line + (extra.length ? " " + extra.map(String).join(" ") : "") + "\n");
144
265
  }
145
266
  // =============================================================================
146
267
  // WebSocket connection to server
@@ -261,7 +382,7 @@ function executeDispatch(dispatch) {
261
382
  const mcpConfig = isTask
262
383
  ? createMcpConfigForAgent(agentId).replace(/\\/g, "/")
263
384
  : ensureEmptyMcpConfigFile().replace(/\\/g, "/");
264
- const maxTurns = isTask ? "30" : "1";
385
+ const maxTurns = isTask ? "30" : "3";
265
386
  const thisDir = path.dirname(fileURLToPath(import.meta.url)).replace(/\\/g, "/");
266
387
  const wrapperScript = path.join(thisDir, "..", "run-claude.sh").replace(/\\/g, "/");
267
388
  log(`${isTask ? "🚀" : "⚡"} Executing for ${agentId} (slots: ${activeSlots}/${SLOTS})`);