@umbra-privacy/ceremony 0.1.4 → 0.2.5

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.
Files changed (2) hide show
  1. package/dist/index.js +264 -156
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { render } from "ink";
5
5
 
6
6
  // src/components/App.tsx
7
7
  import { useEffect as useEffect4, useState as useState4 } from "react";
8
- import { Box as Box6, Text as Text6, useApp, useInput as useInput2 } from "ink";
8
+ import { Box as Box7, Text as Text7, useApp, useInput as useInput2 } from "ink";
9
9
 
10
10
  // src/cleanup.ts
11
11
  var pendingLeaveQueue = null;
@@ -90,26 +90,20 @@ var api = {
90
90
  },
91
91
  // Slot polling
92
92
  myTurn(ceremonyId2, trackId, token) {
93
- return request(
94
- `/api/ceremonies/${ceremonyId2}/tracks/${trackId}/my-turn`,
95
- { headers: bearer(token) }
96
- );
93
+ return request(`/api/ceremonies/${ceremonyId2}/tracks/${trackId}/my-turn`, {
94
+ headers: bearer(token)
95
+ });
97
96
  },
98
97
  // Contribution
99
98
  signalUploaded(ceremonyId2, trackId, contributionId, token) {
100
- return request(
101
- `/api/ceremonies/${ceremonyId2}/tracks/${trackId}/signal-uploaded`,
102
- {
103
- method: "POST",
104
- headers: bearer(token),
105
- body: JSON.stringify({ contribution_id: contributionId })
106
- }
107
- );
99
+ return request(`/api/ceremonies/${ceremonyId2}/tracks/${trackId}/signal-uploaded`, {
100
+ method: "POST",
101
+ headers: bearer(token),
102
+ body: JSON.stringify({ contribution_id: contributionId })
103
+ });
108
104
  },
109
105
  getReceipt(ceremonyId2, contributionId) {
110
- return request(
111
- `/api/ceremonies/${ceremonyId2}/contributions/${contributionId}/receipt`
112
- );
106
+ return request(`/api/ceremonies/${ceremonyId2}/contributions/${contributionId}/receipt`);
113
107
  },
114
108
  // Admin — signed-request flow. Caller supplies the 64-byte Solana keypair
115
109
  // bytes (32 secret + 32 public). The helper fetches a one-time challenge,
@@ -252,6 +246,38 @@ async function recordContribution(trackId, contribution) {
252
246
 
253
247
  // src/components/Header.tsx
254
248
  import { Box, Text } from "ink";
249
+
250
+ // src/labels.ts
251
+ function ceremonyStatusLabel(status) {
252
+ switch (status) {
253
+ case "open":
254
+ return "open";
255
+ case "initialized":
256
+ return "not yet open";
257
+ case "finalizing":
258
+ return "closing";
259
+ case "completed":
260
+ return "complete";
261
+ default:
262
+ return status;
263
+ }
264
+ }
265
+ function trackStatusLabel(status) {
266
+ switch (status) {
267
+ case "open":
268
+ return "open";
269
+ case "initializing":
270
+ return "preparing";
271
+ case "awaiting_beacon":
272
+ return "awaiting beacon";
273
+ case "finalized":
274
+ return "complete";
275
+ default:
276
+ return status;
277
+ }
278
+ }
279
+
280
+ // src/components/Header.tsx
255
281
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
256
282
  var STATUS_COLOR = {
257
283
  open: "green",
@@ -262,15 +288,18 @@ var STATUS_COLOR = {
262
288
  function Header({ ceremony, subtitle }) {
263
289
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
264
290
  /* @__PURE__ */ jsxs(Box, { children: [
265
- /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u25C6 CEREMONY TUI" }),
291
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u25C6 Umbra Ceremony TUI" }),
266
292
  ceremony && /* @__PURE__ */ jsxs(Fragment, { children: [
267
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
293
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
268
294
  /* @__PURE__ */ jsx(Text, { bold: true, children: ceremony.name }),
269
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: " [" }),
270
- /* @__PURE__ */ jsx(Text, { color: STATUS_COLOR[ceremony.status] ?? "white", children: ceremony.status }),
295
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " [" }),
296
+ /* @__PURE__ */ jsx(Text, { color: STATUS_COLOR[ceremony.status] ?? "white", children: ceremonyStatusLabel(ceremony.status) }),
271
297
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "]" })
272
298
  ] })
273
299
  ] }),
300
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: "Phase 2 trusted-setup contribution \xB7 Groth16 / BN254" }),
301
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "You are adding fresh entropy to Umbra's circuit proving keys. The on-chain privacy of every deposit, claim and transfer holds as long as ONE contributor in this ceremony destroys their secret." }),
302
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press ? at any time for a full explanation of what is happening." }),
274
303
  ceremony && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
275
304
  ceremony.total_tracks,
276
305
  " circuit",
@@ -339,7 +368,10 @@ function QueueView({ ceremonyId: ceremonyId2, trackId, token, onReady, onError }
339
368
  ] });
340
369
  }
341
370
  const waitMins = Math.ceil((status.estimated_wait_secs ?? 0) / 60);
