This commit is contained in:
2026-02-27 08:27:43 +00:00
parent 7bf55af5b3
commit bc4c20929c
48 changed files with 4344 additions and 275 deletions
+30 -17
View File
@@ -15,6 +15,7 @@ type Params = {
before?: string;
after?: string;
content_type?: string;
folder?: string;
limit?: number;
};
@@ -72,9 +73,18 @@ function formatRows(rows: Record<string, unknown>[], limit: number): string {
// ── Helpers ──
function buildWhereClause(params: Params): string {
function buildFolderCondition(folder: string | undefined): string | null {
if (!folder || folder === 'all') return null;
return `labels LIKE ${sqlStr(`%${folder}%`)}`;
}
function buildWhereClause(params: Params, defaultFolder?: string): string {
const conditions: string[] = [];
const folder = params.folder ?? defaultFolder;
const folderCond = buildFolderCondition(folder);
if (folderCond) conditions.push(folderCond);
if (params.domain) {
conditions.push(`from_domain = ${sqlStr(params.domain.toLowerCase())}`);
}
@@ -111,20 +121,21 @@ function runQuery(sql: string, limit: number): string {
}
function searchEmails(params: Params, limit: number): string {
const where = withActive(buildWhereClause(params));
const where = withActive(buildWhereClause(params, 'inbox'));
const rows = queryJson(`SELECT id, from_name, from_address, subject, date, snippet, attachment_count FROM emails ${where} ORDER BY date DESC LIMIT ${limit}`);
return formatRows(rows, limit);
}
function getStats(): string {
const totalRows = queryJson('SELECT COUNT(*) as count FROM emails WHERE deleted = 0');
function getStats(params: Params): string {
const folderWhere = withActive(buildWhereClause({ action: 'stats', folder: params.folder }, 'inbox'));
const totalRows = queryJson(`SELECT COUNT(*) as count FROM emails ${folderWhere}`);
const total = (totalRows[0]?.count as number) ?? 0;
if (total === 0) return 'Email database is empty.';
const dateRange = queryJson('SELECT MIN(date) as oldest, MAX(date) as newest FROM emails WHERE deleted = 0');
const topDomains = queryJson('SELECT from_domain, COUNT(*) as count FROM emails WHERE deleted = 0 GROUP BY from_domain ORDER BY count DESC LIMIT 10');
const topSenders = queryJson('SELECT from_address, from_name, COUNT(*) as count FROM emails WHERE deleted = 0 GROUP BY from_address ORDER BY count DESC LIMIT 10');
const attRows = queryJson('SELECT COUNT(*) as count FROM emails WHERE deleted = 0 AND attachment_count > 0');
const dateRange = queryJson(`SELECT MIN(date) as oldest, MAX(date) as newest FROM emails ${folderWhere}`);
const topDomains = queryJson(`SELECT from_domain, COUNT(*) as count FROM emails ${folderWhere} GROUP BY from_domain ORDER BY count DESC LIMIT 10`);
const topSenders = queryJson(`SELECT from_address, from_name, COUNT(*) as count FROM emails ${folderWhere} GROUP BY from_address ORDER BY count DESC LIMIT 10`);
const attRows = queryJson(`SELECT COUNT(*) as count FROM emails ${folderWhere} AND attachment_count > 0`);
const withAttachments = (attRows[0]?.count as number) ?? 0;
const dr = dateRange[0] ?? {};
@@ -146,7 +157,7 @@ function getStats(): string {
}
function countEmails(params: Params): string {
const where = withActive(buildWhereClause(params));
const where = withActive(buildWhereClause(params, 'inbox'));
const rows = queryJson(`SELECT COUNT(*) as count FROM emails ${where}`);
const count = (rows[0]?.count as number) ?? 0;
@@ -161,16 +172,18 @@ function countEmails(params: Params): string {
return `${count} email${count !== 1 ? 's' : ''}${desc}.`;
}
function listDomains(limit: number): string {
const rows = queryJson(`SELECT from_domain, COUNT(*) as count FROM emails WHERE deleted = 0 GROUP BY from_domain ORDER BY count DESC LIMIT ${limit}`);
function listDomains(params: Params, limit: number): string {
const where = withActive(buildWhereClause({ action: 'domains', folder: params.folder }, 'inbox'));
const rows = queryJson(`SELECT from_domain, COUNT(*) as count FROM emails ${where} GROUP BY from_domain ORDER BY count DESC LIMIT ${limit}`);
if (rows.length === 0) return 'No emails in database.';
const lines = rows.map((d, i) => `${i + 1}. ${d.from_domain}${d.count} email${(d.count as number) !== 1 ? 's' : ''}`);
return [`**Sender Domains** (${rows.length}):`, '', ...lines].join('\n');
}
function listSenders(limit: number): string {
const rows = queryJson(`SELECT from_address, from_name, COUNT(*) as count FROM emails WHERE deleted = 0 GROUP BY from_address ORDER BY count DESC LIMIT ${limit}`);
function listSenders(params: Params, limit: number): string {
const where = withActive(buildWhereClause({ action: 'senders', folder: params.folder }, 'inbox'));
const rows = queryJson(`SELECT from_address, from_name, COUNT(*) as count FROM emails ${where} GROUP BY from_address ORDER BY count DESC LIMIT ${limit}`);
if (rows.length === 0) return 'No emails in database.';
const lines = rows.map((s, i) => {
@@ -217,7 +230,7 @@ function searchAttachments(params: Params, limit: number): string {
}
function deleteEmails(params: Params): string {
const where = buildWhereClause(params);
const where = buildWhereClause(params, 'inbox');
if (!where) {
throw new Error('Delete requires at least one filter (domain, sender, before, after, or search).');
}
@@ -254,16 +267,16 @@ export async function execute(_toolCallId: string, params: Params): Promise<Tool
return ok(searchEmails(params, limit));
case 'stats':
return ok(getStats());
return ok(getStats(params));
case 'count':
return ok(countEmails(params));
case 'domains':
return ok(listDomains(limit));
return ok(listDomains(params, limit));
case 'senders':
return ok(listSenders(limit));
return ok(listSenders(params, limit));
case 'attachment-types':
return ok(listAttachmentTypes(limit));