emailr-cli 1.4.1 → 1.5.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/dist/index.js +152 -12
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command11 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/send.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -839,7 +839,10 @@ Total: ${result.length}`);
|
|
|
839
839
|
process.exit(1);
|
|
840
840
|
}
|
|
841
841
|
});
|
|
842
|
-
cmd.command("create").description(
|
|
842
|
+
cmd.command("create").description(`Create a new template
|
|
843
|
+
|
|
844
|
+
TIP: For live preview while building, use "emailr templates draft" first.
|
|
845
|
+
It creates a local file with hot-reload preview, then use this command to save.`).requiredOption("--name <name>", "Template name").requiredOption("--subject <subject>", "Email subject").option("--html <html>", "HTML content").option("--text <text>", "Plain text content").option("--html-file <path>", "Read HTML content from file").option("--text-file <path>", "Read text content from file").option("--from <email>", "Default from email").option("--reply-to <email>", "Default reply-to email").option("--preview-text <text>", "Preview text").option("--format <format>", "Output format (json|table)", "table").action(async (options) => {
|
|
843
846
|
try {
|
|
844
847
|
const config = loadConfig();
|
|
845
848
|
const client = new Emailr3({
|
|
@@ -851,14 +854,14 @@ Total: ${result.length}`);
|
|
|
851
854
|
subject: options.subject
|
|
852
855
|
};
|
|
853
856
|
if (options.htmlFile) {
|
|
854
|
-
const
|
|
855
|
-
request.html_content =
|
|
857
|
+
const fs6 = await import("fs");
|
|
858
|
+
request.html_content = fs6.readFileSync(options.htmlFile, "utf-8");
|
|
856
859
|
} else if (options.html) {
|
|
857
860
|
request.html_content = options.html;
|
|
858
861
|
}
|
|
859
862
|
if (options.textFile) {
|
|
860
|
-
const
|
|
861
|
-
request.text_content =
|
|
863
|
+
const fs6 = await import("fs");
|
|
864
|
+
request.text_content = fs6.readFileSync(options.textFile, "utf-8");
|
|
862
865
|
} else if (options.text) {
|
|
863
866
|
request.text_content = options.text;
|
|
864
867
|
}
|
|
@@ -897,7 +900,10 @@ Open the Preview URL in your browser to view the rendered template.`);
|
|
|
897
900
|
process.exit(1);
|
|
898
901
|
}
|
|
899
902
|
});
|
|
900
|
-
cmd.command("update <id>").description(
|
|
903
|
+
cmd.command("update <id>").description(`Update a template
|
|
904
|
+
|
|
905
|
+
TIP: For live preview while editing, use "emailr templates edit <id>" first.
|
|
906
|
+
It downloads the template with hot-reload preview, then use this command to save.`).option("--name <name>", "Template name").option("--subject <subject>", "Email subject").option("--html <html>", "HTML content").option("--text <text>", "Plain text content").option("--html-file <path>", "Read HTML content from file").option("--text-file <path>", "Read text content from file").option("--from <email>", "Default from email").option("--reply-to <email>", "Default reply-to email").option("--preview-text <text>", "Preview text").option("--format <format>", "Output format (json|table)", "table").action(async (id, options) => {
|
|
901
907
|
try {
|
|
902
908
|
const config = loadConfig();
|
|
903
909
|
const client = new Emailr3({
|
|
@@ -908,14 +914,14 @@ Open the Preview URL in your browser to view the rendered template.`);
|
|
|
908
914
|
if (options.name) request.name = options.name;
|
|
909
915
|
if (options.subject) request.subject = options.subject;
|
|
910
916
|
if (options.htmlFile) {
|
|
911
|
-
const
|
|
912
|
-
request.html_content =
|
|
917
|
+
const fs6 = await import("fs");
|
|
918
|
+
request.html_content = fs6.readFileSync(options.htmlFile, "utf-8");
|
|
913
919
|
} else if (options.html) {
|
|
914
920
|
request.html_content = options.html;
|
|
915
921
|
}
|
|
916
922
|
if (options.textFile) {
|
|
917
|
-
const
|
|
918
|
-
request.text_content =
|
|
923
|
+
const fs6 = await import("fs");
|
|
924
|
+
request.text_content = fs6.readFileSync(options.textFile, "utf-8");
|
|
919
925
|
} else if (options.text) {
|
|
920
926
|
request.text_content = options.text;
|
|
921
927
|
}
|
|
@@ -2316,8 +2322,141 @@ async function executeLogin(options) {
|
|
|
2316
2322
|
}
|
|
2317
2323
|
}
|
|
2318
2324
|
|
|
2325
|
+
// src/commands/agent.ts
|
|
2326
|
+
import { Command as Command10 } from "commander";
|
|
2327
|
+
import { spawn, execSync } from "child_process";
|
|
2328
|
+
import fs5 from "fs";
|
|
2329
|
+
import path5 from "path";
|
|
2330
|
+
import os3 from "os";
|
|
2331
|
+
var OPENCODE_SKILL_DIR = path5.join(os3.homedir(), ".config", "opencode", "skills", "emailr-cli");
|
|
2332
|
+
var SKILL_MD = `---
|
|
2333
|
+
name: emailr-cli
|
|
2334
|
+
description: Operate the Emailr CLI to send emails, manage contacts, templates, domains, broadcasts, webhooks, and segments. Includes LIVE PREVIEW editing for templates with hot-reload.
|
|
2335
|
+
---
|
|
2336
|
+
# Emailr CLI
|
|
2337
|
+
|
|
2338
|
+
## Quick start
|
|
2339
|
+
- Ensure auth: \`emailr login\` (browser-based) or \`emailr config set api-key <token>\`.
|
|
2340
|
+
- Prefer machine-readable output with \`--format json\` on listing/get commands.
|
|
2341
|
+
|
|
2342
|
+
## LIVE TEMPLATE EDITING (Agentic Workflow)
|
|
2343
|
+
|
|
2344
|
+
### Edit existing template with live preview
|
|
2345
|
+
1. Start live editing: \`emailr templates edit <template_id> --file ./template.html\`
|
|
2346
|
+
2. Edit the file - browser auto-refreshes on every save
|
|
2347
|
+
3. When satisfied: \`emailr templates update <template_id> --html-file ./template.html\`
|
|
2348
|
+
|
|
2349
|
+
### Create new template with live preview
|
|
2350
|
+
1. Start drafting: \`emailr templates draft --file ./new-template.html\`
|
|
2351
|
+
2. Edit the file - browser auto-refreshes on every save
|
|
2352
|
+
3. When satisfied: \`emailr templates create --name "Template Name" --subject "Subject" --html-file ./new-template.html\`
|
|
2353
|
+
|
|
2354
|
+
## Common commands
|
|
2355
|
+
|
|
2356
|
+
### Sending emails
|
|
2357
|
+
- Plain text: \`emailr send --to user@example.com --from no-reply@example.com --subject "Hi" --text "Hello"\`
|
|
2358
|
+
- HTML: \`emailr send --to user@example.com --from no-reply@example.com --subject "Hi" --html "<h1>Hello</h1>"\`
|
|
2359
|
+
- With template: \`emailr send --to user@example.com --from no-reply@example.com --template tmpl_xxx --template-data '{"name":"Ada"}'\`
|
|
2360
|
+
|
|
2361
|
+
### Templates
|
|
2362
|
+
- List: \`emailr templates list --format json\`
|
|
2363
|
+
- Get: \`emailr templates get <id> --format json\`
|
|
2364
|
+
- Preview: \`emailr templates preview <id>\`
|
|
2365
|
+
- Create: \`emailr templates create --name "Name" --subject "Subject" --html-file ./template.html\`
|
|
2366
|
+
- Update: \`emailr templates update <id> --html-file ./template.html\`
|
|
2367
|
+
- Delete: \`emailr templates delete <id>\`
|
|
2368
|
+
`;
|
|
2369
|
+
function isOpenCodeInstalled() {
|
|
2370
|
+
try {
|
|
2371
|
+
execSync("which opencode", { stdio: "ignore" });
|
|
2372
|
+
return true;
|
|
2373
|
+
} catch {
|
|
2374
|
+
return false;
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
function installOpenCode() {
|
|
2378
|
+
console.log("Installing OpenCode AI agent...");
|
|
2379
|
+
try {
|
|
2380
|
+
execSync("npm install -g opencode-ai@latest", { stdio: "inherit" });
|
|
2381
|
+
return true;
|
|
2382
|
+
} catch {
|
|
2383
|
+
if (process.platform === "darwin") {
|
|
2384
|
+
try {
|
|
2385
|
+
execSync("brew install anomalyco/tap/opencode", { stdio: "inherit" });
|
|
2386
|
+
return true;
|
|
2387
|
+
} catch {
|
|
2388
|
+
return false;
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
return false;
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
function ensureSkillInstalled() {
|
|
2395
|
+
if (!fs5.existsSync(OPENCODE_SKILL_DIR)) {
|
|
2396
|
+
fs5.mkdirSync(OPENCODE_SKILL_DIR, { recursive: true });
|
|
2397
|
+
}
|
|
2398
|
+
const skillPath = path5.join(OPENCODE_SKILL_DIR, "SKILL.md");
|
|
2399
|
+
fs5.writeFileSync(skillPath, SKILL_MD, "utf-8");
|
|
2400
|
+
}
|
|
2401
|
+
function createAgentCommand() {
|
|
2402
|
+
const cmd = new Command10("agent").description(`Launch an AI agent with Emailr CLI expertise
|
|
2403
|
+
|
|
2404
|
+
This opens OpenCode (opencode.ai), an AI coding agent that knows how to use all Emailr CLI commands.
|
|
2405
|
+
The agent can help you:
|
|
2406
|
+
- Send emails and manage templates with live preview
|
|
2407
|
+
- Manage contacts, broadcasts, and segments
|
|
2408
|
+
- Configure domains and webhooks
|
|
2409
|
+
|
|
2410
|
+
The agent runs in your terminal with full access to the emailr CLI.`).option("--install", "Install OpenCode if not already installed").option("--model <model>", "Model to use (e.g., anthropic/claude-sonnet-4)").action(async (options) => {
|
|
2411
|
+
if (!isOpenCodeInstalled()) {
|
|
2412
|
+
if (options.install) {
|
|
2413
|
+
const installed = installOpenCode();
|
|
2414
|
+
if (!installed) {
|
|
2415
|
+
error("Failed to install OpenCode. Please install manually:");
|
|
2416
|
+
console.log(" npm install -g opencode-ai@latest");
|
|
2417
|
+
console.log(" # or");
|
|
2418
|
+
console.log(" brew install anomalyco/tap/opencode");
|
|
2419
|
+
process.exit(1);
|
|
2420
|
+
}
|
|
2421
|
+
} else {
|
|
2422
|
+
error("OpenCode AI agent is not installed.");
|
|
2423
|
+
console.log("\nInstall it with one of:");
|
|
2424
|
+
console.log(" emailr agent --install");
|
|
2425
|
+
console.log(" npm install -g opencode-ai@latest");
|
|
2426
|
+
console.log(" brew install anomalyco/tap/opencode");
|
|
2427
|
+
process.exit(1);
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
try {
|
|
2431
|
+
ensureSkillInstalled();
|
|
2432
|
+
success("Emailr CLI skill loaded");
|
|
2433
|
+
} catch (err) {
|
|
2434
|
+
warn(`Could not install skill: ${err instanceof Error ? err.message : String(err)}`);
|
|
2435
|
+
}
|
|
2436
|
+
const args = [];
|
|
2437
|
+
if (options.model) {
|
|
2438
|
+
args.push("--model", options.model);
|
|
2439
|
+
}
|
|
2440
|
+
console.log("\nStarting Emailr AI Agent...");
|
|
2441
|
+
console.log("The agent has the emailr-cli skill loaded.");
|
|
2442
|
+
console.log("Ask it to help with emails, templates, contacts, or broadcasts.\n");
|
|
2443
|
+
const opencode = spawn("opencode", args, {
|
|
2444
|
+
stdio: "inherit",
|
|
2445
|
+
env: process.env
|
|
2446
|
+
});
|
|
2447
|
+
opencode.on("error", (err) => {
|
|
2448
|
+
error(`Failed to start agent: ${err.message}`);
|
|
2449
|
+
process.exit(1);
|
|
2450
|
+
});
|
|
2451
|
+
opencode.on("exit", (code) => {
|
|
2452
|
+
process.exit(code ?? 0);
|
|
2453
|
+
});
|
|
2454
|
+
});
|
|
2455
|
+
return cmd;
|
|
2456
|
+
}
|
|
2457
|
+
|
|
2319
2458
|
// src/index.ts
|
|
2320
|
-
var program = new
|
|
2459
|
+
var program = new Command11();
|
|
2321
2460
|
program.name("emailr").description("Emailr CLI - Send emails and manage your email infrastructure").version("1.0.0");
|
|
2322
2461
|
program.addCommand(createSendCommand());
|
|
2323
2462
|
program.addCommand(createContactsCommand());
|
|
@@ -2328,4 +2467,5 @@ program.addCommand(createWebhooksCommand());
|
|
|
2328
2467
|
program.addCommand(createSegmentsCommand());
|
|
2329
2468
|
program.addCommand(createConfigCommand());
|
|
2330
2469
|
program.addCommand(createLoginCommand());
|
|
2470
|
+
program.addCommand(createAgentCommand());
|
|
2331
2471
|
program.parse();
|