@lztek/sarah-sells 0.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.
Files changed (88) hide show
  1. package/AGENTS.md +52 -0
  2. package/CONTEXT.md +42 -0
  3. package/dist/commands/ai.d.ts +3 -0
  4. package/dist/commands/ai.d.ts.map +1 -0
  5. package/dist/commands/ai.js +89 -0
  6. package/dist/commands/ai.js.map +1 -0
  7. package/dist/commands/auth.d.ts +3 -0
  8. package/dist/commands/auth.d.ts.map +1 -0
  9. package/dist/commands/auth.js +154 -0
  10. package/dist/commands/auth.js.map +1 -0
  11. package/dist/commands/campaigns.d.ts +3 -0
  12. package/dist/commands/campaigns.d.ts.map +1 -0
  13. package/dist/commands/campaigns.js +117 -0
  14. package/dist/commands/campaigns.js.map +1 -0
  15. package/dist/commands/inboxes.d.ts +3 -0
  16. package/dist/commands/inboxes.d.ts.map +1 -0
  17. package/dist/commands/inboxes.js +38 -0
  18. package/dist/commands/inboxes.js.map +1 -0
  19. package/dist/commands/leads.d.ts +3 -0
  20. package/dist/commands/leads.d.ts.map +1 -0
  21. package/dist/commands/leads.js +34 -0
  22. package/dist/commands/leads.js.map +1 -0
  23. package/dist/commands/mailgun.d.ts +3 -0
  24. package/dist/commands/mailgun.d.ts.map +1 -0
  25. package/dist/commands/mailgun.js +68 -0
  26. package/dist/commands/mailgun.js.map +1 -0
  27. package/dist/commands/mcp.d.ts +3 -0
  28. package/dist/commands/mcp.d.ts.map +1 -0
  29. package/dist/commands/mcp.js +12 -0
  30. package/dist/commands/mcp.js.map +1 -0
  31. package/dist/commands/org.d.ts +3 -0
  32. package/dist/commands/org.d.ts.map +1 -0
  33. package/dist/commands/org.js +81 -0
  34. package/dist/commands/org.js.map +1 -0
  35. package/dist/commands/prospects.d.ts +3 -0
  36. package/dist/commands/prospects.d.ts.map +1 -0
  37. package/dist/commands/prospects.js +129 -0
  38. package/dist/commands/prospects.js.map +1 -0
  39. package/dist/commands/schema.d.ts +4 -0
  40. package/dist/commands/schema.d.ts.map +1 -0
  41. package/dist/commands/schema.js +23 -0
  42. package/dist/commands/schema.js.map +1 -0
  43. package/dist/commands/templates.d.ts +3 -0
  44. package/dist/commands/templates.d.ts.map +1 -0
  45. package/dist/commands/templates.js +75 -0
  46. package/dist/commands/templates.js.map +1 -0
  47. package/dist/commands/zoominfo.d.ts +3 -0
  48. package/dist/commands/zoominfo.d.ts.map +1 -0
  49. package/dist/commands/zoominfo.js +41 -0
  50. package/dist/commands/zoominfo.js.map +1 -0
  51. package/dist/index.d.ts +3 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +37 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/lib/auth.d.ts +19 -0
  56. package/dist/lib/auth.d.ts.map +1 -0
  57. package/dist/lib/auth.js +151 -0
  58. package/dist/lib/auth.js.map +1 -0
  59. package/dist/lib/http-client.d.ts +21 -0
  60. package/dist/lib/http-client.d.ts.map +1 -0
  61. package/dist/lib/http-client.js +62 -0
  62. package/dist/lib/http-client.js.map +1 -0
  63. package/dist/lib/output.d.ts +7 -0
  64. package/dist/lib/output.d.ts.map +1 -0
  65. package/dist/lib/output.js +22 -0
  66. package/dist/lib/output.js.map +1 -0
  67. package/dist/lib/safety.d.ts +8 -0
  68. package/dist/lib/safety.d.ts.map +1 -0
  69. package/dist/lib/safety.js +64 -0
  70. package/dist/lib/safety.js.map +1 -0
  71. package/dist/lib/schema-registry.d.ts +42 -0
  72. package/dist/lib/schema-registry.d.ts.map +1 -0
  73. package/dist/lib/schema-registry.js +368 -0
  74. package/dist/lib/schema-registry.js.map +1 -0
  75. package/dist/mcp/server.d.ts +2 -0
  76. package/dist/mcp/server.d.ts.map +1 -0
  77. package/dist/mcp/server.js +317 -0
  78. package/dist/mcp/server.js.map +1 -0
  79. package/package.json +50 -0
  80. package/skills/sarah-ai-sdr/SKILL.md +38 -0
  81. package/skills/sarah-campaigns/SKILL.md +54 -0
  82. package/skills/sarah-inboxes/SKILL.md +28 -0
  83. package/skills/sarah-leads/SKILL.md +37 -0
  84. package/skills/sarah-mailgun/SKILL.md +36 -0
  85. package/skills/sarah-org/SKILL.md +41 -0
  86. package/skills/sarah-prospects/SKILL.md +46 -0
  87. package/skills/sarah-setup/SKILL.md +93 -0
  88. package/skills/sarah-zoominfo/SKILL.md +43 -0
