clishop 1.4.7 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-EAXPWOMT.js → chunk-EM4ZGZOU.js} +75 -1
- package/dist/index.js +299 -93
- package/dist/mcp.js +17 -26
- package/package.json +1 -1
|
@@ -141,6 +141,76 @@ async function storeAuthFromSetup(data) {
|
|
|
141
141
|
await storeRefreshToken(data.refreshToken);
|
|
142
142
|
await storeUserInfo(data.user);
|
|
143
143
|
}
|
|
144
|
+
async function postSetupRequest(path, body) {
|
|
145
|
+
const baseUrl = getApiBaseUrl();
|
|
146
|
+
try {
|
|
147
|
+
const res = await axios.post(`${baseUrl}${path}`, body);
|
|
148
|
+
return res.data;
|
|
149
|
+
} catch (error) {
|
|
150
|
+
if (error?.response?.data) {
|
|
151
|
+
return error.response.data;
|
|
152
|
+
}
|
|
153
|
+
throw error;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async function startSetupSession(email) {
|
|
157
|
+
const data = await postSetupRequest("/auth/setup-link", { email });
|
|
158
|
+
if (!data.setupUrl || !(data.setupId || data.deviceCode) || !data.expiresIn || !data.pollInterval) {
|
|
159
|
+
throw new Error(data?.message || "Failed to create setup session.");
|
|
160
|
+
}
|
|
161
|
+
const setupId = data.setupId || data.deviceCode;
|
|
162
|
+
const expiresAt = data.expiresAt || new Date(Date.now() + data.expiresIn * 1e3).toISOString();
|
|
163
|
+
return {
|
|
164
|
+
ok: true,
|
|
165
|
+
setup_id: setupId,
|
|
166
|
+
status: "pending_user_action",
|
|
167
|
+
next_action: "open_setup_url",
|
|
168
|
+
setup_url: data.setupUrl,
|
|
169
|
+
expires_at: expiresAt,
|
|
170
|
+
poll_after_seconds: data.pollInterval,
|
|
171
|
+
human_message: "Open this link to securely connect your payment method."
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
async function getSetupStatus(setupId) {
|
|
175
|
+
return postSetupRequest("/auth/setup/status", { setupId });
|
|
176
|
+
}
|
|
177
|
+
async function cancelSetupSession(setupId) {
|
|
178
|
+
return postSetupRequest("/auth/setup/cancel", { setupId });
|
|
179
|
+
}
|
|
180
|
+
async function claimSetupSession(setupId, { storeAuth = true } = {}) {
|
|
181
|
+
const data = await postSetupRequest("/auth/setup/claim", { setupId });
|
|
182
|
+
if (storeAuth && data.ok && data.token && data.refreshToken && data.user) {
|
|
183
|
+
await storeAuthFromSetup({
|
|
184
|
+
token: data.token,
|
|
185
|
+
refreshToken: data.refreshToken,
|
|
186
|
+
user: data.user
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
return data;
|
|
190
|
+
}
|
|
191
|
+
async function waitForSetupSession(setupId, { timeout = 3e5 } = {}) {
|
|
192
|
+
const deadline = Date.now() + timeout;
|
|
193
|
+
while (Date.now() < deadline) {
|
|
194
|
+
const status = await getSetupStatus(setupId);
|
|
195
|
+
if (status.status === "completed") {
|
|
196
|
+
return claimSetupSession(setupId);
|
|
197
|
+
}
|
|
198
|
+
if (status.status === "expired" || status.status === "cancelled" || status.status === "failed") {
|
|
199
|
+
return status;
|
|
200
|
+
}
|
|
201
|
+
const waitMs = Math.max(1, status.poll_after_seconds || 5) * 1e3;
|
|
202
|
+
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
ok: false,
|
|
206
|
+
setup_id: setupId,
|
|
207
|
+
status: "pending_user_action",
|
|
208
|
+
error: {
|
|
209
|
+
code: "human_action_required",
|
|
210
|
+
message: "Timed out waiting for payment setup to complete."
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
}
|
|
144
214
|
async function logout() {
|
|
145
215
|
const baseUrl = getApiBaseUrl();
|
|
146
216
|
const token = await getToken();
|
|
@@ -261,7 +331,11 @@ export {
|
|
|
261
331
|
getToken,
|
|
262
332
|
getUserInfo,
|
|
263
333
|
isLoggedIn,
|
|
264
|
-
|
|
334
|
+
startSetupSession,
|
|
335
|
+
getSetupStatus,
|
|
336
|
+
cancelSetupSession,
|
|
337
|
+
claimSetupSession,
|
|
338
|
+
waitForSetupSession,
|
|
265
339
|
logout,
|
|
266
340
|
getApiClient,
|
|
267
341
|
ensureAgentOnBackend,
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
cancelSetupSession,
|
|
4
|
+
claimSetupSession,
|
|
3
5
|
ensureAgentOnBackend,
|
|
4
6
|
getApiClient,
|
|
7
|
+
getSetupStatus,
|
|
5
8
|
getToken,
|
|
6
9
|
getUserInfo,
|
|
7
10
|
handleApiError,
|
|
@@ -9,8 +12,9 @@ import {
|
|
|
9
12
|
isLoggedIn,
|
|
10
13
|
logout,
|
|
11
14
|
resolveBackend,
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
startSetupSession,
|
|
16
|
+
waitForSetupSession
|
|
17
|
+
} from "./chunk-EM4ZGZOU.js";
|
|
14
18
|
import {
|
|
15
19
|
createAgent,
|
|
16
20
|
deleteAgent,
|
|
@@ -783,19 +787,19 @@ import chalk4 from "chalk";
|
|
|
783
787
|
import inquirer3 from "inquirer";
|
|
784
788
|
import open from "open";
|
|
785
789
|
import { execFileSync } from "child_process";
|
|
786
|
-
|
|
790
|
+
var DEFAULT_SETUP_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
787
791
|
async function openBrowser(url) {
|
|
788
792
|
try {
|
|
789
793
|
if (process.platform === "win32") {
|
|
790
794
|
execFileSync("cmd", ["/c", "start", "", url], { stdio: "ignore" });
|
|
791
795
|
return true;
|
|
792
|
-
}
|
|
796
|
+
}
|
|
797
|
+
if (process.platform === "darwin") {
|
|
793
798
|
execFileSync("open", [url], { stdio: "ignore" });
|
|
794
799
|
return true;
|
|
795
|
-
} else {
|
|
796
|
-
execFileSync("xdg-open", [url], { stdio: "ignore" });
|
|
797
|
-
return true;
|
|
798
800
|
}
|
|
801
|
+
execFileSync("xdg-open", [url], { stdio: "ignore" });
|
|
802
|
+
return true;
|
|
799
803
|
} catch {
|
|
800
804
|
}
|
|
801
805
|
try {
|
|
@@ -808,6 +812,29 @@ async function openBrowser(url) {
|
|
|
808
812
|
function divider(color = chalk4.cyan) {
|
|
809
813
|
console.log(" " + color("\u2500".repeat(48)));
|
|
810
814
|
}
|
|
815
|
+
function writeJson(payload) {
|
|
816
|
+
process.stdout.write(JSON.stringify(payload, null, 2) + "\n");
|
|
817
|
+
}
|
|
818
|
+
function isInteractiveSession() {
|
|
819
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
820
|
+
}
|
|
821
|
+
function isLikelyEmail(value) {
|
|
822
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value.trim());
|
|
823
|
+
}
|
|
824
|
+
function buildCliError(code, message, extra = {}) {
|
|
825
|
+
return {
|
|
826
|
+
ok: false,
|
|
827
|
+
error: {
|
|
828
|
+
code,
|
|
829
|
+
message,
|
|
830
|
+
...extra
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
function sanitizeSetupPayload(payload) {
|
|
835
|
+
const { token, refreshToken, user, ...rest } = payload;
|
|
836
|
+
return rest;
|
|
837
|
+
}
|
|
811
838
|
function printSetupLink(message, setupUrl) {
|
|
812
839
|
console.log();
|
|
813
840
|
console.log(chalk4.bold(` ${message}`));
|
|
@@ -818,14 +845,225 @@ function printSetupLink(message, setupUrl) {
|
|
|
818
845
|
console.log(" " + setupUrl);
|
|
819
846
|
console.log();
|
|
820
847
|
}
|
|
848
|
+
function printSetupStartResult(result) {
|
|
849
|
+
console.log();
|
|
850
|
+
console.log(chalk4.bold(" Setup session created."));
|
|
851
|
+
console.log(chalk4.dim(` Setup ID: ${result.setup_id}`));
|
|
852
|
+
console.log(chalk4.dim(` Expires: ${new Date(result.expires_at).toLocaleString()}`));
|
|
853
|
+
printSetupLink("Give this link to your human to configure the payment method:", result.setup_url);
|
|
854
|
+
console.log(chalk4.dim(" Check progress later with:"));
|
|
855
|
+
console.log(chalk4.white(` clishop setup status --setup-id ${result.setup_id}`));
|
|
856
|
+
console.log(chalk4.white(` clishop setup wait --setup-id ${result.setup_id}`));
|
|
857
|
+
console.log();
|
|
858
|
+
}
|
|
859
|
+
function printSetupStatusResult(result) {
|
|
860
|
+
console.log();
|
|
861
|
+
if (!result.ok) {
|
|
862
|
+
console.log(chalk4.red(` \u2717 ${result.error?.message || "Setup failed."}`));
|
|
863
|
+
if (result.setup_id) {
|
|
864
|
+
console.log(chalk4.dim(` Setup ID: ${result.setup_id}`));
|
|
865
|
+
}
|
|
866
|
+
console.log();
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
switch (result.status) {
|
|
870
|
+
case "pending_user_action":
|
|
871
|
+
console.log(chalk4.yellow(" Waiting for the human to complete payment setup."));
|
|
872
|
+
console.log(chalk4.dim(` Setup ID: ${result.setup_id}`));
|
|
873
|
+
if (result.expires_at) {
|
|
874
|
+
console.log(chalk4.dim(` Expires: ${new Date(result.expires_at).toLocaleString()}`));
|
|
875
|
+
}
|
|
876
|
+
console.log();
|
|
877
|
+
break;
|
|
878
|
+
case "completed":
|
|
879
|
+
console.log(chalk4.green(" \u2713 Payment linked and account activated!"));
|
|
880
|
+
console.log(chalk4.dim(` Setup ID: ${result.setup_id}`));
|
|
881
|
+
if (result.account_id) {
|
|
882
|
+
console.log(chalk4.dim(` Account: ${result.account_id}`));
|
|
883
|
+
}
|
|
884
|
+
console.log();
|
|
885
|
+
break;
|
|
886
|
+
case "cancelled":
|
|
887
|
+
console.log(chalk4.yellow(" Setup session cancelled."));
|
|
888
|
+
console.log(chalk4.dim(` Setup ID: ${result.setup_id}`));
|
|
889
|
+
console.log();
|
|
890
|
+
break;
|
|
891
|
+
case "expired":
|
|
892
|
+
console.log(chalk4.red(" Setup session expired."));
|
|
893
|
+
console.log(chalk4.dim(` Setup ID: ${result.setup_id}`));
|
|
894
|
+
console.log();
|
|
895
|
+
break;
|
|
896
|
+
case "processing":
|
|
897
|
+
console.log(chalk4.dim(" Setup is being processed."));
|
|
898
|
+
console.log(chalk4.dim(` Setup ID: ${result.setup_id}`));
|
|
899
|
+
console.log();
|
|
900
|
+
break;
|
|
901
|
+
default:
|
|
902
|
+
console.log(chalk4.red(" Setup failed."));
|
|
903
|
+
if (result.setup_id) {
|
|
904
|
+
console.log(chalk4.dim(` Setup ID: ${result.setup_id}`));
|
|
905
|
+
}
|
|
906
|
+
console.log();
|
|
907
|
+
break;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
async function activateCompletedSetup(result) {
|
|
911
|
+
if (!result.ok || result.status !== "completed" || !result.setup_id) {
|
|
912
|
+
return result;
|
|
913
|
+
}
|
|
914
|
+
const config = getConfig();
|
|
915
|
+
const currentUser = await getUserInfo();
|
|
916
|
+
if (currentUser && (!result.account_id || currentUser.id === result.account_id)) {
|
|
917
|
+
config.set("setupCompleted", true);
|
|
918
|
+
return result;
|
|
919
|
+
}
|
|
920
|
+
const claimed = await claimSetupSession(result.setup_id);
|
|
921
|
+
if (claimed.ok) {
|
|
922
|
+
config.set("setupCompleted", true);
|
|
923
|
+
}
|
|
924
|
+
return claimed;
|
|
925
|
+
}
|
|
926
|
+
async function runSetupStartCommand(email, json = false) {
|
|
927
|
+
const normalizedEmail = email.trim();
|
|
928
|
+
if (!isLikelyEmail(normalizedEmail)) {
|
|
929
|
+
const payload = buildCliError("invalid_email", "A valid email address is required.");
|
|
930
|
+
if (json) {
|
|
931
|
+
writeJson(payload);
|
|
932
|
+
} else {
|
|
933
|
+
console.error(chalk4.red(`
|
|
934
|
+
\u2717 ${payload.error.message}
|
|
935
|
+
`));
|
|
936
|
+
}
|
|
937
|
+
process.exitCode = 1;
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
try {
|
|
941
|
+
const result = await startSetupSession(normalizedEmail);
|
|
942
|
+
if (json) {
|
|
943
|
+
writeJson(sanitizeSetupPayload(result));
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
printSetupStartResult(result);
|
|
947
|
+
} catch (error) {
|
|
948
|
+
const payload = buildCliError("internal_error", error?.message || "Failed to create setup session.");
|
|
949
|
+
if (json) {
|
|
950
|
+
writeJson(payload);
|
|
951
|
+
} else {
|
|
952
|
+
console.error(chalk4.red(`
|
|
953
|
+
\u2717 ${payload.error.message}
|
|
954
|
+
`));
|
|
955
|
+
}
|
|
956
|
+
process.exitCode = 1;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
async function runSetupStatusCommand(setupId, json = false) {
|
|
960
|
+
try {
|
|
961
|
+
let result = await getSetupStatus(setupId);
|
|
962
|
+
result = await activateCompletedSetup(result);
|
|
963
|
+
if (json) {
|
|
964
|
+
writeJson(sanitizeSetupPayload(result));
|
|
965
|
+
} else {
|
|
966
|
+
printSetupStatusResult(result);
|
|
967
|
+
}
|
|
968
|
+
if (!result.ok) {
|
|
969
|
+
process.exitCode = 1;
|
|
970
|
+
}
|
|
971
|
+
} catch (error) {
|
|
972
|
+
const payload = buildCliError("internal_error", error?.message || "Failed to fetch setup status.");
|
|
973
|
+
if (json) {
|
|
974
|
+
writeJson(payload);
|
|
975
|
+
} else {
|
|
976
|
+
console.error(chalk4.red(`
|
|
977
|
+
\u2717 ${payload.error.message}
|
|
978
|
+
`));
|
|
979
|
+
}
|
|
980
|
+
process.exitCode = 1;
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
async function runSetupCancelCommand(setupId, json = false) {
|
|
984
|
+
try {
|
|
985
|
+
const result = await cancelSetupSession(setupId);
|
|
986
|
+
if (json) {
|
|
987
|
+
writeJson(sanitizeSetupPayload(result));
|
|
988
|
+
} else {
|
|
989
|
+
printSetupStatusResult(result);
|
|
990
|
+
}
|
|
991
|
+
if (!result.ok) {
|
|
992
|
+
process.exitCode = 1;
|
|
993
|
+
}
|
|
994
|
+
} catch (error) {
|
|
995
|
+
const payload = buildCliError("internal_error", error?.message || "Failed to cancel setup session.");
|
|
996
|
+
if (json) {
|
|
997
|
+
writeJson(payload);
|
|
998
|
+
} else {
|
|
999
|
+
console.error(chalk4.red(`
|
|
1000
|
+
\u2717 ${payload.error.message}
|
|
1001
|
+
`));
|
|
1002
|
+
}
|
|
1003
|
+
process.exitCode = 1;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
async function runSetupWaitCommand(setupId, timeoutSeconds, json = false) {
|
|
1007
|
+
try {
|
|
1008
|
+
if (!json) {
|
|
1009
|
+
console.log();
|
|
1010
|
+
console.log(chalk4.dim(` Waiting up to ${timeoutSeconds}s for payment setup to complete...`));
|
|
1011
|
+
console.log(chalk4.dim(` Setup ID: ${setupId}`));
|
|
1012
|
+
console.log();
|
|
1013
|
+
}
|
|
1014
|
+
const result = await waitForSetupSession(setupId, {
|
|
1015
|
+
timeout: timeoutSeconds * 1e3
|
|
1016
|
+
});
|
|
1017
|
+
if (result.ok && result.status === "completed") {
|
|
1018
|
+
getConfig().set("setupCompleted", true);
|
|
1019
|
+
}
|
|
1020
|
+
if (json) {
|
|
1021
|
+
writeJson(sanitizeSetupPayload(result));
|
|
1022
|
+
} else {
|
|
1023
|
+
printSetupStatusResult(result);
|
|
1024
|
+
}
|
|
1025
|
+
if (!result.ok) {
|
|
1026
|
+
process.exitCode = 1;
|
|
1027
|
+
}
|
|
1028
|
+
} catch (error) {
|
|
1029
|
+
const payload = buildCliError("internal_error", error?.message || "Failed while waiting for setup.");
|
|
1030
|
+
if (json) {
|
|
1031
|
+
writeJson(payload);
|
|
1032
|
+
} else {
|
|
1033
|
+
console.error(chalk4.red(`
|
|
1034
|
+
\u2717 ${payload.error.message}
|
|
1035
|
+
`));
|
|
1036
|
+
}
|
|
1037
|
+
process.exitCode = 1;
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
821
1040
|
function registerSetupCommand(program2) {
|
|
822
|
-
program2.command("setup").description(
|
|
823
|
-
|
|
824
|
-
)
|
|
825
|
-
|
|
1041
|
+
const setup = program2.command("setup").description("Set up your CLISHOP account or manage setup sessions").argument("[email]", "Email address for the human-friendly wrapper").action(async (email) => {
|
|
1042
|
+
await runSetupWizard(email);
|
|
1043
|
+
});
|
|
1044
|
+
setup.command("start").description("Create a setup session and return immediately").requiredOption("--email <email>", "Email address").option("--json", "Output machine-readable JSON").action(async (opts) => {
|
|
1045
|
+
await runSetupStartCommand(opts.email, opts.json);
|
|
1046
|
+
});
|
|
1047
|
+
setup.command("status").description("Check the status of a setup session").requiredOption("--setup-id <setupId>", "Setup session ID").option("--json", "Output machine-readable JSON").action(async (opts) => {
|
|
1048
|
+
await runSetupStatusCommand(opts.setupId, opts.json);
|
|
1049
|
+
});
|
|
1050
|
+
setup.command("cancel").description("Cancel a setup session").requiredOption("--setup-id <setupId>", "Setup session ID").option("--json", "Output machine-readable JSON").action(async (opts) => {
|
|
1051
|
+
await runSetupCancelCommand(opts.setupId, opts.json);
|
|
1052
|
+
});
|
|
1053
|
+
setup.command("wait").description("Wait for setup completion until timeout").requiredOption("--setup-id <setupId>", "Setup session ID").option("--timeout <seconds>", "Timeout in seconds", (value) => parseInt(value, 10), 300).option("--json", "Output machine-readable JSON").action(async (opts) => {
|
|
1054
|
+
await runSetupWaitCommand(opts.setupId, opts.timeout, opts.json);
|
|
826
1055
|
});
|
|
827
1056
|
}
|
|
828
|
-
async function runSetupWizard(emailArg) {
|
|
1057
|
+
async function runSetupWizard(emailArg, { json = false } = {}) {
|
|
1058
|
+
if (json) {
|
|
1059
|
+
if (!emailArg) {
|
|
1060
|
+
writeJson(buildCliError("invalid_email", "Use --email when running setup in JSON mode."));
|
|
1061
|
+
process.exitCode = 1;
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
await runSetupStartCommand(emailArg, true);
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
829
1067
|
const config = getConfig();
|
|
830
1068
|
const loggedIn = await isLoggedIn();
|
|
831
1069
|
if (loggedIn) {
|
|
@@ -856,94 +1094,61 @@ async function runSetupWizard(emailArg) {
|
|
|
856
1094
|
console.log();
|
|
857
1095
|
console.log(chalk4.bold.cyan(" W E L C O M E T O C L I S H O P"));
|
|
858
1096
|
console.log(chalk4.dim(" Order anything from your terminal."));
|
|
859
|
-
console.log(chalk4.dim(` npm: v${"1.
|
|
860
|
-
console.log(chalk4.dim(` Build: ${"2026-04-
|
|
1097
|
+
console.log(chalk4.dim(` npm: v${"1.5.0"}`));
|
|
1098
|
+
console.log(chalk4.dim(` Build: ${"2026-04-04T19:19:52.565Z"}`));
|
|
861
1099
|
console.log();
|
|
862
1100
|
divider(chalk4.cyan);
|
|
863
1101
|
console.log();
|
|
864
|
-
console.log(
|
|
865
|
-
|
|
866
|
-
);
|
|
867
|
-
console.log(
|
|
868
|
-
chalk4.dim(" securely link your payment method in the browser.")
|
|
869
|
-
);
|
|
870
|
-
console.log(
|
|
871
|
-
chalk4.dim(" Your AI agent can then add addresses and place orders for you.")
|
|
872
|
-
);
|
|
1102
|
+
console.log(chalk4.dim(" Set up your account in one step. You'll get a link to"));
|
|
1103
|
+
console.log(chalk4.dim(" securely link your payment method in the browser."));
|
|
1104
|
+
console.log(chalk4.dim(" Your AI agent can then add addresses and place orders for you."));
|
|
873
1105
|
console.log();
|
|
874
|
-
console.log(
|
|
875
|
-
|
|
876
|
-
);
|
|
877
|
-
console.log(
|
|
878
|
-
chalk4.dim(" Terms & Conditions: ") + chalk4.cyan.underline("https://clishop.ai/terms")
|
|
879
|
-
);
|
|
880
|
-
console.log(
|
|
881
|
-
chalk4.dim(" Privacy Policy: ") + chalk4.cyan.underline("https://clishop.ai/privacy")
|
|
882
|
-
);
|
|
1106
|
+
console.log(chalk4.dim(" By creating an account you agree to the CLISHOP"));
|
|
1107
|
+
console.log(chalk4.dim(" Terms & Conditions: ") + chalk4.cyan.underline("https://clishop.ai/terms"));
|
|
1108
|
+
console.log(chalk4.dim(" Privacy Policy: ") + chalk4.cyan.underline("https://clishop.ai/privacy"));
|
|
883
1109
|
console.log();
|
|
884
|
-
let email = emailArg;
|
|
1110
|
+
let email = emailArg?.trim();
|
|
885
1111
|
if (!email) {
|
|
1112
|
+
if (!isInteractiveSession()) {
|
|
1113
|
+
console.error(chalk4.red("\n\u2717 Email is required in non-interactive mode. Use: clishop setup start --email <email> --json\n"));
|
|
1114
|
+
process.exitCode = 1;
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
886
1117
|
const answers = await inquirer3.prompt([
|
|
887
1118
|
{ type: "input", name: "email", message: "Email:" }
|
|
888
1119
|
]);
|
|
889
|
-
email = answers.email;
|
|
1120
|
+
email = answers.email?.trim();
|
|
1121
|
+
}
|
|
1122
|
+
if (!email || !isLikelyEmail(email)) {
|
|
1123
|
+
console.error(chalk4.red("\n\u2717 A valid email address is required.\n"));
|
|
1124
|
+
process.exitCode = 1;
|
|
1125
|
+
return;
|
|
890
1126
|
}
|
|
891
|
-
|
|
892
|
-
let setupUrl;
|
|
893
|
-
let deviceCode;
|
|
1127
|
+
let startResult;
|
|
894
1128
|
try {
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
setupUrl = res.data.setupUrl;
|
|
898
|
-
deviceCode = res.data.deviceCode;
|
|
1129
|
+
console.log(chalk4.dim(" Creating your account and payment link..."));
|
|
1130
|
+
startResult = await startSetupSession(email);
|
|
899
1131
|
} catch (error) {
|
|
900
|
-
|
|
901
|
-
console.log(chalk4.red(` \u2717 Setup failed: ${msg}`));
|
|
1132
|
+
console.log(chalk4.red(` \u2717 Setup failed: ${error?.message || "Unknown error"}`));
|
|
902
1133
|
console.log();
|
|
903
1134
|
console.log(chalk4.dim(" You can try again with: ") + chalk4.white("clishop setup"));
|
|
904
1135
|
console.log();
|
|
905
1136
|
process.exitCode = 1;
|
|
906
1137
|
return;
|
|
907
1138
|
}
|
|
908
|
-
|
|
909
|
-
"Give this link to your human to configure the payment method:",
|
|
910
|
-
setupUrl
|
|
911
|
-
);
|
|
1139
|
+
printSetupStartResult(startResult);
|
|
912
1140
|
console.log(chalk4.dim(" Waiting for you to complete payment setup..."));
|
|
913
|
-
console.log(chalk4.dim("
|
|
1141
|
+
console.log(chalk4.dim(" You can resume later with the setup ID shown above."));
|
|
914
1142
|
console.log();
|
|
915
|
-
const
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
try {
|
|
921
|
-
const res = await axios.post(`${baseUrl}/auth/device/poll`, { deviceCode });
|
|
922
|
-
const data = res.data;
|
|
923
|
-
if (data.status === "complete" && data.token && data.refreshToken && data.user) {
|
|
924
|
-
await storeAuthFromSetup({
|
|
925
|
-
token: data.token,
|
|
926
|
-
refreshToken: data.refreshToken,
|
|
927
|
-
user: data.user
|
|
928
|
-
});
|
|
929
|
-
config.set("setupCompleted", true);
|
|
930
|
-
console.log(chalk4.green(" \u2713 Payment linked and account activated!"));
|
|
931
|
-
completed = true;
|
|
932
|
-
break;
|
|
933
|
-
}
|
|
934
|
-
if (data.status === "expired") {
|
|
935
|
-
console.log(chalk4.red(" Setup link expired. Run ") + chalk4.white("clishop setup") + chalk4.red(" to try again."));
|
|
936
|
-
process.exitCode = 1;
|
|
937
|
-
return;
|
|
938
|
-
}
|
|
939
|
-
} catch {
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
if (!completed) {
|
|
943
|
-
console.log(chalk4.red(" Timed out waiting for setup. Run ") + chalk4.white("clishop setup") + chalk4.red(" to try again."));
|
|
1143
|
+
const result = await waitForSetupSession(startResult.setup_id, {
|
|
1144
|
+
timeout: DEFAULT_SETUP_TIMEOUT_MS
|
|
1145
|
+
});
|
|
1146
|
+
if (!result.ok || result.status !== "completed") {
|
|
1147
|
+
printSetupStatusResult(result);
|
|
944
1148
|
process.exitCode = 1;
|
|
945
1149
|
return;
|
|
946
1150
|
}
|
|
1151
|
+
config.set("setupCompleted", true);
|
|
947
1152
|
console.log();
|
|
948
1153
|
divider(chalk4.green);
|
|
949
1154
|
console.log();
|
|
@@ -955,18 +1160,10 @@ async function runSetupWizard(emailArg) {
|
|
|
955
1160
|
console.log();
|
|
956
1161
|
console.log(chalk4.dim(" Here are some commands to get you started:"));
|
|
957
1162
|
console.log();
|
|
958
|
-
console.log(
|
|
959
|
-
|
|
960
|
-
);
|
|
961
|
-
console.log(
|
|
962
|
-
chalk4.white(" clishop buy <id> ") + chalk4.dim("Quick-buy a product")
|
|
963
|
-
);
|
|
964
|
-
console.log(
|
|
965
|
-
chalk4.white(" clishop order list ") + chalk4.dim("View your orders")
|
|
966
|
-
);
|
|
967
|
-
console.log(
|
|
968
|
-
chalk4.white(" clishop --help ") + chalk4.dim("See all commands")
|
|
969
|
-
);
|
|
1163
|
+
console.log(chalk4.white(" clishop search <query> ") + chalk4.dim("Search for products"));
|
|
1164
|
+
console.log(chalk4.white(" clishop buy <id> ") + chalk4.dim("Quick-buy a product"));
|
|
1165
|
+
console.log(chalk4.white(" clishop order list ") + chalk4.dim("View your orders"));
|
|
1166
|
+
console.log(chalk4.white(" clishop --help ") + chalk4.dim("See all commands"));
|
|
970
1167
|
console.log();
|
|
971
1168
|
divider(chalk4.green);
|
|
972
1169
|
console.log();
|
|
@@ -4036,7 +4233,7 @@ import chalk15 from "chalk";
|
|
|
4036
4233
|
import { join } from "path";
|
|
4037
4234
|
import { homedir } from "os";
|
|
4038
4235
|
import { mkdirSync } from "fs";
|
|
4039
|
-
import
|
|
4236
|
+
import axios from "axios";
|
|
4040
4237
|
function registerDoctorCommand(program2) {
|
|
4041
4238
|
program2.command("doctor").description("Check system compatibility and auth status").action(async () => {
|
|
4042
4239
|
const checks = [];
|
|
@@ -4071,7 +4268,7 @@ function registerDoctorCommand(program2) {
|
|
|
4071
4268
|
});
|
|
4072
4269
|
const apiUrl = getApiBaseUrl();
|
|
4073
4270
|
try {
|
|
4074
|
-
await
|
|
4271
|
+
await axios.get(`${apiUrl}/health`, { timeout: 5e3 });
|
|
4075
4272
|
checks.push({ name: "API reachable", ok: true, detail: apiUrl });
|
|
4076
4273
|
} catch {
|
|
4077
4274
|
checks.push({
|
|
@@ -4091,7 +4288,7 @@ function registerDoctorCommand(program2) {
|
|
|
4091
4288
|
|
|
4092
4289
|
// src/index.ts
|
|
4093
4290
|
var program = new Command();
|
|
4094
|
-
program.name("clishop").version("1.
|
|
4291
|
+
program.name("clishop").version("1.5.0").description(
|
|
4095
4292
|
chalk16.bold("CLISHOP") + ` \u2014 Order anything from your terminal.
|
|
4096
4293
|
|
|
4097
4294
|
Run 'clishop setup' to get started with a single payment link.
|
|
@@ -4133,7 +4330,16 @@ async function main() {
|
|
|
4133
4330
|
if (!hasSubcommand) {
|
|
4134
4331
|
const config = getConfig();
|
|
4135
4332
|
if (!config.get("setupCompleted")) {
|
|
4136
|
-
|
|
4333
|
+
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
4334
|
+
await runSetupWizard();
|
|
4335
|
+
return;
|
|
4336
|
+
}
|
|
4337
|
+
console.error(
|
|
4338
|
+
chalk16.yellow(
|
|
4339
|
+
"CLISHOP setup is incomplete. Run 'clishop setup start --email <email> --json' in non-interactive environments."
|
|
4340
|
+
)
|
|
4341
|
+
);
|
|
4342
|
+
process.exit(1);
|
|
4137
4343
|
return;
|
|
4138
4344
|
}
|
|
4139
4345
|
}
|
package/dist/mcp.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
claimSetupSession,
|
|
3
4
|
getApiClient,
|
|
5
|
+
getSetupStatus,
|
|
4
6
|
getUserInfo,
|
|
5
7
|
isLoggedIn,
|
|
6
|
-
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
startSetupSession
|
|
9
|
+
} from "./chunk-EM4ZGZOU.js";
|
|
8
10
|
import {
|
|
9
11
|
__export,
|
|
10
12
|
getActiveAgent,
|
|
11
|
-
getApiBaseUrl,
|
|
12
13
|
getConfig
|
|
13
14
|
} from "./chunk-X3H7SYR4.js";
|
|
14
15
|
|
|
@@ -13785,7 +13786,6 @@ function date4(params) {
|
|
|
13785
13786
|
config(en_default());
|
|
13786
13787
|
|
|
13787
13788
|
// src/mcp.ts
|
|
13788
|
-
import axios from "axios";
|
|
13789
13789
|
function formatPrice(cents, currency) {
|
|
13790
13790
|
return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(
|
|
13791
13791
|
cents / 100
|
|
@@ -13823,7 +13823,7 @@ var server = new McpServer(
|
|
|
13823
13823
|
);
|
|
13824
13824
|
server.registerTool("setup", {
|
|
13825
13825
|
title: "Setup",
|
|
13826
|
-
description: "
|
|
13826
|
+
description: "Start a resumable setup session. Returns a setup URL for the human and a setup_id for the agent to check later. After the human completes the link, call setup_status with the returned setup_id.",
|
|
13827
13827
|
inputSchema: {
|
|
13828
13828
|
email: external_exports.string().email().describe("User's email address")
|
|
13829
13829
|
},
|
|
@@ -13834,21 +13834,18 @@ server.registerTool("setup", {
|
|
|
13834
13834
|
}
|
|
13835
13835
|
}, async (args) => {
|
|
13836
13836
|
return safeCall(async () => {
|
|
13837
|
-
const
|
|
13838
|
-
const res = await axios.post(`${baseUrl}/auth/setup-link`, {
|
|
13839
|
-
email: args.email
|
|
13840
|
-
});
|
|
13837
|
+
const data = await startSetupSession(args.email);
|
|
13841
13838
|
return {
|
|
13842
|
-
...
|
|
13843
|
-
message: "Give this link to your human to configure their payment method in the browser. Then call setup_status with the
|
|
13839
|
+
...data,
|
|
13840
|
+
message: "Give this link to your human to configure their payment method in the browser. Then call setup_status with the setup_id to check when they're done."
|
|
13844
13841
|
};
|
|
13845
13842
|
});
|
|
13846
13843
|
});
|
|
13847
13844
|
server.registerTool("setup_status", {
|
|
13848
13845
|
title: "Setup Status",
|
|
13849
|
-
description: "
|
|
13846
|
+
description: "Check the current setup state using the setup_id returned by the setup tool. If setup is complete, auth is stored locally so later CLISHOP calls can proceed.",
|
|
13850
13847
|
inputSchema: {
|
|
13851
|
-
|
|
13848
|
+
setupId: external_exports.string().describe("The setup_id returned by the setup tool")
|
|
13852
13849
|
},
|
|
13853
13850
|
annotations: {
|
|
13854
13851
|
title: "Setup Status",
|
|
@@ -13856,19 +13853,13 @@ server.registerTool("setup_status", {
|
|
|
13856
13853
|
}
|
|
13857
13854
|
}, async (args) => {
|
|
13858
13855
|
return safeCall(async () => {
|
|
13859
|
-
|
|
13860
|
-
|
|
13861
|
-
|
|
13862
|
-
|
|
13863
|
-
|
|
13864
|
-
|
|
13865
|
-
|
|
13866
|
-
token: data.token,
|
|
13867
|
-
refreshToken: data.refreshToken,
|
|
13868
|
-
user: data.user
|
|
13869
|
-
});
|
|
13870
|
-
const config2 = getConfig();
|
|
13871
|
-
config2.set("setupCompleted", true);
|
|
13856
|
+
let data = await getSetupStatus(args.setupId);
|
|
13857
|
+
if (data.ok && data.status === "completed") {
|
|
13858
|
+
data = await claimSetupSession(args.setupId);
|
|
13859
|
+
if (data.ok) {
|
|
13860
|
+
const config2 = getConfig();
|
|
13861
|
+
config2.set("setupCompleted", true);
|
|
13862
|
+
}
|
|
13872
13863
|
}
|
|
13873
13864
|
return data;
|
|
13874
13865
|
});
|