@umbra-privacy/ceremony 0.2.9 → 0.2.10

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 +108 -57
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -313,18 +313,27 @@ function trackStatusLabel(status) {
313
313
  }
314
314
  }
315
315
 
316
+ // src/theme.ts
317
+ var COLORS = {
318
+ /** Primary Umbra brand colour — #00B3FF. */
319
+ BRAND: "#00B3FF",
320
+ SUCCESS: "greenBright",
321
+ EMPHASIS: "cyanBright",
322
+ MUTED: "cyan"
323
+ };
324
+
316
325
  // src/components/Header.tsx
317
326
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
318
327
  var STATUS_COLOR = {
319
328
  open: "green",
320
329
  initialized: "yellow",
321
330
  finalizing: "yellow",
322
- completed: "cyan"
331
+ completed: COLORS.BRAND
323
332
  };
324
333
  function Header({ ceremony, subtitle }) {
325
334
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
326
335
  /* @__PURE__ */ jsxs(Box, { children: [
327
- /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u25C6 Umbra Ceremony TUI" }),
336
+ /* @__PURE__ */ jsx(Text, { bold: true, color: COLORS.BRAND, children: "\u25C6 Umbra Ceremony" }),
328
337
  ceremony && /* @__PURE__ */ jsxs(Fragment, { children: [
329
338
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
330
339
  /* @__PURE__ */ jsx(Text, { bold: true, children: ceremony.name }),
@@ -333,7 +342,7 @@ function Header({ ceremony, subtitle }) {
333
342
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "]" })
334
343
  ] })
335
344
  ] }),
336
- /* @__PURE__ */ jsx(Text, { color: "cyan", children: "Phase 2 trusted-setup contribution \xB7 Groth16 / BN254" }),
345
+ /* @__PURE__ */ jsx(Text, { color: COLORS.BRAND, children: "Phase 2 trusted-setup contribution \xB7 Groth16 / BN254" }),
337
346
  /* @__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." }),
338
347
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press ? at any time for a full explanation of what is happening." }),
339
348
  ceremony && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
@@ -1018,7 +1027,7 @@ function MouseEntropyCollector({ title, onComplete, onError }) {
1018
1027
  "\u2518"
1019
1028
  ] }),
1020
1029
  /* @__PURE__ */ jsxs3(Box3, { gap: 2, children: [
1021
- /* @__PURE__ */ jsxs3(Text3, { color: ready ? "green" : "cyan", children: [
1030
+ /* @__PURE__ */ jsxs3(Text3, { color: ready ? COLORS.SUCCESS : COLORS.BRAND, children: [
1022
1031
  "[",
1023
1032
  bar,
1024
1033
  "]"
@@ -1039,7 +1048,7 @@ function MouseEntropyCollector({ title, onComplete, onError }) {
1039
1048
  ] }),
1040
1049
  nudge && /* @__PURE__ */ jsx3(Text3, { color: "yellow", children: nudge })
1041
1050
  ] }),
1042
- /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Enter = commit \xB7 c / \u232B = clear \xB7 Ctrl+C / Ctrl+Z = abort" })
1051
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Enter = commit \xB7 c / \u232B = clear \xB7 Ctrl+C = abort" })
1043
1052
  ] });
1044
1053
  }
1045
1054
 
@@ -1097,7 +1106,7 @@ function EntropyCollector({ onComplete, onError }) {
1097
1106
  /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: "\u2588" })
1098
1107
  ] }),
1099
1108
  /* @__PURE__ */ jsxs4(Box4, { gap: 2, marginTop: 1, children: [
1100
- /* @__PURE__ */ jsxs4(Text4, { color: "cyan", children: [
1109
+ /* @__PURE__ */ jsxs4(Text4, { color: COLORS.BRAND, children: [
1101
1110
  "[",
1102
1111
  bar,
1103
1112
  "]"
@@ -1114,7 +1123,7 @@ function EntropyCollector({ onComplete, onError }) {
1114
1123
  ] })
1115
1124
  ] }),
1116
1125
  /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Shown as * \u2014 your actual input is never revealed." }),
1117
- /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "To quit without contributing: Ctrl+C or Ctrl+Z (Q is part of the entropy alphabet here)." })
1126
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "To quit without contributing: Ctrl+C (Q is part of the entropy alphabet here)." })
1118
1127
  ] });
