nothumanallowed 14.1.56 → 14.1.58

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": "14.1.56",
3
+ "version": "14.1.58",
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 = '14.1.56';
8
+ export const VERSION = '14.1.58';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -353,17 +353,34 @@ function parseMessage(raw) {
353
353
  }
354
354
 
355
355
  let body = '';
356
+ let bodyHtml = '';
357
+
358
+ // Recursive function to find parts in nested multipart structures
359
+ function findParts(parts) {
360
+ if (!parts) return;
361
+ for (const p of parts) {
362
+ if (p.mimeType === 'text/plain' && p.body?.data && !body) {
363
+ body = Buffer.from(p.body.data, 'base64url').toString('utf-8');
364
+ } else if (p.mimeType === 'text/html' && p.body?.data && !bodyHtml) {
365
+ bodyHtml = Buffer.from(p.body.data, 'base64url').toString('utf-8');
366
+ } else if (p.parts) {
367
+ findParts(p.parts);
368
+ }
369
+ }
370
+ }
371
+
356
372
  if (raw.payload?.body?.data) {
357
- body = Buffer.from(raw.payload.body.data, 'base64url').toString('utf-8');
373
+ // Single-part message
374
+ const content = Buffer.from(raw.payload.body.data, 'base64url').toString('utf-8');
375
+ if (raw.payload.mimeType === 'text/html') bodyHtml = content;
376
+ else body = content;
358
377
  } else if (raw.payload?.parts) {
359
- const textPart = raw.payload.parts.find(p => p.mimeType === 'text/plain');
360
- if (textPart?.body?.data) {
361
- body = Buffer.from(textPart.body.data, 'base64url').toString('utf-8');
362
- }
378
+ findParts(raw.payload.parts);
363
379
  }
364
380
 
365
381
  // Extract URLs from body
366
- const urls = (body.match(/https?:\/\/[^\s<>"']+/g) || []).slice(0, 10);
382
+ const textContent = body || bodyHtml.replace(/<[^>]+>/g, '');
383
+ const urls = (textContent.match(/https?:\/\/[^\s<>"']+/g) || []).slice(0, 10);
367
384
 
368
385
  return {
369
386
  id: raw.id,
@@ -373,7 +390,8 @@ function parseMessage(raw) {
373
390
  subject: headers.subject || '(no subject)',
374
391
  date: headers.date || '',
375
392
  snippet: raw.snippet || '',
376
- body: body.slice(0, 5000), // cap for LLM context
393
+ body: body.slice(0, 5000),
394
+ bodyHtml,
377
395
  urls,
378
396
  labels: raw.labelIds || [],
379
397
  isUnread: (raw.labelIds || []).includes('UNREAD'),
@@ -446,9 +464,9 @@ async function cacheMessages(messages, folder = 'INBOX') {
446
464
  const insertStmt = db.prepare(`
447
465
  INSERT OR REPLACE INTO email_messages
448
466
  (id, account_id, folder_id, imap_folder_path, uid, message_id, thread_id,
449
- subject, from_address, from_name, to_addresses, body_text, body_preview,
467
+ subject, from_address, from_name, to_addresses, body_text, body_html, body_preview,
450
468
  internal_date, has_attachments, source)
451
- VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
469
+ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
452
470
  `);
453
471
  const stateStmt = db.prepare(`
454
472
  INSERT OR REPLACE INTO email_message_state (message_id, is_read, is_starred)
@@ -457,15 +475,15 @@ async function cacheMessages(messages, folder = 'INBOX') {
457
475
 
458
476
  const insertAll = db.transaction((msgs) => {
459
477
  for (const msg of msgs) {
460
- const msgId = msg.id; // Use Gmail message ID as primary key (stable, unique)
478
+ const msgId = msg.id;
461
479
  insertStmt.run(
462
480
  msgId, googleAccount.id, folderId, folderKey,
463
- Date.now() + Math.random() * 1000 | 0, // unique uid
481
+ Date.now() + Math.random() * 1000 | 0,
464
482
  msg.id, msg.threadId || msg.id,
465
483
  msg.subject || '(no subject)',
466
484
  extractEmail(msg.from), extractName(msg.from),
467
485
  msg.to || '',
468
- msg.body || '', msg.snippet || '',
486
+ msg.body || '', msg.bodyHtml || '', msg.snippet || '',
469
487
  new Date(msg.date || Date.now()).toISOString(),
470
488
  0, 'gmail_api'
471
489
  );