@cakemail-org/cakemail-cli 1.5.0 → 2.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/.claude/settings.local.json +12 -0
- package/.env.example +40 -0
- package/.env.test.example +45 -0
- package/CHANGELOG.md +1031 -0
- package/README.md +319 -15
- package/audit-formats.js +128 -0
- package/cakemail.rb +20 -0
- package/dist/cli.js +27 -10
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +16 -6
- package/dist/client.js.map +1 -1
- package/dist/commands/account.js +1 -1
- package/dist/commands/account.js.map +1 -1
- package/dist/commands/attributes.js +1 -1
- package/dist/commands/attributes.js.map +1 -1
- package/dist/commands/campaigns.d.ts.map +1 -1
- package/dist/commands/campaigns.js +103 -8
- package/dist/commands/campaigns.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +63 -4
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/contacts.d.ts.map +1 -1
- package/dist/commands/contacts.js +91 -12
- package/dist/commands/contacts.js.map +1 -1
- package/dist/commands/emails.js +1 -1
- package/dist/commands/emails.js.map +1 -1
- package/dist/commands/interests.d.ts +5 -0
- package/dist/commands/interests.d.ts.map +1 -0
- package/dist/commands/interests.js +172 -0
- package/dist/commands/interests.js.map +1 -0
- package/dist/commands/lists.d.ts.map +1 -1
- package/dist/commands/lists.js +6 -8
- package/dist/commands/lists.js.map +1 -1
- package/dist/commands/logs.d.ts +5 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +237 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/reports.js +1 -1
- package/dist/commands/reports.js.map +1 -1
- package/dist/commands/segments.js +1 -1
- package/dist/commands/segments.js.map +1 -1
- package/dist/commands/senders.d.ts.map +1 -1
- package/dist/commands/senders.js +11 -8
- package/dist/commands/senders.js.map +1 -1
- package/dist/commands/suppressed.js +1 -1
- package/dist/commands/suppressed.js.map +1 -1
- package/dist/commands/tags.d.ts +5 -0
- package/dist/commands/tags.d.ts.map +1 -0
- package/dist/commands/tags.js +124 -0
- package/dist/commands/tags.js.map +1 -0
- package/dist/commands/templates.js +1 -1
- package/dist/commands/templates.js.map +1 -1
- package/dist/commands/transactional-templates.d.ts +5 -0
- package/dist/commands/transactional-templates.d.ts.map +1 -0
- package/dist/commands/transactional-templates.js +354 -0
- package/dist/commands/transactional-templates.js.map +1 -0
- package/dist/commands/webhooks.js +1 -1
- package/dist/commands/webhooks.js.map +1 -1
- package/dist/utils/auth.d.ts +8 -1
- package/dist/utils/auth.d.ts.map +1 -1
- package/dist/utils/auth.js +39 -11
- package/dist/utils/auth.js.map +1 -1
- package/dist/utils/config-file.d.ts +7 -0
- package/dist/utils/config-file.d.ts.map +1 -1
- package/dist/utils/config-file.js +15 -0
- package/dist/utils/config-file.js.map +1 -1
- package/dist/utils/config.d.ts +2 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +12 -4
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/errors.js +1 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/list-defaults.d.ts +33 -0
- package/dist/utils/list-defaults.d.ts.map +1 -0
- package/dist/utils/list-defaults.js +52 -0
- package/dist/utils/list-defaults.js.map +1 -0
- package/dist/utils/output.d.ts.map +1 -1
- package/dist/utils/output.js +36 -13
- package/dist/utils/output.js.map +1 -1
- package/dist/utils/progress.d.ts.map +1 -1
- package/dist/utils/progress.js +32 -4
- package/dist/utils/progress.js.map +1 -1
- package/dist/utils/spinner.d.ts +17 -0
- package/dist/utils/spinner.d.ts.map +1 -0
- package/dist/utils/spinner.js +43 -0
- package/dist/utils/spinner.js.map +1 -0
- package/docs/DOCUMENTATION-STANDARD.md +1068 -0
- package/docs/README.md +161 -0
- package/docs/developer/ARCHITECTURE.md +516 -0
- package/docs/developer/AUTH.md +204 -0
- package/docs/developer/CONTRIBUTING.md +227 -0
- package/docs/developer/DOCUMENTATION_SUMMARY.md +346 -0
- package/docs/developer/PROJECT_INDEX.md +365 -0
- package/docs/planning/API_COVERAGE.md +1045 -0
- package/docs/planning/BACKLOG.md +1159 -0
- package/docs/planning/PROFILE_SYSTEM_TASKS.md +287 -0
- package/docs/planning/UX_IMPLEMENTATION_PLAN.md +691 -0
- package/docs/planning/archive/RELEASE_CHECKLIST_v1.3.0.md +332 -0
- package/docs/planning/archive/RELEASE_v1.3.0.md +428 -0
- package/docs/planning/archive/cakemail-cli-ux-improvements.md +438 -0
- package/docs/planning/cakemail-profile-system-plan.md +1121 -0
- package/docs/testing/AI_USER_SIMULATION_DESIGN.md +1342 -0
- package/docs/testing/KENOGAMI_BIDIRECTIONAL_FLOW.md +1517 -0
- package/docs/testing/KENOGAMI_TRUTH_RECONCILIATION_SYSTEM.md +1369 -0
- package/docs/user-manual/.obsidian/app.json +1 -0
- package/docs/user-manual/.obsidian/appearance.json +1 -0
- package/docs/user-manual/.obsidian/core-plugins.json +33 -0
- package/docs/user-manual/.obsidian/workspace.json +167 -0
- package/docs/user-manual/01-getting-started/01-installation.md +214 -0
- package/docs/user-manual/01-getting-started/02-quick-start.md +432 -0
- package/docs/user-manual/01-getting-started/03-authentication.md +448 -0
- package/docs/user-manual/01-getting-started/04-configuration.md +430 -0
- package/docs/user-manual/01-getting-started/05-output-formats.md +447 -0
- package/docs/user-manual/02-core-concepts/01-accounts.md +514 -0
- package/docs/user-manual/02-core-concepts/02-profile-system.md +771 -0
- package/docs/user-manual/02-core-concepts/03-smart-defaults.md +485 -0
- package/docs/user-manual/02-core-concepts/04-authentication-methods.md +435 -0
- package/docs/user-manual/02-core-concepts/05-pagination-filtering.md +600 -0
- package/docs/user-manual/02-core-concepts/06-error-handling.md +718 -0
- package/docs/user-manual/02-core-concepts/07-api-coverage.md +483 -0
- package/docs/user-manual/03-email-operations/01-senders.md +490 -0
- package/docs/user-manual/03-email-operations/02-templates.md +444 -0
- package/docs/user-manual/03-email-operations/03-transactional-emails.md +706 -0
- package/docs/user-manual/03-email-operations/04-email-tracking.md +407 -0
- package/docs/user-manual/04-campaign-management/01-campaigns-basics.md +394 -0
- package/docs/user-manual/04-campaign-management/02-campaign-scheduling.md +630 -0
- package/docs/user-manual/04-campaign-management/03-campaign-testing.md +997 -0
- package/docs/user-manual/04-campaign-management/04-campaign-lifecycle.md +709 -0
- package/docs/user-manual/04-campaign-management/05-campaign-links.md +934 -0
- package/docs/user-manual/05-contact-management/01-lists.md +836 -0
- package/docs/user-manual/05-contact-management/02-contacts.md +1035 -0
- package/docs/user-manual/05-contact-management/03-custom-attributes.md +788 -0
- package/docs/user-manual/05-contact-management/04-segments.md +1028 -0
- package/docs/user-manual/05-contact-management/05-contact-import-export.md +1031 -0
- package/docs/user-manual/06-analytics-reporting/01-campaign-analytics.md +867 -0
- package/docs/user-manual/06-analytics-reporting/02-account-reports.md +227 -0
- package/docs/user-manual/07-integrations/01-webhooks-integration.md +259 -0
- package/docs/user-manual/07-integrations/02-automation.md +326 -0
- package/docs/user-manual/08-advanced-usage/01-scripting-patterns.md +672 -0
- package/docs/user-manual/08-advanced-usage/02-bulk-operations.md +932 -0
- package/docs/user-manual/08-advanced-usage/03-ci-cd-integration.md +892 -0
- package/docs/user-manual/08-advanced-usage/04-performance-optimization.md +766 -0
- package/docs/user-manual/09-command-reference/01-config.md +776 -0
- package/docs/user-manual/09-command-reference/02-account.md +652 -0
- package/docs/user-manual/09-command-reference/03-lists.md +958 -0
- package/docs/user-manual/09-command-reference/04-contacts.md +1408 -0
- package/docs/user-manual/09-command-reference/05-attributes.md +617 -0
- package/docs/user-manual/09-command-reference/06-segments.md +894 -0
- package/docs/user-manual/09-command-reference/07-senders.md +803 -0
- package/docs/user-manual/09-command-reference/08-templates.md +818 -0
- package/docs/user-manual/09-command-reference/09-campaigns.md +1250 -0
- package/docs/user-manual/09-command-reference/10-emails.md +807 -0
- package/docs/user-manual/09-command-reference/11-reports.md +1135 -0
- package/docs/user-manual/09-command-reference/12-webhooks.md +773 -0
- package/docs/user-manual/09-command-reference/13-suppressed.md +797 -0
- package/docs/user-manual/09-command-reference/14-interests.md +630 -0
- package/docs/user-manual/09-command-reference/15-tags.md +584 -0
- package/docs/user-manual/09-command-reference/16-logs.md +656 -0
- package/docs/user-manual/09-command-reference/17-transactional-templates.md +850 -0
- package/docs/user-manual/10-troubleshooting/01-common-errors.md +457 -0
- package/docs/user-manual/10-troubleshooting/02-authentication-issues.md +558 -0
- package/docs/user-manual/10-troubleshooting/03-connection-problems.md +634 -0
- package/docs/user-manual/10-troubleshooting/04-debugging.md +725 -0
- package/docs/user-manual/11-appendix/04-faq.md +484 -0
- package/docs/user-manual/11-appendix/05-glossary.md +250 -0
- package/docs/user-manual/README.md +0 -0
- package/package.json +13 -47
- package/src/cli.ts +125 -0
- package/src/client.ts +16 -0
- package/src/commands/account.ts +267 -0
- package/src/commands/accounts.ts +78 -0
- package/src/commands/actions.ts +249 -0
- package/src/commands/attributes.ts +139 -0
- package/src/commands/campaign-blueprints.ts +106 -0
- package/src/commands/campaigns.ts +469 -0
- package/src/commands/config.ts +77 -0
- package/src/commands/contacts.ts +612 -0
- package/src/commands/custom-attributes.ts +127 -0
- package/src/commands/dkims.ts +117 -0
- package/src/commands/domains.ts +82 -0
- package/src/commands/email-apis.ts +569 -0
- package/src/commands/emails.ts +197 -0
- package/src/commands/forms.ts +283 -0
- package/src/commands/interests.ts +155 -0
- package/src/commands/links.ts +38 -0
- package/src/commands/lists.ts +406 -0
- package/src/commands/logos.ts +71 -0
- package/src/commands/logs.ts +386 -0
- package/src/commands/reports.ts +306 -0
- package/src/commands/segments.ts +158 -0
- package/src/commands/senders.ts +204 -0
- package/src/commands/sub-accounts.ts +271 -0
- package/src/commands/suppressed-emails.ts +234 -0
- package/src/commands/suppressed.ts +198 -0
- package/src/commands/system-emails.ts +85 -0
- package/src/commands/tags.ts +146 -0
- package/src/commands/tasks.ts +116 -0
- package/src/commands/templates.ts +189 -0
- package/src/commands/tokens.ts +83 -0
- package/src/commands/transactional-emails.ts +374 -0
- package/src/commands/transactional-templates.ts +385 -0
- package/src/commands/users.ts +506 -0
- package/src/commands/webhooks.ts +172 -0
- package/src/commands/workflow-blueprints.ts +123 -0
- package/src/commands/workflows.ts +265 -0
- package/src/types/profile.ts +93 -0
- package/src/utils/auth.ts +272 -0
- package/src/utils/config-file.ts +96 -0
- package/src/utils/config.ts +134 -0
- package/src/utils/confirm.ts +32 -0
- package/src/utils/defaults.ts +99 -0
- package/src/utils/errors.ts +116 -0
- package/src/utils/interactive.ts +91 -0
- package/src/utils/list-defaults.ts +74 -0
- package/src/utils/output.ts +190 -0
- package/src/utils/progress.ts +320 -0
- package/src/utils/spinner.ts +22 -0
- package/tests/IMPLEMENTATION_STATUS.md +258 -0
- package/tests/PTY_SETUP.md +118 -0
- package/tests/PTY_TESTING_GUIDE.md +507 -0
- package/tests/README.md +244 -0
- package/tests/fixtures/api-responses/campaigns.json +34 -0
- package/tests/fixtures/test-config.json +13 -0
- package/tests/helpers/cli-runner.ts +128 -0
- package/tests/helpers/mock-server.ts +301 -0
- package/tests/helpers/pty-runner.ts +181 -0
- package/tests/integration/campaigns-real-api.test.ts +196 -0
- package/tests/integration/setup-integration.ts +50 -0
- package/tests/pty/campaigns.test.ts +241 -0
- package/tests/setup.ts +34 -0
- package/tsconfig.json +15 -0
- package/vitest.config.ts +28 -0
|
@@ -0,0 +1,691 @@
|
|
|
1
|
+
# Cakemail CLI UX Implementation Plan
|
|
2
|
+
|
|
3
|
+
## Executive Summary
|
|
4
|
+
|
|
5
|
+
This plan outlines the phased implementation of UX improvements for the Cakemail CLI, transforming it from a developer-focused tool to a user-friendly CLI accessible to both technical and non-technical users.
|
|
6
|
+
|
|
7
|
+
**Current State (v1.3.0):**
|
|
8
|
+
- 104 commands (45% API coverage)
|
|
9
|
+
- Environment variable auth only
|
|
10
|
+
- JSON/table/compact output
|
|
11
|
+
- Strong foundation, but steep learning curve
|
|
12
|
+
|
|
13
|
+
**Target State (v2.0.0):**
|
|
14
|
+
- Interactive auth and onboarding
|
|
15
|
+
- User-friendly error messages
|
|
16
|
+
- Natural language date parsing
|
|
17
|
+
- Preview capabilities
|
|
18
|
+
- Guided workflows for new users
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Phase 1: Critical UX Foundations (v1.4.0) - 3-4 weeks
|
|
23
|
+
|
|
24
|
+
**Goal:** Remove barriers to adoption for new users
|
|
25
|
+
|
|
26
|
+
### Milestone 1.4.0 Features
|
|
27
|
+
|
|
28
|
+
#### 1. Interactive Auth Setup (Week 1)
|
|
29
|
+
**Priority:** CRITICAL - Blocks all non-technical users
|
|
30
|
+
**Effort:** Medium
|
|
31
|
+
**Dependencies:** None
|
|
32
|
+
|
|
33
|
+
**Implementation:**
|
|
34
|
+
```typescript
|
|
35
|
+
// src/commands/auth.ts
|
|
36
|
+
export function createAuthCommand(client, formatter) {
|
|
37
|
+
const auth = new Command('auth')
|
|
38
|
+
.description('Manage authentication');
|
|
39
|
+
|
|
40
|
+
auth.command('setup')
|
|
41
|
+
.description('Interactive auth configuration')
|
|
42
|
+
.action(async () => {
|
|
43
|
+
// 1. Prompt for auth method (email/password or token)
|
|
44
|
+
// 2. Validate credentials
|
|
45
|
+
// 3. Save to ~/.cakemail/config.json (encrypted)
|
|
46
|
+
// 4. Show success message with account info
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
auth.command('status')
|
|
50
|
+
.description('Show current auth status')
|
|
51
|
+
.action(async () => {
|
|
52
|
+
// Show: method, user, expiry
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
auth.command('logout')
|
|
56
|
+
.description('Clear stored credentials')
|
|
57
|
+
.action(async () => {
|
|
58
|
+
// Remove config file, confirm
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Files to create/modify:**
|
|
64
|
+
- Create: `src/commands/auth.ts`
|
|
65
|
+
- Create: `src/utils/config-manager.ts` (handles ~/.cakemail/config.json)
|
|
66
|
+
- Create: `src/utils/encryption.ts` (encrypt/decrypt credentials)
|
|
67
|
+
- Modify: `src/utils/config.ts` (add config file support)
|
|
68
|
+
- Modify: `src/cli.ts` (add auth command)
|
|
69
|
+
|
|
70
|
+
**Library additions:**
|
|
71
|
+
- `inquirer` - Interactive prompts
|
|
72
|
+
- `node-keytar` or `crypto` - Secure credential storage
|
|
73
|
+
- `conf` - Config file management
|
|
74
|
+
|
|
75
|
+
**Testing:**
|
|
76
|
+
- Unit tests for config manager
|
|
77
|
+
- Integration tests for auth flow
|
|
78
|
+
- Test priority: CLI flag > Project config > Global config > Env vars
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
#### 2. Actionable Error Messages (Week 1-2)
|
|
83
|
+
**Priority:** CRITICAL - Current errors frustrate users
|
|
84
|
+
**Effort:** Medium
|
|
85
|
+
**Dependencies:** None
|
|
86
|
+
|
|
87
|
+
**Implementation:**
|
|
88
|
+
```typescript
|
|
89
|
+
// src/utils/error-translator.ts
|
|
90
|
+
export class ErrorTranslator {
|
|
91
|
+
static translate(error: any): string {
|
|
92
|
+
// Map API error codes to user-friendly messages
|
|
93
|
+
const errorMap = {
|
|
94
|
+
401: {
|
|
95
|
+
message: 'Authentication failed. Your credentials may be expired.',
|
|
96
|
+
suggestion: 'Run: cakemail auth setup'
|
|
97
|
+
},
|
|
98
|
+
403: {
|
|
99
|
+
message: (error) => this.handle403(error),
|
|
100
|
+
suggestion: (error) => this.suggest403(error)
|
|
101
|
+
},
|
|
102
|
+
422: {
|
|
103
|
+
message: (error) => this.handleValidation(error),
|
|
104
|
+
suggestion: (error) => this.suggestValidation(error)
|
|
105
|
+
},
|
|
106
|
+
404: {
|
|
107
|
+
message: (error) => `${error.resource} not found`,
|
|
108
|
+
suggestion: 'Check the ID and try again'
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Special handlers for specific error scenarios
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private static handle403(error: any): string {
|
|
116
|
+
if (error.message.includes('sender')) {
|
|
117
|
+
return `Sender '${error.details.email}' is not verified.`;
|
|
118
|
+
}
|
|
119
|
+
if (error.message.includes('permission')) {
|
|
120
|
+
return 'You don\'t have permission for this action.';
|
|
121
|
+
}
|
|
122
|
+
return 'Access denied.';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private static suggest403(error: any): string {
|
|
126
|
+
if (error.message.includes('sender')) {
|
|
127
|
+
return `Run: cakemail senders resend-confirmation ${error.details.id}`;
|
|
128
|
+
}
|
|
129
|
+
return 'Contact your account administrator.';
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Files to create/modify:**
|
|
135
|
+
- Create: `src/utils/error-translator.ts`
|
|
136
|
+
- Create: `src/utils/error-patterns.ts` (common error patterns)
|
|
137
|
+
- Modify: `src/utils/output.ts` (integrate error translator)
|
|
138
|
+
- Modify: All command files (wrap API calls with error translation)
|
|
139
|
+
|
|
140
|
+
**Testing:**
|
|
141
|
+
- Unit tests for each error code
|
|
142
|
+
- Integration tests with real API errors
|
|
143
|
+
- Test with `--debug` flag shows full error
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
#### 3. Natural Date Parsing (Week 2)
|
|
148
|
+
**Priority:** HIGH - ISO 8601 is a major pain point
|
|
149
|
+
**Effort:** Low
|
|
150
|
+
**Dependencies:** None
|
|
151
|
+
|
|
152
|
+
**Implementation:**
|
|
153
|
+
```typescript
|
|
154
|
+
// src/utils/date-parser.ts
|
|
155
|
+
import { parseDate } from 'chrono-node';
|
|
156
|
+
import { formatISO, parse, addDays, addHours } from 'date-fns';
|
|
157
|
+
|
|
158
|
+
export class DateParser {
|
|
159
|
+
static parse(input: string, userTimezone?: string): string {
|
|
160
|
+
// Try multiple parsing strategies:
|
|
161
|
+
|
|
162
|
+
// 1. Relative dates: "tomorrow", "+2 days", "next monday"
|
|
163
|
+
if (input.startsWith('+') || input.includes('next') || input.includes('tomorrow')) {
|
|
164
|
+
return this.parseRelative(input);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 2. Natural language: "Oct 15 10:00", "tomorrow 10am"
|
|
168
|
+
const chronoResult = parseDate(input);
|
|
169
|
+
if (chronoResult) {
|
|
170
|
+
return formatISO(chronoResult);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// 3. ISO 8601 (keep existing support)
|
|
174
|
+
if (this.isISO8601(input)) {
|
|
175
|
+
return input;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 4. Simple format: "2025-10-15 10:00"
|
|
179
|
+
try {
|
|
180
|
+
const parsed = parse(input, 'yyyy-MM-dd HH:mm', new Date());
|
|
181
|
+
return formatISO(parsed);
|
|
182
|
+
} catch (e) {
|
|
183
|
+
throw new Error(`Cannot parse date: "${input}". Try: "tomorrow 10am" or "2025-10-15 10:00"`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
static confirm(parsed: string, original: string): boolean {
|
|
188
|
+
// Show what was parsed, ask for confirmation
|
|
189
|
+
console.log(chalk.cyan(`Parsed "${original}" as: ${format(parseISO(parsed), 'PPpp')}`));
|
|
190
|
+
// Return true to confirm
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Files to create/modify:**
|
|
196
|
+
- Create: `src/utils/date-parser.ts`
|
|
197
|
+
- Modify: `src/commands/campaigns.ts` (schedule, reschedule)
|
|
198
|
+
- Modify: `src/commands/reports.ts` (date filtering)
|
|
199
|
+
|
|
200
|
+
**Library additions:**
|
|
201
|
+
- `chrono-node` - Natural language date parsing
|
|
202
|
+
- `date-fns` - Date manipulation and formatting
|
|
203
|
+
|
|
204
|
+
**Testing:**
|
|
205
|
+
- Unit tests for each date format
|
|
206
|
+
- Test timezone handling
|
|
207
|
+
- Test future date validation
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
#### 4. Quickstart Wizard (Week 3)
|
|
212
|
+
**Priority:** CRITICAL - First user experience
|
|
213
|
+
**Effort:** High
|
|
214
|
+
**Dependencies:** Auth setup, error messages
|
|
215
|
+
|
|
216
|
+
**Implementation:**
|
|
217
|
+
```typescript
|
|
218
|
+
// src/commands/quickstart.ts
|
|
219
|
+
import inquirer from 'inquirer';
|
|
220
|
+
|
|
221
|
+
export function createQuickstartCommand(client, formatter) {
|
|
222
|
+
return new Command('quickstart')
|
|
223
|
+
.description('Guided onboarding: send your first email')
|
|
224
|
+
.action(async () => {
|
|
225
|
+
const wizard = new QuickstartWizard(client, formatter);
|
|
226
|
+
await wizard.run();
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
class QuickstartWizard {
|
|
231
|
+
async run() {
|
|
232
|
+
console.log(chalk.bold.blue('\n🚀 Welcome to Cakemail CLI!\n'));
|
|
233
|
+
console.log('Let\'s get you set up and send your first email.\n');
|
|
234
|
+
|
|
235
|
+
// Step 1: Check auth
|
|
236
|
+
await this.checkAuth();
|
|
237
|
+
|
|
238
|
+
// Step 2: Get/create sender
|
|
239
|
+
const sender = await this.getSender();
|
|
240
|
+
|
|
241
|
+
// Step 3: Get/create list
|
|
242
|
+
const list = await this.getList();
|
|
243
|
+
|
|
244
|
+
// Step 4: Add test contact
|
|
245
|
+
const contact = await this.addTestContact(list.id);
|
|
246
|
+
|
|
247
|
+
// Step 5: Create/select template
|
|
248
|
+
const content = await this.getContent();
|
|
249
|
+
|
|
250
|
+
// Step 6: Send test email
|
|
251
|
+
await this.sendTestEmail(sender, contact, content);
|
|
252
|
+
|
|
253
|
+
// Step 7: Success & next steps
|
|
254
|
+
this.showSuccess();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private async checkAuth() {
|
|
258
|
+
try {
|
|
259
|
+
await this.client.sdk.accountService.getSelfAccount();
|
|
260
|
+
console.log(chalk.green('✓ Already authenticated\n'));
|
|
261
|
+
} catch (error) {
|
|
262
|
+
console.log(chalk.yellow('Need to set up authentication first...\n'));
|
|
263
|
+
// Run auth setup
|
|
264
|
+
const authCmd = createAuthCommand(this.client, this.formatter);
|
|
265
|
+
await authCmd.parseAsync(['node', 'cli', 'auth', 'setup']);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
private async getSender() {
|
|
270
|
+
const { senders } = await this.client.sdk.senderService.listSenders({});
|
|
271
|
+
|
|
272
|
+
if (senders.length === 0) {
|
|
273
|
+
console.log(chalk.cyan('No senders found. Let\'s create one.\n'));
|
|
274
|
+
return await this.createSender();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const { sender } = await inquirer.prompt([{
|
|
278
|
+
type: 'list',
|
|
279
|
+
name: 'sender',
|
|
280
|
+
message: 'Choose a sender:',
|
|
281
|
+
choices: [
|
|
282
|
+
...senders.map(s => ({
|
|
283
|
+
name: `${s.name} <${s.email}> ${s.confirmed ? '✓' : '⚠️ Unverified'}`,
|
|
284
|
+
value: s
|
|
285
|
+
})),
|
|
286
|
+
{ name: '+ Create new sender', value: 'new' }
|
|
287
|
+
]
|
|
288
|
+
}]);
|
|
289
|
+
|
|
290
|
+
if (sender === 'new') {
|
|
291
|
+
return await this.createSender();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (!sender.confirmed) {
|
|
295
|
+
console.log(chalk.yellow(`\n⚠️ Sender "${sender.email}" needs verification.`));
|
|
296
|
+
console.log(`Check your email and confirm, or run:`);
|
|
297
|
+
console.log(chalk.cyan(` cakemail senders resend-confirmation ${sender.id}\n`));
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return sender;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
private async createSender() {
|
|
304
|
+
const { name, email } = await inquirer.prompt([
|
|
305
|
+
{
|
|
306
|
+
type: 'input',
|
|
307
|
+
name: 'name',
|
|
308
|
+
message: 'Sender name:',
|
|
309
|
+
default: 'My Company'
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
type: 'input',
|
|
313
|
+
name: 'email',
|
|
314
|
+
message: 'Sender email:',
|
|
315
|
+
validate: (input) => this.validateEmail(input)
|
|
316
|
+
}
|
|
317
|
+
]);
|
|
318
|
+
|
|
319
|
+
const sender = await this.client.sdk.senderService.createSender({
|
|
320
|
+
requestBody: { name, email }
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
console.log(chalk.green('\n✓ Sender created!'));
|
|
324
|
+
console.log(chalk.yellow('→ Verification email sent. Check your inbox.\n'));
|
|
325
|
+
|
|
326
|
+
return sender;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Similar methods for list, contact, content, sending...
|
|
330
|
+
|
|
331
|
+
private showSuccess() {
|
|
332
|
+
console.log(chalk.bold.green('\n🎉 Success! Your first email has been sent.\n'));
|
|
333
|
+
console.log('Next steps:');
|
|
334
|
+
console.log(' • View campaigns: ' + chalk.cyan('cakemail campaigns list'));
|
|
335
|
+
console.log(' • Create template: ' + chalk.cyan('cakemail templates create'));
|
|
336
|
+
console.log(' • Manage contacts: ' + chalk.cyan('cakemail contacts list <list-id>'));
|
|
337
|
+
console.log(' • View analytics: ' + chalk.cyan('cakemail reports campaign <id>'));
|
|
338
|
+
console.log('\nDocumentation: https://docs.cakemail.com/cli\n');
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**Files to create/modify:**
|
|
344
|
+
- Create: `src/commands/quickstart.ts`
|
|
345
|
+
- Create: `src/utils/wizard-helpers.ts` (shared wizard utilities)
|
|
346
|
+
- Modify: `src/cli.ts` (add quickstart command)
|
|
347
|
+
|
|
348
|
+
**Library additions:**
|
|
349
|
+
- `inquirer` - Interactive prompts
|
|
350
|
+
- `ora` - Already included, use for spinners
|
|
351
|
+
|
|
352
|
+
**Testing:**
|
|
353
|
+
- Integration tests for each step
|
|
354
|
+
- Test skip functionality
|
|
355
|
+
- Test resume from interruption
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
### v1.4.0 Release Checklist
|
|
360
|
+
|
|
361
|
+
**Code:**
|
|
362
|
+
- [ ] All features implemented and tested
|
|
363
|
+
- [ ] Unit tests passing (target: 80%+ coverage for new code)
|
|
364
|
+
- [ ] Integration tests passing
|
|
365
|
+
- [ ] Manual testing completed
|
|
366
|
+
- [ ] Code review completed
|
|
367
|
+
|
|
368
|
+
**Documentation:**
|
|
369
|
+
- [ ] README updated with auth setup instructions
|
|
370
|
+
- [ ] New commands documented
|
|
371
|
+
- [ ] Quickstart guide added
|
|
372
|
+
- [ ] Migration guide from v1.3
|
|
373
|
+
- [ ] CHANGELOG updated
|
|
374
|
+
|
|
375
|
+
**Release:**
|
|
376
|
+
- [ ] Version bumped to 1.4.0
|
|
377
|
+
- [ ] Build and test locally
|
|
378
|
+
- [ ] Publish to npm
|
|
379
|
+
- [ ] Update Homebrew formula
|
|
380
|
+
- [ ] Announce release
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## Phase 2: Enhanced Usability (v1.5.0) - 2-3 weeks
|
|
385
|
+
|
|
386
|
+
**Goal:** Polish the experience and add power user features
|
|
387
|
+
|
|
388
|
+
### Milestone 1.5.0 Features
|
|
389
|
+
|
|
390
|
+
#### 1. Email Preview (Week 1)
|
|
391
|
+
**Files:** `src/utils/preview.ts`, modify `src/commands/emails.ts`
|
|
392
|
+
**Libraries:** `open` (open browser)
|
|
393
|
+
|
|
394
|
+
#### 2. Interactive Mode for Missing Fields (Week 1-2)
|
|
395
|
+
**Files:** `src/middleware/interactive-prompts.ts`, modify all command files
|
|
396
|
+
**Libraries:** `inquirer`
|
|
397
|
+
|
|
398
|
+
#### 3. Confirmation for Dangerous Operations (Week 2)
|
|
399
|
+
**Files:** `src/middleware/confirmation.ts`, modify delete/cancel commands
|
|
400
|
+
**Libraries:** `inquirer`
|
|
401
|
+
|
|
402
|
+
#### 4. Rich Table Output (Week 2)
|
|
403
|
+
**Files:** Modify `src/utils/output.ts`
|
|
404
|
+
**Libraries:** `chalk`, `date-fns`
|
|
405
|
+
|
|
406
|
+
#### 5. Search/Find Commands (Week 2-3)
|
|
407
|
+
**Files:** Add `find` subcommands to campaigns, templates, senders
|
|
408
|
+
**Libraries:** `fuzzysort`
|
|
409
|
+
|
|
410
|
+
#### 6. Smart File Handling (Week 3)
|
|
411
|
+
**Files:** `src/utils/file-parser.ts`, modify `src/commands/emails.ts`
|
|
412
|
+
**Libraries:** `cheerio` (parse HTML)
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## Phase 3: Power User Features (v1.6.0) - 2-3 weeks
|
|
417
|
+
|
|
418
|
+
**Goal:** Advanced workflows and customization
|
|
419
|
+
|
|
420
|
+
### Milestone 1.6.0 Features
|
|
421
|
+
|
|
422
|
+
#### 1. Configuration Management (Week 1)
|
|
423
|
+
**Files:** Create `src/commands/config.ts`, expand `src/utils/config-manager.ts`
|
|
424
|
+
|
|
425
|
+
#### 2. Shell Completion (Week 1)
|
|
426
|
+
**Files:** Create `src/commands/completion.ts`
|
|
427
|
+
**Libraries:** `omelette` or built-in completion
|
|
428
|
+
|
|
429
|
+
#### 3. Bulk Operations Enhancement (Week 2)
|
|
430
|
+
**Files:** Enhance contact import/export, add progress bars
|
|
431
|
+
**Libraries:** `cli-progress`
|
|
432
|
+
|
|
433
|
+
#### 4. Dry Run Mode (Week 2)
|
|
434
|
+
**Files:** `src/middleware/dry-run.ts`, modify all write operations
|
|
435
|
+
|
|
436
|
+
#### 5. Aliases (Week 3)
|
|
437
|
+
**Files:** Create `src/commands/alias.ts`, add alias resolver
|
|
438
|
+
|
|
439
|
+
#### 6. Template Scaffolding (Week 3)
|
|
440
|
+
**Files:** Create `src/commands/init.ts`, add template library
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## Phase 4: Nice to Have (v1.7.0+) - Ongoing
|
|
445
|
+
|
|
446
|
+
### Features
|
|
447
|
+
- Enhanced help with examples
|
|
448
|
+
- Improved default output
|
|
449
|
+
- Better scripting support (exit codes, quiet mode, verbose mode)
|
|
450
|
+
- Update notifications
|
|
451
|
+
- `--watch` mode for real-time updates
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## Implementation Strategy
|
|
456
|
+
|
|
457
|
+
### Week-by-Week Breakdown (First 4 Weeks - v1.4.0)
|
|
458
|
+
|
|
459
|
+
**Week 1:**
|
|
460
|
+
- Days 1-2: Auth setup command (setup, status, logout)
|
|
461
|
+
- Days 3-4: Config manager and encryption
|
|
462
|
+
- Day 5: Testing and documentation
|
|
463
|
+
|
|
464
|
+
**Week 2:**
|
|
465
|
+
- Days 1-2: Error translator and pattern matching
|
|
466
|
+
- Days 3-4: Natural date parsing
|
|
467
|
+
- Day 5: Testing and integration
|
|
468
|
+
|
|
469
|
+
**Week 3:**
|
|
470
|
+
- Days 1-3: Quickstart wizard (all steps)
|
|
471
|
+
- Days 4-5: Testing and polish
|
|
472
|
+
|
|
473
|
+
**Week 4:**
|
|
474
|
+
- Days 1-2: Integration testing
|
|
475
|
+
- Days 3-4: Documentation and examples
|
|
476
|
+
- Day 5: Release prep and publish
|
|
477
|
+
|
|
478
|
+
### Development Workflow
|
|
479
|
+
|
|
480
|
+
1. **Feature Branch Strategy:**
|
|
481
|
+
- `feat/auth-setup`
|
|
482
|
+
- `feat/error-messages`
|
|
483
|
+
- `feat/date-parsing`
|
|
484
|
+
- `feat/quickstart-wizard`
|
|
485
|
+
|
|
486
|
+
2. **Testing Strategy:**
|
|
487
|
+
- Write tests before implementation (TDD)
|
|
488
|
+
- Unit tests for utilities
|
|
489
|
+
- Integration tests for commands
|
|
490
|
+
- Manual testing for interactive features
|
|
491
|
+
|
|
492
|
+
3. **Code Review:**
|
|
493
|
+
- All features require review
|
|
494
|
+
- Check UX, error handling, edge cases
|
|
495
|
+
- Verify backwards compatibility
|
|
496
|
+
|
|
497
|
+
4. **Documentation:**
|
|
498
|
+
- Update README for each feature
|
|
499
|
+
- Add examples to docs
|
|
500
|
+
- Update API_COVERAGE.md
|
|
501
|
+
- Create migration guides
|
|
502
|
+
|
|
503
|
+
---
|
|
504
|
+
|
|
505
|
+
## Dependencies and Libraries
|
|
506
|
+
|
|
507
|
+
### New Dependencies for v1.4.0:
|
|
508
|
+
```json
|
|
509
|
+
{
|
|
510
|
+
"dependencies": {
|
|
511
|
+
"inquirer": "^9.2.0", // Interactive prompts
|
|
512
|
+
"conf": "^11.0.0", // Config management
|
|
513
|
+
"chrono-node": "^2.7.0", // Date parsing
|
|
514
|
+
"date-fns": "^2.30.0" // Date formatting
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### For Future Versions:
|
|
520
|
+
```json
|
|
521
|
+
{
|
|
522
|
+
"dependencies": {
|
|
523
|
+
"fuzzysort": "^2.0.0", // Fuzzy search (v1.5)
|
|
524
|
+
"open": "^9.1.0", // Open browser (v1.5)
|
|
525
|
+
"cheerio": "^1.0.0-rc.12", // Parse HTML (v1.5)
|
|
526
|
+
"cli-progress": "^3.12.0", // Progress bars (v1.6)
|
|
527
|
+
"omelette": "^0.4.0", // Shell completion (v1.6)
|
|
528
|
+
"update-notifier": "^6.0.0" // Update checks (v1.7)
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
## Success Metrics
|
|
536
|
+
|
|
537
|
+
### Quantitative:
|
|
538
|
+
- **Time to first email:** < 5 minutes for new users (via quickstart)
|
|
539
|
+
- **Auth setup success rate:** > 95%
|
|
540
|
+
- **Error resolution rate:** > 80% (users resolve errors without support)
|
|
541
|
+
- **CLI adoption:** +50% increase in WAU
|
|
542
|
+
- **Support tickets:** -30% "how do I" questions
|
|
543
|
+
|
|
544
|
+
### Qualitative:
|
|
545
|
+
- User feedback surveys (NPS score)
|
|
546
|
+
- Community feedback (GitHub issues, discussions)
|
|
547
|
+
- Internal team feedback
|
|
548
|
+
- Customer success team feedback
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
## Risk Mitigation
|
|
553
|
+
|
|
554
|
+
### Risk 1: Breaking Changes
|
|
555
|
+
**Mitigation:**
|
|
556
|
+
- Maintain backwards compatibility for all existing commands
|
|
557
|
+
- Add new features as opt-in (flags, new commands)
|
|
558
|
+
- Provide clear migration guides
|
|
559
|
+
- Test extensively with real users
|
|
560
|
+
|
|
561
|
+
### Risk 2: Complexity Creep
|
|
562
|
+
**Mitigation:**
|
|
563
|
+
- Keep features focused and simple
|
|
564
|
+
- Don't over-engineer
|
|
565
|
+
- Prioritize based on user feedback
|
|
566
|
+
- Can always add more later
|
|
567
|
+
|
|
568
|
+
### Risk 3: Performance
|
|
569
|
+
**Mitigation:**
|
|
570
|
+
- Lazy load dependencies (especially for interactive features)
|
|
571
|
+
- Cache config and frequently-used data
|
|
572
|
+
- Optimize API calls (batch when possible)
|
|
573
|
+
- Test with large datasets
|
|
574
|
+
|
|
575
|
+
### Risk 4: Platform Compatibility
|
|
576
|
+
**Mitigation:**
|
|
577
|
+
- Test on macOS, Linux, Windows
|
|
578
|
+
- Test with different terminal emulators
|
|
579
|
+
- Handle non-TTY environments gracefully
|
|
580
|
+
- Provide fallbacks for unsupported features
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
## Next Immediate Steps
|
|
585
|
+
|
|
586
|
+
1. **This Week (Week 1):**
|
|
587
|
+
- [ ] Create feature branch `feat/ux-v1.4`
|
|
588
|
+
- [ ] Install new dependencies (`inquirer`, `conf`, `chrono-node`, `date-fns`)
|
|
589
|
+
- [ ] Create project structure (commands/auth.ts, utils/config-manager.ts, etc.)
|
|
590
|
+
- [ ] Implement auth setup command
|
|
591
|
+
- [ ] Write unit tests for auth
|
|
592
|
+
- [ ] Manual testing
|
|
593
|
+
|
|
594
|
+
2. **Get User Feedback:**
|
|
595
|
+
- [ ] Share plan with internal team
|
|
596
|
+
- [ ] Get feedback from beta users
|
|
597
|
+
- [ ] Adjust priorities based on feedback
|
|
598
|
+
|
|
599
|
+
3. **Track Progress:**
|
|
600
|
+
- [ ] Create GitHub project board
|
|
601
|
+
- [ ] Create issues for each feature
|
|
602
|
+
- [ ] Weekly progress updates
|
|
603
|
+
- [ ] Demo to stakeholders
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
607
|
+
## Appendix: Architecture Changes
|
|
608
|
+
|
|
609
|
+
### Config File Structure
|
|
610
|
+
|
|
611
|
+
```json
|
|
612
|
+
{
|
|
613
|
+
"version": "1.4.0",
|
|
614
|
+
"auth": {
|
|
615
|
+
"method": "email", // or "token"
|
|
616
|
+
"email": "user@example.com",
|
|
617
|
+
"password": "encrypted_password",
|
|
618
|
+
"token": "encrypted_token",
|
|
619
|
+
"baseURL": "https://api.cakemail.dev"
|
|
620
|
+
},
|
|
621
|
+
"defaults": {
|
|
622
|
+
"senderId": 456,
|
|
623
|
+
"listId": 123,
|
|
624
|
+
"outputFormat": "compact"
|
|
625
|
+
},
|
|
626
|
+
"quickstart": {
|
|
627
|
+
"completed": true,
|
|
628
|
+
"completedAt": "2025-10-11T10:00:00Z"
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### Directory Structure
|
|
634
|
+
|
|
635
|
+
```
|
|
636
|
+
~/.cakemail/
|
|
637
|
+
├── config.json # Global config
|
|
638
|
+
└── cache/ # Cached data (lists, senders, etc.)
|
|
639
|
+
├── senders.json
|
|
640
|
+
└── lists.json
|
|
641
|
+
|
|
642
|
+
project/.cakemail/
|
|
643
|
+
└── config.json # Project-local config (overrides global)
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
### Error Translation Map
|
|
647
|
+
|
|
648
|
+
```typescript
|
|
649
|
+
// src/utils/error-patterns.ts
|
|
650
|
+
export const ERROR_PATTERNS = {
|
|
651
|
+
401: {
|
|
652
|
+
patterns: [
|
|
653
|
+
{
|
|
654
|
+
match: /invalid credentials/i,
|
|
655
|
+
message: 'Invalid email or password',
|
|
656
|
+
suggestion: 'Run: cakemail auth setup'
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
match: /token expired/i,
|
|
660
|
+
message: 'Your session has expired',
|
|
661
|
+
suggestion: 'Run: cakemail auth setup'
|
|
662
|
+
}
|
|
663
|
+
],
|
|
664
|
+
default: {
|
|
665
|
+
message: 'Authentication failed',
|
|
666
|
+
suggestion: 'Check your credentials'
|
|
667
|
+
}
|
|
668
|
+
},
|
|
669
|
+
403: {
|
|
670
|
+
patterns: [
|
|
671
|
+
{
|
|
672
|
+
match: /sender.*not verified/i,
|
|
673
|
+
message: (details) => `Sender '${details.email}' is not verified`,
|
|
674
|
+
suggestion: (details) => `Run: cakemail senders resend-confirmation ${details.id}`
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
match: /permission denied/i,
|
|
678
|
+
message: 'You don\'t have permission for this action',
|
|
679
|
+
suggestion: 'Contact your account administrator'
|
|
680
|
+
}
|
|
681
|
+
]
|
|
682
|
+
},
|
|
683
|
+
// ... more error patterns
|
|
684
|
+
};
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
---
|
|
688
|
+
|
|
689
|
+
*Last Updated: 2025-10-11*
|
|
690
|
+
*Version: 1.0*
|
|
691
|
+
*Author: Claude Code*
|