1119
1128
  }
1120
1129
 
@@ -1318,16 +1327,13 @@ function ContributeFlow(props) {
1318
1327
  /* @__PURE__ */ jsxs5(Box5, { marginTop: 1, flexDirection: "column", children: [
1319
1328
  /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
1320
1329
  /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
1321
- "Need to bail? Press",
1322
- " ",
1330
+ "Need to bail? Press ",
1323
1331
  /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Q" }),
1324
- ", ",
1332
+ " or ",
1325
1333
  /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Ctrl+C" }),
1326
- ", or ",
1327
- /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Ctrl+Z" }),
1328
1334
  " \u2014 your slot is released immediately so the next contributor can take over."
1329
1335
  ] }),
1330
- step.name === "computing" && /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "(During this step snarkjs is busy \u2014 Ctrl+C / Ctrl+Z respond faster than Q.)" })
1336
+ step.name === "computing" && /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "(During this step snarkjs is busy \u2014 Ctrl+C responds faster than Q.)" })
1331
1337
  ] })
1332
1338
  ] });
1333
1339
  }
@@ -1339,31 +1345,40 @@ function Attestation({ contribution }) {
1339
1345
  const hashShort = contribution.contributionHash ? `${contribution.contributionHash.slice(0, 16)}...${contribution.contributionHash.slice(-8)}` : "(pending verification)";
1340
1346
  const verifiedAt = contribution.verifiedAt ? new Date(contribution.verifiedAt).toLocaleString() : null;
1341
1347
  return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", gap: 1, children: [
1342
- /* @__PURE__ */ jsx6(Text6, { bold: true, color: "green", children: "\u2713 Contribution verified!" }),
1348
+ /* @__PURE__ */ jsx6(Text6, { bold: true, color: "greenBright", children: "\u2714 Contribution verified!" }),
1343
1349
  /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", gap: 0, children: [
1344
1350
  /* @__PURE__ */ jsxs6(Box6, { gap: 2, children: [
1345
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Circuit" }),
1346
- /* @__PURE__ */ jsx6(Text6, { bold: true, children: contribution.circuitName })
1351
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, color: "cyan", children: "Circuit" }),
1352
+ /* @__PURE__ */ jsx6(Text6, { bold: true, color: "blueBright", children: contribution.circuitName })
1347
1353
  ] }),
1348
1354
  /* @__PURE__ */ jsxs6(Box6, { gap: 2, children: [
1349
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Round " }),
1350
- /* @__PURE__ */ jsxs6(Text6, { bold: true, children: [
1355
+ /* @__PURE__ */ jsxs6(Text6, { dimColor: true, color: "cyan", children: [
1356
+ "Round",
1357
+ " "
1358
+ ] }),
1359
+ /* @__PURE__ */ jsxs6(Text6, { bold: true, color: "greenBright", children: [
1351
1360
  "#",
1352
1361
  contribution.sequenceNumber
1353
1362
  ] })
1354
1363
  ] }),
1355
1364
  /* @__PURE__ */ jsxs6(Box6, { gap: 2, children: [
1356
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Hash " }),
1357
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: hashShort })
1365
+ /* @__PURE__ */ jsxs6(Text6, { dimColor: true, color: "cyan", children: [
1366
+ "Hash",
1367
+ " "
1368
+ ] }),
1369
+ /* @__PURE__ */ jsx6(Text6, { color: "cyanBright", children: hashShort })
1358
1370
  ] }),
1359
1371
  verifiedAt && /* @__PURE__ */ jsxs6(Box6, { gap: 2, children: [
1360
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Time " }),
1372
+ /* @__PURE__ */ jsxs6(Text6, { dimColor: true, color: "cyan", children: [
1373
+ "Time",
1374
+ " "
1375
+ ] }),
1361
1376
  /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: verifiedAt })
1362
1377
  ] })
1363
1378
  ] }),
1364
1379
  contribution.contributionHash && /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginTop: 1, children: [
1365
1380
  /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Full hash (share this to prove participation):" }),
1366
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", wrap: "wrap", children: contribution.contributionHash })
1381
+ /* @__PURE__ */ jsx6(Text6, { color: "cyanBright", wrap: "wrap", children: contribution.contributionHash })
1367
1382
  ] })
