@zeroxyz/cli 0.0.38 → 0.0.40

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 +567 -186
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { homedir as homedir7 } from "os";
5
- import { join as join8 } from "path";
4
+ import { homedir as homedir8 } from "os";
5
+ import { join as join9 } from "path";
6
6
 
7
7
  // package.json
8
8
  var package_default = {
9
9
  name: "@zeroxyz/cli",
10
- version: "0.0.38",
10
+ version: "0.0.40",
11
11
  type: "module",
12
12
  bin: {
13
13
  zero: "dist/index.js",
@@ -61,12 +61,124 @@ var package_default = {
61
61
  };
62
62
 
63
63
  // src/app.ts
64
- import { Command as Command12 } from "commander";
64
+ import { Command as Command13 } from "commander";
65
+
66
+ // src/commands/auth-command.ts
67
+ import { homedir } from "os";
68
+ import { join } from "path";
69
+ import { Command } from "commander";
70
+ import open from "open";
71
+
72
+ // src/util/secure-config.ts
73
+ import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "fs";
74
+ var SECURE_DIR_MODE = 448;
75
+ var SECURE_FILE_MODE = 384;
76
+ var ensureSecureDir = (path) => {
77
+ mkdirSync(path, { recursive: true, mode: SECURE_DIR_MODE });
78
+ chmodSync(path, SECURE_DIR_MODE);
79
+ };
80
+ var writeSecureFile = (path, contents) => {
81
+ writeFileSync(path, contents, { mode: SECURE_FILE_MODE });
82
+ chmodSync(path, SECURE_FILE_MODE);
83
+ };
84
+ var readConfig = (path) => {
85
+ try {
86
+ const raw = readFileSync(path, "utf8");
87
+ return JSON.parse(raw);
88
+ } catch {
89
+ return {};
90
+ }
91
+ };
92
+
93
+ // src/commands/auth-command.ts
94
+ var getConfigPath = () => join(homedir(), ".zero", "config.json");
95
+ var authLoginCommand = (appContext) => new Command("login").description("Sign in to Zero").option("--no-open", "Do not open the browser automatically").action(async (opts) => {
96
+ const { apiService } = appContext.services;
97
+ const start = await apiService.startDeviceLogin();
98
+ const url = `${start.verificationUri}?code=${start.userCode}`;
99
+ process.stdout.write(
100
+ `Open this URL to authorize:
101
+ ${url}
102
+ User code: ${start.userCode}
103
+ `
104
+ );
105
+ if (opts.open) {
106
+ await open(url).catch(() => {
107
+ });
108
+ }
109
+ while (Date.now() < start.expiresAt) {
110
+ await new Promise(
111
+ (r) => setTimeout(r, start.pollInterval * 1e3)
112
+ );
113
+ const result = await apiService.pollDeviceLogin(start.deviceCode);
114
+ if (result.status === "pending") {
115
+ process.stdout.write(".");
116
+ continue;
117
+ }
118
+ if (result.status === "expired") {
119
+ process.stderr.write(
120
+ "\nDevice code expired. Run `zero auth login` again.\n"
121
+ );
122
+ process.exitCode = 1;
123
+ return;
124
+ }
125
+ const path = getConfigPath();
126
+ const current = readConfig(path);
127
+ const next = {
128
+ ...current,
129
+ session: {
130
+ userId: result.user.id,
131
+ authMethod: "workos",
132
+ accessToken: result.accessToken,
133
+ refreshToken: result.refreshToken
134
+ }
135
+ };
136
+ writeSecureFile(path, JSON.stringify(next, null, 2));
137
+ process.stdout.write(
138
+ `
139
+ Signed in as ${result.user.email ?? result.user.id}
140
+ `
141
+ );
142
+ return;
143
+ }
144
+ process.stderr.write(
145
+ "\nDevice code expired. Run `zero auth login` again.\n"
146
+ );
147
+ process.exitCode = 1;
148
+ });
149
+ var authLogoutCommand = (appContext) => new Command("logout").description("Sign out of Zero").action(async () => {
150
+ const { apiService } = appContext.services;
151
+ const path = getConfigPath();
152
+ const config = readConfig(path);
153
+ if (config.session) {
154
+ await apiService.logout(config.session.refreshToken);
155
+ }
156
+ const { session: _drop, ...rest } = config;
157
+ writeSecureFile(path, JSON.stringify(rest, null, 2));
158
+ process.stdout.write("Signed out.\n");
159
+ });
160
+ var authWhoamiCommand = (appContext) => new Command("whoami").description("Print the current Zero identity").action(async () => {
161
+ const { apiService } = appContext.services;
162
+ const me = await apiService.getMe();
163
+ process.stdout.write(
164
+ `${me.email ?? me.id}
165
+ uid: ${me.id}
166
+ authMethod: ${me.authMethod}
167
+ `
168
+ );
169
+ });
170
+ var authCommand = (appContext) => {
171
+ const cmd = new Command("auth").description("Authentication commands");
172
+ cmd.addCommand(authLoginCommand(appContext));
173
+ cmd.addCommand(authLogoutCommand(appContext));
174
+ cmd.addCommand(authWhoamiCommand(appContext), { hidden: true });
175
+ return cmd;
176
+ };
65
177
 
66
178
  // src/commands/bug-report-command.ts
67
179
  import { createHash as createHash2 } from "crypto";
68
- import { readFileSync } from "fs";
69
- import { Command } from "commander";
180
+ import { readFileSync as readFileSync2 } from "fs";
181
+ import { Command as Command2 } from "commander";
70
182
  import { z as z2 } from "zod";
71
183
 
72
184
  // src/services/api-service.ts
@@ -93,7 +205,11 @@ var searchResultSchema = z.object({
93
205
  reviewCount: z.number().optional(),
94
206
  rating: ratingSchema,
95
207
  availabilityStatus: z.enum(["healthy", "degraded", "down", "unknown"]).nullable().optional(),
96
- displayStatus: z.enum(["healthy", "stable", "degraded", "unhealthy", "unknown"]).optional()
208
+ displayStatus: z.enum(["healthy", "stable", "degraded", "unhealthy", "unknown"]).optional(),
209
+ // Pass-through: API stamps this on Zero-published / withzero.{ai,xyz}
210
+ // services so `zero search --json` consumers can render their own
211
+ // provenance UI. CLI doesn't render a badge today.
212
+ isFirstParty: z.boolean().optional().default(false)
97
213
  });
98
214
  var searchResponseSchema = z.object({
99
215
  searchId: z.string(),
@@ -146,7 +262,9 @@ var capabilityResponseSchema = z.object({
146
262
  displayStatus: z.enum(["healthy", "stable", "degraded", "unhealthy", "unknown"]).optional(),
147
263
  activationCount: z.number().optional(),
148
264
  lastUsedAt: z.string().nullable().optional(),
149
- lastSuccessfullyRanAt: z.string().nullable().optional()
265
+ lastSuccessfullyRanAt: z.string().nullable().optional(),
266
+ // Pass-through (see searchResultSchema). Available on `zero get --json`.
267
+ isFirstParty: z.boolean().optional().default(false)
150
268
  });
151
269
  var createRunResponseSchema = z.object({
152
270
  runId: z.string()
@@ -225,18 +343,64 @@ var listRunsResponseSchema = z.object({
225
343
  runs: z.array(runListItemSchema),
226
344
  nextCursor: z.string().nullable()
227
345
  });
346
+ var userDtoSchema = z.object({
347
+ id: z.string(),
348
+ email: z.string().nullable(),
349
+ authMethod: z.string(),
350
+ createdAt: z.union([z.string(), z.date()]).optional(),
351
+ lastLoginAt: z.union([z.string(), z.date()]).nullable().optional()
352
+ });
353
+ var userWalletDtoSchema = z.object({
354
+ walletAddress: z.string(),
355
+ source: z.enum(["self_custody", "privy_embedded"]),
356
+ isPrimary: z.boolean(),
357
+ linkedAt: z.union([z.string(), z.date()])
358
+ });
359
+ var signResultSchema = z.object({
360
+ signature: z.string(),
361
+ walletAddress: z.string()
362
+ });
363
+ var deviceStartResultSchema = z.object({
364
+ deviceCode: z.string(),
365
+ userCode: z.string(),
366
+ verificationUri: z.string(),
367
+ pollInterval: z.number(),
368
+ expiresAt: z.number()
369
+ });
370
+ var devicePollResponseSchema = z.union([
371
+ z.object({ error: z.literal("authorization_pending") }),
372
+ z.object({ error: z.literal("expired_token") }),
373
+ z.object({
374
+ accessToken: z.string(),
375
+ refreshToken: z.string(),
376
+ expiresIn: z.number(),
377
+ user: userDtoSchema
378
+ })
379
+ ]);
380
+ var jsonStringifyBigintSafe = (value) => JSON.stringify(
381
+ value,
382
+ (_key, v) => typeof v === "bigint" ? v.toString() : v
383
+ );
228
384
  var buildCanonicalMessage = (method, path, body, timestamp, nonce) => {
229
385
  const bodyHash = createHash("sha256").update(body ?? "").digest("hex");
230
386
  return `${method}:${path}:${bodyHash}:${timestamp}:${nonce}`;
231
387
  };
232
388
  var ApiService = class _ApiService {
233
- constructor(baseUrl, account) {
389
+ constructor(baseUrl, account, credentials = { kind: "none" }, onSessionRefreshed = async () => {
390
+ }) {
234
391
  this.baseUrl = baseUrl;
235
392
  this.account = account;
236
393
  this.walletAddress = this.account?.address ?? null;
394
+ this.credentials = credentials;
395
+ this.onSessionRefreshed = onSessionRefreshed;
237
396
  }
238
397
  walletAddress;
239
398
  account;
399
+ credentials;
400
+ onSessionRefreshed;
401
+ setWalletAddress = (address) => {
402
+ this.walletAddress = address;
403
+ };
240
404
  withAccount = (account) => new _ApiService(this.baseUrl, account);
241
405
  signRequest = async (method, path, body) => {
242
406
  if (!this.account) throw new Error("No private key configured");
@@ -251,21 +415,75 @@ var ApiService = class _ApiService {
251
415
  "x-zero-signature": signature
252
416
  };
253
417
  };
254
- request = async (method, path, body) => {
255
- const url = `${this.baseUrl}${path}`;
256
- const bodyStr = body ? JSON.stringify(body) : void 0;
257
- const headers = {
418
+ // Auth modes per request. `this.account` is only ever the local private key
419
+ // (the managed Privy proxy lives on PaymentService, never here), so an
420
+ // account here means a BYO key is present.
421
+ // - "default": session JWT takes precedence over EIP-191. If signed in, the
422
+ // JWT is the identity the API trusts; otherwise fall back to a wallet
423
+ // signature, else anonymous. Used by session-scoped endpoints
424
+ // (/users/me, sign-*, wallets) and read endpoints.
425
+ // - "wallet-attributed": the action is attributed to a wallet (runs,
426
+ // reviews, bug reports). Prefer the local private key (EIP-191) so the run
427
+ // is attributed to the wallet that actually paid; when there's no local
428
+ // key (managed user) fall back to the session Bearer and let the server
429
+ // resolve the wallet from the authenticated user. We never send both — a
430
+ // present session would make the server skip EIP-191 verification, so a
431
+ // Bearer + wallet headers combo must never happen.
432
+ buildHeaders = async (method, path, bodyStr, auth) => {
433
+ const base2 = {
258
434
  "content-type": "application/json"
259
435
  };
436
+ if (auth === "wallet-attributed" && this.account) {
437
+ const walletHeaders = await this.signRequest(method, path, bodyStr);
438
+ return { ...base2, ...walletHeaders };
439
+ }
440
+ if (this.credentials.kind === "session") {
441
+ base2.authorization = `Bearer ${this.credentials.accessToken}`;
442
+ return base2;
443
+ }
260
444
  if (this.account) {
261
445
  const walletHeaders = await this.signRequest(method, path, bodyStr);
262
- Object.assign(headers, walletHeaders);
446
+ return { ...base2, ...walletHeaders };
263
447
  }
264
- const response = await fetch(url, {
448
+ return base2;
449
+ };
450
+ // Rotates the in-memory tokens and fires onSessionRefreshed so the
451
+ // caller can persist them. Returns false on any refresh failure — the
452
+ // outer request then propagates the original 401 to the caller.
453
+ tryRefreshSession = async () => {
454
+ if (this.credentials.kind !== "session") return false;
455
+ const { refreshToken } = this.credentials;
456
+ const resp = await fetch(`${this.baseUrl}/v1/auth/refresh`, {
457
+ method: "POST",
458
+ headers: { "content-type": "application/json" },
459
+ body: JSON.stringify({ refreshToken })
460
+ });
461
+ if (!resp.ok) return false;
462
+ const body = await resp.json();
463
+ this.credentials = {
464
+ ...this.credentials,
465
+ accessToken: body.accessToken,
466
+ refreshToken: body.refreshToken
467
+ };
468
+ await this.onSessionRefreshed(body);
469
+ return true;
470
+ };
471
+ request = async (method, path, body, opts = {}) => {
472
+ const url = `${this.baseUrl}${path}`;
473
+ const bodyStr = body ? jsonStringifyBigintSafe(body) : void 0;
474
+ const auth = opts.auth ?? "default";
475
+ const makeInit = async () => ({
265
476
  method,
266
- headers,
477
+ headers: await this.buildHeaders(method, path, bodyStr, auth),
267
478
  body: bodyStr
268
479
  });
480
+ let response = await fetch(url, await makeInit());
481
+ if (response.status === 401 && this.credentials.kind === "session") {
482
+ const refreshed = await this.tryRefreshSession();
483
+ if (refreshed) {
484
+ response = await fetch(url, await makeInit());
485
+ }
486
+ }
269
487
  if (!response.ok) {
270
488
  const errorBody = await response.json().catch(() => ({ error: "Unknown error" }));
271
489
  throw new Error(
@@ -274,6 +492,44 @@ var ApiService = class _ApiService {
274
492
  }
275
493
  return response.json();
276
494
  };
495
+ startDeviceLogin = async () => {
496
+ const resp = await fetch(`${this.baseUrl}/v1/auth/device/start`, {
497
+ method: "POST"
498
+ });
499
+ if (!resp.ok) throw new Error(`device_start_${resp.status}`);
500
+ return deviceStartResultSchema.parse(await resp.json());
501
+ };
502
+ pollDeviceLogin = async (deviceCode) => {
503
+ const resp = await fetch(`${this.baseUrl}/v1/auth/device/poll`, {
504
+ method: "POST",
505
+ headers: { "content-type": "application/json" },
506
+ body: JSON.stringify({ deviceCode })
507
+ });
508
+ if (!resp.ok) throw new Error(`device_poll_${resp.status}`);
509
+ const parsed = devicePollResponseSchema.parse(await resp.json());
510
+ if ("error" in parsed) {
511
+ return parsed.error === "authorization_pending" ? { status: "pending" } : { status: "expired" };
512
+ }
513
+ return {
514
+ status: "ok",
515
+ accessToken: parsed.accessToken,
516
+ refreshToken: parsed.refreshToken,
517
+ expiresIn: parsed.expiresIn,
518
+ user: parsed.user
519
+ };
520
+ };
521
+ logout = async (refreshToken) => {
522
+ await fetch(`${this.baseUrl}/v1/auth/logout`, {
523
+ method: "POST",
524
+ headers: { "content-type": "application/json" },
525
+ body: JSON.stringify({ refreshToken })
526
+ }).catch(() => {
527
+ });
528
+ };
529
+ getMe = async () => {
530
+ const json = await this.request("GET", "/v1/users/me");
531
+ return userDtoSchema.parse(json);
532
+ };
277
533
  search = async (options) => {
278
534
  const json = await this.request("POST", "/v1/search", options);
279
535
  return searchResponseSchema.parse(json);
@@ -287,7 +543,9 @@ var ApiService = class _ApiService {
287
543
  return capabilityResponseSchema.parse(json);
288
544
  };
289
545
  createRun = async (data) => {
290
- const json = await this.request("POST", "/v1/runs", data);
546
+ const json = await this.request("POST", "/v1/runs", data, {
547
+ auth: "wallet-attributed"
548
+ });
291
549
  return createRunResponseSchema.parse(json);
292
550
  };
293
551
  listRuns = async (params = {}) => {
@@ -297,19 +555,32 @@ var ApiService = class _ApiService {
297
555
  if (params.limit) qs.set("limit", String(params.limit));
298
556
  if (params.cursor) qs.set("cursor", params.cursor);
299
557
  const suffix = qs.toString() ? `?${qs.toString()}` : "";
300
- const json = await this.request("GET", `/v1/runs${suffix}`);
558
+ const json = await this.request("GET", `/v1/runs${suffix}`, void 0, {
559
+ auth: "wallet-attributed"
560
+ });
301
561
  return listRunsResponseSchema.parse(json);
302
562
  };
303
563
  createReview = async (data) => {
304
- const json = await this.request("POST", "/v1/reviews", data);
564
+ const json = await this.request("POST", "/v1/reviews", data, {
565
+ auth: "wallet-attributed"
566
+ });
305
567
  return createReviewResponseSchema.parse(json);
306
568
  };
307
569
  createReviewsBatch = async (reviews) => {
308
- const json = await this.request("POST", "/v1/reviews/batch", { reviews });
570
+ const json = await this.request(
571
+ "POST",
572
+ "/v1/reviews/batch",
573
+ { reviews },
574
+ {
575
+ auth: "wallet-attributed"
576
+ }
577
+ );
309
578
  return batchReviewResponseSchema.parse(json);
310
579
  };
311
580
  createBugReport = async (data) => {
312
- const json = await this.request("POST", "/v1/bug-reports", data);
581
+ const json = await this.request("POST", "/v1/bug-reports", data, {
582
+ auth: "wallet-attributed"
583
+ });
313
584
  return createBugReportResponseSchema.parse(json);
314
585
  };
315
586
  getFundingUrl = async (amount, provider = "coinbase") => {
@@ -326,6 +597,44 @@ var ApiService = class _ApiService {
326
597
  return null;
327
598
  }
328
599
  };
600
+ getWallets = async () => {
601
+ const json = await this.request("GET", "/v1/users/me/wallets");
602
+ return z.array(userWalletDtoSchema).parse(json);
603
+ };
604
+ provisionWallet = async () => {
605
+ const json = await this.request("POST", "/v1/users/me/wallets/provision");
606
+ return userWalletDtoSchema.parse(json);
607
+ };
608
+ signTypedDataRemote = async (typedData) => {
609
+ const json = await this.request("POST", "/v1/users/me/sign-typed-data", {
610
+ typedData
611
+ });
612
+ const parsed = signResultSchema.parse(json);
613
+ return {
614
+ signature: parsed.signature,
615
+ walletAddress: parsed.walletAddress
616
+ };
617
+ };
618
+ signMessageRemote = async (message) => {
619
+ const json = await this.request("POST", "/v1/users/me/sign-message", {
620
+ message
621
+ });
622
+ const parsed = signResultSchema.parse(json);
623
+ return {
624
+ signature: parsed.signature,
625
+ walletAddress: parsed.walletAddress
626
+ };
627
+ };
628
+ signTransactionRemote = async (input) => {
629
+ const json = await this.request("POST", "/v1/users/me/sign-transaction", {
630
+ unsignedTransaction: input.unsignedTransaction
631
+ });
632
+ const parsed = signResultSchema.parse(json);
633
+ return {
634
+ signature: parsed.signature,
635
+ walletAddress: parsed.walletAddress
636
+ };
637
+ };
329
638
  };
330
639
 
331
640
  // src/commands/bug-report-command.ts
@@ -351,7 +660,7 @@ var autoIdempotencyKey = (description, contextSeed) => {
351
660
  const seed = `${description}|${contextSeed ?? ""}|${bucket}`;
352
661
  return `auto-${createHash2("sha256").update(seed).digest("hex").slice(0, 16)}`;
353
662
  };
354
- var bugReportCommand = (appContext) => new Command("bug-report").description(
663
+ var bugReportCommand = (appContext) => new Command2("bug-report").description(
355
664
  "Report a Zero platform bug \u2014 bad search ranking, wrong indexed URL, CLI bugs, billing issues. The CLI auto-attaches your most recent context (last search + last run), auto-derives a title, and lets the server classify the category. For 'this capability returned a bad result', use `zero review` instead."
356
665
  ).addHelpText(
357
666
  "after",
@@ -428,7 +737,7 @@ Categories the classifier picks from:
428
737
  return;
429
738
  }
430
739
  if (options.fromFile) {
431
- const contents = readFileSync(options.fromFile, "utf8");
740
+ const contents = readFileSync2(options.fromFile, "utf8");
432
741
  const lines = contents.split("\n").map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#"));
433
742
  let ok = 0;
434
743
  let failed = 0;
@@ -565,21 +874,21 @@ Bulk bug-report complete: ${ok} ok, ${failed} failed`
565
874
  );
566
875
 
567
876
  // src/commands/config-command.ts
568
- import { existsSync, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
569
- import { homedir } from "os";
570
- import { join } from "path";
571
- import { Command as Command2 } from "commander";
877
+ import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
878
+ import { homedir as homedir2 } from "os";
879
+ import { join as join2 } from "path";
880
+ import { Command as Command3 } from "commander";
572
881
  var VALID_KEYS = ["lowBalanceWarning", "auth", "telemetry"];
573
882
  var loadConfig = (configPath) => {
574
883
  try {
575
884
  if (!existsSync(configPath)) return {};
576
- return JSON.parse(readFileSync2(configPath, "utf8"));
885
+ return JSON.parse(readFileSync3(configPath, "utf8"));
577
886
  } catch {
578
887
  return {};
579
888
  }
580
889
  };
581
- var configCommand = (_appContext) => new Command2("config").description("View or update CLI configuration").option("--set <keyValue>", "Set a config value (key=value)").action((options) => {
582
- const configPath = join(homedir(), ".zero", "config.json");
890
+ var configCommand = (_appContext) => new Command3("config").description("View or update CLI configuration").option("--set <keyValue>", "Set a config value (key=value)").action((options) => {
891
+ const configPath = join2(homedir2(), ".zero", "config.json");
583
892
  if (!options.set) {
584
893
  const config2 = loadConfig(configPath);
585
894
  console.log(JSON.stringify(config2, null, 2));
@@ -609,16 +918,16 @@ var configCommand = (_appContext) => new Command2("config").description("View or
609
918
  }
610
919
  const config = loadConfig(configPath);
611
920
  config[key] = value;
612
- mkdirSync(join(homedir(), ".zero"), { recursive: true });
613
- writeFileSync(configPath, JSON.stringify(config, null, 2));
921
+ mkdirSync2(join2(homedir2(), ".zero"), { recursive: true });
922
+ writeFileSync2(configPath, JSON.stringify(config, null, 2));
614
923
  console.log(`Set ${key} = ${JSON.stringify(value)}`);
615
924
  });
616
925
 
617
926
  // src/commands/fetch-command.ts
618
927
  import { createHash as createHash3 } from "crypto";
619
- import { readFileSync as readFileSync3 } from "fs";
928
+ import { readFileSync as readFileSync4 } from "fs";
620
929
  import { resolve as resolvePath } from "path";
621
- import { Command as Command3 } from "commander";
930
+ import { Command as Command4 } from "commander";
622
931
  import { formatUnits as formatUnits2 } from "viem";
623
932
 
624
933
  // src/services/payment-service.ts
@@ -922,6 +1231,11 @@ var PaymentService = class {
922
1231
  `Insufficient pathUSD on Tempo testnet: have ${formatUnits(tempoBalance, 6)}, need ${capturedAmount}. Fund your wallet with the Tempo testnet faucet: https://docs.tempo.xyz/quickstart/faucet`
923
1232
  );
924
1233
  }
1234
+ if (this.config.managed) {
1235
+ throw new Error(
1236
+ `Insufficient USDC on Tempo: have ${formatUnits(tempoBalance, 6)}, need ${capturedAmount}. Managed wallets can't auto-bridge from Base yet \u2014 fund your Tempo wallet${this.account ? ` (${this.account.address})` : ""} directly, or set a local ZERO_PRIVATE_KEY to bridge.`
1237
+ );
1238
+ }
925
1239
  await this.bridgeToTempo(requiredRaw, onProgress);
926
1240
  }
927
1241
  return capturedAmount;
@@ -1285,8 +1599,8 @@ var extractUpstreamErrorMessage = (body) => {
1285
1599
  };
1286
1600
  var resolveRequestBody = (rawData, readStdin2) => {
1287
1601
  const fromFile = (spec) => {
1288
- if (spec === "@-") return readFileSync3(0);
1289
- return readFileSync3(resolvePath(spec.slice(1)));
1602
+ if (spec === "@-") return readFileSync4(0);
1603
+ return readFileSync4(resolvePath(spec.slice(1)));
1290
1604
  };
1291
1605
  if (readStdin2 && rawData !== void 0) {
1292
1606
  throw new Error(
@@ -1296,7 +1610,7 @@ var resolveRequestBody = (rawData, readStdin2) => {
1296
1610
  let body;
1297
1611
  let cap;
1298
1612
  if (readStdin2) {
1299
- body = readFileSync3(0);
1613
+ body = readFileSync4(0);
1300
1614
  cap = MAX_FILE_REQUEST_BODY_BYTES;
1301
1615
  } else if (rawData?.startsWith("@")) {
1302
1616
  body = fromFile(rawData);
@@ -1349,7 +1663,7 @@ var detectPaymentRequirement = async (response) => {
1349
1663
  }
1350
1664
  return { protocol: "unknown", raw: {} };
1351
1665
  };
1352
- var fetchCommand = (appContext) => new Command3("fetch").description(
1666
+ var fetchCommand = (appContext) => new Command4("fetch").description(
1353
1667
  "Fetch a capability URL, handling 402 challenges automatically"
1354
1668
  ).argument(
1355
1669
  "[url]",
@@ -1848,7 +2162,7 @@ var fetchCommand = (appContext) => new Command3("fetch").description(
1848
2162
  );
1849
2163
 
1850
2164
  // src/commands/get-command.ts
1851
- import { Command as Command4 } from "commander";
2165
+ import { Command as Command5 } from "commander";
1852
2166
 
1853
2167
  // src/util/format-price.ts
1854
2168
  var centsToDollars = (cents) => {
@@ -2007,7 +2321,7 @@ var formatCapability = (capability) => {
2007
2321
  lines.push(...buildTryItExample(capability));
2008
2322
  return lines.join("\n");
2009
2323
  };
2010
- var getCommand = (appContext) => new Command4("get").description(
2324
+ var getCommand = (appContext) => new Command5("get").description(
2011
2325
  "Get details for a capability by position from last search, or by slug"
2012
2326
  ).argument(
2013
2327
  "<identifier>",
@@ -2082,15 +2396,15 @@ import {
2082
2396
  existsSync as existsSync2,
2083
2397
  mkdirSync as mkdirSync3,
2084
2398
  readdirSync,
2085
- readFileSync as readFileSync4,
2399
+ readFileSync as readFileSync5,
2086
2400
  rmSync,
2087
2401
  statSync,
2088
2402
  writeFileSync as writeFileSync3
2089
2403
  } from "fs";
2090
- import { homedir as homedir2 } from "os";
2091
- import { dirname, join as join2, relative } from "path";
2404
+ import { homedir as homedir3 } from "os";
2405
+ import { dirname, join as join3, relative } from "path";
2092
2406
  import { fileURLToPath } from "url";
2093
- import { Command as Command5 } from "commander";
2407
+ import { Command as Command6 } from "commander";
2094
2408
  import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
2095
2409
 
2096
2410
  // src/util/install-banner.ts
@@ -2222,19 +2536,6 @@ var printReadyFooter = () => {
2222
2536
  return lines.join("\n");
2223
2537
  };
2224
2538
 
2225
- // src/util/secure-config.ts
2226
- import { chmodSync, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
2227
- var SECURE_DIR_MODE = 448;
2228
- var SECURE_FILE_MODE = 384;
2229
- var ensureSecureDir = (path) => {
2230
- mkdirSync2(path, { recursive: true, mode: SECURE_DIR_MODE });
2231
- chmodSync(path, SECURE_DIR_MODE);
2232
- };
2233
- var writeSecureFile = (path, contents) => {
2234
- writeFileSync2(path, contents, { mode: SECURE_FILE_MODE });
2235
- chmodSync(path, SECURE_FILE_MODE);
2236
- };
2237
-
2238
2539
  // src/commands/init-command.ts
2239
2540
  var AGENT_TOOLS = [
2240
2541
  { name: "Claude Code", detectDir: ".claude", skillsDir: ".claude/skills" },
@@ -2249,7 +2550,7 @@ var AGENT_TOOLS = [
2249
2550
  var findResourceDir = (startDir, resourceName) => {
2250
2551
  let current = startDir;
2251
2552
  while (true) {
2252
- const candidate = join2(current, resourceName);
2553
+ const candidate = join3(current, resourceName);
2253
2554
  if (existsSync2(candidate)) {
2254
2555
  return candidate;
2255
2556
  }
@@ -2268,7 +2569,7 @@ var getCliModuleDir = () => {
2268
2569
  }
2269
2570
  return __dirname;
2270
2571
  };
2271
- var sha256File = (filePath) => createHash4("sha256").update(readFileSync4(filePath)).digest("hex");
2572
+ var sha256File = (filePath) => createHash4("sha256").update(readFileSync5(filePath)).digest("hex");
2272
2573
  var verifyFileCopy = (src, dest) => {
2273
2574
  if (!existsSync2(dest)) return false;
2274
2575
  return sha256File(src) === sha256File(dest);
@@ -2276,7 +2577,7 @@ var verifyFileCopy = (src, dest) => {
2276
2577
  var collectAllFiles = (dir) => {
2277
2578
  const files = [];
2278
2579
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
2279
- const fullPath = join2(dir, entry.name);
2580
+ const fullPath = join3(dir, entry.name);
2280
2581
  if (entry.isDirectory()) {
2281
2582
  files.push(...collectAllFiles(fullPath));
2282
2583
  } else {
@@ -2286,7 +2587,7 @@ var collectAllFiles = (dir) => {
2286
2587
  return files;
2287
2588
  };
2288
2589
  var copyFile = (src, dest) => {
2289
- writeFileSync3(dest, readFileSync4(src));
2590
+ writeFileSync3(dest, readFileSync5(src));
2290
2591
  try {
2291
2592
  chmodSync2(dest, statSync(src).mode);
2292
2593
  } catch {
@@ -2295,8 +2596,8 @@ var copyFile = (src, dest) => {
2295
2596
  var copyDirRecursive = (src, dest) => {
2296
2597
  mkdirSync3(dest, { recursive: true });
2297
2598
  for (const entry of readdirSync(src, { withFileTypes: true })) {
2298
- const srcPath = join2(src, entry.name);
2299
- const destPath = join2(dest, entry.name);
2599
+ const srcPath = join3(src, entry.name);
2600
+ const destPath = join3(dest, entry.name);
2300
2601
  if (entry.isDirectory()) {
2301
2602
  copyDirRecursive(srcPath, destPath);
2302
2603
  } else {
@@ -2305,22 +2606,22 @@ var copyDirRecursive = (src, dest) => {
2305
2606
  }
2306
2607
  };
2307
2608
  var installHook = (home, verbose = false) => {
2308
- const claudeDir = join2(home, ".claude");
2609
+ const claudeDir = join3(home, ".claude");
2309
2610
  if (!existsSync2(claudeDir)) {
2310
2611
  if (verbose) {
2311
2612
  stepInfo(`~/.claude not found \u2014 Claude Code not installed, skipping`);
2312
2613
  }
2313
2614
  return false;
2314
2615
  }
2315
- const zeroHooksDir = join2(home, ".zero", "hooks");
2616
+ const zeroHooksDir = join3(home, ".zero", "hooks");
2316
2617
  mkdirSync3(zeroHooksDir, { recursive: true });
2317
2618
  if (verbose) stepInfo(`staged hook dir at ${zeroHooksDir}`);
2318
2619
  const hookFiles = ["auto-approve-zero.sh", "zero-context.sh"];
2319
2620
  const hookDests = {};
2320
2621
  const hooksSourceDir = findResourceDir(getCliModuleDir(), "hooks");
2321
2622
  for (const hookFile of hookFiles) {
2322
- const hookSource = join2(hooksSourceDir, hookFile);
2323
- const hookDest = join2(zeroHooksDir, hookFile);
2623
+ const hookSource = join3(hooksSourceDir, hookFile);
2624
+ const hookDest = join3(zeroHooksDir, hookFile);
2324
2625
  copyFile(hookSource, hookDest);
2325
2626
  chmodSync2(hookDest, 493);
2326
2627
  if (!verifyFileCopy(hookSource, hookDest)) {
@@ -2331,14 +2632,14 @@ var installHook = (home, verbose = false) => {
2331
2632
  hookDests[hookFile] = hookDest;
2332
2633
  if (verbose) stepInfo(`copied ${hookFile} \u2192 ${hookDest} (verified)`);
2333
2634
  }
2334
- const settingsPath = join2(claudeDir, "settings.json");
2635
+ const settingsPath = join3(claudeDir, "settings.json");
2335
2636
  let settings = {};
2336
2637
  let settingsExisted = false;
2337
2638
  let settingsCorrupted = false;
2338
2639
  if (existsSync2(settingsPath)) {
2339
2640
  settingsExisted = true;
2340
2641
  try {
2341
- settings = JSON.parse(readFileSync4(settingsPath, "utf-8"));
2642
+ settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
2342
2643
  } catch {
2343
2644
  settingsCorrupted = true;
2344
2645
  }
@@ -2436,7 +2737,7 @@ var CONFLICTING_SKILL_PATTERNS = ["zam"];
2436
2737
  var findConflictingSkills = (home) => {
2437
2738
  const found = [];
2438
2739
  for (const tool of AGENT_TOOLS) {
2439
- const toolSkillsPath = join2(home, tool.skillsDir);
2740
+ const toolSkillsPath = join3(home, tool.skillsDir);
2440
2741
  if (!existsSync2(toolSkillsPath)) continue;
2441
2742
  const entries = readdirSync(toolSkillsPath, { withFileTypes: true });
2442
2743
  for (const entry of entries) {
@@ -2445,7 +2746,7 @@ var findConflictingSkills = (home) => {
2445
2746
  if (CONFLICTING_SKILL_PATTERNS.some((p) => lower.includes(p))) {
2446
2747
  found.push({
2447
2748
  tool: tool.name,
2448
- skillPath: join2(toolSkillsPath, entry.name),
2749
+ skillPath: join3(toolSkillsPath, entry.name),
2449
2750
  skillName: entry.name
2450
2751
  });
2451
2752
  }
@@ -2473,7 +2774,7 @@ var installSkills = (home, verbose = false) => {
2473
2774
  const installed = [];
2474
2775
  const errors = [];
2475
2776
  for (const tool of AGENT_TOOLS) {
2476
- const toolDetectPath = join2(home, tool.detectDir);
2777
+ const toolDetectPath = join3(home, tool.detectDir);
2477
2778
  if (!existsSync2(toolDetectPath)) {
2478
2779
  if (verbose) {
2479
2780
  stepInfo(
@@ -2488,16 +2789,16 @@ var installSkills = (home, verbose = false) => {
2488
2789
  );
2489
2790
  }
2490
2791
  try {
2491
- const toolSkillsPath = join2(home, tool.skillsDir);
2792
+ const toolSkillsPath = join3(home, tool.skillsDir);
2492
2793
  mkdirSync3(toolSkillsPath, { recursive: true });
2493
2794
  for (const skillDir of skillDirs) {
2494
- const src = join2(skillsSourceDir, skillDir);
2495
- const dest = join2(toolSkillsPath, skillDir);
2795
+ const src = join3(skillsSourceDir, skillDir);
2796
+ const dest = join3(toolSkillsPath, skillDir);
2496
2797
  const existed = existsSync2(dest);
2497
2798
  copyDirRecursive(src, dest);
2498
2799
  for (const srcFile of collectAllFiles(src)) {
2499
2800
  const relPath = relative(src, srcFile);
2500
- const destFile = join2(dest, relPath);
2801
+ const destFile = join3(dest, relPath);
2501
2802
  if (!verifyFileCopy(srcFile, destFile)) {
2502
2803
  throw new Error(
2503
2804
  `Integrity check failed: ${destFile} does not match source`
@@ -2528,15 +2829,15 @@ var runInit = async (appContext, options = {}) => {
2528
2829
  let currentStep = "wallet";
2529
2830
  try {
2530
2831
  printZeroBanner();
2531
- const home = homedir2();
2532
- const zeroDir = join2(home, ".zero");
2533
- const configPath = join2(zeroDir, "config.json");
2832
+ const home = homedir3();
2833
+ const zeroDir = join3(home, ".zero");
2834
+ const configPath = join3(zeroDir, "config.json");
2534
2835
  let walletCreated = false;
2535
2836
  let walletAddress = null;
2536
2837
  const walletExists = (() => {
2537
2838
  if (!existsSync2(configPath)) return false;
2538
2839
  try {
2539
- const existing = JSON.parse(readFileSync4(configPath, "utf8"));
2840
+ const existing = JSON.parse(readFileSync5(configPath, "utf8"));
2540
2841
  return !!existing.privateKey;
2541
2842
  } catch {
2542
2843
  return false;
@@ -2546,7 +2847,7 @@ var runInit = async (appContext, options = {}) => {
2546
2847
  const privateKey = generatePrivateKey();
2547
2848
  const account = privateKeyToAccount(privateKey);
2548
2849
  ensureSecureDir(zeroDir);
2549
- const existing = existsSync2(configPath) ? JSON.parse(readFileSync4(configPath, "utf8")) : {};
2850
+ const existing = existsSync2(configPath) ? JSON.parse(readFileSync5(configPath, "utf8")) : {};
2550
2851
  writeSecureFile(
2551
2852
  configPath,
2552
2853
  JSON.stringify(
@@ -2569,7 +2870,7 @@ var runInit = async (appContext, options = {}) => {
2569
2870
  }
2570
2871
  } else {
2571
2872
  try {
2572
- const existing = JSON.parse(readFileSync4(configPath, "utf8"));
2873
+ const existing = JSON.parse(readFileSync5(configPath, "utf8"));
2573
2874
  const account = privateKeyToAccount(existing.privateKey);
2574
2875
  walletAddress = account.address;
2575
2876
  } catch {
@@ -2590,7 +2891,7 @@ var runInit = async (appContext, options = {}) => {
2590
2891
  let hookInstalled = false;
2591
2892
  let hookError = null;
2592
2893
  for (const tool of AGENT_TOOLS) {
2593
- if (existsSync2(join2(home, tool.detectDir))) {
2894
+ if (existsSync2(join3(home, tool.detectDir))) {
2594
2895
  agentsDetected.push(tool.name);
2595
2896
  }
2596
2897
  }
@@ -2700,14 +3001,14 @@ To remove them, run: ${color.cyan("zero init cleanup")}`
2700
3001
  throw err;
2701
3002
  }
2702
3003
  };
2703
- var initCommand = (appContext) => new Command5("init").description("Initialize Zero CLI for usage").option("--force", "Overwrite existing configuration").option(
3004
+ var initCommand = (appContext) => new Command6("init").description("Initialize Zero CLI for usage").option("--force", "Overwrite existing configuration").option(
2704
3005
  "-v, --verbose",
2705
3006
  "Explain why each install step was taken or skipped"
2706
3007
  ).action(async (options) => {
2707
3008
  await runInit(appContext, options);
2708
3009
  }).addCommand(
2709
- new Command5("cleanup").description("Remove deprecated skills (zam) that conflict with Zero").action(() => {
2710
- const home = homedir2();
3010
+ new Command6("cleanup").description("Remove deprecated skills (zam) that conflict with Zero").action(() => {
3011
+ const home = homedir3();
2711
3012
  const removed = removeConflictingSkills(home);
2712
3013
  if (removed.length === 0) {
2713
3014
  console.error("No conflicting skills found. Nothing to remove.");
@@ -2726,8 +3027,8 @@ ${removedList}`);
2726
3027
  );
2727
3028
 
2728
3029
  // src/commands/review-command.ts
2729
- import { readFileSync as readFileSync5 } from "fs";
2730
- import { Command as Command6 } from "commander";
3030
+ import { readFileSync as readFileSync6 } from "fs";
3031
+ import { Command as Command7 } from "commander";
2731
3032
  import { z as z3 } from "zod";
2732
3033
  var bulkEntrySchema2 = z3.object({
2733
3034
  runId: z3.string(),
@@ -2737,7 +3038,7 @@ var bulkEntrySchema2 = z3.object({
2737
3038
  reliability: z3.number().int().min(1).max(5),
2738
3039
  content: z3.string().optional()
2739
3040
  });
2740
- var reviewCommand = (appContext) => new Command6("review").description("Submit a review for a capability run").addHelpText(
3041
+ var reviewCommand = (appContext) => new Command7("review").description("Submit a review for a capability run").addHelpText(
2741
3042
  "after",
2742
3043
  `
2743
3044
  Tips for a great review:
@@ -2768,7 +3069,7 @@ Examples:
2768
3069
  try {
2769
3070
  const { analyticsService, apiService } = appContext.services;
2770
3071
  if (options.fromFile) {
2771
- const contents = readFileSync5(options.fromFile, "utf8");
3072
+ const contents = readFileSync6(options.fromFile, "utf8");
2772
3073
  const lines = contents.split("\n").map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#"));
2773
3074
  const parsed = [];
2774
3075
  let parseFailures = 0;
@@ -2916,7 +3217,7 @@ Bulk review complete: ${ok} ok, ${failed} failed`);
2916
3217
  );
2917
3218
 
2918
3219
  // src/commands/runs-command.ts
2919
- import { Command as Command7 } from "commander";
3220
+ import { Command as Command8 } from "commander";
2920
3221
  var USD_ASSETS = /* @__PURE__ */ new Set(["USD", "USDC"]);
2921
3222
  var formatCost2 = (cost) => {
2922
3223
  if (!cost) return "free";
@@ -2931,7 +3232,7 @@ var formatPayment = (payment) => {
2931
3232
  const mode = payment.mode ? ` (${payment.mode})` : "";
2932
3233
  return `${payment.protocol}${chain}${mode}`;
2933
3234
  };
2934
- var runsCommand = (appContext) => new Command7("runs").description("List your recent capability runs").addHelpText(
3235
+ var runsCommand = (appContext) => new Command8("runs").description("List your recent capability runs").addHelpText(
2935
3236
  "after",
2936
3237
  `
2937
3238
  View your recent capability runs \u2014 status, latency, cost, and payment info.
@@ -2989,7 +3290,7 @@ Examples:
2989
3290
  );
2990
3291
 
2991
3292
  // src/commands/search-command.ts
2992
- import { Command as Command8 } from "commander";
3293
+ import { Command as Command9 } from "commander";
2993
3294
  var DEFAULT_MAX_COST_USD = "30";
2994
3295
  var formatReviewCount2 = (count) => {
2995
3296
  if (count >= 1e3) return `${(count / 1e3).toFixed(1)}k`;
@@ -3021,12 +3322,12 @@ var formatSearchResults = (results) => {
3021
3322
  "${displayDescription}"`;
3022
3323
  }).join("\n");
3023
3324
  };
3024
- 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(
3325
+ var searchCommand = (appContext) => new Command9("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(
3025
3326
  "--max-cost <amount>",
3026
3327
  `Maximum cost per call in USD (default: ${DEFAULT_MAX_COST_USD})`
3027
3328
  ).option("--protocol <protocol>", "Payment protocol (x402 or mpp)").option(
3028
3329
  "--status <status>",
3029
- "Filter by availability (healthy, degraded, down)"
3330
+ "Filter by availability (healthy, unknown, down). Defaults to healthy when neither --status nor --all is set; pass --all to see everything."
3030
3331
  ).option("--all", "Disable default quality filtering").option(
3031
3332
  "--source <source>",
3032
3333
  "Only show results from this crawl source (e.g. mpp, bazaar)"
@@ -3053,14 +3354,20 @@ var searchCommand = (appContext) => new Command8("search").description("Search f
3053
3354
  effectiveMaxCost = DEFAULT_MAX_COST_USD;
3054
3355
  appliedDefaultMaxCost = true;
3055
3356
  }
3056
- const validStatuses = ["healthy", "degraded", "down"];
3357
+ const validStatuses = ["healthy", "unknown", "degraded", "down"];
3057
3358
  if (options.status && !validStatuses.includes(options.status)) {
3058
3359
  console.error(
3059
- `Invalid status "${options.status}". Must be one of: healthy, degraded, down.`
3360
+ `Invalid status "${options.status}". Must be one of: ${validStatuses.join(", ")}.`
3060
3361
  );
3061
3362
  process.exitCode = 1;
3062
3363
  return;
3063
3364
  }
3365
+ let effectiveStatus = options.status;
3366
+ let appliedDefaultStatus = false;
3367
+ if (effectiveStatus === void 0 && !options.all) {
3368
+ effectiveStatus = "healthy";
3369
+ appliedDefaultStatus = true;
3370
+ }
3064
3371
  const result = await apiService.search({
3065
3372
  query,
3066
3373
  offset: options.offset,
@@ -3068,7 +3375,7 @@ var searchCommand = (appContext) => new Command8("search").description("Search f
3068
3375
  freeOnly: options.free,
3069
3376
  maxCost: effectiveMaxCost,
3070
3377
  protocol: options.protocol,
3071
- availabilityStatus: options.status,
3378
+ availabilityStatus: effectiveStatus,
3072
3379
  includeAll: options.all,
3073
3380
  source: options.source,
3074
3381
  excludeSource: options.excludeSource
@@ -3086,7 +3393,8 @@ var searchCommand = (appContext) => new Command8("search").description("Search f
3086
3393
  maxCost: effectiveMaxCost,
3087
3394
  maxCostDefaulted: appliedDefaultMaxCost,
3088
3395
  protocol: options.protocol,
3089
- availabilityStatus: options.status,
3396
+ availabilityStatus: effectiveStatus,
3397
+ availabilityStatusDefaulted: appliedDefaultStatus,
3090
3398
  includeAll: options.all ?? false,
3091
3399
  listingSource: options.source,
3092
3400
  excludeListingSource: options.excludeSource,
@@ -3137,9 +3445,9 @@ var searchCommand = (appContext) => new Command8("search").description("Search f
3137
3445
  );
3138
3446
 
3139
3447
  // src/commands/terms-command.ts
3140
- import { Command as Command9 } from "commander";
3448
+ import { Command as Command10 } from "commander";
3141
3449
  var TERMS_URL = "https://zero.xyz/terms-of-service";
3142
- var termsCommand = (_appContext) => new Command9("terms").description("View the ZeroClick Terms of Service").action(async () => {
3450
+ var termsCommand = (_appContext) => new Command10("terms").description("View the ZeroClick Terms of Service").action(async () => {
3143
3451
  console.log(
3144
3452
  `ZeroClick Agentic Capability Search \u2014 Terms of Service
3145
3453
 
@@ -3157,11 +3465,11 @@ Read the full terms at: ${TERMS_URL}
3157
3465
  });
3158
3466
 
3159
3467
  // src/commands/wallet-command.ts
3160
- import { existsSync as existsSync3, readFileSync as readFileSync6 } from "fs";
3161
- import { homedir as homedir3 } from "os";
3162
- import { join as join3 } from "path";
3163
- import { Command as Command10 } from "commander";
3164
- import open from "open";
3468
+ import { existsSync as existsSync3, readFileSync as readFileSync7 } from "fs";
3469
+ import { homedir as homedir4 } from "os";
3470
+ import { join as join4 } from "path";
3471
+ import { Command as Command11 } from "commander";
3472
+ import open2 from "open";
3165
3473
  import { isAddress } from "viem";
3166
3474
  import { generatePrivateKey as generatePrivateKey2, privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
3167
3475
 
@@ -3177,7 +3485,7 @@ var readStdin = async () => {
3177
3485
  // src/commands/wallet-command.ts
3178
3486
  var PRIVATE_KEY_PATTERN = /^0x[0-9a-fA-F]{64}$/;
3179
3487
  var parseProvider = (raw) => raw === "stripe" ? "stripe" : "coinbase";
3180
- var walletBalanceCommand = (appContext) => new Command10("balance").description("Show wallet balance").option(
3488
+ var walletBalanceCommand = (appContext) => new Command11("balance").description("Show wallet balance").option(
3181
3489
  "--address <address>",
3182
3490
  "Check balance for an arbitrary address (no key needed). Useful with `zero wallet generate` \u2014 verify funds arrived without setting the wallet as your default."
3183
3491
  ).action(async (options) => {
@@ -3226,7 +3534,7 @@ var readPrivateKeyFromStdin = async () => {
3226
3534
  }
3227
3535
  return raw;
3228
3536
  };
3229
- var walletFundCommand = (appContext) => new Command10("fund").description("Fund your wallet").argument("[amount]", "Amount to fund in USDC").option("--manual", "Show wallet address for manual transfer").option(
3537
+ var walletFundCommand = (appContext) => new Command11("fund").description("Fund your wallet").argument("[amount]", "Amount to fund in USDC").option("--manual", "Show wallet address for manual transfer").option(
3230
3538
  "--no-open",
3231
3539
  "Print the funding URL instead of opening a browser (for agents \u2014 funding links are one-time use, hand the URL to the user)"
3232
3540
  ).option(
@@ -3300,7 +3608,7 @@ ${address}`);
3300
3608
  const url = await apiService.getFundingUrl(amount, provider);
3301
3609
  if (url) {
3302
3610
  if (options.open) {
3303
- await open(url);
3611
+ await open2(url);
3304
3612
  console.log("Opened funding page in your browser.");
3305
3613
  console.log(`If it didn't open, visit: ${url}`);
3306
3614
  } else {
@@ -3323,7 +3631,7 @@ ${address}`);
3323
3631
  }
3324
3632
  }
3325
3633
  );
3326
- var walletAddressCommand = (appContext) => new Command10("address").description("Show wallet address").action(() => {
3634
+ var walletAddressCommand = (appContext) => new Command11("address").description("Show wallet address").action(() => {
3327
3635
  const { walletService } = appContext.services;
3328
3636
  const address = walletService.getAddress();
3329
3637
  if (!address) {
@@ -3333,7 +3641,7 @@ var walletAddressCommand = (appContext) => new Command10("address").description(
3333
3641
  }
3334
3642
  console.log(address);
3335
3643
  });
3336
- var walletSetCommand = (appContext) => new Command10("set").description("Set wallet from an existing private key").argument("<privateKey>", "Hex-encoded private key (0x-prefixed)").option("--force", "Overwrite existing wallet without prompting").action(async (privateKey, options) => {
3644
+ var walletSetCommand = (appContext) => new Command11("set").description("Set wallet from an existing private key").argument("<privateKey>", "Hex-encoded private key (0x-prefixed)").option("--force", "Overwrite existing wallet without prompting").action(async (privateKey, options) => {
3337
3645
  const { analyticsService } = appContext.services;
3338
3646
  if (!privateKey.startsWith("0x")) {
3339
3647
  console.error("Private key must be 0x-prefixed hex string.");
@@ -3348,11 +3656,11 @@ var walletSetCommand = (appContext) => new Command10("set").description("Set wal
3348
3656
  process.exitCode = 1;
3349
3657
  return;
3350
3658
  }
3351
- const zeroDir = join3(homedir3(), ".zero");
3352
- const configPath = join3(zeroDir, "config.json");
3659
+ const zeroDir = join4(homedir4(), ".zero");
3660
+ const configPath = join4(zeroDir, "config.json");
3353
3661
  if (!options.force && existsSync3(configPath)) {
3354
3662
  try {
3355
- const existing2 = JSON.parse(readFileSync6(configPath, "utf8"));
3663
+ const existing2 = JSON.parse(readFileSync7(configPath, "utf8"));
3356
3664
  if (existing2.privateKey) {
3357
3665
  console.error(
3358
3666
  "Wallet already configured. Use --force to overwrite."
@@ -3364,7 +3672,7 @@ var walletSetCommand = (appContext) => new Command10("set").description("Set wal
3364
3672
  }
3365
3673
  }
3366
3674
  ensureSecureDir(zeroDir);
3367
- const existing = existsSync3(configPath) ? JSON.parse(readFileSync6(configPath, "utf8")) : {};
3675
+ const existing = existsSync3(configPath) ? JSON.parse(readFileSync7(configPath, "utf8")) : {};
3368
3676
  writeSecureFile(
3369
3677
  configPath,
3370
3678
  JSON.stringify(
@@ -3383,7 +3691,7 @@ var walletSetCommand = (appContext) => new Command10("set").description("Set wal
3383
3691
  force: options.force ?? false
3384
3692
  });
3385
3693
  });
3386
- var walletGenerateCommand = (appContext) => new Command10("generate").description(
3694
+ var walletGenerateCommand = (appContext) => new Command11("generate").description(
3387
3695
  "Generate a fresh wallet (address + private key) without touching your configured wallet"
3388
3696
  ).option("--json", "Emit { address, privateKey } as JSON").option(
3389
3697
  "--fund",
@@ -3461,7 +3769,7 @@ var walletGenerateCommand = (appContext) => new Command10("generate").descriptio
3461
3769
  }
3462
3770
  );
3463
3771
  var walletCommand = (appContext) => {
3464
- const cmd = new Command10("wallet").description("Manage your wallet");
3772
+ const cmd = new Command11("wallet").description("Manage your wallet");
3465
3773
  cmd.addCommand(walletBalanceCommand(appContext));
3466
3774
  cmd.addCommand(walletFundCommand(appContext));
3467
3775
  cmd.addCommand(walletAddressCommand(appContext));
@@ -3471,18 +3779,18 @@ var walletCommand = (appContext) => {
3471
3779
  };
3472
3780
 
3473
3781
  // src/commands/welcome-command.ts
3474
- import { existsSync as existsSync4, readFileSync as readFileSync7 } from "fs";
3475
- import { homedir as homedir4 } from "os";
3476
- import { join as join4 } from "path";
3477
- import { Command as Command11 } from "commander";
3478
- import open2 from "open";
3782
+ import { existsSync as existsSync4, readFileSync as readFileSync8 } from "fs";
3783
+ import { homedir as homedir5 } from "os";
3784
+ import { join as join5 } from "path";
3785
+ import { Command as Command12 } from "commander";
3786
+ import open3 from "open";
3479
3787
  import { getAddress } from "viem";
3480
3788
  import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
3481
3789
  var readPrivateKey = () => {
3482
- const configPath = join4(homedir4(), ".zero", "config.json");
3790
+ const configPath = join5(homedir5(), ".zero", "config.json");
3483
3791
  if (!existsSync4(configPath)) return null;
3484
3792
  try {
3485
- const config = JSON.parse(readFileSync7(configPath, "utf8"));
3793
+ const config = JSON.parse(readFileSync8(configPath, "utf8"));
3486
3794
  if (typeof config.privateKey === "string") {
3487
3795
  return config.privateKey;
3488
3796
  }
@@ -3517,7 +3825,7 @@ var printManualFallback = (url) => {
3517
3825
  }
3518
3826
  console.log(lines.join("\n"));
3519
3827
  };
3520
- var welcomeCommand = (appContext) => new Command11("welcome").description("Claim your $5 welcome bonus.").action(async () => {
3828
+ var welcomeCommand = (appContext) => new Command12("welcome").description("Claim your $5 welcome bonus.").action(async () => {
3521
3829
  const { analyticsService } = appContext.services;
3522
3830
  analyticsService.capture("welcome_started", {});
3523
3831
  let walletAddress;
@@ -3550,7 +3858,7 @@ var welcomeCommand = (appContext) => new Command11("welcome").description("Claim
3550
3858
  const urlString = url.toString();
3551
3859
  analyticsService.setWalletAddress(walletAddress);
3552
3860
  try {
3553
- await open2(urlString);
3861
+ await open3(urlString);
3554
3862
  console.log(
3555
3863
  `Opening ${urlString}
3556
3864
 
@@ -3577,7 +3885,7 @@ If your browser didn't open, paste the URL above.`
3577
3885
  // src/app.ts
3578
3886
  var createApp = (appContext) => {
3579
3887
  const { analyticsService } = appContext.services;
3580
- const program = new Command12().name("zero").description("Zero CLI \u2014 Search engine for AI agents").version(package_default.version, "-v, --version").exitOverride().hook("preAction", async (_thisCommand, actionCommand) => {
3888
+ const program = new Command13().name("zero").description("Zero CLI \u2014 Search engine for AI agents").version(package_default.version, "-v, --version").exitOverride().hook("preAction", async (_thisCommand, actionCommand) => {
3581
3889
  const agentFlag = actionCommand.opts().agent;
3582
3890
  if (typeof agentFlag === "string" && agentFlag.trim().length > 0) {
3583
3891
  analyticsService.setAgentHost(agentFlag.trim());
@@ -3601,6 +3909,7 @@ var createApp = (appContext) => {
3601
3909
  program.addCommand(configCommand(appContext));
3602
3910
  program.addCommand(termsCommand(appContext));
3603
3911
  program.addCommand(welcomeCommand(appContext));
3912
+ program.addCommand(authCommand(appContext), { hidden: true });
3604
3913
  return program;
3605
3914
  };
3606
3915
 
@@ -3610,6 +3919,7 @@ var envSchema = z4.object({
3610
3919
  ZERO_API_URL: z4.string().default("https://api.zero.xyz"),
3611
3920
  ZERO_WEB_URL: z4.string().default("https://zero.xyz"),
3612
3921
  ZERO_PRIVATE_KEY: z4.string().optional(),
3922
+ ZERO_SESSION_TOKEN: z4.string().optional(),
3613
3923
  ZERO_ENV: z4.enum(["development", "production"]).default("production")
3614
3924
  });
3615
3925
  var getEnv = () => {
@@ -3624,14 +3934,14 @@ var getEnv = () => {
3624
3934
 
3625
3935
  // src/app/app-services.ts
3626
3936
  import { randomUUID as randomUUID2 } from "crypto";
3627
- import { existsSync as existsSync7, readFileSync as readFileSync10 } from "fs";
3628
- import { homedir as homedir5 } from "os";
3629
- import { join as join6 } from "path";
3937
+ import { existsSync as existsSync7 } from "fs";
3938
+ import { homedir as homedir6 } from "os";
3939
+ import { join as join7 } from "path";
3630
3940
  import { privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
3631
3941
 
3632
3942
  // src/services/analytics-service.ts
3633
3943
  import { randomUUID } from "crypto";
3634
- import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "fs";
3944
+ import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "fs";
3635
3945
  import { dirname as dirname2 } from "path";
3636
3946
  import { PostHog } from "posthog-node";
3637
3947
  var POSTHOG_API_KEY = "phc_B2vLyNxAf2mnqvdPQajf4d4b2iXc35dep2ZrvebMJLuX";
@@ -3654,7 +3964,7 @@ var AnalyticsService = class {
3654
3964
  let persistedAnonId;
3655
3965
  try {
3656
3966
  if (existsSync5(opts.configPath)) {
3657
- const config = JSON.parse(readFileSync8(opts.configPath, "utf8"));
3967
+ const config = JSON.parse(readFileSync9(opts.configPath, "utf8"));
3658
3968
  if (config.telemetry === false) {
3659
3969
  telemetryEnabled = false;
3660
3970
  }
@@ -3676,15 +3986,17 @@ var AnalyticsService = class {
3676
3986
  } else {
3677
3987
  const newAnonId = randomUUID();
3678
3988
  this.distinctId = newAnonId;
3679
- try {
3680
- const dir = dirname2(opts.configPath);
3681
- mkdirSync4(dir, { recursive: true });
3682
- const existing = existsSync5(opts.configPath) ? JSON.parse(readFileSync8(opts.configPath, "utf8")) : {};
3683
- writeFileSync4(
3684
- opts.configPath,
3685
- JSON.stringify({ ...existing, anonId: newAnonId }, null, 2)
3686
- );
3687
- } catch {
3989
+ if (!process.env.VITEST) {
3990
+ try {
3991
+ const dir = dirname2(opts.configPath);
3992
+ mkdirSync4(dir, { recursive: true });
3993
+ const existing = existsSync5(opts.configPath) ? JSON.parse(readFileSync9(opts.configPath, "utf8")) : {};
3994
+ writeFileSync4(
3995
+ opts.configPath,
3996
+ JSON.stringify({ ...existing, anonId: newAnonId }, null, 2)
3997
+ );
3998
+ } catch {
3999
+ }
3688
4000
  }
3689
4001
  }
3690
4002
  const originalConsoleError = console.error;
@@ -3719,7 +4031,7 @@ var AnalyticsService = class {
3719
4031
  if (anonId === walletAddress) return;
3720
4032
  let aliasedTo;
3721
4033
  try {
3722
- const config = JSON.parse(readFileSync8(configPath, "utf8"));
4034
+ const config = JSON.parse(readFileSync9(configPath, "utf8"));
3723
4035
  if (typeof config.aliasedTo === "string") {
3724
4036
  aliasedTo = config.aliasedTo;
3725
4037
  }
@@ -3727,8 +4039,9 @@ var AnalyticsService = class {
3727
4039
  }
3728
4040
  if (aliasedTo === walletAddress) return;
3729
4041
  this.posthog.alias({ distinctId: walletAddress, alias: anonId });
4042
+ if (process.env.VITEST) return;
3730
4043
  try {
3731
- const config = existsSync5(configPath) ? JSON.parse(readFileSync8(configPath, "utf8")) : {};
4044
+ const config = existsSync5(configPath) ? JSON.parse(readFileSync9(configPath, "utf8")) : {};
3732
4045
  writeFileSync4(
3733
4046
  configPath,
3734
4047
  JSON.stringify({ ...config, aliasedTo: walletAddress }, null, 2)
@@ -3803,15 +4116,43 @@ var AnalyticsService = class {
3803
4116
  }
3804
4117
  };
3805
4118
 
4119
+ // src/services/api-account.ts
4120
+ import {
4121
+ bytesToHex,
4122
+ parseSignature,
4123
+ serializeTransaction
4124
+ } from "viem";
4125
+ import { toAccount } from "viem/accounts";
4126
+ var createApiAccount = (walletAddress, api) => toAccount({
4127
+ address: walletAddress,
4128
+ async signMessage({ message }) {
4129
+ const asMessage = typeof message === "string" ? message : typeof message.raw === "string" ? message.raw : bytesToHex(message.raw);
4130
+ const { signature } = await api.signMessageRemote(asMessage);
4131
+ return signature;
4132
+ },
4133
+ async signTypedData(typedData) {
4134
+ const { signature } = await api.signTypedDataRemote(typedData);
4135
+ return signature;
4136
+ },
4137
+ async signTransaction(transaction, options) {
4138
+ const serialize = options?.serializer ?? serializeTransaction;
4139
+ const unsigned = await serialize(transaction);
4140
+ const { signature } = await api.signTransactionRemote({
4141
+ unsignedTransaction: unsigned
4142
+ });
4143
+ return await serialize(transaction, parseSignature(signature));
4144
+ }
4145
+ });
4146
+
3806
4147
  // src/services/state-service.ts
3807
- import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "fs";
3808
- import { join as join5 } from "path";
4148
+ import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "fs";
4149
+ import { join as join6 } from "path";
3809
4150
  var RECENT_SEARCH_LIMIT = 10;
3810
4151
  var StateService = class {
3811
4152
  constructor(zeroDir) {
3812
4153
  this.zeroDir = zeroDir;
3813
- this.lastSearchPath = join5(zeroDir, "last_search.json");
3814
- this.recentSearchesPath = join5(zeroDir, "recent_searches.json");
4154
+ this.lastSearchPath = join6(zeroDir, "last_search.json");
4155
+ this.recentSearchesPath = join6(zeroDir, "recent_searches.json");
3815
4156
  }
3816
4157
  lastSearchPath;
3817
4158
  recentSearchesPath;
@@ -3831,7 +4172,7 @@ var StateService = class {
3831
4172
  loadLastSearch = () => {
3832
4173
  try {
3833
4174
  if (!existsSync6(this.lastSearchPath)) return null;
3834
- const raw = readFileSync9(this.lastSearchPath, "utf8");
4175
+ const raw = readFileSync10(this.lastSearchPath, "utf8");
3835
4176
  return JSON.parse(raw);
3836
4177
  } catch {
3837
4178
  return null;
@@ -3843,7 +4184,7 @@ var StateService = class {
3843
4184
  const last = this.loadLastSearch();
3844
4185
  return { searches: last ? [last] : [] };
3845
4186
  }
3846
- const raw = readFileSync9(this.recentSearchesPath, "utf8");
4187
+ const raw = readFileSync10(this.recentSearchesPath, "utf8");
3847
4188
  const parsed = JSON.parse(raw);
3848
4189
  return { searches: parsed.searches ?? [] };
3849
4190
  } catch {
@@ -3941,40 +4282,67 @@ var detectAgentHost = (env = process.env) => {
3941
4282
 
3942
4283
  // src/app/app-services.ts
3943
4284
  var CLI_VERSION = package_default.version;
3944
- var getServices = (env) => {
3945
- let privateKey = env.ZERO_PRIVATE_KEY ? env.ZERO_PRIVATE_KEY : null;
3946
- const zeroDir = join6(homedir5(), ".zero");
3947
- const configPath = join6(zeroDir, "config.json");
3948
- if (!privateKey) {
3949
- try {
3950
- if (existsSync7(configPath)) {
3951
- const config = JSON.parse(readFileSync10(configPath, "utf8"));
3952
- if (typeof config.privateKey === "string") {
3953
- privateKey = config.privateKey;
3954
- }
3955
- }
3956
- } catch {
4285
+ var resolveCredentials = (env, config) => {
4286
+ const injectedToken = env.ZERO_SESSION_TOKEN;
4287
+ const credentials = injectedToken ? {
4288
+ kind: "session",
4289
+ accessToken: injectedToken,
4290
+ refreshToken: "",
4291
+ userId: ""
4292
+ } : config.session ? {
4293
+ kind: "session",
4294
+ accessToken: config.session.accessToken,
4295
+ refreshToken: config.session.refreshToken,
4296
+ userId: config.session.userId
4297
+ } : { kind: "none" };
4298
+ const privateKey = env.ZERO_PRIVATE_KEY ?? config.privateKey ?? null;
4299
+ return { credentials, privateKey };
4300
+ };
4301
+ var buildOnSessionRefreshed = (configPath) => async (tokens) => {
4302
+ const current = readConfig(configPath);
4303
+ if (!current.session) return;
4304
+ const next = {
4305
+ ...current,
4306
+ session: {
4307
+ ...current.session,
4308
+ accessToken: tokens.accessToken,
4309
+ refreshToken: tokens.refreshToken
3957
4310
  }
3958
- }
3959
- const account = privateKey ? privateKeyToAccount4(privateKey) : null;
3960
- let lowBalanceWarning = 1;
3961
- try {
3962
- if (existsSync7(configPath)) {
3963
- const config = JSON.parse(readFileSync10(configPath, "utf8"));
3964
- if (typeof config.lowBalanceWarning === "number") {
3965
- lowBalanceWarning = config.lowBalanceWarning;
3966
- }
4311
+ };
4312
+ writeSecureFile(configPath, JSON.stringify(next, null, 2));
4313
+ };
4314
+ var getServices = async (env) => {
4315
+ const zeroDir = join7(homedir6(), ".zero");
4316
+ const configPath = join7(zeroDir, "config.json");
4317
+ const config = existsSync7(configPath) ? readConfig(configPath) : {};
4318
+ const { credentials, privateKey } = resolveCredentials(env, config);
4319
+ const lowBalanceWarning = typeof config.lowBalanceWarning === "number" ? config.lowBalanceWarning : 1;
4320
+ const apiService = new ApiService(
4321
+ env.ZERO_API_URL,
4322
+ privateKey ? privateKeyToAccount4(privateKey) : null,
4323
+ credentials,
4324
+ buildOnSessionRefreshed(configPath)
4325
+ );
4326
+ let account = privateKey ? privateKeyToAccount4(privateKey) : null;
4327
+ let managed = false;
4328
+ if (!account && credentials.kind === "session") {
4329
+ const address = await resolveManagedWalletAddress(apiService);
4330
+ if (address) {
4331
+ account = createApiAccount(address, apiService);
4332
+ managed = true;
3967
4333
  }
3968
- } catch {
3969
4334
  }
3970
- const apiService = new ApiService(env.ZERO_API_URL, account);
3971
- const paymentService = new PaymentService(account, { lowBalanceWarning });
4335
+ if (account && !apiService.walletAddress) {
4336
+ apiService.setWalletAddress(account.address);
4337
+ }
4338
+ const paymentService = new PaymentService(account, {
4339
+ lowBalanceWarning,
4340
+ managed
4341
+ });
3972
4342
  const stateService = new StateService(zeroDir);
3973
4343
  const walletService = new WalletService(
3974
4344
  apiService.walletAddress,
3975
- {
3976
- lowBalanceWarning
3977
- },
4345
+ { lowBalanceWarning },
3978
4346
  paymentService.getTotalBalance
3979
4347
  );
3980
4348
  const analyticsService = new AnalyticsService({
@@ -3993,16 +4361,29 @@ var getServices = (env) => {
3993
4361
  walletService
3994
4362
  };
3995
4363
  };
4364
+ var resolveManagedWalletAddress = async (api) => {
4365
+ try {
4366
+ const wallets = await api.getWallets();
4367
+ const primary = wallets.find(
4368
+ (w) => w.source === "privy_embedded" && w.isPrimary
4369
+ );
4370
+ if (primary) return primary.walletAddress;
4371
+ const provisioned = await api.provisionWallet();
4372
+ return provisioned.walletAddress ?? null;
4373
+ } catch {
4374
+ return null;
4375
+ }
4376
+ };
3996
4377
 
3997
4378
  // src/app/app-context.ts
3998
- var createAppContext = () => {
4379
+ var createAppContext = async () => {
3999
4380
  const env = getEnv();
4000
4381
  if (!env) {
4001
4382
  return null;
4002
4383
  }
4003
4384
  return {
4004
4385
  env,
4005
- services: getServices(env),
4386
+ services: await getServices(env),
4006
4387
  invocation: { current: null }
4007
4388
  };
4008
4389
  };
@@ -4016,8 +4397,8 @@ import {
4016
4397
  readlinkSync,
4017
4398
  writeFileSync as writeFileSync6
4018
4399
  } from "fs";
4019
- import { homedir as homedir6 } from "os";
4020
- import { dirname as dirname3, join as join7, resolve } from "path";
4400
+ import { homedir as homedir7 } from "os";
4401
+ import { dirname as dirname3, join as join8, resolve } from "path";
4021
4402
  var CACHE_FILENAME = "update_check.json";
4022
4403
  var NPM_REGISTRY_URL = "https://registry.npmjs.org/@zeroxyz/cli/latest";
4023
4404
  var CHECK_INTERVAL_MS = 60 * 60 * 1e3;
@@ -4041,10 +4422,10 @@ var resolveExecPath = (execPath) => {
4041
4422
  var detectInstallMethod = (opts = {}) => {
4042
4423
  const execPath = opts.execPath ?? process.execPath;
4043
4424
  const pkg = opts.pkg ?? process.pkg;
4044
- const home = opts.home ?? homedir6();
4425
+ const home = opts.home ?? homedir7();
4045
4426
  if (pkg) return "binary";
4046
4427
  const resolved = resolveExecPath(execPath);
4047
- const zeroBin = join7(home, ".zero", "bin");
4428
+ const zeroBin = join8(home, ".zero", "bin");
4048
4429
  if (resolved.startsWith(zeroBin)) return "binary";
4049
4430
  return "npm";
4050
4431
  };
@@ -4069,7 +4450,7 @@ var compareVersions = (a, b) => {
4069
4450
  if (pb.pre === null) return -1;
4070
4451
  return pa.pre < pb.pre ? -1 : 1;
4071
4452
  };
4072
- var cachePath = (zeroDir) => join7(zeroDir, CACHE_FILENAME);
4453
+ var cachePath = (zeroDir) => join8(zeroDir, CACHE_FILENAME);
4073
4454
  var readCache = (zeroDir) => {
4074
4455
  try {
4075
4456
  const path = cachePath(zeroDir);
@@ -4158,12 +4539,12 @@ var maybePrintUpdateBanner = (zeroDir, currentVersion) => {
4158
4539
 
4159
4540
  // src/index.ts
4160
4541
  var main = async () => {
4161
- const appContext = createAppContext();
4542
+ const appContext = await createAppContext();
4162
4543
  if (!appContext) {
4163
4544
  console.error("Failed to create app context");
4164
4545
  process.exit(1);
4165
4546
  }
4166
- const zeroDir = join8(homedir7(), ".zero");
4547
+ const zeroDir = join9(homedir8(), ".zero");
4167
4548
  maybePrintUpdateBanner(zeroDir, package_default.version);
4168
4549
  const app = createApp(appContext);
4169
4550
  let caughtError = null;