@zeroxyz/cli 0.0.12 → 0.0.14
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 +290 -85
- package/package.json +3 -1
- package/skills/zero/SKILL.md +6 -2
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/app.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command9 } from "commander";
|
|
5
5
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@zeroxyz/cli",
|
|
9
|
-
version: "0.0.
|
|
9
|
+
version: "0.0.14",
|
|
10
10
|
type: "module",
|
|
11
11
|
bin: {
|
|
12
12
|
zero: "dist/index.js",
|
|
@@ -22,6 +22,7 @@ var package_default = {
|
|
|
22
22
|
},
|
|
23
23
|
scripts: {
|
|
24
24
|
build: "tsup src/index.ts --format esm --out-dir dist --clean",
|
|
25
|
+
"build:binary": "tsup --config tsup.binary.ts && cp -r skills hooks dist/pkg/ && pkg dist/pkg/index.cjs --config pkg.json --targets node24-macos-arm64,node24-macos-x64,node24-linux-x64 --output dist/bin/zero",
|
|
25
26
|
prepublishOnly: "pnpm run build",
|
|
26
27
|
dev: "tsx src/index.ts",
|
|
27
28
|
cli: "ZERO_API_URL=http://localhost:1111 tsx src/index.ts",
|
|
@@ -49,6 +50,7 @@ var package_default = {
|
|
|
49
50
|
"@hono/node-server": "^1.19.13",
|
|
50
51
|
"@types/node": "^25.0.7",
|
|
51
52
|
"@x402/hono": "^2.9.0",
|
|
53
|
+
"@yao-pkg/pkg": "^6.15.0",
|
|
52
54
|
hono: "^4.12.12",
|
|
53
55
|
tsup: "^8.5.1",
|
|
54
56
|
tsx: "^4.21.0",
|
|
@@ -128,7 +130,7 @@ var detectPaymentRequirement = (headers, status) => {
|
|
|
128
130
|
}
|
|
129
131
|
return { protocol: "unknown", raw: {} };
|
|
130
132
|
};
|
|
131
|
-
var fetchCommand = (
|
|
133
|
+
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)").action(
|
|
132
134
|
async (url, options) => {
|
|
133
135
|
try {
|
|
134
136
|
const {
|
|
@@ -137,7 +139,7 @@ var fetchCommand = (appContext2) => new Command2("fetch").description("Fetch a c
|
|
|
137
139
|
paymentService,
|
|
138
140
|
stateService,
|
|
139
141
|
walletService
|
|
140
|
-
} =
|
|
142
|
+
} = appContext.services;
|
|
141
143
|
const startTime = Date.now();
|
|
142
144
|
const headers = {};
|
|
143
145
|
if (options.header) {
|
|
@@ -148,7 +150,10 @@ var fetchCommand = (appContext2) => new Command2("fetch").description("Fetch a c
|
|
|
148
150
|
}
|
|
149
151
|
}
|
|
150
152
|
}
|
|
151
|
-
|
|
153
|
+
const hasContentType = Object.keys(headers).some(
|
|
154
|
+
(k) => k.toLowerCase() === "content-type"
|
|
155
|
+
);
|
|
156
|
+
if (options.data && !hasContentType) {
|
|
152
157
|
headers["content-type"] = "application/json";
|
|
153
158
|
}
|
|
154
159
|
const log = (msg) => console.error(` ${msg}`);
|
|
@@ -267,14 +272,14 @@ var fetchCommand = (appContext2) => new Command2("fetch").description("Fetch a c
|
|
|
267
272
|
|
|
268
273
|
// src/commands/get-command.ts
|
|
269
274
|
import { Command as Command3 } from "commander";
|
|
270
|
-
var getCommand = (
|
|
275
|
+
var getCommand = (appContext) => new Command3("get").description(
|
|
271
276
|
"Get details for a capability by position from last search, or by slug"
|
|
272
277
|
).argument(
|
|
273
278
|
"<identifier>",
|
|
274
279
|
"Position number from search results, or a capability slug"
|
|
275
280
|
).action(async (identifier) => {
|
|
276
281
|
try {
|
|
277
|
-
const { analyticsService, apiService, stateService } =
|
|
282
|
+
const { analyticsService, apiService, stateService } = appContext.services;
|
|
278
283
|
const position = Number.parseInt(identifier, 10);
|
|
279
284
|
const isPosition = !Number.isNaN(position) && position >= 1;
|
|
280
285
|
let capabilityId;
|
|
@@ -339,7 +344,12 @@ var AGENT_TOOLS = [
|
|
|
339
344
|
{ name: "Cursor", configDir: ".cursor" }
|
|
340
345
|
];
|
|
341
346
|
var getPackageRoot = () => {
|
|
342
|
-
let dir
|
|
347
|
+
let dir;
|
|
348
|
+
if (import.meta.url) {
|
|
349
|
+
dir = dirname(fileURLToPath(import.meta.url));
|
|
350
|
+
} else {
|
|
351
|
+
dir = __dirname;
|
|
352
|
+
}
|
|
343
353
|
while (!existsSync2(join2(dir, "package.json"))) {
|
|
344
354
|
const parent = dirname(dir);
|
|
345
355
|
if (parent === dir) break;
|
|
@@ -417,6 +427,22 @@ var installHook = (home) => {
|
|
|
417
427
|
} else {
|
|
418
428
|
preToolUse.push(zeroHookEntry);
|
|
419
429
|
}
|
|
430
|
+
if (!settings.sandbox || typeof settings.sandbox !== "object") {
|
|
431
|
+
settings.sandbox = {};
|
|
432
|
+
}
|
|
433
|
+
const sandbox = settings.sandbox;
|
|
434
|
+
if (!sandbox.network || typeof sandbox.network !== "object") {
|
|
435
|
+
sandbox.network = {};
|
|
436
|
+
}
|
|
437
|
+
const network = sandbox.network;
|
|
438
|
+
if (!Array.isArray(network.allowedDomains)) {
|
|
439
|
+
network.allowedDomains = [];
|
|
440
|
+
}
|
|
441
|
+
const allowedDomains = network.allowedDomains;
|
|
442
|
+
const zeroDomain = "*.zero.xyz";
|
|
443
|
+
if (!allowedDomains.includes(zeroDomain)) {
|
|
444
|
+
allowedDomains.push(zeroDomain);
|
|
445
|
+
}
|
|
420
446
|
writeFileSync2(settingsPath, `${JSON.stringify(settings, null, 2)}
|
|
421
447
|
`);
|
|
422
448
|
return true;
|
|
@@ -450,7 +476,7 @@ var installSkills = (home) => {
|
|
|
450
476
|
}
|
|
451
477
|
return installed;
|
|
452
478
|
};
|
|
453
|
-
var initCommand = (
|
|
479
|
+
var initCommand = (appContext) => new Command4("init").description("Initialize Zero CLI for usage").option("--force", "Overwrite existing configuration").action(async (options) => {
|
|
454
480
|
const home = homedir2();
|
|
455
481
|
const zeroDir = join2(home, ".zero");
|
|
456
482
|
const configPath = join2(zeroDir, "config.json");
|
|
@@ -509,7 +535,7 @@ var initCommand = (appContext2) => new Command4("init").description("Initialize
|
|
|
509
535
|
console.error(
|
|
510
536
|
'Zero is ready! Run `zero search` to find capabilities.\n\nTry:\n zero search "translate text to Spanish"\n zero search "generate an image"\n zero search "weather forecast"'
|
|
511
537
|
);
|
|
512
|
-
|
|
538
|
+
appContext.services.analyticsService.capture("wallet_initialized", {
|
|
513
539
|
// biome-ignore lint/style/useNamingConvention: snake_case for analytics
|
|
514
540
|
agents_detected: agentsDetected,
|
|
515
541
|
// biome-ignore lint/style/useNamingConvention: snake_case for analytics
|
|
@@ -530,7 +556,7 @@ var initCommand = (appContext2) => new Command4("init").description("Initialize
|
|
|
530
556
|
|
|
531
557
|
// src/commands/review-command.ts
|
|
532
558
|
import { Command as Command5 } from "commander";
|
|
533
|
-
var reviewCommand = (
|
|
559
|
+
var reviewCommand = (appContext) => new Command5("review").description("Submit a review for a capability run").addHelpText(
|
|
534
560
|
"after",
|
|
535
561
|
`
|
|
536
562
|
Tips for a great review:
|
|
@@ -542,14 +568,50 @@ Tips for a great review:
|
|
|
542
568
|
|
|
543
569
|
Example:
|
|
544
570
|
zero review run_abc123 --success --accuracy 5 --value 4 --reliability 5 --content "Fast, accurate translation"`
|
|
545
|
-
).argument(
|
|
571
|
+
).argument(
|
|
572
|
+
"[runId]",
|
|
573
|
+
"Run ID to review (omit when using --capability to auto-resolve)"
|
|
574
|
+
).option(
|
|
575
|
+
"--capability <id>",
|
|
576
|
+
"Review by capability uid or slug (auto-picks your most recent un-reviewed run)"
|
|
577
|
+
).option("--success", "The capability succeeded").option("--no-success", "The capability failed").requiredOption("--accuracy <n>", "Accuracy rating (1-5)", Number.parseInt).requiredOption("--value <n>", "Value rating (1-5)", Number.parseInt).requiredOption(
|
|
546
578
|
"--reliability <n>",
|
|
547
579
|
"Reliability rating (1-5)",
|
|
548
580
|
Number.parseInt
|
|
549
581
|
).option("--content <text>", "Optional review text").action(
|
|
550
582
|
async (runId, options) => {
|
|
551
583
|
try {
|
|
552
|
-
const { analyticsService, apiService } =
|
|
584
|
+
const { analyticsService, apiService } = appContext.services;
|
|
585
|
+
if (!runId) {
|
|
586
|
+
if (!options.capability) {
|
|
587
|
+
console.error(
|
|
588
|
+
"Provide a <runId> or --capability <slug> to resolve one."
|
|
589
|
+
);
|
|
590
|
+
process.exitCode = 1;
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
const list = await apiService.listRuns({
|
|
594
|
+
capabilityId: options.capability,
|
|
595
|
+
unreviewed: true,
|
|
596
|
+
limit: 2
|
|
597
|
+
});
|
|
598
|
+
if (list.runs.length === 0) {
|
|
599
|
+
console.error(
|
|
600
|
+
`No un-reviewed runs found for capability "${options.capability}".`
|
|
601
|
+
);
|
|
602
|
+
process.exitCode = 1;
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
if (list.runs.length > 1) {
|
|
606
|
+
console.error(
|
|
607
|
+
`Multiple un-reviewed runs for "${options.capability}". Run "zero runs --capability ${options.capability} --unreviewed" and pass the runId explicitly.`
|
|
608
|
+
);
|
|
609
|
+
process.exitCode = 1;
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
runId = list.runs[0].uid;
|
|
613
|
+
console.log(`Resolved to run ${runId}`);
|
|
614
|
+
}
|
|
553
615
|
for (const [field, val] of [
|
|
554
616
|
["accuracy", options.accuracy],
|
|
555
617
|
["value", options.value],
|
|
@@ -581,53 +643,140 @@ Example:
|
|
|
581
643
|
}
|
|
582
644
|
);
|
|
583
645
|
|
|
584
|
-
// src/commands/
|
|
646
|
+
// src/commands/runs-command.ts
|
|
585
647
|
import { Command as Command6 } from "commander";
|
|
648
|
+
var runsCommand = (appContext) => new Command6("runs").description("List your recent capability runs").addHelpText(
|
|
649
|
+
"after",
|
|
650
|
+
`
|
|
651
|
+
View your recent capability runs \u2014 status, latency, cost, and payment info.
|
|
652
|
+
A leading [\u2713] means the run already has a review; [ ] means it does not.
|
|
653
|
+
|
|
654
|
+
Examples:
|
|
655
|
+
zero runs # most recent runs
|
|
656
|
+
zero runs --unreviewed # filter to runs without a review
|
|
657
|
+
zero runs --capability translate-en # filter to one capability (uid or slug)`
|
|
658
|
+
).option("--capability <id>", "Filter by capability uid or slug").option("--unreviewed", "Only show runs without a review").option(
|
|
659
|
+
"--limit <n>",
|
|
660
|
+
"Max rows (1-100, default 25)",
|
|
661
|
+
(v) => Number.parseInt(v, 10)
|
|
662
|
+
).action(
|
|
663
|
+
async (options) => {
|
|
664
|
+
try {
|
|
665
|
+
const { apiService } = appContext.services;
|
|
666
|
+
const result = await apiService.listRuns({
|
|
667
|
+
capabilityId: options.capability,
|
|
668
|
+
unreviewed: options.unreviewed,
|
|
669
|
+
limit: options.limit
|
|
670
|
+
});
|
|
671
|
+
if (result.runs.length === 0) {
|
|
672
|
+
console.log("No runs found.");
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
for (const r of result.runs) {
|
|
676
|
+
const when = r.createdAt.toISOString().replace("T", " ").slice(0, 19);
|
|
677
|
+
const mark = r.reviewed ? "\u2713" : " ";
|
|
678
|
+
const status = r.status ?? "\u2014";
|
|
679
|
+
const latency = r.latencyMs != null ? `${r.latencyMs}ms` : "\u2014";
|
|
680
|
+
console.log(
|
|
681
|
+
`[${mark}] ${r.uid} ${r.capabilitySlug} status=${status} ${latency} ${when}`
|
|
682
|
+
);
|
|
683
|
+
}
|
|
684
|
+
if (result.nextCursor) {
|
|
685
|
+
console.log(`
|
|
686
|
+
(more available \u2014 use --limit to see more)`);
|
|
687
|
+
}
|
|
688
|
+
} catch (err) {
|
|
689
|
+
console.error(err instanceof Error ? err.message : "Failed");
|
|
690
|
+
process.exitCode = 1;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
);
|
|
694
|
+
|
|
695
|
+
// src/commands/search-command.ts
|
|
696
|
+
import { Command as Command7 } from "commander";
|
|
586
697
|
var formatReviewCount = (count) => {
|
|
587
698
|
if (count >= 1e3) return `${(count / 1e3).toFixed(1)}k`;
|
|
588
699
|
return count.toString();
|
|
589
700
|
};
|
|
701
|
+
var formatRatingBadge = (rating) => {
|
|
702
|
+
if (rating.state === "unrated") return "\u2014 unrated";
|
|
703
|
+
const successPct = `${Math.round(Number.parseFloat(rating.successRate) * 100)}%`;
|
|
704
|
+
const reviews = formatReviewCount(rating.reviews);
|
|
705
|
+
if (rating.stars) {
|
|
706
|
+
return `\u2605 ${rating.stars}/5 (${successPct} success, ${reviews} reviews)`;
|
|
707
|
+
}
|
|
708
|
+
return `${successPct} success \xB7 ${reviews} reviews`;
|
|
709
|
+
};
|
|
590
710
|
var formatSearchResults = (results) => {
|
|
591
711
|
if (results.length === 0) return "No capabilities found.";
|
|
592
712
|
return results.map((r) => {
|
|
593
|
-
const
|
|
594
|
-
const
|
|
595
|
-
const
|
|
596
|
-
return ` ${r.position}. ${displayName} \u2014 $${r.cost.amount}/call \u2014
|
|
597
|
-
"${
|
|
713
|
+
const baseName = r.canonicalName ?? r.name;
|
|
714
|
+
const displayName = r.brandName ? `${r.brandName} ${baseName}` : baseName;
|
|
715
|
+
const displayDescription = r.whatItDoes ?? r.description;
|
|
716
|
+
return ` ${r.position}. ${displayName} \u2014 $${r.cost.amount}/call \u2014 ${formatRatingBadge(r.rating)}
|
|
717
|
+
"${displayDescription}"`;
|
|
598
718
|
}).join("\n");
|
|
599
719
|
};
|
|
600
|
-
var searchCommand = (
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
720
|
+
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)").action(
|
|
721
|
+
async (query, options) => {
|
|
722
|
+
try {
|
|
723
|
+
const { analyticsService, apiService, stateService } = appContext.services;
|
|
724
|
+
if (options.protocol && !["x402", "mpp"].includes(options.protocol)) {
|
|
725
|
+
console.error(
|
|
726
|
+
`Invalid protocol "${options.protocol}". Must be x402 or mpp.`
|
|
727
|
+
);
|
|
728
|
+
process.exitCode = 1;
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
const result = await apiService.search({
|
|
732
|
+
query,
|
|
733
|
+
offset: options.offset,
|
|
734
|
+
limit: options.limit,
|
|
735
|
+
freeOnly: options.free,
|
|
736
|
+
maxCost: options.maxCost,
|
|
737
|
+
minRating: options.minRating,
|
|
738
|
+
protocol: options.protocol
|
|
739
|
+
});
|
|
740
|
+
analyticsService.capture("search_executed", {
|
|
741
|
+
query,
|
|
742
|
+
resultCount: result.capabilities.length
|
|
743
|
+
});
|
|
744
|
+
if (options.json) {
|
|
745
|
+
console.log(JSON.stringify(result, null, 2));
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
stateService.saveLastSearch({
|
|
749
|
+
searchId: result.searchId,
|
|
750
|
+
capabilities: result.capabilities.map((c) => ({
|
|
751
|
+
position: c.position,
|
|
752
|
+
id: c.id,
|
|
753
|
+
url: c.url
|
|
754
|
+
}))
|
|
755
|
+
});
|
|
756
|
+
console.log(formatSearchResults(result.capabilities));
|
|
757
|
+
if (result.hasMore) {
|
|
758
|
+
console.error(
|
|
759
|
+
`
|
|
760
|
+
Showing ${result.capabilities.length} of ${result.total} results. Use --offset ${result.offset + result.capabilities.length} to see more.`
|
|
761
|
+
);
|
|
762
|
+
}
|
|
763
|
+
if (result.capabilities.length > 0) {
|
|
764
|
+
console.error(
|
|
765
|
+
"\n Run `zero get {NUMBER}` to view a capability.\n"
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
} catch (err) {
|
|
769
|
+
console.error(err instanceof Error ? err.message : "Search failed");
|
|
770
|
+
process.exitCode = 1;
|
|
619
771
|
}
|
|
620
|
-
} catch (err) {
|
|
621
|
-
console.error(err instanceof Error ? err.message : "Search failed");
|
|
622
|
-
process.exitCode = 1;
|
|
623
772
|
}
|
|
624
|
-
|
|
773
|
+
);
|
|
625
774
|
|
|
626
775
|
// src/commands/wallet-command.ts
|
|
627
|
-
import { Command as
|
|
776
|
+
import { Command as Command8 } from "commander";
|
|
628
777
|
import open from "open";
|
|
629
|
-
var walletBalanceCommand = (
|
|
630
|
-
const { walletService } =
|
|
778
|
+
var walletBalanceCommand = (appContext) => new Command8("balance").description("Show wallet balance").action(async () => {
|
|
779
|
+
const { walletService } = appContext.services;
|
|
631
780
|
const balance = await walletService.getBalance();
|
|
632
781
|
if (balance === null) {
|
|
633
782
|
console.error("No wallet configured. Run `zero init` first.");
|
|
@@ -641,9 +790,9 @@ var walletBalanceCommand = (appContext2) => new Command7("balance").description(
|
|
|
641
790
|
}
|
|
642
791
|
console.log(`${balance.amount} ${balance.asset}`);
|
|
643
792
|
});
|
|
644
|
-
var walletFundCommand = (
|
|
793
|
+
var walletFundCommand = (appContext) => new Command8("fund").description("Fund your wallet").argument("[amount]", "Amount to fund in USDC").option("--manual", "Show wallet address for manual transfer").action(
|
|
645
794
|
async (amount, options) => {
|
|
646
|
-
const { analyticsService, walletService } =
|
|
795
|
+
const { analyticsService, walletService } = appContext.services;
|
|
647
796
|
const address = walletService.getAddress();
|
|
648
797
|
if (!address) {
|
|
649
798
|
console.error("No wallet configured. Run `zero init` first.");
|
|
@@ -659,7 +808,7 @@ ${address}`);
|
|
|
659
808
|
});
|
|
660
809
|
return;
|
|
661
810
|
}
|
|
662
|
-
const url = await
|
|
811
|
+
const url = await appContext.services.apiService.getFundingUrl(amount);
|
|
663
812
|
if (url) {
|
|
664
813
|
await open(url);
|
|
665
814
|
console.log("Opened funding page in your browser.");
|
|
@@ -678,8 +827,8 @@ ${address}`);
|
|
|
678
827
|
}
|
|
679
828
|
}
|
|
680
829
|
);
|
|
681
|
-
var walletAddressCommand = (
|
|
682
|
-
const { walletService } =
|
|
830
|
+
var walletAddressCommand = (appContext) => new Command8("address").description("Show wallet address").action(() => {
|
|
831
|
+
const { walletService } = appContext.services;
|
|
683
832
|
const address = walletService.getAddress();
|
|
684
833
|
if (!address) {
|
|
685
834
|
console.error("No wallet configured. Run `zero init` first.");
|
|
@@ -688,29 +837,30 @@ var walletAddressCommand = (appContext2) => new Command7("address").description(
|
|
|
688
837
|
}
|
|
689
838
|
console.log(address);
|
|
690
839
|
});
|
|
691
|
-
var walletCommand = (
|
|
692
|
-
const cmd = new
|
|
693
|
-
cmd.addCommand(walletBalanceCommand(
|
|
694
|
-
cmd.addCommand(walletFundCommand(
|
|
695
|
-
cmd.addCommand(walletAddressCommand(
|
|
840
|
+
var walletCommand = (appContext) => {
|
|
841
|
+
const cmd = new Command8("wallet").description("Manage your wallet");
|
|
842
|
+
cmd.addCommand(walletBalanceCommand(appContext));
|
|
843
|
+
cmd.addCommand(walletFundCommand(appContext));
|
|
844
|
+
cmd.addCommand(walletAddressCommand(appContext));
|
|
696
845
|
return cmd;
|
|
697
846
|
};
|
|
698
847
|
|
|
699
848
|
// src/app.ts
|
|
700
|
-
var createApp = (
|
|
701
|
-
const { analyticsService } =
|
|
702
|
-
const program = new
|
|
849
|
+
var createApp = (appContext) => {
|
|
850
|
+
const { analyticsService } = appContext.services;
|
|
851
|
+
const program = new Command9().name("zero").description("Zero CLI \u2014 Search engine and payment platform for AI agents").version(package_default.version, "-v, --version").exitOverride().hook("preAction", (_thisCommand, actionCommand) => {
|
|
703
852
|
analyticsService.capture("command_executed", {
|
|
704
853
|
command: actionCommand.name()
|
|
705
854
|
});
|
|
706
855
|
});
|
|
707
|
-
program.addCommand(initCommand(
|
|
708
|
-
program.addCommand(searchCommand(
|
|
709
|
-
program.addCommand(getCommand(
|
|
710
|
-
program.addCommand(fetchCommand(
|
|
711
|
-
program.addCommand(reviewCommand(
|
|
712
|
-
program.addCommand(
|
|
713
|
-
program.addCommand(
|
|
856
|
+
program.addCommand(initCommand(appContext));
|
|
857
|
+
program.addCommand(searchCommand(appContext));
|
|
858
|
+
program.addCommand(getCommand(appContext));
|
|
859
|
+
program.addCommand(fetchCommand(appContext));
|
|
860
|
+
program.addCommand(reviewCommand(appContext));
|
|
861
|
+
program.addCommand(runsCommand(appContext));
|
|
862
|
+
program.addCommand(walletCommand(appContext));
|
|
863
|
+
program.addCommand(configCommand(appContext));
|
|
714
864
|
return program;
|
|
715
865
|
};
|
|
716
866
|
|
|
@@ -834,16 +984,22 @@ var searchResultSchema = z2.object({
|
|
|
834
984
|
name: z2.string(),
|
|
835
985
|
canonicalName: z2.string().nullable().optional(),
|
|
836
986
|
description: z2.string(),
|
|
987
|
+
whatItDoes: z2.string().nullable().optional(),
|
|
837
988
|
url: z2.string(),
|
|
838
989
|
cost: z2.object({ amount: z2.string(), asset: z2.string() }),
|
|
839
990
|
rating: z2.object({
|
|
840
991
|
score: z2.string(),
|
|
841
992
|
successRate: z2.string(),
|
|
842
|
-
reviews: z2.number()
|
|
993
|
+
reviews: z2.number(),
|
|
994
|
+
stars: z2.string().nullable().optional(),
|
|
995
|
+
state: z2.enum(["unrated", "rated"]).optional()
|
|
843
996
|
})
|
|
844
997
|
});
|
|
845
998
|
var searchResponseSchema = z2.object({
|
|
846
999
|
searchId: z2.string(),
|
|
1000
|
+
total: z2.number().optional().default(0),
|
|
1001
|
+
offset: z2.number().optional().default(0),
|
|
1002
|
+
hasMore: z2.boolean().optional().default(false),
|
|
847
1003
|
capabilities: z2.array(searchResultSchema)
|
|
848
1004
|
});
|
|
849
1005
|
var capabilityResponseSchema = z2.object({
|
|
@@ -863,7 +1019,9 @@ var capabilityResponseSchema = z2.object({
|
|
|
863
1019
|
rating: z2.object({
|
|
864
1020
|
score: z2.string(),
|
|
865
1021
|
successRate: z2.string(),
|
|
866
|
-
reviews: z2.number()
|
|
1022
|
+
reviews: z2.number(),
|
|
1023
|
+
stars: z2.string().nullable().optional(),
|
|
1024
|
+
state: z2.enum(["unrated", "rated"]).optional()
|
|
867
1025
|
}),
|
|
868
1026
|
paymentMethods: z2.array(
|
|
869
1027
|
z2.object({
|
|
@@ -885,6 +1043,27 @@ var createReviewResponseSchema = z2.object({
|
|
|
885
1043
|
reviewId: z2.string(),
|
|
886
1044
|
recorded: z2.boolean()
|
|
887
1045
|
});
|
|
1046
|
+
var runListItemSchema = z2.object({
|
|
1047
|
+
uid: z2.string(),
|
|
1048
|
+
capabilityUid: z2.string(),
|
|
1049
|
+
capabilitySlug: z2.string(),
|
|
1050
|
+
capabilityName: z2.string(),
|
|
1051
|
+
status: z2.number().nullable(),
|
|
1052
|
+
latencyMs: z2.number().nullable(),
|
|
1053
|
+
cost: z2.object({ amount: z2.string(), asset: z2.string().nullable() }).nullable(),
|
|
1054
|
+
payment: z2.object({
|
|
1055
|
+
protocol: z2.string(),
|
|
1056
|
+
chain: z2.string().nullable(),
|
|
1057
|
+
txHash: z2.string().nullable(),
|
|
1058
|
+
mode: z2.string().nullable()
|
|
1059
|
+
}).nullable(),
|
|
1060
|
+
createdAt: z2.coerce.date(),
|
|
1061
|
+
reviewed: z2.boolean()
|
|
1062
|
+
});
|
|
1063
|
+
var listRunsResponseSchema = z2.object({
|
|
1064
|
+
runs: z2.array(runListItemSchema),
|
|
1065
|
+
nextCursor: z2.string().nullable()
|
|
1066
|
+
});
|
|
888
1067
|
var buildCanonicalMessage = (method, path, body, timestamp, nonce) => {
|
|
889
1068
|
const bodyHash = createHash2("sha256").update(body ?? "").digest("hex");
|
|
890
1069
|
return `${method}:${path}:${bodyHash}:${timestamp}:${nonce}`;
|
|
@@ -933,8 +1112,8 @@ var ApiService = class {
|
|
|
933
1112
|
}
|
|
934
1113
|
return response.json();
|
|
935
1114
|
};
|
|
936
|
-
search = async (
|
|
937
|
-
const json = await this.request("POST", "/v1/search",
|
|
1115
|
+
search = async (options) => {
|
|
1116
|
+
const json = await this.request("POST", "/v1/search", options);
|
|
938
1117
|
return searchResponseSchema.parse(json);
|
|
939
1118
|
};
|
|
940
1119
|
getCapability = async (id, searchId) => {
|
|
@@ -949,6 +1128,16 @@ var ApiService = class {
|
|
|
949
1128
|
const json = await this.request("POST", "/v1/runs", data);
|
|
950
1129
|
return createRunResponseSchema.parse(json);
|
|
951
1130
|
};
|
|
1131
|
+
listRuns = async (params = {}) => {
|
|
1132
|
+
const qs = new URLSearchParams();
|
|
1133
|
+
if (params.capabilityId) qs.set("capabilityId", params.capabilityId);
|
|
1134
|
+
if (params.unreviewed) qs.set("unreviewed", "true");
|
|
1135
|
+
if (params.limit) qs.set("limit", String(params.limit));
|
|
1136
|
+
if (params.cursor) qs.set("cursor", params.cursor);
|
|
1137
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
1138
|
+
const json = await this.request("GET", `/v1/runs${suffix}`);
|
|
1139
|
+
return listRunsResponseSchema.parse(json);
|
|
1140
|
+
};
|
|
952
1141
|
createReview = async (data) => {
|
|
953
1142
|
const json = await this.request("POST", "/v1/reviews", data);
|
|
954
1143
|
return createReviewResponseSchema.parse(json);
|
|
@@ -995,6 +1184,12 @@ var BASE_CHAIN_ID = 8453;
|
|
|
995
1184
|
var TEMPO_CHAIN_ID = 4217;
|
|
996
1185
|
var TEMPO_TESTNET_CHAIN_ID = 42431;
|
|
997
1186
|
var DEFAULT_MAX_DEPOSIT = "100";
|
|
1187
|
+
var KNOWN_EIP712_DOMAINS = {
|
|
1188
|
+
// USDC on Base
|
|
1189
|
+
[USDC_BASE.toLowerCase()]: { name: "USDC", version: "2" },
|
|
1190
|
+
// USDC on Base Sepolia
|
|
1191
|
+
[USDC_BASE_SEPOLIA.toLowerCase()]: { name: "USDC", version: "2" }
|
|
1192
|
+
};
|
|
998
1193
|
var buildRelayClientOptions = () => ({
|
|
999
1194
|
baseApiUrl: MAINNET_RELAY_API,
|
|
1000
1195
|
source: "zero-cli",
|
|
@@ -1116,6 +1311,13 @@ var PaymentService = class {
|
|
|
1116
1311
|
new ExactEvmScheme(this.account)
|
|
1117
1312
|
);
|
|
1118
1313
|
client.onBeforePaymentCreation(async (context) => {
|
|
1314
|
+
const selected = context.selectedRequirements;
|
|
1315
|
+
if (selected && (!selected.extra?.name || !selected.extra?.version)) {
|
|
1316
|
+
const known = KNOWN_EIP712_DOMAINS[selected.asset?.toLowerCase() ?? ""];
|
|
1317
|
+
if (known) {
|
|
1318
|
+
selected.extra = { ...selected.extra, ...known };
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1119
1321
|
const requirement = context.paymentRequired.accepts[0];
|
|
1120
1322
|
if (!requirement) return;
|
|
1121
1323
|
capturedAmount = formatUnits(BigInt(requirement.amount), 6);
|
|
@@ -1373,20 +1575,23 @@ var createAppContext = () => {
|
|
|
1373
1575
|
};
|
|
1374
1576
|
|
|
1375
1577
|
// src/index.ts
|
|
1376
|
-
var
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
var app = createApp(appContext);
|
|
1382
|
-
try {
|
|
1383
|
-
await app.parseAsync(process.argv);
|
|
1384
|
-
} catch (err) {
|
|
1385
|
-
const isCommanderExit = err instanceof Error && "exitCode" in err && err.exitCode === 0;
|
|
1386
|
-
if (!isCommanderExit) {
|
|
1387
|
-
console.error(err instanceof Error ? err.message : "Unexpected error");
|
|
1388
|
-
process.exitCode = 1;
|
|
1578
|
+
var main = async () => {
|
|
1579
|
+
const appContext = createAppContext();
|
|
1580
|
+
if (!appContext) {
|
|
1581
|
+
console.error("Failed to create app context");
|
|
1582
|
+
process.exit(1);
|
|
1389
1583
|
}
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1584
|
+
const app = createApp(appContext);
|
|
1585
|
+
try {
|
|
1586
|
+
await app.parseAsync(process.argv);
|
|
1587
|
+
} catch (err) {
|
|
1588
|
+
const isCommanderExit = err instanceof Error && "exitCode" in err && err.exitCode === 0;
|
|
1589
|
+
if (!isCommanderExit) {
|
|
1590
|
+
console.error(err instanceof Error ? err.message : "Unexpected error");
|
|
1591
|
+
process.exitCode = 1;
|
|
1592
|
+
}
|
|
1593
|
+
} finally {
|
|
1594
|
+
await appContext.services.analyticsService.shutdown();
|
|
1595
|
+
}
|
|
1596
|
+
};
|
|
1597
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeroxyz/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"zero": "dist/index.js",
|
|
@@ -16,6 +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/ && pkg dist/pkg/index.cjs --config pkg.json --targets node24-macos-arm64,node24-macos-x64,node24-linux-x64 --output dist/bin/zero",
|
|
19
20
|
"prepublishOnly": "pnpm run build",
|
|
20
21
|
"dev": "tsx src/index.ts",
|
|
21
22
|
"cli": "ZERO_API_URL=http://localhost:1111 tsx src/index.ts",
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
"@hono/node-server": "^1.19.13",
|
|
44
45
|
"@types/node": "^25.0.7",
|
|
45
46
|
"@x402/hono": "^2.9.0",
|
|
47
|
+
"@yao-pkg/pkg": "^6.15.0",
|
|
46
48
|
"hono": "^4.12.12",
|
|
47
49
|
"tsup": "^8.5.1",
|
|
48
50
|
"tsx": "^4.21.0",
|
package/skills/zero/SKILL.md
CHANGED
|
@@ -50,7 +50,9 @@ Starter prompts should be user-facing tasks, not command templates:
|
|
|
50
50
|
zero search "<query>"
|
|
51
51
|
zero get <position>
|
|
52
52
|
zero fetch <url> [-d '<json>'] [-H "Key:Value"] [--max-pay <amount>]
|
|
53
|
+
zero runs [--capability <slug>] [--unreviewed]
|
|
53
54
|
zero review <runId> --accuracy <1-5> --value <1-5> --reliability <1-5>
|
|
55
|
+
zero review --capability <slug> --success --accuracy <1-5> --value <1-5> --reliability <1-5>
|
|
54
56
|
```
|
|
55
57
|
|
|
56
58
|
### Workflow
|
|
@@ -58,7 +60,8 @@ zero review <runId> --accuracy <1-5> --value <1-5> --reliability <1-5>
|
|
|
58
60
|
1. **Search** — `zero search "weather forecast"` finds matching capabilities. Results show name, cost, rating, and success rate.
|
|
59
61
|
2. **Inspect** — `zero get 1` returns full details for result #1: URL, method, headers, body schema, examples, and pricing.
|
|
60
62
|
3. **Call** — `zero fetch <url>` makes the request. If the server returns 402, payment is handled automatically (x402 and MPP protocols, including cross-chain bridging from Base to Tempo).
|
|
61
|
-
4. **Review** — `zero review <runId>` submits a quality review. Run IDs are printed after a successful fetch.
|
|
63
|
+
4. **Review** — `zero review <runId>` submits a quality review. Run IDs are printed after a successful fetch. **Always review after a paid call** — reviews bias future search rankings, so this is how you tune future results to services that actually work for you.
|
|
64
|
+
5. **Retroactive review** — if you lost a runId, run `zero runs --unreviewed` (or `zero runs --capability <slug> --unreviewed`) to find it. `zero review --capability <slug> ...` will auto-resolve to your most recent un-reviewed run for that capability.
|
|
62
65
|
|
|
63
66
|
### Request Templates
|
|
64
67
|
|
|
@@ -85,7 +88,8 @@ zero fetch https://api.example.com/expensive --max-pay 0.50
|
|
|
85
88
|
|
|
86
89
|
- Always discover capabilities with `zero search` + `zero get` before calling; never guess endpoint URLs or schemas.
|
|
87
90
|
- Use `--max-pay` before potentially expensive requests.
|
|
88
|
-
- Review capabilities after
|
|
91
|
+
- Review capabilities after every paid call. The review signal feeds search ranking — skipping reviews means your next search is less informed.
|
|
92
|
+
- Before ending a multi-call task, run `zero runs --unreviewed` and review anything you missed.
|
|
89
93
|
|
|
90
94
|
## Configuration
|
|
91
95
|
|