@zeroxyz/cli 0.0.46 → 0.0.47

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 +179 -119
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -76374,7 +76374,7 @@ init_esm_shims();
76374
76374
 
76375
76375
  // package.json
76376
76376
  var package_default = {
76377
- version: "0.0.46"};
76377
+ version: "0.0.47"};
76378
76378
 
76379
76379
  // src/app.ts
76380
76380
  init_esm_shims();
@@ -77005,6 +77005,21 @@ defineLazyProperty(apps, "safari", () => detectPlatformBinary({
77005
77005
  }));
77006
77006
  var open_default = open;
77007
77007
 
77008
+ // src/util/redact.ts
77009
+ init_esm_shims();
77010
+ var ERROR_MAX = 500;
77011
+ var QUERY_MAX = 200;
77012
+ var redactUrl = (raw) => {
77013
+ try {
77014
+ const parsed = new URL(raw);
77015
+ return `${parsed.origin}${parsed.pathname}`;
77016
+ } catch {
77017
+ return raw;
77018
+ }
77019
+ };
77020
+ var truncateQuery = (raw) => raw.length > QUERY_MAX ? `${raw.slice(0, QUERY_MAX)}\u2026` : raw;
77021
+ var truncateError = (raw) => raw.length > ERROR_MAX ? `${raw.slice(0, ERROR_MAX)}\u2026` : raw;
77022
+
77008
77023
  // src/util/secure-config.ts
77009
77024
  init_esm_shims();
77010
77025
  var SECURE_DIR_MODE = 448;
@@ -77052,8 +77067,14 @@ var LEGACY_KEY_NOTICE = {
77052
77067
  keep: "zero wallet set <key>"
77053
77068
  };
77054
77069
  var hasLegacyPrivateKey = () => readConfig(getConfigPath()).privateKey !== void 0;