342
- const expiresAt = status.slot_expires_at ? new Date(status.slot_expires_at).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) : null;
371
+ const expiresAt = status.slot_expires_at ? new Date(status.slot_expires_at).toLocaleTimeString([], {
372
+ hour: "2-digit",
373
+ minute: "2-digit"
374
+ }) : null;
343
375
  const fastPoll = status.queue_position <= 2;
344
376
  return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", gap: 1, children: [
345
377
  /* @__PURE__ */ jsxs2(Box2, { gap: 2, children: [
@@ -369,11 +401,7 @@ function QueueView({ ceremonyId: ceremonyId2, trackId, token, onReady, onError }
369
401
  ] }) }) : status.queue_position > 1 ? (
370
402
  // Slot is idle but people are ahead — they joined and left without releasing.
371
403
  // timeout_watchdog will clear each stale slot after contribution_timeout_secs.
372
- /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
373
- "Slot is idle \u2014 waiting for positions ahead to respond or time out",
374
- " ",
375
- "(up to ~5 min each)"
376
- ] })
404
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Slot is idle \u2014 waiting for positions ahead to respond or time out (up to ~5 min each)" })
377
405
  ) : (
378
406
  // Position 1, slot idle — advance_queue should fire shortly.
379
407
  /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Slot is idle \u2014 your turn is being prepared..." })
@@ -457,7 +485,7 @@ function EntropyCollector({ onComplete, onError }) {
457
485
  /* @__PURE__ */ jsx3(Text3, { bold: true, children: "Type anything to generate entropy:" }),
458
486
  /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Keystroke timing (nanosecond intervals) is the randomness source." }),
459
487
  /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, children: [
460
- /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: " > " }),
488
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: " > " }),
461
489
  /* @__PURE__ */ jsx3(Text3, { color: "green", children: stars }),
462
490
  /* @__PURE__ */ jsx3(Text3, { color: "yellow", children: "\u2588" })
463
491
  ] }),
@@ -472,7 +500,7 @@ function EntropyCollector({ onComplete, onError }) {
472
500
  /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
473
501
  "/",
474
502
  TARGET,
475
- " keystrokes (",
503
+ " keystrokes (",
476
504
  pct,
477
505
  "%)"
478
506
  ] })
@@ -569,9 +597,11 @@ function ContributeFlow(props) {
569
597
  await api.signalUploaded(ceremonyId2, trackId, slotStatus.contribution_id, token);
570
598
  if (cancelled) return;
571
599
  setStep({ name: "verifying", attempt: 1 });
600
+ const TOTAL_POLLS = 80;
601
+ const FAST_POLLS = 20;
572
602
  let receipt = null;
573
603
  let lastErr = null;
574
- for (let i = 0; i < 30; i++) {
604
+ for (let i = 0; i < TOTAL_POLLS; i++) {
575
605
  if (cancelled) return;
576
606
  setStep({ name: "verifying", attempt: i + 1 });
577
607
  try {
@@ -580,7 +610,8 @@ function ContributeFlow(props) {
580
610
  break;
581
611
  } catch (err) {
582
612
  lastErr = err instanceof Error ? err : new Error(String(err));
583
- await new Promise((r) => setTimeout(r, 3e3));
613
+ const delay = i < FAST_POLLS ? 3e3 : 1e4;
614
+ await new Promise((r) => setTimeout(r, delay));
584
615
  }
585
616
  }
586
617
  if (cancelled) return;
@@ -615,7 +646,8 @@ function ContributeFlow(props) {
615
646
  const filled = Math.round(pct / 5);
616
647
  const bar = "\u2588".repeat(filled) + "\u2591".repeat(20 - filled);
617
648
  detail = /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
618
- " [",
649
+ " ",
650
+ "[",
619
651
  bar,
620
652
  "] ",
621
653
  pct,
@@ -623,10 +655,15 @@ function ContributeFlow(props) {
623
655
  ] });
624
656
  }
625
657
  if (isActive && step.name === "verifying") {
658
+ const elapsed = step.attempt <= 20 ? step.attempt * 3 : 20 * 3 + (step.attempt - 20) * 10;
659
+ const mins = Math.floor(elapsed / 60);
660
+ const secs = elapsed % 60;
661
+ const time = mins > 0 ? `${mins}m ${secs.toString().padStart(2, "0")}s` : `${secs}s`;
626
662
  detail = /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
627
- " worker verifying... (",
628
- step.attempt,
629
- "/30)"
663
+ " ",
664
+ "worker verifying \u2014 large circuits can take a few minutes (",
665
+ time,
666
+ " elapsed)"
630
667
  ] });
631
668
  }
632
669
  return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
@@ -659,25 +696,25 @@ function Attestation({ contribution }) {
659
696
  const hashShort = contribution.contributionHash ? `${contribution.contributionHash.slice(0, 16)}...${contribution.contributionHash.slice(-8)}` : "(pending verification)";
660
697
  const verifiedAt = contribution.verifiedAt ? new Date(contribution.verifiedAt).toLocaleString() : null;
661
698
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", gap: 1, children: [
662
- /* @__PURE__ */ jsx5(Text5, { bold: true, color: "green", children: "\u2713 Contribution verified!" }),
699
+ /* @__PURE__ */ jsx5(Text5, { bold: true, color: "green", children: "\u2713 Contribution verified!" }),
663
700
  /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", gap: 0, children: [
664
701
  /* @__PURE__ */ jsxs5(Box5, { gap: 2, children: [
665
702
  /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Circuit" }),
666
703
  /* @__PURE__ */ jsx5(Text5, { bold: true, children: contribution.circuitName })
667
704
  ] }),
668
705
  /* @__PURE__ */ jsxs5(Box5, { gap: 2, children: [
669
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Round " }),
706
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Round " }),
670
707
  /* @__PURE__ */ jsxs5(Text5, { bold: true, children: [
671
708
  "#",
672
709
  contribution.sequenceNumber
673
710
  ] })
674
711
  ] }),
675
712
  /* @__PURE__ */ jsxs5(Box5, { gap: 2, children: [
676
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Hash " }),
713
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Hash " }),
677
714
  /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: hashShort })
678
715
  ] }),
