@toon-protocol/rig 2.12.0 → 2.13.0

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/dist/cli/rig.js CHANGED
@@ -21,14 +21,16 @@ import {
21
21
  } from "../chunk-EEUHZNWS.js";
22
22
  import {
23
23
  DEFAULT_KEYSTORE_PASSWORD,
24
+ MinaZkAppStore,
24
25
  MissingIdentityError,
26
+ TOPOLOGY_CACHE_FILENAME,
25
27
  clientConfigPath,
26
28
  clientKeystorePath,
27
29
  linkKeystoreInClientConfig,
28
30
  readClientConfigFile,
29
31
  resolveAccountIndex,
30
32
  resolveIdentity
31
- } from "../chunk-GZUDRNOK.js";
33
+ } from "../chunk-FFQXFV4W.js";
32
34
  import {
33
35
  ChannelMapStore,
34
36
  channelStatus,
@@ -40,6 +42,9 @@ import {
40
42
  MAX_OBJECT_SIZE,
41
43
  flooredUploadFee
42
44
  } from "../chunk-35ALWUDJ.js";
45
+ import {
46
+ minaPresetForChain
47
+ } from "../chunk-ACTH6ISJ.js";
43
48
  import {
44
49
  COMMENT_KIND,
45
50
  authorizedStatusAuthors,
@@ -1074,7 +1079,7 @@ function loadPaidSession(deps, relayUrl) {
1074
1079
  });
1075
1080
  }
1076
1081
  var defaultLoadStandalone = async (options) => {
1077
- const mod = await import("../standalone-mode-U3OOSVOB.js");
1082
+ const mod = await import("../standalone-mode-D2YSANBJ.js");
1078
1083
  return mod.createStandaloneContext(options);
1079
1084
  };
