nothumanallowed 14.1.37 → 14.1.38
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.
|
|
3
|
+
"version": "14.1.38",
|
|
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.
|
|
8
|
+
export const VERSION = '14.1.38';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
|
@@ -34,7 +34,7 @@ export function register(router) {
|
|
|
34
34
|
|
|
35
35
|
const url = new URL(req.url, 'http://localhost');
|
|
36
36
|
const folder = url.searchParams.get('folder') || 'inbox';
|
|
37
|
-
const limit = parseInt(url.searchParams.get('pageSize') || url.searchParams.get('limit') || '
|
|
37
|
+
const limit = parseInt(url.searchParams.get('pageSize') || url.searchParams.get('limit') || '200');
|
|
38
38
|
const offset = parseInt(url.searchParams.get('page') || url.searchParams.get('offset') || '0') * (url.searchParams.get('page') ? limit : 1);
|
|
39
39
|
try {
|
|
40
40
|
// getUnreadImportant returns fully-parsed messages (subject, from, snippet, etc.)
|
|
@@ -348,6 +348,25 @@ export function setSyncStatus(accountId, status, error) {
|
|
|
348
348
|
.run(status, error || null, accountId);
|
|
349
349
|
}
|
|
350
350
|
|
|
351
|
+
export function ensureGoogleAccount(data) {
|
|
352
|
+
const db = getDb();
|
|
353
|
+
const existing = db.prepare('SELECT * FROM email_accounts WHERE id = ? OR (type = ? AND email_address = ?)').get(data.id, 'google', data.email_address);
|
|
354
|
+
if (existing) {
|
|
355
|
+
return existing;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const id = data.id || 'google';
|
|
359
|
+
db.prepare(`
|
|
360
|
+
INSERT OR REPLACE INTO email_accounts (id, type, email_address, display_name, from_name, imap_host, imap_port, sort_order, is_active)
|
|
361
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
362
|
+
`).run(id, 'google', data.email_address, data.display_name, data.display_name,
|
|
363
|
+
data.imap_host, data.imap_port || 993, data.sort_order || 0, data.is_active || 1);
|
|
364
|
+
|
|
365
|
+
// Seed system labels for new Google account
|
|
366
|
+
seedSystemLabels(db);
|
|
367
|
+
return db.prepare('SELECT * FROM email_accounts WHERE id = ?').get(id);
|
|
368
|
+
}
|
|
369
|
+
|
|
351
370
|
// ── FOLDER CRUD ────────────────────────────────────────────────────────────
|
|
352
371
|
|
|
353
372
|
export function upsertFolder(accountId, path, name, folderType, uidValidity, lastUid) {
|
|
@@ -491,6 +510,17 @@ export function insertMessage(data) {
|
|
|
491
510
|
return id;
|
|
492
511
|
}
|
|
493
512
|
|
|
513
|
+
// Alias for Gmail API integration
|
|
514
|
+
export function saveMessage(accountId, data) {
|
|
515
|
+
return insertMessage({
|
|
516
|
+
...data,
|
|
517
|
+
account_id: accountId,
|
|
518
|
+
imap_folder_path: 'INBOX',
|
|
519
|
+
uid: Date.now(), // Fake UID for Gmail API messages
|
|
520
|
+
source: 'gmail_api'
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
|
|
494
524
|
export function insertAttachments(messageId, attachments) {
|
|
495
525
|
const db = getDb();
|
|
496
526
|
const insert = db.prepare(`
|
|
@@ -91,7 +91,7 @@ export async function getUnreadImportant(config, maxResults = 30) {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
// Cache messages locally
|
|
94
|
-
cacheMessages(messages);
|
|
94
|
+
await cacheMessages(messages);
|
|
95
95
|
return messages;
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -352,12 +352,64 @@ function parseMessage(raw) {
|
|
|
352
352
|
|
|
353
353
|
// ── Local Cache ────────────────────────────────────────────────────────────
|
|
354
354
|
|
|
355
|
-
function cacheMessages(messages) {
|
|
355
|
+
async function cacheMessages(messages) {
|
|
356
|
+
// Cache as JSON files (legacy ops system)
|
|
356
357
|
fs.mkdirSync(INBOX_DIR, { recursive: true });
|
|
357
358
|
for (const msg of messages) {
|
|
358
359
|
const file = path.join(INBOX_DIR, `${msg.id}.json`);
|
|
359
360
|
fs.writeFileSync(file, JSON.stringify(msg, null, 2), { mode: 0o600 });
|
|
360
361
|
}
|
|
362
|
+
|
|
363
|
+
// ENTERPRISE LOCAL-FIRST: Also save to IMAP database for Web UI offline access
|
|
364
|
+
try {
|
|
365
|
+
const { ensureGoogleAccount, saveMessage } = await import('./email-db.mjs');
|
|
366
|
+
|
|
367
|
+
// Ensure Google account exists in IMAP database
|
|
368
|
+
const googleAccount = ensureGoogleAccount({
|
|
369
|
+
id: 'google',
|
|
370
|
+
display_name: 'Gmail',
|
|
371
|
+
email_address: messages[0]?.to || 'gmail@account',
|
|
372
|
+
imap_host: 'gmail.googleapis.com',
|
|
373
|
+
imap_port: 993,
|
|
374
|
+
imap_secure: true,
|
|
375
|
+
is_active: 1
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// Save each message to IMAP database
|
|
379
|
+
for (const msg of messages) {
|
|
380
|
+
saveMessage(googleAccount.id, {
|
|
381
|
+
message_id: msg.id,
|
|
382
|
+
thread_id: msg.threadId || msg.id,
|
|
383
|
+
subject: msg.subject || '(no subject)',
|
|
384
|
+
from_name: extractName(msg.from),
|
|
385
|
+
from_address: extractEmail(msg.from),
|
|
386
|
+
to_addresses: msg.to || '',
|
|
387
|
+
body_text: msg.body || '',
|
|
388
|
+
body_preview: msg.snippet || '',
|
|
389
|
+
internal_date: new Date(msg.date || Date.now()).toISOString(),
|
|
390
|
+
is_read: !msg.isUnread,
|
|
391
|
+
is_starred: !!msg.isImportant,
|
|
392
|
+
labels: (msg.labels || []).join(','),
|
|
393
|
+
has_attachments: false
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
} catch (e) {
|
|
397
|
+
// Fallback gracefully if IMAP DB is not available
|
|
398
|
+
console.warn('[GMAIL CACHE] Failed to save to IMAP database:', e.message);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Helper functions for email parsing
|
|
403
|
+
function extractName(emailField) {
|
|
404
|
+
if (!emailField) return '';
|
|
405
|
+
const match = emailField.match(/^(.+?)\s*<.+>$/);
|
|
406
|
+
return match ? match[1].trim().replace(/['"]/g, '') : '';
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function extractEmail(emailField) {
|
|
410
|
+
if (!emailField) return '';
|
|
411
|
+
const match = emailField.match(/<(.+?)>$/);
|
|
412
|
+
return match ? match[1] : emailField;
|
|
361
413
|
}
|
|
362
414
|
|
|
363
415
|
/**
|