nothumanallowed 13.5.113 → 13.5.115
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 +4 -1
- package/src/commands/ui.mjs +409 -4
- package/src/constants.mjs +1 -1
- package/src/services/email-db.mjs +688 -0
- package/src/services/email-imap.mjs +421 -0
- package/src/services/email-smtp.mjs +135 -0
- package/src/services/llm.mjs +7 -1
- package/src/services/tool-executor.mjs +95 -1
- package/src/services/web-ui.mjs +701 -83
|
@@ -66,6 +66,7 @@ export const DESTRUCTIVE_ACTIONS = new Set([
|
|
|
66
66
|
'gmail_send_attach',
|
|
67
67
|
'gmail_reply',
|
|
68
68
|
'gmail_delete',
|
|
69
|
+
'imap_send',
|
|
69
70
|
'calendar_create',
|
|
70
71
|
'calendar_move',
|
|
71
72
|
'calendar_update',
|
|
@@ -371,9 +372,37 @@ TOOLS:
|
|
|
371
372
|
63. screen_analyze(question: string)
|
|
372
373
|
Capture the screen AND analyze it with vision. Combines capture + question.
|
|
373
374
|
|
|
375
|
+
--- IMAP EMAIL (custom accounts) ---
|
|
376
|
+
|
|
377
|
+
64. imap_list(accountId: string, labelId?: string, search?: string, limit?: number)
|
|
378
|
+
List emails from a custom IMAP account stored in local DB. Use imap_accounts() to get accountId.
|
|
379
|
+
labelId is optional — pass the label id to filter (e.g. inbox system label). search is full-text.
|
|
380
|
+
Returns: [{id, subject, from_address, from_name, internal_date, body_preview, is_read, is_starred}]
|
|
381
|
+
|
|
382
|
+
65. imap_accounts()
|
|
383
|
+
List all configured IMAP accounts. Returns [{id, type, email_address, display_name, sync_status}].
|
|
384
|
+
Use the id from here as accountId in other imap_* tools.
|
|
385
|
+
|
|
386
|
+
66. imap_read(messageId: string)
|
|
387
|
+
Read a full email message from the local DB by its id. Returns subject, from, to, body_text, body_html, attachments.
|
|
388
|
+
|
|
389
|
+
67. imap_send(accountId: string, to: string, subject: string, bodyHtml: string, cc?: string, inReplyTo?: string)
|
|
390
|
+
Send an email via SMTP from a configured IMAP account. ALWAYS confirm with user before sending.
|
|
391
|
+
bodyHtml can contain HTML. inReplyTo is the Message-ID of the original email for threading.
|
|
392
|
+
|
|
393
|
+
68. imap_sync(accountId: string)
|
|
394
|
+
Trigger an incremental IMAP sync for an account. Fetches new messages into local DB.
|
|
395
|
+
Run this before imap_list if you need fresh data.
|
|
396
|
+
|
|
397
|
+
69. imap_labels(accountId: string)
|
|
398
|
+
List all labels for an IMAP account (system + user-defined). Returns [{id, name, system_type, color, unread_count}].
|
|
399
|
+
|
|
400
|
+
70. imap_mark_read(messageId: string, isRead?: boolean)
|
|
401
|
+
Mark a local message as read or unread. Does NOT touch the IMAP server. Default isRead=true.
|
|
402
|
+
|
|
374
403
|
--- CANVAS ---
|
|
375
404
|
|
|
376
|
-
|
|
405
|
+
71. canvas_render(html: string, title?: string)
|
|
377
406
|
Render HTML in the web UI canvas panel. Show charts, tables, diagrams, reports.
|
|
378
407
|
ALWAYS use Chart.js from CDN for charts and graphs — never build charts with raw HTML/CSS.
|
|
379
408
|
Template for charts:
|
|
@@ -846,6 +875,71 @@ export async function executeTool(action, params, config) {
|
|
|
846
875
|
return `Email sent to ${params.to} with attachment "${downloaded.name}" (${formatFileSize(downloaded.size)}).`;
|
|
847
876
|
}
|
|
848
877
|
|
|
878
|
+
// ── IMAP Email (custom accounts) ─────────────────────────────────────
|
|
879
|
+
case 'imap_accounts': {
|
|
880
|
+
const { listAccounts } = await import('./email-db.mjs');
|
|
881
|
+
const accs = listAccounts();
|
|
882
|
+
if (!accs.length) return 'No IMAP accounts configured. Ask the user to add one in Settings > Email Accounts.';
|
|
883
|
+
return accs.map(a => `[${a.id}] ${a.display_name} <${a.email_address}> — ${a.sync_status}`).join('\n');
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
case 'imap_sync': {
|
|
887
|
+
if (!params.accountId) return 'accountId required.';
|
|
888
|
+
const { syncAccount } = await import('./email-imap.mjs');
|
|
889
|
+
syncAccount(params.accountId).catch(e => console.error('[imap_sync]', e.message));
|
|
890
|
+
return `Sync started for account ${params.accountId}. New messages will appear in a few seconds.`;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
case 'imap_labels': {
|
|
894
|
+
if (!params.accountId) return 'accountId required.';
|
|
895
|
+
const { listLabels } = await import('./email-db.mjs');
|
|
896
|
+
const labels = listLabels(params.accountId);
|
|
897
|
+
if (!labels.length) return 'No labels found.';
|
|
898
|
+
return labels.map(l => `[${l.id}] ${l.name}${l.system_type ? ' (' + l.system_type + ')' : ''}${l.unread_count > 0 ? ' — ' + l.unread_count + ' unread' : ''}`).join('\n');
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
case 'imap_list': {
|
|
902
|
+
if (!params.accountId) return 'accountId required. Use imap_accounts() first.';
|
|
903
|
+
const { listMessages: imapListMessages } = await import('./email-db.mjs');
|
|
904
|
+
const result = imapListMessages(params.accountId, params.labelId || null, params.limit || 20, 0, params.search || null);
|
|
905
|
+
if (!result.messages.length) return 'No messages found.';
|
|
906
|
+
return result.messages.map(m =>
|
|
907
|
+
`[${m.id}] ${m.is_read ? '' : '[UNREAD] '}From: ${m.from_name || m.from_address} | ${m.subject} | ${(m.internal_date || '').slice(0, 10)}\n Preview: ${(m.body_preview || '').slice(0, 120)}`
|
|
908
|
+
).join('\n\n') + `\n\n(${result.total} total)`;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
case 'imap_read': {
|
|
912
|
+
if (!params.messageId) return 'messageId required.';
|
|
913
|
+
const { getMessage: imapGetMessage, markRead: imapMarkRead } = await import('./email-db.mjs');
|
|
914
|
+
const msg = imapGetMessage(params.messageId);
|
|
915
|
+
if (!msg) return 'Message not found.';
|
|
916
|
+
imapMarkRead(params.messageId, true);
|
|
917
|
+
const to = (() => { try { const a = JSON.parse(msg.to_addresses || '[]'); return a.map(x => x.address || x).join(', '); } catch { return msg.to_addresses || ''; } })();
|
|
918
|
+
const body = msg.body_reply_only || msg.body_text || msg.body_preview || '(empty)';
|
|
919
|
+
return `Subject: ${msg.subject}\nFrom: ${msg.from_name ? msg.from_name + ' <' + msg.from_address + '>' : msg.from_address}\nTo: ${to}\nDate: ${msg.internal_date}\n\n${body.slice(0, 3000)}`;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
case 'imap_send': {
|
|
923
|
+
if (!params.accountId || !params.to || !params.subject) return 'accountId, to, subject required.';
|
|
924
|
+
const { sendEmail: imapSendEmail } = await import('./email-smtp.mjs');
|
|
925
|
+
const result = await imapSendEmail(params.accountId, {
|
|
926
|
+
to: params.to,
|
|
927
|
+
cc: params.cc || null,
|
|
928
|
+
subject: params.subject,
|
|
929
|
+
bodyHtml: params.bodyHtml || params.body || '',
|
|
930
|
+
bodyText: params.bodyText || null,
|
|
931
|
+
inReplyTo: params.inReplyTo || null,
|
|
932
|
+
});
|
|
933
|
+
return `Email sent successfully. Message-ID: ${result.messageId}`;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
case 'imap_mark_read': {
|
|
937
|
+
if (!params.messageId) return 'messageId required.';
|
|
938
|
+
const { markRead: imapMarkRead2 } = await import('./email-db.mjs');
|
|
939
|
+
imapMarkRead2(params.messageId, params.isRead !== false);
|
|
940
|
+
return `Message marked as ${params.isRead !== false ? 'read' : 'unread'}.`;
|
|
941
|
+
}
|
|
942
|
+
|
|
849
943
|
// ── Calendar ──────────────────────────────────────────────────────────
|
|
850
944
|
case 'calendar_today': {
|
|
851
945
|
const events = await getTodayEvents(config);
|