clishop 0.2.1 → 0.3.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/README.md CHANGED
@@ -16,6 +16,7 @@
16
16
  ## Works with
17
17
 
18
18
  <p>
19
+ <img alt="VS Code" src="https://img.shields.io/badge/VS%20Code-Copilot-007ACC?style=for-the-badge&logo=visualstudiocode&logoColor=white" />
19
20
  <img alt="Claude" src="https://img.shields.io/badge/Claude-Supported-7C3AED?style=for-the-badge&logo=anthropic&logoColor=white" />
20
21
  <img alt="GPT" src="https://img.shields.io/badge/GPT-Supported-10A37F?style=for-the-badge&logo=openai&logoColor=white" />
21
22
  <img alt="Gemini" src="https://img.shields.io/badge/Gemini-Supported-4285F4?style=for-the-badge&logo=googlegemini&logoColor=white" />
@@ -32,15 +33,56 @@ Built for the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) e
32
33
 
33
34
  ## MCP Server
34
35
 
35
- CLISHOP ships as a native MCP server. Every Claude Desktop, Cursor, Windsurf, or other MCP-compatible client gets access to 19 shopping tools out of the box.
36
+ CLISHOP ships as a native MCP server. VS Code (GitHub Copilot), Claude Desktop, Cursor, Windsurf, and any MCP-compatible client gets access to 19 shopping tools out of the box.
36
37
 
37
- ### Claude Desktop
38
+ Install globally and run the dedicated binary:
38
39
 
39
- Add to `claude_desktop_config.json`:
40
+ ```bash
41
+ npm install -g clishop
42
+ clishop-mcp
43
+ ```
44
+
45
+ Or run without installing:
46
+
47
+ ```bash
48
+ npx -y clishop --mcp
49
+ ```
50
+
51
+ ### VS Code (GitHub Copilot)
52
+
53
+ Add to `.vscode/mcp.json` in your workspace:
40
54
 
41
55
  ```json
42
56
  {
43
- "mcpServers": {
57
+ "servers": {
58
+ "clishop": {
59
+ "command": "clishop-mcp",
60
+ "args": []
61
+ }
62
+ }
63
+ }
64
+ ```
65
+
66
+ Or add to your VS Code `settings.json`:
67
+
68
+ ```json
69
+ {
70
+ "mcp": {
71
+ "servers": {
72
+ "clishop": {
73
+ "command": "clishop-mcp",
74
+ "args": []
75
+ }
76
+ }
77
+ }
78
+ }
79
+ ```
80
+
81
+ If you don't have clishop installed globally, use npx instead:
82
+
83
+ ```json
84
+ {
85
+ "servers": {
44
86
  "clishop": {
45
87
  "command": "npx",
46
88
  "args": ["-y", "clishop", "--mcp"]
@@ -49,7 +91,9 @@ Add to `claude_desktop_config.json`:
49
91
  }
50
92
  ```
51
93
 
52
- Or if installed globally:
94
+ ### Claude Desktop
95
+
96
+ Add to `claude_desktop_config.json`:
53
97
 
54
98
  ```json
55
99
  {
@@ -61,6 +105,19 @@ Or if installed globally:
61
105
  }
62
106
  ```
63
107
 
108
+ Or if not installed globally:
109
+
110
+ ```json
111
+ {
112
+ "mcpServers": {
113
+ "clishop": {
114
+ "command": "npx",
115
+ "args": ["-y", "clishop", "--mcp"]
116
+ }
117
+ }
118
+ }
119
+ ```
120
+
64
121
  ### Cursor
65
122
 
66
123
  Add to `.cursor/mcp.json`:
@@ -69,8 +126,7 @@ Add to `.cursor/mcp.json`:
69
126
  {
70
127
  "mcpServers": {
71
128
  "clishop": {
72
- "command": "npx",
73
- "args": ["-y", "clishop", "--mcp"]
129
+ "command": "clishop-mcp"
74
130
  }
75
131
  }
76
132
  }
@@ -84,8 +140,7 @@ Add to `~/.windsurf/mcp.json`:
84
140
  {
85
141
  "mcpServers": {
86
142
  "clishop": {
87
- "command": "npx",
88
- "args": ["-y", "clishop", "--mcp"]
143
+ "command": "clishop-mcp"
89
144
  }
90
145
  }
91
146
  }
