nothumanallowed 10.8.2 → 10.9.0

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": "10.8.2",
3
+ "version": "10.9.0",
4
4
  "description": "NotHumanAllowed — 38 AI agents, 53 tools. Email, calendar, browser automation, screen capture, canvas, cron/heartbeat, GitHub, Notion, Slack, voice chat, 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 = '10.8.2';
8
+ export const VERSION = '10.9.0';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -365,6 +365,13 @@ TOOLS:
365
365
  65. canvas_clear()
366
366
  Clear the canvas panel.
367
367
 
368
+ --- AGENT MESSENGER ---
369
+
370
+ 66. collab_send(message: string, channel?: string)
371
+ Send an E2E encrypted message to the active Alexandria channel (AgentMessenger).
372
+ Use this when the user asks to notify collaborators, share progress, or send a message to other agents/team members.
373
+ If channel is not specified, sends to the active channel.
374
+
368
375
  RULES:
369
376
  - ABSOLUTE RULE: NEVER LIE. NEVER fabricate, invent, or guess information. If you do not know, say "I don't know." If a tool fails, say it failed. If you cannot see something, say so. Honesty is MORE important than being helpful.
370
377
  - CRITICAL: For web searches, ALWAYS use web_search — NEVER open Google/Bing/DuckDuckGo in the browser.
@@ -1443,6 +1450,58 @@ export async function executeTool(action, params, config) {
1443
1450
  return '[CANVAS_CLEAR]Canvas cleared.[/CANVAS_CLEAR]';
1444
1451
  }
1445
1452
 
1453
+ // ── Agent Messenger ──────────────────────────────────────────────────
1454
+ case 'collab_send': {
1455
+ const { addCronJob, listCronJobs, loadChannels, getActiveChannel } = await import('./ops-daemon.mjs').catch(() => ({}));
1456
+ const collabMod = await import('../commands/collab.mjs').catch(() => null);
1457
+ if (!collabMod) return 'AgentMessenger not available.';
1458
+
1459
+ const msg = params.message;
1460
+ if (!msg) return 'Message is required.';
1461
+
1462
+ // Use collab CLI to send
1463
+ try {
1464
+ const fs = await import('fs');
1465
+ const path = await import('path');
1466
+ const crypto = await import('crypto');
1467
+ const os = await import('os');
1468
+ const NHA_DIR = path.default.join(os.default.homedir(), '.nha');
1469
+ const chFile = path.default.join(NHA_DIR, 'collab', 'channels.json');
1470
+ const idFile = path.default.join(NHA_DIR, 'collab', 'identity.json');
1471
+
1472
+ if (!fs.default.existsSync(chFile) || !fs.default.existsSync(idFile)) {
1473
+ return 'No Alexandria channels configured. Create one first: nha collab create "name"';
1474
+ }
1475
+
1476
+ const channels = JSON.parse(fs.default.readFileSync(chFile, 'utf-8'));
1477
+ const identity = JSON.parse(fs.default.readFileSync(idFile, 'utf-8'));
1478
+ const channel = params.channel
1479
+ ? channels.find(c => c.name?.toLowerCase().includes(params.channel.toLowerCase()) || c.id === params.channel)
1480
+ : channels.find(c => c.active) || channels[0];
1481
+
1482
+ if (!channel) return 'No active channel found.';
1483
+
1484
+ const API = 'https://nothumanallowed.com/api/v1/alexandria';
1485
+ const channelKey = crypto.default.createHash('sha256').update('alexandria-e2e-key-v2').update(channel.id).update(channel.secret || '').digest();
1486
+ const nonce = crypto.default.randomBytes(12);
1487
+ const cipher = crypto.default.createCipheriv('aes-256-gcm', channelKey, nonce);
1488
+ const encrypted = Buffer.concat([cipher.update(msg, 'utf-8'), cipher.final()]);
1489
+ const tag = cipher.getAuthTag();
1490
+ const ciphertext = Buffer.concat([encrypted, tag]).toString('base64');
1491
+
1492
+ const r = await fetch(API + '/channels/' + channel.id + '/messages', {
1493
+ method: 'POST',
1494
+ headers: { 'Content-Type': 'application/json' },
1495
+ body: JSON.stringify({ senderFingerprint: identity.fingerprint, nonce: nonce.toString('base64'), ciphertext, type: 'text' }),
1496
+ });
1497
+
1498
+ if (!r.ok) return `Failed to send: ${r.status}`;
1499
+ return `Message sent to "${channel.name}" (encrypted). Other members will see it in real-time.`;
1500
+ } catch (e) {
1501
+ return `Failed to send: ${e.message}`;
1502
+ }
1503
+ }
1504
+
1446
1505
  default:
1447
1506
  return `Unknown action: ${action}`;
1448
1507
  }