clishop 1.3.3 → 1.4.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.
- package/dist/{chunk-ML7L6BAH.js → chunk-EAXPWOMT.js} +6 -43
- package/dist/index.js +223 -862
- package/dist/mcp.js +61 -6
- package/package.json +1 -1
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
|
-
|
|
13
|
-
|
|
14
|
-
} from "./chunk-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
683
|
+
const { instructionsInput } = await inquirer2.prompt([
|
|
789
684
|
{ type: "input", name: "instructionsInput", message: "Delivery instructions (optional):" }
|
|
790
685
|
]);
|
|
791
|
-
const { isCompanyAddr } = await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,147 @@ 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
|
-
"
|
|
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)").action(async (opts) => {
|
|
816
|
+
await runSetupWizard(opts.email);
|
|
930
817
|
});
|
|
931
818
|
}
|
|
932
|
-
async function runSetupWizard() {
|
|
819
|
+
async function runSetupWizard(emailArg) {
|
|
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-
|
|
850
|
+
console.log(chalk4.dim(` Build: ${"2026-04-03T15:19:55.173Z"}`));
|
|
940
851
|
console.log();
|
|
941
852
|
divider(chalk4.cyan);
|
|
942
853
|
console.log();
|
|
943
854
|
console.log(
|
|
944
|
-
chalk4.dim("
|
|
945
|
-
);
|
|
946
|
-
console.log(
|
|
947
|
-
chalk4.dim(" It only takes a minute. You can re-run it anytime with:")
|
|
855
|
+
chalk4.dim(" Set up your account in one step. You'll get a link to")
|
|
948
856
|
);
|
|
949
|
-
console.log(chalk4.dim(" ") + chalk4.white("clishop setup"));
|
|
950
|
-
console.log();
|
|
951
857
|
console.log(
|
|
952
|
-
chalk4.
|
|
858
|
+
chalk4.dim(" securely link your payment method in the browser.")
|
|
953
859
|
);
|
|
954
860
|
console.log(
|
|
955
|
-
chalk4.dim("
|
|
956
|
-
);
|
|
957
|
-
console.log(
|
|
958
|
-
chalk4.dim(" If you installed via npm globally (") + chalk4.white("npm i -g clishop") + chalk4.dim("), it should already be available.")
|
|
959
|
-
);
|
|
960
|
-
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("
|
|
865
|
+
chalk4.dim(" By creating an account you agree to the CLISHOP")
|
|
965
866
|
);
|
|
966
867
|
console.log(
|
|
967
|
-
chalk4.dim("
|
|
868
|
+
chalk4.dim(" Terms & Conditions: ") + chalk4.cyan.underline("https://clishop.ai/terms")
|
|
968
869
|
);
|
|
969
870
|
console.log(
|
|
970
|
-
chalk4.dim("
|
|
871
|
+
chalk4.dim(" Privacy Policy: ") + chalk4.cyan.underline("https://clishop.ai/privacy")
|
|
971
872
|
);
|
|
972
873
|
console.log();
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
name: "
|
|
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
|
-
}
|
|
1010
|
-
]);
|
|
1011
|
-
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: "*" }
|
|
874
|
+
let email = emailArg;
|
|
875
|
+
if (!email) {
|
|
876
|
+
const answers = await inquirer3.prompt([
|
|
877
|
+
{ type: "input", name: "email", message: "Email:" }
|
|
1017
878
|
]);
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
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"'));
|
|
879
|
+
email = answers.email;
|
|
880
|
+
}
|
|
881
|
+
const spinner = ora3("Creating your account and payment link...").start();
|
|
882
|
+
let setupUrl;
|
|
883
|
+
let deviceCode;
|
|
884
|
+
try {
|
|
885
|
+
const baseUrl2 = getApiBaseUrl();
|
|
886
|
+
const res = await axios.post(`${baseUrl2}/auth/setup-link`, { email });
|
|
887
|
+
setupUrl = res.data.setupUrl;
|
|
888
|
+
deviceCode = res.data.deviceCode;
|
|
889
|
+
spinner.stop();
|
|
890
|
+
} catch (error) {
|
|
891
|
+
const msg = error?.response?.data?.message || error.message;
|
|
892
|
+
spinner.fail(chalk4.red(`Setup failed: ${msg}`));
|
|
1073
893
|
console.log();
|
|
1074
|
-
|
|
894
|
+
console.log(chalk4.dim(" You can try again with: ") + chalk4.white("clishop setup"));
|
|
1075
895
|
console.log();
|
|
896
|
+
process.exitCode = 1;
|
|
1076
897
|
return;
|
|
1077
898
|
}
|
|
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
899
|
console.log();
|
|
1230
|
-
|
|
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
|
-
);
|
|
900
|
+
console.log(chalk4.bold(" Open this link to link your payment method:"));
|
|
1302
901
|
console.log();
|
|
1303
|
-
|
|
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
|
-
);
|
|
902
|
+
console.log(" " + chalk4.cyan.underline(setupUrl));
|
|
1499
903
|
console.log();
|
|
1500
|
-
const
|
|
1501
|
-
|
|
1502
|
-
|
|
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
|
-
}
|
|
904
|
+
const opened = await openBrowser(setupUrl);
|
|
905
|
+
if (opened) {
|
|
906
|
+
console.log(chalk4.dim(" (Browser opened automatically)"));
|
|
1581
907
|
} 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!"));
|
|
908
|
+
console.log(chalk4.yellow(" Could not open browser automatically. Please visit the link above."));
|
|
1603
909
|
}
|
|
1604
910
|
console.log();
|
|
1605
|
-
const
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
}
|
|
1612
|
-
]);
|
|
1613
|
-
if (searchQuery.trim()) {
|
|
911
|
+
const pollSpinner = ora3("Waiting for you to complete payment setup...").start();
|
|
912
|
+
const baseUrl = getApiBaseUrl();
|
|
913
|
+
const maxAttempts = 120;
|
|
914
|
+
let completed = false;
|
|
915
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
916
|
+
await new Promise((r) => setTimeout(r, 5e3));
|
|
1614
917
|
try {
|
|
1615
|
-
const
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
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>"));
|
|
918
|
+
const res = await axios.post(`${baseUrl}/auth/device/poll`, { deviceCode });
|
|
919
|
+
const data = res.data;
|
|
920
|
+
if (data.status === "complete" && data.token && data.refreshToken && data.user) {
|
|
921
|
+
await storeAuthFromSetup({
|
|
922
|
+
token: data.token,
|
|
923
|
+
refreshToken: data.refreshToken,
|
|
924
|
+
user: data.user
|
|
925
|
+
});
|
|
926
|
+
config.set("setupCompleted", true);
|
|
927
|
+
pollSpinner.succeed(chalk4.green("Payment linked and account activated!"));
|
|
928
|
+
completed = true;
|
|
929
|
+
break;
|
|
1632
930
|
}
|
|
931
|
+
if (data.status === "expired") {
|
|
932
|
+
pollSpinner.fail(chalk4.red("Setup link expired. Run ") + chalk4.white("clishop setup") + chalk4.red(" to try again."));
|
|
933
|
+
process.exitCode = 1;
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
} catch {
|
|
1633
937
|
}
|
|
1634
938
|
}
|
|
1635
|
-
|
|
939
|
+
if (!completed) {
|
|
940
|
+
pollSpinner.fail(chalk4.red("Timed out waiting for setup. Run ") + chalk4.white("clishop setup") + chalk4.red(" to try again."));
|
|
941
|
+
process.exitCode = 1;
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
1636
944
|
console.log();
|
|
1637
945
|
divider(chalk4.green);
|
|
1638
946
|
console.log();
|
|
1639
947
|
console.log(chalk4.bold.green(" \u2713 You're all set!"));
|
|
1640
948
|
console.log();
|
|
949
|
+
console.log(chalk4.dim(" Your agent can now add addresses and place orders."));
|
|
950
|
+
console.log(chalk4.dim(" To add a shipping address manually:"));
|
|
951
|
+
console.log(chalk4.white(" clishop address add"));
|
|
952
|
+
console.log();
|
|
1641
953
|
console.log(chalk4.dim(" Here are some commands to get you started:"));
|
|
1642
954
|
console.log();
|
|
1643
955
|
console.log(
|
|
@@ -1649,20 +961,51 @@ async function runSetupWizard() {
|
|
|
1649
961
|
console.log(
|
|
1650
962
|
chalk4.white(" clishop order list ") + chalk4.dim("View your orders")
|
|
1651
963
|
);
|
|
1652
|
-
console.log(
|
|
1653
|
-
chalk4.white(" clishop agent list ") + chalk4.dim("Manage your agents")
|
|
1654
|
-
);
|
|
1655
964
|
console.log(
|
|
1656
965
|
chalk4.white(" clishop --help ") + chalk4.dim("See all commands")
|
|
1657
966
|
);
|
|
1658
967
|
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
968
|
divider(chalk4.green);
|
|
1664
969
|
console.log();
|
|
1665
970
|
}
|
|
971
|
+
async function runPaymentLinkFlow(config) {
|
|
972
|
+
const spinner = ora3("Requesting secure payment setup link...").start();
|
|
973
|
+
try {
|
|
974
|
+
const api = getApiClient();
|
|
975
|
+
const agent = getActiveAgent();
|
|
976
|
+
await ensureAgentOnBackend(agent.name);
|
|
977
|
+
const res = await api.post("/payment-methods/setup", { agent: agent.name });
|
|
978
|
+
spinner.stop();
|
|
979
|
+
const { setupUrl } = res.data;
|
|
980
|
+
console.log();
|
|
981
|
+
console.log(chalk4.bold(" Open this link to link your payment method:"));
|
|
982
|
+
console.log();
|
|
983
|
+
console.log(" " + chalk4.cyan.underline(setupUrl));
|
|
984
|
+
console.log();
|
|
985
|
+
const opened = await openBrowser(setupUrl);
|
|
986
|
+
if (opened) {
|
|
987
|
+
console.log(chalk4.dim(" (Browser opened automatically)"));
|
|
988
|
+
}
|
|
989
|
+
console.log();
|
|
990
|
+
await inquirer3.prompt([
|
|
991
|
+
{ type: "input", name: "done", message: "Press Enter after completing payment setup in your browser..." }
|
|
992
|
+
]);
|
|
993
|
+
const checkSpinner = ora3("Checking for your payment method...").start();
|
|
994
|
+
const pmRes = await api.get("/payment-methods", { params: { agent: agent.name } });
|
|
995
|
+
const methods = pmRes.data.paymentMethods || [];
|
|
996
|
+
if (methods.length > 0) {
|
|
997
|
+
const latest = methods[methods.length - 1];
|
|
998
|
+
updateAgent(agent.name, { defaultPaymentMethodId: latest.id });
|
|
999
|
+
checkSpinner.succeed(chalk4.green(`Payment method "${latest.label}" linked and set as default.`));
|
|
1000
|
+
config.set("setupCompleted", true);
|
|
1001
|
+
} else {
|
|
1002
|
+
checkSpinner.warn(chalk4.yellow("No payment method found yet. Run ") + chalk4.white("clishop setup") + chalk4.yellow(" to try again."));
|
|
1003
|
+
}
|
|
1004
|
+
} catch (error) {
|
|
1005
|
+
spinner.fail(chalk4.red(`Could not get setup link: ${error?.response?.data?.message || error.message}`));
|
|
1006
|
+
}
|
|
1007
|
+
console.log();
|
|
1008
|
+
}
|
|
1666
1009
|
|
|
1667
1010
|
// src/commands/payment.ts
|
|
1668
1011
|
function registerPaymentCommands(program2) {
|
|
@@ -1679,7 +1022,7 @@ function registerPaymentCommands(program2) {
|
|
|
1679
1022
|
spinner.stop();
|
|
1680
1023
|
const methods = res.data.paymentMethods;
|
|
1681
1024
|
if (methods.length === 0) {
|
|
1682
|
-
console.log(chalk5.yellow("\nNo payment methods found.
|
|
1025
|
+
console.log(chalk5.yellow("\nNo payment methods found. Run: clishop setup\n"));
|
|
1683
1026
|
return;
|
|
1684
1027
|
}
|
|
1685
1028
|
console.log(chalk5.bold(`
|
|
@@ -1695,7 +1038,7 @@ Payment methods for agent "${agent.name}":
|
|
|
1695
1038
|
handleApiError(error);
|
|
1696
1039
|
}
|
|
1697
1040
|
});
|
|
1698
|
-
payment.command("add").description("Add
|
|
1041
|
+
payment.command("add").description("Add an additional payment method (opens browser). First-time setup? Use 'clishop setup' instead.").action(async () => {
|
|
1699
1042
|
try {
|
|
1700
1043
|
const agent = getActiveAgent();
|
|
1701
1044
|
await ensureAgentOnBackend(agent.name);
|
|
@@ -1712,8 +1055,8 @@ Payment methods for agent "${agent.name}":
|
|
|
1712
1055
|
`));
|
|
1713
1056
|
console.log(chalk5.dim("The CLI never collects raw card details. Payment is set up via the secure web portal."));
|
|
1714
1057
|
console.log(chalk5.dim("Press Enter after completing the setup in your browser.\n"));
|
|
1715
|
-
const
|
|
1716
|
-
await
|
|
1058
|
+
const inquirer10 = (await import("inquirer")).default;
|
|
1059
|
+
await inquirer10.prompt([
|
|
1717
1060
|
{ type: "input", name: "done", message: "Press Enter when done..." }
|
|
1718
1061
|
]);
|
|
1719
1062
|
const checkSpinner = ora4("Checking for your payment method...").start();
|
|
@@ -1759,7 +1102,7 @@ Payment methods for agent "${agent.name}":
|
|
|
1759
1102
|
// src/commands/search.ts
|
|
1760
1103
|
import chalk6 from "chalk";
|
|
1761
1104
|
import ora5 from "ora";
|
|
1762
|
-
import
|
|
1105
|
+
import inquirer4 from "inquirer";
|
|
1763
1106
|
function formatPrice(cents, currency) {
|
|
1764
1107
|
return new Intl.NumberFormat("en-US", {
|
|
1765
1108
|
style: "currency",
|
|
@@ -2208,15 +1551,17 @@ function registerSearchCommands(program2) {
|
|
|
2208
1551
|
}
|
|
2209
1552
|
}
|
|
2210
1553
|
if (!shipToCountry) {
|
|
2211
|
-
|
|
2212
|
-
spinner.fail(chalk6.red("No shipping address set \u2014 a country is required for searches."));
|
|
1554
|
+
spinner.stop();
|
|
2213
1555
|
console.log();
|
|
2214
|
-
console.log(chalk6.yellow(
|
|
2215
|
-
console.log(chalk6.yellow(" Add an address to this agent:"));
|
|
2216
|
-
console.log(chalk6.white(` clishop address add`));
|
|
1556
|
+
console.log(chalk6.yellow(" Please specify where you want your order shipped:"));
|
|
2217
1557
|
console.log();
|
|
2218
|
-
console.log(chalk6.
|
|
2219
|
-
console.log(chalk6.white(` clishop search "
|
|
1558
|
+
console.log(chalk6.white(` clishop search "${query}" --country US`));
|
|
1559
|
+
console.log(chalk6.white(` clishop search "${query}" --country BE`));
|
|
1560
|
+
console.log(chalk6.white(` clishop search "${query}" --country NL`));
|
|
1561
|
+
console.log();
|
|
1562
|
+
console.log(chalk6.dim(" You can use any ISO country code (US, GB, DE, FR, BE, NL, ...)."));
|
|
1563
|
+
console.log(chalk6.dim(" Or add an address to skip this step next time:"));
|
|
1564
|
+
console.log(chalk6.white(` clishop address add`));
|
|
2220
1565
|
console.log();
|
|
2221
1566
|
return;
|
|
2222
1567
|
}
|
|
@@ -2550,7 +1895,7 @@ Results for "${query}" \u2014 ${result.total} found (page ${result.page})
|
|
|
2550
1895
|
short: p.name.length > 40 ? p.name.slice(0, 37) + "..." : p.name
|
|
2551
1896
|
};
|
|
2552
1897
|
});
|
|
2553
|
-
const { selectedIds } = await
|
|
1898
|
+
const { selectedIds } = await inquirer4.prompt([
|
|
2554
1899
|
{
|
|
2555
1900
|
type: "checkbox",
|
|
2556
1901
|
name: "selectedIds",
|
|
@@ -2786,7 +2131,7 @@ Product Information \u2014 ${total} result(s)
|
|
|
2786
2131
|
// src/commands/order.ts
|
|
2787
2132
|
import chalk7 from "chalk";
|
|
2788
2133
|
import ora6 from "ora";
|
|
2789
|
-
import
|
|
2134
|
+
import inquirer5 from "inquirer";
|
|
2790
2135
|
function formatPrice2(cents, currency) {
|
|
2791
2136
|
return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(cents / 100);
|
|
2792
2137
|
}
|
|
@@ -2826,14 +2171,26 @@ function registerOrderCommands(program2) {
|
|
|
2826
2171
|
`));
|
|
2827
2172
|
}
|
|
2828
2173
|
const addressId = opts.address || agent.defaultAddressId;
|
|
2829
|
-
|
|
2174
|
+
let paymentId = opts.payment || agent.defaultPaymentMethodId;
|
|
2175
|
+
if (!paymentId) {
|
|
2176
|
+
try {
|
|
2177
|
+
const api2 = getApiClient();
|
|
2178
|
+
const pmRes = await api2.get("/payment-methods", { params: { agent: agent.name } });
|
|
2179
|
+
const methods = pmRes.data.paymentMethods || [];
|
|
2180
|
+
if (methods.length > 0) {
|
|
2181
|
+
paymentId = methods[0].id;
|
|
2182
|
+
updateAgent(agent.name, { defaultPaymentMethodId: paymentId });
|
|
2183
|
+
}
|
|
2184
|
+
} catch {
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2830
2187
|
if (!addressId) {
|
|
2831
2188
|
console.error(chalk7.red("\n\u2717 No address set. Add one with: clishop address add"));
|
|
2832
2189
|
process.exitCode = 1;
|
|
2833
2190
|
return;
|
|
2834
2191
|
}
|
|
2835
2192
|
if (!paymentId) {
|
|
2836
|
-
console.error(chalk7.red("\n\u2717 No payment method
|
|
2193
|
+
console.error(chalk7.red("\n\u2717 No payment method linked. Run: clishop setup"));
|
|
2837
2194
|
process.exitCode = 1;
|
|
2838
2195
|
return;
|
|
2839
2196
|
}
|
|
@@ -2894,7 +2251,7 @@ function registerOrderCommands(program2) {
|
|
|
2894
2251
|
console.log(` Total: ${chalk7.bold(formatPrice2(totalCents, product.currency))}`);
|
|
2895
2252
|
console.log(` Agent: ${agent.name}`);
|
|
2896
2253
|
console.log();
|
|
2897
|
-
const { confirm } = await
|
|
2254
|
+
const { confirm } = await inquirer5.prompt([
|
|
2898
2255
|
{
|
|
2899
2256
|
type: "confirm",
|
|
2900
2257
|
name: "confirm",
|
|
@@ -3041,7 +2398,7 @@ function registerOrderCommands(program2) {
|
|
|
3041
2398
|
});
|
|
3042
2399
|
order.command("cancel <id>").description("Cancel an order").action(async (id) => {
|
|
3043
2400
|
try {
|
|
3044
|
-
const { confirm } = await
|
|
2401
|
+
const { confirm } = await inquirer5.prompt([
|
|
3045
2402
|
{
|
|
3046
2403
|
type: "confirm",
|
|
3047
2404
|
name: "confirm",
|
|
@@ -3063,7 +2420,7 @@ function registerOrderCommands(program2) {
|
|
|
3063
2420
|
// src/commands/review.ts
|
|
3064
2421
|
import chalk8 from "chalk";
|
|
3065
2422
|
import ora7 from "ora";
|
|
3066
|
-
import
|
|
2423
|
+
import inquirer6 from "inquirer";
|
|
3067
2424
|
function renderStars2(rating) {
|
|
3068
2425
|
const filled = Math.round(rating);
|
|
3069
2426
|
const empty = 10 - filled;
|
|
@@ -3116,7 +2473,7 @@ function registerReviewCommands(program2) {
|
|
|
3116
2473
|
let storeReview = void 0;
|
|
3117
2474
|
for (const item of unreviewedItems) {
|
|
3118
2475
|
console.log(chalk8.bold(` Product: ${item.productName}`));
|
|
3119
|
-
const { wantReview } = await
|
|
2476
|
+
const { wantReview } = await inquirer6.prompt([
|
|
3120
2477
|
{
|
|
3121
2478
|
type: "confirm",
|
|
3122
2479
|
name: "wantReview",
|
|
@@ -3125,7 +2482,7 @@ function registerReviewCommands(program2) {
|
|
|
3125
2482
|
}
|
|
3126
2483
|
]);
|
|
3127
2484
|
if (!wantReview) continue;
|
|
3128
|
-
const answers = await
|
|
2485
|
+
const answers = await inquirer6.prompt([
|
|
3129
2486
|
{
|
|
3130
2487
|
type: "select",
|
|
3131
2488
|
name: "rating",
|
|
@@ -3156,7 +2513,7 @@ function registerReviewCommands(program2) {
|
|
|
3156
2513
|
}
|
|
3157
2514
|
if (!storeAlreadyReviewed) {
|
|
3158
2515
|
console.log(chalk8.bold(` Store: ${reviewable.store.name}`));
|
|
3159
|
-
const { wantStoreReview } = await
|
|
2516
|
+
const { wantStoreReview } = await inquirer6.prompt([
|
|
3160
2517
|
{
|
|
3161
2518
|
type: "confirm",
|
|
3162
2519
|
name: "wantStoreReview",
|
|
@@ -3165,7 +2522,7 @@ function registerReviewCommands(program2) {
|
|
|
3165
2522
|
}
|
|
3166
2523
|
]);
|
|
3167
2524
|
if (wantStoreReview) {
|
|
3168
|
-
const storeAnswers = await
|
|
2525
|
+
const storeAnswers = await inquirer6.prompt([
|
|
3169
2526
|
{
|
|
3170
2527
|
type: "select",
|
|
3171
2528
|
name: "rating",
|
|
@@ -3225,7 +2582,7 @@ function registerReviewCommands(program2) {
|
|
|
3225
2582
|
});
|
|
3226
2583
|
review.command("add <productId>").description("Write a review for a product").option("--order <orderId>", "Associate with an order").action(async (productId, opts) => {
|
|
3227
2584
|
try {
|
|
3228
|
-
const answers = await
|
|
2585
|
+
const answers = await inquirer6.prompt([
|
|
3229
2586
|
{
|
|
3230
2587
|
type: "select",
|
|
3231
2588
|
name: "rating",
|
|
@@ -3258,7 +2615,7 @@ function registerReviewCommands(program2) {
|
|
|
3258
2615
|
});
|
|
3259
2616
|
review.command("store <storeId>").description("Write a review for a store").option("--order <orderId>", "Associate with an order").action(async (storeId, opts) => {
|
|
3260
2617
|
try {
|
|
3261
|
-
const answers = await
|
|
2618
|
+
const answers = await inquirer6.prompt([
|
|
3262
2619
|
{
|
|
3263
2620
|
type: "select",
|
|
3264
2621
|
name: "rating",
|
|
@@ -3360,7 +2717,7 @@ function registerReviewCommands(program2) {
|
|
|
3360
2717
|
});
|
|
3361
2718
|
review.command("delete <reviewId>").alias("rm").description("Delete one of your reviews").option("--store", "Delete a store review").action(async (reviewId, opts) => {
|
|
3362
2719
|
try {
|
|
3363
|
-
const { confirm } = await
|
|
2720
|
+
const { confirm } = await inquirer6.prompt([
|
|
3364
2721
|
{
|
|
3365
2722
|
type: "confirm",
|
|
3366
2723
|
name: "confirm",
|
|
@@ -3599,7 +2956,7 @@ function registerStatusCommand(program2) {
|
|
|
3599
2956
|
program2.command("status").description("Show full account overview \u2014 user, agents, addresses, payment methods").option("--json", "Output raw JSON").action(async (opts) => {
|
|
3600
2957
|
try {
|
|
3601
2958
|
if (!await isLoggedIn()) {
|
|
3602
|
-
console.log(chalk11.yellow("\nNot
|
|
2959
|
+
console.log(chalk11.yellow("\nNot set up yet. Run: clishop setup\n"));
|
|
3603
2960
|
return;
|
|
3604
2961
|
}
|
|
3605
2962
|
const spinner = ora9("Fetching account overview...").start();
|
|
@@ -3671,7 +3028,7 @@ function registerStatusCommand(program2) {
|
|
|
3671
3028
|
console.log();
|
|
3672
3029
|
console.log(chalk11.bold(` \u{1F4B3} Payment Methods (${agent.paymentMethods.length})`));
|
|
3673
3030
|
if (agent.paymentMethods.length === 0) {
|
|
3674
|
-
console.log(chalk11.dim(" None \u2014 run: clishop
|
|
3031
|
+
console.log(chalk11.dim(" None \u2014 run: clishop setup"));
|
|
3675
3032
|
} else {
|
|
3676
3033
|
for (const pm of agent.paymentMethods) {
|
|
3677
3034
|
const isDefault = pm.id === agent.defaultPaymentMethodId;
|
|
@@ -3695,7 +3052,7 @@ function registerStatusCommand(program2) {
|
|
|
3695
3052
|
// src/commands/advertise.ts
|
|
3696
3053
|
import chalk12 from "chalk";
|
|
3697
3054
|
import ora10 from "ora";
|
|
3698
|
-
import
|
|
3055
|
+
import inquirer7 from "inquirer";
|
|
3699
3056
|
function formatPrice4(cents, currency) {
|
|
3700
3057
|
return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(cents / 100);
|
|
3701
3058
|
}
|
|
@@ -3719,7 +3076,7 @@ function registerAdvertiseCommands(program2) {
|
|
|
3719
3076
|
const agent = getActiveAgent();
|
|
3720
3077
|
console.log(chalk12.bold("\n \u{1F4E2} Advertise a Request\n"));
|
|
3721
3078
|
console.log(chalk12.dim(" Can't find what you need? Describe it and vendors will bid to fulfill it.\n"));
|
|
3722
|
-
const answers = await
|
|
3079
|
+
const answers = await inquirer7.prompt([
|
|
3723
3080
|
{
|
|
3724
3081
|
type: "input",
|
|
3725
3082
|
name: "title",
|
|
@@ -3766,7 +3123,7 @@ function registerAdvertiseCommands(program2) {
|
|
|
3766
3123
|
]);
|
|
3767
3124
|
let recurringNote;
|
|
3768
3125
|
if (answers.recurring) {
|
|
3769
|
-
const recAnswer = await
|
|
3126
|
+
const recAnswer = await inquirer7.prompt([
|
|
3770
3127
|
{
|
|
3771
3128
|
type: "input",
|
|
3772
3129
|
name: "recurringNote",
|
|
@@ -3775,7 +3132,7 @@ function registerAdvertiseCommands(program2) {
|
|
|
3775
3132
|
]);
|
|
3776
3133
|
recurringNote = recAnswer.recurringNote || void 0;
|
|
3777
3134
|
}
|
|
3778
|
-
const priceAnswers = await
|
|
3135
|
+
const priceAnswers = await inquirer7.prompt([
|
|
3779
3136
|
{
|
|
3780
3137
|
type: "input",
|
|
3781
3138
|
name: "bidPrice",
|
|
@@ -3784,7 +3141,7 @@ function registerAdvertiseCommands(program2) {
|
|
|
3784
3141
|
]);
|
|
3785
3142
|
let currency = "USD";
|
|
3786
3143
|
if (priceAnswers.bidPrice && parseFloat(priceAnswers.bidPrice) > 0) {
|
|
3787
|
-
const currencyAnswer = await
|
|
3144
|
+
const currencyAnswer = await inquirer7.prompt([
|
|
3788
3145
|
{
|
|
3789
3146
|
type: "list",
|
|
3790
3147
|
name: "currency",
|
|
@@ -3805,7 +3162,7 @@ function registerAdvertiseCommands(program2) {
|
|
|
3805
3162
|
}
|
|
3806
3163
|
]);
|
|
3807
3164
|
if (currencyAnswer.currency === "OTHER") {
|
|
3808
|
-
const customCurrency = await
|
|
3165
|
+
const customCurrency = await inquirer7.prompt([
|
|
3809
3166
|
{
|
|
3810
3167
|
type: "input",
|
|
3811
3168
|
name: "code",
|
|
@@ -3818,14 +3175,14 @@ function registerAdvertiseCommands(program2) {
|
|
|
3818
3175
|
currency = currencyAnswer.currency;
|
|
3819
3176
|
}
|
|
3820
3177
|
}
|
|
3821
|
-
const speedAnswer = await
|
|
3178
|
+
const speedAnswer = await inquirer7.prompt([
|
|
3822
3179
|
{
|
|
3823
3180
|
type: "input",
|
|
3824
3181
|
name: "speedDays",
|
|
3825
3182
|
message: "Desired delivery speed in days (optional):"
|
|
3826
3183
|
}
|
|
3827
3184
|
]);
|
|
3828
|
-
const returnAnswers = await
|
|
3185
|
+
const returnAnswers = await inquirer7.prompt([
|
|
3829
3186
|
{
|
|
3830
3187
|
type: "confirm",
|
|
3831
3188
|
name: "freeReturns",
|
|
@@ -3857,7 +3214,7 @@ function registerAdvertiseCommands(program2) {
|
|
|
3857
3214
|
addrChoices.push({ name: chalk12.dim(skipOption), value: skipOption });
|
|
3858
3215
|
const defaultAddr = addresses.find((a) => a.id === agent.defaultAddressId);
|
|
3859
3216
|
const defaultDisplay = defaultAddr ? `${defaultAddr.label} \u2014 ${defaultAddr.line1}` : "";
|
|
3860
|
-
const { selectedAddress } = await
|
|
3217
|
+
const { selectedAddress } = await inquirer7.prompt([
|
|
3861
3218
|
{
|
|
3862
3219
|
type: "list",
|
|
3863
3220
|
name: "selectedAddress",
|
|
@@ -3891,7 +3248,7 @@ function registerAdvertiseCommands(program2) {
|
|
|
3891
3248
|
// Default: all user's payment methods selected
|
|
3892
3249
|
}))
|
|
3893
3250
|
];
|
|
3894
|
-
const { selectedPayments } = await
|
|
3251
|
+
const { selectedPayments } = await inquirer7.prompt([
|
|
3895
3252
|
{
|
|
3896
3253
|
type: "checkbox",
|
|
3897
3254
|
name: "selectedPayments",
|
|
@@ -3905,7 +3262,7 @@ function registerAdvertiseCommands(program2) {
|
|
|
3905
3262
|
paymentMethods = JSON.stringify(selectedPayments);
|
|
3906
3263
|
}
|
|
3907
3264
|
} else {
|
|
3908
|
-
console.log(chalk12.dim(" No payment methods found.
|
|
3265
|
+
console.log(chalk12.dim(" No payment methods found. Run: clishop setup"));
|
|
3909
3266
|
}
|
|
3910
3267
|
} catch {
|
|
3911
3268
|
paySpinner.stop();
|
|
@@ -4158,7 +3515,7 @@ function registerAdvertiseCommands(program2) {
|
|
|
4158
3515
|
if (bid.shippingDays != null) console.log(` Delivery: ${bid.shippingDays}-day`);
|
|
4159
3516
|
if (bid.note) console.log(` Note: ${bid.note}`);
|
|
4160
3517
|
console.log();
|
|
4161
|
-
const { confirm } = await
|
|
3518
|
+
const { confirm } = await inquirer7.prompt([
|
|
4162
3519
|
{
|
|
4163
3520
|
type: "confirm",
|
|
4164
3521
|
name: "confirm",
|
|
@@ -4179,7 +3536,7 @@ function registerAdvertiseCommands(program2) {
|
|
|
4179
3536
|
});
|
|
4180
3537
|
advertise.command("reject <advertiseId> <bidId>").description("Reject a vendor's bid").action(async (advertiseId, bidId) => {
|
|
4181
3538
|
try {
|
|
4182
|
-
const { confirm } = await
|
|
3539
|
+
const { confirm } = await inquirer7.prompt([
|
|
4183
3540
|
{
|
|
4184
3541
|
type: "confirm",
|
|
4185
3542
|
name: "confirm",
|
|
@@ -4198,7 +3555,7 @@ function registerAdvertiseCommands(program2) {
|
|
|
4198
3555
|
});
|
|
4199
3556
|
advertise.command("cancel <id>").description("Cancel an advertised request").action(async (id) => {
|
|
4200
3557
|
try {
|
|
4201
|
-
const { confirm } = await
|
|
3558
|
+
const { confirm } = await inquirer7.prompt([
|
|
4202
3559
|
{
|
|
4203
3560
|
type: "confirm",
|
|
4204
3561
|
name: "confirm",
|
|
@@ -4220,7 +3577,7 @@ function registerAdvertiseCommands(program2) {
|
|
|
4220
3577
|
// src/commands/support.ts
|
|
4221
3578
|
import chalk13 from "chalk";
|
|
4222
3579
|
import ora11 from "ora";
|
|
4223
|
-
import
|
|
3580
|
+
import inquirer8 from "inquirer";
|
|
4224
3581
|
var CATEGORY_CHOICES = [
|
|
4225
3582
|
{ name: "General question", value: "general" },
|
|
4226
3583
|
{ name: "Damaged item", value: "damaged" },
|
|
@@ -4254,7 +3611,7 @@ function registerSupportCommands(program2) {
|
|
|
4254
3611
|
const support = program2.command("support").description("Manage support tickets for orders");
|
|
4255
3612
|
support.command("create <orderId>").alias("new").description("Create a support ticket for an order").action(async (orderId) => {
|
|
4256
3613
|
try {
|
|
4257
|
-
const answers = await
|
|
3614
|
+
const answers = await inquirer8.prompt([
|
|
4258
3615
|
{
|
|
4259
3616
|
type: "select",
|
|
4260
3617
|
name: "category",
|
|
@@ -4385,7 +3742,7 @@ function registerSupportCommands(program2) {
|
|
|
4385
3742
|
});
|
|
4386
3743
|
support.command("reply <ticketId>").description("Reply to a support ticket").action(async (ticketId) => {
|
|
4387
3744
|
try {
|
|
4388
|
-
const { message } = await
|
|
3745
|
+
const { message } = await inquirer8.prompt([
|
|
4389
3746
|
{
|
|
4390
3747
|
type: "editor",
|
|
4391
3748
|
name: "message",
|
|
@@ -4410,7 +3767,7 @@ function registerSupportCommands(program2) {
|
|
|
4410
3767
|
});
|
|
4411
3768
|
support.command("close <ticketId>").description("Close a resolved ticket").action(async (ticketId) => {
|
|
4412
3769
|
try {
|
|
4413
|
-
const { confirm } = await
|
|
3770
|
+
const { confirm } = await inquirer8.prompt([
|
|
4414
3771
|
{
|
|
4415
3772
|
type: "confirm",
|
|
4416
3773
|
name: "confirm",
|
|
@@ -4432,7 +3789,7 @@ function registerSupportCommands(program2) {
|
|
|
4432
3789
|
// src/commands/feedback.ts
|
|
4433
3790
|
import chalk14 from "chalk";
|
|
4434
3791
|
import ora12 from "ora";
|
|
4435
|
-
import
|
|
3792
|
+
import inquirer9 from "inquirer";
|
|
4436
3793
|
var STATUS_COLORS4 = {
|
|
4437
3794
|
open: chalk14.green,
|
|
4438
3795
|
acknowledged: chalk14.cyan,
|
|
@@ -4465,7 +3822,7 @@ function registerFeedbackCommands(program2) {
|
|
|
4465
3822
|
if (!title || !description || !stepsToReproduce || !actualBehavior || !expectedBehavior) {
|
|
4466
3823
|
console.log(chalk14.bold("\n\u{1F41B} Report a Bug\n"));
|
|
4467
3824
|
console.log(chalk14.dim("Help us fix issues by describing what went wrong.\n"));
|
|
4468
|
-
const answers = await
|
|
3825
|
+
const answers = await inquirer9.prompt([
|
|
4469
3826
|
...!title ? [{
|
|
4470
3827
|
type: "input",
|
|
4471
3828
|
name: "title",
|
|
@@ -4537,7 +3894,7 @@ function registerFeedbackCommands(program2) {
|
|
|
4537
3894
|
if (!title || !description) {
|
|
4538
3895
|
console.log(chalk14.bold("\n\u{1F4A1} Suggest an Improvement\n"));
|
|
4539
3896
|
console.log(chalk14.dim("Tell us how we can make CLISHOP better.\n"));
|
|
4540
|
-
const answers = await
|
|
3897
|
+
const answers = await inquirer9.prompt([
|
|
4541
3898
|
...!title ? [{
|
|
4542
3899
|
type: "input",
|
|
4543
3900
|
name: "title",
|
|
@@ -4662,7 +4019,7 @@ import chalk15 from "chalk";
|
|
|
4662
4019
|
import { join } from "path";
|
|
4663
4020
|
import { homedir } from "os";
|
|
4664
4021
|
import { mkdirSync } from "fs";
|
|
4665
|
-
import
|
|
4022
|
+
import axios2 from "axios";
|
|
4666
4023
|
function registerDoctorCommand(program2) {
|
|
4667
4024
|
program2.command("doctor").description("Check system compatibility and auth status").action(async () => {
|
|
4668
4025
|
const checks = [];
|
|
@@ -4693,11 +4050,11 @@ function registerDoctorCommand(program2) {
|
|
|
4693
4050
|
checks.push({
|
|
4694
4051
|
name: "Authenticated",
|
|
4695
4052
|
ok: !!token,
|
|
4696
|
-
detail: token ? "Token present" : "Not
|
|
4053
|
+
detail: token ? "Token present" : "Not set up \u2014 run: clishop setup"
|
|
4697
4054
|
});
|
|
4698
4055
|
const apiUrl = getApiBaseUrl();
|
|
4699
4056
|
try {
|
|
4700
|
-
await
|
|
4057
|
+
await axios2.get(`${apiUrl}/health`, { timeout: 5e3 });
|
|
4701
4058
|
checks.push({ name: "API reachable", ok: true, detail: apiUrl });
|
|
4702
4059
|
} catch {
|
|
4703
4060
|
checks.push({
|
|
@@ -4717,8 +4074,12 @@ function registerDoctorCommand(program2) {
|
|
|
4717
4074
|
|
|
4718
4075
|
// src/index.ts
|
|
4719
4076
|
var program = new Command();
|
|
4720
|
-
program.name("clishop").version("1.
|
|
4721
|
-
chalk16.bold("CLISHOP") +
|
|
4077
|
+
program.name("clishop").version("1.4.1").description(
|
|
4078
|
+
chalk16.bold("CLISHOP") + ` \u2014 Order anything from your terminal.
|
|
4079
|
+
|
|
4080
|
+
Run 'clishop setup' to get started with a single payment link.
|
|
4081
|
+
Use agents to set safety limits, addresses, and payment methods.
|
|
4082
|
+
The "default" agent is used when no agent is specified.`
|
|
4722
4083
|
).option("--agent <name>", "Use a specific agent for this command").hook("preAction", (thisCommand) => {
|
|
4723
4084
|
const agentOpt = thisCommand.opts().agent;
|
|
4724
4085
|
if (agentOpt) {
|