679
716
  verifiedAt && /* @__PURE__ */ jsxs5(Box5, { gap: 2, children: [
680
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Time " }),
717
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Time " }),
681
718
  /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: verifiedAt })
682
719
  ] })
683
720
  ] }),
@@ -688,8 +725,32 @@ function Attestation({ contribution }) {
688
725
  ] });
689
726
  }
690
727
 
691
- // src/components/App.tsx
728
+ // src/components/InfoModal.tsx
729
+ import { Box as Box6, Text as Text6 } from "ink";
692
730
  import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
731
+ function InfoModal() {
732
+ return /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsxs6(
733
+ Box6,
734
+ {
735
+ flexDirection: "column",
736
+ borderStyle: "round",
737
+ borderColor: "cyan",
738
+ paddingX: 2,
739
+ paddingY: 1,
740
+ width: 84,
741
+ gap: 1,
742
+ children: [
743
+ /* @__PURE__ */ jsx6(Text6, { bold: true, color: "cyan", children: "Umbra Phase 2 Trusted-Setup Ceremony" }),
744
+ /* @__PURE__ */ jsx6(Text6, { children: "Umbra uses Groth16 zero-knowledge proofs to give Solana users on-chain privacy. Every circuit needs a one-time multi-party ceremony to generate its proving key safely \u2014 that is Phase 2. Each contributor adds their own secret entropy and destroys it afterward. The setup stays secure as long as AT LEAST ONE contributor erased theirs, which is why your single contribution genuinely matters." }),
745
+ /* @__PURE__ */ jsx6(Text6, { children: "What you will do: tap 20 keys to seed your entropy, download the latest challenge file, run snarkjs locally to combine your secret with the parameters, and upload the response. Your secret never leaves your machine. Erase it when you are done." }),
746
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Press B, Esc or ? to close" })
747
+ ]
748
+ }
749
+ ) });
750
+ }
751
+
752
+ // src/components/App.tsx
753
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
693
754
  var NAME_MAX_LEN = 100;
694
755
  var NAME_VALID_RE = /^[\p{L}\p{N} _.\-]*$/u;
695
756
  function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName }) {
@@ -705,6 +766,7 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
705
766
  const [contributed, setContributed] = useState4({});
706
767
  const [selectedIdx, setSelectedIdx] = useState4(0);
707
768
  const [tab, setTab] = useState4(0);
769
+ const [showInfo, setShowInfo] = useState4(false);
708
770
  useEffect4(() => {
709
771
  if (!nameSet) return;
710
772
  if (!initialCeremonyId) {
@@ -719,7 +781,11 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
719
781
  setScreen({ name: "ceremony-picker", ceremonies, loading: false });
720
782
  setSelectedIdx(0);
721
783
  } catch (e) {
722
- setScreen({ name: "error", message: e.message ?? "Failed to load ceremonies.", recoverable: false });
784
+ setScreen({
785
+ name: "error",
786
+ message: e.message ?? "Failed to load ceremonies.",
787
+ recoverable: false
788
+ });
723
789
  }
724
790
  }
725
791
  async function boot(cId) {
@@ -741,7 +807,11 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
741
807
  try {
742
808
  const { tracks } = await api.listTracks(cId, s.session_token);
743
809
  if (tracks.length === 0) {
744
- setScreen({ name: "error", message: "No tracks found in this ceremony.", recoverable: false });
810
+ setScreen({
811
+ name: "error",
812
+ message: "No tracks found in this ceremony.",
813
+ recoverable: false
814
+ });
745
815
  return;
746
816
  }
747
817
  setSelectedIdx(0);
@@ -754,17 +824,29 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
754
824
  setSession(fresh);
755
825
  const { tracks } = await api.listTracks(cId, fresh.session_token);
756
826
  if (tracks.length === 0) {
757
- setScreen({ name: "error", message: "No tracks found in this ceremony.", recoverable: false });
827
+ setScreen({
828
+ name: "error",
829
+ message: "No tracks found in this ceremony.",
830
+ recoverable: false
831
+ });
758
832
  return;
759
833
  }
760
834
  setSelectedIdx(0);
761
835
  setScreen({ name: "tracks", tracks });
762
836
  } catch (e2) {
763
- setScreen({ name: "error", message: e2.message ?? "Failed to load tracks.", recoverable: false });
837
+ setScreen({
838
+ name: "error",
839
+ message: e2.message ?? "Failed to load tracks.",
840
+ recoverable: false
841
+ });
764
842
  }
765
843
  return;
766
844
  }
767
- setScreen({ name: "error", message: e.message ?? "Failed to load tracks.", recoverable: false });
845
+ setScreen({
846
+ name: "error",
847
+ message: e.message ?? "Failed to load tracks.",
848
+ recoverable: false
849
+ });
768
850
  }
769
851
  }
