nothumanallowed 13.5.184 → 13.5.185

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nothumanallowed",
3
- "version": "13.5.184",
3
+ "version": "13.5.185",
4
4
  "description": "NotHumanAllowed — 38 AI agents, 80 tools, Studio (visual agentic workflows). Email, calendar, browser automation, screen capture, canvas, cron/heartbeat, Alexandria E2E messaging, GitHub, Notion, Slack, voice chat, free AI (Liara), 28 languages. Zero-dependency CLI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -48,6 +48,27 @@ export async function cmdOps(args) {
48
48
  return;
49
49
  }
50
50
 
51
+ case 'restart': {
52
+ const stopResult = stopDaemon();
53
+ if (stopResult.ok) ok(`Daemon stopped (PID ${stopResult.pid})`);
54
+ // Brief pause to let the process fully exit
55
+ await new Promise(r => setTimeout(r, 1200));
56
+ const startResult = startDaemon();
57
+ if (startResult.ok) {
58
+ ok(`Daemon restarted (PID ${startResult.pid})`);
59
+ const config = loadConfig();
60
+ const hasTelegram = !!config.responder?.telegram?.token;
61
+ const hasDiscord = !!config.responder?.discord?.token;
62
+ if (hasTelegram || hasDiscord) {
63
+ const platforms = [hasTelegram && 'Telegram', hasDiscord && 'Discord'].filter(Boolean).join(' + ');
64
+ info(`Message responder active: ${platforms}`);
65
+ }
66
+ } else {
67
+ warn(startResult.message);
68
+ }
69
+ return;
70
+ }
71
+
51
72
  case 'status': {
52
73
  const status = getDaemonStatus();
53
74
  const config = loadConfig();
@@ -109,6 +130,6 @@ export async function cmdOps(args) {
109
130
 
110
131
  default:
111
132
  fail(`Unknown: nha ops ${sub}`);
112
- info('Commands: start, stop, status, logs, run');
133
+ info('Commands: start, stop, restart, status, logs, run');
113
134
  }
114
135
  }
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 = '13.5.184';
8
+ export const VERSION = '13.5.185';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -228,7 +228,7 @@ function touchTelegramUser(chatId, username, firstName) {
228
228
  saveTelegramUsers(users);
229
229
  }
230
230
 
231
- function getAllTelegramChatIds() {
231
+ export function getAllTelegramChatIds() {
232
232
  const users = loadTelegramUsers();
233
233
  return Object.keys(users);
234
234
  }
@@ -28,7 +28,8 @@ import { notify } from './notification.mjs';
28
28
  import { callAgent } from './llm.mjs';
29
29
  import { runPlanningPipeline } from './ops-pipeline.mjs';
30
30
  import { getTasks, getWeekTasks } from './task-store.mjs';
31
- import { startResponder, stopResponder, getResponderStatus } from './message-responder.mjs';
31
+ import { startResponder, stopResponder, getResponderStatus, getAllTelegramChatIds } from './message-responder.mjs';
32
+ import { VERSION } from '../constants.mjs';
32
33
 
33
34
  const DAEMON_DIR = path.join(NHA_DIR, 'ops', 'daemon');
34
35
  const PID_FILE = path.join(DAEMON_DIR, 'daemon.pid');
@@ -862,6 +863,71 @@ async function daemonLoop() {
862
863
  if (responderResult.telegram) log('Message responder: Telegram active');
863
864
  if (responderResult.discord) log('Message responder: Discord active');
864
865
 
866
+ // ── Auto-update check: every 24h, notify + restart if new npm version ──────
867
+ // First check after 5 minutes (let things settle), then every 24h.
868
+ // When a new version is found: notifies via Telegram, then does
869
+ // `npm install -g nothumanallowed@latest` and restarts itself.
870
+ let _lastNotifiedUpdateVersion = null;
871
+ async function _checkAndAutoUpdate() {
872
+ try {
873
+ const res = await fetch('https://registry.npmjs.org/nothumanallowed/latest', {
874
+ signal: AbortSignal.timeout(8000),
875
+ headers: { 'Accept': 'application/json' },
876
+ });
877
+ const data = await res.json();
878
+ const latest = data.version;
879
+ const current = VERSION;
880
+
881
+ // Compare semver
882
+ const pa = current.split('.').map(Number);
883
+ const pb = latest.split('.').map(Number);
884
+ let updateAvailable = false;
885
+ for (let i = 0; i < 3; i++) {
886
+ if ((pb[i] || 0) > (pa[i] || 0)) { updateAvailable = true; break; }
887
+ if ((pb[i] || 0) < (pa[i] || 0)) break;
888
+ }
889
+
890
+ if (!updateAvailable) return;
891
+ if (_lastNotifiedUpdateVersion === latest) return;
892
+ _lastNotifiedUpdateVersion = latest;
893
+
894
+ log(`[AutoUpdate] New version ${latest} available (current: ${current}). Updating...`);
895
+
896
+ // Notify via Telegram before restarting
897
+ const tgToken = config.responder?.telegram?.token;
898
+ if (tgToken) {
899
+ const chatIds = getAllTelegramChatIds();
900
+ const msg = `NHA v${latest} disponibile — aggiornamento automatico in corso...\nIl bot si riavvierà tra pochi secondi.`;
901
+ for (const chatId of chatIds) {
902
+ await fetch(`https://api.telegram.org/bot${tgToken}/sendMessage`, {
903
+ method: 'POST',
904
+ headers: { 'Content-Type': 'application/json' },
905
+ body: JSON.stringify({ chat_id: parseInt(chatId, 10), text: msg }),
906
+ }).catch(() => {});
907
+ await new Promise(r => setTimeout(r, 300));
908
+ }
909
+ }
910
+
911
+ // npm install -g then restart
912
+ await new Promise((resolve) => {
913
+ const proc = spawn('npm', ['install', '-g', `nothumanallowed@${latest}`], { stdio: 'inherit' });
914
+ proc.on('close', resolve);
915
+ });
916
+
917
+ log('[AutoUpdate] npm install complete. Restarting daemon...');
918
+ // Exit — the parent process (startDaemon) will restart us, or the user will
919
+ // The daemon is spawned detached so we just exit and the next `nha ops start` picks it up
920
+ process.exit(0);
921
+ } catch (err) {
922
+ log(`[AutoUpdate] Check failed: ${err.message}`);
923
+ }
924
+ }
925
+
926
+ setTimeout(() => {
927
+ _checkAndAutoUpdate();
928
+ setInterval(_checkAndAutoUpdate, 24 * 60 * 60 * 1000);
929
+ }, 5 * 60 * 1000);
930
+
865
931
  const state = {
866
932
  startedAt: new Date().toISOString(),
867
933
  lastMailCheck: null,