argorant 0.7.0 → 0.8.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/bin/argorant.js +77 -2
- package/package.json +1 -1
package/bin/argorant.js
CHANGED
|
@@ -1568,6 +1568,47 @@ async function cmdInboxThreads(argv) {
|
|
|
1568
1568
|
die(`unknown inbox subcommand: ${sub} (list, read, reply, classify)`);
|
|
1569
1569
|
}
|
|
1570
1570
|
|
|
1571
|
+
async function campaignsAnalytics(argv) {
|
|
1572
|
+
const key = requireKey();
|
|
1573
|
+
const args = readFlags(argv, { "--days": "days" });
|
|
1574
|
+
const identifier = args._[0];
|
|
1575
|
+
if (!identifier) die("usage: argorant campaigns analytics <campaign> [--days 30]");
|
|
1576
|
+
const campaignId = await resolveCampaign(args.base, key, identifier);
|
|
1577
|
+
const r = need(await request("GET", args.base, `/api/v1/campaigns/${campaignId}/analytics`, { key, query: { days: args.days || 30 } }), "campaigns analytics");
|
|
1578
|
+
if (args.json) return console.log(JSON.stringify(r, null, 2));
|
|
1579
|
+
const t = r.totals || {};
|
|
1580
|
+
console.log(`${bold("last " + r.days + " days")} sent ${Number(t.sent || 0).toLocaleString()} · replies ${Number(t.replies || 0).toLocaleString()} (${t.reply_rate}%) · positive ${Number(t.positive || 0).toLocaleString()} · bounces ${Number(t.bounces || 0).toLocaleString()} (${t.bounce_rate}%) · unsubscribes ${Number(t.unsubscribes || 0).toLocaleString()}`);
|
|
1581
|
+
for (const d of r.series || []) console.log(dim(` ${d.day} sent ${d.sent} replies ${d.replies} positive ${d.positive} bounces ${d.bounces}`));
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
async function cmdBlocklist(argv) {
|
|
1585
|
+
const sub = argv[0] || "list";
|
|
1586
|
+
const key = requireKey();
|
|
1587
|
+
if (sub === "list") {
|
|
1588
|
+
const args = readFlags(argv.slice(1));
|
|
1589
|
+
const r = need(await request("GET", args.base, "/api/v1/blocklist", { key }), "blocklist");
|
|
1590
|
+
if (args.json) return console.log(JSON.stringify(r, null, 2));
|
|
1591
|
+
if (!(r.entries || []).length) return console.log(dim("Blocklist is empty."));
|
|
1592
|
+
for (const e of r.entries) console.log(`${e.type === "domain" ? "@" : " "}${e.value} ${dim(e.reason || "")}${e.yours ? "" : dim(" (Argorant-wide)")} ${dim(e.id)}`);
|
|
1593
|
+
return;
|
|
1594
|
+
}
|
|
1595
|
+
if (sub === "add") {
|
|
1596
|
+
const args = readFlags(argv.slice(1), { "--reason": "reason" });
|
|
1597
|
+
const value = args._[0]; if (!value) die("usage: argorant blocklist add <email|domain> [--reason text]");
|
|
1598
|
+
const r = need(await request("POST", args.base, "/api/v1/blocklist", { key, body: { value, reason: args.reason || "manual" } }), "blocklist add");
|
|
1599
|
+
if (args.json) return console.log(JSON.stringify(r, null, 2));
|
|
1600
|
+
return console.log(green("✓") + ` Blocked ${r.type} ${r.value}` + (r.leads_suppressed ? dim(` (${r.leads_suppressed} enrolled lead(s) suppressed)`) : ""));
|
|
1601
|
+
}
|
|
1602
|
+
if (sub === "remove") {
|
|
1603
|
+
const args = readFlags(argv.slice(1));
|
|
1604
|
+
const id = args._[0]; if (!id) die("usage: argorant blocklist remove <entry-id>");
|
|
1605
|
+
const r = need(await request("DELETE", args.base, `/api/v1/blocklist/${encodeURIComponent(id)}`, { key }), "blocklist remove");
|
|
1606
|
+
if (args.json) return console.log(JSON.stringify(r, null, 2));
|
|
1607
|
+
return console.log(green("✓") + ` Removed ${r.removed}`);
|
|
1608
|
+
}
|
|
1609
|
+
die(`unknown blocklist subcommand: ${sub} (list, add, remove)`);
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1571
1612
|
function campaignsHelp() {
|
|
1572
1613
|
const p = bold("argorant campaigns");
|
|
1573
1614
|
console.log(`
|
|
@@ -1590,6 +1631,7 @@ ${bold("USAGE")}
|
|
|
1590
1631
|
${p} senders set <campaign> --emails a@x.com,b@y.com | --all
|
|
1591
1632
|
${p} senders remove <campaign> <mailbox>
|
|
1592
1633
|
${p} replies <campaign> [-n 50]
|
|
1634
|
+
${p} analytics <campaign> [--days 30] ${dim("daily sent / replies / positive / bounces")}
|
|
1593
1635
|
${p} delete <campaign> [-y]
|
|
1594
1636
|
${p} launch <campaign> [-y] ${dim("asks for confirmation; sends real email")}
|
|
1595
1637
|
${p} pause <campaign>
|
|
@@ -1597,7 +1639,10 @@ ${bold("USAGE")}
|
|
|
1597
1639
|
${p} status <campaign>
|
|
1598
1640
|
|
|
1599
1641
|
${bold("argorant inboxes")} list
|
|
1642
|
+
${bold("argorant inboxes")} set <mailbox> [--daily-limit 40] [--warmup|--no-warmup] [--active|--inactive] [--timezone <tz>]
|
|
1643
|
+
${bold("argorant inboxes")} disconnect <mailbox>
|
|
1600
1644
|
${bold("argorant inboxes")} connect-google --admin <admin@yourdomain.com> [--emails a,b | --all]
|
|
1645
|
+
${bold("argorant blocklist")} list | add <email|domain> | remove <id>
|
|
1601
1646
|
|
|
1602
1647
|
${bold("argorant inbox")} list [--folder replies|interested|not_interested|out_of_office|bounces|unsubscribes|all] [--campaign <c>] [--q text]
|
|
1603
1648
|
${bold("argorant inbox")} read <thread-id>
|
|
@@ -1634,6 +1679,7 @@ async function cmdCampaigns(argv) {
|
|
|
1634
1679
|
set: campaignsUpdate,
|
|
1635
1680
|
delete: campaignsDelete,
|
|
1636
1681
|
replies: campaignsReplies,
|
|
1682
|
+
analytics: campaignsAnalytics,
|
|
1637
1683
|
emails: campaignsEmails,
|
|
1638
1684
|
steps: campaignsSteps,
|
|
1639
1685
|
senders: campaignsSenders,
|
|
@@ -1666,6 +1712,33 @@ async function cmdInboxes(argv) {
|
|
|
1666
1712
|
}
|
|
1667
1713
|
return;
|
|
1668
1714
|
}
|
|
1715
|
+
if (sub === "set") {
|
|
1716
|
+
const args = readFlags(argv.slice(1), { "--daily-limit": "dailyLimit", "--name": "name", "--timezone": "timezone" }, { "--warmup": "warmupOn", "--no-warmup": "warmupOff", "--active": "activeOn", "--inactive": "activeOff" });
|
|
1717
|
+
const email = args._[0]; if (!email) die("usage: argorant inboxes set <mailbox> [--daily-limit 40] [--warmup|--no-warmup] [--active|--inactive] [--name \"…\"] [--timezone Europe/Berlin]");
|
|
1718
|
+
const body = {};
|
|
1719
|
+
if (args.dailyLimit) body.daily_limit = parseLimit(args.dailyLimit, "--daily-limit");
|
|
1720
|
+
if (args.warmupOn) body.warmup = true; if (args.warmupOff) body.warmup = false;
|
|
1721
|
+
if (args.activeOn) body.active = true; if (args.activeOff) body.active = false;
|
|
1722
|
+
if (args.name !== undefined) body.display_name = args.name;
|
|
1723
|
+
if (args.timezone) body.timezone = args.timezone;
|
|
1724
|
+
if (!Object.keys(body).length) die("nothing to change");
|
|
1725
|
+
const r = need(await request("PATCH", args.base, `/api/v1/inboxes/${encodeURIComponent(email)}`, { key, body }), "inboxes set");
|
|
1726
|
+
if (args.json) return console.log(JSON.stringify(r, null, 2));
|
|
1727
|
+
const i = r.inbox || {};
|
|
1728
|
+
return console.log(green("✓") + ` ${i.email}: ${i.daily_limit} a day · warm-up ${i.warmup ? "on" : "off"} · ${i.active ? "active" : "inactive"} · ${i.timezone || ""}`);
|
|
1729
|
+
}
|
|
1730
|
+
if (sub === "disconnect") {
|
|
1731
|
+
const args = readFlags(argv.slice(1));
|
|
1732
|
+
const email = args._[0]; if (!email) die("usage: argorant inboxes disconnect <mailbox> [-y]");
|
|
1733
|
+
if (!args.yes) {
|
|
1734
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1735
|
+
const ok = await new Promise((r) => rl.question(`Disconnect ${email}? It is detached from every campaign. [y/N] `, (a) => { rl.close(); r(/^y/i.test(a)); }));
|
|
1736
|
+
if (!ok) return console.log(dim("aborted"));
|
|
1737
|
+
}
|
|
1738
|
+
const r = need(await request("DELETE", args.base, `/api/v1/inboxes/${encodeURIComponent(email)}`, { key }), "inboxes disconnect");
|
|
1739
|
+
if (args.json) return console.log(JSON.stringify(r, null, 2));
|
|
1740
|
+
return console.log(green("✓") + ` Disconnected ${r.disconnected}`);
|
|
1741
|
+
}
|
|
1669
1742
|
if (sub === "connect-google") {
|
|
1670
1743
|
const args = readFlags(argv.slice(1), { "--admin": "admin", "--emails": "emails" }, { "--all": "all" });
|
|
1671
1744
|
if (!args.admin) die("usage: argorant inboxes connect-google --admin admin@yourdomain.com [--emails a@x.com,b@x.com | --all]");
|
|
@@ -1690,7 +1763,7 @@ async function cmdInboxes(argv) {
|
|
|
1690
1763
|
for (const c of r.connected || []) console.log(dim(` ${c.email} · ${c.health || "ok"}`));
|
|
1691
1764
|
return;
|
|
1692
1765
|
}
|
|
1693
|
-
die(`unknown inboxes subcommand: ${sub} (list, connect-google)`);
|
|
1766
|
+
die(`unknown inboxes subcommand: ${sub} (list, set, disconnect, connect-google)`);
|
|
1694
1767
|
}
|
|
1695
1768
|
|
|
1696
1769
|
function help() {
|
|
@@ -1723,6 +1796,7 @@ ${bold("COMMANDS")}
|
|
|
1723
1796
|
${cyan("campaigns")} ... Email outreach: create, write, enroll, launch ${dim("(argorant campaigns help)")}
|
|
1724
1797
|
${cyan("inboxes")} list | connect-google Connected mailboxes; connect a Google Workspace
|
|
1725
1798
|
${cyan("inbox")} list | read | reply | classify Replies across campaigns; answer in-thread
|
|
1799
|
+
${cyan("blocklist")} list | add | remove Addresses and domains never contacted
|
|
1726
1800
|
|
|
1727
1801
|
${bold("FILTERS")}
|
|
1728
1802
|
--keywords <k> Comma = OR. The widest, most reliable filter - prefer it
|
|
@@ -1780,9 +1854,10 @@ async function main() {
|
|
|
1780
1854
|
// `campaigns` has its own flag vocabulary (--step, --count, --pool, --csv, ...)
|
|
1781
1855
|
// handled by readFlags — it never goes through the generic filter parser
|
|
1782
1856
|
// below, which would reject those flags as unknown.
|
|
1783
|
-
if (cmd === "campaigns" || cmd === "campaign" || cmd === "inboxes" || cmd === "mailboxes" || cmd === "inbox" || cmd === "unibox") {
|
|
1857
|
+
if (cmd === "campaigns" || cmd === "campaign" || cmd === "inboxes" || cmd === "mailboxes" || cmd === "inbox" || cmd === "unibox" || cmd === "blocklist") {
|
|
1784
1858
|
try {
|
|
1785
1859
|
if (cmd.startsWith("campaign")) await cmdCampaigns(argv.slice(1));
|
|
1860
|
+
else if (cmd === "blocklist") await cmdBlocklist(argv.slice(1));
|
|
1786
1861
|
else if (cmd === "inbox" || cmd === "unibox") await cmdInboxThreads(argv.slice(1));
|
|
1787
1862
|
else await cmdInboxes(argv.slice(1));
|
|
1788
1863
|
} catch (e) {
|
package/package.json
CHANGED