1368
1383
  ] });
1369
1384
  }
@@ -1392,6 +1407,22 @@ function InfoModal() {
1392
1407
  ) });
1393
1408
  }
1394
1409
 
1410
+ // src/exit-hints.ts
1411
+ var QUIT_HINTS = {
1412
+ /** Idle screens with no active slot — ceremony picker, tracks list, etc. */
1413
+ quit: "Q / Ctrl+C to quit",
1414
+ /** Auto-mode driving the loop — emphasises "abort run", not just "quit". */
1415
+ abortRun: "Q / Ctrl+C abort run",
1416
+ /** Between-circuits auto-mode "queueing" — calls out the slot-release side effect. */
1417
+ abortSlot: "Q / Ctrl+C to abort (releases any active slot)"
1418
+ };
1419
+
1420
+ // src/slot-release.ts
1421
+ function fireAndForgetLeaveQueue(ceremonyId2, trackId, sessionToken) {
1422
+ api.leaveQueue(ceremonyId2, trackId, sessionToken).catch(() => {
1423
+ });
1424
+ }
1425
+
1395
1426
  // src/components/App.tsx
1396
1427
  import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1397
1428
  var NAME_MAX_LEN = 100;
@@ -1584,10 +1615,8 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
1584
1615
  }
1585
1616
  }
1586
1617
  if (trackId && session) {
1587
- setQueueCleanup(() => {
1588
- api.leaveQueue(activeCeremonyId, trackId, session.session_token).catch(() => {
1589
- });
1590
- });
1618
+ const sessionToken = session.session_token;
1619
+ setQueueCleanup(() => fireAndForgetLeaveQueue(activeCeremonyId, trackId, sessionToken));
1591
1620
  } else {
1592
1621
  clearQueueCleanup();
1593
1622
  }
@@ -1655,12 +1684,13 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
1655
1684
  ]);
1656
1685
  useInput3((input, key) => {
1657
1686
  const q = input.toLowerCase();
1687
+ const isQuit = q === "q" || key.ctrl === true && q === "c";
1658
1688
  if (showInfo) {
1659
1689
  if (key.escape || input === "?" || q === "b") {
1660
1690
  setShowInfo(false);
1661
1691
  return;
1662
1692
  }
1663
- if (q === "q") {
1693
+ if (isQuit) {
1664
1694
  exit();
1665
1695
  return;
1666
1696
  }
@@ -1671,7 +1701,7 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
1671
1701
  return;
1672
1702
  }
1673
1703
  if (screen.name === "name-input") {
1674
- if (key.escape) {
1704
+ if (key.ctrl === true && q === "c") {
1675
1705
  exit();
1676
1706
  return;
1677
1707
  }
@@ -1687,13 +1717,13 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
1687
1717
  setScreen({ name: "name-input", value: screen.value.slice(0, -1) });
1688
1718
  return;
1689
1719
  }
1690
- if (input && input.length === 1 && NAME_VALID_RE.test(input)) {
1720
+ if (input && input.length === 1 && !key.ctrl && !key.meta && NAME_VALID_RE.test(input)) {
1691
1721
  if (screen.value.length >= NAME_MAX_LEN) return;
1692
1722
  setScreen({ name: "name-input", value: screen.value + input });
1693
1723
  }
1694
1724
  return;
1695
1725
  }
1696
- if (q === "q" && screen.name !== "entropy" && screen.name !== "auto-entropy") {
1726
+ if (isQuit && screen.name !== "entropy" && screen.name !== "auto-entropy") {
1697
1727
  let trackId = null;
1698
1728
  if (screen.name === "queue" || screen.name === "contribute") {
1699
1729
  trackId = screen.trackId;
@@ -1705,8 +1735,7 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
1705
1735
  if (trackId && session) {
1706
1736
  clearQueueCleanup();
1707
1737
  clearSessionCleanup();
1708
- api.leaveQueue(activeCeremonyId, trackId, session.session_token).catch(() => {
1709
- });
1738
+ fireAndForgetLeaveQueue(activeCeremonyId, trackId, session.session_token);
1710
1739
  clearSession().catch(() => {
1711
1740
  });
1712
1741
  setTimeout(() => exit(), 500);
@@ -1884,7 +1913,7 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
1884
1913
  /* @__PURE__ */ jsx8(Text8, { children: value }),
1885
1914
  /* @__PURE__ */ jsx8(Text8, { color: "cyan", inverse: true, children: " " })
1886
1915
  ] }),
1887
- /* @__PURE__ */ jsx8(Text8, { 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" })
1916
+ /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: canSubmit ? "Enter to continue \xB7 Tab rerolls random name \xB7 \u232B backspace \xB7 Ctrl+C to quit" : "Type a name, or press Tab to suggest a random anonymous one \xB7 Ctrl+C to quit" })
1888
1917
  ] })
1889
1918
  ] });
