@toon-protocol/rig 2.8.0 → 2.9.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
@@ -532,8 +532,97 @@ function emitCliError(io2, json, command, err) {
532
532
  }
533
533
 
534
534
  // src/cli/push.ts
535
+ import { createHash } from "crypto";
535
536
  import { parseArgs as parseArgs2 } from "util";
536
537
 
538
+ // src/rig-pointer.ts
539
+ var DEFAULT_RIG_WEB_BUNDLE = {
540
+ manifestTx: "Iy8sHYVnoevSpwDC2lqUoIg8BWdes9NmMbgmPd81UpU",
541
+ entryJs: "assets/index-BuKzYubR.js",
542
+ entryCss: "assets/index-H5D6cmfa.css"
543
+ };
544
+ var RIG_WEB_TX_ENV = "RIG_WEB_TX";
545
+ var RIG_WEB_ENTRY_JS_ENV = "RIG_WEB_ENTRY_JS";
546
+ var RIG_WEB_ENTRY_CSS_ENV = "RIG_WEB_ENTRY_CSS";
547
+ var DEFAULT_RIG_WEB_URL = "https://toon-protocol.github.io/toon-client";
548
+ var RIG_WEB_URL_ENV = "RIG_WEB_URL";
549
+ function repoHashRoute(options) {
550
+ const { relay, ownerNpub, repoId } = options;
551
+ return `#/${encodeURIComponent(ownerNpub)}/${encodeURIComponent(repoId)}?relay=${encodeURIComponent(relay)}`;
552
+ }
553
+ function rigWebRoute(options) {
554
+ return `${options.rigWebUrl.replace(/\/+$/, "")}/${repoHashRoute(options)}`;
555
+ }
556
+ function escapeHtml(value) {
557
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
558
+ }
559
+ function generateRigPointerHtml(options) {
560
+ const gateway = options.gateway.replace(/\/+$/, "");
561
+ const base = `${gateway}/${options.bundle.manifestTx}`;
562
+ const cssHref = `${base}/${options.bundle.entryCss}`;
563
+ const jsSrc = `${base}/${options.bundle.entryJs}`;
564
+ const fallback = rigWebRoute(options);
565
+ const safeFallback = escapeHtml(fallback);
566
+ const title = escapeHtml(`${options.repoId} \u2014 Rig`);
567
+ const config = JSON.stringify({
568
+ relay: options.relay,
569
+ owner: options.ownerNpub,
570
+ repo: options.repoId
571
+ }).replace(/</g, "\\u003c");
572
+ const hashRoute = JSON.stringify(repoHashRoute(options)).replace(
573
+ /</g,
574
+ "\\u003c"
575
+ );
576
+ return `<!DOCTYPE html>
577
+ <html lang="en"><head>
578
+ <meta charset="utf-8">
579
+ <meta name="viewport" content="width=device-width,initial-scale=1">
580
+ <meta name="description" content="Decentralized Git on Nostr &amp; TOON Protocol">
581
+ <title>${title}</title>
582
+ <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>&#x2692;</text></svg>">
583
+ <script>window.__RIG_CONFIG__=${config};if(!location.hash||location.hash==="#")location.replace(${hashRoute})</script>
584
+ <link rel="stylesheet" href="${escapeHtml(cssHref)}">
585
+ <script type="module" crossorigin src="${escapeHtml(jsSrc)}"></script>
586
+ </head><body>
587
+ <div id="app"></div>
588
+ <noscript><p>JavaScript is off \u2014 open <a href="${safeFallback}">${title}</a> in the hosted Rig.</p></noscript>
589
+ <p hidden data-fallback>If nothing loads, open <a href="${safeFallback}">${title}</a> in the hosted Rig.</p>
590
+ <script>setTimeout(function(){var p=document.querySelector("[data-fallback]");var app=document.getElementById("app");if(p&&(!app||!app.childElementCount))p.hidden=false},8000)</script>
591
+ </body></html>
592
+ `;
593
+ }
594
+
595
+ // src/cli/rig-pointer-record.ts
596
+ import { mkdirSync, readFileSync, writeFileSync } from "fs";
597
+ import { homedir } from "os";
598
+ import { join } from "path";
599
+ var RIG_POINTER_FILENAME = "rig-pointers.json";
600
+ function storeDir(env) {
601
+ return env["TOON_CLIENT_HOME"] ?? join(homedir(), ".toon-client");
602
+ }
603
+ function storePath(env) {
604
+ return join(storeDir(env), RIG_POINTER_FILENAME);
605
+ }
606
+ function readAll(env) {
607
+ try {
608
+ const parsed = JSON.parse(readFileSync(storePath(env), "utf8"));
609
+ if (parsed && typeof parsed === "object") return parsed;
610
+ return {};
611
+ } catch {
612
+ return {};
613
+ }
614
+ }
615
+ function readRigPointerRecord(env, repoId) {
616
+ return readAll(env)[repoId];
617
+ }
618
+ function writeRigPointerRecord(env, record) {
619
+ const all = readAll(env);
620
+ all[record.repoId] = record;
621
+ mkdirSync(storeDir(env), { recursive: true });
622
+ writeFileSync(storePath(env), `${JSON.stringify(all, null, 2)}
623
+ `);
624
+ }
625
+
537
626
  // src/cli/render.ts
