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.
@@ -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
- storeAuthFromSetup,
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
- storeAuthFromSetup
13
- } from "./chunk-EAXPWOMT.js";
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
- import axios from "axios";
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
- } else if (process.platform === "darwin") {
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
- "Set up your CLISHOP account \u2014 links your payment method via a secure browser link"
824
- ).option("--email <email>", "Email address (skips prompt)").action(async (opts) => {
825
- await runSetupWizard(opts.email);
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.4.7"}`));
860
- console.log(chalk4.dim(` Build: ${"2026-04-04T18:17:20.412Z"}`));
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
- chalk4.dim(" Set up your account in one step. You'll get a link to")
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
- chalk4.dim(" By creating an account you agree to the CLISHOP")
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
- console.log(chalk4.dim(" Creating your account and payment link..."));
892
- let setupUrl;
893
- let deviceCode;
1127
+ let startResult;
894
1128
  try {
895
- const baseUrl2 = getApiBaseUrl();
896
- const res = await axios.post(`${baseUrl2}/auth/setup-link`, { email });
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
- const msg = error?.response?.data?.message || error.message;
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
- printSetupLink(
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(" If your terminal UI hides earlier output, use the plain-text URL above."));
1141
+ console.log(chalk4.dim(" You can resume later with the setup ID shown above."));
914
1142
  console.log();
915
- const baseUrl = getApiBaseUrl();
916
- const maxAttempts = 120;
917
- let completed = false;
918
- for (let i = 0; i < maxAttempts; i++) {
919
- await new Promise((r) => setTimeout(r, 5e3));
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
- chalk4.white(" clishop search <query> ") + chalk4.dim("Search for products")
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 axios2 from "axios";
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 axios2.get(`${apiUrl}/health`, { timeout: 5e3 });
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.4.7").description(
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
- await runSetupWizard();
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
- storeAuthFromSetup
7
- } from "./chunk-EAXPWOMT.js";
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: "Onboard a new user by creating their account and generating a Stripe payment setup link. The user must open this link in their browser to link their payment method. This is the ONLY step requiring human interaction. After the user completes the link, call setup_status with the returned deviceCode to get auth tokens. The agent can then use add_address to set up shipping autonomously.",
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 baseUrl = getApiBaseUrl();
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
- ...res.data,
13843
- message: "Give this link to your human to configure their payment method in the browser. Then call setup_status with the deviceCode to check when they're done."
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: "Poll the setup status after the user was given a payment link via the setup tool. Returns 'pending' while waiting, 'complete' with auth tokens when done, or 'expired' if timed out.",
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
- deviceCode: external_exports.string().describe("The deviceCode returned by the setup tool")
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
- const baseUrl = getApiBaseUrl();
13860
- const res = await axios.post(`${baseUrl}/auth/device/poll`, {
13861
- deviceCode: args.deviceCode
13862
- });
13863
- const data = res.data;
13864
- if (data.status === "complete" && data.token) {
13865
- await storeAuthFromSetup({
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
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clishop",
3
- "version": "1.4.7",
3
+ "version": "1.5.0",
4
4
  "mcpName": "io.github.StefDCL/clishop",
5
5
  "description": "CLISHOP — Order anything from your terminal",
6
6
  "main": "dist/index.js",