@toon-protocol/rig 5.0.2 → 5.2.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-CHVOXCDV.js → chunk-FX5GPZYU.js} +0 -0
- package/dist/{chunk-QKL53YZS.js → chunk-JX5P2KAA.js} +113 -47
- package/dist/chunk-JX5P2KAA.js.map +1 -0
- package/dist/{chunk-4WVH2ITA.js → chunk-S5R44MMB.js} +8 -6
- package/dist/chunk-S5R44MMB.js.map +1 -0
- package/dist/{chunk-2TG4YHEC.js → chunk-Y7TUE7JT.js} +866 -68
- package/dist/chunk-Y7TUE7JT.js.map +1 -0
- package/dist/{ci-serve-BU7NDT7O.js → ci-serve-CA37KQVC.js} +16 -12
- package/dist/ci-serve-CA37KQVC.js.map +1 -0
- package/dist/cli/rig.js +10 -4
- package/dist/cli/rig.js.map +1 -1
- package/dist/index.d.ts +79 -3
- package/dist/index.js +16 -5
- package/dist/index.js.map +1 -1
- package/dist/{publisher-DgbfziOm.d.ts → publisher-CQi69Nwg.d.ts} +8 -24
- package/dist/standalone/index.d.ts +1 -1
- package/dist/{standalone-mode-AT4S5EZG.js → standalone-mode-NWCCRFCL.js} +3 -3
- package/package.json +2 -2
- package/dist/chunk-2TG4YHEC.js.map +0 -1
- package/dist/chunk-4WVH2ITA.js.map +0 -1
- package/dist/chunk-QKL53YZS.js.map +0 -1
- package/dist/ci-serve-BU7NDT7O.js.map +0 -1
- /package/dist/{chunk-CHVOXCDV.js.map → chunk-FX5GPZYU.js.map} +0 -0
- /package/dist/{standalone-mode-AT4S5EZG.js.map → standalone-mode-NWCCRFCL.js.map} +0 -0
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CI_ADVERTISEMENT_KIND,
|
|
3
|
+
CI_JOB_RESULT_KIND,
|
|
4
|
+
CI_SERVICE_REQUEST_KIND,
|
|
5
|
+
CI_SERVICE_STOP_KIND,
|
|
3
6
|
CI_STATUS_USAGE,
|
|
7
|
+
CI_WORKFLOW_PROGRESS_KIND,
|
|
8
|
+
CI_WORKFLOW_RESULT_KIND,
|
|
4
9
|
GitRepoReader,
|
|
5
10
|
InvalidRelayUrlError,
|
|
6
11
|
MultiUrlRemoteError,
|
|
@@ -52,37 +57,42 @@ import {
|
|
|
52
57
|
updateRef,
|
|
53
58
|
writeGitObjects,
|
|
54
59
|
writeToonConfig
|
|
55
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-S5R44MMB.js";
|
|
56
61
|
import {
|
|
57
62
|
PREFERRED_GATEWAY,
|
|
58
63
|
mirrorGatewaysFor,
|
|
59
64
|
readGateways,
|
|
60
65
|
shaResolverFor
|
|
61
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-FX5GPZYU.js";
|
|
62
67
|
import {
|
|
63
68
|
COMMENT_KIND,
|
|
64
69
|
DEFAULT_KEYSTORE_PASSWORD,
|
|
65
70
|
LEGACY_COMMENT_KIND,
|
|
66
71
|
MissingIdentityError,
|
|
67
|
-
|
|
72
|
+
authorizedAuthors,
|
|
68
73
|
buildComment,
|
|
69
74
|
buildIssue,
|
|
70
75
|
buildPatch,
|
|
71
76
|
buildStatus,
|
|
72
77
|
clientConfigPath,
|
|
73
78
|
clientKeystorePath,
|
|
79
|
+
clientStateDir,
|
|
74
80
|
commentBelongsToThread,
|
|
81
|
+
decodeEventPayload,
|
|
75
82
|
defaultWebSocketFactory,
|
|
76
83
|
fetchRemoteState,
|
|
77
84
|
firstTagValue,
|
|
85
|
+
isPatchRevision,
|
|
78
86
|
isValidEvmPayoutAddress,
|
|
79
87
|
linkKeystoreInClientConfig,
|
|
80
88
|
parseMaintainers,
|
|
81
89
|
queryRelay,
|
|
82
90
|
readClientConfigFile,
|
|
83
91
|
resolveAccountIndex,
|
|
84
|
-
resolveIdentity
|
|
85
|
-
|
|
92
|
+
resolveIdentity,
|
|
93
|
+
revisionRootId,
|
|
94
|
+
selectRevision
|
|
95
|
+
} from "./chunk-JX5P2KAA.js";
|
|
86
96
|
import {
|
|
87
97
|
ChannelMapStore,
|
|
88
98
|
channelStatus,
|
|
@@ -311,7 +321,7 @@ function loadPaidSession(deps, relayUrl) {
|
|
|
311
321
|
});
|
|
312
322
|
}
|
|
313
323
|
var defaultLoadStandalone = async (options) => {
|
|
314
|
-
const mod = await import("./standalone-mode-
|
|
324
|
+
const mod = await import("./standalone-mode-NWCCRFCL.js");
|
|
315
325
|
return mod.createStandaloneContext(options);
|
|
316
326
|
};
|
|
317
327
|
function identityReport(ctx) {
|
|
@@ -565,9 +575,23 @@ async function runPush(args, deps) {
|
|
|
565
575
|
} else {
|
|
566
576
|
identity = session.identity;
|
|
567
577
|
}
|
|
568
|
-
|
|
578
|
+
const foreignOwner = toonConfig.owner && toonConfig.owner.toLowerCase() !== identity.pubkey.toLowerCase() ? toonConfig.owner : void 0;
|
|
579
|
+
let maintainerRemote;
|
|
580
|
+
if (session.path === "standalone" && foreignOwner) {
|
|
581
|
+
const ownerState = await session.ctx.fetchRemote({
|
|
582
|
+
ownerPubkey: foreignOwner,
|
|
583
|
+
repoId,
|
|
584
|
+
relayUrls: relaysUsed
|
|
585
|
+
});
|
|
586
|
+
if (ownerState.announced && authorizedAuthors(foreignOwner, ownerState.announceEvent?.tags).has(
|
|
587
|
+
identity.pubkey.toLowerCase()
|
|
588
|
+
)) {
|
|
589
|
+
maintainerRemote = ownerState;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
if (!maintainerRemote && foreignOwner) {
|
|
569
593
|
io.err(
|
|
570
|
-
`warning: git config toon.owner (${
|
|
594
|
+
`warning: git config toon.owner (${foreignOwner.slice(0, 8)}\u2026) differs from the active identity (${identity.pubkey.slice(0, 8)}\u2026) \u2014 this push publishes under the ACTIVE identity's repo namespace, not the configured owner's. Re-run \`rig init\` to adopt the active identity.`
|
|
571
595
|
);
|
|
572
596
|
}
|
|
573
597
|
const announcement = relaysUsed[0] === void 0 ? void 0 : {
|
|
@@ -584,7 +608,7 @@ async function runPush(args, deps) {
|
|
|
584
608
|
let rigPageSkipDetail;
|
|
585
609
|
if (session.path === "standalone") {
|
|
586
610
|
const ctx = session.ctx;
|
|
587
|
-
const remoteState = await ctx.fetchRemote({
|
|
611
|
+
const remoteState = maintainerRemote ?? await ctx.fetchRemote({
|
|
588
612
|
ownerPubkey: ctx.ownerPubkey,
|
|
589
613
|
repoId,
|
|
590
614
|
relayUrls: relaysUsed
|
|
@@ -614,6 +638,8 @@ async function runPush(args, deps) {
|
|
|
614
638
|
rigPageSkipDetail = "skipped (--no-rig-page)";
|
|
615
639
|
} else if (relaysUsed[0] === void 0) {
|
|
616
640
|
rigPageSkipDetail = "skipped (no relay resolved for the pointer)";
|
|
641
|
+
} else if (maintainerRemote) {
|
|
642
|
+
rigPageSkipDetail = "skipped (the owner's rig page is the owner's to refresh)";
|
|
617
643
|
} else if (!ctx.publisher.uploadBlob) {
|
|
618
644
|
rigPageSkipDetail = "skipped (the active publisher cannot upload raw blobs)";
|
|
619
645
|
} else {
|
|
@@ -2493,7 +2519,7 @@ async function runCi(args, deps) {
|
|
|
2493
2519
|
case "status":
|
|
2494
2520
|
return runCiStatus(rest, deps);
|
|
2495
2521
|
case "serve":
|
|
2496
|
-
return (await import("./ci-serve-
|
|
2522
|
+
return (await import("./ci-serve-CA37KQVC.js")).runCiServe(rest, deps);
|
|
2497
2523
|
case "--help":
|
|
2498
2524
|
case "-h":
|
|
2499
2525
|
case "help":
|
|
@@ -2766,6 +2792,8 @@ async function runClone(args, deps) {
|
|
|
2766
2792
|
import { readFile } from "fs/promises";
|
|
2767
2793
|
import { parseArgs as parseArgs8 } from "util";
|
|
2768
2794
|
import {
|
|
2795
|
+
PATCH_KIND as PATCH_KIND2,
|
|
2796
|
+
REPOSITORY_ANNOUNCEMENT_KIND as REPOSITORY_ANNOUNCEMENT_KIND2,
|
|
2769
2797
|
STATUS_APPLIED_KIND as STATUS_APPLIED_KIND2,
|
|
2770
2798
|
STATUS_CLOSED_KIND as STATUS_CLOSED_KIND2,
|
|
2771
2799
|
STATUS_DRAFT_KIND as STATUS_DRAFT_KIND2,
|
|
@@ -2985,7 +3013,7 @@ async function fetchAuthorizedAuthors(ctx, ownerPubkey, repoId) {
|
|
|
2985
3013
|
if (latest) announceTags = latest.tags;
|
|
2986
3014
|
} catch {
|
|
2987
3015
|
}
|
|
2988
|
-
return
|
|
3016
|
+
return authorizedAuthors(ownerPubkey, announceTags);
|
|
2989
3017
|
}
|
|
2990
3018
|
function parseTrackerItem(event, status) {
|
|
2991
3019
|
const item = {
|
|
@@ -3031,7 +3059,7 @@ async function fetchItems(ctx, kind) {
|
|
|
3031
3059
|
)
|
|
3032
3060
|
]);
|
|
3033
3061
|
const items = [...itemEvents.values()].filter(
|
|
3034
|
-
(e) => e.kind === kind && e.tags.some((t) => t[0] === "a" && t[1] === aTag)
|
|
3062
|
+
(e) => e.kind === kind && e.tags.some((t) => t[0] === "a" && t[1] === aTag) && !(kind === PATCH_KIND && isPatchRevision(e))
|
|
3035
3063
|
);
|
|
3036
3064
|
const statuses = new Map(aStatusEvents);
|
|
3037
3065
|
if (items.length > 0) {
|
|
@@ -3065,6 +3093,12 @@ async function fetchItem(ctx, eventId, expectedKind) {
|
|
|
3065
3093
|
if (!event) {
|
|
3066
3094
|
throw new Error(`event ${eventId} not found on ${ctx.relays.join(", ")}`);
|
|
3067
3095
|
}
|
|
3096
|
+
if (event.kind === PATCH_KIND && isPatchRevision(event)) {
|
|
3097
|
+
const rootId = revisionRootId(event);
|
|
3098
|
+
if (rootId !== void 0 && rootId !== eventId) {
|
|
3099
|
+
return fetchItem(ctx, rootId, expectedKind);
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3068
3102
|
if (event.kind !== expectedKind) {
|
|
3069
3103
|
const hint = event.kind === PATCH_KIND ? " (it is a kind:1617 patch \u2014 use `rig pr show`)" : event.kind === ISSUE_KIND ? " (it is a kind:1621 issue \u2014 use `rig issue show`)" : "";
|
|
3070
3104
|
throw new Error(
|
|
@@ -3100,16 +3134,53 @@ async function fetchItem(ctx, eventId, expectedKind) {
|
|
|
3100
3134
|
}));
|
|
3101
3135
|
const repoATag2 = tagValue(event.tags, "a") ?? null;
|
|
3102
3136
|
const parsedAddr = parseRepoATag(repoATag2) ?? ctx.repoAddr;
|
|
3103
|
-
const authorized = parsedAddr ? await fetchAuthorizedAuthors(
|
|
3104
|
-
|
|
3105
|
-
|
|
3137
|
+
const authorized = parsedAddr ? await fetchAuthorizedAuthors(
|
|
3138
|
+
ctx,
|
|
3139
|
+
parsedAddr.ownerPubkey,
|
|
3140
|
+
parsedAddr.repoId
|
|
3141
|
+
) : /* @__PURE__ */ new Set();
|
|
3142
|
+
const item = parseTrackerItem(
|
|
3143
|
+
event,
|
|
3144
|
+
deriveStatus(
|
|
3145
|
+
eventId,
|
|
3146
|
+
statusEvents.values(),
|
|
3147
|
+
withTargetAuthor(authorized, event.pubkey)
|
|
3148
|
+
)
|
|
3149
|
+
);
|
|
3150
|
+
let revisions;
|
|
3151
|
+
if (event.kind === PATCH_KIND) {
|
|
3152
|
+
const revisionEvents = await queryAll(
|
|
3153
|
+
ctx.relays,
|
|
3154
|
+
[{ kinds: [PATCH_KIND], "#e": [eventId] }],
|
|
3155
|
+
ctx.webSocketFactory
|
|
3156
|
+
);
|
|
3157
|
+
const { latest, earlier } = selectRevision(
|
|
3106
3158
|
event,
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3159
|
+
[...revisionEvents.values()].filter((e) => e.kind === PATCH_KIND),
|
|
3160
|
+
authorized
|
|
3161
|
+
);
|
|
3162
|
+
const describe = (e) => ({
|
|
3163
|
+
eventId: e.id,
|
|
3164
|
+
authorPubkey: e.pubkey,
|
|
3165
|
+
createdAt: e.created_at
|
|
3166
|
+
});
|
|
3167
|
+
revisions = { latest: describe(latest), earlier: earlier.map(describe) };
|
|
3168
|
+
if (latest.id !== event.id) {
|
|
3169
|
+
const shown = parseTrackerItem(latest, item.status);
|
|
3170
|
+
item.content = shown.content;
|
|
3171
|
+
item.title = shown.title;
|
|
3172
|
+
item.commitShas = shown.commitShas ?? [];
|
|
3173
|
+
delete item.branch;
|
|
3174
|
+
delete item.description;
|
|
3175
|
+
if (shown.branch !== void 0) item.branch = shown.branch;
|
|
3176
|
+
if (shown.description !== void 0) {
|
|
3177
|
+
item.description = shown.description;
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
}
|
|
3181
|
+
return {
|
|
3182
|
+
item,
|
|
3183
|
+
...revisions ? { revisions } : {},
|
|
3113
3184
|
comments,
|
|
3114
3185
|
repoATag: repoATag2
|
|
3115
3186
|
};
|
|
@@ -3225,6 +3296,10 @@ async function runShow(args, deps, spec) {
|
|
|
3225
3296
|
relays: ctx.relays,
|
|
3226
3297
|
repoATag: shown.repoATag,
|
|
3227
3298
|
[spec.jsonKey]: shown.item,
|
|
3299
|
+
...shown.revisions ? {
|
|
3300
|
+
latestRevision: shown.revisions.latest,
|
|
3301
|
+
earlierRevisions: shown.revisions.earlier
|
|
3302
|
+
} : {},
|
|
3228
3303
|
comments: shown.comments
|
|
3229
3304
|
});
|
|
3230
3305
|
return 0;
|
|
@@ -3241,6 +3316,20 @@ async function runShow(args, deps, spec) {
|
|
|
3241
3316
|
io.out(`Commits: ${item.commitShas.join(", ")}`);
|
|
3242
3317
|
}
|
|
3243
3318
|
if (shown.repoATag !== null) io.out(`Repo: ${shown.repoATag}`);
|
|
3319
|
+
if (shown.revisions) {
|
|
3320
|
+
const { latest, earlier } = shown.revisions;
|
|
3321
|
+
if (earlier.length > 0) {
|
|
3322
|
+
io.out(
|
|
3323
|
+
`Showing: ${latest.eventId} (latest revision, by ${latest.authorPubkey.slice(0, 8)}, ${isoDate(latest.createdAt)})`
|
|
3324
|
+
);
|
|
3325
|
+
io.out("Earlier revisions (oldest first):");
|
|
3326
|
+
for (const r of shown.revisions.earlier) {
|
|
3327
|
+
io.out(
|
|
3328
|
+
` ${r.eventId} (${r.authorPubkey.slice(0, 8)}, ${isoDate(r.createdAt)})`
|
|
3329
|
+
);
|
|
3330
|
+
}
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3244
3333
|
if (item.description !== void 0) {
|
|
3245
3334
|
io.out("");
|
|
3246
3335
|
io.out("Body:");
|
|
@@ -3341,7 +3430,11 @@ ${COMMON_FLAGS_USAGE2}
|
|
|
3341
3430
|
|
|
3342
3431
|
Related (FREE reads \u2014 no payment):
|
|
3343
3432
|
rig issue list [--state open|closed|all] list the repo's issues
|
|
3344
|
-
rig issue show <event-id> one issue + its comments
|
|
3433
|
+
rig issue show <event-id> one issue + its comments
|
|
3434
|
+
|
|
3435
|
+
Related (paid status \u2014 see \`rig issue status --help\`):
|
|
3436
|
+
rig issue status <event-id> <open|closed> set an issue's status
|
|
3437
|
+
rig issue close | reopen <event-id> shortcuts for closed / open`;
|
|
3345
3438
|
var COMMENT_USAGE = `Usage: rig comment <target-event-id> --body <text> [options]
|
|
3346
3439
|
|
|
3347
3440
|
Comment (NIP-22 kind:1111) on an issue or patch \u2014 a paid publish; writes are
|
|
@@ -3364,7 +3457,7 @@ comments published by this version.
|
|
|
3364
3457
|
Options:
|
|
3365
3458
|
--body <text> comment body (Markdown) [required]
|
|
3366
3459
|
${COMMON_FLAGS_USAGE2}`;
|
|
3367
|
-
var PR_CREATE_USAGE = `Usage: rig pr create --title <title> (--range <range> | --patch-file <path>) [options]
|
|
3460
|
+
var PR_CREATE_USAGE = `Usage: rig pr create --title <title> (--range <range> | --patch-file <path>) [--revises <patch-id>] [options]
|
|
3368
3461
|
|
|
3369
3462
|
Publish a patch (kind:1617) whose content is REAL \`git format-patch\` output \u2014
|
|
3370
3463
|
a paid publish; writes are permanent and non-refundable. --range runs
|
|
@@ -3378,6 +3471,12 @@ The PR body (--body/--body-file) is carried in a dedicated \`description\`
|
|
|
3378
3471
|
tag, not in the event content \u2014 the content stays pure format-patch output so
|
|
3379
3472
|
\`rig pr show \u2026 | git am\` keeps working.
|
|
3380
3473
|
|
|
3474
|
+
--revises publishes the patch as a NIP-34 revision of an existing root patch
|
|
3475
|
+
(\`t root-revision\` plus a NIP-10 reply to it), keeping the original thread,
|
|
3476
|
+
comments and status. Readers honor a revision only from the root's author or a
|
|
3477
|
+
declared maintainer; otherwise rig warns and still publishes. A revision is
|
|
3478
|
+
always published through the embedded (standalone) path.
|
|
3479
|
+
|
|
3381
3480
|
Options:
|
|
3382
3481
|
--title <title> patch/PR title (subject tag) [required]
|
|
3383
3482
|
--range <range> revision range for format-patch: <rev>, <rev>..<rev>,
|
|
@@ -3386,6 +3485,7 @@ Options:
|
|
|
3386
3485
|
--body <text> PR description (Markdown; description tag)
|
|
3387
3486
|
--body-file <path> read the PR description from a file
|
|
3388
3487
|
--branch <name> branch name (branch-name tag)
|
|
3488
|
+
--revises <patch-id> publish as a revision of this root patch (64-hex id)
|
|
3389
3489
|
${COMMON_FLAGS_USAGE2}`;
|
|
3390
3490
|
var PR_STATUS_USAGE = `Usage: rig pr status <target-event-id> <open|applied|closed|draft> [options]
|
|
3391
3491
|
|
|
@@ -3396,6 +3496,18 @@ with the repo a-tag attached so readers can scope a status stream to the
|
|
|
3396
3496
|
repository. (This command was \`rig status\` before v2 \u2014 bare \`rig status\`
|
|
3397
3497
|
now passes through to \`git status\`.)
|
|
3398
3498
|
|
|
3499
|
+
Options:
|
|
3500
|
+
${COMMON_FLAGS_USAGE2}`;
|
|
3501
|
+
var ISSUE_STATUS_USAGE = `Usage: rig issue status <issue-event-id> <open|closed> [options]
|
|
3502
|
+
rig issue close <issue-event-id> [options]
|
|
3503
|
+
rig issue reopen <issue-event-id> [options]
|
|
3504
|
+
|
|
3505
|
+
Set the status of an issue \u2014 a paid publish; writes are permanent and
|
|
3506
|
+
non-refundable. Aliases over \`rig pr status\`: \`closed\` / \`close\` publish
|
|
3507
|
+
kind:1632, \`open\` / \`reopen\` publish kind:1630, against the 64-char hex id
|
|
3508
|
+
of the issue, with the repo a-tag attached. \`applied\` and \`draft\` apply to
|
|
3509
|
+
patches only and are rejected for issues (use \`rig pr status\`).
|
|
3510
|
+
|
|
3399
3511
|
Options:
|
|
3400
3512
|
${COMMON_FLAGS_USAGE2}`;
|
|
3401
3513
|
var PR_USAGE = `${PR_CREATE_USAGE}
|
|
@@ -3578,13 +3690,22 @@ async function runIssue(args, deps) {
|
|
|
3578
3690
|
io.out(ISSUE_LIST_USAGE);
|
|
3579
3691
|
io.out("");
|
|
3580
3692
|
io.out(ISSUE_SHOW_USAGE);
|
|
3693
|
+
io.out("");
|
|
3694
|
+
io.out(ISSUE_STATUS_USAGE);
|
|
3581
3695
|
return 0;
|
|
3582
3696
|
}
|
|
3697
|
+
if (sub === "status") return runStatusCommand(rest, deps, ISSUE_STATUS_SPEC);
|
|
3698
|
+
if (sub === "close") {
|
|
3699
|
+
return runStatusCommand(rest, deps, ISSUE_STATUS_SPEC, "closed");
|
|
3700
|
+
}
|
|
3701
|
+
if (sub === "reopen") {
|
|
3702
|
+
return runStatusCommand(rest, deps, ISSUE_STATUS_SPEC, "open");
|
|
3703
|
+
}
|
|
3583
3704
|
if (sub === "list") return runIssueList(rest, deps);
|
|
3584
3705
|
if (sub === "show") return runIssueShow(rest, deps);
|
|
3585
3706
|
if (sub !== "create") {
|
|
3586
3707
|
io.err(
|
|
3587
|
-
sub === void 0 ? "missing subcommand: rig issue <create|list|show>" : `unknown rig issue subcommand: ${sub}`
|
|
3708
|
+
sub === void 0 ? "missing subcommand: rig issue <create|list|show|status|close|reopen>" : `unknown rig issue subcommand: ${sub}`
|
|
3588
3709
|
);
|
|
3589
3710
|
io.err(ISSUE_USAGE);
|
|
3590
3711
|
return 2;
|
|
@@ -3797,7 +3918,7 @@ async function runPr(args, deps) {
|
|
|
3797
3918
|
case "create":
|
|
3798
3919
|
return runPrCreate(rest, deps);
|
|
3799
3920
|
case "status":
|
|
3800
|
-
return
|
|
3921
|
+
return runStatusCommand(rest, deps, PR_STATUS_SPEC);
|
|
3801
3922
|
// FREE read subcommands (#278): relay queries only, no payment path.
|
|
3802
3923
|
case "list":
|
|
3803
3924
|
return runPrList(rest, deps);
|
|
@@ -3816,6 +3937,69 @@ async function runPr(args, deps) {
|
|
|
3816
3937
|
return 2;
|
|
3817
3938
|
}
|
|
3818
3939
|
}
|
|
3940
|
+
async function resolveRevisedRoot(deps, rootId, relayUrl, addr) {
|
|
3941
|
+
if (relayUrl === void 0) {
|
|
3942
|
+
throw new Error(
|
|
3943
|
+
"--revises needs the root patch from a relay; pass --relay <url> or configure a remote"
|
|
3944
|
+
);
|
|
3945
|
+
}
|
|
3946
|
+
const found = await queryRelay(
|
|
3947
|
+
relayUrl,
|
|
3948
|
+
{ ids: [rootId] },
|
|
3949
|
+
TARGET_LOOKUP_TIMEOUT_MS,
|
|
3950
|
+
deps.webSocketFactory ?? defaultWebSocketFactory
|
|
3951
|
+
);
|
|
3952
|
+
const root = found.find((e) => e.id === rootId);
|
|
3953
|
+
if (!root) {
|
|
3954
|
+
throw new Error(
|
|
3955
|
+
`patch ${rootId} not found on ${relayUrl} \u2014 nothing was published or paid`
|
|
3956
|
+
);
|
|
3957
|
+
}
|
|
3958
|
+
if (root.kind !== PATCH_KIND2) {
|
|
3959
|
+
throw new Error(
|
|
3960
|
+
`event ${rootId} has kind ${root.kind}, not a kind:1617 patch \u2014 nothing was published or paid`
|
|
3961
|
+
);
|
|
3962
|
+
}
|
|
3963
|
+
const aTag = `${REPOSITORY_ANNOUNCEMENT_KIND2}:${addr.ownerPubkey}:${addr.repoId}`;
|
|
3964
|
+
if (!root.tags.some((t) => t[0] === "a" && t[1] === aTag)) {
|
|
3965
|
+
throw new Error(
|
|
3966
|
+
`patch ${rootId} belongs to a different repository than ${aTag} \u2014 nothing was published or paid`
|
|
3967
|
+
);
|
|
3968
|
+
}
|
|
3969
|
+
if (isPatchRevision(root)) {
|
|
3970
|
+
throw new Error(
|
|
3971
|
+
`patch ${rootId} is itself a revision \u2014 pass the ROOT patch id to --revises; nothing was published or paid`
|
|
3972
|
+
);
|
|
3973
|
+
}
|
|
3974
|
+
return { pubkey: root.pubkey };
|
|
3975
|
+
}
|
|
3976
|
+
async function warnIfRevisionIgnored(deps, args, rootAuthor) {
|
|
3977
|
+
const { io } = deps;
|
|
3978
|
+
const { identity, addr, relayUrl } = args;
|
|
3979
|
+
const me = identity.pubkey.toLowerCase();
|
|
3980
|
+
if (me === rootAuthor?.toLowerCase()) return;
|
|
3981
|
+
if (me === addr.ownerPubkey.toLowerCase()) return;
|
|
3982
|
+
let authorized;
|
|
3983
|
+
if (relayUrl !== void 0) {
|
|
3984
|
+
try {
|
|
3985
|
+
const remote = await fetchRemoteState({
|
|
3986
|
+
relayUrls: [relayUrl],
|
|
3987
|
+
ownerPubkey: addr.ownerPubkey,
|
|
3988
|
+
repoId: addr.repoId,
|
|
3989
|
+
...deps.webSocketFactory ? { webSocketFactory: deps.webSocketFactory } : {}
|
|
3990
|
+
});
|
|
3991
|
+
authorized = authorizedAuthors(
|
|
3992
|
+
addr.ownerPubkey,
|
|
3993
|
+
remote.announceEvent?.tags ?? []
|
|
3994
|
+
);
|
|
3995
|
+
} catch {
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
if (authorized?.has(me)) return;
|
|
3999
|
+
io.err(
|
|
4000
|
+
authorized === void 0 ? "warning: could not read the repo announcement to verify your maintainer status \u2014 unless you are the root patch's author or a declared maintainer, readers will IGNORE this revision." : `warning: you (${identity.pubkey.slice(0, 8)}\u2026) are neither the root patch's author nor a maintainer of 30617:${addr.ownerPubkey.slice(0, 8)}\u2026:${addr.repoId} \u2014 readers will IGNORE this revision. Publishing anyway (the relay is permissionless).`
|
|
4001
|
+
);
|
|
4002
|
+
}
|
|
3819
4003
|
async function runPrCreate(rest, deps) {
|
|
3820
4004
|
const { io } = deps;
|
|
3821
4005
|
let flags;
|
|
@@ -3825,6 +4009,7 @@ async function runPrCreate(rest, deps) {
|
|
|
3825
4009
|
let branch;
|
|
3826
4010
|
let bodyFlag;
|
|
3827
4011
|
let bodyFile;
|
|
4012
|
+
let revises;
|
|
3828
4013
|
try {
|
|
3829
4014
|
const { values } = parseArgs8({
|
|
3830
4015
|
args: rest,
|
|
@@ -3835,7 +4020,8 @@ async function runPrCreate(rest, deps) {
|
|
|
3835
4020
|
"patch-file": { type: "string" },
|
|
3836
4021
|
body: { type: "string" },
|
|
3837
4022
|
"body-file": { type: "string" },
|
|
3838
|
-
branch: { type: "string" }
|
|
4023
|
+
branch: { type: "string" },
|
|
4024
|
+
revises: { type: "string" }
|
|
3839
4025
|
},
|
|
3840
4026
|
allowPositionals: false
|
|
3841
4027
|
});
|
|
@@ -3859,6 +4045,11 @@ async function runPrCreate(rest, deps) {
|
|
|
3859
4045
|
branch = values.branch;
|
|
3860
4046
|
bodyFlag = values.body;
|
|
3861
4047
|
bodyFile = values["body-file"];
|
|
4048
|
+
if (values.revises !== void 0) {
|
|
4049
|
+
assertHex64(values.revises, "--revises");
|
|
4050
|
+
revises = values.revises;
|
|
4051
|
+
flags = { ...flags, standalone: true };
|
|
4052
|
+
}
|
|
3862
4053
|
} catch (err) {
|
|
3863
4054
|
io.err(err instanceof Error ? err.message : String(err));
|
|
3864
4055
|
io.err(PR_CREATE_USAGE);
|
|
@@ -3883,12 +4074,16 @@ async function runPrCreate(rest, deps) {
|
|
|
3883
4074
|
}
|
|
3884
4075
|
let builtPatchText;
|
|
3885
4076
|
let builtCommits = [];
|
|
4077
|
+
let rootAuthor;
|
|
3886
4078
|
return runEvent({
|
|
3887
4079
|
command: "pr",
|
|
3888
4080
|
flags,
|
|
3889
4081
|
deps,
|
|
3890
4082
|
actionLabel: `patch ${JSON.stringify(title)}`,
|
|
3891
|
-
buildEvent: async (addr) => {
|
|
4083
|
+
buildEvent: async (addr, relayUrl) => {
|
|
4084
|
+
if (revises !== void 0) {
|
|
4085
|
+
rootAuthor = (await resolveRevisedRoot(deps, revises, relayUrl, addr)).pubkey;
|
|
4086
|
+
}
|
|
3892
4087
|
let patchText;
|
|
3893
4088
|
let commits;
|
|
3894
4089
|
if (range !== void 0) {
|
|
@@ -3908,7 +4103,9 @@ async function runPrCreate(rest, deps) {
|
|
|
3908
4103
|
} else {
|
|
3909
4104
|
patchText = await readFile(patchFile, "utf-8");
|
|
3910
4105
|
if (patchText.trim() === "") {
|
|
3911
|
-
throw new Error(
|
|
4106
|
+
throw new Error(
|
|
4107
|
+
`--patch-file ${patchFile} is empty \u2014 nothing to publish`
|
|
4108
|
+
);
|
|
3912
4109
|
}
|
|
3913
4110
|
commits = [];
|
|
3914
4111
|
}
|
|
@@ -3921,9 +4118,16 @@ async function runPrCreate(rest, deps) {
|
|
|
3921
4118
|
commits,
|
|
3922
4119
|
branch,
|
|
3923
4120
|
patchText,
|
|
3924
|
-
body
|
|
4121
|
+
body,
|
|
4122
|
+
revises !== void 0 ? {
|
|
4123
|
+
rootEventId: revises,
|
|
4124
|
+
...rootAuthor !== void 0 ? { rootAuthorPubkey: rootAuthor } : {}
|
|
4125
|
+
} : void 0
|
|
3925
4126
|
);
|
|
3926
4127
|
},
|
|
4128
|
+
// A revision from anyone but the root's author or a maintainer is ignored
|
|
4129
|
+
// by readers: warn, but publish (the relay is permissionless).
|
|
4130
|
+
preConfirm: revises === void 0 ? void 0 : (args) => warnIfRevisionIgnored(deps, args, rootAuthor),
|
|
3927
4131
|
sendDaemon: (client, addr) => {
|
|
3928
4132
|
if (builtPatchText === void 0) {
|
|
3929
4133
|
throw new Error("internal: patch text not built before delegation");
|
|
@@ -3948,7 +4152,21 @@ var STATUS_KIND_BY_VALUE = {
|
|
|
3948
4152
|
function isStatusValue(value) {
|
|
3949
4153
|
return Object.hasOwn(STATUS_KIND_BY_VALUE, value);
|
|
3950
4154
|
}
|
|
3951
|
-
|
|
4155
|
+
var PR_STATUS_SPEC = {
|
|
4156
|
+
command: "pr status",
|
|
4157
|
+
usage: PR_STATUS_USAGE,
|
|
4158
|
+
allowed: ["open", "applied", "closed", "draft"],
|
|
4159
|
+
shape: "<target-event-id> <open|applied|closed|draft>",
|
|
4160
|
+
targetLabel: "<target-event-id>"
|
|
4161
|
+
};
|
|
4162
|
+
var ISSUE_STATUS_SPEC = {
|
|
4163
|
+
command: "issue status",
|
|
4164
|
+
usage: ISSUE_STATUS_USAGE,
|
|
4165
|
+
allowed: ["open", "closed"],
|
|
4166
|
+
shape: "<issue-event-id> <open|closed>",
|
|
4167
|
+
targetLabel: "<issue-event-id>"
|
|
4168
|
+
};
|
|
4169
|
+
async function runStatusCommand(args, deps, spec, fixedStatus) {
|
|
3952
4170
|
const { io } = deps;
|
|
3953
4171
|
let flags;
|
|
3954
4172
|
let targetEventId;
|
|
@@ -3961,30 +4179,31 @@ async function runPrStatus(args, deps) {
|
|
|
3961
4179
|
});
|
|
3962
4180
|
flags = pickCommon2(values);
|
|
3963
4181
|
if (flags.help) {
|
|
3964
|
-
io.out(
|
|
4182
|
+
io.out(spec.usage);
|
|
3965
4183
|
return 0;
|
|
3966
4184
|
}
|
|
3967
|
-
|
|
4185
|
+
const want = fixedStatus === void 0 ? 2 : 1;
|
|
4186
|
+
if (positionals.length !== want) {
|
|
3968
4187
|
throw new Error(
|
|
3969
|
-
|
|
4188
|
+
fixedStatus === void 0 ? `expected exactly two arguments: ${spec.shape}` : `expected exactly one argument: ${spec.targetLabel}`
|
|
3970
4189
|
);
|
|
3971
4190
|
}
|
|
3972
4191
|
targetEventId = positionals[0];
|
|
3973
|
-
assertHex64(targetEventId,
|
|
3974
|
-
const rawStatus = positionals[1];
|
|
3975
|
-
if (!isStatusValue(rawStatus)) {
|
|
4192
|
+
assertHex64(targetEventId, spec.targetLabel);
|
|
4193
|
+
const rawStatus = fixedStatus ?? positionals[1];
|
|
4194
|
+
if (!isStatusValue(rawStatus) || !spec.allowed.includes(rawStatus)) {
|
|
3976
4195
|
throw new Error(
|
|
3977
|
-
`status must be one of
|
|
4196
|
+
`status must be one of ${spec.allowed.join(" | ")} (got ${JSON.stringify(rawStatus)})`
|
|
3978
4197
|
);
|
|
3979
4198
|
}
|
|
3980
4199
|
status = rawStatus;
|
|
3981
4200
|
} catch (err) {
|
|
3982
4201
|
io.err(err instanceof Error ? err.message : String(err));
|
|
3983
|
-
io.err(
|
|
4202
|
+
io.err(spec.usage);
|
|
3984
4203
|
return 2;
|
|
3985
4204
|
}
|
|
3986
4205
|
return runEvent({
|
|
3987
|
-
command:
|
|
4206
|
+
command: spec.command,
|
|
3988
4207
|
flags,
|
|
3989
4208
|
deps,
|
|
3990
4209
|
actionLabel: `status ${status} on ${targetEventId.slice(0, 8)}\u2026`,
|
|
@@ -4021,7 +4240,7 @@ async function warnIfNotMaintainer(deps, args) {
|
|
|
4021
4240
|
repoId: addr.repoId,
|
|
4022
4241
|
...deps.webSocketFactory ? { webSocketFactory: deps.webSocketFactory } : {}
|
|
4023
4242
|
});
|
|
4024
|
-
const authorized =
|
|
4243
|
+
const authorized = authorizedAuthors(
|
|
4025
4244
|
addr.ownerPubkey,
|
|
4026
4245
|
remote.announceEvent?.tags ?? []
|
|
4027
4246
|
);
|
|
@@ -5254,9 +5473,569 @@ async function defaultReadSecretLine(prompt, isInteractive) {
|
|
|
5254
5473
|
}
|
|
5255
5474
|
}
|
|
5256
5475
|
|
|
5476
|
+
// src/cli/inbox.ts
|
|
5477
|
+
import { parseArgs as parseArgs13 } from "util";
|
|
5478
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
5479
|
+
import { join as join6 } from "path";
|
|
5480
|
+
import {
|
|
5481
|
+
ISSUE_KIND as ISSUE_KIND2,
|
|
5482
|
+
PATCH_KIND as PATCH_KIND3,
|
|
5483
|
+
REPOSITORY_ANNOUNCEMENT_KIND as REPOSITORY_ANNOUNCEMENT_KIND3,
|
|
5484
|
+
STATUS_APPLIED_KIND as STATUS_APPLIED_KIND3,
|
|
5485
|
+
STATUS_CLOSED_KIND as STATUS_CLOSED_KIND3,
|
|
5486
|
+
STATUS_DRAFT_KIND as STATUS_DRAFT_KIND3,
|
|
5487
|
+
STATUS_OPEN_KIND as STATUS_OPEN_KIND3
|
|
5488
|
+
} from "@toon-protocol/core/nip34";
|
|
5489
|
+
|
|
5490
|
+
// src/cli/relay-follow.ts
|
|
5491
|
+
var WS_OPEN = 1;
|
|
5492
|
+
var CONNECT_TIMEOUT_MS = 1e4;
|
|
5493
|
+
function defaultBackoffMs(attempt) {
|
|
5494
|
+
return Math.min(3e4, 1e3 * 2 ** Math.max(0, attempt - 1));
|
|
5495
|
+
}
|
|
5496
|
+
function connectOnce(opts, onSubscribed) {
|
|
5497
|
+
return new Promise((resolve2) => {
|
|
5498
|
+
let ws;
|
|
5499
|
+
let done = false;
|
|
5500
|
+
let subscribed = false;
|
|
5501
|
+
const subIds = [];
|
|
5502
|
+
let connectTimer;
|
|
5503
|
+
const finish = (reason) => {
|
|
5504
|
+
if (done) return;
|
|
5505
|
+
done = true;
|
|
5506
|
+
clearTimeout(connectTimer);
|
|
5507
|
+
opts.signal.removeEventListener("abort", onAbort);
|
|
5508
|
+
try {
|
|
5509
|
+
if (ws.readyState === WS_OPEN) {
|
|
5510
|
+
for (const id of subIds) ws.send(JSON.stringify(["CLOSE", id]));
|
|
5511
|
+
}
|
|
5512
|
+
ws.close();
|
|
5513
|
+
} catch {
|
|
5514
|
+
}
|
|
5515
|
+
resolve2(reason);
|
|
5516
|
+
};
|
|
5517
|
+
const onAbort = () => finish(null);
|
|
5518
|
+
try {
|
|
5519
|
+
ws = opts.webSocketFactory(opts.url);
|
|
5520
|
+
} catch (err) {
|
|
5521
|
+
resolve2(`failed to connect to ${opts.url}: ${String(err)}`);
|
|
5522
|
+
return;
|
|
5523
|
+
}
|
|
5524
|
+
opts.signal.addEventListener("abort", onAbort);
|
|
5525
|
+
connectTimer = setTimeout(
|
|
5526
|
+
() => finish(`timed out connecting to ${opts.url}`),
|
|
5527
|
+
CONNECT_TIMEOUT_MS
|
|
5528
|
+
);
|
|
5529
|
+
ws.addEventListener("open", () => {
|
|
5530
|
+
clearTimeout(connectTimer);
|
|
5531
|
+
opts.filters().forEach((filter, i) => {
|
|
5532
|
+
const subId = `follow-${Date.now()}-${i}-${Math.random().toString(36).slice(2, 8)}`;
|
|
5533
|
+
subIds.push(subId);
|
|
5534
|
+
ws.send(JSON.stringify(["REQ", subId, filter]));
|
|
5535
|
+
});
|
|
5536
|
+
});
|
|
5537
|
+
ws.addEventListener("message", (msgEvent) => {
|
|
5538
|
+
try {
|
|
5539
|
+
const msg = JSON.parse(String(msgEvent.data));
|
|
5540
|
+
if (msg[0] === "EVENT" && msg[2] !== void 0) {
|
|
5541
|
+
const event = decodeEventPayload(msg[2]);
|
|
5542
|
+
if (event) opts.onEvent(event, opts.url);
|
|
5543
|
+
} else if (msg[0] === "EOSE" && !subscribed && subIds.includes(msg[1])) {
|
|
5544
|
+
subscribed = true;
|
|
5545
|
+
onSubscribed();
|
|
5546
|
+
}
|
|
5547
|
+
} catch {
|
|
5548
|
+
}
|
|
5549
|
+
});
|
|
5550
|
+
ws.addEventListener("error", (event) => {
|
|
5551
|
+
const detail = typeof event === "object" && event !== null && "message" in event ? String(event.message) : "unknown";
|
|
5552
|
+
finish(`websocket error on ${opts.url}: ${detail}`);
|
|
5553
|
+
});
|
|
5554
|
+
ws.addEventListener("close", () => {
|
|
5555
|
+
finish(`connection to ${opts.url} closed`);
|
|
5556
|
+
});
|
|
5557
|
+
});
|
|
5558
|
+
}
|
|
5559
|
+
async function followRelay(opts) {
|
|
5560
|
+
let attempt = 0;
|
|
5561
|
+
while (!opts.signal.aborted) {
|
|
5562
|
+
const reason = await connectOnce(opts, () => {
|
|
5563
|
+
attempt = 0;
|
|
5564
|
+
});
|
|
5565
|
+
if (opts.signal.aborted) return;
|
|
5566
|
+
opts.onError(reason ?? `connection to ${opts.url} ended`);
|
|
5567
|
+
attempt += 1;
|
|
5568
|
+
await new Promise((resolve2) => {
|
|
5569
|
+
const done = () => {
|
|
5570
|
+
clearTimeout(timer);
|
|
5571
|
+
opts.signal.removeEventListener("abort", done);
|
|
5572
|
+
resolve2();
|
|
5573
|
+
};
|
|
5574
|
+
const timer = setTimeout(done, opts.backoffMs(attempt));
|
|
5575
|
+
opts.signal.addEventListener("abort", done);
|
|
5576
|
+
});
|
|
5577
|
+
}
|
|
5578
|
+
}
|
|
5579
|
+
|
|
5580
|
+
// src/cli/inbox.ts
|
|
5581
|
+
var INBOX_USAGE = `Usage: rig inbox [options]
|
|
5582
|
+
|
|
5583
|
+
Print everything new since you last checked (free \u2014 relay reads only):
|
|
5584
|
+
patches and revisions, issues, comments, status changes and CI results for
|
|
5585
|
+
repos you own or maintain, plus any event that tags your pubkey.
|
|
5586
|
+
|
|
5587
|
+
Options:
|
|
5588
|
+
--since <time> read from a unix time, an ISO date, or a relative
|
|
5589
|
+
age (30m, 2h, 7d); does not move the cursor
|
|
5590
|
+
--all read everything, ignoring the cursor; does not move it
|
|
5591
|
+
--pubkey <pubkey> act as this pubkey (npub or hex) instead of the
|
|
5592
|
+
resolved identity
|
|
5593
|
+
--remote <name> read via this configured git remote (default: origin)
|
|
5594
|
+
--relay <url> ad-hoc relay override; repeatable \u2014 reads are merged
|
|
5595
|
+
--json machine-readable array, one object per event
|
|
5596
|
+
--follow emit the backlog, then stay connected and stream new
|
|
5597
|
+
events as JSON lines (one object per line) until
|
|
5598
|
+
interrupted; reconnects when a relay drops
|
|
5599
|
+
-h, --help show this help`;
|
|
5600
|
+
var STATUS_KINDS2 = [
|
|
5601
|
+
STATUS_OPEN_KIND3,
|
|
5602
|
+
STATUS_APPLIED_KIND3,
|
|
5603
|
+
STATUS_CLOSED_KIND3,
|
|
5604
|
+
STATUS_DRAFT_KIND3
|
|
5605
|
+
];
|
|
5606
|
+
var CI_KINDS = [
|
|
5607
|
+
CI_SERVICE_REQUEST_KIND,
|
|
5608
|
+
CI_SERVICE_STOP_KIND,
|
|
5609
|
+
CI_WORKFLOW_RESULT_KIND,
|
|
5610
|
+
CI_WORKFLOW_PROGRESS_KIND,
|
|
5611
|
+
CI_JOB_RESULT_KIND
|
|
5612
|
+
];
|
|
5613
|
+
var INBOX_KINDS = [
|
|
5614
|
+
PATCH_KIND3,
|
|
5615
|
+
ISSUE_KIND2,
|
|
5616
|
+
COMMENT_KIND,
|
|
5617
|
+
LEGACY_COMMENT_KIND,
|
|
5618
|
+
...STATUS_KINDS2,
|
|
5619
|
+
...CI_KINDS
|
|
5620
|
+
];
|
|
5621
|
+
var HEX64_RE4 = /^[0-9a-f]{64}$/;
|
|
5622
|
+
var INBOX_CURSOR_FILENAME = "inbox-cursors.json";
|
|
5623
|
+
function cursorPath(env) {
|
|
5624
|
+
return join6(clientStateDir(env), INBOX_CURSOR_FILENAME);
|
|
5625
|
+
}
|
|
5626
|
+
function readCursors(env) {
|
|
5627
|
+
try {
|
|
5628
|
+
const parsed = JSON.parse(readFileSync5(cursorPath(env), "utf8"));
|
|
5629
|
+
if (parsed && typeof parsed === "object") {
|
|
5630
|
+
return parsed;
|
|
5631
|
+
}
|
|
5632
|
+
} catch {
|
|
5633
|
+
}
|
|
5634
|
+
return {};
|
|
5635
|
+
}
|
|
5636
|
+
function writeCursor(env, pubkey, cursor) {
|
|
5637
|
+
const cursors = readCursors(env);
|
|
5638
|
+
cursors[pubkey] = cursor;
|
|
5639
|
+
mkdirSync5(clientStateDir(env), { recursive: true });
|
|
5640
|
+
writeFileSync4(cursorPath(env), JSON.stringify(cursors, null, 2) + "\n");
|
|
5641
|
+
}
|
|
5642
|
+
function parseSince(value, nowSec) {
|
|
5643
|
+
const trimmed = value.trim();
|
|
5644
|
+
if (/^\d+$/.test(trimmed)) return Number(trimmed);
|
|
5645
|
+
const rel = /^(\d+)([smhdw])$/.exec(trimmed);
|
|
5646
|
+
if (rel) {
|
|
5647
|
+
const unit = { s: 1, m: 60, h: 3600, d: 86400, w: 604800 }[rel[2]];
|
|
5648
|
+
return nowSec - Number(rel[1]) * unit;
|
|
5649
|
+
}
|
|
5650
|
+
const ms = Date.parse(trimmed);
|
|
5651
|
+
if (Number.isNaN(ms)) {
|
|
5652
|
+
throw new Error(
|
|
5653
|
+
`--since must be a unix time, an ISO date, or an age like 2h (got ${JSON.stringify(value)})`
|
|
5654
|
+
);
|
|
5655
|
+
}
|
|
5656
|
+
return Math.floor(ms / 1e3);
|
|
5657
|
+
}
|
|
5658
|
+
var tagValue2 = firstTagValue;
|
|
5659
|
+
function hasTopic(event, topic) {
|
|
5660
|
+
return event.tags.some((t) => t[0] === "t" && t[1] === topic);
|
|
5661
|
+
}
|
|
5662
|
+
function typeOf(event) {
|
|
5663
|
+
if (event.kind === PATCH_KIND3) {
|
|
5664
|
+
if (hasTopic(event, "root-revision")) return "revision";
|
|
5665
|
+
if (hasTopic(event, "root") || tagValue2(event.tags, "e") === void 0) {
|
|
5666
|
+
return "patch";
|
|
5667
|
+
}
|
|
5668
|
+
return null;
|
|
5669
|
+
}
|
|
5670
|
+
if (event.kind === ISSUE_KIND2) return "issue";
|
|
5671
|
+
if (event.kind === COMMENT_KIND || event.kind === LEGACY_COMMENT_KIND) {
|
|
5672
|
+
return "comment";
|
|
5673
|
+
}
|
|
5674
|
+
if (STATUS_KINDS2.includes(event.kind)) return "status";
|
|
5675
|
+
if (CI_KINDS.includes(event.kind)) return "ci";
|
|
5676
|
+
return null;
|
|
5677
|
+
}
|
|
5678
|
+
function targetOf(event, type) {
|
|
5679
|
+
const root = tagValue2(event.tags, "E");
|
|
5680
|
+
const parent = tagValue2(event.tags, "e");
|
|
5681
|
+
switch (type) {
|
|
5682
|
+
case "patch":
|
|
5683
|
+
case "issue":
|
|
5684
|
+
return event.id;
|
|
5685
|
+
case "revision":
|
|
5686
|
+
return parent ?? event.id;
|
|
5687
|
+
case "comment":
|
|
5688
|
+
return root ?? parent ?? event.id;
|
|
5689
|
+
case "status":
|
|
5690
|
+
return parent ?? event.id;
|
|
5691
|
+
case "ci":
|
|
5692
|
+
return root ?? tagValue2(event.tags, "c") ?? event.id;
|
|
5693
|
+
}
|
|
5694
|
+
}
|
|
5695
|
+
function toInboxEntry(event) {
|
|
5696
|
+
const type = typeOf(event);
|
|
5697
|
+
if (type === null) return null;
|
|
5698
|
+
const repo = event.tags.find(
|
|
5699
|
+
(t) => t[0] === "a" && t[1]?.startsWith(`${REPOSITORY_ANNOUNCEMENT_KIND3}:`)
|
|
5700
|
+
)?.[1];
|
|
5701
|
+
return {
|
|
5702
|
+
id: event.id,
|
|
5703
|
+
kind: event.kind,
|
|
5704
|
+
type,
|
|
5705
|
+
repo: repo ?? null,
|
|
5706
|
+
target: targetOf(event, type),
|
|
5707
|
+
author: event.pubkey,
|
|
5708
|
+
created_at: event.created_at
|
|
5709
|
+
};
|
|
5710
|
+
}
|
|
5711
|
+
function newest(events) {
|
|
5712
|
+
let winner = null;
|
|
5713
|
+
for (const e of events) {
|
|
5714
|
+
if (winner === null || e.created_at > winner.created_at || e.created_at === winner.created_at && e.id < winner.id) {
|
|
5715
|
+
winner = e;
|
|
5716
|
+
}
|
|
5717
|
+
}
|
|
5718
|
+
return winner;
|
|
5719
|
+
}
|
|
5720
|
+
async function ownerAnnouncement(relays, owner, repoId, ws) {
|
|
5721
|
+
const found = await queryAll(
|
|
5722
|
+
relays,
|
|
5723
|
+
[
|
|
5724
|
+
{
|
|
5725
|
+
kinds: [REPOSITORY_ANNOUNCEMENT_KIND3],
|
|
5726
|
+
authors: [owner],
|
|
5727
|
+
"#d": [repoId]
|
|
5728
|
+
}
|
|
5729
|
+
],
|
|
5730
|
+
ws
|
|
5731
|
+
).catch(() => /* @__PURE__ */ new Map());
|
|
5732
|
+
return newest(
|
|
5733
|
+
[...found.values()].filter(
|
|
5734
|
+
(e) => e.kind === REPOSITORY_ANNOUNCEMENT_KIND3 && e.pubkey.toLowerCase() === owner && tagValue2(e.tags, "d") === repoId
|
|
5735
|
+
)
|
|
5736
|
+
);
|
|
5737
|
+
}
|
|
5738
|
+
function relaysTag(tags) {
|
|
5739
|
+
return tags.filter((t) => t[0] === "relays").flatMap((t) => t.slice(1)).filter((url) => WS_URL_RE.test(url));
|
|
5740
|
+
}
|
|
5741
|
+
var INBOX_OPTIONS = {
|
|
5742
|
+
json: { type: "boolean", default: false },
|
|
5743
|
+
follow: { type: "boolean", default: false },
|
|
5744
|
+
all: { type: "boolean", default: false },
|
|
5745
|
+
since: { type: "string" },
|
|
5746
|
+
pubkey: { type: "string" },
|
|
5747
|
+
remote: { type: "string" },
|
|
5748
|
+
relay: { type: "string", multiple: true },
|
|
5749
|
+
help: { type: "boolean", short: "h", default: false }
|
|
5750
|
+
};
|
|
5751
|
+
function renderLine(entry) {
|
|
5752
|
+
const when = new Date(entry.created_at * 1e3).toISOString().slice(0, 16).replace("T", " ");
|
|
5753
|
+
const repo = entry.repo ?? "(no repo)";
|
|
5754
|
+
return `${when} ${entry.type.padEnd(8)} ${entry.id.slice(0, 8)} \u2192 ${entry.target.slice(0, 8)} ${repo} (${entry.author.slice(0, 8)})`;
|
|
5755
|
+
}
|
|
5756
|
+
async function runInbox(args, deps) {
|
|
5757
|
+
const { io } = deps;
|
|
5758
|
+
let json = false;
|
|
5759
|
+
let all = false;
|
|
5760
|
+
let follow = false;
|
|
5761
|
+
let sinceArg;
|
|
5762
|
+
let pubkeyArg;
|
|
5763
|
+
let remote;
|
|
5764
|
+
let relayFlags = [];
|
|
5765
|
+
try {
|
|
5766
|
+
const { values, positionals } = parseArgs13({
|
|
5767
|
+
args,
|
|
5768
|
+
options: INBOX_OPTIONS,
|
|
5769
|
+
allowPositionals: true
|
|
5770
|
+
});
|
|
5771
|
+
if (values.help) {
|
|
5772
|
+
io.out(INBOX_USAGE);
|
|
5773
|
+
return 0;
|
|
5774
|
+
}
|
|
5775
|
+
if (positionals.length > 0) {
|
|
5776
|
+
throw new Error("rig inbox takes no positional arguments");
|
|
5777
|
+
}
|
|
5778
|
+
json = values.json === true;
|
|
5779
|
+
all = values.all === true;
|
|
5780
|
+
follow = values.follow === true;
|
|
5781
|
+
sinceArg = values.since;
|
|
5782
|
+
if (values.pubkey !== void 0) pubkeyArg = ownerToHex(values.pubkey);
|
|
5783
|
+
remote = values.remote;
|
|
5784
|
+
relayFlags = values.relay ?? [];
|
|
5785
|
+
if (all && sinceArg !== void 0) {
|
|
5786
|
+
throw new Error("--all and --since are mutually exclusive");
|
|
5787
|
+
}
|
|
5788
|
+
} catch (err) {
|
|
5789
|
+
io.err(err instanceof Error ? err.message : String(err));
|
|
5790
|
+
io.err(INBOX_USAGE);
|
|
5791
|
+
return 2;
|
|
5792
|
+
}
|
|
5793
|
+
try {
|
|
5794
|
+
const nowSec = Math.floor((deps.now ?? Date.now)() / 1e3);
|
|
5795
|
+
const override = sinceArg !== void 0 ? parseSince(sinceArg, nowSec) : null;
|
|
5796
|
+
const me = (pubkeyArg ?? (await (deps.resolveIdentityImpl ?? resolveIdentity)({
|
|
5797
|
+
env: deps.env,
|
|
5798
|
+
cwd: deps.cwd,
|
|
5799
|
+
warn: (line) => io.err(line)
|
|
5800
|
+
})).pubkey).toLowerCase();
|
|
5801
|
+
let repoRoot;
|
|
5802
|
+
let toonRelays = [];
|
|
5803
|
+
try {
|
|
5804
|
+
repoRoot = await resolveRepoRoot(deps.cwd);
|
|
5805
|
+
toonRelays = (await readToonConfig(repoRoot)).relays;
|
|
5806
|
+
} catch {
|
|
5807
|
+
}
|
|
5808
|
+
const resolved = await resolveRelays({
|
|
5809
|
+
relayFlags,
|
|
5810
|
+
remoteName: remote,
|
|
5811
|
+
repoRoot,
|
|
5812
|
+
toonRelays
|
|
5813
|
+
});
|
|
5814
|
+
const configured = resolved.relays.filter((url) => WS_URL_RE.test(url));
|
|
5815
|
+
if (configured.length === 0) {
|
|
5816
|
+
throw new InvalidRelayUrlError(
|
|
5817
|
+
resolved.relays[0] ?? "",
|
|
5818
|
+
"reads need a ws:// or wss:// relay"
|
|
5819
|
+
);
|
|
5820
|
+
}
|
|
5821
|
+
const ws = deps.webSocketFactory ?? defaultWebSocketFactory;
|
|
5822
|
+
const announcements = await queryAll(
|
|
5823
|
+
configured,
|
|
5824
|
+
[
|
|
5825
|
+
{ kinds: [REPOSITORY_ANNOUNCEMENT_KIND3], authors: [me] },
|
|
5826
|
+
{ kinds: [REPOSITORY_ANNOUNCEMENT_KIND3], "#maintainers": [me] }
|
|
5827
|
+
],
|
|
5828
|
+
ws
|
|
5829
|
+
);
|
|
5830
|
+
const byRepo = /* @__PURE__ */ new Map();
|
|
5831
|
+
for (const e of announcements.values()) {
|
|
5832
|
+
if (e.kind !== REPOSITORY_ANNOUNCEMENT_KIND3) continue;
|
|
5833
|
+
const d = tagValue2(e.tags, "d");
|
|
5834
|
+
if (!d) continue;
|
|
5835
|
+
const key = `${e.pubkey.toLowerCase()}:${d}`;
|
|
5836
|
+
byRepo.set(key, [...byRepo.get(key) ?? [], e]);
|
|
5837
|
+
}
|
|
5838
|
+
const watched = [];
|
|
5839
|
+
for (const [key, events2] of byRepo) {
|
|
5840
|
+
const owner = events2[0].pubkey.toLowerCase();
|
|
5841
|
+
const repoId = key.slice(owner.length + 1);
|
|
5842
|
+
const latest = owner === me ? newest(events2) : await ownerAnnouncement(configured, owner, repoId, ws);
|
|
5843
|
+
if (latest === null) continue;
|
|
5844
|
+
if (owner !== me && !parseMaintainers(latest.tags).includes(me)) continue;
|
|
5845
|
+
watched.push({
|
|
5846
|
+
address: `${REPOSITORY_ANNOUNCEMENT_KIND3}:${owner}:${repoId}`,
|
|
5847
|
+
ownerPubkey: owner,
|
|
5848
|
+
authorized: authorizedAuthors(owner, latest.tags),
|
|
5849
|
+
relays: relaysTag(latest.tags)
|
|
5850
|
+
});
|
|
5851
|
+
}
|
|
5852
|
+
const cursor = readCursors(deps.env)[me];
|
|
5853
|
+
const since = all ? void 0 : override !== null ? override : cursor?.at;
|
|
5854
|
+
const base = since !== void 0 ? { since } : {};
|
|
5855
|
+
const events = /* @__PURE__ */ new Map();
|
|
5856
|
+
const collect = (found) => {
|
|
5857
|
+
for (const [id, e] of found) if (!events.has(id)) events.set(id, e);
|
|
5858
|
+
};
|
|
5859
|
+
collect(
|
|
5860
|
+
await queryAll(
|
|
5861
|
+
configured,
|
|
5862
|
+
[{ kinds: INBOX_KINDS, "#p": [me], ...base }],
|
|
5863
|
+
ws
|
|
5864
|
+
)
|
|
5865
|
+
);
|
|
5866
|
+
for (const repo of watched) {
|
|
5867
|
+
const relays = [.../* @__PURE__ */ new Set([...configured, ...repo.relays])];
|
|
5868
|
+
collect(
|
|
5869
|
+
await queryAll(
|
|
5870
|
+
relays,
|
|
5871
|
+
[{ kinds: INBOX_KINDS, "#a": [repo.address], ...base }],
|
|
5872
|
+
ws
|
|
5873
|
+
)
|
|
5874
|
+
);
|
|
5875
|
+
}
|
|
5876
|
+
const authCache = /* @__PURE__ */ new Map();
|
|
5877
|
+
for (const repo of watched) authCache.set(repo.address, repo.authorized);
|
|
5878
|
+
const authorizedFor = async (address) => {
|
|
5879
|
+
const hit = authCache.get(address);
|
|
5880
|
+
if (hit) return hit;
|
|
5881
|
+
const m = /^30617:([0-9a-f]{64}):(.+)$/i.exec(address);
|
|
5882
|
+
let set = /* @__PURE__ */ new Set();
|
|
5883
|
+
if (m) {
|
|
5884
|
+
const owner = m[1].toLowerCase();
|
|
5885
|
+
const latest = await ownerAnnouncement(
|
|
5886
|
+
configured,
|
|
5887
|
+
owner,
|
|
5888
|
+
m[2],
|
|
5889
|
+
ws
|
|
5890
|
+
);
|
|
5891
|
+
set = authorizedAuthors(owner, latest?.tags ?? []);
|
|
5892
|
+
}
|
|
5893
|
+
authCache.set(address, set);
|
|
5894
|
+
return set;
|
|
5895
|
+
};
|
|
5896
|
+
const toEntries = async (found) => {
|
|
5897
|
+
const targetAuthors = /* @__PURE__ */ new Map();
|
|
5898
|
+
const statusEvents = [...found.values()].filter(
|
|
5899
|
+
(e) => STATUS_KINDS2.includes(e.kind)
|
|
5900
|
+
);
|
|
5901
|
+
const unknownTargets = /* @__PURE__ */ new Set();
|
|
5902
|
+
for (const e of statusEvents) {
|
|
5903
|
+
const target = tagValue2(e.tags, "e");
|
|
5904
|
+
if (!target || !HEX64_RE4.test(target)) continue;
|
|
5905
|
+
const known = found.get(target);
|
|
5906
|
+
if (known) targetAuthors.set(target, known.pubkey.toLowerCase());
|
|
5907
|
+
else unknownTargets.add(target);
|
|
5908
|
+
}
|
|
5909
|
+
if (unknownTargets.size > 0) {
|
|
5910
|
+
const lookedUp = await queryAll(
|
|
5911
|
+
configured,
|
|
5912
|
+
[{ ids: [...unknownTargets] }],
|
|
5913
|
+
ws
|
|
5914
|
+
).catch(() => /* @__PURE__ */ new Map());
|
|
5915
|
+
for (const [id, e] of lookedUp)
|
|
5916
|
+
targetAuthors.set(id, e.pubkey.toLowerCase());
|
|
5917
|
+
}
|
|
5918
|
+
const entries = [];
|
|
5919
|
+
for (const event of found.values()) {
|
|
5920
|
+
const entry = toInboxEntry(event);
|
|
5921
|
+
if (entry === null) continue;
|
|
5922
|
+
if (entry.type === "status") {
|
|
5923
|
+
if (entry.repo === null) continue;
|
|
5924
|
+
const repoWide = await authorizedFor(entry.repo);
|
|
5925
|
+
const targetAuthor = targetAuthors.get(entry.target);
|
|
5926
|
+
const authors = targetAuthor === void 0 ? repoWide : withTargetAuthor(repoWide, targetAuthor);
|
|
5927
|
+
if (!authors.has(event.pubkey.toLowerCase())) continue;
|
|
5928
|
+
}
|
|
5929
|
+
entries.push(entry);
|
|
5930
|
+
}
|
|
5931
|
+
return entries;
|
|
5932
|
+
};
|
|
5933
|
+
const entriesOf = await toEntries(events);
|
|
5934
|
+
const isFresh = (e) => all || override !== null || cursor === void 0 || e.created_at > cursor.at || e.created_at === cursor.at && !cursor.seen.includes(e.id);
|
|
5935
|
+
const byAge = (a, b) => a.created_at - b.created_at || (a.id < b.id ? -1 : 1);
|
|
5936
|
+
const fresh = entriesOf.filter(isFresh).sort(byAge);
|
|
5937
|
+
const moveCursor = !all && override === null;
|
|
5938
|
+
let position = cursor;
|
|
5939
|
+
const advance = (emitted) => {
|
|
5940
|
+
if (!moveCursor || emitted.length === 0) return;
|
|
5941
|
+
const at = Math.max(...emitted.map((e) => e.created_at));
|
|
5942
|
+
const seen = emitted.filter((e) => e.created_at === at).map((e) => e.id);
|
|
5943
|
+
if (position?.at === at) seen.push(...position.seen);
|
|
5944
|
+
else if (position !== void 0 && position.at > at) return;
|
|
5945
|
+
position = { at, seen: [...new Set(seen)] };
|
|
5946
|
+
writeCursor(deps.env, me, position);
|
|
5947
|
+
};
|
|
5948
|
+
if (follow) {
|
|
5949
|
+
const line = (entry) => io.emitJsonLine ? io.emitJsonLine(entry) : io.out(JSON.stringify(entry));
|
|
5950
|
+
const emittedIds = /* @__PURE__ */ new Set();
|
|
5951
|
+
let liveSince = position?.at;
|
|
5952
|
+
const emit = (entries) => {
|
|
5953
|
+
for (const entry of entries) {
|
|
5954
|
+
emittedIds.add(entry.id);
|
|
5955
|
+
liveSince = Math.max(liveSince ?? 0, entry.created_at);
|
|
5956
|
+
line(entry);
|
|
5957
|
+
}
|
|
5958
|
+
advance(entries);
|
|
5959
|
+
};
|
|
5960
|
+
emit(fresh);
|
|
5961
|
+
const controller = new AbortController();
|
|
5962
|
+
const stop = () => controller.abort();
|
|
5963
|
+
const external = deps.followSignal;
|
|
5964
|
+
if (external?.aborted) return 0;
|
|
5965
|
+
external?.addEventListener("abort", stop);
|
|
5966
|
+
if (!external) {
|
|
5967
|
+
process.once("SIGINT", stop);
|
|
5968
|
+
process.once("SIGTERM", stop);
|
|
5969
|
+
}
|
|
5970
|
+
let chain = Promise.resolve();
|
|
5971
|
+
const onEvent = (event) => {
|
|
5972
|
+
chain = chain.then(async () => {
|
|
5973
|
+
if (emittedIds.has(event.id)) return;
|
|
5974
|
+
try {
|
|
5975
|
+
const [entry] = await toEntries(/* @__PURE__ */ new Map([[event.id, event]]));
|
|
5976
|
+
if (entry === void 0 || emittedIds.has(entry.id) || !isFresh(entry)) {
|
|
5977
|
+
return;
|
|
5978
|
+
}
|
|
5979
|
+
emit([entry]);
|
|
5980
|
+
} catch (err) {
|
|
5981
|
+
io.err(
|
|
5982
|
+
`rig inbox: could not process live event ${event.id}: ${err instanceof Error ? err.message : String(err)}`
|
|
5983
|
+
);
|
|
5984
|
+
}
|
|
5985
|
+
});
|
|
5986
|
+
};
|
|
5987
|
+
const targets = [];
|
|
5988
|
+
for (const url of configured) {
|
|
5989
|
+
targets.push({ url, filter: { kinds: INBOX_KINDS, "#p": [me] } });
|
|
5990
|
+
}
|
|
5991
|
+
for (const repo of watched) {
|
|
5992
|
+
for (const url of /* @__PURE__ */ new Set([...configured, ...repo.relays])) {
|
|
5993
|
+
targets.push({
|
|
5994
|
+
url,
|
|
5995
|
+
filter: { kinds: INBOX_KINDS, "#a": [repo.address] }
|
|
5996
|
+
});
|
|
5997
|
+
}
|
|
5998
|
+
}
|
|
5999
|
+
const urls = [...new Set(targets.map((t) => t.url))];
|
|
6000
|
+
try {
|
|
6001
|
+
await Promise.all(
|
|
6002
|
+
urls.map(
|
|
6003
|
+
(url) => followRelay({
|
|
6004
|
+
url,
|
|
6005
|
+
filters: () => targets.filter((t) => t.url === url).map((t) => ({ ...t.filter, since: liveSince ?? nowSec })),
|
|
6006
|
+
webSocketFactory: ws,
|
|
6007
|
+
onEvent,
|
|
6008
|
+
onError: (message) => io.err(`rig inbox: ${message}`),
|
|
6009
|
+
signal: controller.signal,
|
|
6010
|
+
backoffMs: deps.followBackoffMs ?? defaultBackoffMs
|
|
6011
|
+
})
|
|
6012
|
+
)
|
|
6013
|
+
);
|
|
6014
|
+
await chain;
|
|
6015
|
+
} finally {
|
|
6016
|
+
external?.removeEventListener("abort", stop);
|
|
6017
|
+
process.off("SIGINT", stop);
|
|
6018
|
+
process.off("SIGTERM", stop);
|
|
6019
|
+
}
|
|
6020
|
+
return 0;
|
|
6021
|
+
}
|
|
6022
|
+
if (json) {
|
|
6023
|
+
io.emitJson(fresh);
|
|
6024
|
+
} else if (fresh.length === 0) {
|
|
6025
|
+
io.out("inbox is empty");
|
|
6026
|
+
} else {
|
|
6027
|
+
for (const entry of fresh) io.out(renderLine(entry));
|
|
6028
|
+
}
|
|
6029
|
+
advance(fresh);
|
|
6030
|
+
return 0;
|
|
6031
|
+
} catch (err) {
|
|
6032
|
+
return emitCliError(io, json, "inbox", err);
|
|
6033
|
+
}
|
|
6034
|
+
}
|
|
6035
|
+
|
|
5257
6036
|
// src/cli/init.ts
|
|
5258
6037
|
import { basename as basename2 } from "path";
|
|
5259
|
-
import { parseArgs as
|
|
6038
|
+
import { parseArgs as parseArgs14 } from "util";
|
|
5260
6039
|
|
|
5261
6040
|
// src/cli/git-author.ts
|
|
5262
6041
|
var PROFILE_KIND = 0;
|
|
@@ -5374,7 +6153,7 @@ Options:
|
|
|
5374
6153
|
--json machine-readable report
|
|
5375
6154
|
-h, --help show this help`;
|
|
5376
6155
|
function parseInitArgs(args) {
|
|
5377
|
-
const { values, positionals } =
|
|
6156
|
+
const { values, positionals } = parseArgs14({
|
|
5378
6157
|
args,
|
|
5379
6158
|
options: {
|
|
5380
6159
|
"repo-id": { type: "string" },
|
|
@@ -5601,8 +6380,9 @@ async function runInit(args, deps) {
|
|
|
5601
6380
|
}
|
|
5602
6381
|
|
|
5603
6382
|
// src/cli/maintainers.ts
|
|
5604
|
-
import { parseArgs as
|
|
5605
|
-
var
|
|
6383
|
+
import { parseArgs as parseArgs15 } from "util";
|
|
6384
|
+
var HEX64_RE5 = /^[0-9a-f]{64}$/;
|
|
6385
|
+
var REF_AUTHORITY_NOTICE = "Note: maintainers can move refs (publish honored repo state), not only set status.";
|
|
5606
6386
|
var MAINTAINERS_USAGE = `Usage: rig maintainers <list|add|remove> [<pubkey>] [options]
|
|
5607
6387
|
|
|
5608
6388
|
Manage a repo's declared maintainers (#287). Status authority is consumer-side:
|
|
@@ -5654,7 +6434,7 @@ async function runList2(args, deps) {
|
|
|
5654
6434
|
const { io } = deps;
|
|
5655
6435
|
let flags;
|
|
5656
6436
|
try {
|
|
5657
|
-
const { values, positionals } =
|
|
6437
|
+
const { values, positionals } = parseArgs15({
|
|
5658
6438
|
args,
|
|
5659
6439
|
options: REPO_COMMAND_OPTIONS,
|
|
5660
6440
|
allowPositionals: true
|
|
@@ -5721,7 +6501,7 @@ async function runMutate(op, args, deps) {
|
|
|
5721
6501
|
let flags;
|
|
5722
6502
|
let pubkey;
|
|
5723
6503
|
try {
|
|
5724
|
-
const { values, positionals } =
|
|
6504
|
+
const { values, positionals } = parseArgs15({
|
|
5725
6505
|
args,
|
|
5726
6506
|
options: REPO_COMMAND_OPTIONS,
|
|
5727
6507
|
allowPositionals: true
|
|
@@ -5735,8 +6515,10 @@ async function runMutate(op, args, deps) {
|
|
|
5735
6515
|
throw new Error(`expected exactly one <pubkey> to ${op}`);
|
|
5736
6516
|
}
|
|
5737
6517
|
pubkey = ownerToHex(positionals[0]).toLowerCase();
|
|
5738
|
-
if (!
|
|
5739
|
-
throw new Error(
|
|
6518
|
+
if (!HEX64_RE5.test(pubkey)) {
|
|
6519
|
+
throw new Error(
|
|
6520
|
+
`<pubkey> must resolve to 64-char hex (got ${JSON.stringify(positionals[0])})`
|
|
6521
|
+
);
|
|
5740
6522
|
}
|
|
5741
6523
|
} catch (err) {
|
|
5742
6524
|
io.err(err instanceof Error ? err.message : String(err));
|
|
@@ -5781,11 +6563,14 @@ async function runMutate(op, args, deps) {
|
|
|
5781
6563
|
if (!flags.json) {
|
|
5782
6564
|
io.out(`Republish ${action}`);
|
|
5783
6565
|
io.out(`Repo: 30617:${ctx.owner}:${ctx.repoId}`);
|
|
5784
|
-
io.out(
|
|
6566
|
+
io.out(
|
|
6567
|
+
`Maintainers after: ${next.length === 0 ? "(none)" : next.join(", ")}`
|
|
6568
|
+
);
|
|
5785
6569
|
if (!diff.unchanged) {
|
|
5786
6570
|
io.out("Tags changed:");
|
|
5787
6571
|
for (const line of describeAnnouncementDiff(diff)) io.out(line);
|
|
5788
6572
|
}
|
|
6573
|
+
io.out(REF_AUTHORITY_NOTICE);
|
|
5789
6574
|
io.out(`Fee: ${feeLabel(fee)}. Writes are permanent and non-refundable.`);
|
|
5790
6575
|
}
|
|
5791
6576
|
if (!flags.yes) {
|
|
@@ -5835,6 +6620,7 @@ async function runMutate(op, args, deps) {
|
|
|
5835
6620
|
io.out(
|
|
5836
6621
|
`Published ${action}: ${result.eventId} paid ${result.feePaid} base units`
|
|
5837
6622
|
);
|
|
6623
|
+
io.out(REF_AUTHORITY_NOTICE);
|
|
5838
6624
|
}
|
|
5839
6625
|
return 0;
|
|
5840
6626
|
} catch (err) {
|
|
@@ -5850,7 +6636,7 @@ async function runMutate(op, args, deps) {
|
|
|
5850
6636
|
}
|
|
5851
6637
|
|
|
5852
6638
|
// src/cli/refresh.ts
|
|
5853
|
-
import { parseArgs as
|
|
6639
|
+
import { parseArgs as parseArgs16 } from "util";
|
|
5854
6640
|
var REFRESH_USAGE = `Usage: rig refresh [options]
|
|
5855
6641
|
|
|
5856
6642
|
Republish this repo's kind:30617 announcement with no field edit, refreshing
|
|
@@ -5886,7 +6672,7 @@ async function runRefresh(args, deps) {
|
|
|
5886
6672
|
const { io } = deps;
|
|
5887
6673
|
let flags;
|
|
5888
6674
|
try {
|
|
5889
|
-
const { values, positionals } =
|
|
6675
|
+
const { values, positionals } = parseArgs16({
|
|
5890
6676
|
args,
|
|
5891
6677
|
options: REPO_COMMAND_OPTIONS,
|
|
5892
6678
|
allowPositionals: true
|
|
@@ -6009,7 +6795,7 @@ async function runRefresh(args, deps) {
|
|
|
6009
6795
|
|
|
6010
6796
|
// src/cli/name.ts
|
|
6011
6797
|
import { randomUUID } from "crypto";
|
|
6012
|
-
import { parseArgs as
|
|
6798
|
+
import { parseArgs as parseArgs17 } from "util";
|
|
6013
6799
|
var ARIO_DECIMALS = 6;
|
|
6014
6800
|
function renderMario(mario) {
|
|
6015
6801
|
return `${mario.toString()} mARIO (~${formatUnits(mario.toString(), ARIO_DECIMALS)} ARIO)`;
|
|
@@ -6518,7 +7304,7 @@ async function resolveNameContext(deps, network, processId, mode) {
|
|
|
6518
7304
|
return { identity, solanaAddress, network, processId, sdk, nostrSecretKey };
|
|
6519
7305
|
}
|
|
6520
7306
|
function parseNameFlags(args, env) {
|
|
6521
|
-
const { values, positionals } =
|
|
7307
|
+
const { values, positionals } = parseArgs17({
|
|
6522
7308
|
args,
|
|
6523
7309
|
allowPositionals: true,
|
|
6524
7310
|
options: {
|
|
@@ -7077,7 +7863,7 @@ async function runName(args, deps) {
|
|
|
7077
7863
|
}
|
|
7078
7864
|
|
|
7079
7865
|
// src/cli/payout.ts
|
|
7080
|
-
import { parseArgs as
|
|
7866
|
+
import { parseArgs as parseArgs18 } from "util";
|
|
7081
7867
|
import { getAddress } from "viem";
|
|
7082
7868
|
var PAYOUT_USAGE = `Usage: rig payout <set|clear|show> [<address>] [options]
|
|
7083
7869
|
|
|
@@ -7133,7 +7919,7 @@ async function runShow2(args, deps) {
|
|
|
7133
7919
|
const { io } = deps;
|
|
7134
7920
|
let flags;
|
|
7135
7921
|
try {
|
|
7136
|
-
const { values, positionals } =
|
|
7922
|
+
const { values, positionals } = parseArgs18({
|
|
7137
7923
|
args,
|
|
7138
7924
|
options: REPO_COMMAND_OPTIONS,
|
|
7139
7925
|
allowPositionals: true
|
|
@@ -7195,7 +7981,7 @@ async function runMutate2(op, args, deps) {
|
|
|
7195
7981
|
let flags;
|
|
7196
7982
|
let nextPayout = null;
|
|
7197
7983
|
try {
|
|
7198
|
-
const { values, positionals } =
|
|
7984
|
+
const { values, positionals } = parseArgs18({
|
|
7199
7985
|
args,
|
|
7200
7986
|
options: REPO_COMMAND_OPTIONS,
|
|
7201
7987
|
allowPositionals: true
|
|
@@ -7329,7 +8115,7 @@ async function runMutate2(op, args, deps) {
|
|
|
7329
8115
|
}
|
|
7330
8116
|
|
|
7331
8117
|
// src/cli/site.ts
|
|
7332
|
-
import { parseArgs as
|
|
8118
|
+
import { parseArgs as parseArgs19 } from "util";
|
|
7333
8119
|
|
|
7334
8120
|
// src/arweave-manifest.ts
|
|
7335
8121
|
var DEFAULT_INDEX = "index.html";
|
|
@@ -7348,22 +8134,22 @@ function buildArweaveManifest(entries, indexPath = DEFAULT_INDEX, fallbackTxId)
|
|
|
7348
8134
|
}
|
|
7349
8135
|
|
|
7350
8136
|
// src/cli/site-record.ts
|
|
7351
|
-
import { mkdirSync as
|
|
8137
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
7352
8138
|
import { homedir as homedir5 } from "os";
|
|
7353
|
-
import { join as
|
|
8139
|
+
import { join as join7 } from "path";
|
|
7354
8140
|
var SITE_MANIFEST_FILENAME = "site-manifests.json";
|
|
7355
8141
|
function storeDir2(env) {
|
|
7356
|
-
return env["TOON_CLIENT_HOME"] ??
|
|
8142
|
+
return env["TOON_CLIENT_HOME"] ?? join7(homedir5(), ".toon-client");
|
|
7357
8143
|
}
|
|
7358
8144
|
function storePath2(env) {
|
|
7359
|
-
return
|
|
8145
|
+
return join7(storeDir2(env), SITE_MANIFEST_FILENAME);
|
|
7360
8146
|
}
|
|
7361
8147
|
function keyOf(repoId, ref) {
|
|
7362
8148
|
return `${repoId}\0${ref}`;
|
|
7363
8149
|
}
|
|
7364
8150
|
function readFile2(env) {
|
|
7365
8151
|
try {
|
|
7366
|
-
const parsed = JSON.parse(
|
|
8152
|
+
const parsed = JSON.parse(readFileSync6(storePath2(env), "utf8"));
|
|
7367
8153
|
if (parsed && typeof parsed === "object") return parsed;
|
|
7368
8154
|
return {};
|
|
7369
8155
|
} catch {
|
|
@@ -7375,10 +8161,10 @@ function readSiteRecord(env, repoId, ref) {
|
|
|
7375
8161
|
}
|
|
7376
8162
|
function writeSiteRecord(env, record) {
|
|
7377
8163
|
const dir = storeDir2(env);
|
|
7378
|
-
|
|
8164
|
+
mkdirSync6(dir, { recursive: true });
|
|
7379
8165
|
const file = readFile2(env);
|
|
7380
8166
|
file[keyOf(record.repoId, record.ref)] = record;
|
|
7381
|
-
|
|
8167
|
+
writeFileSync5(storePath2(env), `${JSON.stringify(file, null, 2)}
|
|
7382
8168
|
`, "utf8");
|
|
7383
8169
|
}
|
|
7384
8170
|
|
|
@@ -7420,7 +8206,7 @@ Options (publish):
|
|
|
7420
8206
|
estimate (nothing uploaded)
|
|
7421
8207
|
-h, --help show this help`;
|
|
7422
8208
|
function parseSiteArgs(args) {
|
|
7423
|
-
const { values, positionals } =
|
|
8209
|
+
const { values, positionals } = parseArgs19({
|
|
7424
8210
|
args,
|
|
7425
8211
|
options: {
|
|
7426
8212
|
index: { type: "string" },
|
|
@@ -7821,14 +8607,23 @@ Commands rig owns:
|
|
|
7821
8607
|
site url [ref] print the last-published site URL for a ref (free)
|
|
7822
8608
|
issue create file an issue (kind:1621) against a repo
|
|
7823
8609
|
issue list | show <id> read the repo's issues + comments (free)
|
|
8610
|
+
issue status <id> <open|closed> set an issue's status (kind:1630/1632);
|
|
8611
|
+
close | reopen <id> are shortcuts
|
|
7824
8612
|
pr list | show <id> read the repo's patches; show prints the full
|
|
7825
8613
|
patch text (free)
|
|
7826
8614
|
comment <target-event-id> comment (NIP-22 kind:1111) on an issue or patch,
|
|
7827
8615
|
or reply to an existing kind:1111 comment
|
|
7828
8616
|
pr create publish a patch (kind:1617) with real
|
|
7829
|
-
\`git format-patch\` content
|
|
8617
|
+
\`git format-patch\` content (--revises <patch-id>
|
|
8618
|
+
publishes a revision of an existing patch)
|
|
7830
8619
|
pr status <event-id> <state> set an issue/patch status (kind:1630-1633):
|
|
7831
8620
|
open | applied | closed | draft
|
|
8621
|
+
inbox everything new since you last read it (free):
|
|
8622
|
+
patches, revisions, issues, comments, statuses
|
|
8623
|
+
and CI results for repos you own or maintain,
|
|
8624
|
+
plus events that tag you; --since/--all look
|
|
8625
|
+
back without moving the cursor; --follow keeps
|
|
8626
|
+
streaming new events as JSON lines
|
|
7832
8627
|
maintainers list show the repo's declared maintainers (free); add/
|
|
7833
8628
|
maintainers add <pubkey> remove republish the kind:30617 to change who may
|
|
7834
8629
|
maintainers remove <pubkey> author authoritative issue/PR status (owner is
|
|
@@ -7889,7 +8684,8 @@ Any other command is passed through to git verbatim: \`rig status\` runs
|
|
|
7889
8684
|
Run \`rig <command> --help\` for a rig command's flags. \`rig init\`,
|
|
7890
8685
|
\`rig remote\`, \`rig clone\`, \`rig fetch\`, \`rig issue list/show\`,
|
|
7891
8686
|
\`rig pr list/show\`, \`rig fund\`, \`rig balance\`, and \`rig channel list\`
|
|
7892
|
-
are free; push/issue create/comment/pr create/pr
|
|
8687
|
+
are free; push/issue create/issue status/close/reopen/comment/pr create/pr
|
|
8688
|
+
status are paid writes \u2014
|
|
7893
8689
|
permanent and non-refundable \u2014
|
|
7894
8690
|
and channel open/close/settle are on-chain wallet transactions; each states
|
|
7895
8691
|
what it will spend and asks for confirmation before doing so (--yes skips,
|
|
@@ -7950,6 +8746,8 @@ async function dispatch(argv, deps) {
|
|
|
7950
8746
|
return runComment(rest, deps);
|
|
7951
8747
|
case "pr":
|
|
7952
8748
|
return runPr(rest, deps);
|
|
8749
|
+
case "inbox":
|
|
8750
|
+
return runInbox(rest, deps);
|
|
7953
8751
|
case "maintainers":
|
|
7954
8752
|
return runMaintainers(rest, deps);
|
|
7955
8753
|
case "payout":
|
|
@@ -8006,4 +8804,4 @@ export {
|
|
|
8006
8804
|
rigVersion,
|
|
8007
8805
|
dispatch
|
|
8008
8806
|
};
|
|
8009
|
-
//# sourceMappingURL=chunk-
|
|
8807
|
+
//# sourceMappingURL=chunk-Y7TUE7JT.js.map
|