zk-agent-cli 0.1.0-rc.3 → 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 +16 -0
  2. package/dist/index.js +765 -68
  3. package/package.json +2 -1
package/README.md CHANGED
@@ -34,6 +34,18 @@ What each step is doing:
34
34
  - `workflow pay` is the flagship zkSync-native AA native-send path
35
35
  - `suite` is the packaged surface
36
36
 
37
+ The packaged default story is payment-first: send native value now, stay on
38
+ the approval-based pay path when fee-token/default state matters, and recover
39
+ funding only when the workflow says the write path is blocked.
40
+
41
+ The first Agent Pay platform primitive now exists as a local-first payment
42
+ request surface:
43
+
44
+ ```bash
45
+ zk-agent payment create --wallet main --to <address> --amount <amount>
46
+ zk-agent payment list
47
+ ```
48
+
37
49
  If readiness is unclear before you choose a fix, use:
38
50
 
39
51
  ```bash
@@ -116,6 +128,7 @@ ZK_AGENT_STORAGE_DIR=
116
128
  `zk-agent wallet next --name <wallet>`: wallet-scoped repair and readiness
117
129
  - `zk-agent workflow ...`: explicit workflow planning, persistence, status, and
118
130
  resume questions
131
+ - `zk-agent payment ...`: local-first payment request capture and settlement-state tracking for the Agent Pay platform layer
119
132
  - `zk-agent suite`: the packaged post-flagship catalog once wallet readiness is
120
133
  no longer the blocker
121
134
 
@@ -225,6 +238,9 @@ Current `suite` operator journeys:
225
238
  - `unstick a write`
226
239
  - `recover remote approval`
227
240
 
241
+ If you only need one default starting point inside `suite`, start with
242
+ `send value now`.
243
+
228
244
  Use `--wallet <name>` or `--chain <chain>` when the returned suite commands
229
245
  should stay on a non-default wallet or chain.
230
246
 
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);
@@ -8000,6 +8022,37 @@ function buildWorkflowPayRecommendedCommand(walletName, paymasterMode) {
8000
8022
  const command = `zk-agent workflow pay --wallet ${walletName} --to <address> --amount <amount>`;
8001
8023
  return appendPaymasterMode(command, paymasterMode);
8002
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
+ }
8003
8056
  function buildWorkflowFundRecommendedCommand(walletName) {
8004
8057
  return `zk-agent workflow fund --wallet ${walletName}`;
8005
8058
  }
@@ -12838,8 +12891,615 @@ function createDefaultsCommand() {
12838
12891
  });
12839
12892
  }
12840
12893
 
12841
- // src/commands/resolve-token.ts
12894
+ // src/commands/payment.ts
12895
+ import { randomBytes as randomBytes5 } from "node:crypto";
12842
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";
12843
13503
  function resolveResolveTokenCommandDeps(deps) {
12844
13504
  return {
12845
13505
  loadWallet: deps?.loadWallet ?? (async (walletName) => {
@@ -12897,7 +13557,7 @@ function buildResolveTokenDiscoverySummary(result) {
12897
13557
  }
12898
13558
  function createResolveTokenCommand(deps) {
12899
13559
  const resolvedDeps = resolveResolveTokenCommandDeps(deps);
12900
- 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(
12901
13561
  "after",
12902
13562
  [
12903
13563
  "",
@@ -13031,7 +13691,7 @@ function normalizeSource(value) {
13031
13691
  }
13032
13692
 
13033
13693
  // src/commands/suite.ts
13034
- import { Command as Command8 } from "commander";
13694
+ import { Command as Command9 } from "commander";
13035
13695
 
13036
13696
  // src/lib/operator-suite.ts
13037
13697
  function buildOperatorSuitePayload(options = {}) {
@@ -13219,6 +13879,13 @@ function buildOperatorSuitePayload(options = {}) {
13219
13879
  entryIds: ["hosted-approval-recovery"]
13220
13880
  }
13221
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
+ };
13222
13889
  return {
13223
13890
  ok: true,
13224
13891
  summary: {
@@ -13229,6 +13896,7 @@ function buildOperatorSuitePayload(options = {}) {
13229
13896
  stage: "wallet-ready-post-flagship",
13230
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.",
13231
13898
  entryModes: ["local-first", "hosted-recovery"],
13899
+ startHereJourneyId: recommendedJourney.id,
13232
13900
  journeyOrder: journeys.map((entry) => entry.id),
13233
13901
  surfaceOrder: ["workflow", "discovery", "relay"],
13234
13902
  categoryOrder: [flagship.category, ...slices.map((entry) => entry.category)],
@@ -13238,6 +13906,7 @@ function buildOperatorSuitePayload(options = {}) {
13238
13906
  nextAction: flagship.primaryCommand
13239
13907
  },
13240
13908
  ...preflight ? { preflight } : {},
13909
+ recommendedJourney,
13241
13910
  journeys,
13242
13911
  surfaces,
13243
13912
  flagship,
@@ -13294,6 +13963,10 @@ function operatorSuiteLines(payload) {
13294
13963
  ["stage", payload.summary.stage],
13295
13964
  ["use when", payload.summary.useWhen],
13296
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],
13297
13970
  ["journey order", payload.summary.journeyOrder.join(" -> ")],
13298
13971
  ["surface order", payload.summary.surfaceOrder.join(" -> ")],
13299
13972
  ["category order", payload.summary.categoryOrder.join(" -> ")],
@@ -13320,7 +13993,7 @@ function operatorSuiteLines(payload) {
13320
13993
 
13321
13994
  // src/commands/suite.ts
13322
13995
  function createSuiteCommand() {
13323
- 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").option("--include-onboarding", "Include the first-run preflight and wallet-bootstrap map", false).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(
13324
13997
  "after",
13325
13998
  [
13326
13999
  "",
@@ -13340,6 +14013,9 @@ function createSuiteCommand() {
13340
14013
  " unstick a write: recover paymaster/funding readiness on the workflow path",
13341
14014
  " recover remote approval: move approval to the hosted relay path",
13342
14015
  "",
14016
+ " If you only need one default starting point inside suite:",
14017
+ " send value now",
14018
+ "",
13343
14019
  " Where `suite` hands you off next:",
13344
14020
  " workflow: flagship pay, approval-based pay, and funding recovery",
13345
14021
  " discovery: assets, defaults, and token inspection",
@@ -13360,11 +14036,12 @@ function createSuiteCommand() {
13360
14036
  " guidance in the same packaged readout.",
13361
14037
  "",
13362
14038
  " In JSON mode, `summary.catalogView`, `summary.entryModes`,",
13363
- " `summary.journeyOrder`, `summary.surfaceOrder`, top-level `journeys[]`,",
13364
- " top-level `surfaces[]`, `summary.categoryOrder`, `summary.recommendedOrder`,",
13365
- " optional `preflight`, and each entry `category` + `surface` +",
13366
- " `surfaceCommand` + `useWhen` field explain which slice to choose",
13367
- " and which deeper surface owns it next.",
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.",
13368
14045
  " `recommendedCommands.workflowSurface|discoverySurface|relaySurface`",
13369
14046
  " expose the direct deeper-surface entry commands."
13370
14047
  ].join("\n")
@@ -13379,7 +14056,7 @@ function createSuiteCommand() {
13379
14056
  }
13380
14057
 
13381
14058
  // src/commands/tokens.ts
13382
- import { Command as Command9 } from "commander";
14059
+ import { Command as Command10 } from "commander";
13383
14060
  var provider2 = new ZkSyncWalletProvider();
13384
14061
  function resolveTokensCommandDeps(deps) {
13385
14062
  return {
@@ -13509,7 +14186,7 @@ function buildTokenDiscoverySummary(result) {
13509
14186
  }
13510
14187
  function createTokensCommand(deps) {
13511
14188
  const resolvedDeps = resolveTokensCommandDeps(deps);
13512
- 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(
13513
14190
  "after",
13514
14191
  [
13515
14192
  "",
@@ -13714,7 +14391,7 @@ function normalizeRole2(value) {
13714
14391
  }
13715
14392
 
13716
14393
  // src/commands/relay.ts
13717
- import { Command as Command10 } from "commander";
14394
+ import { Command as Command11 } from "commander";
13718
14395
 
13719
14396
  // src/lib/relay.ts
13720
14397
  import { createServer } from "node:http";
@@ -14579,7 +15256,7 @@ function buildRelayInspectPayload(relayUrl, rawHealth) {
14579
15256
  };
14580
15257
  }
14581
15258
  function createRelayCommand() {
14582
- const relay = new Command10("relay").description(
15259
+ const relay = new Command11("relay").description(
14583
15260
  "Serve and inspect the single-host connector relay baseline for hosted approval"
14584
15261
  );
14585
15262
  relay.addHelpText(
@@ -14841,7 +15518,7 @@ function createRelayCommand() {
14841
15518
  // src/commands/wallet.ts
14842
15519
  import { createServer as createServer2 } from "node:http";
14843
15520
  import { createInterface } from "node:readline/promises";
14844
- import { Command as Command11 } from "commander";
15521
+ import { Command as Command12 } from "commander";
14845
15522
 
14846
15523
  // ../account-profiles/src/profiles.ts
14847
15524
  import fs8 from "node:fs";
@@ -15426,8 +16103,9 @@ function stripSensitiveWalletRecord(wallet) {
15426
16103
  };
15427
16104
  }
15428
16105
  function sanitizeWalletRecord(wallet) {
16106
+ const { walletId: _walletId, ...rest } = stripSensitiveWalletRecord(wallet);
15429
16107
  return {
15430
- ...stripSensitiveWalletRecord(wallet),
16108
+ ...rest,
15431
16109
  sessionPayload: sanitizeSessionPayload(wallet.sessionPayload)
15432
16110
  };
15433
16111
  }
@@ -17508,32 +18186,32 @@ async function printBuiltinSmartAccountProfiles() {
17508
18186
  }
17509
18187
  function createWalletCommand(deps) {
17510
18188
  const resolvedDeps = resolveWalletCommandDeps(deps);
17511
- const wallet = new Command11("wallet").description(
18189
+ const wallet = new Command12("wallet").description(
17512
18190
  "Create, inspect, and recover local-first wallet sessions"
17513
18191
  );
17514
- const request = new Command11("request").description("Inspect and finalize pending wallet requests");
17515
- 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(
17516
18194
  "Inspect and manage the stored local execution signer for a wallet"
17517
18195
  );
17518
- const smartAccount = new Command11("smart-account").description(
18196
+ const smartAccount = new Command12("smart-account").description(
17519
18197
  "Predict and deploy zkSync smart-account contracts from a supplied artifact or built-in profile"
17520
18198
  );
17521
- const sedLite = new Command11("sed-lite").description(
18199
+ const sedLite = new Command12("sed-lite").description(
17522
18200
  "Inspect and manage the SED modular smart-account profile"
17523
18201
  );
17524
- const nativeCapHook = new Command11("native-cap-hook").description(
18202
+ const nativeCapHook = new Command12("native-cap-hook").description(
17525
18203
  "Inspect and manage the first SED Lite validation-hook policy: native per-transaction spend caps"
17526
18204
  );
17527
- const targetAllowlistHook = new Command11("target-allowlist-hook").description(
18205
+ const targetAllowlistHook = new Command12("target-allowlist-hook").description(
17528
18206
  "Inspect and manage the SED Lite validation-hook policy that restricts transactions to an allowlisted target set"
17529
18207
  );
17530
- const selectorAllowlistHook = new Command11("selector-allowlist-hook").description(
18208
+ const selectorAllowlistHook = new Command12("selector-allowlist-hook").description(
17531
18209
  "Inspect and manage the SED Lite validation-hook policy that restricts contract calls to allowlisted target and selector pairs"
17532
18210
  );
17533
- const dailySpendLimit = new Command11("daily-spend-limit").description(
18211
+ const dailySpendLimit = new Command12("daily-spend-limit").description(
17534
18212
  "Read and update the native-token daily spend limit used by the built-in daily-spend-limit smart-account profile"
17535
18213
  );
17536
- const paymaster = new Command11("paymaster").description(
18214
+ const paymaster = new Command12("paymaster").description(
17537
18215
  "Manage saved paymaster defaults for stored wallets"
17538
18216
  );
17539
18217
  wallet.addHelpText(
@@ -18041,6 +18719,13 @@ function createWalletCommand(deps) {
18041
18719
  wallet.command("list").description("List stored wallets").action(async () => printWalletList());
18042
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) => {
18043
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
+ );
18044
18729
  printResult(
18045
18730
  [
18046
18731
  ["status", "Wallet renamed"],
@@ -18048,6 +18733,7 @@ function createWalletCommand(deps) {
18048
18733
  ["to", result.wallet.walletName],
18049
18734
  ["address", result.wallet.walletAddress],
18050
18735
  ["requests updated", String(result.updatedRequestIds.length)],
18736
+ ["payment requests updated", String(updatedPaymentRequestIds.length)],
18051
18737
  ["workflow checkpoints updated", String(result.updatedWorkflowRequestIds.length)],
18052
18738
  ...walletFollowUpLines(result.wallet)
18053
18739
  ],
@@ -18057,6 +18743,7 @@ function createWalletCommand(deps) {
18057
18743
  previousWalletName: options.name,
18058
18744
  wallet: sanitizeWalletRecord(result.wallet),
18059
18745
  updatedRequestIds: result.updatedRequestIds,
18746
+ updatedPaymentRequestIds,
18060
18747
  updatedWorkflowRequestIds: result.updatedWorkflowRequestIds,
18061
18748
  recommendedCommands: buildWalletFollowUpRecommendedCommands(result.wallet)
18062
18749
  }
@@ -20182,8 +20869,8 @@ function createWalletCommand(deps) {
20182
20869
  }
20183
20870
 
20184
20871
  // src/commands/workflow.ts
20185
- import { randomBytes as randomBytes4 } from "node:crypto";
20186
- import { Command as Command12 } from "commander";
20872
+ import { randomBytes as randomBytes6 } from "node:crypto";
20873
+ import { Command as Command13 } from "commander";
20187
20874
  var defaultProvider2 = new ZkSyncWalletProvider();
20188
20875
  var defaultDefiProvider2 = new ZkSyncDefiProvider({
20189
20876
  walletWriter: defaultProvider2
@@ -20250,7 +20937,7 @@ function parseBooleanString(value, label) {
20250
20937
  throw new Error(`${label} must be true or false`);
20251
20938
  }
20252
20939
  function generateWorkflowRequestId() {
20253
- return randomBytes4(4).toString("hex");
20940
+ return randomBytes6(4).toString("hex");
20254
20941
  }
20255
20942
  async function reserveWorkflowRequestId(requestId) {
20256
20943
  const explicit = requestId?.trim();
@@ -21956,7 +22643,7 @@ function applyWorkflowHelpCommandOrder(workflow) {
21956
22643
  }
21957
22644
  function createWorkflowCommand(deps) {
21958
22645
  const resolvedDeps = resolveWorkflowCommandDeps(deps);
21959
- const workflow = new Command12("workflow").description(
22646
+ const workflow = new Command13("workflow").description(
21960
22647
  "Plan, persist, and execute higher-level wallet workflows"
21961
22648
  );
21962
22649
  workflow.addHelpText("after", buildWorkflowHelpText());
@@ -22644,10 +23331,18 @@ function buildDefaultOperatorPathHelpText() {
22644
23331
  " zk-agent suite",
22645
23332
  " zk-agent suite --include-onboarding",
22646
23333
  "",
23334
+ "First local Agent Pay primitive:",
23335
+ " zk-agent payment create --wallet main --to <address> --amount <amount>",
23336
+ " zk-agent payment list",
23337
+ "",
22647
23338
  "Product routing by operator question:",
22648
23339
  " next -> bootstrap | recover | operate | workflow",
22649
23340
  " suite -> operate | discover | pay | fund | recover",
22650
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
+ "",
22651
23346
  "Use `next` while the CLI still needs to choose across setup, wallet readiness, or stored workflow continuation.",
22652
23347
  "Use `suite` once wallet readiness is no longer the blocker and you want the packaged post-flagship surface.",
22653
23348
  "Use `zk-agent suite --include-onboarding` when you want one readout from first-run bootstrap through the packaged operator catalog.",
@@ -22675,6 +23370,7 @@ var ROOT_HELP_COMMAND_ORDER = [
22675
23370
  "wallet",
22676
23371
  "workflow",
22677
23372
  "suite",
23373
+ "payment",
22678
23374
  "assets",
22679
23375
  "balances",
22680
23376
  "fund",
@@ -22708,7 +23404,7 @@ function applyRootHelpCommandOrder(program) {
22708
23404
  program.commands = sortedCommands;
22709
23405
  }
22710
23406
  function createProgram() {
22711
- const program = new Command13().name("zk-agent").description(
23407
+ const program = new Command14().name("zk-agent").description(
22712
23408
  "Local-first zkSync-native CLI for wallet approval, workflow execution, and single-host hosted relay recovery"
22713
23409
  ).showHelpAfterError().option("--json", "Force JSON output for agent harnesses", false).hook("preAction", (thisCommand) => {
22714
23410
  if (thisCommand.optsWithGlobals().json) process.env.ZK_AGENT_OUTPUT = "json";
@@ -22719,6 +23415,7 @@ function createProgram() {
22719
23415
  program.addCommand(createAgentCommand());
22720
23416
  program.addCommand(createDefaultsCommand());
22721
23417
  program.addCommand(createSuiteCommand());
23418
+ program.addCommand(createPaymentCommand());
22722
23419
  program.addCommand(createTokensCommand());
22723
23420
  program.addCommand(createResolveTokenCommand());
22724
23421
  program.addCommand(createRelayCommand());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zk-agent-cli",
3
- "version": "0.1.0-rc.3",
3
+ "version": "0.1.0-rc.4",
4
4
  "description": "Local-first zkSync Era and ZK Stack agent CLI with wallet session recovery, workflow orchestration, relay-backed approval, and SED smart-account support.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -67,6 +67,7 @@
67
67
  "devDependencies": {
68
68
  "@zk-agent/account-profiles": "workspace:*",
69
69
  "@zk-agent/agent-core": "workspace:*",
70
+ "@zk-agent/agent-pay": "workspace:*",
70
71
  "@zk-agent/agent-session-protocol": "workspace:*",
71
72
  "@zk-agent/plugin-identity": "workspace:*",
72
73
  "@zk-agent/provider-zksync-defi": "workspace:*",