zele 0.3.20 → 0.4.0
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/README.md +26 -20
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +40 -14
- package/dist/cli.js.map +1 -1
- package/dist/commands/auth-cmd.js +58 -52
- package/dist/commands/auth-cmd.js.map +1 -1
- package/dist/commands/calendar.js +13 -14
- package/dist/commands/calendar.js.map +1 -1
- package/dist/commands/draft.js +11 -12
- package/dist/commands/draft.js.map +1 -1
- package/dist/commands/label.js +5 -6
- package/dist/commands/label.js.map +1 -1
- package/dist/commands/mail.js +10 -10
- package/dist/commands/mail.js.map +1 -1
- package/dist/commands/watch.js +2 -2
- package/dist/commands/watch.js.map +1 -1
- package/dist/output.js +0 -1
- package/dist/output.js.map +1 -1
- package/package.json +4 -3
- package/skills/zele/SKILL.md +8 -1
- package/src/cli.ts +42 -16
- package/src/commands/auth-cmd.ts +64 -54
- package/src/commands/calendar.ts +13 -14
- package/src/commands/draft.ts +11 -12
- package/src/commands/label.ts +5 -6
- package/src/commands/mail.ts +10 -10
- package/src/commands/watch.ts +2 -2
- package/src/output.ts +0 -1
package/src/commands/auth-cmd.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import type { ZeleCli } from '../cli-types.js'
|
|
6
6
|
import { z } from 'zod'
|
|
7
7
|
import pc from 'picocolors'
|
|
8
|
+
import * as clack from '@clack/prompts'
|
|
8
9
|
import { login, loginImap, logout, listAccounts, getAuthStatuses } from '../auth.js'
|
|
9
10
|
import { closePrisma } from '../db.js'
|
|
10
11
|
import * as out from '../output.js'
|
|
@@ -13,60 +14,71 @@ import { handleCommandError } from '../output.js'
|
|
|
13
14
|
export function registerAuthCommands(cli: ZeleCli) {
|
|
14
15
|
cli
|
|
15
16
|
.command('login', 'Authenticate with Google (opens browser) or show IMAP/SMTP login instructions')
|
|
16
|
-
.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
.option(
|
|
18
|
+
'--method <method>',
|
|
19
|
+
z.enum(['google', 'imap']).optional().describe('Authentication method (google or imap)'),
|
|
20
|
+
)
|
|
21
|
+
.action(async (options) => {
|
|
22
|
+
let method = options.method
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
if (!method) {
|
|
25
|
+
if (!process.stdin.isTTY) {
|
|
26
|
+
out.error('Run non-interactively with: zele login --method google|imap')
|
|
27
|
+
process.exit(1)
|
|
28
|
+
}
|
|
25
29
|
|
|
26
|
-
const
|
|
27
|
-
|
|
30
|
+
const choice = await clack.select({
|
|
31
|
+
message: 'Choose authentication method',
|
|
32
|
+
options: [
|
|
33
|
+
{ value: 'google', label: 'Google', hint: 'opens browser for OAuth' },
|
|
34
|
+
{ value: 'imap', label: 'Other', hint: 'IMAP/SMTP with password' },
|
|
35
|
+
],
|
|
28
36
|
})
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (choice === '2') {
|
|
34
|
-
console.error(pc.bold('\nTo add an IMAP/SMTP account, run:\n'))
|
|
35
|
-
console.error(pc.dim(' # Fastmail'))
|
|
36
|
-
console.error(` zele login imap \\`)
|
|
37
|
-
console.error(` --email you@fastmail.com \\`)
|
|
38
|
-
console.error(` --imap-host imap.fastmail.com --imap-port 993 \\`)
|
|
39
|
-
console.error(` --smtp-host smtp.fastmail.com --smtp-port 465 \\`)
|
|
40
|
-
console.error(` --password "your-app-password"`)
|
|
41
|
-
console.error()
|
|
42
|
-
console.error(pc.dim(' # Gmail (app password)'))
|
|
43
|
-
console.error(` zele login imap \\`)
|
|
44
|
-
console.error(` --email you@gmail.com \\`)
|
|
45
|
-
console.error(` --imap-host imap.gmail.com --imap-port 993 \\`)
|
|
46
|
-
console.error(` --smtp-host smtp.gmail.com --smtp-port 465 \\`)
|
|
47
|
-
console.error(` --password "your-app-password"`)
|
|
48
|
-
console.error()
|
|
49
|
-
console.error(pc.dim(' # Outlook/Hotmail'))
|
|
50
|
-
console.error(` zele login imap \\`)
|
|
51
|
-
console.error(` --email you@outlook.com \\`)
|
|
52
|
-
console.error(` --imap-host outlook.office365.com --imap-port 993 \\`)
|
|
53
|
-
console.error(` --smtp-host smtp-mail.outlook.com --smtp-port 587 \\`)
|
|
54
|
-
console.error(` --password "your-password"`)
|
|
55
|
-
console.error()
|
|
56
|
-
console.error(pc.dim(' # Generic (any IMAP/SMTP provider)'))
|
|
57
|
-
console.error(` zele login imap \\`)
|
|
58
|
-
console.error(` --email you@example.com \\`)
|
|
59
|
-
console.error(` --imap-host imap.example.com --imap-port 993 \\`)
|
|
60
|
-
console.error(` --smtp-host smtp.example.com --smtp-port 465 \\`)
|
|
61
|
-
console.error(` --password "your-password"`)
|
|
62
|
-
console.error()
|
|
63
|
-
console.error(pc.dim('Omit --smtp-host for read-only (IMAP only, no sending).'))
|
|
64
|
-
console.error(pc.dim('Use --imap-user/--smtp-user if the login username differs from your email.'))
|
|
65
|
-
return
|
|
37
|
+
|
|
38
|
+
if (clack.isCancel(choice)) {
|
|
39
|
+
out.hint('Cancelled')
|
|
40
|
+
process.exit(0)
|
|
66
41
|
}
|
|
42
|
+
|
|
43
|
+
method = choice
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (method === 'imap') {
|
|
47
|
+
console.error(pc.bold('\nTo add an IMAP/SMTP account, run:\n'))
|
|
48
|
+
console.error(pc.dim(' # Fastmail'))
|
|
49
|
+
console.error(` zele login imap \\`)
|
|
50
|
+
console.error(` --email you@fastmail.com \\`)
|
|
51
|
+
console.error(` --imap-host imap.fastmail.com --imap-port 993 \\`)
|
|
52
|
+
console.error(` --smtp-host smtp.fastmail.com --smtp-port 465 \\`)
|
|
53
|
+
console.error(` --password "your-app-password"`)
|
|
54
|
+
console.error()
|
|
55
|
+
console.error(pc.dim(' # Gmail (app password)'))
|
|
56
|
+
console.error(` zele login imap \\`)
|
|
57
|
+
console.error(` --email you@gmail.com \\`)
|
|
58
|
+
console.error(` --imap-host imap.gmail.com --imap-port 993 \\`)
|
|
59
|
+
console.error(` --smtp-host smtp.gmail.com --smtp-port 465 \\`)
|
|
60
|
+
console.error(` --password "your-app-password"`)
|
|
61
|
+
console.error()
|
|
62
|
+
console.error(pc.dim(' # Outlook/Hotmail'))
|
|
63
|
+
console.error(` zele login imap \\`)
|
|
64
|
+
console.error(` --email you@outlook.com \\`)
|
|
65
|
+
console.error(` --imap-host outlook.office365.com --imap-port 993 \\`)
|
|
66
|
+
console.error(` --smtp-host smtp-mail.outlook.com --smtp-port 587 \\`)
|
|
67
|
+
console.error(` --password "your-password"`)
|
|
68
|
+
console.error()
|
|
69
|
+
console.error(pc.dim(' # Generic (any IMAP/SMTP provider)'))
|
|
70
|
+
console.error(` zele login imap \\`)
|
|
71
|
+
console.error(` --email you@example.com \\`)
|
|
72
|
+
console.error(` --imap-host imap.example.com --imap-port 993 \\`)
|
|
73
|
+
console.error(` --smtp-host smtp.example.com --smtp-port 465 \\`)
|
|
74
|
+
console.error(` --password "your-password"`)
|
|
75
|
+
console.error()
|
|
76
|
+
console.error(pc.dim('Omit --smtp-host for read-only (IMAP only, no sending).'))
|
|
77
|
+
console.error(pc.dim('Use --imap-user/--smtp-user if the login username differs from your email.'))
|
|
78
|
+
return
|
|
67
79
|
}
|
|
68
80
|
|
|
69
|
-
//
|
|
81
|
+
// Google OAuth flow
|
|
70
82
|
const result = await login()
|
|
71
83
|
if (result instanceof Error) handleCommandError(result)
|
|
72
84
|
const { email } = result
|
|
@@ -162,14 +174,12 @@ export function registerAuthCommands(cli: ZeleCli) {
|
|
|
162
174
|
process.exit(1)
|
|
163
175
|
}
|
|
164
176
|
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
rl.question(`Remove credentials for ${targetEmail}? [y/N] `, resolve)
|
|
177
|
+
const confirmed = await clack.confirm({
|
|
178
|
+
message: `Remove credentials for ${targetEmail}?`,
|
|
179
|
+
initialValue: false,
|
|
169
180
|
})
|
|
170
|
-
rl.close()
|
|
171
181
|
|
|
172
|
-
if (
|
|
182
|
+
if (clack.isCancel(confirmed) || !confirmed) {
|
|
173
183
|
out.hint('Cancelled')
|
|
174
184
|
return
|
|
175
185
|
}
|
package/src/commands/calendar.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { ZeleCli } from '../cli-types.js'
|
|
7
7
|
import { z } from 'zod'
|
|
8
|
-
import
|
|
8
|
+
import * as clack from '@clack/prompts'
|
|
9
9
|
import { getCalendarClients, getCalendarClient } from '../auth.js'
|
|
10
10
|
import type { CalendarClient, CalendarEvent, CalendarListItem, EventListResult } from '../calendar-client.js'
|
|
11
11
|
import { AuthError } from '../api-utils.js'
|
|
@@ -76,11 +76,11 @@ export function registerCalendarCommands(cli: ZeleCli) {
|
|
|
76
76
|
.option('--week', 'Show this week')
|
|
77
77
|
.option('--days <days>', z.number().describe('Show next N days'))
|
|
78
78
|
.option('--all', 'Fetch from all calendars')
|
|
79
|
-
.option('--
|
|
80
|
-
.option('--
|
|
79
|
+
.option('--filter <filter>', 'Free text search')
|
|
80
|
+
.option('--limit [limit]', 'Max results (default: 20)')
|
|
81
81
|
.option('--page <page>', 'Pagination token (requires --account, only works for a single account)')
|
|
82
82
|
.action(async (options) => {
|
|
83
|
-
const
|
|
83
|
+
const limit = options.limit ? Number(options.limit) : 20
|
|
84
84
|
const calendarId = options.calendar ?? 'primary'
|
|
85
85
|
|
|
86
86
|
if (options.all && options.calendar) {
|
|
@@ -122,8 +122,8 @@ export function registerCalendarCommands(cli: ZeleCli) {
|
|
|
122
122
|
calendarId: cal.id,
|
|
123
123
|
timeMin,
|
|
124
124
|
timeMax,
|
|
125
|
-
query: options.
|
|
126
|
-
maxResults:
|
|
125
|
+
query: options.filter,
|
|
126
|
+
maxResults: limit,
|
|
127
127
|
})
|
|
128
128
|
if (r instanceof Error) return r
|
|
129
129
|
return r.events.map((e) => ({ ...e, calendarId: cal.id }))
|
|
@@ -145,8 +145,8 @@ export function registerCalendarCommands(cli: ZeleCli) {
|
|
|
145
145
|
calendarId,
|
|
146
146
|
timeMin,
|
|
147
147
|
timeMax,
|
|
148
|
-
query: options.
|
|
149
|
-
maxResults:
|
|
148
|
+
query: options.filter,
|
|
149
|
+
maxResults: limit,
|
|
150
150
|
pageToken: options.page,
|
|
151
151
|
})
|
|
152
152
|
if (r instanceof Error) return r
|
|
@@ -171,7 +171,7 @@ export function registerCalendarCommands(cli: ZeleCli) {
|
|
|
171
171
|
result.events.map((e) => ({ ...e, account: email })),
|
|
172
172
|
)
|
|
173
173
|
.sort((a, b) => new Date(a.start).getTime() - new Date(b.start).getTime())
|
|
174
|
-
.slice(0,
|
|
174
|
+
.slice(0, limit)
|
|
175
175
|
|
|
176
176
|
if (merged.length === 0) {
|
|
177
177
|
out.printList([], { summary: 'No events found' })
|
|
@@ -418,13 +418,12 @@ export function registerCalendarCommands(cli: ZeleCli) {
|
|
|
418
418
|
const { client } = await getCalendarClient(options.account)
|
|
419
419
|
|
|
420
420
|
if (!options.force && process.stdin.isTTY) {
|
|
421
|
-
const
|
|
422
|
-
|
|
423
|
-
|
|
421
|
+
const confirmed = await clack.confirm({
|
|
422
|
+
message: `Delete event ${eventId}?`,
|
|
423
|
+
initialValue: false,
|
|
424
424
|
})
|
|
425
|
-
rl.close()
|
|
426
425
|
|
|
427
|
-
if (
|
|
426
|
+
if (clack.isCancel(confirmed) || !confirmed) {
|
|
428
427
|
out.hint('Cancelled')
|
|
429
428
|
return
|
|
430
429
|
}
|
package/src/commands/draft.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import type { ZeleCli } from '../cli-types.js'
|
|
7
7
|
import { z } from 'zod'
|
|
8
8
|
import fs from 'node:fs'
|
|
9
|
+
import * as clack from '@clack/prompts'
|
|
9
10
|
import { getClients, getClient } from '../auth.js'
|
|
10
11
|
import type { GmailClient } from '../gmail-client.js'
|
|
11
12
|
import type { ImapSmtpClient } from '../imap-smtp-client.js'
|
|
@@ -21,9 +22,9 @@ export function registerDraftCommands(cli: ZeleCli) {
|
|
|
21
22
|
|
|
22
23
|
cli
|
|
23
24
|
.command('draft list', 'List drafts')
|
|
24
|
-
.option('--
|
|
25
|
+
.option('--limit <limit>', z.number().default(20).describe('Max results'))
|
|
25
26
|
.option('--page <page>', z.string().describe('Pagination token (requires --account, only works for a single account)'))
|
|
26
|
-
.option('--
|
|
27
|
+
.option('--filter <filter>', z.string().describe('Search query'))
|
|
27
28
|
.action(async (options) => {
|
|
28
29
|
const clients = await getClients(options.account)
|
|
29
30
|
|
|
@@ -36,8 +37,8 @@ export function registerDraftCommands(cli: ZeleCli) {
|
|
|
36
37
|
const results = await Promise.all(
|
|
37
38
|
clients.map(async ({ email, client }) => {
|
|
38
39
|
const result = await client.listDrafts({
|
|
39
|
-
query: options.
|
|
40
|
-
maxResults: options.
|
|
40
|
+
query: options.filter,
|
|
41
|
+
maxResults: options.limit,
|
|
41
42
|
pageToken: options.page,
|
|
42
43
|
})
|
|
43
44
|
if (result instanceof Error) return result
|
|
@@ -51,13 +52,13 @@ export function registerDraftCommands(cli: ZeleCli) {
|
|
|
51
52
|
return true
|
|
52
53
|
})
|
|
53
54
|
|
|
54
|
-
// Merge drafts from all accounts, sorted by date descending, capped at
|
|
55
|
+
// Merge drafts from all accounts, sorted by date descending, capped at limit
|
|
55
56
|
const merged = allResults
|
|
56
57
|
.flatMap(({ email, result }) =>
|
|
57
58
|
result.drafts.map((d) => ({ ...d, account: email })),
|
|
58
59
|
)
|
|
59
60
|
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
|
60
|
-
.slice(0, options.
|
|
61
|
+
.slice(0, options.limit)
|
|
61
62
|
|
|
62
63
|
if (merged.length === 0) {
|
|
63
64
|
out.printList([], { summary: 'No drafts found' })
|
|
@@ -240,14 +241,12 @@ export function registerDraftCommands(cli: ZeleCli) {
|
|
|
240
241
|
.option('--force', 'Skip confirmation')
|
|
241
242
|
.action(async (draftId, options) => {
|
|
242
243
|
if (!options.force && process.stdin.isTTY) {
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
rl.question(`Delete draft ${draftId}? [y/N] `, resolve)
|
|
244
|
+
const confirmed = await clack.confirm({
|
|
245
|
+
message: `Delete draft ${draftId}?`,
|
|
246
|
+
initialValue: false,
|
|
247
247
|
})
|
|
248
|
-
rl.close()
|
|
249
248
|
|
|
250
|
-
if (
|
|
249
|
+
if (clack.isCancel(confirmed) || !confirmed) {
|
|
251
250
|
out.hint('Cancelled')
|
|
252
251
|
return
|
|
253
252
|
}
|
package/src/commands/label.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { ZeleCli } from '../cli-types.js'
|
|
7
7
|
import { z } from 'zod'
|
|
8
|
+
import * as clack from '@clack/prompts'
|
|
8
9
|
import { getClients, getGmailClient } from '../auth.js'
|
|
9
10
|
import { AuthError, UnsupportedError } from '../api-utils.js'
|
|
10
11
|
import type { GmailClient } from '../gmail-client.js'
|
|
@@ -122,14 +123,12 @@ export function registerLabelCommands(cli: ZeleCli) {
|
|
|
122
123
|
.option('--force', 'Skip confirmation')
|
|
123
124
|
.action(async (labelId, options) => {
|
|
124
125
|
if (!options.force && process.stdin.isTTY) {
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
rl.question(`Delete label ${labelId}? [y/N] `, resolve)
|
|
126
|
+
const confirmed = await clack.confirm({
|
|
127
|
+
message: `Delete label ${labelId}?`,
|
|
128
|
+
initialValue: false,
|
|
129
129
|
})
|
|
130
|
-
rl.close()
|
|
131
130
|
|
|
132
|
-
if (
|
|
131
|
+
if (clack.isCancel(confirmed) || !confirmed) {
|
|
133
132
|
out.hint('Cancelled')
|
|
134
133
|
return
|
|
135
134
|
}
|
package/src/commands/mail.ts
CHANGED
|
@@ -52,15 +52,15 @@ export function registerMailCommands(cli: ZeleCli) {
|
|
|
52
52
|
cli
|
|
53
53
|
.command('mail list', 'List email threads')
|
|
54
54
|
.option('--folder [folder]', 'Folder to list (inbox, sent, trash, spam, starred, drafts, archive, all) (default: inbox)')
|
|
55
|
-
.option('--
|
|
55
|
+
.option('--limit [limit]', 'Max threads to show (default: 20)')
|
|
56
56
|
.option('--page <page>', 'Pagination token (requires --account, only works for a single account)')
|
|
57
57
|
.option('--label <label>', 'Filter by label name')
|
|
58
58
|
.option('--filter <filter>', 'Gmail search filter (e.g. "is:unread", "from:github", "has:attachment")')
|
|
59
59
|
.action(async (options) => {
|
|
60
|
-
// `options.folder` / `options.
|
|
60
|
+
// `options.folder` / `options.limit` are `string | undefined` now.
|
|
61
61
|
// `''` (bare flag) falls back to the default via `||`.
|
|
62
62
|
const folder = options.folder || 'inbox'
|
|
63
|
-
const
|
|
63
|
+
const limit = options.limit ? Number(options.limit) : 20
|
|
64
64
|
const clients = await getClients(options.account)
|
|
65
65
|
|
|
66
66
|
if (options.page && clients.length > 1) {
|
|
@@ -73,7 +73,7 @@ export function registerMailCommands(cli: ZeleCli) {
|
|
|
73
73
|
clients.map(async ({ email, client, accountType }) => {
|
|
74
74
|
const result = await client.listThreads({
|
|
75
75
|
folder,
|
|
76
|
-
maxResults:
|
|
76
|
+
maxResults: limit,
|
|
77
77
|
labelIds: options.label ? [options.label] : undefined,
|
|
78
78
|
pageToken: options.page,
|
|
79
79
|
query: options.filter,
|
|
@@ -102,13 +102,13 @@ export function registerMailCommands(cli: ZeleCli) {
|
|
|
102
102
|
const labelMap = new Map<string, string>()
|
|
103
103
|
for (const r of allResults) for (const [id, name] of r.labelMap) labelMap.set(id, name)
|
|
104
104
|
|
|
105
|
-
// Merge threads from all accounts, sorted by date descending, capped at
|
|
105
|
+
// Merge threads from all accounts, sorted by date descending, capped at limit
|
|
106
106
|
const merged = allResults
|
|
107
107
|
.flatMap(({ email, result }) =>
|
|
108
108
|
result.threads.map((t) => ({ ...t, account: email })),
|
|
109
109
|
)
|
|
110
110
|
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
|
111
|
-
.slice(0,
|
|
111
|
+
.slice(0, limit)
|
|
112
112
|
|
|
113
113
|
if (merged.length === 0) {
|
|
114
114
|
out.printList([], { summary: 'No threads found' })
|
|
@@ -150,10 +150,10 @@ export function registerMailCommands(cli: ZeleCli) {
|
|
|
150
150
|
|
|
151
151
|
cli
|
|
152
152
|
.command('mail search <query>', 'Search email threads using Gmail query syntax (from:, to:, subject:, has:attachment, etc). See https://support.google.com/mail/answer/7190')
|
|
153
|
-
.option('--
|
|
153
|
+
.option('--limit [limit]', 'Max results to show (default: 20)')
|
|
154
154
|
.option('--page <page>', 'Pagination token (requires --account, only works for a single account)')
|
|
155
155
|
.action(async (query, options) => {
|
|
156
|
-
const
|
|
156
|
+
const limit = options.limit ? Number(options.limit) : 20
|
|
157
157
|
const clients = await getClients(options.account)
|
|
158
158
|
|
|
159
159
|
if (options.page && clients.length > 1) {
|
|
@@ -166,7 +166,7 @@ export function registerMailCommands(cli: ZeleCli) {
|
|
|
166
166
|
clients.map(async ({ email, client, accountType }) => {
|
|
167
167
|
const result = await client.listThreads({
|
|
168
168
|
query,
|
|
169
|
-
maxResults:
|
|
169
|
+
maxResults: limit,
|
|
170
170
|
pageToken: options.page,
|
|
171
171
|
})
|
|
172
172
|
if (result instanceof Error) return result
|
|
@@ -197,7 +197,7 @@ export function registerMailCommands(cli: ZeleCli) {
|
|
|
197
197
|
result.threads.map((t) => ({ ...t, account: email })),
|
|
198
198
|
)
|
|
199
199
|
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
|
200
|
-
.slice(0,
|
|
200
|
+
.slice(0, limit)
|
|
201
201
|
|
|
202
202
|
if (merged.length === 0) {
|
|
203
203
|
out.printList([], { summary: `No results for "${query}"` })
|
package/src/commands/watch.ts
CHANGED
|
@@ -18,7 +18,7 @@ export function registerWatchCommands(cli: ZeleCli) {
|
|
|
18
18
|
.command('mail watch', 'Watch for new emails (poll via History API)')
|
|
19
19
|
.option('--interval [interval]', z.string().describe('Poll interval in seconds (default: 15)'))
|
|
20
20
|
.option('--folder [folder]', z.string().describe('Folder to watch (default: inbox)'))
|
|
21
|
-
.option('--
|
|
21
|
+
.option('--filter [filter]', z.string().describe('Filter messages client-side (from:, to:, cc:, subject:, is:unread, is:starred, has:attachment, -negate). See https://support.google.com/mail/answer/7190'))
|
|
22
22
|
.option('--once', z.boolean().describe('Print changes once and exit (no loop)'))
|
|
23
23
|
.action(async (options) => {
|
|
24
24
|
const interval = options.interval ? Number(options.interval) : 15
|
|
@@ -43,7 +43,7 @@ export function registerWatchCommands(cli: ZeleCli) {
|
|
|
43
43
|
client.watchInbox({
|
|
44
44
|
folder,
|
|
45
45
|
intervalMs: interval * 1000,
|
|
46
|
-
query: options.
|
|
46
|
+
query: options.filter,
|
|
47
47
|
once: options.once,
|
|
48
48
|
}),
|
|
49
49
|
)
|
package/src/output.ts
CHANGED
|
@@ -140,7 +140,6 @@ turndown.addRule('hidden-elements', {
|
|
|
140
140
|
export function htmlToMarkdown(html: string): string {
|
|
141
141
|
// Pre-clean: remove common email noise
|
|
142
142
|
const cleaned = html
|
|
143
|
-
.replace(/<!\-\-[\s\S]*?\-\->/g, '') // HTML comments
|
|
144
143
|
.replace(/<o:p>[\s\S]*?<\/o:p>/gi, '') // Outlook tags
|
|
145
144
|
.replace(/<!\[if[\s\S]*?<!\[endif\]>/gi, '') // Outlook conditional comments
|
|
146
145
|
|