@plosson/agentio 0.1.14 → 0.1.16
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 +3 -2
- package/src/commands/gmail.ts +70 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plosson/agentio",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "CLI for LLM agents to interact with communication and tracking services",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"commander": "^14.0.2",
|
|
50
|
-
"googleapis": "^169.0.0"
|
|
50
|
+
"googleapis": "^169.0.0",
|
|
51
|
+
"playwright-core": "^1.57.0"
|
|
51
52
|
}
|
|
52
53
|
}
|
package/src/commands/gmail.ts
CHANGED
|
@@ -11,6 +11,14 @@ import { CliError, handleError } from '../utils/errors';
|
|
|
11
11
|
import { readStdin, resolveProfileName } from '../utils/stdin';
|
|
12
12
|
import type { GmailAttachment } from '../types/gmail';
|
|
13
13
|
|
|
14
|
+
function escapeHtml(text: string): string {
|
|
15
|
+
return text
|
|
16
|
+
.replace(/&/g, '&')
|
|
17
|
+
.replace(/</g, '<')
|
|
18
|
+
.replace(/>/g, '>')
|
|
19
|
+
.replace(/"/g, '"');
|
|
20
|
+
}
|
|
21
|
+
|
|
14
22
|
async function getGmailClient(profileName?: string): Promise<{ client: GmailClient; profile: string }> {
|
|
15
23
|
const { tokens, profile } = await getValidTokens('gmail', profileName);
|
|
16
24
|
const auth = createGoogleAuth(tokens);
|
|
@@ -277,6 +285,68 @@ Query Syntax Examples:
|
|
|
277
285
|
}
|
|
278
286
|
});
|
|
279
287
|
|
|
288
|
+
gmail
|
|
289
|
+
.command('export <message-id>')
|
|
290
|
+
.description('Export a message as PDF')
|
|
291
|
+
.option('--profile <name>', 'Profile name')
|
|
292
|
+
.option('--output <path>', 'Output file path', 'message.pdf')
|
|
293
|
+
.action(async (messageId: string, options) => {
|
|
294
|
+
try {
|
|
295
|
+
const { client } = await getGmailClient(options.profile);
|
|
296
|
+
const message = await client.get(messageId, 'html');
|
|
297
|
+
|
|
298
|
+
// Build HTML document - inject header before body content
|
|
299
|
+
const emailHeader = `
|
|
300
|
+
<div style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; padding: 16px 20px; margin-bottom: 16px; border-bottom: 1px solid #ddd; background: #f9f9f9;">
|
|
301
|
+
<div style="font-size: 1.3em; font-weight: 600; margin-bottom: 12px;">${escapeHtml(message.subject)}</div>
|
|
302
|
+
<div style="margin: 4px 0; font-size: 0.9em;"><strong>From:</strong> ${escapeHtml(message.from)}</div>
|
|
303
|
+
<div style="margin: 4px 0; font-size: 0.9em;"><strong>To:</strong> ${escapeHtml(message.to.join(', '))}</div>
|
|
304
|
+
<div style="margin: 4px 0; font-size: 0.9em;"><strong>Date:</strong> ${escapeHtml(message.date)}</div>
|
|
305
|
+
</div>`;
|
|
306
|
+
|
|
307
|
+
let html: string;
|
|
308
|
+
const body = message.body || '';
|
|
309
|
+
|
|
310
|
+
// Check if body is already a full HTML document
|
|
311
|
+
if (body.trim().toLowerCase().startsWith('<!doctype') || body.trim().toLowerCase().startsWith('<html')) {
|
|
312
|
+
// Inject header after <body> tag
|
|
313
|
+
html = body.replace(/<body[^>]*>/i, (match) => `${match}${emailHeader}`);
|
|
314
|
+
} else {
|
|
315
|
+
// Wrap fragment in minimal HTML
|
|
316
|
+
html = `<!DOCTYPE html>
|
|
317
|
+
<html>
|
|
318
|
+
<head><meta charset="utf-8"></head>
|
|
319
|
+
<body>
|
|
320
|
+
${emailHeader}
|
|
321
|
+
<div style="padding: 0 20px;">${body}</div>
|
|
322
|
+
</body>
|
|
323
|
+
</html>`;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Lazy load playwright-core to avoid bundling issues
|
|
327
|
+
const { chromium } = await import('playwright-core');
|
|
328
|
+
|
|
329
|
+
// Launch browser and generate PDF
|
|
330
|
+
console.error('Launching browser...');
|
|
331
|
+
const browser = await chromium.launch({
|
|
332
|
+
channel: 'chrome', // Use system Chrome
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
const page = await browser.newPage();
|
|
336
|
+
await page.setContent(html, { waitUntil: 'networkidle' });
|
|
337
|
+
await page.pdf({
|
|
338
|
+
path: options.output,
|
|
339
|
+
format: 'A4',
|
|
340
|
+
margin: { top: '1cm', right: '1cm', bottom: '1cm', left: '1cm' },
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
await browser.close();
|
|
344
|
+
console.log(`Exported to ${options.output}`);
|
|
345
|
+
} catch (error) {
|
|
346
|
+
handleError(error);
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
|
|
280
350
|
// Profile management
|
|
281
351
|
const profile = gmail
|
|
282
352
|
.command('profile')
|