@arcsend/cli 1.0.0 → 1.2.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 (3) hide show
  1. package/README.md +1 -3
  2. package/dist/index.js +230 -50
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -15,9 +15,7 @@ npx @arcsend/cli --help
15
15
  Get an API key from your ArcSend workspace (Settings → API Keys), then:
16
16
 
17
17
  ```bash
18
- arcsend auth setup --key arc_xxxxxxxx
19
- # dedicated instance? point at your domain:
20
- arcsend auth setup --key arc_xxxxxxxx --url https://send.yourdomain.com
18
+ arcsend auth setup --key arc_xxxxxxxx --url https://app.arcsend.io # your instance URL — the /cli page has it pre-filled
21
19
  ```
22
20
 
23
21
  Or use env vars: `ARCSEND_API_KEY`, `ARCSEND_URL`.
package/dist/index.js CHANGED
@@ -10,7 +10,6 @@ import chalk2 from "chalk";
10
10
  import { homedir } from "os";
11
11
  import { join } from "path";
12
12
  import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync } from "fs";
13
- var DEFAULT_URL = "https://send.highsend.io";
14
13
  var CONFIG_DIR = join(homedir(), ".arcsend");
15
14
  var CONFIG_PATH = join(CONFIG_DIR, "config.txt");
16
15
  function loadConfig(keyOverride, urlOverride) {
@@ -26,7 +25,7 @@ function loadConfig(keyOverride, urlOverride) {
26
25
  if (!baseUrl && (key === "instance_url" || key === "url")) baseUrl = val;
27
26
  }
28
27
  }
29
- baseUrl = (baseUrl || DEFAULT_URL).replace(/\/+$/, "");
28
+ baseUrl = baseUrl.replace(/\/+$/, "");
30
29
  return { apiKey, baseUrl };
31
30
  }