538
627
  function formatNumber(value) {
539
628
  return String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
@@ -1001,10 +1090,18 @@ remote name it is the remote; otherwise it is a refspec and the remote
1001
1090
  defaults to origin. Refspecs are branch/tag names or full refnames; default
1002
1091
  is the current branch.
1003
1092
 
1093
+ Every push also keeps the repo's RIG PAGE current: a permanent Arweave
1094
+ page that RENDERS this repo in place \u2014 it boots the FULL Rig (rig-web)
1095
+ from its Arweave deployment with this repo pinned, everything served from
1096
+ Arweave + the relay. The pointer is content-addressed, so it is paid for
1097
+ once and reused for free until the relay or Rig deployment changes.
1098
+ --no-rig-page skips it.
1099
+
1004
1100
  Options:
1005
1101
  --force allow non-fast-forward ref updates (overwrites remote history)
1006
1102
  --all push all local branches
1007
1103
  --tags push all local tags
1104
+ --no-rig-page skip the Rig-page pointer upload for this push
1008
1105
  --yes skip the fee confirmation (required when not a TTY)
1009
1106
  --json machine-readable plan/receipts; without --yes it is a pure
1010
1107
  estimate (nothing executed)
@@ -1077,6 +1174,7 @@ function parsePushArgs(args) {
1077
1174
  force: { type: "boolean", default: false },
1078
1175
  all: { type: "boolean", default: false },
1079
1176
  tags: { type: "boolean", default: false },
1177
+ "no-rig-page": { type: "boolean", default: false },
1080
1178
  yes: { type: "boolean", default: false },
1081
1179
  json: { type: "boolean", default: false },
1082
1180
  relay: { type: "string", multiple: true },
@@ -1089,6 +1187,7 @@ function parsePushArgs(args) {
1089
1187
  force: values.force ?? false,
1090
1188
  all: values.all ?? false,
1091
1189
  tags: values.tags ?? false,
1190
+ rigPage: !(values["no-rig-page"] ?? false),
1092
1191
  yes: values.yes ?? false,
1093
1192
  json: values.json ?? false,
1094
1193
  relay: values.relay ?? [],
@@ -1099,6 +1198,46 @@ function parsePushArgs(args) {
1099
1198
  if (repoId !== void 0) flags.repoId = repoId;
1100
1199
  return flags;
1101
1200
  }
1201
+ function pointerGateway(env) {
1202
+ return (env["RIG_ARWEAVE_GATEWAY"] ?? "https://arweave.net").replace(
1203
+ /\/+$/,
1204
+ ""
1205
+ );
1206
+ }
1207
+ function planRigPointer(args) {
1208
+ const html = generateRigPointerHtml({
1209
+ bundle: {
1210
+ manifestTx: args.env[RIG_WEB_TX_ENV] ?? DEFAULT_RIG_WEB_BUNDLE.manifestTx,
1211
+ entryJs: args.env[RIG_WEB_ENTRY_JS_ENV] ?? DEFAULT_RIG_WEB_BUNDLE.entryJs,
1212
+ entryCss: args.env[RIG_WEB_ENTRY_CSS_ENV] ?? DEFAULT_RIG_WEB_BUNDLE.entryCss
1213
+ },
1214
+ gateway: pointerGateway(args.env),
1215
+ rigWebUrl: args.env[RIG_WEB_URL_ENV] ?? DEFAULT_RIG_WEB_URL,
1216
+ relay: args.relay,
1217
+ ownerNpub: hexToNpub(args.ownerPubkey),
1218
+ repoId: args.repoId
1219
+ });
1220
+ const contentHash = createHash("sha256").update(html).digest("hex");
1221
+ const bytes = Buffer.byteLength(html);
1222
+ const record = readRigPointerRecord(args.env, args.repoId);
1223
+ if (record && record.contentHash === contentHash && record.owner === args.ownerPubkey) {
1224
+ return {
1225
+ action: "unchanged",
1226
+ html,
1227
+ contentHash,
1228
+ bytes,
1229
+ fee: 0n,
1230
+ recordedTxId: record.pointerTxId
1231
+ };
1232
+ }
1233
+ return {
1234
+ action: "upload",
1235
+ html,
1236
+ contentHash,
1237
+ bytes,
1238
+ fee: BigInt(bytes) * args.uploadFeePerByte
1239
+ };
1240
+ }
1102
1241
  async function runPush(args, deps) {
1103
1242
  const { io: io2 } = deps;
1104
1243
  let flags;
@@ -1175,6 +1314,8 @@ async function runPush(args, deps) {
1175
1314
  }
1176
1315
  let plan;
1177
1316
  let execute;
1317
+ let pointerPlan;
1318
+ let rigPageSkipDetail;
1178
1319
  if (session.path === "standalone") {
1179
1320
  const ctx = session.ctx;
1180
1321
  const remoteState = await ctx.fetchRemote({
@@ -1202,6 +1343,21 @@ async function runPush(args, deps) {
1202
1343
  relayUrls: relaysUsed
1203
1344
  })
1204
1345
  );
1346
+ if (!flags.rigPage) {
1347
+ rigPageSkipDetail = "skipped (--no-rig-page)";
1348
+ } else if (relaysUsed[0] === void 0) {
1349
+ rigPageSkipDetail = "skipped (no relay resolved for the pointer)";
1350
+ } else if (!ctx.publisher.uploadBlob) {
1351
+ rigPageSkipDetail = "skipped (the active publisher cannot upload raw blobs)";
1352
+ } else {
1353
+ pointerPlan = planRigPointer({
1354
+ env: deps.env,
1355
+ ownerPubkey: ctx.ownerPubkey,
1356
+ repoId,
1357
+ relay: relaysUsed[0],
1358
+ uploadFeePerByte: feeRates.uploadFeePerByte
1359
+ });
1360
+ }
1205
1361
  } else {
1206
1362
  const client = session.client;
1207
1363
  plan = await client.gitEstimate({
@@ -1219,9 +1375,100 @@ async function runPush(args, deps) {
1219
1375
  relayUrls: relaysUsed,
1220
1376
  confirm: true
1221
1377
  });
1378
+ rigPageSkipDetail = "skipped on the daemon path (refreshes on the next standalone push)";
1222
1379
  }
1380
+ const gateway = pointerGateway(deps.env);
1381
+ const publishPointer = async (pointer) => {
1382
+ try {
1383
+ const ctx = standaloneCtx;
1384
+ const receipt = await ctx.publisher.uploadBlob({
1385
+ body: Buffer.from(pointer.html, "utf8"),
1386
+ contentType: "text/html",
1387
+ repoId
1388
+ });
1389
+ writeRigPointerRecord(deps.env, {
1390
+ repoId,
1391
+ owner: identity.pubkey,
1392
+ pointerTxId: receipt.txId,
1393
+ contentHash: pointer.contentHash,
1394
+ updatedAt: Date.now()
1395
+ });
1396
+ return {
1397
+ status: "published",
1398
+ txId: receipt.txId,
1399
+ url: `${gateway}/${receipt.txId}`,
1400
+ feePaid: receipt.feePaid.toString()
1401
+ };
1402
+ } catch (err) {
1403
+ return {
1404
+ status: "skipped",
1405
+ detail: `pointer upload failed (push itself succeeded; the next push retries): ${err instanceof Error ? err.message : String(err)}`
1406
+ };
1407
+ }
1408
+ };
1409
+ const printRigPage = (rigPage2) => {
1410
+ if (rigPage2.url) {
1411
+ io2.out(
1412
+ `Rig page: ${rigPage2.url}` + (rigPage2.status === "published" ? ` paid ${rigPage2.feePaid}` : "") + " (renders this repo from Arweave)"
1413
+ );
1414
+ } else if (rigPage2.detail) {
1415
+ io2.err(`rig page: ${rigPage2.detail}`);
1416
+ }
1417
+ };
1223
1418
  const upToDate = plan.refUpdates.every((u) => u.kind === "up-to-date");
1224
1419
  if (upToDate) {
1420
+ if (pointerPlan?.action !== "upload") {
1421
+ if (flags.json) {
1422
+ io2.emitJson({
1423
+ command: "push",
1424
+ repoId,
1425
+ path,
1426
+ identity,
1427
+ executed: false,
1428
+ upToDate: true,
1429
+ plan
1430
+ });
1431
+ } else {
1432
+ io2.out("Everything up-to-date \u2014 nothing to push (and nothing paid).");
1433
+ }
1434
+ return 0;
1435
+ }
1436
+ if (!flags.json) {
1437
+ io2.out(
1438
+ "Everything up-to-date \u2014 refs unchanged, but the Rig page is stale (new Rig build, relay, or gateway):"
1439
+ );
1440
+ io2.out(` rig page ${pointerPlan.bytes} bytes ${pointerPlan.fee}`);
1441
+ io2.out(renderIdentityLine(identity));
1442
+ }
1443
+ if (!flags.yes) {
1444
+ if (flags.json) {
1445
+ io2.emitJson({
1446
+ command: "push",
1447
+ repoId,
1448
+ path,
1449
+ identity,
1450
+ executed: false,
1451
+ upToDate: true,
1452
+ plan,
1453
+ hint: "refs up-to-date; the Rig page is stale \u2014 re-run with --yes to refresh it (or --no-rig-page to skip)"
1454
+ });
1455
+ return 0;
1456
+ }
1457
+ if (!io2.isInteractive) {
1458
+ io2.err(
1459
+ "refusing to spend channel funds without confirmation in a non-interactive session \u2014 re-run with --yes (or --no-rig-page to skip the refresh)"
1460
+ );
1461
+ return 1;
1462
+ }
1463
+ const proceed = await io2.confirm(
1464
+ `Refresh the Rig page (total ${pointerPlan.fee} base units)? [y/N] `
1465
+ );
1466
+ if (!proceed) {
1467
+ io2.err("aborted \u2014 nothing was uploaded or published.");
1468
+ return 1;
1469
+ }
1470
+ }
1471
+ const rigPage2 = await publishPointer(pointerPlan);
1225
1472
  if (flags.json) {
1226
1473
  io2.emitJson({
1227
1474
  command: "push",
@@ -1230,15 +1477,23 @@ async function runPush(args, deps) {
1230
1477
  identity,
1231
1478
  executed: false,
1232
1479
  upToDate: true,
1233
- plan
1480
+ plan,
1481
+ rigPage: rigPage2
1234
1482
  });
1235
1483
  } else {
1236
- io2.out("Everything up-to-date \u2014 nothing to push (and nothing paid).");
1484
+ printRigPage(rigPage2);
1237
1485
  }
1238
1486
  return 0;
1239
1487
  }
1488
+ const confirmTotal = BigInt(plan.estimate.totalFee) + (pointerPlan?.fee ?? 0n);
1240
1489
  if (!flags.json) {
1241
1490
  for (const line of renderPlan(plan)) io2.out(line);
1491
+ if (pointerPlan?.action === "upload") {
1492
+ io2.out(
1493
+ ` rig page ${pointerPlan.bytes} bytes ${pointerPlan.fee} (repo page \u2014 paid once, reused until relay/rig-web changes)`
1494
+ );
1495
+ io2.out(` total with rig page ${confirmTotal}`);
1496
+ }
1242
1497
  io2.out(renderIdentityLine(identity));
1243
1498
  }
1244
1499
  if (!flags.yes) {
@@ -1262,7 +1517,7 @@ async function runPush(args, deps) {
1262
1517
  return 1;
1263
1518
  }
1264
1519
  const proceed = await io2.confirm(
1265
- `Proceed with paid push (total ${plan.estimate.totalFee} base units)? [y/N] `
1520
+ `Proceed with paid push (total ${confirmTotal} base units)? [y/N] `
1266
1521
  );
1267
1522
  if (!proceed) {
1268
1523
  io2.err("aborted \u2014 nothing was uploaded or published.");
@@ -1270,6 +1525,18 @@ async function runPush(args, deps) {
1270
1525
  }
1271
1526
  }
1272
1527
  const result = await execute();
1528
+ let rigPage;
1529
+ if (!pointerPlan) {
1530
+ rigPage = { status: "skipped", ...rigPageSkipDetail ? { detail: rigPageSkipDetail } : {} };
1531
+ } else if (pointerPlan.action === "unchanged") {
1532
+ rigPage = {
1533
+ status: "unchanged",
1534
+ txId: pointerPlan.recordedTxId,
1535
+ url: `${gateway}/${pointerPlan.recordedTxId}`
1536
+ };
1537
+ } else {
1538
+ rigPage = await publishPointer(pointerPlan);
1539
+ }
1273
1540
  if (flags.json) {
1274
1541
  io2.emitJson({
1275
1542
  command: "push",
@@ -1279,10 +1546,12 @@ async function runPush(args, deps) {
1279
1546
  executed: true,
1280
1547
  upToDate: false,
1281
1548
  plan,
1282
- result
1549
+ result,
1550
+ rigPage
1283
1551
  });
1284
1552
  } else {
1285
1553
  for (const line of renderResult(result)) io2.out(line);
1554
+ printRigPage(rigPage);
1286
1555
  }
1287
1556
  return 0;
1288
1557
  } catch (err) {
@@ -1896,7 +2165,7 @@ async function stopQuietly(ctx) {
1896
2165
 
1897
2166
  // src/cli/clone.ts
1898
2167
  import { mkdtemp, mkdir, readdir, rename, rm, rmdir } from "fs/promises";
1899
- import { basename, dirname, join, resolve } from "path";
2168
+ import { basename, dirname, join as join2, resolve } from "path";
1900
2169
  import { parseArgs as parseArgs5 } from "util";
1901
2170
  var CLONE_USAGE = `Usage: rig clone <relay-url> <owner>/<repo-id> [dir] [options]
1902
2171
 
@@ -2067,7 +2336,7 @@ async function runClone(args, deps) {
2067
2336
  }
2068
2337
  const parent = dirname(dest);
2069
2338
  await mkdir(parent, { recursive: true });
2070
- tempDir = await mkdtemp(join(parent, `.${basename(dest)}.rig-clone-`));
2339
+ tempDir = await mkdtemp(join2(parent, `.${basename(dest)}.rig-clone-`));
2071
2340
  await runGit(tempDir, [
2072
2341
  "init",
2073
2342
  "--quiet",
@@ -3533,9 +3802,9 @@ async function runFetch(args, deps) {
3533
3802
  }
3534
3803
 
3535
3804
  // src/cli/fund.ts
3536
- import { readFileSync } from "fs";
3537
- import { homedir } from "os";
3538
- import { join as join2 } from "path";
3805
+ import { readFileSync as readFileSync2 } from "fs";
3806
+ import { homedir as homedir2 } from "os";
3807
+ import { join as join3 } from "path";
3539
3808
  import { parseArgs as parseArgs9 } from "util";
3540
3809
  var DEVNET_FAUCET_URL = "https://faucet.devnet.toonprotocol.dev";
3541
3810
  var CHAINS = ["evm", "solana", "mina"];
@@ -3625,11 +3894,11 @@ function noFaucetGuidance(network, devnetOrigin) {
3625
3894
  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}`;
3626
3895
  }
3627
3896
  function readFundConfig(env) {
3628
- const dir = env["TOON_CLIENT_HOME"] ?? join2(homedir(), ".toon-client");
3629
- const configPath = join2(dir, "config.json");
3897
+ const dir = env["TOON_CLIENT_HOME"] ?? join3(homedir2(), ".toon-client");
3898
+ const configPath = join3(dir, "config.json");
3630
3899
  try {
3631
3900
  return {
3632
- file: JSON.parse(readFileSync(configPath, "utf8")),
3901
+ file: JSON.parse(readFileSync2(configPath, "utf8")),
3633
3902
  configPath
3634
3903
  };
3635
3904
  } catch (err) {
@@ -3862,7 +4131,7 @@ var runGitPassthrough = (argv2, options = {}) => {
3862
4131
  };
3863
4132
 
3864
4133
  // src/cli/identity-cmd.ts
3865
- import { existsSync, mkdirSync } from "fs";
4134
+ import { existsSync, mkdirSync as mkdirSync2 } from "fs";
3866
4135
  import { dirname as dirname2 } from "path";
3867
4136
  import { createInterface } from "readline/promises";
3868
4137
  import { parseArgs as parseArgs10 } from "util";
@@ -3914,7 +4183,7 @@ async function prepareKeystoreTarget(input) {
3914
4183
  const envPassword = input.env["TOON_CLIENT_KEYSTORE_PASSWORD"]?.trim() || void 0;
3915
4184
  const autoPassword = envPassword === void 0;
3916
4185
  const password = envPassword ?? DEFAULT_KEYSTORE_PASSWORD;
3917
- mkdirSync(dirname2(keystorePath), { recursive: true });
4186
+ mkdirSync2(dirname2(keystorePath), { recursive: true });
3918
4187
  return { keystorePath, password, autoPassword, existing, keyOps };
3919
4188
  }
3920
4189
  function readAccountIndex(env) {
@@ -5391,22 +5660,22 @@ function buildArweaveManifest(entries, indexPath = DEFAULT_INDEX, fallbackTxId)
5391
5660
  }
5392
5661
 
5393
5662
  // src/cli/site-record.ts
5394
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
5395
- import { homedir as homedir2 } from "os";
5396
- import { join as join3 } from "path";
5663
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
5664
+ import { homedir as homedir3 } from "os";
5665
+ import { join as join4 } from "path";
5397
5666
  var SITE_MANIFEST_FILENAME = "site-manifests.json";
5398
- function storeDir(env) {
5399
- return env["TOON_CLIENT_HOME"] ?? join3(homedir2(), ".toon-client");
5667
+ function storeDir2(env) {
5668
+ return env["TOON_CLIENT_HOME"] ?? join4(homedir3(), ".toon-client");
5400
5669
  }
5401
- function storePath(env) {
5402
- return join3(storeDir(env), SITE_MANIFEST_FILENAME);
5670
+ function storePath2(env) {
5671
+ return join4(storeDir2(env), SITE_MANIFEST_FILENAME);
5403
5672
  }
5404
5673
  function keyOf(repoId, ref) {
5405
5674
  return `${repoId}\0${ref}`;
5406
5675
  }
5407
5676
  function readFile2(env) {
5408
5677
  try {
5409
- const parsed = JSON.parse(readFileSync2(storePath(env), "utf8"));
5678
+ const parsed = JSON.parse(readFileSync3(storePath2(env), "utf8"));
5410
5679
  if (parsed && typeof parsed === "object") return parsed;
5411
5680
  return {};
5412
5681
  } catch {
@@ -5417,11 +5686,11 @@ function readSiteRecord(env, repoId, ref) {
5417
5686
  return readFile2(env)[keyOf(repoId, ref)];
5418
5687
  }
5419
5688
  function writeSiteRecord(env, record) {
5420
- const dir = storeDir(env);
5421
- mkdirSync2(dir, { recursive: true });
5689
+ const dir = storeDir2(env);
5690
+ mkdirSync3(dir, { recursive: true });
5422
5691
  const file = readFile2(env);
5423
5692
  file[keyOf(record.repoId, record.ref)] = record;
5424
- writeFileSync(storePath(env), `${JSON.stringify(file, null, 2)}
5693
+ writeFileSync2(storePath2(env), `${JSON.stringify(file, null, 2)}
5425
5694
  `, "utf8");
5426
5695
  }
5427
5696