@toon-protocol/rig 4.5.0 → 4.6.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.
@@ -10,11 +10,15 @@ import {
10
10
  UnconfiguredRepoAddressError,
11
11
  UnknownRemoteError,
12
12
  addGitRemote,
13
+ amendRepoAnnouncement,
13
14
  buildCiManualTrigger,
14
15
  buildCiSecretUpdate,
15
16
  buildCiServiceRequest,
16
17
  buildCiServiceStop,
17
18
  collectRepoObjects,
19
+ conformanceEdits,
20
+ diffAnnouncementTags,
21
+ earliestUniqueCommit,
18
22
  emitCliError,
19
23
  encryptSecretUpdate,
20
24
  executePush,
@@ -48,22 +52,24 @@ import {
48
52
  updateRef,
49
53
  writeGitObjects,
50
54
  writeToonConfig
51
- } from "./chunk-S2BMLXAD.js";
55
+ } from "./chunk-DCGV6ALH.js";
52
56
  import {
53
57
  ARWEAVE_GATEWAYS,
54
58
  COMMENT_KIND,
55
59
  DEFAULT_KEYSTORE_PASSWORD,
60
+ LEGACY_COMMENT_KIND,
56
61
  MissingIdentityError,
57
62
  authorizedStatusAuthors,
58
63
  buildComment,
59
64
  buildIssue,
60
65
  buildPatch,
61
- buildRepoAnnouncement,
62
66
  buildStatus,
63
67
  clientConfigPath,
64
68
  clientKeystorePath,
69
+ commentBelongsToThread,
65
70
  defaultWebSocketFactory,
66
71
  fetchRemoteState,
72
+ firstTagValue,
67
73
  isValidEvmPayoutAddress,
68
74
  linkKeystoreInClientConfig,
69
75
  parseMaintainers,
@@ -71,7 +77,7 @@ import {
71
77
  readClientConfigFile,
72
78
  resolveAccountIndex,
73
79
  resolveIdentity
74
- } from "./chunk-HMED76GU.js";
80
+ } from "./chunk-JBFBD7HV.js";
75
81
  import {
76
82
  ChannelMapStore,
77
83
  channelStatus,
@@ -100,6 +106,12 @@ function mirrorGatewaysFor(primary) {
100
106
  }
101
107
 
102
108
  // src/cli/render.ts
109
+ function describeAnnouncementDiff(diff) {
110
+ return [
111
+ ...diff.removed.map((tag) => ` - ${tag.join(" ")}`),
112
+ ...diff.added.map((tag) => ` + ${tag.join(" ")}`)
113
+ ];
114
+ }
103
115
  function formatNumber(value) {
104
116
  return String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
105
117
  }
@@ -214,6 +226,14 @@ function repoHashRoute(options) {
214
226
  function rigWebRoute(options) {
215
227
  return `${options.rigWebUrl.replace(/\/+$/, "")}/${repoHashRoute(options)}`;
216
228
  }
229
+ function repoWebUrl(options) {
230
+ return rigWebRoute({
231
+ rigWebUrl: options.env[RIG_WEB_URL_ENV] ?? DEFAULT_RIG_WEB_URL,
232
+ relay: options.relay,
233
+ ownerNpub: hexToNpub(options.ownerPubkey),
234
+ repoId: options.repoId
235
+ });
236
+ }
217
237
  function escapeHtml(value) {
218
238
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
219
239
  }
@@ -300,7 +320,7 @@ function loadPaidSession(deps, relayUrl) {
300
320
  });
301
321
  }
302
322
  var defaultLoadStandalone = async (options) => {
303
- const mod = await import("./standalone-mode-W3ZEKC6M.js");
323
+ const mod = await import("./standalone-mode-UQSP4677.js");
304
324
  return mod.createStandaloneContext(options);
305
325
  };
306
326
  function identityReport(ctx) {
@@ -559,6 +579,14 @@ async function runPush(args, deps) {
559
579
  `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.`
560
580
  );
561
581
  }
582
+ const announcement = relaysUsed[0] === void 0 ? void 0 : {
583
+ web: repoWebUrl({
584
+ env: deps.env,
585
+ relay: relaysUsed[0],
586
+ ownerPubkey: identity.pubkey,
587
+ repoId
588
+ })
589
+ };
562
590
  let plan;
563
591
  let execute;
564
592
  let pointerPlan;
@@ -577,7 +605,8 @@ async function runPush(args, deps) {
577
605
  feeRates,
578
606
  repoId,
579
607
  refs: refspecs,
580
- force: flags.force
608
+ force: flags.force,
609
+ ...announcement ? { announcement } : {}
581
610
  });
582
611
  plan = serializePushPlan(pushPlan);
583
612
  execute = async () => serializePushResult(
@@ -612,7 +641,8 @@ async function runPush(args, deps) {
612
641
  repoId,
613
642
  refspecs,
614
643
  force: flags.force,
615
- relayUrls: relaysUsed
644
+ relayUrls: relaysUsed,
645
+ ...announcement ? { announcement } : {}
616
646
  });
617
647
  execute = () => client.gitPush({
618
648
  repoPath: repoRoot,
@@ -620,7 +650,8 @@ async function runPush(args, deps) {
620
650
  refspecs,
621
651
  force: flags.force,
622
652
  relayUrls: relaysUsed,
623
- confirm: true
653
+ confirm: true,
654
+ ...announcement ? { announcement } : {}
624
655
  });
625
656
  rigPageSkipDetail = "skipped on the daemon path (refreshes on the next standalone push)";
626
657
  }
@@ -879,6 +910,82 @@ async function resolveRepoContext(flags, deps) {
879
910
  ...repoRoot !== void 0 ? { repoRoot } : {}
880
911
  };
881
912
  }