770
852
  function commitName(raw) {
@@ -777,10 +859,9 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
777
859
  );
778
860
  }
779
861
  function randomAnonName() {
780
- const hex = Array.from(
781
- { length: 6 },
782
- () => Math.floor(Math.random() * 16).toString(16)
783
- ).join("");
862
+ const hex = Array.from({ length: 6 }, () => Math.floor(Math.random() * 16).toString(16)).join(
863
+ ""
864
+ );
784
865
  return `anon-${hex}`;
785
866
  }
786
867
  async function joinTrack(track) {
@@ -790,7 +871,11 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
790
871
  await api.joinQueue(activeCeremonyId, track.id, session.session_token);
791
872
  } catch (e) {
792
873
  if (e.code !== "ALREADY_IN_QUEUE") {
793
- setScreen({ name: "error", message: e.message ?? "Failed to join queue.", recoverable: true });
874
+ setScreen({
875
+ name: "error",
876
+ message: e.message ?? "Failed to join queue.",
877
+ recoverable: true
878
+ });
794
879
  return;
795
880
  }
796
881
  }
@@ -818,13 +903,28 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
818
903
  }, [screen.name]);
819
904
  useInput2((input, key) => {
820
905
  const q = input.toLowerCase();
906
+ if (showInfo) {
907
+ if (key.escape || input === "?" || q === "b") {
908
+ setShowInfo(false);
909
+ return;
910
+ }
911
+ if (q === "q") {
912
+ exit();
913
+ return;
914
+ }
915
+ return;
916
+ }
917
+ if (input === "?" && screen.name !== "entropy") {
918
+ setShowInfo(true);
919
+ return;
920
+ }
821
921
  if (screen.name === "name-input") {
822
922
  if (key.escape) {
823
923
  exit();
824
924
  return;
825
925
  }
826
926
  if (key.tab) {
827
- commitName(randomAnonName());
927
+ setScreen({ name: "name-input", value: randomAnonName() });
828
928
  return;
829
929
  }
830
930
  if (key.return) {
@@ -912,49 +1012,53 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
912
1012
  goHome();
913
1013
  }
914
1014
  });
1015
+ if (showInfo) {
1016
+ return /* @__PURE__ */ jsx7(InfoModal, {});
1017
+ }
915
1018
  if (screen.name === "name-input") {
916
1019
  const { value } = screen;
917
1020
  const canSubmit = value.trim().length > 0;
918
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
919
- /* @__PURE__ */ jsx6(Header, { ceremony: null }),
920
- /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginTop: 1, gap: 1, children: [
921
- /* @__PURE__ */ jsx6(Text6, { bold: true, children: "Who are you contributing as?" }),
922
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Your display name appears next to your contributions in the public transcript. Pick anything \u2014 your real name, a handle, or hit Tab for a random anonymous name." }),
923
- /* @__PURE__ */ jsxs6(Box6, { children: [
924
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: " > " }),
925
- /* @__PURE__ */ jsx6(Text6, { children: value }),
926
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", inverse: true, children: " " })
1021
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1022
+ /* @__PURE__ */ jsx7(Header, { ceremony: null }),
1023
+ /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginTop: 1, gap: 1, children: [
1024
+ /* @__PURE__ */ jsx7(Text7, { bold: true, children: "Who are you contributing as?" }),
1025
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Your display name appears next to your contributions in the public transcript. Pick anything \u2014 your real name, a handle, or hit Tab for a random anonymous name." }),
1026
+ /* @__PURE__ */ jsxs7(Box7, { children: [
1027
+ /* @__PURE__ */ jsx7(Text7, { color: "cyan", children: " > " }),
1028
+ /* @__PURE__ */ jsx7(Text7, { children: value }),
1029
+ /* @__PURE__ */ jsx7(Text7, { color: "cyan", inverse: true, children: " " })
927
1030
  ] }),
928
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: canSubmit ? "Enter to continue \xB7 Tab for random \xB7 \u232B backspace \xB7 Esc to quit" : "Type a name, or Tab for a random anonymous name \xB7 Esc to quit" })
1031
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: canSubmit ? "Enter to continue \xB7 Tab rerolls random name \xB7 \u232B backspace \xB7 Esc to quit" : "Type a name, or press Tab to suggest a random anonymous one \xB7 Esc to quit" })
929
1032
  ] })
930
1033
  ] });
931
1034
  }
