@toon-protocol/rig 2.12.0 → 2.13.1

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,
@@ -41,6 +43,10 @@ import {
41
43
  flooredUploadFee
42
44
  } from "../chunk-35ALWUDJ.js";
43
45
  import {
46
+ minaPresetForChain
47
+ } from "../chunk-ACTH6ISJ.js";
48
+ import {
49
+ ARWEAVE_GATEWAYS,
44
50
  COMMENT_KIND,
45
51
  authorizedStatusAuthors,
46
52
  buildComment,
@@ -555,6 +561,8 @@ var DEFAULT_RIG_WEB_BUNDLE = {
555
561
  var RIG_WEB_TX_ENV = "RIG_WEB_TX";
556
562
  var RIG_WEB_ENTRY_JS_ENV = "RIG_WEB_ENTRY_JS";
557
563
  var RIG_WEB_ENTRY_CSS_ENV = "RIG_WEB_ENTRY_CSS";
564
+ var DEFAULT_RIG_WEB_GATEWAY = "https://arweave.net";
565
+ var RIG_WEB_GATEWAY_ENV = "RIG_WEB_GATEWAY";
558
566
  var DEFAULT_RIG_WEB_URL = "https://toon-protocol.github.io/toon-client";
559
567
  var RIG_WEB_URL_ENV = "RIG_WEB_URL";
560
568
  function repoHashRoute(options) {
@@ -1074,7 +1082,7 @@ function loadPaidSession(deps, relayUrl) {
1074
1082
  });
1075
1083
  }
1076
1084
  var defaultLoadStandalone = async (options) => {
1077
- const mod = await import("../standalone-mode-U3OOSVOB.js");
1085
+ const mod = await import("../standalone-mode-D2YSANBJ.js");
1078
1086
  return mod.createStandaloneContext(options);
1079
1087
  };
1080
1088
  function identityReport(ctx) {
@@ -1210,11 +1218,14 @@ function parsePushArgs(args) {
1210
1218
  return flags;
1211
1219
  }
1212
1220
  function pointerGateway(env) {
1213
- return (env["RIG_ARWEAVE_GATEWAY"] ?? "https://arweave.net").replace(
1221
+ return (env["RIG_ARWEAVE_GATEWAY"] ?? "https://ar-io.dev").replace(
1214
1222
  /\/+$/,
1215
1223
  ""
1216
1224
  );
1217
1225
  }
1226
+ function mirrorGateway(primary) {
1227
+ return ARWEAVE_GATEWAYS.find((g) => g !== primary);
1228
+ }
1218
1229
  function planRigPointer(args) {
1219
1230
  const html = generateRigPointerHtml({
1220
1231
  bundle: {
@@ -1222,7 +1233,7 @@ function planRigPointer(args) {
1222
1233
  entryJs: args.env[RIG_WEB_ENTRY_JS_ENV] ?? DEFAULT_RIG_WEB_BUNDLE.entryJs,
1223
1234
  entryCss: args.env[RIG_WEB_ENTRY_CSS_ENV] ?? DEFAULT_RIG_WEB_BUNDLE.entryCss
1224
1235
  },
1225
- gateway: pointerGateway(args.env),
1236
+ gateway: (args.env[RIG_WEB_GATEWAY_ENV] ?? DEFAULT_RIG_WEB_GATEWAY).replace(/\/+$/, ""),
1226
1237
  rigWebUrl: args.env[RIG_WEB_URL_ENV] ?? DEFAULT_RIG_WEB_URL,
1227
1238
  relay: args.relay,
1228
1239
  ownerNpub: hexToNpub(args.ownerPubkey),
@@ -1423,6 +1434,12 @@ async function runPush(args, deps) {
1423
1434
  io2.out(
1424
1435
  `Rig page: ${rigPage2.url}` + (rigPage2.status === "published" ? ` paid ${rigPage2.feePaid}` : "") + " (renders this repo from Arweave)"
1425
1436
  );
1437
+ const mirror = rigPage2.txId ? mirrorGateway(gateway) : void 0;
1438
+ if (mirror) {
1439
+ io2.out(
1440
+ ` also: ${mirror}/${rigPage2.txId} (same page; gateways index fresh uploads at different speeds)`
1441
+ );
1442
+ }
1426
1443
  } else if (rigPage2.detail) {
1427
1444
  io2.err(`rig page: ${rigPage2.detail}`);
1428
1445
  }
@@ -1941,6 +1958,9 @@ async function runChain(args, deps) {
1941
1958
  }
1942
1959
 
1943
1960
  // src/cli/channel.ts
1961
+ import { readFileSync as readFileSync3 } from "fs";
1962
+ import { homedir as homedir3 } from "os";
1963
+ import { join as join3 } from "path";
1944
1964
  import { parseArgs as parseArgs5 } from "util";
1945
1965
  var CHANNEL_USAGE = `Usage: rig channel <subcommand>
1946
1966
 
@@ -1963,6 +1983,17 @@ Subcommands:
1963
1983
  apex); --deposit adds that much extra collateral after the
1964
1984
  open/resume. On-chain: asks for confirmation (--yes skips).
1965
1985
 
1986
+ deploy-zkapp [--graphql-url <url>]
1987
+ deploy a dedicated Mina PaymentChannel zkApp for THIS
1988
+ identity (the zkApp is single-pair; Mina channels open on
1989
+ an identity-owned deployment). Normally automatic \u2014 the
1990
+ Mina open path deploys one when needed \u2014 this explicit
1991
+ form pre-deploys it (compile \u22481-3 min, inclusion \u22483-6 min).
1992
+ On-chain: costs the 1 MINA account-creation fee + tx fee
1993
+ from the wallet's MINA. The zkApp key is saved under
1994
+ TOON_CLIENT_HOME/keys/. Asks for confirmation (--yes
1995
+ skips).
1996
+
1966
1997
  close <channelId>
1967
1998
  close a recorded channel \u2014 an on-chain tx that starts the
1968
1999
  settlement challenge window (the peer's settlementTimeout).
@@ -1986,6 +2017,8 @@ async function runChannel(args, deps) {
1986
2017
  return runChannelList(rest, deps);
1987
2018
  case "open":
1988
2019
  return runChannelOpen(rest, deps);
2020
+ case "deploy-zkapp":
2021
+ return runChannelDeployZkApp(rest, deps);
1989
2022
  case "close":
1990
2023
  return runChannelWithdrawStep(rest, deps, "close");
1991
2024
  case "settle":
@@ -2178,6 +2211,9 @@ async function runChannelOpen(args, deps) {
2178
2211
  io2.out(
2179
2212
  "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
2213
  );
2214
+ io2.out(
2215
+ "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)."
2216
+ );
2181
2217
  }
2182
2218
  const gate = await confirmOnChain(
2183
2219
  io2,
@@ -2236,6 +2272,160 @@ async function runChannelOpen(args, deps) {
2236
2272
  await stopQuietly(ctx);
2237
2273
  }
2238
2274
  }
2275
+ async function runChannelDeployZkApp(args, deps) {
2276
+ const { io: io2, env } = deps;
2277
+ let graphqlFlag;
2278
+ let yes = false;
2279
+ let json = false;
2280
+ try {
2281
+ const { values } = parseArgs5({
2282
+ args,
2283
+ options: {
2284
+ "graphql-url": { type: "string" },
2285
+ yes: { type: "boolean", default: false },
2286
+ json: { type: "boolean", default: false },
2287
+ help: { type: "boolean", short: "h", default: false }
2288
+ }
2289
+ });
2290
+ if (values.help) {
2291
+ io2.out(CHANNEL_USAGE);
2292
+ return 0;
2293
+ }
2294
+ graphqlFlag = values["graphql-url"];
2295
+ yes = values.yes ?? false;
2296
+ json = values.json ?? false;
2297
+ } catch (err) {
2298
+ io2.err(err instanceof Error ? err.message : String(err));
2299
+ io2.err(CHANNEL_USAGE);
2300
+ return 2;
2301
+ }
2302
+ try {
2303
+ const dir = env["TOON_CLIENT_HOME"] ?? join3(homedir3(), ".toon-client");
2304
+ let file = {};
2305
+ try {
2306
+ file = JSON.parse(readFileSync3(join3(dir, "config.json"), "utf8"));
2307
+ } catch {
2308
+ }
2309
+ const pinned = env["TOON_CLIENT_CHAIN"] ?? file.chain;
2310
+ const chain = pinned !== void 0 && pinned.startsWith("mina:") ? pinned : "mina:devnet";
2311
+ const graphqlUrl = graphqlFlag ?? file.minaChannel?.graphqlUrl ?? minaPresetForChain(chain)?.graphqlUrl;
2312
+ if (!graphqlUrl) {
2313
+ throw new Error(
2314
+ `no Mina GraphQL endpoint for ${chain} \u2014 pass --graphql-url or set minaChannel.graphqlUrl in the client config`
2315
+ );
2316
+ }
2317
+ const resolved = await resolveIdentity({
2318
+ env,
2319
+ cwd: deps.cwd,
2320
+ warn: (line) => io2.err(line)
2321
+ });
2322
+ const identity = {
2323
+ pubkey: resolved.pubkey,
2324
+ source: resolved.source,
2325
+ sourceLabel: resolved.sourceLabel
2326
+ };
2327
+ const store = MinaZkAppStore.forHome(dir);
2328
+ const existing = store.lookup(resolved.pubkey, chain);
2329
+ if (existing) {
2330
+ if (json) {
2331
+ io2.emitJson({
2332
+ command: "channel deploy-zkapp",
2333
+ identity,
2334
+ executed: false,
2335
+ plan: { chain, graphqlUrl },
2336
+ result: {
2337
+ zkAppAddress: existing.zkAppAddress,
2338
+ deployTxHash: existing.deployTxHash ?? null,
2339
+ vkHash: existing.vkHash ?? null,
2340
+ storePath: store.filePath
2341
+ },
2342
+ hint: "a zkApp is already recorded for this identity/chain \u2014 the open path reuses it"
2343
+ });
2344
+ return 0;
2345
+ }
2346
+ io2.out(
2347
+ `A Mina zkApp is already recorded for this identity on ${chain}: ` + existing.zkAppAddress
2348
+ );
2349
+ io2.out(`The open path reuses it (record: ${store.filePath}).`);
2350
+ return 0;
2351
+ }
2352
+ const plan = { chain, graphqlUrl };
2353
+ if (!json) {
2354
+ io2.out("Mina zkApp deploy plan:");
2355
+ io2.out(` chain ${chain}`);
2356
+ io2.out(` graphql ${graphqlUrl}`);
2357
+ io2.out(renderIdentityLine(identity));
2358
+ io2.out(
2359
+ "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."
2360
+ );
2361
+ }
2362
+ const gate = await confirmOnChain(
2363
+ io2,
2364
+ { yes, json },
2365
+ "Proceed with the on-chain zkApp deploy? [y/N] "
2366
+ );
2367
+ if (gate === "json-plan") {
2368
+ io2.emitJson({
2369
+ command: "channel deploy-zkapp",
2370
+ identity,
2371
+ executed: false,
2372
+ plan,
2373
+ hint: "plan only \u2014 re-run with --yes to deploy (on-chain: ~1.1 MINA + fees)"
2374
+ });
2375
+ return 0;
2376
+ }
2377
+ if (gate !== "proceed") return gate;
2378
+ const client = await import("@toon-protocol/client");
2379
+ const derived = await client.deriveFullIdentity(
2380
+ resolved.mnemonic,
2381
+ resolved.accountIndex
2382
+ );
2383
+ if (!derived.mina.privateKey) {
2384
+ throw new Error(
2385
+ "no Mina key derived \u2014 the optional `mina-signer` dependency is not installed"
2386
+ );
2387
+ }
2388
+ const record = await client.deployMinaChannelZkApp({
2389
+ graphqlUrl,
2390
+ payerPrivateKey: derived.mina.privateKey,
2391
+ onProgress: (line) => io2.err(`rig: mina: ${line}`)
2392
+ });
2393
+ store.save({
2394
+ identity: resolved.pubkey,
2395
+ chain,
2396
+ zkAppAddress: record.zkAppAddress,
2397
+ zkAppPrivateKey: record.zkAppPrivateKey,
2398
+ feePayer: record.feePayer,
2399
+ ...record.deployTxHash !== void 0 ? { deployTxHash: record.deployTxHash } : {},
2400
+ ...record.vkHash !== void 0 ? { vkHash: record.vkHash } : {},
2401
+ deployedAt: (/* @__PURE__ */ new Date()).toISOString(),
2402
+ source: "rig channel deploy-zkapp (npm @toon-protocol/mina-zkapp build)"
2403
+ });
2404
+ if (json) {
2405
+ io2.emitJson({
2406
+ command: "channel deploy-zkapp",
2407
+ identity,
2408
+ executed: true,
2409
+ plan,
2410
+ result: {
2411
+ zkAppAddress: record.zkAppAddress,
2412
+ deployTxHash: record.deployTxHash ?? null,
2413
+ vkHash: record.vkHash ?? null,
2414
+ storePath: store.filePath
2415
+ }
2416
+ });
2417
+ return 0;
2418
+ }
2419
+ io2.out(`Deployed Mina PaymentChannel zkApp ${record.zkAppAddress}.`);
2420
+ if (record.deployTxHash) io2.out(` deploy tx ${record.deployTxHash}`);
2421
+ if (record.vkHash) io2.out(` vk hash ${record.vkHash}`);
2422
+ io2.out(` record ${store.filePath} (holds the zkApp key \u2014 back it up)`);
2423
+ io2.out("The next Mina channel open/push finds and reuses this zkApp.");
2424
+ return 0;
2425
+ } catch (err) {
2426
+ return emitCliError(io2, json, "channel deploy-zkapp", err);
2427
+ }
2428
+ }
2239
2429
  function withdrawPrecheck(step, channelId, watermark, nowSec) {
2240
2430
  const status = channelStatus(watermark, nowSec);
2241
2431
  if (status === "settled") {
@@ -2405,7 +2595,7 @@ async function stopQuietly(ctx) {
2405
2595
 
2406
2596
  // src/cli/clone.ts
2407
2597
  import { mkdtemp, mkdir, readdir, rename, rm, rmdir } from "fs/promises";
2408
- import { basename, dirname as dirname2, join as join3, resolve } from "path";
2598
+ import { basename, dirname as dirname2, join as join4, resolve } from "path";
2409
2599
  import { parseArgs as parseArgs6 } from "util";
2410
2600
  var CLONE_USAGE = `Usage: rig clone <relay-url> <owner>/<repo-id> [dir] [options]
2411
2601
 
@@ -2576,7 +2766,7 @@ async function runClone(args, deps) {
2576
2766
  }
2577
2767
  const parent = dirname2(dest);
2578
2768
  await mkdir(parent, { recursive: true });
2579
- tempDir = await mkdtemp(join3(parent, `.${basename(dest)}.rig-clone-`));
2769
+ tempDir = await mkdtemp(join4(parent, `.${basename(dest)}.rig-clone-`));
2580
2770
  await runGit(tempDir, [
2581
2771
  "init",
2582
2772
  "--quiet",
@@ -3822,8 +4012,288 @@ async function warnIfNotMaintainer(deps, args) {
3822
4012
  }
3823
4013
  }
3824
4014
 
3825
- // src/cli/fetch.ts
4015
+ // src/cli/entry.ts
4016
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
4017
+ import { homedir as homedir4 } from "os";
4018
+ import { dirname as dirname3, join as join5 } from "path";
3826
4019
  import { parseArgs as parseArgs9 } from "util";
4020
+ var SANDBOX_BTP_URL = "wss://proxy.sandbox.devnet.toonprotocol.dev:443";
4021
+ var SANDBOX_RELAY_URL = "wss://relay-ws.sandbox.devnet.toonprotocol.dev";
4022
+ var ENTRY_USAGE = `Usage: rig entry [apex | sandbox | <wss-url>] [options]
4023
+
4024
+ Choose which network entry node (payment ingress + relay) rig talks to. Free:
4025
+ only the local config file is touched.
4026
+
4027
+ rig entry show the effective entry endpoints and their source
4028
+ rig entry apex revert to the default apex: clears the btpUrl/
4029
+ relayUrl override so core's genesis seed (or a live
4030
+ announce) applies \u2014 settles evm | sol | mina
4031
+ rig entry sandbox the devnet sandbox entry (Mina USDC ONLY \u2014 the
4032
+ cross-currency multihop demo path):
4033
+ btp ${SANDBOX_BTP_URL}
4034
+ relay ${SANDBOX_RELAY_URL}
4035
+ rig entry <wss-url> an explicit BTP endpoint (ws:// or wss://); pass
4036
+ --relay <url> to also set the relay
4037
+
4038
+ Switching entries deletes the cached topology (the next paid command
4039
+ re-discovers the new entry's announce) and leaves existing payment channels
4040
+ behind \u2014 channels are per-entry-peer; the next paid command opens or resumes
4041
+ one with the new peer.
4042
+
4043
+ NOTE for repos: the relay a repo publishes to is its git \`origin\` remote,
4044
+ which OVERRIDES the config relayUrl. After switching entries, point the repo
4045
+ too: \`rig remote add origin <relay-url>\` (or use a fresh repo).
4046
+
4047
+ Options:
4048
+ --relay <url> with <wss-url>: also set the relay URL
4049
+ --json machine-readable envelope
4050
+ -h, --help show this help`;
4051
+ function configPathFor2(env) {
4052
+ const dir = env["TOON_CLIENT_HOME"] ?? join5(homedir4(), ".toon-client");
4053
+ return join5(dir, "config.json");
4054
+ }
4055
+ function readEntryConfig(configPath) {
4056
+ try {
4057
+ return JSON.parse(readFileSync4(configPath, "utf8"));
4058
+ } catch (err) {
4059
+ if (err.code === "ENOENT") return {};
4060
+ throw new Error(
4061
+ `failed to read client config at ${configPath}: ${err instanceof Error ? err.message : String(err)}`
4062
+ );
4063
+ }
4064
+ }
4065
+ function writeEntryConfig(configPath, file) {
4066
+ mkdirSync3(dirname3(configPath), { recursive: true });
4067
+ writeFileSync3(configPath, `${JSON.stringify(file, null, 2)}
4068
+ `, "utf8");
4069
+ }
4070
+ async function loadGenesisSeedDefault() {
4071
+ try {
4072
+ const { loadGenesisSeed } = await import("../network-bootstrap-3X2GXNJB.js");
4073
+ return loadGenesisSeed();
4074
+ } catch {
4075
+ return void 0;
4076
+ }
4077
+ }
4078
+ function classifyEntry(btpUrl, seedBtp, btpSource) {
4079
+ if (btpUrl === null) return null;
4080
+ if (btpUrl === SANDBOX_BTP_URL) return "sandbox";
4081
+ if (btpSource === "genesis-seed" || btpUrl === seedBtp) return "apex";
4082
+ return "custom";
4083
+ }
4084
+ async function runEntry(args, deps) {
4085
+ const { io: io2, env } = deps;
4086
+ let positionals;
4087
+ let relayFlag;
4088
+ let json = false;
4089
+ try {
4090
+ const parsed = parseArgs9({
4091
+ args,
4092
+ allowPositionals: true,
4093
+ options: {
4094
+ relay: { type: "string" },
4095
+ json: { type: "boolean", default: false },
4096
+ help: { type: "boolean", short: "h", default: false }
4097
+ }
4098
+ });
4099
+ if (parsed.values.help) {
4100
+ io2.out(ENTRY_USAGE);
4101
+ return 0;
4102
+ }
4103
+ positionals = parsed.positionals;
4104
+ relayFlag = parsed.values.relay;
4105
+ json = parsed.values.json ?? false;
4106
+ } catch (err) {
4107
+ io2.err(err instanceof Error ? err.message : String(err));
4108
+ io2.err(ENTRY_USAGE);
4109
+ return 2;
4110
+ }
4111
+ if (positionals.length > 1) {
4112
+ io2.err(
4113
+ `rig entry takes at most one argument, got ${positionals.length}: ${positionals.join(" ")}`
4114
+ );
4115
+ io2.err(ENTRY_USAGE);
4116
+ return 2;
4117
+ }
4118
+ const target = positionals[0];
4119
+ let mutation;
4120
+ if (target !== void 0) {
4121
+ if (target === "apex") {
4122
+ if (relayFlag !== void 0) {
4123
+ io2.err("--relay only applies to an explicit <wss-url> entry");
4124
+ io2.err(ENTRY_USAGE);
4125
+ return 2;
4126
+ }
4127
+ mutation = { kind: "apex" };
4128
+ } else if (target === "sandbox") {
4129
+ if (relayFlag !== void 0) {
4130
+ io2.err("--relay only applies to an explicit <wss-url> entry");
4131
+ io2.err(ENTRY_USAGE);
4132
+ return 2;
4133
+ }
4134
+ mutation = { kind: "sandbox" };
4135
+ } else if (/^wss?:\/\/.+/.test(target)) {
4136
+ if (relayFlag !== void 0 && !/^wss?:\/\/.+/.test(relayFlag)) {
4137
+ io2.err(
4138
+ `--relay must be a ws(s) URL, got ${JSON.stringify(relayFlag)}`
4139
+ );
4140
+ io2.err(ENTRY_USAGE);
4141
+ return 2;
4142
+ }
4143
+ mutation = {
4144
+ kind: "url",
4145
+ btpUrl: target,
4146
+ ...relayFlag !== void 0 ? { relayUrl: relayFlag } : {}
4147
+ };
4148
+ } else {
4149
+ io2.err(
4150
+ `unknown entry ${JSON.stringify(target)} \u2014 expected \`apex\`, \`sandbox\`, or a ws(s):// URL`
4151
+ );
4152
+ io2.err(ENTRY_USAGE);
4153
+ return 2;
4154
+ }
4155
+ }
4156
+ try {
4157
+ const configPath = configPathFor2(env);
4158
+ const file = readEntryConfig(configPath);
4159
+ const seed = await (deps.loadGenesisSeed ?? loadGenesisSeedDefault)();
4160
+ const effective = () => {
4161
+ const btpExplicit = env["TOON_CLIENT_PROXY_URL"] ?? env["TOON_CLIENT_BTP_URL"] ?? file.proxyUrl ?? file.btpUrl;
4162
+ const btpFromEnv = env["TOON_CLIENT_PROXY_URL"] ?? env["TOON_CLIENT_BTP_URL"];
4163
+ const relayExplicit = env["TOON_CLIENT_RELAY_URL"] ?? file.relayUrl;
4164
+ return {
4165
+ btpUrl: btpExplicit ?? seed?.btpEndpoint ?? null,
4166
+ btpSource: btpExplicit ? btpFromEnv ? "env" : "config" : seed?.btpEndpoint ? "genesis-seed" : null,
4167
+ relayUrl: relayExplicit ?? seed?.relayUrl ?? null,
4168
+ relaySource: env["TOON_CLIENT_RELAY_URL"] ? "env" : file.relayUrl ? "config" : seed?.relayUrl ? "genesis-seed" : null
4169
+ };
4170
+ };
4171
+ if (mutation === void 0) {
4172
+ const state2 = effective();
4173
+ const entry = classifyEntry(state2.btpUrl, seed?.btpEndpoint, state2.btpSource);
4174
+ if (json) {
4175
+ io2.emitJson({
4176
+ command: "entry",
4177
+ entry,
4178
+ btpUrl: state2.btpUrl,
4179
+ btpSource: state2.btpSource,
4180
+ relayUrl: state2.relayUrl,
4181
+ relaySource: state2.relaySource,
4182
+ configPath
4183
+ });
4184
+ return 0;
4185
+ }
4186
+ const label = (source) => source === "env" ? "env" : source === "config" ? `config (${configPath})` : source === "genesis-seed" ? "default apex \u2014 genesis seed" : "not configured";
4187
+ io2.out(
4188
+ `Entry: ${entry ?? "(none)"}${entry === "sandbox" ? " (Mina USDC only \u2014 multihop demo path)" : ""}`
4189
+ );
4190
+ io2.out(` btp ${state2.btpUrl ?? "(none)"} [${label(state2.btpSource)}]`);
4191
+ io2.out(` relay ${state2.relayUrl ?? "(none)"} [${label(state2.relaySource)}]`);
4192
+ io2.out(
4193
+ "Switch with `rig entry apex`, `rig entry sandbox`, or `rig entry <wss-url>`."
4194
+ );
4195
+ return 0;
4196
+ }
4197
+ const warnings = [];
4198
+ for (const envVar of [
4199
+ "TOON_CLIENT_BTP_URL",
4200
+ "TOON_CLIENT_PROXY_URL",
4201
+ "TOON_CLIENT_RELAY_URL"
4202
+ ]) {
4203
+ if (env[envVar] !== void 0) {
4204
+ warnings.push(
4205
+ `${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.`
4206
+ );
4207
+ }
4208
+ }
4209
+ warnings.push(
4210
+ "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."
4211
+ );
4212
+ const hadProxyUrl = file.proxyUrl !== void 0;
4213
+ let wroteBtp;
4214
+ let wroteRelay;
4215
+ if (mutation.kind === "apex") {
4216
+ wroteBtp = null;
4217
+ wroteRelay = null;
4218
+ delete file.btpUrl;
4219
+ delete file.relayUrl;
4220
+ delete file.proxyUrl;
4221
+ } else if (mutation.kind === "sandbox") {
4222
+ wroteBtp = SANDBOX_BTP_URL;
4223
+ wroteRelay = SANDBOX_RELAY_URL;
4224
+ file.btpUrl = SANDBOX_BTP_URL;
4225
+ file.relayUrl = SANDBOX_RELAY_URL;
4226
+ delete file.proxyUrl;
4227
+ } else {
4228
+ wroteBtp = mutation.btpUrl;
4229
+ wroteRelay = mutation.relayUrl ?? null;
4230
+ file.btpUrl = mutation.btpUrl;
4231
+ if (mutation.relayUrl !== void 0) file.relayUrl = mutation.relayUrl;
4232
+ delete file.proxyUrl;
4233
+ }
4234
+ if (hadProxyUrl) {
4235
+ warnings.push(
4236
+ "Removed the legacy `proxyUrl` config field \u2014 it outranks `btpUrl` and would have silently kept the old entry."
4237
+ );
4238
+ }
4239
+ writeEntryConfig(configPath, file);
4240
+ let clearedTopologyCache = false;
4241
+ try {
4242
+ unlinkSync(join5(dirname3(configPath), TOPOLOGY_CACHE_FILENAME));
4243
+ clearedTopologyCache = true;
4244
+ } catch {
4245
+ }
4246
+ if (mutation.kind === "sandbox") {
4247
+ const effectiveChain = env["TOON_CLIENT_CHAIN"] ?? file.chain ?? file.supportedChains?.[0];
4248
+ if (effectiveChain === void 0 || !effectiveChain.startsWith("mina")) {
4249
+ warnings.push(
4250
+ "The sandbox entry settles ONLY mina:devnet \u2014 run `rig chain set mina` " + (effectiveChain !== void 0 ? `(currently ${effectiveChain}).` : "to pin it.")
4251
+ );
4252
+ }
4253
+ warnings.push(
4254
+ `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).`
4255
+ );
4256
+ }
4257
+ const state = effective();
4258
+ if (json) {
4259
+ io2.emitJson({
4260
+ command: "entry",
4261
+ entry: mutation.kind === "url" ? "custom" : mutation.kind,
4262
+ btpUrl: state.btpUrl,
4263
+ btpSource: state.btpSource,
4264
+ relayUrl: state.relayUrl,
4265
+ relaySource: state.relaySource,
4266
+ wrote: { btpUrl: wroteBtp, relayUrl: wroteRelay },
4267
+ clearedTopologyCache,
4268
+ configPath,
4269
+ ...warnings.length ? { warnings } : {}
4270
+ });
4271
+ return 0;
4272
+ }
4273
+ if (mutation.kind === "apex") {
4274
+ io2.out("Entry reverted to the default apex (cleared btpUrl/relayUrl/proxyUrl).");
4275
+ io2.out(` btp ${state.btpUrl ?? "(genesis seed unavailable)"}`);
4276
+ io2.out(` relay ${state.relayUrl ?? "(genesis seed unavailable)"}`);
4277
+ } else if (mutation.kind === "sandbox") {
4278
+ io2.out("Entry set to the devnet sandbox (Mina USDC only \u2014 multihop demo path).");
4279
+ io2.out(` btp ${SANDBOX_BTP_URL}`);
4280
+ io2.out(` relay ${SANDBOX_RELAY_URL}`);
4281
+ } else {
4282
+ io2.out(`Entry set to ${mutation.btpUrl}.`);
4283
+ if (mutation.relayUrl !== void 0) io2.out(` relay ${mutation.relayUrl}`);
4284
+ }
4285
+ io2.out(
4286
+ `Saved to ${configPath}.` + (clearedTopologyCache ? " Cleared the cached topology." : "")
4287
+ );
4288
+ for (const w of warnings) io2.err(`warning: ${w}`);
4289
+ return 0;
4290
+ } catch (err) {
4291
+ return emitCliError(io2, json, "entry", err);
4292
+ }
4293
+ }
4294
+
4295
+ // src/cli/fetch.ts
4296
+ import { parseArgs as parseArgs10 } from "util";
3827
4297
  var FETCH_USAGE = `Usage: rig fetch [remote] [options]
3828
4298
 
3829
4299
  Fetch from a TOON remote \u2014 FREE (relay reads + Arweave gateway downloads; no
@@ -3877,7 +4347,7 @@ async function runFetch(args, deps) {
3877
4347
  let ownerFlag;
3878
4348
  let concurrency;
3879
4349
  try {
3880
- const { values, positionals } = parseArgs9({
4350
+ const { values, positionals } = parseArgs10({
3881
4351
  args,
3882
4352
  options: {
3883
4353
  json: { type: "boolean", default: false },
@@ -4042,10 +4512,10 @@ async function runFetch(args, deps) {
4042
4512
  }
4043
4513
 
4044
4514
  // 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";
4515
+ import { readFileSync as readFileSync5 } from "fs";
4516
+ import { homedir as homedir5 } from "os";
4517
+ import { join as join6 } from "path";
4518
+ import { parseArgs as parseArgs11 } from "util";
4049
4519
  var DEVNET_FAUCET_URL = "https://faucet.devnet.toonprotocol.dev";
4050
4520
  var CHAINS = ["evm", "solana", "mina"];
4051
4521
  var CHAIN_ALIASES = {
@@ -4083,7 +4553,9 @@ The identity comes from RIG_MNEMONIC (env or a project .env) or the
4083
4553
  faucetUrl config field, or the deployed devnet faucet when the network is
4084
4554
  devnet \u2014 including when a configured *.devnet.toonprotocol.dev origin infers
4085
4555
  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
4556
+ \`rig remote add origin <devnet relay>\`). A completely fresh install with NO
4557
+ origin configured anywhere infers devnet from the built-in genesis seed, so a
4558
+ bare \`rig fund\` works with zero config. The faucet drips a FIXED amount per
4087
4559
  chain (there is no --amount). On a network without a faucet, prints the wallet
4088
4560
  address(es) to fund externally instead.
4089
4561
 
@@ -4120,6 +4592,44 @@ function sharedDevnetOrigin(env, file, originRelays = []) {
4120
4592
  }
4121
4593
  return void 0;
4122
4594
  }
4595
+ async function loadGenesisSeedDefault2() {
4596
+ try {
4597
+ const { loadGenesisSeed } = await import("../network-bootstrap-3X2GXNJB.js");
4598
+ return loadGenesisSeed();
4599
+ } catch {
4600
+ return void 0;
4601
+ }
4602
+ }
4603
+ async function resolveEffectiveNetwork(opts) {
4604
+ const { env, cwd } = opts;
4605
+ const file = opts.file ?? readFundConfig(env).file;
4606
+ const network = env["TOON_CLIENT_NETWORK"] ?? file.network;
4607
+ const canInfer = network === void 0 || network === "custom";
4608
+ const originRelays = canInfer ? await resolveOriginRelays(cwd) : [];
4609
+ let devnetOrigin = sharedDevnetOrigin(env, file, originRelays);
4610
+ let seededOrigin = false;
4611
+ if (devnetOrigin === void 0 && canInfer) {
4612
+ const anyConfiguredOrigin = [
4613
+ env["TOON_CLIENT_RELAY_URL"] ?? file.relayUrl,
4614
+ env["TOON_CLIENT_PROXY_URL"] ?? file.proxyUrl,
4615
+ env["TOON_CLIENT_BTP_URL"] ?? file.btpUrl,
4616
+ ...originRelays
4617
+ ].some((url) => url !== void 0);
4618
+ if (!anyConfiguredOrigin) {
4619
+ const seed = await (opts.loadGenesisSeed ?? loadGenesisSeedDefault2)();
4620
+ devnetOrigin = devnetHost(seed?.relayUrl) ?? devnetHost(seed?.btpEndpoint);
4621
+ seededOrigin = devnetOrigin !== void 0;
4622
+ }
4623
+ }
4624
+ const inferredDevnet = devnetOrigin !== void 0 && canInfer;
4625
+ return {
4626
+ network,
4627
+ effectiveNetwork: inferredDevnet ? "devnet" : network,
4628
+ devnetOrigin,
4629
+ seededOrigin,
4630
+ inferredDevnet
4631
+ };
4632
+ }
4123
4633
  async function resolveOriginRelays(cwd) {
4124
4634
  let repoRoot;
4125
4635
  try {
@@ -4149,11 +4659,11 @@ function noFaucetGuidance(network, devnetOrigin) {
4149
4659
  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
4660
  }
4151
4661
  function readFundConfig(env) {
4152
- const dir = env["TOON_CLIENT_HOME"] ?? join4(homedir3(), ".toon-client");
4153
- const configPath = join4(dir, "config.json");
4662
+ const dir = env["TOON_CLIENT_HOME"] ?? join6(homedir5(), ".toon-client");
4663
+ const configPath = join6(dir, "config.json");
4154
4664
  try {
4155
4665
  return {
4156
- file: JSON.parse(readFileSync3(configPath, "utf8")),
4666
+ file: JSON.parse(readFileSync5(configPath, "utf8")),
4157
4667
  configPath
4158
4668
  };
4159
4669
  } catch (err) {
@@ -4171,7 +4681,7 @@ async function runFund(args, deps) {
4171
4681
  let addressFlag;
4172
4682
  let json = false;
4173
4683
  try {
4174
- const { values, positionals } = parseArgs10({
4684
+ const { values, positionals } = parseArgs11({
4175
4685
  args,
4176
4686
  allowPositionals: true,
4177
4687
  options: {
@@ -4213,11 +4723,12 @@ async function runFund(args, deps) {
4213
4723
  const { file } = readFundConfig(env);
4214
4724
  const targetChains = resolvedChain === void 0 || resolvedChain === "all" ? [...CHAINS] : [resolvedChain];
4215
4725
  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;
4726
+ const { devnetOrigin, seededOrigin, inferredDevnet, effectiveNetwork } = await resolveEffectiveNetwork({
4727
+ env,
4728
+ cwd: deps.cwd,
4729
+ file,
4730
+ ...deps.loadGenesisSeed ? { loadGenesisSeed: deps.loadGenesisSeed } : {}
4731
+ });
4221
4732
  const faucetUrl = env["TOON_CLIENT_FAUCET_URL"] ?? file.faucetUrl ?? (effectiveNetwork === "devnet" ? DEVNET_FAUCET_URL : void 0);
4222
4733
  const resolved = await resolveIdentity({
4223
4734
  env,
@@ -4268,7 +4779,7 @@ async function runFund(args, deps) {
4268
4779
  };
4269
4780
  if (!json && inferredDevnet) {
4270
4781
  io2.out(
4271
- `Inferred network 'devnet' from the configured origin ${devnetOrigin} (network was ${JSON.stringify(network ?? "custom")}). Set TOON_CLIENT_NETWORK explicitly to override.`
4782
+ 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
4783
  );
4273
4784
  }
4274
4785
  if (!json) {
@@ -4321,7 +4832,9 @@ async function runFund(args, deps) {
4321
4832
  network: effectiveNetwork ?? null,
4322
4833
  faucetUrl,
4323
4834
  results,
4324
- ...inferredDevnet ? { inferredDevnetFrom: devnetOrigin } : {}
4835
+ ...inferredDevnet ? {
4836
+ inferredDevnetFrom: seededOrigin ? `${devnetOrigin} (genesis seed)` : devnetOrigin
4837
+ } : {}
4325
4838
  });
4326
4839
  return allFunded ? 0 : 1;
4327
4840
  }
@@ -4393,10 +4906,10 @@ var runGitPassthrough = (argv2, options = {}) => {
4393
4906
  };
4394
4907
 
4395
4908
  // src/cli/identity-cmd.ts
4396
- import { existsSync, mkdirSync as mkdirSync3 } from "fs";
4397
- import { dirname as dirname3 } from "path";
4909
+ import { existsSync, mkdirSync as mkdirSync4 } from "fs";
4910
+ import { dirname as dirname4 } from "path";
4398
4911
  import { createInterface } from "readline/promises";
4399
- import { parseArgs as parseArgs11 } from "util";
4912
+ import { parseArgs as parseArgs12 } from "util";
4400
4913
  async function loadKeyOps() {
4401
4914
  return await import("@toon-protocol/client");
4402
4915
  }
@@ -4445,7 +4958,7 @@ async function prepareKeystoreTarget(input) {
4445
4958
  const envPassword = input.env["TOON_CLIENT_KEYSTORE_PASSWORD"]?.trim() || void 0;
4446
4959
  const autoPassword = envPassword === void 0;
4447
4960
  const password = envPassword ?? DEFAULT_KEYSTORE_PASSWORD;
4448
- mkdirSync3(dirname3(keystorePath), { recursive: true });
4961
+ mkdirSync4(dirname4(keystorePath), { recursive: true });
4449
4962
  return { keystorePath, password, autoPassword, existing, keyOps };
4450
4963
  }
4451
4964
  function readAccountIndex(env) {
@@ -4567,7 +5080,7 @@ async function runIdentity(args, deps) {
4567
5080
  }
4568
5081
  }
4569
5082
  function parseMintArgs(args, verb) {
4570
- const { values, positionals } = parseArgs11({
5083
+ const { values, positionals } = parseArgs12({
4571
5084
  args,
4572
5085
  options: {
4573
5086
  force: { type: "boolean", default: false },
@@ -4672,7 +5185,7 @@ async function runIdentityShow(args, deps) {
4672
5185
  let json = false;
4673
5186
  let help = false;
4674
5187
  try {
4675
- const parsed = parseArgs11({
5188
+ const parsed = parseArgs12({
4676
5189
  args,
4677
5190
  options: {
4678
5191
  json: { type: "boolean", default: false },
@@ -4781,7 +5294,7 @@ async function defaultReadSecretLine(prompt, isInteractive) {
4781
5294
 
4782
5295
  // src/cli/init.ts
4783
5296
  import { basename as basename2 } from "path";
4784
- import { parseArgs as parseArgs12 } from "util";
5297
+ import { parseArgs as parseArgs13 } from "util";
4785
5298
 
4786
5299
  // src/cli/git-author.ts
4787
5300
  var PROFILE_KIND = 0;
@@ -4899,7 +5412,7 @@ Options:
4899
5412
  --json machine-readable report
4900
5413
  -h, --help show this help`;
4901
5414
  function parseInitArgs(args) {
4902
- const { values, positionals } = parseArgs12({
5415
+ const { values, positionals } = parseArgs13({
4903
5416
  args,
4904
5417
  options: {
4905
5418
  "repo-id": { type: "string" },
@@ -5132,7 +5645,7 @@ async function runInit(args, deps) {
5132
5645
  }
5133
5646
 
5134
5647
  // src/cli/maintainers.ts
5135
- import { parseArgs as parseArgs13 } from "util";
5648
+ import { parseArgs as parseArgs14 } from "util";
5136
5649
  var HEX64_RE3 = /^[0-9a-f]{64}$/;
5137
5650
  var WS_URL_RE4 = /^wss?:\/\//i;
5138
5651
  var MAINTAINERS_USAGE = `Usage: rig maintainers <list|add|remove> [<pubkey>] [options]
@@ -5237,7 +5750,7 @@ async function runList2(args, deps) {
5237
5750
  const { io: io2 } = deps;
5238
5751
  let flags;
5239
5752
  try {
5240
- const { values, positionals } = parseArgs13({
5753
+ const { values, positionals } = parseArgs14({
5241
5754
  args,
5242
5755
  options: MAINT_OPTIONS,
5243
5756
  allowPositionals: true
@@ -5304,7 +5817,7 @@ async function runMutate(op, args, deps) {
5304
5817
  let flags;
5305
5818
  let pubkey;
5306
5819
  try {
5307
- const { values, positionals } = parseArgs13({
5820
+ const { values, positionals } = parseArgs14({
5308
5821
  args,
5309
5822
  options: MAINT_OPTIONS,
5310
5823
  allowPositionals: true
@@ -5453,7 +5966,7 @@ async function runMutate(op, args, deps) {
5453
5966
 
5454
5967
  // src/cli/name.ts
5455
5968
  import { randomUUID } from "crypto";
5456
- import { parseArgs as parseArgs14 } from "util";
5969
+ import { parseArgs as parseArgs15 } from "util";
5457
5970
  var ARIO_DECIMALS = 6;
5458
5971
  function renderMario(mario) {
5459
5972
  return `${mario.toString()} mARIO (~${formatUnits(mario.toString(), ARIO_DECIMALS)} ARIO)`;
@@ -5857,6 +6370,7 @@ var defaultGasStationClient = {
5857
6370
  };
5858
6371
  }
5859
6372
  };
6373
+ var DEVNET_DVM_URL = "https://dvm.devnet.toonprotocol.dev";
5860
6374
  var NAME_USAGE = `Usage: rig name <buy|set|status> <name> [options]
5861
6375
 
5862
6376
  ArNS naming for Arweave-served artifacts. A name registered on the ar.io
@@ -5909,12 +6423,18 @@ Options:
5909
6423
  unverified.
5910
6424
  --process-id <id> explicit ArNS registry program id \u2014 a Solana program
5911
6425
  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.
6426
+ --via <dvm-url> broker buy/set through a store DVM's job endpoint (or
6427
+ RIG_ARNS_DVM_URL). The DVM pays the mARIO; you own the
6428
+ name via your spawned ANT. Direct backend targeting
6429
+ stubs the job payment (dev/e2e) \u2014 the paid path runs
6430
+ the same job through the connector payment proxy.
6431
+ DEVNET DEFAULT: with --network devnet and the TOON
6432
+ network on devnet too, buy/set default to the deployed
6433
+ devnet store DVM (${DEVNET_DVM_URL})
6434
+ unless --direct opts out.
6435
+ --direct force the direct wallet-paid path: never default (or
6436
+ read RIG_ARNS_DVM_URL as) a --via DVM. Mutually
6437
+ exclusive with an explicit --via.
5918
6438
  --yes skip the confirmation (required when not a TTY) for
5919
6439
  buy/set
5920
6440
  --json machine-readable envelope; for buy/set without --yes it
@@ -5960,7 +6480,7 @@ async function resolveNameContext(deps, network, processId, mode) {
5960
6480
  return { identity, solanaAddress, network, processId, sdk, nostrSecretKey };
5961
6481
  }
5962
6482
  function parseNameFlags(args, env) {
5963
- const { values, positionals } = parseArgs14({
6483
+ const { values, positionals } = parseArgs15({
5964
6484
  args,
5965
6485
  allowPositionals: true,
5966
6486
  options: {
@@ -5971,6 +6491,7 @@ function parseNameFlags(args, env) {
5971
6491
  network: { type: "string" },
5972
6492
  "process-id": { type: "string" },
5973
6493
  via: { type: "string" },
6494
+ direct: { type: "boolean", default: false },
5974
6495
  "tx-id": { type: "string" },
5975
6496
  yes: { type: "boolean", default: false },
5976
6497
  json: { type: "boolean", default: false },
@@ -5984,6 +6505,7 @@ function parseNameFlags(args, env) {
5984
6505
  permabuy: false,
5985
6506
  ttl: 0,
5986
6507
  network: "mainnet",
6508
+ direct: false,
5987
6509
  yes: false,
5988
6510
  json: false
5989
6511
  }
@@ -6017,7 +6539,12 @@ function parseNameFlags(args, env) {
6017
6539
  );
6018
6540
  }
6019
6541
  const processId = values["process-id"] ?? env["RIG_ARIO_PROCESS_ID"];
6020
- const viaRaw = values.via ?? env["RIG_ARNS_DVM_URL"];
6542
+ if (values.direct && values.via !== void 0) {
6543
+ throw new Error(
6544
+ "--direct and --via are mutually exclusive: --direct forces the wallet-paid path, --via brokers through a DVM"
6545
+ );
6546
+ }
6547
+ const viaRaw = values.direct ? void 0 : values.via ?? env["RIG_ARNS_DVM_URL"];
6021
6548
  let via;
6022
6549
  if (viaRaw !== void 0) {
6023
6550
  if (!/^https?:\/\/.+/.test(viaRaw)) {
@@ -6037,6 +6564,7 @@ function parseNameFlags(args, env) {
6037
6564
  network: networkRaw,
6038
6565
  ...processId !== void 0 ? { processId } : {},
6039
6566
  ...via !== void 0 ? { via } : {},
6567
+ direct: values.direct ?? false,
6040
6568
  ...values["tx-id"] !== void 0 ? { txId: values["tx-id"] } : {},
6041
6569
  yes: values.yes ?? false,
6042
6570
  json: values.json ?? false
@@ -6427,6 +6955,20 @@ async function runName(args, deps) {
6427
6955
  io2.err(NAME_USAGE);
6428
6956
  return 2;
6429
6957
  }
6958
+ if ((sub === "buy" || sub === "set") && !flags.direct && flags.via === void 0 && flags.network === "devnet") {
6959
+ let toonDevnet = false;
6960
+ try {
6961
+ const resolved = await (deps.resolveToonNetwork ?? resolveEffectiveNetwork)({ env: deps.env, cwd: deps.cwd });
6962
+ toonDevnet = resolved.effectiveNetwork === "devnet";
6963
+ } catch {
6964
+ }
6965
+ if (toonDevnet) {
6966
+ flags = { ...flags, via: DEVNET_DVM_URL };
6967
+ io2.err(
6968
+ `Brokering via the devnet store DVM ${DEVNET_DVM_URL} (no --via given; pass --direct for a wallet-paid ${sub}).`
6969
+ );
6970
+ }
6971
+ }
6430
6972
  try {
6431
6973
  if (sub === "buy") return await runBuy(name, flags, deps);
6432
6974
  if (sub === "status") return await runStatus(name, flags, deps);
@@ -6450,7 +6992,7 @@ async function runName(args, deps) {
6450
6992
  }
6451
6993
 
6452
6994
  // src/cli/site.ts
6453
- import { parseArgs as parseArgs15 } from "util";
6995
+ import { parseArgs as parseArgs16 } from "util";
6454
6996
 
6455
6997
  // src/arweave-manifest.ts
6456
6998
  var DEFAULT_INDEX = "index.html";
@@ -6469,22 +7011,22 @@ function buildArweaveManifest(entries, indexPath = DEFAULT_INDEX, fallbackTxId)
6469
7011
  }
6470
7012
 
6471
7013
  // 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";
7014
+ import { mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
7015
+ import { homedir as homedir6 } from "os";
7016
+ import { join as join7 } from "path";
6475
7017
  var SITE_MANIFEST_FILENAME = "site-manifests.json";
6476
7018
  function storeDir2(env) {
6477
- return env["TOON_CLIENT_HOME"] ?? join5(homedir4(), ".toon-client");
7019
+ return env["TOON_CLIENT_HOME"] ?? join7(homedir6(), ".toon-client");
6478
7020
  }
6479
7021
  function storePath2(env) {
6480
- return join5(storeDir2(env), SITE_MANIFEST_FILENAME);
7022
+ return join7(storeDir2(env), SITE_MANIFEST_FILENAME);
6481
7023
  }
6482
7024
  function keyOf(repoId, ref) {
6483
7025
  return `${repoId}\0${ref}`;
6484
7026
  }
6485
7027
  function readFile2(env) {
6486
7028
  try {
6487
- const parsed = JSON.parse(readFileSync4(storePath2(env), "utf8"));
7029
+ const parsed = JSON.parse(readFileSync6(storePath2(env), "utf8"));
6488
7030
  if (parsed && typeof parsed === "object") return parsed;
6489
7031
  return {};
6490
7032
  } catch {
@@ -6496,16 +7038,16 @@ function readSiteRecord(env, repoId, ref) {
6496
7038
  }
6497
7039
  function writeSiteRecord(env, record) {
6498
7040
  const dir = storeDir2(env);
6499
- mkdirSync4(dir, { recursive: true });
7041
+ mkdirSync5(dir, { recursive: true });
6500
7042
  const file = readFile2(env);
6501
7043
  file[keyOf(record.repoId, record.ref)] = record;
6502
- writeFileSync3(storePath2(env), `${JSON.stringify(file, null, 2)}
7044
+ writeFileSync4(storePath2(env), `${JSON.stringify(file, null, 2)}
6503
7045
  `, "utf8");
6504
7046
  }
6505
7047
 
6506
7048
  // src/cli/site.ts
6507
7049
  var MANIFEST_CONTENT_TYPE = "application/x.arweave-manifest+json";
6508
- var DEFAULT_GATEWAY = "https://arweave.net";
7050
+ var DEFAULT_GATEWAY = "https://ar-io.dev";
6509
7051
  var SITE_USAGE = `Usage: rig site <publish|url> [ref] [options]
6510
7052
 
6511
7053
  Serve a pushed repo as a permanent, path-routed website. \`rig push\` already
@@ -6541,7 +7083,7 @@ Options (publish):
6541
7083
  estimate (nothing uploaded)
6542
7084
  -h, --help show this help`;
6543
7085
  function parseSiteArgs(args) {
6544
- const { values, positionals } = parseArgs15({
7086
+ const { values, positionals } = parseArgs16({
6545
7087
  args,
6546
7088
  options: {
6547
7089
  index: { type: "string" },
@@ -6951,15 +7493,23 @@ Commands rig owns:
6951
7493
  (free \u2014 chain reads and local state only)
6952
7494
  chain [set <c>|unset] choose which chain/USDC settles paid writes
6953
7495
  (evm|sol|mina); free \u2014 reads/writes local config
7496
+ entry [apex|sandbox|url] choose the network entry node (payment ingress +
7497
+ relay): apex settles evm|sol|mina, sandbox is the
7498
+ Mina-only multihop demo path; free \u2014 writes local
7499
+ config and clears the cached topology
6954
7500
  name buy <name> ArNS naming (#367): buy points a human name at an
6955
7501
  name set <name> <txId> Arweave txId, owned + paid by this identity's
6956
7502
  name status <name> Solana key. buy spends mARIO on Solana via the
6957
7503
  ar.io registry (NOT ILP); status is free. Needs
6958
7504
  the optional \`@ar.io/sdk\` dependency
6959
7505
  channel list show the payment channels paid commands hold
6960
- (free \u2014 reads local state)
7506
+ (free \u2014 reads local state; \`rig channels\` is a
7507
+ shorthand for \`rig channel list\`)
6961
7508
  channel open explicitly open (or resume) the channel for a
6962
7509
  peer; --deposit adds collateral (on-chain)
7510
+ channel deploy-zkapp pre-deploy this identity's dedicated Mina
7511
+ PaymentChannel zkApp (on-chain; the Mina open
7512
+ path otherwise does this automatically)
6963
7513
  channel close <channelId> start the settlement challenge window (on-chain)
6964
7514
  channel settle <channelId> release collateral after the window (on-chain)
6965
7515
 
@@ -7022,12 +7572,19 @@ async function dispatch(argv2, deps) {
7022
7572
  return runMaintainers(rest, deps);
7023
7573
  case "channel":
7024
7574
  return runChannel(rest, deps);
7575
+ case "channels":
7576
+ return runChannel(
7577
+ rest[0] !== void 0 && !rest[0].startsWith("-") ? rest : ["list", ...rest],
7578
+ deps
7579
+ );
7025
7580
  case "fund":
7026
7581
  return runFund(rest, deps);
7027
7582
  case "balance":
7028
7583
  return runBalance(rest, deps);
7029
7584
  case "chain":
7030
7585
  return runChain(rest, deps);
7586
+ case "entry":
7587
+ return runEntry(rest, deps);
7031
7588
  case "name":
7032
7589
  return runName(rest, deps);
7033
7590
  case "help":
@@ -7105,8 +7662,11 @@ var RIG_OWNED_VERBS = /* @__PURE__ */ new Set([
7105
7662
  "pr",
7106
7663
  "maintainers",
7107
7664
  "channel",
7665
+ "channels",
7108
7666
  "fund",
7109
7667
  "balance",
7668
+ "chain",
7669
+ "entry",
7110
7670
  "name"
7111
7671
  ]);
7112
7672
  function isJsonInvocation(argv2) {