913
+ async function conformanceFactsFor(options) {
914
+ const { ctx, relayUrl, deps } = options;
915
+ const repoRoot = ctx.repoRoot;
916
+ const rootCommits = deps.rootCommits ?? (repoRoot === void 0 ? void 0 : (rev) => new GitRepoReader(repoRoot).rootCommits(rev));
917
+ let euc = null;
918
+ if (rootCommits !== void 0) {
919
+ try {
920
+ euc = await earliestUniqueCommit({ rootCommits });
921
+ } catch {
922
+ euc = null;
923
+ }
924
+ }
925
+ let web = null;
926
+ try {
927
+ web = repoWebUrl({
928
+ env: deps.env,
929
+ relay: relayUrl,
930
+ ownerPubkey: ctx.owner,
931
+ repoId: ctx.repoId
932
+ });
933
+ } catch {
934
+ web = null;
935
+ }
936
+ return { relays: [relayUrl], web, earliestUniqueCommit: euc };
937
+ }
938
+ async function openAnnouncementRepublish(options) {
939
+ const { deps, flags, what, before } = options;
940
+ const { io } = deps;
941
+ const ctx = await resolveRepoContext(flags, deps);
942
+ if (ctx.relays.length > 1) {
943
+ io.err(singleRelayRefusal(ctx.resolved, "Nothing was published or paid."));
944
+ return { ok: false, exitCode: 1 };
945
+ }
946
+ const relayUrl = ctx.relays[0];
947
+ if (relayUrl === void 0 || !WS_URL_RE.test(relayUrl)) {
948
+ throw new InvalidRelayUrlError(
949
+ relayUrl ?? "",
950
+ "a paid publish needs a ws:// or wss:// relay"
951
+ );
952
+ }
953
+ const load = deps.loadStandalone ?? defaultLoadStandalone;
954
+ const standalone = await load({
955
+ env: deps.env,
956
+ cwd: deps.cwd,
957
+ warn: (line) => io.err(line),
958
+ relayUrl
959
+ });
960
+ const identity = identityReport(standalone);
961
+ if (identity.pubkey.toLowerCase() !== ctx.owner.toLowerCase()) {
962
+ io.err(
963
+ `rig: only the repo owner (${ctx.owner.slice(0, 8)}\u2026) can ${what} \u2014 the active identity is ${identity.pubkey.slice(0, 8)}\u2026. A non-owner republish would write your own (ignored) announcement. Nothing was published or paid.`
964
+ );
965
+ return { ok: false, exitCode: 1, standalone };
966
+ }
967
+ const remote = await fetchRemoteState({
968
+ relayUrls: [relayUrl],
969
+ ownerPubkey: ctx.owner,
970
+ repoId: ctx.repoId,
971
+ ...deps.webSocketFactory ? { webSocketFactory: deps.webSocketFactory } : {}
972
+ });
973
+ if (!remote.announced) {
974
+ io.err(
975
+ `rig: 30617:${ctx.owner.slice(0, 8)}\u2026:${ctx.repoId} has no announcement yet \u2014 run \`rig push\` to publish the repo (with its real name/description) ${before}. Nothing was published or paid.`
976
+ );
977
+ return { ok: false, exitCode: 1, standalone };
978
+ }
979
+ return {
980
+ ok: true,
981
+ ctx,
982
+ relayUrl,
983
+ standalone,
984
+ identity,
985
+ remote,
986
+ facts: await conformanceFactsFor({ ctx, relayUrl, deps })
987
+ };
988
+ }
882
989
 
883
990
  // src/cli/dispatch.ts
884
991
  import { createRequire } from "module";