1080
1085
  function identityReport(ctx) {
@@ -1941,6 +1946,9 @@ async function runChain(args, deps) {
1941
1946
  }
1942
1947
 
1943
1948
  // src/cli/channel.ts
1949
+ import { readFileSync as readFileSync3 } from "fs";
1950
+ import { homedir as homedir3 } from "os";
1951
+ import { join as join3 } from "path";
1944
1952
  import { parseArgs as parseArgs5 } from "util";
1945
1953
  var CHANNEL_USAGE = `Usage: rig channel <subcommand>
1946
1954
 
@@ -1963,6 +1971,17 @@ Subcommands:
1963
1971
  apex); --deposit adds that much extra collateral after the
1964
1972
  open/resume. On-chain: asks for confirmation (--yes skips).
1965
1973
 
1974
+ deploy-zkapp [--graphql-url <url>]
1975
+ deploy a dedicated Mina PaymentChannel zkApp for THIS
1976
+ identity (the zkApp is single-pair; Mina channels open on
1977
+ an identity-owned deployment). Normally automatic \u2014 the
1978
+ Mina open path deploys one when needed \u2014 this explicit
1979
+ form pre-deploys it (compile \u22481-3 min, inclusion \u22483-6 min).
1980
+ On-chain: costs the 1 MINA account-creation fee + tx fee
1981
+ from the wallet's MINA. The zkApp key is saved under
1982
+ TOON_CLIENT_HOME/keys/. Asks for confirmation (--yes
1983
+ skips).
1984
+
1966
1985
  close <channelId>
1967
1986
  close a recorded channel \u2014 an on-chain tx that starts the
1968
1987
  settlement challenge window (the peer's settlementTimeout).
@@ -1986,6 +2005,8 @@ async function runChannel(args, deps) {
1986
2005
  return runChannelList(rest, deps);
1987
2006
  case "open":
1988
2007
  return runChannelOpen(rest, deps);
2008
+ case "deploy-zkapp":
2009
+ return runChannelDeployZkApp(rest, deps);
1989
2010
  case "close":
1990
2011
  return runChannelWithdrawStep(rest, deps, "close");
1991
2012
  case "settle":
@@ -2178,6 +2199,9 @@ async function runChannelOpen(args, deps) {
2178
2199
  io2.out(
2179
2200
  "If a live channel is already recorded for this peer it is RESUMED (no on-chain spend); otherwise an on-chain channel open locks the peer-negotiated initial deposit from your wallet (plus gas)."
2180
2201
  );
2202
+ io2.out(
2203
+ "On a Mina chain a first open may also deploy a dedicated PaymentChannel zkApp for this identity (~1.1 MINA + fees; compile \u22481-3 min, inclusion \u22483-6 min \u2014 progress is printed)."
2204
+ );
2181
2205
  }
2182
2206
  const gate = await confirmOnChain(
2183
2207
  io2,
@@ -2236,6 +2260,160 @@ async function runChannelOpen(args, deps) {
2236
2260
  await stopQuietly(ctx);
2237
2261
  }
2238
2262
  }
2263
+ async function runChannelDeployZkApp(args, deps) {
2264
+ const { io: io2, env } = deps;
2265
+ let graphqlFlag;
2266
+ let yes = false;
2267
+ let json = false;
2268
+ try {
2269
+ const { values } = parseArgs5({
2270
+ args,
2271
+ options: {
2272
+ "graphql-url": { type: "string" },
2273
+ yes: { type: "boolean", default: false },
2274
+ json: { type: "boolean", default: false },
2275
+ help: { type: "boolean", short: "h", default: false }
2276
+ }
2277
+ });
2278
+ if (values.help) {
2279
+ io2.out(CHANNEL_USAGE);
2280
+ return 0;
2281
+ }
2282
+ graphqlFlag = values["graphql-url"];
2283
+ yes = values.yes ?? false;
2284
+ json = values.json ?? false;
2285
+ } catch (err) {
2286
+ io2.err(err instanceof Error ? err.message : String(err));
2287
+ io2.err(CHANNEL_USAGE);
2288
+ return 2;
2289
+ }
2290
+ try {
2291
+ const dir = env["TOON_CLIENT_HOME"] ?? join3(homedir3(), ".toon-client");
2292
+ let file = {};
2293
+ try {
2294
+ file = JSON.parse(readFileSync3(join3(dir, "config.json"), "utf8"));
2295
+ } catch {
2296
+ }
2297
+ const pinned = env["TOON_CLIENT_CHAIN"] ?? file.chain;
2298
+ const chain = pinned !== void 0 && pinned.startsWith("mina:") ? pinned : "mina:devnet";
2299
+ const graphqlUrl = graphqlFlag ?? file.minaChannel?.graphqlUrl ?? minaPresetForChain(chain)?.graphqlUrl;
2300
+ if (!graphqlUrl) {
2301
+ throw new Error(
2302
+ `no Mina GraphQL endpoint for ${chain} \u2014 pass --graphql-url or set minaChannel.graphqlUrl in the client config`
2303
+ );
2304
+ }
2305
+ const resolved = await resolveIdentity({
2306
+ env,
2307
+ cwd: deps.cwd,
2308
+ warn: (line) => io2.err(line)
2309
+ });
2310
+ const identity = {
2311
+ pubkey: resolved.pubkey,
2312
+ source: resolved.source,
2313
+ sourceLabel: resolved.sourceLabel
2314
+ };
2315
+ const store = MinaZkAppStore.forHome(dir);
2316
+ const existing = store.lookup(resolved.pubkey, chain);
2317
+ if (existing) {
2318
+ if (json) {
2319
+ io2.emitJson({
2320
+ command: "channel deploy-zkapp",
2321
+ identity,
2322
+ executed: false,
2323
+ plan: { chain, graphqlUrl },
2324
+ result: {
2325
+ zkAppAddress: existing.zkAppAddress,
2326
+ deployTxHash: existing.deployTxHash ?? null,
2327
+ vkHash: existing.vkHash ?? null,
2328
+ storePath: store.filePath
2329
+ },
2330
+ hint: "a zkApp is already recorded for this identity/chain \u2014 the open path reuses it"
2331
+ });
2332
+ return 0;
2333
+ }
2334
+ io2.out(
2335
+ `A Mina zkApp is already recorded for this identity on ${chain}: ` + existing.zkAppAddress
2336
+ );
2337
+ io2.out(`The open path reuses it (record: ${store.filePath}).`);
2338
+ return 0;
2339
+ }
2340
+ const plan = { chain, graphqlUrl };
2341
+ if (!json) {
2342
+ io2.out("Mina zkApp deploy plan:");
2343
+ io2.out(` chain ${chain}`);
2344
+ io2.out(` graphql ${graphqlUrl}`);
2345
+ io2.out(renderIdentityLine(identity));
2346
+ io2.out(
2347
+ "Deploys a dedicated PaymentChannel zkApp for this identity \u2014 on-chain: the 1 MINA account-creation fee + a 0.1 MINA tx fee from your wallet. Compile \u22481-3 min; inclusion \u22483-6 min."
2348
+ );
2349
+ }
2350
+ const gate = await confirmOnChain(
2351
+ io2,
2352
+ { yes, json },
2353
+ "Proceed with the on-chain zkApp deploy? [y/N] "
2354
+ );
2355
+ if (gate === "json-plan") {
2356
+ io2.emitJson({
2357
+ command: "channel deploy-zkapp",
2358
+ identity,
2359
+ executed: false,
2360
+ plan,
2361
+ hint: "plan only \u2014 re-run with --yes to deploy (on-chain: ~1.1 MINA + fees)"
2362
+ });
2363
+ return 0;
2364
+ }
2365
+ if (gate !== "proceed") return gate;
2366
+ const client = await import("@toon-protocol/client");
2367
+ const derived = await client.deriveFullIdentity(
2368
+ resolved.mnemonic,
2369
+ resolved.accountIndex
2370
+ );
2371
+ if (!derived.mina.privateKey) {
2372
+ throw new Error(
2373
+ "no Mina key derived \u2014 the optional `mina-signer` dependency is not installed"
2374
+ );
2375
+ }
2376
+ const record = await client.deployMinaChannelZkApp({
2377
+ graphqlUrl,
2378
+ payerPrivateKey: derived.mina.privateKey,
2379
+ onProgress: (line) => io2.err(`rig: mina: ${line}`)
2380
+ });
2381
+ store.save({
2382
+ identity: resolved.pubkey,
2383
+ chain,
2384
+ zkAppAddress: record.zkAppAddress,
2385
+ zkAppPrivateKey: record.zkAppPrivateKey,
2386
+ feePayer: record.feePayer,
2387
+ ...record.deployTxHash !== void 0 ? { deployTxHash: record.deployTxHash } : {},
2388
+ ...record.vkHash !== void 0 ? { vkHash: record.vkHash } : {},
2389
+ deployedAt: (/* @__PURE__ */ new Date()).toISOString(),
2390
+ source: "rig channel deploy-zkapp (npm @toon-protocol/mina-zkapp build)"
2391
+ });
2392
+ if (json) {
2393
+ io2.emitJson({
2394
+ command: "channel deploy-zkapp",
2395
+ identity,
2396
+ executed: true,
2397
+ plan,
2398
+ result: {
2399
+ zkAppAddress: record.zkAppAddress,
2400
+ deployTxHash: record.deployTxHash ?? null,
2401
+ vkHash: record.vkHash ?? null,
2402
+ storePath: store.filePath
2403
+ }
2404
+ });
2405
+ return 0;
2406
+ }
2407
+ io2.out(`Deployed Mina PaymentChannel zkApp ${record.zkAppAddress}.`);
2408
+ if (record.deployTxHash) io2.out(` deploy tx ${record.deployTxHash}`);
2409
+ if (record.vkHash) io2.out(` vk hash ${record.vkHash}`);
2410
+ io2.out(` record ${store.filePath} (holds the zkApp key \u2014 back it up)`);
2411
+ io2.out("The next Mina channel open/push finds and reuses this zkApp.");
2412
+ return 0;
2413
+ } catch (err) {
2414
+ return emitCliError(io2, json, "channel deploy-zkapp", err);
2415
+ }
2416
+ }
2239
2417
  function withdrawPrecheck(step, channelId, watermark, nowSec) {
2240
2418
  const status = channelStatus(watermark, nowSec);
2241
2419
  if (status === "settled") {
@@ -2405,7 +2583,7 @@ async function stopQuietly(ctx) {
2405
2583
 
2406
2584
  // src/cli/clone.ts
2407
2585
  import { mkdtemp, mkdir, readdir, rename, rm, rmdir } from "fs/promises";
2408
- import { basename, dirname as dirname2, join as join3, resolve } from "path";
2586
+ import { basename, dirname as dirname2, join as join4, resolve } from "path";
2409
2587
  import { parseArgs as parseArgs6 } from "util";
2410
2588
  var CLONE_USAGE = `Usage: rig clone <relay-url> <owner>/<repo-id> [dir] [options]
2411
2589
 
@@ -2576,7 +2754,7 @@ async function runClone(args, deps) {
2576
2754
  }
2577
2755
  const parent = dirname2(dest);
2578
2756
  await mkdir(parent, { recursive: true });
2579
- tempDir = await mkdtemp(join3(parent, `.${basename(dest)}.rig-clone-`));
2757
+ tempDir = await mkdtemp(join4(parent, `.${basename(dest)}.rig-clone-`));
2580
2758
  await runGit(tempDir, [
2581
2759
  "init",
2582
2760
  "--quiet",
@@ -3822,8 +4000,288 @@ async function warnIfNotMaintainer(deps, args) {
3822
4000
  }
3823
4001
  }
3824
4002
 
3825
- // src/cli/fetch.ts
4003
+ // src/cli/entry.ts
4004
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
4005
+ import { homedir as homedir4 } from "os";
4006
+ import { dirname as dirname3, join as join5 } from "path";
3826
4007
  import { parseArgs as parseArgs9 } from "util";
4008
+ var SANDBOX_BTP_URL = "wss://proxy.sandbox.devnet.toonprotocol.dev:443";
4009
+ var SANDBOX_RELAY_URL = "wss://relay-ws.sandbox.devnet.toonprotocol.dev";
4010
+ var ENTRY_USAGE = `Usage: rig entry [apex | sandbox | <wss-url>] [options]
4011
+
4012
+ Choose which network entry node (payment ingress + relay) rig talks to. Free:
4013
+ only the local config file is touched.
4014
+
4015
+ rig entry show the effective entry endpoints and their source
4016
+ rig entry apex revert to the default apex: clears the btpUrl/
4017
+ relayUrl override so core's genesis seed (or a live
4018
+ announce) applies \u2014 settles evm | sol | mina
4019
+ rig entry sandbox the devnet sandbox entry (Mina USDC ONLY \u2014 the
4020
+ cross-currency multihop demo path):
4021
+ btp ${SANDBOX_BTP_URL}
4022
+ relay ${SANDBOX_RELAY_URL}
4023
+ rig entry <wss-url> an explicit BTP endpoint (ws:// or wss://); pass
4024
+ --relay <url> to also set the relay
4025
+
4026
+ Switching entries deletes the cached topology (the next paid command
4027
+ re-discovers the new entry's announce) and leaves existing payment channels
4028
+ behind \u2014 channels are per-entry-peer; the next paid command opens or resumes
4029
+ one with the new peer.
4030
+
4031
+ NOTE for repos: the relay a repo publishes to is its git \`origin\` remote,
4032
+ which OVERRIDES the config relayUrl. After switching entries, point the repo
4033
+ too: \`rig remote add origin <relay-url>\` (or use a fresh repo).
4034
+
4035
+ Options:
4036
+ --relay <url> with <wss-url>: also set the relay URL
4037
+ --json machine-readable envelope
4038
+ -h, --help show this help`;
4039
+ function configPathFor2(env) {
4040
+ const dir = env["TOON_CLIENT_HOME"] ?? join5(homedir4(), ".toon-client");
4041
+ return join5(dir, "config.json");
4042
+ }
4043
+ function readEntryConfig(configPath) {
4044
+ try {
4045
+ return JSON.parse(readFileSync4(configPath, "utf8"));
4046
+ } catch (err) {
4047
+ if (err.code === "ENOENT") return {};
4048
+ throw new Error(
4049
+ `failed to read client config at ${configPath}: ${err instanceof Error ? err.message : String(err)}`
4050
+ );
4051
+ }
4052
+ }
4053
+ function writeEntryConfig(configPath, file) {
4054
+ mkdirSync3(dirname3(configPath), { recursive: true });
4055
+ writeFileSync3(configPath, `${JSON.stringify(file, null, 2)}
4056
+ `, "utf8");
4057
+ }
4058
+ async function loadGenesisSeedDefault() {
4059
+ try {
4060
+ const { loadGenesisSeed } = await import("../network-bootstrap-3X2GXNJB.js");
4061
+ return loadGenesisSeed();
4062
+ } catch {
4063
+ return void 0;
4064
+ }
4065
+ }
4066
+ function classifyEntry(btpUrl, seedBtp, btpSource) {
4067
+ if (btpUrl === null) return null;
4068
+ if (btpUrl === SANDBOX_BTP_URL) return "sandbox";
4069
+ if (btpSource === "genesis-seed" || btpUrl === seedBtp) return "apex";
4070
+ return "custom";
4071
+ }
4072
+ async function runEntry(args, deps) {
4073
+ const { io: io2, env } = deps;
4074
+ let positionals;
4075
+ let relayFlag;
4076
+ let json = false;
4077
+ try {
4078
+ const parsed = parseArgs9({
4079
+ args,
4080
+ allowPositionals: true,
4081
+ options: {
4082
+ relay: { type: "string" },
4083
+ json: { type: "boolean", default: false },
4084
+ help: { type: "boolean", short: "h", default: false }
4085
+ }
4086
+ });
4087
+ if (parsed.values.help) {
4088
+ io2.out(ENTRY_USAGE);
4089
+ return 0;
4090
+ }
4091
+ positionals = parsed.positionals;
4092
+ relayFlag = parsed.values.relay;
4093
+ json = parsed.values.json ?? false;
4094
+ } catch (err) {
4095
+ io2.err(err instanceof Error ? err.message : String(err));
4096
+ io2.err(ENTRY_USAGE);
4097
+ return 2;
4098
+ }
4099
+ if (positionals.length > 1) {
4100
+ io2.err(
4101
+ `rig entry takes at most one argument, got ${positionals.length}: ${positionals.join(" ")}`
4102
+ );
4103
+ io2.err(ENTRY_USAGE);
4104
+ return 2;
4105
+ }
4106
+ const target = positionals[0];
4107
+ let mutation;
4108
+ if (target !== void 0) {
4109
+ if (target === "apex") {
4110
+ if (relayFlag !== void 0) {
4111
+ io2.err("--relay only applies to an explicit <wss-url> entry");
4112
+ io2.err(ENTRY_USAGE);
4113
+ return 2;
4114
+ }
4115
+ mutation = { kind: "apex" };
4116
+ } else if (target === "sandbox") {
4117
+ if (relayFlag !== void 0) {
4118
+ io2.err("--relay only applies to an explicit <wss-url> entry");
4119
+ io2.err(ENTRY_USAGE);
4120
+ return 2;
4121
+ }
4122
+ mutation = { kind: "sandbox" };
4123
+ } else if (/^wss?:\/\/.+/.test(target)) {
4124
+ if (relayFlag !== void 0 && !/^wss?:\/\/.+/.test(relayFlag)) {
4125
+ io2.err(
4126
+ `--relay must be a ws(s) URL, got ${JSON.stringify(relayFlag)}`
4127
+ );
4128
+ io2.err(ENTRY_USAGE);
4129
+ return 2;
4130
+ }
4131
+ mutation = {
4132
+ kind: "url",
4133
+ btpUrl: target,
4134
+ ...relayFlag !== void 0 ? { relayUrl: relayFlag } : {}
4135
+ };
4136
+ } else {
4137
+ io2.err(
4138
+ `unknown entry ${JSON.stringify(target)} \u2014 expected \`apex\`, \`sandbox\`, or a ws(s):// URL`
4139
+ );
4140
+ io2.err(ENTRY_USAGE);
4141
+ return 2;
4142
+ }
4143
+ }
4144
+ try {
4145
+ const configPath = configPathFor2(env);
4146
+ const file = readEntryConfig(configPath);
4147
+ const seed = await (deps.loadGenesisSeed ?? loadGenesisSeedDefault)();
4148
+ const effective = () => {
4149
+ const btpExplicit = env["TOON_CLIENT_PROXY_URL"] ?? env["TOON_CLIENT_BTP_URL"] ?? file.proxyUrl ?? file.btpUrl;
4150
+ const btpFromEnv = env["TOON_CLIENT_PROXY_URL"] ?? env["TOON_CLIENT_BTP_URL"];
4151
+ const relayExplicit = env["TOON_CLIENT_RELAY_URL"] ?? file.relayUrl;
4152
+ return {
4153
+ btpUrl: btpExplicit ?? seed?.btpEndpoint ?? null,
4154
+ btpSource: btpExplicit ? btpFromEnv ? "env" : "config" : seed?.btpEndpoint ? "genesis-seed" : null,
4155
+ relayUrl: relayExplicit ?? seed?.relayUrl ?? null,
4156
+ relaySource: env["TOON_CLIENT_RELAY_URL"] ? "env" : file.relayUrl ? "config" : seed?.relayUrl ? "genesis-seed" : null
4157
+ };
4158
+ };
4159
+ if (mutation === void 0) {
4160
+ const state2 = effective();
4161
+ const entry = classifyEntry(state2.btpUrl, seed?.btpEndpoint, state2.btpSource);
4162
+ if (json) {
4163
+ io2.emitJson({
4164
+ command: "entry",
4165
+ entry,
4166
+ btpUrl: state2.btpUrl,
4167
+ btpSource: state2.btpSource,
4168
+ relayUrl: state2.relayUrl,
4169
+ relaySource: state2.relaySource,
4170
+ configPath
4171
+ });
4172
+ return 0;
4173
+ }
4174
+ const label = (source) => source === "env" ? "env" : source === "config" ? `config (${configPath})` : source === "genesis-seed" ? "default apex \u2014 genesis seed" : "not configured";
4175
+ io2.out(
4176
+ `Entry: ${entry ?? "(none)"}${entry === "sandbox" ? " (Mina USDC only \u2014 multihop demo path)" : ""}`
4177
+ );
4178
+ io2.out(` btp ${state2.btpUrl ?? "(none)"} [${label(state2.btpSource)}]`);
4179
+ io2.out(` relay ${state2.relayUrl ?? "(none)"} [${label(state2.relaySource)}]`);
4180
+ io2.out(
4181
+ "Switch with `rig entry apex`, `rig entry sandbox`, or `rig entry <wss-url>`."
4182
+ );
4183
+ return 0;
4184
+ }
4185
+ const warnings = [];
4186
+ for (const envVar of [
4187
+ "TOON_CLIENT_BTP_URL",
4188
+ "TOON_CLIENT_PROXY_URL",
4189
+ "TOON_CLIENT_RELAY_URL"
4190
+ ]) {
4191
+ if (env[envVar] !== void 0) {
4192
+ warnings.push(
4193
+ `${envVar}=${env[envVar]} is set in the environment and overrides the config value you just wrote \u2014 unset it for this entry to take effect.`
4194
+ );
4195
+ }
4196
+ }
4197
+ warnings.push(
4198
+ "Payment channels are per-entry-peer: existing channels (see `rig channels`) are not used with the new entry \u2014 the next paid command opens or resumes a channel with the new peer."
4199
+ );
4200
+ const hadProxyUrl = file.proxyUrl !== void 0;
4201
+ let wroteBtp;
4202
+ let wroteRelay;
4203
+ if (mutation.kind === "apex") {
4204
+ wroteBtp = null;
4205
+ wroteRelay = null;
4206
+ delete file.btpUrl;
4207
+ delete file.relayUrl;
4208
+ delete file.proxyUrl;
4209
+ } else if (mutation.kind === "sandbox") {
4210
+ wroteBtp = SANDBOX_BTP_URL;
4211
+ wroteRelay = SANDBOX_RELAY_URL;
4212
+ file.btpUrl = SANDBOX_BTP_URL;
4213
+ file.relayUrl = SANDBOX_RELAY_URL;
4214
+ delete file.proxyUrl;
4215
+ } else {
4216
+ wroteBtp = mutation.btpUrl;
4217
+ wroteRelay = mutation.relayUrl ?? null;
4218
+ file.btpUrl = mutation.btpUrl;
4219
+ if (mutation.relayUrl !== void 0) file.relayUrl = mutation.relayUrl;
4220
+ delete file.proxyUrl;
4221
+ }
4222
+ if (hadProxyUrl) {
4223
+ warnings.push(
4224
+ "Removed the legacy `proxyUrl` config field \u2014 it outranks `btpUrl` and would have silently kept the old entry."
4225
+ );
4226
+ }
4227
+ writeEntryConfig(configPath, file);
4228
+ let clearedTopologyCache = false;
4229
+ try {
4230
+ unlinkSync(join5(dirname3(configPath), TOPOLOGY_CACHE_FILENAME));
4231
+ clearedTopologyCache = true;
4232
+ } catch {
4233
+ }
4234
+ if (mutation.kind === "sandbox") {
4235
+ const effectiveChain = env["TOON_CLIENT_CHAIN"] ?? file.chain ?? file.supportedChains?.[0];
4236
+ if (effectiveChain === void 0 || !effectiveChain.startsWith("mina")) {
4237
+ warnings.push(
4238
+ "The sandbox entry settles ONLY mina:devnet \u2014 run `rig chain set mina` " + (effectiveChain !== void 0 ? `(currently ${effectiveChain}).` : "to pin it.")
4239
+ );
4240
+ }
4241
+ warnings.push(
4242
+ `Repos publish to their git \`origin\` relay, which OVERRIDES the config relayUrl \u2014 for the sandbox demo run \`rig remote add origin ${SANDBOX_RELAY_URL}\` in the repo (or use a fresh repo).`
4243
+ );
4244
+ }
4245
+ const state = effective();
4246
+ if (json) {
4247
+ io2.emitJson({
4248
+ command: "entry",
4249
+ entry: mutation.kind === "url" ? "custom" : mutation.kind,
4250
+ btpUrl: state.btpUrl,
4251
+ btpSource: state.btpSource,
4252
+ relayUrl: state.relayUrl,
4253
+ relaySource: state.relaySource,
4254
+ wrote: { btpUrl: wroteBtp, relayUrl: wroteRelay },
4255
+ clearedTopologyCache,
4256
+ configPath,
4257
+ ...warnings.length ? { warnings } : {}
4258
+ });
4259
+ return 0;
4260
+ }
4261
+ if (mutation.kind === "apex") {
4262
+ io2.out("Entry reverted to the default apex (cleared btpUrl/relayUrl/proxyUrl).");
4263
+ io2.out(` btp ${state.btpUrl ?? "(genesis seed unavailable)"}`);
4264
+ io2.out(` relay ${state.relayUrl ?? "(genesis seed unavailable)"}`);
4265
+ } else if (mutation.kind === "sandbox") {
4266
+ io2.out("Entry set to the devnet sandbox (Mina USDC only \u2014 multihop demo path).");
4267
+ io2.out(` btp ${SANDBOX_BTP_URL}`);
4268
+ io2.out(` relay ${SANDBOX_RELAY_URL}`);
4269
+ } else {
4270
+ io2.out(`Entry set to ${mutation.btpUrl}.`);
4271
+ if (mutation.relayUrl !== void 0) io2.out(` relay ${mutation.relayUrl}`);
4272
+ }
4273
+ io2.out(
4274
+ `Saved to ${configPath}.` + (clearedTopologyCache ? " Cleared the cached topology." : "")
4275
+ );
4276
+ for (const w of warnings) io2.err(`warning: ${w}`);
4277
+ return 0;
4278
+ } catch (err) {
4279
+ return emitCliError(io2, json, "entry", err);
4280
+ }
4281
+ }
4282
+
4283
+ // src/cli/fetch.ts
4284
+ import { parseArgs as parseArgs10 } from "util";
3827
4285
  var FETCH_USAGE = `Usage: rig fetch [remote] [options]
3828
4286
 
3829
4287
  Fetch from a TOON remote \u2014 FREE (relay reads + Arweave gateway downloads; no
@@ -3877,7 +4335,7 @@ async function runFetch(args, deps) {
3877
4335
  let ownerFlag;
3878
4336
  let concurrency;
3879
4337
  try {
3880
- const { values, positionals } = parseArgs9({
4338
+ const { values, positionals } = parseArgs10({
3881
4339
  args,
3882
4340
  options: {
3883
4341
  json: { type: "boolean", default: false },
@@ -4042,10 +4500,10 @@ async function runFetch(args, deps) {
4042
4500
  }
4043
4501
 
4044
4502
  // src/cli/fund.ts
4045
- import { readFileSync as readFileSync3 } from "fs";
4046
- import { homedir as homedir3 } from "os";
4047
- import { join as join4 } from "path";
4048
- import { parseArgs as parseArgs10 } from "util";
4503
+ import { readFileSync as readFileSync5 } from "fs";
4504
+ import { homedir as homedir5 } from "os";
4505
+ import { join as join6 } from "path";
4506
+ import { parseArgs as parseArgs11 } from "util";
4049
4507
  var DEVNET_FAUCET_URL = "https://faucet.devnet.toonprotocol.dev";
4050
4508
  var CHAINS = ["evm", "solana", "mina"];
4051
4509
  var CHAIN_ALIASES = {
@@ -4083,7 +4541,9 @@ The identity comes from RIG_MNEMONIC (env or a project .env) or the
4083
4541
  faucetUrl config field, or the deployed devnet faucet when the network is
4084
4542
  devnet \u2014 including when a configured *.devnet.toonprotocol.dev origin infers
4085
4543
  it (a devnet relay/proxy/btp endpoint, or the git origin remote from
4086
- \`rig remote add origin <devnet relay>\`). The faucet drips a FIXED amount per
4544
+ \`rig remote add origin <devnet relay>\`). A completely fresh install with NO
4545
+ origin configured anywhere infers devnet from the built-in genesis seed, so a
4546
+ bare \`rig fund\` works with zero config. The faucet drips a FIXED amount per
4087
4547
  chain (there is no --amount). On a network without a faucet, prints the wallet
4088
4548
  address(es) to fund externally instead.
4089
4549
 
@@ -4120,6 +4580,44 @@ function sharedDevnetOrigin(env, file, originRelays = []) {
4120
4580
  }
4121
4581
  return void 0;
4122
4582
  }
4583
+ async function loadGenesisSeedDefault2() {
4584
+ try {
4585
+ const { loadGenesisSeed } = await import("../network-bootstrap-3X2GXNJB.js");
4586
+ return loadGenesisSeed();
4587
+ } catch {
4588
+ return void 0;
4589
+ }
4590
+ }
4591
+ async function resolveEffectiveNetwork(opts) {
4592
+ const { env, cwd } = opts;
4593
+ const file = opts.file ?? readFundConfig(env).file;
4594
+ const network = env["TOON_CLIENT_NETWORK"] ?? file.network;
4595
+ const canInfer = network === void 0 || network === "custom";
4596
+ const originRelays = canInfer ? await resolveOriginRelays(cwd) : [];
4597
+ let devnetOrigin = sharedDevnetOrigin(env, file, originRelays);
4598
+ let seededOrigin = false;
4599
+ if (devnetOrigin === void 0 && canInfer) {
4600
+ const anyConfiguredOrigin = [
4601
+ env["TOON_CLIENT_RELAY_URL"] ?? file.relayUrl,
4602
+ env["TOON_CLIENT_PROXY_URL"] ?? file.proxyUrl,
4603
+ env["TOON_CLIENT_BTP_URL"] ?? file.btpUrl,
4604
+ ...originRelays
4605
+ ].some((url) => url !== void 0);
4606
+ if (!anyConfiguredOrigin) {
4607
+ const seed = await (opts.loadGenesisSeed ?? loadGenesisSeedDefault2)();
4608
+ devnetOrigin = devnetHost(seed?.relayUrl) ?? devnetHost(seed?.btpEndpoint);
4609
+ seededOrigin = devnetOrigin !== void 0;
4610
+ }
4611
+ }
4612
+ const inferredDevnet = devnetOrigin !== void 0 && canInfer;
4613
+ return {
4614
+ network,
4615
+ effectiveNetwork: inferredDevnet ? "devnet" : network,
4616
+ devnetOrigin,
4617
+ seededOrigin,
4618
+ inferredDevnet
4619
+ };
4620
+ }
4123
4621
  async function resolveOriginRelays(cwd) {
4124
4622
  let repoRoot;
4125
4623
  try {
@@ -4149,11 +4647,11 @@ function noFaucetGuidance(network, devnetOrigin) {
4149
4647
  return `${head}. If you meant the shared devnet, set TOON_CLIENT_NETWORK=devnet and re-run \`rig fund\` \u2014 no faucet URL is needed there. If this is a self-hosted network with its own faucet, set TOON_CLIENT_FAUCET_URL (or the faucetUrl config field). ${external}`;
4150
4648
  }
4151
4649
  function readFundConfig(env) {
4152
- const dir = env["TOON_CLIENT_HOME"] ?? join4(homedir3(), ".toon-client");
4153
- const configPath = join4(dir, "config.json");
4650
+ const dir = env["TOON_CLIENT_HOME"] ?? join6(homedir5(), ".toon-client");
4651
+ const configPath = join6(dir, "config.json");
4154
4652
  try {
4155
4653
  return {
4156
- file: JSON.parse(readFileSync3(configPath, "utf8")),
4654
+ file: JSON.parse(readFileSync5(configPath, "utf8")),
4157
4655
  configPath
4158
4656
  };
4159
4657
  } catch (err) {
@@ -4171,7 +4669,7 @@ async function runFund(args, deps) {
4171
4669
  let addressFlag;
4172
4670
  let json = false;
4173
4671
  try {
4174
- const { values, positionals } = parseArgs10({
4672
+ const { values, positionals } = parseArgs11({
4175
4673
  args,
4176
4674
  allowPositionals: true,
4177
4675
  options: {
@@ -4213,11 +4711,12 @@ async function runFund(args, deps) {
4213
4711
  const { file } = readFundConfig(env);
4214
4712
  const targetChains = resolvedChain === void 0 || resolvedChain === "all" ? [...CHAINS] : [resolvedChain];
4215
4713
  const network = env["TOON_CLIENT_NETWORK"] ?? file.network;
4216
- const canInfer = network === void 0 || network === "custom";
4217
- const originRelays = canInfer ? await resolveOriginRelays(deps.cwd) : [];
4218
- const devnetOrigin = sharedDevnetOrigin(env, file, originRelays);
4219
- const inferredDevnet = devnetOrigin !== void 0 && (network === void 0 || network === "custom");
4220
- const effectiveNetwork = inferredDevnet ? "devnet" : network;
4714
+ const { devnetOrigin, seededOrigin, inferredDevnet, effectiveNetwork } = await resolveEffectiveNetwork({
4715
+ env,
4716
+ cwd: deps.cwd,
4717
+ file,
4718
+ ...deps.loadGenesisSeed ? { loadGenesisSeed: deps.loadGenesisSeed } : {}
4719
+ });
4221
4720
  const faucetUrl = env["TOON_CLIENT_FAUCET_URL"] ?? file.faucetUrl ?? (effectiveNetwork === "devnet" ? DEVNET_FAUCET_URL : void 0);
4222
4721
  const resolved = await resolveIdentity({
4223
4722
  env,
@@ -4268,7 +4767,7 @@ async function runFund(args, deps) {
4268
4767
  };
4269
4768
  if (!json && inferredDevnet) {
4270
4769
  io2.out(
4271
- `Inferred network 'devnet' from the configured origin ${devnetOrigin} (network was ${JSON.stringify(network ?? "custom")}). Set TOON_CLIENT_NETWORK explicitly to override.`
4770
+ seededOrigin ? `Inferred network 'devnet' from the built-in genesis seed ${devnetOrigin} (nothing configured \u2014 fresh install). Set TOON_CLIENT_NETWORK explicitly to override.` : `Inferred network 'devnet' from the configured origin ${devnetOrigin} (network was ${JSON.stringify(network ?? "custom")}). Set TOON_CLIENT_NETWORK explicitly to override.`
4272
4771
  );
4273
4772
  }
4274
4773
  if (!json) {
@@ -4321,7 +4820,9 @@ async function runFund(args, deps) {
4321
4820
  network: effectiveNetwork ?? null,
4322
4821
  faucetUrl,
4323
4822
  results,
4324
- ...inferredDevnet ? { inferredDevnetFrom: devnetOrigin } : {}
4823
+ ...inferredDevnet ? {
4824
+ inferredDevnetFrom: seededOrigin ? `${devnetOrigin} (genesis seed)` : devnetOrigin
4825
+ } : {}
4325
4826
  });
4326
4827
  return allFunded ? 0 : 1;
4327
4828
  }
@@ -4393,10 +4894,10 @@ var runGitPassthrough = (argv2, options = {}) => {
4393
4894
  };
4394
4895
 
4395
4896
  // src/cli/identity-cmd.ts
4396
- import { existsSync, mkdirSync as mkdirSync3 } from "fs";
4397
- import { dirname as dirname3 } from "path";
4897
+ import { existsSync, mkdirSync as mkdirSync4 } from "fs";
4898
+ import { dirname as dirname4 } from "path";
4398
4899
  import { createInterface } from "readline/promises";
4399
- import { parseArgs as parseArgs11 } from "util";
4900
+ import { parseArgs as parseArgs12 } from "util";
4400
4901
  async function loadKeyOps() {
4401
4902
  return await import("@toon-protocol/client");
4402
4903
  }
@@ -4445,7 +4946,7 @@ async function prepareKeystoreTarget(input) {
4445
4946
  const envPassword = input.env["TOON_CLIENT_KEYSTORE_PASSWORD"]?.trim() || void 0;
4446
4947
  const autoPassword = envPassword === void 0;
4447
4948
  const password = envPassword ?? DEFAULT_KEYSTORE_PASSWORD;
4448
- mkdirSync3(dirname3(keystorePath), { recursive: true });
4949
+ mkdirSync4(dirname4(keystorePath), { recursive: true });
4449
4950
  return { keystorePath, password, autoPassword, existing, keyOps };
4450
4951
  }
4451
4952
  function readAccountIndex(env) {
@@ -4567,7 +5068,7 @@ async function runIdentity(args, deps) {
4567
5068
  }
4568
5069
  }
4569
5070
  function parseMintArgs(args, verb) {
4570
- const { values, positionals } = parseArgs11({
5071
+ const { values, positionals } = parseArgs12({
4571
5072
  args,
4572
5073
  options: {
4573
5074
  force: { type: "boolean", default: false },
@@ -4672,7 +5173,7 @@ async function runIdentityShow(args, deps) {
4672
5173
  let json = false;
4673
5174
  let help = false;
4674
5175
  try {
4675
- const parsed = parseArgs11({
5176
+ const parsed = parseArgs12({
4676
5177
  args,
4677
5178
  options: {
4678
5179
  json: { type: "boolean", default: false },
@@ -4781,7 +5282,7 @@ async function defaultReadSecretLine(prompt, isInteractive) {
4781
5282
 
4782
5283
  // src/cli/init.ts
4783
5284
  import { basename as basename2 } from "path";
4784
- import { parseArgs as parseArgs12 } from "util";
5285
+ import { parseArgs as parseArgs13 } from "util";
4785
5286
 
4786
5287
  // src/cli/git-author.ts
4787
5288
  var PROFILE_KIND = 0;
@@ -4899,7 +5400,7 @@ Options:
4899
5400
  --json machine-readable report
4900
5401
  -h, --help show this help`;
4901
5402
  function parseInitArgs(args) {
4902
- const { values, positionals } = parseArgs12({
5403
+ const { values, positionals } = parseArgs13({
4903
5404
  args,
4904
5405
  options: {
4905
5406
  "repo-id": { type: "string" },
@@ -5132,7 +5633,7 @@ async function runInit(args, deps) {
5132
5633
  }
5133
5634
 
5134
5635
  // src/cli/maintainers.ts
5135
- import { parseArgs as parseArgs13 } from "util";
5636
+ import { parseArgs as parseArgs14 } from "util";
5136
5637
  var HEX64_RE3 = /^[0-9a-f]{64}$/;
5137
5638
  var WS_URL_RE4 = /^wss?:\/\//i;
5138
5639
  var MAINTAINERS_USAGE = `Usage: rig maintainers <list|add|remove> [<pubkey>] [options]
@@ -5237,7 +5738,7 @@ async function runList2(args, deps) {
5237
5738
  const { io: io2 } = deps;
5238
5739
  let flags;
5239
5740
  try {
5240
- const { values, positionals } = parseArgs13({
5741
+ const { values, positionals } = parseArgs14({
5241
5742
  args,
5242
5743
  options: MAINT_OPTIONS,
5243
5744
  allowPositionals: true
@@ -5304,7 +5805,7 @@ async function runMutate(op, args, deps) {
5304
5805
  let flags;
5305
5806
  let pubkey;
5306
5807
  try {
5307
- const { values, positionals } = parseArgs13({
5808
+ const { values, positionals } = parseArgs14({
5308
5809
  args,
5309
5810
  options: MAINT_OPTIONS,
5310
5811
  allowPositionals: true
@@ -5453,7 +5954,7 @@ async function runMutate(op, args, deps) {
5453
5954
 
5454
5955
  // src/cli/name.ts
5455
5956
  import { randomUUID } from "crypto";
5456
- import { parseArgs as parseArgs14 } from "util";
5957
+ import { parseArgs as parseArgs15 } from "util";
5457
5958
  var ARIO_DECIMALS = 6;
5458
5959
  function renderMario(mario) {
5459
5960
  return `${mario.toString()} mARIO (~${formatUnits(mario.toString(), ARIO_DECIMALS)} ARIO)`;
@@ -5857,6 +6358,7 @@ var defaultGasStationClient = {
5857
6358
  };
5858
6359
  }
5859
6360
  };
6361
+ var DEVNET_DVM_URL = "https://dvm.devnet.toonprotocol.dev";
5860
6362
  var NAME_USAGE = `Usage: rig name <buy|set|status> <name> [options]
5861
6363
 
5862
6364
  ArNS naming for Arweave-served artifacts. A name registered on the ar.io
@@ -5909,12 +6411,18 @@ Options:
5909
6411
  unverified.
5910
6412
  --process-id <id> explicit ArNS registry program id \u2014 a Solana program
5911
6413
  address (overrides --network; or RIG_ARIO_PROCESS_ID)
5912
- --via <dvm-url> buy only: broker the purchase through a store DVM's
5913
- kind:5095 job endpoint (or RIG_ARNS_DVM_URL). The DVM
5914
- pays the mARIO; you own the name via your spawned ANT.
5915
- Direct backend targeting stubs the job payment
5916
- (dev/e2e) \u2014 the paid path runs the same job through
5917
- the connector payment proxy.
6414
+ --via <dvm-url> broker buy/set through a store DVM's job endpoint (or
6415
+ RIG_ARNS_DVM_URL). The DVM pays the mARIO; you own the
6416
+ name via your spawned ANT. Direct backend targeting
6417
+ stubs the job payment (dev/e2e) \u2014 the paid path runs
6418
+ the same job through the connector payment proxy.
6419
+ DEVNET DEFAULT: with --network devnet and the TOON
6420
+ network on devnet too, buy/set default to the deployed
6421
+ devnet store DVM (${DEVNET_DVM_URL})
6422
+ unless --direct opts out.
6423
+ --direct force the direct wallet-paid path: never default (or
6424
+ read RIG_ARNS_DVM_URL as) a --via DVM. Mutually
6425
+ exclusive with an explicit --via.
5918
6426
  --yes skip the confirmation (required when not a TTY) for
5919
6427
  buy/set
5920
6428
  --json machine-readable envelope; for buy/set without --yes it
@@ -5960,7 +6468,7 @@ async function resolveNameContext(deps, network, processId, mode) {
5960
6468
  return { identity, solanaAddress, network, processId, sdk, nostrSecretKey };
5961
6469
  }
5962
6470
  function parseNameFlags(args, env) {
5963
- const { values, positionals } = parseArgs14({
6471
+ const { values, positionals } = parseArgs15({
5964
6472
  args,
5965
6473
  allowPositionals: true,
5966
6474
  options: {
@@ -5971,6 +6479,7 @@ function parseNameFlags(args, env) {
5971
6479
  network: { type: "string" },
5972
6480
  "process-id": { type: "string" },
5973
6481
  via: { type: "string" },
6482
+ direct: { type: "boolean", default: false },
5974
6483
  "tx-id": { type: "string" },
5975
6484
  yes: { type: "boolean", default: false },
5976
6485
  json: { type: "boolean", default: false },
@@ -5984,6 +6493,7 @@ function parseNameFlags(args, env) {
5984
6493
  permabuy: false,
5985
6494
  ttl: 0,
5986
6495
  network: "mainnet",
6496
+ direct: false,
5987
6497
  yes: false,
5988
6498
  json: false
5989
6499
  }
@@ -6017,7 +6527,12 @@ function parseNameFlags(args, env) {
6017
6527
  );
6018
6528
  }
6019
6529
  const processId = values["process-id"] ?? env["RIG_ARIO_PROCESS_ID"];
6020
- const viaRaw = values.via ?? env["RIG_ARNS_DVM_URL"];
6530
+ if (values.direct && values.via !== void 0) {
6531
+ throw new Error(
6532
+ "--direct and --via are mutually exclusive: --direct forces the wallet-paid path, --via brokers through a DVM"
6533
+ );
6534
+ }
6535
+ const viaRaw = values.direct ? void 0 : values.via ?? env["RIG_ARNS_DVM_URL"];
6021
6536
  let via;
6022
6537
  if (viaRaw !== void 0) {
6023
6538
  if (!/^https?:\/\/.+/.test(viaRaw)) {
@@ -6037,6 +6552,7 @@ function parseNameFlags(args, env) {
6037
6552
  network: networkRaw,
6038
6553
  ...processId !== void 0 ? { processId } : {},
6039
6554
  ...via !== void 0 ? { via } : {},
6555
+ direct: values.direct ?? false,
6040
6556
  ...values["tx-id"] !== void 0 ? { txId: values["tx-id"] } : {},
6041
6557
  yes: values.yes ?? false,
6042
6558
  json: values.json ?? false
@@ -6427,6 +6943,20 @@ async function runName(args, deps) {
6427
6943
  io2.err(NAME_USAGE);
6428
6944
  return 2;
6429
6945
  }
6946
+ if ((sub === "buy" || sub === "set") && !flags.direct && flags.via === void 0 && flags.network === "devnet") {
6947
+ let toonDevnet = false;
6948
+ try {
6949
+ const resolved = await (deps.resolveToonNetwork ?? resolveEffectiveNetwork)({ env: deps.env, cwd: deps.cwd });
6950
+ toonDevnet = resolved.effectiveNetwork === "devnet";
6951
+ } catch {
6952
+ }
6953
+ if (toonDevnet) {
6954
+ flags = { ...flags, via: DEVNET_DVM_URL };
6955
+ io2.err(
6956
+ `Brokering via the devnet store DVM ${DEVNET_DVM_URL} (no --via given; pass --direct for a wallet-paid ${sub}).`
6957
+ );
6958
+ }
6959
+ }
6430
6960
  try {
6431
6961
  if (sub === "buy") return await runBuy(name, flags, deps);
6432
6962
  if (sub === "status") return await runStatus(name, flags, deps);
@@ -6450,7 +6980,7 @@ async function runName(args, deps) {
6450
6980
  }
6451
6981
 
6452
6982
  // src/cli/site.ts
6453
- import { parseArgs as parseArgs15 } from "util";
6983
+ import { parseArgs as parseArgs16 } from "util";
6454
6984
 
6455
6985
  // src/arweave-manifest.ts
6456
6986
  var DEFAULT_INDEX = "index.html";
@@ -6469,22 +6999,22 @@ function buildArweaveManifest(entries, indexPath = DEFAULT_INDEX, fallbackTxId)
6469
6999
  }
6470
7000
 
6471
7001
  // src/cli/site-record.ts
6472
- import { mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
6473
- import { homedir as homedir4 } from "os";
6474
- import { join as join5 } from "path";
7002
+ import { mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
7003
+ import { homedir as homedir6 } from "os";
7004
+ import { join as join7 } from "path";
6475
7005
  var SITE_MANIFEST_FILENAME = "site-manifests.json";
6476
7006
  function storeDir2(env) {
6477
- return env["TOON_CLIENT_HOME"] ?? join5(homedir4(), ".toon-client");
7007
+ return env["TOON_CLIENT_HOME"] ?? join7(homedir6(), ".toon-client");
6478
7008
  }
6479
7009
  function storePath2(env) {
6480
- return join5(storeDir2(env), SITE_MANIFEST_FILENAME);
7010
+ return join7(storeDir2(env), SITE_MANIFEST_FILENAME);
6481
7011
  }
6482
7012
  function keyOf(repoId, ref) {
6483
7013
  return `${repoId}\0${ref}`;
6484
7014
  }
6485
7015
  function readFile2(env) {
6486
7016
  try {
6487
- const parsed = JSON.parse(readFileSync4(storePath2(env), "utf8"));
7017
+ const parsed = JSON.parse(readFileSync6(storePath2(env), "utf8"));
6488
7018
  if (parsed && typeof parsed === "object") return parsed;
6489
7019
  return {};
6490
7020
  } catch {
@@ -6496,10 +7026,10 @@ function readSiteRecord(env, repoId, ref) {
6496
7026
  }
6497
7027
  function writeSiteRecord(env, record) {
6498
7028
  const dir = storeDir2(env);
6499
- mkdirSync4(dir, { recursive: true });
7029
+ mkdirSync5(dir, { recursive: true });
6500
7030
  const file = readFile2(env);
6501
7031
  file[keyOf(record.repoId, record.ref)] = record;
6502
- writeFileSync3(storePath2(env), `${JSON.stringify(file, null, 2)}
7032
+ writeFileSync4(storePath2(env), `${JSON.stringify(file, null, 2)}
6503
7033
  `, "utf8");
6504
7034
  }
6505
7035
 
@@ -6541,7 +7071,7 @@ Options (publish):
6541
7071
  estimate (nothing uploaded)
6542
7072
  -h, --help show this help`;
6543
7073
  function parseSiteArgs(args) {
6544
- const { values, positionals } = parseArgs15({
7074
+ const { values, positionals } = parseArgs16({
6545
7075
  args,
6546
7076
  options: {
6547
7077
  index: { type: "string" },
@@ -6951,15 +7481,23 @@ Commands rig owns:
6951
7481
  (free \u2014 chain reads and local state only)
6952
7482
  chain [set <c>|unset] choose which chain/USDC settles paid writes
6953
7483
  (evm|sol|mina); free \u2014 reads/writes local config
7484
+ entry [apex|sandbox|url] choose the network entry node (payment ingress +
7485
+ relay): apex settles evm|sol|mina, sandbox is the
7486
+ Mina-only multihop demo path; free \u2014 writes local
7487
+ config and clears the cached topology
6954
7488
  name buy <name> ArNS naming (#367): buy points a human name at an
6955
7489
  name set <name> <txId> Arweave txId, owned + paid by this identity's
6956
7490
  name status <name> Solana key. buy spends mARIO on Solana via the
6957
7491
  ar.io registry (NOT ILP); status is free. Needs
6958
7492
  the optional \`@ar.io/sdk\` dependency
6959
7493
  channel list show the payment channels paid commands hold
6960
- (free \u2014 reads local state)
7494
+ (free \u2014 reads local state; \`rig channels\` is a
7495
+ shorthand for \`rig channel list\`)
6961
7496
  channel open explicitly open (or resume) the channel for a
6962
7497
  peer; --deposit adds collateral (on-chain)
7498
+ channel deploy-zkapp pre-deploy this identity's dedicated Mina
7499
+ PaymentChannel zkApp (on-chain; the Mina open
7500
+ path otherwise does this automatically)
6963
7501
  channel close <channelId> start the settlement challenge window (on-chain)
6964
7502
  channel settle <channelId> release collateral after the window (on-chain)
6965
7503
 
@@ -7022,12 +7560,19 @@ async function dispatch(argv2, deps) {
7022
7560
  return runMaintainers(rest, deps);
7023
7561
  case "channel":
7024
7562
  return runChannel(rest, deps);
7563
+ case "channels":
7564
+ return runChannel(
7565
+ rest[0] !== void 0 && !rest[0].startsWith("-") ? rest : ["list", ...rest],
7566
+ deps
7567
+ );
7025
7568
  case "fund":
7026
7569
  return runFund(rest, deps);
7027
7570
  case "balance":
7028
7571
  return runBalance(rest, deps);
7029
7572
  case "chain":
7030
7573
  return runChain(rest, deps);
7574
+ case "entry":
7575
+ return runEntry(rest, deps);
7031
7576
  case "name":
7032
7577
  return runName(rest, deps);
7033
7578
  case "help":
@@ -7105,8 +7650,11 @@ var RIG_OWNED_VERBS = /* @__PURE__ */ new Set([
7105
7650
  "pr",
7106
7651
  "maintainers",
7107
7652
  "channel",
7653
+ "channels",
7108
7654
  "fund",
7109
7655
  "balance",
7656
+ "chain",
7657
+ "entry",
7110
7658
  "name"
7111
7659
  ]);
7112
7660
  function isJsonInvocation(argv2) {