clishop 0.3.1 → 1.0.1

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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getApiBaseUrl
3
- } from "./chunk-ZF3JIQRK.js";
3
+ } from "./chunk-X3H7SYR4.js";
4
4
 
5
5
  // src/auth.ts
6
6
  import keytar from "keytar";
@@ -155,6 +155,22 @@ function getApiClient() {
155
155
  );
156
156
  return client;
157
157
  }
158
+ async function ensureAgentOnBackend(agentName, maxOrderAmountInCents, requireConfirmation = true) {
159
+ const api = getApiClient();
160
+ try {
161
+ const res = await api.get("/agents");
162
+ const agents = res.data.agents || [];
163
+ const exists = agents.some((a) => a.name === agentName);
164
+ if (!exists) {
165
+ await api.post("/agents", {
166
+ name: agentName,
167
+ maxOrderAmountInCents: maxOrderAmountInCents || void 0,
168
+ requireConfirmation
169
+ });
170
+ }
171
+ } catch {
172
+ }
173
+ }
158
174
  function handleApiError(error) {
159
175
  if (axios2.isAxiosError(error)) {
160
176
  const data = error.response?.data;
@@ -188,5 +204,6 @@ export {
188
204
  register,
189
205
  logout,
190
206
  getApiClient,
207
+ ensureAgentOnBackend,
191
208
  handleApiError
192
209
  };
@@ -92,6 +92,18 @@ function deleteAgent(name) {
92
92
  function listAgents() {
93
93
  return Object.values(config.store.agents);
94
94
  }
95
+ function resetAgents() {
96
+ config.set("agents", {
97
+ default: {
98
+ name: "default",
99
+ requireConfirmation: true,
100
+ maxOrderAmount: 500,
101
+ allowedCategories: [],
102
+ blockedCategories: []
103
+ }
104
+ });
105
+ config.set("activeAgent", "default");
106
+ }
95
107
 
96
108
  export {
97
109
  __export,
@@ -104,5 +116,6 @@ export {
104
116
  createAgent,
105
117
  updateAgent,
106
118
  deleteAgent,
107
- listAgents
119
+ listAgents,
120
+ resetAgents
108
121
  };
@@ -7,9 +7,10 @@ import {
7
7
  getApiBaseUrl,
8
8
  getConfig,
9
9
  listAgents,
10
+ resetAgents,
10
11
  setActiveAgent,
11
12
  updateAgent
12
- } from "./chunk-ZF3JIQRK.js";
13
+ } from "./chunk-X3H7SYR4.js";
13
14
  export {
14
15
  DEFAULT_API_BASE_URL,
15
16
  createAgent,
@@ -19,6 +20,7 @@ export {
19
20
  getApiBaseUrl,
20
21
  getConfig,
21
22
  listAgents,
23
+ resetAgents,
22
24
  setActiveAgent,
23
25
  updateAgent
24
26
  };
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ ensureAgentOnBackend,
3
4
  getApiClient,
4
5
  getUserInfo,
5
6
  handleApiError,
@@ -7,7 +8,7 @@ import {
7
8
  login,
8
9
  logout,
9
10
  register
10
- } from "./chunk-RHBOI27D.js";
11
+ } from "./chunk-CVK6G342.js";
11
12
  import {
12
13
  createAgent,
13
14
  deleteAgent,
@@ -17,7 +18,7 @@ import {
17
18
  listAgents,
18
19
  setActiveAgent,
19
20
  updateAgent
20
- } from "./chunk-ZF3JIQRK.js";
21
+ } from "./chunk-X3H7SYR4.js";
21
22
 
22
23
  // src/index.ts
23
24
  import { Command } from "commander";
@@ -43,12 +44,12 @@ function registerAuthCommands(program2) {
43
44
  return;
44
45
  }
45
46
  if (await isLoggedIn()) {
46
- const user2 = await getUserInfo();
47
+ const user = await getUserInfo();
47
48
  const { confirm } = await inquirer.prompt([
48
49
  {
49
50
  type: "confirm",
50
51
  name: "confirm",
51
- message: `You are already logged in as ${chalk.cyan(user2?.email || "unknown")}. Log in as a different user?`,
52
+ message: `You are already logged in as ${chalk.cyan(user?.email || "unknown")}. Log in as a different user?`,
52
53
  default: false
53
54
  }
54
55
  ]);
@@ -77,8 +78,14 @@ function registerAuthCommands(program2) {
77
78
  password = password || answers.password;
78
79
  }
79
80
  const spinner = ora("Logging in...").start();
80
- const user = await login(email, password);
81
- spinner.succeed(chalk.green(`Logged in as ${chalk.bold(user.name)} (${user.email})`));
81
+ try {
82
+ const user = await login(email, password);
83
+ spinner.succeed(chalk.green(`Logged in as ${chalk.bold(user.name)} (${user.email})`));
84
+ } catch (loginErr) {
85
+ const msg = loginErr?.response?.data?.message || loginErr.message;
86
+ spinner.fail(chalk.red(`Login failed: ${msg}`));
87
+ process.exitCode = 1;
88
+ }
82
89
  } catch (error) {
83
90
  const msg = error?.response?.data?.message || error.message;
84
91
  console.error(chalk.red(`
@@ -110,8 +117,14 @@ function registerAuthCommands(program2) {
110
117
  return;
111
118
  }
112
119
  const spinner = ora("Creating account...").start();
113
- const user = await register(answers.email, answers.password, answers.name);
114
- spinner.succeed(chalk.green(`Account created! Welcome, ${chalk.bold(user.name)}.`));
120
+ try {
121
+ const user = await register(answers.email, answers.password, answers.name);
122
+ spinner.succeed(chalk.green(`Account created! Welcome, ${chalk.bold(user.name)}.`));
123
+ } catch (regErr) {
124
+ const msg = regErr?.response?.data?.message || regErr.message;
125
+ spinner.fail(chalk.red(`Registration failed: ${msg}`));
126
+ process.exitCode = 1;
127
+ }
115
128
  } catch (error) {
116
129
  const msg = error?.response?.data?.message || error.message;
117
130
  console.error(chalk.red(`
@@ -122,7 +135,19 @@ function registerAuthCommands(program2) {
122
135
  program2.command("logout").description("Log out of your CLISHOP account").action(async () => {
123
136
  const spinner = ora("Logging out...").start();
124
137
  await logout();
125
- spinner.succeed(chalk.green("Logged out."));
138
+ const config = getConfig();
139
+ config.set("agents", {
140
+ default: {
141
+ name: "default",
142
+ requireConfirmation: true,
143
+ maxOrderAmount: 500,
144
+ allowedCategories: [],
145
+ blockedCategories: []
146
+ }
147
+ });
148
+ config.set("activeAgent", "default");
149
+ config.set("setupCompleted", false);
150
+ spinner.succeed(chalk.green("Logged out. Local config reset."));
126
151
  });
127
152
  program2.command("whoami").description("Show the currently logged-in user").action(async () => {
128
153
  if (!await isLoggedIn()) {
@@ -372,11 +397,283 @@ function registerAgentCommands(program2) {
372
397
  import chalk3 from "chalk";
373
398
  import ora2 from "ora";
374
399
  import inquirer3 from "inquirer";
400
+
401
+ // src/countries.ts
402
+ var COUNTRY_ALIASES = {
403
+ // ISO codes
404
+ "us": "US",
405
+ "gb": "GB",
406
+ "uk": "GB",
407
+ "fr": "FR",
408
+ "de": "DE",
409
+ "it": "IT",
410
+ "ca": "CA",
411
+ "au": "AU",
412
+ "be": "BE",
413
+ "nl": "NL",
414
+ "ie": "IE",
415
+ "pl": "PL",
416
+ "se": "SE",
417
+ "dk": "DK",
418
+ "no": "NO",
419
+ "fi": "FI",
420
+ "at": "AT",
421
+ "ch": "CH",
422
+ "es": "ES",
423
+ "pt": "PT",
424
+ "cz": "CZ",
425
+ "sk": "SK",
426
+ "hu": "HU",
427
+ "ro": "RO",
428
+ "bg": "BG",
429
+ "hr": "HR",
430
+ "si": "SI",
431
+ "gr": "GR",
432
+ "ee": "EE",
433
+ "lv": "LV",
434
+ "lt": "LT",
435
+ "lu": "LU",
436
+ "li": "LI",
437
+ "mc": "MC",
438
+ "sm": "SM",
439
+ "mx": "MX",
440
+ "pr": "PR",
441
+ "nz": "NZ",
442
+ "ae": "AE",
443
+ "br": "BR",
444
+ "jp": "JP",
445
+ "cn": "CN",
446
+ "kr": "KR",
447
+ "in": "IN",
448
+ "sg": "SG",
449
+ "za": "ZA",
450
+ "il": "IL",
451
+ "tr": "TR",
452
+ "ru": "RU",
453
+ "ua": "UA",
454
+ "ph": "PH",
455
+ "co": "CO",
456
+ "ar": "AR",
457
+ "cl": "CL",
458
+ "th": "TH",
459
+ "my": "MY",
460
+ "id": "ID",
461
+ "vn": "VN",
462
+ "tw": "TW",
463
+ // English names
464
+ "united states": "US",
465
+ "united states of america": "US",
466
+ "usa": "US",
467
+ "america": "US",
468
+ "united kingdom": "GB",
469
+ "great britain": "GB",
470
+ "england": "GB",
471
+ "scotland": "GB",
472
+ "wales": "GB",
473
+ "britain": "GB",
474
+ "france": "FR",
475
+ "germany": "DE",
476
+ "italy": "IT",
477
+ "spain": "ES",
478
+ "portugal": "PT",
479
+ "canada": "CA",
480
+ "australia": "AU",
481
+ "new zealand": "NZ",
482
+ "belgium": "BE",
483
+ "netherlands": "NL",
484
+ "holland": "NL",
485
+ "the netherlands": "NL",
486
+ "ireland": "IE",
487
+ "poland": "PL",
488
+ "sweden": "SE",
489
+ "denmark": "DK",
490
+ "norway": "NO",
491
+ "finland": "FI",
492
+ "austria": "AT",
493
+ "switzerland": "CH",
494
+ "czech republic": "CZ",
495
+ "czechia": "CZ",
496
+ "slovakia": "SK",
497
+ "hungary": "HU",
498
+ "romania": "RO",
499
+ "bulgaria": "BG",
500
+ "croatia": "HR",
501
+ "slovenia": "SI",
502
+ "greece": "GR",
503
+ "estonia": "EE",
504
+ "latvia": "LV",
505
+ "lithuania": "LT",
506
+ "luxembourg": "LU",
507
+ "liechtenstein": "LI",
508
+ "monaco": "MC",
509
+ "san marino": "SM",
510
+ "mexico": "MX",
511
+ "puerto rico": "PR",
512
+ "united arab emirates": "AE",
513
+ "emirates": "AE",
514
+ "uae": "AE",
515
+ "brazil": "BR",
516
+ "japan": "JP",
517
+ "china": "CN",
518
+ "south korea": "KR",
519
+ "korea": "KR",
520
+ "india": "IN",
521
+ "singapore": "SG",
522
+ "south africa": "ZA",
523
+ "israel": "IL",
524
+ "turkey": "TR",
525
+ "russia": "RU",
526
+ "russian federation": "RU",
527
+ "ukraine": "UA",
528
+ "philippines": "PH",
529
+ "colombia": "CO",
530
+ "argentina": "AR",
531
+ "chile": "CL",
532
+ "thailand": "TH",
533
+ "malaysia": "MY",
534
+ "indonesia": "ID",
535
+ "vietnam": "VN",
536
+ "taiwan": "TW",
537
+ // Native names
538
+ "deutschland": "DE",
539
+ "italia": "IT",
540
+ "espana": "ES",
541
+ "espa\xF1a": "ES",
542
+ "belgique": "BE",
543
+ "belgie": "BE",
544
+ "belgi\xEB": "BE",
545
+ "belgien": "BE",
546
+ "nederland": "NL",
547
+ "osterreich": "AT",
548
+ "\xF6sterreich": "AT",
549
+ "schweiz": "CH",
550
+ "suisse": "CH",
551
+ "svizzera": "CH",
552
+ "polska": "PL",
553
+ "sverige": "SE",
554
+ "danmark": "DK",
555
+ "norge": "NO",
556
+ "suomi": "FI",
557
+ "hrvatska": "HR",
558
+ "slovensko": "SK",
559
+ "slovenija": "SI",
560
+ "eesti": "EE",
561
+ "latvija": "LV",
562
+ "lietuva": "LT",
563
+ "luxemburg": "LU",
564
+ "magyarorszag": "HU",
565
+ "magyarorsz\xE1g": "HU",
566
+ "turkiye": "TR",
567
+ "t\xFCrkiye": "TR",
568
+ "brasil": "BR",
569
+ "m\xE9xico": "MX",
570
+ // Common typos
571
+ "belguim": "BE",
572
+ "belgum": "BE",
573
+ "nethrelands": "NL",
574
+ "sweeden": "SE",
575
+ "philipines": "PH",
576
+ "phillipines": "PH",
577
+ "columbia": "CO"
578
+ };
579
+ var CODE_TO_NAME = {
580
+ US: "United States",
581
+ GB: "United Kingdom",
582
+ FR: "France",
583
+ DE: "Germany",
584
+ IT: "Italy",
585
+ CA: "Canada",
586
+ AU: "Australia",
587
+ BE: "Belgium",
588
+ NL: "Netherlands",
589
+ IE: "Ireland",
590
+ PL: "Poland",
591
+ SE: "Sweden",
592
+ DK: "Denmark",
593
+ NO: "Norway",
594
+ FI: "Finland",
595
+ AT: "Austria",
596
+ CH: "Switzerland",
597
+ ES: "Spain",
598
+ PT: "Portugal",
599
+ CZ: "Czech Republic",
600
+ SK: "Slovakia",
601
+ HU: "Hungary",
602
+ RO: "Romania",
603
+ BG: "Bulgaria",
604
+ HR: "Croatia",
605
+ SI: "Slovenia",
606
+ GR: "Greece",
607
+ EE: "Estonia",
608
+ LV: "Latvia",
609
+ LT: "Lithuania",
610
+ LU: "Luxembourg",
611
+ LI: "Liechtenstein",
612
+ MC: "Monaco",
613
+ SM: "San Marino",
614
+ MX: "Mexico",
615
+ PR: "Puerto Rico",
616
+ NZ: "New Zealand",
617
+ AE: "United Arab Emirates",
618
+ BR: "Brazil",
619
+ JP: "Japan",
620
+ CN: "China",
621
+ KR: "South Korea",
622
+ IN: "India",
623
+ SG: "Singapore",
624
+ ZA: "South Africa",
625
+ IL: "Israel",
626
+ TR: "Turkey",
627
+ RU: "Russia",
628
+ UA: "Ukraine",
629
+ PH: "Philippines",
630
+ CO: "Colombia",
631
+ AR: "Argentina",
632
+ CL: "Chile",
633
+ TH: "Thailand",
634
+ MY: "Malaysia",
635
+ ID: "Indonesia",
636
+ VN: "Vietnam",
637
+ TW: "Taiwan"
638
+ };
639
+ function stripDiacritics(str) {
640
+ return str.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
641
+ }
642
+ function normalizeCountry(input) {
643
+ if (!input?.trim()) return { code: null, name: null, exact: false };
644
+ const lower = input.trim().toLowerCase();
645
+ const stripped = stripDiacritics(lower);
646
+ const direct = COUNTRY_ALIASES[lower] || COUNTRY_ALIASES[stripped];
647
+ if (direct) {
648
+ return { code: direct, name: CODE_TO_NAME[direct] || direct, exact: true };
649
+ }
650
+ if (/^[a-zA-Z]{2}$/.test(input.trim())) {
651
+ const upper = input.trim().toUpperCase();
652
+ const name = CODE_TO_NAME[upper];
653
+ if (name) return { code: upper, name, exact: true };
654
+ return { code: upper, name: null, exact: false };
655
+ }
656
+ const keys = Object.keys(COUNTRY_ALIASES);
657
+ const prefixMatch = keys.find((k) => k.length > 2 && (k.startsWith(lower) || k.startsWith(stripped)));
658
+ if (prefixMatch) {
659
+ const code = COUNTRY_ALIASES[prefixMatch];
660
+ return { code, name: CODE_TO_NAME[code] || code, exact: false };
661
+ }
662
+ const subMatch = keys.find((k) => k.length > 2 && (k.includes(lower) || k.includes(stripped)));
663
+ if (subMatch) {
664
+ const code = COUNTRY_ALIASES[subMatch];
665
+ return { code, name: CODE_TO_NAME[code] || code, exact: false };
666
+ }
667
+ return { code: null, name: null, exact: false };
668
+ }
669
+
670
+ // src/commands/address.ts
375
671
  function registerAddressCommands(program2) {
376
672
  const address = program2.command("address").description("Manage shipping addresses (scoped to the active agent)");
377
673
  address.command("list").alias("ls").description("List all addresses for the active agent").action(async () => {
378
674
  try {
379
675
  const agent = getActiveAgent();
676
+ await ensureAgentOnBackend(agent.name);
380
677
  const spinner = ora2("Fetching addresses...").start();
381
678
  const api = getApiClient();
382
679
  const res = await api.get("/addresses", {
@@ -403,7 +700,6 @@ Addresses for agent "${agent.name}":
403
700
  console.log(` ${addr.country}`);
404
701
  if (addr.recipientPhone) console.log(` ${chalk3.dim("Phone:")} ${addr.recipientPhone}`);
405
702
  if (addr.vatNumber) console.log(` ${chalk3.dim("VAT:")} ${addr.vatNumber}`);
406
- if (addr.taxId) console.log(` ${chalk3.dim("Tax ID:")} ${addr.taxId}`);
407
703
  if (addr.instructions) console.log(` ${chalk3.dim("Instructions:")} ${addr.instructions}`);
408
704
  console.log();
409
705
  }
@@ -416,7 +712,12 @@ Addresses for agent "${agent.name}":
416
712
  const agent = getActiveAgent();
417
713
  const answers = await inquirer3.prompt([
418
714
  { type: "input", name: "label", message: "Label (e.g. Home, Office):" },
419
- { type: "input", name: "recipientName", message: "Recipient name (optional):" },
715
+ {
716
+ type: "input",
717
+ name: "recipientName",
718
+ message: "Recipient name:",
719
+ validate: (v) => v.trim() ? true : "Recipient name is required"
720
+ },
420
721
  { type: "input", name: "recipientPhone", message: "Recipient phone (optional):" },
421
722
  {
422
723
  type: "input",
@@ -452,7 +753,28 @@ Addresses for agent "${agent.name}":
452
753
  default: false
453
754
  }
454
755
  ]);
455
- let companyAnswers = { companyName: "", vatNumber: "", taxId: "" };
756
+ const countryResult = normalizeCountry(answers.country);
757
+ if (countryResult.code) {
758
+ if (countryResult.name && answers.country.toLowerCase() !== countryResult.code.toLowerCase()) {
759
+ console.log(chalk3.green(` \u2713 Country: ${countryResult.name} (${countryResult.code})`));
760
+ }
761
+ answers.country = countryResult.code;
762
+ } else {
763
+ console.log(chalk3.yellow(` \u26A0 Could not recognize "${answers.country}" as a known country.`));
764
+ const { keepCountry } = await inquirer3.prompt([
765
+ {
766
+ type: "confirm",
767
+ name: "keepCountry",
768
+ message: `Use "${answers.country}" anyway?`,
769
+ default: true
770
+ }
771
+ ]);
772
+ if (!keepCountry) {
773
+ console.log(chalk3.dim(" Try again with a country name or code (e.g. US, Belgium, DE)"));
774
+ return;
775
+ }
776
+ }
777
+ let companyAnswers = { companyName: "", vatNumber: "" };
456
778
  if (answers.isCompany) {
457
779
  companyAnswers = await inquirer3.prompt([
458
780
  {
@@ -461,8 +783,7 @@ Addresses for agent "${agent.name}":
461
783
  message: "Company name:",
462
784
  validate: (v) => v.trim() ? true : "Required for company addresses"
463
785
  },
464
- { type: "input", name: "vatNumber", message: "VAT number (optional):" },
465
- { type: "input", name: "taxId", message: "Tax ID / EIN (optional):" }
786
+ { type: "input", name: "vatNumber", message: "VAT number (optional):" }
466
787
  ]);
467
788
  }
468
789
  const { setDefault } = await inquirer3.prompt([
@@ -474,6 +795,7 @@ Addresses for agent "${agent.name}":
474
795
  }
475
796
  ]);
476
797
  const spinner = ora2("Saving address...").start();
798
+ await ensureAgentOnBackend(agent.name);
477
799
  const api = getApiClient();
478
800
  const res = await api.post("/addresses", {
479
801
  agent: agent.name,
@@ -482,7 +804,6 @@ Addresses for agent "${agent.name}":
482
804
  recipientPhone: answers.recipientPhone || void 0,
483
805
  companyName: companyAnswers.companyName || void 0,
484
806
  vatNumber: companyAnswers.vatNumber || void 0,
485
- taxId: companyAnswers.taxId || void 0,
486
807
  line1: answers.line1,
487
808
  line2: answers.line2 || void 0,
488
809
  city: answers.city,
@@ -539,6 +860,7 @@ function registerPaymentCommands(program2) {
539
860
  payment.command("list").alias("ls").description("List payment methods for the active agent").action(async () => {
540
861
  try {
541
862
  const agent = getActiveAgent();
863
+ await ensureAgentOnBackend(agent.name);
542
864
  const spinner = ora3("Fetching payment methods...").start();
543
865
  const api = getApiClient();
544
866
  const res = await api.get("/payment-methods", {
@@ -556,8 +878,7 @@ Payment methods for agent "${agent.name}":
556
878
  for (const pm of methods) {
557
879
  const isDefault = pm.id === agent.defaultPaymentMethodId;
558
880
  const marker = isDefault ? chalk4.green("\u25CF ") : " ";
559
- const last4 = pm.last4 ? ` \u2022\u2022\u2022\u2022 ${pm.last4}` : "";
560
- console.log(`${marker}${chalk4.bold(pm.label)}${last4} ${chalk4.dim(`[${pm.type}]`)} ${chalk4.dim(`(${pm.id})`)}`);
881
+ console.log(`${marker}${chalk4.bold(pm.label)} ${chalk4.dim(`[${pm.type}]`)} ${chalk4.dim(`(${pm.id})`)}`);
561
882
  }
562
883
  console.log();
563
884
  } catch (error) {
@@ -567,6 +888,7 @@ Payment methods for agent "${agent.name}":
567
888
  payment.command("add").description("Add a payment method (opens browser for secure entry)").action(async () => {
568
889
  try {
569
890
  const agent = getActiveAgent();
891
+ await ensureAgentOnBackend(agent.name);
570
892
  const spinner = ora3("Requesting secure payment setup link...").start();
571
893
  const api = getApiClient();
572
894
  const res = await api.post("/payment-methods/setup", {
@@ -579,7 +901,25 @@ Payment methods for agent "${agent.name}":
579
901
  console.log(chalk4.cyan.underline(` ${setupUrl}
580
902
  `));
581
903
  console.log(chalk4.dim("The CLI never collects raw card details. Payment is set up via the secure web portal."));
582
- console.log(chalk4.dim("Once completed, run 'clishop payment list' to see your new method.\n"));
904
+ console.log(chalk4.dim("Press Enter after completing the setup in your browser.\n"));
905
+ const inquirer11 = (await import("inquirer")).default;
906
+ await inquirer11.prompt([
907
+ { type: "input", name: "done", message: "Press Enter when done..." }
908
+ ]);
909
+ const checkSpinner = ora3("Checking for your payment method...").start();
910
+ const pmRes = await api.get("/payment-methods", { params: { agent: agent.name } });
911
+ const methods = pmRes.data.paymentMethods || [];
912
+ if (methods.length > 0) {
913
+ const latest = methods[methods.length - 1];
914
+ if (!agent.defaultPaymentMethodId) {
915
+ updateAgent(agent.name, { defaultPaymentMethodId: latest.id });
916
+ checkSpinner.succeed(chalk4.green(`Payment method "${latest.label}" added and set as default.`));
917
+ } else {
918
+ checkSpinner.succeed(chalk4.green(`Payment method "${latest.label}" added.`));
919
+ }
920
+ } else {
921
+ checkSpinner.warn(chalk4.yellow("No payment method found yet. Try again or run: clishop payment list"));
922
+ }
583
923
  } catch (error) {
584
924
  handleApiError(error);
585
925
  }
@@ -1056,6 +1396,13 @@ function registerSearchCommands(program2) {
1056
1396
  } catch {
1057
1397
  }
1058
1398
  }
1399
+ if (!shipToCountry) {
1400
+ const savedCountry = getConfig().get("defaultCountry");
1401
+ if (savedCountry) {
1402
+ shipToCountry = savedCountry;
1403
+ spinner.text = `Searching for "${query}" (delivering to: ${shipToCountry})...`;
1404
+ }
1405
+ }
1059
1406
  }
1060
1407
  const forceExtended = opts.extendedSearch === true;
1061
1408
  const disableExtended = opts.extendedSearch === false;
@@ -1359,6 +1706,20 @@ Results for "${query}" \u2014 ${result.total} found (page ${result.page})
1359
1706
  }
1360
1707
  console.log();
1361
1708
  }
1709
+ const cacheItems = allProducts.filter((p) => p.id).map((p) => ({
1710
+ id: p.id,
1711
+ name: p.name,
1712
+ priceInCents: p.priceInCents,
1713
+ currency: p.currency,
1714
+ isExtended: p.isExtended
1715
+ }));
1716
+ getConfig().set("lastSearchResults", cacheItems);
1717
+ if (cacheItems.length > 0) {
1718
+ console.log(
1719
+ chalk5.dim(" \u{1F4A1} ") + chalk5.white("Buy a result by number: ") + chalk5.cyan("clishop buy 1") + chalk5.dim(" (buys the first result)")
1720
+ );
1721
+ console.log();
1722
+ }
1362
1723
  }
1363
1724
  const hasExtendedProducts = extended?.products?.length > 0;
1364
1725
  if (opts.interactive && allProducts.length > 0) {
@@ -1596,6 +1957,8 @@ function formatPrice2(cents, currency) {
1596
1957
  }
1597
1958
  var STATUS_COLORS = {
1598
1959
  pending: chalk6.yellow,
1960
+ pending_confirmation: chalk6.hex("#f97316"),
1961
+ // orange
1599
1962
  confirmed: chalk6.blue,
1600
1963
  processing: chalk6.cyan,
1601
1964
  shipped: chalk6.magenta,
@@ -1604,9 +1967,29 @@ var STATUS_COLORS = {
1604
1967
  };
1605
1968
  function registerOrderCommands(program2) {
1606
1969
  const order = program2.command("order").description("Place and manage orders");
1607
- program2.command("buy <productId>").description("Quick-buy a product").option("-q, --quantity <qty>", "Quantity", parseInt, 1).option("--address <id>", "Shipping address ID (uses agent default if omitted)").option("--payment <id>", "Payment method ID (uses agent default if omitted)").option("-y, --yes", "Skip confirmation prompt").action(async (productId, opts) => {
1970
+ program2.command("buy <productIdOrNumber>").description("Quick-buy a product (use product ID or search result number like 1, 2, 3)").option("-q, --quantity <qty>", "Quantity", parseInt, 1).option("--address <id>", "Shipping address ID (uses agent default if omitted)").option("--payment <id>", "Payment method ID (uses agent default if omitted)").option("-y, --yes", "Skip confirmation prompt").action(async (productIdOrNumber, opts) => {
1608
1971
  try {
1609
1972
  const agent = getActiveAgent();
1973
+ let productId = productIdOrNumber;
1974
+ const asNumber = parseInt(productIdOrNumber, 10);
1975
+ if (!isNaN(asNumber) && asNumber > 0 && String(asNumber) === productIdOrNumber.trim()) {
1976
+ const cached = getConfig().get("lastSearchResults") || [];
1977
+ if (cached.length === 0) {
1978
+ console.error(chalk6.red("\n\u2717 No recent search results. Run a search first: clishop search <query>"));
1979
+ process.exitCode = 1;
1980
+ return;
1981
+ }
1982
+ const index = asNumber - 1;
1983
+ if (index < 0 || index >= cached.length) {
1984
+ console.error(chalk6.red(`
1985
+ \u2717 Result #${asNumber} doesn't exist. Last search had ${cached.length} result(s).`));
1986
+ process.exitCode = 1;
1987
+ return;
1988
+ }
1989
+ productId = cached[index].id;
1990
+ console.log(chalk6.dim(` Resolved #${asNumber} \u2192 ${cached[index].name} (${productId})
1991
+ `));
1992
+ }
1610
1993
  const addressId = opts.address || agent.defaultAddressId;
1611
1994
  const paymentId = opts.payment || agent.defaultPaymentMethodId;
1612
1995
  if (!addressId) {
@@ -1696,7 +2079,17 @@ function registerOrderCommands(program2) {
1696
2079
  shippingAddressId: addressId,
1697
2080
  paymentMethodId: paymentId
1698
2081
  });
1699
- spinner.succeed(chalk6.green(`Order placed! Order ID: ${chalk6.bold(res.data.order.id)}`));
2082
+ const orderStatus = res.data.order?.status;
2083
+ if (orderStatus === "pending_confirmation") {
2084
+ spinner.succeed(chalk6.green(`Order placed! Order ID: ${chalk6.bold(res.data.order.id)}`));
2085
+ console.log();
2086
+ console.log(chalk6.yellow(" \u26A0 Confirmation required before this order ships."));
2087
+ console.log(chalk6.dim(" Check your email for a confirmation link, or confirm on the website:"));
2088
+ console.log(chalk6.cyan(` https://clishop.ai/orders/${res.data.order.id}`));
2089
+ console.log();
2090
+ } else {
2091
+ spinner.succeed(chalk6.green(`Order placed and confirmed! Order ID: ${chalk6.bold(res.data.order.id)}`));
2092
+ }
1700
2093
  } catch (error) {
1701
2094
  handleApiError(error);
1702
2095
  }
@@ -2448,8 +2841,7 @@ function registerStatusCommand(program2) {
2448
2841
  for (const pm of agent.paymentMethods) {
2449
2842
  const isDefault = pm.id === agent.defaultPaymentMethodId;
2450
2843
  const defaultBadge = isDefault ? chalk10.green(" \u2605 default") : "";
2451
- const last4 = pm.last4 ? ` \u2022\u2022\u2022\u2022 ${pm.last4}` : "";
2452
- console.log(` \u2022 ${chalk10.white(pm.label)}${last4}${defaultBadge}`);
2844
+ console.log(` \u2022 ${chalk10.white(pm.label)}${defaultBadge}`);
2453
2845
  console.log(chalk10.dim(` ${pm.type} via ${pm.provider || "unknown"} (${pm.id})`));
2454
2846
  }
2455
2847
  }
@@ -2469,6 +2861,8 @@ function registerStatusCommand(program2) {
2469
2861
  import chalk11 from "chalk";
2470
2862
  import ora9 from "ora";
2471
2863
  import inquirer7 from "inquirer";
2864
+ import open2 from "open";
2865
+ import { execFileSync } from "child_process";
2472
2866
  function divider(color = chalk11.cyan) {
2473
2867
  console.log(" " + color("\u2500".repeat(48)));
2474
2868
  }
@@ -2481,12 +2875,6 @@ function stepHeader(step, total, title) {
2481
2875
  );
2482
2876
  console.log();
2483
2877
  }
2484
- function formatPrice4(cents, currency = "USD") {
2485
- return new Intl.NumberFormat("en-US", {
2486
- style: "currency",
2487
- currency
2488
- }).format(cents / 100);
2489
- }
2490
2878
  function registerSetupCommand(program2) {
2491
2879
  program2.command("setup").description(
2492
2880
  "First-time setup wizard \u2014 account, agent, address, payment, first search"
@@ -2511,9 +2899,64 @@ async function runSetupWizard() {
2511
2899
  chalk11.dim(" It only takes a minute. You can re-run it anytime with:")
2512
2900
  );
2513
2901
  console.log(chalk11.dim(" ") + chalk11.white("clishop setup"));
2514
- stepHeader(1, 6, "Account");
2902
+ console.log();
2903
+ console.log(
2904
+ chalk11.bold.yellow(" \u{1F4CB} PATH Setup")
2905
+ );
2906
+ console.log(
2907
+ chalk11.dim(" Make sure clishop is in your PATH so your AI agents can use it.")
2908
+ );
2909
+ console.log(
2910
+ chalk11.dim(" If you installed via npm globally (") + chalk11.white("npm i -g clishop") + chalk11.dim("), it should already be available.")
2911
+ );
2912
+ console.log(
2913
+ chalk11.dim(" Verify with: ") + chalk11.white("clishop --version")
2914
+ );
2915
+ console.log(
2916
+ chalk11.dim(" If not, add the npm global bin to your PATH:")
2917
+ );
2918
+ console.log(
2919
+ chalk11.dim(" macOS/Linux: ") + chalk11.white('export PATH="$(npm config get prefix)/bin:$PATH"')
2920
+ );
2921
+ console.log(
2922
+ chalk11.dim(" Windows: ") + chalk11.white("npm config get prefix") + chalk11.dim(" \u2192 add that path to your system PATH")
2923
+ );
2924
+ console.log();
2925
+ const { setupMethod } = await inquirer7.prompt([
2926
+ {
2927
+ type: "select",
2928
+ name: "setupMethod",
2929
+ message: "How would you like to configure CLISHOP?",
2930
+ choices: [
2931
+ { name: "Here in the CLI", value: "cli" },
2932
+ { name: "On the website (opens browser)", value: "web" }
2933
+ ]
2934
+ }
2935
+ ]);
2936
+ if (setupMethod === "web") {
2937
+ const webSetupUrl = "https://clishop.ai/setup";
2938
+ console.log();
2939
+ console.log(chalk11.bold(" Opening the setup wizard on the website..."));
2940
+ console.log();
2941
+ console.log(" " + chalk11.cyan.underline(webSetupUrl));
2942
+ console.log();
2943
+ console.log(
2944
+ chalk11.dim(" Complete the setup there, then return here and run:")
2945
+ );
2946
+ console.log(chalk11.dim(" ") + chalk11.white("clishop login"));
2947
+ console.log();
2948
+ try {
2949
+ await open2(webSetupUrl);
2950
+ } catch {
2951
+ console.log(
2952
+ chalk11.yellow(" Could not open browser automatically. Please visit the link above.")
2953
+ );
2954
+ }
2955
+ config.set("setupCompleted", true);
2956
+ return;
2957
+ }
2958
+ stepHeader(1, 5, "Account");
2515
2959
  let loggedIn = await isLoggedIn();
2516
- let isNewAccount = false;
2517
2960
  if (loggedIn) {
2518
2961
  const user = await getUserInfo();
2519
2962
  console.log(
@@ -2571,46 +3014,18 @@ async function runSetupWizard() {
2571
3014
  process.exitCode = 1;
2572
3015
  return;
2573
3016
  }
2574
- console.log();
2575
- console.log(
2576
- chalk11.dim(
2577
- " Your monthly spending limit controls the maximum your AI agent"
2578
- )
2579
- );
2580
- console.log(
2581
- chalk11.dim(
2582
- " can spend per month. Default: $200. You can only change this"
2583
- )
2584
- );
2585
- console.log(
2586
- chalk11.dim(
2587
- " later via the website or email confirmation."
2588
- )
2589
- );
2590
- console.log();
2591
- const { spendingLimit } = await inquirer7.prompt([
2592
- {
2593
- type: "number",
2594
- name: "spendingLimit",
2595
- message: "Monthly spending limit ($):",
2596
- default: 200
2597
- }
2598
- ]);
2599
- const limitInCents = Math.round((spendingLimit || 200) * 100);
2600
3017
  const spinner = ora9("Creating your account...").start();
2601
3018
  try {
2602
3019
  const user = await register(
2603
3020
  answers.email,
2604
3021
  answers.password,
2605
- answers.name,
2606
- limitInCents
3022
+ answers.name
2607
3023
  );
2608
3024
  spinner.succeed(
2609
3025
  chalk11.green(
2610
3026
  `Account created! Welcome, ${chalk11.bold(user.name)}.`
2611
3027
  )
2612
3028
  );
2613
- isNewAccount = true;
2614
3029
  } catch (error) {
2615
3030
  spinner.fail(
2616
3031
  chalk11.red(
@@ -2665,95 +3080,14 @@ async function runSetupWizard() {
2665
3080
  }
2666
3081
  }
2667
3082
  }
2668
- stepHeader(2, 6, "Monthly Spending Limit");
2669
- if (isNewAccount) {
2670
- console.log(
2671
- chalk11.green(" \u2713 Spending limit was set during registration.")
2672
- );
2673
- console.log(
2674
- chalk11.dim(
2675
- " To change it later, visit " + chalk11.white("https://clishop.ai/agents") + chalk11.dim(" or use email confirmation.")
2676
- )
2677
- );
2678
- } else {
2679
- try {
2680
- const api = getApiClient();
2681
- const res = await api.get("/spending-limit");
2682
- const { monthlySpendingLimitInCents, configured } = res.data;
2683
- const currentLimit = (monthlySpendingLimitInCents / 100).toFixed(0);
2684
- if (!configured) {
2685
- console.log(
2686
- chalk11.dim(
2687
- " Your monthly spending limit controls the maximum your AI agent"
2688
- )
2689
- );
2690
- console.log(
2691
- chalk11.dim(
2692
- " can spend per month. Default: $200. You can only change this"
2693
- )
2694
- );
2695
- console.log(
2696
- chalk11.dim(
2697
- " later via the website or email confirmation."
2698
- )
2699
- );
2700
- console.log();
2701
- const { spendingLimit } = await inquirer7.prompt([
2702
- {
2703
- type: "number",
2704
- name: "spendingLimit",
2705
- message: "Monthly spending limit ($):",
2706
- default: parseInt(currentLimit) || 200
2707
- }
2708
- ]);
2709
- const limitInCents = Math.round((spendingLimit || 200) * 100);
2710
- const spinner = ora9("Setting spending limit...").start();
2711
- try {
2712
- await api.patch("/spending-limit", { limitInCents });
2713
- spinner.succeed(
2714
- chalk11.green(
2715
- `Monthly spending limit set to $${(limitInCents / 100).toFixed(0)}.`
2716
- )
2717
- );
2718
- } catch (error) {
2719
- spinner.fail(
2720
- chalk11.red(
2721
- `Failed: ${error?.response?.data?.message || error.message}`
2722
- )
2723
- );
2724
- }
2725
- } else {
2726
- console.log(
2727
- chalk11.green(
2728
- ` \u2713 Monthly spending limit: $${currentLimit}/month (already configured).`
2729
- )
2730
- );
2731
- console.log(
2732
- chalk11.dim(
2733
- " To change it, visit " + chalk11.white("https://clishop.ai/agents") + chalk11.dim(" or it will require email confirmation.")
2734
- )
2735
- );
2736
- }
2737
- } catch (error) {
2738
- console.log(
2739
- chalk11.yellow(
2740
- ` \u26A0 Could not fetch spending limit: ${error?.response?.data?.message || error.message}`
2741
- )
2742
- );
2743
- console.log(
2744
- chalk11.dim(" You can set it later on the website.")
2745
- );
2746
- }
2747
- }
2748
- stepHeader(3, 6, "Agent (optional)");
2749
- const activeAgent = getActiveAgent();
3083
+ stepHeader(2, 5, "Agent");
2750
3084
  console.log(
2751
3085
  chalk11.dim(
2752
- ` A default agent is ready ($${activeAgent.maxOrderAmount} limit, confirmation on).`
3086
+ " Agents are safety profiles that control per-order limits and categories."
2753
3087
  )
2754
3088
  );
2755
3089
  console.log(
2756
- chalk11.dim(" Agents control spending limits and category restrictions.")
3090
+ chalk11.dim(" A default agent is ready. You can customize it or create a new one.")
2757
3091
  );
2758
3092
  console.log();
2759
3093
  const { agentChoice } = await inquirer7.prompt([
@@ -2791,10 +3125,15 @@ async function runSetupWizard() {
2791
3125
  requireConfirmation: answers.requireConfirmation
2792
3126
  });
2793
3127
  setActiveAgent(agent.name);
2794
- console.log(
3128
+ const syncSpinner = ora9("Syncing agent to backend...").start();
3129
+ await ensureAgentOnBackend(
3130
+ agent.name,
3131
+ agent.maxOrderAmount ? agent.maxOrderAmount * 100 : void 0,
3132
+ agent.requireConfirmation
3133
+ );
3134
+ syncSpinner.succeed(
2795
3135
  chalk11.green(
2796
- `
2797
- \u2713 Agent "${chalk11.bold(agent.name)}" created and set as active.`
3136
+ `Agent "${chalk11.bold(agent.name)}" created and set as active.`
2798
3137
  )
2799
3138
  );
2800
3139
  } catch (error) {
@@ -2805,12 +3144,17 @@ async function runSetupWizard() {
2805
3144
  } else {
2806
3145
  console.log(chalk11.green(" \u2713 Using default agent."));
2807
3146
  }
2808
- stepHeader(4, 6, "Shipping Address");
3147
+ stepHeader(3, 5, "Shipping Address");
2809
3148
  console.log(
2810
3149
  chalk11.dim(
2811
3150
  " Add an address so products can be delivered to you."
2812
3151
  )
2813
3152
  );
3153
+ console.log(
3154
+ chalk11.dim(
3155
+ " A shipping country is required for product searches to work correctly."
3156
+ )
3157
+ );
2814
3158
  console.log();
2815
3159
  const { addAddress } = await inquirer7.prompt([
2816
3160
  {
@@ -2821,6 +3165,7 @@ async function runSetupWizard() {
2821
3165
  }
2822
3166
  ]);
2823
3167
  let addressCity = "";
3168
+ let addressCountry = "";
2824
3169
  if (addAddress) {
2825
3170
  const addr = await inquirer7.prompt([
2826
3171
  {
@@ -2832,7 +3177,8 @@ async function runSetupWizard() {
2832
3177
  {
2833
3178
  type: "input",
2834
3179
  name: "recipientName",
2835
- message: "Recipient name (optional):"
3180
+ message: "Recipient name:",
3181
+ validate: (v) => v.trim() ? true : "Recipient name is required"
2836
3182
  },
2837
3183
  {
2838
3184
  type: "input",
@@ -2885,7 +3231,7 @@ async function runSetupWizard() {
2885
3231
  default: false
2886
3232
  }
2887
3233
  ]);
2888
- let companyInfo = { companyName: "", vatNumber: "", taxId: "" };
3234
+ let companyInfo = { companyName: "", vatNumber: "" };
2889
3235
  if (addr.isCompany) {
2890
3236
  companyInfo = await inquirer7.prompt([
2891
3237
  {
@@ -2898,19 +3244,25 @@ async function runSetupWizard() {
2898
3244
  type: "input",
2899
3245
  name: "vatNumber",
2900
3246
  message: "VAT number (optional):"
2901
- },
2902
- {
2903
- type: "input",
2904
- name: "taxId",
2905
- message: "Tax ID / EIN (optional):"
2906
3247
  }
2907
3248
  ]);
2908
3249
  }
2909
3250
  addressCity = addr.city;
3251
+ const countryResult = normalizeCountry(addr.country);
3252
+ if (countryResult.code) {
3253
+ addr.country = countryResult.code;
3254
+ if (countryResult.name) {
3255
+ console.log(chalk11.green(` \u2713 Country: ${countryResult.name} (${countryResult.code})`));
3256
+ }
3257
+ } else {
3258
+ console.log(chalk11.yellow(` \u26A0 Could not recognize "${addr.country}" \u2014 using as entered.`));
3259
+ }
3260
+ addressCountry = addr.country;
2910
3261
  const spinner = ora9("Saving address...").start();
2911
3262
  try {
2912
3263
  const api = getApiClient();
2913
3264
  const agent = getActiveAgent();
3265
+ await ensureAgentOnBackend(agent.name);
2914
3266
  const res = await api.post("/addresses", {
2915
3267
  agent: agent.name,
2916
3268
  label: addr.label,
@@ -2918,7 +3270,6 @@ async function runSetupWizard() {
2918
3270
  recipientPhone: addr.recipientPhone || void 0,
2919
3271
  companyName: companyInfo.companyName || void 0,
2920
3272
  vatNumber: companyInfo.vatNumber || void 0,
2921
- taxId: companyInfo.taxId || void 0,
2922
3273
  line1: addr.line1,
2923
3274
  line2: addr.line2 || void 0,
2924
3275
  city: addr.city,
@@ -2946,13 +3297,35 @@ async function runSetupWizard() {
2946
3297
  );
2947
3298
  }
2948
3299
  } else {
3300
+ console.log();
3301
+ console.log(
3302
+ chalk11.yellow(
3303
+ " \u26A0 A country is required for product searches to show relevant results."
3304
+ )
3305
+ );
3306
+ console.log();
3307
+ const { country } = await inquirer7.prompt([
3308
+ {
3309
+ type: "input",
3310
+ name: "country",
3311
+ message: "Which country should we search products for? (e.g. US, NL, DE):",
3312
+ validate: (v) => v.trim() ? true : "Country is required for searches to work"
3313
+ }
3314
+ ]);
3315
+ const countryResult = normalizeCountry(country.trim());
3316
+ addressCountry = countryResult.code || country.trim().toUpperCase();
3317
+ config.set("defaultCountry", addressCountry);
3318
+ const displayName = countryResult.name ? `${countryResult.name} (${addressCountry})` : addressCountry;
3319
+ console.log(
3320
+ chalk11.green(` \u2713 Country set to ${displayName} for product searches.`)
3321
+ );
2949
3322
  console.log(
2950
3323
  chalk11.dim(
2951
- "\n You can add one later with: " + chalk11.white("clishop address add")
3324
+ "\n You can add a full address later with: " + chalk11.white("clishop address add")
2952
3325
  )
2953
3326
  );
2954
3327
  }
2955
- stepHeader(5, 6, "Payment Method");
3328
+ stepHeader(4, 5, "Payment Method");
2956
3329
  console.log(
2957
3330
  chalk11.dim(
2958
3331
  " For security, payment details are entered through a secure web"
@@ -2975,6 +3348,7 @@ async function runSetupWizard() {
2975
3348
  try {
2976
3349
  const api = getApiClient();
2977
3350
  const agent = getActiveAgent();
3351
+ await ensureAgentOnBackend(agent.name);
2978
3352
  const res = await api.post("/payment-methods/setup", {
2979
3353
  agent: agent.name
2980
3354
  });
@@ -2994,6 +3368,43 @@ async function runSetupWizard() {
2994
3368
  " Once done, verify with: " + chalk11.white("clishop payment list")
2995
3369
  )
2996
3370
  );
3371
+ try {
3372
+ await open2(setupUrl);
3373
+ console.log(chalk11.dim(" (Browser opened automatically)"));
3374
+ } catch {
3375
+ }
3376
+ console.log();
3377
+ await inquirer7.prompt([
3378
+ {
3379
+ type: "input",
3380
+ name: "done",
3381
+ message: "Press Enter after completing the payment setup in your browser..."
3382
+ }
3383
+ ]);
3384
+ const pollSpinner = ora9("Checking for your payment method...").start();
3385
+ try {
3386
+ const agent2 = getActiveAgent();
3387
+ await ensureAgentOnBackend(agent2.name);
3388
+ const pmRes = await api.get("/payment-methods", {
3389
+ params: { agent: agent2.name }
3390
+ });
3391
+ const methods = pmRes.data.paymentMethods || [];
3392
+ if (methods.length > 0) {
3393
+ const latest = methods[methods.length - 1];
3394
+ updateAgent(agent2.name, { defaultPaymentMethodId: latest.id });
3395
+ pollSpinner.succeed(
3396
+ chalk11.green(`Payment method "${latest.label}" found and set as default.`)
3397
+ );
3398
+ } else {
3399
+ pollSpinner.warn(
3400
+ chalk11.yellow("No payment method found yet. You can add one later with: clishop payment add")
3401
+ );
3402
+ }
3403
+ } catch {
3404
+ pollSpinner.warn(
3405
+ chalk11.yellow("Could not verify payment method. You can check with: clishop payment list")
3406
+ );
3407
+ }
2997
3408
  } catch (error) {
2998
3409
  spinner.fail(
2999
3410
  chalk11.red(
@@ -3013,13 +3424,19 @@ async function runSetupWizard() {
3013
3424
  )
3014
3425
  );
3015
3426
  }
3016
- stepHeader(6, 6, "Your First Search");
3427
+ stepHeader(5, 5, "Your First Search");
3017
3428
  if (addressCity) {
3018
3429
  console.log(
3019
3430
  chalk11.dim(
3020
3431
  ` Let's find something! Products can be shipped to ${chalk11.white(addressCity)}.`
3021
3432
  )
3022
3433
  );
3434
+ } else if (addressCountry) {
3435
+ console.log(
3436
+ chalk11.dim(
3437
+ ` Let's find something! Searching products available in ${chalk11.white(addressCountry)}.`
3438
+ )
3439
+ );
3023
3440
  } else {
3024
3441
  console.log(chalk11.dim(" Let's find something to order!"));
3025
3442
  }
@@ -3033,53 +3450,25 @@ async function runSetupWizard() {
3033
3450
  }
3034
3451
  ]);
3035
3452
  if (searchQuery.trim()) {
3036
- const spinner = ora9(`Searching for "${searchQuery}"...`).start();
3037
3453
  try {
3038
- const api = getApiClient();
3039
- const res = await api.get("/products/search", {
3040
- params: { q: searchQuery, page: 1, pageSize: 5 }
3454
+ const args = ["search", searchQuery.trim(), "--per-page", "5"];
3455
+ if (addressCountry) {
3456
+ args.push("--country", addressCountry);
3457
+ }
3458
+ if (addressCity) {
3459
+ args.push("--city", addressCity);
3460
+ }
3461
+ const nodeBin = process.argv[0];
3462
+ const scriptPath = process.argv[1];
3463
+ execFileSync(nodeBin, [scriptPath, ...args], {
3464
+ stdio: "inherit",
3465
+ timeout: 45e3,
3466
+ env: process.env
3041
3467
  });
3042
- spinner.stop();
3043
- const result = res.data;
3044
- if (result.products.length === 0) {
3045
- console.log(
3046
- chalk11.yellow(
3047
- `
3048
- No results for "${searchQuery}". Try other terms later!`
3049
- )
3050
- );
3051
- } else {
3052
- console.log(
3053
- chalk11.bold(
3054
- `
3055
- Found ${result.total} result${result.total !== 1 ? "s" : ""} for "${searchQuery}":
3056
- `
3057
- )
3058
- );
3059
- for (const p of result.products) {
3060
- const price = formatPrice4(p.priceInCents, p.currency || "USD");
3061
- const stock = p.inStock ? chalk11.green("In Stock") : chalk11.red("Out of Stock");
3062
- console.log(
3063
- ` ${chalk11.bold.cyan(p.name)} ${chalk11.bold.white(price)} ${stock}`
3064
- );
3065
- console.log(chalk11.dim(` ID: ${p.id}`));
3066
- console.log(
3067
- chalk11.dim(
3068
- ` ${p.description.length > 100 ? p.description.slice(0, 100) + "..." : p.description}`
3069
- )
3070
- );
3071
- console.log();
3072
- }
3073
- console.log(
3074
- chalk11.dim(" Buy a product with: ") + chalk11.white("clishop buy <product-id>")
3075
- );
3076
- }
3077
3468
  } catch (error) {
3078
- spinner.fail(
3079
- chalk11.red(
3080
- `Search failed: ${error?.response?.data?.message || error.message}`
3081
- )
3082
- );
3469
+ if (error.status == null && error.signal === "SIGTERM") {
3470
+ console.log(chalk11.yellow("\n Search timed out. Try again later with: clishop search <query>"));
3471
+ }
3083
3472
  }
3084
3473
  }
3085
3474
  config.set("setupCompleted", true);
@@ -3114,7 +3503,7 @@ async function runSetupWizard() {
3114
3503
  import chalk12 from "chalk";
3115
3504
  import ora10 from "ora";
3116
3505
  import inquirer8 from "inquirer";
3117
- function formatPrice5(cents, currency) {
3506
+ function formatPrice4(cents, currency) {
3118
3507
  return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(cents / 100);
3119
3508
  }
3120
3509
  var STATUS_COLORS2 = {
@@ -3451,7 +3840,7 @@ function registerAdvertiseCommands(program2) {
3451
3840
  const meta = [];
3452
3841
  if (ad.quantity > 1) meta.push(`qty: ${ad.quantity}`);
3453
3842
  if (ad.brand) meta.push(ad.brand);
3454
- if (ad.bidPriceInCents) meta.push(`max: ${formatPrice5(ad.bidPriceInCents, ad.currency)}`);
3843
+ if (ad.bidPriceInCents) meta.push(`max: ${formatPrice4(ad.bidPriceInCents, ad.currency)}`);
3455
3844
  if (ad.speedDays) meta.push(`${ad.speedDays}-day delivery`);
3456
3845
  if (ad.freeReturns) meta.push("free returns");
3457
3846
  if (ad.minReturnDays) meta.push(`${ad.minReturnDays}d return min`);
@@ -3493,7 +3882,7 @@ function registerAdvertiseCommands(program2) {
3493
3882
  if (ad.company) console.log(` Company: ${ad.company}`);
3494
3883
  if (ad.features) console.log(` Features: ${ad.features}`);
3495
3884
  console.log(` Quantity: ${ad.quantity}`);
3496
- if (ad.bidPriceInCents) console.log(` Max Bid: ${chalk12.bold(formatPrice5(ad.bidPriceInCents, ad.currency))}`);
3885
+ if (ad.bidPriceInCents) console.log(` Max Bid: ${chalk12.bold(formatPrice4(ad.bidPriceInCents, ad.currency))}`);
3497
3886
  if (ad.speedDays) console.log(` Speed: ${ad.speedDays}-day delivery`);
3498
3887
  const returnReqs = [];
3499
3888
  if (ad.freeReturns) returnReqs.push(chalk12.green("Free Returns required"));
@@ -3529,7 +3918,7 @@ function registerAdvertiseCommands(program2) {
3529
3918
  const bidStatusColor = BID_STATUS_COLORS[bid.status] || chalk12.white;
3530
3919
  const storeBadge = bid.store?.verified ? chalk12.green(" \u2713") : "";
3531
3920
  const storeRating = bid.store?.rating != null ? chalk12.dim(` (${bid.store.rating.toFixed(1)}\u2605)`) : "";
3532
- console.log(` ${chalk12.bold(bid.id)} ${bidStatusColor(bid.status.toUpperCase().padEnd(10))} ${chalk12.bold(formatPrice5(bid.priceInCents, bid.currency))}`);
3921
+ console.log(` ${chalk12.bold(bid.id)} ${bidStatusColor(bid.status.toUpperCase().padEnd(10))} ${chalk12.bold(formatPrice4(bid.priceInCents, bid.currency))}`);
3533
3922
  console.log(` Store: ${bid.store?.name || bid.storeId}${storeBadge}${storeRating}`);
3534
3923
  if (bid.shippingDays != null) console.log(` Delivery: ${bid.shippingDays}-day`);
3535
3924
  const bidReturns = [];
@@ -3537,7 +3926,7 @@ function registerAdvertiseCommands(program2) {
3537
3926
  if (bid.returnWindowDays) bidReturns.push(`${bid.returnWindowDays}-day return window`);
3538
3927
  if (bidReturns.length) console.log(` Returns: ${bidReturns.join(" \xB7 ")}`);
3539
3928
  if (bid.note) console.log(` Note: ${bid.note}`);
3540
- if (bid.product) console.log(` Product: ${bid.product.name} (${formatPrice5(bid.product.priceInCents, bid.product.currency)})`);
3929
+ if (bid.product) console.log(` Product: ${bid.product.name} (${formatPrice4(bid.product.priceInCents, bid.product.currency)})`);
3541
3930
  console.log(` Date: ${new Date(bid.createdAt).toLocaleString()}`);
3542
3931
  console.log();
3543
3932
  }
@@ -3572,7 +3961,7 @@ function registerAdvertiseCommands(program2) {
3572
3961
  console.log(chalk12.bold("\n Accept this bid?\n"));
3573
3962
  console.log(` Request: ${ad.title}`);
3574
3963
  console.log(` Store: ${bid.store?.name || bid.storeId}${bid.store?.verified ? chalk12.green(" \u2713") : ""}`);
3575
- console.log(` Price: ${chalk12.bold(formatPrice5(bid.priceInCents, bid.currency))}`);
3964
+ console.log(` Price: ${chalk12.bold(formatPrice4(bid.priceInCents, bid.currency))}`);
3576
3965
  if (bid.shippingDays != null) console.log(` Delivery: ${bid.shippingDays}-day`);
3577
3966
  if (bid.note) console.log(` Note: ${bid.note}`);
3578
3967
  console.log();
package/dist/mcp.js CHANGED
@@ -3,12 +3,12 @@ import {
3
3
  getApiClient,
4
4
  getUserInfo,
5
5
  isLoggedIn
6
- } from "./chunk-RHBOI27D.js";
6
+ } from "./chunk-CVK6G342.js";
7
7
  import {
8
8
  __export,
9
9
  getActiveAgent,
10
10
  getConfig
11
- } from "./chunk-ZF3JIQRK.js";
11
+ } from "./chunk-X3H7SYR4.js";
12
12
 
13
13
  // src/mcp.ts
14
14
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -14100,7 +14100,7 @@ server.registerTool("add_address", {
14100
14100
  instructions: args.instructions || void 0
14101
14101
  });
14102
14102
  if (args.setDefault && res.data.address?.id) {
14103
- const { updateAgent } = await import("./config-63FY6NWX.js");
14103
+ const { updateAgent } = await import("./config-WZBIQWME.js");
14104
14104
  updateAgent(agent.name, { defaultAddressId: res.data.address.id });
14105
14105
  }
14106
14106
  return res.data;
@@ -14291,7 +14291,7 @@ server.registerTool("list_agents", {
14291
14291
  }
14292
14292
  }, async () => {
14293
14293
  return safeCall(async () => {
14294
- const { listAgents, getConfig: getConfig2 } = await import("./config-63FY6NWX.js");
14294
+ const { listAgents, getConfig: getConfig2 } = await import("./config-WZBIQWME.js");
14295
14295
  const agents = listAgents();
14296
14296
  const active = getConfig2().get("activeAgent");
14297
14297
  return { agents, activeAgent: active };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clishop",
3
- "version": "0.3.1",
3
+ "version": "1.0.1",
4
4
  "mcpName": "io.github.StefDCL/clishop",
5
5
  "description": "CLISHOP — Order anything from your terminal",
6
6
  "main": "dist/index.js",