nothumanallowed 13.5.182 → 13.5.183
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/services/message-responder.mjs +124 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.5.
|
|
3
|
+
"version": "13.5.183",
|
|
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/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.183';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
|
@@ -13,6 +13,10 @@ import { buildSystemPrompt, parseActions, executeTool, TOOL_DEFINITIONS } from '
|
|
|
13
13
|
import https from 'https';
|
|
14
14
|
import http from 'http';
|
|
15
15
|
import { URL } from 'url';
|
|
16
|
+
import fs from 'fs';
|
|
17
|
+
import path from 'path';
|
|
18
|
+
import os from 'os';
|
|
19
|
+
import { VERSION } from '../constants.mjs';
|
|
16
20
|
|
|
17
21
|
// ── Agent Routing (keyword-based, zero LLM calls) ───────────────────────────
|
|
18
22
|
|
|
@@ -190,6 +194,71 @@ async function callAgentWithTools(config, agentName, userMessage) {
|
|
|
190
194
|
|
|
191
195
|
// ── Telegram Bot (Long Polling via native fetch) ─────────────────────────────
|
|
192
196
|
|
|
197
|
+
// ── User store for Telegram chat IDs (for broadcast notifications) ──────────
|
|
198
|
+
|
|
199
|
+
const TELEGRAM_USERS_FILE = path.join(os.homedir(), '.nha', 'telegram-users.json');
|
|
200
|
+
|
|
201
|
+
function loadTelegramUsers() {
|
|
202
|
+
try {
|
|
203
|
+
const raw = fs.readFileSync(TELEGRAM_USERS_FILE, 'utf8');
|
|
204
|
+
return JSON.parse(raw);
|
|
205
|
+
} catch {
|
|
206
|
+
return {};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function saveTelegramUsers(users) {
|
|
211
|
+
try {
|
|
212
|
+
fs.mkdirSync(path.dirname(TELEGRAM_USERS_FILE), { recursive: true });
|
|
213
|
+
fs.writeFileSync(TELEGRAM_USERS_FILE, JSON.stringify(users, null, 2));
|
|
214
|
+
} catch {}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function touchTelegramUser(chatId, username, firstName) {
|
|
218
|
+
const users = loadTelegramUsers();
|
|
219
|
+
const id = String(chatId);
|
|
220
|
+
const now = new Date().toISOString();
|
|
221
|
+
users[id] = {
|
|
222
|
+
chatId: id,
|
|
223
|
+
username: username || null,
|
|
224
|
+
firstName: firstName || null,
|
|
225
|
+
firstSeen: users[id]?.firstSeen || now,
|
|
226
|
+
lastSeen: now,
|
|
227
|
+
};
|
|
228
|
+
saveTelegramUsers(users);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function getAllTelegramChatIds() {
|
|
232
|
+
const users = loadTelegramUsers();
|
|
233
|
+
return Object.keys(users);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ── npm update check ─────────────────────────────────────────────────────────
|
|
237
|
+
|
|
238
|
+
function compareSemver(a, b) {
|
|
239
|
+
const pa = a.split('.').map(Number);
|
|
240
|
+
const pb = b.split('.').map(Number);
|
|
241
|
+
for (let i = 0; i < 3; i++) {
|
|
242
|
+
if ((pa[i] || 0) > (pb[i] || 0)) return 1;
|
|
243
|
+
if ((pa[i] || 0) < (pb[i] || 0)) return -1;
|
|
244
|
+
}
|
|
245
|
+
return 0;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async function checkNpmVersion() {
|
|
249
|
+
const res = await fetch('https://registry.npmjs.org/nothumanallowed/latest', {
|
|
250
|
+
signal: AbortSignal.timeout(8000),
|
|
251
|
+
headers: { 'Accept': 'application/json' },
|
|
252
|
+
});
|
|
253
|
+
const data = await res.json();
|
|
254
|
+
const latest = data.version;
|
|
255
|
+
const current = VERSION;
|
|
256
|
+
const updateAvailable = compareSemver(latest, current) > 0;
|
|
257
|
+
return { current, latest, updateAvailable };
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// ── Telegram Bot (Long Polling via native fetch) ─────────────────────────────
|
|
261
|
+
|
|
193
262
|
class TelegramResponder {
|
|
194
263
|
constructor(config, log, wsBroadcast) {
|
|
195
264
|
this.config = config;
|
|
@@ -203,6 +272,8 @@ class TelegramResponder {
|
|
|
203
272
|
this.abortController = null;
|
|
204
273
|
this.pendingRequests = 0;
|
|
205
274
|
this.maxConcurrent = 3;
|
|
275
|
+
this._updateCheckTimer = null;
|
|
276
|
+
this._lastNotifiedVersion = null;
|
|
206
277
|
}
|
|
207
278
|
|
|
208
279
|
get enabled() {
|
|
@@ -214,6 +285,8 @@ class TelegramResponder {
|
|
|
214
285
|
this.running = true;
|
|
215
286
|
this.log('[Telegram] Responder started — polling for messages');
|
|
216
287
|
this._pollLoop();
|
|
288
|
+
// Check for npm updates after 60s, then every 24h
|
|
289
|
+
this._updateCheckTimer = setTimeout(() => this._scheduleUpdateCheck(), 60 * 1000);
|
|
217
290
|
}
|
|
218
291
|
|
|
219
292
|
stop() {
|
|
@@ -222,9 +295,57 @@ class TelegramResponder {
|
|
|
222
295
|
this.abortController.abort();
|
|
223
296
|
this.abortController = null;
|
|
224
297
|
}
|
|
298
|
+
if (this._updateCheckTimer) {
|
|
299
|
+
clearTimeout(this._updateCheckTimer);
|
|
300
|
+
clearInterval(this._updateCheckTimer);
|
|
301
|
+
this._updateCheckTimer = null;
|
|
302
|
+
}
|
|
225
303
|
this.log('[Telegram] Responder stopped');
|
|
226
304
|
}
|
|
227
305
|
|
|
306
|
+
async _scheduleUpdateCheck() {
|
|
307
|
+
await this._checkAndNotifyUpdate();
|
|
308
|
+
// Then every 24h
|
|
309
|
+
this._updateCheckTimer = setInterval(() => this._checkAndNotifyUpdate(), 24 * 60 * 60 * 1000);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
async _checkAndNotifyUpdate() {
|
|
313
|
+
try {
|
|
314
|
+
const { latest, updateAvailable } = await checkNpmVersion();
|
|
315
|
+
if (!updateAvailable) return;
|
|
316
|
+
if (this._lastNotifiedVersion === latest) return; // Already notified for this version
|
|
317
|
+
|
|
318
|
+
this._lastNotifiedVersion = latest;
|
|
319
|
+
const chatIds = getAllTelegramChatIds();
|
|
320
|
+
if (chatIds.length === 0) return;
|
|
321
|
+
|
|
322
|
+
const msg =
|
|
323
|
+
`🆕 *NHA v${latest} disponibile!*\n\n` +
|
|
324
|
+
`Una nuova versione di NotHumanAllowed è stata pubblicata.\n\n` +
|
|
325
|
+
`Aggiorna con:\n` +
|
|
326
|
+
`\`npm install -g nothumanallowed@latest\`\n\n` +
|
|
327
|
+
`Poi riavvia il bot con: \`nha responder restart\``;
|
|
328
|
+
|
|
329
|
+
this.log(`[Telegram] Broadcasting update notification v${latest} to ${chatIds.length} users`);
|
|
330
|
+
|
|
331
|
+
for (const chatId of chatIds) {
|
|
332
|
+
try {
|
|
333
|
+
await this._telegramCall('sendMessage', {
|
|
334
|
+
chat_id: parseInt(chatId, 10),
|
|
335
|
+
text: msg,
|
|
336
|
+
parse_mode: 'Markdown',
|
|
337
|
+
});
|
|
338
|
+
} catch {
|
|
339
|
+
// User blocked bot or chat no longer exists — ignore
|
|
340
|
+
}
|
|
341
|
+
// Small delay to avoid Telegram rate limits
|
|
342
|
+
await this._sleep(300);
|
|
343
|
+
}
|
|
344
|
+
} catch (err) {
|
|
345
|
+
this.log(`[Telegram] Update check failed: ${err.message}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
228
349
|
async _pollLoop() {
|
|
229
350
|
while (this.running) {
|
|
230
351
|
try {
|
|
@@ -343,6 +464,9 @@ class TelegramResponder {
|
|
|
343
464
|
return;
|
|
344
465
|
}
|
|
345
466
|
|
|
467
|
+
// Track this user for broadcast notifications (update alerts, etc.)
|
|
468
|
+
touchTelegramUser(chatId, message.from?.username, message.from?.first_name);
|
|
469
|
+
|
|
346
470
|
let rawText = message.text || '';
|
|
347
471
|
let isVoice = false;
|
|
348
472
|
|