@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.
- package/AGENTS.md +52 -0
- package/CONTEXT.md +42 -0
- package/dist/commands/ai.d.ts +3 -0
- package/dist/commands/ai.d.ts.map +1 -0
- package/dist/commands/ai.js +89 -0
- package/dist/commands/ai.js.map +1 -0
- package/dist/commands/auth.d.ts +3 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +154 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/campaigns.d.ts +3 -0
- package/dist/commands/campaigns.d.ts.map +1 -0
- package/dist/commands/campaigns.js +117 -0
- package/dist/commands/campaigns.js.map +1 -0
- package/dist/commands/inboxes.d.ts +3 -0
- package/dist/commands/inboxes.d.ts.map +1 -0
- package/dist/commands/inboxes.js +38 -0
- package/dist/commands/inboxes.js.map +1 -0
- package/dist/commands/leads.d.ts +3 -0
- package/dist/commands/leads.d.ts.map +1 -0
- package/dist/commands/leads.js +34 -0
- package/dist/commands/leads.js.map +1 -0
- package/dist/commands/mailgun.d.ts +3 -0
- package/dist/commands/mailgun.d.ts.map +1 -0
- package/dist/commands/mailgun.js +68 -0
- package/dist/commands/mailgun.js.map +1 -0
- package/dist/commands/mcp.d.ts +3 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +12 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/org.d.ts +3 -0
- package/dist/commands/org.d.ts.map +1 -0
- package/dist/commands/org.js +81 -0
- package/dist/commands/org.js.map +1 -0
- package/dist/commands/prospects.d.ts +3 -0
- package/dist/commands/prospects.d.ts.map +1 -0
- package/dist/commands/prospects.js +129 -0
- package/dist/commands/prospects.js.map +1 -0
- package/dist/commands/schema.d.ts +4 -0
- package/dist/commands/schema.d.ts.map +1 -0
- package/dist/commands/schema.js +23 -0
- package/dist/commands/schema.js.map +1 -0
- package/dist/commands/templates.d.ts +3 -0
- package/dist/commands/templates.d.ts.map +1 -0
- package/dist/commands/templates.js +75 -0
- package/dist/commands/templates.js.map +1 -0
- package/dist/commands/zoominfo.d.ts +3 -0
- package/dist/commands/zoominfo.d.ts.map +1 -0
- package/dist/commands/zoominfo.js +41 -0
- package/dist/commands/zoominfo.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/auth.d.ts +19 -0
- package/dist/lib/auth.d.ts.map +1 -0
- package/dist/lib/auth.js +151 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/http-client.d.ts +21 -0
- package/dist/lib/http-client.d.ts.map +1 -0
- package/dist/lib/http-client.js +62 -0
- package/dist/lib/http-client.js.map +1 -0
- package/dist/lib/output.d.ts +7 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +22 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/safety.d.ts +8 -0
- package/dist/lib/safety.d.ts.map +1 -0
- package/dist/lib/safety.js +64 -0
- package/dist/lib/safety.js.map +1 -0
- package/dist/lib/schema-registry.d.ts +42 -0
- package/dist/lib/schema-registry.d.ts.map +1 -0
- package/dist/lib/schema-registry.js +368 -0
- package/dist/lib/schema-registry.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +317 -0
- package/dist/mcp/server.js.map +1 -0
- package/package.json +50 -0
- package/skills/sarah-ai-sdr/SKILL.md +38 -0
- package/skills/sarah-campaigns/SKILL.md +54 -0
- package/skills/sarah-inboxes/SKILL.md +28 -0
- package/skills/sarah-leads/SKILL.md +37 -0
- package/skills/sarah-mailgun/SKILL.md +36 -0
- package/skills/sarah-org/SKILL.md +41 -0
- package/skills/sarah-prospects/SKILL.md +46 -0
- package/skills/sarah-setup/SKILL.md +93 -0
- 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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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":"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,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE7E,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,OAAO,CAAC,WAAW,CAAC;KACrD,WAAW,CAAC,kBAAkB,CAAC,CAAC;AAEnC,gBAAgB;KACb,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,oBAAoB,CAAC;KACjC,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,gBAAgB,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CACzD,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEL,gBAAgB;KACb,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,sBAAsB,CAAC;KACnC,MAAM,CAAC,mBAAmB,EAAE,kCAAkC,CAAC;KAC/D,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,IAAI,EAAE,EAAE;IACjC,YAAY,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,iBAAiB,CAC5B,MAAM,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAC/D,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEL,gBAAgB;KACb,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,uBAAuB,CAAC;KACpC,cAAc,CAAC,eAAe,EAAE,uBAAuB,CAAC;KACxD,MAAM,CAAC,WAAW,EAAE,2BAA2B,CAAC;KAChD,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAE/C,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,iBAAiB,CAC5B,MAAM,GAAG,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,CACvC,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEL,gBAAgB;KACb,OAAO,CAAC,aAAa,CAAC;KACtB,WAAW,CAAC,mBAAmB,CAAC;KAChC,cAAc,CAAC,eAAe,EAAE,8BAA8B,CAAC;KAC/D,MAAM,CAAC,WAAW,EAAE,2BAA2B,CAAC;KAChD,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,IAAI,EAAE,EAAE;IACjC,YAAY,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAE/C,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACnE,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,iBAAiB,CAC5B,MAAM,GAAG,CAAC,KAAK,CAAC,kBAAkB,EAAE,EAAE,EAAE,IAAI,CAAC,CAC9C,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEL,gBAAgB;KACb,OAAO,CAAC,aAAa,CAAC;KACtB,WAAW,CAAC,mBAAmB,CAAC;KAChC,MAAM,CAAC,WAAW,EAAE,0BAA0B,CAAC;KAC/C,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,IAAI,EAAE,EAAE;IACjC,YAAY,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;IAEhC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;QAChE,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,EAAE,EAAE,CAAC,CACzC,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,CAAC;IACjB,aAAa,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEL,gBAAgB;KACb,OAAO,CAAC,cAAc,CAAC;KACvB,WAAW,CAAC,0BAA0B,CAAC;KACvC,cAAc,CAAC,gBAAgB,EAAE,iDAAiD,CAAC;KACnF,MAAM,CAAC,WAAW,EAAE,mCAAmC,CAAC;KACxD,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,IAAI,EAAE,EAAE;IACjC,YAAY,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;IAChC,MAAM,WAAW,GAAG,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;IAC5D,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACtC,WAAW,CAAC,kBAAkB,IAAI,CAAC,KAAK,sBAAsB,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG;QACX,SAAS,EAAE,IAAI,CAAC,KAAK;QACrB,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,KAAK;KAC7B,CAAC;IAEF,MAAM,IAAI,GAAG,iBAAiB,CAC5B,MAAM,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,UAAU,EAAE,IAAI,CAAC,CACrD,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEL,gBAAgB;KACb,OAAO,CAAC,cAAc,CAAC;KACvB,WAAW,CAAC,sBAAsB,CAAC;KACnC,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,EAAE;IAC3B,YAAY,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,iBAAiB,CAC5B,MAAM,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAC9C,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEL,gBAAgB;KACb,OAAO,CAAC,oBAAoB,CAAC;KAC7B,WAAW,CAAC,qCAAqC,CAAC;KAClD,cAAc,CAAC,eAAe,EAAE,8BAA8B,CAAC;KAC/D,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,IAAI,EAAE,EAAE;IACjC,YAAY,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,iBAAiB,CAC5B,MAAM,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAC3D,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEL,gBAAgB;KACb,OAAO,CAAC,eAAe,CAAC;KACxB,WAAW,CAAC,6CAA6C,CAAC;KAC1D,cAAc,CAAC,eAAe,EAAE,yBAAyB,CAAC;KAC1D,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,IAAI,EAAE,EAAE;IACjC,YAAY,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,iBAAiB,CAC5B,MAAM,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,WAAW,EAAE,IAAI,CAAC,CACtD,CAAC;IACF,UAAU,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC"}
|
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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"}
|