1890
1919
  }
@@ -1894,11 +1923,11 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
1894
1923
  /* @__PURE__ */ jsx8(Header, { ceremony: null }),
1895
1924
  loading ? /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
1896
1925
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Loading ceremonies..." }),
1897
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Q / Ctrl+C / Ctrl+Z to quit" }) })
1926
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: QUIT_HINTS.quit }) })
1898
1927
  ] }) : ceremonies.length === 0 ? /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", gap: 1, children: [
1899
1928
  /* @__PURE__ */ jsx8(Text8, { color: "yellow", children: "No ceremonies found." }),
1900
1929
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "The server may not have any active ceremonies yet." }),
1901
- /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Q to quit" })
1930
+ /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: QUIT_HINTS.quit })
1902
1931
  ] }) : /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
1903
1932
  /* @__PURE__ */ jsx8(Text8, { bold: true, children: "Select a ceremony:" }),
1904
1933
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: " " + "\u2500".repeat(60) }),
@@ -1932,7 +1961,10 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
1932
1961
  (() => {
1933
1962
  const c = ceremonies[selectedIdx];
1934
1963
  if (!c) return null;
1935
- const navHint = /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "\u2191/\u2193 select \xB7 Enter join \xB7 Q / Ctrl+C / Ctrl+Z to quit" });
1964
+ const navHint = /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
1965
+ "\u2191/\u2193 select \xB7 Enter join \xB7 ",
1966
+ QUIT_HINTS.quit
1967
+ ] }) });
1936
1968
  if (c.status === "initialized") {
1937
1969
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
1938
1970
  /* @__PURE__ */ jsxs8(Text8, { color: "yellow", children: [
@@ -1953,9 +1985,12 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
1953
1985
  }
1954
1986
  if (c.status === "completed") {
1955
1987
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
1956
- /* @__PURE__ */ jsxs8(Text8, { color: "cyan", children: [
1988
+ /* @__PURE__ */ jsxs8(Text8, { children: [
1957
1989
  " ",
1958
- "Ceremony complete. The verification keys are finalised \u2014 thank you to everyone who contributed."
1990
+ /* @__PURE__ */ jsx8(Text8, { color: "greenBright", bold: true, children: "\u2714 Ceremony complete." }),
1991
+ " ",
1992
+ /* @__PURE__ */ jsx8(Text8, { color: "cyanBright", children: "The verification keys are finalised" }),
1993
+ /* @__PURE__ */ jsx8(Text8, { color: "blueBright", children: " \u2014 thank you to everyone who contributed." })
1959
1994
  ] }),
1960
1995
  navHint
1961
1996
  ] });
@@ -1969,7 +2004,7 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
1969
2004
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
1970
2005
  /* @__PURE__ */ jsx8(Header, { ceremony }),
1971
2006
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Loading tracks..." }),
1972
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Q / Ctrl+C / Ctrl+Z to quit" }) })
2007
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: QUIT_HINTS.quit }) })
1973
2008
  ] });
1974
2009
  }
1975
2010
  if (screen.name === "mode-select") {
@@ -2017,7 +2052,10 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
2017
2052
  ]
2018
2053
  }
2019
2054
  ),
2020
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "\u232B back \xB7 Q quit" }) })
2055
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
2056
+ "\u232B back \xB7 ",
2057
+ QUIT_HINTS.quit
2058
+ ] }) })
2021
2059
  ] });
2022
2060
  }
2023
2061
  if (screen.name === "auto-entropy") {
@@ -2102,7 +2140,7 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
2102
2140
  "\u2026"
2103
2141
  ] }),
