@cli4ai/gmail 1.0.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 +214 -0
- package/c4ai.json +46 -0
- package/package.json +42 -0
- package/run.ts +316 -0
package/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Gmail
|
|
2
|
+
|
|
3
|
+
Full-featured Gmail CLI via Google API. Fast, powerful search, send/reply/forward.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
### Reading
|
|
8
|
+
```bash
|
|
9
|
+
./run.js inbox [limit] # Recent inbox messages (default: 20)
|
|
10
|
+
./run.js unread [limit] # Unread messages only
|
|
11
|
+
./run.js search <query> [limit] # Search with Gmail syntax
|
|
12
|
+
./run.js read <id> # Read full message
|
|
13
|
+
./run.js thread <id> # Full conversation thread
|
|
14
|
+
./run.js threads [limit] [query] # List recent threads
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Actions
|
|
18
|
+
```bash
|
|
19
|
+
./run.js archive <id> # Archive (remove from inbox)
|
|
20
|
+
./run.js trash <id> # Move to trash
|
|
21
|
+
./run.js untrash <id> # Restore from trash
|
|
22
|
+
./run.js star <id> # Star message
|
|
23
|
+
./run.js unstar <id> # Unstar message
|
|
24
|
+
./run.js markread <id> # Mark as read
|
|
25
|
+
./run.js markunread <id> # Mark as unread
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Sending
|
|
29
|
+
```bash
|
|
30
|
+
./run.js send <to> <subject> <body> # Send new email
|
|
31
|
+
./run.js reply <id> <body> # Reply to message
|
|
32
|
+
./run.js replyall <id> <body> # Reply to all
|
|
33
|
+
./run.js forward <id> <to> [body] # Forward message
|
|
34
|
+
./run.js draft <to> <subject> <body> # Create draft (legacy)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Drafts
|
|
38
|
+
```bash
|
|
39
|
+
./run.js drafts # List all drafts
|
|
40
|
+
./run.js draft-get <id> # Get draft content
|
|
41
|
+
./run.js draft-create <to> <subj> <body> # Create new draft
|
|
42
|
+
./run.js draft-reply <msg-id> <body> # Create draft reply to message
|
|
43
|
+
./run.js draft-update <id> <to> <s> <b> # Update existing draft
|
|
44
|
+
./run.js draft-delete <id> # Delete draft
|
|
45
|
+
./run.js draft-send <id> # Send draft
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Attachments
|
|
49
|
+
```bash
|
|
50
|
+
./run.js attachments <id> # List attachments in message
|
|
51
|
+
./run.js download <id> [filename] [out] # Download specific attachment
|
|
52
|
+
./run.js download-all <id> [dir] # Download all attachments
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Labels
|
|
56
|
+
```bash
|
|
57
|
+
./run.js labels # List all labels
|
|
58
|
+
./run.js label <id> <label> # Add label to message
|
|
59
|
+
./run.js unlabel <id> <label> # Remove label
|
|
60
|
+
./run.js label-info <label> # Get label with counts
|
|
61
|
+
./run.js label-create <name> # Create new label
|
|
62
|
+
./run.js label-delete <name> # Delete label
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Output Flags
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
--raw, -r # Full JSON output
|
|
69
|
+
--compact, -c # One-line per message (great for quick scans)
|
|
70
|
+
--body, -b # Include body in search results
|
|
71
|
+
--full, -f # Full body (no truncation)
|
|
72
|
+
--limit=N # Override default limit
|
|
73
|
+
--cc=email # Add CC recipient
|
|
74
|
+
--bcc=email # Add BCC recipient
|
|
75
|
+
--attach=/path/file # Add attachment (repeatable)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Gmail Search Syntax
|
|
79
|
+
|
|
80
|
+
The search command uses Gmail's powerful search syntax:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# By sender/recipient
|
|
84
|
+
./run.js search "from:boss@company.com"
|
|
85
|
+
./run.js search "to:me"
|
|
86
|
+
./run.js search "cc:team@company.com"
|
|
87
|
+
|
|
88
|
+
# By status
|
|
89
|
+
./run.js search "is:unread"
|
|
90
|
+
./run.js search "is:starred"
|
|
91
|
+
./run.js search "is:important"
|
|
92
|
+
|
|
93
|
+
# By content
|
|
94
|
+
./run.js search "subject:meeting"
|
|
95
|
+
./run.js search "has:attachment"
|
|
96
|
+
./run.js search "filename:pdf"
|
|
97
|
+
|
|
98
|
+
# By date
|
|
99
|
+
./run.js search "after:2024/12/01"
|
|
100
|
+
./run.js search "before:2024/12/31"
|
|
101
|
+
./run.js search "newer_than:7d"
|
|
102
|
+
./run.js search "older_than:1m"
|
|
103
|
+
|
|
104
|
+
# By label/location
|
|
105
|
+
./run.js search "label:work"
|
|
106
|
+
./run.js search "in:inbox"
|
|
107
|
+
./run.js search "in:sent"
|
|
108
|
+
|
|
109
|
+
# Combine queries
|
|
110
|
+
./run.js search "from:boss@company.com is:unread newer_than:7d"
|
|
111
|
+
./run.js search "has:attachment larger:5M"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Examples
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Quick inbox scan
|
|
118
|
+
./run.js inbox 10 --compact
|
|
119
|
+
|
|
120
|
+
# Find unread from specific sender
|
|
121
|
+
./run.js search "from:important@client.com is:unread"
|
|
122
|
+
|
|
123
|
+
# Read a specific email
|
|
124
|
+
./run.js read 19b176a2f49b681f
|
|
125
|
+
|
|
126
|
+
# View full conversation thread
|
|
127
|
+
./run.js thread 19b176a2f49b681f
|
|
128
|
+
|
|
129
|
+
# Send an email
|
|
130
|
+
./run.js send "john@example.com" "Meeting tomorrow" "Hi John,\n\nAre we still on for tomorrow?\n\nThanks"
|
|
131
|
+
|
|
132
|
+
# Reply to an email
|
|
133
|
+
./run.js reply 19b176a2f49b681f "Thanks for the update, looks good!"
|
|
134
|
+
|
|
135
|
+
# Forward an email
|
|
136
|
+
./run.js forward 19b176a2f49b681f "colleague@example.com" "FYI - see below"
|
|
137
|
+
|
|
138
|
+
# Archive old emails
|
|
139
|
+
./run.js archive 19b176a2f49b681f
|
|
140
|
+
|
|
141
|
+
# Label management
|
|
142
|
+
./run.js label 19b176a2f49b681f "Work"
|
|
143
|
+
./run.js label-info "INBOX"
|
|
144
|
+
|
|
145
|
+
# Send with attachment
|
|
146
|
+
./run.js send "john@example.com" "Report" "See attached" --attach=./report.pdf
|
|
147
|
+
|
|
148
|
+
# Multiple attachments
|
|
149
|
+
./run.js send "john@example.com" "Files" "Here are the files" --attach=./a.pdf --attach=./b.pdf
|
|
150
|
+
|
|
151
|
+
# List and download attachments
|
|
152
|
+
./run.js attachments 19b176a2f49b681f
|
|
153
|
+
./run.js download 19b176a2f49b681f "report.pdf" ./downloads/report.pdf
|
|
154
|
+
./run.js download-all 19b176a2f49b681f ./downloads/
|
|
155
|
+
|
|
156
|
+
# Draft management
|
|
157
|
+
./run.js drafts
|
|
158
|
+
./run.js draft-create "john@example.com" "Draft" "Will finish later"
|
|
159
|
+
./run.js draft-reply 19b176a2f49b681f "Thanks, need to think about this"
|
|
160
|
+
./run.js draft-send r123456789
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Setup
|
|
164
|
+
|
|
165
|
+
### 1. Google Cloud Project
|
|
166
|
+
|
|
167
|
+
1. Go to [Google Cloud Console](https://console.cloud.google.com)
|
|
168
|
+
2. Create a project (or use existing)
|
|
169
|
+
3. Enable Gmail API
|
|
170
|
+
4. Create OAuth 2.0 credentials (Desktop app type)
|
|
171
|
+
5. Download `credentials.json`
|
|
172
|
+
|
|
173
|
+
### 2. Place Credentials
|
|
174
|
+
|
|
175
|
+
Put `credentials.json` in the `gmail/` directory, or set path in `.env`:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
GMAIL_CREDENTIALS_PATH=/path/to/credentials.json
|
|
179
|
+
GMAIL_TOKEN_PATH=/path/to/token.json
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 3. First Run
|
|
183
|
+
|
|
184
|
+
On first run, you'll be prompted to authorize:
|
|
185
|
+
|
|
186
|
+
1. Visit the OAuth URL shown
|
|
187
|
+
2. Sign in with your Google account
|
|
188
|
+
3. Copy the authorization code
|
|
189
|
+
4. Paste it in the terminal
|
|
190
|
+
|
|
191
|
+
Token is saved and auto-refreshes.
|
|
192
|
+
|
|
193
|
+
## Project Structure
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
gmail/
|
|
197
|
+
├── run.js # CLI entry point
|
|
198
|
+
├── lib/
|
|
199
|
+
│ ├── api.js # Gmail API client + OAuth
|
|
200
|
+
│ ├── messages.js # inbox, unread, search, read, archive...
|
|
201
|
+
│ ├── threads.js # Thread operations
|
|
202
|
+
│ ├── send.js # send, reply, forward (with attachment support)
|
|
203
|
+
│ ├── drafts.js # Draft management, reply drafts
|
|
204
|
+
│ ├── attachments.js # List, download attachments
|
|
205
|
+
│ └── labels.js # Label management
|
|
206
|
+
├── credentials.json # OAuth credentials (gitignored)
|
|
207
|
+
└── token.json # Auth token (gitignored)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Required Scopes
|
|
211
|
+
|
|
212
|
+
- `gmail.modify` - Read, send, delete, manage labels
|
|
213
|
+
- `gmail.compose` - Create drafts and send
|
|
214
|
+
- `gmail.send` - Send emails
|
package/c4ai.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gmail",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Gmail CLI tool for messages, threads, and drafts",
|
|
5
|
+
"author": "cliforai",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"entry": "run.ts",
|
|
8
|
+
"runtime": "bun",
|
|
9
|
+
"keywords": ["gmail", "email", "google", "mail"],
|
|
10
|
+
"commands": {
|
|
11
|
+
"inbox": { "description": "Recent inbox messages", "args": [{ "name": "limit", "required": false }] },
|
|
12
|
+
"unread": { "description": "Unread messages only", "args": [{ "name": "limit", "required": false }] },
|
|
13
|
+
"search": { "description": "Search with Gmail syntax", "args": [{ "name": "query", "required": true }, { "name": "limit", "required": false }] },
|
|
14
|
+
"read": { "description": "Read full message", "args": [{ "name": "id", "required": true }] },
|
|
15
|
+
"archive": { "description": "Archive message", "args": [{ "name": "id", "required": true }] },
|
|
16
|
+
"trash": { "description": "Move to trash", "args": [{ "name": "id", "required": true }] },
|
|
17
|
+
"untrash": { "description": "Remove from trash", "args": [{ "name": "id", "required": true }] },
|
|
18
|
+
"star": { "description": "Star message", "args": [{ "name": "id", "required": true }] },
|
|
19
|
+
"unstar": { "description": "Unstar message", "args": [{ "name": "id", "required": true }] },
|
|
20
|
+
"markread": { "description": "Mark as read", "args": [{ "name": "id", "required": true }] },
|
|
21
|
+
"markunread": { "description": "Mark as unread", "args": [{ "name": "id", "required": true }] },
|
|
22
|
+
"thread": { "description": "Full conversation thread", "args": [{ "name": "id", "required": true }] },
|
|
23
|
+
"threads": { "description": "List recent threads", "args": [{ "name": "limit", "required": false }] },
|
|
24
|
+
"send": { "description": "Send new email", "args": [{ "name": "to", "required": true }, { "name": "subject", "required": true }, { "name": "body", "required": true }] },
|
|
25
|
+
"reply": { "description": "Reply to message", "args": [{ "name": "id", "required": true }, { "name": "body", "required": true }] },
|
|
26
|
+
"replyall": { "description": "Reply all", "args": [{ "name": "id", "required": true }, { "name": "body", "required": true }] },
|
|
27
|
+
"forward": { "description": "Forward message", "args": [{ "name": "id", "required": true }, { "name": "to", "required": true }] },
|
|
28
|
+
"draft": { "description": "Create draft", "args": [{ "name": "to", "required": true }, { "name": "subject", "required": true }, { "name": "body", "required": true }] },
|
|
29
|
+
"labels": { "description": "List all labels" },
|
|
30
|
+
"label": { "description": "Add label to message", "args": [{ "name": "id", "required": true }, { "name": "label", "required": true }] },
|
|
31
|
+
"unlabel": { "description": "Remove label from message", "args": [{ "name": "id", "required": true }, { "name": "label", "required": true }] },
|
|
32
|
+
"attachments": { "description": "List attachments in message", "args": [{ "name": "id", "required": true }] },
|
|
33
|
+
"download": { "description": "Download attachment", "args": [{ "name": "id", "required": true }] },
|
|
34
|
+
"drafts": { "description": "List all drafts" },
|
|
35
|
+
"draft-send": { "description": "Send draft", "args": [{ "name": "id", "required": true }] }
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"googleapis": "^144.0.0",
|
|
39
|
+
"google-auth-library": "^9.0.0",
|
|
40
|
+
"commander": "^14.0.0"
|
|
41
|
+
},
|
|
42
|
+
"mcp": {
|
|
43
|
+
"enabled": true,
|
|
44
|
+
"transport": "stdio"
|
|
45
|
+
}
|
|
46
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cli4ai/gmail",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Gmail CLI tool for messages, threads, and drafts",
|
|
5
|
+
"author": "cliforai",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "run.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"gmail": "./run.ts"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"c4ai",
|
|
14
|
+
"cli",
|
|
15
|
+
"ai-tools",
|
|
16
|
+
"gmail",
|
|
17
|
+
"email",
|
|
18
|
+
"google",
|
|
19
|
+
"mail"
|
|
20
|
+
],
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/cli4ai/packages",
|
|
24
|
+
"directory": "packages/gmail"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/cli4ai/packages/tree/main/packages/gmail",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/cli4ai/packages/issues"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"run.ts",
|
|
32
|
+
"c4ai.json",
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"test": "bun test"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/run.ts
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// Gmail CLI tool
|
|
3
|
+
|
|
4
|
+
import { cli, withErrorHandling } from '../lib/cli.ts';
|
|
5
|
+
|
|
6
|
+
const messages = require('./lib/messages');
|
|
7
|
+
const threads = require('./lib/threads');
|
|
8
|
+
const send = require('./lib/send');
|
|
9
|
+
const labels = require('./lib/labels');
|
|
10
|
+
const attachments = require('./lib/attachments');
|
|
11
|
+
const drafts = require('./lib/drafts');
|
|
12
|
+
|
|
13
|
+
interface Flags {
|
|
14
|
+
raw?: boolean;
|
|
15
|
+
compact?: boolean;
|
|
16
|
+
body?: boolean;
|
|
17
|
+
fullBody?: boolean;
|
|
18
|
+
limit?: number;
|
|
19
|
+
cc?: string;
|
|
20
|
+
bcc?: string;
|
|
21
|
+
attach?: string[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const program = cli('gmail', '1.0.0', 'Gmail CLI tool');
|
|
25
|
+
|
|
26
|
+
// Global options
|
|
27
|
+
program
|
|
28
|
+
.option('--raw, -r', 'Full JSON output')
|
|
29
|
+
.option('--compact, -c', 'Compact one-line output')
|
|
30
|
+
.option('--body, -b', 'Include body in search results')
|
|
31
|
+
.option('--full, -f', 'Full body (no truncation)')
|
|
32
|
+
.option('--limit <n>', 'Override default limit', parseInt)
|
|
33
|
+
.option('--cc <email>', 'Add CC recipient (send/draft)')
|
|
34
|
+
.option('--bcc <email>', 'Add BCC recipient (send/draft)')
|
|
35
|
+
.option('--attach <path>', 'Add attachment (repeatable)', (val: string, prev: string[] | undefined) => {
|
|
36
|
+
const list = prev || [];
|
|
37
|
+
list.push(val);
|
|
38
|
+
return list;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
42
|
+
// MESSAGE COMMANDS
|
|
43
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
44
|
+
|
|
45
|
+
program
|
|
46
|
+
.command('inbox')
|
|
47
|
+
.description('Recent inbox messages')
|
|
48
|
+
.argument('[limit]', 'Number of messages', '20')
|
|
49
|
+
.action(withErrorHandling(async (limit: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
50
|
+
const flags = { ...cmd.parent.opts(), limit: parseInt(limit) };
|
|
51
|
+
await messages.inbox(flags);
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
program
|
|
55
|
+
.command('unread')
|
|
56
|
+
.description('Unread messages only')
|
|
57
|
+
.argument('[limit]', 'Number of messages', '20')
|
|
58
|
+
.action(withErrorHandling(async (limit: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
59
|
+
const flags = { ...cmd.parent.opts(), limit: parseInt(limit) };
|
|
60
|
+
await messages.unread(flags);
|
|
61
|
+
}));
|
|
62
|
+
|
|
63
|
+
program
|
|
64
|
+
.command('search <query>')
|
|
65
|
+
.description('Search with Gmail syntax')
|
|
66
|
+
.argument('[limit]', 'Number of results', '20')
|
|
67
|
+
.action(withErrorHandling(async (query: string, limit: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
68
|
+
const flags = { ...cmd.parent.opts(), limit: parseInt(limit) };
|
|
69
|
+
await messages.search(query, flags);
|
|
70
|
+
}));
|
|
71
|
+
|
|
72
|
+
program
|
|
73
|
+
.command('read <id>')
|
|
74
|
+
.description('Read full message')
|
|
75
|
+
.action(withErrorHandling(async (id: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
76
|
+
await messages.read(id, cmd.parent.opts());
|
|
77
|
+
}));
|
|
78
|
+
|
|
79
|
+
program
|
|
80
|
+
.command('archive <id>')
|
|
81
|
+
.description('Archive message (remove from inbox)')
|
|
82
|
+
.action(withErrorHandling(async (id: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
83
|
+
await messages.archive(id, cmd.parent.opts());
|
|
84
|
+
}));
|
|
85
|
+
|
|
86
|
+
program
|
|
87
|
+
.command('trash <id>')
|
|
88
|
+
.description('Move to trash')
|
|
89
|
+
.action(withErrorHandling(async (id: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
90
|
+
await messages.trash(id, cmd.parent.opts());
|
|
91
|
+
}));
|
|
92
|
+
|
|
93
|
+
program
|
|
94
|
+
.command('untrash <id>')
|
|
95
|
+
.description('Remove from trash')
|
|
96
|
+
.action(withErrorHandling(async (id: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
97
|
+
await messages.untrash(id, cmd.parent.opts());
|
|
98
|
+
}));
|
|
99
|
+
|
|
100
|
+
program
|
|
101
|
+
.command('star <id>')
|
|
102
|
+
.description('Star message')
|
|
103
|
+
.action(withErrorHandling(async (id: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
104
|
+
await messages.star(id, cmd.parent.opts());
|
|
105
|
+
}));
|
|
106
|
+
|
|
107
|
+
program
|
|
108
|
+
.command('unstar <id>')
|
|
109
|
+
.description('Unstar message')
|
|
110
|
+
.action(withErrorHandling(async (id: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
111
|
+
await messages.unstar(id, cmd.parent.opts());
|
|
112
|
+
}));
|
|
113
|
+
|
|
114
|
+
program
|
|
115
|
+
.command('markread <id>')
|
|
116
|
+
.description('Mark as read')
|
|
117
|
+
.action(withErrorHandling(async (id: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
118
|
+
await messages.markRead(id, cmd.parent.opts());
|
|
119
|
+
}));
|
|
120
|
+
|
|
121
|
+
program
|
|
122
|
+
.command('markunread <id>')
|
|
123
|
+
.description('Mark as unread')
|
|
124
|
+
.action(withErrorHandling(async (id: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
125
|
+
await messages.markUnread(id, cmd.parent.opts());
|
|
126
|
+
}));
|
|
127
|
+
|
|
128
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
129
|
+
// THREAD COMMANDS
|
|
130
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
131
|
+
|
|
132
|
+
program
|
|
133
|
+
.command('thread <id>')
|
|
134
|
+
.description('Full conversation thread')
|
|
135
|
+
.action(withErrorHandling(async (id: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
136
|
+
await threads.get(id, cmd.parent.opts());
|
|
137
|
+
}));
|
|
138
|
+
|
|
139
|
+
program
|
|
140
|
+
.command('threads')
|
|
141
|
+
.description('List recent threads')
|
|
142
|
+
.argument('[limit]', 'Number of threads', '20')
|
|
143
|
+
.argument('[query]', 'Search query')
|
|
144
|
+
.action(withErrorHandling(async (limit: string, query: string | undefined, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
145
|
+
const flags = { ...cmd.parent.opts(), limit: parseInt(limit), query };
|
|
146
|
+
await threads.list(flags);
|
|
147
|
+
}));
|
|
148
|
+
|
|
149
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
150
|
+
// SEND COMMANDS
|
|
151
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
152
|
+
|
|
153
|
+
program
|
|
154
|
+
.command('send <to> <subject> <body>')
|
|
155
|
+
.description('Send new email')
|
|
156
|
+
.action(withErrorHandling(async (to: string, subject: string, body: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
157
|
+
await send.send(to, subject, body, cmd.parent.opts());
|
|
158
|
+
}));
|
|
159
|
+
|
|
160
|
+
program
|
|
161
|
+
.command('reply <id> <body>')
|
|
162
|
+
.description('Reply to message')
|
|
163
|
+
.action(withErrorHandling(async (id: string, body: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
164
|
+
await send.reply(id, body, cmd.parent.opts());
|
|
165
|
+
}));
|
|
166
|
+
|
|
167
|
+
program
|
|
168
|
+
.command('replyall <id> <body>')
|
|
169
|
+
.description('Reply all')
|
|
170
|
+
.action(withErrorHandling(async (id: string, body: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
171
|
+
await send.replyAll(id, body, cmd.parent.opts());
|
|
172
|
+
}));
|
|
173
|
+
|
|
174
|
+
program
|
|
175
|
+
.command('forward <id> <to>')
|
|
176
|
+
.description('Forward message')
|
|
177
|
+
.argument('[body]', 'Additional message')
|
|
178
|
+
.action(withErrorHandling(async (id: string, to: string, body: string | undefined, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
179
|
+
await send.forward(id, to, body, cmd.parent.opts());
|
|
180
|
+
}));
|
|
181
|
+
|
|
182
|
+
program
|
|
183
|
+
.command('draft <to> <subject> <body>')
|
|
184
|
+
.description('Create draft')
|
|
185
|
+
.action(withErrorHandling(async (to: string, subject: string, body: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
186
|
+
await send.draft(to, subject, body, cmd.parent.opts());
|
|
187
|
+
}));
|
|
188
|
+
|
|
189
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
190
|
+
// LABEL COMMANDS
|
|
191
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
192
|
+
|
|
193
|
+
program
|
|
194
|
+
.command('labels')
|
|
195
|
+
.description('List all labels')
|
|
196
|
+
.action(withErrorHandling(async (options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
197
|
+
await labels.list(cmd.parent.opts());
|
|
198
|
+
}));
|
|
199
|
+
|
|
200
|
+
program
|
|
201
|
+
.command('label <id> <label>')
|
|
202
|
+
.description('Add label to message')
|
|
203
|
+
.action(withErrorHandling(async (id: string, label: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
204
|
+
await labels.addToMessage(id, label, cmd.parent.opts());
|
|
205
|
+
}));
|
|
206
|
+
|
|
207
|
+
program
|
|
208
|
+
.command('unlabel <id> <label>')
|
|
209
|
+
.description('Remove label from message')
|
|
210
|
+
.action(withErrorHandling(async (id: string, label: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
211
|
+
await labels.removeFromMessage(id, label, cmd.parent.opts());
|
|
212
|
+
}));
|
|
213
|
+
|
|
214
|
+
program
|
|
215
|
+
.command('label-info <label>')
|
|
216
|
+
.description('Get label details with counts')
|
|
217
|
+
.action(withErrorHandling(async (label: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
218
|
+
await labels.get(label, cmd.parent.opts());
|
|
219
|
+
}));
|
|
220
|
+
|
|
221
|
+
program
|
|
222
|
+
.command('label-create <name>')
|
|
223
|
+
.description('Create new label')
|
|
224
|
+
.action(withErrorHandling(async (name: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
225
|
+
await labels.create(name, cmd.parent.opts());
|
|
226
|
+
}));
|
|
227
|
+
|
|
228
|
+
program
|
|
229
|
+
.command('label-delete <name>')
|
|
230
|
+
.description('Delete label')
|
|
231
|
+
.action(withErrorHandling(async (name: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
232
|
+
await labels.remove(name, cmd.parent.opts());
|
|
233
|
+
}));
|
|
234
|
+
|
|
235
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
236
|
+
// ATTACHMENT COMMANDS
|
|
237
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
238
|
+
|
|
239
|
+
program
|
|
240
|
+
.command('attachments <id>')
|
|
241
|
+
.description('List attachments in message')
|
|
242
|
+
.action(withErrorHandling(async (id: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
243
|
+
await attachments.list(id, cmd.parent.opts());
|
|
244
|
+
}));
|
|
245
|
+
|
|
246
|
+
program
|
|
247
|
+
.command('download <id>')
|
|
248
|
+
.description('Download attachment')
|
|
249
|
+
.argument('[filename]', 'Specific attachment filename')
|
|
250
|
+
.argument('[out]', 'Output directory')
|
|
251
|
+
.action(withErrorHandling(async (id: string, filename: string | undefined, out: string | undefined, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
252
|
+
await attachments.download(id, filename, out, cmd.parent.opts());
|
|
253
|
+
}));
|
|
254
|
+
|
|
255
|
+
program
|
|
256
|
+
.command('download-all <id>')
|
|
257
|
+
.description('Download all attachments')
|
|
258
|
+
.argument('[dir]', 'Output directory')
|
|
259
|
+
.action(withErrorHandling(async (id: string, dir: string | undefined, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
260
|
+
await attachments.downloadAll(id, dir, cmd.parent.opts());
|
|
261
|
+
}));
|
|
262
|
+
|
|
263
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
264
|
+
// DRAFT COMMANDS
|
|
265
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
266
|
+
|
|
267
|
+
program
|
|
268
|
+
.command('drafts')
|
|
269
|
+
.description('List all drafts')
|
|
270
|
+
.action(withErrorHandling(async (options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
271
|
+
await drafts.list(cmd.parent.opts());
|
|
272
|
+
}));
|
|
273
|
+
|
|
274
|
+
program
|
|
275
|
+
.command('draft-get <id>')
|
|
276
|
+
.description('Get draft content')
|
|
277
|
+
.action(withErrorHandling(async (id: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
278
|
+
await drafts.get(id, cmd.parent.opts());
|
|
279
|
+
}));
|
|
280
|
+
|
|
281
|
+
program
|
|
282
|
+
.command('draft-create <to> <subject> <body>')
|
|
283
|
+
.description('Create new draft')
|
|
284
|
+
.action(withErrorHandling(async (to: string, subject: string, body: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
285
|
+
await drafts.create(to, subject, body, cmd.parent.opts());
|
|
286
|
+
}));
|
|
287
|
+
|
|
288
|
+
program
|
|
289
|
+
.command('draft-reply <msgId> <body>')
|
|
290
|
+
.description('Create draft reply to message')
|
|
291
|
+
.action(withErrorHandling(async (msgId: string, body: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
292
|
+
await drafts.createReply(msgId, body, cmd.parent.opts());
|
|
293
|
+
}));
|
|
294
|
+
|
|
295
|
+
program
|
|
296
|
+
.command('draft-update <id> <to> <subject> <body>')
|
|
297
|
+
.description('Update existing draft')
|
|
298
|
+
.action(withErrorHandling(async (id: string, to: string, subject: string, body: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
299
|
+
await drafts.update(id, to, subject, body, cmd.parent.opts());
|
|
300
|
+
}));
|
|
301
|
+
|
|
302
|
+
program
|
|
303
|
+
.command('draft-delete <id>')
|
|
304
|
+
.description('Delete draft')
|
|
305
|
+
.action(withErrorHandling(async (id: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
306
|
+
await drafts.remove(id, cmd.parent.opts());
|
|
307
|
+
}));
|
|
308
|
+
|
|
309
|
+
program
|
|
310
|
+
.command('draft-send <id>')
|
|
311
|
+
.description('Send draft')
|
|
312
|
+
.action(withErrorHandling(async (id: string, options: Flags, cmd: { parent: { opts: () => Flags } }) => {
|
|
313
|
+
await drafts.send(id, cmd.parent.opts());
|
|
314
|
+
}));
|
|
315
|
+
|
|
316
|
+
program.parse();
|