zk-agent-cli 0.1.0-beta.6 → 0.1.0-beta.8
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.
- package/README.md +89 -4
- package/dist/connector-ui/assets/index-B7BdrG9K.js +40 -0
- package/dist/connector-ui/index.html +1 -1
- package/dist/index.js +1000 -115
- package/package.json +1 -1
- package/dist/connector-ui/assets/index-8Wcy2mMo.js +0 -40
package/dist/index.js
CHANGED
|
@@ -7722,6 +7722,10 @@ function formatHumanErrorMessage(error) {
|
|
|
7722
7722
|
pushDetailLine(lines, "reason", details.reason);
|
|
7723
7723
|
pushDetailLine(lines, "note", details.note);
|
|
7724
7724
|
pushDetailLine(lines, "suggested action", details.suggestedAction);
|
|
7725
|
+
pushDetailLine(lines, "status command", details.statusCommand);
|
|
7726
|
+
pushDetailLine(lines, "approve command", details.approveCommand);
|
|
7727
|
+
pushDetailLine(lines, "relay inspect command", details.relayInspectCommand);
|
|
7728
|
+
pushDetailLine(lines, "reissue remote approval command", details.reissueRemoteApprovalCommand);
|
|
7725
7729
|
pushDetailLine(lines, "validation domain", details.validationDomain);
|
|
7726
7730
|
pushDetailLine(lines, "validation stage", details.validationStage);
|
|
7727
7731
|
const validation = asRecord2(details.validation);
|
|
@@ -7758,6 +7762,18 @@ function buildTopLevelNextRecommendedCommand(requestId, paymasterMode) {
|
|
|
7758
7762
|
function buildWalletCreateRecommendedCommand() {
|
|
7759
7763
|
return "zk-agent wallet create --await-local";
|
|
7760
7764
|
}
|
|
7765
|
+
function buildRelayInspectRecommendedCommand(relayUrl = "<url>") {
|
|
7766
|
+
return `zk-agent relay inspect --relay-url ${relayUrl}`;
|
|
7767
|
+
}
|
|
7768
|
+
function buildWalletCreateRemoteRecommendedCommand(relayUrl = "<url>", paymasterMode, walletName = "main", accountKind = "smart-account") {
|
|
7769
|
+
const command = [
|
|
7770
|
+
"zk-agent wallet create",
|
|
7771
|
+
walletName !== "main" ? `--name ${walletName}` : "",
|
|
7772
|
+
accountKind !== "smart-account" ? `--account-kind ${accountKind}` : "",
|
|
7773
|
+
`--relay-url ${relayUrl} --wait-relay --prompt-code`
|
|
7774
|
+
].filter(Boolean).join(" ");
|
|
7775
|
+
return appendPaymasterMode(command, paymasterMode);
|
|
7776
|
+
}
|
|
7761
7777
|
function buildWalletListRecommendedCommand() {
|
|
7762
7778
|
return "zk-agent wallet list";
|
|
7763
7779
|
}
|
|
@@ -7784,6 +7800,12 @@ function buildResolveTokenRecommendedCommand(chain, symbol, role, source) {
|
|
|
7784
7800
|
const withRole = role ? `${command} --role ${role}` : command;
|
|
7785
7801
|
return source ? `${withRole} --source ${source}` : withRole;
|
|
7786
7802
|
}
|
|
7803
|
+
function buildPaymasterFeeTokensRecommendedCommand(chain) {
|
|
7804
|
+
return buildTokensRecommendedCommand(chain, void 0, "paymaster-fee-token");
|
|
7805
|
+
}
|
|
7806
|
+
function buildPaymasterFeeTokenResolveRecommendedCommand(chain, symbol) {
|
|
7807
|
+
return buildResolveTokenRecommendedCommand(chain, symbol, "paymaster-fee-token");
|
|
7808
|
+
}
|
|
7787
7809
|
function buildDiscoveryRecommendedCommands(input) {
|
|
7788
7810
|
return {
|
|
7789
7811
|
inspectDefaults: buildDefaultsRecommendedCommand(),
|
|
@@ -7814,6 +7836,9 @@ function buildDiscoveryRecommendedCommands(input) {
|
|
|
7814
7836
|
function buildWalletReapproveRecommendedCommand(walletName) {
|
|
7815
7837
|
return `zk-agent wallet reapprove --name ${walletName} --await-local`;
|
|
7816
7838
|
}
|
|
7839
|
+
function buildWalletReapproveRemoteRecommendedCommand(walletName, relayUrl = "<url>") {
|
|
7840
|
+
return `zk-agent wallet reapprove --name ${walletName} --relay-url ${relayUrl} --wait-relay --prompt-code`;
|
|
7841
|
+
}
|
|
7817
7842
|
function buildWalletNextRecommendedCommand(walletName) {
|
|
7818
7843
|
return `zk-agent wallet next --name ${walletName}`;
|
|
7819
7844
|
}
|
|
@@ -8507,9 +8532,15 @@ function workflowFollowupLines(recommendedCommands) {
|
|
|
8507
8532
|
if (recommendedCommands.discoverOwnedTokens) {
|
|
8508
8533
|
lines.push(["discover owned tokens", recommendedCommands.discoverOwnedTokens]);
|
|
8509
8534
|
}
|
|
8535
|
+
if (recommendedCommands.discoverPaymasterTokens) {
|
|
8536
|
+
lines.push(["discover paymaster tokens", recommendedCommands.discoverPaymasterTokens]);
|
|
8537
|
+
}
|
|
8510
8538
|
if (recommendedCommands.discoverTokens) {
|
|
8511
8539
|
lines.push(["discover tokens", recommendedCommands.discoverTokens]);
|
|
8512
8540
|
}
|
|
8541
|
+
if (recommendedCommands.inspectPaymasterToken) {
|
|
8542
|
+
lines.push(["inspect paymaster token", recommendedCommands.inspectPaymasterToken]);
|
|
8543
|
+
}
|
|
8513
8544
|
if (recommendedCommands.inspectToken) {
|
|
8514
8545
|
lines.push(["inspect token", recommendedCommands.inspectToken]);
|
|
8515
8546
|
}
|
|
@@ -9214,7 +9245,25 @@ function createBalancesCommand(deps) {
|
|
|
9214
9245
|
}
|
|
9215
9246
|
function createAssetsCommand(deps) {
|
|
9216
9247
|
const resolvedDeps = resolveBalancesCommandDeps(deps);
|
|
9217
|
-
return new Command("assets").description("Fetch the preferred single-chain asset view with native balance plus registry-backed ERC-20 holdings").
|
|
9248
|
+
return new Command("assets").description("Fetch the preferred single-chain asset view with native balance plus registry-backed ERC-20 holdings").addHelpText(
|
|
9249
|
+
"after",
|
|
9250
|
+
[
|
|
9251
|
+
"",
|
|
9252
|
+
"Discovery asset path:",
|
|
9253
|
+
" Preferred single-chain asset entrypoint:",
|
|
9254
|
+
" zk-agent assets --wallet main",
|
|
9255
|
+
"",
|
|
9256
|
+
" Narrower owned ERC-20 registry subset:",
|
|
9257
|
+
" zk-agent tokens --wallet main --owned",
|
|
9258
|
+
"",
|
|
9259
|
+
" Symbol-first token lookup before a tokenized command:",
|
|
9260
|
+
" zk-agent tokens --chain zksync-sepolia --symbol USDC",
|
|
9261
|
+
" zk-agent resolve-token --chain zksync-sepolia --symbol USDC",
|
|
9262
|
+
"",
|
|
9263
|
+
" For the machine-readable registry/default catalog:",
|
|
9264
|
+
" zk-agent defaults"
|
|
9265
|
+
].join("\n")
|
|
9266
|
+
).option("--wallet <name>", "Wallet name", "main").option("--chain <chain>", "Single chain override").action(async (options) => {
|
|
9218
9267
|
const walletName = options.wallet;
|
|
9219
9268
|
const wallet = await resolvedDeps.loadWallet(walletName);
|
|
9220
9269
|
if (!wallet) throw new Error(`Wallet not found: ${walletName}`);
|
|
@@ -9912,11 +9961,35 @@ function createPlannedCommands() {
|
|
|
9912
9961
|
|
|
9913
9962
|
// src/commands/setup.ts
|
|
9914
9963
|
import { Command as Command2 } from "commander";
|
|
9964
|
+
function buildSetupHelpText() {
|
|
9965
|
+
return [
|
|
9966
|
+
"",
|
|
9967
|
+
"What setup does:",
|
|
9968
|
+
" Writes the local default chain and connector URL used by the first-run path.",
|
|
9969
|
+
"",
|
|
9970
|
+
"After setup, stay on the canonical local-first path:",
|
|
9971
|
+
" zk-agent next",
|
|
9972
|
+
" zk-agent wallet create --await-local",
|
|
9973
|
+
" zk-agent next",
|
|
9974
|
+
"",
|
|
9975
|
+
"If the browser is not colocated with this terminal, switch at the wallet step:",
|
|
9976
|
+
" zk-agent relay inspect --relay-url <url>",
|
|
9977
|
+
" zk-agent wallet create --relay-url <url> --wait-relay --prompt-code",
|
|
9978
|
+
" zk-agent next",
|
|
9979
|
+
"",
|
|
9980
|
+
"Environment note:",
|
|
9981
|
+
" No custom .env is required for setup, next, or wallet request creation.",
|
|
9982
|
+
" Add RPC env vars later, before live reads or broadcasts."
|
|
9983
|
+
].join("\n");
|
|
9984
|
+
}
|
|
9915
9985
|
function createInitCommand() {
|
|
9916
|
-
return new Command2("init").alias("setup").description("Initialize local zk-agent configuration").option("--default-chain <chain>", "Default chain key", "zksync-era").option("--connector-url <url>", "Connector UI base URL", "http://localhost:4444").option("--force", "Overwrite an existing config", false).action(async (options) => {
|
|
9986
|
+
return new Command2("init").alias("setup").description("Initialize local zk-agent configuration for the default operator path").addHelpText("after", buildSetupHelpText()).option("--default-chain <chain>", "Default chain key", "zksync-era").option("--connector-url <url>", "Connector UI base URL", "http://localhost:4444").option("--force", "Overwrite an existing config", false).action(async (options) => {
|
|
9917
9987
|
const recommendedCommands = {
|
|
9988
|
+
next: buildTopLevelNextRecommendedCommand(),
|
|
9918
9989
|
inspectDefaults: buildDefaultsRecommendedCommand(),
|
|
9919
9990
|
createWallet: buildWalletCreateRecommendedCommand(),
|
|
9991
|
+
relayInspect: buildRelayInspectRecommendedCommand(),
|
|
9992
|
+
createWalletRemote: buildWalletCreateRemoteRecommendedCommand(),
|
|
9920
9993
|
afterWalletApproval: buildTopLevelNextRecommendedCommand()
|
|
9921
9994
|
};
|
|
9922
9995
|
const existing = await loadProjectConfig();
|
|
@@ -9926,8 +9999,11 @@ function createInitCommand() {
|
|
|
9926
9999
|
["status", "Config already exists. Re-run with --force to overwrite."],
|
|
9927
10000
|
["default chain", existing.defaultChain],
|
|
9928
10001
|
["connector", existing.connectorUrl],
|
|
10002
|
+
["next", recommendedCommands.next],
|
|
9929
10003
|
["inspect defaults", recommendedCommands.inspectDefaults],
|
|
9930
|
-
["create wallet", recommendedCommands.createWallet],
|
|
10004
|
+
["create wallet (local)", recommendedCommands.createWallet],
|
|
10005
|
+
["relay inspect", recommendedCommands.relayInspect],
|
|
10006
|
+
["create wallet (remote)", recommendedCommands.createWalletRemote],
|
|
9931
10007
|
["after approval", recommendedCommands.afterWalletApproval]
|
|
9932
10008
|
],
|
|
9933
10009
|
{
|
|
@@ -9952,8 +10028,11 @@ function createInitCommand() {
|
|
|
9952
10028
|
["status", "Config saved"],
|
|
9953
10029
|
["default chain", config.defaultChain],
|
|
9954
10030
|
["connector", config.connectorUrl],
|
|
10031
|
+
["next", recommendedCommands.next],
|
|
9955
10032
|
["inspect defaults", recommendedCommands.inspectDefaults],
|
|
9956
|
-
["create wallet", recommendedCommands.createWallet],
|
|
10033
|
+
["create wallet (local)", recommendedCommands.createWallet],
|
|
10034
|
+
["relay inspect", recommendedCommands.relayInspect],
|
|
10035
|
+
["create wallet (remote)", recommendedCommands.createWalletRemote],
|
|
9957
10036
|
["after approval", recommendedCommands.afterWalletApproval]
|
|
9958
10037
|
],
|
|
9959
10038
|
{ ok: true, config, recommendedCommands }
|
|
@@ -10383,9 +10462,17 @@ function buildTopLevelWorkflowRecommendedCommands(input) {
|
|
|
10383
10462
|
discoverOwnedTokens: buildOwnedTokensRecommendedCommand(input.walletName),
|
|
10384
10463
|
discoverTokens: buildTokensRecommendedCommand(input.chain),
|
|
10385
10464
|
inspectToken: buildResolveTokenRecommendedCommand(input.chain)
|
|
10465
|
+
} : {},
|
|
10466
|
+
...input.paymasterMode === "approval-based" ? {
|
|
10467
|
+
discoverPaymasterTokens: buildPaymasterFeeTokensRecommendedCommand(input.chain),
|
|
10468
|
+
inspectPaymasterToken: buildPaymasterFeeTokenResolveRecommendedCommand(input.chain)
|
|
10386
10469
|
} : {}
|
|
10387
10470
|
};
|
|
10388
10471
|
}
|
|
10472
|
+
function extractCheckpointPaymasterMode(checkpoint) {
|
|
10473
|
+
if (!("paymaster" in checkpoint.goal)) return void 0;
|
|
10474
|
+
return checkpoint.goal.paymaster?.mode;
|
|
10475
|
+
}
|
|
10389
10476
|
function resolveNextCommandDeps(deps) {
|
|
10390
10477
|
return {
|
|
10391
10478
|
provider: deps?.provider ?? defaultProvider,
|
|
@@ -10409,7 +10496,15 @@ function buildNextHelpText() {
|
|
|
10409
10496
|
return [
|
|
10410
10497
|
"",
|
|
10411
10498
|
"Use `next` as the product entrypoint:",
|
|
10412
|
-
" Fresh
|
|
10499
|
+
" Fresh local-first routing:",
|
|
10500
|
+
" zk-agent setup",
|
|
10501
|
+
" zk-agent next",
|
|
10502
|
+
" zk-agent wallet create --await-local",
|
|
10503
|
+
" zk-agent next",
|
|
10504
|
+
"",
|
|
10505
|
+
" If the browser is remote, switch at the wallet step instead of waiting for a local callback:",
|
|
10506
|
+
" zk-agent relay inspect --relay-url <url>",
|
|
10507
|
+
" zk-agent wallet create --relay-url <url> --wait-relay --prompt-code",
|
|
10413
10508
|
" zk-agent next",
|
|
10414
10509
|
"",
|
|
10415
10510
|
" Continue a stored workflow checkpoint:",
|
|
@@ -10418,6 +10513,9 @@ function buildNextHelpText() {
|
|
|
10418
10513
|
" Stay on the wallet layer only when you need wallet-specific remediation:",
|
|
10419
10514
|
" zk-agent wallet next --name main",
|
|
10420
10515
|
"",
|
|
10516
|
+
" Switch to the hosted remote-approval path only when the browser is not colocated:",
|
|
10517
|
+
" zk-agent wallet --help",
|
|
10518
|
+
"",
|
|
10421
10519
|
" Stay on the workflow layer only when you already have an explicit workflow or checkpoint:",
|
|
10422
10520
|
" zk-agent workflow next --request-id <id>"
|
|
10423
10521
|
].join("\n");
|
|
@@ -10464,7 +10562,8 @@ function createNextCommand(deps) {
|
|
|
10464
10562
|
walletName: wallet2.walletName,
|
|
10465
10563
|
nextAction: nextCommand2,
|
|
10466
10564
|
chain: result.plan.chain,
|
|
10467
|
-
intent: result.intent
|
|
10565
|
+
intent: result.intent,
|
|
10566
|
+
paymasterMode: extractCheckpointPaymasterMode(updatedCheckpoint)
|
|
10468
10567
|
});
|
|
10469
10568
|
const workflowAgentProfile = await loadAgentIdentitySummary(wallet2.walletName);
|
|
10470
10569
|
const agentFollowup2 = buildAgentFollowup(workflowAgentProfile, {
|
|
@@ -10509,6 +10608,7 @@ function createNextCommand(deps) {
|
|
|
10509
10608
|
if (!config) {
|
|
10510
10609
|
const recommendedCommands2 = {
|
|
10511
10610
|
setup: buildSetupCommand(),
|
|
10611
|
+
afterSetup: buildTopLevelNextRecommendedCommand2(),
|
|
10512
10612
|
inspectDefaults: buildDefaultsRecommendedCommand()
|
|
10513
10613
|
};
|
|
10514
10614
|
printResult(
|
|
@@ -10517,6 +10617,7 @@ function createNextCommand(deps) {
|
|
|
10517
10617
|
...agentProfileLines(agentProfile),
|
|
10518
10618
|
...agentFollowupLines(defaultAgentFollowup),
|
|
10519
10619
|
["next", recommendedCommands2.setup],
|
|
10620
|
+
["after setup", recommendedCommands2.afterSetup],
|
|
10520
10621
|
["inspect defaults", recommendedCommands2.inspectDefaults]
|
|
10521
10622
|
]),
|
|
10522
10623
|
{
|
|
@@ -10538,6 +10639,11 @@ function createNextCommand(deps) {
|
|
|
10538
10639
|
buildWalletCreateRecommendedCommand(),
|
|
10539
10640
|
paymasterMode
|
|
10540
10641
|
),
|
|
10642
|
+
relayInspect: buildRelayInspectRecommendedCommand(),
|
|
10643
|
+
createWalletRemote: buildWalletCreateRemoteRecommendedCommand(
|
|
10644
|
+
"<url>",
|
|
10645
|
+
paymasterMode
|
|
10646
|
+
),
|
|
10541
10647
|
afterApproval: appendPaymasterMode2(buildTopLevelNextRecommendedCommand2(), paymasterMode),
|
|
10542
10648
|
inspectDefaults: buildDefaultsRecommendedCommand()
|
|
10543
10649
|
};
|
|
@@ -10549,6 +10655,8 @@ function createNextCommand(deps) {
|
|
|
10549
10655
|
...agentProfileLines(agentProfile),
|
|
10550
10656
|
...agentFollowupLines(defaultAgentFollowup),
|
|
10551
10657
|
["next", recommendedCommands2.createWallet],
|
|
10658
|
+
["relay inspect", recommendedCommands2.relayInspect],
|
|
10659
|
+
["remote fallback", recommendedCommands2.createWalletRemote],
|
|
10552
10660
|
["after approval", recommendedCommands2.afterApproval],
|
|
10553
10661
|
["inspect defaults", recommendedCommands2.inspectDefaults]
|
|
10554
10662
|
]),
|
|
@@ -10602,6 +10710,10 @@ function createNextCommand(deps) {
|
|
|
10602
10710
|
walletStatus: buildWalletStatusRecommendedCommand(wallet.walletName),
|
|
10603
10711
|
discoverAssets: buildAssetsRecommendedCommand(wallet.walletName),
|
|
10604
10712
|
discoverOwnedTokens: buildOwnedTokensRecommendedCommand(wallet.walletName),
|
|
10713
|
+
...paymasterMode === "approval-based" ? {
|
|
10714
|
+
discoverPaymasterTokens: buildPaymasterFeeTokensRecommendedCommand(wallet.chain),
|
|
10715
|
+
inspectPaymasterToken: buildPaymasterFeeTokenResolveRecommendedCommand(wallet.chain)
|
|
10716
|
+
} : {},
|
|
10605
10717
|
discoverTokens: buildTokensRecommendedCommand(wallet.chain),
|
|
10606
10718
|
inspectToken: buildResolveTokenRecommendedCommand(wallet.chain),
|
|
10607
10719
|
workflowPay,
|
|
@@ -10617,7 +10729,9 @@ function createNextCommand(deps) {
|
|
|
10617
10729
|
...summary.recommendedCommand ? [] : [["next", workflowPay]],
|
|
10618
10730
|
["discover assets", recommendedCommands.discoverAssets],
|
|
10619
10731
|
["discover owned tokens", recommendedCommands.discoverOwnedTokens],
|
|
10732
|
+
...recommendedCommands.discoverPaymasterTokens ? [["discover paymaster tokens", recommendedCommands.discoverPaymasterTokens]] : [],
|
|
10620
10733
|
["discover tokens", recommendedCommands.discoverTokens],
|
|
10734
|
+
...recommendedCommands.inspectPaymasterToken ? [["inspect paymaster token", recommendedCommands.inspectPaymasterToken]] : [],
|
|
10621
10735
|
["inspect token", recommendedCommands.inspectToken],
|
|
10622
10736
|
["inspect defaults", recommendedCommands.inspectDefaults]
|
|
10623
10737
|
]),
|
|
@@ -10734,6 +10848,21 @@ function createAgentCommand() {
|
|
|
10734
10848
|
agent.addHelpText(
|
|
10735
10849
|
"after",
|
|
10736
10850
|
[
|
|
10851
|
+
"",
|
|
10852
|
+
" Agent identity path:",
|
|
10853
|
+
" zk-agent agent status",
|
|
10854
|
+
' zk-agent agent set --name "SED Operator" --wallet main',
|
|
10855
|
+
" zk-agent agent show",
|
|
10856
|
+
"",
|
|
10857
|
+
" Portable local profile management:",
|
|
10858
|
+
" zk-agent agent export",
|
|
10859
|
+
" zk-agent agent import --payload @agent-profile.json --overwrite",
|
|
10860
|
+
"",
|
|
10861
|
+
" Remove the saved local profile:",
|
|
10862
|
+
" zk-agent agent clear",
|
|
10863
|
+
"",
|
|
10864
|
+
" This profile is optional. Wallet approval and workflow execution still work",
|
|
10865
|
+
" without a saved local agent profile.",
|
|
10737
10866
|
"",
|
|
10738
10867
|
"Examples:",
|
|
10739
10868
|
" zk-agent agent status",
|
|
@@ -11380,7 +11509,24 @@ function buildDefaultsLines(input) {
|
|
|
11380
11509
|
return lines;
|
|
11381
11510
|
}
|
|
11382
11511
|
function createDefaultsCommand() {
|
|
11383
|
-
return new Command5("defaults").description("Show the machine-readable registry of supported, validated, experimental, and manually configured defaults").
|
|
11512
|
+
return new Command5("defaults").description("Show the machine-readable registry of supported, validated, experimental, and manually configured defaults").addHelpText(
|
|
11513
|
+
"after",
|
|
11514
|
+
[
|
|
11515
|
+
"",
|
|
11516
|
+
"Discovery defaults path:",
|
|
11517
|
+
" Use `defaults` as the machine-readable registry escape hatch for:",
|
|
11518
|
+
" - validated or fallback swap / bridge paths",
|
|
11519
|
+
" - tracked token roles and source order",
|
|
11520
|
+
" - paymaster defaults and supported modes",
|
|
11521
|
+
"",
|
|
11522
|
+
" For wallet-scoped asset discovery, prefer:",
|
|
11523
|
+
" zk-agent assets --wallet main",
|
|
11524
|
+
"",
|
|
11525
|
+
" For symbol-first token discovery, prefer:",
|
|
11526
|
+
" zk-agent tokens --chain zksync-sepolia",
|
|
11527
|
+
" zk-agent resolve-token --chain zksync-sepolia --symbol USDC"
|
|
11528
|
+
].join("\n")
|
|
11529
|
+
).action(async () => {
|
|
11384
11530
|
const defaults = loadValidatedDefaults();
|
|
11385
11531
|
const localTokenRegistry = listLocalTokenRegistryEntries();
|
|
11386
11532
|
const tokenRegistrySources = describeDefaultTokenRegistrySources();
|
|
@@ -11440,7 +11586,27 @@ async function resolveActiveChain(options, deps) {
|
|
|
11440
11586
|
}
|
|
11441
11587
|
function createResolveTokenCommand(deps) {
|
|
11442
11588
|
const resolvedDeps = resolveResolveTokenCommandDeps(deps);
|
|
11443
|
-
return new Command6("resolve-token").description("Resolve a token symbol or address against the configured local-first token registry").
|
|
11589
|
+
return new Command6("resolve-token").description("Resolve a token symbol or address against the configured local-first token registry").addHelpText(
|
|
11590
|
+
"after",
|
|
11591
|
+
[
|
|
11592
|
+
"",
|
|
11593
|
+
"Resolve-token path:",
|
|
11594
|
+
" Symbol-first resolution on one active chain:",
|
|
11595
|
+
" zk-agent resolve-token --chain zksync-sepolia --symbol USDC",
|
|
11596
|
+
"",
|
|
11597
|
+
" Use the stored wallet to infer the active chain:",
|
|
11598
|
+
" zk-agent resolve-token --wallet main --symbol USDC",
|
|
11599
|
+
"",
|
|
11600
|
+
" Use broader chain discovery before resolution when you still need the candidate set:",
|
|
11601
|
+
" zk-agent tokens --chain zksync-sepolia",
|
|
11602
|
+
"",
|
|
11603
|
+
" Use the wallet asset entrypoint when the real question is balances/holdings:",
|
|
11604
|
+
" zk-agent assets --wallet main",
|
|
11605
|
+
"",
|
|
11606
|
+
" Use the registry/default catalog when you need tracked roles or source order:",
|
|
11607
|
+
" zk-agent defaults"
|
|
11608
|
+
].join("\n")
|
|
11609
|
+
).option("--wallet <name>", "Optional stored wallet name to infer the active chain").option("--chain <chain>", "Chain key or chain id override").option("--symbol <symbol>", "Token symbol to resolve on the active chain").option("--address <address>", "Token address to inspect on the active chain").option(
|
|
11444
11610
|
"--role <role>",
|
|
11445
11611
|
`Optional defaults-registry role filter: ${REGISTRY_TOKEN_ROLES.join(", ")}`
|
|
11446
11612
|
).option(
|
|
@@ -11643,7 +11809,29 @@ function ownedTokenSummaryLines2(summary) {
|
|
|
11643
11809
|
}
|
|
11644
11810
|
function createTokensCommand(deps) {
|
|
11645
11811
|
const resolvedDeps = resolveTokensCommandDeps(deps);
|
|
11646
|
-
return new Command7("tokens").description("List discoverable tokens from the configured local-first token registry, or inspect the owned ERC-20 registry subset for one wallet").
|
|
11812
|
+
return new Command7("tokens").description("List discoverable tokens from the configured local-first token registry, or inspect the owned ERC-20 registry subset for one wallet").addHelpText(
|
|
11813
|
+
"after",
|
|
11814
|
+
[
|
|
11815
|
+
"",
|
|
11816
|
+
"Discovery token path:",
|
|
11817
|
+
" Start with the preferred wallet asset view when you need balances plus tracked ERC-20 holdings:",
|
|
11818
|
+
" zk-agent assets --wallet main",
|
|
11819
|
+
"",
|
|
11820
|
+
" Use the narrower owned ERC-20 registry subset when you only want held tokens:",
|
|
11821
|
+
" zk-agent tokens --wallet main --owned",
|
|
11822
|
+
"",
|
|
11823
|
+
" Use chain-scoped discovery before choosing a token address:",
|
|
11824
|
+
" zk-agent tokens --chain zksync-sepolia",
|
|
11825
|
+
" zk-agent tokens --chain zksync-sepolia --symbol USDC",
|
|
11826
|
+
" zk-agent tokens --chain zksync-sepolia --role paymaster-fee-token",
|
|
11827
|
+
"",
|
|
11828
|
+
" For one direct token-resolution check:",
|
|
11829
|
+
" zk-agent resolve-token --chain zksync-sepolia --symbol USDC",
|
|
11830
|
+
"",
|
|
11831
|
+
" For the full defaults/registry catalog:",
|
|
11832
|
+
" zk-agent defaults"
|
|
11833
|
+
].join("\n")
|
|
11834
|
+
).option("--wallet <name>", "Optional stored wallet name to infer the active chain").option("--chain <chain>", "Chain key or chain id override").option("--symbol <symbol>", "Optional exact symbol filter").option(
|
|
11647
11835
|
"--role <role>",
|
|
11648
11836
|
`Optional defaults-registry role filter: ${REGISTRY_TOKEN_ROLES.join(", ")}`
|
|
11649
11837
|
).option(
|
|
@@ -11829,21 +12017,157 @@ import { Command as Command8 } from "commander";
|
|
|
11829
12017
|
// src/lib/relay.ts
|
|
11830
12018
|
import { createServer } from "node:http";
|
|
11831
12019
|
import fs7 from "node:fs";
|
|
11832
|
-
import
|
|
12020
|
+
import path7 from "node:path";
|
|
11833
12021
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
12022
|
+
|
|
12023
|
+
// src/lib/http.ts
|
|
12024
|
+
import { spawn } from "node:child_process";
|
|
12025
|
+
import { mkdtemp, readFile as readFile2, rm as rm2 } from "node:fs/promises";
|
|
12026
|
+
import os2 from "node:os";
|
|
12027
|
+
import path6 from "node:path";
|
|
12028
|
+
function isDnsResolutionFailure(error) {
|
|
12029
|
+
if (!error || typeof error !== "object") {
|
|
12030
|
+
return false;
|
|
12031
|
+
}
|
|
12032
|
+
const cause = "cause" in error ? error.cause : void 0;
|
|
12033
|
+
if (!cause || typeof cause !== "object") {
|
|
12034
|
+
return false;
|
|
12035
|
+
}
|
|
12036
|
+
const code = "code" in cause ? cause.code : void 0;
|
|
12037
|
+
return code === "ENOTFOUND" || code === "EAI_AGAIN";
|
|
12038
|
+
}
|
|
12039
|
+
function isHttpUrl(value) {
|
|
12040
|
+
return value.startsWith("http://") || value.startsWith("https://");
|
|
12041
|
+
}
|
|
12042
|
+
function parseCurlHeaders(rawHeaders) {
|
|
12043
|
+
const blocks = rawHeaders.replace(/\r\n/g, "\n").split(/\n{2,}/).map((block) => block.trim()).filter((block) => block.startsWith("HTTP/"));
|
|
12044
|
+
const lastBlock = blocks.at(-1);
|
|
12045
|
+
if (!lastBlock) {
|
|
12046
|
+
throw new Error("curl fallback did not emit an HTTP response header block.");
|
|
12047
|
+
}
|
|
12048
|
+
const [statusLine, ...headerLines] = lastBlock.split("\n");
|
|
12049
|
+
const status = Number.parseInt(statusLine.split(/\s+/)[1] || "", 10);
|
|
12050
|
+
if (!Number.isInteger(status)) {
|
|
12051
|
+
throw new Error(`curl fallback emitted an invalid status line: ${statusLine}`);
|
|
12052
|
+
}
|
|
12053
|
+
const headers = new Headers();
|
|
12054
|
+
for (const line of headerLines) {
|
|
12055
|
+
const separator = line.indexOf(":");
|
|
12056
|
+
if (separator <= 0) continue;
|
|
12057
|
+
const key = line.slice(0, separator).trim();
|
|
12058
|
+
const value = line.slice(separator + 1).trim();
|
|
12059
|
+
if (key) {
|
|
12060
|
+
headers.append(key, value);
|
|
12061
|
+
}
|
|
12062
|
+
}
|
|
12063
|
+
return { status, headers };
|
|
12064
|
+
}
|
|
12065
|
+
async function runCurlRequest(url, options) {
|
|
12066
|
+
const tempDir = await mkdtemp(path6.join(os2.tmpdir(), "zk-agent-http-"));
|
|
12067
|
+
const headersPath = path6.join(tempDir, "headers.txt");
|
|
12068
|
+
const bodyPath = path6.join(tempDir, "body.txt");
|
|
12069
|
+
try {
|
|
12070
|
+
const args = [
|
|
12071
|
+
"--silent",
|
|
12072
|
+
"--show-error",
|
|
12073
|
+
"--output",
|
|
12074
|
+
bodyPath,
|
|
12075
|
+
"--dump-header",
|
|
12076
|
+
headersPath,
|
|
12077
|
+
"--request",
|
|
12078
|
+
options.method || "GET"
|
|
12079
|
+
];
|
|
12080
|
+
if (options.redirect === "follow") {
|
|
12081
|
+
args.push("--location");
|
|
12082
|
+
}
|
|
12083
|
+
for (const [key, value] of Object.entries(options.headers || {})) {
|
|
12084
|
+
args.push("--header", `${key}: ${value}`);
|
|
12085
|
+
}
|
|
12086
|
+
if (typeof options.body === "string") {
|
|
12087
|
+
args.push("--data-raw", options.body);
|
|
12088
|
+
}
|
|
12089
|
+
args.push(url);
|
|
12090
|
+
const child = spawn("curl", args, {
|
|
12091
|
+
env: process.env,
|
|
12092
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
12093
|
+
});
|
|
12094
|
+
let stdout = "";
|
|
12095
|
+
let stderr = "";
|
|
12096
|
+
child.stdout.setEncoding("utf8");
|
|
12097
|
+
child.stderr.setEncoding("utf8");
|
|
12098
|
+
child.stdout.on("data", (chunk) => {
|
|
12099
|
+
stdout += chunk;
|
|
12100
|
+
});
|
|
12101
|
+
child.stderr.on("data", (chunk) => {
|
|
12102
|
+
stderr += chunk;
|
|
12103
|
+
});
|
|
12104
|
+
const exitCode = await new Promise((resolve, reject) => {
|
|
12105
|
+
child.once("error", reject);
|
|
12106
|
+
child.once("close", resolve);
|
|
12107
|
+
});
|
|
12108
|
+
if (exitCode !== 0) {
|
|
12109
|
+
throw new Error(stderr.trim() || stdout.trim() || `curl exited with code ${exitCode}`);
|
|
12110
|
+
}
|
|
12111
|
+
const [rawHeaders, body] = await Promise.all([
|
|
12112
|
+
readFile2(headersPath, "utf8"),
|
|
12113
|
+
readFile2(bodyPath, "utf8")
|
|
12114
|
+
]);
|
|
12115
|
+
const { status, headers } = parseCurlHeaders(rawHeaders);
|
|
12116
|
+
return {
|
|
12117
|
+
ok: status >= 200 && status < 300,
|
|
12118
|
+
status,
|
|
12119
|
+
headers,
|
|
12120
|
+
body
|
|
12121
|
+
};
|
|
12122
|
+
} finally {
|
|
12123
|
+
await rm2(tempDir, { recursive: true, force: true });
|
|
12124
|
+
}
|
|
12125
|
+
}
|
|
12126
|
+
async function fetchTextWithFallback(url, options = {}) {
|
|
12127
|
+
try {
|
|
12128
|
+
const response = await fetch(url, {
|
|
12129
|
+
method: options.method,
|
|
12130
|
+
headers: options.headers,
|
|
12131
|
+
body: options.body,
|
|
12132
|
+
redirect: options.redirect
|
|
12133
|
+
});
|
|
12134
|
+
return {
|
|
12135
|
+
ok: response.ok,
|
|
12136
|
+
status: response.status,
|
|
12137
|
+
headers: response.headers,
|
|
12138
|
+
body: await response.text()
|
|
12139
|
+
};
|
|
12140
|
+
} catch (error) {
|
|
12141
|
+
if (!isHttpUrl(url) || !isDnsResolutionFailure(error)) {
|
|
12142
|
+
throw error;
|
|
12143
|
+
}
|
|
12144
|
+
return await runCurlRequest(url, options);
|
|
12145
|
+
}
|
|
12146
|
+
}
|
|
12147
|
+
async function fetchJsonWithFallback(url, options = {}) {
|
|
12148
|
+
const response = await fetchTextWithFallback(url, options);
|
|
12149
|
+
return {
|
|
12150
|
+
...response,
|
|
12151
|
+
json: JSON.parse(response.body)
|
|
12152
|
+
};
|
|
12153
|
+
}
|
|
12154
|
+
|
|
12155
|
+
// src/lib/relay.ts
|
|
11834
12156
|
var RELAY_BODY_LIMIT_BYTES = 1024 * 1024;
|
|
11835
12157
|
var RELAY_SERVICE = "zk-agent-relay";
|
|
11836
12158
|
var RELAY_PROTOCOL = "zk-agent-session-relay";
|
|
11837
12159
|
var RELAY_SCHEMA_VERSION = 1;
|
|
12160
|
+
var RELAY_STATE_BACKEND = "local-filesystem";
|
|
12161
|
+
var RELAY_DEPLOYMENT_SCOPE = "single-host";
|
|
11838
12162
|
function relayDir() {
|
|
11839
|
-
const directory =
|
|
12163
|
+
const directory = path7.join(storageDir(), "relay");
|
|
11840
12164
|
if (!fs7.existsSync(directory)) {
|
|
11841
12165
|
fs7.mkdirSync(directory, { recursive: true, mode: 448 });
|
|
11842
12166
|
}
|
|
11843
12167
|
return directory;
|
|
11844
12168
|
}
|
|
11845
12169
|
function relayRecordPath(requestId) {
|
|
11846
|
-
return
|
|
12170
|
+
return path7.join(relayDir(), `${requestId}.json`);
|
|
11847
12171
|
}
|
|
11848
12172
|
function writeRelayRecord(record) {
|
|
11849
12173
|
fs7.writeFileSync(relayRecordPath(record.request_id), JSON.stringify(record, null, 2), {
|
|
@@ -11870,11 +12194,15 @@ function sanitizeRelayRecord(record) {
|
|
|
11870
12194
|
}
|
|
11871
12195
|
function relayStatusResponse(baseUrl, record) {
|
|
11872
12196
|
const sanitized = sanitizeRelayRecord(record);
|
|
12197
|
+
const shareUrl = relayShareUrl(baseUrl, sanitized.request_id);
|
|
12198
|
+
const statusUrl = relayStatusUrl(baseUrl, sanitized.request_id);
|
|
11873
12199
|
return {
|
|
11874
12200
|
request_id: sanitized.request_id,
|
|
11875
12201
|
status: relayStatus(record),
|
|
11876
12202
|
approval_ready: Boolean(record.encrypted_payload),
|
|
11877
|
-
|
|
12203
|
+
share_url: shareUrl,
|
|
12204
|
+
status_url: statusUrl,
|
|
12205
|
+
approval_url: shareUrl,
|
|
11878
12206
|
expires_at: sanitized.expires_at,
|
|
11879
12207
|
request: sanitized.request,
|
|
11880
12208
|
approval_submitted_at: sanitized.approval_submitted_at
|
|
@@ -11925,14 +12253,14 @@ function writeBody(response, statusCode, contentType, value, extraHeaders = {})
|
|
|
11925
12253
|
}
|
|
11926
12254
|
function resolveConnectorUiDistRoot() {
|
|
11927
12255
|
const currentFile = fileURLToPath3(import.meta.url);
|
|
11928
|
-
const currentDir2 =
|
|
12256
|
+
const currentDir2 = path7.dirname(currentFile);
|
|
11929
12257
|
const candidates = [
|
|
11930
|
-
|
|
11931
|
-
|
|
11932
|
-
|
|
12258
|
+
path7.resolve(currentDir2, "./connector-ui"),
|
|
12259
|
+
path7.resolve(currentDir2, "../../../zk-connector-ui/dist"),
|
|
12260
|
+
path7.resolve(currentDir2, "../../zk-connector-ui/dist")
|
|
11933
12261
|
];
|
|
11934
12262
|
for (const candidate of candidates) {
|
|
11935
|
-
if (fs7.existsSync(
|
|
12263
|
+
if (fs7.existsSync(path7.join(candidate, "index.html"))) {
|
|
11936
12264
|
return candidate;
|
|
11937
12265
|
}
|
|
11938
12266
|
}
|
|
@@ -11961,7 +12289,7 @@ function relayCapabilities(connectorUiAvailable) {
|
|
|
11961
12289
|
...connectorUiAvailable ? ["connector-ui"] : []
|
|
11962
12290
|
];
|
|
11963
12291
|
}
|
|
11964
|
-
function relayHealthResponse(bindBaseUrl, publicBaseUrl, connectorUiAvailable) {
|
|
12292
|
+
function relayHealthResponse(bindBaseUrl, publicBaseUrl, connectorUiAvailable, publicOriginSource) {
|
|
11965
12293
|
return {
|
|
11966
12294
|
ok: true,
|
|
11967
12295
|
service: RELAY_SERVICE,
|
|
@@ -11970,6 +12298,10 @@ function relayHealthResponse(bindBaseUrl, publicBaseUrl, connectorUiAvailable) {
|
|
|
11970
12298
|
relay_mode: "local-file",
|
|
11971
12299
|
origin: normalizeRelayBaseUrl(bindBaseUrl),
|
|
11972
12300
|
public_origin: normalizeRelayBaseUrl(publicBaseUrl),
|
|
12301
|
+
public_origin_source: publicOriginSource,
|
|
12302
|
+
state_backend: RELAY_STATE_BACKEND,
|
|
12303
|
+
deployment_scope: RELAY_DEPLOYMENT_SCOPE,
|
|
12304
|
+
same_host_restart_persists: true,
|
|
11973
12305
|
connector_ui_available: connectorUiAvailable,
|
|
11974
12306
|
capabilities: relayCapabilities(connectorUiAvailable)
|
|
11975
12307
|
};
|
|
@@ -11984,31 +12316,34 @@ function relayApprovalUrl(baseUrl, requestId) {
|
|
|
11984
12316
|
return `${relayStatusUrl(baseUrl, requestId)}/approval`;
|
|
11985
12317
|
}
|
|
11986
12318
|
async function publishRelayRequest(baseUrl, body) {
|
|
11987
|
-
const response = await
|
|
11988
|
-
|
|
11989
|
-
|
|
11990
|
-
|
|
11991
|
-
|
|
11992
|
-
|
|
11993
|
-
|
|
12319
|
+
const response = await fetchJsonWithFallback(
|
|
12320
|
+
`${normalizeRelayBaseUrl(baseUrl)}/api/requests`,
|
|
12321
|
+
{
|
|
12322
|
+
method: "POST",
|
|
12323
|
+
headers: {
|
|
12324
|
+
"Content-Type": "application/json"
|
|
12325
|
+
},
|
|
12326
|
+
body: JSON.stringify(body)
|
|
12327
|
+
}
|
|
12328
|
+
);
|
|
11994
12329
|
if (!response.ok) {
|
|
11995
12330
|
throw new Error(`Relay publish failed with status ${response.status}`);
|
|
11996
12331
|
}
|
|
11997
|
-
return
|
|
12332
|
+
return response.json;
|
|
11998
12333
|
}
|
|
11999
12334
|
async function fetchRelayStatus(baseUrl, requestId) {
|
|
12000
|
-
const response = await
|
|
12335
|
+
const response = await fetchJsonWithFallback(relayStatusUrl(baseUrl, requestId));
|
|
12001
12336
|
if (!response.ok) {
|
|
12002
12337
|
throw new Error(`Relay status fetch failed with status ${response.status}`);
|
|
12003
12338
|
}
|
|
12004
|
-
return
|
|
12339
|
+
return response.json;
|
|
12005
12340
|
}
|
|
12006
12341
|
async function fetchRelayHealth(baseUrl) {
|
|
12007
|
-
const response = await
|
|
12342
|
+
const response = await fetchJsonWithFallback(`${normalizeRelayBaseUrl(baseUrl)}/health`);
|
|
12008
12343
|
if (!response.ok) {
|
|
12009
12344
|
throw new Error(`Relay health fetch failed with status ${response.status}`);
|
|
12010
12345
|
}
|
|
12011
|
-
return
|
|
12346
|
+
return response.json;
|
|
12012
12347
|
}
|
|
12013
12348
|
function sleep(ms) {
|
|
12014
12349
|
return new Promise((resolve) => {
|
|
@@ -12033,15 +12368,16 @@ async function waitForRelayApprovalReady(baseUrl, requestId, options) {
|
|
|
12033
12368
|
);
|
|
12034
12369
|
}
|
|
12035
12370
|
async function fetchRelayApproval(baseUrl, requestId) {
|
|
12036
|
-
const response = await
|
|
12371
|
+
const response = await fetchJsonWithFallback(relayApprovalUrl(baseUrl, requestId));
|
|
12037
12372
|
if (!response.ok) {
|
|
12038
12373
|
throw new Error(`Relay approval fetch failed with status ${response.status}`);
|
|
12039
12374
|
}
|
|
12040
|
-
return
|
|
12375
|
+
return response.json;
|
|
12041
12376
|
}
|
|
12042
12377
|
async function startRelayServer(options) {
|
|
12043
12378
|
const uiDistRoot = resolveConnectorUiDistRoot();
|
|
12044
12379
|
let bindBaseUrl = "";
|
|
12380
|
+
const publicOriginSource = options.publicOrigin?.trim() ? "configured" : "bind-origin-default";
|
|
12045
12381
|
const server = createServer(async (request, response) => {
|
|
12046
12382
|
try {
|
|
12047
12383
|
const requestUrl = new URL(request.url || "/", "http://localhost");
|
|
@@ -12056,7 +12392,12 @@ async function startRelayServer(options) {
|
|
|
12056
12392
|
writeJson2(
|
|
12057
12393
|
response,
|
|
12058
12394
|
200,
|
|
12059
|
-
relayHealthResponse(
|
|
12395
|
+
relayHealthResponse(
|
|
12396
|
+
bindBaseUrl,
|
|
12397
|
+
publicBaseUrl,
|
|
12398
|
+
Boolean(uiDistRoot),
|
|
12399
|
+
publicOriginSource
|
|
12400
|
+
)
|
|
12060
12401
|
);
|
|
12061
12402
|
return;
|
|
12062
12403
|
}
|
|
@@ -12125,7 +12466,7 @@ async function startRelayServer(options) {
|
|
|
12125
12466
|
}
|
|
12126
12467
|
if (method === "GET" && uiDistRoot) {
|
|
12127
12468
|
const relativePath = pathname === "/" ? "/index.html" : pathname;
|
|
12128
|
-
const filePath =
|
|
12469
|
+
const filePath = path7.resolve(uiDistRoot, `.${relativePath}`);
|
|
12129
12470
|
if (!filePath.startsWith(uiDistRoot)) {
|
|
12130
12471
|
writeJson2(response, 403, { error: "Forbidden path" });
|
|
12131
12472
|
return;
|
|
@@ -12134,7 +12475,7 @@ async function startRelayServer(options) {
|
|
|
12134
12475
|
writeBody(response, 200, contentTypeFor(filePath), fs7.readFileSync(filePath));
|
|
12135
12476
|
return;
|
|
12136
12477
|
}
|
|
12137
|
-
const indexPath =
|
|
12478
|
+
const indexPath = path7.join(uiDistRoot, "index.html");
|
|
12138
12479
|
if (fs7.existsSync(indexPath)) {
|
|
12139
12480
|
writeBody(response, 200, "text/html; charset=utf-8", fs7.readFileSync(indexPath));
|
|
12140
12481
|
return;
|
|
@@ -12181,8 +12522,14 @@ async function startRelayServer(options) {
|
|
|
12181
12522
|
// src/commands/relay.ts
|
|
12182
12523
|
function buildRelayServeRecommendedCommands(relayUrl) {
|
|
12183
12524
|
return {
|
|
12184
|
-
createWallet: `zk-agent wallet create --relay-url ${relayUrl}`,
|
|
12185
|
-
reapproveWallet: `zk-agent wallet reapprove --name main --relay-url ${relayUrl}`
|
|
12525
|
+
createWallet: `zk-agent wallet create --relay-url ${relayUrl} --wait-relay --prompt-code`,
|
|
12526
|
+
reapproveWallet: `zk-agent wallet reapprove --name main --relay-url ${relayUrl} --wait-relay --prompt-code`
|
|
12527
|
+
};
|
|
12528
|
+
}
|
|
12529
|
+
function buildAdvertisedRelayBases(publicOrigin) {
|
|
12530
|
+
return {
|
|
12531
|
+
shareLinkBaseUrl: `${publicOrigin}/r`,
|
|
12532
|
+
statusApiBaseUrl: `${publicOrigin}/api/requests`
|
|
12186
12533
|
};
|
|
12187
12534
|
}
|
|
12188
12535
|
function isRecord3(value) {
|
|
@@ -12198,6 +12545,15 @@ function isRelayCapability(value) {
|
|
|
12198
12545
|
"connector-ui"
|
|
12199
12546
|
].includes(String(value));
|
|
12200
12547
|
}
|
|
12548
|
+
function isRelayPublicOriginSource(value) {
|
|
12549
|
+
return value === "configured" || value === "bind-origin-default";
|
|
12550
|
+
}
|
|
12551
|
+
function isRelayStateBackend(value) {
|
|
12552
|
+
return value === "local-filesystem";
|
|
12553
|
+
}
|
|
12554
|
+
function isRelayDeploymentScope(value) {
|
|
12555
|
+
return value === "single-host";
|
|
12556
|
+
}
|
|
12201
12557
|
function asRelayHealthResponse(value) {
|
|
12202
12558
|
if (!isRecord3(value)) return null;
|
|
12203
12559
|
if (value.ok !== true) return null;
|
|
@@ -12207,6 +12563,18 @@ function asRelayHealthResponse(value) {
|
|
|
12207
12563
|
if (value.relay_mode !== "local-file") return null;
|
|
12208
12564
|
if (typeof value.origin !== "string") return null;
|
|
12209
12565
|
if (typeof value.public_origin !== "string") return null;
|
|
12566
|
+
if (typeof value.public_origin_source !== "undefined" && !isRelayPublicOriginSource(value.public_origin_source)) {
|
|
12567
|
+
return null;
|
|
12568
|
+
}
|
|
12569
|
+
if (typeof value.state_backend !== "undefined" && !isRelayStateBackend(value.state_backend)) {
|
|
12570
|
+
return null;
|
|
12571
|
+
}
|
|
12572
|
+
if (typeof value.deployment_scope !== "undefined" && !isRelayDeploymentScope(value.deployment_scope)) {
|
|
12573
|
+
return null;
|
|
12574
|
+
}
|
|
12575
|
+
if (typeof value.same_host_restart_persists !== "undefined" && typeof value.same_host_restart_persists !== "boolean") {
|
|
12576
|
+
return null;
|
|
12577
|
+
}
|
|
12210
12578
|
if (typeof value.connector_ui_available !== "boolean") return null;
|
|
12211
12579
|
if (!Array.isArray(value.capabilities) || !value.capabilities.every(isRelayCapability)) {
|
|
12212
12580
|
return null;
|
|
@@ -12225,6 +12593,38 @@ function relayPublicOriginLooksLocal(origin) {
|
|
|
12225
12593
|
return false;
|
|
12226
12594
|
}
|
|
12227
12595
|
}
|
|
12596
|
+
function normalizeComparableRelayUrl(value) {
|
|
12597
|
+
try {
|
|
12598
|
+
return new URL(value).toString().replace(/\/+$/, "");
|
|
12599
|
+
} catch {
|
|
12600
|
+
return null;
|
|
12601
|
+
}
|
|
12602
|
+
}
|
|
12603
|
+
function relayUrlMatches(left, right) {
|
|
12604
|
+
const normalizedLeft = normalizeComparableRelayUrl(left);
|
|
12605
|
+
const normalizedRight = right ? normalizeComparableRelayUrl(right) : null;
|
|
12606
|
+
if (normalizedLeft === null || normalizedRight === null) {
|
|
12607
|
+
return null;
|
|
12608
|
+
}
|
|
12609
|
+
return normalizedLeft === normalizedRight;
|
|
12610
|
+
}
|
|
12611
|
+
function inferRelayPublicOriginSource(options) {
|
|
12612
|
+
const normalizedOrigin = options.origin ? normalizeComparableRelayUrl(options.origin) : null;
|
|
12613
|
+
const normalizedPublicOrigin = normalizeComparableRelayUrl(options.publicOrigin);
|
|
12614
|
+
if (!normalizedOrigin || !normalizedPublicOrigin) {
|
|
12615
|
+
return null;
|
|
12616
|
+
}
|
|
12617
|
+
return normalizedOrigin === normalizedPublicOrigin ? "bind-origin-default" : "configured";
|
|
12618
|
+
}
|
|
12619
|
+
function inferRelayStateBackend(relayMode) {
|
|
12620
|
+
return relayMode === "local-file" ? "local-filesystem" : null;
|
|
12621
|
+
}
|
|
12622
|
+
function inferRelayDeploymentScope(relayMode) {
|
|
12623
|
+
return relayMode === "local-file" ? "single-host" : null;
|
|
12624
|
+
}
|
|
12625
|
+
function inferSameHostRestartPersists(relayMode) {
|
|
12626
|
+
return relayMode === "local-file" ? true : null;
|
|
12627
|
+
}
|
|
12228
12628
|
function relayHostedReadinessNotes(options) {
|
|
12229
12629
|
const notes = [];
|
|
12230
12630
|
if (!options.compatible) {
|
|
@@ -12235,7 +12635,7 @@ function relayHostedReadinessNotes(options) {
|
|
|
12235
12635
|
}
|
|
12236
12636
|
if (relayPublicOriginLooksLocal(options.publicOrigin)) {
|
|
12237
12637
|
notes.push(
|
|
12238
|
-
"Relay compatibility is present, but the advertised public origin still points at a local-only address. Set --public-origin to the externally reachable URL before using this as a hosted approval path."
|
|
12638
|
+
options.publicOriginSource === "bind-origin-default" ? "Relay compatibility is present, but the relay is still advertising its bind origin as the public origin. Set --public-origin to the externally reachable URL before using this as a hosted approval path." : "Relay compatibility is present, but the advertised public origin still points at a local-only address. Set --public-origin to the externally reachable URL before using this as a hosted approval path."
|
|
12239
12639
|
);
|
|
12240
12640
|
}
|
|
12241
12641
|
if (options.connectorUiAvailable === false) {
|
|
@@ -12245,19 +12645,70 @@ function relayHostedReadinessNotes(options) {
|
|
|
12245
12645
|
}
|
|
12246
12646
|
return notes;
|
|
12247
12647
|
}
|
|
12648
|
+
function relayOperationalContractNotes(options) {
|
|
12649
|
+
if (!options.compatible) {
|
|
12650
|
+
return [];
|
|
12651
|
+
}
|
|
12652
|
+
if (options.stateBackend === "local-filesystem" && options.deploymentScope === "single-host" && options.sameHostRestartPersists === true) {
|
|
12653
|
+
return [
|
|
12654
|
+
"Relay state is stored on the relay host local filesystem. Restarts on the same host keep pending approval state, but multi-instance or load-balanced deployments do not share relay state."
|
|
12655
|
+
];
|
|
12656
|
+
}
|
|
12657
|
+
return [];
|
|
12658
|
+
}
|
|
12659
|
+
function relayOriginRelationshipNotes(options) {
|
|
12660
|
+
const notes = [];
|
|
12661
|
+
const relayUrlMatchesOrigin = relayUrlMatches(options.relayUrl, options.origin);
|
|
12662
|
+
const relayUrlMatchesPublicOrigin = relayUrlMatches(options.relayUrl, options.publicOrigin);
|
|
12663
|
+
if (relayUrlMatchesOrigin === false) {
|
|
12664
|
+
notes.push(
|
|
12665
|
+
"The inspected relay URL differs from the bind origin reported by /health. That is expected when you inspect a relay through a reverse proxy or tunnel instead of the local bind address."
|
|
12666
|
+
);
|
|
12667
|
+
}
|
|
12668
|
+
if (relayUrlMatchesPublicOrigin === false) {
|
|
12669
|
+
notes.push(
|
|
12670
|
+
"The inspected relay URL differs from the advertised public origin. Share links and wallet approval commands will use the public origin, not the inspected relay URL."
|
|
12671
|
+
);
|
|
12672
|
+
}
|
|
12673
|
+
return notes;
|
|
12674
|
+
}
|
|
12248
12675
|
function buildRelayInspectPayload(relayUrl, rawHealth) {
|
|
12249
12676
|
const health = asRelayHealthResponse(rawHealth);
|
|
12250
12677
|
const fallbackPublicOrigin = isRecord3(rawHealth) && typeof rawHealth.public_origin === "string" ? rawHealth.public_origin : relayUrl;
|
|
12251
12678
|
const publicOrigin = health?.public_origin || fallbackPublicOrigin;
|
|
12679
|
+
const publicOriginSource = health?.public_origin_source || inferRelayPublicOriginSource({
|
|
12680
|
+
origin: health?.origin || null,
|
|
12681
|
+
publicOrigin
|
|
12682
|
+
});
|
|
12683
|
+
const stateBackend = health?.state_backend || inferRelayStateBackend(health?.relay_mode || null);
|
|
12684
|
+
const deploymentScope = health?.deployment_scope || inferRelayDeploymentScope(health?.relay_mode || null);
|
|
12685
|
+
const sameHostRestartPersists = typeof health?.same_host_restart_persists === "boolean" ? health.same_host_restart_persists : inferSameHostRestartPersists(health?.relay_mode || null);
|
|
12252
12686
|
const compatible = Boolean(health && hasCoreRelayCapabilities(health.capabilities));
|
|
12253
12687
|
const connectorUiAvailable = health?.connector_ui_available ?? null;
|
|
12688
|
+
const relayUrlMatchesOrigin = relayUrlMatches(relayUrl, health?.origin || null);
|
|
12689
|
+
const relayUrlMatchesPublicOrigin = relayUrlMatches(relayUrl, publicOrigin);
|
|
12254
12690
|
const publicOriginLooksLocal = relayPublicOriginLooksLocal(publicOrigin);
|
|
12255
12691
|
const hostedShareRedirectReady = compatible && connectorUiAvailable === true && !publicOriginLooksLocal;
|
|
12256
|
-
const
|
|
12257
|
-
|
|
12258
|
-
|
|
12259
|
-
|
|
12260
|
-
|
|
12692
|
+
const { shareLinkBaseUrl, statusApiBaseUrl } = buildAdvertisedRelayBases(publicOrigin);
|
|
12693
|
+
const notes = [
|
|
12694
|
+
...relayHostedReadinessNotes({
|
|
12695
|
+
compatible,
|
|
12696
|
+
publicOrigin,
|
|
12697
|
+
publicOriginSource,
|
|
12698
|
+
connectorUiAvailable
|
|
12699
|
+
}),
|
|
12700
|
+
...relayOperationalContractNotes({
|
|
12701
|
+
compatible,
|
|
12702
|
+
stateBackend,
|
|
12703
|
+
deploymentScope,
|
|
12704
|
+
sameHostRestartPersists
|
|
12705
|
+
}),
|
|
12706
|
+
...relayOriginRelationshipNotes({
|
|
12707
|
+
relayUrl,
|
|
12708
|
+
origin: health?.origin || null,
|
|
12709
|
+
publicOrigin
|
|
12710
|
+
})
|
|
12711
|
+
];
|
|
12261
12712
|
return {
|
|
12262
12713
|
ok: true,
|
|
12263
12714
|
status: "relay-inspected",
|
|
@@ -12269,6 +12720,14 @@ function buildRelayInspectPayload(relayUrl, rawHealth) {
|
|
|
12269
12720
|
relayMode: health?.relay_mode || null,
|
|
12270
12721
|
origin: health?.origin || null,
|
|
12271
12722
|
publicOrigin,
|
|
12723
|
+
publicOriginSource,
|
|
12724
|
+
stateBackend,
|
|
12725
|
+
deploymentScope,
|
|
12726
|
+
sameHostRestartPersists,
|
|
12727
|
+
shareLinkBaseUrl,
|
|
12728
|
+
statusApiBaseUrl,
|
|
12729
|
+
relayUrlMatchesOrigin,
|
|
12730
|
+
relayUrlMatchesPublicOrigin,
|
|
12272
12731
|
publicOriginLooksLocal,
|
|
12273
12732
|
connectorUiAvailable,
|
|
12274
12733
|
hostedShareRedirectReady,
|
|
@@ -12279,6 +12738,23 @@ function buildRelayInspectPayload(relayUrl, rawHealth) {
|
|
|
12279
12738
|
}
|
|
12280
12739
|
function createRelayCommand() {
|
|
12281
12740
|
const relay = new Command8("relay").description("Run the local connector relay prototype server");
|
|
12741
|
+
relay.addHelpText(
|
|
12742
|
+
"after",
|
|
12743
|
+
[
|
|
12744
|
+
"",
|
|
12745
|
+
" Hosted remote-approval path:",
|
|
12746
|
+
" zk-agent relay serve --public-origin https://relay.example.com",
|
|
12747
|
+
" zk-agent relay inspect --relay-url <url>",
|
|
12748
|
+
" zk-agent wallet create --relay-url <url> --wait-relay --prompt-code",
|
|
12749
|
+
" zk-agent wallet reapprove --name main --relay-url <url> --wait-relay --prompt-code",
|
|
12750
|
+
"",
|
|
12751
|
+
" Keep `wallet create|reapprove --await-local` as the default baseline when",
|
|
12752
|
+
" the browser and terminal are colocated.",
|
|
12753
|
+
"",
|
|
12754
|
+
" Use `relay inspect` before sending operators to a hosted share link so",
|
|
12755
|
+
" the public origin, connector UI, and hosted-readiness contract are visible."
|
|
12756
|
+
].join("\n")
|
|
12757
|
+
);
|
|
12282
12758
|
relay.command("serve").description("Serve the local relay API and, when available, the built connector UI").option("--host <host>", "Host to bind", "127.0.0.1").option("--port <port>", "Port to bind (0 = choose a free port)", "4445").option(
|
|
12283
12759
|
"--public-origin <url>",
|
|
12284
12760
|
"Public base URL to advertise in share/status links when the relay is behind a tunnel or reverse proxy"
|
|
@@ -12294,13 +12770,16 @@ function createRelayCommand() {
|
|
|
12294
12770
|
publicOrigin: options.publicOrigin?.trim()
|
|
12295
12771
|
});
|
|
12296
12772
|
const publicOrigin = options.publicOrigin?.trim() || server.origin;
|
|
12773
|
+
const publicOriginSource = options.publicOrigin?.trim() ? "configured" : "bind-origin-default";
|
|
12297
12774
|
const publicOriginLooksLocal = relayPublicOriginLooksLocal(publicOrigin);
|
|
12298
12775
|
const connectorUiAvailable = server.connectorUiAvailable;
|
|
12299
12776
|
const hostedShareRedirectReady = connectorUiAvailable && !publicOriginLooksLocal;
|
|
12777
|
+
const { shareLinkBaseUrl, statusApiBaseUrl } = buildAdvertisedRelayBases(publicOrigin);
|
|
12300
12778
|
const recommendedCommands = buildRelayServeRecommendedCommands(publicOrigin);
|
|
12301
12779
|
const notes = relayHostedReadinessNotes({
|
|
12302
12780
|
compatible: true,
|
|
12303
12781
|
publicOrigin,
|
|
12782
|
+
publicOriginSource,
|
|
12304
12783
|
connectorUiAvailable
|
|
12305
12784
|
});
|
|
12306
12785
|
const payload = {
|
|
@@ -12308,6 +12787,12 @@ function createRelayCommand() {
|
|
|
12308
12787
|
status: "relay-serving",
|
|
12309
12788
|
origin: server.origin,
|
|
12310
12789
|
publicOrigin,
|
|
12790
|
+
publicOriginSource,
|
|
12791
|
+
stateBackend: "local-filesystem",
|
|
12792
|
+
deploymentScope: "single-host",
|
|
12793
|
+
sameHostRestartPersists: true,
|
|
12794
|
+
shareLinkBaseUrl,
|
|
12795
|
+
statusApiBaseUrl,
|
|
12311
12796
|
publicOriginLooksLocal,
|
|
12312
12797
|
port: server.port,
|
|
12313
12798
|
healthUrl: `${server.origin}/health`,
|
|
@@ -12334,6 +12819,15 @@ function createRelayCommand() {
|
|
|
12334
12819
|
if (publicOrigin !== server.origin) {
|
|
12335
12820
|
humanLine("public origin", publicOrigin);
|
|
12336
12821
|
}
|
|
12822
|
+
humanLine("public origin source", publicOriginSource);
|
|
12823
|
+
humanLine("state backend", payload.stateBackend);
|
|
12824
|
+
humanLine("deployment scope", payload.deploymentScope);
|
|
12825
|
+
humanLine(
|
|
12826
|
+
"same-host restart persists",
|
|
12827
|
+
payload.sameHostRestartPersists ? "yes" : "no"
|
|
12828
|
+
);
|
|
12829
|
+
humanLine("share-link base", shareLinkBaseUrl);
|
|
12830
|
+
humanLine("status api base", statusApiBaseUrl);
|
|
12337
12831
|
humanLine("health", `${server.origin}/health`);
|
|
12338
12832
|
humanLine("hosted ready", hostedShareRedirectReady ? "yes" : "no");
|
|
12339
12833
|
if (connectorUiAvailable !== null) {
|
|
@@ -12385,6 +12879,32 @@ function createRelayCommand() {
|
|
|
12385
12879
|
if (payload.publicOrigin) {
|
|
12386
12880
|
humanLine("public origin", payload.publicOrigin);
|
|
12387
12881
|
}
|
|
12882
|
+
if (payload.publicOriginSource) {
|
|
12883
|
+
humanLine("public origin source", payload.publicOriginSource);
|
|
12884
|
+
}
|
|
12885
|
+
if (payload.stateBackend) {
|
|
12886
|
+
humanLine("state backend", payload.stateBackend);
|
|
12887
|
+
}
|
|
12888
|
+
if (payload.deploymentScope) {
|
|
12889
|
+
humanLine("deployment scope", payload.deploymentScope);
|
|
12890
|
+
}
|
|
12891
|
+
if (payload.sameHostRestartPersists !== null) {
|
|
12892
|
+
humanLine(
|
|
12893
|
+
"same-host restart persists",
|
|
12894
|
+
payload.sameHostRestartPersists ? "yes" : "no"
|
|
12895
|
+
);
|
|
12896
|
+
}
|
|
12897
|
+
humanLine("share-link base", payload.shareLinkBaseUrl);
|
|
12898
|
+
humanLine("status api base", payload.statusApiBaseUrl);
|
|
12899
|
+
if (payload.relayUrlMatchesOrigin !== null) {
|
|
12900
|
+
humanLine("relay url matches origin", payload.relayUrlMatchesOrigin ? "yes" : "no");
|
|
12901
|
+
}
|
|
12902
|
+
if (payload.relayUrlMatchesPublicOrigin !== null) {
|
|
12903
|
+
humanLine(
|
|
12904
|
+
"relay url matches public origin",
|
|
12905
|
+
payload.relayUrlMatchesPublicOrigin ? "yes" : "no"
|
|
12906
|
+
);
|
|
12907
|
+
}
|
|
12388
12908
|
humanLine("public origin local", payload.publicOriginLooksLocal ? "yes" : "no");
|
|
12389
12909
|
if (payload.connectorUiAvailable !== null) {
|
|
12390
12910
|
humanLine("connector ui", payload.connectorUiAvailable ? "available" : "missing");
|
|
@@ -12400,10 +12920,9 @@ function createRelayCommand() {
|
|
|
12400
12920
|
if (payload.recommendedCommands.reapproveWallet) {
|
|
12401
12921
|
humanLine("reapprove wallet", payload.recommendedCommands.reapproveWallet);
|
|
12402
12922
|
}
|
|
12403
|
-
}
|
|
12404
|
-
|
|
12405
|
-
|
|
12406
|
-
}
|
|
12923
|
+
}
|
|
12924
|
+
for (const note of payload.notes) {
|
|
12925
|
+
humanLine("note", note);
|
|
12407
12926
|
}
|
|
12408
12927
|
});
|
|
12409
12928
|
return relay;
|
|
@@ -12416,12 +12935,12 @@ import { Command as Command9 } from "commander";
|
|
|
12416
12935
|
|
|
12417
12936
|
// ../account-profiles/src/profiles.ts
|
|
12418
12937
|
import fs8 from "node:fs";
|
|
12419
|
-
import
|
|
12938
|
+
import path8 from "node:path";
|
|
12420
12939
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
12421
12940
|
var PACKAGE_NAME = "@zk-agent/account-profiles";
|
|
12422
12941
|
var PACKAGE_ROOT_FALLBACK = `<${PACKAGE_NAME} package root unavailable>`;
|
|
12423
12942
|
function isExpectedPackageRoot(candidate) {
|
|
12424
|
-
const manifestPath =
|
|
12943
|
+
const manifestPath = path8.join(candidate, "package.json");
|
|
12425
12944
|
if (!fs8.existsSync(manifestPath)) return false;
|
|
12426
12945
|
try {
|
|
12427
12946
|
const manifest = JSON.parse(fs8.readFileSync(manifestPath, "utf8"));
|
|
@@ -12431,19 +12950,19 @@ function isExpectedPackageRoot(candidate) {
|
|
|
12431
12950
|
}
|
|
12432
12951
|
}
|
|
12433
12952
|
function resolvePackageRoot() {
|
|
12434
|
-
const moduleRoot =
|
|
12953
|
+
const moduleRoot = path8.resolve(path8.dirname(fileURLToPath4(import.meta.url)), "..");
|
|
12435
12954
|
const cwd = process.cwd();
|
|
12436
12955
|
const candidates = [
|
|
12437
12956
|
process.env.ZK_AGENT_ACCOUNT_PROFILES_ROOT,
|
|
12438
|
-
|
|
12957
|
+
path8.join(moduleRoot, "dist", "builtin-account-profiles"),
|
|
12439
12958
|
moduleRoot,
|
|
12440
|
-
|
|
12441
|
-
|
|
12959
|
+
path8.join(cwd, "packages", "account-profiles"),
|
|
12960
|
+
path8.join(cwd, "account-profiles"),
|
|
12442
12961
|
cwd
|
|
12443
12962
|
].filter((value) => typeof value === "string" && value.trim().length > 0);
|
|
12444
12963
|
const seen = /* @__PURE__ */ new Set();
|
|
12445
12964
|
for (const candidate of candidates) {
|
|
12446
|
-
const normalized =
|
|
12965
|
+
const normalized = path8.resolve(candidate);
|
|
12447
12966
|
if (seen.has(normalized)) continue;
|
|
12448
12967
|
seen.add(normalized);
|
|
12449
12968
|
if (isExpectedPackageRoot(normalized)) {
|
|
@@ -12515,11 +13034,11 @@ function missingArtifactError(profileId, artifactPath2) {
|
|
|
12515
13034
|
}
|
|
12516
13035
|
function contractPath(...segments) {
|
|
12517
13036
|
const packageRoot = tryResolvePackageRoot();
|
|
12518
|
-
return packageRoot ?
|
|
13037
|
+
return packageRoot ? path8.join(packageRoot, "contracts", ...segments) : path8.join(PACKAGE_ROOT_FALLBACK, "contracts", ...segments);
|
|
12519
13038
|
}
|
|
12520
13039
|
function artifactPath(...segments) {
|
|
12521
13040
|
const packageRoot = tryResolvePackageRoot();
|
|
12522
|
-
return packageRoot ?
|
|
13041
|
+
return packageRoot ? path8.join(packageRoot, "artifacts", ...segments) : path8.join(PACKAGE_ROOT_FALLBACK, "artifacts", ...segments);
|
|
12523
13042
|
}
|
|
12524
13043
|
function createDailySpendLimitProfile() {
|
|
12525
13044
|
const resolvedArtifactPath = artifactPath("daily-spend-limit", "Account.json");
|
|
@@ -13005,11 +13524,16 @@ function sanitizeWalletRecord(wallet) {
|
|
|
13005
13524
|
function relayOutputAliases(relay) {
|
|
13006
13525
|
const shareUrl = relay && "share_url" in relay ? relay.share_url : void 0;
|
|
13007
13526
|
const statusUrl = relay && "status_url" in relay ? relay.status_url : void 0;
|
|
13527
|
+
const approvalUrl = relay?.approval_url;
|
|
13528
|
+
const shareLinkBaseUrl = shareUrl ? shareUrl.replace(/\/[^/]+$/, "") : approvalUrl ? approvalUrl.replace(/\/[^/]+$/, "") : void 0;
|
|
13529
|
+
const statusApiBaseUrl = statusUrl ? statusUrl.replace(/\/[^/]+$/, "") : approvalUrl && relay?.request_id ? `${approvalUrl.replace(/\/r\/[^/]+$/, "")}/api/requests` : void 0;
|
|
13008
13530
|
return {
|
|
13009
13531
|
relayRequestId: relay?.request_id,
|
|
13010
13532
|
relayShareUrl: shareUrl,
|
|
13011
13533
|
relayStatusUrl: statusUrl,
|
|
13012
|
-
relayApprovalUrl:
|
|
13534
|
+
relayApprovalUrl: approvalUrl,
|
|
13535
|
+
relayShareLinkBaseUrl: shareLinkBaseUrl,
|
|
13536
|
+
relayStatusApiBaseUrl: statusApiBaseUrl
|
|
13013
13537
|
};
|
|
13014
13538
|
}
|
|
13015
13539
|
function sanitizeWalletRequestRecord(request) {
|
|
@@ -14279,6 +14803,165 @@ function buildPendingRequestRecommendedCommands(walletName, requestId, relayUrl,
|
|
|
14279
14803
|
function buildPendingRequestNextAction(recommendedCommands) {
|
|
14280
14804
|
return recommendedCommands.relayStatus ?? recommendedCommands.awaitLocal;
|
|
14281
14805
|
}
|
|
14806
|
+
function buildRelayWaitGuidanceLines(options) {
|
|
14807
|
+
return [
|
|
14808
|
+
["status", "Waiting for relay approval"],
|
|
14809
|
+
["request", options.requestId],
|
|
14810
|
+
["wallet", options.walletName],
|
|
14811
|
+
["share url", options.relay.share_url],
|
|
14812
|
+
["status url", options.relay.status_url],
|
|
14813
|
+
["approval url", options.relay.approval_url],
|
|
14814
|
+
["expires", options.expiresAt],
|
|
14815
|
+
["browser step", "Open the share url in a browser and complete connector approval."],
|
|
14816
|
+
[
|
|
14817
|
+
"terminal step",
|
|
14818
|
+
options.codeEntry === "prompt" ? "After the relay is ready, enter the 6-digit approval code in this terminal." : "The CLI will finalize automatically with the provided 6-digit approval code once the relay is ready."
|
|
14819
|
+
],
|
|
14820
|
+
["fallback status", options.statusCommand],
|
|
14821
|
+
["fallback approve", options.approveCommand]
|
|
14822
|
+
];
|
|
14823
|
+
}
|
|
14824
|
+
function printRelayWaitGuidance(options) {
|
|
14825
|
+
if (shouldJsonOutput()) return;
|
|
14826
|
+
for (const [label, value] of buildRelayWaitGuidanceLines(options)) {
|
|
14827
|
+
humanLine(label, value);
|
|
14828
|
+
}
|
|
14829
|
+
}
|
|
14830
|
+
async function buildRelayStatusFollowUp(options) {
|
|
14831
|
+
if (options.relay.status === "expired") {
|
|
14832
|
+
return await buildRelayExpiredRecoveryCommands({
|
|
14833
|
+
walletName: options.relay.request?.walletName,
|
|
14834
|
+
relayUrl: options.relayUrl,
|
|
14835
|
+
paymasterMode: options.relay.request?.requestedPaymasterMode,
|
|
14836
|
+
accountKind: options.relay.request?.requestedAccountKind
|
|
14837
|
+
});
|
|
14838
|
+
}
|
|
14839
|
+
if (options.relay.approval_ready) {
|
|
14840
|
+
const approve = buildWalletRequestRelayApproveRecommendedCommand(
|
|
14841
|
+
options.relay.request_id,
|
|
14842
|
+
options.relayUrl
|
|
14843
|
+
);
|
|
14844
|
+
return {
|
|
14845
|
+
nextAction: approve,
|
|
14846
|
+
recommendedCommands: {
|
|
14847
|
+
status: buildWalletRequestRelayStatusRecommendedCommand(
|
|
14848
|
+
options.relay.request_id,
|
|
14849
|
+
options.relayUrl
|
|
14850
|
+
),
|
|
14851
|
+
approve
|
|
14852
|
+
}
|
|
14853
|
+
};
|
|
14854
|
+
}
|
|
14855
|
+
return {
|
|
14856
|
+
nextAction: buildWalletRequestRelayStatusRecommendedCommand(
|
|
14857
|
+
options.relay.request_id,
|
|
14858
|
+
options.relayUrl
|
|
14859
|
+
),
|
|
14860
|
+
recommendedCommands: {
|
|
14861
|
+
status: buildWalletRequestRelayStatusRecommendedCommand(
|
|
14862
|
+
options.relay.request_id,
|
|
14863
|
+
options.relayUrl
|
|
14864
|
+
)
|
|
14865
|
+
}
|
|
14866
|
+
};
|
|
14867
|
+
}
|
|
14868
|
+
async function buildRelayExpiredRecoveryCommands(options) {
|
|
14869
|
+
const relayInspect = buildRelayInspectRecommendedCommand(options.relayUrl);
|
|
14870
|
+
const walletName = options.walletName?.trim();
|
|
14871
|
+
if (!walletName) {
|
|
14872
|
+
return {
|
|
14873
|
+
nextAction: relayInspect,
|
|
14874
|
+
recommendedCommands: {
|
|
14875
|
+
relayInspect
|
|
14876
|
+
},
|
|
14877
|
+
note: "Relay approval expired. Inspect the hosted relay, then reissue the wallet request again."
|
|
14878
|
+
};
|
|
14879
|
+
}
|
|
14880
|
+
const existingWallet = await loadWalletSession(walletName);
|
|
14881
|
+
const reissueRemoteApproval = existingWallet ? buildWalletReapproveRemoteRecommendedCommand(walletName, options.relayUrl) : buildWalletCreateRemoteRecommendedCommand(
|
|
14882
|
+
options.relayUrl,
|
|
14883
|
+
options.paymasterMode,
|
|
14884
|
+
walletName,
|
|
14885
|
+
options.accountKind
|
|
14886
|
+
);
|
|
14887
|
+
return {
|
|
14888
|
+
nextAction: reissueRemoteApproval,
|
|
14889
|
+
recommendedCommands: {
|
|
14890
|
+
relayInspect,
|
|
14891
|
+
reissueRemoteApproval
|
|
14892
|
+
},
|
|
14893
|
+
note: "Relay approval expired. Reissue the remote request. If the original request used scoped session flags, add those same policy flags again."
|
|
14894
|
+
};
|
|
14895
|
+
}
|
|
14896
|
+
function buildRelayApprovalTimeoutError(options) {
|
|
14897
|
+
const statusCommand = buildWalletRequestRelayStatusRecommendedCommand(
|
|
14898
|
+
options.requestId,
|
|
14899
|
+
options.relayUrl
|
|
14900
|
+
);
|
|
14901
|
+
const approveCommand = buildWalletRequestRelayApproveRecommendedCommand(
|
|
14902
|
+
options.requestId,
|
|
14903
|
+
options.relayUrl
|
|
14904
|
+
);
|
|
14905
|
+
return new AgentError(
|
|
14906
|
+
"RELAY_APPROVAL_TIMEOUT",
|
|
14907
|
+
`Timed out waiting for relay approval after ${Math.ceil(options.timeoutMs / 1e3)} seconds.`,
|
|
14908
|
+
{
|
|
14909
|
+
requestId: options.requestId,
|
|
14910
|
+
relayUrl: options.relayUrl,
|
|
14911
|
+
timeoutMs: options.timeoutMs,
|
|
14912
|
+
intervalMs: options.intervalMs,
|
|
14913
|
+
retryable: true,
|
|
14914
|
+
statusCommand,
|
|
14915
|
+
approveCommand,
|
|
14916
|
+
suggestedAction: "Check the current relay status, then finalize the wallet approval once approval_ready=true."
|
|
14917
|
+
}
|
|
14918
|
+
);
|
|
14919
|
+
}
|
|
14920
|
+
async function buildRelayApprovalExpiredError(options) {
|
|
14921
|
+
const recovery = await buildRelayExpiredRecoveryCommands({
|
|
14922
|
+
walletName: options.walletName,
|
|
14923
|
+
relayUrl: options.relayUrl,
|
|
14924
|
+
paymasterMode: options.paymasterMode,
|
|
14925
|
+
accountKind: options.accountKind
|
|
14926
|
+
});
|
|
14927
|
+
return new AgentError(
|
|
14928
|
+
"RELAY_APPROVAL_EXPIRED",
|
|
14929
|
+
`Relay approval expired before the encrypted payload was ready for request ${options.requestId}.`,
|
|
14930
|
+
{
|
|
14931
|
+
requestId: options.requestId,
|
|
14932
|
+
relayUrl: options.relayUrl,
|
|
14933
|
+
retryable: true,
|
|
14934
|
+
note: recovery.note,
|
|
14935
|
+
relayInspectCommand: recovery.recommendedCommands.relayInspect,
|
|
14936
|
+
reissueRemoteApprovalCommand: recovery.recommendedCommands.reissueRemoteApproval,
|
|
14937
|
+
suggestedAction: "Inspect the hosted relay, then reissue the remote approval request."
|
|
14938
|
+
}
|
|
14939
|
+
);
|
|
14940
|
+
}
|
|
14941
|
+
function buildRelayApprovalNotReadyError(options) {
|
|
14942
|
+
const statusCommand = buildWalletRequestRelayStatusRecommendedCommand(
|
|
14943
|
+
options.requestId,
|
|
14944
|
+
options.relayUrl
|
|
14945
|
+
);
|
|
14946
|
+
const approveCommand = buildWalletRequestRelayApproveRecommendedCommand(
|
|
14947
|
+
options.requestId,
|
|
14948
|
+
options.relayUrl
|
|
14949
|
+
);
|
|
14950
|
+
return new AgentError(
|
|
14951
|
+
"RELAY_APPROVAL_NOT_READY",
|
|
14952
|
+
`Relay approval is not ready yet for request ${options.requestId}.`,
|
|
14953
|
+
{
|
|
14954
|
+
requestId: options.requestId,
|
|
14955
|
+
relayUrl: options.relayUrl,
|
|
14956
|
+
status: options.status,
|
|
14957
|
+
approvalReady: options.approvalReady,
|
|
14958
|
+
retryable: true,
|
|
14959
|
+
statusCommand,
|
|
14960
|
+
approveCommand,
|
|
14961
|
+
suggestedAction: "Check the current relay status, then retry approval once approval_ready=true."
|
|
14962
|
+
}
|
|
14963
|
+
);
|
|
14964
|
+
}
|
|
14282
14965
|
function buildRequestListEntryRecommendedCommands(walletName, requestId, paymasterMode) {
|
|
14283
14966
|
return {
|
|
14284
14967
|
show: buildWalletRequestShowRecommendedCommand(requestId),
|
|
@@ -14421,25 +15104,55 @@ async function fetchEncryptedRelayApprovalPayload(relayUrl, requestId, options)
|
|
|
14421
15104
|
intervalMs: options.intervalMs ?? 2e3
|
|
14422
15105
|
});
|
|
14423
15106
|
if (!relay.approval_ready) {
|
|
14424
|
-
throw
|
|
15107
|
+
throw await buildRelayApprovalExpiredError({
|
|
15108
|
+
requestId,
|
|
15109
|
+
relayUrl
|
|
15110
|
+
});
|
|
14425
15111
|
}
|
|
14426
15112
|
}
|
|
14427
15113
|
const approval = await fetchRelayApproval(relayUrl, requestId);
|
|
14428
15114
|
if (!approval.approval_ready || !approval.encrypted_payload) {
|
|
14429
|
-
throw
|
|
15115
|
+
throw buildRelayApprovalNotReadyError({
|
|
15116
|
+
requestId,
|
|
15117
|
+
relayUrl,
|
|
15118
|
+
status: approval.status,
|
|
15119
|
+
approvalReady: approval.approval_ready
|
|
15120
|
+
});
|
|
14430
15121
|
}
|
|
14431
15122
|
return approval.encrypted_payload;
|
|
14432
15123
|
}
|
|
14433
15124
|
async function finalizePublishedRelayWalletRequest(options) {
|
|
14434
|
-
|
|
14435
|
-
|
|
14436
|
-
|
|
14437
|
-
|
|
14438
|
-
|
|
14439
|
-
|
|
14440
|
-
|
|
15125
|
+
let encryptedPayload;
|
|
15126
|
+
try {
|
|
15127
|
+
encryptedPayload = await fetchEncryptedRelayApprovalPayload(
|
|
15128
|
+
options.relayUrl,
|
|
15129
|
+
options.walletRequest.requestId,
|
|
15130
|
+
{
|
|
15131
|
+
wait: true,
|
|
15132
|
+
timeoutMs: options.timeoutMs,
|
|
15133
|
+
intervalMs: options.intervalMs
|
|
15134
|
+
}
|
|
15135
|
+
);
|
|
15136
|
+
} catch (error) {
|
|
15137
|
+
if (error instanceof Error && error.message.startsWith("Timed out waiting for relay approval after ")) {
|
|
15138
|
+
throw buildRelayApprovalTimeoutError({
|
|
15139
|
+
requestId: options.walletRequest.requestId,
|
|
15140
|
+
relayUrl: options.relayUrl,
|
|
15141
|
+
timeoutMs: options.timeoutMs,
|
|
15142
|
+
intervalMs: options.intervalMs
|
|
15143
|
+
});
|
|
14441
15144
|
}
|
|
14442
|
-
|
|
15145
|
+
if (error instanceof AgentError && error.code === "RELAY_APPROVAL_EXPIRED") {
|
|
15146
|
+
throw await buildRelayApprovalExpiredError({
|
|
15147
|
+
requestId: options.walletRequest.requestId,
|
|
15148
|
+
walletName: options.walletRequest.walletName,
|
|
15149
|
+
relayUrl: options.relayUrl,
|
|
15150
|
+
paymasterMode: options.walletRequest.requestedPaymasterMode,
|
|
15151
|
+
accountKind: options.walletRequest.requestedAccountKind
|
|
15152
|
+
});
|
|
15153
|
+
}
|
|
15154
|
+
throw error;
|
|
15155
|
+
}
|
|
14443
15156
|
const code = options.code || (options.promptCode ? await readApprovalCodeFromStdin() : void 0);
|
|
14444
15157
|
if (!code) {
|
|
14445
15158
|
throw new Error("Missing relay approval code.");
|
|
@@ -14806,7 +15519,9 @@ async function printBuiltinSmartAccountProfiles() {
|
|
|
14806
15519
|
}
|
|
14807
15520
|
function createWalletCommand(deps) {
|
|
14808
15521
|
const resolvedDeps = resolveWalletCommandDeps(deps);
|
|
14809
|
-
const wallet = new Command9("wallet").description(
|
|
15522
|
+
const wallet = new Command9("wallet").description(
|
|
15523
|
+
"Create, inspect, and recover local-first wallet sessions"
|
|
15524
|
+
);
|
|
14810
15525
|
const request = new Command9("request").description("Inspect and finalize pending wallet requests");
|
|
14811
15526
|
const signer = new Command9("signer").description(
|
|
14812
15527
|
"Inspect and manage the stored local execution signer for a wallet"
|
|
@@ -14836,13 +15551,14 @@ function createWalletCommand(deps) {
|
|
|
14836
15551
|
"after",
|
|
14837
15552
|
[
|
|
14838
15553
|
"",
|
|
14839
|
-
"
|
|
15554
|
+
"Local-first wallet path:",
|
|
14840
15555
|
" First bootstrap:",
|
|
14841
15556
|
" zk-agent wallet create --await-local",
|
|
14842
15557
|
" zk-agent next",
|
|
14843
15558
|
"",
|
|
14844
15559
|
" Restore approval metadata for an existing wallet:",
|
|
14845
15560
|
" zk-agent wallet reapprove --name main --await-local",
|
|
15561
|
+
" zk-agent next",
|
|
14846
15562
|
"",
|
|
14847
15563
|
" Attach a local signer when approval is still present:",
|
|
14848
15564
|
" zk-agent wallet signer attach --name main --private-key <hex>",
|
|
@@ -14852,10 +15568,11 @@ function createWalletCommand(deps) {
|
|
|
14852
15568
|
" zk-agent wallet status --name main",
|
|
14853
15569
|
" zk-agent wallet next --name main",
|
|
14854
15570
|
"",
|
|
14855
|
-
"
|
|
15571
|
+
" Hosted remote approval path:",
|
|
14856
15572
|
" zk-agent relay inspect --relay-url <url>",
|
|
14857
15573
|
" zk-agent wallet create --relay-url <url> --wait-relay --prompt-code",
|
|
14858
|
-
" zk-agent wallet reapprove --name main --relay-url <url> --wait-relay --prompt-code"
|
|
15574
|
+
" zk-agent wallet reapprove --name main --relay-url <url> --wait-relay --prompt-code",
|
|
15575
|
+
" zk-agent next"
|
|
14859
15576
|
].join("\n")
|
|
14860
15577
|
);
|
|
14861
15578
|
request.addHelpText(
|
|
@@ -14869,7 +15586,11 @@ function createWalletCommand(deps) {
|
|
|
14869
15586
|
" Remote relay completion:",
|
|
14870
15587
|
" zk-agent wallet request relay-publish --request-id <id> --relay-url <url>",
|
|
14871
15588
|
" zk-agent wallet request relay-status --request-id <id> --relay-url <url> --wait",
|
|
14872
|
-
" zk-agent wallet request approve --request-id <id> --relay-url <url> --code <code> --wait"
|
|
15589
|
+
" zk-agent wallet request approve --request-id <id> --relay-url <url> --code <code> --wait",
|
|
15590
|
+
"",
|
|
15591
|
+
" If relay-status returns status = expired:",
|
|
15592
|
+
" zk-agent relay inspect --relay-url <url>",
|
|
15593
|
+
" zk-agent wallet create|reapprove --relay-url <url> --wait-relay --prompt-code"
|
|
14873
15594
|
].join("\n")
|
|
14874
15595
|
);
|
|
14875
15596
|
signer.addHelpText(
|
|
@@ -14968,6 +15689,23 @@ function createWalletCommand(deps) {
|
|
|
14968
15689
|
}
|
|
14969
15690
|
const relay = options.relayUrl ? await publishWalletRequestToRelay(request2, options.relayUrl) : void 0;
|
|
14970
15691
|
if (relayWaitOptions) {
|
|
15692
|
+
if (relay) {
|
|
15693
|
+
printRelayWaitGuidance({
|
|
15694
|
+
requestId: request2.requestId,
|
|
15695
|
+
walletName: request2.walletName,
|
|
15696
|
+
relay,
|
|
15697
|
+
expiresAt: request2.expiresAt,
|
|
15698
|
+
codeEntry: relayWaitOptions.promptCode ? "prompt" : "provided",
|
|
15699
|
+
statusCommand: buildWalletRequestRelayStatusRecommendedCommand(
|
|
15700
|
+
request2.requestId,
|
|
15701
|
+
relayWaitOptions.relayUrl
|
|
15702
|
+
),
|
|
15703
|
+
approveCommand: buildWalletRequestRelayApproveRecommendedCommand(
|
|
15704
|
+
request2.requestId,
|
|
15705
|
+
relayWaitOptions.relayUrl
|
|
15706
|
+
)
|
|
15707
|
+
});
|
|
15708
|
+
}
|
|
14971
15709
|
const { payload, walletRecord } = await finalizePublishedRelayWalletRequest({
|
|
14972
15710
|
walletRequest: request2,
|
|
14973
15711
|
...relayWaitOptions
|
|
@@ -15010,7 +15748,9 @@ function createWalletCommand(deps) {
|
|
|
15010
15748
|
["approval url", request2.approvalUrl],
|
|
15011
15749
|
...relay ? [
|
|
15012
15750
|
["share url", relay.share_url],
|
|
15013
|
-
["status url", relay.status_url]
|
|
15751
|
+
["status url", relay.status_url],
|
|
15752
|
+
["share-link base", relay.share_url.replace(/\/[^/]+$/, "")],
|
|
15753
|
+
["status api base", relay.status_url.replace(/\/[^/]+$/, "")]
|
|
15014
15754
|
] : [],
|
|
15015
15755
|
["expires", request2.expiresAt],
|
|
15016
15756
|
["next local", buildWalletRequestAwaitLocalRecommendedCommand(request2.requestId)],
|
|
@@ -15114,6 +15854,23 @@ function createWalletCommand(deps) {
|
|
|
15114
15854
|
}
|
|
15115
15855
|
const relay = options.relayUrl ? await publishWalletRequestToRelay(request2, options.relayUrl) : void 0;
|
|
15116
15856
|
if (relayWaitOptions) {
|
|
15857
|
+
if (relay) {
|
|
15858
|
+
printRelayWaitGuidance({
|
|
15859
|
+
requestId: request2.requestId,
|
|
15860
|
+
walletName: request2.walletName,
|
|
15861
|
+
relay,
|
|
15862
|
+
expiresAt: request2.expiresAt,
|
|
15863
|
+
codeEntry: relayWaitOptions.promptCode ? "prompt" : "provided",
|
|
15864
|
+
statusCommand: buildWalletRequestRelayStatusRecommendedCommand(
|
|
15865
|
+
request2.requestId,
|
|
15866
|
+
relayWaitOptions.relayUrl
|
|
15867
|
+
),
|
|
15868
|
+
approveCommand: buildWalletRequestRelayApproveRecommendedCommand(
|
|
15869
|
+
request2.requestId,
|
|
15870
|
+
relayWaitOptions.relayUrl
|
|
15871
|
+
)
|
|
15872
|
+
});
|
|
15873
|
+
}
|
|
15117
15874
|
const { payload, walletRecord: approvedWallet } = await finalizePublishedRelayWalletRequest({
|
|
15118
15875
|
walletRequest: request2,
|
|
15119
15876
|
...relayWaitOptions
|
|
@@ -15157,7 +15914,9 @@ function createWalletCommand(deps) {
|
|
|
15157
15914
|
["approval url", request2.approvalUrl],
|
|
15158
15915
|
...relay ? [
|
|
15159
15916
|
["share url", relay.share_url],
|
|
15160
|
-
["status url", relay.status_url]
|
|
15917
|
+
["status url", relay.status_url],
|
|
15918
|
+
["share-link base", relay.share_url.replace(/\/[^/]+$/, "")],
|
|
15919
|
+
["status api base", relay.status_url.replace(/\/[^/]+$/, "")]
|
|
15161
15920
|
] : [],
|
|
15162
15921
|
["expires", request2.expiresAt],
|
|
15163
15922
|
["next local", buildWalletRequestAwaitLocalRecommendedCommand(request2.requestId)],
|
|
@@ -15511,6 +16270,8 @@ function createWalletCommand(deps) {
|
|
|
15511
16270
|
["request", relay.request_id],
|
|
15512
16271
|
["share url", relay.share_url],
|
|
15513
16272
|
["status url", relay.status_url],
|
|
16273
|
+
["share-link base", relay.share_url.replace(/\/[^/]+$/, "")],
|
|
16274
|
+
["status api base", relay.status_url.replace(/\/[^/]+$/, "")],
|
|
15514
16275
|
["next status", buildWalletRequestRelayStatusRecommendedCommand(relay.request_id, options.relayUrl)],
|
|
15515
16276
|
["next approve", buildWalletRequestRelayApproveRecommendedCommand(relay.request_id, options.relayUrl)]
|
|
15516
16277
|
],
|
|
@@ -15529,38 +16290,53 @@ function createWalletCommand(deps) {
|
|
|
15529
16290
|
);
|
|
15530
16291
|
});
|
|
15531
16292
|
request.command("relay-status").description("Inspect the relay status of a published wallet request, optionally waiting until approval is ready").requiredOption("--request-id <id>", "Wallet request id").requiredOption("--relay-url <url>", "Relay server base URL").option("--wait", "Poll until the encrypted relay approval is ready or the request expires").option("--timeout-seconds <seconds>", "How long to wait while polling relay status", "600").option("--interval-ms <milliseconds>", "How often to poll relay status while waiting", "2000").action(async (options) => {
|
|
15532
|
-
const
|
|
15533
|
-
|
|
15534
|
-
|
|
15535
|
-
|
|
16293
|
+
const timeoutMs = parsePositiveIntegerOption(options.timeoutSeconds, "--timeout-seconds", 600) * 1e3;
|
|
16294
|
+
const intervalMs = parsePositiveIntegerOption(options.intervalMs, "--interval-ms", 2e3);
|
|
16295
|
+
let relay;
|
|
16296
|
+
try {
|
|
16297
|
+
relay = options.wait ? await waitForRelayApprovalReady(options.relayUrl, options.requestId, {
|
|
16298
|
+
timeoutMs,
|
|
16299
|
+
intervalMs
|
|
16300
|
+
}) : await fetchRelayStatus(options.relayUrl, options.requestId);
|
|
16301
|
+
} catch (error) {
|
|
16302
|
+
if (options.wait && error instanceof Error && error.message.startsWith("Timed out waiting for relay approval after ")) {
|
|
16303
|
+
throw buildRelayApprovalTimeoutError({
|
|
16304
|
+
requestId: options.requestId,
|
|
16305
|
+
relayUrl: options.relayUrl,
|
|
16306
|
+
timeoutMs,
|
|
16307
|
+
intervalMs
|
|
16308
|
+
});
|
|
16309
|
+
}
|
|
16310
|
+
throw error;
|
|
16311
|
+
}
|
|
16312
|
+
const followUp = await buildRelayStatusFollowUp({
|
|
16313
|
+
relay,
|
|
16314
|
+
relayUrl: options.relayUrl
|
|
16315
|
+
});
|
|
15536
16316
|
printResult(
|
|
15537
16317
|
[
|
|
15538
16318
|
["status", relay.status],
|
|
15539
16319
|
["request", relay.request_id],
|
|
15540
16320
|
["approval ready", relay.approval_ready ? "yes" : "no"],
|
|
15541
|
-
["share url", relay.
|
|
16321
|
+
["share url", relay.share_url],
|
|
16322
|
+
["status url", relay.status_url],
|
|
16323
|
+
["approval url", relay.approval_url],
|
|
16324
|
+
["share-link base", relay.share_url.replace(/\/[^/]+$/, "")],
|
|
16325
|
+
["status api base", relay.status_url.replace(/\/[^/]+$/, "")],
|
|
15542
16326
|
["expires", relay.expires_at],
|
|
15543
|
-
["
|
|
15544
|
-
...
|
|
15545
|
-
|
|
15546
|
-
|
|
15547
|
-
]] : []
|
|
16327
|
+
...followUp.note ? [["note", followUp.note]] : [],
|
|
16328
|
+
...Object.entries(followUp.recommendedCommands).map(
|
|
16329
|
+
([label, command]) => [label, command]
|
|
16330
|
+
)
|
|
15548
16331
|
],
|
|
15549
16332
|
{
|
|
15550
16333
|
ok: true,
|
|
15551
16334
|
walletRequestId: relay.request_id,
|
|
15552
16335
|
relay,
|
|
15553
16336
|
...relayOutputAliases(relay),
|
|
15554
|
-
nextAction:
|
|
15555
|
-
recommendedCommands:
|
|
15556
|
-
|
|
15557
|
-
...relay.approval_ready ? {
|
|
15558
|
-
approve: buildWalletRequestRelayApproveRecommendedCommand(
|
|
15559
|
-
relay.request_id,
|
|
15560
|
-
options.relayUrl
|
|
15561
|
-
)
|
|
15562
|
-
} : {}
|
|
15563
|
-
}
|
|
16337
|
+
nextAction: followUp.nextAction,
|
|
16338
|
+
recommendedCommands: followUp.recommendedCommands,
|
|
16339
|
+
...followUp.note ? { note: followUp.note } : {}
|
|
15564
16340
|
}
|
|
15565
16341
|
);
|
|
15566
16342
|
});
|
|
@@ -15573,6 +16349,24 @@ function createWalletCommand(deps) {
|
|
|
15573
16349
|
if (options.wait && !options.relayUrl) {
|
|
15574
16350
|
throw new Error("--wait is only supported together with --relay-url.");
|
|
15575
16351
|
}
|
|
16352
|
+
if (options.wait && options.relayUrl && !shouldJsonOutput()) {
|
|
16353
|
+
const relayStatus2 = await fetchRelayStatus(options.relayUrl, walletRequest.requestId);
|
|
16354
|
+
printRelayWaitGuidance({
|
|
16355
|
+
requestId: walletRequest.requestId,
|
|
16356
|
+
walletName: walletRequest.walletName,
|
|
16357
|
+
relay: relayStatus2,
|
|
16358
|
+
expiresAt: walletRequest.expiresAt,
|
|
16359
|
+
codeEntry: "provided",
|
|
16360
|
+
statusCommand: buildWalletRequestRelayStatusRecommendedCommand(
|
|
16361
|
+
walletRequest.requestId,
|
|
16362
|
+
options.relayUrl
|
|
16363
|
+
),
|
|
16364
|
+
approveCommand: buildWalletRequestRelayApproveRecommendedCommand(
|
|
16365
|
+
walletRequest.requestId,
|
|
16366
|
+
options.relayUrl
|
|
16367
|
+
)
|
|
16368
|
+
});
|
|
16369
|
+
}
|
|
15576
16370
|
const payload = options.payload ? parseJsonInput(options.payload) : decryptApprovedPayloadForWalletRequest(
|
|
15577
16371
|
walletRequest,
|
|
15578
16372
|
options.encryptedPayload ? parseJsonInput(options.encryptedPayload) : await fetchEncryptedRelayApprovalPayload(options.relayUrl, walletRequest.requestId, {
|
|
@@ -17818,6 +18612,7 @@ async function ensureWorkflowWalletSession(input, deps) {
|
|
|
17818
18612
|
}
|
|
17819
18613
|
function workflowWalletApprovalLines(walletApproval) {
|
|
17820
18614
|
if (!walletApproval) return [];
|
|
18615
|
+
const relayAliases = workflowWalletApprovalRelayAliases(walletApproval.relay);
|
|
17821
18616
|
const lines = [
|
|
17822
18617
|
["wallet approval", walletApproval.stage],
|
|
17823
18618
|
["wallet request", walletApproval.request.requestId]
|
|
@@ -17837,6 +18632,12 @@ function workflowWalletApprovalLines(walletApproval) {
|
|
|
17837
18632
|
if (walletApproval.relay?.status_url) {
|
|
17838
18633
|
lines.push(["status url", walletApproval.relay.status_url]);
|
|
17839
18634
|
}
|
|
18635
|
+
if (relayAliases.walletApprovalRelayShareLinkBaseUrl) {
|
|
18636
|
+
lines.push(["share-link base", relayAliases.walletApprovalRelayShareLinkBaseUrl]);
|
|
18637
|
+
}
|
|
18638
|
+
if (relayAliases.walletApprovalRelayStatusApiBaseUrl) {
|
|
18639
|
+
lines.push(["status api base", relayAliases.walletApprovalRelayStatusApiBaseUrl]);
|
|
18640
|
+
}
|
|
17840
18641
|
if (walletApproval.stage === "request-created" && walletApproval.recommendedCommands) {
|
|
17841
18642
|
lines.push(["next local", walletApproval.recommendedCommands.awaitLocal]);
|
|
17842
18643
|
lines.push(["next remote", walletApproval.recommendedCommands.approve]);
|
|
@@ -17873,7 +18674,8 @@ async function printWorkflowRunCommandResult(execution) {
|
|
|
17873
18674
|
walletName: execution.result.walletName,
|
|
17874
18675
|
nextAction: execution.result.nextCommand,
|
|
17875
18676
|
chain: execution.result.plan.chain,
|
|
17876
|
-
intent: execution.result.intent
|
|
18677
|
+
intent: execution.result.intent,
|
|
18678
|
+
paymasterMode: execution.walletApproval?.request.requestedPaymasterMode ?? extractWorkflowGoalPaymasterMode(execution.goal)
|
|
17877
18679
|
});
|
|
17878
18680
|
printResult(
|
|
17879
18681
|
prependWorkflowRequestId(
|
|
@@ -17896,6 +18698,7 @@ async function printWorkflowRunCommandResult(execution) {
|
|
|
17896
18698
|
result: execution.result,
|
|
17897
18699
|
walletRequestId: execution.walletApproval?.request.requestId,
|
|
17898
18700
|
walletApprovalRelay: execution.walletApproval?.relay,
|
|
18701
|
+
...workflowWalletApprovalRelayAliases(execution.walletApproval?.relay),
|
|
17899
18702
|
walletApprovalRecommendedCommands: execution.walletApproval?.recommendedCommands,
|
|
17900
18703
|
walletApproval: serializeWalletApproval(execution.walletApproval),
|
|
17901
18704
|
recommendedCommands: recommendedCommands2
|
|
@@ -17913,7 +18716,8 @@ async function printWorkflowRunCommandResult(execution) {
|
|
|
17913
18716
|
walletName: execution.status.walletName,
|
|
17914
18717
|
nextAction: execution.status.recommendedCommand,
|
|
17915
18718
|
chain: execution.status.plan.chain,
|
|
17916
|
-
intent: execution.status.intent
|
|
18719
|
+
intent: execution.status.intent,
|
|
18720
|
+
paymasterMode: execution.walletApproval?.request.requestedPaymasterMode ?? extractWorkflowGoalPaymasterMode(execution.checkpoint?.goal)
|
|
17917
18721
|
});
|
|
17918
18722
|
printResult(
|
|
17919
18723
|
prependWorkflowRequestId(
|
|
@@ -17937,6 +18741,7 @@ async function printWorkflowRunCommandResult(execution) {
|
|
|
17937
18741
|
checkpoint: execution.checkpoint,
|
|
17938
18742
|
walletRequestId: execution.walletApproval?.request.requestId,
|
|
17939
18743
|
walletApprovalRelay: execution.walletApproval?.relay,
|
|
18744
|
+
...workflowWalletApprovalRelayAliases(execution.walletApproval?.relay),
|
|
17940
18745
|
walletApprovalRecommendedCommands: execution.walletApproval?.recommendedCommands,
|
|
17941
18746
|
walletApproval: serializeWalletApproval(execution.walletApproval),
|
|
17942
18747
|
recommendedCommands
|
|
@@ -18184,6 +18989,7 @@ async function executeWorkflowAutoCommand(options, deps = resolveWorkflowCommand
|
|
|
18184
18989
|
action: result ? result.stage : walletApproval?.stage ?? status.status,
|
|
18185
18990
|
requestId: context.requestId,
|
|
18186
18991
|
checkpointPersisted: Boolean(checkpoint),
|
|
18992
|
+
goal: context.goal,
|
|
18187
18993
|
checkpoint,
|
|
18188
18994
|
status,
|
|
18189
18995
|
result,
|
|
@@ -18202,7 +19008,8 @@ async function printWorkflowAutoCommandResult(execution) {
|
|
|
18202
19008
|
walletName: execution.status.walletName,
|
|
18203
19009
|
nextAction,
|
|
18204
19010
|
chain: execution.status.plan.chain,
|
|
18205
|
-
intent: execution.status.intent
|
|
19011
|
+
intent: execution.status.intent,
|
|
19012
|
+
paymasterMode: execution.walletApproval?.request.requestedPaymasterMode ?? extractWorkflowGoalPaymasterMode(execution.goal) ?? extractWorkflowGoalPaymasterMode(execution.checkpoint?.goal)
|
|
18206
19013
|
});
|
|
18207
19014
|
const summaryLines = [
|
|
18208
19015
|
["source", execution.source],
|
|
@@ -18237,6 +19044,7 @@ async function printWorkflowAutoCommandResult(execution) {
|
|
|
18237
19044
|
checkpoint: execution.checkpoint,
|
|
18238
19045
|
walletRequestId: execution.walletApproval?.request.requestId,
|
|
18239
19046
|
walletApprovalRelay: execution.walletApproval?.relay,
|
|
19047
|
+
...workflowWalletApprovalRelayAliases(execution.walletApproval?.relay),
|
|
18240
19048
|
walletApprovalRecommendedCommands: execution.walletApproval?.recommendedCommands,
|
|
18241
19049
|
walletApproval: serializeWalletApproval(execution.walletApproval),
|
|
18242
19050
|
recommendedCommands
|
|
@@ -18263,7 +19071,21 @@ function buildWorkflowCheckpointRecommendedCommands(checkpoint) {
|
|
|
18263
19071
|
walletStatus: buildWalletStatusRecommendedCommand(checkpoint.walletName)
|
|
18264
19072
|
};
|
|
18265
19073
|
}
|
|
19074
|
+
function extractWorkflowGoalPaymasterMode(goal) {
|
|
19075
|
+
if (!goal || !("paymaster" in goal)) {
|
|
19076
|
+
return void 0;
|
|
19077
|
+
}
|
|
19078
|
+
return goal.paymaster?.mode;
|
|
19079
|
+
}
|
|
19080
|
+
function extractPaymasterModeFromCommand(command) {
|
|
19081
|
+
if (!command) {
|
|
19082
|
+
return void 0;
|
|
19083
|
+
}
|
|
19084
|
+
const match = command.match(/--paymaster-mode (none|sponsored|approval-based)\b/);
|
|
19085
|
+
return match?.[1];
|
|
19086
|
+
}
|
|
18266
19087
|
function buildWorkflowRuntimeRecommendedCommands(input) {
|
|
19088
|
+
const paymasterMode = extractPaymasterModeFromCommand(input.nextAction) ?? input.paymasterMode;
|
|
18267
19089
|
return {
|
|
18268
19090
|
inspectDefaults: "zk-agent defaults",
|
|
18269
19091
|
list: buildWorkflowListRecommendedCommand(),
|
|
@@ -18287,6 +19109,10 @@ function buildWorkflowRuntimeRecommendedCommands(input) {
|
|
|
18287
19109
|
} : {},
|
|
18288
19110
|
discoverTokens: `zk-agent tokens --chain ${input.chain}`,
|
|
18289
19111
|
inspectToken: `zk-agent resolve-token --chain ${input.chain} --symbol <symbol>`
|
|
19112
|
+
} : {},
|
|
19113
|
+
...input.chain && paymasterMode === "approval-based" ? {
|
|
19114
|
+
discoverPaymasterTokens: buildPaymasterFeeTokensRecommendedCommand(input.chain),
|
|
19115
|
+
inspectPaymasterToken: buildPaymasterFeeTokenResolveRecommendedCommand(input.chain)
|
|
18290
19116
|
} : {}
|
|
18291
19117
|
};
|
|
18292
19118
|
}
|
|
@@ -18304,6 +19130,10 @@ function buildWorkflowPlanRecommendedCommands(plan) {
|
|
|
18304
19130
|
discoverOwnedTokens: buildOwnedTokensRecommendedCommand(plan.walletName),
|
|
18305
19131
|
discoverTokens: buildTokensRecommendedCommand(plan.chain),
|
|
18306
19132
|
inspectToken: buildResolveTokenRecommendedCommand(plan.chain)
|
|
19133
|
+
} : {},
|
|
19134
|
+
...plan.paymasterMode === "approval-based" ? {
|
|
19135
|
+
discoverPaymasterTokens: buildPaymasterFeeTokensRecommendedCommand(plan.chain),
|
|
19136
|
+
inspectPaymasterToken: buildPaymasterFeeTokenResolveRecommendedCommand(plan.chain)
|
|
18307
19137
|
} : {}
|
|
18308
19138
|
};
|
|
18309
19139
|
}
|
|
@@ -18367,11 +19197,29 @@ function serializeWalletApproval(walletApproval) {
|
|
|
18367
19197
|
if (!walletApproval) return void 0;
|
|
18368
19198
|
return {
|
|
18369
19199
|
...walletApproval,
|
|
19200
|
+
...workflowWalletApprovalRelayAliases(walletApproval.relay, {
|
|
19201
|
+
shareLinkBaseField: "relayShareLinkBaseUrl",
|
|
19202
|
+
statusApiBaseField: "relayStatusApiBaseUrl"
|
|
19203
|
+
}),
|
|
18370
19204
|
walletRequestId: walletApproval.request.requestId,
|
|
18371
19205
|
request: sanitizeWalletRequestRecord(walletApproval.request),
|
|
18372
19206
|
wallet: walletApproval.wallet ? sanitizeWalletRecord(walletApproval.wallet) : void 0
|
|
18373
19207
|
};
|
|
18374
19208
|
}
|
|
19209
|
+
function workflowWalletApprovalRelayAliases(relay, fieldNames = {
|
|
19210
|
+
shareLinkBaseField: "walletApprovalRelayShareLinkBaseUrl",
|
|
19211
|
+
statusApiBaseField: "walletApprovalRelayStatusApiBaseUrl"
|
|
19212
|
+
}) {
|
|
19213
|
+
const shareUrl = relay?.share_url;
|
|
19214
|
+
const statusUrl = relay?.status_url;
|
|
19215
|
+
const approvalUrl = relay?.approval_url;
|
|
19216
|
+
const shareLinkBaseUrl = shareUrl ? shareUrl.replace(/\/[^/]+$/, "") : approvalUrl ? approvalUrl.replace(/\/[^/]+$/, "") : void 0;
|
|
19217
|
+
const statusApiBaseUrl = statusUrl ? statusUrl.replace(/\/[^/]+$/, "") : approvalUrl && relay?.request_id ? `${approvalUrl.replace(/\/r\/[^/]+$/, "")}/api/requests` : void 0;
|
|
19218
|
+
return {
|
|
19219
|
+
[fieldNames.shareLinkBaseField]: shareLinkBaseUrl,
|
|
19220
|
+
[fieldNames.statusApiBaseField]: statusApiBaseUrl
|
|
19221
|
+
};
|
|
19222
|
+
}
|
|
18375
19223
|
function addWorkflowGoalOptions(command, config = {}) {
|
|
18376
19224
|
if (config.includeExecutionFlags) {
|
|
18377
19225
|
command.option("--broadcast", "Broadcast the underlying transaction(s) instead of returning a preview", false).option(
|
|
@@ -18533,6 +19381,7 @@ async function executeWorkflowRunCommand(options, deps = resolveWorkflowCommandD
|
|
|
18533
19381
|
if (inspection.walletApproval?.stage === "request-created" || inspection.result.status === "blocked") {
|
|
18534
19382
|
return {
|
|
18535
19383
|
requestId: inspection.requestId,
|
|
19384
|
+
goal: context.goal,
|
|
18536
19385
|
status: inspection.result,
|
|
18537
19386
|
walletApproval: inspection.walletApproval,
|
|
18538
19387
|
checkpoint: inspection.checkpoint
|
|
@@ -18570,6 +19419,7 @@ async function executeWorkflowRunCommand(options, deps = resolveWorkflowCommandD
|
|
|
18570
19419
|
);
|
|
18571
19420
|
return {
|
|
18572
19421
|
requestId: context.requestId,
|
|
19422
|
+
goal: context.goal,
|
|
18573
19423
|
result,
|
|
18574
19424
|
walletApproval
|
|
18575
19425
|
};
|
|
@@ -18646,14 +19496,13 @@ function assertWorkflowResumeReady(result) {
|
|
|
18646
19496
|
}
|
|
18647
19497
|
function buildWorkflowHelpText() {
|
|
18648
19498
|
return [
|
|
18649
|
-
"",
|
|
18650
|
-
"Default workflow path:",
|
|
18651
|
-
" Guided default:",
|
|
18652
|
-
" zk-agent workflow auto --wallet main --intent <intent> [goal flags] --create-checkpoint --execute-when-ready",
|
|
18653
19499
|
"",
|
|
18654
19500
|
" Flagship native pay path:",
|
|
18655
19501
|
" zk-agent workflow pay --wallet main --to <address> --amount <amount>",
|
|
18656
19502
|
"",
|
|
19503
|
+
" Broader multi-intent guided path:",
|
|
19504
|
+
" zk-agent workflow auto --wallet main --intent <intent> [goal flags] --create-checkpoint --execute-when-ready",
|
|
19505
|
+
"",
|
|
18657
19506
|
" Checkpointed execution:",
|
|
18658
19507
|
" zk-agent workflow start --wallet main --intent <intent> [goal flags]",
|
|
18659
19508
|
" zk-agent workflow status --request-id <id>",
|
|
@@ -18663,13 +19512,24 @@ function buildWorkflowHelpText() {
|
|
|
18663
19512
|
" Funding-only step:",
|
|
18664
19513
|
" zk-agent workflow fund --wallet main --amount <amount> --execute",
|
|
18665
19514
|
"",
|
|
19515
|
+
" Token/discovery recovery path:",
|
|
19516
|
+
" zk-agent assets --wallet main",
|
|
19517
|
+
" zk-agent tokens --wallet main --owned",
|
|
19518
|
+
" zk-agent tokens --chain zksync-sepolia",
|
|
19519
|
+
" zk-agent resolve-token --chain zksync-sepolia --symbol USDC",
|
|
19520
|
+
"",
|
|
19521
|
+
" Approval-based paymaster fee-token recovery:",
|
|
19522
|
+
" zk-agent tokens --chain zksync-sepolia --role paymaster-fee-token",
|
|
19523
|
+
" zk-agent resolve-token --chain zksync-sepolia --symbol <symbol> --role paymaster-fee-token",
|
|
19524
|
+
" zk-agent defaults",
|
|
19525
|
+
"",
|
|
18666
19526
|
" Lower-level one-shot escape hatch:",
|
|
18667
19527
|
" zk-agent workflow run --wallet main --intent <intent> [goal flags]"
|
|
18668
19528
|
].join("\n");
|
|
18669
19529
|
}
|
|
18670
19530
|
var WORKFLOW_HELP_COMMAND_ORDER = [
|
|
18671
|
-
"auto",
|
|
18672
19531
|
"pay",
|
|
19532
|
+
"auto",
|
|
18673
19533
|
"start",
|
|
18674
19534
|
"status",
|
|
18675
19535
|
"next",
|
|
@@ -18698,7 +19558,7 @@ function applyWorkflowHelpCommandOrder(workflow) {
|
|
|
18698
19558
|
function createWorkflowCommand(deps) {
|
|
18699
19559
|
const resolvedDeps = resolveWorkflowCommandDeps(deps);
|
|
18700
19560
|
const workflow = new Command10("workflow").description(
|
|
18701
|
-
"
|
|
19561
|
+
"Plan, persist, and execute higher-level wallet workflows"
|
|
18702
19562
|
);
|
|
18703
19563
|
workflow.addHelpText("after", buildWorkflowHelpText());
|
|
18704
19564
|
workflow.command("plan").description("Plan the prerequisite and execution steps for one concrete wallet workflow").requiredOption(
|
|
@@ -18710,15 +19570,19 @@ function createWorkflowCommand(deps) {
|
|
|
18710
19570
|
).option("--to-chain <chain>", "Optional destination chain override for bridge workflows").option("--paymaster-mode <mode>", "none, sponsored, or approval-based").option("--paymaster-address <address>", "Explicit paymaster contract address override").option("--paymaster-token <address>", "ERC-20 token address for approval-based paymaster mode").action(
|
|
18711
19571
|
async (options) => {
|
|
18712
19572
|
const intent = parseWorkflowIntent(options.intent);
|
|
19573
|
+
const paymasterInput = resolveWorkflowPaymasterInput(options);
|
|
18713
19574
|
const { inspection, plan } = await loadWorkflowPlanState(
|
|
18714
19575
|
options.wallet,
|
|
18715
19576
|
intent,
|
|
18716
19577
|
parseWorkflowSwapProtocol(options.protocol),
|
|
18717
19578
|
options.toChain,
|
|
18718
|
-
|
|
19579
|
+
paymasterInput,
|
|
18719
19580
|
resolvedDeps
|
|
18720
19581
|
);
|
|
18721
|
-
const recommendedCommands = buildWorkflowPlanRecommendedCommands(
|
|
19582
|
+
const recommendedCommands = buildWorkflowPlanRecommendedCommands({
|
|
19583
|
+
...plan,
|
|
19584
|
+
paymasterMode: paymasterInput?.mode
|
|
19585
|
+
});
|
|
18722
19586
|
const agentProfile = await loadWorkflowAgentProfile(plan.walletName);
|
|
18723
19587
|
const agentFollowup = buildAgentFollowup(agentProfile, {
|
|
18724
19588
|
walletName: plan.walletName,
|
|
@@ -18936,7 +19800,8 @@ function createWorkflowCommand(deps) {
|
|
|
18936
19800
|
walletName: inspection.result.walletName,
|
|
18937
19801
|
nextAction: inspection.result.recommendedCommand,
|
|
18938
19802
|
chain: inspection.result.plan.chain,
|
|
18939
|
-
intent: inspection.result.intent
|
|
19803
|
+
intent: inspection.result.intent,
|
|
19804
|
+
paymasterMode: inspection.walletApproval?.request.requestedPaymasterMode ?? extractWorkflowGoalPaymasterMode(inspection.checkpoint?.goal)
|
|
18940
19805
|
});
|
|
18941
19806
|
const agentProfile = await loadWorkflowAgentProfile(inspection.result.walletName);
|
|
18942
19807
|
const agentFollowup = buildAgentFollowup(agentProfile, {
|
|
@@ -18965,6 +19830,7 @@ function createWorkflowCommand(deps) {
|
|
|
18965
19830
|
checkpoint: inspection.checkpoint,
|
|
18966
19831
|
walletRequestId: inspection.walletApproval?.request.requestId,
|
|
18967
19832
|
walletApprovalRelay: inspection.walletApproval?.relay,
|
|
19833
|
+
...workflowWalletApprovalRelayAliases(inspection.walletApproval?.relay),
|
|
18968
19834
|
walletApprovalRecommendedCommands: inspection.walletApproval?.recommendedCommands,
|
|
18969
19835
|
walletApproval: serializeWalletApproval(inspection.walletApproval),
|
|
18970
19836
|
recommendedCommands
|
|
@@ -18986,7 +19852,8 @@ function createWorkflowCommand(deps) {
|
|
|
18986
19852
|
walletName: inspection.result.walletName,
|
|
18987
19853
|
nextAction: nextCommand,
|
|
18988
19854
|
chain: inspection.result.plan.chain,
|
|
18989
|
-
intent: inspection.result.intent
|
|
19855
|
+
intent: inspection.result.intent,
|
|
19856
|
+
paymasterMode: inspection.walletApproval?.request.requestedPaymasterMode ?? extractWorkflowGoalPaymasterMode(inspection.checkpoint?.goal)
|
|
18990
19857
|
});
|
|
18991
19858
|
const agentProfile = await loadWorkflowAgentProfile(inspection.result.walletName);
|
|
18992
19859
|
const agentFollowup = buildAgentFollowup(agentProfile, {
|
|
@@ -19028,6 +19895,7 @@ function createWorkflowCommand(deps) {
|
|
|
19028
19895
|
checkpoint: inspection.checkpoint,
|
|
19029
19896
|
walletRequestId: inspection.walletApproval?.request.requestId,
|
|
19030
19897
|
walletApprovalRelay: inspection.walletApproval?.relay,
|
|
19898
|
+
...workflowWalletApprovalRelayAliases(inspection.walletApproval?.relay),
|
|
19031
19899
|
walletApprovalRecommendedCommands: inspection.walletApproval?.recommendedCommands,
|
|
19032
19900
|
walletApproval: serializeWalletApproval(inspection.walletApproval),
|
|
19033
19901
|
recommendedCommands
|
|
@@ -19050,7 +19918,8 @@ function createWorkflowCommand(deps) {
|
|
|
19050
19918
|
walletName: inspection.result.walletName,
|
|
19051
19919
|
nextAction: inspection.result.recommendedCommand,
|
|
19052
19920
|
chain: inspection.result.plan.chain,
|
|
19053
|
-
intent: inspection.result.intent
|
|
19921
|
+
intent: inspection.result.intent,
|
|
19922
|
+
paymasterMode: inspection.walletApproval.request.requestedPaymasterMode
|
|
19054
19923
|
});
|
|
19055
19924
|
const agentProfile2 = await loadWorkflowAgentProfile(inspection.result.walletName);
|
|
19056
19925
|
const agentFollowup2 = buildAgentFollowup(agentProfile2, {
|
|
@@ -19079,6 +19948,7 @@ function createWorkflowCommand(deps) {
|
|
|
19079
19948
|
checkpoint: inspection.checkpoint,
|
|
19080
19949
|
walletRequestId: inspection.walletApproval.request.requestId,
|
|
19081
19950
|
walletApprovalRelay: inspection.walletApproval.relay,
|
|
19951
|
+
...workflowWalletApprovalRelayAliases(inspection.walletApproval.relay),
|
|
19082
19952
|
walletApprovalRecommendedCommands: inspection.walletApproval.recommendedCommands,
|
|
19083
19953
|
walletApproval: serializeWalletApproval(inspection.walletApproval),
|
|
19084
19954
|
recommendedCommands: recommendedCommands2
|
|
@@ -19100,7 +19970,8 @@ function createWorkflowCommand(deps) {
|
|
|
19100
19970
|
walletName: execution.status.walletName,
|
|
19101
19971
|
nextAction: execution.status.recommendedCommand,
|
|
19102
19972
|
chain: execution.status.plan.chain,
|
|
19103
|
-
intent: execution.status.intent
|
|
19973
|
+
intent: execution.status.intent,
|
|
19974
|
+
paymasterMode: execution.walletApproval?.request.requestedPaymasterMode ?? extractWorkflowGoalPaymasterMode(execution.checkpoint?.goal)
|
|
19104
19975
|
});
|
|
19105
19976
|
const agentProfile2 = await loadWorkflowAgentProfile(execution.status.walletName);
|
|
19106
19977
|
const agentFollowup2 = buildAgentFollowup(agentProfile2, {
|
|
@@ -19129,6 +20000,7 @@ function createWorkflowCommand(deps) {
|
|
|
19129
20000
|
checkpoint: execution.checkpoint,
|
|
19130
20001
|
walletRequestId: execution.walletApproval?.request.requestId,
|
|
19131
20002
|
walletApprovalRelay: execution.walletApproval?.relay,
|
|
20003
|
+
...workflowWalletApprovalRelayAliases(execution.walletApproval?.relay),
|
|
19132
20004
|
walletApprovalRecommendedCommands: execution.walletApproval?.recommendedCommands,
|
|
19133
20005
|
walletApproval: serializeWalletApproval(execution.walletApproval),
|
|
19134
20006
|
recommendedCommands: recommendedCommands2
|
|
@@ -19141,7 +20013,8 @@ function createWorkflowCommand(deps) {
|
|
|
19141
20013
|
walletName: execution.result.walletName,
|
|
19142
20014
|
nextAction: execution.result.nextCommand,
|
|
19143
20015
|
chain: execution.result.plan.chain,
|
|
19144
|
-
intent: execution.result.intent
|
|
20016
|
+
intent: execution.result.intent,
|
|
20017
|
+
paymasterMode: execution.walletApproval?.request.requestedPaymasterMode ?? extractWorkflowGoalPaymasterMode(execution.goal)
|
|
19145
20018
|
});
|
|
19146
20019
|
const agentProfile = await loadWorkflowAgentProfile(execution.result.walletName);
|
|
19147
20020
|
const agentFollowup = buildAgentFollowup(agentProfile, {
|
|
@@ -19170,6 +20043,7 @@ function createWorkflowCommand(deps) {
|
|
|
19170
20043
|
result: execution.result,
|
|
19171
20044
|
walletRequestId: inspection.walletApproval?.request.requestId,
|
|
19172
20045
|
walletApprovalRelay: inspection.walletApproval?.relay,
|
|
20046
|
+
...workflowWalletApprovalRelayAliases(inspection.walletApproval?.relay),
|
|
19173
20047
|
walletApprovalRecommendedCommands: inspection.walletApproval?.recommendedCommands,
|
|
19174
20048
|
walletApproval: serializeWalletApproval(inspection.walletApproval),
|
|
19175
20049
|
recommendedCommands
|
|
@@ -19207,15 +20081,24 @@ function createWorkflowCommand(deps) {
|
|
|
19207
20081
|
function buildDefaultOperatorPathHelpText() {
|
|
19208
20082
|
return [
|
|
19209
20083
|
"",
|
|
19210
|
-
"
|
|
20084
|
+
"Public entrypoints:",
|
|
20085
|
+
" Agent harness: npx skills add https://github.com/AgiWeb3/zk-agent-cli",
|
|
20086
|
+
" One-shot CLI: npx zk-agent-cli --help",
|
|
20087
|
+
" Global CLI: npm install -g zk-agent-cli",
|
|
20088
|
+
"",
|
|
20089
|
+
"Canonical terminal path:",
|
|
19211
20090
|
" zk-agent setup",
|
|
19212
20091
|
" zk-agent next",
|
|
19213
20092
|
" zk-agent wallet create --await-local",
|
|
19214
20093
|
" zk-agent next",
|
|
19215
|
-
` ${
|
|
20094
|
+
` ${buildWorkflowPayRecommendedCommand("main")}`,
|
|
20095
|
+
"",
|
|
20096
|
+
"No custom .env is required for setup, next, or wallet create/reapprove request generation.",
|
|
20097
|
+
"Add RPC env vars later, before live reads or broadcasts.",
|
|
19216
20098
|
"",
|
|
19217
20099
|
"Use `zk-agent next --request-id <id>` to continue a stored workflow checkpoint.",
|
|
19218
|
-
"Use `zk-agent
|
|
20100
|
+
"Use `zk-agent relay inspect --relay-url <url>` plus `zk-agent wallet create|reapprove --relay-url <url> --wait-relay --prompt-code` when the browser is not colocated.",
|
|
20101
|
+
"Use `zk-agent wallet --help` for wallet recovery details and `zk-agent workflow --help` when the intent is broader than the flagship native-send path."
|
|
19219
20102
|
].join("\n");
|
|
19220
20103
|
}
|
|
19221
20104
|
var ROOT_HELP_COMMAND_ORDER = [
|
|
@@ -19256,7 +20139,9 @@ function applyRootHelpCommandOrder(program) {
|
|
|
19256
20139
|
program.commands = sortedCommands;
|
|
19257
20140
|
}
|
|
19258
20141
|
function createProgram() {
|
|
19259
|
-
const program = new Command11().name("zk-agent").description(
|
|
20142
|
+
const program = new Command11().name("zk-agent").description(
|
|
20143
|
+
"Local-first zkSync Era CLI for wallet approval, workflow execution, and hosted relay recovery"
|
|
20144
|
+
).showHelpAfterError().option("--json", "Force JSON output for agent harnesses", false).hook("preAction", (thisCommand) => {
|
|
19260
20145
|
if (thisCommand.optsWithGlobals().json) process.env.ZK_AGENT_OUTPUT = "json";
|
|
19261
20146
|
});
|
|
19262
20147
|
program.addCommand(createInitCommand());
|