nothumanallowed 13.5.183 → 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.
|
|
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": {
|
package/src/commands/ops.mjs
CHANGED
|
@@ -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.
|
|
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
|
}
|
|
@@ -405,10 +405,29 @@ class TelegramResponder {
|
|
|
405
405
|
if (!audioRes.ok) throw new Error(`Download failed: ${audioRes.status}`);
|
|
406
406
|
const audioBuffer = Buffer.from(await audioRes.arrayBuffer());
|
|
407
407
|
|
|
408
|
-
// Step 3: transcribe —
|
|
408
|
+
// Step 3: transcribe — priority: NHA proxy (no user key needed) → Groq local key → OpenAI local key
|
|
409
409
|
const groqKey = this.config.llm?.groqKey;
|
|
410
410
|
const openaiKey = this.config.llm?.openaiKey || (this.config.llm?.provider === 'openai' ? this.config.llm?.apiKey : null);
|
|
411
411
|
|
|
412
|
+
// Option A: NHA voice proxy (server-side Groq key, free for all users)
|
|
413
|
+
try {
|
|
414
|
+
const proxyForm = new FormData();
|
|
415
|
+
proxyForm.append('audio', new Blob([audioBuffer], { type: 'audio/ogg' }), 'voice.ogg');
|
|
416
|
+
const proxyRes = await fetch('https://nothumanallowed.com/api/v1/voice/transcribe', {
|
|
417
|
+
method: 'POST',
|
|
418
|
+
body: proxyForm,
|
|
419
|
+
signal: AbortSignal.timeout(30000),
|
|
420
|
+
});
|
|
421
|
+
if (proxyRes.ok) {
|
|
422
|
+
const d = await proxyRes.json();
|
|
423
|
+
if (d.text) return d.text;
|
|
424
|
+
}
|
|
425
|
+
// If proxy returned rate limit or error, fall through to local keys
|
|
426
|
+
} catch {
|
|
427
|
+
// Network error — fall through to local keys
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Option B: local Groq key
|
|
412
431
|
const boundary = '----NHAVoice' + Date.now().toString(36);
|
|
413
432
|
const crlf = '\r\n';
|
|
414
433
|
const filename = 'voice.ogg';
|
|
@@ -435,6 +454,7 @@ class TelegramResponder {
|
|
|
435
454
|
return d.text || '';
|
|
436
455
|
}
|
|
437
456
|
|
|
457
|
+
// Option C: local OpenAI key
|
|
438
458
|
if (openaiKey) {
|
|
439
459
|
const modelPartOAI = Buffer.from(
|
|
440
460
|
`${crlf}--${boundary}${crlf}` +
|
|
@@ -452,7 +472,7 @@ class TelegramResponder {
|
|
|
452
472
|
return d.text || '';
|
|
453
473
|
}
|
|
454
474
|
|
|
455
|
-
throw new Error('
|
|
475
|
+
throw new Error('Voice transcription unavailable. The NHA proxy is temporarily unreachable.');
|
|
456
476
|
}
|
|
457
477
|
|
|
458
478
|
async _handleMessage(message) {
|
|
@@ -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,
|