32
31
  function saveConfig(apiKey, url) {
@@ -282,7 +281,10 @@ var Api = class {
282
281
  if (this.ready) return;
283
282
  const { apiKey, baseUrl } = loadConfig(this.keyOverride, this.urlOverride);
284
283
  if (!apiKey) {
285
- fail("No API key. Use --api-key, set ARCSEND_API_KEY, or run `arcsend auth setup --key <key>`.");
284
+ fail("No API key. Use --api-key, set ARCSEND_API_KEY, or run `arcsend auth setup --key <key> --url <url>`.");
285
+ }
286
+ if (!baseUrl) {
287
+ fail("No instance URL. Use --url, set ARCSEND_URL, or run `arcsend auth setup --key <key> --url https://your-instance` (e.g. https://app.arcsend.io \u2014 your /cli page has it pre-filled).");
286
288
  }
287
289
  this.apiKey = apiKey;
288
290
  this.baseUrl = `${baseUrl}/api/external`;
@@ -958,36 +960,48 @@ var campaigns = {
958
960
  params: [{ name: "id", positional: true, desc: "campaign id" }, ...replyFilters],
959
961
  output: { columns: REPLY_COLS, headers: REPLY_HDRS, noun: "reply(ies)" }
960
962
  },
961
- // Account assignment
963
+ // Sender-account assignment (by email — additive attach/detach, or full replace)
962
964
  {
963
965
  name: "accounts",
964
- summary: "List sending accounts assigned to a campaign.",
966
+ summary: "List sender accounts assigned to a campaign.",
965
967
  method: "GET",
966
- path: "/campaigns/:id/accounts",
968
+ path: "/campaigns/:id/sender-accounts",
967
969
  params: [{ name: "id", positional: true, desc: "campaign id" }],
968
- output: { columns: ["id", "email", "status", "daily_limit"], headers: ["ID", "Email", "Status", "Limit"], noun: "account(s)" }
970
+ output: { columns: ["email", "status", "daily_limit", "is_paused"], headers: ["Email", "Status", "Limit", "Paused"], noun: "account(s)" }
969
971
  },
970
972
  {
971
- name: "assign",
972
- summary: "Set the campaign's sending accounts (REPLACES the current set).",
973
+ name: "attach",
974
+ summary: "Attach sender accounts to a campaign by email (additive \u2014 keeps existing).",
973
975
  method: "POST",
974
- path: "/campaigns/:id/accounts",
976
+ path: "/campaigns/:id/sender-accounts/attach",
975
977
  params: [
976
- { name: "id", positional: true, echoBody: true, apiName: "campaign_id", desc: "campaign id" },
977
- { name: "ids", type: "csv", required: true, apiName: "account_ids", desc: "comma-separated account ids (full replace set)" }
978
+ { name: "id", positional: true, desc: "campaign id" },
979
+ { name: "emails", type: "csv", required: true, desc: "comma-separated sender-account emails to attach" }
978
980
  ],
979
- success: "Accounts assigned."
981
+ success: "Sender accounts attached."
980
982
  },
981
983
  {
982
- name: "unassign",
983
- summary: "Remove specific sending accounts from a campaign.",
984
+ name: "detach",
985
+ summary: "Detach specific sender accounts from a campaign, by email.",
984
986
  method: "POST",
985
- path: "/campaigns/:id/accounts/batch-unassign",
987
+ path: "/campaigns/:id/sender-accounts/detach",
988
+ params: [
989
+ { name: "id", positional: true, desc: "campaign id" },
990
+ { name: "emails", type: "csv", required: true, desc: "comma-separated sender-account emails to detach" }
991
+ ],
992
+ success: "Sender accounts detached."
993
+ },
994
+ {
995
+ name: "replace",
996
+ summary: "Replace the campaign's entire sender-account set with exactly these emails.",
997
+ method: "PUT",
998
+ path: "/campaigns/:id/sender-accounts",
999
+ confirm: "Replace ALL of this campaign's sender accounts with the provided set?",
986
1000
  params: [
987
1001
  { name: "id", positional: true, desc: "campaign id" },
988
- { name: "ids", type: "csv", required: true, apiName: "account_ids", desc: "comma-separated account ids to remove" }
1002
+ { name: "emails", type: "csv", required: true, desc: "comma-separated sender-account emails (full replace set)" }
989
1003
  ],
990
- success: "Accounts unassigned."
1004
+ success: "Sender accounts replaced."
991
1005
  }
992
1006
  ],
993
1007
  subgroups: [
@@ -1134,16 +1148,181 @@ var campaigns = {
1134
1148
  ]
1135
1149
  };
1136
1150
 
1151
+ // src/defs/subsequences.ts
1152
+ var TRIGGERS = "replied | sentiment_interested | sentiment_not_interested | sentiment_not_now | sentiment_question | sentiment_referral | reply_keyword | no_reply | lead_status";
1153
+ var subsequences = {
1154
+ name: "subsequences",
1155
+ summary: "In-campaign branches. A lead matching a trigger (reply/sentiment/keyword/no-reply) is moved off the main line onto its own mini-sequence. Max 10 per campaign.",
1156
+ commands: [
1157
+ {
1158
+ name: "list",
1159
+ summary: "List a campaign's subsequences.",
1160
+ method: "GET",
1161
+ path: "/campaigns/:campaign/subsequences",
1162
+ params: [{ name: "campaign", positional: true, desc: "campaign id" }],
1163
+ output: { columns: ["id", "name", "trigger_type", "is_active"], headers: ["ID", "Name", "Trigger", "Active"], noun: "subsequence(s)" }
1164
+ },
1165
+ {
1166
+ name: "create",
1167
+ summary: "Create a subsequence (max 10 per campaign).",
1168
+ method: "POST",
1169
+ path: "/campaigns/:campaign/subsequences",
1170
+ params: [
1171
+ { name: "campaign", positional: true, desc: "campaign id" },
1172
+ { name: "name", required: true, desc: "subsequence name" },
1173
+ { name: "triggerType", required: true, apiName: "trigger_type", desc: TRIGGERS },
1174
+ { name: "triggerConfig", type: "json", apiName: "trigger_config", desc: `JSON config \u2014 {"keyword":"pricing"} for reply_keyword, {"status":"meeting_booked"} for lead_status` },
1175
+ { name: "delayDays", type: "number", apiName: "initial_delay_days", desc: "wait days before the first step" },
1176
+ { name: "delayHours", type: "number", apiName: "initial_delay_hours", desc: "wait hours before the first step" }
1177
+ ],
1178
+ success: "Subsequence created."
1179
+ },
1180
+ {
1181
+ name: "get",
1182
+ summary: "Show one subsequence.",
1183
+ method: "GET",
1184
+ path: "/campaigns/:campaign/subsequences/:id",
1185
+ params: [{ name: "campaign", positional: true, desc: "campaign id" }, { name: "id", positional: true, desc: "subsequence id" }]
1186
+ },
1187
+ {
1188
+ name: "update",
1189
+ summary: "Update a subsequence (name, trigger config, delay, or active state). trigger_type is immutable.",
1190
+ method: "PATCH",
1191
+ path: "/campaigns/:campaign/subsequences/:id",
1192
+ params: [
1193
+ { name: "campaign", positional: true, desc: "campaign id" },
1194
+ { name: "id", positional: true, desc: "subsequence id" },
1195
+ { name: "name", desc: "new name" },
1196
+ { name: "triggerConfig", type: "json", apiName: "trigger_config", desc: "new trigger config JSON" },
1197
+ { name: "delayDays", type: "number", apiName: "initial_delay_days", desc: "wait days before the first step" },
1198
+ { name: "delayHours", type: "number", apiName: "initial_delay_hours", desc: "wait hours before the first step" },
1199
+ { name: "active", type: "tri", negFlag: "--inactive", apiName: "is_active", desc: "activate / pause the subsequence" }
1200
+ ],
1201
+ success: "Subsequence updated."
1202
+ },
1203
+ {
1204
+ name: "delete",
1205
+ summary: "Delete a subsequence (its steps go too; its leads return to the main line).",
1206
+ method: "DELETE",
1207
+ path: "/campaigns/:campaign/subsequences/:id",
1208
+ confirm: "Delete this subsequence?",
1209
+ params: [{ name: "campaign", positional: true, desc: "campaign id" }, { name: "id", positional: true, desc: "subsequence id" }],
1210
+ success: "Deleted."
1211
+ },
1212
+ {
1213
+ name: "move",
1214
+ summary: "Move leads (by email) onto a subsequence. Cancels their queued main-line sends. Fails if the subsequence is paused.",
1215
+ method: "POST",
1216
+ path: "/campaigns/:campaign/subsequences/:id/move",
1217
+ params: [
1218
+ { name: "campaign", positional: true, desc: "campaign id" },
1219
+ { name: "id", positional: true, desc: "subsequence id" },
1220
+ { name: "emails", type: "csv", required: true, desc: "comma-separated lead emails to move" }
1221
+ ],
1222
+ success: "Leads moved."
1223
+ },
1224
+ {
1225
+ name: "remove",
1226
+ summary: "Remove leads (by email) from a subsequence, releasing them to the main line.",
1227
+ method: "POST",
1228
+ path: "/campaigns/:campaign/subsequences/:id/remove",
1229
+ params: [
1230
+ { name: "campaign", positional: true, desc: "campaign id" },
1231
+ { name: "id", positional: true, desc: "subsequence id" },
1232
+ { name: "emails", type: "csv", required: true, desc: "comma-separated lead emails to remove" }
1233
+ ],
1234
+ success: "Leads removed."
1235
+ },
1236
+ {
1237
+ name: "pause",
1238
+ summary: "Pause a subsequence \u2014 no new leads enter and its steps freeze until resumed.",
1239
+ method: "POST",
1240
+ path: "/campaigns/:campaign/subsequences/:id/pause",
1241
+ params: [{ name: "campaign", positional: true, desc: "campaign id" }, { name: "id", positional: true, desc: "subsequence id" }],
1242
+ success: "Paused."
1243
+ },
1244
+ {
1245
+ name: "resume",
1246
+ summary: "Resume a paused subsequence.",
1247
+ method: "POST",
1248
+ path: "/campaigns/:campaign/subsequences/:id/resume",
1249
+ params: [{ name: "campaign", positional: true, desc: "campaign id" }, { name: "id", positional: true, desc: "subsequence id" }],
1250
+ success: "Resumed."
1251
+ }
1252
+ ],
1253
+ subgroups: [
1254
+ {
1255
+ name: "steps",
1256
+ summary: "The email steps inside a subsequence. Step 1 needs a subject; every step needs a body. Spintax {a|b} and {{variables}} are supported.",
1257
+ commands: [
1258
+ {
1259
+ name: "list",
1260
+ summary: "List a subsequence's steps.",
1261
+ method: "GET",
1262
+ path: "/campaigns/:campaign/subsequences/:id/steps",
1263
+ params: [{ name: "campaign", positional: true, desc: "campaign id" }, { name: "id", positional: true, desc: "subsequence id" }],
1264
+ output: { columns: ["step_number", "variant", "subject", "delay_days", "delay_hours"], headers: ["Step", "Var", "Subject", "Days", "Hrs"], noun: "step(s)" }
1265
+ },
1266
+ {
1267
+ name: "add",
1268
+ summary: "Add an email step to a subsequence.",
1269
+ method: "POST",
1270
+ path: "/campaigns/:campaign/subsequences/:id/steps",
1271
+ params: [
1272
+ { name: "campaign", positional: true, desc: "campaign id" },
1273
+ { name: "id", positional: true, desc: "subsequence id" },
1274
+ { name: "step", type: "number", required: true, apiName: "step_number", desc: "step number (1 = first)" },
1275
+ { name: "body", required: true, desc: "email body (spintax + {{vars}} allowed)" },
1276
+ { name: "subject", desc: "subject line (required on step 1)" },
1277
+ { name: "delayDays", type: "number", apiName: "delay_days", desc: "days after the previous step" },
1278
+ { name: "delayHours", type: "number", apiName: "delay_hours", desc: "additional hours" },
1279
+ { name: "variant", desc: "A/B variant: A, B, C, or D (default A)" },
1280
+ { name: "splitWeight", type: "number", apiName: "split_weight", desc: "A/B weight 1-100 (blank = equal split)" }
1281
+ ],
1282
+ success: "Step added."
1283
+ },
1284
+ {
1285
+ name: "update",
1286
+ summary: "Update a subsequence step.",
1287
+ method: "PATCH",
1288
+ path: "/campaigns/:campaign/subsequences/:id/steps/:step",
1289
+ params: [
1290
+ { name: "campaign", positional: true, desc: "campaign id" },
1291
+ { name: "id", positional: true, desc: "subsequence id" },
1292
+ { name: "step", positional: true, desc: "sequence step id" },
1293
+ { name: "stepNumber", type: "number", apiName: "step_number", desc: "step number" },
1294
+ { name: "subject", desc: "subject line" },
1295
+ { name: "body", desc: "email body" },
1296
+ { name: "delayDays", type: "number", apiName: "delay_days", desc: "days after the previous step" },
1297
+ { name: "delayHours", type: "number", apiName: "delay_hours", desc: "additional hours" },
1298
+ { name: "splitWeight", type: "number", apiName: "split_weight", desc: "A/B weight 1-100" }
1299
+ ],
1300
+ success: "Step updated."
1301
+ },
1302
+ {
1303
+ name: "delete",
1304
+ summary: "Delete a subsequence step.",
1305
+ method: "DELETE",
1306
+ path: "/campaigns/:campaign/subsequences/:id/steps/:step",
1307
+ confirm: "Delete this step?",
1308
+ params: [{ name: "campaign", positional: true, desc: "campaign id" }, { name: "id", positional: true, desc: "subsequence id" }, { name: "step", positional: true, desc: "sequence step id" }],
1309
+ success: "Deleted."
1310
+ }
1311
+ ]
1312
+ }
1313
+ ]
1314
+ };
1315
+
1137
1316
  // src/defs/accounts.ts
1138
1317
  var accounts = {
1139
1318
  name: "accounts",
1140
- summary: "Sending accounts (mailboxes). Connect/reconnect happens in the app; here you list, inspect, edit, scan, and remove them.",
1319
+ summary: "Sending accounts (mailboxes), addressed by email. Connect/reconnect happens in the app; here you list, inspect, edit, scan, and remove them.",
1141
1320
  commands: [
1142
1321
  {
1143
1322
  name: "list",
1144
1323
  summary: "List sending accounts with operational filters.",
1145
1324
  method: "GET",
1146
- path: "/accounts",
1325
+ path: "/sender-accounts",
1147
1326
  paged: true,
1148
1327
  params: [
1149
1328
  { name: "status", desc: "connected|connecting|disconnected|error" },
@@ -1159,25 +1338,25 @@ var accounts = {
1159
1338
  },
1160
1339
  {
1161
1340
  name: "get",
1162
- summary: "Show one account in full.",
1341
+ summary: "Show one sender account in full.",
1163
1342
  method: "GET",
1164
- path: "/accounts/:id",
1165
- params: [{ name: "id", positional: true, desc: "account id" }]
1343
+ path: "/sender-accounts/:email",
1344
+ params: [{ name: "email", positional: true, desc: "sender-account email" }]
1166
1345
  },
1167
1346
  {
1168
1347
  name: "stats",
1169
- summary: "Sending stats for one account.",
1348
+ summary: "Sending stats for one sender account.",
1170
1349
  method: "GET",
1171
- path: "/accounts/:id/stats",
1172
- params: [{ name: "id", positional: true, desc: "account id" }]
1350
+ path: "/sender-accounts/:email/stats",
1351
+ params: [{ name: "email", positional: true, desc: "sender-account email" }]
1173
1352
  },
1174
1353
  {
1175
1354
  name: "update",
1176
- summary: "Edit an account: sender name, daily limit (1\u201350), pause state, or tags.",
1355
+ summary: "Edit a sender account: sender name, daily limit (1\u201350), pause state, or tags.",
1177
1356
  method: "PATCH",
1178
- path: "/accounts/:id",
1357
+ path: "/sender-accounts/:email",
1179
1358
  params: [
1180
- { name: "id", positional: true, desc: "account id" },
1359
+ { name: "email", positional: true, desc: "sender-account email" },
1181
1360
  { name: "senderName", apiName: "sender_name", desc: "the From display name" },
1182
1361
  { name: "dailyLimit", type: "number", apiName: "daily_limit", desc: "emails/day, 1\u201350 (default 5)" },
1183
1362
  { name: "paused", type: "tri", negFlag: "--active", apiName: "is_paused", desc: "pause (stop sending) / re-activate the account" },
@@ -1188,12 +1367,12 @@ var accounts = {
1188
1367
  },
1189
1368
  {
1190
1369
  name: "bulk-action",
1191
- summary: "Apply one action (pause/unpause/delete) to up to 200 accounts.",
1370
+ summary: "Apply one action (pause/unpause/delete) to up to 200 sender accounts, by email.",
1192
1371
  method: "POST",
1193
- path: "/accounts/bulk-action",
1372
+ path: "/sender-accounts/bulk-action",
1194
1373
  confirm: "Apply this action to all listed accounts?",
1195
1374
  params: [
1196
- { name: "ids", type: "csv", required: true, apiName: "account_ids", desc: "comma-separated account ids (1\u2013200)" },
1375
+ { name: "emails", type: "csv", required: true, desc: "comma-separated sender-account emails (1\u2013200)" },
1197
1376
  { name: "action", required: true, desc: "pause|unpause|delete" }
1198
1377
  ],
1199
1378
  success: "Applied."
@@ -1202,17 +1381,17 @@ var accounts = {
1202
1381
  name: "dns-check",
1203
1382
  summary: "Run an SPF/DKIM/DMARC check on the account's sending domain.",
1204
1383
  method: "POST",
1205
- path: "/accounts/:id/dns-check",
1206
- params: [{ name: "id", positional: true, desc: "account id" }],
1384
+ path: "/sender-accounts/:email/dns-check",
1385
+ params: [{ name: "email", positional: true, desc: "sender-account email" }],
1207
1386
  success: "DNS check run."
1208
1387
  },
1209
1388
  {
1210
1389
  name: "delete",
1211
- summary: "Delete (disconnect) an account.",
1390
+ summary: "Delete (disconnect) a sender account.",
1212
1391
  method: "DELETE",
1213
- path: "/accounts/:id",
1392
+ path: "/sender-accounts/:email",
1214
1393
  confirm: "Delete this account?",
1215
- params: [{ name: "id", positional: true, desc: "account id" }],
1394
+ params: [{ name: "email", positional: true, desc: "sender-account email" }],
1216
1395
  success: "Deleted."
1217
1396
  }
1218
1397
  ]
@@ -1558,24 +1737,24 @@ var warmup = {
1558
1737
  name: "list",
1559
1738
  summary: "List accounts with their warmup status.",
1560
1739
  method: "GET",
1561
- path: "/warmup/accounts",
1740
+ path: "/warmup/sender-accounts",
1562
1741
  paged: true,
1563
1742
  params: [{ name: "active", type: "tri", negFlag: "--inactive", apiName: "is_active", desc: "only warming / only not-warming" }],
1564
- output: { columns: ["id", "email", "warmup_enabled", "warmup_score"], headers: ["ID", "Email", "Enabled", "Score"], noun: "account(s)" }
1743
+ output: { columns: ["email", "warmup_enabled", "warmup_score", "days_warming"], headers: ["Email", "Enabled", "Score", "Days"], noun: "account(s)" }
1565
1744
  },
1566
1745
  {
1567
1746
  name: "get",
1568
1747
  summary: "Show one account's warmup detail.",
1569
1748
  method: "GET",
1570
- path: "/warmup/accounts/:id",
1571
- params: [{ name: "id", positional: true, desc: "account id" }]
1749
+ path: "/warmup/sender-accounts/:email",
1750
+ params: [{ name: "email", positional: true, desc: "sender-account email" }]
1572
1751
  },
1573
1752
  {
1574
1753
  name: "enable",
1575
1754
  summary: "Enable warmup for an account (must be connected). Optionally set targets.",
1576
1755
  method: "POST",
1577
- path: "/warmup/accounts/:id/enable",
1578
- params: [{ name: "id", positional: true, desc: "account id" }, ...warmupSettings],
1756
+ path: "/warmup/sender-accounts/:email/enable",
1757
+ params: [{ name: "email", positional: true, desc: "sender-account email" }, ...warmupSettings],
1579
1758
  validate: "warmup.settings",
1580
1759
  success: "Warmup enabled."
1581
1760
  },
@@ -1583,16 +1762,16 @@ var warmup = {
1583
1762
  name: "disable",
1584
1763
  summary: "Disable warmup for an account (cancels pending warmup sends).",
1585
1764
  method: "POST",
1586
- path: "/warmup/accounts/:id/disable",
1587
- params: [{ name: "id", positional: true, desc: "account id" }],
1765
+ path: "/warmup/sender-accounts/:email/disable",
1766
+ params: [{ name: "email", positional: true, desc: "sender-account email" }],
1588
1767
  success: "Warmup disabled."
1589
1768
  },
1590
1769
  {
1591
1770
  name: "settings",
1592
1771
  summary: "Update warmup targets for an account.",
1593
1772
  method: "PATCH",
1594
- path: "/warmup/accounts/:id/settings",
1595
- params: [{ name: "id", positional: true, desc: "account id" }, ...warmupSettings],
1773
+ path: "/warmup/sender-accounts/:email/settings",
1774
+ params: [{ name: "email", positional: true, desc: "sender-account email" }, ...warmupSettings],
1596
1775
  validate: "warmup.settings",
1597
1776
  success: "Warmup settings updated."
1598
1777
  },
@@ -1601,8 +1780,8 @@ var warmup = {
1601
1780
  name: "history",
1602
1781
  summary: "Warmup send/receive history for an account.",
1603
1782
  method: "GET",
1604
- path: "/warmup/history/:id",
1605
- params: [{ name: "id", positional: true, desc: "account id" }, { name: "limit", type: "number", default: "50", desc: "rows (default 50)" }]
1783
+ path: "/warmup/sender-accounts/:email/history",
1784
+ params: [{ name: "email", positional: true, desc: "sender-account email" }, { name: "limit", type: "number", default: "50", desc: "rows (default 50)" }]
1606
1785
  }
1607
1786
  ]
1608
1787
  };
@@ -2016,6 +2195,7 @@ var workspaces = {
2016
2195
  var groups = [
2017
2196
  workspaces,
2018
2197
  campaigns,
2198
+ subsequences,
2019
2199
  accounts,
2020
2200
  leads,
2021
2201
  inbox,
@@ -2031,7 +2211,7 @@ var groups = [
2031
2211
  // src/commands/auth.ts
2032
2212
  function registerAuth(program2) {
2033
2213
  const auth = program2.command("auth").description("API key setup + identity");
2034
- auth.command("setup").description("Save your API key + instance URL to ~/.arcsend/config.txt (chmod 600)").requiredOption("--key <key>", "Your arc_ API key").option("--url <url>", "Instance URL", DEFAULT_URL).action((opts) => {
2214
+ auth.command("setup").description("Save your API key + instance URL to ~/.arcsend/config.txt (chmod 600)").requiredOption("--key <key>", "Your arc_ API key").requiredOption("--url <url>", "Your instance URL, e.g. https://app.arcsend.io (the /cli page has it pre-filled)").action((opts) => {
2035
2215
  saveConfig(opts.key, opts.url);
2036
2216
  ok(`Saved credentials to ${CONFIG_PATH}`);
2037
2217
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@arcsend/cli",
3
- "version": "1.0.0",
4
- "description": "ArcSend cold email automation from your terminal",
3
+ "version": "1.2.0",
4
+ "description": "ArcSend \u2014 cold email automation from your terminal",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "arcsend": "./dist/index.js"
@@ -41,4 +41,4 @@
41
41
  "tsx": "^4.16.0",
42
42
  "typescript": "^5.5.0"
43
43
  }
44
- }
44
+ }