932
1035
  if (screen.name === "ceremony-picker") {
933
1036
  const { ceremonies, loading } = screen;
934
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
935
- /* @__PURE__ */ jsx6(Header, { ceremony: null }),
936
- loading ? /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Loading ceremonies..." }) : ceremonies.length === 0 ? /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", gap: 1, children: [
937
- /* @__PURE__ */ jsx6(Text6, { color: "yellow", children: "No ceremonies found." }),
938
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "The server may not have any active ceremonies yet." }),
939
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Q to quit" })
940
- ] }) : /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
941
- /* @__PURE__ */ jsx6(Text6, { bold: true, children: "Select a ceremony:" }),
942
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " " + "\u2500".repeat(60) }),
1037
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1038
+ /* @__PURE__ */ jsx7(Header, { ceremony: null }),
1039
+ loading ? /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Loading ceremonies..." }) : ceremonies.length === 0 ? /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", gap: 1, children: [
1040
+ /* @__PURE__ */ jsx7(Text7, { color: "yellow", children: "No ceremonies found." }),
1041
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "The server may not have any active ceremonies yet." }),
1042
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Q to quit" })
1043
+ ] }) : /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1044
+ /* @__PURE__ */ jsx7(Text7, { bold: true, children: "Select a ceremony:" }),
1045
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " " + "\u2500".repeat(60) }),
943
1046
  ceremonies.map((c, i) => {
944
1047
  const isSelected = i === selectedIdx;
945
1048
  const isOpen = c.status === "open";
946
1049
  const statusColor = c.status === "open" ? "green" : c.status === "completed" ? "cyan" : "yellow";
947
- return /* @__PURE__ */ jsxs6(Box6, { gap: 2, children: [
948
- /* @__PURE__ */ jsxs6(Text6, { color: isSelected ? "cyan" : isOpen ? void 0 : "gray", children: [
1050
+ const statusLabel = ceremonyStatusLabel(c.status);
1051
+ return /* @__PURE__ */ jsxs7(Box7, { gap: 2, children: [
1052
+ /* @__PURE__ */ jsxs7(Text7, { color: isSelected ? "cyan" : isOpen ? void 0 : "gray", children: [
949
1053
  isSelected ? "\u25B6 " : " ",
950
1054
  c.name.padEnd(30)
951
1055
  ] }),
952
- /* @__PURE__ */ jsxs6(Text6, { color: statusColor, children: [
1056
+ /* @__PURE__ */ jsxs7(Text7, { color: statusColor, children: [
953
1057
  "[",
954
- c.status,
1058
+ statusLabel,
955
1059
  "]"
956
1060
  ] }),
957
- /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
1061
+ /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
958
1062
  c.track_count,
959
1063
  " track",
960
1064
  c.track_count !== 1 ? "s" : "",
@@ -965,159 +1069,164 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
965
1069
  ] })
966
1070
  ] }, c.id);
967
1071
  }),
968
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " " + "\u2500".repeat(60) }),
1072
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " " + "\u2500".repeat(60) }),
969
1073
  (() => {
970
1074
  const c = ceremonies[selectedIdx];
971
1075
  if (!c) return null;
972
1076
  if (c.status === "initialized") {
973
- return /* @__PURE__ */ jsxs6(Text6, { color: "yellow", children: [
974
- " Not open yet \u2014 admin: run initialize ",
975
- "<id>",
976
- " then open ",
977
- "<id>",
978
- " to start contributions."
1077
+ return /* @__PURE__ */ jsxs7(Text7, { color: "yellow", children: [
1078
+ " ",
1079
+ "This ceremony is not yet open for contributions. The Umbra team is still preparing the circuits \u2014 please check back shortly."
979
1080
  ] });
980
1081
  }
981
1082
  if (c.status === "finalizing") {
982
- return /* @__PURE__ */ jsx6(Text6, { color: "yellow", children: " Contribution phase is closed \u2014 ceremony is applying the final beacon." });
1083
+ return /* @__PURE__ */ jsxs7(Text7, { color: "yellow", children: [
1084
+ " ",
1085
+ "Contributions are closed. The ceremony is computing the final verification key \u2014 no further contributions can be added."
1086
+ ] });
983
1087
  }
984
1088
  if (c.status === "completed") {
985
- return /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: " Ceremony complete \u2014 verification keys are available." });
1089
+ return /* @__PURE__ */ jsxs7(Text7, { color: "cyan", children: [
1090
+ " ",
1091
+ "Ceremony complete. The verification keys are finalised \u2014 thank you to everyone who contributed."
1092
+ ] });
986
1093
  }
987
- return /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "\u2191/\u2193 select \xB7 Enter join \xB7 Q quit" });
1094
+ return /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "\u2191/\u2193 select \xB7 Enter join \xB7 Q quit" });
988
1095
  })()
989
1096
  ] })
990
1097
  ] });
991
1098
  }
992
1099
  if (screen.name === "loading") {
993
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
994
- /* @__PURE__ */ jsx6(Header, { ceremony }),
995
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Loading tracks..." })
1100
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1101
+ /* @__PURE__ */ jsx7(Header, { ceremony }),
1102
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Loading tracks..." })
996
1103
  ] });
997
1104
  }
998
1105
  if (screen.name === "error") {
999
1106
  const backHint = !initialCeremonyId ? "\u232B Backspace \u2014 back to ceremony list \xB7 Q to quit" : screen.recoverable ? "\u232B Backspace / B to go back \xB7 Q to quit" : "Q to quit";
1000
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1001
- /* @__PURE__ */ jsx6(Header, { ceremony }),
1002
- /* @__PURE__ */ jsxs6(Text6, { color: "red", bold: true, children: [
1003
- "\u2717 ",
1107
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1108
+ /* @__PURE__ */ jsx7(Header, { ceremony }),
1109
+ /* @__PURE__ */ jsxs7(Text7, { color: "red", bold: true, children: [
1110
+ "\u2717 ",
1004
1111
  screen.message
1005
1112
  ] }),
1006
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: backHint })
1113
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: backHint })
1007
1114
  ] });
