@mauricode/token-derby 2.5.2 → 2.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -420,8 +420,8 @@ var HEARTBEAT_RETRY_DELAYS_MS = [1e3, 2e3, 4e3, 8e3, 15e3];
420
420
  // src/version.ts
421
421
  import { createRequire } from "module";
422
422
  function readVersion() {
423
- if ("2.5.2".length > 0) {
424
- return "2.5.2";
423
+ if ("2.5.4".length > 0) {
424
+ return "2.5.4";
425
425
  }
426
426
  try {
427
427
  const req = createRequire(import.meta.url);
@@ -592,7 +592,7 @@ var HATS = [
592
592
  { id: "spartan_helmet", name: "Spartan Helmet", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "........Q..", ".......QQ..", ".....QQQQ..", "....QQQQQ..", "..QQQQQQ...", ".QQQAA.....", "QQAAAAAAA..", "Q.AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#B0BEC5", Q: "#B71C1C" }, { A: "#B0BEC5", Q: "#b2b51c" }, { A: "#B0BEC5", Q: "#b5611c" }] },
593
593
  { id: "conquistador_full", name: "Conquistador Helm", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "...AAAAA...", "..AAAAAAA..", "...AQQQA...", "...AQQQA..."], variants: [{ A: "#B0BEC5", Q: "#FFD700" }, { A: "#B0BEC5", Q: "#0040ff" }, { A: "#B0BEC5", Q: "#36123b" }] },
594
594
  // ── LEGENDARY (5) ──────────────────────────────────────────────────────
595
- { id: "rainbow_crown", name: "Rainbow Crown", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "...........", ".....A.....", "....AQA....", "....AQA....", "....AQA....", "...AAQAA...", "...AQQQA...", "..AAQQQAA..", "..AAAAAAA.."], colors: { A: "#FFD700", Q: "#553f3f" }, animation: { type: "cycle", frames: ["#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#8B00FF"], fps: 8 } },
595
+ { id: "rainbow_crown", name: "Rainbow Crown", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "...........", ".....A.....", "....AAA....", "....AQA....", "....AAA....", "...AAQAA...", "...AAAAA...", "..AAAQAAA..", "..AAAAAAA.."], colors: { A: "#FFD700", Q: "#553f3f" }, animation: { type: "cycle", frames: ["#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#8B00FF"], fps: 8 } },
596
596
  { id: "inferno_cap", name: "Inferno Cap", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "....AAA....", "...AAAAA...", "....AAA....", ".....Q.....", "A....Q....A", "A...QQQ...A", ".A..QQQ..A.", "..AAAAAAA..", "..AAAAAAA.."], colors: { A: "#FF4500", Q: "#FFD700" }, animation: { type: "cycle", frames: ["#FF0000", "#FF2200", "#FF4500", "#FF6600", "#FF8C00", "#FFA500"], fps: 12 } },
597
597
  { id: "void_hood", name: "Void Hood", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...AAA.....", "..AAAAAA...", ".AAAAAAA...", ".AAAAAAAA..", "AAAAAAAAA..", "AAAAQQQAA..", "AAAAQQQAA.."], colors: { A: "#1A0033", Q: "#d9cfe3" }, animation: { type: "cycle", frames: ["#0D0019", "#1A0033", "#2D004D", "#3D0066", "#2D004D", "#1A0033"], fps: 3 } },
598
598
  { id: "prismatic_jester", name: "Prismatic Jester", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "..Q.Q.Q.Q..", "Q..A.A.A..Q", ".Q.A.A.A.Q.", "..AQAQAQA..", "..AQAQAQA..", "..AAAAAAA..", "..AAAAAAA..", "..AAAAAAA..", "..AAAAAAA.."], colors: { A: "#FF0000", Q: "#0000FF" }, animation: { type: "cycle", frames: ["#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#8B00FF", "#FF00FF", "#00FFFF"], fps: 15 } },
@@ -939,7 +939,7 @@ async function stableDeleteCommand(name) {
939
939
  }
940
940
 
941
941
  // src/commands/stable-edit.ts
942
- import React6 from "react";
942
+ import React7 from "react";
943
943
  import { render as render3 } from "ink";
944
944
 
945
945
  // src/ui/HatPicker.tsx
@@ -1046,23 +1046,81 @@ function PreviewArea({ focused, colors }) {
1046
1046
  return /* @__PURE__ */ jsx5(HorseSprite, { sprite: MAIN_SPRITE, colors, hat: { hat, variant: focused.collected.variant ?? 0 } });
1047
1047
  }