@@ -2378,7 +2485,7 @@ async function runCi(args, deps) {
2378
2485
  case "status":
2379
2486
  return runCiStatus(rest, deps);
2380
2487
  case "serve":
2381
- return (await import("./ci-serve-PYEHIBN7.js")).runCiServe(rest, deps);
2488
+ return (await import("./ci-serve-AYFZOY4O.js")).runCiServe(rest, deps);
2382
2489
  case "--help":
2383
2490
  case "-h":
2384
2491
  case "help":
@@ -2640,7 +2747,6 @@ async function runClone(args, deps) {
2640
2747
  import { readFile } from "fs/promises";
2641
2748
  import { parseArgs as parseArgs8 } from "util";
2642
2749
  import {
2643
- REPOSITORY_ANNOUNCEMENT_KIND as REPOSITORY_ANNOUNCEMENT_KIND2,
2644
2750
  STATUS_APPLIED_KIND as STATUS_APPLIED_KIND2,
2645
2751
  STATUS_CLOSED_KIND as STATUS_CLOSED_KIND2,
2646
2752
  STATUS_DRAFT_KIND as STATUS_DRAFT_KIND2,
@@ -2675,9 +2781,10 @@ Options:
2675
2781
  ${READ_COMMON_FLAGS}`;
2676
2782
  var ISSUE_SHOW_USAGE = `Usage: rig issue show <event-id> [options]
2677
2783
 
2678
- Show one issue (kind:1621): metadata, derived state, body, and its
2679
- kind:1622 comments \u2014 FREE (relay reads only). <event-id> is the 64-char hex
2680
- id \`rig issue create\` printed (also visible in \`rig issue list\`).
2784
+ Show one issue (kind:1621): metadata, derived state, body, and its comments
2785
+ \u2014 NIP-22 kind:1111 merged with legacy kind:1622 in time order \u2014 FREE (relay
2786
+ reads only). <event-id> is the 64-char hex id \`rig issue create\` printed
2787
+ (also visible in \`rig issue list\`).
2681
2788
 
2682
2789
  Options:
2683
2790
  ${READ_COMMON_FLAGS}`;
@@ -2694,7 +2801,8 @@ var PR_SHOW_USAGE = `Usage: rig pr show <event-id> [options]
2694
2801
 
2695
2802
  Show one patch/PR (kind:1617): metadata, derived state, the FULL patch text
2696
2803
  (real \`git format-patch\` output \u2014 pipe it to \`git am\` to apply), and its
2697
- kind:1622 comments \u2014 FREE (relay reads only).
2804
+ comments \u2014 NIP-22 kind:1111 merged with legacy kind:1622 in time order \u2014
2805
+ FREE (relay reads only).
2698
2806
 
2699
2807
  Options:
2700
2808
  ${READ_COMMON_FLAGS}`;
@@ -2710,9 +2818,7 @@ var STATUS_KINDS = [
2710
2818
  STATUS_CLOSED_KIND,
2711
2819
  STATUS_DRAFT_KIND
2712
2820
  ];
2713
- function tagValue(tags, name) {
2714
- return tags.find((t) => t[0] === name)?.[1];
2715
- }
2821
+ var tagValue = firstTagValue;
2716
2822
  function tagValues(tags, name) {
2717
2823
  return tags.filter((t) => t[0] === name && t[1]).map((t) => t[1]);
2718
2824
  }
@@ -2729,6 +2835,9 @@ function deriveStatus(targetEventId, statusEvents, authorized) {
2729
2835
  }
2730
2836
  return winner === null ? "open" : STATUS_BY_KIND[winner.kind];
2731
2837
  }
2838
+ function withTargetAuthor(authorized, targetAuthorPubkey) {
2839
+ return /* @__PURE__ */ new Set([...authorized, targetAuthorPubkey.toLowerCase()]);
2840
+ }
2732
2841
  var RELAY_TIMEOUT_MS = 1e4;
2733
2842
  var HEX64_RE2 = /^[0-9a-f]{64}$/;
2734
2843
  var WS_URL_RE3 = /^wss?:\/\//i;
@@ -2872,7 +2981,7 @@ function parseTrackerItem(event, status) {
2872
2981
  };
2873
2982
  if (event.kind === PATCH_KIND) {
2874
2983
  item.commitShas = tagValues(event.tags, "commit");
2875
- const branch = tagValue(event.tags, "branch");
2984
+ const branch = tagValue(event.tags, "branch-name") ?? tagValue(event.tags, "branch");
2876
2985
  if (branch !== void 0) item.branch = branch;
2877
2986
  const description = tagValue(event.tags, "description");
2878
2987
  if (description !== void 0) item.description = description;
@@ -2917,7 +3026,14 @@ async function fetchItems(ctx, kind) {
2917
3026
  }
2918
3027
  const authorized = await authorizedPromise;
2919
3028
  return items.map(
2920
- (event) => parseTrackerItem(event, deriveStatus(event.id, statuses.values(), authorized))
3029
+ (event) => parseTrackerItem(
3030
+ event,
3031
+ deriveStatus(
3032
+ event.id,
3033
+ statuses.values(),
3034
+ withTargetAuthor(authorized, event.pubkey)
3035
+ )
3036
+ )
2921
3037
  ).sort((a, b) => b.createdAt - a.createdAt);
2922
3038
  }
2923
3039
  async function fetchItem(ctx, eventId, expectedKind) {
@@ -2942,16 +3058,23 @@ async function fetchItem(ctx, eventId, expectedKind) {
2942
3058
  [{ kinds: STATUS_KINDS, "#e": [eventId] }],
2943
3059
  ctx.webSocketFactory
2944
3060
  ),
3061
+ // One thread, two wire shapes (#159): NIP-22 kind:1111 comments hang off
3062
+ // the root's UPPERCASE `E` tag (a nested reply's lowercase `e` names its
3063
+ // parent comment, so `#e` would miss it); legacy kind:1622 comments only
3064
+ // ever carry the lowercase `e`. Both are merged below by `created_at`.
2945
3065
  queryAll(
2946
3066
  ctx.relays,
2947
- [{ kinds: [COMMENT_KIND], "#e": [eventId] }],
3067
+ [
3068
+ { kinds: [COMMENT_KIND], "#E": [eventId] },
3069
+ { kinds: [LEGACY_COMMENT_KIND], "#e": [eventId] }
3070
+ ],
2948
3071
  ctx.webSocketFactory
2949
3072
  )
2950
3073
  ]);
2951
- const comments = [...commentEvents.values()].filter(
2952
- (e) => e.kind === COMMENT_KIND && e.tags.some((t) => t[0] === "e" && t[1] === eventId)
2953
- ).sort((a, b) => a.created_at - b.created_at).map((e) => ({
3074
+ const comments = [...commentEvents.values()].filter((e) => commentBelongsToThread(e, eventId)).sort((a, b) => a.created_at - b.created_at).map((e) => ({
2954
3075
  eventId: e.id,
3076
+ kind: e.kind,
3077
+ replyToEventId: tagValue(e.tags, "e") ?? null,
2955
3078
  authorPubkey: e.pubkey,
2956
3079
  createdAt: e.created_at,
2957
3080
  content: e.content
@@ -2962,7 +3085,11 @@ async function fetchItem(ctx, eventId, expectedKind) {
2962
3085
  return {
2963
3086
  item: parseTrackerItem(
2964
3087
  event,
2965
- deriveStatus(eventId, statusEvents.values(), authorized)
3088
+ deriveStatus(
3089
+ eventId,
3090
+ statusEvents.values(),
3091
+ withTargetAuthor(authorized, event.pubkey)
3092
+ )
2966
3093
  ),
2967
3094
  comments,
2968
3095
  repoATag: repoATag2
@@ -3028,8 +3155,9 @@ async function runList(args, deps, spec) {
3028
3155
  }
3029
3156
  for (const item of items) {
3030
3157
  const labels = item.labels.length > 0 ? ` [${item.labels.join(", ")}]` : "";
3158
+ const branch = item.branch !== void 0 ? ` \u2192 ${item.branch}` : "";
3031
3159
  io.out(
3032
- `${item.status.padEnd(7)} ${item.eventId.slice(0, 8)} ${item.title} (${item.authorPubkey.slice(0, 8)}, ${isoDate(item.createdAt)})${labels}`
3160
+ `${item.status.padEnd(7)} ${item.eventId.slice(0, 8)} ${item.title} (${item.authorPubkey.slice(0, 8)}, ${isoDate(item.createdAt)})${labels}${branch}`
3033
3161
  );
3034
3162
  }
3035
3163
  io.out(
@@ -3105,8 +3233,9 @@ async function runShow(args, deps, spec) {
3105
3233
  io.out("");
3106
3234
  io.out(`Comments (${shown.comments.length}):`);
3107
3235
  for (const comment of shown.comments) {
3236
+ const replyTo = comment.replyToEventId !== null && comment.replyToEventId !== item.eventId ? ` in reply to ${comment.replyToEventId.slice(0, 8)}` : "";
3108
3237
  io.out(
3109
- `--- ${comment.eventId.slice(0, 8)} by ${comment.authorPubkey.slice(0, 8)} on ${isoDate(comment.createdAt)}`
3238
+ `--- ${comment.eventId.slice(0, 8)} by ${comment.authorPubkey.slice(0, 8)} on ${isoDate(comment.createdAt)}${replyTo}`
3110
3239
  );
3111
3240
  for (const line of comment.content.split("\n")) io.out(line);
3112
3241
  }
@@ -3194,18 +3323,27 @@ ${COMMON_FLAGS_USAGE2}
3194
3323
  Related (FREE reads \u2014 no payment):
3195
3324
  rig issue list [--state open|closed|all] list the repo's issues
3196
3325
  rig issue show <event-id> one issue + its comments`;
3197
- var COMMENT_USAGE = `Usage: rig comment <root-event-id> --body <text> [options]
3326
+ var COMMENT_USAGE = `Usage: rig comment <target-event-id> --body <text> [options]
3198
3327
 
3199
- Comment (kind:1622) on an issue or patch \u2014 a paid publish; writes are
3200
- permanent and non-refundable. <root-event-id> is the 64-char hex id of the
3201
- kind:1621 issue / kind:1617 patch being commented on.
3328
+ Comment (NIP-22 kind:1111) on an issue or patch \u2014 a paid publish; writes are
3329
+ permanent and non-refundable. <target-event-id> is the 64-char hex id of
3330
+ either:
3331
+
3332
+ the kind:1621 issue / kind:1617 patch being commented on \u2192 a top-level
3333
+ comment, whose NIP-22 root scope (E/K/P) and parent (e/k/p) both name it;
3334
+ an existing kind:1111 comment \u2192 a REPLY: the comment becomes the lowercase
3335
+ parent (k=1111) while the uppercase root stays the issue/patch it hangs
3336
+ off.
3337
+
3338
+ The target is read from the resolved relay first (a FREE read) so the root's
3339
+ kind and author are taken from the wire rather than guessed. The repo
3340
+ coordinate rides along as an \`a\` tag for subscription filtering.
3341
+
3342
+ Older rig releases read only the legacy kind:1622 dialect and will NOT see
3343
+ comments published by this version.
3202
3344
 
3203
3345
  Options:
3204
3346
  --body <text> comment body (Markdown) [required]
3205
- --parent-author <pubkey> pubkey of the TARGET event's author (p threading
3206
- tag; default: the repo owner)
3207
- --marker <root|reply> e-tag marker (default: root \u2014 commenting directly
3208
- on the issue/patch)
3209
3347
  ${COMMON_FLAGS_USAGE2}`;
3210
3348
  var PR_CREATE_USAGE = `Usage: rig pr create --title <title> (--range <range> | --patch-file <path>) [options]
3211
3349
 
@@ -3228,7 +3366,7 @@ Options:
3228
3366
  --patch-file <path> literal patch text to publish
3229
3367
  --body <text> PR description (Markdown; description tag)
3230
3368
  --body-file <path> read the PR description from a file
3231
- --branch <name> branch name (t tag)
3369
+ --branch <name> branch name (branch-name tag)
3232
3370
  ${COMMON_FLAGS_USAGE2}`;
3233
3371
  var PR_STATUS_USAGE = `Usage: rig pr status <target-event-id> <open|applied|closed|draft> [options]
3234
3372
 
@@ -3333,7 +3471,7 @@ async function runEvent(opts) {
3333
3471
  }
3334
3472
  const owner = flags.owner ?? toonConfig.owner ?? identity.pubkey;
3335
3473
  const addr = { ownerPubkey: owner, repoId };
3336
- const event = await opts.buildEvent(addr);
3474
+ const event = await opts.buildEvent(addr, relaysUsed[0]);
3337
3475
  const action = `kind:${event.kind} ${actionLabel}`;
3338
3476
  if (opts.preConfirm) {
3339
3477
  await opts.preConfirm({ identity, addr, relayUrl: relaysUsed[0] });
@@ -3506,19 +3644,64 @@ async function runIssue(args, deps) {
3506
3644
  })
3507
3645
  });
3508
3646
  }
3647
+ var TARGET_LOOKUP_TIMEOUT_MS = 1e4;
3648
+ async function resolveCommentTarget(deps, targetEventId, relayUrl) {
3649
+ if (relayUrl === void 0) {
3650
+ throw new Error(
3651
+ "no relay resolved \u2014 a comment needs the target event to derive its NIP-22 root; pass --relay <url> or configure a remote"
3652
+ );
3653
+ }
3654
+ const found = await queryRelay(
3655
+ relayUrl,
3656
+ { ids: [targetEventId] },
3657
+ TARGET_LOOKUP_TIMEOUT_MS,
3658
+ deps.webSocketFactory ?? defaultWebSocketFactory
3659
+ );
3660
+ const target = found.find((e) => e.id === targetEventId);
3661
+ if (!target) {
3662
+ throw new Error(
3663
+ `event ${targetEventId} not found on ${relayUrl} \u2014 nothing was published or paid`
3664
+ );
3665
+ }
3666
+ if (target.kind === LEGACY_COMMENT_KIND) {
3667
+ throw new Error(
3668
+ `event ${targetEventId} is a legacy kind:1622 comment \u2014 replies to it are not representable in NIP-22; comment on the issue or patch instead`
3669
+ );
3670
+ }
3671
+ if (target.kind === COMMENT_KIND) {
3672
+ const rootEventId = firstTagValue(target.tags, "E");
3673
+ const rootKind = Number(firstTagValue(target.tags, "K"));
3674
+ const rootAuthor = firstTagValue(target.tags, "P");
3675
+ if (rootEventId === void 0 || !HEX64_RE3.test(rootEventId) || !Number.isSafeInteger(rootKind) || rootAuthor === void 0 || !HEX64_RE3.test(rootAuthor)) {
3676
+ throw new Error(
3677
+ `kind:1111 comment ${targetEventId} carries no usable NIP-22 root scope (E/K/P tags) \u2014 cannot derive the thread root to reply into`
3678
+ );
3679
+ }
3680
+ return {
3681
+ root: { eventId: rootEventId, kind: rootKind, authorPubkey: rootAuthor },
3682
+ parent: { eventId: target.id, authorPubkey: target.pubkey }
3683
+ };
3684
+ }
3685
+ return {
3686
+ root: {
3687
+ eventId: target.id,
3688
+ kind: target.kind,
3689
+ authorPubkey: target.pubkey
3690
+ }
3691
+ };
3692
+ }
3509
3693
  async function runComment(args, deps) {
3510
3694
  const { io } = deps;
3511
3695
  let flags;
3512
- let rootEventId;
3696
+ let targetEventId;
3513
3697
  let body;
3514
- let parentAuthor;
3515
- let marker;
3516
3698
  try {
3517
3699
  const { values, positionals } = parseArgs8({
3518
3700
  args,
3519
3701
  options: {
3520
3702
  ...COMMON_OPTIONS2,
3521
3703
  body: { type: "string" },
3704
+ // Retired by #159 — parsed only to explain the migration.
3522
3705
  "parent-author": { type: "string" },
3523
3706
  marker: { type: "string" }
3524
3707
  },
@@ -3529,49 +3712,59 @@ async function runComment(args, deps) {
3529
3712
  io.out(COMMENT_USAGE);
3530
3713
  return 0;
3531
3714
  }
3715
+ if (values.marker !== void 0 || values["parent-author"] !== void 0) {
3716
+ throw new Error(
3717
+ "--marker and --parent-author were removed with the move to NIP-22 kind:1111 (#159): pass the comment you are replying to as <target-event-id> instead \u2014 its author and the thread root are read from the relay"
3718
+ );
3719
+ }
3532
3720
  if (positionals.length !== 1) {
3533
3721
  throw new Error(
3534
- positionals.length === 0 ? "<root-event-id> is required" : `expected exactly one <root-event-id>, got ${positionals.length} positionals`
3722
+ positionals.length === 0 ? "<target-event-id> is required" : `expected exactly one <target-event-id>, got ${positionals.length} positionals`
3535
3723
  );
3536
3724
  }
3537
- rootEventId = positionals[0];
3538
- assertHex64(rootEventId, "<root-event-id>");
3725
+ targetEventId = positionals[0];
3726
+ assertHex64(targetEventId, "<target-event-id>");
3539
3727
  if (values.body === void 0 || values.body === "") {
3540
3728
  throw new Error("--body is required");
3541
3729
  }
3542
3730
  body = values.body;
3543
- parentAuthor = values["parent-author"];
3544
- if (parentAuthor !== void 0) assertHex64(parentAuthor, "--parent-author");
3545
- const rawMarker = values.marker ?? "root";
3546
- if (rawMarker !== "root" && rawMarker !== "reply") {
3547
- throw new Error(`--marker must be root or reply (got ${JSON.stringify(rawMarker)})`);
3548
- }
3549
- marker = rawMarker;
3550
3731
  } catch (err) {
3551
3732
  io.err(err instanceof Error ? err.message : String(err));
3552
3733
  io.err(COMMENT_USAGE);
3553
3734
  return 2;
3554
3735
  }
3736
+ let threading;
3555
3737
  return runEvent({
3556
3738
  command: "comment",
3557
3739
  flags,
3558
3740
  deps,
3559
- actionLabel: `comment on ${rootEventId.slice(0, 8)}\u2026`,
3560
- buildEvent: async (addr) => buildComment(
3561
- addr.ownerPubkey,
3562
- addr.repoId,
3563
- rootEventId,
3564
- parentAuthor ?? addr.ownerPubkey,
3565
- body,
3566
- marker
3567
- ),
3568
- sendDaemon: (client, addr) => client.gitComment({
3569
- repoAddr: addr,
3570
- rootEventId,
3571
- body,
3572
- ...parentAuthor !== void 0 ? { parentAuthorPubkey: parentAuthor } : {},
3573
- marker
3574
- })
3741
+ actionLabel: `comment on ${targetEventId.slice(0, 8)}\u2026`,
3742
+ buildEvent: async (addr, relayUrl) => {
3743
+ threading = await resolveCommentTarget(deps, targetEventId, relayUrl);
3744
+ return buildComment(
3745
+ addr.ownerPubkey,
3746
+ addr.repoId,
3747
+ threading.root,
3748
+ body,
3749
+ threading.parent
3750
+ );
3751
+ },
3752
+ sendDaemon: (client, addr) => {
3753
+ if (threading === void 0) {
3754
+ throw new Error(
3755
+ "internal: the comment target was not resolved before the publish"
3756
+ );
3757
+ }
3758
+ const { root, parent } = threading;
3759
+ return client.gitComment({
3760
+ repoAddr: addr,
3761
+ body,
3762
+ rootEventId: root.eventId,
3763
+ rootKind: root.kind,
3764
+ rootAuthorPubkey: root.authorPubkey,
3765
+ ...parent !== void 0 ? { parentComment: parent } : {}
3766
+ });
3767
+ }
3575
3768
  });
3576
3769
  }
3577
3770
  var PATCH_FROM_RE = /^From ([0-9a-f]{40}) /gm;
@@ -3776,14 +3969,18 @@ async function runPrStatus(args, deps) {
3776
3969
  flags,
3777
3970
  deps,
3778
3971
  actionLabel: `status ${status} on ${targetEventId.slice(0, 8)}\u2026`,
3779
- buildEvent: async (addr) => {
3780
- const event = buildStatus(targetEventId, STATUS_KIND_BY_VALUE[status]);
3781
- event.tags.push([
3782
- "a",
3783
- `${REPOSITORY_ANNOUNCEMENT_KIND2}:${addr.ownerPubkey}:${addr.repoId}`
3784
- ]);
3785
- return event;
3786
- },
3972
+ buildEvent: async (addr) => (
3973
+ // buildStatus (rig#160) now emits the root-marked `e` tag and the repo
3974
+ // `a` tag itself, so readers can scope a status stream to the
3975
+ // repository without resolving the target first (mirrors the
3976
+ // daemon's gitStatus).
3977
+ buildStatus(
3978
+ addr.ownerPubkey,
3979
+ addr.repoId,
3980
+ targetEventId,
3981
+ STATUS_KIND_BY_VALUE[status]
3982
+ )
3983
+ ),
3787
3984
  // Authority warning (#287): a status event only moves an issue/PR's
3788
3985
  // resolved state for repo-authority-honoring clients if its author is the
3789
3986
  // owner or a declared maintainer. Warn clearly when the active identity is
@@ -3811,11 +4008,11 @@ async function warnIfNotMaintainer(deps, args) {
3811
4008
  );
3812
4009
  if (authorized.has(identity.pubkey.toLowerCase())) return;
3813
4010
  io.err(
3814
- `warning: you (${identity.pubkey.slice(0, 8)}\u2026) are not a maintainer of 30617:${addr.ownerPubkey.slice(0, 8)}\u2026:${addr.repoId} \u2014 clients honoring repo authority (rig, rig-web) will IGNORE this status when resolving the issue/PR's state. Publishing anyway (the relay is permissionless); ask the owner to \`rig maintainers add\` you if this should stick.`
4011
+ `warning: you (${identity.pubkey.slice(0, 8)}\u2026) are not a maintainer of 30617:${addr.ownerPubkey.slice(0, 8)}\u2026:${addr.repoId} \u2014 clients honoring repo authority (rig, rig-web) will IGNORE this status when resolving the issue/PR's state, UNLESS you are also the target event's own author (rig#160: an issue/PR author may move their own item\u2019s status even without maintainer standing \u2014 this check cannot tell from here, since it does not know the target's author without a second relay read). Publishing anyway (the relay is permissionless); ask the owner to \`rig maintainers add\` you if this should stick for OTHER items too.`
3815
4012
  );
3816
4013
  } catch {
3817
4014
  io.err(
3818
- "warning: could not read the repo announcement to verify your maintainer status \u2014 if you are not the owner or a declared maintainer, authority-honoring clients will ignore this status."
4015
+ "warning: could not read the repo announcement to verify your maintainer status \u2014 if you are not the owner, a declared maintainer, or the target event's own author, authority-honoring clients will ignore this status."
3819
4016
  );
3820
4017
  }
3821
4018
  }
@@ -4178,12 +4375,7 @@ async function runFetch(args, deps) {
4178
4375
  }
4179
4376
  const reader = new GitRepoReader(repoRoot);
4180
4377
  const tips = [...new Set(planned.map((p) => p.newSha))];
4181
- const candidates = [.../* @__PURE__ */ new Set([...remoteState.shaToTxId.keys(), ...tips])];
4182
- const { missing: absent } = await reader.statObjects(candidates);
4183
- const absentSet = new Set(absent);
4184
- const presentLocally = new Set(
4185
- candidates.filter((sha) => !absentSet.has(sha))
4186
- );
4378
+ const presentLocally = new Set(await reader.listAllObjectShas());
4187
4379
  const collected = await collectRepoObjects({
4188
4380
  tips,
4189
4381
  shaToTxId: remoteState.shaToTxId,
@@ -5522,44 +5714,15 @@ async function runMutate(op, args, deps) {
5522
5714
  }
5523
5715
  let standaloneCtx;
5524
5716
  try {
5525
- const ctx = await resolveRepoContext(flags, deps);
5526
- if (ctx.relays.length > 1) {
5527
- io.err(singleRelayRefusal(ctx.resolved, "Nothing was published or paid."));
5528
- return 1;
5529
- }
5530
- const relayUrl = ctx.relays[0];
5531
- if (relayUrl === void 0 || !WS_URL_RE.test(relayUrl)) {
5532
- throw new InvalidRelayUrlError(
5533
- relayUrl ?? "",
5534
- "a paid publish needs a ws:// or wss:// relay"
5535
- );
5536
- }
5537
- const load = deps.loadStandalone ?? defaultLoadStandalone;
5538
- standaloneCtx = await load({
5539
- env: deps.env,
5540
- cwd: deps.cwd,
5541
- warn: (line) => io.err(line),
5542
- relayUrl
5543
- });
5544
- const identity = identityReport(standaloneCtx);
5545
- if (identity.pubkey.toLowerCase() !== ctx.owner.toLowerCase()) {
5546
- io.err(
5547
- `rig: only the repo owner (${ctx.owner.slice(0, 8)}\u2026) can change the maintainer set \u2014 the active identity is ${identity.pubkey.slice(0, 8)}\u2026. A non-owner republish would write your own (ignored) announcement. Nothing was published or paid.`
5548
- );
5549
- return 1;
5550
- }
5551
- const remote = await fetchRemoteState({
5552
- relayUrls: [relayUrl],
5553
- ownerPubkey: ctx.owner,
5554
- repoId: ctx.repoId,
5555
- ...deps.webSocketFactory ? { webSocketFactory: deps.webSocketFactory } : {}
5717
+ const opened = await openAnnouncementRepublish({
5718
+ deps,
5719
+ flags,
5720
+ what: "change the maintainer set",
5721
+ before: "before managing maintainers"
5556
5722
  });
5557
- if (!remote.announced) {
5558
- io.err(
5559
- `rig: 30617:${ctx.owner.slice(0, 8)}\u2026:${ctx.repoId} has no announcement yet \u2014 run \`rig push\` to publish the repo (with its real name/description) before managing maintainers. Nothing was published or paid.`
5560
- );
5561
- return 1;
5562
- }
5723
+ standaloneCtx = opened.standalone;
5724
+ if (!opened.ok) return opened.exitCode;
5725
+ const { ctx, relayUrl, identity, remote, facts } = opened;
5563
5726
  const current = remote.announceEvent ? parseMaintainers(remote.announceEvent.tags) : [];
5564
5727
  const currentSet = new Set(current);
5565
5728
  if (op === "add" && currentSet.has(pubkey)) {
@@ -5575,21 +5738,23 @@ async function runMutate(op, args, deps) {
5575
5738
  return 0;
5576
5739
  }
5577
5740
  const next = op === "add" ? [...current, pubkey] : current.filter((m) => m !== pubkey);
5578
- const name = remote.name ?? ctx.repoId;
5579
- const description = remote.description ?? "";
5580
- const event = buildRepoAnnouncement(
5581
- ctx.repoId,
5582
- name,
5583
- description,
5584
- next,
5585
- remote.payout
5586
- );
5587
- const fee = (await standaloneCtx.publisher.getFeeRates()).eventFee.toString();
5741
+ const event = amendRepoAnnouncement(remote.announceEvent, {
5742
+ repoId: ctx.repoId,
5743
+ maintainers: next,
5744
+ ...conformanceEdits(remote.announceEvent, facts)
5745
+ });
5746
+ const diff = diffAnnouncementTags(remote.announceEvent, event);
5747
+ const changes = { added: diff.added, removed: diff.removed };
5748
+ const fee = (await opened.standalone.publisher.getFeeRates()).eventFee.toString();
5588
5749
  const action = `kind:30617 maintainers ${op} ${pubkey.slice(0, 8)}\u2026`;
5589
5750
  if (!flags.json) {
5590
5751
  io.out(`Republish ${action}`);
5591
5752
  io.out(`Repo: 30617:${ctx.owner}:${ctx.repoId}`);
5592
5753
  io.out(`Maintainers after: ${next.length === 0 ? "(none)" : next.join(", ")}`);
5754
+ if (!diff.unchanged) {
5755
+ io.out("Tags changed:");
5756
+ for (const line of describeAnnouncementDiff(diff)) io.out(line);
5757
+ }
5593
5758
  io.out(`Fee: ${feeLabel(fee)}. Writes are permanent and non-refundable.`);
5594
5759
  }
5595
5760
  if (!flags.yes) {
@@ -5601,6 +5766,7 @@ async function runMutate(op, args, deps) {
5601
5766
  executed: false,
5602
5767
  feeEstimate: fee,
5603
5768
  maintainers: next,
5769
+ changes,
5604
5770
  hint: "estimate only \u2014 re-run with --yes to publish (permanent, non-refundable)"
5605
5771
  });
5606
5772
  return 0;
@@ -5619,7 +5785,7 @@ async function runMutate(op, args, deps) {
5619
5785
  return 1;
5620
5786
  }
5621
5787
  }
5622
- const receipt = await standaloneCtx.publisher.publishEvent(event, [
5788
+ const receipt = await opened.standalone.publisher.publishEvent(event, [
5623
5789
  relayUrl
5624
5790
  ]);
5625
5791
  const result = serializeEventReceipt(event.kind, receipt);
@@ -5631,6 +5797,7 @@ async function runMutate(op, args, deps) {
5631
5797
  executed: true,
5632
5798
  feeEstimate: fee,
5633
5799
  maintainers: next,
5800
+ changes,
5634
5801
  result
5635
5802
  });
5636
5803
  } else {
@@ -5651,9 +5818,167 @@ async function runMutate(op, args, deps) {
5651
5818
  }
5652
5819
  }
5653
5820
 
5821
+ // src/cli/refresh.ts
5822
+ import { parseArgs as parseArgs15 } from "util";
5823
+ var REFRESH_USAGE = `Usage: rig refresh [options]
5824
+
5825
+ Republish this repo's kind:30617 announcement with no field edit, refreshing
5826
+ its NIP-34 conformance tags (#158) so other clients can find and group it:
5827
+
5828
+ relays the relay this repo publishes to \u2014 where its issues,
5829
+ patches and state live. Added to the relays the
5830
+ announcement already lists; none are removed
5831
+ web the repo's rig-web viewer URL, added alongside any
5832
+ viewer URL another client already announced
5833
+ r <sha> euc the earliest unique commit: the repo's fork identity.
5834
+ Written only if the announcement has none \u2014 once declared it
5835
+ never changes, so forks stay grouped
5836
+
5837
+ Every other tag rides along verbatim, including tags written by other NIP-34
5838
+ clients. rig never writes a \`clone\` tag (it has no git-clonable URL) and never
5839
+ removes one.
5840
+
5841
+ PAID: republishing the kind:30617 costs one event fee (permanent,
5842
+ non-refundable). Nothing is published and nothing is paid when no tag would
5843
+ change. Must run under the repo OWNER's identity \u2014 only the owner's
5844
+ announcement is authoritative.
5845
+
5846
+ Options:
5847
+ --repo-id <id> repository id / NIP-34 d-tag (default: git config)
5848
+ --owner <pubkey> repository owner (npub or hex; default: git config)
5849
+ --remote <name> publish/read via this configured git remote (default: origin)
5850
+ --relay <url> ad-hoc relay override (exactly one)
5851
+ --yes skip the fee confirmation (required when not a TTY)
5852
+ --json machine-readable envelope
5853
+ -h, --help show this help`;
5854
+ async function runRefresh(args, deps) {
5855
+ const { io } = deps;
5856
+ let flags;
5857
+ try {
5858
+ const { values, positionals } = parseArgs15({
5859
+ args,
5860
+ options: REPO_COMMAND_OPTIONS,
5861
+ allowPositionals: true
5862
+ });
5863
+ flags = pickRepoCommandFlags(values);
5864
+ if (flags.help) {
5865
+ io.out(REFRESH_USAGE);
5866
+ return 0;
5867
+ }
5868
+ if (positionals.length > 0) {
5869
+ throw new Error("rig refresh takes no positional arguments");
5870
+ }
5871
+ } catch (err) {
5872
+ io.err(err instanceof Error ? err.message : String(err));
5873
+ io.err(REFRESH_USAGE);
5874
+ return 2;
5875
+ }
5876
+ let standaloneCtx;
5877
+ try {
5878
+ const opened = await openAnnouncementRepublish({
5879
+ deps,
5880
+ flags,
5881
+ what: "refresh the announcement",
5882
+ before: "before refreshing it"
5883
+ });
5884
+ standaloneCtx = opened.standalone;
5885
+ if (!opened.ok) return opened.exitCode;
5886
+ const { ctx, relayUrl, identity, remote, facts } = opened;
5887
+ const event = amendRepoAnnouncement(remote.announceEvent, {
5888
+ repoId: ctx.repoId,
5889
+ ...conformanceEdits(remote.announceEvent, facts)
5890
+ });
5891
+ const diff = diffAnnouncementTags(remote.announceEvent, event);
5892
+ if (diff.unchanged) {
5893
+ const changes2 = { added: diff.added, removed: diff.removed };
5894
+ if (flags.json) {
5895
+ io.emitJson({
5896
+ command: "refresh",
5897
+ repoAddr: { ownerPubkey: ctx.owner, repoId: ctx.repoId },
5898
+ identity,
5899
+ executed: false,
5900
+ feeEstimate: null,
5901
+ changes: changes2,
5902
+ hint: "announcement is already up to date \u2014 nothing published, nothing paid"
5903
+ });
5904
+ return 0;
5905
+ }
5906
+ io.out(
5907
+ `Announcement 30617:${ctx.owner}:${ctx.repoId} is already up to date \u2014 nothing to do (not published, nothing paid).`
5908
+ );
5909
+ return 0;
5910
+ }
5911
+ const fee = (await opened.standalone.publisher.getFeeRates()).eventFee.toString();
5912
+ const changes = { added: diff.added, removed: diff.removed };
5913
+ if (!flags.json) {
5914
+ io.out("Republish kind:30617 announcement (refresh)");
5915
+ io.out(`Repo: 30617:${ctx.owner}:${ctx.repoId}`);
5916
+ io.out("Tags changed:");
5917
+ for (const line of describeAnnouncementDiff(diff)) io.out(line);
5918
+ io.out(`Fee: ${feeLabel(fee)}. Writes are permanent and non-refundable.`);
5919
+ }
5920
+ if (!flags.yes) {
5921
+ if (flags.json) {
5922
+ io.emitJson({
5923
+ command: "refresh",
5924
+ repoAddr: { ownerPubkey: ctx.owner, repoId: ctx.repoId },
5925
+ identity,
5926
+ executed: false,
5927
+ feeEstimate: fee,
5928
+ changes,
5929
+ hint: "estimate only \u2014 re-run with --yes to publish (permanent, non-refundable)"
5930
+ });
5931
+ return 0;
5932
+ }
5933
+ if (!io.isInteractive) {
5934
+ io.err(
5935
+ "refusing to spend channel funds without confirmation in a non-interactive session \u2014 re-run with --yes (or use --json for an estimate)"
5936
+ );
5937
+ return 1;
5938
+ }
5939
+ const proceed = await io.confirm(
5940
+ `Proceed with paid republish (${feeLabel(fee)})? [y/N] `
5941
+ );
5942
+ if (!proceed) {
5943
+ io.err("aborted \u2014 nothing was published.");
5944
+ return 1;
5945
+ }
5946
+ }
5947
+ const receipt = await opened.standalone.publisher.publishEvent(event, [
5948
+ relayUrl
5949
+ ]);
5950
+ const result = serializeEventReceipt(event.kind, receipt);
5951
+ if (flags.json) {
5952
+ io.emitJson({
5953
+ command: "refresh",
5954
+ repoAddr: { ownerPubkey: ctx.owner, repoId: ctx.repoId },
5955
+ identity,
5956
+ executed: true,
5957
+ feeEstimate: fee,
5958
+ changes,
5959
+ result
5960
+ });
5961
+ } else {
5962
+ io.out(
5963
+ `Published kind:30617 refresh: ${result.eventId} paid ${result.feePaid} base units`
5964
+ );
5965
+ }
5966
+ return 0;
5967
+ } catch (err) {
5968
+ return emitCliError(io, flags.json, "refresh", err);
5969
+ } finally {
5970
+ if (standaloneCtx) {
5971
+ try {
5972
+ await standaloneCtx.stop();
5973
+ } catch {
5974
+ }
5975
+ }
5976
+ }
5977
+ }
5978
+
5654
5979
  // src/cli/name.ts
5655
5980
  import { randomUUID } from "crypto";
5656
- import { parseArgs as parseArgs15 } from "util";
5981
+ import { parseArgs as parseArgs16 } from "util";
5657
5982
  var ARIO_DECIMALS = 6;
5658
5983
  function renderMario(mario) {
5659
5984
  return `${mario.toString()} mARIO (~${formatUnits(mario.toString(), ARIO_DECIMALS)} ARIO)`;
@@ -6162,7 +6487,7 @@ async function resolveNameContext(deps, network, processId, mode) {
6162
6487
  return { identity, solanaAddress, network, processId, sdk, nostrSecretKey };
6163
6488
  }
6164
6489
  function parseNameFlags(args, env) {
6165
- const { values, positionals } = parseArgs15({
6490
+ const { values, positionals } = parseArgs16({
6166
6491
  args,
6167
6492
  allowPositionals: true,
6168
6493
  options: {
@@ -6721,7 +7046,7 @@ async function runName(args, deps) {
6721
7046
  }
6722
7047
 
6723
7048
  // src/cli/payout.ts
6724
- import { parseArgs as parseArgs16 } from "util";
7049
+ import { parseArgs as parseArgs17 } from "util";
6725
7050
  import { getAddress } from "viem";
6726
7051
  var PAYOUT_USAGE = `Usage: rig payout <set|clear|show> [<address>] [options]
6727
7052
 
@@ -6777,7 +7102,7 @@ async function runShow2(args, deps) {
6777
7102
  const { io } = deps;
6778
7103
  let flags;
6779
7104
  try {
6780
- const { values, positionals } = parseArgs16({
7105
+ const { values, positionals } = parseArgs17({
6781
7106
  args,
6782
7107
  options: REPO_COMMAND_OPTIONS,
6783
7108
  allowPositionals: true
@@ -6839,7 +7164,7 @@ async function runMutate2(op, args, deps) {
6839
7164
  let flags;
6840
7165
  let nextPayout = null;
6841
7166
  try {
6842
- const { values, positionals } = parseArgs16({
7167
+ const { values, positionals } = parseArgs17({
6843
7168
  args,
6844
7169
  options: REPO_COMMAND_OPTIONS,
6845
7170
  allowPositionals: true
@@ -6870,44 +7195,15 @@ async function runMutate2(op, args, deps) {
6870
7195
  }
6871
7196
  let standaloneCtx;
6872
7197
  try {
6873
- const ctx = await resolveRepoContext(flags, deps);
6874
- if (ctx.relays.length > 1) {
6875
- io.err(singleRelayRefusal(ctx.resolved, "Nothing was published or paid."));
6876
- return 1;
6877
- }
6878
- const relayUrl = ctx.relays[0];
6879
- if (relayUrl === void 0 || !WS_URL_RE.test(relayUrl)) {
6880
- throw new InvalidRelayUrlError(
6881
- relayUrl ?? "",
6882
- "a paid publish needs a ws:// or wss:// relay"
6883
- );
6884
- }
6885
- const load = deps.loadStandalone ?? defaultLoadStandalone;
6886
- standaloneCtx = await load({
6887
- env: deps.env,
6888
- cwd: deps.cwd,
6889
- warn: (line) => io.err(line),
6890
- relayUrl
6891
- });
6892
- const identity = identityReport(standaloneCtx);
6893
- if (identity.pubkey.toLowerCase() !== ctx.owner.toLowerCase()) {
6894
- io.err(
6895
- `rig: only the repo owner (${ctx.owner.slice(0, 8)}\u2026) can change the payout pointer \u2014 the active identity is ${identity.pubkey.slice(0, 8)}\u2026. A non-owner republish would write your own (ignored) announcement. Nothing was published or paid.`
6896
- );
6897
- return 1;
6898
- }
6899
- const remote = await fetchRemoteState({
6900
- relayUrls: [relayUrl],
6901
- ownerPubkey: ctx.owner,
6902
- repoId: ctx.repoId,
6903
- ...deps.webSocketFactory ? { webSocketFactory: deps.webSocketFactory } : {}
7198
+ const opened = await openAnnouncementRepublish({
7199
+ deps,
7200
+ flags,
7201
+ what: "change the payout pointer",
7202
+ before: "before managing the payout pointer"
6904
7203
  });
6905
- if (!remote.announced) {
6906
- io.err(
6907
- `rig: 30617:${ctx.owner.slice(0, 8)}\u2026:${ctx.repoId} has no announcement yet \u2014 run \`rig push\` to publish the repo (with its real name/description) before managing the payout pointer. Nothing was published or paid.`
6908
- );
6909
- return 1;
6910
- }
7204
+ standaloneCtx = opened.standalone;
7205
+ if (!opened.ok) return opened.exitCode;
7206
+ const { ctx, relayUrl, identity, remote, facts } = opened;
6911
7207
  const current = remote.payout;
6912
7208
  if (nextPayout !== null && current !== null && current.chain === nextPayout.chain && current.address === nextPayout.address) {
6913
7209
  io.err(
@@ -6919,16 +7215,14 @@ async function runMutate2(op, args, deps) {
6919
7215
  io.err("rig: no payout pointer is set \u2014 nothing to do (not published).");
6920
7216
  return 0;
6921
7217
  }
6922
- const name = remote.name ?? ctx.repoId;
6923
- const description = remote.description ?? "";
6924
- const event = buildRepoAnnouncement(
6925
- ctx.repoId,
6926
- name,
6927
- description,
6928
- remote.maintainers,
6929
- nextPayout
6930
- );
6931
- const fee = (await standaloneCtx.publisher.getFeeRates()).eventFee.toString();
7218
+ const event = amendRepoAnnouncement(remote.announceEvent, {
7219
+ repoId: ctx.repoId,
7220
+ payout: nextPayout,
7221
+ ...conformanceEdits(remote.announceEvent, facts)
7222
+ });
7223
+ const diff = diffAnnouncementTags(remote.announceEvent, event);
7224
+ const changes = { added: diff.added, removed: diff.removed };
7225
+ const fee = (await opened.standalone.publisher.getFeeRates()).eventFee.toString();
6932
7226
  const action = nextPayout ? `kind:30617 payout set ${nextPayout.chain} ${nextPayout.address}` : "kind:30617 payout clear";
6933
7227
  if (!flags.json) {
6934
7228
  io.out(`Republish ${action}`);
@@ -6936,6 +7230,10 @@ async function runMutate2(op, args, deps) {
6936
7230
  io.out(
6937
7231
  `Payout after: ${nextPayout ? `${nextPayout.chain} ${nextPayout.address}` : "(none)"}`
6938
7232
  );
7233
+ if (!diff.unchanged) {
7234
+ io.out("Tags changed:");
7235
+ for (const line of describeAnnouncementDiff(diff)) io.out(line);
7236
+ }
6939
7237
  io.out(`Fee: ${feeLabel(fee)}. Writes are permanent and non-refundable.`);
6940
7238
  }
6941
7239
  if (!flags.yes) {
@@ -6947,6 +7245,7 @@ async function runMutate2(op, args, deps) {
6947
7245
  executed: false,
6948
7246
  feeEstimate: fee,
6949
7247
  payout: nextPayout,
7248
+ changes,
6950
7249
  hint: "estimate only \u2014 re-run with --yes to publish (permanent, non-refundable)"
6951
7250
  });
6952
7251
  return 0;
@@ -6965,7 +7264,7 @@ async function runMutate2(op, args, deps) {
6965
7264
  return 1;
6966
7265
  }
6967
7266
  }
6968
- const receipt = await standaloneCtx.publisher.publishEvent(event, [
7267
+ const receipt = await opened.standalone.publisher.publishEvent(event, [
6969
7268
  relayUrl
6970
7269
  ]);
6971
7270
  const result = serializeEventReceipt(event.kind, receipt);
@@ -6977,6 +7276,7 @@ async function runMutate2(op, args, deps) {
6977
7276
  executed: true,
6978
7277
  feeEstimate: fee,
6979
7278
  payout: nextPayout,
7279
+ changes,
6980
7280
  result
6981
7281
  });
6982
7282
  } else {
@@ -6998,7 +7298,7 @@ async function runMutate2(op, args, deps) {
6998
7298
  }
6999
7299
 
7000
7300
  // src/cli/site.ts
7001
- import { parseArgs as parseArgs17 } from "util";
7301
+ import { parseArgs as parseArgs18 } from "util";
7002
7302
 
7003
7303
  // src/arweave-manifest.ts
7004
7304
  var DEFAULT_INDEX = "index.html";
@@ -7089,7 +7389,7 @@ Options (publish):
7089
7389
  estimate (nothing uploaded)
7090
7390
  -h, --help show this help`;
7091
7391
  function parseSiteArgs(args) {
7092
- const { values, positionals } = parseArgs17({
7392
+ const { values, positionals } = parseArgs18({
7093
7393
  args,
7094
7394
  options: {
7095
7395
  index: { type: "string" },
@@ -7492,7 +7792,8 @@ Commands rig owns:
7492
7792
  issue list | show <id> read the repo's issues + comments (free)
7493
7793
  pr list | show <id> read the repo's patches; show prints the full
7494
7794
  patch text (free)
7495
- comment <root-event-id> comment (kind:1622) on an issue or patch
7795
+ comment <target-event-id> comment (NIP-22 kind:1111) on an issue or patch,
7796
+ or reply to an existing kind:1111 comment
7496
7797
  pr create publish a patch (kind:1617) with real
7497
7798
  \`git format-patch\` content
7498
7799
  pr status <event-id> <state> set an issue/patch status (kind:1630-1633):
@@ -7501,6 +7802,9 @@ Commands rig owns:
7501
7802
  maintainers add <pubkey> remove republish the kind:30617 to change who may
7502
7803
  maintainers remove <pubkey> author authoritative issue/PR status (owner is
7503
7804
  always an implicit maintainer)
7805
+ refresh republish the kind:30617 with no field edit to
7806
+ refresh its NIP-34 tags (relays, web, the euc fork
7807
+ identity) \u2014 PAID, and free when nothing changes
7504
7808
  payout show show the repo's declared payout pointer (free);
7505
7809
  payout set <address> set/clear republish the kind:30617 \u2014 no pointer
7506
7810
  payout clear means the serving node keeps 100% of
@@ -7619,6 +7923,8 @@ async function dispatch(argv, deps) {
7619
7923
  return runMaintainers(rest, deps);
7620
7924
  case "payout":
7621
7925
  return runPayout(rest, deps);
7926
+ case "refresh":
7927
+ return runRefresh(rest, deps);
7622
7928
  case "channel":
7623
7929
  return runChannel(rest, deps);
7624
7930
  case "channels":
@@ -7670,4 +7976,4 @@ export {
7670
7976
  rigVersion,
7671
7977
  dispatch
7672
7978
  };
7673
- //# sourceMappingURL=chunk-UZZ2JKEC.js.map
7979
+ //# sourceMappingURL=chunk-X232W4TG.js.map