zk-agent-cli 0.1.0-rc.2 → 0.1.0-rc.4

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 (3) hide show
  1. package/README.md +97 -31
  2. package/dist/index.js +1298 -137
  3. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { Command as Command13, CommanderError } from "commander";
4
+ import { Command as Command14, CommanderError } from "commander";
5
5
  import { config as loadEnv } from "dotenv";
6
6
 
7
7
  // src/commands/operations.ts
@@ -79,6 +79,9 @@ import fs from "node:fs";
79
79
  import os from "node:os";
80
80
  import path from "node:path";
81
81
 
82
+ // ../agent-core/src/wallet-session.ts
83
+ import { createHash } from "node:crypto";
84
+
82
85
  // ../agent-session-protocol/src/constants.ts
83
86
  var PROTOCOL_VERSION = "zk-agent-session-v1";
84
87
 
@@ -239,6 +242,10 @@ function buildApprovedSessionPayload(input) {
239
242
  function isHexPrivateKey(value) {
240
243
  return /^0x[a-fA-F0-9]{64}$/.test(value);
241
244
  }
245
+ function deriveStableWalletId(wallet) {
246
+ const seed = `${wallet.walletAddress.trim().toLowerCase()}:${wallet.chainId}:${wallet.createdAt.trim()}`;
247
+ return `wal_${createHash("sha256").update(seed).digest("hex").slice(0, 24)}`;
248
+ }
242
249
  function deriveLocalExecutionSignerAddress(privateKey) {
243
250
  if (!privateKey || !isHexPrivateKey(privateKey)) return void 0;
244
251
  try {
@@ -263,15 +270,25 @@ function resolveLocalExecutionPrivateKey(wallet) {
263
270
  function migrateWalletSessionRecord(wallet) {
264
271
  const legacyPrivateKey = wallet.sessionPayload?.sessionPrivateKey;
265
272
  const existingAuthority = wallet.localExecutionAuthority;
273
+ const walletId = wallet.walletId || deriveStableWalletId(wallet);
266
274
  if (!existingAuthority && !legacyPrivateKey) {
267
- return wallet;
275
+ if (wallet.walletId === walletId) return wallet;
276
+ return {
277
+ ...wallet,
278
+ walletId
279
+ };
268
280
  }
269
281
  const privateKey = existingAuthority?.privateKey || legacyPrivateKey;
270
282
  if (!privateKey) {
271
- return wallet;
283
+ if (wallet.walletId === walletId) return wallet;
284
+ return {
285
+ ...wallet,
286
+ walletId
287
+ };
272
288
  }
273
289
  return {
274
290
  ...wallet,
291
+ walletId,
275
292
  localExecutionAuthority: {
276
293
  privateKey,
277
294
  signerAddress: existingAuthority?.signerAddress || deriveLocalExecutionSignerAddress(privateKey),
@@ -375,6 +392,33 @@ function readEncryptedJson(filePath) {
375
392
  function storageDir() {
376
393
  return ensureStorageDir();
377
394
  }
395
+ function ensureStorageCollectionDir(collectionName) {
396
+ const storageDirectory = ensureStorageDir();
397
+ const collectionDirectory = path.join(storageDirectory, collectionName);
398
+ if (!fs.existsSync(collectionDirectory)) {
399
+ fs.mkdirSync(collectionDirectory, { recursive: true, mode: 448 });
400
+ }
401
+ return collectionDirectory;
402
+ }
403
+ async function saveEncryptedStorageRecord(collectionName, recordId, value) {
404
+ const collectionDirectory = ensureStorageCollectionDir(collectionName);
405
+ writeEncryptedJson(path.join(collectionDirectory, `${recordId}.json`), value);
406
+ }
407
+ async function loadEncryptedStorageRecord(collectionName, recordId) {
408
+ const filePath = storagePath(collectionName, `${recordId}.json`);
409
+ if (!fs.existsSync(filePath)) return null;
410
+ return readEncryptedJson(filePath);
411
+ }
412
+ async function listEncryptedStorageRecordIds(collectionName) {
413
+ const collectionDirectory = ensureStorageCollectionDir(collectionName);
414
+ return fs.readdirSync(collectionDirectory).filter((entry) => entry.endsWith(".json")).map((entry) => entry.replace(/\.json$/, ""));
415
+ }
416
+ async function deleteEncryptedStorageRecord(collectionName, recordId) {
417
+ const filePath = storagePath(collectionName, `${recordId}.json`);
418
+ if (!fs.existsSync(filePath)) return false;
419
+ fs.unlinkSync(filePath);
420
+ return true;
421
+ }
378
422
  async function saveProjectConfig(config) {
379
423
  const storageDirectory = ensureStorageDir();
380
424
  writeJson(path.join(storageDirectory, "config.json"), config);
@@ -385,64 +429,42 @@ async function loadProjectConfig() {
385
429
  return readJson(filePath);
386
430
  }
387
431
  async function saveWalletSession(record) {
388
- const storageDirectory = ensureStorageDir();
389
- writeEncryptedJson(
390
- path.join(storageDirectory, "wallets", `${record.walletName}.json`),
391
- migrateWalletSessionRecord(record)
392
- );
432
+ await saveEncryptedStorageRecord("wallets", record.walletName, migrateWalletSessionRecord(record));
393
433
  }
394
434
  async function loadWalletSession(walletName) {
395
- const filePath = storagePath("wallets", `${walletName}.json`);
396
- if (!fs.existsSync(filePath)) return null;
397
- return migrateWalletSessionRecord(readEncryptedJson(filePath));
435
+ const record = await loadEncryptedStorageRecord("wallets", walletName);
436
+ return record ? migrateWalletSessionRecord(record) : null;
398
437
  }
399
438
  async function listWalletNames() {
400
- const storageDirectory = ensureStorageDir();
401
- return fs.readdirSync(path.join(storageDirectory, "wallets")).filter((entry) => entry.endsWith(".json")).map((entry) => entry.replace(/\.json$/, ""));
439
+ return listEncryptedStorageRecordIds("wallets");
402
440
  }
403
441
  async function listWalletRequestIds() {
404
442
  const storageDirectory = ensureStorageDir();
405
443
  return fs.readdirSync(path.join(storageDirectory, "requests")).filter((entry) => entry.endsWith(".json")).map((entry) => entry.replace(/\.json$/, ""));
406
444
  }
407
445
  async function deleteWalletSession(walletName) {
408
- const filePath = storagePath("wallets", `${walletName}.json`);
409
- if (!fs.existsSync(filePath)) return false;
410
- fs.unlinkSync(filePath);
411
- return true;
446
+ return deleteEncryptedStorageRecord("wallets", walletName);
412
447
  }
413
448
  async function saveWalletRequest(record) {
414
- const storageDirectory = ensureStorageDir();
415
- writeEncryptedJson(path.join(storageDirectory, "requests", `${record.requestId}.json`), record);
449
+ await saveEncryptedStorageRecord("requests", record.requestId, record);
416
450
  }
417
451
  async function loadWalletRequest(requestId) {
418
- const filePath = storagePath("requests", `${requestId}.json`);
419
- if (!fs.existsSync(filePath)) return null;
420
- return readEncryptedJson(filePath);
452
+ return loadEncryptedStorageRecord("requests", requestId);
421
453
  }
422
454
  async function deleteWalletRequest(requestId) {
423
- const filePath = storagePath("requests", `${requestId}.json`);
424
- if (!fs.existsSync(filePath)) return false;
425
- fs.unlinkSync(filePath);
426
- return true;
455
+ return deleteEncryptedStorageRecord("requests", requestId);
427
456
  }
428
457
  async function saveWorkflowCheckpoint(record) {
429
- const storageDirectory = ensureStorageDir();
430
- writeEncryptedJson(path.join(storageDirectory, "workflows", `${record.requestId}.json`), record);
458
+ await saveEncryptedStorageRecord("workflows", record.requestId, record);
431
459
  }
432
460
  async function loadWorkflowCheckpoint(requestId) {
433
- const filePath = storagePath("workflows", `${requestId}.json`);
434
- if (!fs.existsSync(filePath)) return null;
435
- return readEncryptedJson(filePath);
461
+ return loadEncryptedStorageRecord("workflows", requestId);
436
462
  }
437
463
  async function listWorkflowCheckpointIds() {
438
- const storageDirectory = ensureStorageDir();
439
- return fs.readdirSync(path.join(storageDirectory, "workflows")).filter((entry) => entry.endsWith(".json")).map((entry) => entry.replace(/\.json$/, ""));
464
+ return listEncryptedStorageRecordIds("workflows");
440
465
  }
441
466
  async function deleteWorkflowCheckpoint(requestId) {
442
- const filePath = storagePath("workflows", `${requestId}.json`);
443
- if (!fs.existsSync(filePath)) return false;
444
- fs.unlinkSync(filePath);
445
- return true;
467
+ return deleteEncryptedStorageRecord("workflows", requestId);
446
468
  }
447
469
  async function renameWalletSession(walletName, nextWalletName) {
448
470
  const storageDirectory = ensureStorageDir();
@@ -461,7 +483,7 @@ async function renameWalletSession(walletName, nextWalletName) {
461
483
  if (fs.existsSync(targetFilePath)) {
462
484
  throw new Error(`Wallet already exists: ${targetName}`);
463
485
  }
464
- const wallet = readEncryptedJson(currentFilePath);
486
+ const wallet = migrateWalletSessionRecord(readEncryptedJson(currentFilePath));
465
487
  wallet.walletName = targetName;
466
488
  writeEncryptedJson(targetFilePath, wallet);
467
489
  fs.unlinkSync(currentFilePath);
@@ -7823,7 +7845,7 @@ function appendPaymasterMode(command, paymasterMode) {
7823
7845
  function buildDefaultsRecommendedCommand() {
7824
7846
  return "zk-agent defaults";
7825
7847
  }
7826
- function buildSuiteRecommendedCommand(walletName = "main", chain = "zksync-sepolia") {
7848
+ function buildSuiteRecommendedCommand(walletName = "main", chain = "zksync-sepolia", options = {}) {
7827
7849
  const flags = [];
7828
7850
  if (walletName !== "main") {
7829
7851
  flags.push(`--wallet ${walletName}`);
@@ -7831,14 +7853,18 @@ function buildSuiteRecommendedCommand(walletName = "main", chain = "zksync-sepol
7831
7853
  if (chain !== "zksync-sepolia") {
7832
7854
  flags.push(`--chain ${chain}`);
7833
7855
  }
7856
+ if (options.includeOnboarding) {
7857
+ flags.push("--include-onboarding");
7858
+ }
7834
7859
  return flags.length > 0 ? `zk-agent suite ${flags.join(" ")}` : "zk-agent suite";
7835
7860
  }
7836
- function buildTopLevelNextRecommendedCommand(requestId, paymasterMode) {
7837
- const command = requestId ? `zk-agent next --request-id ${requestId}` : "zk-agent next";
7861
+ function buildTopLevelNextRecommendedCommand(requestId, paymasterMode, walletName = "main") {
7862
+ const command = requestId ? `zk-agent next --request-id ${requestId}` : walletName !== "main" ? `zk-agent next --wallet ${walletName}` : "zk-agent next";
7838
7863
  return appendPaymasterMode(command, paymasterMode);
7839
7864
  }
7840
- function buildWalletCreateRecommendedCommand(paymasterMode) {
7841
- return appendPaymasterMode("zk-agent wallet create --await-local", paymasterMode);
7865
+ function buildWalletCreateRecommendedCommand(paymasterMode, walletName = "main") {
7866
+ const command = walletName !== "main" ? `zk-agent wallet create --name ${walletName} --await-local` : "zk-agent wallet create --await-local";
7867
+ return appendPaymasterMode(command, paymasterMode);
7842
7868
  }
7843
7869
  function buildRelayInspectRecommendedCommand(relayUrl = "<url>") {
7844
7870
  return `zk-agent relay inspect --relay-url ${relayUrl}`;
@@ -7996,6 +8022,37 @@ function buildWorkflowPayRecommendedCommand(walletName, paymasterMode) {
7996
8022
  const command = `zk-agent workflow pay --wallet ${walletName} --to <address> --amount <amount>`;
7997
8023
  return appendPaymasterMode(command, paymasterMode);
7998
8024
  }
8025
+ function buildSendTokenRecommendedCommand(input) {
8026
+ let command = `zk-agent send-token --wallet ${input.walletName}`;
8027
+ command += ` --to ${input.to || "<address>"}`;
8028
+ command += ` --amount ${input.amount || "<amount>"}`;
8029
+ if (input.symbol) {
8030
+ command += ` --symbol ${input.symbol}`;
8031
+ }
8032
+ if (input.tokenAddress) {
8033
+ command += ` --token ${input.tokenAddress}`;
8034
+ }
8035
+ if (input.decimals !== void 0) {
8036
+ command += ` --decimals ${input.decimals}`;
8037
+ }
8038
+ return appendPaymasterMode(command, input.paymasterMode);
8039
+ }
8040
+ function buildPaymentListRecommendedCommand() {
8041
+ return "zk-agent payment list";
8042
+ }
8043
+ function buildPaymentShowRecommendedCommand(requestId) {
8044
+ return `zk-agent payment show --request-id ${requestId}`;
8045
+ }
8046
+ function buildPaymentSetStatusRecommendedCommand(requestId, status, txHash) {
8047
+ let command = `zk-agent payment set-status --request-id ${requestId} --status ${status}`;
8048
+ if (txHash) {
8049
+ command += ` --tx-hash ${txHash}`;
8050
+ }
8051
+ return command;
8052
+ }
8053
+ function buildPaymentRemoveRecommendedCommand(requestId) {
8054
+ return `zk-agent payment remove --request-id ${requestId}`;
8055
+ }
7999
8056
  function buildWorkflowFundRecommendedCommand(walletName) {
8000
8057
  return `zk-agent workflow fund --wallet ${walletName}`;
8001
8058
  }
@@ -10175,28 +10232,28 @@ function recommendedPathLines(paths) {
10175
10232
  ...paths.remoteBrowser?.length ? [["path (remote-browser)", formatRecommendedPath(paths.remoteBrowser)]] : []
10176
10233
  ];
10177
10234
  }
10178
- function buildSetupRecommendedPaths(relayUrl = "<url>", paymasterMode) {
10179
- const next = buildTopLevelNextRecommendedCommand(void 0, paymasterMode);
10235
+ function buildSetupRecommendedPaths(relayUrl = "<url>", paymasterMode, walletName = "main") {
10236
+ const next = buildTopLevelNextRecommendedCommand(void 0, paymasterMode, walletName);
10180
10237
  return {
10181
10238
  local: [
10182
10239
  "zk-agent setup",
10183
10240
  next,
10184
- buildWalletCreateRecommendedCommand(paymasterMode),
10241
+ buildWalletCreateRecommendedCommand(paymasterMode, walletName),
10185
10242
  next
10186
10243
  ],
10187
10244
  remoteBrowser: [
10188
10245
  "zk-agent setup",
10189
10246
  next,
10190
10247
  buildRelayInspectRecommendedCommand(relayUrl),
10191
- buildWalletCreateRemoteRecommendedCommand(relayUrl, paymasterMode),
10248
+ buildWalletCreateRemoteRecommendedCommand(relayUrl, paymasterMode, walletName),
10192
10249
  next
10193
10250
  ]
10194
10251
  };
10195
10252
  }
10196
10253
  function buildWalletBootstrapRecommendedPaths(relayUrl = "<url>", paymasterMode, walletName = "main") {
10197
- const next = buildTopLevelNextRecommendedCommand(void 0, paymasterMode);
10254
+ const next = buildTopLevelNextRecommendedCommand(void 0, paymasterMode, walletName);
10198
10255
  return {
10199
- local: [buildWalletCreateRecommendedCommand(paymasterMode), next],
10256
+ local: [buildWalletCreateRecommendedCommand(paymasterMode, walletName), next],
10200
10257
  remoteBrowser: [
10201
10258
  buildRelayInspectRecommendedCommand(relayUrl),
10202
10259
  buildWalletCreateRemoteRecommendedCommand(relayUrl, paymasterMode, walletName),
@@ -10205,7 +10262,7 @@ function buildWalletBootstrapRecommendedPaths(relayUrl = "<url>", paymasterMode,
10205
10262
  };
10206
10263
  }
10207
10264
  function buildWalletReapprovalRecommendedPaths(walletName, relayUrl = "<url>", paymasterMode) {
10208
- const next = buildTopLevelNextRecommendedCommand(void 0, paymasterMode);
10265
+ const next = buildTopLevelNextRecommendedCommand(void 0, paymasterMode, walletName);
10209
10266
  return {
10210
10267
  local: [buildWalletReapproveRecommendedCommand(walletName), next],
10211
10268
  remoteBrowser: [
@@ -10219,7 +10276,7 @@ function buildSignerRecoveryRecommendedPaths(walletName, paymasterMode) {
10219
10276
  return {
10220
10277
  local: [
10221
10278
  buildWalletSignerAttachRecommendedCommand(walletName),
10222
- buildTopLevelNextRecommendedCommand(void 0, paymasterMode)
10279
+ buildTopLevelNextRecommendedCommand(void 0, paymasterMode, walletName)
10223
10280
  ]
10224
10281
  };
10225
10282
  }
@@ -10698,11 +10755,139 @@ function agentProfileLines(summary) {
10698
10755
  return lines;
10699
10756
  }
10700
10757
 
10758
+ // src/lib/product-entry-summary.ts
10759
+ function buildProductEntrySummary(input) {
10760
+ const currentSurface = input.currentSurface ?? "next";
10761
+ switch (input.stage) {
10762
+ case "setup":
10763
+ return {
10764
+ view: "product-entry",
10765
+ currentSurface,
10766
+ stage: input.stage,
10767
+ category: "bootstrap",
10768
+ recommendedMode: "local-first",
10769
+ nextSurface: input.nextSurface ?? "setup",
10770
+ nextAction: input.nextAction ?? null,
10771
+ suiteAvailable: false,
10772
+ note: input.note ?? "Start with setup first. The operator path is still in first-run bootstrap."
10773
+ };
10774
+ case "wallet-bootstrap":
10775
+ return {
10776
+ view: "product-entry",
10777
+ currentSurface,
10778
+ stage: input.stage,
10779
+ category: "bootstrap",
10780
+ recommendedMode: "local-first",
10781
+ nextSurface: input.nextSurface ?? "wallet",
10782
+ nextAction: input.nextAction ?? null,
10783
+ suiteAvailable: false,
10784
+ note: input.note ?? "Local defaults exist, but wallet bootstrap is still the current product question."
10785
+ };
10786
+ case "wallet-recovery":
10787
+ return {
10788
+ view: "product-entry",
10789
+ currentSurface,
10790
+ stage: input.stage,
10791
+ category: "recover",
10792
+ recommendedMode: "local-first",
10793
+ nextSurface: input.nextSurface ?? "wallet",
10794
+ nextAction: input.nextAction ?? null,
10795
+ suiteAvailable: false,
10796
+ note: input.note ?? "Stay on wallet recovery until approval or local signer readiness stops being the blocker."
10797
+ };
10798
+ case "wallet-ready":
10799
+ return {
10800
+ view: "product-entry",
10801
+ currentSurface,
10802
+ stage: input.stage,
10803
+ category: "operate",
10804
+ recommendedMode: "local-first",
10805
+ nextSurface: input.nextSurface ?? (currentSurface === "doctor" ? "next" : "workflow"),
10806
+ nextAction: input.nextAction ?? null,
10807
+ suiteAvailable: input.suiteAvailable === true,
10808
+ note: input.note ?? (currentSurface === "doctor" ? "Local readiness is clear. Return to zk-agent next when you want the live operator path instead of a local-only diagnosis." : "The default product action is now the flagship workflow path. Switch to suite when the question becomes broader than one flagship pay step.")
10809
+ };
10810
+ case "workflow":
10811
+ return {
10812
+ view: "product-entry",
10813
+ currentSurface,
10814
+ stage: input.stage,
10815
+ category: "workflow",
10816
+ recommendedMode: "workflow-followup",
10817
+ nextSurface: input.nextSurface ?? "workflow",
10818
+ nextAction: input.nextAction ?? null,
10819
+ suiteAvailable: input.suiteAvailable === true,
10820
+ note: input.note ?? "A stored workflow checkpoint is now the active product context. Stay on workflow follow-up until the question is no longer workflow-specific."
10821
+ };
10822
+ default: {
10823
+ const exhaustive = input.stage;
10824
+ throw new Error(`Unsupported product entry stage: ${String(exhaustive)}`);
10825
+ }
10826
+ }
10827
+ }
10828
+ function productEntrySummaryLines(summary) {
10829
+ return [
10830
+ ["entry view", summary.view],
10831
+ ["entry category", summary.category],
10832
+ ["recommended mode", summary.recommendedMode],
10833
+ ["next surface", summary.nextSurface],
10834
+ ["suite available", summary.suiteAvailable ? "yes" : "no"],
10835
+ ["entry note", summary.note]
10836
+ ];
10837
+ }
10838
+
10701
10839
  // src/lib/suite-handoff.ts
10840
+ function buildSuiteHandoffJourney(journeyId, walletName) {
10841
+ switch (journeyId) {
10842
+ case "send-value-now":
10843
+ return {
10844
+ id: journeyId,
10845
+ title: "Send Value Now",
10846
+ command: buildWorkflowPayRecommendedCommand(walletName)
10847
+ };
10848
+ case "inspect-before-acting":
10849
+ return {
10850
+ id: journeyId,
10851
+ title: "Inspect Before Acting",
10852
+ command: buildAssetsRecommendedCommand(walletName)
10853
+ };
10854
+ case "unstick-a-write":
10855
+ return {
10856
+ id: journeyId,
10857
+ title: "Unstick a Write",
10858
+ command: buildWorkflowPayRecommendedCommand(walletName, "approval-based")
10859
+ };
10860
+ case "recover-remote-approval":
10861
+ return {
10862
+ id: journeyId,
10863
+ title: "Recover Remote Approval",
10864
+ command: buildRelayInspectRecommendedCommand("<url>")
10865
+ };
10866
+ case null:
10867
+ case void 0:
10868
+ return null;
10869
+ default: {
10870
+ const exhaustive = journeyId;
10871
+ throw new Error(`Unsupported suite handoff journey: ${String(exhaustive)}`);
10872
+ }
10873
+ }
10874
+ }
10702
10875
  function buildSuiteHandoffSummary(input) {
10876
+ const walletName = input.walletName?.trim() || "main";
10703
10877
  const command = buildSuiteRecommendedCommand(input.walletName, input.chain);
10704
- const useWhen = "Use suite once wallet approval and local signer readiness are no longer the blocker and you want one packaged surface for flagship pay plus the current post-flagship discovery, paymaster, and funding slices.";
10878
+ const recommendedJourney = input.recommendedNow === true ? buildSuiteHandoffJourney(input.recommendedJourneyId ?? null, walletName) : null;
10879
+ const useWhen = "Use suite once wallet approval and local signer readiness are no longer the blocker and you want one packaged surface for flagship pay plus the current post-flagship discovery, paymaster, funding, and hosted recovery slices.";
10705
10880
  switch (input.currentSurface) {
10881
+ case "doctor":
10882
+ return {
10883
+ currentSurface: input.currentSurface,
10884
+ recommendedNow: input.recommendedNow,
10885
+ command,
10886
+ useWhen,
10887
+ stayOnCurrentSurfaceWhen: "Stay on doctor when local config, approval metadata, or local signer state is still unclear and you need a local-only diagnosis before choosing the live path.",
10888
+ note: input.recommendedNow ? "Local readiness is clear. Return to zk-agent next for the shortest live path, or start with the suggested suite journey when the operator question is broader than one immediate flagship workflow step." : "Suite is not the current recommendation because doctor is still diagnosing a local setup or wallet-readiness blocker.",
10889
+ recommendedJourney
10890
+ };
10706
10891
  case "next":
10707
10892
  return {
10708
10893
  currentSurface: input.currentSurface,
@@ -10710,7 +10895,8 @@ function buildSuiteHandoffSummary(input) {
10710
10895
  command,
10711
10896
  useWhen,
10712
10897
  stayOnCurrentSurfaceWhen: "Stay on next when you still need the CLI to choose across setup, wallet readiness, and the shortest flagship workflow entry.",
10713
- note: input.recommendedNow ? "Wallet readiness is no longer the blocker. The default shortest action can still be workflow pay, while suite is the broader packaged follow-up surface." : "Suite is not the current recommendation because next is still steering setup or wallet remediation."
10898
+ note: input.recommendedNow ? "Wallet readiness is no longer the blocker. The default shortest action can still be workflow pay, while suite is the broader packaged follow-up surface. Start with the suggested suite journey when the question is broader than one immediate workflow pay step." : "Suite is not the current recommendation because next is still steering setup or wallet remediation.",
10899
+ recommendedJourney
10714
10900
  };
10715
10901
  case "wallet":
10716
10902
  return {
@@ -10719,7 +10905,8 @@ function buildSuiteHandoffSummary(input) {
10719
10905
  command,
10720
10906
  useWhen,
10721
10907
  stayOnCurrentSurfaceWhen: "Stay on wallet status or wallet next when approval, signer attach, deployment sync, or wallet-specific remediation is still the blocker.",
10722
- note: input.recommendedNow ? "Wallet readiness is no longer the blocker, so suite is available as the broader packaged surface." : "Suite is not the current recommendation because wallet-specific remediation is still the blocker."
10908
+ note: input.recommendedNow ? "Wallet readiness is no longer the blocker, so suite is available as the broader packaged surface. Start with the suggested suite journey when the operator question is broader than one wallet-status remediation step." : "Suite is not the current recommendation because wallet-specific remediation is still the blocker.",
10909
+ recommendedJourney
10723
10910
  };
10724
10911
  case "workflow":
10725
10912
  return {
@@ -10728,7 +10915,8 @@ function buildSuiteHandoffSummary(input) {
10728
10915
  command,
10729
10916
  useWhen,
10730
10917
  stayOnCurrentSurfaceWhen: "Stay on workflow when you already have an explicit workflow question, checkpoint, or execution state to inspect, continue, or resume.",
10731
- note: "This workflow surface stays authoritative for the current workflow. Switch to suite only after the question is no longer workflow-specific."
10918
+ note: "This workflow surface stays authoritative for the current workflow. Switch to suite only after the question is no longer workflow-specific.",
10919
+ recommendedJourney
10732
10920
  };
10733
10921
  default: {
10734
10922
  const exhaustive = input.currentSurface;
@@ -10741,6 +10929,13 @@ function suiteHandoffLines(summary) {
10741
10929
  ["suite", summary.command],
10742
10930
  ["suite ready", summary.recommendedNow ? "yes" : "no"],
10743
10931
  ["suite when", summary.useWhen],
10932
+ ...summary.recommendedJourney ? [
10933
+ [
10934
+ "suite journey",
10935
+ `${summary.recommendedJourney.id} (${summary.recommendedJourney.title})`
10936
+ ],
10937
+ ["suite journey start", summary.recommendedJourney.command]
10938
+ ] : [],
10744
10939
  [`stay on ${summary.currentSurface} when`, summary.stayOnCurrentSurfaceWhen],
10745
10940
  ["suite note", summary.note]
10746
10941
  ];
@@ -10866,8 +11061,8 @@ function resolveNextCommandDeps(deps) {
10866
11061
  function buildSetupCommand() {
10867
11062
  return "zk-agent setup";
10868
11063
  }
10869
- function buildTopLevelNextRecommendedCommand2(requestId) {
10870
- return requestId ? `zk-agent next --request-id ${requestId}` : "zk-agent next";
11064
+ function buildTopLevelNextRecommendedCommand2(requestId, walletName = "main") {
11065
+ return requestId ? `zk-agent next --request-id ${requestId}` : walletName !== "main" ? `zk-agent next --wallet ${walletName}` : "zk-agent next";
10871
11066
  }
10872
11067
  function buildTopLevelWorkflowSummary(result, nextCommand) {
10873
11068
  return {
@@ -10888,10 +11083,11 @@ function appendPaymasterMode2(command, paymasterMode) {
10888
11083
  if (!paymasterMode) return command;
10889
11084
  return `${command} --paymaster-mode ${paymasterMode}`;
10890
11085
  }
10891
- function topLevelNextLines(scope, lines, onboardingSummary) {
11086
+ function topLevelNextLines(scope, lines, onboardingSummary, productEntrySummary) {
10892
11087
  return [
10893
11088
  ["scope", scope],
10894
11089
  ...onboardingSummary ? onboardingSummaryLines(onboardingSummary) : [],
11090
+ ...productEntrySummary ? productEntrySummaryLines(productEntrySummary) : [],
10895
11091
  ...lines
10896
11092
  ];
10897
11093
  }
@@ -10901,6 +11097,13 @@ function buildNextHelpText() {
10901
11097
  "Use `next` as the product entrypoint:",
10902
11098
  " Stay on `next` until it points you at a wallet-specific or workflow-specific blocker.",
10903
11099
  "",
11100
+ " What `next` answers right now:",
11101
+ " bootstrap: config or wallet bootstrap is still the current blocker",
11102
+ " recover: wallet approval or local signer readiness still needs repair",
11103
+ " operate: wallet readiness is clear, so the flagship workflow path is next",
11104
+ " workflow: a stored checkpoint is already the active question",
11105
+ " suite: switch only when the question becomes broader than one immediate next step",
11106
+ "",
10904
11107
  " Fresh local-first routing:",
10905
11108
  " zk-agent setup",
10906
11109
  " zk-agent next",
@@ -10999,6 +11202,11 @@ function createNextCommand(deps) {
10999
11202
  walletName: wallet2.walletName,
11000
11203
  walletExists: true
11001
11204
  });
11205
+ const productEntrySummary2 = buildProductEntrySummary({
11206
+ stage: "workflow",
11207
+ nextAction: nextCommand2,
11208
+ suiteAvailable: false
11209
+ });
11002
11210
  printResult(
11003
11211
  topLevelNextLines("workflow", [
11004
11212
  ["workflow request", requestId],
@@ -11017,7 +11225,7 @@ function createNextCommand(deps) {
11017
11225
  ["funding txHash", result.fundingProgress.txHash],
11018
11226
  ["funding status", result.fundingProgress.status]
11019
11227
  ] : []
11020
- ]),
11228
+ ], void 0, productEntrySummary2),
11021
11229
  {
11022
11230
  ok: true,
11023
11231
  scope: "workflow",
@@ -11025,6 +11233,7 @@ function createNextCommand(deps) {
11025
11233
  workflowRequestId: requestId,
11026
11234
  walletName: wallet2.walletName,
11027
11235
  nextCommand: nextCommand2,
11236
+ productEntrySummary: productEntrySummary2,
11028
11237
  agentProfile: workflowAgentProfile,
11029
11238
  agentFollowup: agentFollowup2,
11030
11239
  summary: buildTopLevelWorkflowSummary(result, nextCommand2),
@@ -11041,10 +11250,10 @@ function createNextCommand(deps) {
11041
11250
  if (!config) {
11042
11251
  const recommendedCommands2 = {
11043
11252
  setup: buildSetupCommand(),
11044
- afterSetup: buildTopLevelNextRecommendedCommand2(),
11253
+ afterSetup: buildTopLevelNextRecommendedCommand2(void 0, walletName),
11045
11254
  inspectDefaults: buildDefaultsRecommendedCommand()
11046
11255
  };
11047
- const recommendedPaths2 = buildSetupRecommendedPaths("<url>", paymasterMode);
11256
+ const recommendedPaths2 = buildSetupRecommendedPaths("<url>", paymasterMode, walletName);
11048
11257
  const onboardingSummary2 = buildOnboardingSummary({
11049
11258
  stage: "setup",
11050
11259
  localOnly: true,
@@ -11056,6 +11265,10 @@ function createNextCommand(deps) {
11056
11265
  "This scope is local-only and does not require live RPC reads."
11057
11266
  ]
11058
11267
  });
11268
+ const productEntrySummary2 = buildProductEntrySummary({
11269
+ stage: "setup",
11270
+ nextAction: recommendedCommands2.setup
11271
+ });
11059
11272
  printResult(
11060
11273
  topLevelNextLines("setup", [
11061
11274
  ["status", "No local config found"],
@@ -11065,12 +11278,13 @@ function createNextCommand(deps) {
11065
11278
  ["next", recommendedCommands2.setup],
11066
11279
  ["after setup", recommendedCommands2.afterSetup],
11067
11280
  ["inspect defaults", recommendedCommands2.inspectDefaults]
11068
- ], onboardingSummary2),
11281
+ ], onboardingSummary2, productEntrySummary2),
11069
11282
  {
11070
11283
  ok: true,
11071
11284
  scope: "setup",
11072
11285
  status: "action-required",
11073
11286
  nextCommand: recommendedCommands2.setup,
11287
+ productEntrySummary: productEntrySummary2,
11074
11288
  onboardingSummary: onboardingSummary2,
11075
11289
  recommendedPaths: recommendedPaths2,
11076
11290
  agentProfile,
@@ -11084,15 +11298,19 @@ function createNextCommand(deps) {
11084
11298
  if (!wallet) {
11085
11299
  const recommendedCommands2 = {
11086
11300
  createWallet: appendPaymasterMode2(
11087
- buildWalletCreateRecommendedCommand(),
11301
+ buildWalletCreateRecommendedCommand(void 0, walletName),
11088
11302
  paymasterMode
11089
11303
  ),
11090
11304
  relayInspect: buildRelayInspectRecommendedCommand(),
11091
11305
  createWalletRemote: buildWalletCreateRemoteRecommendedCommand(
11092
11306
  "<url>",
11307
+ paymasterMode,
11308
+ walletName
11309
+ ),
11310
+ afterApproval: appendPaymasterMode2(
11311
+ buildTopLevelNextRecommendedCommand2(void 0, walletName),
11093
11312
  paymasterMode
11094
11313
  ),
11095
- afterApproval: appendPaymasterMode2(buildTopLevelNextRecommendedCommand2(), paymasterMode),
11096
11314
  inspectDefaults: buildDefaultsRecommendedCommand()
11097
11315
  };
11098
11316
  const recommendedPaths2 = buildWalletBootstrapRecommendedPaths(
@@ -11113,6 +11331,10 @@ function createNextCommand(deps) {
11113
11331
  "Use the remote approval fallback only when the browser is not colocated with this terminal."
11114
11332
  ]
11115
11333
  });
11334
+ const productEntrySummary2 = buildProductEntrySummary({
11335
+ stage: "wallet-bootstrap",
11336
+ nextAction: recommendedCommands2.createWallet
11337
+ });
11116
11338
  printResult(
11117
11339
  topLevelNextLines("wallet-bootstrap", [
11118
11340
  ["status", `Wallet not found: ${walletName}`],
@@ -11126,13 +11348,14 @@ function createNextCommand(deps) {
11126
11348
  ["remote fallback", recommendedCommands2.createWalletRemote],
11127
11349
  ["after approval", recommendedCommands2.afterApproval],
11128
11350
  ["inspect defaults", recommendedCommands2.inspectDefaults]
11129
- ], onboardingSummary2),
11351
+ ], onboardingSummary2, productEntrySummary2),
11130
11352
  {
11131
11353
  ok: true,
11132
11354
  scope: "wallet-bootstrap",
11133
11355
  walletName,
11134
11356
  config,
11135
11357
  nextCommand: recommendedCommands2.createWallet,
11358
+ productEntrySummary: productEntrySummary2,
11136
11359
  onboardingSummary: onboardingSummary2,
11137
11360
  recommendedPaths: recommendedPaths2,
11138
11361
  agentProfile,
@@ -11216,11 +11439,14 @@ function createNextCommand(deps) {
11216
11439
  reapprove: buildWalletReapproveRecommendedCommand(wallet.walletName),
11217
11440
  relayInspect: buildRelayInspectRecommendedCommand(),
11218
11441
  reapproveRemote: buildWalletReapproveRemoteRecommendedCommand(wallet.walletName),
11219
- afterRecovery: appendPaymasterMode2(buildTopLevelNextRecommendedCommand2(), paymasterMode)
11442
+ afterRecovery: appendPaymasterMode2(
11443
+ buildTopLevelNextRecommendedCommand2(void 0, wallet.walletName),
11444
+ paymasterMode
11445
+ )
11220
11446
  } : !inspection.localExecutionKeyStored ? {
11221
11447
  attachSigner: buildWalletSignerAttachRecommendedCommand(wallet.walletName),
11222
11448
  afterRecovery: appendPaymasterMode2(
11223
- buildTopLevelNextRecommendedCommand2(),
11449
+ buildTopLevelNextRecommendedCommand2(void 0, wallet.walletName),
11224
11450
  paymasterMode
11225
11451
  )
11226
11452
  } : {};
@@ -11242,7 +11468,13 @@ function createNextCommand(deps) {
11242
11468
  currentSurface: "next",
11243
11469
  recommendedNow: summary.status === "ready",
11244
11470
  walletName: wallet.walletName,
11245
- chain: wallet.chain
11471
+ chain: wallet.chain,
11472
+ recommendedJourneyId: summary.status === "ready" ? "send-value-now" : null
11473
+ });
11474
+ const productEntrySummary = buildProductEntrySummary({
11475
+ stage: onboardingSummary.stage,
11476
+ nextAction: nextCommand,
11477
+ suiteAvailable: summary.status === "ready"
11246
11478
  });
11247
11479
  printResult(
11248
11480
  topLevelNextLines("wallet", [
@@ -11263,11 +11495,12 @@ function createNextCommand(deps) {
11263
11495
  ...mergedRecommendedCommands.inspectPaymasterToken ? [["inspect paymaster token", mergedRecommendedCommands.inspectPaymasterToken]] : [],
11264
11496
  ["inspect token", mergedRecommendedCommands.inspectToken],
11265
11497
  ["inspect defaults", mergedRecommendedCommands.inspectDefaults]
11266
- ], onboardingSummary),
11498
+ ], onboardingSummary, productEntrySummary),
11267
11499
  {
11268
11500
  ok: true,
11269
11501
  scope: "wallet",
11270
11502
  walletName: wallet.walletName,
11503
+ productEntrySummary,
11271
11504
  onboardingSummary,
11272
11505
  recommendedPaths,
11273
11506
  agentProfile,
@@ -11299,10 +11532,18 @@ function buildDoctorHelpText() {
11299
11532
  " zk-agent doctor --wallet main",
11300
11533
  " zk-agent doctor --wallet main --relay-url https://relay.example.com",
11301
11534
  "",
11535
+ " What `doctor` answers right now:",
11536
+ " bootstrap: local config or wallet bootstrap is still missing",
11537
+ " recover: local approval or signer state still needs repair",
11538
+ " operate: local readiness is clear, so return to `zk-agent next` for the live path",
11539
+ " suite: once readiness is clear, the broader packaged post-flagship surface is available too",
11540
+ "",
11302
11541
  "Default behavior:",
11303
11542
  " Inspects saved config, local wallet approval metadata, local signer state,",
11304
11543
  " and the shortest next command without requiring live RPC reads.",
11305
11544
  " Run this before guessing whether the blocker is setup, wallet approval, or local signer state.",
11545
+ " When doctor shows local readiness is clear and the question is broader than one next step:",
11546
+ " zk-agent suite",
11306
11547
  "",
11307
11548
  "Remote-browser variant:",
11308
11549
  " Pass --relay-url when you want the remote approval fallback commands",
@@ -11328,25 +11569,25 @@ function summarizeLocalWalletState(wallet) {
11328
11569
  signerSource: wallet.localExecutionAuthority?.source || (wallet.sessionPayload?.sessionPrivateKey ? "legacy-session-payload" : null)
11329
11570
  };
11330
11571
  }
11331
- function buildSetupRecommendedCommands() {
11572
+ function buildSetupRecommendedCommands(walletName) {
11332
11573
  return {
11333
11574
  setup: "zk-agent setup",
11334
- next: buildTopLevelNextRecommendedCommand(),
11575
+ next: buildTopLevelNextRecommendedCommand(void 0, void 0, walletName),
11335
11576
  inspectDefaults: buildDefaultsRecommendedCommand()
11336
11577
  };
11337
11578
  }
11338
11579
  function buildWalletBootstrapRecommendedCommands(walletName, relayUrl) {
11339
11580
  return {
11340
- next: buildTopLevelNextRecommendedCommand(),
11581
+ next: buildTopLevelNextRecommendedCommand(void 0, void 0, walletName),
11341
11582
  inspectDefaults: buildDefaultsRecommendedCommand(),
11342
- createWallet: buildWalletCreateRecommendedCommand(),
11583
+ createWallet: buildWalletCreateRecommendedCommand(void 0, walletName),
11343
11584
  relayInspect: buildRelayInspectRecommendedCommand(relayUrl),
11344
11585
  createWalletRemote: buildWalletCreateRemoteRecommendedCommand(relayUrl, void 0, walletName)
11345
11586
  };
11346
11587
  }
11347
11588
  function buildWalletRecoveryRecommendedCommands(wallet, relayUrl) {
11348
11589
  const shared = {
11349
- next: buildTopLevelNextRecommendedCommand(),
11590
+ next: buildTopLevelNextRecommendedCommand(void 0, void 0, wallet.walletName),
11350
11591
  walletStatus: buildWalletStatusRecommendedCommand(wallet.walletName),
11351
11592
  walletNext: buildWalletNextRecommendedCommand(wallet.walletName),
11352
11593
  signerShow: buildWalletSignerShowRecommendedCommand(wallet.walletName),
@@ -11367,7 +11608,8 @@ function buildWalletRecoveryRecommendedCommands(wallet, relayUrl) {
11367
11608
  }
11368
11609
  function buildWalletReadyRecommendedCommands(wallet) {
11369
11610
  return {
11370
- next: buildTopLevelNextRecommendedCommand(),
11611
+ next: buildTopLevelNextRecommendedCommand(void 0, void 0, wallet.walletName),
11612
+ suite: buildSuiteRecommendedCommand(wallet.walletName, wallet.chain),
11371
11613
  walletStatus: buildWalletStatusRecommendedCommand(wallet.walletName),
11372
11614
  walletNext: buildWalletNextRecommendedCommand(wallet.walletName),
11373
11615
  workflowPay: buildWorkflowPayRecommendedCommand(wallet.walletName),
@@ -11376,7 +11618,7 @@ function buildWalletReadyRecommendedCommands(wallet) {
11376
11618
  }
11377
11619
  function buildDoctorResult(options) {
11378
11620
  if (!options.config) {
11379
- const recommendedCommands2 = buildSetupRecommendedCommands();
11621
+ const recommendedCommands2 = buildSetupRecommendedCommands(options.walletName);
11380
11622
  const onboardingSummary2 = buildOnboardingSummary({
11381
11623
  stage: "setup",
11382
11624
  localOnly: true,
@@ -11391,10 +11633,16 @@ function buildDoctorResult(options) {
11391
11633
  "Doctor is local-only by default and does not require live RPC reads."
11392
11634
  ]
11393
11635
  });
11636
+ const productEntrySummary2 = buildProductEntrySummary({
11637
+ currentSurface: "doctor",
11638
+ stage: "setup",
11639
+ nextAction: recommendedCommands2.setup
11640
+ });
11394
11641
  return {
11395
11642
  scope: "setup",
11396
11643
  nextAction: recommendedCommands2.setup,
11397
- recommendedPaths: buildSetupRecommendedPaths(options.relayUrl),
11644
+ recommendedPaths: buildSetupRecommendedPaths(options.relayUrl, void 0, options.walletName),
11645
+ productEntrySummary: productEntrySummary2,
11398
11646
  onboardingSummary: onboardingSummary2,
11399
11647
  summary: {
11400
11648
  stage: "setup",
@@ -11432,10 +11680,16 @@ function buildDoctorResult(options) {
11432
11680
  "Use the remote relay path only when the browser is not colocated with this terminal."
11433
11681
  ]
11434
11682
  });
11683
+ const productEntrySummary2 = buildProductEntrySummary({
11684
+ currentSurface: "doctor",
11685
+ stage: "wallet-bootstrap",
11686
+ nextAction: recommendedCommands2.createWallet
11687
+ });
11435
11688
  return {
11436
11689
  scope: "wallet-bootstrap",
11437
11690
  nextAction: recommendedCommands2.createWallet,
11438
11691
  recommendedPaths: buildWalletBootstrapRecommendedPaths(options.relayUrl, void 0, options.walletName),
11692
+ productEntrySummary: productEntrySummary2,
11439
11693
  onboardingSummary: onboardingSummary2,
11440
11694
  summary: {
11441
11695
  stage: "wallet-bootstrap",
@@ -11475,6 +11729,11 @@ function buildDoctorResult(options) {
11475
11729
  "Use the remote reapproval path only when the browser cannot return directly to this terminal."
11476
11730
  ]
11477
11731
  });
11732
+ const productEntrySummary2 = buildProductEntrySummary({
11733
+ currentSurface: "doctor",
11734
+ stage: "wallet-recovery",
11735
+ nextAction: recommendedCommands2.reapprove
11736
+ });
11478
11737
  return {
11479
11738
  scope: "wallet-recovery",
11480
11739
  nextAction: recommendedCommands2.reapprove,
@@ -11482,6 +11741,7 @@ function buildDoctorResult(options) {
11482
11741
  options.wallet.walletName,
11483
11742
  options.relayUrl
11484
11743
  ),
11744
+ productEntrySummary: productEntrySummary2,
11485
11745
  onboardingSummary: onboardingSummary2,
11486
11746
  summary: {
11487
11747
  stage: "wallet-recovery",
@@ -11522,10 +11782,16 @@ function buildDoctorResult(options) {
11522
11782
  "Doctor is local-only: it confirms stored signer state, not live chain deployment or gas balance."
11523
11783
  ]
11524
11784
  });
11785
+ const productEntrySummary2 = buildProductEntrySummary({
11786
+ currentSurface: "doctor",
11787
+ stage: "wallet-recovery",
11788
+ nextAction: attachSigner
11789
+ });
11525
11790
  return {
11526
11791
  scope: "wallet-recovery",
11527
11792
  nextAction: attachSigner,
11528
11793
  recommendedPaths: buildSignerRecoveryRecommendedPaths(options.wallet.walletName),
11794
+ productEntrySummary: productEntrySummary2,
11529
11795
  onboardingSummary: onboardingSummary2,
11530
11796
  summary: {
11531
11797
  stage: "wallet-recovery",
@@ -11561,13 +11827,29 @@ function buildDoctorResult(options) {
11561
11827
  "Run zk-agent next for the current shortest live path; doctor does not confirm RPC reachability, deployment state, or funding."
11562
11828
  ]
11563
11829
  });
11830
+ const productEntrySummary = buildProductEntrySummary({
11831
+ currentSurface: "doctor",
11832
+ stage: "wallet-ready",
11833
+ nextAction: recommendedCommands.next,
11834
+ suiteAvailable: true,
11835
+ nextSurface: "next"
11836
+ });
11837
+ const suiteHandoffSummary = buildSuiteHandoffSummary({
11838
+ currentSurface: "doctor",
11839
+ recommendedNow: true,
11840
+ walletName: options.wallet.walletName,
11841
+ chain: options.wallet.chain,
11842
+ recommendedJourneyId: "send-value-now"
11843
+ });
11564
11844
  return {
11565
11845
  scope: "wallet-ready",
11566
11846
  nextAction: recommendedCommands.next,
11567
11847
  recommendedPaths: {
11568
11848
  local: [recommendedCommands.next]
11569
11849
  },
11850
+ productEntrySummary,
11570
11851
  onboardingSummary,
11852
+ suiteHandoffSummary,
11571
11853
  summary: {
11572
11854
  stage: "wallet-ready",
11573
11855
  configExists: true,
@@ -11589,6 +11871,7 @@ function buildDoctorLines(input) {
11589
11871
  const lines = [
11590
11872
  ["scope", input.scope],
11591
11873
  ...onboardingSummaryLines(input.onboardingSummary),
11874
+ ...productEntrySummaryLines(input.productEntrySummary),
11592
11875
  ["config", input.config ? "present" : "missing"]
11593
11876
  ];
11594
11877
  if (input.config) {
@@ -11625,6 +11908,9 @@ function buildDoctorLines(input) {
11625
11908
  }
11626
11909
  lines.push(["next", input.nextAction]);
11627
11910
  lines.push(...recommendedPathLines(input.recommendedPaths));
11911
+ if (input.suiteHandoffSummary) {
11912
+ lines.push(...suiteHandoffLines(input.suiteHandoffSummary));
11913
+ }
11628
11914
  if (input.recommendedCommands.createWallet) {
11629
11915
  lines.push(["create wallet (local)", input.recommendedCommands.createWallet]);
11630
11916
  }
@@ -11637,6 +11923,9 @@ function buildDoctorLines(input) {
11637
11923
  if (input.recommendedCommands.workflowPay) {
11638
11924
  lines.push(["workflow pay", input.recommendedCommands.workflowPay]);
11639
11925
  }
11926
+ if (input.recommendedCommands.suite) {
11927
+ lines.push(["suite command", input.recommendedCommands.suite]);
11928
+ }
11640
11929
  if (input.recommendedCommands.relayInspect) {
11641
11930
  lines.push(["relay inspect", input.recommendedCommands.relayInspect]);
11642
11931
  }
@@ -11679,7 +11968,9 @@ function createDoctorCommand() {
11679
11968
  config,
11680
11969
  wallet,
11681
11970
  onboardingSummary: result.onboardingSummary,
11971
+ productEntrySummary: result.productEntrySummary,
11682
11972
  summary: result.summary,
11973
+ suiteHandoffSummary: "suiteHandoffSummary" in result ? result.suiteHandoffSummary : void 0,
11683
11974
  recommendedPaths: result.recommendedPaths,
11684
11975
  recommendedCommands: result.recommendedCommands,
11685
11976
  nextAction: result.nextAction
@@ -11700,8 +11991,10 @@ function createDoctorCommand() {
11700
11991
  exists: false
11701
11992
  },
11702
11993
  wallet,
11994
+ productEntrySummary: result.productEntrySummary,
11703
11995
  onboardingSummary: result.onboardingSummary,
11704
11996
  summary: result.summary,
11997
+ ..."suiteHandoffSummary" in result ? { suiteHandoffSummary: result.suiteHandoffSummary } : {},
11705
11998
  agentProfile,
11706
11999
  agentFollowup,
11707
12000
  nextAction: result.nextAction,
@@ -11805,7 +12098,11 @@ function createAgentCommand() {
11805
12098
  "after",
11806
12099
  [
11807
12100
  "",
11808
- " Agent identity path:",
12101
+ " Agent profile surface:",
12102
+ " Use this layer only when you want explicit local operator identity metadata on top of the wallet path.",
12103
+ " Wallet approval and workflow execution still work without a saved local agent profile.",
12104
+ "",
12105
+ " Basic local identity path:",
11809
12106
  " zk-agent agent status",
11810
12107
  ' zk-agent agent set --name "SED Operator" --wallet main',
11811
12108
  " zk-agent agent show",
@@ -11814,12 +12111,9 @@ function createAgentCommand() {
11814
12111
  " zk-agent agent export",
11815
12112
  " zk-agent agent import --payload @agent-profile.json --overwrite",
11816
12113
  "",
11817
- " Remove the saved local profile:",
12114
+ " Clear the saved local profile:",
11818
12115
  " zk-agent agent clear",
11819
12116
  "",
11820
- " This profile is optional. Wallet approval and workflow execution still work",
11821
- " without a saved local agent profile.",
11822
- "",
11823
12117
  "Examples:",
11824
12118
  " zk-agent agent status",
11825
12119
  ' zk-agent agent set --name "SED Operator" --wallet main',
@@ -12597,8 +12891,615 @@ function createDefaultsCommand() {
12597
12891
  });
12598
12892
  }
12599
12893
 
12600
- // src/commands/resolve-token.ts
12894
+ // src/commands/payment.ts
12895
+ import { randomBytes as randomBytes5 } from "node:crypto";
12601
12896
  import { Command as Command7 } from "commander";
12897
+
12898
+ // ../agent-pay/src/execution-plan.ts
12899
+ function buildPaymentExecutionPlan(record) {
12900
+ return {
12901
+ action: record.asset.kind === "native" ? "native-transfer" : "erc20-transfer",
12902
+ surface: record.executionPreference.surface,
12903
+ walletId: record.walletId,
12904
+ walletName: record.walletName,
12905
+ chain: record.chain,
12906
+ chainId: record.chainId,
12907
+ paymasterMode: record.executionPreference.paymasterMode,
12908
+ payeeAddress: record.payee.address,
12909
+ asset: record.asset
12910
+ };
12911
+ }
12912
+
12913
+ // ../agent-pay/src/payment-request.ts
12914
+ import { randomBytes as randomBytes4 } from "node:crypto";
12915
+ var PAYMENT_REQUEST_STATUS_TRANSITIONS = {
12916
+ draft: ["draft", "ready", "cancelled"],
12917
+ ready: ["draft", "ready", "paid", "cancelled"],
12918
+ paid: ["paid"],
12919
+ cancelled: ["cancelled"]
12920
+ };
12921
+ function nowIso2() {
12922
+ return (/* @__PURE__ */ new Date()).toISOString();
12923
+ }
12924
+ function createPaymentHistoryEventId() {
12925
+ return `payevt-${randomBytes4(4).toString("hex")}`;
12926
+ }
12927
+ function normalizeOptionalString4(value) {
12928
+ const trimmed = value?.trim();
12929
+ return trimmed ? trimmed : void 0;
12930
+ }
12931
+ function normalizeMetadata2(metadata) {
12932
+ if (!metadata) return {};
12933
+ const normalized = {};
12934
+ for (const [key, value] of Object.entries(metadata)) {
12935
+ const normalizedKey = key.trim();
12936
+ const normalizedValue = value.trim();
12937
+ if (!normalizedKey || !normalizedValue) continue;
12938
+ normalized[normalizedKey] = normalizedValue;
12939
+ }
12940
+ return normalized;
12941
+ }
12942
+ function normalizePaymentAsset(asset) {
12943
+ const amount = asset.amount.trim();
12944
+ if (!amount) {
12945
+ throw new AgentError("PAYMENT_AMOUNT_REQUIRED", "Payment amount is required.");
12946
+ }
12947
+ if (asset.kind === "native") {
12948
+ return {
12949
+ kind: "native",
12950
+ amount,
12951
+ symbol: normalizeOptionalString4(asset.symbol)
12952
+ };
12953
+ }
12954
+ const tokenAddress = asset.tokenAddress?.trim();
12955
+ if (!tokenAddress) {
12956
+ throw new AgentError(
12957
+ "PAYMENT_TOKEN_REQUIRED",
12958
+ "ERC-20 payment requests require a token address."
12959
+ );
12960
+ }
12961
+ if (!Number.isInteger(asset.decimals) || Number(asset.decimals) < 0) {
12962
+ throw new AgentError(
12963
+ "PAYMENT_TOKEN_DECIMALS_REQUIRED",
12964
+ "ERC-20 payment requests require non-negative token decimals."
12965
+ );
12966
+ }
12967
+ return {
12968
+ kind: "erc20",
12969
+ amount,
12970
+ tokenAddress,
12971
+ decimals: Number(asset.decimals),
12972
+ symbol: normalizeOptionalString4(asset.symbol)
12973
+ };
12974
+ }
12975
+ function inferExecutionSurface(asset) {
12976
+ return asset.kind === "native" ? "workflow-pay" : "send-token";
12977
+ }
12978
+ function createPaymentHistoryEvent(input) {
12979
+ return {
12980
+ eventId: createPaymentHistoryEventId(),
12981
+ type: input.type,
12982
+ at: input.at,
12983
+ status: input.status,
12984
+ previousStatus: input.previousStatus,
12985
+ txHash: normalizeOptionalString4(input.txHash),
12986
+ note: normalizeOptionalString4(input.note)
12987
+ };
12988
+ }
12989
+ function buildLegacyPaymentHistory(record) {
12990
+ return [
12991
+ {
12992
+ eventId: `payevt-${record.requestId}-legacy-created`,
12993
+ type: "created",
12994
+ at: record.createdAt,
12995
+ status: record.settlement.status,
12996
+ txHash: record.settlement.txHash,
12997
+ note: record.settlement.note
12998
+ }
12999
+ ];
13000
+ }
13001
+ function migratePaymentRequestRecord(record) {
13002
+ return {
13003
+ ...record,
13004
+ history: Array.isArray(record.history) && record.history.length > 0 ? record.history.map((event) => ({
13005
+ ...event,
13006
+ txHash: normalizeOptionalString4(event.txHash),
13007
+ note: normalizeOptionalString4(event.note)
13008
+ })) : buildLegacyPaymentHistory(record)
13009
+ };
13010
+ }
13011
+ function createPaymentRequestRecord(input) {
13012
+ const timestamp = nowIso2();
13013
+ const payeeAddress = input.payeeAddress.trim();
13014
+ if (!payeeAddress) {
13015
+ throw new AgentError("PAYMENT_PAYEE_REQUIRED", "Payment payee address is required.");
13016
+ }
13017
+ const asset = normalizePaymentAsset(input.asset);
13018
+ const status = input.status ?? "ready";
13019
+ return {
13020
+ format: "zk-agent-payment-request",
13021
+ version: 1,
13022
+ requestId: input.requestId.trim(),
13023
+ walletId: input.walletId.trim(),
13024
+ walletName: input.walletName.trim(),
13025
+ walletAddress: input.walletAddress.trim(),
13026
+ chain: input.chain.trim(),
13027
+ chainId: input.chainId,
13028
+ payer: {
13029
+ walletId: input.walletId.trim(),
13030
+ walletName: input.walletName.trim(),
13031
+ walletAddress: input.walletAddress.trim(),
13032
+ name: normalizeOptionalString4(input.payerName)
13033
+ },
13034
+ payee: {
13035
+ address: payeeAddress,
13036
+ name: normalizeOptionalString4(input.payeeName)
13037
+ },
13038
+ asset,
13039
+ description: normalizeOptionalString4(input.description),
13040
+ memo: normalizeOptionalString4(input.memo),
13041
+ metadata: normalizeMetadata2(input.metadata),
13042
+ executionPreference: {
13043
+ surface: inferExecutionSurface(asset),
13044
+ paymasterMode: input.paymasterMode ?? "none"
13045
+ },
13046
+ settlement: {
13047
+ status
13048
+ },
13049
+ history: [
13050
+ createPaymentHistoryEvent({
13051
+ type: "created",
13052
+ at: timestamp,
13053
+ status
13054
+ })
13055
+ ],
13056
+ createdAt: timestamp,
13057
+ updatedAt: timestamp
13058
+ };
13059
+ }
13060
+ function applyPaymentRequestStatusUpdate(record, input) {
13061
+ const nextStatus = input.status;
13062
+ const allowedTransitions = PAYMENT_REQUEST_STATUS_TRANSITIONS[record.settlement.status];
13063
+ if (!allowedTransitions.includes(nextStatus)) {
13064
+ throw new AgentError(
13065
+ "PAYMENT_STATUS_TRANSITION_INVALID",
13066
+ `Cannot move payment request ${record.requestId} from ${record.settlement.status} to ${nextStatus}.`,
13067
+ {
13068
+ currentStatus: record.settlement.status,
13069
+ nextStatus,
13070
+ allowedTransitions
13071
+ }
13072
+ );
13073
+ }
13074
+ const timestamp = nowIso2();
13075
+ const nextTxHash = normalizeOptionalString4(input.txHash);
13076
+ const nextNote = normalizeOptionalString4(input.note);
13077
+ return {
13078
+ ...record,
13079
+ updatedAt: timestamp,
13080
+ settlement: {
13081
+ status: nextStatus,
13082
+ paidAt: nextStatus === "paid" ? timestamp : record.settlement.paidAt,
13083
+ cancelledAt: nextStatus === "cancelled" ? timestamp : record.settlement.cancelledAt,
13084
+ txHash: nextTxHash ?? record.settlement.txHash,
13085
+ note: nextNote ?? record.settlement.note
13086
+ },
13087
+ history: [
13088
+ ...record.history,
13089
+ createPaymentHistoryEvent({
13090
+ type: "status-updated",
13091
+ at: timestamp,
13092
+ status: nextStatus,
13093
+ previousStatus: record.settlement.status,
13094
+ txHash: nextTxHash,
13095
+ note: nextNote
13096
+ })
13097
+ ]
13098
+ };
13099
+ }
13100
+
13101
+ // ../agent-pay/src/storage.ts
13102
+ var PAYMENT_REQUEST_COLLECTION = "payments";
13103
+ async function savePaymentRequest(record) {
13104
+ await saveEncryptedStorageRecord(
13105
+ PAYMENT_REQUEST_COLLECTION,
13106
+ record.requestId,
13107
+ migratePaymentRequestRecord(record)
13108
+ );
13109
+ }
13110
+ async function loadPaymentRequest(requestId) {
13111
+ const record = await loadEncryptedStorageRecord(
13112
+ PAYMENT_REQUEST_COLLECTION,
13113
+ requestId
13114
+ );
13115
+ return record ? migratePaymentRequestRecord(record) : null;
13116
+ }
13117
+ async function listPaymentRequestIds() {
13118
+ return listEncryptedStorageRecordIds(PAYMENT_REQUEST_COLLECTION);
13119
+ }
13120
+ async function deletePaymentRequest(requestId) {
13121
+ return deleteEncryptedStorageRecord(PAYMENT_REQUEST_COLLECTION, requestId);
13122
+ }
13123
+ async function renamePaymentRequestWalletReferences(options) {
13124
+ const currentName = options.previousWalletName.trim();
13125
+ const targetName = options.nextWalletName.trim();
13126
+ const walletId = options.walletId?.trim();
13127
+ if (!currentName) throw new Error("Current wallet name is required.");
13128
+ if (!targetName) throw new Error("New wallet name is required.");
13129
+ if (currentName === targetName) return [];
13130
+ const updatedRequestIds = [];
13131
+ for (const requestId of await listPaymentRequestIds()) {
13132
+ const paymentRequest = await loadPaymentRequest(requestId);
13133
+ if (!paymentRequest) continue;
13134
+ const matchesWallet = walletId && paymentRequest.walletId ? paymentRequest.walletId === walletId : paymentRequest.walletName === currentName;
13135
+ if (!matchesWallet) continue;
13136
+ if (walletId) {
13137
+ paymentRequest.walletId = walletId;
13138
+ paymentRequest.payer.walletId = walletId;
13139
+ }
13140
+ paymentRequest.walletName = targetName;
13141
+ paymentRequest.payer.walletName = targetName;
13142
+ await savePaymentRequest(paymentRequest);
13143
+ updatedRequestIds.push(requestId);
13144
+ }
13145
+ return updatedRequestIds;
13146
+ }
13147
+
13148
+ // ../agent-pay/src/service.ts
13149
+ async function requirePaymentRequest(requestId) {
13150
+ const record = await loadPaymentRequest(requestId);
13151
+ if (!record) {
13152
+ throw new AgentError(
13153
+ "PAYMENT_REQUEST_NOT_FOUND",
13154
+ `Payment request not found: ${requestId}`
13155
+ );
13156
+ }
13157
+ return record;
13158
+ }
13159
+ async function createStoredPaymentRequest(input) {
13160
+ const paymentRequest = createPaymentRequestRecord(input);
13161
+ await savePaymentRequest(paymentRequest);
13162
+ return {
13163
+ paymentRequest,
13164
+ executionPlan: buildPaymentExecutionPlan(paymentRequest)
13165
+ };
13166
+ }
13167
+ async function getStoredPaymentRequest(requestId) {
13168
+ const paymentRequest = await requirePaymentRequest(requestId);
13169
+ return {
13170
+ paymentRequest,
13171
+ executionPlan: buildPaymentExecutionPlan(paymentRequest)
13172
+ };
13173
+ }
13174
+ async function listStoredPaymentRequests(input = {}) {
13175
+ const requestIds = await listPaymentRequestIds();
13176
+ const requests = [];
13177
+ for (const requestId of requestIds) {
13178
+ const record = await loadPaymentRequest(requestId);
13179
+ if (!record) continue;
13180
+ if (input.walletName && record.walletName !== input.walletName) continue;
13181
+ if (input.status && record.settlement.status !== input.status) continue;
13182
+ requests.push(record);
13183
+ }
13184
+ return requests.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
13185
+ }
13186
+ async function updateStoredPaymentRequestStatus(input) {
13187
+ const paymentRequest = await requirePaymentRequest(input.requestId);
13188
+ const updated = applyPaymentRequestStatusUpdate(paymentRequest, input);
13189
+ await savePaymentRequest(updated);
13190
+ return {
13191
+ paymentRequest: updated,
13192
+ executionPlan: buildPaymentExecutionPlan(updated)
13193
+ };
13194
+ }
13195
+ async function removeStoredPaymentRequest(requestId) {
13196
+ return deletePaymentRequest(requestId);
13197
+ }
13198
+
13199
+ // src/commands/payment.ts
13200
+ function parseMetadataEntries2(entries) {
13201
+ const metadata = {};
13202
+ for (const entry of entries) {
13203
+ const separatorIndex = entry.indexOf("=");
13204
+ if (separatorIndex <= 0 || separatorIndex === entry.length - 1) {
13205
+ throw new AgentError(
13206
+ "PAYMENT_METADATA_INVALID",
13207
+ `Invalid metadata entry: ${entry}. Use key=value.`
13208
+ );
13209
+ }
13210
+ const key = entry.slice(0, separatorIndex).trim();
13211
+ const value = entry.slice(separatorIndex + 1).trim();
13212
+ if (!key || !value) {
13213
+ throw new AgentError(
13214
+ "PAYMENT_METADATA_INVALID",
13215
+ `Invalid metadata entry: ${entry}. Use key=value.`
13216
+ );
13217
+ }
13218
+ metadata[key] = value;
13219
+ }
13220
+ return metadata;
13221
+ }
13222
+ function resolvePaymentStatus(value) {
13223
+ const normalized = value?.trim().toLowerCase();
13224
+ if (!normalized) return "ready";
13225
+ if (normalized === "draft" || normalized === "ready" || normalized === "paid" || normalized === "cancelled") {
13226
+ return normalized;
13227
+ }
13228
+ throw new AgentError(
13229
+ "PAYMENT_STATUS_INVALID",
13230
+ `Unsupported payment status: ${value}. Use draft, ready, paid, or cancelled.`
13231
+ );
13232
+ }
13233
+ function resolvePaymasterMode2(value) {
13234
+ const normalized = value?.trim().toLowerCase();
13235
+ if (!normalized) return void 0;
13236
+ if (normalized === "none" || normalized === "sponsored" || normalized === "approval-based") {
13237
+ return normalized;
13238
+ }
13239
+ throw new AgentError(
13240
+ "PAYMENT_PAYMASTER_MODE_INVALID",
13241
+ `Unsupported paymaster mode: ${value}. Use none, sponsored, or approval-based.`
13242
+ );
13243
+ }
13244
+ function buildPaymentRequestId(value) {
13245
+ const trimmed = value?.trim();
13246
+ if (trimmed) return trimmed;
13247
+ return `payreq-${randomBytes5(4).toString("hex")}`;
13248
+ }
13249
+ function formatPaymentAsset(record) {
13250
+ const symbol = record.asset.kind === "native" ? record.asset.symbol || "native" : record.asset.symbol || record.asset.tokenAddress || "erc20";
13251
+ return `${record.asset.amount} ${symbol}`;
13252
+ }
13253
+ function buildPaymentExecuteCommand(plan) {
13254
+ if (plan.asset.kind === "native") {
13255
+ return buildWorkflowPayRecommendedCommand(
13256
+ plan.walletName,
13257
+ plan.paymasterMode
13258
+ ).replace("--to <address>", `--to ${plan.payeeAddress}`).replace("--amount <amount>", `--amount ${plan.asset.amount}`);
13259
+ }
13260
+ return buildSendTokenRecommendedCommand({
13261
+ walletName: plan.walletName,
13262
+ to: plan.payeeAddress,
13263
+ amount: plan.asset.amount,
13264
+ tokenAddress: plan.asset.tokenAddress,
13265
+ symbol: plan.asset.symbol,
13266
+ decimals: plan.asset.decimals,
13267
+ paymasterMode: plan.paymasterMode
13268
+ });
13269
+ }
13270
+ function buildPaymentRecommendedCommands(record, executionPlan) {
13271
+ return {
13272
+ list: buildPaymentListRecommendedCommand(),
13273
+ show: buildPaymentShowRecommendedCommand(record.requestId),
13274
+ execute: buildPaymentExecuteCommand(executionPlan),
13275
+ ...record.settlement.status === "draft" ? {
13276
+ markReady: buildPaymentSetStatusRecommendedCommand(record.requestId, "ready"),
13277
+ cancel: buildPaymentSetStatusRecommendedCommand(record.requestId, "cancelled")
13278
+ } : {},
13279
+ ...record.settlement.status === "ready" ? {
13280
+ markDraft: buildPaymentSetStatusRecommendedCommand(record.requestId, "draft"),
13281
+ markPaid: buildPaymentSetStatusRecommendedCommand(
13282
+ record.requestId,
13283
+ "paid",
13284
+ "<tx-hash>"
13285
+ ),
13286
+ cancel: buildPaymentSetStatusRecommendedCommand(record.requestId, "cancelled")
13287
+ } : {},
13288
+ remove: buildPaymentRemoveRecommendedCommand(record.requestId)
13289
+ };
13290
+ }
13291
+ function paymentRequestLines(record, executionPlan) {
13292
+ const lines = [
13293
+ ["request", record.requestId],
13294
+ ["status", record.settlement.status],
13295
+ ["wallet", record.walletName],
13296
+ ["chain", `${record.chain} (${record.chainId})`],
13297
+ ["payer", `${record.payer.name || record.payer.walletName} ${record.payer.walletAddress}`],
13298
+ ["payee", `${record.payee.name || "payee"} ${record.payee.address}`],
13299
+ ["asset", formatPaymentAsset(record)],
13300
+ ["execution surface", record.executionPreference.surface],
13301
+ ["paymaster mode", record.executionPreference.paymasterMode],
13302
+ ["execute", buildPaymentExecuteCommand(executionPlan)],
13303
+ ["show", buildPaymentShowRecommendedCommand(record.requestId)],
13304
+ ["remove", buildPaymentRemoveRecommendedCommand(record.requestId)]
13305
+ ];
13306
+ if (record.description) lines.splice(7, 0, ["description", record.description]);
13307
+ if (record.memo) lines.splice(record.description ? 8 : 7, 0, ["memo", record.memo]);
13308
+ if (record.settlement.txHash) lines.push(["txHash", record.settlement.txHash]);
13309
+ if (record.settlement.note) lines.push(["note", record.settlement.note]);
13310
+ if (record.settlement.paidAt) lines.push(["paid at", record.settlement.paidAt]);
13311
+ if (record.settlement.cancelledAt) lines.push(["cancelled at", record.settlement.cancelledAt]);
13312
+ lines.push(["history events", String(record.history.length)]);
13313
+ lines.push(["metadata keys", String(Object.keys(record.metadata).length)]);
13314
+ return lines;
13315
+ }
13316
+ function buildPaymentExecutionPlanJson(plan) {
13317
+ return {
13318
+ ...plan,
13319
+ command: buildPaymentExecuteCommand(plan)
13320
+ };
13321
+ }
13322
+ function buildPaymentListSummary(record) {
13323
+ return `${record.requestId} ${record.settlement.status} ${formatPaymentAsset(record)} -> ${record.payee.address} (${record.walletName})`;
13324
+ }
13325
+ function createPaymentCommand() {
13326
+ const payment = new Command7("payment").description(
13327
+ "Manage local-first Agent Pay request records separately from the execution-layer workflow and send commands"
13328
+ );
13329
+ payment.addHelpText(
13330
+ "after",
13331
+ [
13332
+ "",
13333
+ " Payment request surface:",
13334
+ " Use this layer to capture payer/payee intent and local settlement state before or after execution.",
13335
+ " `workflow pay` and `send-token` still execute the transfer; `payment` stores the request record and status lifecycle.",
13336
+ "",
13337
+ " First platform path:",
13338
+ " zk-agent payment create --wallet main --to <address> --amount <amount>",
13339
+ " zk-agent payment show --request-id <id>",
13340
+ " zk-agent payment set-status --request-id <id> --status paid --tx-hash <tx-hash>",
13341
+ "",
13342
+ " ERC-20 request path:",
13343
+ " zk-agent payment create --wallet main --to <address> --amount <amount> --symbol USDC",
13344
+ "",
13345
+ " Stored request management:",
13346
+ " zk-agent payment list",
13347
+ " zk-agent payment remove --request-id <id>"
13348
+ ].join("\n")
13349
+ );
13350
+ payment.command("create").description("Create a local payment request record for native value or an ERC-20 transfer").option("--wallet <name>", "Stored payer wallet name", "main").requiredOption("--to <address>", "Payee address").requiredOption("--amount <value>", "Amount in human-readable units").option("--token <address>", "ERC-20 token contract address").option("--symbol <symbol>", "ERC-20 token symbol for registry-backed resolution").option("--decimals <value>", "ERC-20 token decimals when registry metadata is unavailable").option("--payee-name <name>", "Optional payee display name").option("--payer-name <name>", "Optional payer display name").option("--description <text>", "Short payment description").option("--memo <text>", "Optional memo or invoice reference").option("--metadata <key=value>", "Additional payment metadata", collectRepeatedString2, []).option("--paymaster-mode <mode>", "Optional execution preference: none, sponsored, or approval-based").option("--status <status>", "Initial local payment status: draft, ready, paid, or cancelled").option("--request-id <id>", "Optional explicit payment request id").action(async (options) => {
13351
+ const wallet = await loadWalletSession(options.wallet);
13352
+ if (!wallet) {
13353
+ throw new AgentError("PAYMENT_WALLET_NOT_FOUND", `Wallet not found: ${options.wallet}`);
13354
+ }
13355
+ if (!wallet.walletId) {
13356
+ throw new AgentError(
13357
+ "WALLET_ID_MISSING",
13358
+ `Wallet ${wallet.walletName} is missing a stable walletId. Re-save or reapprove the wallet session before creating a payment request.`
13359
+ );
13360
+ }
13361
+ const paymasterMode = resolvePaymasterMode2(options.paymasterMode) ?? wallet.paymasterMode ?? "none";
13362
+ const status = resolvePaymentStatus(options.status);
13363
+ const metadata = parseMetadataEntries2(options.metadata);
13364
+ const requestId = buildPaymentRequestId(options.requestId);
13365
+ const hasTokenInput = Boolean(options.token?.trim() || options.symbol?.trim());
13366
+ const asset = hasTokenInput ? await resolveRequiredTokenInput({
13367
+ tokenAddress: options.token,
13368
+ symbol: options.symbol,
13369
+ decimals: options.decimals,
13370
+ chain: wallet.chain,
13371
+ tokenOptionLabel: "--token",
13372
+ symbolOptionLabel: "--symbol",
13373
+ decimalsOptionLabel: "--decimals"
13374
+ }).then((token) => ({
13375
+ kind: "erc20",
13376
+ amount: options.amount,
13377
+ tokenAddress: token.address,
13378
+ decimals: token.decimals,
13379
+ symbol: token.symbol
13380
+ })) : {
13381
+ kind: "native",
13382
+ amount: options.amount
13383
+ };
13384
+ const result = await createStoredPaymentRequest({
13385
+ requestId,
13386
+ walletId: wallet.walletId,
13387
+ walletName: wallet.walletName,
13388
+ walletAddress: wallet.walletAddress,
13389
+ chain: wallet.chain,
13390
+ chainId: wallet.chainId,
13391
+ payerName: options.payerName,
13392
+ payeeAddress: options.to,
13393
+ payeeName: options.payeeName,
13394
+ asset,
13395
+ description: options.description,
13396
+ memo: options.memo,
13397
+ metadata,
13398
+ paymasterMode,
13399
+ status
13400
+ });
13401
+ printResult(paymentRequestLines(result.paymentRequest, result.executionPlan), {
13402
+ ok: true,
13403
+ paymentRequest: result.paymentRequest,
13404
+ executionPlan: buildPaymentExecutionPlanJson(result.executionPlan),
13405
+ recommendedCommands: buildPaymentRecommendedCommands(
13406
+ result.paymentRequest,
13407
+ result.executionPlan
13408
+ )
13409
+ });
13410
+ });
13411
+ payment.command("list").description("List stored local payment request records").option("--wallet <name>", "Optional payer wallet filter").option("--status <status>", "Optional status filter: draft, ready, paid, or cancelled").action(async (options) => {
13412
+ const statusFilter = options.status ? resolvePaymentStatus(options.status) : void 0;
13413
+ const requests = await listStoredPaymentRequests({
13414
+ walletName: options.wallet,
13415
+ status: statusFilter
13416
+ });
13417
+ printResult(
13418
+ requests.length > 0 ? requests.flatMap((record) => [
13419
+ ["payment", buildPaymentListSummary(record)],
13420
+ ["show", buildPaymentShowRecommendedCommand(record.requestId)]
13421
+ ]) : [
13422
+ ["status", "No stored payment requests"],
13423
+ ["next", "zk-agent payment create --wallet main --to <address> --amount <amount>"]
13424
+ ],
13425
+ {
13426
+ ok: true,
13427
+ count: requests.length,
13428
+ filters: {
13429
+ walletName: options.wallet || null,
13430
+ status: statusFilter || null
13431
+ },
13432
+ requests,
13433
+ recommendedCommands: requests.length === 0 ? {
13434
+ create: "zk-agent payment create --wallet main --to <address> --amount <amount>"
13435
+ } : {
13436
+ list: buildPaymentListRecommendedCommand()
13437
+ }
13438
+ }
13439
+ );
13440
+ });
13441
+ payment.command("show").description("Show one stored payment request record").requiredOption("--request-id <id>", "Stored payment request id").action(async (options) => {
13442
+ const result = await getStoredPaymentRequest(options.requestId);
13443
+ printResult(paymentRequestLines(result.paymentRequest, result.executionPlan), {
13444
+ ok: true,
13445
+ paymentRequest: result.paymentRequest,
13446
+ executionPlan: buildPaymentExecutionPlanJson(result.executionPlan),
13447
+ recommendedCommands: buildPaymentRecommendedCommands(
13448
+ result.paymentRequest,
13449
+ result.executionPlan
13450
+ )
13451
+ });
13452
+ });
13453
+ payment.command("set-status").description("Update the local settlement status of one stored payment request").requiredOption("--request-id <id>", "Stored payment request id").requiredOption("--status <status>", "Next status: draft, ready, paid, or cancelled").option("--tx-hash <hash>", "Optional settlement transaction hash").option("--note <text>", "Optional operator note for the status update").action(async (options) => {
13454
+ const result = await updateStoredPaymentRequestStatus({
13455
+ requestId: options.requestId,
13456
+ status: resolvePaymentStatus(options.status),
13457
+ txHash: options.txHash,
13458
+ note: options.note
13459
+ });
13460
+ printResult(paymentRequestLines(result.paymentRequest, result.executionPlan), {
13461
+ ok: true,
13462
+ paymentRequest: result.paymentRequest,
13463
+ executionPlan: buildPaymentExecutionPlanJson(result.executionPlan),
13464
+ recommendedCommands: buildPaymentRecommendedCommands(
13465
+ result.paymentRequest,
13466
+ result.executionPlan
13467
+ )
13468
+ });
13469
+ });
13470
+ payment.command("remove").description("Delete one stored payment request record").requiredOption("--request-id <id>", "Stored payment request id").action(async (options) => {
13471
+ const removed = await removeStoredPaymentRequest(options.requestId);
13472
+ if (!removed) {
13473
+ throw new AgentError(
13474
+ "PAYMENT_REQUEST_NOT_FOUND",
13475
+ `Payment request not found: ${options.requestId}`
13476
+ );
13477
+ }
13478
+ printResult(
13479
+ [
13480
+ ["status", "Payment request removed"],
13481
+ ["request", options.requestId],
13482
+ ["next", buildPaymentListRecommendedCommand()]
13483
+ ],
13484
+ {
13485
+ ok: true,
13486
+ requestId: options.requestId,
13487
+ removed: true,
13488
+ recommendedCommands: {
13489
+ list: buildPaymentListRecommendedCommand(),
13490
+ create: "zk-agent payment create --wallet main --to <address> --amount <amount>"
13491
+ }
13492
+ }
13493
+ );
13494
+ });
13495
+ return payment;
13496
+ }
13497
+ function collectRepeatedString2(value, previous) {
13498
+ return [...previous, value];
13499
+ }
13500
+
13501
+ // src/commands/resolve-token.ts
13502
+ import { Command as Command8 } from "commander";
12602
13503
  function resolveResolveTokenCommandDeps(deps) {
12603
13504
  return {
12604
13505
  loadWallet: deps?.loadWallet ?? (async (walletName) => {
@@ -12656,7 +13557,7 @@ function buildResolveTokenDiscoverySummary(result) {
12656
13557
  }
12657
13558
  function createResolveTokenCommand(deps) {
12658
13559
  const resolvedDeps = resolveResolveTokenCommandDeps(deps);
12659
- return new Command7("resolve-token").description("Resolve a token symbol or address against the configured local-first token registry").addHelpText(
13560
+ return new Command8("resolve-token").description("Resolve a token symbol or address against the configured local-first token registry").addHelpText(
12660
13561
  "after",
12661
13562
  [
12662
13563
  "",
@@ -12790,33 +13691,67 @@ function normalizeSource(value) {
12790
13691
  }
12791
13692
 
12792
13693
  // src/commands/suite.ts
12793
- import { Command as Command8 } from "commander";
13694
+ import { Command as Command9 } from "commander";
12794
13695
 
12795
13696
  // src/lib/operator-suite.ts
12796
13697
  function buildOperatorSuitePayload(options = {}) {
12797
13698
  const walletName = options.walletName?.trim() || "main";
12798
13699
  const chain = options.chain?.trim() || "zksync-sepolia";
13700
+ const includeOnboarding = options.includeOnboarding === true;
12799
13701
  const flagshipCommand = buildWorkflowPayRecommendedCommand(walletName);
12800
13702
  const inspectDefaults = buildDefaultsRecommendedCommand();
13703
+ const workflowSurfaceCommand = "zk-agent workflow --help";
13704
+ const relaySurfaceCommand = "zk-agent relay --help";
12801
13705
  const discoveryCommand = buildAssetsRecommendedCommand(walletName);
12802
13706
  const paymasterCommand = buildWorkflowPayRecommendedCommand(walletName, "approval-based");
12803
13707
  const fundingCommand = buildWorkflowFundRecommendedCommand(walletName);
13708
+ const nextCommand = buildTopLevelNextRecommendedCommand(void 0, void 0, walletName);
13709
+ const hostedRelayInspectCommand = buildRelayInspectRecommendedCommand("<url>");
13710
+ const hostedCreateWalletCommand = buildWalletCreateRemoteRecommendedCommand(
13711
+ "<url>",
13712
+ void 0,
13713
+ walletName
13714
+ );
13715
+ const hostedReapproveCommand = buildWalletReapproveRemoteRecommendedCommand(
13716
+ walletName,
13717
+ "<url>"
13718
+ );
13719
+ const suiteCommand = buildSuiteRecommendedCommand(walletName, chain, {
13720
+ includeOnboarding
13721
+ });
13722
+ const preflightPaths = includeOnboarding ? buildSetupRecommendedPaths("<url>", void 0, walletName) : void 0;
13723
+ const preflight = preflightPaths ? {
13724
+ id: "first-run-preflight",
13725
+ title: "First-Run Preflight",
13726
+ goal: "Start from a fresh install, write local defaults, and bootstrap a writable wallet session before using the packaged operator surface.",
13727
+ useWhen: "Use this when the machine is new, the wallet is not ready yet, or you want the full operator map before choosing local-first versus remote-browser approval.",
13728
+ diagnosticCommand: walletName === "main" ? "zk-agent doctor" : `zk-agent doctor --wallet ${walletName}`,
13729
+ localPath: preflightPaths.local,
13730
+ remoteBrowserPath: preflightPaths.remoteBrowser,
13731
+ afterWalletReady: buildSuiteRecommendedCommand(walletName, chain)
13732
+ } : void 0;
12804
13733
  const flagship = {
13734
+ category: "operate",
13735
+ surface: "workflow",
12805
13736
  id: "flagship-pay",
12806
13737
  title: "Flagship Pay",
12807
13738
  goal: "Run the default zkSync-native native-send path through the workflow layer.",
12808
13739
  useWhen: "Start here when the wallet is already ready and the next real goal is a native send.",
12809
13740
  primaryCommand: flagshipCommand,
12810
- supportingCommands: ["zk-agent next", buildWalletStatusRecommendedCommand(walletName), inspectDefaults],
13741
+ surfaceCommand: workflowSurfaceCommand,
13742
+ supportingCommands: [nextCommand, buildWalletStatusRecommendedCommand(walletName), inspectDefaults],
12811
13743
  skillPath: "skills/zk-aa/SKILL.md"
12812
13744
  };
12813
13745
  const slices = [
12814
13746
  {
13747
+ category: "discover",
13748
+ surface: "discovery",
12815
13749
  id: "discovery-defaults",
12816
13750
  title: "Discovery / Defaults",
12817
13751
  goal: "Discover owned assets, tracked defaults, and symbol-first token resolution before acting.",
12818
13752
  useWhen: "Use this before tokenized actions or whenever asset/default context is unclear.",
12819
13753
  primaryCommand: discoveryCommand,
13754
+ surfaceCommand: inspectDefaults,
12820
13755
  supportingCommands: [
12821
13756
  inspectDefaults,
12822
13757
  `zk-agent tokens --chain ${chain}`,
@@ -12826,11 +13761,14 @@ function buildOperatorSuitePayload(options = {}) {
12826
13761
  smokeCommand: `pnpm smoke:discovery -- --wallet ${walletName}`
12827
13762
  },
12828
13763
  {
13764
+ category: "pay",
13765
+ surface: "workflow",
12829
13766
  id: "paymaster-readiness",
12830
13767
  title: "Paymaster Readiness",
12831
13768
  goal: "Stay on the approval-based flagship path and recover the exact fee-token/default metadata when needed.",
12832
13769
  useWhen: "Use this when approval-based pay or another sponsored write needs fee-token/default recovery.",
12833
13770
  primaryCommand: paymasterCommand,
13771
+ surfaceCommand: workflowSurfaceCommand,
12834
13772
  supportingCommands: [
12835
13773
  inspectDefaults,
12836
13774
  buildPaymasterFeeTokensRecommendedCommand(chain),
@@ -12840,11 +13778,14 @@ function buildOperatorSuitePayload(options = {}) {
12840
13778
  smokeCommand: `pnpm smoke:paymaster-success -- --wallet ${walletName}`
12841
13779
  },
12842
13780
  {
13781
+ category: "fund",
13782
+ surface: "workflow",
12843
13783
  id: "funding-readiness",
12844
13784
  title: "Funding Readiness",
12845
13785
  goal: "Ask the workflow layer for the exact funding route before executing bridge/deposit follow-up.",
12846
13786
  useWhen: "Use this when the workflow path is blocked on gas or the CLI says funding is required.",
12847
13787
  primaryCommand: fundingCommand,
13788
+ surfaceCommand: workflowSurfaceCommand,
12848
13789
  supportingCommands: [
12849
13790
  buildWorkflowFundRunRecommendedCommand(walletName),
12850
13791
  `zk-agent fund --wallet ${walletName} --amount <amount>`,
@@ -12852,48 +13793,197 @@ function buildOperatorSuitePayload(options = {}) {
12852
13793
  ],
12853
13794
  skillPath: "skills/zk-funding/SKILL.md",
12854
13795
  smokeCommand: `pnpm smoke:funding-readiness -- --wallet ${walletName}`
13796
+ },
13797
+ {
13798
+ category: "recover",
13799
+ surface: "relay",
13800
+ id: "hosted-approval-recovery",
13801
+ title: "Hosted Approval Recovery",
13802
+ goal: "Validate a hosted relay URL and switch to the remote approval path when the browser is not colocated or a writable session must be reapproved remotely.",
13803
+ useWhen: "Use this when local callback is not viable, the browser is remote, or an expired writable session must be recovered through the single-host hosted relay baseline.",
13804
+ primaryCommand: hostedRelayInspectCommand,
13805
+ surfaceCommand: relaySurfaceCommand,
13806
+ supportingCommands: [
13807
+ hostedCreateWalletCommand,
13808
+ hostedReapproveCommand,
13809
+ `pnpm smoke:hosted-operated-baseline -- --wallet ${walletName} --relay-url <url> --reapprove --prompt-code --plan`
13810
+ ],
13811
+ skillPath: "skills/zk-relay/SKILL.md"
12855
13812
  }
12856
13813
  ];
13814
+ const surfaces = [
13815
+ {
13816
+ surface: "workflow",
13817
+ title: "Workflow Surface",
13818
+ useWhen: "Use this when the question is already about execution, approval-based pay, or funding recovery after suite has identified the right slice.",
13819
+ command: workflowSurfaceCommand,
13820
+ categoryIds: ["operate", "pay", "fund"],
13821
+ entryIds: [flagship.id, "paymaster-readiness", "funding-readiness"]
13822
+ },
13823
+ {
13824
+ surface: "discovery",
13825
+ title: "Discovery Surface",
13826
+ useWhen: "Use this when the question is about assets, defaults, token ownership, or symbol-first inspection after suite has identified the discovery slice.",
13827
+ command: inspectDefaults,
13828
+ categoryIds: ["discover"],
13829
+ entryIds: ["discovery-defaults"]
13830
+ },
13831
+ {
13832
+ surface: "relay",
13833
+ title: "Relay Surface",
13834
+ useWhen: "Use this when the browser is remote or hosted approval readiness must be checked before wallet recovery can continue.",
13835
+ command: relaySurfaceCommand,
13836
+ categoryIds: ["recover"],
13837
+ entryIds: ["hosted-approval-recovery"]
13838
+ }
13839
+ ];
13840
+ const journeys = [
13841
+ {
13842
+ id: "send-value-now",
13843
+ title: "Send Value Now",
13844
+ operatorQuestion: "I already have a ready wallet and want the shortest path to send native value now.",
13845
+ useWhen: "Use this when the wallet is already ready and the operator wants the flagship zkSync-native pay path first.",
13846
+ startCommand: flagshipCommand,
13847
+ surface: "workflow",
13848
+ categoryIds: ["operate"],
13849
+ entryIds: [flagship.id]
13850
+ },
13851
+ {
13852
+ id: "inspect-before-acting",
13853
+ title: "Inspect Before Acting",
13854
+ operatorQuestion: "I need to inspect assets, defaults, or token metadata before I choose a tokenized action.",
13855
+ useWhen: "Use this when asset visibility, defaults, or symbol-first token inspection is still the real blocker.",
13856
+ startCommand: discoveryCommand,
13857
+ surface: "discovery",
13858
+ categoryIds: ["discover"],
13859
+ entryIds: ["discovery-defaults"]
13860
+ },
13861
+ {
13862
+ id: "unstick-a-write",
13863
+ title: "Unstick a Write",
13864
+ operatorQuestion: "The write path is blocked on fee-token/default state or funding, and I need the shortest recovery route.",
13865
+ useWhen: "Use this when approval-based pay or a workflow write is blocked and the CLI needs to recover paymaster or funding readiness.",
13866
+ startCommand: paymasterCommand,
13867
+ surface: "workflow",
13868
+ categoryIds: ["pay", "fund"],
13869
+ entryIds: ["paymaster-readiness", "funding-readiness"]
13870
+ },
13871
+ {
13872
+ id: "recover-remote-approval",
13873
+ title: "Recover Remote Approval",
13874
+ operatorQuestion: "The browser is remote or local callback is not viable, so approval must move to the hosted relay path.",
13875
+ useWhen: "Use this when a writable session must be recovered through the single-host hosted relay baseline.",
13876
+ startCommand: hostedRelayInspectCommand,
13877
+ surface: "relay",
13878
+ categoryIds: ["recover"],
13879
+ entryIds: ["hosted-approval-recovery"]
13880
+ }
13881
+ ];
13882
+ const recommendedJourney = {
13883
+ id: journeys[0].id,
13884
+ title: journeys[0].title,
13885
+ startCommand: journeys[0].startCommand,
13886
+ surface: journeys[0].surface,
13887
+ useWhen: journeys[0].useWhen
13888
+ };
12857
13889
  return {
12858
13890
  ok: true,
12859
13891
  summary: {
12860
13892
  suiteId: "zk-agent-operator-suite",
13893
+ catalogView: "operator-catalog",
12861
13894
  walletName,
12862
13895
  chain,
12863
13896
  stage: "wallet-ready-post-flagship",
12864
- useWhen: "Use suite after wallet readiness when you want one packaged surface for flagship pay plus the current post-flagship discovery, paymaster, and funding slices.",
13897
+ useWhen: "Use suite after wallet readiness when you want one packaged surface for flagship pay plus the current post-flagship discovery, paymaster, funding, and hosted recovery slices.",
13898
+ entryModes: ["local-first", "hosted-recovery"],
13899
+ startHereJourneyId: recommendedJourney.id,
13900
+ journeyOrder: journeys.map((entry) => entry.id),
13901
+ surfaceOrder: ["workflow", "discovery", "relay"],
13902
+ categoryOrder: [flagship.category, ...slices.map((entry) => entry.category)],
12865
13903
  flagshipId: flagship.id,
12866
13904
  postFlagshipSliceIds: slices.map((entry) => entry.id),
12867
13905
  recommendedOrder: [flagship.id, ...slices.map((entry) => entry.id)],
12868
13906
  nextAction: flagship.primaryCommand
12869
13907
  },
13908
+ ...preflight ? { preflight } : {},
13909
+ recommendedJourney,
13910
+ journeys,
13911
+ surfaces,
12870
13912
  flagship,
12871
13913
  slices,
12872
13914
  recommendedCommands: {
12873
- suite: buildSuiteRecommendedCommand(walletName, chain),
13915
+ suite: suiteCommand,
12874
13916
  flagship: flagshipCommand,
13917
+ workflowSurface: workflowSurfaceCommand,
13918
+ discoverySurface: inspectDefaults,
13919
+ relaySurface: relaySurfaceCommand,
12875
13920
  discovery: discoveryCommand,
12876
13921
  paymaster: paymasterCommand,
12877
13922
  funding: fundingCommand,
13923
+ hostedApproval: hostedRelayInspectCommand,
12878
13924
  inspectDefaults
12879
13925
  }
12880
13926
  };
12881
13927
  }
12882
13928
  function operatorSuiteLines(payload) {
13929
+ const preflightLines = payload.preflight ? [
13930
+ ["preflight", formatRecommendedPath(payload.preflight.localPath)],
13931
+ ...payload.preflight.remoteBrowserPath?.length ? [["preflight (remote-browser)", formatRecommendedPath(payload.preflight.remoteBrowserPath)]] : [],
13932
+ ["preflight when", payload.preflight.useWhen],
13933
+ ["preflight diagnose", payload.preflight.diagnosticCommand],
13934
+ ["preflight handoff", payload.preflight.afterWalletReady]
13935
+ ] : [];
13936
+ const journeyLines = payload.journeys.flatMap((journey) => [
13937
+ [`journey ${journey.id}`, journey.startCommand],
13938
+ [`journey ${journey.id} surface`, journey.surface],
13939
+ [`journey ${journey.id} categories`, journey.categoryIds.join(" -> ")],
13940
+ [`journey ${journey.id} entries`, journey.entryIds.join(" -> ")],
13941
+ [`journey ${journey.id} when`, journey.useWhen]
13942
+ ]);
12883
13943
  const sliceLines = payload.slices.flatMap((entry) => [
13944
+ [`${entry.title.toLowerCase()} category`, entry.category],
13945
+ [`${entry.title.toLowerCase()} surface`, entry.surface],
13946
+ [`${entry.title.toLowerCase()} surface command`, entry.surfaceCommand],
12884
13947
  [entry.title.toLowerCase(), formatRecommendedPath([entry.primaryCommand, ...entry.supportingCommands])],
12885
13948
  [`${entry.title.toLowerCase()} when`, entry.useWhen],
12886
13949
  [`${entry.title.toLowerCase()} skill`, entry.skillPath],
12887
13950
  ...entry.smokeCommand ? [[`${entry.title.toLowerCase()} smoke`, entry.smokeCommand]] : []
12888
13951
  ]);
13952
+ const surfaceLines = payload.surfaces.flatMap((surface) => [
13953
+ [`${surface.surface} surface`, surface.command],
13954
+ [`${surface.surface} surface categories`, surface.categoryIds.join(" -> ")],
13955
+ [`${surface.surface} surface entries`, surface.entryIds.join(" -> ")],
13956
+ [`${surface.surface} surface when`, surface.useWhen]
13957
+ ]);
12889
13958
  return [
12890
13959
  ["suite", payload.summary.suiteId],
13960
+ ["catalog", payload.summary.catalogView],
12891
13961
  ["wallet", payload.summary.walletName],
12892
13962
  ["chain", payload.summary.chain],
12893
13963
  ["stage", payload.summary.stage],
12894
13964
  ["use when", payload.summary.useWhen],
13965
+ ["entry modes", payload.summary.entryModes.join(" -> ")],
13966
+ ["start here journey", payload.summary.startHereJourneyId],
13967
+ ["start here", payload.recommendedJourney.startCommand],
13968
+ ["start here surface", payload.recommendedJourney.surface],
13969
+ ["start here when", payload.recommendedJourney.useWhen],
13970
+ ["journey order", payload.summary.journeyOrder.join(" -> ")],
13971
+ ["surface order", payload.summary.surfaceOrder.join(" -> ")],
13972
+ ["category order", payload.summary.categoryOrder.join(" -> ")],
13973
+ ...preflightLines,
13974
+ ...journeyLines,
13975
+ ...surfaceLines,
12895
13976
  ["recommended order", payload.summary.recommendedOrder.join(" -> ")],
12896
- [payload.flagship.title.toLowerCase(), formatRecommendedPath([payload.flagship.primaryCommand, "zk-agent next"])],
13977
+ [`${payload.flagship.title.toLowerCase()} category`, payload.flagship.category],
13978
+ [`${payload.flagship.title.toLowerCase()} surface`, payload.flagship.surface],
13979
+ [`${payload.flagship.title.toLowerCase()} surface command`, payload.flagship.surfaceCommand],
13980
+ [
13981
+ payload.flagship.title.toLowerCase(),
13982
+ formatRecommendedPath([
13983
+ payload.flagship.primaryCommand,
13984
+ buildTopLevelNextRecommendedCommand(void 0, void 0, payload.summary.walletName)
13985
+ ])
13986
+ ],
12897
13987
  [`${payload.flagship.title.toLowerCase()} when`, payload.flagship.useWhen],
12898
13988
  [`${payload.flagship.title.toLowerCase()} skill`, payload.flagship.skillPath],
12899
13989
  ...sliceLines,
@@ -12903,35 +13993,70 @@ function operatorSuiteLines(payload) {
12903
13993
 
12904
13994
  // src/commands/suite.ts
12905
13995
  function createSuiteCommand() {
12906
- return new Command8("suite").description("Show the flagship and post-flagship zkSync-native operator suite").option("--wallet <name>", "Wallet name used in example commands", "main").option("--chain <chain>", "Chain key used in example commands", "zksync-sepolia").addHelpText(
13996
+ return new Command9("suite").description("Show the flagship and post-flagship zkSync-native operator suite").option("--wallet <name>", "Wallet name used in example commands", "main").option("--chain <chain>", "Chain key used in example commands", "zksync-sepolia").option("--include-onboarding", "Include the first-run preflight and wallet-bootstrap map", false).addHelpText(
12907
13997
  "after",
12908
13998
  [
12909
13999
  "",
12910
14000
  " Use `suite` after wallet readiness when you want one packaged surface",
12911
14001
  " for flagship pay plus the current post-flagship slices.",
12912
14002
  "",
14003
+ " What `suite` answers right now:",
14004
+ " operate: send native value through the flagship workflow path",
14005
+ " discover: inspect owned assets and defaults before tokenized actions",
14006
+ " pay: stay on the approval-based paymaster path with exact fee-token follow-up",
14007
+ " fund: recover from gas/funding blockers without guessing the route",
14008
+ " recover: switch to hosted relay approval when the browser is remote",
14009
+ "",
14010
+ " Most common operator journeys:",
14011
+ " send value now: go straight to the flagship pay path",
14012
+ " inspect before acting: open assets/defaults/token inspection first",
14013
+ " unstick a write: recover paymaster/funding readiness on the workflow path",
14014
+ " recover remote approval: move approval to the hosted relay path",
14015
+ "",
14016
+ " If you only need one default starting point inside suite:",
14017
+ " send value now",
14018
+ "",
14019
+ " Where `suite` hands you off next:",
14020
+ " workflow: flagship pay, approval-based pay, and funding recovery",
14021
+ " discovery: assets, defaults, and token inspection",
14022
+ " relay: hosted approval recovery and relay readiness",
14023
+ "",
14024
+ " For the full first-run to post-flagship map:",
14025
+ " zk-agent suite --include-onboarding",
14026
+ "",
12913
14027
  " Recommended order inside the suite:",
12914
14028
  " zk-agent workflow pay --wallet main --to <address> --amount <amount>",
12915
14029
  " zk-agent assets --wallet main",
12916
14030
  " zk-agent workflow pay --wallet main --to <address> --amount <amount> --paymaster-mode approval-based",
12917
14031
  " zk-agent workflow fund --wallet main",
14032
+ " zk-agent relay inspect --relay-url <url>",
12918
14033
  "",
12919
14034
  " Pass `--wallet` or `--chain` to retarget the entire suite contract.",
14035
+ " Pass `--include-onboarding` when you want setup, doctor, and wallet bootstrap",
14036
+ " guidance in the same packaged readout.",
12920
14037
  "",
12921
- " In JSON mode, `summary.useWhen`, `summary.recommendedOrder`, and each",
12922
- " entry `useWhen` field explain when to stay on one slice instead of guessing."
14038
+ " In JSON mode, `summary.catalogView`, `summary.entryModes`,",
14039
+ " `summary.startHereJourneyId`, `summary.journeyOrder`,",
14040
+ " `summary.surfaceOrder`, top-level `recommendedJourney`, top-level",
14041
+ " `journeys[]`, top-level `surfaces[]`, `summary.categoryOrder`,",
14042
+ " `summary.recommendedOrder`, optional `preflight`, and each entry",
14043
+ " `category` + `surface` + `surfaceCommand` + `useWhen` field explain",
14044
+ " which slice to choose and which deeper surface owns it next.",
14045
+ " `recommendedCommands.workflowSurface|discoverySurface|relaySurface`",
14046
+ " expose the direct deeper-surface entry commands."
12923
14047
  ].join("\n")
12924
14048
  ).action((options) => {
12925
14049
  const payload = buildOperatorSuitePayload({
12926
14050
  walletName: options.wallet,
12927
- chain: options.chain
14051
+ chain: options.chain,
14052
+ includeOnboarding: options.includeOnboarding
12928
14053
  });
12929
14054
  printResult(operatorSuiteLines(payload), payload);
12930
14055
  });
12931
14056
  }
12932
14057
 
12933
14058
  // src/commands/tokens.ts
12934
- import { Command as Command9 } from "commander";
14059
+ import { Command as Command10 } from "commander";
12935
14060
  var provider2 = new ZkSyncWalletProvider();
12936
14061
  function resolveTokensCommandDeps(deps) {
12937
14062
  return {
@@ -13061,7 +14186,7 @@ function buildTokenDiscoverySummary(result) {
13061
14186
  }
13062
14187
  function createTokensCommand(deps) {
13063
14188
  const resolvedDeps = resolveTokensCommandDeps(deps);
13064
- return new Command9("tokens").description("List discoverable tokens from the configured local-first token registry, or inspect the owned ERC-20 registry subset for one wallet").addHelpText(
14189
+ return new Command10("tokens").description("List discoverable tokens from the configured local-first token registry, or inspect the owned ERC-20 registry subset for one wallet").addHelpText(
13065
14190
  "after",
13066
14191
  [
13067
14192
  "",
@@ -13266,7 +14391,7 @@ function normalizeRole2(value) {
13266
14391
  }
13267
14392
 
13268
14393
  // src/commands/relay.ts
13269
- import { Command as Command10 } from "commander";
14394
+ import { Command as Command11 } from "commander";
13270
14395
 
13271
14396
  // src/lib/relay.ts
13272
14397
  import { createServer } from "node:http";
@@ -14131,14 +15256,18 @@ function buildRelayInspectPayload(relayUrl, rawHealth) {
14131
15256
  };
14132
15257
  }
14133
15258
  function createRelayCommand() {
14134
- const relay = new Command10("relay").description(
15259
+ const relay = new Command11("relay").description(
14135
15260
  "Serve and inspect the single-host connector relay baseline for hosted approval"
14136
15261
  );
14137
15262
  relay.addHelpText(
14138
15263
  "after",
14139
15264
  [
14140
15265
  "",
14141
- " Hosted remote-approval path:",
15266
+ " Relay surface:",
15267
+ " Use this layer only when approval must happen through a publicly reachable hosted path.",
15268
+ " Keep `wallet create|reapprove --await-local` as the default baseline when the browser and terminal are colocated.",
15269
+ "",
15270
+ " Hosted remote-approval path today:",
14142
15271
  " zk-agent relay serve --public-origin https://relay.example.com",
14143
15272
  " zk-agent relay inspect --relay-url <url>",
14144
15273
  " zk-agent wallet create --relay-url <url> --wait-relay --prompt-code",
@@ -14150,9 +15279,6 @@ function createRelayCommand() {
14150
15279
  " one same-origin share-link + approval UI surface",
14151
15280
  " Do not assume multi-host or load-balanced durability.",
14152
15281
  "",
14153
- " Keep `wallet create|reapprove --await-local` as the default baseline when",
14154
- " the browser and terminal are colocated.",
14155
- "",
14156
15282
  " Use `relay inspect` before sending operators to a hosted share link so",
14157
15283
  " the public origin, connector UI, and hosted-readiness contract are visible."
14158
15284
  ].join("\n")
@@ -14392,7 +15518,7 @@ function createRelayCommand() {
14392
15518
  // src/commands/wallet.ts
14393
15519
  import { createServer as createServer2 } from "node:http";
14394
15520
  import { createInterface } from "node:readline/promises";
14395
- import { Command as Command11 } from "commander";
15521
+ import { Command as Command12 } from "commander";
14396
15522
 
14397
15523
  // ../account-profiles/src/profiles.ts
14398
15524
  import fs8 from "node:fs";
@@ -14977,8 +16103,9 @@ function stripSensitiveWalletRecord(wallet) {
14977
16103
  };
14978
16104
  }
14979
16105
  function sanitizeWalletRecord(wallet) {
16106
+ const { walletId: _walletId, ...rest } = stripSensitiveWalletRecord(wallet);
14980
16107
  return {
14981
- ...stripSensitiveWalletRecord(wallet),
16108
+ ...rest,
14982
16109
  sessionPayload: sanitizeSessionPayload(wallet.sessionPayload)
14983
16110
  };
14984
16111
  }
@@ -17059,62 +18186,62 @@ async function printBuiltinSmartAccountProfiles() {
17059
18186
  }
17060
18187
  function createWalletCommand(deps) {
17061
18188
  const resolvedDeps = resolveWalletCommandDeps(deps);
17062
- const wallet = new Command11("wallet").description(
18189
+ const wallet = new Command12("wallet").description(
17063
18190
  "Create, inspect, and recover local-first wallet sessions"
17064
18191
  );
17065
- const request = new Command11("request").description("Inspect and finalize pending wallet requests");
17066
- const signer = new Command11("signer").description(
18192
+ const request = new Command12("request").description("Inspect and finalize pending wallet requests");
18193
+ const signer = new Command12("signer").description(
17067
18194
  "Inspect and manage the stored local execution signer for a wallet"
17068
18195
  );
17069
- const smartAccount = new Command11("smart-account").description(
18196
+ const smartAccount = new Command12("smart-account").description(
17070
18197
  "Predict and deploy zkSync smart-account contracts from a supplied artifact or built-in profile"
17071
18198
  );
17072
- const sedLite = new Command11("sed-lite").description(
18199
+ const sedLite = new Command12("sed-lite").description(
17073
18200
  "Inspect and manage the SED modular smart-account profile"
17074
18201
  );
17075
- const nativeCapHook = new Command11("native-cap-hook").description(
18202
+ const nativeCapHook = new Command12("native-cap-hook").description(
17076
18203
  "Inspect and manage the first SED Lite validation-hook policy: native per-transaction spend caps"
17077
18204
  );
17078
- const targetAllowlistHook = new Command11("target-allowlist-hook").description(
18205
+ const targetAllowlistHook = new Command12("target-allowlist-hook").description(
17079
18206
  "Inspect and manage the SED Lite validation-hook policy that restricts transactions to an allowlisted target set"
17080
18207
  );
17081
- const selectorAllowlistHook = new Command11("selector-allowlist-hook").description(
18208
+ const selectorAllowlistHook = new Command12("selector-allowlist-hook").description(
17082
18209
  "Inspect and manage the SED Lite validation-hook policy that restricts contract calls to allowlisted target and selector pairs"
17083
18210
  );
17084
- const dailySpendLimit = new Command11("daily-spend-limit").description(
18211
+ const dailySpendLimit = new Command12("daily-spend-limit").description(
17085
18212
  "Read and update the native-token daily spend limit used by the built-in daily-spend-limit smart-account profile"
17086
18213
  );
17087
- const paymaster = new Command11("paymaster").description(
18214
+ const paymaster = new Command12("paymaster").description(
17088
18215
  "Manage saved paymaster defaults for stored wallets"
17089
18216
  );
17090
18217
  wallet.addHelpText(
17091
18218
  "after",
17092
18219
  [
17093
18220
  "",
17094
- "Local-first wallet path:",
17095
- " Use this layer when the blocker is specifically about wallet approval or signer state.",
17096
- " Otherwise start with `zk-agent next` or `zk-agent doctor`.",
18221
+ "Wallet surface:",
18222
+ " Use this layer when the blocker is specifically wallet approval, signer state, or session recovery.",
18223
+ " If the CLI still needs to decide whether the problem is setup, wallet readiness, or workflow continuation, start with `zk-agent next` or `zk-agent doctor`.",
17097
18224
  "",
17098
- " First bootstrap:",
18225
+ " First local-first bootstrap:",
17099
18226
  " zk-agent wallet create --await-local",
17100
18227
  " zk-agent next",
17101
18228
  "",
17102
- " Restore approval metadata for an existing wallet:",
18229
+ " Repair an existing wallet session:",
17103
18230
  " zk-agent wallet reapprove --name main --await-local",
17104
18231
  " zk-agent next",
17105
18232
  "",
17106
- " Attach a local signer when approval is still present:",
18233
+ " Repair signer-only local execution state:",
17107
18234
  " zk-agent wallet signer attach --name main --private-key <hex>",
17108
18235
  " zk-agent next",
17109
18236
  "",
17110
- " Wallet-layer inspection:",
18237
+ " Wallet-scoped diagnosis:",
17111
18238
  " zk-agent wallet status --name main",
17112
18239
  " zk-agent wallet next --name main",
17113
18240
  "",
17114
- " When wallet readiness is no longer the blocker and you want the packaged surface:",
18241
+ " Switch to the packaged catalog after wallet readiness:",
17115
18242
  " zk-agent suite",
17116
18243
  "",
17117
- " Hosted remote approval path:",
18244
+ " Hosted remote approval only when the browser is remote:",
17118
18245
  " zk-agent relay inspect --relay-url <url>",
17119
18246
  " zk-agent wallet create --relay-url <url> --wait-relay --prompt-code",
17120
18247
  " zk-agent wallet reapprove --name main --relay-url <url> --wait-relay --prompt-code",
@@ -17592,6 +18719,13 @@ function createWalletCommand(deps) {
17592
18719
  wallet.command("list").description("List stored wallets").action(async () => printWalletList());
17593
18720
  wallet.command("rename").description("Rename a stored wallet and update any local pending requests that reference it").option("--name <name>", "Current wallet name", "main").requiredOption("--new-name <name>", "New wallet name").action(async (options) => {
17594
18721
  const result = await renameWalletSession(options.name, options.newName);
18722
+ const updatedPaymentRequestIds = await renamePaymentRequestWalletReferences(
18723
+ {
18724
+ walletId: result.wallet.walletId,
18725
+ previousWalletName: options.name,
18726
+ nextWalletName: options.newName
18727
+ }
18728
+ );
17595
18729
  printResult(
17596
18730
  [
17597
18731
  ["status", "Wallet renamed"],
@@ -17599,6 +18733,7 @@ function createWalletCommand(deps) {
17599
18733
  ["to", result.wallet.walletName],
17600
18734
  ["address", result.wallet.walletAddress],
17601
18735
  ["requests updated", String(result.updatedRequestIds.length)],
18736
+ ["payment requests updated", String(updatedPaymentRequestIds.length)],
17602
18737
  ["workflow checkpoints updated", String(result.updatedWorkflowRequestIds.length)],
17603
18738
  ...walletFollowUpLines(result.wallet)
17604
18739
  ],
@@ -17608,6 +18743,7 @@ function createWalletCommand(deps) {
17608
18743
  previousWalletName: options.name,
17609
18744
  wallet: sanitizeWalletRecord(result.wallet),
17610
18745
  updatedRequestIds: result.updatedRequestIds,
18746
+ updatedPaymentRequestIds,
17611
18747
  updatedWorkflowRequestIds: result.updatedWorkflowRequestIds,
17612
18748
  recommendedCommands: buildWalletFollowUpRecommendedCommands(result.wallet)
17613
18749
  }
@@ -17713,7 +18849,8 @@ function createWalletCommand(deps) {
17713
18849
  currentSurface: "wallet",
17714
18850
  recommendedNow: summary.status === "ready",
17715
18851
  walletName: walletRecord.walletName,
17716
- chain: summary.chain
18852
+ chain: summary.chain,
18853
+ recommendedJourneyId: summary.status === "ready" ? "send-value-now" : null
17717
18854
  });
17718
18855
  printResult(
17719
18856
  [
@@ -17756,7 +18893,8 @@ function createWalletCommand(deps) {
17756
18893
  currentSurface: "wallet",
17757
18894
  recommendedNow: summary.status === "ready",
17758
18895
  walletName: walletRecord.walletName,
17759
- chain: summary.chain
18896
+ chain: summary.chain,
18897
+ recommendedJourneyId: summary.status === "ready" ? "send-value-now" : null
17760
18898
  });
17761
18899
  printResult(
17762
18900
  [
@@ -19731,8 +20869,8 @@ function createWalletCommand(deps) {
19731
20869
  }
19732
20870
 
19733
20871
  // src/commands/workflow.ts
19734
- import { randomBytes as randomBytes4 } from "node:crypto";
19735
- import { Command as Command12 } from "commander";
20872
+ import { randomBytes as randomBytes6 } from "node:crypto";
20873
+ import { Command as Command13 } from "commander";
19736
20874
  var defaultProvider2 = new ZkSyncWalletProvider();
19737
20875
  var defaultDefiProvider2 = new ZkSyncDefiProvider({
19738
20876
  walletWriter: defaultProvider2
@@ -19799,7 +20937,7 @@ function parseBooleanString(value, label) {
19799
20937
  throw new Error(`${label} must be true or false`);
19800
20938
  }
19801
20939
  function generateWorkflowRequestId() {
19802
- return randomBytes4(4).toString("hex");
20940
+ return randomBytes6(4).toString("hex");
19803
20941
  }
19804
20942
  async function reserveWorkflowRequestId(requestId) {
19805
20943
  const explicit = requestId?.trim();
@@ -21438,25 +22576,26 @@ function assertWorkflowResumeReady(result) {
21438
22576
  function buildWorkflowHelpText() {
21439
22577
  return [
21440
22578
  "",
21441
- " Flagship native pay path:",
22579
+ " Workflow surface:",
22580
+ " Use this layer when the question is already an explicit workflow, checkpoint, or execution state.",
22581
+ " If the CLI still needs to choose across setup, wallet readiness, or recovery, go back to `zk-agent next` or `zk-agent doctor`.",
22582
+ "",
22583
+ " Fastest flagship pay path:",
21442
22584
  " zk-agent workflow pay --wallet main --to <address> --amount <amount>",
21443
22585
  "",
21444
- " Broader multi-intent guided path:",
22586
+ " Multi-intent guided path:",
21445
22587
  " zk-agent workflow auto --wallet main --intent <intent> [goal flags] --create-checkpoint --execute-when-ready",
21446
22588
  "",
21447
- " Checkpointed execution:",
22589
+ " Checkpoint lifecycle when you want explicit control:",
21448
22590
  " zk-agent workflow start --wallet main --intent <intent> [goal flags]",
21449
22591
  " zk-agent workflow status --request-id <id>",
21450
22592
  " zk-agent workflow next --request-id <id>",
21451
22593
  " zk-agent workflow resume --request-id <id> [--broadcast]",
21452
22594
  "",
21453
- " When the explicit workflow is no longer the real question and you want the broader packaged surface:",
21454
- " zk-agent suite",
21455
- "",
21456
- " Funding-only step:",
22595
+ " Funding-only recovery when execution is blocked on gas:",
21457
22596
  " zk-agent workflow fund --wallet main --amount <amount> --execute",
21458
22597
  "",
21459
- " Token/discovery recovery path:",
22598
+ " Discovery / token recovery before the workflow can continue:",
21460
22599
  " zk-agent assets --wallet main",
21461
22600
  " zk-agent tokens --wallet main --owned",
21462
22601
  " zk-agent tokens --chain zksync-sepolia",
@@ -21467,6 +22606,9 @@ function buildWorkflowHelpText() {
21467
22606
  " zk-agent resolve-token --chain zksync-sepolia --symbol <symbol> --role paymaster-fee-token",
21468
22607
  " zk-agent defaults",
21469
22608
  "",
22609
+ " When the question becomes broader than one explicit workflow:",
22610
+ " zk-agent suite",
22611
+ "",
21470
22612
  " Lower-level one-shot escape hatch:",
21471
22613
  " zk-agent workflow run --wallet main --intent <intent> [goal flags]"
21472
22614
  ].join("\n");
@@ -21501,7 +22643,7 @@ function applyWorkflowHelpCommandOrder(workflow) {
21501
22643
  }
21502
22644
  function createWorkflowCommand(deps) {
21503
22645
  const resolvedDeps = resolveWorkflowCommandDeps(deps);
21504
- const workflow = new Command12("workflow").description(
22646
+ const workflow = new Command13("workflow").description(
21505
22647
  "Plan, persist, and execute higher-level wallet workflows"
21506
22648
  );
21507
22649
  workflow.addHelpText("after", buildWorkflowHelpText());
@@ -22187,6 +23329,23 @@ function buildDefaultOperatorPathHelpText() {
22187
23329
  "",
22188
23330
  "Operator suite beyond flagship pay:",
22189
23331
  " zk-agent suite",
23332
+ " zk-agent suite --include-onboarding",
23333
+ "",
23334
+ "First local Agent Pay primitive:",
23335
+ " zk-agent payment create --wallet main --to <address> --amount <amount>",
23336
+ " zk-agent payment list",
23337
+ "",
23338
+ "Product routing by operator question:",
23339
+ " next -> bootstrap | recover | operate | workflow",
23340
+ " suite -> operate | discover | pay | fund | recover",
23341
+ "",
23342
+ "Payment-first default path after wallet readiness:",
23343
+ " send native value now -> stay on approval-based pay when fee-token/default state matters -> recover funding only when blocked",
23344
+ " Default start inside suite: send value now",
23345
+ "",
23346
+ "Use `next` while the CLI still needs to choose across setup, wallet readiness, or stored workflow continuation.",
23347
+ "Use `suite` once wallet readiness is no longer the blocker and you want the packaged post-flagship surface.",
23348
+ "Use `zk-agent suite --include-onboarding` when you want one readout from first-run bootstrap through the packaged operator catalog.",
22190
23349
  "",
22191
23350
  "Validated first-run baseline:",
22192
23351
  " setup defaults to zksync-sepolia and the local connector at http://localhost:4444",
@@ -22211,6 +23370,7 @@ var ROOT_HELP_COMMAND_ORDER = [
22211
23370
  "wallet",
22212
23371
  "workflow",
22213
23372
  "suite",
23373
+ "payment",
22214
23374
  "assets",
22215
23375
  "balances",
22216
23376
  "fund",
@@ -22244,7 +23404,7 @@ function applyRootHelpCommandOrder(program) {
22244
23404
  program.commands = sortedCommands;
22245
23405
  }
22246
23406
  function createProgram() {
22247
- const program = new Command13().name("zk-agent").description(
23407
+ const program = new Command14().name("zk-agent").description(
22248
23408
  "Local-first zkSync-native CLI for wallet approval, workflow execution, and single-host hosted relay recovery"
22249
23409
  ).showHelpAfterError().option("--json", "Force JSON output for agent harnesses", false).hook("preAction", (thisCommand) => {
22250
23410
  if (thisCommand.optsWithGlobals().json) process.env.ZK_AGENT_OUTPUT = "json";
@@ -22255,6 +23415,7 @@ function createProgram() {
22255
23415
  program.addCommand(createAgentCommand());
22256
23416
  program.addCommand(createDefaultsCommand());
22257
23417
  program.addCommand(createSuiteCommand());
23418
+ program.addCommand(createPaymentCommand());
22258
23419
  program.addCommand(createTokensCommand());
22259
23420
  program.addCommand(createResolveTokenCommand());
22260
23421
  program.addCommand(createRelayCommand());