inboxd 1.0.13 → 1.1.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/.claude/skills/inbox-assistant/SKILL.md +17 -6
- package/CLAUDE.md +19 -4
- package/package.json +1 -1
- package/src/archive-log.js +104 -0
- package/src/cli.js +473 -17
- package/src/deletion-log.js +101 -0
- package/src/gmail-monitor.js +29 -0
- package/src/sent-log.js +35 -0
- package/tests/archive-log.test.js +196 -0
- package/tests/cleanup-suggest.test.js +239 -0
- package/tests/install-service.test.js +210 -0
- package/tests/interactive-confirm.test.js +175 -0
- package/tests/json-output.test.js +189 -0
- package/tests/stats.test.js +218 -0
- package/tests/unarchive.test.js +228 -0
|
@@ -281,22 +281,22 @@ This will guide you through:
|
|
|
281
281
|
|
|
282
282
|
### Optional: Automatic Background Monitoring
|
|
283
283
|
|
|
284
|
-
Users can enable automatic inbox checking with
|
|
284
|
+
Users can enable automatic inbox checking with notifications:
|
|
285
285
|
|
|
286
286
|
```bash
|
|
287
287
|
inbox install-service # Check every 5 minutes
|
|
288
288
|
inbox install-service --interval 10 # Check every 10 minutes
|
|
289
|
+
inbox install-service --uninstall # Remove service
|
|
289
290
|
```
|
|
290
291
|
|
|
291
292
|
This installs and starts a background service that:
|
|
292
293
|
- Checks for new emails automatically
|
|
293
|
-
- Sends
|
|
294
|
+
- Sends desktop notifications when new emails arrive
|
|
294
295
|
- Starts on login
|
|
295
296
|
|
|
296
|
-
To stop: `launchctl unload ~/Library/LaunchAgents/com.
|
|
297
|
+
**macOS:** Uses launchd. To stop: `launchctl unload ~/Library/LaunchAgents/com.danielparedes.inboxd.plist`
|
|
297
298
|
|
|
298
|
-
|
|
299
|
-
> This is macOS-only. Linux users can set up a cron job instead.
|
|
299
|
+
**Linux:** Uses systemd. To stop: `systemctl --user stop inboxd.timer`
|
|
300
300
|
|
|
301
301
|
## Command Reference
|
|
302
302
|
|
|
@@ -331,7 +331,16 @@ To stop: `launchctl unload ~/Library/LaunchAgents/com.yourname.inboxd.plist`
|
|
|
331
331
|
| `inbox mark-read --ids "id1,id2"` | Mark emails as read (remove UNREAD label) |
|
|
332
332
|
| `inbox mark-unread --ids "id1,id2"` | Mark emails as unread (add UNREAD label) |
|
|
333
333
|
| `inbox archive --ids "id1,id2" --confirm` | Archive emails (remove from inbox, keep in All Mail) |
|
|
334
|
+
| `inbox unarchive --last N` | Undo last N archived emails |
|
|
335
|
+
| `inbox unarchive --ids "id1,id2"` | Unarchive specific emails |
|
|
336
|
+
| `inbox stats` | Show email activity dashboard (deletions, sent counts) |
|
|
337
|
+
| `inbox stats --days 7 --json` | Get stats as JSON for custom period |
|
|
338
|
+
| `inbox cleanup-suggest` | Get smart cleanup suggestions based on deletion patterns |
|
|
334
339
|
| `inbox deletion-log` | View recent deletions |
|
|
340
|
+
| `inbox deletion-log --json` | Get deletion log as JSON |
|
|
341
|
+
| `inbox accounts --json` | List accounts as JSON |
|
|
342
|
+
| `inbox delete --dry-run --json` | Preview deletion as structured JSON |
|
|
343
|
+
| `inbox restore --json` | Get restore results as JSON |
|
|
335
344
|
|
|
336
345
|
### Smart Filtering Options
|
|
337
346
|
|
|
@@ -590,6 +599,8 @@ When user has job-related emails (LinkedIn, Indeed, recruiters) and wants to eva
|
|
|
590
599
|
| "Delete [sender]'s emails" | Bulk sender cleanup | Two-step pattern with `--sender` filter |
|
|
591
600
|
| "Delete the security emails" | Subject-based cleanup | `--match "security" --dry-run` → confirm → `--ids` |
|
|
592
601
|
| "What senders have the most emails?" | Inbox analysis | `inbox analyze --group-by sender` |
|
|
602
|
+
| "Show my email stats" | Activity summary | `inbox stats` |
|
|
603
|
+
| "What should I clean up?" | Pattern analysis | `inbox cleanup-suggest` |
|
|
593
604
|
| "What links are in this email?" | Extract URLs | `inbox read --id <id> --links` |
|
|
594
605
|
| "Find my old emails" / "Clean up old stuff" | Stale email review | `inbox analyze --older-than 30d` |
|
|
595
606
|
| "I keep getting these" | Recurring annoyance | Suggest unsubscribe/filter, then delete batch |
|
|
@@ -627,7 +638,7 @@ When user has job-related emails (LinkedIn, Indeed, recruiters) and wants to eva
|
|
|
627
638
|
|--------|--------------|
|
|
628
639
|
| Deleted emails | `inbox restore --last N` |
|
|
629
640
|
| Marked as read | `inbox mark-unread --ids "id1,id2,..."` |
|
|
630
|
-
| Archived |
|
|
641
|
+
| Archived | `inbox unarchive --last N` |
|
|
631
642
|
|
|
632
643
|
---
|
|
633
644
|
|
package/CLAUDE.md
CHANGED
|
@@ -11,7 +11,7 @@ inbox setup # First-time setup wizard
|
|
|
11
11
|
inbox auth -a <name> # Add account
|
|
12
12
|
inbox summary # Check all inboxes
|
|
13
13
|
inbox check -q # Background check
|
|
14
|
-
inbox install-service # Install
|
|
14
|
+
inbox install-service # Install background service (macOS/Linux)
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## Architecture
|
|
@@ -20,9 +20,10 @@ inbox install-service # Install launchd service (macOS only)
|
|
|
20
20
|
src/
|
|
21
21
|
├── cli.js # Entry point, command definitions (commander)
|
|
22
22
|
├── gmail-auth.js # OAuth2 flow, token storage, multi-account management
|
|
23
|
-
├── gmail-monitor.js # Gmail API: fetch, count, trash, restore
|
|
23
|
+
├── gmail-monitor.js # Gmail API: fetch, count, trash, restore, archive
|
|
24
24
|
├── state.js # Tracks seen emails per account
|
|
25
25
|
├── deletion-log.js # Logs deleted emails for restore capability
|
|
26
|
+
├── archive-log.js # Logs archived emails for unarchive capability
|
|
26
27
|
├── sent-log.js # Logs sent emails for audit trail
|
|
27
28
|
├── notifier.js # macOS notifications (node-notifier)
|
|
28
29
|
└── skill-installer.js # Copies skill to ~/.claude/skills/
|
|
@@ -54,6 +55,7 @@ All user data lives in `~/.config/inboxd/`:
|
|
|
54
55
|
| `token-<name>.json` | OAuth refresh/access tokens |
|
|
55
56
|
| `state-<name>.json` | `{ seenEmailIds, lastCheck, lastNotifiedAt }` |
|
|
56
57
|
| `deletion-log.json` | Audit log for deleted emails |
|
|
58
|
+
| `archive-log.json` | Audit log for archived emails |
|
|
57
59
|
| `sent-log.json` | Audit log for sent emails |
|
|
58
60
|
|
|
59
61
|
## Code Patterns
|
|
@@ -70,7 +72,10 @@ All user data lives in `~/.config/inboxd/`:
|
|
|
70
72
|
- `inbox check` marks emails as seen after notifying
|
|
71
73
|
- `inbox delete` logs to `deletion-log.json` before trashing
|
|
72
74
|
- `inbox restore` moves from Trash to Inbox, removes log entry
|
|
73
|
-
- `
|
|
75
|
+
- `inbox archive` logs to `archive-log.json` before archiving
|
|
76
|
+
- `inbox unarchive` moves archived emails back to Inbox, removes log entry
|
|
77
|
+
- `inbox send/reply` prompts for interactive confirmation (or use `--confirm` to skip)
|
|
78
|
+
- `install-service` creates and enables launchd (macOS) or systemd (Linux) service
|
|
74
79
|
|
|
75
80
|
## OAuth Notes
|
|
76
81
|
|
|
@@ -169,7 +174,16 @@ scripts/postinstall.js # npm postinstall hint about install-skill
|
|
|
169
174
|
| `inbox reply --id <id> -b <body> --confirm` | Reply to email (requires --confirm) |
|
|
170
175
|
| `inbox mark-read --ids "id1,id2"` | Mark emails as read |
|
|
171
176
|
| `inbox mark-unread --ids "id1,id2"` | Mark emails as unread (undo mark-read) |
|
|
177
|
+
| `inbox archive --ids "id1,id2" --confirm` | Archive emails (remove from inbox) |
|
|
178
|
+
| `inbox unarchive --last N` | Undo last N archives |
|
|
179
|
+
| `inbox stats` | Show email activity dashboard (deletions, sent) |
|
|
180
|
+
| `inbox stats --json` | Get stats as JSON |
|
|
181
|
+
| `inbox cleanup-suggest` | Get smart cleanup suggestions based on patterns |
|
|
182
|
+
| `inbox accounts --json` | List accounts as JSON |
|
|
183
|
+
| `inbox deletion-log --json` | Get deletion log as JSON |
|
|
184
|
+
| `inbox delete --dry-run --json` | Preview deletion as JSON |
|
|
172
185
|
| `inbox install-skill` | Install/update the Claude Code skill |
|
|
186
|
+
| `inbox install-service --uninstall` | Remove background service |
|
|
173
187
|
|
|
174
188
|
### Smart Filtering Options
|
|
175
189
|
| Option | Description |
|
|
@@ -182,8 +196,9 @@ scripts/postinstall.js # npm postinstall hint about install-skill
|
|
|
182
196
|
|
|
183
197
|
### Send/Reply Safety
|
|
184
198
|
The `send` and `reply` commands have built-in safety features:
|
|
199
|
+
- **Interactive confirmation**: Prompts "Send this email? (y/N)" when no flags provided
|
|
185
200
|
- **`--dry-run`**: Preview the email without sending
|
|
186
|
-
- **`--confirm`**:
|
|
201
|
+
- **`--confirm`**: Skip the interactive prompt (for automation/scripts)
|
|
187
202
|
- **Audit logging**: All sent emails are logged to `~/.config/inboxd/sent-log.json`
|
|
188
203
|
- **Account resolution**: Prompts for account selection when multiple accounts exist
|
|
189
204
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { TOKEN_DIR } = require('./gmail-auth');
|
|
4
|
+
const { atomicWriteJsonSync } = require('./utils');
|
|
5
|
+
|
|
6
|
+
const LOG_DIR = TOKEN_DIR;
|
|
7
|
+
const LOG_FILE = path.join(LOG_DIR, 'archive-log.json');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Ensures the log directory exists
|
|
11
|
+
*/
|
|
12
|
+
function ensureLogDir() {
|
|
13
|
+
if (!fs.existsSync(LOG_DIR)) {
|
|
14
|
+
fs.mkdirSync(LOG_DIR, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Reads the current archive log
|
|
20
|
+
* @returns {Array} Array of archive entries
|
|
21
|
+
*/
|
|
22
|
+
function readArchiveLog() {
|
|
23
|
+
ensureLogDir();
|
|
24
|
+
if (!fs.existsSync(LOG_FILE)) {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const content = fs.readFileSync(LOG_FILE, 'utf8');
|
|
29
|
+
return JSON.parse(content);
|
|
30
|
+
} catch (_err) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Logs archived emails to the archive log
|
|
37
|
+
* @param {Array} emails - Array of email objects with id, threadId, account, from, subject, snippet
|
|
38
|
+
*/
|
|
39
|
+
function logArchives(emails) {
|
|
40
|
+
ensureLogDir();
|
|
41
|
+
const log = readArchiveLog();
|
|
42
|
+
const timestamp = new Date().toISOString();
|
|
43
|
+
|
|
44
|
+
for (const email of emails) {
|
|
45
|
+
log.push({
|
|
46
|
+
archivedAt: timestamp,
|
|
47
|
+
account: email.account,
|
|
48
|
+
id: email.id,
|
|
49
|
+
threadId: email.threadId,
|
|
50
|
+
from: email.from,
|
|
51
|
+
subject: email.subject,
|
|
52
|
+
snippet: email.snippet,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
atomicWriteJsonSync(LOG_FILE, log);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Gets recent archives from the log
|
|
61
|
+
* @param {number} days - Number of days to look back (default: 30)
|
|
62
|
+
* @returns {Array} Array of archive entries within the time range
|
|
63
|
+
*/
|
|
64
|
+
function getRecentArchives(days = 30) {
|
|
65
|
+
const log = readArchiveLog();
|
|
66
|
+
const cutoff = new Date();
|
|
67
|
+
cutoff.setDate(cutoff.getDate() - days);
|
|
68
|
+
|
|
69
|
+
return log.filter((entry) => {
|
|
70
|
+
const archivedAt = new Date(entry.archivedAt);
|
|
71
|
+
return archivedAt >= cutoff;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Gets the path to the log file (for display purposes)
|
|
77
|
+
* @returns {string} The log file path
|
|
78
|
+
*/
|
|
79
|
+
function getArchiveLogPath() {
|
|
80
|
+
return LOG_FILE;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Removes entries from the archive log (e.g., after unarchiving)
|
|
85
|
+
* @param {Array<string>} ids - Array of message IDs to remove
|
|
86
|
+
*/
|
|
87
|
+
function removeArchiveLogEntries(ids) {
|
|
88
|
+
ensureLogDir();
|
|
89
|
+
const log = readArchiveLog();
|
|
90
|
+
|
|
91
|
+
const newLog = log.filter(entry => !ids.includes(entry.id));
|
|
92
|
+
|
|
93
|
+
if (log.length !== newLog.length) {
|
|
94
|
+
atomicWriteJsonSync(LOG_FILE, newLog);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = {
|
|
99
|
+
logArchives,
|
|
100
|
+
getRecentArchives,
|
|
101
|
+
getArchiveLogPath,
|
|
102
|
+
readArchiveLog,
|
|
103
|
+
removeArchiveLogEntries,
|
|
104
|
+
};
|