@tokamak-private-dapps/private-state-cli 2.4.1 → 2.4.2

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/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 2.4.2 - 2026-05-30
6
+
7
+ - Changed channel workspace recovery guidance so CLI help, guide output, agent instructions, and documentation direct
8
+ users to registered workspace mirrors before explicit RPC genesis rebuilds.
9
+
5
10
  ## 2.4.1 - 2026-05-30
6
11
 
7
12
  - Classified `UnexpectedCurrentRootVector()` submit reverts as stale channel-root failures with recovery hints that
package/README.md CHANGED
@@ -199,7 +199,14 @@ unless the user explicitly understands the compliance implications. Prefer a sel
199
199
 
200
200
  Workspace recovery commands use saved recovery indexes by default. If the local channel workspace is missing,
201
201
  corrupted, or does not contain a usable index, `channel recover-workspace` stops with an explicit error instead of
202
- silently replaying logs from channel genesis. Use `channel recover-workspace --source rpc --from-genesis` only when
202
+ silently replaying logs from channel genesis. When the channel has a registered workspace mirror, recover from the
203
+ mirror first:
204
+
205
+ ```bash
206
+ private-state-cli channel recover-workspace --channel-name <CHANNEL> --network mainnet --source mirror
207
+ ```
208
+
209
+ Use `channel recover-workspace --source rpc --from-genesis` only when no compatible workspace mirror is available and
203
210
  you intentionally want to rebuild channel workspace state from the channel creation block:
204
211
 
