@zeroxyz/cli 0.0.26 → 0.0.28
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 +127 -46
- package/package.json +1 -1
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 Command12 } 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.28",
|
|
10
10
|
type: "module",
|
|
11
11
|
bin: {
|
|
12
12
|
zero: "dist/index.js",
|
|
@@ -1167,9 +1167,14 @@ var isTextContentType = (contentType) => {
|
|
|
1167
1167
|
if (ct === "application/x-www-form-urlencoded") return true;
|
|
1168
1168
|
return false;
|
|
1169
1169
|
};
|
|
1170
|
-
var
|
|
1171
|
-
if (
|
|
1172
|
-
const
|
|
1170
|
+
var looksLikeX402V1Body = (body) => {
|
|
1171
|
+
if (!body || typeof body !== "object") return false;
|
|
1172
|
+
const b = body;
|
|
1173
|
+
return b.x402Version === 1 && Array.isArray(b.accepts) && b.accepts.length > 0;
|
|
1174
|
+
};
|
|
1175
|
+
var detectPaymentRequirement = async (response) => {
|
|
1176
|
+
if (response.status !== 402) return null;
|
|
1177
|
+
const x402Header = response.headers.get("payment-required") ?? response.headers.get("x-payment-required");
|
|
1173
1178
|
if (x402Header) {
|
|
1174
1179
|
try {
|
|
1175
1180
|
const decoded = JSON.parse(
|
|
@@ -1180,10 +1185,20 @@ var detectPaymentRequirement = (headers, status) => {
|
|
|
1180
1185
|
return { protocol: "x402", raw: { encoded: x402Header } };
|
|
1181
1186
|
}
|
|
1182
1187
|
}
|
|
1183
|
-
const wwwAuth = headers.get("www-authenticate");
|
|
1188
|
+
const wwwAuth = response.headers.get("www-authenticate");
|
|
1184
1189
|
if (wwwAuth?.toLowerCase().includes("payment")) {
|
|
1185
1190
|
return { protocol: "mpp", raw: { "www-authenticate": wwwAuth } };
|
|
1186
1191
|
}
|
|
1192
|
+
try {
|
|
1193
|
+
const text = await response.clone().text();
|
|
1194
|
+
if (text) {
|
|
1195
|
+
const parsed = JSON.parse(text);
|
|
1196
|
+
if (looksLikeX402V1Body(parsed)) {
|
|
1197
|
+
return { protocol: "x402", raw: parsed };
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
} catch {
|
|
1201
|
+
}
|
|
1187
1202
|
return { protocol: "unknown", raw: {} };
|
|
1188
1203
|
};
|
|
1189
1204
|
var fetchCommand = (appContext) => new Command3("fetch").description("Fetch a capability URL with automatic payment handling").argument("<url>", "URL to fetch").option(
|
|
@@ -1258,10 +1273,7 @@ var fetchCommand = (appContext) => new Command3("fetch").description("Fetch a ca
|
|
|
1258
1273
|
try {
|
|
1259
1274
|
log(`Calling ${url}...`);
|
|
1260
1275
|
const response = await fetch(url, requestInit);
|
|
1261
|
-
const paymentReq = detectPaymentRequirement(
|
|
1262
|
-
response.headers,
|
|
1263
|
-
response.status
|
|
1264
|
-
);
|
|
1276
|
+
const paymentReq = await detectPaymentRequirement(response);
|
|
1265
1277
|
if (paymentReq) {
|
|
1266
1278
|
log(
|
|
1267
1279
|
`Payment required (${paymentReq.protocol}) \u2014 preparing payment...`
|
|
@@ -1612,10 +1624,14 @@ import { fileURLToPath } from "url";
|
|
|
1612
1624
|
import { Command as Command5 } from "commander";
|
|
1613
1625
|
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
|
|
1614
1626
|
var AGENT_TOOLS = [
|
|
1615
|
-
{ name: "Claude Code",
|
|
1616
|
-
{ name: "Codex",
|
|
1617
|
-
{
|
|
1618
|
-
|
|
1627
|
+
{ name: "Claude Code", detectDir: ".claude", skillsDir: ".claude/skills" },
|
|
1628
|
+
{ name: "Codex", detectDir: ".codex", skillsDir: ".agents/skills" },
|
|
1629
|
+
{
|
|
1630
|
+
name: "OpenCode",
|
|
1631
|
+
detectDir: ".config/opencode",
|
|
1632
|
+
skillsDir: ".config/opencode/skills"
|
|
1633
|
+
},
|
|
1634
|
+
{ name: "Cursor", detectDir: ".cursor", skillsDir: ".cursor/skills" }
|
|
1619
1635
|
];
|
|
1620
1636
|
var getPackageRoot = () => {
|
|
1621
1637
|
let dir;
|
|
@@ -1754,7 +1770,7 @@ var CONFLICTING_SKILL_PATTERNS = ["zam", "tempo"];
|
|
|
1754
1770
|
var findConflictingSkills = (home) => {
|
|
1755
1771
|
const found = [];
|
|
1756
1772
|
for (const tool of AGENT_TOOLS) {
|
|
1757
|
-
const toolSkillsPath = join2(home, tool.
|
|
1773
|
+
const toolSkillsPath = join2(home, tool.skillsDir);
|
|
1758
1774
|
if (!existsSync2(toolSkillsPath)) continue;
|
|
1759
1775
|
const entries = readdirSync(toolSkillsPath, { withFileTypes: true });
|
|
1760
1776
|
for (const entry of entries) {
|
|
@@ -1785,11 +1801,11 @@ var installSkills = (home) => {
|
|
|
1785
1801
|
const skillDirs = readdirSync(skillsSourceDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
1786
1802
|
const installed = [];
|
|
1787
1803
|
for (const tool of AGENT_TOOLS) {
|
|
1788
|
-
const
|
|
1789
|
-
if (!existsSync2(
|
|
1804
|
+
const toolDetectPath = join2(home, tool.detectDir);
|
|
1805
|
+
if (!existsSync2(toolDetectPath)) {
|
|
1790
1806
|
continue;
|
|
1791
1807
|
}
|
|
1792
|
-
const toolSkillsPath = join2(
|
|
1808
|
+
const toolSkillsPath = join2(home, tool.skillsDir);
|
|
1793
1809
|
mkdirSync2(toolSkillsPath, { recursive: true });
|
|
1794
1810
|
for (const skillDir of skillDirs) {
|
|
1795
1811
|
const src = join2(skillsSourceDir, skillDir);
|
|
@@ -1809,7 +1825,7 @@ var installSkills = (home) => {
|
|
|
1809
1825
|
}
|
|
1810
1826
|
return installed;
|
|
1811
1827
|
};
|
|
1812
|
-
var
|
|
1828
|
+
var runInit = async (appContext, options = {}) => {
|
|
1813
1829
|
appContext.services.analyticsService.capture("init_started", {
|
|
1814
1830
|
force: options.force ?? false
|
|
1815
1831
|
});
|
|
@@ -1859,7 +1875,7 @@ var initCommand = (appContext) => new Command5("init").description("Initialize Z
|
|
|
1859
1875
|
let hookInstalled = false;
|
|
1860
1876
|
let hookError = null;
|
|
1861
1877
|
for (const tool of AGENT_TOOLS) {
|
|
1862
|
-
if (existsSync2(join2(home, tool.
|
|
1878
|
+
if (existsSync2(join2(home, tool.detectDir))) {
|
|
1863
1879
|
agentsDetected.push(tool.name);
|
|
1864
1880
|
}
|
|
1865
1881
|
}
|
|
@@ -1920,16 +1936,18 @@ To remove them, run: zero init cleanup`
|
|
|
1920
1936
|
conflicting_skills_found: conflictingSkills.length,
|
|
1921
1937
|
force: options.force ?? false
|
|
1922
1938
|
});
|
|
1939
|
+
return { walletAddress, walletCreated };
|
|
1923
1940
|
} catch (err) {
|
|
1924
1941
|
appContext.services.analyticsService.capture("init_failed", {
|
|
1925
1942
|
step: currentStep,
|
|
1926
|
-
error: truncateError(
|
|
1927
|
-
err instanceof Error ? err.message : String(err)
|
|
1928
|
-
),
|
|
1943
|
+
error: truncateError(err instanceof Error ? err.message : String(err)),
|
|
1929
1944
|
force: options.force ?? false
|
|
1930
1945
|
});
|
|
1931
1946
|
throw err;
|
|
1932
1947
|
}
|
|
1948
|
+
};
|
|
1949
|
+
var initCommand = (appContext) => new Command5("init").description("Initialize Zero CLI for usage").option("--force", "Overwrite existing configuration").action(async (options) => {
|
|
1950
|
+
await runInit(appContext, options);
|
|
1933
1951
|
}).addCommand(
|
|
1934
1952
|
new Command5("cleanup").description(
|
|
1935
1953
|
"Remove deprecated skills (zam, tempo) that conflict with Zero"
|
|
@@ -2455,10 +2473,71 @@ var walletCommand = (appContext) => {
|
|
|
2455
2473
|
return cmd;
|
|
2456
2474
|
};
|
|
2457
2475
|
|
|
2476
|
+
// src/commands/welcome-command.ts
|
|
2477
|
+
import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
|
|
2478
|
+
import { homedir as homedir4 } from "os";
|
|
2479
|
+
import { join as join4 } from "path";
|
|
2480
|
+
import { Command as Command11 } from "commander";
|
|
2481
|
+
import open2 from "open";
|
|
2482
|
+
import { getAddress } from "viem";
|
|
2483
|
+
import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
|
|
2484
|
+
var readPrivateKey = () => {
|
|
2485
|
+
const configPath = join4(homedir4(), ".zero", "config.json");
|
|
2486
|
+
if (!existsSync4(configPath)) return null;
|
|
2487
|
+
try {
|
|
2488
|
+
const config = JSON.parse(readFileSync6(configPath, "utf8"));
|
|
2489
|
+
if (typeof config.privateKey === "string") {
|
|
2490
|
+
return config.privateKey;
|
|
2491
|
+
}
|
|
2492
|
+
} catch {
|
|
2493
|
+
return null;
|
|
2494
|
+
}
|
|
2495
|
+
return null;
|
|
2496
|
+
};
|
|
2497
|
+
var welcomeCommand = (appContext) => new Command11("welcome").description("Claim your $5 welcome bonus.").action(async () => {
|
|
2498
|
+
const { analyticsService } = appContext.services;
|
|
2499
|
+
analyticsService.capture("welcome_started", {});
|
|
2500
|
+
try {
|
|
2501
|
+
let privateKey = readPrivateKey();
|
|
2502
|
+
if (!privateKey) {
|
|
2503
|
+
await runInit(appContext);
|
|
2504
|
+
privateKey = readPrivateKey();
|
|
2505
|
+
if (!privateKey) {
|
|
2506
|
+
throw new Error("Wallet initialization failed");
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
const account = privateKeyToAccount3(privateKey);
|
|
2510
|
+
const walletAddress = getAddress(account.address);
|
|
2511
|
+
const walletSignature = await account.signMessage({
|
|
2512
|
+
message: walletAddress
|
|
2513
|
+
});
|
|
2514
|
+
const url = new URL("/welcome", appContext.env.ZERO_WEB_URL);
|
|
2515
|
+
url.searchParams.set("wallet", walletAddress);
|
|
2516
|
+
url.searchParams.set("walletSignature", walletSignature);
|
|
2517
|
+
console.log(
|
|
2518
|
+
`Opening ${url.toString()}
|
|
2519
|
+
|
|
2520
|
+
If your browser didn't open, paste the URL above.`
|
|
2521
|
+
);
|
|
2522
|
+
await open2(url.toString());
|
|
2523
|
+
analyticsService.capture("welcome_link_opened", {
|
|
2524
|
+
// biome-ignore lint/style/useNamingConvention: snake_case for analytics
|
|
2525
|
+
wallet_address: walletAddress
|
|
2526
|
+
});
|
|
2527
|
+
} catch (err) {
|
|
2528
|
+
analyticsService.capture("welcome_failed", {
|
|
2529
|
+
error: truncateError(
|
|
2530
|
+
err instanceof Error ? err.message : String(err)
|
|
2531
|
+
)
|
|
2532
|
+
});
|
|
2533
|
+
throw err;
|
|
2534
|
+
}
|
|
2535
|
+
});
|
|
2536
|
+
|
|
2458
2537
|
// src/app.ts
|
|
2459
2538
|
var createApp = (appContext) => {
|
|
2460
2539
|
const { analyticsService } = appContext.services;
|
|
2461
|
-
const program = new
|
|
2540
|
+
const program = new Command12().name("zero").description("Zero CLI \u2014 Search engine and payment platform for AI agents").version(package_default.version, "-v, --version").exitOverride().hook("preAction", async (_thisCommand, actionCommand) => {
|
|
2462
2541
|
const agentFlag = actionCommand.opts().agent;
|
|
2463
2542
|
if (typeof agentFlag === "string" && agentFlag.trim().length > 0) {
|
|
2464
2543
|
analyticsService.setAgentHost(agentFlag.trim());
|
|
@@ -2481,6 +2560,7 @@ var createApp = (appContext) => {
|
|
|
2481
2560
|
program.addCommand(walletCommand(appContext));
|
|
2482
2561
|
program.addCommand(configCommand(appContext));
|
|
2483
2562
|
program.addCommand(termsCommand(appContext));
|
|
2563
|
+
program.addCommand(welcomeCommand(appContext));
|
|
2484
2564
|
return program;
|
|
2485
2565
|
};
|
|
2486
2566
|
|
|
@@ -2488,6 +2568,7 @@ var createApp = (appContext) => {
|
|
|
2488
2568
|
import z4 from "zod";
|
|
2489
2569
|
var envSchema = z4.object({
|
|
2490
2570
|
ZERO_API_URL: z4.string().default("https://api.zero.xyz"),
|
|
2571
|
+
ZERO_WEB_URL: z4.string().default("https://zero.xyz"),
|
|
2491
2572
|
ZERO_PRIVATE_KEY: z4.string().optional(),
|
|
2492
2573
|
ZERO_ENV: z4.enum(["development", "production"]).default("production")
|
|
2493
2574
|
});
|
|
@@ -2503,14 +2584,14 @@ var getEnv = () => {
|
|
|
2503
2584
|
|
|
2504
2585
|
// src/app/app-services.ts
|
|
2505
2586
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2506
|
-
import { existsSync as
|
|
2507
|
-
import { homedir as
|
|
2508
|
-
import { join as
|
|
2509
|
-
import { privateKeyToAccount as
|
|
2587
|
+
import { existsSync as existsSync7, readFileSync as readFileSync9 } from "fs";
|
|
2588
|
+
import { homedir as homedir5 } from "os";
|
|
2589
|
+
import { join as join6 } from "path";
|
|
2590
|
+
import { privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
|
|
2510
2591
|
|
|
2511
2592
|
// src/services/analytics-service.ts
|
|
2512
2593
|
import { randomUUID } from "crypto";
|
|
2513
|
-
import { existsSync as
|
|
2594
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
2514
2595
|
import { dirname as dirname2 } from "path";
|
|
2515
2596
|
import { PostHog } from "posthog-node";
|
|
2516
2597
|
var POSTHOG_API_KEY = "phc_B2vLyNxAf2mnqvdPQajf4d4b2iXc35dep2ZrvebMJLuX";
|
|
@@ -2532,8 +2613,8 @@ var AnalyticsService = class {
|
|
|
2532
2613
|
let telemetryEnabled = true;
|
|
2533
2614
|
let persistedAnonId;
|
|
2534
2615
|
try {
|
|
2535
|
-
if (
|
|
2536
|
-
const config = JSON.parse(
|
|
2616
|
+
if (existsSync5(opts.configPath)) {
|
|
2617
|
+
const config = JSON.parse(readFileSync7(opts.configPath, "utf8"));
|
|
2537
2618
|
if (config.telemetry === false) {
|
|
2538
2619
|
telemetryEnabled = false;
|
|
2539
2620
|
}
|
|
@@ -2558,7 +2639,7 @@ var AnalyticsService = class {
|
|
|
2558
2639
|
try {
|
|
2559
2640
|
const dir = dirname2(opts.configPath);
|
|
2560
2641
|
mkdirSync4(dir, { recursive: true });
|
|
2561
|
-
const existing =
|
|
2642
|
+
const existing = existsSync5(opts.configPath) ? JSON.parse(readFileSync7(opts.configPath, "utf8")) : {};
|
|
2562
2643
|
writeFileSync4(
|
|
2563
2644
|
opts.configPath,
|
|
2564
2645
|
JSON.stringify({ ...existing, anonId: newAnonId }, null, 2)
|
|
@@ -2594,7 +2675,7 @@ var AnalyticsService = class {
|
|
|
2594
2675
|
if (anonId === walletAddress) return;
|
|
2595
2676
|
let aliasedTo;
|
|
2596
2677
|
try {
|
|
2597
|
-
const config = JSON.parse(
|
|
2678
|
+
const config = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
2598
2679
|
if (typeof config.aliasedTo === "string") {
|
|
2599
2680
|
aliasedTo = config.aliasedTo;
|
|
2600
2681
|
}
|
|
@@ -2603,7 +2684,7 @@ var AnalyticsService = class {
|
|
|
2603
2684
|
if (aliasedTo === walletAddress) return;
|
|
2604
2685
|
this.posthog.alias({ distinctId: walletAddress, alias: anonId });
|
|
2605
2686
|
try {
|
|
2606
|
-
const config =
|
|
2687
|
+
const config = existsSync5(configPath) ? JSON.parse(readFileSync7(configPath, "utf8")) : {};
|
|
2607
2688
|
writeFileSync4(
|
|
2608
2689
|
configPath,
|
|
2609
2690
|
JSON.stringify({ ...config, aliasedTo: walletAddress }, null, 2)
|
|
@@ -2646,12 +2727,12 @@ var AnalyticsService = class {
|
|
|
2646
2727
|
};
|
|
2647
2728
|
|
|
2648
2729
|
// src/services/state-service.ts
|
|
2649
|
-
import { existsSync as
|
|
2650
|
-
import { join as
|
|
2730
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
|
|
2731
|
+
import { join as join5 } from "path";
|
|
2651
2732
|
var StateService = class {
|
|
2652
2733
|
constructor(zeroDir) {
|
|
2653
2734
|
this.zeroDir = zeroDir;
|
|
2654
|
-
this.lastSearchPath =
|
|
2735
|
+
this.lastSearchPath = join5(zeroDir, "last_search.json");
|
|
2655
2736
|
}
|
|
2656
2737
|
lastSearchPath;
|
|
2657
2738
|
saveLastSearch = (data) => {
|
|
@@ -2660,8 +2741,8 @@ var StateService = class {
|
|
|
2660
2741
|
};
|
|
2661
2742
|
loadLastSearch = () => {
|
|
2662
2743
|
try {
|
|
2663
|
-
if (!
|
|
2664
|
-
const raw =
|
|
2744
|
+
if (!existsSync6(this.lastSearchPath)) return null;
|
|
2745
|
+
const raw = readFileSync8(this.lastSearchPath, "utf8");
|
|
2665
2746
|
return JSON.parse(raw);
|
|
2666
2747
|
} catch {
|
|
2667
2748
|
return null;
|
|
@@ -2709,12 +2790,12 @@ var detectAgentHost = (env = process.env) => {
|
|
|
2709
2790
|
var CLI_VERSION = package_default.version;
|
|
2710
2791
|
var getServices = (env) => {
|
|
2711
2792
|
let privateKey = env.ZERO_PRIVATE_KEY ? env.ZERO_PRIVATE_KEY : null;
|
|
2712
|
-
const zeroDir =
|
|
2713
|
-
const configPath =
|
|
2793
|
+
const zeroDir = join6(homedir5(), ".zero");
|
|
2794
|
+
const configPath = join6(zeroDir, "config.json");
|
|
2714
2795
|
if (!privateKey) {
|
|
2715
2796
|
try {
|
|
2716
|
-
if (
|
|
2717
|
-
const config = JSON.parse(
|
|
2797
|
+
if (existsSync7(configPath)) {
|
|
2798
|
+
const config = JSON.parse(readFileSync9(configPath, "utf8"));
|
|
2718
2799
|
if (typeof config.privateKey === "string") {
|
|
2719
2800
|
privateKey = config.privateKey;
|
|
2720
2801
|
}
|
|
@@ -2722,11 +2803,11 @@ var getServices = (env) => {
|
|
|
2722
2803
|
} catch {
|
|
2723
2804
|
}
|
|
2724
2805
|
}
|
|
2725
|
-
const account = privateKey ?
|
|
2806
|
+
const account = privateKey ? privateKeyToAccount4(privateKey) : null;
|
|
2726
2807
|
let lowBalanceWarning = 1;
|
|
2727
2808
|
try {
|
|
2728
|
-
if (
|
|
2729
|
-
const config = JSON.parse(
|
|
2809
|
+
if (existsSync7(configPath)) {
|
|
2810
|
+
const config = JSON.parse(readFileSync9(configPath, "utf8"));
|
|
2730
2811
|
if (typeof config.lowBalanceWarning === "number") {
|
|
2731
2812
|
lowBalanceWarning = config.lowBalanceWarning;
|
|
2732
2813
|
}
|