package/AGENTS.md ADDED
@@ -0,0 +1,52 @@
1
+ # Agent Safety Rules
2
+
3
+ This CLI is designed for AI agent consumption. Agents are the primary users. These rules apply to all agent interactions with the `sarah` CLI.
4
+
5
+ ## Assume Inputs Can Be Adversarial
6
+
7
+ - All UUIDs are validated before use
8
+ - File paths are checked for directory traversal (`../`)
9
+ - Control characters (below ASCII 0x20) are rejected
10
+ - Resource names reject `?`, `#`, and `%` to prevent query injection and double-encoding
11
+
12
+ ## Mutating Operations Require Safeguards
13
+
14
+ - **Always use `--dry-run` before executing campaign phases.** Campaign execution sends real emails to real people.
15
+ - **Always confirm with the user before destructive operations.** Deleting campaigns, removing leads, and deleting prospect lists require explicit confirmation.
16
+ - **Never execute both campaign phases simultaneously.** Run Mailgun mass first, then SDR follow-up after verifying results.
17
+
18
+ ## Safety Defaults for MCP
19
+
20
+ When accessed via MCP, mutating tools default to safe behavior:
21
+
22
+ - `campaigns_execute` defaults `dryRun` to `true`
23
+ - `prospects_assign_to_campaign` defaults `dryRun` to `true`
24
+
25
+ The agent must explicitly set `dryRun: false` to execute for real, which should only happen after the user confirms.
26
+
27
+ ## Pre-Flight Checks
28
+
29
+ Before executing any campaign phase, verify:
30
+
31
+ 1. `sarah mailgun domains verify` -- DNS records are correct
32
+ 2. `sarah inboxes test <id>` -- Inbox connections are healthy
33
+ 3. `sarah inboxes daily-sent` -- Send limits not exceeded
34
+ 4. `sarah leads list <campaignId>` -- Campaign has leads
35
+ 5. `sarah campaigns execute <id> --phase <type> --dry-run` -- Dry-run succeeds
36
+
37
+ ## Rate Limiting Awareness
38
+
39
+ - Gmail: ~500 emails/day per Google Workspace account
40
+ - Mailgun: Rate limits vary by plan, check Mailgun dashboard
41
+ - ZoomInfo: API quota depends on subscription tier
42
+
43
+ ## Error Handling
44
+
45
+ - All CLI commands return structured JSON, including errors
46
+ - Non-zero exit codes indicate failure
47
+ - Error messages are written to stderr, data to stdout
48
+ - If an API call fails with 401, the access token is expired -- inform the user to refresh it
49
+
50
+ ## Audit Trail
51
+
52
+ Every agent invocation should be traceable. The CLI logs to stderr for observability. In MCP mode, all tool calls are recorded by the MCP client.
package/CONTEXT.md ADDED
@@ -0,0 +1,42 @@
1
+ # SarahAI Platform Context
2
+
3
+ SarahAI (Sarah SDR) is an AI-powered sales development platform by Peliguard. It automates email outreach through two campaign phases:
4
+
5
+ 1. **Mailgun mass phase** -- Bulk brochure emails sent via Mailgun
6
+ 2. **Google SDR follow-up phase** -- Personalized AI-generated follow-ups sent from connected Gmail inboxes
7
+
8
+ ## Core Concepts
9
+
10
+ - **Organization (Location):** Multi-tenant unit. Each org has its own campaigns, leads, inboxes, and Mailgun domain.
11
+ - **Campaign:** An outreach sequence targeting a set of leads through one or both phases.
12
+ - **Prospect List:** A named, reusable collection of contacts. Prospects become leads when assigned to a campaign.
13
+ - **Lead:** A contact assigned to a campaign. Tracked per-campaign for Mailgun and SDR engagement.
14
+ - **Inbox:** A Gmail account connected via OAuth for sending SDR emails. Each inbox has its own AI model configuration.
15
+ - **Copy Template:** Brochure HTML or opener text used in campaigns. Has version history.
16
+ - **AI SDR:** The AI system that generates personalized email responses using OpenAI or Anthropic models.
17
+
18
+ ## API Design
19
+
20
+ All CLI commands map to REST API routes on the SarahAI Next.js backend:
21
+
22
+ - All responses are JSON
23
+ - Auth is via `Authorization: Bearer <supabase_token>` or `X-Auth-Token`
24
+ - Supabase Row Level Security enforces org-scoping and role permissions
25
+ - The CLI can only do what the authenticated user is permitted to do
26
+
27
+ ## Context Window Discipline
28
+
29
+ Workspace APIs can return large payloads. When using the CLI:
30
+
31
+ - **Use `--fields` to limit response fields** when listing campaigns or leads
32
+ - **Process prospect list members in batches** rather than fetching the entire list at once
33
+ - **Use `sarah schema <resource.method>`** to check expected request/response shapes instead of guessing
34
+
35
+ ## Environment Variables
36
+
37
+ | Variable | Required | Description |
38
+ |----------|----------|-------------|
39
+ | `SARAH_ACCESS_TOKEN` | Yes (unless service mode) | Supabase access token for the authenticated user |
40
+ | `SARAH_SERVICE_SECRET` | No | Service secret for cron/admin operations |
41
+ | `SARAH_API_URL` | No | API base URL (defaults to `http://localhost:3010`) |
42
+ | `SARAH_CONFIRM` | No | Set to `true` to skip confirmation prompts |
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const aiCommand: Command;
3
+ //# sourceMappingURL=ai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/commands/ai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,SAAS,SACkC,CAAC"}
@@ -0,0 +1,89 @@
1
+ import { Command } from 'commander';
2
+ import { api } from '../lib/http-client.js';
3
+ import { outputJson, handleApiResponse } from '../lib/output.js';
4
+ import { validateUuid, parseJsonArg } from '../lib/safety.js';
5
+ export const aiCommand = new Command('ai')
6
+ .description('Manage AI models and SDR configuration');
7
+ aiCommand
8
+ .command('models')
9
+ .description('List available AI models')
10
+ .action(async () => {
11
+ const data = handleApiResponse(await api.get('/api/ai/models'));
12
+ outputJson(data);
13
+ });
14
+ const sdrConfig = aiCommand
15
+ .command('sdr-config')
16
+ .description('Manage SDR configuration per inbox');
17
+ sdrConfig
18
+ .command('get <inboxId>')
19
+ .description('Get SDR config for an inbox')
20
+ .action(async (inboxId) => {
21
+ validateUuid(inboxId, 'inbox ID');
22
+ const data = handleApiResponse(await api.get(`/api/ai/sdr-config/${inboxId}`));
23
+ outputJson(data);
24
+ });
25
+ sdrConfig
26
+ .command('set <inboxId>')
27
+ .description('Set SDR config for an inbox')
28
+ .requiredOption('--json <json>', 'SDR config as JSON')
29
+ .action(async (inboxId, opts) => {
30
+ validateUuid(inboxId, 'inbox ID');
31
+ const body = parseJsonArg(opts.json, '--json');
32
+ const data = handleApiResponse(await api.post(`/api/ai/sdr-config/${inboxId}`, body));
33
+ outputJson(data);
34
+ });
35
+ aiCommand
36
+ .command('generate-response')
37
+ .description('Generate an AI SDR response')
38
+ .requiredOption('--json <json>', 'Response generation config as JSON')
39
+ .action(async (opts) => {
40
+ const body = parseJsonArg(opts.json, '--json');
41
+ const data = handleApiResponse(await api.post('/api/ai/sdr-response', body));
42
+ outputJson(data);
43
+ });
44
+ const modelSettings = aiCommand
45
+ .command('model-settings')
46
+ .description('Manage model settings');
47
+ modelSettings
48
+ .command('list')
49
+ .description('List all model settings')
50
+ .action(async () => {
51
+ const data = handleApiResponse(await api.get('/api/ai/model-settings'));
52
+ outputJson(data);
53
+ });
54
+ modelSettings
55
+ .command('get <id>')
56
+ .description('Get a model setting by ID')
57
+ .action(async (id) => {
58
+ validateUuid(id, 'model setting ID');
59
+ const data = handleApiResponse(await api.get(`/api/ai/model-settings/${id}`));
60
+ outputJson(data);
61
+ });
62
+ modelSettings
63
+ .command('create')
64
+ .description('Create a model setting')
65
+ .requiredOption('--json <json>', 'Model setting data as JSON')
66
+ .action(async (opts) => {
67
+ const body = parseJsonArg(opts.json, '--json');
68
+ const data = handleApiResponse(await api.post('/api/ai/model-settings', body));
69
+ outputJson(data);
70
+ });
71
+ modelSettings
72
+ .command('update <id>')
73
+ .description('Update a model setting')
74
+ .requiredOption('--json <json>', 'Model setting update data as JSON')
75
+ .action(async (id, opts) => {
76
+ validateUuid(id, 'model setting ID');
77
+ const body = parseJsonArg(opts.json, '--json');
78
+ const data = handleApiResponse(await api.patch(`/api/ai/model-settings/${id}`, body));
79
+ outputJson(data);
80
+ });
81
+ modelSettings
82
+ .command('delete <id>')
83
+ .description('Delete a model setting')
84
+ .action(async (id) => {
85
+ validateUuid(id, 'model setting ID');
86
+ const data = handleApiResponse(await api.delete(`/api/ai/model-settings/${id}`));
87
+ outputJson(data);
88
+ });
89
+ //# sourceMappingURL=ai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.js","sourceRoot":"","sources":["../../src/commands/ai.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const authCommand: Command;
3
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiDpC,eAAO,MAAM,WAAW,SACe,CAAC"}
@@ -0,0 +1,154 @@
1
+ import { Command } from 'commander';
2
+ import * as readline from 'node:readline';
3
+ import { getAccessToken, getApiUrl, loginWithPassword, clearSession, getStoredSessionInfo, getServiceSecret } from '../lib/auth.js';
4
+ import { api } from '../lib/http-client.js';
5
+ import { outputJson, outputError, outputSuccess } from '../lib/output.js';
6
+ function prompt(question, hidden = false) {
7
+ return new Promise((resolve) => {
8
+ const rl = readline.createInterface({
9
+ input: process.stdin,
10
+ output: process.stdout,
11
+ });
12
+ if (hidden && process.stdin.isTTY) {
13
+ process.stdout.write(question);
14
+ const stdin = process.stdin;
15
+ const wasRaw = stdin.isRaw;
16
+ stdin.setRawMode(true);
17
+ stdin.resume();
18
+ let input = '';
19
+ const onData = (char) => {
20
+ const c = char.toString();
21
+ if (c === '\n' || c === '\r') {
22
+ stdin.setRawMode(wasRaw ?? false);
23
+ stdin.removeListener('data', onData);
24
+ process.stdout.write('\n');
25
+ rl.close();
26
+ resolve(input);
27
+ }
28
+ else if (c === '\u0003') {
29
+ // Ctrl+C
30
+ rl.close();
31
+ process.exit(130);
32
+ }
33
+ else if (c === '\u007F' || c === '\b') {
34
+ input = input.slice(0, -1);
35
+ }
36
+ else {
37
+ input += c;
38
+ }
39
+ };
40
+ stdin.on('data', onData);
41
+ }
42
+ else {
43
+ rl.question(question, (answer) => {
44
+ rl.close();
45
+ resolve(answer);
46
+ });
47
+ }
48
+ });
49
+ }
50
+ export const authCommand = new Command('auth')
51
+ .description('Manage authentication');
52
+ authCommand
53
+ .command('login')
54
+ .description('Log in with email and password (session stored in ~/.config/sarah/)')
55
+ .option('-e, --email <email>', 'Email address')
56
+ .option('-p, --password <password>', 'Password (omit for interactive prompt)')
57
+ .action(async (opts) => {
58
+ try {
59
+ const email = opts.email || await prompt('Email: ');
60
+ const password = opts.password || await prompt('Password: ', true);
61
+ if (!email || !password) {
62
+ outputError('Email and password are required.');
63
+ process.exit(1);
64
+ }
65
+ const session = await loginWithPassword(email, password);
66
+ const expiresAt = new Date(session.expires_at * 1000).toISOString();
67
+ outputJson({
68
+ authenticated: true,
69
+ email: session.user_email,
70
+ token_preview: `${session.access_token.substring(0, 20)}...`,
71
+ expires_at: expiresAt,
72
+ session_stored: '~/.config/sarah/session.json',
73
+ });
74
+ outputSuccess(`Logged in as ${session.user_email}. Session stored locally.`);
75
+ }
76
+ catch (err) {
77
+ outputError(err instanceof Error ? err.message : String(err));
78
+ process.exit(1);
79
+ }
80
+ });
81
+ authCommand
82
+ .command('logout')
83
+ .description('Clear stored session')
84
+ .action(() => {
85
+ clearSession();
86
+ outputSuccess('Session cleared.');
87
+ });
88
+ authCommand
89
+ .command('token')
90
+ .description('Print the current access token and validate it')
91
+ .action(async () => {
92
+ try {
93
+ const token = await getAccessToken();
94
+ const apiUrl = getApiUrl();
95
+ const response = await api.get('/api/organization/check');
96
+ if (response.ok) {
97
+ outputJson({
98
+ authenticated: true,
99
+ api_url: apiUrl,
100
+ token_preview: `${token.substring(0, 20)}...${token.substring(token.length - 10)}`,
101
+ });
102
+ }
103
+ else {
104
+ outputJson({
105
+ authenticated: false,
106
+ api_url: apiUrl,
107
+ error: response.error,
108
+ });
109
+ process.exit(1);
110
+ }
111
+ }
112
+ catch (err) {
113
+ outputError(err instanceof Error ? err.message : String(err));
114
+ process.exit(1);
115
+ }
116
+ });
117
+ authCommand
118
+ .command('status')
119
+ .description('Show current auth configuration')
120
+ .action(() => {
121
+ const hasEnvToken = !!process.env.SARAH_ACCESS_TOKEN;
122
+ const hasService = !!getServiceSecret();
123
+ const storedSession = getStoredSessionInfo();
124
+ const apiUrl = getApiUrl();
125
+ let authMode = 'none';
126
+ if (hasService)
127
+ authMode = 'service';
128
+ else if (hasEnvToken)
129
+ authMode = 'env_token';
130
+ else if (storedSession)
131
+ authMode = 'session';
132
+ const info = {
133
+ api_url: apiUrl,
134
+ auth_mode: authMode,
135
+ env_token_set: hasEnvToken,
136
+ service_secret_set: hasService,
137
+ };
138
+ if (storedSession) {
139
+ const now = Math.floor(Date.now() / 1000);
140
+ const expired = now >= storedSession.expires_at;
141
+ info.session = {
142
+ email: storedSession.email,
143
+ expires_at: new Date(storedSession.expires_at * 1000).toISOString(),
144
+ expired,
145
+ auto_refresh: !expired,
146
+ };
147
+ }
148
+ outputJson(info);
149
+ if (authMode === 'none') {
150
+ outputError('Not authenticated. Run `sarah auth login` to get started.');
151
+ process.exit(1);
152
+ }
153
+ });
154
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const campaignsCommand: Command;
3
+ //# sourceMappingURL=campaigns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"campaigns.d.ts","sourceRoot":"","sources":["../../src/commands/campaigns.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,gBAAgB,SACK,CAAC"}
@@ -0,0 +1,117 @@
1
+ import { Command } from 'commander';
2
+ import { api } from '../lib/http-client.js';
3
+ import { outputJson, handleApiResponse, outputSuccess, outputError } from '../lib/output.js';
4
+ import { validateUuid, parseJsonArg, confirmAction } from '../lib/safety.js';
5
+ export const campaignsCommand = new Command('campaigns')
6
+ .description('Manage campaigns');
7
+ campaignsCommand
8
+ .command('list')
9
+ .description('List all campaigns')
10
+ .option('--fields <fields>', 'Comma-separated fields to return')
11
+ .action(async (opts) => {
12
+ const data = handleApiResponse(await api.get('/api/campaigns', { fields: opts.fields }));
13
+ outputJson(data);
14
+ });
15
+ campaignsCommand
16
+ .command('get <id>')
17
+ .description('Get a campaign by ID')
18
+ .option('--fields <fields>', 'Comma-separated fields to return')
19
+ .action(async (id, opts) => {
20
+ validateUuid(id, 'campaign ID');
21
+ const data = handleApiResponse(await api.get(`/api/campaigns/${id}`, { fields: opts.fields }));
22
+ outputJson(data);
23
+ });
24
+ campaignsCommand
25
+ .command('create')
26
+ .description('Create a new campaign')
27
+ .requiredOption('--json <json>', 'Campaign data as JSON')
28
+ .option('--dry-run', 'Validate without creating')
29
+ .action(async (opts) => {
30
+ const body = parseJsonArg(opts.json, '--json');
31
+ if (opts.dryRun) {
32
+ outputJson({ dry_run: true, would_create: body });
33
+ return;
34
+ }
35
+ const data = handleApiResponse(await api.post('/api/campaigns', body));
36
+ outputJson(data);
37
+ });
38
+ campaignsCommand
39
+ .command('update <id>')
40
+ .description('Update a campaign')
41
+ .requiredOption('--json <json>', 'Campaign update data as JSON')
42
+ .option('--dry-run', 'Validate without updating')
43
+ .action(async (id, opts) => {
44
+ validateUuid(id, 'campaign ID');
45
+ const body = parseJsonArg(opts.json, '--json');
46
+ if (opts.dryRun) {
47
+ outputJson({ dry_run: true, campaign_id: id, would_update: body });
48
+ return;
49
+ }
50
+ const data = handleApiResponse(await api.patch(`/api/campaigns/${id}`, body));
51
+ outputJson(data);
52
+ });
53
+ campaignsCommand
54
+ .command('delete <id>')
55
+ .description('Delete a campaign')
56
+ .option('--confirm', 'Skip confirmation prompt')
57
+ .action(async (id, opts) => {
58
+ validateUuid(id, 'campaign ID');
59
+ if (!opts.confirm) {
60
+ const confirmed = await confirmAction(`Delete campaign ${id}?`);
61
+ if (!confirmed) {
62
+ outputError('Cancelled');
63
+ process.exit(1);
64
+ }
65
+ }
66
+ const data = handleApiResponse(await api.delete(`/api/campaigns/${id}`));
67
+ outputJson(data);
68
+ outputSuccess(`Campaign ${id} deleted`);
69
+ });
70
+ campaignsCommand
71
+ .command('execute <id>')
72
+ .description('Execute a campaign phase')
73
+ .requiredOption('--phase <type>', 'Phase type: mailgun_mass or google_sdr_followup')
74
+ .option('--dry-run', 'Preview execution without sending')
75
+ .action(async (id, opts) => {
76
+ validateUuid(id, 'campaign ID');
77
+ const validPhases = ['mailgun_mass', 'google_sdr_followup'];
78
+ if (!validPhases.includes(opts.phase)) {
79
+ outputError(`Invalid phase "${opts.phase}". Must be one of: ${validPhases.join(', ')}`);
80
+ process.exit(1);
81
+ }
82
+ const body = {
83
+ phaseType: opts.phase,
84
+ dryRun: opts.dryRun || false,
85
+ };
86
+ const data = handleApiResponse(await api.post(`/api/campaigns/${id}/execute`, body));
87
+ outputJson(data);
88
+ });
89
+ campaignsCommand
90
+ .command('metrics <id>')
91
+ .description('Get campaign metrics')
92
+ .action(async (id) => {
93
+ validateUuid(id, 'campaign ID');
94
+ const data = handleApiResponse(await api.get(`/api/campaigns/${id}/metrics`));
95
+ outputJson(data);
96
+ });
97
+ campaignsCommand
98
+ .command('test-brochure <id>')
99
+ .description('Send a test brochure for a campaign')
100
+ .requiredOption('--json <json>', 'Test brochure config as JSON')
101
+ .action(async (id, opts) => {
102
+ validateUuid(id, 'campaign ID');
103
+ const body = parseJsonArg(opts.json, '--json');
104
+ const data = handleApiResponse(await api.post(`/api/campaigns/${id}/test-brochure`, body));
105
+ outputJson(data);
106
+ });
107
+ campaignsCommand
108
+ .command('test-sdr <id>')
109
+ .description('Test SDR response generation for a campaign')
110
+ .requiredOption('--json <json>', 'Test SDR config as JSON')
111
+ .action(async (id, opts) => {
112
+ validateUuid(id, 'campaign ID');
113
+ const body = parseJsonArg(opts.json, '--json');
114
+ const data = handleApiResponse(await api.post(`/api/campaigns/${id}/test-sdr`, body));
115
+ outputJson(data);
116
+ });
117
+ //# sourceMappingURL=campaigns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"campaigns.js","sourceRoot":"","sources":["../../src/commands/campaigns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const inboxesCommand: Command;
3
+ //# sourceMappingURL=inboxes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inboxes.d.ts","sourceRoot":"","sources":["../../src/commands/inboxes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,cAAc,SACW,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { Command } from 'commander';
2
+ import { api } from '../lib/http-client.js';
3
+ import { outputJson, handleApiResponse } from '../lib/output.js';
4
+ import { validateUuid } from '../lib/safety.js';
5
+ export const inboxesCommand = new Command('inboxes')
6
+ .description('Manage email inboxes');
7
+ inboxesCommand
8
+ .command('list')
9
+ .description('List all inboxes')
10
+ .option('--fields <fields>', 'Comma-separated fields to return')
11
+ .action(async (opts) => {
12
+ const data = handleApiResponse(await api.get('/api/inboxes', { fields: opts.fields }));
13
+ outputJson(data);
14
+ });
15
+ inboxesCommand
16
+ .command('test <id>')
17
+ .description('Test an inbox connection')
18
+ .action(async (id) => {
19
+ validateUuid(id, 'inbox ID');
20
+ const data = handleApiResponse(await api.post(`/api/inboxes/${id}/test`));
21
+ outputJson(data);
22
+ });
23
+ inboxesCommand
24
+ .command('diagnostics <id>')
25
+ .description('Get inbox diagnostics')
26
+ .action(async (id) => {
27
+ validateUuid(id, 'inbox ID');
28
+ const data = handleApiResponse(await api.get(`/api/inboxes/${id}/diagnostics`));
29
+ outputJson(data);
30
+ });
31
+ inboxesCommand
32
+ .command('daily-sent')
33
+ .description('Get daily sent counts for all inboxes')
34
+ .action(async () => {
35
+ const data = handleApiResponse(await api.get('/api/inboxes/daily-sent-counts'));
36
+ outputJson(data);
37
+ });
38
+ //# sourceMappingURL=inboxes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inboxes.js","sourceRoot":"","sources":["../../src/commands/inboxes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC;KACjD,WAAW,CAAC,sBAAsB,CAAC,CAAC;AAEvC,cAAc;KACX,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,kBAAkB,CAAC;KAC/B,MAAM,CAAC,mBAAmB,EAAE,kCAAkC,CAAC;KAC/D,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,MAAM,IAAI,GAAG,iBAAiB,CAC5B,MAAM,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CACvD,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEL,cAAc;KACX,OAAO,CAAC,WAAW,CAAC;KACpB,WAAW,CAAC,0BAA0B,CAAC;KACvC,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,EAAE;IAC3B,YAAY,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,iBAAiB,CAC5B,MAAM,GAAG,CAAC,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAC1C,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEL,cAAc;KACX,OAAO,CAAC,kBAAkB,CAAC;KAC3B,WAAW,CAAC,uBAAuB,CAAC;KACpC,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,EAAE;IAC3B,YAAY,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,iBAAiB,CAC5B,MAAM,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAChD,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEL,cAAc;KACX,OAAO,CAAC,YAAY,CAAC;KACrB,WAAW,CAAC,uCAAuC,CAAC;KACpD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,IAAI,GAAG,iBAAiB,CAC5B,MAAM,GAAG,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAChD,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const leadsCommand: Command;
3
+ //# sourceMappingURL=leads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leads.d.ts","sourceRoot":"","sources":["../../src/commands/leads.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,YAAY,SACc,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { Command } from 'commander';
2
+ import { api } from '../lib/http-client.js';
3
+ import { outputJson, handleApiResponse, outputSuccess, outputError } from '../lib/output.js';
4
+ import { validateUuid, confirmAction } from '../lib/safety.js';
5
+ export const leadsCommand = new Command('leads')
6
+ .description('Manage campaign leads');
7
+ leadsCommand
8
+ .command('list <campaignId>')
9
+ .description('List leads for a campaign')
10
+ .option('--fields <fields>', 'Comma-separated fields to return')
11
+ .action(async (campaignId, opts) => {
12
+ validateUuid(campaignId, 'campaign ID');
13
+ const data = handleApiResponse(await api.get(`/api/campaigns/${campaignId}/leads`, { fields: opts.fields }));
14
+ outputJson(data);
15
+ });
16
+ leadsCommand
17
+ .command('remove <campaignId> <leadId>')
18
+ .description('Remove a lead from a campaign')
19
+ .option('--confirm', 'Skip confirmation prompt')
20
+ .action(async (campaignId, leadId, opts) => {
21
+ validateUuid(campaignId, 'campaign ID');
22
+ validateUuid(leadId, 'lead ID');
23
+ if (!opts.confirm) {
24
+ const confirmed = await confirmAction(`Remove lead ${leadId} from campaign ${campaignId}?`);
25
+ if (!confirmed) {
26
+ outputError('Cancelled');
27
+ process.exit(1);
28
+ }
29
+ }
30
+ const data = handleApiResponse(await api.delete(`/api/campaigns/${campaignId}/leads/${leadId}`));
31
+ outputJson(data);
32
+ outputSuccess(`Lead ${leadId} removed from campaign ${campaignId}`);
33
+ });
34
+ //# sourceMappingURL=leads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leads.js","sourceRoot":"","sources":["../../src/commands/leads.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC7F,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE/D,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,uBAAuB,CAAC,CAAC;AAExC,YAAY;KACT,OAAO,CAAC,mBAAmB,CAAC;KAC5B,WAAW,CAAC,2BAA2B,CAAC;KACxC,MAAM,CAAC,mBAAmB,EAAE,kCAAkC,CAAC;KAC/D,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,IAAI,EAAE,EAAE;IACzC,YAAY,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,iBAAiB,CAC5B,MAAM,GAAG,CAAC,GAAG,CAAC,kBAAkB,UAAU,QAAQ,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAC7E,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEL,YAAY;KACT,OAAO,CAAC,8BAA8B,CAAC;KACvC,WAAW,CAAC,+BAA+B,CAAC;KAC5C,MAAM,CAAC,WAAW,EAAE,0BAA0B,CAAC;KAC/C,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,MAAc,EAAE,IAAI,EAAE,EAAE;IACzD,YAAY,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IACxC,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAEhC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,eAAe,MAAM,kBAAkB,UAAU,GAAG,CAAC,CAAC;QAC5F,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,WAAW,CAAC,WAAW,CAAC,CAAC;YACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,iBAAiB,CAC5B,MAAM,GAAG,CAAC,MAAM,CAAC,kBAAkB,UAAU,UAAU,MAAM,EAAE,CAAC,CACjE,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,CAAC;IACjB,aAAa,CAAC,QAAQ,MAAM,0BAA0B,UAAU,EAAE,CAAC,CAAC;AACtE,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const mailgunCommand: Command;
3
+ //# sourceMappingURL=mailgun.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mailgun.d.ts","sourceRoot":"","sources":["../../src/commands/mailgun.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,cAAc,SACqC,CAAC"}