2104
2142
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Waiting for the server to confirm the slot is free before joining the next circuit's queue." }),
2105
- /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Q / Ctrl+C / Ctrl+Z abort run" })
2143
+ /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: QUIT_HINTS.abortRun })
2106
2144
  ] });
2107
2145
  }
2108
2146
  if (screen.subPhase.kind === "queueing") {
@@ -2110,7 +2148,7 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
2110
2148
  /* @__PURE__ */ jsx8(Header, { ceremony, subtitle: "Auto-mode \xB7 joining next queue" }),
2111
2149
  progressStrip,
2112
2150
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Picking the next circuit\u2026" }),
2113
- /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Q / Ctrl+C / Ctrl+Z to abort (releases any active slot)" })
2151
+ /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: QUIT_HINTS.abortSlot })
2114
2152
  ] });
2115
2153
  }
2116
2154
  if (screen.subPhase.kind === "waiting") {
@@ -2165,7 +2203,10 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
2165
2203
  }
2166
2204
  }
2167
2205
  ),
2168
- /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "\u232B Backspace skip this circuit \xB7 Q / Ctrl+C / Ctrl+Z abort run" })
2206
+ /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
2207
+ "\u232B Backspace skip this circuit \xB7 ",
2208
+ QUIT_HINTS.abortRun
2209
+ ] })
2169
2210
  ] });
2170
2211
  }
2171
2212
  if (screen.subPhase.kind === "contributing") {
@@ -2249,13 +2290,13 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
2249
2290
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2250
2291
  /* @__PURE__ */ jsx8(Header, { ceremony, subtitle: "Auto-mode \xB7 complete" }),
2251
2292
  /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", gap: 1, children: [
2252
- /* @__PURE__ */ jsx8(Text8, { bold: true, color: failed.length === 0 ? "green" : "yellow", children: failed.length === 0 ? `\u2713 Auto-mode complete \u2014 ${verified.length} circuits verified` : `\u26A0 Auto-mode complete with ${failed.length} failure${failed.length === 1 ? "" : "s"}` }),
2293
+ /* @__PURE__ */ jsx8(Text8, { bold: true, color: failed.length === 0 ? "greenBright" : "yellow", children: failed.length === 0 ? `\u2714 Auto-mode complete \u2014 ${verified.length} circuits verified` : `\u26A0 Auto-mode complete with ${failed.length} failure${failed.length === 1 ? "" : "s"}` }),
2253
2294
  verified.length > 0 && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2254
- /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Verified contributions:" }),
2295
+ /* @__PURE__ */ jsx8(Text8, { dimColor: true, color: "cyan", children: "Verified contributions:" }),
2255
2296
  verified.map((o, i) => /* @__PURE__ */ jsxs8(Box8, { paddingLeft: 2, children: [
2256
- /* @__PURE__ */ jsx8(Text8, { color: "green", children: "\u2713 " }),
2257
- /* @__PURE__ */ jsx8(Text8, { children: elideMiddle(o.circuitName, 42).padEnd(44) }),
2258
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: o.hash ? o.hash.slice(0, 16) + "\u2026" : "" })
2297
+ /* @__PURE__ */ jsx8(Text8, { color: "greenBright", children: "\u2714 " }),
2298
+ /* @__PURE__ */ jsx8(Text8, { color: "blueBright", children: elideMiddle(o.circuitName, 42).padEnd(44) }),
2299
+ /* @__PURE__ */ jsx8(Text8, { color: "cyanBright", children: o.hash ? o.hash.slice(0, 16) + "\u2026" : "" })
2259
2300
  ] }, i))
2260
2301
  ] }),
2261
2302
  failed.length > 0 && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
@@ -2269,12 +2310,12 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
2269
2310
  ] }, i)),
2270
2311
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "\u232B Backspace / B \u2014 back to track list (you can retry failed circuits manually)" })
2271
2312
  ] }),
2272
- /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Q / Ctrl+C / Ctrl+Z \u2014 quit" })
2313
+ /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: QUIT_HINTS.quit })
2273
2314
  ] })
2274
2315
  ] });
2275
2316
  }
