@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.
Files changed (2) hide show
  1. package/dist/index.js +127 -46
  2. 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 Command11 } from "commander";
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.26",
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 detectPaymentRequirement = (headers, status) => {
1171
- if (status !== 402) return null;
1172
- const x402Header = headers.get("payment-required") ?? headers.get("x-payment-required");
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", configDir: ".claude" },
1616
- { name: "Codex", configDir: ".codex" },
1617
- { name: "OpenCode", configDir: ".config/opencode" },
1618
- { name: "Cursor", configDir: ".cursor" }
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.configDir, "skills");
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 toolConfigPath = join2(home, tool.configDir);
1789
- if (!existsSync2(toolConfigPath)) {
1804
+ const toolDetectPath = join2(home, tool.detectDir);
1805
+ if (!existsSync2(toolDetectPath)) {
1790
1806
  continue;
1791
1807
  }
1792
- const toolSkillsPath = join2(toolConfigPath, "skills");
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 initCommand = (appContext) => new Command5("init").description("Initialize Zero CLI for usage").option("--force", "Overwrite existing configuration").action(async (options) => {
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.configDir))) {
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 Command11().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) => {
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 existsSync6, readFileSync as readFileSync8 } from "fs";
2507
- import { homedir as homedir4 } from "os";
2508
- import { join as join5 } from "path";
2509
- import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
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 existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
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 (existsSync4(opts.configPath)) {
2536
- const config = JSON.parse(readFileSync6(opts.configPath, "utf8"));
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 = existsSync4(opts.configPath) ? JSON.parse(readFileSync6(opts.configPath, "utf8")) : {};
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(readFileSync6(configPath, "utf8"));
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 = existsSync4(configPath) ? JSON.parse(readFileSync6(configPath, "utf8")) : {};
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 existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
2650
- import { join as join4 } from "path";
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 = join4(zeroDir, "last_search.json");
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 (!existsSync5(this.lastSearchPath)) return null;
2664
- const raw = readFileSync7(this.lastSearchPath, "utf8");
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 = join5(homedir4(), ".zero");
2713
- const configPath = join5(zeroDir, "config.json");
2793
+ const zeroDir = join6(homedir5(), ".zero");
2794
+ const configPath = join6(zeroDir, "config.json");
2714
2795
  if (!privateKey) {
2715
2796
  try {
2716
- if (existsSync6(configPath)) {
2717
- const config = JSON.parse(readFileSync8(configPath, "utf8"));
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 ? privateKeyToAccount3(privateKey) : null;
2806
+ const account = privateKey ? privateKeyToAccount4(privateKey) : null;
2726
2807
  let lowBalanceWarning = 1;
2727
2808
  try {
2728
- if (existsSync6(configPath)) {
2729
- const config = JSON.parse(readFileSync8(configPath, "utf8"));
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeroxyz/cli",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "zero": "dist/index.js",