205
212
  ```bash
@@ -226,9 +233,9 @@ existing history, while `--from-genesis` overwrites it with one full genesis-to-
226
233
  by replaying from the channel's genesis block because no prior recovery index can exist for a new channel.
227
234
 
228
235
  `channel join` refreshes stale channel workspace state through the saved recovery index before submitting the
229
- registration transaction. For a channel that was created elsewhere, run `channel recover-workspace --source rpc --from-genesis`
230
- once before joining, or recover from a registered workspace mirror; later joins and wallet commands resume from the
231
- saved index instead of silently replaying from genesis.
236
+ registration transaction. For a channel that was created elsewhere, recover from a registered workspace mirror first.
237
+ Use `channel recover-workspace --source rpc --from-genesis` only when no compatible mirror is available; later joins
238
+ and wallet commands resume from the saved index instead of silently replaying from genesis.
232
239
 
233
240
  Wallet commands that need channel state, including `wallet recover-workspace`, `wallet get-meta`,
234
241
  `wallet get-channel-fund`, and `wallet get-notes`, refresh stale local channel workspaces through saved recovery
package/agents.md CHANGED
@@ -37,12 +37,13 @@ activity or as a bridge-wide disclosure rule for every DApp.
37
37
  `private-state-cli set rpc --network <NETWORK> --rpc-url <URL> --provider <PROVIDER>`, or with explicit
38
38
  `--log-requests-per-second` and `--block-range-cap` values when the provider is not built in.
39
39
  - A workspace recovery index is the saved block pointer and state-root hash that lets the CLI resume log scanning
40
- without replaying the channel from its creation block. If it is missing, explain `--from-genesis` before using it
41
- because genesis replay can take much longer.
40
+ without replaying the channel from its creation block. If it is missing, check whether the channel has a registered
41
+ workspace mirror before explaining or using `--from-genesis`, because genesis replay can take much longer.
42
42
  - Before guiding a user to run `channel recover-workspace --source rpc --from-genesis`, explain that RPC genesis
43
- recovery can be very slow because it scans channel logs from the creation block. If a channel workspace mirror is
44
- available, try mirror-based recovery first, and use RPC genesis replay only when mirror recovery is unavailable or
45
- unsuitable.
43
+ recovery can be very slow because it scans channel logs from the creation block. Run or suggest
44
+ `channel get-meta --channel-name <CHANNEL> --network <NETWORK>` first; if `workspaceMirror` is set, try
45
+ `channel recover-workspace --channel-name <CHANNEL> --network <NETWORK> --source mirror`. Use RPC genesis replay only
46
+ when no compatible workspace mirror is available.
46
47
  - When the user asks about gas use, transaction fees, transaction cost, or USD cost for private-state CLI commands, run
47
48
  `private-state-cli help transaction-fees --network <NETWORK> --json` and answer from the returned `rows`. If the
48
49
  network is unclear, ask which network to use. Do not tell the user to ask the developer unless the command fails after
@@ -210,7 +210,7 @@ export const PRIVATE_STATE_CLI_FIELD_CATALOG = Object.freeze({
210
210
  fromGenesis: {
211
211
  label: "Scan From Genesis",
212
212
  type: "checkbox",
213
- hint: "Requires --source rpc. Ignore the local recovery index and replay channel logs from genesis.",
213
+ hint: "Requires --source rpc. Use only when no compatible workspace mirror is available and a full genesis replay is intentional.",
214
214
  option: "--from-genesis",
215
215
  optional: true,
216
216
  },
@@ -233,7 +233,7 @@ export const PRIVATE_STATE_CLI_FIELD_CATALOG = Object.freeze({
233
233
  type: "select",
234
234
  options: ["rpc", "mirror"],
235
235
  valueLabel: "<rpc|mirror>",
236
- hint: "Optional. Defaults to rpc. mirror validates the channel leader's checkpoint manifest and downloads only the needed checkpoint or delta bundle before RPC delta replay.",
236
+ hint: "Use mirror first when a channel workspace mirror is registered. If omitted, the CLI uses rpc and resumes from the local recovery index when available.",
237
237
  option: "--source",
238
238
  optional: true,
239
239
  },
@@ -429,12 +429,13 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
429
429
  optionalFields: ["source", "fromGenesis", "outputRaw", "publishWorkspaceMirror", "leaderAccount", "output", "force"],
430
430
  usage: "--channel-name, --network, optional --source, optional --from-genesis, optional --output-raw, optional --publish-workspace-mirror with --leader-account and --output, optional --force",
431
431
  help: [
432
- "By default, --source rpc resumes RPC log scanning from the workspace recovery index when available",
432
+ "When a channel workspace mirror is registered, try --source mirror before an explicit RPC genesis rebuild",
433
433
  "--source mirror validates the channel leader's registered checkpoint manifest, downloads only the needed checkpoint or delta bundle, and then replays RPC logs to latest",
434
+ "If --source is omitted, the CLI uses rpc and resumes RPC log scanning from the workspace recovery index when available",
434
435
  "RPC recovery writes a usable channel workspace checkpoint after each RPC log chunk, so interrupted runs can resume from the last completed chunk",
435
436
  "Mirror recovery uses a matching delta bundle when available; otherwise a newer verified full checkpoint replaces the local checkpoint before RPC catch-up",
436
437
  "Fails instead of falling back to genesis when no usable recovery index exists",
437
- "Use --source rpc --from-genesis to ignore the recovery index and replay logs from channel genesis",
438
+ "Use --source rpc --from-genesis only when no compatible workspace mirror is available and you intentionally want to replay logs from channel genesis",
438
439
  "--output-raw with --source rpc appends raw JSON-RPC request and response history to method-specific JSON files under the channel workspace rpcCallHistory directory; eth_getLogs is split by event",
439
440
  "--from-genesis moves the existing local channel workspace to workspace-rebuild-backups before writing the current-format workspace; local secrets are preserved",
440
441
  "--publish-workspace-mirror writes manifest.json, checkpoint.zip, and any needed delta bundle after recovery",
@@ -524,7 +525,7 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
524
525
  usage: "--channel-name, --network, --account, --wallet-secret-path, --acknowledge-action-impact",
525
526
  help: [
526
527
  "Refreshes the local channel workspace through the saved recovery index before joining when the scan fits the 7,200-block pre-command budget",
527
- "Fails instead of replaying from genesis; run channel recover-workspace --source rpc --from-genesis when a genesis rebuild is required",
528
+ "Fails instead of replaying from genesis; recover from a registered workspace mirror first, and use channel recover-workspace --source rpc --from-genesis only when no compatible mirror is available",
528
529
  "--wallet-secret-path is read once for channel-bound L2 spending-key derivation and is not stored in the wallet workspace",
529
530
  "Pays any join toll directly from the L1 wallet, not from bridge-deposited balance",
530
531
  "Prints the immutable policy snapshot before first registration",
package/lib/runtime.mjs CHANGED
@@ -2061,7 +2061,8 @@ async function syncChannelWorkspace({
2061
2061
  throw new Error([
2062
2062
  `Workspace recovery index is missing or unusable for channel ${channelName} on ${networkNameFromChainId(network.chainId)}.`,
2063
2063
  "The CLI will not fall back to replaying channel logs from genesis unless explicitly requested.",
2064
- "Run channel recover-workspace first to refresh the local channel workspace.",
2064
+ `If a workspace mirror is registered, run channel recover-workspace --channel-name ${channelName} --network ${networkNameFromChainId(network.chainId)} --source mirror first.`,
2065
+ `Use channel recover-workspace --channel-name ${channelName} --network ${networkNameFromChainId(network.chainId)} --source rpc --from-genesis only when no compatible mirror is available.`,
2065
2066
  ].join(" "));
2066
2067
  }
2067
2068
  const workspaceBase = {
@@ -3873,12 +3874,14 @@ async function inspectGuideChannel({ channelName, network, provider, artifactsIn
3873
3874
  bridgeResources.bridgeAbiManifest.contracts.channelManager.abi,
3874
3875
  provider,
3875
3876
  );
3876
- const [joinToll, refundSchedule] = await Promise.all([
3877
+ const [joinToll, refundSchedule, workspaceMirror] = await Promise.all([
3877
3878
  channelManager.joinToll(),
3878
3879
  readChannelRefundSchedule(channelManager),
3880
+ readChannelWorkspaceMirror({ bridgeCore, channelId }),
3879
3881
  ]);
3880
3882
  result.onchain.joinTollBaseUnits = joinToll.toString();
3881
3883
  result.onchain.refundSchedule = refundSchedule;
3884
+ result.onchain.workspaceMirror = workspaceMirror;
3882
3885
  }
3883
3886
  } catch (error) {
3884
3887
  result.error = error.message;
@@ -4054,9 +4057,19 @@ function applyGuideNextAction(guide) {
4054
4057
  return;
4055
4058
  }
4056
4059
  if (guide.selectors.channelName && guide.state.channel?.onchain?.exists && !guide.state.channel?.local?.workspaceExists) {
4060
+ const workspaceMirror = typeof guide.state.channel.onchain.workspaceMirror === "string"
4061
+ ? guide.state.channel.onchain.workspaceMirror.trim()
4062
+ : "";
4063
+ if (workspaceMirror) {
4064
+ setGuideNextAction(guide, {
4065
+ command: `channel recover-workspace --channel-name ${guide.selectors.channelName} --network ${guide.selectors.network} --source mirror`,
4066
+ why: "The channel has a registered workspace mirror. Use mirror recovery before considering an explicit RPC genesis rebuild.",
4067
+ });
4068
+ return;
4069
+ }
4057
4070
  setGuideNextAction(guide, {
4058
4071
  command: `channel recover-workspace --channel-name ${guide.selectors.channelName} --network ${guide.selectors.network} --source rpc --from-genesis`,
4059
- why: "The channel exists on-chain, but the local channel workspace has not been recovered yet, so there is no local recovery index to resume from.",
4072
+ why: "The channel exists on-chain, but the local channel workspace has not been recovered yet and no workspace mirror is registered. RPC genesis rebuild is the remaining explicit bootstrap path.",
4060
4073
  });
4061
4074
  return;
4062
4075
  }
@@ -11802,7 +11815,9 @@ function buildRecoveryHints(error, args = {}) {
11802
11815
  }
11803
11816
 
11804
11817
  if (error?.code === CLI_ERROR_CODES.STALE_WORKSPACE) {
11805
- hints.push(`private-state-cli channel recover-workspace --channel-name ${channelName} --network ${networkName}`);
11818
+ hints.push(`private-state-cli channel get-meta --channel-name ${channelName} --network ${networkName}`);
11819
+ hints.push(`if workspaceMirror is set: private-state-cli channel recover-workspace --channel-name ${channelName} --network ${networkName} --source mirror`);
11820
+ hints.push(`otherwise use indexed RPC recovery: private-state-cli channel recover-workspace --channel-name ${channelName} --network ${networkName}`);
11806
11821
  hints.push(`private-state-cli help guide --network ${networkName} --channel-name ${channelName}`);
11807
11822
  }
11808
11823
 
@@ -11810,7 +11825,9 @@ function buildRecoveryHints(error, args = {}) {
11810
11825
  error?.code === CLI_ERROR_CODES.STALE_CHANNEL_ROOT
11811
11826
  || message.includes("UnexpectedCurrentRootVector")
11812
11827
  ) {
11813
- hints.push(`private-state-cli channel recover-workspace --channel-name ${channelName} --network ${networkName}`);
11828
+ hints.push(`private-state-cli channel get-meta --channel-name ${channelName} --network ${networkName}`);
11829
+ hints.push(`if workspaceMirror is set: private-state-cli channel recover-workspace --channel-name ${channelName} --network ${networkName} --source mirror`);
11830
+ hints.push(`otherwise use indexed RPC recovery: private-state-cli channel recover-workspace --channel-name ${channelName} --network ${networkName}`);
11814
11831
  if (walletName !== "<WALLET>") {
11815
11832
  hints.push(`private-state-cli wallet get-notes --wallet ${walletName} --network ${networkName}`);
11816
11833
  }
@@ -11818,7 +11835,9 @@ function buildRecoveryHints(error, args = {}) {
11818
11835
  }
11819
11836
 
11820
11837
  if (message.includes("Workspace recovery index is missing or unusable")) {
11821
- hints.push(`private-state-cli channel recover-workspace --channel-name ${channelName} --network ${networkName}`);
11838
+ hints.push(`private-state-cli channel get-meta --channel-name ${channelName} --network ${networkName}`);
11839
+ hints.push(`if workspaceMirror is set: private-state-cli channel recover-workspace --channel-name ${channelName} --network ${networkName} --source mirror`);
11840
+ hints.push(`only if no compatible workspace mirror is available: private-state-cli channel recover-workspace --channel-name ${channelName} --network ${networkName} --source rpc --from-genesis`);
11822
11841
  }
11823
11842
 
11824
11843
  if (message.includes("Wallet note recovery index is missing or unusable")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokamak-private-dapps/private-state-cli",
3
- "version": "2.4.1",
3
+ "version": "2.4.2",
4
4
  "description": "Command-line client for the Tokamak private-state DApp.",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "author": "Tokamak Network",