@toon-protocol/rig 5.2.0 → 5.3.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/{chunk-S5R44MMB.js → chunk-DGF7WCRW.js} +18 -2
- package/dist/{chunk-S5R44MMB.js.map → chunk-DGF7WCRW.js.map} +1 -1
- package/dist/{chunk-Y7TUE7JT.js → chunk-KQ4NQV7T.js} +754 -305
- package/dist/chunk-KQ4NQV7T.js.map +1 -0
- package/dist/{chunk-JX5P2KAA.js → chunk-OVZJ5P6E.js} +11 -2
- package/dist/chunk-OVZJ5P6E.js.map +1 -0
- package/dist/{chunk-FX5GPZYU.js → chunk-UXRWMKXV.js} +0 -0
- package/dist/{ci-serve-CA37KQVC.js → ci-serve-R7ZQ7GJQ.js} +5 -5
- package/dist/cli/rig.js +4 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/{publisher-CQi69Nwg.d.ts → publisher-rblR_O9q.d.ts} +9 -1
- package/dist/standalone/index.d.ts +1 -1
- package/dist/{standalone-mode-NWCCRFCL.js → standalone-mode-E7TNMWGO.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-JX5P2KAA.js.map +0 -1
- package/dist/chunk-Y7TUE7JT.js.map +0 -1
- /package/dist/{chunk-FX5GPZYU.js.map → chunk-UXRWMKXV.js.map} +0 -0
- /package/dist/{ci-serve-CA37KQVC.js.map → ci-serve-R7ZQ7GJQ.js.map} +0 -0
- /package/dist/{standalone-mode-NWCCRFCL.js.map → standalone-mode-E7TNMWGO.js.map} +0 -0
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
InvalidRelayUrlError,
|
|
11
11
|
MultiUrlRemoteError,
|
|
12
12
|
NotAGitRepositoryError,
|
|
13
|
+
PrMergeError,
|
|
13
14
|
RESERVED_SECRET_NAMES,
|
|
14
15
|
SECRET_NAME_RE,
|
|
15
16
|
UnconfiguredRepoAddressError,
|
|
@@ -57,13 +58,13 @@ import {
|
|
|
57
58
|
updateRef,
|
|
58
59
|
writeGitObjects,
|
|
59
60
|
writeToonConfig
|
|
60
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-DGF7WCRW.js";
|
|
61
62
|
import {
|
|
62
63
|
PREFERRED_GATEWAY,
|
|
63
64
|
mirrorGatewaysFor,
|
|
64
65
|
readGateways,
|
|
65
66
|
shaResolverFor
|
|
66
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-UXRWMKXV.js";
|
|
67
68
|
import {
|
|
68
69
|
COMMENT_KIND,
|
|
69
70
|
DEFAULT_KEYSTORE_PASSWORD,
|
|
@@ -92,7 +93,7 @@ import {
|
|
|
92
93
|
resolveIdentity,
|
|
93
94
|
revisionRootId,
|
|
94
95
|
selectRevision
|
|
95
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-OVZJ5P6E.js";
|
|
96
97
|
import {
|
|
97
98
|
ChannelMapStore,
|
|
98
99
|
channelStatus,
|
|
@@ -321,7 +322,7 @@ function loadPaidSession(deps, relayUrl) {
|
|
|
321
322
|
});
|
|
322
323
|
}
|
|
323
324
|
var defaultLoadStandalone = async (options) => {
|
|
324
|
-
const mod = await import("./standalone-mode-
|
|
325
|
+
const mod = await import("./standalone-mode-E7TNMWGO.js");
|
|
325
326
|
return mod.createStandaloneContext(options);
|
|
326
327
|
};
|
|
327
328
|
function identityReport(ctx) {
|
|
@@ -2306,9 +2307,9 @@ async function runCiTrigger(args, deps) {
|
|
|
2306
2307
|
});
|
|
2307
2308
|
}
|
|
2308
2309
|
async function gitShowBytes(repoRoot, commit, path) {
|
|
2309
|
-
const { execFile } = await import("child_process");
|
|
2310
|
+
const { execFile: execFile2 } = await import("child_process");
|
|
2310
2311
|
return new Promise((resolve2, reject) => {
|
|
2311
|
-
|
|
2312
|
+
execFile2(
|
|
2312
2313
|
"git",
|
|
2313
2314
|
["show", `${commit}:${path}`],
|
|
2314
2315
|
{ cwd: repoRoot, encoding: "buffer", maxBuffer: 16 * 1024 * 1024 },
|
|
@@ -2519,7 +2520,7 @@ async function runCi(args, deps) {
|
|
|
2519
2520
|
case "status":
|
|
2520
2521
|
return runCiStatus(rest, deps);
|
|
2521
2522
|
case "serve":
|
|
2522
|
-
return (await import("./ci-serve-
|
|
2523
|
+
return (await import("./ci-serve-R7ZQ7GJQ.js")).runCiServe(rest, deps);
|
|
2523
2524
|
case "--help":
|
|
2524
2525
|
case "-h":
|
|
2525
2526
|
case "help":
|
|
@@ -2790,18 +2791,257 @@ async function runClone(args, deps) {
|
|
|
2790
2791
|
|
|
2791
2792
|
// src/cli/events.ts
|
|
2792
2793
|
import { readFile } from "fs/promises";
|
|
2793
|
-
import { parseArgs as
|
|
2794
|
+
import { parseArgs as parseArgs10 } from "util";
|
|
2794
2795
|
import {
|
|
2795
|
-
PATCH_KIND as
|
|
2796
|
-
REPOSITORY_ANNOUNCEMENT_KIND as
|
|
2797
|
-
STATUS_APPLIED_KIND as
|
|
2796
|
+
PATCH_KIND as PATCH_KIND3,
|
|
2797
|
+
REPOSITORY_ANNOUNCEMENT_KIND as REPOSITORY_ANNOUNCEMENT_KIND3,
|
|
2798
|
+
STATUS_APPLIED_KIND as STATUS_APPLIED_KIND3,
|
|
2798
2799
|
STATUS_CLOSED_KIND as STATUS_CLOSED_KIND2,
|
|
2799
2800
|
STATUS_DRAFT_KIND as STATUS_DRAFT_KIND2,
|
|
2800
2801
|
STATUS_OPEN_KIND as STATUS_OPEN_KIND2
|
|
2801
2802
|
} from "@toon-protocol/core/nip34";
|
|
2802
2803
|
|
|
2803
|
-
// src/cli/
|
|
2804
|
+
// src/cli/merge.ts
|
|
2805
|
+
import { execFile } from "child_process";
|
|
2806
|
+
import { mkdtemp as mkdtemp2, rm as rm2, writeFile } from "fs/promises";
|
|
2807
|
+
import { tmpdir } from "os";
|
|
2808
|
+
import { join as join4 } from "path";
|
|
2809
|
+
import { parseArgs as parseArgs9 } from "util";
|
|
2810
|
+
import { promisify } from "util";
|
|
2811
|
+
import {
|
|
2812
|
+
PATCH_KIND as PATCH_KIND2,
|
|
2813
|
+
REPOSITORY_ANNOUNCEMENT_KIND as REPOSITORY_ANNOUNCEMENT_KIND2,
|
|
2814
|
+
STATUS_APPLIED_KIND as STATUS_APPLIED_KIND2
|
|
2815
|
+
} from "@toon-protocol/core/nip34";
|
|
2816
|
+
|
|
2817
|
+
// src/cli/fetch.ts
|
|
2804
2818
|
import { parseArgs as parseArgs7 } from "util";
|
|
2819
|
+
var FETCH_USAGE = `Usage: rig fetch [remote] [options]
|
|
2820
|
+
|
|
2821
|
+
Fetch from a TOON remote \u2014 FREE (relay reads + Arweave gateway downloads; no
|
|
2822
|
+
payments, no identity needed). Reads the kind:30618 repository state from the
|
|
2823
|
+
remote's relay, downloads only the git objects this repository is missing
|
|
2824
|
+
(SHA-1 verified), and updates the remote-tracking refs
|
|
2825
|
+
(refs/remotes/<remote>/*; tags land at refs/tags/*), reporting what moved.
|
|
2826
|
+
|
|
2827
|
+
No merge happens: integrate with the git passthrough, e.g.
|
|
2828
|
+
\`rig merge origin/main\`. \`rig fetch\` is the TOON transport and shadows
|
|
2829
|
+
\`git fetch\` \u2014 plain-git fetches remain available via \`git fetch\` directly.
|
|
2830
|
+
|
|
2831
|
+
The repo address (toon.repoid/toon.owner) comes from the config \`rig init\`
|
|
2832
|
+
or \`rig clone\` writes; --repo-id/--owner override.
|
|
2833
|
+
|
|
2834
|
+
Options:
|
|
2835
|
+
--repo-id <id> repository id / NIP-34 d-tag (default: git config)
|
|
2836
|
+
--owner <pubkey> repository owner (npub or 64-char hex; default: git config)
|
|
2837
|
+
--relay <url> ad-hoc relay override \u2014 bypasses the remote's URL
|
|
2838
|
+
--gateway <url> gateway to read objects through FIRST, on its raw-bytes
|
|
2839
|
+
route <url>/raw/<txId>, ahead of the public gateway
|
|
2840
|
+
list \u2014 name a private, local or air-gapped gateway to
|
|
2841
|
+
fetch objects the public ones do not carry
|
|
2842
|
+
(env RIG_ARWEAVE_GATEWAY also sets it)
|
|
2843
|
+
--concurrency <n> parallel gateway downloads (default 8)
|
|
2844
|
+
--json machine-readable result envelope
|
|
2845
|
+
-h, --help show this help`;
|
|
2846
|
+
var WS_URL_RE3 = /^wss?:\/\//i;
|
|
2847
|
+
function localRefFor(refname, remote) {
|
|
2848
|
+
if (refname.startsWith("refs/heads/")) {
|
|
2849
|
+
return `refs/remotes/${remote}/${refname.slice("refs/heads/".length)}`;
|
|
2850
|
+
}
|
|
2851
|
+
if (refname.startsWith("refs/tags/")) return refname;
|
|
2852
|
+
return null;
|
|
2853
|
+
}
|
|
2854
|
+
async function resolveLocalRef(repoRoot, refname) {
|
|
2855
|
+
try {
|
|
2856
|
+
const out = await runGit(repoRoot, [
|
|
2857
|
+
"rev-parse",
|
|
2858
|
+
"--verify",
|
|
2859
|
+
"--quiet",
|
|
2860
|
+
refname
|
|
2861
|
+
]);
|
|
2862
|
+
const sha = out.trim();
|
|
2863
|
+
return /^[0-9a-f]{40}$/.test(sha) ? sha : null;
|
|
2864
|
+
} catch {
|
|
2865
|
+
return null;
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2868
|
+
async function runFetch(args, deps) {
|
|
2869
|
+
const { io } = deps;
|
|
2870
|
+
let json = false;
|
|
2871
|
+
let remote = "origin";
|
|
2872
|
+
let relayFlag;
|
|
2873
|
+
let repoIdFlag;
|
|
2874
|
+
let ownerFlag;
|
|
2875
|
+
let gatewayFlag;
|
|
2876
|
+
let concurrency;
|
|
2877
|
+
try {
|
|
2878
|
+
const { values, positionals } = parseArgs7({
|
|
2879
|
+
args,
|
|
2880
|
+
options: {
|
|
2881
|
+
json: { type: "boolean", default: false },
|
|
2882
|
+
relay: { type: "string" },
|
|
2883
|
+
"repo-id": { type: "string" },
|
|
2884
|
+
owner: { type: "string" },
|
|
2885
|
+
gateway: { type: "string" },
|
|
2886
|
+
concurrency: { type: "string" },
|
|
2887
|
+
help: { type: "boolean", short: "h", default: false }
|
|
2888
|
+
},
|
|
2889
|
+
allowPositionals: true
|
|
2890
|
+
});
|
|
2891
|
+
if (values.help) {
|
|
2892
|
+
io.out(FETCH_USAGE);
|
|
2893
|
+
return 0;
|
|
2894
|
+
}
|
|
2895
|
+
json = values.json === true;
|
|
2896
|
+
if (positionals.length > 1) {
|
|
2897
|
+
throw new Error(
|
|
2898
|
+
`expected at most one [remote] argument, got ${positionals.length}`
|
|
2899
|
+
);
|
|
2900
|
+
}
|
|
2901
|
+
if (positionals[0] !== void 0) remote = positionals[0];
|
|
2902
|
+
relayFlag = values.relay;
|
|
2903
|
+
repoIdFlag = values["repo-id"];
|
|
2904
|
+
ownerFlag = values.owner !== void 0 ? ownerToHex(values.owner) : void 0;
|
|
2905
|
+
gatewayFlag = values.gateway;
|
|
2906
|
+
if (values.concurrency !== void 0) {
|
|
2907
|
+
concurrency = Number.parseInt(values.concurrency, 10);
|
|
2908
|
+
if (!Number.isSafeInteger(concurrency) || concurrency < 1) {
|
|
2909
|
+
throw new Error("--concurrency must be a positive integer");
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
} catch (err) {
|
|
2913
|
+
io.err(err instanceof Error ? err.message : String(err));
|
|
2914
|
+
io.err(FETCH_USAGE);
|
|
2915
|
+
return 2;
|
|
2916
|
+
}
|
|
2917
|
+
try {
|
|
2918
|
+
const repoRoot = await resolveRepoRoot(deps.cwd);
|
|
2919
|
+
const toonConfig = await readToonConfig(repoRoot);
|
|
2920
|
+
const repoId = repoIdFlag ?? toonConfig.repoId;
|
|
2921
|
+
if (!repoId) throw new UnconfiguredRepoAddressError("repository id");
|
|
2922
|
+
const owner = ownerFlag ?? toonConfig.owner;
|
|
2923
|
+
if (!owner) throw new UnconfiguredRepoAddressError("repository owner");
|
|
2924
|
+
let relayUrl;
|
|
2925
|
+
if (relayFlag !== void 0) {
|
|
2926
|
+
relayUrl = relayFlag;
|
|
2927
|
+
} else {
|
|
2928
|
+
const urls = await getGitRemoteUrls(repoRoot, remote);
|
|
2929
|
+
if (urls.length === 0) throw new UnknownRemoteError(remote);
|
|
2930
|
+
if (urls.length > 1) throw new MultiUrlRemoteError(remote, urls);
|
|
2931
|
+
relayUrl = urls[0];
|
|
2932
|
+
}
|
|
2933
|
+
if (!WS_URL_RE3.test(relayUrl)) {
|
|
2934
|
+
throw new InvalidRelayUrlError(
|
|
2935
|
+
relayUrl,
|
|
2936
|
+
`remote ${JSON.stringify(remote)}`
|
|
2937
|
+
);
|
|
2938
|
+
}
|
|
2939
|
+
const remoteState = await fetchRemoteState({
|
|
2940
|
+
relayUrls: [relayUrl],
|
|
2941
|
+
ownerPubkey: owner,
|
|
2942
|
+
repoId,
|
|
2943
|
+
...deps.webSocketFactory ? { webSocketFactory: deps.webSocketFactory } : {},
|
|
2944
|
+
// The GraphQL fallback for SHAs the map does not cover asks the SAME
|
|
2945
|
+
// permaweb the objects are read from (#183).
|
|
2946
|
+
resolveSha: deps.resolveSha ?? shaResolverFor(gatewayFlag, deps.env)
|
|
2947
|
+
});
|
|
2948
|
+
const planned = [];
|
|
2949
|
+
for (const [refname, sha] of remoteState.refs) {
|
|
2950
|
+
if (!isSafeRefname(refname)) {
|
|
2951
|
+
io.err(
|
|
2952
|
+
`warning: skipping unsafe ref name from relay: ${JSON.stringify(refname)}`
|
|
2953
|
+
);
|
|
2954
|
+
continue;
|
|
2955
|
+
}
|
|
2956
|
+
const localRef = localRefFor(refname, remote);
|
|
2957
|
+
if (localRef === null) {
|
|
2958
|
+
io.err(
|
|
2959
|
+
`warning: skipping ref outside refs/heads and refs/tags: ${refname}`
|
|
2960
|
+
);
|
|
2961
|
+
continue;
|
|
2962
|
+
}
|
|
2963
|
+
planned.push({ refname, localRef, newSha: sha });
|
|
2964
|
+
}
|
|
2965
|
+
const reader = new GitRepoReader(repoRoot);
|
|
2966
|
+
const tips = [...new Set(planned.map((p) => p.newSha))];
|
|
2967
|
+
const presentLocally = new Set(await reader.listAllObjectShas());
|
|
2968
|
+
const collected = await collectRepoObjects({
|
|
2969
|
+
tips,
|
|
2970
|
+
shaToTxId: remoteState.shaToTxId,
|
|
2971
|
+
resolveMissing: (shas) => remoteState.resolveMissing(shas),
|
|
2972
|
+
presentLocally,
|
|
2973
|
+
// `--gateway` / RIG_ARWEAVE_GATEWAY first, public list behind it (#176).
|
|
2974
|
+
gateways: readGateways(gatewayFlag, deps.env),
|
|
2975
|
+
...deps.fetchFn ? { fetchFn: deps.fetchFn } : {},
|
|
2976
|
+
...concurrency !== void 0 ? { concurrency } : {}
|
|
2977
|
+
});
|
|
2978
|
+
if (collected.missing.length > 0) {
|
|
2979
|
+
throw new MissingRemoteObjectsError(
|
|
2980
|
+
collected.missing,
|
|
2981
|
+
`cannot fetch from ${relayUrl}`
|
|
2982
|
+
);
|
|
2983
|
+
}
|
|
2984
|
+
const written = await writeGitObjects(repoRoot, collected.objects.values());
|
|
2985
|
+
const updates = [];
|
|
2986
|
+
for (const { refname, localRef, newSha } of planned) {
|
|
2987
|
+
const oldSha = await resolveLocalRef(repoRoot, localRef);
|
|
2988
|
+
if (oldSha === newSha) {
|
|
2989
|
+
updates.push({ refname, localRef, oldSha, newSha, kind: "up-to-date" });
|
|
2990
|
+
continue;
|
|
2991
|
+
}
|
|
2992
|
+
let kind;
|
|
2993
|
+
if (oldSha === null) {
|
|
2994
|
+
kind = "new";
|
|
2995
|
+
} else {
|
|
2996
|
+
kind = await reader.isAncestor(oldSha, newSha) ? "fast-forward" : "forced";
|
|
2997
|
+
}
|
|
2998
|
+
await updateRef(repoRoot, localRef, newSha);
|
|
2999
|
+
updates.push({ refname, localRef, oldSha, newSha, kind });
|
|
3000
|
+
}
|
|
3001
|
+
const moved = updates.filter((u) => u.kind !== "up-to-date");
|
|
3002
|
+
if (json) {
|
|
3003
|
+
io.emitJson({
|
|
3004
|
+
command: "fetch",
|
|
3005
|
+
repoAddr: { ownerPubkey: owner, repoId },
|
|
3006
|
+
remote,
|
|
3007
|
+
relay: relayUrl,
|
|
3008
|
+
objectsDownloaded: written,
|
|
3009
|
+
updates,
|
|
3010
|
+
executed: true
|
|
3011
|
+
});
|
|
3012
|
+
return 0;
|
|
3013
|
+
}
|
|
3014
|
+
if (moved.length === 0) {
|
|
3015
|
+
io.out("Already up to date.");
|
|
3016
|
+
return 0;
|
|
3017
|
+
}
|
|
3018
|
+
io.out(`From ${relayUrl}`);
|
|
3019
|
+
for (const u of moved) {
|
|
3020
|
+
const short = (refname) => refname.replace(/^refs\/heads\//, "").replace(/^refs\/tags\//, "").replace(/^refs\/remotes\//, "");
|
|
3021
|
+
const src = short(u.refname);
|
|
3022
|
+
const dst = short(u.localRef);
|
|
3023
|
+
if (u.kind === "new") {
|
|
3024
|
+
const label = u.refname.startsWith("refs/tags/") ? "[new tag]" : "[new branch]";
|
|
3025
|
+
io.out(` * ${label.padEnd(17)} ${src.padEnd(14)} -> ${dst}`);
|
|
3026
|
+
} else if (u.kind === "forced") {
|
|
3027
|
+
io.out(
|
|
3028
|
+
` + ${u.oldSha.slice(0, 7)}...${u.newSha.slice(0, 7)} ${src.padEnd(14)} -> ${dst} (forced update)`
|
|
3029
|
+
);
|
|
3030
|
+
} else {
|
|
3031
|
+
io.out(
|
|
3032
|
+
` ${u.oldSha.slice(0, 7)}..${u.newSha.slice(0, 7)} ${src.padEnd(14)} -> ${dst}`
|
|
3033
|
+
);
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
io.out(`Downloaded ${written} object(s) (SHA-1 verified).`);
|
|
3037
|
+
return 0;
|
|
3038
|
+
} catch (err) {
|
|
3039
|
+
return emitCliError(io, json, "fetch", err);
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
3042
|
+
|
|
3043
|
+
// src/cli/tracker.ts
|
|
3044
|
+
import { parseArgs as parseArgs8 } from "util";
|
|
2805
3045
|
import {
|
|
2806
3046
|
ISSUE_KIND,
|
|
2807
3047
|
PATCH_KIND,
|
|
@@ -2887,7 +3127,7 @@ function withTargetAuthor(authorized, targetAuthorPubkey) {
|
|
|
2887
3127
|
}
|
|
2888
3128
|
var RELAY_TIMEOUT_MS = 1e4;
|
|
2889
3129
|
var HEX64_RE2 = /^[0-9a-f]{64}$/;
|
|
2890
|
-
var
|
|
3130
|
+
var WS_URL_RE4 = /^wss?:\/\//i;
|
|
2891
3131
|
function defaultWebSocketFactory2(url) {
|
|
2892
3132
|
const ctor = globalThis.WebSocket;
|
|
2893
3133
|
if (!ctor) {
|
|
@@ -2971,7 +3211,7 @@ async function resolveTrackerContext(flags, deps, needRepoAddr) {
|
|
|
2971
3211
|
repoRoot,
|
|
2972
3212
|
toonRelays: toonConfig.relays
|
|
2973
3213
|
});
|
|
2974
|
-
const wsRelays = resolved.relays.filter((url) =>
|
|
3214
|
+
const wsRelays = resolved.relays.filter((url) => WS_URL_RE4.test(url));
|
|
2975
3215
|
if (wsRelays.length === 0) {
|
|
2976
3216
|
throw new InvalidRelayUrlError(
|
|
2977
3217
|
resolved.relays[0] ?? "",
|
|
@@ -3198,7 +3438,7 @@ async function runList(args, deps, spec) {
|
|
|
3198
3438
|
const { io } = deps;
|
|
3199
3439
|
let flags;
|
|
3200
3440
|
try {
|
|
3201
|
-
const { values, positionals } =
|
|
3441
|
+
const { values, positionals } = parseArgs8({
|
|
3202
3442
|
args,
|
|
3203
3443
|
options: TRACKER_OPTIONS,
|
|
3204
3444
|
allowPositionals: true
|
|
@@ -3263,7 +3503,7 @@ async function runShow(args, deps, spec) {
|
|
|
3263
3503
|
let flags;
|
|
3264
3504
|
let eventId;
|
|
3265
3505
|
try {
|
|
3266
|
-
const { values, positionals } =
|
|
3506
|
+
const { values, positionals } = parseArgs8({
|
|
3267
3507
|
args,
|
|
3268
3508
|
options: TRACKER_OPTIONS,
|
|
3269
3509
|
allowPositionals: true
|
|
@@ -3391,6 +3631,435 @@ function runPrShow(args, deps) {
|
|
|
3391
3631
|
});
|
|
3392
3632
|
}
|
|
3393
3633
|
|
|
3634
|
+
// src/cli/merge.ts
|
|
3635
|
+
var execFileAsync = promisify(execFile);
|
|
3636
|
+
var HEX64_RE3 = /^[0-9a-f]{64}$/;
|
|
3637
|
+
var PR_MERGE_USAGE = `Usage: rig pr merge <patch-id> [--target <branch>] [options]
|
|
3638
|
+
|
|
3639
|
+
Apply the latest authorized revision of a patch with \`git am\` onto the
|
|
3640
|
+
honored tip of the target branch, push the result, and publish an applied
|
|
3641
|
+
status (kind:1631) naming the new commit SHAs \u2014 in that order, so the status
|
|
3642
|
+
never claims a merge that did not happen. A paid command; writes are permanent
|
|
3643
|
+
and non-refundable. Only the owner or a declared maintainer may merge.
|
|
3644
|
+
|
|
3645
|
+
If the patch does not apply, nothing is spent and your working tree is left as
|
|
3646
|
+
it was. If the push succeeds but the status publish fails, the merge is
|
|
3647
|
+
reported as a partial success; retry with \`rig pr status <patch-id> applied\`.
|
|
3648
|
+
|
|
3649
|
+
Options:
|
|
3650
|
+
--target <branch> branch to merge onto (default: the patch's branch-name
|
|
3651
|
+
tag, else the repo's default branch)
|
|
3652
|
+
--yes skip the confirmation prompt
|
|
3653
|
+
--json machine-readable output (without --yes: estimate only)
|
|
3654
|
+
--relay <url> ad-hoc relay override (bypasses git remotes)
|
|
3655
|
+
--remote <name> git remote to use (default: origin)
|
|
3656
|
+
--repo-id <id> repository id (default: git config toon.repoid)
|
|
3657
|
+
--owner <pubkey> repository owner (default: git config toon.owner)`;
|
|
3658
|
+
function parseMergeArgs(args) {
|
|
3659
|
+
const { values, positionals } = parseArgs9({
|
|
3660
|
+
args,
|
|
3661
|
+
options: {
|
|
3662
|
+
target: { type: "string" },
|
|
3663
|
+
yes: { type: "boolean", default: false },
|
|
3664
|
+
json: { type: "boolean", default: false },
|
|
3665
|
+
relay: { type: "string", multiple: true },
|
|
3666
|
+
remote: { type: "string" },
|
|
3667
|
+
"repo-id": { type: "string" },
|
|
3668
|
+
owner: { type: "string" },
|
|
3669
|
+
standalone: { type: "boolean", default: false },
|
|
3670
|
+
"no-daemon": { type: "boolean", default: false },
|
|
3671
|
+
help: { type: "boolean", short: "h", default: false }
|
|
3672
|
+
},
|
|
3673
|
+
allowPositionals: true
|
|
3674
|
+
});
|
|
3675
|
+
if (values.help) return "help";
|
|
3676
|
+
if (positionals.length !== 1) {
|
|
3677
|
+
throw new Error("expected exactly one argument: <patch-id>");
|
|
3678
|
+
}
|
|
3679
|
+
const patchId = positionals[0];
|
|
3680
|
+
if (!HEX64_RE3.test(patchId)) {
|
|
3681
|
+
throw new Error("<patch-id> must be a 64-character lowercase hex event id");
|
|
3682
|
+
}
|
|
3683
|
+
if (values.owner !== void 0 && !HEX64_RE3.test(values.owner)) {
|
|
3684
|
+
throw new Error("--owner must be a 64-character lowercase hex pubkey");
|
|
3685
|
+
}
|
|
3686
|
+
const flags = {
|
|
3687
|
+
patchId,
|
|
3688
|
+
yes: values.yes === true,
|
|
3689
|
+
json: values.json === true,
|
|
3690
|
+
relay: values.relay ?? []
|
|
3691
|
+
};
|
|
3692
|
+
if (values.target !== void 0) flags.target = values.target;
|
|
3693
|
+
if (values.remote !== void 0) flags.remote = values.remote;
|
|
3694
|
+
if (values["repo-id"] !== void 0) flags.repoId = values["repo-id"];
|
|
3695
|
+
if (values.owner !== void 0) flags.owner = values.owner;
|
|
3696
|
+
return flags;
|
|
3697
|
+
}
|
|
3698
|
+
async function git(cwd, args, env) {
|
|
3699
|
+
const { stdout } = await execFileAsync("git", args, {
|
|
3700
|
+
cwd,
|
|
3701
|
+
encoding: "utf-8",
|
|
3702
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
3703
|
+
...env ? { env } : {}
|
|
3704
|
+
});
|
|
3705
|
+
return stdout.trim();
|
|
3706
|
+
}
|
|
3707
|
+
async function gitOk(cwd, args) {
|
|
3708
|
+
try {
|
|
3709
|
+
await git(cwd, args);
|
|
3710
|
+
return true;
|
|
3711
|
+
} catch {
|
|
3712
|
+
return false;
|
|
3713
|
+
}
|
|
3714
|
+
}
|
|
3715
|
+
function gitFailure(err) {
|
|
3716
|
+
const e = err;
|
|
3717
|
+
return (e.stderr || e.stdout || e.message || String(err)).trim();
|
|
3718
|
+
}
|
|
3719
|
+
var OverlayReader = class extends GitRepoReader {
|
|
3720
|
+
constructor(repoPath, overlay) {
|
|
3721
|
+
super(repoPath);
|
|
3722
|
+
this.overlay = overlay;
|
|
3723
|
+
}
|
|
3724
|
+
overlay;
|
|
3725
|
+
async listRefs() {
|
|
3726
|
+
const base = await super.listRefs();
|
|
3727
|
+
const refs = base.refs.filter(
|
|
3728
|
+
(r) => r.refname !== this.overlay.refname
|
|
3729
|
+
);
|
|
3730
|
+
refs.push({
|
|
3731
|
+
refname: this.overlay.refname,
|
|
3732
|
+
sha: this.overlay.sha,
|
|
3733
|
+
type: "commit"
|
|
3734
|
+
});
|
|
3735
|
+
return { ...base, refs };
|
|
3736
|
+
}
|
|
3737
|
+
};
|
|
3738
|
+
async function applyInIsolation(repoRoot, tip, patchText, committer) {
|
|
3739
|
+
const scratch = await mkdtemp2(join4(tmpdir(), "rig-merge-"));
|
|
3740
|
+
const worktree = join4(scratch, "wt");
|
|
3741
|
+
try {
|
|
3742
|
+
await git(repoRoot, ["worktree", "add", "--detach", worktree, tip]);
|
|
3743
|
+
const patchFile = join4(scratch, "patch.mbox");
|
|
3744
|
+
await writeFile(patchFile, patchText, "utf-8");
|
|
3745
|
+
const env = { ...process.env };
|
|
3746
|
+
if (committer) {
|
|
3747
|
+
env["GIT_COMMITTER_NAME"] = committer.name;
|
|
3748
|
+
env["GIT_COMMITTER_EMAIL"] = committer.email;
|
|
3749
|
+
}
|
|
3750
|
+
try {
|
|
3751
|
+
await git(worktree, ["am", "--quiet", patchFile], env);
|
|
3752
|
+
} catch (err) {
|
|
3753
|
+
await git(worktree, ["am", "--abort"]).catch(() => void 0);
|
|
3754
|
+
throw new PrMergeError(
|
|
3755
|
+
"apply_conflict",
|
|
3756
|
+
`the patch does not apply cleanly onto ${tip.slice(0, 7)} \u2014 ask the contributor for a revision (\`rig pr create --revises\`). Nothing was pushed, published, or paid, and your working tree is unchanged.
|
|
3757
|
+
` + gitFailure(err)
|
|
3758
|
+
);
|
|
3759
|
+
}
|
|
3760
|
+
const newHead = await git(worktree, ["rev-parse", "HEAD"]);
|
|
3761
|
+
const listed = await git(worktree, [
|
|
3762
|
+
"rev-list",
|
|
3763
|
+
"--reverse",
|
|
3764
|
+
`${tip}..${newHead}`
|
|
3765
|
+
]);
|
|
3766
|
+
const commits = listed === "" ? [] : listed.split("\n");
|
|
3767
|
+
if (commits.length === 0) {
|
|
3768
|
+
throw new PrMergeError(
|
|
3769
|
+
"nothing_to_apply",
|
|
3770
|
+
"the patch applied no commits (already merged?) \u2014 nothing was pushed, published, or paid."
|
|
3771
|
+
);
|
|
3772
|
+
}
|
|
3773
|
+
return { newHead, commits };
|
|
3774
|
+
} finally {
|
|
3775
|
+
await git(repoRoot, ["worktree", "remove", "--force", worktree]).catch(
|
|
3776
|
+
() => void 0
|
|
3777
|
+
);
|
|
3778
|
+
await git(repoRoot, ["worktree", "prune"]).catch(() => void 0);
|
|
3779
|
+
await rm2(scratch, { recursive: true, force: true });
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
var BRANCH_PREFIX = "refs/heads/";
|
|
3783
|
+
async function runPrMerge(args, deps) {
|
|
3784
|
+
const { io } = deps;
|
|
3785
|
+
let flags;
|
|
3786
|
+
try {
|
|
3787
|
+
const parsed = parseMergeArgs(args);
|
|
3788
|
+
if (parsed === "help") {
|
|
3789
|
+
io.out(PR_MERGE_USAGE);
|
|
3790
|
+
return 0;
|
|
3791
|
+
}
|
|
3792
|
+
flags = parsed;
|
|
3793
|
+
} catch (err) {
|
|
3794
|
+
io.err(err instanceof Error ? err.message : String(err));
|
|
3795
|
+
io.err(PR_MERGE_USAGE);
|
|
3796
|
+
return 2;
|
|
3797
|
+
}
|
|
3798
|
+
deps = withForcedStandalone(deps);
|
|
3799
|
+
const webSocketFactory = deps.webSocketFactory ?? defaultWebSocketFactory;
|
|
3800
|
+
let stop;
|
|
3801
|
+
try {
|
|
3802
|
+
const repoRoot = await resolveRepoRoot(deps.cwd);
|
|
3803
|
+
const toonConfig = await readToonConfig(repoRoot);
|
|
3804
|
+
const repoId = flags.repoId ?? toonConfig.repoId;
|
|
3805
|
+
if (!repoId) throw new UnconfiguredRepoAddressError("repository id");
|
|
3806
|
+
const resolved = await resolveRelays({
|
|
3807
|
+
relayFlags: flags.relay,
|
|
3808
|
+
remoteName: flags.remote,
|
|
3809
|
+
repoRoot,
|
|
3810
|
+
toonRelays: toonConfig.relays
|
|
3811
|
+
});
|
|
3812
|
+
if (resolved.nudge !== void 0) io.err(resolved.nudge);
|
|
3813
|
+
const relays = resolved.relays;
|
|
3814
|
+
if (relays.length > 1) {
|
|
3815
|
+
io.err(singleRelayRefusal(resolved, "Nothing was pushed or paid."));
|
|
3816
|
+
return 1;
|
|
3817
|
+
}
|
|
3818
|
+
const relay = relays[0];
|
|
3819
|
+
const session = await loadPaidSession(deps, relay);
|
|
3820
|
+
if (session.path !== "standalone") {
|
|
3821
|
+
throw new Error("internal: rig pr merge requires the standalone session");
|
|
3822
|
+
}
|
|
3823
|
+
const ctx = session.ctx;
|
|
3824
|
+
stop = () => ctx.stop();
|
|
3825
|
+
const identity = identityReport(ctx);
|
|
3826
|
+
const owner = flags.owner ?? toonConfig.owner ?? identity.pubkey;
|
|
3827
|
+
const addr = { ownerPubkey: owner, repoId };
|
|
3828
|
+
const aTag = `${REPOSITORY_ANNOUNCEMENT_KIND2}:${owner}:${repoId}`;
|
|
3829
|
+
const lookup = async (id) => (await queryAll(relays, [{ ids: [id] }], webSocketFactory)).get(id);
|
|
3830
|
+
let root = await lookup(flags.patchId);
|
|
3831
|
+
if (root && root.kind === PATCH_KIND2 && isPatchRevision(root)) {
|
|
3832
|
+
const rootId = revisionRootId(root);
|
|
3833
|
+
if (rootId !== void 0) root = await lookup(rootId);
|
|
3834
|
+
}
|
|
3835
|
+
if (!root || root.kind !== PATCH_KIND2) {
|
|
3836
|
+
throw new PrMergeError(
|
|
3837
|
+
"patch_not_found",
|
|
3838
|
+
`patch ${flags.patchId} not found as a kind:1617 patch on ${relay} \u2014 nothing was pushed or paid`
|
|
3839
|
+
);
|
|
3840
|
+
}
|
|
3841
|
+
if (!root.tags.some((t) => t[0] === "a" && t[1] === aTag)) {
|
|
3842
|
+
throw new PrMergeError(
|
|
3843
|
+
"patch_not_found",
|
|
3844
|
+
`patch ${root.id} does not belong to ${aTag} \u2014 nothing was pushed or paid`
|
|
3845
|
+
);
|
|
3846
|
+
}
|
|
3847
|
+
const remote = await ctx.fetchRemote({
|
|
3848
|
+
ownerPubkey: owner,
|
|
3849
|
+
repoId,
|
|
3850
|
+
relayUrls: relays
|
|
3851
|
+
});
|
|
3852
|
+
const authorized = authorizedAuthors(
|
|
3853
|
+
owner,
|
|
3854
|
+
remote.announceEvent?.tags ?? []
|
|
3855
|
+
);
|
|
3856
|
+
const revisionEvents = await queryAll(
|
|
3857
|
+
relays,
|
|
3858
|
+
[{ kinds: [PATCH_KIND2], "#e": [root.id] }],
|
|
3859
|
+
webSocketFactory
|
|
3860
|
+
);
|
|
3861
|
+
const { latest } = selectRevision(
|
|
3862
|
+
root,
|
|
3863
|
+
[...revisionEvents.values()].filter((e) => e.kind === PATCH_KIND2),
|
|
3864
|
+
authorized
|
|
3865
|
+
);
|
|
3866
|
+
if (!authorized.has(identity.pubkey.toLowerCase())) {
|
|
3867
|
+
throw new PrMergeError(
|
|
3868
|
+
"not_authorized",
|
|
3869
|
+
`only the owner or a declared maintainer can merge \u2014 ${identity.pubkey.slice(0, 8)}\u2026 is neither for ${aTag}. Readers would ignore the pushed state. Nothing was pushed or paid.`
|
|
3870
|
+
);
|
|
3871
|
+
}
|
|
3872
|
+
if (!remote.announced) {
|
|
3873
|
+
throw new PrMergeError(
|
|
3874
|
+
"target_not_found",
|
|
3875
|
+
`${aTag} is not announced on ${relay} \u2014 nothing to merge onto`
|
|
3876
|
+
);
|
|
3877
|
+
}
|
|
3878
|
+
const branch = (flags.target ?? firstTagValue(latest.tags, "branch-name") ?? remote.headSymref ?? "main").replace(/^refs\/heads\//, "");
|
|
3879
|
+
const refname = `${BRANCH_PREFIX}${branch}`;
|
|
3880
|
+
const tip = remote.refs.get(refname);
|
|
3881
|
+
if (tip === void 0) {
|
|
3882
|
+
throw new PrMergeError(
|
|
3883
|
+
"target_not_found",
|
|
3884
|
+
`branch ${JSON.stringify(branch)} is not in the honored repo state (${[...remote.refs.keys()].join(", ") || "no refs"}) \u2014 pass --target. Nothing was pushed or paid.`
|
|
3885
|
+
);
|
|
3886
|
+
}
|
|
3887
|
+
if (!await gitOk(repoRoot, ["cat-file", "-e", `${tip}^{commit}`])) {
|
|
3888
|
+
await runFetch(
|
|
3889
|
+
["--relay", relay, "--owner", owner, "--repo-id", repoId],
|
|
3890
|
+
{ ...deps, io: { ...io, out: () => void 0 } }
|
|
3891
|
+
);
|
|
3892
|
+
if (!await gitOk(repoRoot, ["cat-file", "-e", `${tip}^{commit}`])) {
|
|
3893
|
+
throw new PrMergeError(
|
|
3894
|
+
"tip_unavailable",
|
|
3895
|
+
`the honored tip ${tip.slice(0, 7)} of ${branch} could not be fetched \u2014 run \`rig fetch\` and retry. Nothing was pushed or paid.`
|
|
3896
|
+
);
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
const reader = new GitRepoReader(repoRoot);
|
|
3900
|
+
const localRefs = (await reader.listRefs()).refs;
|
|
3901
|
+
const localSha = localRefs.find((r) => r.refname === refname)?.sha;
|
|
3902
|
+
if (localSha !== void 0 && localSha !== tip && !await reader.isAncestor(localSha, tip)) {
|
|
3903
|
+
throw new PrMergeError(
|
|
3904
|
+
"local_branch_diverged",
|
|
3905
|
+
`local ${branch} (${localSha.slice(0, 7)}) is not behind the honored tip (${tip.slice(0, 7)}) \u2014 push or reset it first. Nothing was pushed or paid.`
|
|
3906
|
+
);
|
|
3907
|
+
}
|
|
3908
|
+
const hasCommitter = await gitOk(repoRoot, ["config", "user.email"]);
|
|
3909
|
+
const applied = await applyInIsolation(
|
|
3910
|
+
repoRoot,
|
|
3911
|
+
tip,
|
|
3912
|
+
latest.content,
|
|
3913
|
+
hasCommitter ? void 0 : {
|
|
3914
|
+
name: hexToNpub(identity.pubkey),
|
|
3915
|
+
email: `${hexToNpub(identity.pubkey)}@nostr`
|
|
3916
|
+
}
|
|
3917
|
+
);
|
|
3918
|
+
const overlay = new OverlayReader(repoRoot, {
|
|
3919
|
+
refname,
|
|
3920
|
+
sha: applied.newHead
|
|
3921
|
+
});
|
|
3922
|
+
const feeRates = await ctx.publisher.getFeeRates();
|
|
3923
|
+
const pushPlan = await planPush({
|
|
3924
|
+
repoReader: overlay,
|
|
3925
|
+
remoteState: remote,
|
|
3926
|
+
feeRates,
|
|
3927
|
+
repoId,
|
|
3928
|
+
refs: [refname],
|
|
3929
|
+
force: false
|
|
3930
|
+
});
|
|
3931
|
+
const plan = serializePushPlan(pushPlan);
|
|
3932
|
+
const total = BigInt(plan.estimate.totalFee) + feeRates.eventFee;
|
|
3933
|
+
if (!flags.json) {
|
|
3934
|
+
for (const line of renderPlan(plan)) io.out(line);
|
|
3935
|
+
io.out(
|
|
3936
|
+
` status kind:1631 applied (${applied.commits.length} commit${applied.commits.length === 1 ? "" : "s"}) ${feeRates.eventFee}`
|
|
3937
|
+
);
|
|
3938
|
+
io.out(` total with status ${total}`);
|
|
3939
|
+
io.out(renderIdentityLine(identity));
|
|
3940
|
+
}
|
|
3941
|
+
if (!flags.yes) {
|
|
3942
|
+
if (flags.json) {
|
|
3943
|
+
io.emitJson({
|
|
3944
|
+
command: "pr merge",
|
|
3945
|
+
repoAddr: addr,
|
|
3946
|
+
identity,
|
|
3947
|
+
executed: false,
|
|
3948
|
+
patchId: root.id,
|
|
3949
|
+
revisionId: latest.id,
|
|
3950
|
+
target: refname,
|
|
3951
|
+
mergedShas: applied.commits,
|
|
3952
|
+
plan,
|
|
3953
|
+
totalFee: total.toString(),
|
|
3954
|
+
hint: "estimate only \u2014 re-run with --yes to push and publish (permanent, non-refundable)"
|
|
3955
|
+
});
|
|
3956
|
+
return 0;
|
|
3957
|
+
}
|
|
3958
|
+
if (!io.isInteractive) {
|
|
3959
|
+
io.err(
|
|
3960
|
+
"refusing to spend channel funds without confirmation in a non-interactive session \u2014 re-run with --yes (or use --json for an estimate)"
|
|
3961
|
+
);
|
|
3962
|
+
return 1;
|
|
3963
|
+
}
|
|
3964
|
+
const proceed = await io.confirm(
|
|
3965
|
+
`Proceed with paid merge (total ${total} base units)? [y/N] `
|
|
3966
|
+
);
|
|
3967
|
+
if (!proceed) {
|
|
3968
|
+
io.err("aborted \u2014 nothing was pushed or published.");
|
|
3969
|
+
return 1;
|
|
3970
|
+
}
|
|
3971
|
+
}
|
|
3972
|
+
const pushResult = await executePush({
|
|
3973
|
+
plan: pushPlan,
|
|
3974
|
+
publisher: ctx.publisher,
|
|
3975
|
+
remoteState: remote,
|
|
3976
|
+
repoReader: overlay,
|
|
3977
|
+
relayUrls: relays
|
|
3978
|
+
});
|
|
3979
|
+
const result = serializePushResult(pushPlan, pushResult);
|
|
3980
|
+
const localNote = await advanceLocalBranch(
|
|
3981
|
+
repoRoot,
|
|
3982
|
+
reader,
|
|
3983
|
+
refname,
|
|
3984
|
+
applied.newHead,
|
|
3985
|
+
localSha
|
|
3986
|
+
);
|
|
3987
|
+
if (localNote !== void 0) io.err(localNote);
|
|
3988
|
+
let statusEventId;
|
|
3989
|
+
let statusError;
|
|
3990
|
+
try {
|
|
3991
|
+
const receipt = await ctx.publisher.publishEvent(
|
|
3992
|
+
buildStatus(owner, repoId, root.id, STATUS_APPLIED_KIND2, root.pubkey, {
|
|
3993
|
+
commits: applied.commits,
|
|
3994
|
+
revisionEventId: latest.id
|
|
3995
|
+
}),
|
|
3996
|
+
relays
|
|
3997
|
+
);
|
|
3998
|
+
statusEventId = receipt.eventId;
|
|
3999
|
+
} catch (err) {
|
|
4000
|
+
statusError = err instanceof Error ? err.message : String(err);
|
|
4001
|
+
}
|
|
4002
|
+
const retryHint = `rig pr status ${root.id} applied`;
|
|
4003
|
+
if (flags.json) {
|
|
4004
|
+
io.emitJson({
|
|
4005
|
+
command: "pr merge",
|
|
4006
|
+
repoAddr: addr,
|
|
4007
|
+
identity,
|
|
4008
|
+
executed: true,
|
|
4009
|
+
patchId: root.id,
|
|
4010
|
+
revisionId: latest.id,
|
|
4011
|
+
target: refname,
|
|
4012
|
+
mergedShas: applied.commits,
|
|
4013
|
+
result,
|
|
4014
|
+
...statusEventId !== void 0 ? { statusEventId } : {},
|
|
4015
|
+
...statusError !== void 0 ? {
|
|
4016
|
+
partial: true,
|
|
4017
|
+
error: "status_publish_failed",
|
|
4018
|
+
detail: statusError,
|
|
4019
|
+
hint: `the push succeeded but the applied status was not published \u2014 retry with \`${retryHint}\``
|
|
4020
|
+
} : {}
|
|
4021
|
+
});
|
|
4022
|
+
} else {
|
|
4023
|
+
for (const line of renderResult(result)) io.out(line);
|
|
4024
|
+
if (statusEventId !== void 0) {
|
|
4025
|
+
io.out(
|
|
4026
|
+
`Merged ${applied.commits.length} commit(s) onto ${branch}; applied status ${statusEventId}`
|
|
4027
|
+
);
|
|
4028
|
+
}
|
|
4029
|
+
}
|
|
4030
|
+
if (statusError !== void 0) {
|
|
4031
|
+
io.err(
|
|
4032
|
+
`partial success: the push succeeded but publishing the applied status failed: ${statusError}`
|
|
4033
|
+
);
|
|
4034
|
+
io.err(`retry the status with: ${retryHint}`);
|
|
4035
|
+
return 1;
|
|
4036
|
+
}
|
|
4037
|
+
return 0;
|
|
4038
|
+
} catch (err) {
|
|
4039
|
+
return emitCliError(io, flags.json, "pr merge", err);
|
|
4040
|
+
} finally {
|
|
4041
|
+
if (stop) await stop().catch(() => void 0);
|
|
4042
|
+
}
|
|
4043
|
+
}
|
|
4044
|
+
async function advanceLocalBranch(repoRoot, reader, refname, newHead, oldSha) {
|
|
4045
|
+
try {
|
|
4046
|
+
const { head } = await reader.listRefs();
|
|
4047
|
+
if (head === refname) {
|
|
4048
|
+
await git(repoRoot, ["merge", "--ff-only", newHead]);
|
|
4049
|
+
} else {
|
|
4050
|
+
await git(repoRoot, [
|
|
4051
|
+
"update-ref",
|
|
4052
|
+
refname,
|
|
4053
|
+
newHead,
|
|
4054
|
+
oldSha ?? "0".repeat(40)
|
|
4055
|
+
]);
|
|
4056
|
+
}
|
|
4057
|
+
return void 0;
|
|
4058
|
+
} catch (err) {
|
|
4059
|
+
return `warning: the push succeeded but local ${refname} could not be moved to ${newHead.slice(0, 7)}: ${gitFailure(err)} \u2014 run \`rig fetch\``;
|
|
4060
|
+
}
|
|
4061
|
+
}
|
|
4062
|
+
|
|
3394
4063
|
// src/cli/events.ts
|
|
3395
4064
|
var defaultReadStdin2 = async () => {
|
|
3396
4065
|
if (process.stdin.isTTY) return "";
|
|
@@ -3512,14 +4181,16 @@ Options:
|
|
|
3512
4181
|
${COMMON_FLAGS_USAGE2}`;
|
|
3513
4182
|
var PR_USAGE = `${PR_CREATE_USAGE}
|
|
3514
4183
|
|
|
4184
|
+
${PR_MERGE_USAGE}
|
|
4185
|
+
|
|
3515
4186
|
${PR_STATUS_USAGE}
|
|
3516
4187
|
|
|
3517
4188
|
${PR_LIST_USAGE}
|
|
3518
4189
|
|
|
3519
4190
|
${PR_SHOW_USAGE}`;
|
|
3520
|
-
var
|
|
4191
|
+
var HEX64_RE4 = /^[0-9a-f]{64}$/;
|
|
3521
4192
|
function assertHex64(value, what) {
|
|
3522
|
-
if (!
|
|
4193
|
+
if (!HEX64_RE4.test(value)) {
|
|
3523
4194
|
throw new Error(
|
|
3524
4195
|
`${what} must be a 64-char lowercase hex id (got ${JSON.stringify(value)})`
|
|
3525
4196
|
);
|
|
@@ -3716,7 +4387,7 @@ async function runIssue(args, deps) {
|
|
|
3716
4387
|
let bodyFile;
|
|
3717
4388
|
let labels;
|
|
3718
4389
|
try {
|
|
3719
|
-
const { values } =
|
|
4390
|
+
const { values } = parseArgs10({
|
|
3720
4391
|
args: rest,
|
|
3721
4392
|
options: {
|
|
3722
4393
|
...COMMON_OPTIONS2,
|
|
@@ -3812,7 +4483,7 @@ async function resolveCommentTarget(deps, targetEventId, relayUrl) {
|
|
|
3812
4483
|
const rootEventId = firstTagValue(target.tags, "E");
|
|
3813
4484
|
const rootKind = Number(firstTagValue(target.tags, "K"));
|
|
3814
4485
|
const rootAuthor = firstTagValue(target.tags, "P");
|
|
3815
|
-
if (rootEventId === void 0 || !
|
|
4486
|
+
if (rootEventId === void 0 || !HEX64_RE4.test(rootEventId) || !Number.isSafeInteger(rootKind) || rootAuthor === void 0 || !HEX64_RE4.test(rootAuthor)) {
|
|
3816
4487
|
throw new Error(
|
|
3817
4488
|
`kind:1111 comment ${targetEventId} carries no usable NIP-22 root scope (E/K/P tags) \u2014 cannot derive the thread root to reply into`
|
|
3818
4489
|
);
|
|
@@ -3836,7 +4507,7 @@ async function runComment(args, deps) {
|
|
|
3836
4507
|
let targetEventId;
|
|
3837
4508
|
let body;
|
|
3838
4509
|
try {
|
|
3839
|
-
const { values, positionals } =
|
|
4510
|
+
const { values, positionals } = parseArgs10({
|
|
3840
4511
|
args,
|
|
3841
4512
|
options: {
|
|
3842
4513
|
...COMMON_OPTIONS2,
|
|
@@ -3917,6 +4588,8 @@ async function runPr(args, deps) {
|
|
|
3917
4588
|
switch (sub) {
|
|
3918
4589
|
case "create":
|
|
3919
4590
|
return runPrCreate(rest, deps);
|
|
4591
|
+
case "merge":
|
|
4592
|
+
return runPrMerge(rest, deps);
|
|
3920
4593
|
case "status":
|
|
3921
4594
|
return runStatusCommand(rest, deps, PR_STATUS_SPEC);
|
|
3922
4595
|
// FREE read subcommands (#278): relay queries only, no payment path.
|
|
@@ -3931,7 +4604,7 @@ async function runPr(args, deps) {
|
|
|
3931
4604
|
return 0;
|
|
3932
4605
|
default:
|
|
3933
4606
|
io.err(
|
|
3934
|
-
sub === void 0 ? "missing subcommand: rig pr <create|status|list|show>" : `unknown rig pr subcommand: ${sub}`
|
|
4607
|
+
sub === void 0 ? "missing subcommand: rig pr <create|merge|status|list|show>" : `unknown rig pr subcommand: ${sub}`
|
|
3935
4608
|
);
|
|
3936
4609
|
io.err(PR_USAGE);
|
|
3937
4610
|
return 2;
|
|
@@ -3955,12 +4628,12 @@ async function resolveRevisedRoot(deps, rootId, relayUrl, addr) {
|
|
|
3955
4628
|
`patch ${rootId} not found on ${relayUrl} \u2014 nothing was published or paid`
|
|
3956
4629
|
);
|
|
3957
4630
|
}
|
|
3958
|
-
if (root.kind !==
|
|
4631
|
+
if (root.kind !== PATCH_KIND3) {
|
|
3959
4632
|
throw new Error(
|
|
3960
4633
|
`event ${rootId} has kind ${root.kind}, not a kind:1617 patch \u2014 nothing was published or paid`
|
|
3961
4634
|
);
|
|
3962
4635
|
}
|
|
3963
|
-
const aTag = `${
|
|
4636
|
+
const aTag = `${REPOSITORY_ANNOUNCEMENT_KIND3}:${addr.ownerPubkey}:${addr.repoId}`;
|
|
3964
4637
|
if (!root.tags.some((t) => t[0] === "a" && t[1] === aTag)) {
|
|
3965
4638
|
throw new Error(
|
|
3966
4639
|
`patch ${rootId} belongs to a different repository than ${aTag} \u2014 nothing was published or paid`
|
|
@@ -4011,7 +4684,7 @@ async function runPrCreate(rest, deps) {
|
|
|
4011
4684
|
let bodyFile;
|
|
4012
4685
|
let revises;
|
|
4013
4686
|
try {
|
|
4014
|
-
const { values } =
|
|
4687
|
+
const { values } = parseArgs10({
|
|
4015
4688
|
args: rest,
|
|
4016
4689
|
options: {
|
|
4017
4690
|
...COMMON_OPTIONS2,
|
|
@@ -4145,7 +4818,7 @@ async function runPrCreate(rest, deps) {
|
|
|
4145
4818
|
}
|
|
4146
4819
|
var STATUS_KIND_BY_VALUE = {
|
|
4147
4820
|
open: STATUS_OPEN_KIND2,
|
|
4148
|
-
applied:
|
|
4821
|
+
applied: STATUS_APPLIED_KIND3,
|
|
4149
4822
|
closed: STATUS_CLOSED_KIND2,
|
|
4150
4823
|
draft: STATUS_DRAFT_KIND2
|
|
4151
4824
|
};
|
|
@@ -4172,7 +4845,7 @@ async function runStatusCommand(args, deps, spec, fixedStatus) {
|
|
|
4172
4845
|
let targetEventId;
|
|
4173
4846
|
let status;
|
|
4174
4847
|
try {
|
|
4175
|
-
const { values, positionals } =
|
|
4848
|
+
const { values, positionals } = parseArgs10({
|
|
4176
4849
|
args,
|
|
4177
4850
|
options: COMMON_OPTIONS2,
|
|
4178
4851
|
allowPositionals: true
|
|
@@ -4258,8 +4931,8 @@ async function warnIfNotMaintainer(deps, args) {
|
|
|
4258
4931
|
// src/cli/entry.ts
|
|
4259
4932
|
import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
4260
4933
|
import { homedir as homedir3 } from "os";
|
|
4261
|
-
import { dirname as dirname4, join as
|
|
4262
|
-
import { parseArgs as
|
|
4934
|
+
import { dirname as dirname4, join as join5 } from "path";
|
|
4935
|
+
import { parseArgs as parseArgs11 } from "util";
|
|
4263
4936
|
var ENTRY_USAGE = `Usage: rig entry [<connector-url> | clear] [options]
|
|
4264
4937
|
|
|
4265
4938
|
Name the TOON connector rig pays. A connector describes itself on GET /ilp
|
|
@@ -4283,8 +4956,8 @@ Options:
|
|
|
4283
4956
|
--json machine-readable envelope
|
|
4284
4957
|
-h, --help show this help`;
|
|
4285
4958
|
function configPathFor2(env) {
|
|
4286
|
-
const dir = env["TOON_CLIENT_HOME"] ??
|
|
4287
|
-
return
|
|
4959
|
+
const dir = env["TOON_CLIENT_HOME"] ?? join5(homedir3(), ".toon-client");
|
|
4960
|
+
return join5(dir, "config.json");
|
|
4288
4961
|
}
|
|
4289
4962
|
function readEntryConfig(configPath) {
|
|
4290
4963
|
try {
|
|
@@ -4329,7 +5002,7 @@ async function runEntry(args, deps) {
|
|
|
4329
5002
|
let relayFlag;
|
|
4330
5003
|
let json = false;
|
|
4331
5004
|
try {
|
|
4332
|
-
const parsed =
|
|
5005
|
+
const parsed = parseArgs11({
|
|
4333
5006
|
args,
|
|
4334
5007
|
allowPositionals: true,
|
|
4335
5008
|
options: {
|
|
@@ -4473,237 +5146,11 @@ async function runEntry(args, deps) {
|
|
|
4473
5146
|
}
|
|
4474
5147
|
}
|
|
4475
5148
|
|
|
4476
|
-
// src/cli/fetch.ts
|
|
4477
|
-
import { parseArgs as parseArgs10 } from "util";
|
|
4478
|
-
var FETCH_USAGE = `Usage: rig fetch [remote] [options]
|
|
4479
|
-
|
|
4480
|
-
Fetch from a TOON remote \u2014 FREE (relay reads + Arweave gateway downloads; no
|
|
4481
|
-
payments, no identity needed). Reads the kind:30618 repository state from the
|
|
4482
|
-
remote's relay, downloads only the git objects this repository is missing
|
|
4483
|
-
(SHA-1 verified), and updates the remote-tracking refs
|
|
4484
|
-
(refs/remotes/<remote>/*; tags land at refs/tags/*), reporting what moved.
|
|
4485
|
-
|
|
4486
|
-
No merge happens: integrate with the git passthrough, e.g.
|
|
4487
|
-
\`rig merge origin/main\`. \`rig fetch\` is the TOON transport and shadows
|
|
4488
|
-
\`git fetch\` \u2014 plain-git fetches remain available via \`git fetch\` directly.
|
|
4489
|
-
|
|
4490
|
-
The repo address (toon.repoid/toon.owner) comes from the config \`rig init\`
|
|
4491
|
-
or \`rig clone\` writes; --repo-id/--owner override.
|
|
4492
|
-
|
|
4493
|
-
Options:
|
|
4494
|
-
--repo-id <id> repository id / NIP-34 d-tag (default: git config)
|
|
4495
|
-
--owner <pubkey> repository owner (npub or 64-char hex; default: git config)
|
|
4496
|
-
--relay <url> ad-hoc relay override \u2014 bypasses the remote's URL
|
|
4497
|
-
--gateway <url> gateway to read objects through FIRST, on its raw-bytes
|
|
4498
|
-
route <url>/raw/<txId>, ahead of the public gateway
|
|
4499
|
-
list \u2014 name a private, local or air-gapped gateway to
|
|
4500
|
-
fetch objects the public ones do not carry
|
|
4501
|
-
(env RIG_ARWEAVE_GATEWAY also sets it)
|
|
4502
|
-
--concurrency <n> parallel gateway downloads (default 8)
|
|
4503
|
-
--json machine-readable result envelope
|
|
4504
|
-
-h, --help show this help`;
|
|
4505
|
-
var WS_URL_RE4 = /^wss?:\/\//i;
|
|
4506
|
-
function localRefFor(refname, remote) {
|
|
4507
|
-
if (refname.startsWith("refs/heads/")) {
|
|
4508
|
-
return `refs/remotes/${remote}/${refname.slice("refs/heads/".length)}`;
|
|
4509
|
-
}
|
|
4510
|
-
if (refname.startsWith("refs/tags/")) return refname;
|
|
4511
|
-
return null;
|
|
4512
|
-
}
|
|
4513
|
-
async function resolveLocalRef(repoRoot, refname) {
|
|
4514
|
-
try {
|
|
4515
|
-
const out = await runGit(repoRoot, [
|
|
4516
|
-
"rev-parse",
|
|
4517
|
-
"--verify",
|
|
4518
|
-
"--quiet",
|
|
4519
|
-
refname
|
|
4520
|
-
]);
|
|
4521
|
-
const sha = out.trim();
|
|
4522
|
-
return /^[0-9a-f]{40}$/.test(sha) ? sha : null;
|
|
4523
|
-
} catch {
|
|
4524
|
-
return null;
|
|
4525
|
-
}
|
|
4526
|
-
}
|
|
4527
|
-
async function runFetch(args, deps) {
|
|
4528
|
-
const { io } = deps;
|
|
4529
|
-
let json = false;
|
|
4530
|
-
let remote = "origin";
|
|
4531
|
-
let relayFlag;
|
|
4532
|
-
let repoIdFlag;
|
|
4533
|
-
let ownerFlag;
|
|
4534
|
-
let gatewayFlag;
|
|
4535
|
-
let concurrency;
|
|
4536
|
-
try {
|
|
4537
|
-
const { values, positionals } = parseArgs10({
|
|
4538
|
-
args,
|
|
4539
|
-
options: {
|
|
4540
|
-
json: { type: "boolean", default: false },
|
|
4541
|
-
relay: { type: "string" },
|
|
4542
|
-
"repo-id": { type: "string" },
|
|
4543
|
-
owner: { type: "string" },
|
|
4544
|
-
gateway: { type: "string" },
|
|
4545
|
-
concurrency: { type: "string" },
|
|
4546
|
-
help: { type: "boolean", short: "h", default: false }
|
|
4547
|
-
},
|
|
4548
|
-
allowPositionals: true
|
|
4549
|
-
});
|
|
4550
|
-
if (values.help) {
|
|
4551
|
-
io.out(FETCH_USAGE);
|
|
4552
|
-
return 0;
|
|
4553
|
-
}
|
|
4554
|
-
json = values.json === true;
|
|
4555
|
-
if (positionals.length > 1) {
|
|
4556
|
-
throw new Error(
|
|
4557
|
-
`expected at most one [remote] argument, got ${positionals.length}`
|
|
4558
|
-
);
|
|
4559
|
-
}
|
|
4560
|
-
if (positionals[0] !== void 0) remote = positionals[0];
|
|
4561
|
-
relayFlag = values.relay;
|
|
4562
|
-
repoIdFlag = values["repo-id"];
|
|
4563
|
-
ownerFlag = values.owner !== void 0 ? ownerToHex(values.owner) : void 0;
|
|
4564
|
-
gatewayFlag = values.gateway;
|
|
4565
|
-
if (values.concurrency !== void 0) {
|
|
4566
|
-
concurrency = Number.parseInt(values.concurrency, 10);
|
|
4567
|
-
if (!Number.isSafeInteger(concurrency) || concurrency < 1) {
|
|
4568
|
-
throw new Error("--concurrency must be a positive integer");
|
|
4569
|
-
}
|
|
4570
|
-
}
|
|
4571
|
-
} catch (err) {
|
|
4572
|
-
io.err(err instanceof Error ? err.message : String(err));
|
|
4573
|
-
io.err(FETCH_USAGE);
|
|
4574
|
-
return 2;
|
|
4575
|
-
}
|
|
4576
|
-
try {
|
|
4577
|
-
const repoRoot = await resolveRepoRoot(deps.cwd);
|
|
4578
|
-
const toonConfig = await readToonConfig(repoRoot);
|
|
4579
|
-
const repoId = repoIdFlag ?? toonConfig.repoId;
|
|
4580
|
-
if (!repoId) throw new UnconfiguredRepoAddressError("repository id");
|
|
4581
|
-
const owner = ownerFlag ?? toonConfig.owner;
|
|
4582
|
-
if (!owner) throw new UnconfiguredRepoAddressError("repository owner");
|
|
4583
|
-
let relayUrl;
|
|
4584
|
-
if (relayFlag !== void 0) {
|
|
4585
|
-
relayUrl = relayFlag;
|
|
4586
|
-
} else {
|
|
4587
|
-
const urls = await getGitRemoteUrls(repoRoot, remote);
|
|
4588
|
-
if (urls.length === 0) throw new UnknownRemoteError(remote);
|
|
4589
|
-
if (urls.length > 1) throw new MultiUrlRemoteError(remote, urls);
|
|
4590
|
-
relayUrl = urls[0];
|
|
4591
|
-
}
|
|
4592
|
-
if (!WS_URL_RE4.test(relayUrl)) {
|
|
4593
|
-
throw new InvalidRelayUrlError(
|
|
4594
|
-
relayUrl,
|
|
4595
|
-
`remote ${JSON.stringify(remote)}`
|
|
4596
|
-
);
|
|
4597
|
-
}
|
|
4598
|
-
const remoteState = await fetchRemoteState({
|
|
4599
|
-
relayUrls: [relayUrl],
|
|
4600
|
-
ownerPubkey: owner,
|
|
4601
|
-
repoId,
|
|
4602
|
-
...deps.webSocketFactory ? { webSocketFactory: deps.webSocketFactory } : {},
|
|
4603
|
-
// The GraphQL fallback for SHAs the map does not cover asks the SAME
|
|
4604
|
-
// permaweb the objects are read from (#183).
|
|
4605
|
-
resolveSha: deps.resolveSha ?? shaResolverFor(gatewayFlag, deps.env)
|
|
4606
|
-
});
|
|
4607
|
-
const planned = [];
|
|
4608
|
-
for (const [refname, sha] of remoteState.refs) {
|
|
4609
|
-
if (!isSafeRefname(refname)) {
|
|
4610
|
-
io.err(
|
|
4611
|
-
`warning: skipping unsafe ref name from relay: ${JSON.stringify(refname)}`
|
|
4612
|
-
);
|
|
4613
|
-
continue;
|
|
4614
|
-
}
|
|
4615
|
-
const localRef = localRefFor(refname, remote);
|
|
4616
|
-
if (localRef === null) {
|
|
4617
|
-
io.err(
|
|
4618
|
-
`warning: skipping ref outside refs/heads and refs/tags: ${refname}`
|
|
4619
|
-
);
|
|
4620
|
-
continue;
|
|
4621
|
-
}
|
|
4622
|
-
planned.push({ refname, localRef, newSha: sha });
|
|
4623
|
-
}
|
|
4624
|
-
const reader = new GitRepoReader(repoRoot);
|
|
4625
|
-
const tips = [...new Set(planned.map((p) => p.newSha))];
|
|
4626
|
-
const presentLocally = new Set(await reader.listAllObjectShas());
|
|
4627
|
-
const collected = await collectRepoObjects({
|
|
4628
|
-
tips,
|
|
4629
|
-
shaToTxId: remoteState.shaToTxId,
|
|
4630
|
-
resolveMissing: (shas) => remoteState.resolveMissing(shas),
|
|
4631
|
-
presentLocally,
|
|
4632
|
-
// `--gateway` / RIG_ARWEAVE_GATEWAY first, public list behind it (#176).
|
|
4633
|
-
gateways: readGateways(gatewayFlag, deps.env),
|
|
4634
|
-
...deps.fetchFn ? { fetchFn: deps.fetchFn } : {},
|
|
4635
|
-
...concurrency !== void 0 ? { concurrency } : {}
|
|
4636
|
-
});
|
|
4637
|
-
if (collected.missing.length > 0) {
|
|
4638
|
-
throw new MissingRemoteObjectsError(
|
|
4639
|
-
collected.missing,
|
|
4640
|
-
`cannot fetch from ${relayUrl}`
|
|
4641
|
-
);
|
|
4642
|
-
}
|
|
4643
|
-
const written = await writeGitObjects(repoRoot, collected.objects.values());
|
|
4644
|
-
const updates = [];
|
|
4645
|
-
for (const { refname, localRef, newSha } of planned) {
|
|
4646
|
-
const oldSha = await resolveLocalRef(repoRoot, localRef);
|
|
4647
|
-
if (oldSha === newSha) {
|
|
4648
|
-
updates.push({ refname, localRef, oldSha, newSha, kind: "up-to-date" });
|
|
4649
|
-
continue;
|
|
4650
|
-
}
|
|
4651
|
-
let kind;
|
|
4652
|
-
if (oldSha === null) {
|
|
4653
|
-
kind = "new";
|
|
4654
|
-
} else {
|
|
4655
|
-
kind = await reader.isAncestor(oldSha, newSha) ? "fast-forward" : "forced";
|
|
4656
|
-
}
|
|
4657
|
-
await updateRef(repoRoot, localRef, newSha);
|
|
4658
|
-
updates.push({ refname, localRef, oldSha, newSha, kind });
|
|
4659
|
-
}
|
|
4660
|
-
const moved = updates.filter((u) => u.kind !== "up-to-date");
|
|
4661
|
-
if (json) {
|
|
4662
|
-
io.emitJson({
|
|
4663
|
-
command: "fetch",
|
|
4664
|
-
repoAddr: { ownerPubkey: owner, repoId },
|
|
4665
|
-
remote,
|
|
4666
|
-
relay: relayUrl,
|
|
4667
|
-
objectsDownloaded: written,
|
|
4668
|
-
updates,
|
|
4669
|
-
executed: true
|
|
4670
|
-
});
|
|
4671
|
-
return 0;
|
|
4672
|
-
}
|
|
4673
|
-
if (moved.length === 0) {
|
|
4674
|
-
io.out("Already up to date.");
|
|
4675
|
-
return 0;
|
|
4676
|
-
}
|
|
4677
|
-
io.out(`From ${relayUrl}`);
|
|
4678
|
-
for (const u of moved) {
|
|
4679
|
-
const short = (refname) => refname.replace(/^refs\/heads\//, "").replace(/^refs\/tags\//, "").replace(/^refs\/remotes\//, "");
|
|
4680
|
-
const src = short(u.refname);
|
|
4681
|
-
const dst = short(u.localRef);
|
|
4682
|
-
if (u.kind === "new") {
|
|
4683
|
-
const label = u.refname.startsWith("refs/tags/") ? "[new tag]" : "[new branch]";
|
|
4684
|
-
io.out(` * ${label.padEnd(17)} ${src.padEnd(14)} -> ${dst}`);
|
|
4685
|
-
} else if (u.kind === "forced") {
|
|
4686
|
-
io.out(
|
|
4687
|
-
` + ${u.oldSha.slice(0, 7)}...${u.newSha.slice(0, 7)} ${src.padEnd(14)} -> ${dst} (forced update)`
|
|
4688
|
-
);
|
|
4689
|
-
} else {
|
|
4690
|
-
io.out(
|
|
4691
|
-
` ${u.oldSha.slice(0, 7)}..${u.newSha.slice(0, 7)} ${src.padEnd(14)} -> ${dst}`
|
|
4692
|
-
);
|
|
4693
|
-
}
|
|
4694
|
-
}
|
|
4695
|
-
io.out(`Downloaded ${written} object(s) (SHA-1 verified).`);
|
|
4696
|
-
return 0;
|
|
4697
|
-
} catch (err) {
|
|
4698
|
-
return emitCliError(io, json, "fetch", err);
|
|
4699
|
-
}
|
|
4700
|
-
}
|
|
4701
|
-
|
|
4702
5149
|
// src/cli/fund.ts
|
|
4703
5150
|
import { readFileSync as readFileSync4 } from "fs";
|
|
4704
5151
|
import { homedir as homedir4 } from "os";
|
|
4705
|
-
import { join as
|
|
4706
|
-
import { parseArgs as
|
|
5152
|
+
import { join as join6 } from "path";
|
|
5153
|
+
import { parseArgs as parseArgs12 } from "util";
|
|
4707
5154
|
var DEVNET_FAUCET_URL = "https://faucet.devnet.toonprotocol.dev";
|
|
4708
5155
|
var CHAINS = ["evm", "solana"];
|
|
4709
5156
|
var CHAIN_ALIASES = {
|
|
@@ -4841,8 +5288,8 @@ function noFaucetGuidance(network, devnetOrigin) {
|
|
|
4841
5288
|
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}`;
|
|
4842
5289
|
}
|
|
4843
5290
|
function readFundConfig(env) {
|
|
4844
|
-
const dir = env["TOON_CLIENT_HOME"] ??
|
|
4845
|
-
const configPath =
|
|
5291
|
+
const dir = env["TOON_CLIENT_HOME"] ?? join6(homedir4(), ".toon-client");
|
|
5292
|
+
const configPath = join6(dir, "config.json");
|
|
4846
5293
|
try {
|
|
4847
5294
|
return {
|
|
4848
5295
|
file: JSON.parse(readFileSync4(configPath, "utf8")),
|
|
@@ -4863,7 +5310,7 @@ async function runFund(args, deps) {
|
|
|
4863
5310
|
let addressFlag;
|
|
4864
5311
|
let json = false;
|
|
4865
5312
|
try {
|
|
4866
|
-
const { values, positionals } =
|
|
5313
|
+
const { values, positionals } = parseArgs12({
|
|
4867
5314
|
args,
|
|
4868
5315
|
allowPositionals: true,
|
|
4869
5316
|
options: {
|
|
@@ -5089,7 +5536,7 @@ var runGitPassthrough = (argv, options = {}) => {
|
|
|
5089
5536
|
import { existsSync, mkdirSync as mkdirSync4 } from "fs";
|
|
5090
5537
|
import { dirname as dirname5 } from "path";
|
|
5091
5538
|
import { createInterface } from "readline/promises";
|
|
5092
|
-
import { parseArgs as
|
|
5539
|
+
import { parseArgs as parseArgs13 } from "util";
|
|
5093
5540
|
async function loadKeyOps() {
|
|
5094
5541
|
const { generateKeystore, importKeystore } = await import("@toon-protocol/client");
|
|
5095
5542
|
return { generateKeystore, importKeystore, deriveNostrKeyFromMnemonic };
|
|
@@ -5261,7 +5708,7 @@ async function runIdentity(args, deps) {
|
|
|
5261
5708
|
}
|
|
5262
5709
|
}
|
|
5263
5710
|
function parseMintArgs(args, verb) {
|
|
5264
|
-
const { values, positionals } =
|
|
5711
|
+
const { values, positionals } = parseArgs13({
|
|
5265
5712
|
args,
|
|
5266
5713
|
options: {
|
|
5267
5714
|
force: { type: "boolean", default: false },
|
|
@@ -5366,7 +5813,7 @@ async function runIdentityShow(args, deps) {
|
|
|
5366
5813
|
let json = false;
|
|
5367
5814
|
let help = false;
|
|
5368
5815
|
try {
|
|
5369
|
-
const parsed =
|
|
5816
|
+
const parsed = parseArgs13({
|
|
5370
5817
|
args,
|
|
5371
5818
|
options: {
|
|
5372
5819
|
json: { type: "boolean", default: false },
|
|
@@ -5474,14 +5921,14 @@ async function defaultReadSecretLine(prompt, isInteractive) {
|
|
|
5474
5921
|
}
|
|
5475
5922
|
|
|
5476
5923
|
// src/cli/inbox.ts
|
|
5477
|
-
import { parseArgs as
|
|
5924
|
+
import { parseArgs as parseArgs14 } from "util";
|
|
5478
5925
|
import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
5479
|
-
import { join as
|
|
5926
|
+
import { join as join7 } from "path";
|
|
5480
5927
|
import {
|
|
5481
5928
|
ISSUE_KIND as ISSUE_KIND2,
|
|
5482
|
-
PATCH_KIND as
|
|
5483
|
-
REPOSITORY_ANNOUNCEMENT_KIND as
|
|
5484
|
-
STATUS_APPLIED_KIND as
|
|
5929
|
+
PATCH_KIND as PATCH_KIND4,
|
|
5930
|
+
REPOSITORY_ANNOUNCEMENT_KIND as REPOSITORY_ANNOUNCEMENT_KIND4,
|
|
5931
|
+
STATUS_APPLIED_KIND as STATUS_APPLIED_KIND4,
|
|
5485
5932
|
STATUS_CLOSED_KIND as STATUS_CLOSED_KIND3,
|
|
5486
5933
|
STATUS_DRAFT_KIND as STATUS_DRAFT_KIND3,
|
|
5487
5934
|
STATUS_OPEN_KIND as STATUS_OPEN_KIND3
|
|
@@ -5599,7 +6046,7 @@ Options:
|
|
|
5599
6046
|
-h, --help show this help`;
|
|
5600
6047
|
var STATUS_KINDS2 = [
|
|
5601
6048
|
STATUS_OPEN_KIND3,
|
|
5602
|
-
|
|
6049
|
+
STATUS_APPLIED_KIND4,
|
|
5603
6050
|
STATUS_CLOSED_KIND3,
|
|
5604
6051
|
STATUS_DRAFT_KIND3
|
|
5605
6052
|
];
|
|
@@ -5611,17 +6058,17 @@ var CI_KINDS = [
|
|
|
5611
6058
|
CI_JOB_RESULT_KIND
|
|
5612
6059
|
];
|
|
5613
6060
|
var INBOX_KINDS = [
|
|
5614
|
-
|
|
6061
|
+
PATCH_KIND4,
|
|
5615
6062
|
ISSUE_KIND2,
|
|
5616
6063
|
COMMENT_KIND,
|
|
5617
6064
|
LEGACY_COMMENT_KIND,
|
|
5618
6065
|
...STATUS_KINDS2,
|
|
5619
6066
|
...CI_KINDS
|
|
5620
6067
|
];
|
|
5621
|
-
var
|
|
6068
|
+
var HEX64_RE5 = /^[0-9a-f]{64}$/;
|
|
5622
6069
|
var INBOX_CURSOR_FILENAME = "inbox-cursors.json";
|
|
5623
6070
|
function cursorPath(env) {
|
|
5624
|
-
return
|
|
6071
|
+
return join7(clientStateDir(env), INBOX_CURSOR_FILENAME);
|
|
5625
6072
|
}
|
|
5626
6073
|
function readCursors(env) {
|
|
5627
6074
|
try {
|
|
@@ -5660,7 +6107,7 @@ function hasTopic(event, topic) {
|
|
|
5660
6107
|
return event.tags.some((t) => t[0] === "t" && t[1] === topic);
|
|
5661
6108
|
}
|
|
5662
6109
|
function typeOf(event) {
|
|
5663
|
-
if (event.kind ===
|
|
6110
|
+
if (event.kind === PATCH_KIND4) {
|
|
5664
6111
|
if (hasTopic(event, "root-revision")) return "revision";
|
|
5665
6112
|
if (hasTopic(event, "root") || tagValue2(event.tags, "e") === void 0) {
|
|
5666
6113
|
return "patch";
|
|
@@ -5696,7 +6143,7 @@ function toInboxEntry(event) {
|
|
|
5696
6143
|
const type = typeOf(event);
|
|
5697
6144
|
if (type === null) return null;
|
|
5698
6145
|
const repo = event.tags.find(
|
|
5699
|
-
(t) => t[0] === "a" && t[1]?.startsWith(`${
|
|
6146
|
+
(t) => t[0] === "a" && t[1]?.startsWith(`${REPOSITORY_ANNOUNCEMENT_KIND4}:`)
|
|
5700
6147
|
)?.[1];
|
|
5701
6148
|
return {
|
|
5702
6149
|
id: event.id,
|
|
@@ -5722,7 +6169,7 @@ async function ownerAnnouncement(relays, owner, repoId, ws) {
|
|
|
5722
6169
|
relays,
|
|
5723
6170
|
[
|
|
5724
6171
|
{
|
|
5725
|
-
kinds: [
|
|
6172
|
+
kinds: [REPOSITORY_ANNOUNCEMENT_KIND4],
|
|
5726
6173
|
authors: [owner],
|
|
5727
6174
|
"#d": [repoId]
|
|
5728
6175
|
}
|
|
@@ -5731,7 +6178,7 @@ async function ownerAnnouncement(relays, owner, repoId, ws) {
|
|
|
5731
6178
|
).catch(() => /* @__PURE__ */ new Map());
|
|
5732
6179
|
return newest(
|
|
5733
6180
|
[...found.values()].filter(
|
|
5734
|
-
(e) => e.kind ===
|
|
6181
|
+
(e) => e.kind === REPOSITORY_ANNOUNCEMENT_KIND4 && e.pubkey.toLowerCase() === owner && tagValue2(e.tags, "d") === repoId
|
|
5735
6182
|
)
|
|
5736
6183
|
);
|
|
5737
6184
|
}
|
|
@@ -5763,7 +6210,7 @@ async function runInbox(args, deps) {
|
|
|
5763
6210
|
let remote;
|
|
5764
6211
|
let relayFlags = [];
|
|
5765
6212
|
try {
|
|
5766
|
-
const { values, positionals } =
|
|
6213
|
+
const { values, positionals } = parseArgs14({
|
|
5767
6214
|
args,
|
|
5768
6215
|
options: INBOX_OPTIONS,
|
|
5769
6216
|
allowPositionals: true
|
|
@@ -5822,14 +6269,14 @@ async function runInbox(args, deps) {
|
|
|
5822
6269
|
const announcements = await queryAll(
|
|
5823
6270
|
configured,
|
|
5824
6271
|
[
|
|
5825
|
-
{ kinds: [
|
|
5826
|
-
{ kinds: [
|
|
6272
|
+
{ kinds: [REPOSITORY_ANNOUNCEMENT_KIND4], authors: [me] },
|
|
6273
|
+
{ kinds: [REPOSITORY_ANNOUNCEMENT_KIND4], "#maintainers": [me] }
|
|
5827
6274
|
],
|
|
5828
6275
|
ws
|
|
5829
6276
|
);
|
|
5830
6277
|
const byRepo = /* @__PURE__ */ new Map();
|
|
5831
6278
|
for (const e of announcements.values()) {
|
|
5832
|
-
if (e.kind !==
|
|
6279
|
+
if (e.kind !== REPOSITORY_ANNOUNCEMENT_KIND4) continue;
|
|
5833
6280
|
const d = tagValue2(e.tags, "d");
|
|
5834
6281
|
if (!d) continue;
|
|
5835
6282
|
const key = `${e.pubkey.toLowerCase()}:${d}`;
|
|
@@ -5843,7 +6290,7 @@ async function runInbox(args, deps) {
|
|
|
5843
6290
|
if (latest === null) continue;
|
|
5844
6291
|
if (owner !== me && !parseMaintainers(latest.tags).includes(me)) continue;
|
|
5845
6292
|
watched.push({
|
|
5846
|
-
address: `${
|
|
6293
|
+
address: `${REPOSITORY_ANNOUNCEMENT_KIND4}:${owner}:${repoId}`,
|
|
5847
6294
|
ownerPubkey: owner,
|
|
5848
6295
|
authorized: authorizedAuthors(owner, latest.tags),
|
|
5849
6296
|
relays: relaysTag(latest.tags)
|
|
@@ -5901,7 +6348,7 @@ async function runInbox(args, deps) {
|
|
|
5901
6348
|
const unknownTargets = /* @__PURE__ */ new Set();
|
|
5902
6349
|
for (const e of statusEvents) {
|
|
5903
6350
|
const target = tagValue2(e.tags, "e");
|
|
5904
|
-
if (!target || !
|
|
6351
|
+
if (!target || !HEX64_RE5.test(target)) continue;
|
|
5905
6352
|
const known = found.get(target);
|
|
5906
6353
|
if (known) targetAuthors.set(target, known.pubkey.toLowerCase());
|
|
5907
6354
|
else unknownTargets.add(target);
|
|
@@ -6035,7 +6482,7 @@ async function runInbox(args, deps) {
|
|
|
6035
6482
|
|
|
6036
6483
|
// src/cli/init.ts
|
|
6037
6484
|
import { basename as basename2 } from "path";
|
|
6038
|
-
import { parseArgs as
|
|
6485
|
+
import { parseArgs as parseArgs15 } from "util";
|
|
6039
6486
|
|
|
6040
6487
|
// src/cli/git-author.ts
|
|
6041
6488
|
var PROFILE_KIND = 0;
|
|
@@ -6153,7 +6600,7 @@ Options:
|
|
|
6153
6600
|
--json machine-readable report
|
|
6154
6601
|
-h, --help show this help`;
|
|
6155
6602
|
function parseInitArgs(args) {
|
|
6156
|
-
const { values, positionals } =
|
|
6603
|
+
const { values, positionals } = parseArgs15({
|
|
6157
6604
|
args,
|
|
6158
6605
|
options: {
|
|
6159
6606
|
"repo-id": { type: "string" },
|
|
@@ -6380,8 +6827,8 @@ async function runInit(args, deps) {
|
|
|
6380
6827
|
}
|
|
6381
6828
|
|
|
6382
6829
|
// src/cli/maintainers.ts
|
|
6383
|
-
import { parseArgs as
|
|
6384
|
-
var
|
|
6830
|
+
import { parseArgs as parseArgs16 } from "util";
|
|
6831
|
+
var HEX64_RE6 = /^[0-9a-f]{64}$/;
|
|
6385
6832
|
var REF_AUTHORITY_NOTICE = "Note: maintainers can move refs (publish honored repo state), not only set status.";
|
|
6386
6833
|
var MAINTAINERS_USAGE = `Usage: rig maintainers <list|add|remove> [<pubkey>] [options]
|
|
6387
6834
|
|
|
@@ -6434,7 +6881,7 @@ async function runList2(args, deps) {
|
|
|
6434
6881
|
const { io } = deps;
|
|
6435
6882
|
let flags;
|
|
6436
6883
|
try {
|
|
6437
|
-
const { values, positionals } =
|
|
6884
|
+
const { values, positionals } = parseArgs16({
|
|
6438
6885
|
args,
|
|
6439
6886
|
options: REPO_COMMAND_OPTIONS,
|
|
6440
6887
|
allowPositionals: true
|
|
@@ -6501,7 +6948,7 @@ async function runMutate(op, args, deps) {
|
|
|
6501
6948
|
let flags;
|
|
6502
6949
|
let pubkey;
|
|
6503
6950
|
try {
|
|
6504
|
-
const { values, positionals } =
|
|
6951
|
+
const { values, positionals } = parseArgs16({
|
|
6505
6952
|
args,
|
|
6506
6953
|
options: REPO_COMMAND_OPTIONS,
|
|
6507
6954
|
allowPositionals: true
|
|
@@ -6515,7 +6962,7 @@ async function runMutate(op, args, deps) {
|
|
|
6515
6962
|
throw new Error(`expected exactly one <pubkey> to ${op}`);
|
|
6516
6963
|
}
|
|
6517
6964
|
pubkey = ownerToHex(positionals[0]).toLowerCase();
|
|
6518
|
-
if (!
|
|
6965
|
+
if (!HEX64_RE6.test(pubkey)) {
|
|
6519
6966
|
throw new Error(
|
|
6520
6967
|
`<pubkey> must resolve to 64-char hex (got ${JSON.stringify(positionals[0])})`
|
|
6521
6968
|
);
|
|
@@ -6636,7 +7083,7 @@ async function runMutate(op, args, deps) {
|
|
|
6636
7083
|
}
|
|
6637
7084
|
|
|
6638
7085
|
// src/cli/refresh.ts
|
|
6639
|
-
import { parseArgs as
|
|
7086
|
+
import { parseArgs as parseArgs17 } from "util";
|
|
6640
7087
|
var REFRESH_USAGE = `Usage: rig refresh [options]
|
|
6641
7088
|
|
|
6642
7089
|
Republish this repo's kind:30617 announcement with no field edit, refreshing
|
|
@@ -6672,7 +7119,7 @@ async function runRefresh(args, deps) {
|
|
|
6672
7119
|
const { io } = deps;
|
|
6673
7120
|
let flags;
|
|
6674
7121
|
try {
|
|
6675
|
-
const { values, positionals } =
|
|
7122
|
+
const { values, positionals } = parseArgs17({
|
|
6676
7123
|
args,
|
|
6677
7124
|
options: REPO_COMMAND_OPTIONS,
|
|
6678
7125
|
allowPositionals: true
|
|
@@ -6795,7 +7242,7 @@ async function runRefresh(args, deps) {
|
|
|
6795
7242
|
|
|
6796
7243
|
// src/cli/name.ts
|
|
6797
7244
|
import { randomUUID } from "crypto";
|
|
6798
|
-
import { parseArgs as
|
|
7245
|
+
import { parseArgs as parseArgs18 } from "util";
|
|
6799
7246
|
var ARIO_DECIMALS = 6;
|
|
6800
7247
|
function renderMario(mario) {
|
|
6801
7248
|
return `${mario.toString()} mARIO (~${formatUnits(mario.toString(), ARIO_DECIMALS)} ARIO)`;
|
|
@@ -7304,7 +7751,7 @@ async function resolveNameContext(deps, network, processId, mode) {
|
|
|
7304
7751
|
return { identity, solanaAddress, network, processId, sdk, nostrSecretKey };
|
|
7305
7752
|
}
|
|
7306
7753
|
function parseNameFlags(args, env) {
|
|
7307
|
-
const { values, positionals } =
|
|
7754
|
+
const { values, positionals } = parseArgs18({
|
|
7308
7755
|
args,
|
|
7309
7756
|
allowPositionals: true,
|
|
7310
7757
|
options: {
|
|
@@ -7863,7 +8310,7 @@ async function runName(args, deps) {
|
|
|
7863
8310
|
}
|
|
7864
8311
|
|
|
7865
8312
|
// src/cli/payout.ts
|
|
7866
|
-
import { parseArgs as
|
|
8313
|
+
import { parseArgs as parseArgs19 } from "util";
|
|
7867
8314
|
import { getAddress } from "viem";
|
|
7868
8315
|
var PAYOUT_USAGE = `Usage: rig payout <set|clear|show> [<address>] [options]
|
|
7869
8316
|
|
|
@@ -7919,7 +8366,7 @@ async function runShow2(args, deps) {
|
|
|
7919
8366
|
const { io } = deps;
|
|
7920
8367
|
let flags;
|
|
7921
8368
|
try {
|
|
7922
|
-
const { values, positionals } =
|
|
8369
|
+
const { values, positionals } = parseArgs19({
|
|
7923
8370
|
args,
|
|
7924
8371
|
options: REPO_COMMAND_OPTIONS,
|
|
7925
8372
|
allowPositionals: true
|
|
@@ -7981,7 +8428,7 @@ async function runMutate2(op, args, deps) {
|
|
|
7981
8428
|
let flags;
|
|
7982
8429
|
let nextPayout = null;
|
|
7983
8430
|
try {
|
|
7984
|
-
const { values, positionals } =
|
|
8431
|
+
const { values, positionals } = parseArgs19({
|
|
7985
8432
|
args,
|
|
7986
8433
|
options: REPO_COMMAND_OPTIONS,
|
|
7987
8434
|
allowPositionals: true
|
|
@@ -8115,7 +8562,7 @@ async function runMutate2(op, args, deps) {
|
|
|
8115
8562
|
}
|
|
8116
8563
|
|
|
8117
8564
|
// src/cli/site.ts
|
|
8118
|
-
import { parseArgs as
|
|
8565
|
+
import { parseArgs as parseArgs20 } from "util";
|
|
8119
8566
|
|
|
8120
8567
|
// src/arweave-manifest.ts
|
|
8121
8568
|
var DEFAULT_INDEX = "index.html";
|
|
@@ -8136,13 +8583,13 @@ function buildArweaveManifest(entries, indexPath = DEFAULT_INDEX, fallbackTxId)
|
|
|
8136
8583
|
// src/cli/site-record.ts
|
|
8137
8584
|
import { mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
8138
8585
|
import { homedir as homedir5 } from "os";
|
|
8139
|
-
import { join as
|
|
8586
|
+
import { join as join8 } from "path";
|
|
8140
8587
|
var SITE_MANIFEST_FILENAME = "site-manifests.json";
|
|
8141
8588
|
function storeDir2(env) {
|
|
8142
|
-
return env["TOON_CLIENT_HOME"] ??
|
|
8589
|
+
return env["TOON_CLIENT_HOME"] ?? join8(homedir5(), ".toon-client");
|
|
8143
8590
|
}
|
|
8144
8591
|
function storePath2(env) {
|
|
8145
|
-
return
|
|
8592
|
+
return join8(storeDir2(env), SITE_MANIFEST_FILENAME);
|
|
8146
8593
|
}
|
|
8147
8594
|
function keyOf(repoId, ref) {
|
|
8148
8595
|
return `${repoId}\0${ref}`;
|
|
@@ -8206,7 +8653,7 @@ Options (publish):
|
|
|
8206
8653
|
estimate (nothing uploaded)
|
|
8207
8654
|
-h, --help show this help`;
|
|
8208
8655
|
function parseSiteArgs(args) {
|
|
8209
|
-
const { values, positionals } =
|
|
8656
|
+
const { values, positionals } = parseArgs20({
|
|
8210
8657
|
args,
|
|
8211
8658
|
options: {
|
|
8212
8659
|
index: { type: "string" },
|
|
@@ -8616,6 +9063,8 @@ Commands rig owns:
|
|
|
8616
9063
|
pr create publish a patch (kind:1617) with real
|
|
8617
9064
|
\`git format-patch\` content (--revises <patch-id>
|
|
8618
9065
|
publishes a revision of an existing patch)
|
|
9066
|
+
pr merge <patch-id> apply the latest revision with git am, push, then
|
|
9067
|
+
publish the applied status (owner/maintainer)
|
|
8619
9068
|
pr status <event-id> <state> set an issue/patch status (kind:1630-1633):
|
|
8620
9069
|
open | applied | closed | draft
|
|
8621
9070
|
inbox everything new since you last read it (free):
|
|
@@ -8804,4 +9253,4 @@ export {
|
|
|
8804
9253
|
rigVersion,
|
|
8805
9254
|
dispatch
|
|
8806
9255
|
};
|
|
8807
|
-
//# sourceMappingURL=chunk-
|
|
9256
|
+
//# sourceMappingURL=chunk-KQ4NQV7T.js.map
|