clishop 1.2.3 → 1.3.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/README.md +8 -8
- package/dist/{chunk-CVK6G342.js → chunk-3BBLDX6L.js} +118 -12
- package/dist/index.js +72 -14
- package/dist/mcp.js +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -31,12 +31,12 @@ CLISHOP is an open-source CLI that lets AI agents and humans search for products
|
|
|
31
31
|
|
|
32
32
|
## Highlights
|
|
33
33
|
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
34
|
+
- One query searches every store in the network. Results are filtered to what actually ships to your address.
|
|
35
|
+
- Set spending caps per order, require email confirmation before anything ships, or let it go through automatically — your call.
|
|
36
|
+
- Ships as a native [MCP server](https://modelcontextprotocol.io/) with 44 tools. Works with VS Code Copilot, Claude, Cursor, Windsurf, and anything else that speaks MCP.
|
|
37
|
+
- Can't find what you need? Post an advertise request and let vendors compete to fulfill it.
|
|
38
|
+
- Support tickets, product reviews, store reviews — all from the terminal.
|
|
39
|
+
- Anyone can sell on CLISHOP by deploying a [Dark Store](https://github.com/DavooxBv2/CLISHOP-DARKSTORE). No website needed.
|
|
40
40
|
|
|
41
41
|
---
|
|
42
42
|
|
|
@@ -132,7 +132,7 @@ clishop buy 1
|
|
|
132
132
|
|
|
133
133
|
## Sell on CLISHOP
|
|
134
134
|
|
|
135
|
-
|
|
135
|
+
You can run your own store with the [Dark Store](https://github.com/DavooxBv2/CLISHOP-DARKSTORE) template. Define your catalog, shipping rules, and pricing in YAML, deploy to Vercel, and you're live. No website needed.
|
|
136
136
|
|
|
137
137
|
---
|
|
138
138
|
|
|
@@ -150,7 +150,7 @@ npm run lint # Type-check
|
|
|
150
150
|
|
|
151
151
|
## MCP Server
|
|
152
152
|
|
|
153
|
-
CLISHOP ships as a native MCP server with
|
|
153
|
+
CLISHOP ships as a native MCP server with 44 tools. Any MCP-compatible client gets shopping capabilities out of the box.
|
|
154
154
|
|
|
155
155
|
```bash
|
|
156
156
|
clishop-mcp # If installed globally
|
|
@@ -3,12 +3,116 @@ import {
|
|
|
3
3
|
} from "./chunk-X3H7SYR4.js";
|
|
4
4
|
|
|
5
5
|
// src/auth.ts
|
|
6
|
-
import
|
|
6
|
+
import { createRequire } from "module";
|
|
7
7
|
import axios from "axios";
|
|
8
|
+
|
|
9
|
+
// src/auth-file-store.ts
|
|
10
|
+
import { readFileSync, writeFileSync, mkdirSync, chmodSync } from "fs";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
import { homedir } from "os";
|
|
13
|
+
var CONFIG_DIR = join(homedir(), ".config", "clishop");
|
|
14
|
+
var AUTH_FILE = join(CONFIG_DIR, "auth.json");
|
|
15
|
+
function ensureDir() {
|
|
16
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
17
|
+
}
|
|
18
|
+
function readStore() {
|
|
19
|
+
try {
|
|
20
|
+
return JSON.parse(readFileSync(AUTH_FILE, "utf-8"));
|
|
21
|
+
} catch {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function writeStore(data) {
|
|
26
|
+
ensureDir();
|
|
27
|
+
writeFileSync(AUTH_FILE, JSON.stringify(data, null, 2), { mode: 384 });
|
|
28
|
+
try {
|
|
29
|
+
chmodSync(AUTH_FILE, 384);
|
|
30
|
+
} catch {
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function fileSetPassword(service, account, password) {
|
|
34
|
+
const store = readStore();
|
|
35
|
+
store[`${service}:${account}`] = password;
|
|
36
|
+
writeStore(store);
|
|
37
|
+
}
|
|
38
|
+
function fileGetPassword(service, account) {
|
|
39
|
+
const store = readStore();
|
|
40
|
+
return store[`${service}:${account}`] ?? null;
|
|
41
|
+
}
|
|
42
|
+
function fileDeletePassword(service, account) {
|
|
43
|
+
const store = readStore();
|
|
44
|
+
delete store[`${service}:${account}`];
|
|
45
|
+
writeStore(store);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/auth.ts
|
|
49
|
+
var require2 = createRequire(import.meta.url);
|
|
50
|
+
var _keytar = null;
|
|
51
|
+
var _keytarChecked = false;
|
|
52
|
+
function getKeytar() {
|
|
53
|
+
if (_keytarChecked) return _keytar;
|
|
54
|
+
_keytarChecked = true;
|
|
55
|
+
try {
|
|
56
|
+
_keytar = require2("keytar");
|
|
57
|
+
} catch {
|
|
58
|
+
_keytar = null;
|
|
59
|
+
}
|
|
60
|
+
return _keytar;
|
|
61
|
+
}
|
|
8
62
|
var SERVICE_NAME = "clishop";
|
|
9
63
|
var ACCOUNT_TOKEN = "auth-token";
|
|
10
64
|
var ACCOUNT_REFRESH = "refresh-token";
|
|
11
65
|
var ACCOUNT_USER = "user-info";
|
|
66
|
+
var _activeBackend = null;
|
|
67
|
+
function resolveBackend() {
|
|
68
|
+
if (_activeBackend) return _activeBackend;
|
|
69
|
+
if (process.env.CLISHOP_TOKEN) {
|
|
70
|
+
_activeBackend = "env";
|
|
71
|
+
return _activeBackend;
|
|
72
|
+
}
|
|
73
|
+
const kt = getKeytar();
|
|
74
|
+
if (kt) {
|
|
75
|
+
_activeBackend = "keytar";
|
|
76
|
+
return _activeBackend;
|
|
77
|
+
}
|
|
78
|
+
if (!process.env.CLISHOP_QUIET) {
|
|
79
|
+
console.warn(
|
|
80
|
+
"[clishop] Secure keychain unavailable \u2014 using file-based token storage (~/.config/clishop/auth.json).\n To enable keychain on Ubuntu/WSL: sudo apt install libsecret-1-0\n"
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
_activeBackend = "file";
|
|
84
|
+
return _activeBackend;
|
|
85
|
+
}
|
|
86
|
+
function isKeytarAvailable() {
|
|
87
|
+
return getKeytar() !== null;
|
|
88
|
+
}
|
|
89
|
+
async function setPassword(account, value) {
|
|
90
|
+
const backend = resolveBackend();
|
|
91
|
+
if (backend === "env") return;
|
|
92
|
+
if (backend === "keytar") {
|
|
93
|
+
return getKeytar().setPassword(SERVICE_NAME, account, value);
|
|
94
|
+
}
|
|
95
|
+
fileSetPassword(SERVICE_NAME, account, value);
|
|
96
|
+
}
|
|
97
|
+
async function getPassword(account) {
|
|
98
|
+
const backend = resolveBackend();
|
|
99
|
+
if (backend === "env" && account === ACCOUNT_TOKEN) {
|
|
100
|
+
return process.env.CLISHOP_TOKEN;
|
|
101
|
+
}
|
|
102
|
+
if (backend === "keytar") {
|
|
103
|
+
return getKeytar().getPassword(SERVICE_NAME, account);
|
|
104
|
+
}
|
|
105
|
+
return fileGetPassword(SERVICE_NAME, account);
|
|
106
|
+
}
|
|
107
|
+
async function deletePassword(account) {
|
|
108
|
+
const backend = resolveBackend();
|
|
109
|
+
if (backend === "env") return;
|
|
110
|
+
if (backend === "keytar") {
|
|
111
|
+
await getKeytar().deletePassword(SERVICE_NAME, account);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
fileDeletePassword(SERVICE_NAME, account);
|
|
115
|
+
}
|
|
12
116
|
function assertAuthResponse(data) {
|
|
13
117
|
const payload = data;
|
|
14
118
|
if (!payload || typeof payload !== "object") {
|
|
@@ -29,22 +133,22 @@ function assertAuthResponse(data) {
|
|
|
29
133
|
return payload;
|
|
30
134
|
}
|
|
31
135
|
async function storeToken(token) {
|
|
32
|
-
await
|
|
136
|
+
await setPassword(ACCOUNT_TOKEN, token);
|
|
33
137
|
}
|
|
34
138
|
async function storeRefreshToken(token) {
|
|
35
|
-
await
|
|
139
|
+
await setPassword(ACCOUNT_REFRESH, token);
|
|
36
140
|
}
|
|
37
141
|
async function storeUserInfo(user) {
|
|
38
|
-
await
|
|
142
|
+
await setPassword(ACCOUNT_USER, JSON.stringify(user));
|
|
39
143
|
}
|
|
40
144
|
async function getToken() {
|
|
41
|
-
return
|
|
145
|
+
return getPassword(ACCOUNT_TOKEN);
|
|
42
146
|
}
|
|
43
147
|
async function getRefreshToken() {
|
|
44
|
-
return
|
|
148
|
+
return getPassword(ACCOUNT_REFRESH);
|
|
45
149
|
}
|
|
46
150
|
async function getUserInfo() {
|
|
47
|
-
const raw = await
|
|
151
|
+
const raw = await getPassword(ACCOUNT_USER);
|
|
48
152
|
if (!raw) return null;
|
|
49
153
|
try {
|
|
50
154
|
return JSON.parse(raw);
|
|
@@ -53,13 +157,12 @@ async function getUserInfo() {
|
|
|
53
157
|
}
|
|
54
158
|
}
|
|
55
159
|
async function clearAuth() {
|
|
56
|
-
await
|
|
57
|
-
await
|
|
58
|
-
await
|
|
160
|
+
await deletePassword(ACCOUNT_TOKEN);
|
|
161
|
+
await deletePassword(ACCOUNT_REFRESH);
|
|
162
|
+
await deletePassword(ACCOUNT_USER);
|
|
59
163
|
}
|
|
60
164
|
async function isLoggedIn() {
|
|
61
|
-
|
|
62
|
-
return !!token;
|
|
165
|
+
return !!await getToken();
|
|
63
166
|
}
|
|
64
167
|
async function login(email, password) {
|
|
65
168
|
const baseUrl = getApiBaseUrl();
|
|
@@ -198,6 +301,9 @@ function handleApiError(error) {
|
|
|
198
301
|
}
|
|
199
302
|
|
|
200
303
|
export {
|
|
304
|
+
resolveBackend,
|
|
305
|
+
isKeytarAvailable,
|
|
306
|
+
getToken,
|
|
201
307
|
getUserInfo,
|
|
202
308
|
isLoggedIn,
|
|
203
309
|
login,
|
package/dist/index.js
CHANGED
|
@@ -2,18 +2,22 @@
|
|
|
2
2
|
import {
|
|
3
3
|
ensureAgentOnBackend,
|
|
4
4
|
getApiClient,
|
|
5
|
+
getToken,
|
|
5
6
|
getUserInfo,
|
|
6
7
|
handleApiError,
|
|
8
|
+
isKeytarAvailable,
|
|
7
9
|
isLoggedIn,
|
|
8
10
|
login,
|
|
9
11
|
logout,
|
|
10
|
-
register
|
|
11
|
-
|
|
12
|
+
register,
|
|
13
|
+
resolveBackend
|
|
14
|
+
} from "./chunk-3BBLDX6L.js";
|
|
12
15
|
import {
|
|
13
16
|
createAgent,
|
|
14
17
|
deleteAgent,
|
|
15
18
|
getActiveAgent,
|
|
16
19
|
getAgent,
|
|
20
|
+
getApiBaseUrl,
|
|
17
21
|
getConfig,
|
|
18
22
|
listAgents,
|
|
19
23
|
setActiveAgent,
|
|
@@ -22,7 +26,7 @@ import {
|
|
|
22
26
|
|
|
23
27
|
// src/index.ts
|
|
24
28
|
import { Command } from "commander";
|
|
25
|
-
import
|
|
29
|
+
import chalk16 from "chalk";
|
|
26
30
|
|
|
27
31
|
// src/commands/auth.ts
|
|
28
32
|
import chalk from "chalk";
|
|
@@ -932,7 +936,7 @@ async function runSetupWizard() {
|
|
|
932
936
|
console.log();
|
|
933
937
|
console.log(chalk4.bold.cyan(" W E L C O M E T O C L I S H O P"));
|
|
934
938
|
console.log(chalk4.dim(" Order anything from your terminal."));
|
|
935
|
-
console.log(chalk4.dim(` Build: ${"2026-03-
|
|
939
|
+
console.log(chalk4.dim(` Build: ${"2026-03-22T16:08:08.167Z"}`));
|
|
936
940
|
console.log();
|
|
937
941
|
divider(chalk4.cyan);
|
|
938
942
|
console.log();
|
|
@@ -1895,7 +1899,6 @@ function renderProductInfo(result, index, totalResults, formatPriceFn) {
|
|
|
1895
1899
|
}
|
|
1896
1900
|
if (info.checkout && typeof info.checkout === "object") {
|
|
1897
1901
|
const parts = [];
|
|
1898
|
-
if (info.checkout.mode) parts.push(info.checkout.mode);
|
|
1899
1902
|
if (info.checkout.note) parts.push(info.checkout.note);
|
|
1900
1903
|
if (parts.length > 0) {
|
|
1901
1904
|
console.log(` ${chalk6.bold("Checkout:")} ${parts.join(" \u2014 ")}`);
|
|
@@ -2073,7 +2076,7 @@ function renderProductInfo(result, index, totalResults, formatPriceFn) {
|
|
|
2073
2076
|
}
|
|
2074
2077
|
}
|
|
2075
2078
|
function registerSearchCommands(program2) {
|
|
2076
|
-
program2.command("search <query>").description("Search for products").option("-c, --category <category>", "Filter by category").option("--brand <brand>", "Filter by brand").option("--model <model>", "Filter by model name/number").option("--sku <sku>", "Filter by SKU").option("--gtin <gtin>", "Filter by GTIN (UPC/EAN/ISBN)").option("--variant <variant>", "Filter by variant (size/color/storage/etc.)").option("--min-price <price>", "Minimum price (cents)", parseFloat).option("--max-price <price>", "Maximum price (cents)", parseFloat).option("--max-shipping <price>", "Maximum shipping cost (cents)", parseInt).option("--max-total <price>", "Maximum landed total: item + shipping (cents)", parseInt).option("--free-shipping", "Only show items with free shipping").option("--ship-to <address>", "Saved address label or ID (resolves country/city/postal automatically)").option("--country <code>", "Delivery country (ISO 3166-1 alpha-2, e.g. US, BE, NL)").option("--city <city>", "Delivery city").option("--postal-code <code>", "Delivery postal/zip code").option("--region <region>", "Delivery state/province/region").option("--lat <latitude>", "Delivery latitude (for local/proximity search)", parseFloat).option("--lng <longitude>", "Delivery longitude (for local/proximity search)", parseFloat).option("--deliver-by <date>", "Need delivery by date (YYYY-MM-DD)").option("--max-delivery-days <days>", "Maximum delivery/transit days", parseInt).option("--in-stock", "Only show in-stock items").option("--exclude-backorder", "Exclude backordered items").option("--min-qty <qty>", "Minimum quantity available", parseInt).option("--free-returns", "Only show items with free returns").option("--min-return-window-days <days>", "Minimum return window in days", parseInt).option("--store <store>", "Limit to a store (ID, slug, or name)").option("--vendor <vendor>", "Filter by vendor name (alias for --store)").option("--trusted-only", "Only show products from verified stores").option("--min-store-rating <rating>", "Minimum store rating (0-5)", parseFloat).option("--
|
|
2079
|
+
program2.command("search <query>").description("Search for products").option("-c, --category <category>", "Filter by category").option("--brand <brand>", "Filter by brand").option("--model <model>", "Filter by model name/number").option("--sku <sku>", "Filter by SKU").option("--gtin <gtin>", "Filter by GTIN (UPC/EAN/ISBN)").option("--variant <variant>", "Filter by variant (size/color/storage/etc.)").option("--min-price <price>", "Minimum price (cents)", parseFloat).option("--max-price <price>", "Maximum price (cents)", parseFloat).option("--max-shipping <price>", "Maximum shipping cost (cents)", parseInt).option("--max-total <price>", "Maximum landed total: item + shipping (cents)", parseInt).option("--free-shipping", "Only show items with free shipping").option("--ship-to <address>", "Saved address label or ID (resolves country/city/postal automatically)").option("--country <code>", "Delivery country (ISO 3166-1 alpha-2, e.g. US, BE, NL)").option("--city <city>", "Delivery city").option("--postal-code <code>", "Delivery postal/zip code").option("--region <region>", "Delivery state/province/region").option("--lat <latitude>", "Delivery latitude (for local/proximity search)", parseFloat).option("--lng <longitude>", "Delivery longitude (for local/proximity search)", parseFloat).option("--deliver-by <date>", "Need delivery by date (YYYY-MM-DD)").option("--max-delivery-days <days>", "Maximum delivery/transit days", parseInt).option("--in-stock", "Only show in-stock items").option("--exclude-backorder", "Exclude backordered items").option("--min-qty <qty>", "Minimum quantity available", parseInt).option("--free-returns", "Only show items with free returns").option("--min-return-window-days <days>", "Minimum return window in days", parseInt).option("--store <store>", "Limit to a store (ID, slug, or name)").option("--vendor <vendor>", "Filter by vendor name (alias for --store)").option("--trusted-only", "Only show products from verified stores").option("--min-store-rating <rating>", "Minimum store rating (0-5)", parseFloat).option("--min-rating <rating>", "Minimum product rating (1-5)", parseFloat).option("-s, --sort <field>", "Sort by: price, total-cost, rating, relevance, newest, delivery", "relevance").option("--order <dir>", "Sort order: asc, desc", "desc").option("-p, --page <page>", "Page number", parseInt, 1).option("-n, --per-page <count>", "Results per page", parseInt, 10).option("--express", "Only show items with 2-day or faster delivery").option("-e, --extended-search", "Enable extended search: query darkstores when no local results found").option("--no-extended-search", "Disable automatic extended search when no local results found").option("--extended-timeout <seconds>", "Extended search timeout in seconds (default: 30, max: 60)", parseInt).option("--json", "Output raw JSON").option("--compact", "Compact one-line-per-result output").option("--detailed", "Show full product details inline").option("-i, --interactive", "After results, interactively select products to get more info from their store").action(async (query, opts) => {
|
|
2077
2080
|
try {
|
|
2078
2081
|
const spinner = ora5(`Searching for "${query}"...`).start();
|
|
2079
2082
|
const api = getApiClient();
|
|
@@ -2186,7 +2189,6 @@ function registerSearchCommands(program2) {
|
|
|
2186
2189
|
vendor: opts.vendor,
|
|
2187
2190
|
trustedOnly: opts.trustedOnly || void 0,
|
|
2188
2191
|
minStoreRating: opts.minStoreRating,
|
|
2189
|
-
checkoutMode: opts.checkoutMode,
|
|
2190
2192
|
// Rating / sorting / pagination
|
|
2191
2193
|
minRating: opts.minRating,
|
|
2192
2194
|
sort: opts.sort === "total-cost" ? "price" : opts.sort,
|
|
@@ -2634,9 +2636,6 @@ Results for "${query}" \u2014 ${result.total} found (page ${result.page})
|
|
|
2634
2636
|
if (p.freeReturns) returnParts.push(chalk6.green("Free Returns"));
|
|
2635
2637
|
if (p.returnWindowDays) returnParts.push(`${p.returnWindowDays}-day return window`);
|
|
2636
2638
|
if (returnParts.length) console.log(` Returns: ${returnParts.join(" \xB7 ")}`);
|
|
2637
|
-
if (p.checkoutMode && p.checkoutMode !== "instant") {
|
|
2638
|
-
console.log(` Checkout: ${chalk6.yellow(p.checkoutMode)}`);
|
|
2639
|
-
}
|
|
2640
2639
|
console.log();
|
|
2641
2640
|
console.log(` ${p.description}`);
|
|
2642
2641
|
console.log();
|
|
@@ -4585,16 +4584,74 @@ function registerFeedbackCommands(program2) {
|
|
|
4585
4584
|
});
|
|
4586
4585
|
}
|
|
4587
4586
|
|
|
4587
|
+
// src/commands/doctor.ts
|
|
4588
|
+
import chalk15 from "chalk";
|
|
4589
|
+
import { join } from "path";
|
|
4590
|
+
import { homedir } from "os";
|
|
4591
|
+
import { mkdirSync } from "fs";
|
|
4592
|
+
import axios from "axios";
|
|
4593
|
+
function registerDoctorCommand(program2) {
|
|
4594
|
+
program2.command("doctor").description("Check system compatibility and auth status").action(async () => {
|
|
4595
|
+
const checks = [];
|
|
4596
|
+
const keytarOk = isKeytarAvailable();
|
|
4597
|
+
checks.push({
|
|
4598
|
+
name: "Secure keychain (keytar)",
|
|
4599
|
+
ok: keytarOk,
|
|
4600
|
+
detail: keytarOk ? "keytar loaded successfully" : "keytar unavailable \u2014 install libsecret:\n sudo apt install libsecret-1-0"
|
|
4601
|
+
});
|
|
4602
|
+
const backend = resolveBackend();
|
|
4603
|
+
checks.push({
|
|
4604
|
+
name: "Auth backend",
|
|
4605
|
+
ok: true,
|
|
4606
|
+
detail: backend === "env" ? "Using CLISHOP_TOKEN environment variable" : backend === "keytar" ? "Using OS keychain" : "Using file store (~/.config/clishop/auth.json)"
|
|
4607
|
+
});
|
|
4608
|
+
try {
|
|
4609
|
+
const dir = join(homedir(), ".config", "clishop");
|
|
4610
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
4611
|
+
checks.push({ name: "File store writable", ok: true, detail: dir });
|
|
4612
|
+
} catch (e) {
|
|
4613
|
+
checks.push({
|
|
4614
|
+
name: "File store writable",
|
|
4615
|
+
ok: false,
|
|
4616
|
+
detail: e instanceof Error ? e.message : String(e)
|
|
4617
|
+
});
|
|
4618
|
+
}
|
|
4619
|
+
const token = await getToken();
|
|
4620
|
+
checks.push({
|
|
4621
|
+
name: "Authenticated",
|
|
4622
|
+
ok: !!token,
|
|
4623
|
+
detail: token ? "Token present" : "Not logged in \u2014 run: clishop setup"
|
|
4624
|
+
});
|
|
4625
|
+
const apiUrl = getApiBaseUrl();
|
|
4626
|
+
try {
|
|
4627
|
+
await axios.get(`${apiUrl}/health`, { timeout: 5e3 });
|
|
4628
|
+
checks.push({ name: "API reachable", ok: true, detail: apiUrl });
|
|
4629
|
+
} catch {
|
|
4630
|
+
checks.push({
|
|
4631
|
+
name: "API reachable",
|
|
4632
|
+
ok: false,
|
|
4633
|
+
detail: `Cannot reach ${apiUrl}`
|
|
4634
|
+
});
|
|
4635
|
+
}
|
|
4636
|
+
console.log(chalk15.bold("\n CLISHOP Doctor\n"));
|
|
4637
|
+
for (const c of checks) {
|
|
4638
|
+
const icon = c.ok ? chalk15.green("\u2713") : chalk15.red("\u2717");
|
|
4639
|
+
console.log(` ${icon} ${chalk15.bold(c.name)}: ${c.detail}`);
|
|
4640
|
+
}
|
|
4641
|
+
console.log();
|
|
4642
|
+
});
|
|
4643
|
+
}
|
|
4644
|
+
|
|
4588
4645
|
// src/index.ts
|
|
4589
4646
|
var program = new Command();
|
|
4590
|
-
program.name("clishop").version("1.
|
|
4591
|
-
|
|
4647
|
+
program.name("clishop").version("1.3.0").description(
|
|
4648
|
+
chalk16.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.'
|
|
4592
4649
|
).option("--agent <name>", "Use a specific agent for this command").hook("preAction", (thisCommand) => {
|
|
4593
4650
|
const agentOpt = thisCommand.opts().agent;
|
|
4594
4651
|
if (agentOpt) {
|
|
4595
4652
|
const config = getConfig();
|
|
4596
4653
|
if (!config.store.agents[agentOpt]) {
|
|
4597
|
-
console.error(
|
|
4654
|
+
console.error(chalk16.red(`\u2717 Agent "${agentOpt}" does not exist.`));
|
|
4598
4655
|
process.exit(1);
|
|
4599
4656
|
}
|
|
4600
4657
|
process.env.__CLISHOP_AGENT_OVERRIDE = agentOpt;
|
|
@@ -4614,6 +4671,7 @@ registerSetupCommand(program);
|
|
|
4614
4671
|
registerAdvertiseCommands(program);
|
|
4615
4672
|
registerSupportCommands(program);
|
|
4616
4673
|
registerFeedbackCommands(program);
|
|
4674
|
+
registerDoctorCommand(program);
|
|
4617
4675
|
async function main() {
|
|
4618
4676
|
if (process.argv.includes("--mcp")) {
|
|
4619
4677
|
const { startMcpServer } = await import("./mcp.js");
|
|
@@ -4631,6 +4689,6 @@ async function main() {
|
|
|
4631
4689
|
await program.parseAsync(process.argv);
|
|
4632
4690
|
}
|
|
4633
4691
|
main().catch((err) => {
|
|
4634
|
-
console.error(
|
|
4692
|
+
console.error(chalk16.red(err.message));
|
|
4635
4693
|
process.exit(1);
|
|
4636
4694
|
});
|
package/dist/mcp.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clishop",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"mcpName": "io.github.StefDCL/clishop",
|
|
5
5
|
"description": "CLISHOP — Order anything from your terminal",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"dev:mcp": "tsx src/mcp.ts",
|
|
18
18
|
"start": "node dist/index.js",
|
|
19
19
|
"start:mcp": "node dist/mcp.js",
|
|
20
|
-
"lint": "tsc --noEmit"
|
|
20
|
+
"lint": "tsc --noEmit",
|
|
21
|
+
"postinstall": "node -e \"try{require('keytar')}catch{console.warn('\\n[clishop] Optional: install libsecret for secure keychain storage:\\n sudo apt install libsecret-1-0\\nWithout it, clishop uses file-based token storage.\\n')}\""
|
|
21
22
|
},
|
|
22
23
|
"repository": {
|
|
23
24
|
"type": "git",
|
|
@@ -49,10 +50,12 @@
|
|
|
49
50
|
"commander": "^14.0.3",
|
|
50
51
|
"conf": "^15.1.0",
|
|
51
52
|
"inquirer": "^13.2.4",
|
|
52
|
-
"keytar": "^7.9.0",
|
|
53
53
|
"open": "^11.0.0",
|
|
54
54
|
"ora": "^9.3.0"
|
|
55
55
|
},
|
|
56
|
+
"optionalDependencies": {
|
|
57
|
+
"keytar": "^7.9.0"
|
|
58
|
+
},
|
|
56
59
|
"devDependencies": {
|
|
57
60
|
"@types/inquirer": "^9.0.9",
|
|
58
61
|
"@types/keytar": "^4.4.0",
|