@@ -70,9 +70,13 @@ async function login(email, password) {
70
70
  await storeUserInfo(user);
71
71
  return user;
72
72
  }
73
- async function register(email, password, name) {
73
+ async function register(email, password, name, monthlySpendingLimitInCents) {
74
74
  const baseUrl = getApiBaseUrl();
75
- const res = await axios.post(`${baseUrl}/auth/register`, { email, password, name });
75
+ const body = { email, password, name };
76
+ if (monthlySpendingLimitInCents !== void 0) {
77
+ body.monthlySpendingLimitInCents = monthlySpendingLimitInCents;
78
+ }
79
+ const res = await axios.post(`${baseUrl}/auth/register`, body);
76
80
  const { token, refreshToken, user } = assertAuthResponse(res.data);
77
81
  await storeToken(token);
78
82
  if (refreshToken) await storeRefreshToken(refreshToken);
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  login,
8
8
  logout,
9
9
  register
10
- } from "./chunk-EGTXN73P.js";
10
+ } from "./chunk-RHBOI27D.js";
11
11
  import {
12
12
  createAgent,
13
13
  deleteAgent,
@@ -154,12 +154,25 @@ function printAgent(agent, isActive) {
154
154
  console.log(` Default payment: ${agent.defaultPaymentMethodId || chalk2.dim("not set")}`);
155
155
  console.log();
156
156
  }
157
+ async function printMonthlyLimit() {
158
+ try {
159
+ const api = getApiClient();
160
+ const res = await api.get("/spending-limit");
161
+ const limit = res.data.monthlySpendingLimitInCents;
162
+ console.log(
163
+ chalk2.dim(" Monthly spending limit: ") + chalk2.bold.white(`$${(limit / 100).toFixed(0)}/month`) + chalk2.dim(" (change at https://clishop.ai/agents)")
164
+ );
165
+ console.log();
166
+ } catch {
167
+ }
168
+ }
157
169
  function registerAgentCommands(program2) {
158
170
  const agent = program2.command("agent").description("Manage agents (safety profiles for ordering)");
159
- agent.command("list").alias("ls").description("List all agents").action(() => {
171
+ agent.command("list").alias("ls").description("List all agents").action(async () => {
160
172
  const agents = listAgents();
161
173
  const active = getConfig().get("activeAgent");
162
174
  console.log(chalk2.bold("\nAgents:\n"));
175
+ await printMonthlyLimit();
163
176
  for (const a of agents) {
164
177
  printAgent(a, a.name === active);
165
178
  }
@@ -213,6 +226,16 @@ function registerAgentCommands(program2) {
213
226
  process.exitCode = 1;
214
227
  return;
215
228
  }
229
+ console.log();
230
+ console.log(
231
+ chalk2.dim(
232
+ " Note: To change the monthly spending limit, run:"
233
+ )
234
+ );
235
+ console.log(
236
+ chalk2.dim(" ") + chalk2.white("clishop agent spending-limit <amount>")
237
+ );
238
+ console.log();
216
239
  const answers = await inquirer2.prompt([
217
240
  {
218
241
  type: "number",
@@ -250,6 +273,79 @@ function registerAgentCommands(program2) {
250
273
  `));
251
274
  printAgent(updated, agentName === getConfig().get("activeAgent"));
252
275
  });
276
+ agent.command("spending-limit [amount]").alias("limit").description("View or change your monthly spending limit").action(async (amount) => {
277
+ const api = getApiClient();
278
+ let current;
279
+ try {
280
+ const res = await api.get("/spending-limit");
281
+ current = res.data;
282
+ } catch (error) {
283
+ console.error(chalk2.red(`
284
+ \u2717 ${error?.response?.data?.message || error.message}`));
285
+ process.exitCode = 1;
286
+ return;
287
+ }
288
+ const currentDollars = (current.monthlySpendingLimitInCents / 100).toFixed(0);
289
+ console.log(
290
+ chalk2.bold(`
291
+ Monthly spending limit: `) + chalk2.bold.cyan(`$${currentDollars}/month`)
292
+ );
293
+ if (!amount) {
294
+ if (current.configured) {
295
+ console.log(
296
+ chalk2.dim(" To change it, run: ") + chalk2.white("clishop agent spending-limit <amount>")
297
+ );
298
+ console.log(
299
+ chalk2.dim(" A confirmation email will be sent to verify the change.\n")
300
+ );
301
+ } else {
302
+ console.log(
303
+ chalk2.dim(" Not yet configured. Run: ") + chalk2.white("clishop agent spending-limit <amount>") + chalk2.dim(" to set it.\n")
304
+ );
305
+ }
306
+ return;
307
+ }
308
+ const newAmount = parseFloat(amount);
309
+ if (isNaN(newAmount) || newAmount < 1) {
310
+ console.error(chalk2.red("\n\u2717 Please provide a valid amount (minimum $1).\n"));
311
+ process.exitCode = 1;
312
+ return;
313
+ }
314
+ const limitInCents = Math.round(newAmount * 100);
315
+ if (limitInCents === current.monthlySpendingLimitInCents) {
316
+ console.log(chalk2.yellow(`
317
+ Already set to $${newAmount}. No change needed.
318
+ `));
319
+ return;
320
+ }
321
+ try {
322
+ const res = await api.patch("/spending-limit", { limitInCents });
323
+ if (res.status === 202 || res.data.pendingLimitInCents) {
324
+ console.log();
325
+ console.log(chalk2.yellow(" \u{1F4E7} Confirmation email sent!"));
326
+ console.log(
327
+ chalk2.dim(" Check your inbox and click the link to confirm the change:")
328
+ );
329
+ console.log(
330
+ chalk2.dim(` $${currentDollars}/month \u2192 $${newAmount}/month`)
331
+ );
332
+ console.log(
333
+ chalk2.dim(" The link expires in 72 hours.\n")
334
+ );
335
+ } else {
336
+ console.log(
337
+ chalk2.green(`
338
+ \u2713 Monthly spending limit set to $${newAmount}/month.
339
+ `)
340
+ );
341
+ }
342
+ } catch (error) {
343
+ console.error(chalk2.red(`
344
+ \u2717 ${error?.response?.data?.message || error.message}
345
+ `));
346
+ process.exitCode = 1;
347
+ }
348
+ });
253
349
  agent.command("delete <name>").alias("rm").description("Delete an agent").action(async (name) => {
254
350
  try {
255
351
  const { confirm } = await inquirer2.prompt([
@@ -437,6 +533,7 @@ Addresses for agent "${agent.name}":
437
533
  // src/commands/payment.ts
438
534
  import chalk4 from "chalk";
439
535
  import ora3 from "ora";
536
+ import open from "open";
440
537
  function registerPaymentCommands(program2) {
441
538
  const payment = program2.command("payment").description("Manage payment methods (scoped to the active agent)");
442
539
  payment.command("list").alias("ls").description("List payment methods for the active agent").action(async () => {
@@ -477,7 +574,8 @@ Payment methods for agent "${agent.name}":
477
574
  });
478
575
  spinner.stop();
479
576
  const { setupUrl } = res.data;
480
- console.log(chalk4.bold("\nTo add a payment method securely, open this link in your browser:\n"));
577
+ console.log(chalk4.bold("\nOpening secure payment setup in your browser...\n"));
578
+ await open(setupUrl);
481
579
  console.log(chalk4.cyan.underline(` ${setupUrl}
482
580
  `));
483
581
  console.log(chalk4.dim("The CLI never collects raw card details. Payment is set up via the secure web portal."));
@@ -2413,8 +2511,9 @@ async function runSetupWizard() {
2413
2511
  chalk11.dim(" It only takes a minute. You can re-run it anytime with:")
2414
2512
  );
2415
2513
  console.log(chalk11.dim(" ") + chalk11.white("clishop setup"));
2416
- stepHeader(1, 5, "Account");
2514
+ stepHeader(1, 6, "Account");
2417
2515
  let loggedIn = await isLoggedIn();
2516
+ let isNewAccount = false;
2418
2517
  if (loggedIn) {
2419
2518
  const user = await getUserInfo();
2420
2519
  console.log(
@@ -2472,18 +2571,46 @@ async function runSetupWizard() {
2472
2571
  process.exitCode = 1;
2473
2572
  return;
2474
2573
  }
2574
+ console.log();
2575
+ console.log(
2576
+ chalk11.dim(
2577
+ " Your monthly spending limit controls the maximum your AI agent"
2578
+ )
2579
+ );
2580
+ console.log(
2581
+ chalk11.dim(
2582
+ " can spend per month. Default: $200. You can only change this"
2583
+ )
2584
+ );
2585
+ console.log(
2586
+ chalk11.dim(
2587
+ " later via the website or email confirmation."
2588
+ )
2589
+ );
2590
+ console.log();
2591
+ const { spendingLimit } = await inquirer7.prompt([
2592
+ {
2593
+ type: "number",
2594
+ name: "spendingLimit",
2595
+ message: "Monthly spending limit ($):",
2596
+ default: 200
2597
+ }
2598
+ ]);
2599
+ const limitInCents = Math.round((spendingLimit || 200) * 100);
2475
2600
  const spinner = ora9("Creating your account...").start();
2476
2601
  try {
2477
2602
  const user = await register(
2478
2603
  answers.email,
2479
2604
  answers.password,
2480
- answers.name
2605
+ answers.name,
2606
+ limitInCents
2481
2607
  );
2482
2608
  spinner.succeed(
2483
2609
  chalk11.green(
2484
2610
  `Account created! Welcome, ${chalk11.bold(user.name)}.`
2485
2611
  )
2486
2612
  );
2613
+ isNewAccount = true;
2487
2614
  } catch (error) {
2488
2615
  spinner.fail(
2489
2616
  chalk11.red(
@@ -2538,7 +2665,87 @@ async function runSetupWizard() {
2538
2665
  }
2539
2666
  }
2540
2667
  }
2541
- stepHeader(2, 5, "Agent (optional)");
2668
+ stepHeader(2, 6, "Monthly Spending Limit");
2669
+ if (isNewAccount) {
2670
+ console.log(
2671
+ chalk11.green(" \u2713 Spending limit was set during registration.")
2672
+ );
2673
+ console.log(
2674
+ chalk11.dim(
2675
+ " To change it later, visit " + chalk11.white("https://clishop.ai/agents") + chalk11.dim(" or use email confirmation.")
2676
+ )
2677
+ );
2678
+ } else {
2679
+ try {
2680
+ const api = getApiClient();
2681
+ const res = await api.get("/spending-limit");
2682
+ const { monthlySpendingLimitInCents, configured } = res.data;
2683
+ const currentLimit = (monthlySpendingLimitInCents / 100).toFixed(0);
2684
+ if (!configured) {
2685
+ console.log(
2686
+ chalk11.dim(
2687
+ " Your monthly spending limit controls the maximum your AI agent"
2688
+ )
2689
+ );
2690
+ console.log(
2691
+ chalk11.dim(
2692
+ " can spend per month. Default: $200. You can only change this"
2693
+ )
2694
+ );
2695
+ console.log(
2696
+ chalk11.dim(
2697
+ " later via the website or email confirmation."
2698
+ )
2699
+ );
2700
+ console.log();
2701
+ const { spendingLimit } = await inquirer7.prompt([
2702
+ {
2703
+ type: "number",
2704
+ name: "spendingLimit",
2705
+ message: "Monthly spending limit ($):",
2706
+ default: parseInt(currentLimit) || 200
2707
+ }
2708
+ ]);
2709
+ const limitInCents = Math.round((spendingLimit || 200) * 100);
2710
+ const spinner = ora9("Setting spending limit...").start();
2711
+ try {
2712
+ await api.patch("/spending-limit", { limitInCents });
2713
+ spinner.succeed(
2714
+ chalk11.green(
2715
+ `Monthly spending limit set to $${(limitInCents / 100).toFixed(0)}.`
2716
+ )
2717
+ );
2718
+ } catch (error) {
2719
+ spinner.fail(
2720
+ chalk11.red(
2721
+ `Failed: ${error?.response?.data?.message || error.message}`
2722
+ )
2723
+ );
2724
+ }
2725
+ } else {
2726
+ console.log(
2727
+ chalk11.green(
2728
+ ` \u2713 Monthly spending limit: $${currentLimit}/month (already configured).`
2729
+ )
2730
+ );
2731
+ console.log(
2732
+ chalk11.dim(
2733
+ " To change it, visit " + chalk11.white("https://clishop.ai/agents") + chalk11.dim(" or it will require email confirmation.")
2734
+ )
2735
+ );
2736
+ }
2737
+ } catch (error) {
2738
+ console.log(
2739
+ chalk11.yellow(
2740
+ ` \u26A0 Could not fetch spending limit: ${error?.response?.data?.message || error.message}`
2741
+ )
2742
+ );
2743
+ console.log(
2744
+ chalk11.dim(" You can set it later on the website.")
2745
+ );
2746
+ }
2747
+ }
2748
+ stepHeader(3, 6, "Agent (optional)");
2542
2749
  const activeAgent = getActiveAgent();
2543
2750
  console.log(
2544
2751
  chalk11.dim(
@@ -2598,7 +2805,7 @@ async function runSetupWizard() {
2598
2805
  } else {
2599
2806
  console.log(chalk11.green(" \u2713 Using default agent."));
2600
2807
  }
2601
- stepHeader(3, 5, "Shipping Address");
2808
+ stepHeader(4, 6, "Shipping Address");
2602
2809
  console.log(
2603
2810
  chalk11.dim(
2604
2811
  " Add an address so products can be delivered to you."
@@ -2745,7 +2952,7 @@ async function runSetupWizard() {
2745
2952
  )
2746
2953
  );
2747
2954
  }
2748
- stepHeader(4, 5, "Payment Method");
2955
+ stepHeader(5, 6, "Payment Method");
2749
2956
  console.log(
2750
2957
  chalk11.dim(
2751
2958
  " For security, payment details are entered through a secure web"
@@ -2806,7 +3013,7 @@ async function runSetupWizard() {
2806
3013
  )
2807
3014
  );
2808
3015
  }
2809
- stepHeader(5, 5, "Your First Search");
3016
+ stepHeader(6, 6, "Your First Search");
2810
3017
  if (addressCity) {
2811
3018
  console.log(
2812
3019
  chalk11.dim(
@@ -3870,7 +4077,7 @@ function registerFeedbackCommands(program2) {
3870
4077
 
3871
4078
  // src/index.ts
3872
4079
  var program = new Command();
3873
- program.name("clishop").version("0.1.0").description(
4080
+ program.name("clishop").version("0.3.1").description(
3874
4081
  chalk15.bold("CLISHOP") + ' \u2014 Order anything from your terminal.\n\n Use agents to set safety limits, addresses, and payment methods.\n The "default" agent is used when no agent is specified.'
3875
4082
  ).option("--agent <name>", "Use a specific agent for this command").hook("preAction", (thisCommand) => {
3876
4083
  const agentOpt = thisCommand.opts().agent;
package/dist/mcp.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  getApiClient,
4
4
  getUserInfo,
5
5
  isLoggedIn
6
- } from "./chunk-EGTXN73P.js";
6
+ } from "./chunk-RHBOI27D.js";
7
7
  import {
8
8
  __export,
9
9
  getActiveAgent,
@@ -13810,7 +13810,7 @@ function safeCall(fn) {
13810
13810
  var server = new McpServer(
13811
13811
  {
13812
13812
  name: "clishop",
13813
- version: "0.1.0"
13813
+ version: "0.3.1"
13814
13814
  },
13815
13815
  {
13816
13816
  capabilities: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clishop",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "mcpName": "io.github.StefDCL/clishop",
5
5
  "description": "CLISHOP — Order anything from your terminal",
6
6
  "main": "dist/index.js",
@@ -47,6 +47,7 @@
47
47
  "conf": "^15.1.0",
48
48
  "inquirer": "^13.2.4",
49
49
  "keytar": "^7.9.0",
50
+ "open": "^11.0.0",
50
51
  "ora": "^9.3.0"
51
52
  },
52
53
  "devDependencies": {
package/server.json CHANGED
@@ -6,24 +6,18 @@
6
6
  "url": "https://github.com/DavooxBv2/CLISHOP",
7
7
  "source": "github"
8
8
  },
9
- "version": "0.2.1",
9
+ "version": "0.3.0",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "clishop",
14
- "version": "0.2.1",
14
+ "version": "0.3.0",
15
+ "runtime": "node",
16
+ "args": ["--mcp"],
15
17
  "transport": {
16
18
  "type": "stdio"
17
19
  },
18
- "environmentVariables": [
19
- {
20
- "description": "CLISHOP API key for authentication",
21
- "isRequired": true,
22
- "format": "string",
23
- "isSecret": true,
24
- "name": "CLISHOP_API_KEY"
25
- }
26
- ]
20
+ "environmentVariables": []
27
21
  }
28
22
  ]
29
23
  }