1008
1115
  }
1009
1116
  if (screen.name === "tracks") {
1010
1117
  const { tracks } = screen;
1011
1118
  const openTracks = tracks.filter((t) => t.status === "open");
1012
- const myContributions = Object.values(contributed).filter((c) => c.ceremonyId === activeCeremonyId);
1013
- const TabBar = () => /* @__PURE__ */ jsxs6(Box6, { gap: 1, marginBottom: 1, children: [
1014
- /* @__PURE__ */ jsx6(Text6, { bold: tab === 0, color: tab === 0 ? "cyan" : void 0, dimColor: tab !== 0, children: tab === 0 ? "[ Dashboard ]" : " Dashboard " }),
1015
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "|" }),
1016
- /* @__PURE__ */ jsx6(Text6, { bold: tab === 1, color: tab === 1 ? "cyan" : void 0, dimColor: tab !== 1, children: tab === 1 ? `[ My Contributions (${myContributions.length}) ]` : ` My Contributions (${myContributions.length}) ` }),
1017
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " Tab to switch" })
1119
+ const myContributions = Object.values(contributed).filter(
1120
+ (c) => c.ceremonyId === activeCeremonyId
1121
+ );
1122
+ const TabBar = () => /* @__PURE__ */ jsxs7(Box7, { gap: 1, marginBottom: 1, children: [
1123
+ /* @__PURE__ */ jsx7(Text7, { bold: tab === 0, color: tab === 0 ? "cyan" : void 0, dimColor: tab !== 0, children: tab === 0 ? "[ Dashboard ]" : " Dashboard " }),
1124
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "|" }),
1125
+ /* @__PURE__ */ jsx7(Text7, { bold: tab === 1, color: tab === 1 ? "cyan" : void 0, dimColor: tab !== 1, children: tab === 1 ? `[ My Contributions (${myContributions.length}) ]` : ` My Contributions (${myContributions.length}) ` }),
1126
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " Tab to switch" })
1018
1127
  ] });
1019
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1020
- /* @__PURE__ */ jsx6(Header, { ceremony }),
1021
- /* @__PURE__ */ jsx6(TabBar, {}),
1128
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1129
+ /* @__PURE__ */ jsx7(Header, { ceremony }),
1130
+ /* @__PURE__ */ jsx7(TabBar, {}),
1022
1131
  tab === 0 ? (
1023
1132
  // ── Dashboard tab ────────────────────────────────────────────────
1024
- /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1025
- /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
1133
+ /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1134
+ /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
1026
1135
  " CIRCUIT".padEnd(30),
1027
1136
  "TOTAL".padEnd(10),
1028
1137
  "QUEUE".padEnd(8),
1029
- "STATUS".padEnd(14),
1138
+ "STATUS".padEnd(16),
1030
1139
  "MY CONTRIBUTIONS"
1031
1140
  ] }),
1032
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " " + "\u2500".repeat(68) }),
1141
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " " + "\u2500".repeat(70) }),
1033
1142
  tracks.map((t, i) => {
1034
1143
  const isSelected = i === selectedIdx;
1035
1144
  const canContribute = t.status === "open";
1036
1145
  const nameClipped = t.circuit_name.length > 26 ? t.circuit_name.slice(0, 24) + ".." : t.circuit_name;
1037
1146
  const statusColor = t.status === "open" ? "green" : t.status === "finalized" ? "cyan" : "yellow";
1038
1147
  const myContrib = contributed[t.id];
1039
- return /* @__PURE__ */ jsxs6(Box6, { children: [
1040
- /* @__PURE__ */ jsxs6(Text6, { color: isSelected ? "cyan" : canContribute ? void 0 : "gray", children: [
1148
+ return /* @__PURE__ */ jsxs7(Box7, { children: [
1149
+ /* @__PURE__ */ jsxs7(Text7, { color: isSelected ? "cyan" : canContribute ? void 0 : "gray", children: [
1041
1150
  isSelected ? "\u25B6 " : " ",
1042
1151
  nameClipped.padEnd(28),
1043
1152
  String(t.contribution_count).padEnd(10),
1044
1153
  String(t.queue_depth).padEnd(8)
1045
1154
  ] }),
1046
- /* @__PURE__ */ jsx6(Text6, { color: statusColor, children: t.status.padEnd(14) }),
1047
- myContrib ? isSelected ? /* @__PURE__ */ jsxs6(Text6, { color: "green", children: [
1155
+ /* @__PURE__ */ jsx7(Text7, { color: statusColor, children: trackStatusLabel(t.status).padEnd(16) }),
1156
+ myContrib ? isSelected ? /* @__PURE__ */ jsxs7(Text7, { color: "green", children: [
1048
1157
  "\u2713 contributed (round #",
1049
1158
  myContrib.sequenceNumber,
1050
- ") \u2014 already done"
1051
- ] }) : /* @__PURE__ */ jsxs6(Text6, { color: "green", children: [
1052
- "\u2713 contributed (round #",
1159
+ ") \u2014 already done"
1160
+ ] }) : /* @__PURE__ */ jsxs7(Text7, { color: "green", children: [
1161
+ "\u2713 contributed (round #",
1053
1162
  myContrib.sequenceNumber,
1054
1163
  ")"
1055
- ] }) : canContribute ? isSelected ? /* @__PURE__ */ jsx6(Text6, { color: "yellow", children: "\u2190 Enter to contribute" }) : /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "not contributed" }) : /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "\u2014" })
1164
+ ] }) : canContribute ? isSelected ? /* @__PURE__ */ jsx7(Text7, { color: "yellow", children: "\u2190 Enter to contribute" }) : /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "not contributed" }) : /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "\u2014" })
1056
1165
  ] }, t.id);