77055
- var reportSignedIn = (result, json3) => {
77070
+ var reportSignedIn = (result, json3, la) => {
77056
77071
  const legacyKeyPresent = hasLegacyPrivateKey();
77072
+ la?.analytics.capture("auth_login_completed", {
77073
+ mode: la.mode,
77074
+ authMethod: "workos_device",
77075
+ legacyKeyDetected: legacyKeyPresent,
77076
+ hadPriorSession: la.hadPriorSession
77077
+ });
77057
77078
  if (json3) {
77058
77079
  process.stdout.write(
77059
77080
  `${JSON.stringify({
@@ -77085,7 +77106,12 @@ Signed in as ${result.user.email ?? result.user.id}
77085
77106
  );
77086
77107
  }
77087
77108
  };
77088
- var reportExpired = (json3) => {
77109
+ var reportExpired = (json3, la) => {
77110
+ la?.analytics.capture("auth_login_failed", {
77111
+ mode: la.mode,
77112
+ reason: "device_expired",
77113
+ error: "device code expired"
77114
+ });
77089
77115
  if (json3) {
77090
77116
  process.stdout.write(`${JSON.stringify({ status: "expired" })}
77091
77117
  `);
@@ -77127,7 +77153,7 @@ Once authorized, run:
77127
77153
  `
77128
77154
  );
77129
77155
  };
77130
- var runFinish = async (client, deviceCode, json3) => {
77156
+ var runFinish = async (client, deviceCode, json3, la) => {
77131
77157
  const deadline = Date.now() + FINISH_MAX_WAIT_MS;
77132
77158
  while (Date.now() < deadline) {
77133
77159
  const result = await client.auth.device.poll(deviceCode);
@@ -77137,16 +77163,16 @@ var runFinish = async (client, deviceCode, json3) => {
77137
77163
  continue;
77138
77164
  }
77139
77165
  if (result.status === "expired") {
77140
- reportExpired(json3);
77166
+ reportExpired(json3, la);
77141
77167
  return;
77142
77168
  }
77143
77169
  persistSession(result);
77144
- reportSignedIn(result, json3);
77170
+ reportSignedIn(result, json3, la);
77145
77171
  return;
77146
77172
  }
77147
- reportExpired(json3);
77173
+ reportExpired(json3, la);
77148
77174
  };
77149
- var runInteractive = async (client, shouldOpen) => {
77175
+ var runInteractive = async (client, shouldOpen, la) => {
77150
77176
  const start = await client.auth.device.start();
77151
77177
  const url4 = `${start.verificationUri}?code=${start.userCode}`;
77152
77178
  process.stdout.write(
@@ -77167,14 +77193,14 @@ User code: ${start.userCode}
77167
77193
  continue;
77168
77194
  }
77169
77195
  if (result.status === "expired") {
77170
- reportExpired(false);
77196
+ reportExpired(false, la);
77171
77197
  return;
77172
77198
  }
77173
77199
  persistSession(result);
77174
- reportSignedIn(result, false);
77200
+ reportSignedIn(result, false, la);
77175
77201
  return;
77176
77202
  }
77177
- reportExpired(false);
77203
+ reportExpired(false, la);
77178
77204
  };
77179
77205
  var authLoginCommand = (appContext) => new Command("login").description("Sign in to Zero").option("--no-open", "Do not open the browser automatically").option(
77180
77206
  "--start",
@@ -77184,7 +77210,7 @@ var authLoginCommand = (appContext) => new Command("login").description("Sign in
77184
77210
  "Complete a login begun with --start: poll until the user authorizes, then save the session."
77185
77211
  ).option("--json", "Emit machine-readable JSON instead of human text").action(
77186
77212
  async (opts) => {
77187
- const { client } = appContext.services;
77213
+ const { client, analyticsService } = appContext.services;
77188
77214
  const json3 = opts.json ?? false;
77189
77215
  if (opts.start && opts.finish) {
77190
77216
  process.stderr.write("Pass either --start or --finish, not both.\n");
@@ -77195,23 +77221,42 @@ var authLoginCommand = (appContext) => new Command("login").description("Sign in
77195
77221
  await runStart(client, json3);
77196
77222
  return;
77197
77223
  }
77198
- if (opts.finish) {
77199
- await runFinish(client, opts.finish, json3);
77200
- return;
77224
+ const mode = opts.finish ? "finish" : "interactive";
77225
+ const hadPriorSession = readConfig(getConfigPath()).session !== void 0;
77226
+ analyticsService.capture("auth_login_started", { mode, json: json3 });
77227
+ const la = {
77228
+ analytics: analyticsService,
77229
+ mode,
77230
+ hadPriorSession
77231
+ };
77232
+ try {
77233
+ if (opts.finish) {
77234
+ await runFinish(client, opts.finish, json3, la);
77235
+ return;
77236
+ }
77237
+ await runInteractive(client, opts.open, la);
77238
+ } catch (err) {
77239
+ analyticsService.capture("auth_login_failed", {
77240
+ mode,
77241
+ reason: "api_error",
77242
+ error: truncateError(err.message)
77243
+ });
77244
+ throw err;
77201
77245
  }
77202
- await runInteractive(client, opts.open);
77203
77246
  }
77204
77247
  );
77205
77248
  var authLogoutCommand = (appContext) => new Command("logout").description("Sign out of Zero").action(async () => {
77206
- const { client } = appContext.services;
77249
+ const { client, analyticsService } = appContext.services;
77207
77250
  const path3 = getConfigPath();
77208
77251
  const config2 = readConfig(path3);
77252
+ const hadSession = config2.session !== void 0;
77209
77253
  if (config2.session) {
77210
77254
  await client.auth.logout(config2.session.refreshToken).catch(() => {
77211
77255
  });
77212
77256
  }
77213
77257
  const { session: _drop, ...rest } = config2;
77214
77258
  writeSecureFile(path3, JSON.stringify(rest, null, 2));
77259
+ analyticsService.capture("auth_logout_completed", { hadSession });
77215
77260
  process.stdout.write("Signed out.\n");
77216
77261
  });
77217
77262
  var authWhoamiCommand = (appContext) => new Command("whoami").description("Print the current Zero identity").option("--json", "Emit machine-readable JSON instead of human text").action(async (opts) => {
@@ -138372,7 +138417,7 @@ var isTextContentType = (contentType) => {
138372
138417
  const lower = contentType.toLowerCase();
138373
138418
  return TEXT_CONTENT_TYPES.some((marker) => lower.includes(marker));
138374
138419
  };
138375
- var redactUrl = (url4) => {
138420
+ var redactUrl2 = (url4) => {
138376
138421
  try {
138377
138422
  const u2 = new URL(url4);
138378
138423
  return `${u2.origin}${u2.pathname}`;
@@ -138819,7 +138864,7 @@ var clientFetch = async (client, url4, opts = {}) => {
138819
138864
  level: "warn",
138820
138865
  message: "Failed to record run for fetch",
138821
138866
  meta: {
138822
- url: redactUrl(url4),
138867
+ url: redactUrl2(url4),
138823
138868
  capabilityId: opts.capabilityId,
138824
138869
  error: errorMessage22,
138825
138870
  errorCode: code
@@ -139575,21 +139620,6 @@ var tryParseJson2 = (text) => {
139575
139620
  }
139576
139621
  };
139577
139622
 
139578
- // src/util/redact.ts
139579
- init_esm_shims();
139580
- var ERROR_MAX = 500;
139581
- var QUERY_MAX = 200;
139582
- var redactUrl2 = (raw) => {
139583
- try {
139584
- const parsed = new URL(raw);
139585
- return `${parsed.origin}${parsed.pathname}`;
139586
- } catch {
139587
- return raw;
139588
- }
139589
- };
139590
- var truncateQuery = (raw) => raw.length > QUERY_MAX ? `${raw.slice(0, QUERY_MAX)}\u2026` : raw;
139591
- var truncateError = (raw) => raw.length > ERROR_MAX ? `${raw.slice(0, ERROR_MAX)}\u2026` : raw;
139592
-
139593
139623
  // src/commands/fetch-command.ts
139594
139624
  var MAX_INLINE_REQUEST_BODY_BYTES = 10 * 1024 * 1024;
139595
139625
  var MAX_FILE_REQUEST_BODY_BYTES = 500 * 1024 * 1024;
@@ -139753,7 +139783,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
139753
139783
  const message2 = err instanceof Error ? err.message : "Failed to read request body";
139754
139784
  analyticsService.capture("fetch_error", {
139755
139785
  cliErrorClass: /exceeds the .* byte local cap/.test(message2) ? "payload_too_large" : "schema_validation_failed",
139756
- url: redactUrl2(resolvedUrl),
139786
+ url: redactUrl(resolvedUrl),
139757
139787
  error: truncateError(message2)
139758
139788
  });
139759
139789
  console.error(message2);
@@ -139809,7 +139839,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
139809
139839
  const lastSearch = stateService.loadLastSearch();
139810
139840
  const cached2 = lastSearch?.capabilities ?? [];
139811
139841
  analyticsService.capture("capability_resolution_missed", {
139812
- url: redactUrl2(resolvedUrl),
139842
+ url: redactUrl(resolvedUrl),
139813
139843
  method,
139814
139844
  hasLastSearch: lastSearch !== null,
139815
139845
  lastSearchSize: cached2.length,
@@ -139867,7 +139897,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
139867
139897
  const message2 = err instanceof Error ? err.message : "Fetch failed";
139868
139898
  analyticsService.capture("fetch_error", {
139869
139899
  cliErrorClass: "network",
139870
- url: redactUrl2(resolvedUrl),
139900
+ url: redactUrl(resolvedUrl),
139871
139901
  error: truncateError(message2)
139872
139902
  });
139873
139903
  console.error(` Fetch failed: ${message2}`);
@@ -139959,7 +139989,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
139959
139989
  }
139960
139990
  }
139961
139991
  analyticsService.capture("fetch_executed", {
139962
- url: redactUrl2(resolvedUrl),
139992
+ url: redactUrl(resolvedUrl),
139963
139993
  status: status ?? void 0,
139964
139994
  outcome,
139965
139995
  latencyMs,
@@ -139978,6 +140008,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
139978
140008
  resultRank: resultRank ?? void 0,
139979
140009
  runId: runId ?? void 0,
139980
140010
  runTracked: !!runId,
140011
+ signingSource: signing?.source ?? "none",
139981
140012
  // A NULL searchId on a direct_slug fetch is correct here,
139982
140013
  // not a funnel gap to paper over.
139983
140014
  fetchOrigin,
@@ -139997,7 +140028,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
139997
140028
  capabilityId: capabilityId ?? void 0,
139998
140029
  searchId: searchId ?? void 0,
139999
140030
  resultRank: resultRank ?? void 0,
140000
- url: redactUrl2(resolvedUrl),
140031
+ url: redactUrl(resolvedUrl),
140001
140032
  status: typeof status === "number" ? status : void 0,
140002
140033
  upstreamErrorMessage: upstreamError?.message,
140003
140034
  errorSnippetHash: upstreamError?.snippetHash,
@@ -140094,7 +140125,7 @@ var fetchCommand = (appContext) => new Command("fetch").description(
140094
140125
  try {
140095
140126
  appContext.services.analyticsService.capture("fetch_error", {
140096
140127
  cliErrorClass: "unknown",
140097
- url: url4 ? redactUrl2(url4) : "unknown",
140128
+ url: url4 ? redactUrl(url4) : "unknown",
140098
140129
  error: truncateError(message2)
140099
140130
  });
140100
140131
  } catch {
@@ -142344,7 +142375,7 @@ var walletGenerateCommand = (appContext) => new Command("generate").description(
142344
142375
  var walletMigrateCommand = (appContext) => new Command("migrate").description(
142345
142376
  "Sweep all USDC from your private-key wallet into your Zero wallet"
142346
142377
  ).option("--json", "Emit the migration result as JSON").option("-y, --yes", "Skip the confirmation prompt").action(async (options) => {
142347
- const { client, walletMigrationService } = appContext.services;
142378
+ const { client, walletMigrationService, analyticsService } = appContext.services;
142348
142379
  const zeroDir = join(homedir(), ".zero");
142349
142380
  const configPath = join(zeroDir, "config.json");
142350
142381
  const config2 = existsSync(configPath) ? readConfig(configPath) : {};
@@ -142372,99 +142403,126 @@ var walletMigrateCommand = (appContext) => new Command("migrate").description(
142372
142403
  process.exitCode = 1;
142373
142404
  return;
142374
142405
  }
142375
- const to2 = await resolveManagedWalletAddress(client);
142376
- if (!to2) {
142377
- console.error(
142378
- "Could not resolve your Zero wallet. Run `zero auth login` and try again."
142379
- );
142380
- process.exitCode = 1;
142381
- return;
142382
- }
142383
- if (to2.toLowerCase() === source.address.toLowerCase()) {
142384
- console.error(
142385
- "Source and destination are the same wallet \u2014 nothing to migrate."
142386
- );
142387
- process.exitCode = 1;
142388
- return;
142389
- }
142390
- const balance = await walletMigrationService.getSweepableBalance();
142391
- if (balance.raw <= 0n) {
142392
- if (options.json) {
142393
- console.log(
142394
- JSON.stringify({ destination: to2, legs: [], keyRemoved: false })
142395
- );
142396
- } else {
142397
- console.log("Nothing to migrate (no USDC found).");
142398
- }
142399
- return;
142400
- }
142401
- if (!options.yes) {
142402
- if (options.json || !process.stdin.isTTY) {
142406
+ const keySource = appContext.env.ZERO_PRIVATE_KEY ? "env" : "config";
142407
+ let step = "destination_resolve";
142408
+ try {
142409
+ const to2 = await resolveManagedWalletAddress(client);
142410
+ if (!to2) {
142403
142411
  console.error(
142404
- "Refusing to migrate without confirmation. Re-run with --yes to proceed."
142412
+ "Could not resolve your Zero wallet. Run `zero auth login` and try again."
142405
142413
  );
142406
142414
  process.exitCode = 1;
142407
142415
  return;
142408
142416
  }
142409
- const proceed = await ye({
142410
- message: `Please confirm you would like to transfer $${balance.usdc} from your private wallet to your Zero managed wallet`
142411
- });
142412
- if (pD(proceed) || !proceed) {
142413
- console.log("Migration cancelled.");
142417
+ if (to2.toLowerCase() === source.address.toLowerCase()) {
142418
+ console.error(
142419
+ "Source and destination are the same wallet \u2014 nothing to migrate."
142420
+ );
142421
+ process.exitCode = 1;
142414
142422
  return;
142415
142423
  }
142416
- }
142417
- const results = await walletMigrationService.migrateAllUsdc(to2, {
142418
- migrateWallet: (authorization) => client.wallet.migrateAuthorization(authorization)
142419
- });
142420
- const anyFailed = results.some((r2) => r2.status === "failed");
142421
- const anySwept = results.some((r2) => r2.status === "swept");
142422
- let backupPath = null;
142423
- if (anySwept && !anyFailed && config2.privateKey) {
142424
- try {
142425
- backupPath = backupAndStripPrivateKey(zeroDir).backupPath;
142426
- } catch {
142427
- backupPath = null;
142428
- }
142429
- }
142430
- if (options.json) {
142431
- console.log(
142432
- JSON.stringify({
142433
- destination: to2,
142434
- legs: results,
142435
- keyRemoved: backupPath !== null,
142436
- backupPath
142437
- })
142438
- );
142439
- } else {
142440
- console.log(`Migrating USDC \u2192 ${to2}`);
142441
- for (const r2 of results) {
142442
- if (r2.status === "swept") {
142424
+ step = "balance_check";
142425
+ const balance = await walletMigrationService.getSweepableBalance();
142426
+ if (balance.raw <= 0n) {
142427
+ if (options.json) {
142443
142428
  console.log(
142444
- ` ${r2.chain}: swept ${r2.amount} USDC (tx ${r2.txHash})`
142429
+ JSON.stringify({ destination: to2, legs: [], keyRemoved: false })
142445
142430
  );
142446
- } else if (r2.status === "skipped") {
142447
- console.log(` ${r2.chain}: skipped (no balance)`);
142448
142431
  } else {
142449
- console.log(` ${r2.chain}: FAILED \u2014 ${r2.error}`);
142432
+ console.log("Nothing to migrate (no USDC found).");
142450
142433
  }
142434
+ return;
142451
142435
  }
142452
- if (backupPath) {
142453
- console.log("");
142454
- console.log(
142455
- `Private key removed from config (backed up to ${backupPath}). Your Zero wallet is now primary.`
142456
- );
142457
- } else if (anyFailed) {
142458
- console.log("");
142436
+ analyticsService.capture("wallet_migrate_started", {
142437
+ hasLegacyKey: config2.privateKey !== void 0,
142438
+ keySource
142439
+ });
142440
+ if (!options.yes) {
142441
+ if (options.json || !process.stdin.isTTY) {
142442
+ console.error(
142443
+ "Refusing to migrate without confirmation. Re-run with --yes to proceed."
142444
+ );
142445
+ process.exitCode = 1;
142446
+ return;
142447
+ }
142448
+ const proceed = await ye({
142449
+ message: `Please confirm you would like to transfer $${balance.usdc} from your private wallet to your Zero managed wallet`
142450
+ });
142451
+ if (pD(proceed) || !proceed) {
142452
+ console.log("Migration cancelled.");
142453
+ return;
142454
+ }
142455
+ }
142456
+ step = "sweep";
142457
+ const results = await walletMigrationService.migrateAllUsdc(to2, {
142458
+ migrateWallet: (authorization) => client.wallet.migrateAuthorization(authorization)
142459
+ });
142460
+ const anyFailed = results.some((r2) => r2.status === "failed");
142461
+ const anySwept = results.some((r2) => r2.status === "swept");
142462
+ step = "key_backup";
142463
+ let backupPath = null;
142464
+ if (anySwept && !anyFailed && config2.privateKey) {
142465
+ try {
142466
+ backupPath = backupAndStripPrivateKey(zeroDir).backupPath;
142467
+ } catch {
142468
+ backupPath = null;
142469
+ }
142470
+ }
142471
+ const baseLeg = results.find((r2) => r2.chain === "base");
142472
+ const tempoLeg = results.find((r2) => r2.chain === "tempo");
142473
+ analyticsService.capture("wallet_migrate_completed", {
142474
+ baseStatus: baseLeg?.status ?? "skipped",
142475
+ tempoStatus: tempoLeg?.status ?? "skipped",
142476
+ baseAmountUsdc: baseLeg?.amount,
142477
+ tempoAmountUsdc: tempoLeg?.amount,
142478
+ keyRemoved: backupPath !== null,
142479
+ anyFailed
142480
+ });
142481
+ if (options.json) {
142459
142482
  console.log(
142460
- "A transfer failed \u2014 your private key was kept. Re-run `zero wallet migrate` to retry."
142483
+ JSON.stringify({
142484
+ destination: to2,
142485
+ legs: results,
142486
+ keyRemoved: backupPath !== null,
142487
+ backupPath
142488
+ })
142461
142489
  );
142462
- } else if (!anySwept) {
142463
- console.log("");
142464
- console.log("Nothing to migrate (no USDC found).");
142490
+ } else {
142491
+ console.log(`Migrating USDC \u2192 ${to2}`);
142492
+ for (const r2 of results) {
142493
+ if (r2.status === "swept") {
142494
+ console.log(
142495
+ ` ${r2.chain}: swept ${r2.amount} USDC (tx ${r2.txHash})`
142496
+ );
142497
+ } else if (r2.status === "skipped") {
142498
+ console.log(` ${r2.chain}: skipped (no balance)`);
142499
+ } else {
142500
+ console.log(` ${r2.chain}: FAILED \u2014 ${r2.error}`);
142501
+ }
142502
+ }
142503
+ if (backupPath) {
142504
+ console.log("");
142505
+ console.log(
142506
+ `Private key removed from config (backed up to ${backupPath}). Your Zero wallet is now primary.`
142507
+ );
142508
+ } else if (anyFailed) {
142509
+ console.log("");
142510
+ console.log(
142511
+ "A transfer failed \u2014 your private key was kept. Re-run `zero wallet migrate` to retry."
142512
+ );
142513
+ } else if (!anySwept) {
142514
+ console.log("");
142515
+ console.log("Nothing to migrate (no USDC found).");
142516
+ }
142465
142517
  }
142518
+ if (anyFailed) process.exitCode = 1;
142519
+ } catch (err) {
142520
+ analyticsService.capture("wallet_migrate_failed", {
142521
+ step,
142522
+ error: truncateError(err.message)
142523
+ });
142524
+ throw err;
142466
142525
  }
142467
- if (anyFailed) process.exitCode = 1;
142468
142526
  });
142469
142527
  var walletCommand = (appContext) => {
142470
142528
  const cmd = new Command("wallet").description("Manage your wallet");
@@ -147072,7 +147130,9 @@ var getServices = async (env) => {
147072
147130
  account = legacyAccount;
147073
147131
  signingSource = "legacy";
147074
147132
  }
147075
- const walletMigrationService = new WalletMigrationService(account);
147133
+ const walletMigrationService = new WalletMigrationService(
147134
+ byoAccount ?? legacyAccount
147135
+ );
147076
147136
  const stateService = new StateService(zeroDir);
147077
147137
  const analyticsService = new AnalyticsService({
147078
147138
  walletAddress: account?.address ?? null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeroxyz/cli",
3
- "version": "0.0.46",
3
+ "version": "0.0.47",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "zero": "dist/index.js",