clishop 1.3.3 → 1.4.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 CHANGED
@@ -7,11 +7,10 @@ import {
7
7
  handleApiError,
8
8
  isKeytarAvailable,
9
9
  isLoggedIn,
10
- login,
11
10
  logout,
12
- register,
13
- resolveBackend
14
- } from "./chunk-ML7L6BAH.js";
11
+ resolveBackend,
12
+ storeAuthFromSetup
13
+ } from "./chunk-EAXPWOMT.js";
15
14
  import {
16
15
  createAgent,
17
16
  deleteAgent,
@@ -31,111 +30,7 @@ import chalk16 from "chalk";
31
30
  // src/commands/auth.ts
32
31
  import chalk from "chalk";
33
32
  import ora from "ora";
34
- import inquirer from "inquirer";
35
- async function readPasswordFromStdin() {
36
- const chunks = [];
37
- for await (const chunk of process.stdin) {
38
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
39
- }
40
- return Buffer.concat(chunks).toString("utf8").trim();
41
- }
42
33
  function registerAuthCommands(program2) {
43
- program2.command("login").description("Log in to your CLISHOP account").option("-e, --email <email>", "Email address").option("-p, --password <password>", "Password (less secure: exposed to shell history)").option("--password-stdin", "Read password from stdin").action(async (opts) => {
44
- try {
45
- if (opts.password && opts.passwordStdin) {
46
- console.error(chalk.red("\n\u2717 Use either --password or --password-stdin, not both."));
47
- process.exitCode = 1;
48
- return;
49
- }
50
- if (await isLoggedIn()) {
51
- const user = await getUserInfo();
52
- const { confirm } = await inquirer.prompt([
53
- {
54
- type: "confirm",
55
- name: "confirm",
56
- message: `You are already logged in as ${chalk.cyan(user?.email || "unknown")}. Log in as a different user?`,
57
- default: false
58
- }
59
- ]);
60
- if (!confirm) return;
61
- }
62
- let email = opts.email;
63
- let password = opts.password;
64
- if (opts.passwordStdin) {
65
- password = await readPasswordFromStdin();
66
- if (!password) {
67
- console.error(chalk.red("\n\u2717 No password was provided on stdin."));
68
- process.exitCode = 1;
69
- return;
70
- }
71
- }
72
- if (opts.password) {
73
- console.log(chalk.yellow("\u26A0 Warning: --password can leak credentials via shell history/process list."));
74
- console.log(chalk.yellow(" Prefer --password-stdin or the interactive masked prompt.\n"));
75
- }
76
- if (!email || !password) {
77
- const answers = await inquirer.prompt([
78
- ...!email ? [{ type: "input", name: "email", message: "Email:" }] : [],
79
- ...!password ? [{ type: "password", name: "password", message: "Password:", mask: "*" }] : []
80
- ]);
81
- email = email || answers.email;
82
- password = password || answers.password;
83
- }
84
- const spinner = ora("Logging in...").start();
85
- try {
86
- const user = await login(email, password);
87
- spinner.succeed(chalk.green(`Logged in as ${chalk.bold(user.name)} (${user.email})`));
88
- } catch (loginErr) {
89
- const msg = loginErr?.response?.data?.message || loginErr.message;
90
- spinner.fail(chalk.red(`Login failed: ${msg}`));
91
- process.exitCode = 1;
92
- }
93
- } catch (error) {
94
- const msg = error?.response?.data?.message || error.message;
95
- console.error(chalk.red(`
96
- \u2717 Login failed: ${msg}`));
97
- process.exitCode = 1;
98
- }
99
- });
100
- program2.command("register").description("Create a new CLISHOP account").action(async () => {
101
- try {
102
- const answers = await inquirer.prompt([
103
- { type: "input", name: "name", message: "Full name:" },
104
- { type: "input", name: "email", message: "Email:" },
105
- {
106
- type: "password",
107
- name: "password",
108
- message: "Password:",
109
- mask: "*"
110
- },
111
- {
112
- type: "password",
113
- name: "confirmPassword",
114
- message: "Confirm password:",
115
- mask: "*"
116
- }
117
- ]);
118
- if (answers.password !== answers.confirmPassword) {
119
- console.error(chalk.red("\u2717 Passwords do not match."));
120
- process.exitCode = 1;
121
- return;
122
- }
123
- const spinner = ora("Creating account...").start();
124
- try {
125
- const user = await register(answers.email, answers.password, answers.name);
126
- spinner.succeed(chalk.green(`Account created! Welcome, ${chalk.bold(user.name)}.`));
127
- } catch (regErr) {
128
- const msg = regErr?.response?.data?.message || regErr.message;
129
- spinner.fail(chalk.red(`Registration failed: ${msg}`));
130
- process.exitCode = 1;
131
- }
132
- } catch (error) {
133
- const msg = error?.response?.data?.message || error.message;
134
- console.error(chalk.red(`
135
- \u2717 Registration failed: ${msg}`));
136
- process.exitCode = 1;
137
- }
138
- });
139
34
  program2.command("logout").description("Log out of your CLISHOP account").action(async () => {
140
35
  const spinner = ora("Logging out...").start();
141
36
  await logout();
@@ -155,7 +50,7 @@ function registerAuthCommands(program2) {
155
50
  });
156
51
  program2.command("whoami").description("Show the currently logged-in user").action(async () => {
157
52
  if (!await isLoggedIn()) {
158
- console.log(chalk.yellow("Not logged in. Run: clishop login"));
53
+ console.log(chalk.yellow("Not set up yet. Run: clishop setup"));
159
54
  return;
160
55
  }
161
56
  const user = await getUserInfo();
@@ -171,7 +66,7 @@ function registerAuthCommands(program2) {
171
66
 
172
67
  // src/commands/agent.ts
173
68
  import chalk2 from "chalk";
174
- import inquirer2 from "inquirer";
69
+ import inquirer from "inquirer";
175
70
  function printAgent(agent, isActive) {
176
71
  const marker = isActive ? chalk2.green("\u25CF ") : " ";
177
72
  console.log(`${marker}${chalk2.bold(agent.name)}`);
@@ -265,7 +160,7 @@ function registerAgentCommands(program2) {
265
160
  chalk2.dim(" ") + chalk2.white("clishop agent spending-limit <amount>")
266
161
  );
267
162
  console.log();
268
- const answers = await inquirer2.prompt([
163
+ const answers = await inquirer.prompt([
269
164
  {
270
165
  type: "number",
271
166
  name: "maxOrderAmount",
@@ -377,7 +272,7 @@ function registerAgentCommands(program2) {
377
272
  });
378
273
  agent.command("delete <name>").alias("rm").description("Delete an agent").action(async (name) => {
379
274
  try {
380
- const { confirm } = await inquirer2.prompt([
275
+ const { confirm } = await inquirer.prompt([
381
276
  {
382
277
  type: "confirm",
383
278
  name: "confirm",
@@ -400,7 +295,7 @@ function registerAgentCommands(program2) {
400
295
  // src/commands/address.ts
401
296
  import chalk3 from "chalk";
402
297
  import ora2 from "ora";
403
- import inquirer3 from "inquirer";
298
+ import inquirer2 from "inquirer";
404
299
 
405
300
  // src/countries.ts
406
301
  var COUNTRY_ALIASES = {
@@ -677,7 +572,7 @@ function getCountryName(code) {
677
572
  // src/commands/address.ts
678
573
  async function askCountry() {
679
574
  while (true) {
680
- const { rawCountry } = await inquirer3.prompt([
575
+ const { rawCountry } = await inquirer2.prompt([
681
576
  {
682
577
  type: "input",
683
578
  name: "rawCountry",
@@ -688,7 +583,7 @@ async function askCountry() {
688
583
  const result = normalizeCountry(rawCountry.trim());
689
584
  if (result.code && result.name) {
690
585
  console.log(chalk3.green(` \u2713 Country: ${result.name} (${result.code})`));
691
- const { confirm } = await inquirer3.prompt([
586
+ const { confirm } = await inquirer2.prompt([
692
587
  {
693
588
  type: "confirm",
694
589
  name: "confirm",
@@ -748,7 +643,7 @@ Addresses for agent "${agent.name}":
748
643
  address.command("add").description("Add a new address").action(async () => {
749
644
  try {
750
645
  const agent = getActiveAgent();
751
- const answers = await inquirer3.prompt([
646
+ const answers = await inquirer2.prompt([
752
647
  { type: "input", name: "label", message: "Label (e.g. Home, Office):" },
753
648
  {
754
649
  type: "input",
@@ -785,10 +680,10 @@ Addresses for agent "${agent.name}":
785
680
  { type: "input", name: "region", message: "State / Province / Region (optional):" }
786
681
  ]);
787
682
  const countryInfo = await askCountry();
788
- const { instructionsInput } = await inquirer3.prompt([
683
+ const { instructionsInput } = await inquirer2.prompt([
789
684
  { type: "input", name: "instructionsInput", message: "Delivery instructions (optional):" }
790
685
  ]);
791
- const { isCompanyAddr } = await inquirer3.prompt([
686
+ const { isCompanyAddr } = await inquirer2.prompt([
792
687
  {
793
688
  type: "confirm",
794
689
  name: "isCompanyAddr",
@@ -798,7 +693,7 @@ Addresses for agent "${agent.name}":
798
693
  ]);
799
694
  let companyAnswers = { companyName: "", vatNumber: "" };
800
695
  if (isCompanyAddr) {
801
- companyAnswers = await inquirer3.prompt([
696
+ companyAnswers = await inquirer2.prompt([
802
697
  {
803
698
  type: "input",
804
699
  name: "companyName",
@@ -808,7 +703,7 @@ Addresses for agent "${agent.name}":
808
703
  { type: "input", name: "vatNumber", message: "VAT number (optional):" }
809
704
  ]);
810
705
  }
811
- const { setDefault } = await inquirer3.prompt([
706
+ const { setDefault } = await inquirer2.prompt([
812
707
  {
813
708
  type: "confirm",
814
709
  name: "setDefault",
@@ -845,7 +740,7 @@ Addresses for agent "${agent.name}":
845
740
  });
846
741
  address.command("remove <id>").alias("rm").description("Remove an address by ID").action(async (id) => {
847
742
  try {
848
- const { confirm } = await inquirer3.prompt([
743
+ const { confirm } = await inquirer2.prompt([
849
744
  {
850
745
  type: "confirm",
851
746
  name: "confirm",
@@ -886,9 +781,10 @@ import ora4 from "ora";
886
781
  // src/commands/setup.ts
887
782
  import chalk4 from "chalk";
888
783
  import ora3 from "ora";
889
- import inquirer4 from "inquirer";
784
+ import inquirer3 from "inquirer";
890
785
  import open from "open";
891
786
  import { execFileSync } from "child_process";
787
+ import axios from "axios";
892
788
  async function openBrowser(url) {
893
789
  try {
894
790
  if (process.platform === "win32") {
@@ -913,731 +809,150 @@ async function openBrowser(url) {
913
809
  function divider(color = chalk4.cyan) {
914
810
  console.log(" " + color("\u2500".repeat(48)));
915
811
  }
916
- function stepHeader(step, total, title) {
917
- console.log();
918
- divider();
919
- console.log();
920
- console.log(
921
- chalk4.bold.white(` STEP ${step} of ${total}`) + chalk4.dim(" \xB7 ") + chalk4.bold(title)
922
- );
923
- console.log();
924
- }
925
812
  function registerSetupCommand(program2) {
926
813
  program2.command("setup").description(
927
- "First-time setup wizard \u2014 account, agent, address, payment, first search"
928
- ).action(async () => {
929
- await runSetupWizard();
814
+ "Set up your CLISHOP account \u2014 links your payment method via a secure browser link"
815
+ ).option("--email <email>", "Email address (skips prompt)").option("--name <name>", "Full name (skips prompt)").action(async (opts) => {
816
+ await runSetupWizard(opts.email, opts.name);
930
817
  });
931
818
  }
932
- async function runSetupWizard() {
819
+ async function runSetupWizard(emailArg, nameArg) {
933
820
  const config = getConfig();
821
+ const loggedIn = await isLoggedIn();
822
+ if (loggedIn) {
823
+ const user = await getUserInfo();
824
+ try {
825
+ const api = getApiClient();
826
+ const agent = getActiveAgent();
827
+ const pmRes = await api.get("/payment-methods", { params: { agent: agent.name } });
828
+ const methods = pmRes.data.paymentMethods || [];
829
+ if (methods.length > 0) {
830
+ console.log();
831
+ console.log(chalk4.green(` \u2713 Already set up as ${chalk4.bold(user?.name || user?.email || "unknown")} with a payment method linked.`));
832
+ console.log(chalk4.dim(" Nothing to do. Run ") + chalk4.white("clishop search <query>") + chalk4.dim(" to get started."));
833
+ console.log();
834
+ return;
835
+ }
836
+ } catch {
837
+ }
838
+ console.log();
839
+ console.log(chalk4.green(` \u2713 Logged in as ${chalk4.bold(user?.name || user?.email || "unknown")}`));
840
+ console.log(chalk4.dim(" No payment method linked yet. Let's fix that."));
841
+ console.log();
842
+ await runPaymentLinkFlow(config);
843
+ return;
844
+ }
934
845
  console.log();
935
846
  divider(chalk4.cyan);
936
847
  console.log();
937
848
  console.log(chalk4.bold.cyan(" W E L C O M E T O C L I S H O P"));
938
849
  console.log(chalk4.dim(" Order anything from your terminal."));
939
- console.log(chalk4.dim(` Build: ${"2026-03-22T18:05:29.439Z"}`));
850
+ console.log(chalk4.dim(` Build: ${"2026-03-31T19:16:20.769Z"}`));
940
851
  console.log();
941
852
  divider(chalk4.cyan);
942
853
  console.log();
943
854
  console.log(
944
- chalk4.dim(" This wizard will guide you through the initial setup.")
945
- );
946
- console.log(
947
- chalk4.dim(" It only takes a minute. You can re-run it anytime with:")
948
- );
949
- console.log(chalk4.dim(" ") + chalk4.white("clishop setup"));
950
- console.log();
951
- console.log(
952
- chalk4.bold.yellow(" \u{1F4CB} PATH Setup")
953
- );
954
- console.log(
955
- chalk4.dim(" Make sure clishop is in your PATH so your AI agents can use it.")
855
+ chalk4.dim(" Set up your account in one step. You'll get a link to")
956
856
  );
957
857
  console.log(
958
- chalk4.dim(" If you installed via npm globally (") + chalk4.white("npm i -g clishop") + chalk4.dim("), it should already be available.")
858
+ chalk4.dim(" securely link your payment method in the browser.")
959
859
  );
960
860
  console.log(
961
- chalk4.dim(" Verify with: ") + chalk4.white("clishop --version")
861
+ chalk4.dim(" Your AI agent can then add addresses and place orders for you.")
962
862
  );
863
+ console.log();
963
864
  console.log(
964
- chalk4.dim(" If not, add the npm global bin to your PATH:")
865
+ chalk4.dim(" By creating an account you agree to the CLISHOP")
965
866
  );
966
867
  console.log(
967
- chalk4.dim(" macOS/Linux: ") + chalk4.white('export PATH="$(npm config get prefix)/bin:$PATH"')
868
+ chalk4.dim(" Terms & Conditions: ") + chalk4.cyan.underline("https://clishop.ai/terms")
968
869
  );
969
870
  console.log(
970
- chalk4.dim(" Windows: ") + chalk4.white("npm config get prefix") + chalk4.dim(" \u2192 add that path to your system PATH")
871
+ chalk4.dim(" Privacy Policy: ") + chalk4.cyan.underline("https://clishop.ai/privacy")
971
872
  );
972
873
  console.log();
973
- const { setupMethod } = await inquirer4.prompt([
974
- {
975
- type: "select",
976
- name: "setupMethod",
977
- message: "How would you like to configure CLISHOP?",
978
- choices: [
979
- { name: "Here in the CLI", value: "cli" },
980
- { name: "On the website (opens browser)", value: "web" }
981
- ]
982
- }
983
- ]);
984
- if (setupMethod === "web") {
985
- const webSetupUrl = "https://clishop.ai/setup";
986
- console.log();
987
- console.log(chalk4.bold(" Opening the setup wizard on the website..."));
988
- console.log();
989
- console.log(" " + chalk4.cyan.underline(webSetupUrl));
990
- console.log();
991
- const opened = await openBrowser(webSetupUrl);
992
- if (!opened) {
993
- console.log(
994
- chalk4.yellow(" Could not open browser automatically. Please visit the link above.")
995
- );
996
- }
997
- console.log(
998
- chalk4.dim(" Create your account and configure everything on the website.")
999
- );
1000
- console.log(
1001
- chalk4.dim(" When you're done, come back here to link your account to the CLI.")
1002
- );
1003
- console.log();
1004
- await inquirer4.prompt([
1005
- {
1006
- type: "input",
1007
- name: "done",
1008
- message: "Press Enter after completing setup on the website..."
1009
- }
874
+ let email = emailArg;
875
+ let name = nameArg;
876
+ if (!email || !name) {
877
+ const answers = await inquirer3.prompt([
878
+ ...!email ? [{ type: "input", name: "email", message: "Email:" }] : [],
879
+ ...!name ? [{ type: "input", name: "name", message: "Your name:" }] : []
1010
880
  ]);
881
+ email = email || answers.email;
882
+ name = name || answers.name;
883
+ }
884
+ const spinner = ora3("Creating your account and payment link...").start();
885
+ let setupUrl;
886
+ let deviceCode;
887
+ try {
888
+ const baseUrl2 = getApiBaseUrl();
889
+ const res = await axios.post(`${baseUrl2}/auth/setup-link`, { email, name });
890
+ setupUrl = res.data.setupUrl;
891
+ deviceCode = res.data.deviceCode;
892
+ spinner.stop();
893
+ } catch (error) {
894
+ const msg = error?.response?.data?.message || error.message;
895
+ spinner.fail(chalk4.red(`Setup failed: ${msg}`));
1011
896
  console.log();
1012
- console.log(chalk4.bold(" Now let's link your account to the CLI."));
1013
- console.log();
1014
- const creds = await inquirer4.prompt([
1015
- { type: "input", name: "email", message: "Email (same as on the website):" },
1016
- { type: "password", name: "password", message: "Password:", mask: "*" }
1017
- ]);
1018
- const spinner = ora3("Logging in...").start();
1019
- try {
1020
- const user = await login(creds.email, creds.password);
1021
- spinner.succeed(chalk4.green(`Logged in as ${chalk4.bold(user.name)}.`));
1022
- } catch (error) {
1023
- spinner.fail(
1024
- chalk4.red(
1025
- `Login failed: ${error?.response?.data?.message || error.message}`
1026
- )
1027
- );
1028
- console.log();
1029
- console.log(
1030
- chalk4.dim(" You can try again with: ") + chalk4.white("clishop login")
1031
- );
1032
- console.log();
1033
- config.set("setupCompleted", true);
1034
- return;
1035
- }
1036
- const syncSpinner = ora3("Syncing your settings from the website...").start();
1037
- try {
1038
- const api = getApiClient();
1039
- const agent = getActiveAgent();
1040
- await ensureAgentOnBackend(agent.name);
1041
- const [addrRes, pmRes] = await Promise.all([
1042
- api.get("/addresses", { params: { agent: agent.name } }),
1043
- api.get("/payment-methods", { params: { agent: agent.name } })
1044
- ]);
1045
- const addresses = addrRes.data.addresses || [];
1046
- const methods = pmRes.data.paymentMethods || [];
1047
- const synced = [];
1048
- if (addresses.length > 0) {
1049
- updateAgent(agent.name, { defaultAddressId: addresses[0].id });
1050
- synced.push(`address "${addresses[0].label || "Home"}"`);
1051
- }
1052
- if (methods.length > 0) {
1053
- updateAgent(agent.name, { defaultPaymentMethodId: methods[0].id });
1054
- synced.push(`payment "${methods[0].label}"`);
1055
- }
1056
- if (synced.length > 0) {
1057
- syncSpinner.succeed(chalk4.green(`Synced: ${synced.join(", ")}`));
1058
- } else {
1059
- syncSpinner.info(
1060
- chalk4.dim("No addresses or payment methods found yet. You can add them with:") + "\n " + chalk4.white("clishop address add") + "\n " + chalk4.white("clishop payment add")
1061
- );
1062
- }
1063
- } catch {
1064
- syncSpinner.warn(chalk4.yellow("Could not sync settings \u2014 you can add them manually later."));
1065
- }
1066
- config.set("setupCompleted", true);
1067
- console.log();
1068
- divider(chalk4.green);
1069
- console.log();
1070
- console.log(chalk4.bold.green(" \u2713 You're all set!"));
1071
- console.log();
1072
- console.log(chalk4.dim(" Try: ") + chalk4.white('clishop search "headphones"'));
1073
- console.log();
1074
- divider(chalk4.green);
897
+ console.log(chalk4.dim(" You can try again with: ") + chalk4.white("clishop setup"));
1075
898
  console.log();
899
+ process.exitCode = 1;
1076
900
  return;
1077
901
  }
1078
- stepHeader(1, 5, "Account");
1079
- let loggedIn = await isLoggedIn();
1080
- if (loggedIn) {
1081
- const user = await getUserInfo();
1082
- console.log(
1083
- chalk4.green(
1084
- ` \u2713 Already logged in as ${chalk4.bold(user?.name || user?.email || "unknown")}`
1085
- )
1086
- );
1087
- console.log();
1088
- const { continueAs } = await inquirer4.prompt([
1089
- {
1090
- type: "confirm",
1091
- name: "continueAs",
1092
- message: `Continue as ${user?.email}?`,
1093
- default: true
1094
- }
1095
- ]);
1096
- if (!continueAs) {
1097
- loggedIn = false;
1098
- }
1099
- }
1100
- if (!loggedIn) {
1101
- const { authChoice } = await inquirer4.prompt([
1102
- {
1103
- type: "select",
1104
- name: "authChoice",
1105
- message: "Do you have a CLISHOP account?",
1106
- choices: [
1107
- { name: "No \u2014 create a new account", value: "register" },
1108
- { name: "Yes \u2014 log in to existing account", value: "login" }
1109
- ]
1110
- }
1111
- ]);
1112
- if (authChoice === "register") {
1113
- console.log();
1114
- console.log(
1115
- chalk4.dim(" By creating an account you agree to the CLISHOP")
1116
- );
1117
- console.log(
1118
- chalk4.dim(" Terms & Conditions: ") + chalk4.cyan.underline("https://clishop.ai/terms")
1119
- );
1120
- console.log(
1121
- chalk4.dim(" Privacy Policy: ") + chalk4.cyan.underline("https://clishop.ai/privacy")
1122
- );
1123
- console.log();
1124
- const answers = await inquirer4.prompt([
1125
- { type: "input", name: "name", message: "Your name:" },
1126
- { type: "input", name: "email", message: "Email:" },
1127
- {
1128
- type: "password",
1129
- name: "password",
1130
- message: "Password:",
1131
- mask: "*"
1132
- },
1133
- {
1134
- type: "password",
1135
- name: "confirmPassword",
1136
- message: "Confirm password:",
1137
- mask: "*"
1138
- }
1139
- ]);
1140
- if (answers.password !== answers.confirmPassword) {
1141
- console.error(chalk4.red("\n \u2717 Passwords do not match."));
1142
- console.log(
1143
- chalk4.dim(" Run ") + chalk4.white("clishop setup") + chalk4.dim(" to try again.\n")
1144
- );
1145
- process.exitCode = 1;
1146
- return;
1147
- }
1148
- const spinner = ora3("Creating your account...").start();
1149
- try {
1150
- const user = await register(
1151
- answers.email,
1152
- answers.password,
1153
- answers.name
1154
- );
1155
- spinner.succeed(
1156
- chalk4.green(
1157
- `Account created! Welcome, ${chalk4.bold(user.name)}.`
1158
- )
1159
- );
1160
- } catch (error) {
1161
- spinner.fail(
1162
- chalk4.red(
1163
- `Registration failed: ${error?.response?.data?.message || error.message}`
1164
- )
1165
- );
1166
- console.log();
1167
- console.log(
1168
- chalk4.dim(
1169
- " Make sure the backend is running at: " + chalk4.white(config.get("apiBaseUrl"))
1170
- )
1171
- );
1172
- console.log(
1173
- chalk4.dim(" Then run ") + chalk4.white("clishop setup") + chalk4.dim(" again.\n")
1174
- );
1175
- process.exitCode = 1;
1176
- return;
1177
- }
1178
- } else {
1179
- const answers = await inquirer4.prompt([
1180
- { type: "input", name: "email", message: "Email:" },
1181
- {
1182
- type: "password",
1183
- name: "password",
1184
- message: "Password:",
1185
- mask: "*"
1186
- }
1187
- ]);
1188
- const spinner = ora3("Logging in...").start();
1189
- try {
1190
- const user = await login(answers.email, answers.password);
1191
- spinner.succeed(
1192
- chalk4.green(`Logged in as ${chalk4.bold(user.name)}.`)
1193
- );
1194
- } catch (error) {
1195
- spinner.fail(
1196
- chalk4.red(
1197
- `Login failed: ${error?.response?.data?.message || error.message}`
1198
- )
1199
- );
1200
- console.log();
1201
- console.log(
1202
- chalk4.dim(
1203
- " Make sure the backend is running at: " + chalk4.white(config.get("apiBaseUrl"))
1204
- )
1205
- );
1206
- console.log(
1207
- chalk4.dim(" Then run ") + chalk4.white("clishop setup") + chalk4.dim(" again.\n")
1208
- );
1209
- process.exitCode = 1;
1210
- return;
1211
- }
1212
- }
1213
- }
1214
- stepHeader(2, 5, "Agent");
1215
- console.log(
1216
- chalk4.dim(
1217
- " Agents are safety profiles that control per-order limits and categories."
1218
- )
1219
- );
1220
- console.log(
1221
- chalk4.dim(" A default agent is ready. You can customize it or create a new one.")
1222
- );
1223
- console.log(
1224
- chalk4.dim(" Default settings: ") + chalk4.white("$200 max per order") + chalk4.dim(", ") + chalk4.white("confirmation required") + chalk4.dim(" for every order.")
1225
- );
1226
- console.log(
1227
- chalk4.dim(" When an order is placed, you'll receive an ") + chalk4.white("email") + chalk4.dim(" and can also confirm on the ") + chalk4.white("website") + chalk4.dim(".")
1228
- );
1229
902
  console.log();
1230
- const { agentChoice } = await inquirer4.prompt([
1231
- {
1232
- type: "confirm",
1233
- name: "agentChoice",
1234
- message: "Configure a custom agent instead?",
1235
- default: false
1236
- }
1237
- ]);
1238
- if (agentChoice) {
1239
- const answers = await inquirer4.prompt([
1240
- {
1241
- type: "input",
1242
- name: "name",
1243
- message: "Agent name:",
1244
- validate: (v) => v.trim() ? true : "Name is required"
1245
- },
1246
- {
1247
- type: "number",
1248
- name: "maxOrderAmount",
1249
- message: "Max order amount per order ($) (optional, default $200):",
1250
- default: 200
1251
- },
1252
- {
1253
- type: "confirm",
1254
- name: "requireConfirmation",
1255
- message: "Require confirmation before ordering?",
1256
- default: true
1257
- }
1258
- ]);
1259
- const maxAmount = answers.maxOrderAmount || 200;
1260
- if (answers.requireConfirmation) {
1261
- console.log();
1262
- console.log(
1263
- chalk4.dim(" \u{1F512} When an order is placed you can confirm it via ") + chalk4.white("email") + chalk4.dim(" or on the ") + chalk4.white("website dashboard") + chalk4.dim(" \u2014 both are always available.")
1264
- );
1265
- }
1266
- try {
1267
- const agent = createAgent(answers.name.trim(), {
1268
- maxOrderAmount: maxAmount,
1269
- requireConfirmation: answers.requireConfirmation
1270
- });
1271
- setActiveAgent(agent.name);
1272
- const syncSpinner = ora3("Syncing agent to backend...").start();
1273
- await ensureAgentOnBackend(
1274
- agent.name,
1275
- maxAmount * 100,
1276
- answers.requireConfirmation
1277
- );
1278
- syncSpinner.succeed(
1279
- chalk4.green(
1280
- `Agent "${chalk4.bold(agent.name)}" created and set as active.`
1281
- )
1282
- );
1283
- } catch (error) {
1284
- console.error(chalk4.red(`
1285
- \u2717 ${error.message}`));
1286
- console.log(chalk4.dim(" Continuing with the default agent."));
1287
- }
1288
- } else {
1289
- console.log(chalk4.green(" \u2713 Using default agent (max $200/order, confirmation required)."));
1290
- }
1291
- stepHeader(3, 5, "Shipping Address");
1292
- console.log(
1293
- chalk4.dim(
1294
- " Add an address so products can be delivered to you."
1295
- )
1296
- );
1297
- console.log(
1298
- chalk4.dim(
1299
- " A shipping country is required for product searches to work correctly."
1300
- )
1301
- );
903
+ console.log(chalk4.bold(" Open this link to link your payment method:"));
1302
904
  console.log();
1303
- let addressCity = "";
1304
- let addressCountry = "";
1305
- {
1306
- const addr = await inquirer4.prompt([
1307
- {
1308
- type: "input",
1309
- name: "label",
1310
- message: "Label (e.g. Home, Office):",
1311
- default: "Home"
1312
- },
1313
- {
1314
- type: "input",
1315
- name: "firstName",
1316
- message: "First name:",
1317
- validate: (v) => v.trim() ? true : "First name is required"
1318
- },
1319
- {
1320
- type: "input",
1321
- name: "lastName",
1322
- message: "Last name:",
1323
- validate: (v) => v.trim() ? true : "Last name is required"
1324
- },
1325
- {
1326
- type: "input",
1327
- name: "phone",
1328
- message: "Phone number with country code (e.g. +32412345678, optional):"
1329
- },
1330
- {
1331
- type: "input",
1332
- name: "line1",
1333
- message: "Street name and number:",
1334
- validate: (v) => v.trim() ? true : "Required"
1335
- },
1336
- {
1337
- type: "input",
1338
- name: "line2",
1339
- message: "Apartment, suite, floor, etc. (optional):"
1340
- },
1341
- {
1342
- type: "input",
1343
- name: "postalCode",
1344
- message: "Postal / ZIP code:",
1345
- validate: (v) => v.trim() ? true : "Required"
1346
- },
1347
- {
1348
- type: "input",
1349
- name: "city",
1350
- message: "City:",
1351
- validate: (v) => v.trim() ? true : "Required"
1352
- },
1353
- {
1354
- type: "input",
1355
- name: "region",
1356
- message: "State / Province / Region (optional):"
1357
- }
1358
- ]);
1359
- let resolvedCountryCode = "";
1360
- let resolvedCountryName = "";
1361
- while (true) {
1362
- const { rawCountry } = await inquirer4.prompt([
1363
- {
1364
- type: "input",
1365
- name: "rawCountry",
1366
- message: "Country (full name, e.g. Belgium, United States):",
1367
- validate: (v) => v.trim() ? true : "Country is required"
1368
- }
1369
- ]);
1370
- const countryResult = normalizeCountry(rawCountry.trim());
1371
- if (countryResult.code && countryResult.name) {
1372
- console.log(chalk4.green(` \u2713 Country: ${countryResult.name} (${countryResult.code})`));
1373
- const { confirmCountry } = await inquirer4.prompt([
1374
- {
1375
- type: "confirm",
1376
- name: "confirmCountry",
1377
- message: `Is "${countryResult.name}" correct?`,
1378
- default: true
1379
- }
1380
- ]);
1381
- if (confirmCountry) {
1382
- resolvedCountryCode = countryResult.code;
1383
- resolvedCountryName = countryResult.name;
1384
- break;
1385
- }
1386
- continue;
1387
- }
1388
- console.log(chalk4.yellow(` \u26A0 Could not recognize "${rawCountry}" as a known country.`));
1389
- console.log(chalk4.dim(" Please try again with a full country name (e.g. Belgium, Germany, United States)."));
1390
- }
1391
- addressCountry = resolvedCountryCode;
1392
- const { instructionsInput } = await inquirer4.prompt([
1393
- {
1394
- type: "input",
1395
- name: "instructionsInput",
1396
- message: "Delivery instructions (optional):"
1397
- }
1398
- ]);
1399
- const { isCompanySetup } = await inquirer4.prompt([
1400
- {
1401
- type: "confirm",
1402
- name: "isCompanySetup",
1403
- message: "Is this a company/business address?",
1404
- default: false
1405
- }
1406
- ]);
1407
- let companyInfo = { companyName: "", vatNumber: "" };
1408
- if (isCompanySetup) {
1409
- companyInfo = await inquirer4.prompt([
1410
- {
1411
- type: "input",
1412
- name: "companyName",
1413
- message: "Company name:",
1414
- validate: (v) => v.trim() ? true : "Required for company addresses"
1415
- },
1416
- {
1417
- type: "input",
1418
- name: "vatNumber",
1419
- message: "VAT number (optional):"
1420
- }
1421
- ]);
1422
- }
1423
- addressCity = addr.city;
1424
- const spinner = ora3("Saving address...").start();
1425
- try {
1426
- const api = getApiClient();
1427
- const agent = getActiveAgent();
1428
- await ensureAgentOnBackend(agent.name);
1429
- if (agent.name !== "default") {
1430
- await ensureAgentOnBackend("default");
1431
- }
1432
- const res = await api.post("/addresses", {
1433
- agent: agent.name,
1434
- label: addr.label,
1435
- firstName: addr.firstName.trim(),
1436
- lastName: addr.lastName.trim(),
1437
- phone: addr.phone || void 0,
1438
- companyName: companyInfo.companyName || void 0,
1439
- vatNumber: companyInfo.vatNumber || void 0,
1440
- line1: addr.line1,
1441
- line2: addr.line2 || void 0,
1442
- city: addr.city,
1443
- region: addr.region || void 0,
1444
- postalCode: addr.postalCode,
1445
- country: resolvedCountryCode,
1446
- instructions: instructionsInput || void 0
1447
- });
1448
- const addressId = res.data.address.id;
1449
- updateAgent(agent.name, { defaultAddressId: addressId });
1450
- if (agent.name !== "default") {
1451
- try {
1452
- await api.post("/addresses", {
1453
- agent: "default",
1454
- label: addr.label,
1455
- firstName: addr.firstName.trim(),
1456
- lastName: addr.lastName.trim(),
1457
- phone: addr.phone || void 0,
1458
- companyName: companyInfo.companyName || void 0,
1459
- vatNumber: companyInfo.vatNumber || void 0,
1460
- line1: addr.line1,
1461
- line2: addr.line2 || void 0,
1462
- city: addr.city,
1463
- region: addr.region || void 0,
1464
- postalCode: addr.postalCode,
1465
- country: resolvedCountryCode,
1466
- instructions: instructionsInput || void 0
1467
- });
1468
- updateAgent("default", { defaultAddressId: addressId });
1469
- } catch {
1470
- }
1471
- }
1472
- spinner.succeed(
1473
- chalk4.green(
1474
- `Address "${addr.label}" saved and set as default${agent.name !== "default" ? ` for both "${agent.name}" and "default" agents` : ""}.`
1475
- )
1476
- );
1477
- } catch (error) {
1478
- spinner.fail(
1479
- chalk4.red(
1480
- `Failed to save address: ${error?.response?.data?.message || error.message}`
1481
- )
1482
- );
1483
- console.log(
1484
- chalk4.dim(
1485
- " You can add an address later with: " + chalk4.white("clishop address add")
1486
- )
1487
- );
1488
- }
1489
- }
1490
- stepHeader(4, 5, "Payment Method");
1491
- console.log(
1492
- chalk4.dim(
1493
- " For security, payment details are entered through a secure web"
1494
- )
1495
- );
1496
- console.log(
1497
- chalk4.dim(" page. The CLI never sees your card number.")
1498
- );
905
+ console.log(" " + chalk4.cyan.underline(setupUrl));
1499
906
  console.log();
1500
- const { addPayment } = await inquirer4.prompt([
1501
- {
1502
- type: "confirm",
1503
- name: "addPayment",
1504
- message: "Set up a payment method now?",
1505
- default: true
1506
- }
1507
- ]);
1508
- if (addPayment) {
1509
- const spinner = ora3("Requesting secure payment setup link...").start();
1510
- try {
1511
- const api = getApiClient();
1512
- const agent = getActiveAgent();
1513
- await ensureAgentOnBackend(agent.name);
1514
- const res = await api.post("/payment-methods/setup", {
1515
- agent: agent.name
1516
- });
1517
- spinner.stop();
1518
- const { setupUrl } = res.data;
1519
- console.log();
1520
- console.log(
1521
- chalk4.bold(
1522
- " Open this link in your browser to add a payment method:"
1523
- )
1524
- );
1525
- console.log();
1526
- console.log(" " + chalk4.cyan.underline(setupUrl));
1527
- console.log();
1528
- console.log(
1529
- chalk4.dim(
1530
- " Once done, verify with: " + chalk4.white("clishop payment list")
1531
- )
1532
- );
1533
- const paymentOpened = await openBrowser(setupUrl);
1534
- if (paymentOpened) {
1535
- console.log(chalk4.dim(" (Browser opened automatically)"));
1536
- }
1537
- console.log();
1538
- await inquirer4.prompt([
1539
- {
1540
- type: "input",
1541
- name: "done",
1542
- message: "Press Enter after completing the payment setup in your browser..."
1543
- }
1544
- ]);
1545
- const pollSpinner = ora3("Checking for your payment method...").start();
1546
- try {
1547
- const agent2 = getActiveAgent();
1548
- await ensureAgentOnBackend(agent2.name);
1549
- const pmRes = await api.get("/payment-methods", {
1550
- params: { agent: agent2.name }
1551
- });
1552
- const methods = pmRes.data.paymentMethods || [];
1553
- if (methods.length > 0) {
1554
- const latest = methods[methods.length - 1];
1555
- updateAgent(agent2.name, { defaultPaymentMethodId: latest.id });
1556
- pollSpinner.succeed(
1557
- chalk4.green(`Payment method "${latest.label}" found and set as default.`)
1558
- );
1559
- } else {
1560
- pollSpinner.warn(
1561
- chalk4.yellow("No payment method found yet. You can add one later with: clishop payment add")
1562
- );
1563
- }
1564
- } catch {
1565
- pollSpinner.warn(
1566
- chalk4.yellow("Could not verify payment method. You can check with: clishop payment list")
1567
- );
1568
- }
1569
- } catch (error) {
1570
- spinner.fail(
1571
- chalk4.red(
1572
- `Could not get setup link: ${error?.response?.data?.message || error.message}`
1573
- )
1574
- );
1575
- console.log(
1576
- chalk4.dim(
1577
- " You can set up payment later with: " + chalk4.white("clishop payment add")
1578
- )
1579
- );
1580
- }
907
+ const opened = await openBrowser(setupUrl);
908
+ if (opened) {
909
+ console.log(chalk4.dim(" (Browser opened automatically)"));
1581
910
  } else {
1582
- console.log(
1583
- chalk4.dim(
1584
- "\n You can set one up later with: " + chalk4.white("clishop payment add")
1585
- )
1586
- );
1587
- }
1588
- stepHeader(5, 5, "Your First Search");
1589
- if (addressCity) {
1590
- console.log(
1591
- chalk4.dim(
1592
- ` Let's find something! Products can be shipped to ${chalk4.white(addressCity)}.`
1593
- )
1594
- );
1595
- } else if (addressCountry) {
1596
- console.log(
1597
- chalk4.dim(
1598
- ` Let's find something! Searching products available in ${chalk4.white(addressCountry)}.`
1599
- )
1600
- );
1601
- } else {
1602
- console.log(chalk4.dim(" Let's find something to order!"));
911
+ console.log(chalk4.yellow(" Could not open browser automatically. Please visit the link above."));
1603
912
  }
1604
913
  console.log();
1605
- const { searchQuery } = await inquirer4.prompt([
1606
- {
1607
- type: "input",
1608
- name: "searchQuery",
1609
- message: "Search for a product (or press Enter to skip):",
1610
- default: "headphones"
1611
- }
1612
- ]);
1613
- if (searchQuery.trim()) {
914
+ const pollSpinner = ora3("Waiting for you to complete payment setup...").start();
915
+ const baseUrl = getApiBaseUrl();
916
+ const maxAttempts = 120;
917
+ let completed = false;
918
+ for (let i = 0; i < maxAttempts; i++) {
919
+ await new Promise((r) => setTimeout(r, 5e3));
1614
920
  try {
1615
- const args = ["search", searchQuery.trim(), "--per-page", "5"];
1616
- if (addressCountry) {
1617
- args.push("--country", addressCountry);
1618
- }
1619
- if (addressCity) {
1620
- args.push("--city", addressCity);
1621
- }
1622
- const nodeBin = process.argv[0];
1623
- const scriptPath = process.argv[1];
1624
- execFileSync(nodeBin, [scriptPath, ...args], {
1625
- stdio: "inherit",
1626
- timeout: 45e3,
1627
- env: process.env
1628
- });
1629
- } catch (error) {
1630
- if (error.status == null && error.signal === "SIGTERM") {
1631
- console.log(chalk4.yellow("\n Search timed out. Try again later with: clishop search <query>"));
921
+ const res = await axios.post(`${baseUrl}/auth/device/poll`, { deviceCode });
922
+ const data = res.data;
923
+ if (data.status === "complete" && data.token && data.refreshToken && data.user) {
924
+ await storeAuthFromSetup({
925
+ token: data.token,
926
+ refreshToken: data.refreshToken,
927
+ user: data.user
928
+ });
929
+ config.set("setupCompleted", true);
930
+ pollSpinner.succeed(chalk4.green("Payment linked and account activated!"));
931
+ completed = true;
932
+ break;
1632
933
  }
934
+ if (data.status === "expired") {
935
+ pollSpinner.fail(chalk4.red("Setup link expired. Run ") + chalk4.white("clishop setup") + chalk4.red(" to try again."));
936
+ process.exitCode = 1;
937
+ return;
938
+ }
939
+ } catch {
1633
940
  }
1634
941
  }
1635
- config.set("setupCompleted", true);
942
+ if (!completed) {
943
+ pollSpinner.fail(chalk4.red("Timed out waiting for setup. Run ") + chalk4.white("clishop setup") + chalk4.red(" to try again."));
944
+ process.exitCode = 1;
945
+ return;
946
+ }
1636
947
  console.log();
1637
948
  divider(chalk4.green);
1638
949
  console.log();
1639
950
  console.log(chalk4.bold.green(" \u2713 You're all set!"));
1640
951
  console.log();
952
+ console.log(chalk4.dim(" Your agent can now add addresses and place orders."));
953
+ console.log(chalk4.dim(" To add a shipping address manually:"));
954
+ console.log(chalk4.white(" clishop address add"));
955
+ console.log();
1641
956
  console.log(chalk4.dim(" Here are some commands to get you started:"));
1642
957
  console.log();
1643
958
  console.log(
@@ -1649,20 +964,51 @@ async function runSetupWizard() {
1649
964
  console.log(
1650
965
  chalk4.white(" clishop order list ") + chalk4.dim("View your orders")
1651
966
  );
1652
- console.log(
1653
- chalk4.white(" clishop agent list ") + chalk4.dim("Manage your agents")
1654
- );
1655
967
  console.log(
1656
968
  chalk4.white(" clishop --help ") + chalk4.dim("See all commands")
1657
969
  );
1658
970
  console.log();
1659
- console.log(
1660
- chalk4.dim(" \u{1F4AC} Join our Discord community: ") + chalk4.cyan.underline("https://discord.gg/vwXMbzD4bx")
1661
- );
1662
- console.log();
1663
971
  divider(chalk4.green);
1664
972
  console.log();
1665
973
  }
974
+ async function runPaymentLinkFlow(config) {
975
+ const spinner = ora3("Requesting secure payment setup link...").start();
976
+ try {
977
+ const api = getApiClient();
978
+ const agent = getActiveAgent();
979
+ await ensureAgentOnBackend(agent.name);
980
+ const res = await api.post("/payment-methods/setup", { agent: agent.name });
981
+ spinner.stop();
982
+ const { setupUrl } = res.data;
983
+ console.log();
984
+ console.log(chalk4.bold(" Open this link to link your payment method:"));
985
+ console.log();
986
+ console.log(" " + chalk4.cyan.underline(setupUrl));
987
+ console.log();
988
+ const opened = await openBrowser(setupUrl);
989
+ if (opened) {
990
+ console.log(chalk4.dim(" (Browser opened automatically)"));
991
+ }
992
+ console.log();
993
+ await inquirer3.prompt([
994
+ { type: "input", name: "done", message: "Press Enter after completing payment setup in your browser..." }
995
+ ]);
996
+ const checkSpinner = ora3("Checking for your payment method...").start();
997
+ const pmRes = await api.get("/payment-methods", { params: { agent: agent.name } });
998
+ const methods = pmRes.data.paymentMethods || [];
999
+ if (methods.length > 0) {
1000
+ const latest = methods[methods.length - 1];
1001
+ updateAgent(agent.name, { defaultPaymentMethodId: latest.id });
1002
+ checkSpinner.succeed(chalk4.green(`Payment method "${latest.label}" linked and set as default.`));
1003
+ config.set("setupCompleted", true);
1004
+ } else {
1005
+ checkSpinner.warn(chalk4.yellow("No payment method found yet. Run ") + chalk4.white("clishop setup") + chalk4.yellow(" to try again."));
1006
+ }
1007
+ } catch (error) {
1008
+ spinner.fail(chalk4.red(`Could not get setup link: ${error?.response?.data?.message || error.message}`));
1009
+ }
1010
+ console.log();
1011
+ }
1666
1012
 
1667
1013
  // src/commands/payment.ts
1668
1014
  function registerPaymentCommands(program2) {
@@ -1679,7 +1025,7 @@ function registerPaymentCommands(program2) {
1679
1025
  spinner.stop();
1680
1026
  const methods = res.data.paymentMethods;
1681
1027
  if (methods.length === 0) {
1682
- console.log(chalk5.yellow("\nNo payment methods found. Add one with: clishop payment add\n"));
1028
+ console.log(chalk5.yellow("\nNo payment methods found. Run: clishop setup\n"));
1683
1029
  return;
1684
1030
  }
1685
1031
  console.log(chalk5.bold(`
@@ -1695,7 +1041,7 @@ Payment methods for agent "${agent.name}":
1695
1041
  handleApiError(error);
1696
1042
  }
1697
1043
  });
1698
- payment.command("add").description("Add a payment method (opens browser for secure entry)").action(async () => {
1044
+ payment.command("add").description("Add an additional payment method (opens browser). First-time setup? Use 'clishop setup' instead.").action(async () => {
1699
1045
  try {
1700
1046
  const agent = getActiveAgent();
1701
1047
  await ensureAgentOnBackend(agent.name);
@@ -1712,8 +1058,8 @@ Payment methods for agent "${agent.name}":
1712
1058
  `));
1713
1059
  console.log(chalk5.dim("The CLI never collects raw card details. Payment is set up via the secure web portal."));
1714
1060
  console.log(chalk5.dim("Press Enter after completing the setup in your browser.\n"));
1715
- const inquirer11 = (await import("inquirer")).default;
1716
- await inquirer11.prompt([
1061
+ const inquirer10 = (await import("inquirer")).default;
1062
+ await inquirer10.prompt([
1717
1063
  { type: "input", name: "done", message: "Press Enter when done..." }
1718
1064
  ]);
1719
1065
  const checkSpinner = ora4("Checking for your payment method...").start();
@@ -1759,7 +1105,7 @@ Payment methods for agent "${agent.name}":
1759
1105
  // src/commands/search.ts
1760
1106
  import chalk6 from "chalk";
1761
1107
  import ora5 from "ora";
1762
- import inquirer5 from "inquirer";
1108
+ import inquirer4 from "inquirer";
1763
1109
  function formatPrice(cents, currency) {
1764
1110
  return new Intl.NumberFormat("en-US", {
1765
1111
  style: "currency",
@@ -2550,7 +1896,7 @@ Results for "${query}" \u2014 ${result.total} found (page ${result.page})
2550
1896
  short: p.name.length > 40 ? p.name.slice(0, 37) + "..." : p.name
2551
1897
  };
2552
1898
  });
2553
- const { selectedIds } = await inquirer5.prompt([
1899
+ const { selectedIds } = await inquirer4.prompt([
2554
1900
  {
2555
1901
  type: "checkbox",
2556
1902
  name: "selectedIds",
@@ -2786,7 +2132,7 @@ Product Information \u2014 ${total} result(s)
2786
2132
  // src/commands/order.ts
2787
2133
  import chalk7 from "chalk";
2788
2134
  import ora6 from "ora";
2789
- import inquirer6 from "inquirer";
2135
+ import inquirer5 from "inquirer";
2790
2136
  function formatPrice2(cents, currency) {
2791
2137
  return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(cents / 100);
2792
2138
  }
@@ -2833,7 +2179,7 @@ function registerOrderCommands(program2) {
2833
2179
  return;
2834
2180
  }
2835
2181
  if (!paymentId) {
2836
- console.error(chalk7.red("\n\u2717 No payment method set. Add one with: clishop payment add"));
2182
+ console.error(chalk7.red("\n\u2717 No payment method linked. Run: clishop setup"));
2837
2183
  process.exitCode = 1;
2838
2184
  return;
2839
2185
  }
@@ -2894,7 +2240,7 @@ function registerOrderCommands(program2) {
2894
2240
  console.log(` Total: ${chalk7.bold(formatPrice2(totalCents, product.currency))}`);
2895
2241
  console.log(` Agent: ${agent.name}`);
2896
2242
  console.log();
2897
- const { confirm } = await inquirer6.prompt([
2243
+ const { confirm } = await inquirer5.prompt([
2898
2244
  {
2899
2245
  type: "confirm",
2900
2246
  name: "confirm",
@@ -3041,7 +2387,7 @@ function registerOrderCommands(program2) {
3041
2387
  });
3042
2388
  order.command("cancel <id>").description("Cancel an order").action(async (id) => {
3043
2389
  try {
3044
- const { confirm } = await inquirer6.prompt([
2390
+ const { confirm } = await inquirer5.prompt([
3045
2391
  {
3046
2392
  type: "confirm",
3047
2393
  name: "confirm",
@@ -3063,7 +2409,7 @@ function registerOrderCommands(program2) {
3063
2409
  // src/commands/review.ts
3064
2410
  import chalk8 from "chalk";
3065
2411
  import ora7 from "ora";
3066
- import inquirer7 from "inquirer";
2412
+ import inquirer6 from "inquirer";
3067
2413
  function renderStars2(rating) {
3068
2414
  const filled = Math.round(rating);
3069
2415
  const empty = 10 - filled;
@@ -3116,7 +2462,7 @@ function registerReviewCommands(program2) {
3116
2462
  let storeReview = void 0;
3117
2463
  for (const item of unreviewedItems) {
3118
2464
  console.log(chalk8.bold(` Product: ${item.productName}`));
3119
- const { wantReview } = await inquirer7.prompt([
2465
+ const { wantReview } = await inquirer6.prompt([
3120
2466
  {
3121
2467
  type: "confirm",
3122
2468
  name: "wantReview",
@@ -3125,7 +2471,7 @@ function registerReviewCommands(program2) {
3125
2471
  }
3126
2472
  ]);
3127
2473
  if (!wantReview) continue;
3128
- const answers = await inquirer7.prompt([
2474
+ const answers = await inquirer6.prompt([
3129
2475
  {
3130
2476
  type: "select",
3131
2477
  name: "rating",
@@ -3156,7 +2502,7 @@ function registerReviewCommands(program2) {
3156
2502
  }
3157
2503
  if (!storeAlreadyReviewed) {
3158
2504
  console.log(chalk8.bold(` Store: ${reviewable.store.name}`));
3159
- const { wantStoreReview } = await inquirer7.prompt([
2505
+ const { wantStoreReview } = await inquirer6.prompt([
3160
2506
  {
3161
2507
  type: "confirm",
3162
2508
  name: "wantStoreReview",
@@ -3165,7 +2511,7 @@ function registerReviewCommands(program2) {
3165
2511
  }
3166
2512
  ]);
3167
2513
  if (wantStoreReview) {
3168
- const storeAnswers = await inquirer7.prompt([
2514
+ const storeAnswers = await inquirer6.prompt([
3169
2515
  {
3170
2516
  type: "select",
3171
2517
  name: "rating",
@@ -3225,7 +2571,7 @@ function registerReviewCommands(program2) {
3225
2571
  });
3226
2572
  review.command("add <productId>").description("Write a review for a product").option("--order <orderId>", "Associate with an order").action(async (productId, opts) => {
3227
2573
  try {
3228
- const answers = await inquirer7.prompt([
2574
+ const answers = await inquirer6.prompt([
3229
2575
  {
3230
2576
  type: "select",
3231
2577
  name: "rating",
@@ -3258,7 +2604,7 @@ function registerReviewCommands(program2) {
3258
2604
  });
3259
2605
  review.command("store <storeId>").description("Write a review for a store").option("--order <orderId>", "Associate with an order").action(async (storeId, opts) => {
3260
2606
  try {
3261
- const answers = await inquirer7.prompt([
2607
+ const answers = await inquirer6.prompt([
3262
2608
  {
3263
2609
  type: "select",
3264
2610
  name: "rating",
@@ -3360,7 +2706,7 @@ function registerReviewCommands(program2) {
3360
2706
  });
3361
2707
  review.command("delete <reviewId>").alias("rm").description("Delete one of your reviews").option("--store", "Delete a store review").action(async (reviewId, opts) => {
3362
2708
  try {
3363
- const { confirm } = await inquirer7.prompt([
2709
+ const { confirm } = await inquirer6.prompt([
3364
2710
  {
3365
2711
  type: "confirm",
3366
2712
  name: "confirm",
@@ -3599,7 +2945,7 @@ function registerStatusCommand(program2) {
3599
2945
  program2.command("status").description("Show full account overview \u2014 user, agents, addresses, payment methods").option("--json", "Output raw JSON").action(async (opts) => {
3600
2946
  try {
3601
2947
  if (!await isLoggedIn()) {
3602
- console.log(chalk11.yellow("\nNot logged in. Run: clishop login\n"));
2948
+ console.log(chalk11.yellow("\nNot set up yet. Run: clishop setup\n"));
3603
2949
  return;
3604
2950
  }
3605
2951
  const spinner = ora9("Fetching account overview...").start();
@@ -3671,7 +3017,7 @@ function registerStatusCommand(program2) {
3671
3017
  console.log();
3672
3018
  console.log(chalk11.bold(` \u{1F4B3} Payment Methods (${agent.paymentMethods.length})`));
3673
3019
  if (agent.paymentMethods.length === 0) {
3674
- console.log(chalk11.dim(" None \u2014 run: clishop payment add"));
3020
+ console.log(chalk11.dim(" None \u2014 run: clishop setup"));
3675
3021
  } else {
3676
3022
  for (const pm of agent.paymentMethods) {
3677
3023
  const isDefault = pm.id === agent.defaultPaymentMethodId;
@@ -3695,7 +3041,7 @@ function registerStatusCommand(program2) {
3695
3041
  // src/commands/advertise.ts
3696
3042
  import chalk12 from "chalk";
3697
3043
  import ora10 from "ora";
3698
- import inquirer8 from "inquirer";
3044
+ import inquirer7 from "inquirer";
3699
3045
  function formatPrice4(cents, currency) {
3700
3046
  return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(cents / 100);
3701
3047
  }
@@ -3719,7 +3065,7 @@ function registerAdvertiseCommands(program2) {
3719
3065
  const agent = getActiveAgent();
3720
3066
  console.log(chalk12.bold("\n \u{1F4E2} Advertise a Request\n"));
3721
3067
  console.log(chalk12.dim(" Can't find what you need? Describe it and vendors will bid to fulfill it.\n"));
3722
- const answers = await inquirer8.prompt([
3068
+ const answers = await inquirer7.prompt([
3723
3069
  {
3724
3070
  type: "input",
3725
3071
  name: "title",
@@ -3766,7 +3112,7 @@ function registerAdvertiseCommands(program2) {
3766
3112
  ]);
3767
3113
  let recurringNote;
3768
3114
  if (answers.recurring) {
3769
- const recAnswer = await inquirer8.prompt([
3115
+ const recAnswer = await inquirer7.prompt([
3770
3116
  {
3771
3117
  type: "input",
3772
3118
  name: "recurringNote",
@@ -3775,7 +3121,7 @@ function registerAdvertiseCommands(program2) {
3775
3121
  ]);
3776
3122
  recurringNote = recAnswer.recurringNote || void 0;
3777
3123
  }
3778
- const priceAnswers = await inquirer8.prompt([
3124
+ const priceAnswers = await inquirer7.prompt([
3779
3125
  {
3780
3126
  type: "input",
3781
3127
  name: "bidPrice",
@@ -3784,7 +3130,7 @@ function registerAdvertiseCommands(program2) {
3784
3130
  ]);
3785
3131
  let currency = "USD";
3786
3132
  if (priceAnswers.bidPrice && parseFloat(priceAnswers.bidPrice) > 0) {
3787
- const currencyAnswer = await inquirer8.prompt([
3133
+ const currencyAnswer = await inquirer7.prompt([
3788
3134
  {
3789
3135
  type: "list",
3790
3136
  name: "currency",
@@ -3805,7 +3151,7 @@ function registerAdvertiseCommands(program2) {
3805
3151
  }
3806
3152
  ]);
3807
3153
  if (currencyAnswer.currency === "OTHER") {
3808
- const customCurrency = await inquirer8.prompt([
3154
+ const customCurrency = await inquirer7.prompt([
3809
3155
  {
3810
3156
  type: "input",
3811
3157
  name: "code",
@@ -3818,14 +3164,14 @@ function registerAdvertiseCommands(program2) {
3818
3164
  currency = currencyAnswer.currency;
3819
3165
  }
3820
3166
  }
3821
- const speedAnswer = await inquirer8.prompt([
3167
+ const speedAnswer = await inquirer7.prompt([
3822
3168
  {
3823
3169
  type: "input",
3824
3170
  name: "speedDays",
3825
3171
  message: "Desired delivery speed in days (optional):"
3826
3172
  }
3827
3173
  ]);
3828
- const returnAnswers = await inquirer8.prompt([
3174
+ const returnAnswers = await inquirer7.prompt([
3829
3175
  {
3830
3176
  type: "confirm",
3831
3177
  name: "freeReturns",
@@ -3857,7 +3203,7 @@ function registerAdvertiseCommands(program2) {
3857
3203
  addrChoices.push({ name: chalk12.dim(skipOption), value: skipOption });
3858
3204
  const defaultAddr = addresses.find((a) => a.id === agent.defaultAddressId);
3859
3205
  const defaultDisplay = defaultAddr ? `${defaultAddr.label} \u2014 ${defaultAddr.line1}` : "";
3860
- const { selectedAddress } = await inquirer8.prompt([
3206
+ const { selectedAddress } = await inquirer7.prompt([
3861
3207
  {
3862
3208
  type: "list",
3863
3209
  name: "selectedAddress",
@@ -3891,7 +3237,7 @@ function registerAdvertiseCommands(program2) {
3891
3237
  // Default: all user's payment methods selected
3892
3238
  }))
3893
3239
  ];
3894
- const { selectedPayments } = await inquirer8.prompt([
3240
+ const { selectedPayments } = await inquirer7.prompt([
3895
3241
  {
3896
3242
  type: "checkbox",
3897
3243
  name: "selectedPayments",
@@ -3905,7 +3251,7 @@ function registerAdvertiseCommands(program2) {
3905
3251
  paymentMethods = JSON.stringify(selectedPayments);
3906
3252
  }
3907
3253
  } else {
3908
- console.log(chalk12.dim(" No payment methods found. You can add one later with: clishop payment add"));
3254
+ console.log(chalk12.dim(" No payment methods found. Run: clishop setup"));
3909
3255
  }
3910
3256
  } catch {
3911
3257
  paySpinner.stop();
@@ -4158,7 +3504,7 @@ function registerAdvertiseCommands(program2) {
4158
3504
  if (bid.shippingDays != null) console.log(` Delivery: ${bid.shippingDays}-day`);
4159
3505
  if (bid.note) console.log(` Note: ${bid.note}`);
4160
3506
  console.log();
4161
- const { confirm } = await inquirer8.prompt([
3507
+ const { confirm } = await inquirer7.prompt([
4162
3508
  {
4163
3509
  type: "confirm",
4164
3510
  name: "confirm",
@@ -4179,7 +3525,7 @@ function registerAdvertiseCommands(program2) {
4179
3525
  });
4180
3526
  advertise.command("reject <advertiseId> <bidId>").description("Reject a vendor's bid").action(async (advertiseId, bidId) => {
4181
3527
  try {
4182
- const { confirm } = await inquirer8.prompt([
3528
+ const { confirm } = await inquirer7.prompt([
4183
3529
  {
4184
3530
  type: "confirm",
4185
3531
  name: "confirm",
@@ -4198,7 +3544,7 @@ function registerAdvertiseCommands(program2) {
4198
3544
  });
4199
3545
  advertise.command("cancel <id>").description("Cancel an advertised request").action(async (id) => {
4200
3546
  try {
4201
- const { confirm } = await inquirer8.prompt([
3547
+ const { confirm } = await inquirer7.prompt([
4202
3548
  {
4203
3549
  type: "confirm",
4204
3550
  name: "confirm",
@@ -4220,7 +3566,7 @@ function registerAdvertiseCommands(program2) {
4220
3566
  // src/commands/support.ts
4221
3567
  import chalk13 from "chalk";
4222
3568
  import ora11 from "ora";
4223
- import inquirer9 from "inquirer";
3569
+ import inquirer8 from "inquirer";
4224
3570
  var CATEGORY_CHOICES = [
4225
3571
  { name: "General question", value: "general" },
4226
3572
  { name: "Damaged item", value: "damaged" },
@@ -4254,7 +3600,7 @@ function registerSupportCommands(program2) {
4254
3600
  const support = program2.command("support").description("Manage support tickets for orders");
4255
3601
  support.command("create <orderId>").alias("new").description("Create a support ticket for an order").action(async (orderId) => {
4256
3602
  try {
4257
- const answers = await inquirer9.prompt([
3603
+ const answers = await inquirer8.prompt([
4258
3604
  {
4259
3605
  type: "select",
4260
3606
  name: "category",
@@ -4385,7 +3731,7 @@ function registerSupportCommands(program2) {
4385
3731
  });
4386
3732
  support.command("reply <ticketId>").description("Reply to a support ticket").action(async (ticketId) => {
4387
3733
  try {
4388
- const { message } = await inquirer9.prompt([
3734
+ const { message } = await inquirer8.prompt([
4389
3735
  {
4390
3736
  type: "editor",
4391
3737
  name: "message",
@@ -4410,7 +3756,7 @@ function registerSupportCommands(program2) {
4410
3756
  });
4411
3757
  support.command("close <ticketId>").description("Close a resolved ticket").action(async (ticketId) => {
4412
3758
  try {
4413
- const { confirm } = await inquirer9.prompt([
3759
+ const { confirm } = await inquirer8.prompt([
4414
3760
  {
4415
3761
  type: "confirm",
4416
3762
  name: "confirm",
@@ -4432,7 +3778,7 @@ function registerSupportCommands(program2) {
4432
3778
  // src/commands/feedback.ts
4433
3779
  import chalk14 from "chalk";
4434
3780
  import ora12 from "ora";
4435
- import inquirer10 from "inquirer";
3781
+ import inquirer9 from "inquirer";
4436
3782
  var STATUS_COLORS4 = {
4437
3783
  open: chalk14.green,
4438
3784
  acknowledged: chalk14.cyan,
@@ -4465,7 +3811,7 @@ function registerFeedbackCommands(program2) {
4465
3811
  if (!title || !description || !stepsToReproduce || !actualBehavior || !expectedBehavior) {
4466
3812
  console.log(chalk14.bold("\n\u{1F41B} Report a Bug\n"));
4467
3813
  console.log(chalk14.dim("Help us fix issues by describing what went wrong.\n"));
4468
- const answers = await inquirer10.prompt([
3814
+ const answers = await inquirer9.prompt([
4469
3815
  ...!title ? [{
4470
3816
  type: "input",
4471
3817
  name: "title",
@@ -4537,7 +3883,7 @@ function registerFeedbackCommands(program2) {
4537
3883
  if (!title || !description) {
4538
3884
  console.log(chalk14.bold("\n\u{1F4A1} Suggest an Improvement\n"));
4539
3885
  console.log(chalk14.dim("Tell us how we can make CLISHOP better.\n"));
4540
- const answers = await inquirer10.prompt([
3886
+ const answers = await inquirer9.prompt([
4541
3887
  ...!title ? [{
4542
3888
  type: "input",
4543
3889
  name: "title",
@@ -4662,7 +4008,7 @@ import chalk15 from "chalk";
4662
4008
  import { join } from "path";
4663
4009
  import { homedir } from "os";
4664
4010
  import { mkdirSync } from "fs";
4665
- import axios from "axios";
4011
+ import axios2 from "axios";
4666
4012
  function registerDoctorCommand(program2) {
4667
4013
  program2.command("doctor").description("Check system compatibility and auth status").action(async () => {
4668
4014
  const checks = [];
@@ -4693,11 +4039,11 @@ function registerDoctorCommand(program2) {
4693
4039
  checks.push({
4694
4040
  name: "Authenticated",
4695
4041
  ok: !!token,
4696
- detail: token ? "Token present" : "Not logged in \u2014 run: clishop setup"
4042
+ detail: token ? "Token present" : "Not set up \u2014 run: clishop setup"
4697
4043
  });
4698
4044
  const apiUrl = getApiBaseUrl();
4699
4045
  try {
4700
- await axios.get(`${apiUrl}/health`, { timeout: 5e3 });
4046
+ await axios2.get(`${apiUrl}/health`, { timeout: 5e3 });
4701
4047
  checks.push({ name: "API reachable", ok: true, detail: apiUrl });
4702
4048
  } catch {
4703
4049
  checks.push({
@@ -4718,7 +4064,11 @@ function registerDoctorCommand(program2) {
4718
4064
  // src/index.ts
4719
4065
  var program = new Command();
4720
4066
  program.name("clishop").version("1.3.1").description(
4721
- chalk16.bold("CLISHOP") + ' \u2014 Order anything from your terminal.\n\n Use agents to set safety limits, addresses, and payment methods.\n The "default" agent is used when no agent is specified.'
4067
+ chalk16.bold("CLISHOP") + ` \u2014 Order anything from your terminal.
4068
+
4069
+ Run 'clishop setup' to get started with a single payment link.
4070
+ Use agents to set safety limits, addresses, and payment methods.
4071
+ The "default" agent is used when no agent is specified.`
4722
4072
  ).option("--agent <name>", "Use a specific agent for this command").hook("preAction", (thisCommand) => {
4723
4073
  const agentOpt = thisCommand.opts().agent;
4724
4074
  if (agentOpt) {