1048
1048
 
1049
+ // src/ui/HorsePicker.tsx
1050
+ import { useState as useState4 } from "react";
1051
+ import { Box as Box6, Text as Text6, useInput as useInput3 } from "ink";
1052
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1053
+ function HorsePicker({ horses, onPick, onCancel }) {
1054
+ const [idx, setIdx] = useState4(0);
1055
+ useInput3((input, key) => {
1056
+ if (key.escape) {
1057
+ onCancel();
1058
+ return;
1059
+ }
1060
+ if (horses.length === 0) return;
1061
+ if (key.upArrow) {
1062
+ setIdx((idx - 1 + horses.length) % horses.length);
1063
+ return;
1064
+ }
1065
+ if (key.downArrow) {
1066
+ setIdx((idx + 1) % horses.length);
1067
+ return;
1068
+ }
1069
+ if (key.return) {
1070
+ onPick(horses[idx]);
1071
+ return;
1072
+ }
1073
+ });
1074
+ if (horses.length === 0) {
1075
+ return /* @__PURE__ */ jsxs4(Box6, { flexDirection: "column", children: [
1076
+ /* @__PURE__ */ jsx6(Text6, { children: "No horses in your stable." }),
1077
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Run `token-derby stable create` to make one." })
1078
+ ] });
1079
+ }
1080
+ return /* @__PURE__ */ jsxs4(Box6, { flexDirection: "column", children: [
1081
+ /* @__PURE__ */ jsx6(Text6, { children: "Pick a horse to race:" }),
1082
+ horses.map((h, i) => /* @__PURE__ */ jsxs4(Box6, { flexDirection: "column", children: [
1083
+ /* @__PURE__ */ jsx6(Box6, { flexDirection: "row", children: /* @__PURE__ */ jsxs4(Text6, { children: [
1084
+ i === idx ? "\u25BA" : " ",
1085
+ " ",
1086
+ h.name,
1087
+ " ",
1088
+ /* @__PURE__ */ jsxs4(Text6, { color: "cyan", children: [
1089
+ "[Lvl. ",
1090
+ levelFromXp(h.xp),
1091
+ "]"
1092
+ ] })
1093
+ ] }) }),
1094
+ /* @__PURE__ */ jsxs4(Box6, { flexDirection: "row", children: [
1095
+ /* @__PURE__ */ jsx6(Text6, { children: " " }),
1096
+ /* @__PURE__ */ jsx6(HorseSprite, { sprite: MINI_SPRITE, colors: h.colors })
1097
+ ] })
1098
+ ] }, h.stable_horse_id)),
1099
+ /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "\u2191/\u2193 choose \xB7 Enter pick \xB7 Esc cancel" }) })
1100
+ ] });
1101
+ }
1102
+
1049
1103
  // src/commands/stable-edit.ts