2276
2317
  if (screen.name === "error") {
2277
- 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";
2318
+ const backHint = !initialCeremonyId ? `\u232B Backspace \u2014 back to ceremony list \xB7 ${QUIT_HINTS.quit}` : screen.recoverable ? `\u232B Backspace / B to go back \xB7 ${QUIT_HINTS.quit}` : QUIT_HINTS.quit;
2278
2319
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2279
2320
  /* @__PURE__ */ jsx8(Header, { ceremony }),
2280
2321
  /* @__PURE__ */ jsxs8(Text8, { color: "red", bold: true, children: [
@@ -2350,7 +2391,8 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
2350
2391
  }),
2351
2392
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: " " + "\u2500".repeat(70) }),
2352
2393
  openTracks.length === 0 ? /* @__PURE__ */ jsx8(Text8, { color: "yellow", children: "No circuits are open for contributions right now \u2014 the ceremony may be closing or already complete." }) : /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
2353
- "\u2191/\u2193 select \xB7 Enter contribute \xB7 R refresh \xB7 Q quit",
2394
+ "\u2191/\u2193 select \xB7 Enter contribute \xB7 R refresh \xB7 ",
2395
+ QUIT_HINTS.quit,
2354
2396
  !initialCeremonyId ? " \xB7 \u232B back to ceremony list" : ""
2355
2397
  ] })
2356
2398
  ] })
@@ -2389,7 +2431,8 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
2389
2431
  " contribution",
2390
2432
  myContributions.length !== 1 ? "s" : "",
2391
2433
  " \xB7 ",
2392
- "\u2191/\u2193 select \xB7 C copy hash \xB7 Tab switch \xB7 Q quit"
2434
+ "\u2191/\u2193 select \xB7 C copy hash \xB7 Tab switch \xB7 ",
2435
+ QUIT_HINTS.quit
2393
2436
  ] })
2394
2437
  ] }) })
2395
2438
  )
@@ -2399,7 +2442,7 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
2399
2442
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2400
2443
  /* @__PURE__ */ jsx8(Header, { ceremony }),
2401
2444
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Joining queue..." }),
2402
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Q / Ctrl+C / Ctrl+Z to quit" }) })
2445
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: QUIT_HINTS.quit }) })
2403
2446
  ] });
2404
2447
  }
2405
2448
  if (screen.name === "queue") {
@@ -2427,7 +2470,10 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
2427
2470
  onError: (e) => setScreen({ name: "error", message: e.message, recoverable: true })
2428
2471
  }
2429
2472
  ),
2430
- /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "\u232B Backspace to go back \xB7 Q to quit" })
2473
+ /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
2474
+ "\u232B Backspace to go back \xB7 ",
2475
+ QUIT_HINTS.quit
2476
+ ] })
2431
2477
  ] });
2432
2478
  }
2433
2479
  if (screen.name === "entropy") {
@@ -2497,7 +2543,10 @@ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName })
2497
2543
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2498
2544
  /* @__PURE__ */ jsx8(Header, { ceremony }),
2499
2545
  /* @__PURE__ */ jsx8(Attestation, { contribution }),
2500
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "\u232B Backspace / B = contribute to another circuit \xB7 Q to quit" }) })
2546
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
2547
+ "\u232B Backspace / B = contribute to another circuit \xB7 ",
2548
+ QUIT_HINTS.quit
2549
+ ] }) })
2501
2550
  ] });
2502
2551
  }
2503
2552
  return null;
@@ -2525,8 +2574,10 @@ async function gracefulExit(code = 0, deliberate = false) {
2525
2574
  process.exit(code);
2526
2575
  }
2527
2576
  globalThis.__ceremonyGracefulExit = gracefulExit;
2528
- var DELIBERATE_SIGNALS = /* @__PURE__ */ new Set(["SIGINT", "SIGTSTP"]);
2529
- for (const signal of ["SIGINT", "SIGTERM", "SIGTSTP", "SIGHUP"]) {
2577
+ process.on("SIGTSTP", () => {
2578
+ });
2579
+ var DELIBERATE_SIGNALS = /* @__PURE__ */ new Set(["SIGINT"]);
2580
+ for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
2530
2581
  process.on(signal, () => {
2531
2582
  gracefulExit(0, DELIBERATE_SIGNALS.has(signal)).catch(() => {
2532
2583
  restoreScreen();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umbra-privacy/ceremony",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
4
4
  "description": "Terminal UI for the Umbra Phase 2 trusted setup ceremony",
5
5
  "type": "module",
6
6
  "bin": {