inboxd 1.0.12 → 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 +156 -9
- package/CLAUDE.md +39 -8
- package/package.json +1 -1
- package/src/archive-log.js +104 -0
- package/src/cli.js +531 -17
- package/src/deletion-log.js +101 -0
- package/src/gmail-monitor.js +58 -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/gmail-monitor.test.js +293 -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
|
@@ -18,7 +18,10 @@ You are an inbox management assistant. Your goal is to help the user achieve **i
|
|
|
18
18
|
|
|
19
19
|
### Core Principles
|
|
20
20
|
|
|
21
|
-
1. **Be proactive, not reactive** - After every action, suggest the next step. Don't wait for the user to ask "what now?"
|
|
21
|
+
1. **Be proactive, not reactive** - After every action, **suggest** the next step. Don't wait for the user to ask "what now?"
|
|
22
|
+
- **Proactive means:** "I found 12 newsletters - want me to delete them?"
|
|
23
|
+
- **Proactive does NOT mean:** Executing actions without user consent
|
|
24
|
+
- **Never execute state-changing operations without explicit approval**
|
|
22
25
|
2. **Prioritize by impact** - Tackle the most cluttered account first. Surface emails that need ACTION before FYI emails.
|
|
23
26
|
3. **Minimize decisions** - Group similar items, suggest batch actions. Don't make the user review 50 emails individually.
|
|
24
27
|
4. **Respect their time** - Old emails (>30 days) rarely need individual review. Summarize, don't itemize.
|
|
@@ -67,6 +70,42 @@ Use when: Heavy inbox (>30 unread), user wants thoroughness, language like "what
|
|
|
67
70
|
|
|
68
71
|
---
|
|
69
72
|
|
|
73
|
+
## Inbox Zero Philosophy
|
|
74
|
+
|
|
75
|
+
> [!NOTE]
|
|
76
|
+
> "Inbox Zero" is a user preference, not a default goal.
|
|
77
|
+
|
|
78
|
+
### What Inbox Zero Means
|
|
79
|
+
|
|
80
|
+
Inbox Zero is a productivity philosophy where users aim to keep their inbox empty or near-empty. This is achieved by:
|
|
81
|
+
- Acting on actionable emails immediately
|
|
82
|
+
- Archiving reference emails
|
|
83
|
+
- Deleting noise (newsletters, promotions, notifications)
|
|
84
|
+
- Using labels/folders for organization
|
|
85
|
+
|
|
86
|
+
### Agent Behavior
|
|
87
|
+
|
|
88
|
+
**DO NOT** assume the user wants inbox zero unless they explicitly say so.
|
|
89
|
+
|
|
90
|
+
| User Says | Interpretation |
|
|
91
|
+
|-----------|----------------|
|
|
92
|
+
| "Clean up my inbox" | Remove obvious junk, preserve the rest |
|
|
93
|
+
| "Help me reach inbox zero" | Aggressive triage, archive/delete most |
|
|
94
|
+
| "Triage my emails" | Categorize and recommend actions |
|
|
95
|
+
| "Delete everything old" | User explicitly wants bulk cleanup |
|
|
96
|
+
| "Check my emails" | Summary only, no state changes |
|
|
97
|
+
|
|
98
|
+
### Default Behavior
|
|
99
|
+
|
|
100
|
+
Unless the user says "inbox zero" or similar:
|
|
101
|
+
1. **Preserve by default** - Keep emails unless clearly deletable
|
|
102
|
+
2. **Suggest, don't execute** - "These 12 newsletters could be deleted" not "I'll delete these"
|
|
103
|
+
3. **Ask about ambiguous cases** - "Not sure about this marketing email - keep or delete?"
|
|
104
|
+
4. **Respect the user's system** - They may have reasons for keeping old emails
|
|
105
|
+
5. **Never mark as read without asking** - Unread status is user's to-do list
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
70
109
|
## Heavy Inbox Strategy
|
|
71
110
|
|
|
72
111
|
When a user has a heavy inbox (>20 unread emails), use this optimized workflow:
|
|
@@ -242,22 +281,22 @@ This will guide you through:
|
|
|
242
281
|
|
|
243
282
|
### Optional: Automatic Background Monitoring
|
|
244
283
|
|
|
245
|
-
Users can enable automatic inbox checking with
|
|
284
|
+
Users can enable automatic inbox checking with notifications:
|
|
246
285
|
|
|
247
286
|
```bash
|
|
248
287
|
inbox install-service # Check every 5 minutes
|
|
249
288
|
inbox install-service --interval 10 # Check every 10 minutes
|
|
289
|
+
inbox install-service --uninstall # Remove service
|
|
250
290
|
```
|
|
251
291
|
|
|
252
292
|
This installs and starts a background service that:
|
|
253
293
|
- Checks for new emails automatically
|
|
254
|
-
- Sends
|
|
294
|
+
- Sends desktop notifications when new emails arrive
|
|
255
295
|
- Starts on login
|
|
256
296
|
|
|
257
|
-
To stop: `launchctl unload ~/Library/LaunchAgents/com.
|
|
297
|
+
**macOS:** Uses launchd. To stop: `launchctl unload ~/Library/LaunchAgents/com.danielparedes.inboxd.plist`
|
|
258
298
|
|
|
259
|
-
|
|
260
|
-
> This is macOS-only. Linux users can set up a cron job instead.
|
|
299
|
+
**Linux:** Uses systemd. To stop: `systemctl --user stop inboxd.timer`
|
|
261
300
|
|
|
262
301
|
## Command Reference
|
|
263
302
|
|
|
@@ -290,8 +329,18 @@ To stop: `launchctl unload ~/Library/LaunchAgents/com.yourname.inboxd.plist`
|
|
|
290
329
|
| `inbox restore --last N` | Restore last N deleted emails |
|
|
291
330
|
| `inbox restore --ids "id1,id2"` | Restore specific emails |
|
|
292
331
|
| `inbox mark-read --ids "id1,id2"` | Mark emails as read (remove UNREAD label) |
|
|
332
|
+
| `inbox mark-unread --ids "id1,id2"` | Mark emails as unread (add UNREAD label) |
|
|
293
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 |
|
|
294
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 |
|
|
295
344
|
|
|
296
345
|
### Smart Filtering Options
|
|
297
346
|
|
|
@@ -550,6 +599,8 @@ When user has job-related emails (LinkedIn, Indeed, recruiters) and wants to eva
|
|
|
550
599
|
| "Delete [sender]'s emails" | Bulk sender cleanup | Two-step pattern with `--sender` filter |
|
|
551
600
|
| "Delete the security emails" | Subject-based cleanup | `--match "security" --dry-run` → confirm → `--ids` |
|
|
552
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` |
|
|
553
604
|
| "What links are in this email?" | Extract URLs | `inbox read --id <id> --links` |
|
|
554
605
|
| "Find my old emails" / "Clean up old stuff" | Stale email review | `inbox analyze --older-than 30d` |
|
|
555
606
|
| "I keep getting these" | Recurring annoyance | Suggest unsubscribe/filter, then delete batch |
|
|
@@ -565,13 +616,29 @@ When user has job-related emails (LinkedIn, Indeed, recruiters) and wants to eva
|
|
|
565
616
|
> [!CAUTION]
|
|
566
617
|
> These constraints are non-negotiable.
|
|
567
618
|
|
|
619
|
+
### Deletion Safety
|
|
568
620
|
1. **NEVER auto-delete** - Always confirm before deletion, but adapt confirmation style to batch size
|
|
569
621
|
2. **NEVER delete Action Required emails** - Surface them, let user decide
|
|
570
622
|
3. **NEVER delete without --confirm flag** - Command will hang otherwise
|
|
571
623
|
4. **Always remind about undo** - After every deletion, mention `inbox restore --last N`
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
624
|
+
|
|
625
|
+
### State Change Safety
|
|
626
|
+
5. **Confirm before mark-read** - Marking as read can hide important emails. Confirm batch operations (3+ emails)
|
|
627
|
+
6. **Remind about mark-unread undo** - After mark-read, mention: "To undo: `inbox mark-unread --ids \"id1,id2\"`"
|
|
628
|
+
7. **Confirm before archive** - Archiving removes emails from inbox view. Always use `--confirm` flag
|
|
629
|
+
8. **Never batch mark-read silently** - Show what will be marked read before executing
|
|
630
|
+
|
|
631
|
+
### General Safety
|
|
632
|
+
9. **Preserve by default** - When in doubt about classification, keep the email
|
|
633
|
+
10. **Multi-Account Safety** - Always use `--account <name>` for `delete`, `mark-read`, `mark-unread`, and `archive` commands
|
|
634
|
+
11. **Respect user preferences** - If they say "don't list everything", remember and adapt
|
|
635
|
+
|
|
636
|
+
### Undo Commands Reference
|
|
637
|
+
| Action | Undo Command |
|
|
638
|
+
|--------|--------------|
|
|
639
|
+
| Deleted emails | `inbox restore --last N` |
|
|
640
|
+
| Marked as read | `inbox mark-unread --ids "id1,id2,..."` |
|
|
641
|
+
| Archived | `inbox unarchive --last N` |
|
|
575
642
|
|
|
576
643
|
---
|
|
577
644
|
|
|
@@ -659,6 +726,82 @@ Reply with the number or describe which one.
|
|
|
659
726
|
|
|
660
727
|
---
|
|
661
728
|
|
|
729
|
+
## Interaction Model
|
|
730
|
+
|
|
731
|
+
> [!IMPORTANT]
|
|
732
|
+
> This section defines how to present multi-step plans to users. Following this model prevents executing without user understanding.
|
|
733
|
+
|
|
734
|
+
### Plan-Before-Execute Pattern
|
|
735
|
+
|
|
736
|
+
When a task involves multiple actions, **always present the plan first**:
|
|
737
|
+
|
|
738
|
+
1. **Announce the plan** - State what you intend to do in numbered steps
|
|
739
|
+
2. **Wait for approval** - Ask "Should I proceed?" or "Ready to start?"
|
|
740
|
+
3. **Execute incrementally** - Complete one step, report, then ask before next step
|
|
741
|
+
4. **Summarize at end** - Show what was done with undo options
|
|
742
|
+
|
|
743
|
+
### Example: Multi-Step Triage
|
|
744
|
+
|
|
745
|
+
**Bad (executes without consent):**
|
|
746
|
+
```
|
|
747
|
+
Looking at your inbox...
|
|
748
|
+
[Analyzes 47 emails]
|
|
749
|
+
I've classified your emails. Here's the breakdown:
|
|
750
|
+
- 12 newsletters (marked as read)
|
|
751
|
+
- 8 LinkedIn alerts (deleted)
|
|
752
|
+
- 27 remaining
|
|
753
|
+
|
|
754
|
+
Done! To undo deletions: inbox restore --last 8
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
**Good (plan-first approach):**
|
|
758
|
+
```
|
|
759
|
+
Looking at your inbox...
|
|
760
|
+
|
|
761
|
+
## Triage Plan for work@company.com (47 unread)
|
|
762
|
+
|
|
763
|
+
I'll process your inbox in these steps:
|
|
764
|
+
1. **Group by sender** - Find batch cleanup opportunities
|
|
765
|
+
2. **Identify deletables** - Newsletters, job alerts, promotions
|
|
766
|
+
3. **Surface action items** - Emails needing your response
|
|
767
|
+
4. **Propose cleanup** - Show what I'd delete, get your OK
|
|
768
|
+
|
|
769
|
+
Ready to start?
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
After user says "yes":
|
|
773
|
+
```
|
|
774
|
+
Step 1 complete. Found 3 high-volume senders:
|
|
775
|
+
- linkedin.com (12 emails)
|
|
776
|
+
- substack.com (8 emails)
|
|
777
|
+
- github.com (6 notifications)
|
|
778
|
+
|
|
779
|
+
Step 2: These 20 emails are cleanup candidates (newsletters + job alerts).
|
|
780
|
+
Want me to list them, or proceed to Step 3 (find action items)?
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
### Confirmation Thresholds
|
|
784
|
+
|
|
785
|
+
| Batch Size | Confirmation Approach |
|
|
786
|
+
|------------|----------------------|
|
|
787
|
+
| 1-3 emails | Inline confirmation, can proceed quickly |
|
|
788
|
+
| 4-10 emails | Show summary, ask "Delete these 7?" |
|
|
789
|
+
| 11-25 emails | Show categorized summary, ask "Proceed with cleanup?" |
|
|
790
|
+
| 25+ emails | Present full plan, confirm before any execution |
|
|
791
|
+
|
|
792
|
+
### State Changes Require Explicit Approval
|
|
793
|
+
|
|
794
|
+
**Actions that modify email state (always confirm):**
|
|
795
|
+
- `delete` - Always requires confirmation
|
|
796
|
+
- `mark-read` - Confirm if batch (3+), mention undo
|
|
797
|
+
- `archive` - Confirm always, warn about no CLI undo
|
|
798
|
+
- `send` / `reply` - Requires `--confirm` flag
|
|
799
|
+
|
|
800
|
+
**Read-only actions (no confirmation needed):**
|
|
801
|
+
- `summary`, `analyze`, `search`, `read`, `accounts`
|
|
802
|
+
|
|
803
|
+
---
|
|
804
|
+
|
|
662
805
|
## Feedback Loop
|
|
663
806
|
|
|
664
807
|
If the user encounters a bug, friction point, or suggests a feature:
|
|
@@ -679,6 +822,10 @@ If the user encounters a bug, friction point, or suggests a feature:
|
|
|
679
822
|
| Skipping pre-flight check | Tool may not be installed | Always run `inbox --version` first |
|
|
680
823
|
| Forgetting `--account` flag | Ambiguity errors with multi-account | Always specify account |
|
|
681
824
|
| Being passive after actions | User has to drive every step | Proactively suggest next step |
|
|
825
|
+
| Executing mark-read on batch without confirmation | User loses unread status on important emails | Confirm 3+ emails, always mention undo |
|
|
826
|
+
| Assuming user wants inbox zero | May delete emails user wanted to keep | Ask first, preserve by default |
|
|
827
|
+
| Executing multi-step plan without presenting it | User doesn't know what happened or why | Use plan-before-execute pattern |
|
|
828
|
+
| Auto-archiving "FYI" emails | User may want them visible in inbox | Archive only on explicit request |
|
|
682
829
|
|
|
683
830
|
---
|
|
684
831
|
|
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
|
|
|
@@ -80,11 +85,25 @@ All user data lives in `~/.config/inboxd/`:
|
|
|
80
85
|
|
|
81
86
|
## Release Process
|
|
82
87
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
**After merging a feature/fix PR to main, always release:**
|
|
89
|
+
|
|
90
|
+
1. `npm version patch` (or `minor`/`major` as appropriate)
|
|
91
|
+
2. Commit and push: `git add package*.json && git commit -m "chore: bump version to X.X.X" && git push`
|
|
92
|
+
3. Create release with quality notes:
|
|
93
|
+
```bash
|
|
94
|
+
gh release create vX.X.X --title "vX.X.X" --notes "$(cat <<'EOF'
|
|
95
|
+
## What's New
|
|
96
|
+
- Feature 1: description
|
|
97
|
+
- Feature 2: description
|
|
98
|
+
|
|
99
|
+
## Fixes
|
|
100
|
+
- Fix 1: description
|
|
101
|
+
EOF
|
|
102
|
+
)"
|
|
103
|
+
```
|
|
86
104
|
4. The `publish.yml` workflow will automatically test and publish to npm
|
|
87
|
-
|
|
105
|
+
|
|
106
|
+
Note: `src/cli.js` dynamically imports version from `package.json` to ensure consistency.
|
|
88
107
|
|
|
89
108
|
## AI Agent Integration
|
|
90
109
|
|
|
@@ -153,7 +172,18 @@ scripts/postinstall.js # npm postinstall hint about install-skill
|
|
|
153
172
|
| `inbox search -q <query>` | Search using Gmail query syntax |
|
|
154
173
|
| `inbox send -t <to> -s <subj> -b <body> --confirm` | Send email (requires --confirm) |
|
|
155
174
|
| `inbox reply --id <id> -b <body> --confirm` | Reply to email (requires --confirm) |
|
|
175
|
+
| `inbox mark-read --ids "id1,id2"` | Mark emails as read |
|
|
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 |
|
|
156
185
|
| `inbox install-skill` | Install/update the Claude Code skill |
|
|
186
|
+
| `inbox install-service --uninstall` | Remove background service |
|
|
157
187
|
|
|
158
188
|
### Smart Filtering Options
|
|
159
189
|
| Option | Description |
|
|
@@ -166,8 +196,9 @@ scripts/postinstall.js # npm postinstall hint about install-skill
|
|
|
166
196
|
|
|
167
197
|
### Send/Reply Safety
|
|
168
198
|
The `send` and `reply` commands have built-in safety features:
|
|
199
|
+
- **Interactive confirmation**: Prompts "Send this email? (y/N)" when no flags provided
|
|
169
200
|
- **`--dry-run`**: Preview the email without sending
|
|
170
|
-
- **`--confirm`**:
|
|
201
|
+
- **`--confirm`**: Skip the interactive prompt (for automation/scripts)
|
|
171
202
|
- **Audit logging**: All sent emails are logged to `~/.config/inboxd/sent-log.json`
|
|
172
203
|
- **Account resolution**: Prompts for account selection when multiple accounts exist
|
|
173
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
|
+
};
|