1050
1104
  async function stableEditCommand(name) {
1051
- if (!name) {
1052
- console.error("Usage: token-derby stable edit <name>");
1053
- return 2;
1054
- }
1055
1105
  const horses = await fetchStable();
1056
1106
  if (!horses) return 1;
1057
- const existing = horses.find((h) => h.name === name);
1058
- if (!existing) {
1107
+ const existing = await pickHorseToEdit(horses, name);
1108
+ if (existing === "not_found") {
1059
1109
  console.error(`No horse named "${name}" in your stable.`);
1060
1110
  return 1;
1061
1111
  }
1112
+ if (existing === "empty") {
1113
+ console.log("No horses in your stable. Run `token-derby stable create` to make one.");
1114
+ return 0;
1115
+ }
1116
+ if (existing === "cancelled") {
1117
+ console.log("Cancelled.");
1118
+ return 1;
1119
+ }
1062
1120
  let exitCode = 0;
1063
1121
  let liveColors = existing.colors;
1064
1122
  const app = render3(
1065
- React6.createElement(HorseCreator, {
1123
+ React7.createElement(HorseCreator, {
1066
1124
  initialColors: existing.colors,
1067
1125
  initialName: existing.name,
1068
1126
  lockName: true,
@@ -1094,7 +1152,7 @@ async function stableEditCommand(name) {
1094
1152
  if (exitCode === 0 && existing.hats && existing.hats.length > 0) {
1095
1153
  const equipResult = await new Promise((resolve) => {
1096
1154
  const app2 = render3(
1097
- React6.createElement(HatPicker, {
1155
+ React7.createElement(HatPicker, {
1098
1156
  hats: existing.hats,
1099
1157
  equipped: existing.equipped_hat ?? null,
1100
1158
  colors: liveColors,
@@ -1133,6 +1191,29 @@ async function fetchStable() {
1133
1191
  throw e;
1134
1192
  }
1135
1193
  }
1194
+ async function pickHorseToEdit(horses, name) {
1195
+ if (name) {
1196
+ const found = horses.find((h) => h.name === name);
1197
+ return found ?? "not_found";
1198
+ }
1199
+ if (horses.length === 0) return "empty";
1200
+ const picked = await new Promise((resolve) => {
1201
+ const app = render3(
1202
+ React7.createElement(HorsePicker, {
1203
+ horses,
1204
+ onPick: (h) => {
1205
+ app.unmount();
1206
+ resolve(h);
1207
+ },
1208
+ onCancel: () => {
1209
+ app.unmount();
1210
+ resolve(null);
1211
+ }
1212
+ })
1213
+ );
1214
+ });
1215
+ return picked ?? "cancelled";
1216
+ }
1136
1217
 
1137
1218
  // src/commands/create.ts
1138
1219
  import * as readline2 from "readline/promises";
@@ -1222,60 +1303,6 @@ function isIso(s) {
1222
1303
  import React9 from "react";
1223
1304
  import { render as render4 } from "ink";
1224
1305
 
1225
- // src/ui/HorsePicker.tsx
1226
- import { useState as useState4 } from "react";
1227
- import { Box as Box6, Text as Text6, useInput as useInput3 } from "ink";
1228
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1229
- function HorsePicker({ horses, onPick, onCancel }) {
1230
- const [idx, setIdx] = useState4(0);
1231
- useInput3((input, key) => {
1232
- if (key.escape) {
1233
- onCancel();
1234
- return;
1235
- }
1236
- if (horses.length === 0) return;
1237
- if (key.upArrow) {
1238
- setIdx((idx - 1 + horses.length) % horses.length);
1239
- return;
1240
- }
1241
- if (key.downArrow) {
1242
- setIdx((idx + 1) % horses.length);
1243
- return;
1244
- }
1245
- if (key.return) {
1246
- onPick(horses[idx]);
1247
- return;
1248
- }
1249
- });
1250
- if (horses.length === 0) {
1251
- return /* @__PURE__ */ jsxs4(Box6, { flexDirection: "column", children: [
1252
- /* @__PURE__ */ jsx6(Text6, { children: "No horses in your stable." }),
1253
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Run `token-derby stable create` to make one." })
1254
- ] });
1255
- }
1256
- return /* @__PURE__ */ jsxs4(Box6, { flexDirection: "column", children: [
1257
- /* @__PURE__ */ jsx6(Text6, { children: "Pick a horse to race:" }),
1258
- horses.map((h, i) => /* @__PURE__ */ jsxs4(Box6, { flexDirection: "column", children: [
1259
- /* @__PURE__ */ jsx6(Box6, { flexDirection: "row", children: /* @__PURE__ */ jsxs4(Text6, { children: [
1260
- i === idx ? "\u25BA" : " ",
1261
- " ",
1262
- h.name,
1263
- " ",
1264
- /* @__PURE__ */ jsxs4(Text6, { color: "cyan", children: [
1265
- "[Lvl. ",
1266
- levelFromXp(h.xp),
1267
- "]"
1268
- ] })
1269
- ] }) }),
1270
- /* @__PURE__ */ jsxs4(Box6, { flexDirection: "row", children: [
1271
- /* @__PURE__ */ jsx6(Text6, { children: " " }),
1272
- /* @__PURE__ */ jsx6(HorseSprite, { sprite: MINI_SPRITE, colors: h.colors })
1273
- ] })
1274
- ] }, h.stable_horse_id)),
1275
- /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "\u2191/\u2193 choose \xB7 Enter pick \xB7 Esc cancel" }) })
1276
- ] });
1277
- }
1278
-
1279
1306
  // src/stable/active-race.ts
1280
1307
  import * as fs2 from "fs/promises";
1281
1308
  import * as path3 from "path";
@@ -2152,12 +2179,6 @@ var BOX_EMPTY = [
2152
2179
  function GiftBox({ frame, color }) {
2153
2180
  return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: frame.map((line, i) => /* @__PURE__ */ jsx10(Text10, { children: line ? ansiFg(color) + line + RESET3 : line }, i)) });
2154
2181
  }
2155
- function printClosedBox() {
2156
- for (const line of BOX_CLOSED) {
2157
- const colored = line.trim().length > 0 ? `${ansiFg(BOX_COLOR)}${line}${RESET3}` : line;
2158
- process.stdout.write(colored + "\n");
2159
- }
2160
- }
2161
2182
  function spawnParticles(tier, count, cx, cy) {
2162
2183
  const palette = TIER_PALETTE[tier];
2163
2184
  const out = [];
@@ -2194,23 +2215,26 @@ function ConfettiBurst({ tier }) {
2194
2215
  }
2195
2216
  return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: grid.map((row, y) => /* @__PURE__ */ jsx10(Text10, { children: row.join("") }, y)) });
2196
2217
  }
2218
+ var CLOSED_HOLD_MS = 3e3;
2197
2219
  function RollReveal({ outcome, onDone }) {
2198
2220
  const isNoHat = outcome.kind === "no_hat";
2199
2221
  const isLegendary = outcome.kind !== "no_hat" && outcome.hat.rarity === "legendary";
2200
- const [phase, setPhase] = useState7("open1");
2222
+ const [phase, setPhase] = useState7("closed");
2201
2223
  useEffect4(() => {
2202
2224
  const timers = [];
2203
- timers.push(setTimeout(() => setPhase("open2"), 350));
2225
+ timers.push(setTimeout(() => setPhase("open1"), CLOSED_HOLD_MS));
2226
+ timers.push(setTimeout(() => setPhase("open2"), CLOSED_HOLD_MS + 350));
2204
2227
  if (isNoHat) {
2205
- timers.push(setTimeout(() => setPhase("empty"), 700));
2206
- timers.push(setTimeout(onDone, 1500));
2228
+ timers.push(setTimeout(() => setPhase("empty"), CLOSED_HOLD_MS + 700));
2229
+ timers.push(setTimeout(onDone, CLOSED_HOLD_MS + 1500));
2207
2230
  } else {
2208
- timers.push(setTimeout(() => setPhase("burst"), 700));
2209
- timers.push(setTimeout(() => setPhase("reveal"), 1650));
2210
- timers.push(setTimeout(onDone, isLegendary ? 4650 : 2650));
2231
+ timers.push(setTimeout(() => setPhase("burst"), CLOSED_HOLD_MS + 700));
2232
+ timers.push(setTimeout(() => setPhase("reveal"), CLOSED_HOLD_MS + 1650));
2233
+ timers.push(setTimeout(onDone, CLOSED_HOLD_MS + (isLegendary ? 4650 : 2650)));
2211
2234
  }
2212
2235
  return () => timers.forEach(clearTimeout);
2213
2236
  }, [isNoHat, isLegendary, onDone]);
2237
+ if (phase === "closed") return /* @__PURE__ */ jsx10(GiftBox, { frame: BOX_CLOSED, color: BOX_COLOR });
2214
2238
  if (phase === "open1") return /* @__PURE__ */ jsx10(GiftBox, { frame: BOX_OPENING_1, color: BOX_COLOR });
2215
2239
  if (phase === "open2") return /* @__PURE__ */ jsx10(GiftBox, { frame: BOX_OPENING_2, color: BOX_COLOR });
2216
2240
  if (phase === "empty") return /* @__PURE__ */ jsx10(GiftBox, { frame: BOX_EMPTY, color: BOX_COLOR });
@@ -2299,12 +2323,6 @@ function resetStdinAfterInk() {
2299
2323
  process.stdin.pause();
2300
2324
  }
2301
2325
  async function runReveal(outcome) {
2302
- resetStdinAfterInk();
2303
- printClosedBox();
2304
- const readline7 = await import("readline/promises");
2305
- const rl = readline7.createInterface({ input: process.stdin, output: process.stdout });
2306
- await rl.question("Press Enter to open the box\u2026 ");
2307
- rl.close();
2308
2326
  await new Promise((resolve) => {
2309
2327
  const app = render5(React13.createElement(RollReveal, {
2310
2328
  outcome,
@@ -2603,7 +2621,7 @@ Maintenance:
2603
2621
  Stable management:
2604
2622
  token-derby stable create Make a new horse (interactive)
2605
2623
  token-derby stable list Show your saved horses
2606
- token-derby stable edit <name> Edit an existing horse's colors
2624
+ token-derby stable edit [name] Edit an existing horse's colors (interactive picker if no name)
2607
2625
  token-derby stable delete <name> Remove a horse from your stable
2608
2626
 
2609
2627
  Organisations: