@zeroxyz/cli 0.0.36 → 0.0.37

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
@@ -46,7 +46,7 @@ Search for capabilities by free-text query.
46
46
  zero search "image classification"
47
47
  ```
48
48
 
49
- Results are numbered. Use `zero get <number>` to view details.
49
+ Results are numbered and include public rating/review context. Use `zero get <number>` to view details.
50
50
 
51
51
  **Cost filtering.** By default, results are filtered to capabilities priced **≤ $30/call** as a wallet-safety cap. Override per-call:
52
52
 
@@ -56,7 +56,7 @@ zero search "expensive deep research" --max-cost 100 # raise the cap for hard ta
56
56
  zero search "image classification" --free # only free capabilities
57
57
  ```
58
58
 
59
- Other useful filters: `--min-rating <1-5>`, `--min-trust <0-100>`, `--protocol x402|mpp`, `--status healthy|degraded|down`, `--source <name>`, `--all` (no trust/health filtering).
59
+ Other useful filters: `--protocol x402|mpp`, `--status healthy|degraded|down`, `--source <name>`, `--all` (disables default quality filtering).
60
60
 
61
61
  ### `zero get <position>`
62
62
 
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import { join as join8 } from "path";
7
7
  // package.json
8
8
  var package_default = {
9
9
  name: "@zeroxyz/cli",
10
- version: "0.0.36",
10
+ version: "0.0.37",
11
11
  type: "module",
12
12
  bin: {
13
13
  zero: "dist/index.js",
@@ -23,7 +23,7 @@ var package_default = {
23
23
  },
24
24
  scripts: {
25
25
  build: "tsup src/index.ts --format esm --out-dir dist --clean",
26
- "build:binary": "tsup --config tsup.binary.ts && cp -r skills hooks dist/pkg/ && pnpm exec pkg dist/pkg/index.cjs --config pkg.json --targets node24-macos-arm64,node24-macos-x64,node24-linux-x64 --output dist/bin/zero",
26
+ "build:binary": "tsup --config tsup.binary.ts && cp -r skills hooks dist/pkg/ && pnpm exec pkg dist/pkg/index.cjs --config pkg.json --targets node24-macos-arm64,node24-macos-x64,node24-linux-x64,node24-linux-arm64 --output dist/bin/zero",
27
27
  prepublishOnly: "pnpm run build",
28
28
  dev: "ZERO_ENV=development tsx src/index.ts",
29
29
  cli: "ZERO_ENV=development ZERO_API_URL=http://localhost:1111 tsx src/index.ts",
@@ -41,7 +41,7 @@ var package_default = {
41
41
  "@x402/extensions": "^2.9.0",
42
42
  "@x402/fetch": "^2.9.0",
43
43
  commander: "^13.0.0",
44
- mppx: "^0.5.9",
44
+ mppx: "^0.6.9",
45
45
  open: "^11.0.0",
46
46
  "posthog-node": "^5.29.2",
47
47
  viem: "^2.47.10",
@@ -72,6 +72,13 @@ import { z as z2 } from "zod";
72
72
  // src/services/api-service.ts
73
73
  import { createHash } from "crypto";
74
74
  import z from "zod";
75
+ var ratingSchema = z.object({
76
+ score: z.string(),
77
+ successRate: z.string(),
78
+ reviews: z.number(),
79
+ stars: z.string().nullable().optional(),
80
+ state: z.enum(["unrated", "rated"]).optional()
81
+ });
75
82
  var searchResultSchema = z.object({
76
83
  id: z.string(),
77
84
  position: z.number(),
@@ -83,17 +90,10 @@ var searchResultSchema = z.object({
83
90
  url: z.string(),
84
91
  urlTemplate: z.string().nullable().optional(),
85
92
  cost: z.object({ amount: z.string(), asset: z.string() }),
86
- rating: z.object({
87
- score: z.string(),
88
- successRate: z.string(),
89
- reviews: z.number(),
90
- stars: z.string().nullable().optional(),
91
- state: z.enum(["unrated", "rated"]).optional()
92
- }),
93
- trustScore: z.number().nullable().optional(),
94
- trustSignalCount: z.number().optional(),
93
+ reviewCount: z.number().optional(),
94
+ rating: ratingSchema,
95
95
  availabilityStatus: z.enum(["healthy", "degraded", "down", "unknown"]).nullable().optional(),
96
- relevanceScore: z.number().optional()
96
+ displayStatus: z.enum(["healthy", "stable", "degraded", "unhealthy", "unknown"]).optional()
97
97
  });
98
98
  var searchResponseSchema = z.object({
99
99
  searchId: z.string(),
@@ -117,13 +117,8 @@ var capabilityResponseSchema = z.object({
117
117
  tags: z.array(z.string()).nullable(),
118
118
  displayCostAmount: z.string(),
119
119
  displayCostAsset: z.string(),
120
- rating: z.object({
121
- score: z.string(),
122
- successRate: z.string(),
123
- reviews: z.number(),
124
- stars: z.string().nullable().optional(),
125
- state: z.enum(["unrated", "rated"]).optional()
126
- }),
120
+ reviewCount: z.number(),
121
+ rating: ratingSchema,
127
122
  priceObserved: z.object({
128
123
  minCents: z.string().nullable(),
129
124
  medianCents: z.string().nullable(),
@@ -146,13 +141,8 @@ var capabilityResponseSchema = z.object({
146
141
  priority: z.number()
147
142
  })
148
143
  ).nullable(),
149
- trustScore: z.number().nullable().optional(),
150
- trustComponents: z.object({
151
- apiQuality: z.number().nullable(),
152
- blockchainActivity: z.number().nullable(),
153
- performance: z.number().nullable()
154
- }).nullable().optional(),
155
144
  availabilityStatus: z.enum(["healthy", "degraded", "down", "unknown"]).nullable().optional(),
145
+ displayStatus: z.enum(["healthy", "stable", "degraded", "unhealthy", "unknown"]).optional(),
156
146
  activationCount: z.number().optional(),
157
147
  lastUsedAt: z.string().nullable().optional(),
158
148
  lastSuccessfullyRanAt: z.string().nullable().optional()
@@ -1775,10 +1765,6 @@ var fetchCommand = (appContext) => new Command3("fetch").description(
1775
1765
 
1776
1766
  // src/commands/get-command.ts
1777
1767
  import { Command as Command4 } from "commander";
1778
- var formatReviewCount = (count) => {
1779
- if (count >= 1e3) return `${(count / 1e3).toFixed(1)}k`;
1780
- return count.toString();
1781
- };
1782
1768
  var formatRelativeTimestamp = (iso) => {
1783
1769
  if (!iso) return "never";
1784
1770
  const then = new Date(iso).getTime();
@@ -1795,16 +1781,6 @@ var formatRelativeTimestamp = (iso) => {
1795
1781
  if (diffMo < 12) return `${diffMo}mo ago`;
1796
1782
  return `${Math.round(diffMo / 12)}y ago`;
1797
1783
  };
1798
- var formatTrustScore = (capability) => {
1799
- if (capability.trustScore != null) {
1800
- return `Trust Score: ${capability.trustScore}/100`;
1801
- }
1802
- return "Trust Score: --";
1803
- };
1804
- var formatTrustComponent = (label, value) => {
1805
- const display = value != null ? `${value}/100` : "--";
1806
- return ` ${label.padEnd(22)}${display}`;
1807
- };
1808
1784
  var centsToDollars = (cents) => {
1809
1785
  const value = Number.parseFloat(cents) / 100;
1810
1786
  if (value < 0.01) return value.toFixed(4);
@@ -1829,6 +1805,10 @@ var formatCost = (capability) => {
1829
1805
  }
1830
1806
  return lines;
1831
1807
  };
1808
+ var formatReviewCount = (count) => {
1809
+ if (count >= 1e3) return `${(count / 1e3).toFixed(1)}k`;
1810
+ return count.toString();
1811
+ };
1832
1812
  var formatRating = (rating) => {
1833
1813
  if (rating.state === "unrated") return "unrated";
1834
1814
  const successPct = `${Math.round(Number.parseFloat(rating.successRate) * 100)}%`;
@@ -1915,29 +1895,8 @@ var buildTryItExample = (capability) => {
1915
1895
  var formatCapability = (capability) => {
1916
1896
  const lines = [];
1917
1897
  lines.push(capability.name);
1918
- lines.push(` ${formatTrustScore(capability)}`);
1919
- if (capability.trustComponents) {
1920
- lines.push(
1921
- formatTrustComponent(
1922
- "API Quality:",
1923
- capability.trustComponents.apiQuality
1924
- )
1925
- );
1926
- lines.push(
1927
- formatTrustComponent(
1928
- "Blockchain Activity:",
1929
- capability.trustComponents.blockchainActivity
1930
- )
1931
- );
1932
- lines.push(
1933
- formatTrustComponent(
1934
- "Performance:",
1935
- capability.trustComponents.performance
1936
- )
1937
- );
1938
- }
1939
1898
  lines.push(` Rating: ${formatRating(capability.rating)}`);
1940
- lines.push(` Status: ${capability.availabilityStatus ?? "unknown"}`);
1899
+ lines.push(` Status: ${capability.displayStatus ?? "unknown"}`);
1941
1900
  lines.push(...formatCost(capability));
1942
1901
  lines.push(` URL: ${capability.url}`);
1943
1902
  lines.push(` Method: ${capability.method}`);
@@ -1952,7 +1911,7 @@ var getCommand = (appContext) => new Command4("get").description(
1952
1911
  ).argument(
1953
1912
  "<identifier>",
1954
1913
  "Position number from search results, or a capability slug"
1955
- ).option("--formatted", "Output formatted trust breakdown").option(
1914
+ ).option("--formatted", "Output formatted capability details").option(
1956
1915
  "--agent <name>",
1957
1916
  "Identify your agent host for this invocation. Overrides auto-detect for this call only."
1958
1917
  ).action(async (identifier, options) => {
@@ -2922,7 +2881,7 @@ var formatReviewCount2 = (count) => {
2922
2881
  return count.toString();
2923
2882
  };
2924
2883
  var formatRatingBadge = (rating) => {
2925
- if (rating.state === "unrated") return "\u2014 unrated";
2884
+ if (rating.state === "unrated") return "unrated";
2926
2885
  const successPct = `${Math.round(Number.parseFloat(rating.successRate) * 100)}%`;
2927
2886
  const reviews = formatReviewCount2(rating.reviews);
2928
2887
  if (rating.stars) {
@@ -2930,13 +2889,7 @@ var formatRatingBadge = (rating) => {
2930
2889
  }
2931
2890
  return `${successPct} success \xB7 ${reviews} reviews`;
2932
2891
  };
2933
- var formatTrustBadge = (item) => {
2934
- if (item.trustScore != null) {
2935
- return `Trust: ${item.trustScore}`;
2936
- }
2937
- return "Trust: --";
2938
- };
2939
- var formatHealthBadge = (status) => {
2892
+ var formatStatusBadge = (status) => {
2940
2893
  if (!status || status === "unknown") return "";
2941
2894
  return ` \u2014 ${status}`;
2942
2895
  };
@@ -2946,21 +2899,19 @@ var formatSearchResults = (results) => {
2946
2899
  const baseName = r.canonicalName ?? r.name;
2947
2900
  const displayName = r.brandName ? `${r.brandName} ${baseName}` : baseName;
2948
2901
  const displayDescription = r.whatItDoes ?? r.description;
2949
- const trustBadge = formatTrustBadge(r);
2950
2902
  const ratingBadge = formatRatingBadge(r.rating);
2951
- const healthBadge = formatHealthBadge(r.availabilityStatus);
2952
- const relevance = r.relevanceScore != null ? ` [${r.relevanceScore.toFixed(3)}]` : "";
2953
- return ` ${r.position}. ${displayName} \u2014 $${r.cost.amount}/call \u2014 ${trustBadge} \u2014 ${ratingBadge}${healthBadge}${relevance}
2903
+ const statusBadge = formatStatusBadge(r.displayStatus);
2904
+ return ` ${r.position}. ${displayName} \u2014 $${r.cost.amount}/call \u2014 ${ratingBadge}${statusBadge}
2954
2905
  "${displayDescription}"`;
2955
2906
  }).join("\n");
2956
2907
  };
2957
2908
  var searchCommand = (appContext) => new Command8("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(
2958
2909
  "--max-cost <amount>",
2959
2910
  `Maximum cost per call in USD (default: ${DEFAULT_MAX_COST_USD})`
2960
- ).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(
2911
+ ).option("--protocol <protocol>", "Payment protocol (x402 or mpp)").option(
2961
2912
  "--status <status>",
2962
2913
  "Filter by availability (healthy, degraded, down)"
2963
- ).option("--all", "Show all results (no trust or health filtering)").option(
2914
+ ).option("--all", "Disable default quality filtering").option(
2964
2915
  "--source <source>",
2965
2916
  "Only show results from this crawl source (e.g. mpp, bazaar)"
2966
2917
  ).option(
@@ -3000,9 +2951,7 @@ var searchCommand = (appContext) => new Command8("search").description("Search f
3000
2951
  limit: options.limit,
3001
2952
  freeOnly: options.free,
3002
2953
  maxCost: effectiveMaxCost,
3003
- minRating: options.minRating,
3004
2954
  protocol: options.protocol,
3005
- minTrust: options.minTrust,
3006
2955
  availabilityStatus: options.status,
3007
2956
  includeAll: options.all,
3008
2957
  source: options.source,
@@ -3020,9 +2969,7 @@ var searchCommand = (appContext) => new Command8("search").description("Search f
3020
2969
  freeOnly: options.free ?? false,
3021
2970
  maxCost: effectiveMaxCost,
3022
2971
  maxCostDefaulted: appliedDefaultMaxCost,
3023
- minRating: options.minRating,
3024
2972
  protocol: options.protocol,
3025
- minTrust: options.minTrust,
3026
2973
  availabilityStatus: options.status,
3027
2974
  includeAll: options.all ?? false,
3028
2975
  source: options.source,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeroxyz/cli",
3
- "version": "0.0.36",
3
+ "version": "0.0.37",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "zero": "dist/index.js",
@@ -16,7 +16,7 @@
16
16
  },
17
17
  "scripts": {
18
18
  "build": "tsup src/index.ts --format esm --out-dir dist --clean",
19
- "build:binary": "tsup --config tsup.binary.ts && cp -r skills hooks dist/pkg/ && pnpm exec pkg dist/pkg/index.cjs --config pkg.json --targets node24-macos-arm64,node24-macos-x64,node24-linux-x64 --output dist/bin/zero",
19
+ "build:binary": "tsup --config tsup.binary.ts && cp -r skills hooks dist/pkg/ && pnpm exec pkg dist/pkg/index.cjs --config pkg.json --targets node24-macos-arm64,node24-macos-x64,node24-linux-x64,node24-linux-arm64 --output dist/bin/zero",
20
20
  "prepublishOnly": "pnpm run build",
21
21
  "dev": "ZERO_ENV=development tsx src/index.ts",
22
22
  "cli": "ZERO_ENV=development ZERO_API_URL=http://localhost:1111 tsx src/index.ts",
@@ -34,7 +34,7 @@
34
34
  "@x402/extensions": "^2.9.0",
35
35
  "@x402/fetch": "^2.9.0",
36
36
  "commander": "^13.0.0",
37
- "mppx": "^0.5.9",
37
+ "mppx": "^0.6.9",
38
38
  "open": "^11.0.0",
39
39
  "posthog-node": "^5.29.2",
40
40
  "viem": "^2.47.10",
@@ -98,13 +98,16 @@ zero review --capability <slug> --success --accuracy <1-5> --value <1-5> --relia
98
98
 
99
99
  ### Workflow
100
100
 
101
- 1. **Search** — `zero search "weather forecast"` finds matching capabilities. Results show name, cost, rating, and success rate.
101
+ 1. **Search** — `zero search "weather forecast"` finds matching capabilities. Results show ranked capabilities with name, cost, availability, and a short description.
102
102
  > **Detail-page → CLI bridge.** When you only have a capability slug (e.g. copied from a zero.xyz capability page), `zero get <slug>` and `zero fetch --capability <slug>` both work as drop-in replacements for the position-based forms. You don't need to run `zero search` first.
103
103
 
104
104
  2. **Inspect** — `zero get 1 --formatted` prints a human summary **and a copy-pasteable `Try it:` command** wired to the capability's schema. Plain `zero get 1` returns full JSON (URL, method, `bodySchema`, examples, pricing) for `jq` pipelines. **If `bodySchema` is `null`**, the capability hasn't been schema-indexed yet — skip it and `zero get 2`, don't invent field names.
105
105
  3. **Call** — `zero fetch <url>` makes the request. If the server returns 402, payment is handled automatically (x402 and MPP, including cross-chain bridging from Base to Tempo).
106
106
  4. **Review** — `zero review <runId>` submits a quality review. Run IDs are printed to **stderr** after a successful fetch (or returned on stdout in `--json` mode). Always review after a paid call, and **pass `--content "<notes>"` whenever you have something specific to say** — the content line lands on the capability's public detail page on zero.xyz, so it's what the next human buyer (and the next agent) reads when deciding whether to call this capability. See "Writing review content" below.
107
107
  5. **Retroactive review** — if you lost a runId, run `zero runs --unreviewed` (or `zero runs --capability <slug> --unreviewed`). `zero review --capability <slug> ...` auto-resolves to your most recent un-reviewed run for that capability.
108
+ 6. **Revise a review** — re-running `zero review <runId> ...` for a run you've already reviewed **overwrites** your prior ratings and content (same wallet only). Use this when a retry succeeded, a result that looked good failed downstream, or you want to expand the notes after more usage. There's no separate edit command — same call, same runId.
109
+
110
+ > **Only your latest review per capability is shown publicly.** When you've reviewed a capability across multiple runs, both the public detail page and the search-ranking math dedupe to your most recent review per capability — older reviews stay in the DB as a version trail but don't display and don't count toward the rating. So if your judgment has changed, submit a fresh review on a recent run (or edit the existing one via the same-`runId` upsert above) — don't assume the old review still represents you.
108
111
 
109
112
  ### Writing review content
110
113
 
@@ -118,6 +121,10 @@ zero review --capability <slug> --success --accuracy <1-5> --value <1-5> --relia
118
121
 
119
122
  Each names the task attempted, what the output actually was, and a specific observation (latency, a gotcha, a fit/misfit note). That's the kind of line a human buyer trusts and another agent can learn from.
120
123
 
124
+ **Name the use case.** State the general type of work you were using the capability for (no private/proprietary detail) so other readers can tell whether their task fits. Examples: *"Used this to generate stock-style hero photography for a vibe-coded landing page"*, *"Called from a daily ETL to enrich new signups with company metadata"*, *"Translating short product blurbs (~80 chars) for a Spanish-language store"*. This is what makes a review useful for someone deciding whether to call the capability for *their* task — not just whether it worked for yours.
125
+
126
+ **Two-part structure works well** when you have enough to say: lead with the human-facing half (use case, what you got, fit/misfit), then a second half with agent-facing technical notes (exact field names, gotchas, retry behavior, schema quirks). Each half is independently useful — humans skim the top, agents grep the bottom.
127
+
121
128
  **Review failures with content too.** Failure notes are arguably more valuable — they warn the next caller. Example: *"FLUX Schnell returned HTTP 500 Internal Server Error — paid 0.003 USDC via MPP but got no image."* Pair with `--no-success`.
122
129
 
123
130
  **Skip `--content` rather than write filler.** "Worked great", "Fast response", or test strings like "trial 1" add noise, pollute the capability's public page, and dilute the signal agents rely on. If you don't have a specific observation, just submit the numeric ratings.
@@ -231,7 +238,7 @@ cat payload.json | zero fetch https://api.example.com --data-stdin
231
238
 
232
239
  ### Rules
233
240
 
234
- - **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.
241
+ - **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 ranking and availability.
235
242
  - **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.
236
243
  - Never guess endpoint URLs or schemas.
237
244
  - Use `--max-pay` before potentially expensive requests.