@toon-protocol/rig 5.1.0 → 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.
@@ -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,13 +57,13 @@ import {
52
57
  updateRef,
53
58
  writeGitObjects,
54
59
  writeToonConfig
55
- } from "./chunk-J6GNB54J.js";
60
+ } from "./chunk-S5R44MMB.js";
56
61
  import {
57
62
  PREFERRED_GATEWAY,
58
63
  mirrorGatewaysFor,
59
64
  readGateways,
60
65
  shaResolverFor
61
- } from "./chunk-P5ZKJN6B.js";
66
+ } from "./chunk-FX5GPZYU.js";
62
67
  import {
63
68
  COMMENT_KIND,
64
69
  DEFAULT_KEYSTORE_PASSWORD,
@@ -71,18 +76,23 @@ import {
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
- } from "./chunk-ITC7ESTZ.js";
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-IETLYVCE.js");
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
- if (toonConfig.owner && toonConfig.owner !== identity.pubkey) {
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 (${toonConfig.owner.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.`
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-MPJ2WPCC.js")).runCiServe(rest, deps);
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,
@@ -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(
@@ -3105,15 +3139,48 @@ async function fetchItem(ctx, eventId, expectedKind) {
3105
3139
  parsedAddr.ownerPubkey,
3106
3140
  parsedAddr.repoId
3107
3141
  ) : /* @__PURE__ */ new Set();
3108
- return {
3109
- item: parseTrackerItem(
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(
3110
3158
  event,
3111
- deriveStatus(
3112
- eventId,
3113
- statusEvents.values(),
3114
- withTargetAuthor(authorized, event.pubkey)
3115
- )
3116
- ),
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 } : {},
3117
3184
  comments,
3118
3185
  repoATag: repoATag2
3119
3186
  };
@@ -3229,6 +3296,10 @@ async function runShow(args, deps, spec) {
3229
3296
  relays: ctx.relays,
3230
3297
  repoATag: shown.repoATag,
3231
3298
  [spec.jsonKey]: shown.item,
3299
+ ...shown.revisions ? {
3300
+ latestRevision: shown.revisions.latest,
3301
+ earlierRevisions: shown.revisions.earlier
3302
+ } : {},
3232
3303
  comments: shown.comments
3233
3304
  });
3234
3305
  return 0;
@@ -3245,6 +3316,20 @@ async function runShow(args, deps, spec) {
3245
3316
  io.out(`Commits: ${item.commitShas.join(", ")}`);
3246
3317
  }
3247
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
+ }
3248
3333
  if (item.description !== void 0) {
3249
3334
  io.out("");
3250
3335
  io.out("Body:");
@@ -3372,7 +3457,7 @@ comments published by this version.
3372
3457
  Options:
3373
3458
  --body <text> comment body (Markdown) [required]
3374
3459
  ${COMMON_FLAGS_USAGE2}`;
3375
- 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]
3376
3461
 
3377
3462
  Publish a patch (kind:1617) whose content is REAL \`git format-patch\` output \u2014
3378
3463
  a paid publish; writes are permanent and non-refundable. --range runs
@@ -3386,6 +3471,12 @@ The PR body (--body/--body-file) is carried in a dedicated \`description\`
3386
3471
  tag, not in the event content \u2014 the content stays pure format-patch output so
3387
3472
  \`rig pr show \u2026 | git am\` keeps working.
3388
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
+
3389
3480
  Options:
3390
3481
  --title <title> patch/PR title (subject tag) [required]
3391
3482
  --range <range> revision range for format-patch: <rev>, <rev>..<rev>,
@@ -3394,6 +3485,7 @@ Options:
3394
3485
  --body <text> PR description (Markdown; description tag)
3395
3486
  --body-file <path> read the PR description from a file
3396
3487
  --branch <name> branch name (branch-name tag)
3488
+ --revises <patch-id> publish as a revision of this root patch (64-hex id)
3397
3489
  ${COMMON_FLAGS_USAGE2}`;
3398
3490
  var PR_STATUS_USAGE = `Usage: rig pr status <target-event-id> <open|applied|closed|draft> [options]
3399
3491
 
@@ -3845,6 +3937,69 @@ async function runPr(args, deps) {
3845
3937
  return 2;
3846
3938
  }
3847
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
+ }
3848
4003
  async function runPrCreate(rest, deps) {
3849
4004
  const { io } = deps;
3850
4005
  let flags;
@@ -3854,6 +4009,7 @@ async function runPrCreate(rest, deps) {
3854
4009
  let branch;
3855
4010
  let bodyFlag;
3856
4011
  let bodyFile;
4012
+ let revises;
3857
4013
  try {
3858
4014
  const { values } = parseArgs8({
3859
4015
  args: rest,
@@ -3864,7 +4020,8 @@ async function runPrCreate(rest, deps) {
3864
4020
  "patch-file": { type: "string" },
3865
4021
  body: { type: "string" },
3866
4022
  "body-file": { type: "string" },
3867
- branch: { type: "string" }
4023
+ branch: { type: "string" },
4024
+ revises: { type: "string" }
3868
4025
  },
3869
4026
  allowPositionals: false
3870
4027
  });
@@ -3888,6 +4045,11 @@ async function runPrCreate(rest, deps) {
3888
4045
  branch = values.branch;
3889
4046
  bodyFlag = values.body;
3890
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
+ }
3891
4053
  } catch (err) {
3892
4054
  io.err(err instanceof Error ? err.message : String(err));
3893
4055
  io.err(PR_CREATE_USAGE);
@@ -3912,12 +4074,16 @@ async function runPrCreate(rest, deps) {
3912
4074
  }
3913
4075
  let builtPatchText;
3914
4076
  let builtCommits = [];
4077
+ let rootAuthor;
3915
4078
  return runEvent({
3916
4079
  command: "pr",
3917
4080
  flags,
3918
4081
  deps,
3919
4082
  actionLabel: `patch ${JSON.stringify(title)}`,
3920
- buildEvent: async (addr) => {
4083
+ buildEvent: async (addr, relayUrl) => {
4084
+ if (revises !== void 0) {
4085
+ rootAuthor = (await resolveRevisedRoot(deps, revises, relayUrl, addr)).pubkey;
4086
+ }
3921
4087
  let patchText;
3922
4088
  let commits;
3923
4089
  if (range !== void 0) {
@@ -3952,9 +4118,16 @@ async function runPrCreate(rest, deps) {
3952
4118
  commits,
3953
4119
  branch,
3954
4120
  patchText,
3955
- body
4121
+ body,
4122
+ revises !== void 0 ? {
4123
+ rootEventId: revises,
4124
+ ...rootAuthor !== void 0 ? { rootAuthorPubkey: rootAuthor } : {}
4125
+ } : void 0
3956
4126
  );
3957
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),
3958
4131
  sendDaemon: (client, addr) => {
3959
4132
  if (builtPatchText === void 0) {
3960
4133
  throw new Error("internal: patch text not built before delegation");
@@ -5300,9 +5473,569 @@ async function defaultReadSecretLine(prompt, isInteractive) {
5300
5473
  }
5301
5474
  }
5302
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
+
5303
6036
  // src/cli/init.ts
5304
6037
  import { basename as basename2 } from "path";
5305
- import { parseArgs as parseArgs13 } from "util";
6038
+ import { parseArgs as parseArgs14 } from "util";
5306
6039
 
5307
6040
  // src/cli/git-author.ts
5308
6041
  var PROFILE_KIND = 0;
@@ -5420,7 +6153,7 @@ Options:
5420
6153
  --json machine-readable report
5421
6154
  -h, --help show this help`;
5422
6155
  function parseInitArgs(args) {
5423
- const { values, positionals } = parseArgs13({
6156
+ const { values, positionals } = parseArgs14({
5424
6157
  args,
5425
6158
  options: {
5426
6159
  "repo-id": { type: "string" },
@@ -5647,8 +6380,8 @@ async function runInit(args, deps) {
5647
6380
  }
5648
6381
 
5649
6382
  // src/cli/maintainers.ts
5650
- import { parseArgs as parseArgs14 } from "util";
5651
- var HEX64_RE4 = /^[0-9a-f]{64}$/;
6383
+ import { parseArgs as parseArgs15 } from "util";
6384
+ var HEX64_RE5 = /^[0-9a-f]{64}$/;
5652
6385
  var REF_AUTHORITY_NOTICE = "Note: maintainers can move refs (publish honored repo state), not only set status.";
5653
6386
  var MAINTAINERS_USAGE = `Usage: rig maintainers <list|add|remove> [<pubkey>] [options]
5654
6387
 
@@ -5701,7 +6434,7 @@ async function runList2(args, deps) {
5701
6434
  const { io } = deps;
5702
6435
  let flags;
5703
6436
  try {
5704
- const { values, positionals } = parseArgs14({
6437
+ const { values, positionals } = parseArgs15({
5705
6438
  args,
5706
6439
  options: REPO_COMMAND_OPTIONS,
5707
6440
  allowPositionals: true
@@ -5768,7 +6501,7 @@ async function runMutate(op, args, deps) {
5768
6501
  let flags;
5769
6502
  let pubkey;
5770
6503
  try {
5771
- const { values, positionals } = parseArgs14({
6504
+ const { values, positionals } = parseArgs15({
5772
6505
  args,
5773
6506
  options: REPO_COMMAND_OPTIONS,
5774
6507
  allowPositionals: true
@@ -5782,7 +6515,7 @@ async function runMutate(op, args, deps) {
5782
6515
  throw new Error(`expected exactly one <pubkey> to ${op}`);
5783
6516
  }
5784
6517
  pubkey = ownerToHex(positionals[0]).toLowerCase();
5785
- if (!HEX64_RE4.test(pubkey)) {
6518
+ if (!HEX64_RE5.test(pubkey)) {
5786
6519
  throw new Error(
5787
6520
  `<pubkey> must resolve to 64-char hex (got ${JSON.stringify(positionals[0])})`
5788
6521
  );
@@ -5903,7 +6636,7 @@ async function runMutate(op, args, deps) {
5903
6636
  }
5904
6637
 
5905
6638
  // src/cli/refresh.ts
5906
- import { parseArgs as parseArgs15 } from "util";
6639
+ import { parseArgs as parseArgs16 } from "util";
5907
6640
  var REFRESH_USAGE = `Usage: rig refresh [options]
5908
6641
 
5909
6642
  Republish this repo's kind:30617 announcement with no field edit, refreshing
@@ -5939,7 +6672,7 @@ async function runRefresh(args, deps) {
5939
6672
  const { io } = deps;
5940
6673
  let flags;
5941
6674
  try {
5942
- const { values, positionals } = parseArgs15({
6675
+ const { values, positionals } = parseArgs16({
5943
6676
  args,
5944
6677
  options: REPO_COMMAND_OPTIONS,
5945
6678
  allowPositionals: true
@@ -6062,7 +6795,7 @@ async function runRefresh(args, deps) {
6062
6795
 
6063
6796
  // src/cli/name.ts
6064
6797
  import { randomUUID } from "crypto";
6065
- import { parseArgs as parseArgs16 } from "util";
6798
+ import { parseArgs as parseArgs17 } from "util";
6066
6799
  var ARIO_DECIMALS = 6;
6067
6800
  function renderMario(mario) {
6068
6801
  return `${mario.toString()} mARIO (~${formatUnits(mario.toString(), ARIO_DECIMALS)} ARIO)`;
@@ -6571,7 +7304,7 @@ async function resolveNameContext(deps, network, processId, mode) {
6571
7304
  return { identity, solanaAddress, network, processId, sdk, nostrSecretKey };
6572
7305
  }
6573
7306
  function parseNameFlags(args, env) {
6574
- const { values, positionals } = parseArgs16({
7307
+ const { values, positionals } = parseArgs17({
6575
7308
  args,
6576
7309
  allowPositionals: true,
6577
7310
  options: {
@@ -7130,7 +7863,7 @@ async function runName(args, deps) {
7130
7863
  }
7131
7864
 
7132
7865
  // src/cli/payout.ts
7133
- import { parseArgs as parseArgs17 } from "util";
7866
+ import { parseArgs as parseArgs18 } from "util";
7134
7867
  import { getAddress } from "viem";
7135
7868
  var PAYOUT_USAGE = `Usage: rig payout <set|clear|show> [<address>] [options]
7136
7869
 
@@ -7186,7 +7919,7 @@ async function runShow2(args, deps) {
7186
7919
  const { io } = deps;
7187
7920
  let flags;
7188
7921
  try {
7189
- const { values, positionals } = parseArgs17({
7922
+ const { values, positionals } = parseArgs18({
7190
7923
  args,
7191
7924
  options: REPO_COMMAND_OPTIONS,
7192
7925
  allowPositionals: true
@@ -7248,7 +7981,7 @@ async function runMutate2(op, args, deps) {
7248
7981
  let flags;
7249
7982
  let nextPayout = null;
7250
7983
  try {
7251
- const { values, positionals } = parseArgs17({
7984
+ const { values, positionals } = parseArgs18({
7252
7985
  args,
7253
7986
  options: REPO_COMMAND_OPTIONS,
7254
7987
  allowPositionals: true
@@ -7382,7 +8115,7 @@ async function runMutate2(op, args, deps) {
7382
8115
  }
7383
8116
 
7384
8117
  // src/cli/site.ts
7385
- import { parseArgs as parseArgs18 } from "util";
8118
+ import { parseArgs as parseArgs19 } from "util";
7386
8119
 
7387
8120
  // src/arweave-manifest.ts
7388
8121
  var DEFAULT_INDEX = "index.html";
@@ -7401,22 +8134,22 @@ function buildArweaveManifest(entries, indexPath = DEFAULT_INDEX, fallbackTxId)
7401
8134
  }
7402
8135
 
7403
8136
  // src/cli/site-record.ts
7404
- import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
8137
+ import { mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
7405
8138
  import { homedir as homedir5 } from "os";
7406
- import { join as join6 } from "path";
8139
+ import { join as join7 } from "path";
7407
8140
  var SITE_MANIFEST_FILENAME = "site-manifests.json";
7408
8141
  function storeDir2(env) {
7409
- return env["TOON_CLIENT_HOME"] ?? join6(homedir5(), ".toon-client");
8142
+ return env["TOON_CLIENT_HOME"] ?? join7(homedir5(), ".toon-client");
7410
8143
  }
7411
8144
  function storePath2(env) {
7412
- return join6(storeDir2(env), SITE_MANIFEST_FILENAME);
8145
+ return join7(storeDir2(env), SITE_MANIFEST_FILENAME);
7413
8146
  }
7414
8147
  function keyOf(repoId, ref) {
7415
8148
  return `${repoId}\0${ref}`;
7416
8149
  }
7417
8150
  function readFile2(env) {
7418
8151
  try {
7419
- const parsed = JSON.parse(readFileSync5(storePath2(env), "utf8"));
8152
+ const parsed = JSON.parse(readFileSync6(storePath2(env), "utf8"));
7420
8153
  if (parsed && typeof parsed === "object") return parsed;
7421
8154
  return {};
7422
8155
  } catch {
@@ -7428,10 +8161,10 @@ function readSiteRecord(env, repoId, ref) {
7428
8161
  }
7429
8162
  function writeSiteRecord(env, record) {
7430
8163
  const dir = storeDir2(env);
7431
- mkdirSync5(dir, { recursive: true });
8164
+ mkdirSync6(dir, { recursive: true });
7432
8165
  const file = readFile2(env);
7433
8166
  file[keyOf(record.repoId, record.ref)] = record;
7434
- writeFileSync4(storePath2(env), `${JSON.stringify(file, null, 2)}
8167
+ writeFileSync5(storePath2(env), `${JSON.stringify(file, null, 2)}
7435
8168
  `, "utf8");
7436
8169
  }
7437
8170
 
@@ -7473,7 +8206,7 @@ Options (publish):
7473
8206
  estimate (nothing uploaded)
7474
8207
  -h, --help show this help`;
7475
8208
  function parseSiteArgs(args) {
7476
- const { values, positionals } = parseArgs18({
8209
+ const { values, positionals } = parseArgs19({
7477
8210
  args,
7478
8211
  options: {
7479
8212
  index: { type: "string" },
@@ -7881,9 +8614,16 @@ Commands rig owns:
7881
8614
  comment <target-event-id> comment (NIP-22 kind:1111) on an issue or patch,
7882
8615
  or reply to an existing kind:1111 comment
7883
8616
  pr create publish a patch (kind:1617) with real
7884
- \`git format-patch\` content
8617
+ \`git format-patch\` content (--revises <patch-id>
8618
+ publishes a revision of an existing patch)
7885
8619
  pr status <event-id> <state> set an issue/patch status (kind:1630-1633):
7886
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
7887
8627
  maintainers list show the repo's declared maintainers (free); add/
7888
8628
  maintainers add <pubkey> remove republish the kind:30617 to change who may
7889
8629
  maintainers remove <pubkey> author authoritative issue/PR status (owner is
@@ -8006,6 +8746,8 @@ async function dispatch(argv, deps) {
8006
8746
  return runComment(rest, deps);
8007
8747
  case "pr":
8008
8748
  return runPr(rest, deps);
8749
+ case "inbox":
8750
+ return runInbox(rest, deps);
8009
8751
  case "maintainers":
8010
8752
  return runMaintainers(rest, deps);
8011
8753
  case "payout":
@@ -8062,4 +8804,4 @@ export {
8062
8804
  rigVersion,
8063
8805
  dispatch
8064
8806
  };
8065
- //# sourceMappingURL=chunk-ANVDRW5F.js.map
8807
+ //# sourceMappingURL=chunk-Y7TUE7JT.js.map