@zeroxyz/cli 0.0.22 → 0.0.23

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/index.js CHANGED
@@ -6,7 +6,7 @@ import { Command as Command9 } from "commander";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@zeroxyz/cli",
9
- version: "0.0.22",
9
+ version: "0.0.23",
10
10
  type: "module",
11
11
  bin: {
12
12
  zero: "dist/index.js",
@@ -168,7 +168,10 @@ var detectPaymentRequirement = (headers, status) => {
168
168
  }
169
169
  return { protocol: "unknown", raw: {} };
170
170
  };
171
- var fetchCommand = (appContext) => new Command2("fetch").description("Fetch a capability URL with automatic payment handling").argument("<url>", "URL to fetch").option("-d, --data <body>", "Request body (JSON string)").option("-H, --header <header...>", "Headers in Key:Value format").option("--max-pay <amount>", "Maximum amount willing to pay (USDC)").option(
171
+ var fetchCommand = (appContext) => new Command2("fetch").description("Fetch a capability URL with automatic payment handling").argument("<url>", "URL to fetch").option(
172
+ "-X, --method <method>",
173
+ "HTTP method (GET, POST, PUT, PATCH, DELETE). Defaults to POST when -d is set, otherwise GET"
174
+ ).option("-d, --data <body>", "Request body (JSON string)").option("-H, --header <header...>", "Headers in Key:Value format").option("--max-pay <amount>", "Maximum amount willing to pay (USDC)").option(
172
175
  "--capability <id>",
173
176
  "Bind this fetch to a capability (uid or slug) so a reviewable run is recorded even without a prior `zero search`"
174
177
  ).option(
@@ -201,55 +204,80 @@ var fetchCommand = (appContext) => new Command2("fetch").description("Fetch a ca
201
204
  headers["content-type"] = "application/json";
202
205
  }
203
206
  const log = (msg) => console.error(` ${msg}`);
207
+ const method = options.method ? options.method.toUpperCase() : options.data ? "POST" : "GET";
204
208
  const requestInit = {
205
- method: options.data ? "POST" : "GET",
209
+ method,
206
210
  headers,
207
211
  body: options.data
208
212
  };
209
- log(`Calling ${url}...`);
210
- const response = await fetch(url, requestInit);
211
- const paymentReq = detectPaymentRequirement(
212
- response.headers,
213
- response.status
213
+ const lastSearch = stateService.loadLastSearch();
214
+ const matchedCapability = lastSearch?.capabilities.find(
215
+ (c) => url.startsWith(c.url)
214
216
  );
215
- let finalResponse;
216
- let paymentMeta;
217
- if (paymentReq) {
218
- log(
219
- `Payment required (${paymentReq.protocol}) \u2014 preparing payment...`
217
+ const capabilityId = options.capability ?? matchedCapability?.id ?? null;
218
+ const searchId = matchedCapability ? lastSearch?.searchId : void 0;
219
+ const skipReasons = [];
220
+ if (!apiService.walletAddress) {
221
+ skipReasons.push(
222
+ "no wallet configured (run `zero wallet import` / set ZERO_PRIVATE_KEY)"
220
223
  );
221
- const result = await paymentService.handlePayment(
222
- url,
223
- requestInit,
224
- paymentReq,
225
- options.maxPay,
226
- log
224
+ }
225
+ if (!capabilityId) {
226
+ skipReasons.push(
227
+ "no capability resolved \u2014 pass --capability <uid|slug> or run `zero search` first so the URL can be matched"
227
228
  );
228
- finalResponse = result.response;
229
- paymentMeta = {
230
- protocol: result.protocol,
231
- chain: result.chain,
232
- txHash: result.txHash,
233
- amount: result.amount,
234
- asset: result.asset
235
- };
236
- log(
237
- `Paid ${result.amount} ${result.asset} via ${result.protocol} on ${result.chain}`
229
+ }
230
+ let finalResponse;
231
+ let body = "";
232
+ let paymentMeta;
233
+ let fetchError;
234
+ try {
235
+ log(`Calling ${url}...`);
236
+ const response = await fetch(url, requestInit);
237
+ const paymentReq = detectPaymentRequirement(
238
+ response.headers,
239
+ response.status
238
240
  );
239
- } else {
240
- finalResponse = response;
241
+ if (paymentReq) {
242
+ log(
243
+ `Payment required (${paymentReq.protocol}) \u2014 preparing payment...`
244
+ );
245
+ const result = await paymentService.handlePayment(
246
+ url,
247
+ requestInit,
248
+ paymentReq,
249
+ options.maxPay,
250
+ log
251
+ );
252
+ finalResponse = result.response;
253
+ paymentMeta = {
254
+ protocol: result.protocol,
255
+ chain: result.chain,
256
+ txHash: result.txHash,
257
+ amount: result.amount,
258
+ asset: result.asset
259
+ };
260
+ log(
261
+ `Paid ${result.amount} ${result.asset} via ${result.protocol} on ${result.chain}`
262
+ );
263
+ } else {
264
+ finalResponse = response;
265
+ }
266
+ body = await finalResponse.text();
267
+ } catch (err) {
268
+ fetchError = err instanceof Error ? err : new Error(String(err));
241
269
  }
242
270
  const latencyMs = Date.now() - startTime;
243
- const body = await finalResponse.text();
244
- if (!options.json) {
271
+ if (finalResponse && !options.json) {
245
272
  console.log(body);
246
273
  }
247
274
  analyticsService.capture("fetch_executed", {
248
275
  url,
249
- status: finalResponse.status,
276
+ status: finalResponse?.status,
250
277
  hasPayment: !!paymentMeta,
251
278
  paymentProtocol: paymentMeta?.protocol,
252
- paymentAmount: paymentMeta?.amount
279
+ paymentAmount: paymentMeta?.amount,
280
+ ...fetchError && { error: fetchError.message }
253
281
  });
254
282
  if (paymentMeta) {
255
283
  try {
@@ -268,24 +296,7 @@ var fetchCommand = (appContext) => new Command2("fetch").description("Fetch a ca
268
296
  } catch {
269
297
  }
270
298
  }
271
- const lastSearch = stateService.loadLastSearch();
272
- const matchedCapability = lastSearch?.capabilities.find(
273
- (c) => url.startsWith(c.url)
274
- );
275
- const capabilityId = options.capability ?? matchedCapability?.id ?? null;
276
- const searchId = matchedCapability ? lastSearch?.searchId : void 0;
277
299
  let runId = null;
278
- const skipReasons = [];
279
- if (!apiService.walletAddress) {
280
- skipReasons.push(
281
- "no wallet configured (run `zero wallet import` / set ZERO_PRIVATE_KEY)"
282
- );
283
- }
284
- if (!capabilityId) {
285
- skipReasons.push(
286
- "no capability resolved \u2014 pass --capability <uid|slug> or run `zero search` first so the URL can be matched"
287
- );
288
- }
289
300
  if (capabilityId && apiService.walletAddress) {
290
301
  let requestSchema;
291
302
  let responseSchema;
@@ -305,7 +316,7 @@ var fetchCommand = (appContext) => new Command2("fetch").description("Fetch a ca
305
316
  const runResult = await apiService.createRun({
306
317
  capabilityId,
307
318
  searchId,
308
- status: finalResponse.status,
319
+ status: finalResponse?.status,
309
320
  latencyMs,
310
321
  requestSchema,
311
322
  responseSchema,
@@ -325,14 +336,18 @@ var fetchCommand = (appContext) => new Command2("fetch").description("Fetch a ca
325
336
  );
326
337
  }
327
338
  }
339
+ if (fetchError && !options.json) {
340
+ console.error(` Fetch failed: ${fetchError.message}`);
341
+ }
328
342
  if (options.json) {
329
343
  console.log(
330
344
  JSON.stringify({
331
345
  runId,
332
- status: finalResponse.status,
346
+ status: finalResponse?.status ?? null,
333
347
  latencyMs,
334
348
  payment: paymentMeta ?? null,
335
- body,
349
+ body: finalResponse ? body : null,
350
+ ...fetchError && { error: fetchError.message },
336
351
  ...skipReasons.length > 0 && {
337
352
  runTrackingSkipped: skipReasons
338
353
  }
@@ -365,6 +380,9 @@ var fetchCommand = (appContext) => new Command2("fetch").description("Fetch a ca
365
380
  Note: this run was NOT recorded for review \u2014 ${skipReasons.join("; ")}.`
366
381
  );
367
382
  }
383
+ if (fetchError) {
384
+ process.exitCode = 1;
385
+ }
368
386
  } catch (err) {
369
387
  console.error(err instanceof Error ? err.message : "Fetch failed");
370
388
  process.exitCode = 1;
@@ -994,7 +1012,13 @@ var formatSearchResults = (results) => {
994
1012
  var searchCommand = (appContext) => new Command7("search").description("Search for capabilities").argument("<query>", "Search query").option("--json", "Output raw JSON to stdout").option("--offset <n>", "Pagination offset", Number).option("--limit <n>", "Results per page", Number).option("--free", "Only show free capabilities").option("--max-cost <amount>", "Maximum cost per call").option("--min-rating <stars>", "Minimum star rating (1-5)", Number).option("--protocol <protocol>", "Payment protocol (x402 or mpp)").option("--min-trust <n>", "Minimum trust score (0-100)", Number).option(
995
1013
  "--status <status>",
996
1014
  "Filter by availability (healthy, degraded, down)"
997
- ).option("--all", "Show all results (no trust or health filtering)").action(
1015
+ ).option("--all", "Show all results (no trust or health filtering)").option(
1016
+ "--source <source>",
1017
+ "Only show results from this crawl source (e.g. mpp, bazaar)"
1018
+ ).option(
1019
+ "--exclude-source <source>",
1020
+ "Exclude results from this crawl source"
1021
+ ).action(
998
1022
  async (query, options) => {
999
1023
  try {
1000
1024
  const { analyticsService, apiService, stateService } = appContext.services;
@@ -1023,7 +1047,9 @@ var searchCommand = (appContext) => new Command7("search").description("Search f
1023
1047
  protocol: options.protocol,
1024
1048
  minTrust: options.minTrust,
1025
1049
  availabilityStatus: options.status,
1026
- includeAll: options.all
1050
+ includeAll: options.all,
1051
+ source: options.source,
1052
+ excludeSource: options.excludeSource
1027
1053
  });
1028
1054
  analyticsService.capture("search_executed", {
1029
1055
  query,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeroxyz/cli",
3
- "version": "0.0.22",
3
+ "version": "0.0.23",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "zero": "dist/index.js",
@@ -33,7 +33,13 @@ Run these commands in order. Do not skip steps.
33
33
 
34
34
  **Step 1 — Install:** `npm i -g @zeroxyz/cli`
35
35
 
36
- **Step 2 — Initialize wallet:** `zero init` — generates a new wallet. Save the printed address. Or, to use an existing wallet: `zero wallet set <privateKey>` (0x-prefixed hex private key).
36
+ **Step 2 — Provide a wallet.** Pick one path:
37
+
38
+ - **New wallet (persistent):** `zero init` — generates a wallet and writes it to `~/.zero/config.json`. Save the printed address.
39
+ - **Existing wallet (persistent):** `zero wallet set <privateKey>` — 0x-prefixed hex. Writes to `~/.zero/config.json`. Refuses to overwrite an existing wallet without `--force`.
40
+ - **Existing wallet (ephemeral, e.g. CI):** set `ZERO_PRIVATE_KEY=0x...` in the environment. The CLI reads it at runtime and writes nothing to disk.
41
+
42
+ **Prefer `zero init` or `zero wallet set` for local/interactive use** so the wallet persists across shells. Use `ZERO_PRIVATE_KEY` only when persisting to disk is undesirable — CI jobs, containers, one-off scripts, or secrets-manager-injected environments.
37
43
 
38
44
  **Step 3 — Fund wallet:** `zero wallet fund` — opens browser to add USDC (Base). For manual transfer: `zero wallet fund --manual`.
39
45
 
@@ -41,7 +47,7 @@ Run these commands in order. Do not skip steps.
41
47
 
42
48
  ### Setup Rules
43
49
 
44
- - If `ZERO_PRIVATE_KEY` is set in the environment, the CLI uses that key instead of the one from `zero init`.
50
+ - Precedence: `ZERO_PRIVATE_KEY` (env) > `~/.zero/config.json`. If the env var is set, it wins even when a config file exists useful for overriding on a single invocation (`ZERO_PRIVATE_KEY=0x... zero wallet balance`).
45
51
  - Wallet must be funded with USDC on Base before calling paid capabilities.
46
52
 
47
53
  ## After Setup
@@ -105,7 +111,9 @@ zero fetch https://api.example.com/expensive --max-pay 0.50
105
111
 
106
112
  ### Rules
107
113
 
108
- - Always discover capabilities with `zero search` + `zero get` before calling; never guess endpoint URLs or schemas.
114
+ - **Always `zero search` fresh, every time.** Never reuse a capability URL, slug, schema, or price from an earlier turn, prior conversation, training data, or memory. Capabilities churn constantly — endpoints go offline, prices change, schemas evolve, and rankings shift as reviews accumulate. A capability that worked yesterday may be dead, repriced, or outranked today. Searching again costs nothing and is the only way to get current trust scores and availability.
115
+ - **Always `zero get` before `zero fetch`.** Even if you "know" the URL, re-fetch the full details to confirm the URL, method, required headers, body schema, and current price. Do not reconstruct a fetch call from memory.
116
+ - Never guess endpoint URLs or schemas.
109
117
  - Use `--max-pay` before potentially expensive requests.
110
118
  - Review capabilities after every paid call. The review signal feeds search ranking — skipping reviews means your next search is less informed.
111
119
  - Before ending a multi-call task, run `zero runs --unreviewed` and review anything you missed.