@lead-routing/cli 0.6.2 → 0.6.4

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 (2) hide show
  1. package/dist/index.js +135 -25
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import { readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "
9
9
  import { exec } from "child_process";
10
10
  import { platform } from "os";
11
11
  import { join as join5 } from "path";
12
- import { intro, outro, note as note3, log as log7, confirm, cancel as cancel3, isCancel as isCancel3, password as promptPassword } from "@clack/prompts";
12
+ import { intro, outro, note as note3, log as log7, confirm, cancel as cancel3, isCancel as isCancel3, password as promptPassword, select, text as text3 } from "@clack/prompts";
13
13
  import chalk2 from "chalk";
14
14
 
15
15
  // src/steps/prerequisites.ts
@@ -1208,16 +1208,108 @@ async function runInit(options = {}) {
1208
1208
  let auth;
1209
1209
  try {
1210
1210
  auth = await requireAuth();
1211
- } catch (err) {
1212
- log7.error(err instanceof Error ? err.message : "Authentication required");
1213
- note3(
1214
- `Run one of the following:
1215
-
1216
- ${chalk2.cyan("lead-routing signup")} Create a new account
1217
- ${chalk2.cyan("lead-routing login")} Log in to existing account`,
1218
- "Account Required"
1219
- );
1220
- process.exit(1);
1211
+ } catch {
1212
+ const action = await select({
1213
+ message: "You need an account to continue. What would you like to do?",
1214
+ options: [
1215
+ { value: "signup", label: "Create a new account" },
1216
+ { value: "login", label: "Log in to existing account" }
1217
+ ]
1218
+ });
1219
+ if (isCancel3(action)) {
1220
+ cancel3("Setup cancelled.");
1221
+ process.exit(0);
1222
+ }
1223
+ if (action === "signup") {
1224
+ const firstName = await text3({ message: "First name", placeholder: "John", validate: (v) => v.trim() ? void 0 : "Required" });
1225
+ if (isCancel3(firstName)) {
1226
+ cancel3("Setup cancelled.");
1227
+ process.exit(0);
1228
+ }
1229
+ const lastName = await text3({ message: "Last name", placeholder: "Smith", validate: (v) => v.trim() ? void 0 : "Required" });
1230
+ if (isCancel3(lastName)) {
1231
+ cancel3("Setup cancelled.");
1232
+ process.exit(0);
1233
+ }
1234
+ const signupEmail = await text3({ message: "Email", placeholder: "john@acme.com", validate: (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v.trim()) ? void 0 : "Invalid email" });
1235
+ if (isCancel3(signupEmail)) {
1236
+ cancel3("Setup cancelled.");
1237
+ process.exit(0);
1238
+ }
1239
+ const signupPw = await promptPassword({ message: "Password (min 8 characters)", validate: (v) => v.length >= 8 ? void 0 : "Must be at least 8 characters" });
1240
+ if (isCancel3(signupPw)) {
1241
+ cancel3("Setup cancelled.");
1242
+ process.exit(0);
1243
+ }
1244
+ const confirmPw = await promptPassword({ message: "Confirm password", validate: (v) => v === signupPw ? void 0 : "Passwords do not match" });
1245
+ if (isCancel3(confirmPw)) {
1246
+ cancel3("Setup cancelled.");
1247
+ process.exit(0);
1248
+ }
1249
+ log7.step("Creating account...");
1250
+ try {
1251
+ await apiSignup({ firstName: firstName.trim(), lastName: lastName.trim(), email: signupEmail.trim(), password: signupPw });
1252
+ log7.success("Account created!");
1253
+ } catch (err) {
1254
+ log7.error(err instanceof Error ? err.message : "Signup failed");
1255
+ process.exit(1);
1256
+ }
1257
+ note3(
1258
+ `Check your email (${signupEmail.trim()}) for a verification link.
1259
+ After verifying, press Enter to continue.`,
1260
+ "Verify Email"
1261
+ );
1262
+ await text3({ message: "Press Enter once you've verified your email...", defaultValue: "" });
1263
+ log7.step("Logging in...");
1264
+ try {
1265
+ const { token, customer } = await apiLogin(signupEmail.trim(), signupPw);
1266
+ if (!customer.emailVerified) {
1267
+ log7.warn("Email not verified yet.");
1268
+ const resend = await confirm({ message: "Resend verification email?" });
1269
+ if (resend && !isCancel3(resend)) {
1270
+ await apiResendVerification(token).catch(() => {
1271
+ });
1272
+ log7.info("Verification email sent. Verify and re-run `lead-routing init`.");
1273
+ }
1274
+ process.exit(1);
1275
+ }
1276
+ saveCredentials({ token, customer, storedAt: (/* @__PURE__ */ new Date()).toISOString() });
1277
+ auth = { token, customer, storedAt: (/* @__PURE__ */ new Date()).toISOString() };
1278
+ } catch (err) {
1279
+ log7.error(err instanceof Error ? err.message : "Login failed");
1280
+ process.exit(1);
1281
+ }
1282
+ } else {
1283
+ const loginEmail = await text3({ message: "Email", placeholder: "john@acme.com" });
1284
+ if (isCancel3(loginEmail)) {
1285
+ cancel3("Setup cancelled.");
1286
+ process.exit(0);
1287
+ }
1288
+ const loginPw = await promptPassword({ message: "Password" });
1289
+ if (isCancel3(loginPw)) {
1290
+ cancel3("Setup cancelled.");
1291
+ process.exit(0);
1292
+ }
1293
+ log7.step("Authenticating...");
1294
+ try {
1295
+ const { token, customer } = await apiLogin(loginEmail.trim(), loginPw);
1296
+ if (!customer.emailVerified) {
1297
+ log7.warn("Email not verified yet.");
1298
+ const resend = await confirm({ message: "Resend verification email?" });
1299
+ if (resend && !isCancel3(resend)) {
1300
+ await apiResendVerification(token).catch(() => {
1301
+ });
1302
+ log7.info("Verification email sent. Verify and re-run `lead-routing init`.");
1303
+ }
1304
+ process.exit(1);
1305
+ }
1306
+ saveCredentials({ token, customer, storedAt: (/* @__PURE__ */ new Date()).toISOString() });
1307
+ auth = { token, customer, storedAt: (/* @__PURE__ */ new Date()).toISOString() };
1308
+ } catch (err) {
1309
+ log7.error(err instanceof Error ? err.message : "Login failed");
1310
+ process.exit(1);
1311
+ }
1312
+ }
1221
1313
  }
1222
1314
  log7.success(`Logged in as ${auth.customer.firstName} ${auth.customer.lastName} \u2014 ${formatTierBadge(auth.customer.tier)}`);
1223
1315
  try {
@@ -1313,6 +1405,24 @@ Files created: docker-compose.yml, Caddyfile, .env.web, .env.engine, lead-routin
1313
1405
  The managed package is already installed \u2014 just click "Connect Salesforce" to authorize.`,
1314
1406
  "Next: Connect Salesforce"
1315
1407
  );
1408
+ let webhookSecret = "";
1409
+ try {
1410
+ const envEngineContent = readFileSync4(join5(dir, ".env.engine"), "utf-8");
1411
+ const match = envEngineContent.match(/^WEBHOOK_SECRET=(.+)$/m);
1412
+ if (match) webhookSecret = match[1].trim();
1413
+ } catch {
1414
+ }
1415
+ if (webhookSecret) {
1416
+ const mcpCmd = `claude mcp add lead-routing \\
1417
+ -e APP_URL=${cfg.appUrl} \\
1418
+ -e ENGINE_URL=${cfg.engineUrl} \\
1419
+ -e WEBHOOK_SECRET=${webhookSecret} \\
1420
+ -- npx -y @lead-routing/mcp`;
1421
+ note3(
1422
+ "Paste this command in your terminal to connect Lead Routing to Claude Code:\n\n" + chalk2.cyan(mcpCmd),
1423
+ "Claude Code MCP"
1424
+ );
1425
+ }
1316
1426
  outro(
1317
1427
  chalk2.green("\u2714 You're live!") + `
1318
1428
 
@@ -1591,7 +1701,7 @@ function runConfigShow() {
1591
1701
  }
1592
1702
 
1593
1703
  // src/commands/sfdc.ts
1594
- import { intro as intro5, outro as outro5, text as text3, note as note4, confirm as confirm2, log as log14, isCancel as isCancel4, cancel as cancel4 } from "@clack/prompts";
1704
+ import { intro as intro5, outro as outro5, text as text4, note as note4, confirm as confirm2, log as log14, isCancel as isCancel4, cancel as cancel4 } from "@clack/prompts";
1595
1705
  import chalk6 from "chalk";
1596
1706
  import { exec as exec2 } from "child_process";
1597
1707
  import { platform as platform2 } from "os";
@@ -1723,9 +1833,9 @@ Content-Type: application/zip\r
1723
1833
  body
1724
1834
  });
1725
1835
  if (!res.ok) {
1726
- const text7 = await res.text();
1836
+ const text8 = await res.text();
1727
1837
  throw new Error(
1728
- `Metadata deploy request failed (${res.status}): ${text7}`
1838
+ `Metadata deploy request failed (${res.status}): ${text8}`
1729
1839
  );
1730
1840
  }
1731
1841
  const result = await res.json();
@@ -1742,9 +1852,9 @@ Content-Type: application/zip\r
1742
1852
  const url = `${this.baseUrl}/metadata/deployRequest/${deployId}?includeDetails=true`;
1743
1853
  const res = await fetch(url, { headers: this.headers() });
1744
1854
  if (!res.ok) {
1745
- const text7 = await res.text();
1855
+ const text8 = await res.text();
1746
1856
  throw new Error(
1747
- `Deploy status check failed (${res.status}): ${text7}`
1857
+ `Deploy status check failed (${res.status}): ${text8}`
1748
1858
  );
1749
1859
  }
1750
1860
  const data = await res.json();
@@ -2112,13 +2222,13 @@ async function runSfdcDeploy() {
2112
2222
  log14.info(`Using config from ${dir}/lead-routing.json`);
2113
2223
  } else {
2114
2224
  log14.warn("No lead-routing.json found \u2014 enter the URLs from your installation.");
2115
- const rawApp = await text3({
2225
+ const rawApp = await text4({
2116
2226
  message: "App URL (e.g. https://leads.acme.com)",
2117
2227
  validate: (v) => !v ? "Required" : void 0
2118
2228
  });
2119
2229
  if (typeof rawApp === "symbol") process.exit(0);
2120
2230
  appUrl = rawApp.trim();
2121
- const rawEngine = await text3({
2231
+ const rawEngine = await text4({
2122
2232
  message: "Engine URL (e.g. https://engine.acme.com or https://acme.com:3001)",
2123
2233
  validate: (v) => !v ? "Required" : void 0
2124
2234
  });
@@ -2148,7 +2258,7 @@ Install URL: ${chalk6.cyan(MANAGED_PACKAGE_INSTALL_URL2)}`,
2148
2258
  } else {
2149
2259
  log14.success("Salesforce package installed");
2150
2260
  }
2151
- const alias = await text3({
2261
+ const alias = await text4({
2152
2262
  message: "Salesforce org alias (used to log in)",
2153
2263
  placeholder: "lead-routing",
2154
2264
  initialValue: "lead-routing",
@@ -2351,7 +2461,7 @@ import {
2351
2461
  intro as intro9,
2352
2462
  outro as outro9,
2353
2463
  spinner as spinner8,
2354
- text as text6,
2464
+ text as text7,
2355
2465
  password as promptPassword4,
2356
2466
  note as note7,
2357
2467
  log as log18,
@@ -2470,7 +2580,7 @@ async function runDev(opts = {}) {
2470
2580
  "You need a Salesforce Connected App with callback URL:\n http://localhost:3000/api/auth/sfdc/callback",
2471
2581
  "Before you begin"
2472
2582
  );
2473
- const clientId = await text6({
2583
+ const clientId = await text7({
2474
2584
  message: "Consumer Key (Client ID)",
2475
2585
  validate: (v) => !v ? "Required" : void 0
2476
2586
  });
@@ -2483,7 +2593,7 @@ async function runDev(opts = {}) {
2483
2593
  cancel5("Cancelled.");
2484
2594
  process.exit(0);
2485
2595
  }
2486
- const loginUrl = await text6({
2596
+ const loginUrl = await text7({
2487
2597
  message: "Login URL",
2488
2598
  initialValue: "https://login.salesforce.com",
2489
2599
  validate: (v) => !v ? "Required" : void 0
@@ -2582,7 +2692,7 @@ async function runDev(opts = {}) {
2582
2692
  "Sets up a full Lead Routing stack locally using Docker.\nNo SSH, no VPS, no manual steps.",
2583
2693
  "First-time setup"
2584
2694
  );
2585
- const adminEmail = await text6({
2695
+ const adminEmail = await text7({
2586
2696
  message: "Admin email",
2587
2697
  placeholder: "you@company.com",
2588
2698
  validate: (v) => {
@@ -2604,7 +2714,7 @@ async function runDev(opts = {}) {
2604
2714
  "Optional \u2014 needed to connect Salesforce.\nPress Enter to skip; add credentials later via `lead-routing config sfdc`.",
2605
2715
  "Salesforce Connected App"
2606
2716
  );
2607
- const sfdcClientId = await text6({
2717
+ const sfdcClientId = await text7({
2608
2718
  message: "Consumer Key (Client ID)",
2609
2719
  placeholder: "Leave blank to skip"
2610
2720
  });
@@ -2615,7 +2725,7 @@ async function runDev(opts = {}) {
2615
2725
  if (isCancel8(s)) bail3(s);
2616
2726
  sfdcClientSecret = s.trim();
2617
2727
  }
2618
- const tunnelUrl = await text6({
2728
+ const tunnelUrl = await text7({
2619
2729
  message: "Engine tunnel URL (for Salesforce webhooks)",
2620
2730
  placeholder: "Leave blank \u2014 use `ssh -R 80:localhost:3001 localhost.run` to get one"
2621
2731
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lead-routing/cli",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "Self-hosted deployment CLI for Lead Routing",
5
5
  "homepage": "https://github.com/lead-routing/lead-routing",
6
6
  "keywords": [