1057
1166
  }),
1058
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " " + "\u2500".repeat(68) }),
1059
- openTracks.length === 0 ? /* @__PURE__ */ jsx6(Text6, { color: "yellow", children: "No open tracks \u2014 ceremony may be finalizing or complete." }) : /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
1060
- "\u2191/\u2193 select \xB7 Enter contribute \xB7 R refresh \xB7 Q quit",
1167
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " " + "\u2500".repeat(70) }),
1168
+ openTracks.length === 0 ? /* @__PURE__ */ jsx7(Text7, { color: "yellow", children: "No circuits are open for contributions right now \u2014 the ceremony may be closing or already complete." }) : /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
1169
+ "\u2191/\u2193 select \xB7 Enter contribute \xB7 R refresh \xB7 Q quit",
1061
1170
  !initialCeremonyId ? " \xB7 \u232B back to ceremony list" : ""
1062
1171
  ] })
1063
1172
  ] })
1064
1173
  ) : (
1065
1174
  // ── My Contributions tab ─────────────────────────────────────────
1066
- /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", children: myContributions.length === 0 ? /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", gap: 1, children: [
1067
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "No contributions yet." }),
1068
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Switch to Dashboard tab and press Enter on a circuit to contribute." })
1069
- ] }) : /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1070
- /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
1175
+ /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", children: myContributions.length === 0 ? /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", gap: 1, children: [
1176
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "No contributions yet." }),
1177
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Switch to Dashboard tab and press Enter on a circuit to contribute." })
1178
+ ] }) : /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1179
+ /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
1071
1180
  " CIRCUIT".padEnd(28),
1072
1181
  "ROUND".padEnd(8),
1073
1182
  "HASH".padEnd(20),
1074
1183
  "TIME"
1075
1184
  ] }),
1076
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " " + "\u2500".repeat(68) }),
1077
- myContributions.map((c, i) => /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1078
- /* @__PURE__ */ jsxs6(Box6, { children: [
1079
- /* @__PURE__ */ jsx6(Text6, { color: "green", children: " \u2713 " }),
1080
- /* @__PURE__ */ jsx6(Text6, { bold: true, children: c.circuitName.padEnd(24) }),
1081
- /* @__PURE__ */ jsx6(Text6, { color: "yellow", children: "#" + c.sequenceNumber + " " }),
1082
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: c.contributionHash ? c.contributionHash.slice(0, 16) + "..." : "(pending)" })
1185
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " " + "\u2500".repeat(68) }),
1186
+ myContributions.map((c, i) => /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1187
+ /* @__PURE__ */ jsxs7(Box7, { children: [
1188
+ /* @__PURE__ */ jsx7(Text7, { color: "green", children: " \u2713 " }),
1189
+ /* @__PURE__ */ jsx7(Text7, { bold: true, children: c.circuitName.padEnd(24) }),
1190
+ /* @__PURE__ */ jsx7(Text7, { color: "yellow", children: "#" + c.sequenceNumber + " " }),
1191
+ /* @__PURE__ */ jsx7(Text7, { color: "cyan", children: c.contributionHash ? c.contributionHash.slice(0, 16) + "..." : "(pending)" })
1083
1192
  ] }),
1084
- /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
1193
+ /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
1085
1194
  " ",
1086
1195
  c.verifiedAt ? new Date(c.verifiedAt).toLocaleString() : ""
1087
1196
  ] })
1088
1197
  ] }, i)),
1089
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " " + "\u2500".repeat(68) }),
1090
- /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
1198
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " " + "\u2500".repeat(68) }),
1199
+ /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
1091
1200
  "Total: ",
1092
1201
  myContributions.length,
1093
1202
  " contribution",
1094
1203
  myContributions.length !== 1 ? "s" : "",
1095
1204
  " \xB7 ",
1096
- "Tab to switch \xB7 Q to quit"
1205
+ "Tab to switch \xB7 Q to quit"
1097
1206
  ] })
1098
1207
  ] }) })
1099
1208
  )
1100
1209
  ] });
1101
1210
  }
1102
1211
  if (screen.name === "joining") {
1103
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1104
- /* @__PURE__ */ jsx6(Header, { ceremony }),
1105
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Joining queue..." })
1212
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1213
+ /* @__PURE__ */ jsx7(Header, { ceremony }),
1214
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Joining queue..." })
1106
1215
  ] });
1107
1216
  }
