nothumanallowed 16.0.63 → 16.0.64
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/package.json +1 -1
- package/src/constants.mjs +1 -1
- package/src/server/index.mjs +51 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "16.0.
|
|
3
|
+
"version": "16.0.64",
|
|
4
4
|
"description": "Local AI assistant: 80 tools (Gmail, Calendar, Drive, GitHub, Slack, browser, code, files), 38 agents, visual workflows (Studio, AWF, WebCraft). Install with `npm i -g nothumanallowed`, run with `nha ui`. Free tier built-in (Liara), no API key required. Your data stays on your PC — OAuth tokens local, no cloud. Open-source MIT.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/constants.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'url';
|
|
|
5
5
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
6
|
const __dirname = path.dirname(__filename);
|
|
7
7
|
|
|
8
|
-
export const VERSION = '16.0.
|
|
8
|
+
export const VERSION = '16.0.64';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
package/src/server/index.mjs
CHANGED
|
@@ -473,20 +473,64 @@ export async function startServer({ port = 3847, host = '127.0.0.1', noBrowser =
|
|
|
473
473
|
|
|
474
474
|
if (!noBrowser) openBrowser(`http://localhost:${port}`);
|
|
475
475
|
|
|
476
|
-
//
|
|
476
|
+
// ── Unified graceful shutdown ─────────────────────────────────────────────
|
|
477
|
+
// Stops, in this order: PAO daemon (Telegram bot + cron + Gmail/Calendar
|
|
478
|
+
// pollers), orphan WS listener on 3848, sandbox processes on 4000-4010, the
|
|
479
|
+
// HTTP server itself. Second Ctrl+C bails out hard. 5-second hard timeout
|
|
480
|
+
// guards against any step hanging.
|
|
481
|
+
let shuttingDown = false;
|
|
477
482
|
const cleanup = async () => {
|
|
483
|
+
if (shuttingDown) {
|
|
484
|
+
process.stderr.write(`\n ${R}✗${NC} ${D}Force exit${NC}\n`);
|
|
485
|
+
process.exit(130);
|
|
486
|
+
}
|
|
487
|
+
shuttingDown = true;
|
|
488
|
+
process.stdout.write(`\n ${D}Shutting down...${NC}\n`);
|
|
489
|
+
|
|
490
|
+
const hardTimeout = setTimeout(() => {
|
|
491
|
+
process.stderr.write(` ${R}!${NC} ${D}Timed out, killing process${NC}\n`);
|
|
492
|
+
process.exit(1);
|
|
493
|
+
}, 5000);
|
|
494
|
+
hardTimeout.unref();
|
|
495
|
+
|
|
496
|
+
// 1. PAO daemon (Telegram, cron, Gmail/Calendar pollers, notifications)
|
|
497
|
+
try {
|
|
498
|
+
const { stopDaemon, isRunning: isDaemonRunning } = await import('../services/ops-daemon.mjs');
|
|
499
|
+
if (isDaemonRunning()) {
|
|
500
|
+
const r = stopDaemon();
|
|
501
|
+
if (r.ok) process.stdout.write(` ${G}✓${NC} ${D}PAO daemon stopped (PID ${r.pid})${NC}\n`);
|
|
502
|
+
}
|
|
503
|
+
} catch {}
|
|
504
|
+
|
|
505
|
+
// 2. Orphan WS listeners on port 3848 (stale daemon instances from
|
|
506
|
+
// previous sessions that never cleaned up)
|
|
507
|
+
try {
|
|
508
|
+
const { execSync } = await import('child_process');
|
|
509
|
+
const out = execSync('lsof -ti:3848 2>/dev/null', { encoding: 'utf-8', timeout: 1500 }).trim();
|
|
510
|
+
const pids = out.split('\n').filter(Boolean).filter((p) => p !== String(process.pid));
|
|
511
|
+
for (const pid of pids) { try { process.kill(parseInt(pid), 'SIGTERM'); } catch {} }
|
|
512
|
+
if (pids.length) process.stdout.write(` ${G}✓${NC} ${D}Cleaned ${pids.length} orphan(s) on port 3848${NC}\n`);
|
|
513
|
+
} catch {}
|
|
514
|
+
|
|
515
|
+
// 3. WebCraft sandbox processes (4000-4010)
|
|
478
516
|
try {
|
|
479
|
-
const {
|
|
480
|
-
|
|
481
|
-
const execAsync = promisify(exec);
|
|
517
|
+
const { execSync } = await import('child_process');
|
|
518
|
+
let sandboxKilled = 0;
|
|
482
519
|
for (let p = 4000; p <= 4010; p++) {
|
|
483
520
|
try {
|
|
484
|
-
const
|
|
485
|
-
const pids =
|
|
486
|
-
for (const pid of pids) { try { process.kill(parseInt(pid), 'SIGKILL'); } catch {} }
|
|
521
|
+
const out = execSync(`lsof -ti:${p} 2>/dev/null`, { encoding: 'utf-8', timeout: 1500 }).trim();
|
|
522
|
+
const pids = out.split('\n').filter(Boolean);
|
|
523
|
+
for (const pid of pids) { try { process.kill(parseInt(pid), 'SIGKILL'); sandboxKilled++; } catch {} }
|
|
487
524
|
} catch {}
|
|
488
525
|
}
|
|
526
|
+
if (sandboxKilled) process.stdout.write(` ${G}✓${NC} ${D}Stopped ${sandboxKilled} sandbox process(es)${NC}\n`);
|
|
489
527
|
} catch {}
|
|
528
|
+
|
|
529
|
+
// 4. HTTP server — close listening socket so the port frees up immediately
|
|
530
|
+
try { server.close(); } catch {}
|
|
531
|
+
|
|
532
|
+
process.stdout.write(` ${G}✓${NC} ${D}Bye${NC}\n`);
|
|
533
|
+
clearTimeout(hardTimeout);
|
|
490
534
|
process.exit(0);
|
|
491
535
|
};
|
|
492
536
|
process.on('SIGINT', cleanup);
|