1108
1217
  if (screen.name === "queue") {
1109
1218
  const { trackId, circuitName } = screen;
1110
1219
  const priorContrib = contributed[trackId];
1111
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1112
- /* @__PURE__ */ jsx6(Header, { ceremony, subtitle: `Circuit: ${circuitName}` }),
1113
- priorContrib && /* @__PURE__ */ jsx6(Box6, { marginBottom: 1, paddingX: 1, children: /* @__PURE__ */ jsxs6(Text6, { color: "yellow", children: [
1114
- "\u26A0 You already contributed to this circuit (round #",
1220
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1221
+ /* @__PURE__ */ jsx7(Header, { ceremony, subtitle: `Circuit: ${circuitName}` }),
1222
+ priorContrib && /* @__PURE__ */ jsx7(Box7, { marginBottom: 1, paddingX: 1, children: /* @__PURE__ */ jsxs7(Text7, { color: "yellow", children: [
1223
+ "\u26A0 You already contributed to this circuit (round #",
1115
1224
  priorContrib.sequenceNumber,
1116
1225
  ").",
1117
1226
  " ",
1118
1227
  "Contributing again is allowed and adds more entropy."
1119
1228
  ] }) }),
1120
- /* @__PURE__ */ jsx6(
1229
+ /* @__PURE__ */ jsx7(
1121
1230
  QueueView,
1122
1231
  {
1123
1232
  ceremonyId: activeCeremonyId,
@@ -1127,14 +1236,14 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
1127
1236
  onError: (e) => setScreen({ name: "error", message: e.message, recoverable: true })
1128
1237
  }
1129
1238
  ),
1130
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "\u232B Backspace to go back \xB7 Q to quit" })
1239
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "\u232B Backspace to go back \xB7 Q to quit" })
1131
1240
  ] });
1132
1241
  }
1133
1242
  if (screen.name === "entropy") {
1134
1243
  const { trackId, circuitName, slotStatus } = screen;
1135
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1136
- /* @__PURE__ */ jsx6(Header, { ceremony, subtitle: `Circuit: ${circuitName} \xB7 Your turn!` }),
1137
- /* @__PURE__ */ jsx6(
1244
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1245
+ /* @__PURE__ */ jsx7(Header, { ceremony, subtitle: `Circuit: ${circuitName} \xB7 Your turn!` }),
1246
+ /* @__PURE__ */ jsx7(
1138
1247
  EntropyCollector,
1139
1248
  {
1140
1249
  onComplete: (entropy) => setScreen({ name: "contribute", trackId, circuitName, slotStatus, entropy }),
@@ -1145,9 +1254,9 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
1145
1254
  }
1146
1255
  if (screen.name === "contribute") {
1147
1256
  const { trackId, circuitName, slotStatus, entropy } = screen;
1148
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1149
- /* @__PURE__ */ jsx6(Header, { ceremony, subtitle: `Circuit: ${circuitName} \xB7 Contributing` }),
1150
- /* @__PURE__ */ jsx6(
1257
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1258
+ /* @__PURE__ */ jsx7(Header, { ceremony, subtitle: `Circuit: ${circuitName} \xB7 Contributing` }),
1259
+ /* @__PURE__ */ jsx7(
1151
1260
  ContributeFlow,
1152
1261
  {
1153
1262
  ceremonyId: activeCeremonyId,
@@ -1176,17 +1285,17 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
1176
1285
  }
1177
1286
  if (screen.name === "done") {
1178
1287
  const { contribution } = screen;
1179
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1180
- /* @__PURE__ */ jsx6(Header, { ceremony }),
1181
- /* @__PURE__ */ jsx6(Attestation, { contribution }),
1182
- /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "\u232B Backspace / B = contribute to another circuit \xB7 Q to quit" }) })
1288
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1289
+ /* @__PURE__ */ jsx7(Header, { ceremony }),
1290
+ /* @__PURE__ */ jsx7(Attestation, { contribution }),
1291
+ /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "\u232B Backspace / B = contribute to another circuit \xB7 Q to quit" }) })
1183
1292
  ] });
1184
1293
  }
1185
1294
  return null;
1186
1295
  }
1187
1296
 
1188
1297
  // src/index.tsx
1189
- import { jsx as jsx7 } from "react/jsx-runtime";
1298
+ import { jsx as jsx8 } from "react/jsx-runtime";
1190
1299
  var ceremonyId = process.env["CEREMONY_ID"] ?? "";
1191
1300
  var displayName = process.env["CONTRIBUTOR_NAME"];
1192
1301
  process.stdout.write("\x1B[?1049h\x1B[H");
@@ -1210,10 +1319,9 @@ process.on("SIGTERM", () => {
1210
1319
  process.exit(0);
1211
1320
  });
1212
1321
  });
1213
- var { waitUntilExit } = render(
1214
- /* @__PURE__ */ jsx7(App, { ceremonyId, displayName }),
1215
- { exitOnCtrlC: false }
1216
- );
1322
+ var { waitUntilExit } = render(/* @__PURE__ */ jsx8(App, { ceremonyId, displayName }), {
1323
+ exitOnCtrlC: false
1324
+ });
1217
1325
  await waitUntilExit();
1218
1326
  restoreScreen();
1219
1327
  process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umbra-privacy/ceremony",
3
- "version": "0.1.4",
3
+ "version": "0.2.5",
4
4
  "description": "Terminal UI for the Umbra Phase 2 trusted setup ceremony",
5
5
  "type": "module",
6
6
  "bin": {