@mauricode/token-derby 2.12.0 → 2.12.2
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 +171 -77
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -26,19 +26,10 @@ import TextInput from "ink-text-input";
|
|
|
26
26
|
|
|
27
27
|
// ../shared/dist/models.js
|
|
28
28
|
var MODEL_KEYS = ["claude", "codex", "gemini"];
|
|
29
|
-
var SECONDARY_WEIGHT = 0.
|
|
29
|
+
var SECONDARY_WEIGHT = 0.5;
|
|
30
30
|
function isModelKey(v) {
|
|
31
31
|
return typeof v === "string" && MODEL_KEYS.includes(v);
|
|
32
32
|
}
|
|
33
|
-
function weightFor(primary, key) {
|
|
34
|
-
return key === primary ? 1 : SECONDARY_WEIGHT;
|
|
35
|
-
}
|
|
36
|
-
function weightedTotal(primary, perSource) {
|
|
37
|
-
let total = 0;
|
|
38
|
-
for (const key of MODEL_KEYS)
|
|
39
|
-
total += perSource[key] * weightFor(primary, key);
|
|
40
|
-
return total;
|
|
41
|
-
}
|
|
42
33
|
|
|
43
34
|
// ../shared/dist/constants.js
|
|
44
35
|
var CLI_VERSION_HEADER = "x-cli-version";
|
|
@@ -208,6 +199,59 @@ var HATS = [
|
|
|
208
199
|
// ../shared/dist/series-transform.js
|
|
209
200
|
var PACE_WINDOW_MS = 15 * 6e4;
|
|
210
201
|
|
|
202
|
+
// ../shared/dist/sprite-grid.js
|
|
203
|
+
var ROWS = [
|
|
204
|
+
"................................",
|
|
205
|
+
"................................",
|
|
206
|
+
"..........................MMM...",
|
|
207
|
+
"..........................MMM...",
|
|
208
|
+
".........................MBBEBB.",
|
|
209
|
+
".........................MBBEBB.",
|
|
210
|
+
"........................MBBBBBBB",
|
|
211
|
+
"........................MBBBBBBB",
|
|
212
|
+
"..................MMMMMMMBBB....",
|
|
213
|
+
"..................MMMMMMMBBB....",
|
|
214
|
+
"....BBBBBBBBSSSSSSMMBBBBBB......",
|
|
215
|
+
"...BBBBBBBBBSSSSSSMMBBBBBB......",
|
|
216
|
+
".TTBBBBBBBBBSSSSSSBBBBBBBB......",
|
|
217
|
+
".TTBBBBBBBBBSSSSSSBBBBBBBB......",
|
|
218
|
+
"TTTBBBBBBBBBBBBBBBBBBBBBBB......",
|
|
219
|
+
"TTTBBBBBBBBBBBBBBBBBBBBB........",
|
|
220
|
+
"...BBB.BBB.....BBB.BBB..........",
|
|
221
|
+
"...BBB.BBB.....BBB.BBB..........",
|
|
222
|
+
"....BB..BB......BB..BB..........",
|
|
223
|
+
"....BB..BB......BB..BB..........",
|
|
224
|
+
"....BB..BB......BB..BB..........",
|
|
225
|
+
"....BB..BB......BB..BB..........",
|
|
226
|
+
"....BB..BB......BB..BB..........",
|
|
227
|
+
"...HHH.HHH.....HHH.HHH.........."
|
|
228
|
+
];
|
|
229
|
+
var GRID = ROWS.map((row, y) => {
|
|
230
|
+
if (row.length !== 32)
|
|
231
|
+
throw new Error(`sprite row ${y} has length ${row.length}, expected 32`);
|
|
232
|
+
return [...row].map((c) => toTag(c, y));
|
|
233
|
+
});
|
|
234
|
+
function toTag(c, y) {
|
|
235
|
+
switch (c) {
|
|
236
|
+
case "B":
|
|
237
|
+
return "B";
|
|
238
|
+
case "M":
|
|
239
|
+
return "M";
|
|
240
|
+
case "T":
|
|
241
|
+
return "T";
|
|
242
|
+
case "S":
|
|
243
|
+
return "S";
|
|
244
|
+
case "H":
|
|
245
|
+
return "H";
|
|
246
|
+
case "E":
|
|
247
|
+
return "B";
|
|
248
|
+
case ".":
|
|
249
|
+
return null;
|
|
250
|
+
default:
|
|
251
|
+
throw new Error(`unknown sprite char '${c}' at y=${y}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
211
255
|
// src/ui/HorseSprite.tsx
|
|
212
256
|
import { Box, Text } from "ink";
|
|
213
257
|
|
|
@@ -258,10 +302,10 @@ function parse(rows, width, height) {
|
|
|
258
302
|
if (row.length !== width) {
|
|
259
303
|
throw new Error(`sprite row ${y} has length ${row.length}, expected ${width}`);
|
|
260
304
|
}
|
|
261
|
-
return [...row].map((c) =>
|
|
305
|
+
return [...row].map((c) => toTag2(c));
|
|
262
306
|
});
|
|
263
307
|
}
|
|
264
|
-
function
|
|
308
|
+
function toTag2(c) {
|
|
265
309
|
switch (c) {
|
|
266
310
|
case "B":
|
|
267
311
|
return "B";
|
|
@@ -702,10 +746,40 @@ function renderHatLabel(hats, hatChoice, initialEquipped) {
|
|
|
702
746
|
] });
|
|
703
747
|
}
|
|
704
748
|
|
|
749
|
+
// src/env/env.ts
|
|
750
|
+
import { readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
751
|
+
import * as os from "os";
|
|
752
|
+
import * as path from "path";
|
|
753
|
+
var ENV_NAMES = ["prod", "staging"];
|
|
754
|
+
function baseDir() {
|
|
755
|
+
return process.env.TOKEN_DERBY_BASE ?? os.homedir();
|
|
756
|
+
}
|
|
757
|
+
function configFile() {
|
|
758
|
+
return path.join(baseDir(), ".token-derby", "config.json");
|
|
759
|
+
}
|
|
760
|
+
function selectedEnv() {
|
|
761
|
+
try {
|
|
762
|
+
const raw = readFileSync(configFile(), "utf8");
|
|
763
|
+
const parsed = JSON.parse(raw);
|
|
764
|
+
if (parsed.env === "prod" || parsed.env === "staging") return parsed.env;
|
|
765
|
+
return "prod";
|
|
766
|
+
} catch {
|
|
767
|
+
return "prod";
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
function setSelectedEnv(env) {
|
|
771
|
+
const file = configFile();
|
|
772
|
+
mkdirSync(path.dirname(file), { recursive: true });
|
|
773
|
+
writeFileSync(file, JSON.stringify({ env }, null, 2) + "\n", "utf8");
|
|
774
|
+
}
|
|
775
|
+
|
|
705
776
|
// src/config.ts
|
|
706
|
-
var
|
|
777
|
+
var ENVIRONMENTS = {
|
|
778
|
+
prod: { apiBase: "https://token-derby.mauricode.co.uk/api" },
|
|
779
|
+
staging: { apiBase: "https://token-derby-staging.mauricode.co.uk/api" }
|
|
780
|
+
};
|
|
707
781
|
function apiBase() {
|
|
708
|
-
return process.env.TOKEN_DERBY_API_BASE ??
|
|
782
|
+
return process.env.TOKEN_DERBY_API_BASE ?? ENVIRONMENTS[selectedEnv()].apiBase;
|
|
709
783
|
}
|
|
710
784
|
var HEARTBEAT_INTERVAL_MS = 6e4;
|
|
711
785
|
var HEARTBEAT_RETRY_DELAYS_MS = [1e3, 2e3, 4e3, 8e3, 15e3];
|
|
@@ -713,8 +787,8 @@ var HEARTBEAT_RETRY_DELAYS_MS = [1e3, 2e3, 4e3, 8e3, 15e3];
|
|
|
713
787
|
// src/version.ts
|
|
714
788
|
import { createRequire } from "module";
|
|
715
789
|
function readVersion() {
|
|
716
|
-
if ("2.12.
|
|
717
|
-
return "2.12.
|
|
790
|
+
if ("2.12.2".length > 0) {
|
|
791
|
+
return "2.12.2";
|
|
718
792
|
}
|
|
719
793
|
try {
|
|
720
794
|
const req = createRequire(import.meta.url);
|
|
@@ -728,31 +802,34 @@ var CLI_VERSION = readVersion();
|
|
|
728
802
|
|
|
729
803
|
// src/identity/identity.ts
|
|
730
804
|
import { promises as fs } from "fs";
|
|
731
|
-
import * as
|
|
805
|
+
import * as path3 from "path";
|
|
732
806
|
|
|
733
807
|
// src/paths.ts
|
|
734
|
-
import * as
|
|
735
|
-
import * as
|
|
808
|
+
import * as os2 from "os";
|
|
809
|
+
import * as path2 from "path";
|
|
736
810
|
function homeDir() {
|
|
737
|
-
|
|
811
|
+
const override = process.env.TOKEN_DERBY_HOME;
|
|
812
|
+
if (override) return override;
|
|
813
|
+
const dir = selectedEnv() === "staging" ? ".token-derby-staging" : ".token-derby";
|
|
814
|
+
return path2.join(baseDir(), dir);
|
|
738
815
|
}
|
|
739
816
|
function identityFile() {
|
|
740
|
-
return
|
|
817
|
+
return path2.join(homeDir(), "identity.json");
|
|
741
818
|
}
|
|
742
819
|
function activeRaceFile(joinCode) {
|
|
743
|
-
return
|
|
820
|
+
return path2.join(homeDir(), "active-races", `${joinCode}.json`);
|
|
744
821
|
}
|
|
745
822
|
function activeRacesDir() {
|
|
746
|
-
return
|
|
823
|
+
return path2.join(homeDir(), "active-races");
|
|
747
824
|
}
|
|
748
825
|
function claudeProjectsDir() {
|
|
749
|
-
return process.env.TOKEN_DERBY_CLAUDE_DIR ??
|
|
826
|
+
return process.env.TOKEN_DERBY_CLAUDE_DIR ?? path2.join(os2.homedir(), ".claude", "projects");
|
|
750
827
|
}
|
|
751
828
|
function codexSessionsDir() {
|
|
752
|
-
return process.env.TOKEN_DERBY_CODEX_DIR ??
|
|
829
|
+
return process.env.TOKEN_DERBY_CODEX_DIR ?? path2.join(os2.homedir(), ".codex");
|
|
753
830
|
}
|
|
754
831
|
function geminiTmpDir() {
|
|
755
|
-
return process.env.TOKEN_DERBY_GEMINI_DIR ??
|
|
832
|
+
return process.env.TOKEN_DERBY_GEMINI_DIR ?? path2.join(os2.homedir(), ".gemini", "tmp");
|
|
756
833
|
}
|
|
757
834
|
|
|
758
835
|
// src/identity/identity.ts
|
|
@@ -808,8 +885,8 @@ function getIdentity() {
|
|
|
808
885
|
function _resetIdentityCacheForTests() {
|
|
809
886
|
identityCache = null;
|
|
810
887
|
}
|
|
811
|
-
async function request(method,
|
|
812
|
-
const url =
|
|
888
|
+
async function request(method, path8, body, horseAuthToken, fetchImpl = fetch) {
|
|
889
|
+
const url = path8.startsWith("http") ? path8 : `${apiBase()}${path8}`;
|
|
813
890
|
const headers = {};
|
|
814
891
|
headers[CLI_VERSION_HEADER] = CLI_VERSION;
|
|
815
892
|
headers["user-agent"] = `token-derby/${CLI_VERSION}`;
|
|
@@ -1310,7 +1387,7 @@ function PrimaryPicker({ onPick }) {
|
|
|
1310
1387
|
else if (key.return) onPick(MODEL_KEYS[i]);
|
|
1311
1388
|
});
|
|
1312
1389
|
return /* @__PURE__ */ jsxs4(Box6, { flexDirection: "column", children: [
|
|
1313
|
-
/* @__PURE__ */ jsx6(Text6, { bold: true, children: "Pick your primary model for this race (counts 1:1; the others count at
|
|
1390
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, children: "Pick your primary model for this race (counts 1:1; the others count at 50%)." }),
|
|
1314
1391
|
/* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "This is locked for the whole race \u2014 you can't change it, even by rejoining." }),
|
|
1315
1392
|
MODEL_KEYS.map((m, idx) => /* @__PURE__ */ jsxs4(Text6, { color: idx === i ? "cyan" : void 0, children: [
|
|
1316
1393
|
idx === i ? "\u276F " : " ",
|
|
@@ -1321,7 +1398,7 @@ function PrimaryPicker({ onPick }) {
|
|
|
1321
1398
|
|
|
1322
1399
|
// src/stable/active-race.ts
|
|
1323
1400
|
import * as fs2 from "fs/promises";
|
|
1324
|
-
import * as
|
|
1401
|
+
import * as path4 from "path";
|
|
1325
1402
|
async function saveActiveRace(active) {
|
|
1326
1403
|
await fs2.mkdir(activeRacesDir(), { recursive: true });
|
|
1327
1404
|
await fs2.writeFile(
|
|
@@ -1339,20 +1416,20 @@ import { Box as Box8, Text as Text8, useApp } from "ink";
|
|
|
1339
1416
|
import { Box as Box7, Text as Text7 } from "ink";
|
|
1340
1417
|
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1341
1418
|
var MODEL_LABELS = { claude: "Claude", codex: "Codex", gemini: "Gemini" };
|
|
1342
|
-
function
|
|
1343
|
-
const { primaryModel
|
|
1344
|
-
const
|
|
1345
|
-
return /* @__PURE__ */
|
|
1346
|
-
|
|
1347
|
-
MODEL_KEYS.map((m) => /* @__PURE__ */ jsxs5(Text7, { children: [
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
] });
|
|
1419
|
+
function ModelList(props) {
|
|
1420
|
+
const { primaryModel } = props;
|
|
1421
|
+
const secondaryTag = ` (${Math.round(SECONDARY_WEIGHT * 100)}%)`;
|
|
1422
|
+
return /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsxs5(Text7, { children: [
|
|
1423
|
+
"Models: ",
|
|
1424
|
+
MODEL_KEYS.map((m, i) => /* @__PURE__ */ jsxs5(Text7, { children: [
|
|
1425
|
+
i > 0 ? " \xB7 " : "",
|
|
1426
|
+
MODEL_LABELS[m],
|
|
1427
|
+
/* @__PURE__ */ jsx7(Text7, { dimColor: true, children: m === primaryModel ? " (primary)" : secondaryTag })
|
|
1428
|
+
] }, m))
|
|
1429
|
+
] }) });
|
|
1353
1430
|
}
|
|
1354
1431
|
function StatusScreen(props) {
|
|
1355
|
-
const { race, ownHorseId, ownHorseName, ownColors, ownUserName, lastHeartbeatAgoSec, lastHeartbeatOk, stalled, stallReason, primaryModel
|
|
1432
|
+
const { race, ownHorseId, ownHorseName, ownColors, ownUserName, lastHeartbeatAgoSec, lastHeartbeatOk, stalled, stallReason, primaryModel } = props;
|
|
1356
1433
|
if (!race) {
|
|
1357
1434
|
return /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", children: /* @__PURE__ */ jsx7(Text7, { children: "Joining race\u2026" }) });
|
|
1358
1435
|
}
|
|
@@ -1432,15 +1509,7 @@ function StatusScreen(props) {
|
|
|
1432
1509
|
". Your race continues."
|
|
1433
1510
|
] })
|
|
1434
1511
|
] }),
|
|
1435
|
-
primaryModel &&
|
|
1436
|
-
TokenBreakdown,
|
|
1437
|
-
{
|
|
1438
|
-
primaryModel,
|
|
1439
|
-
perSource,
|
|
1440
|
-
raceScore: own?.current_tokens ?? weightedTotal(primaryModel, perSource),
|
|
1441
|
-
primaryCapped
|
|
1442
|
-
}
|
|
1443
|
-
),
|
|
1512
|
+
primaryModel && /* @__PURE__ */ jsx7(ModelList, { primaryModel }),
|
|
1444
1513
|
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Press Ctrl+C to crash out of the race." }) })
|
|
1445
1514
|
] });
|
|
1446
1515
|
}
|
|
@@ -1512,11 +1581,11 @@ function runHeartbeatLoop(opts) {
|
|
|
1512
1581
|
|
|
1513
1582
|
// src/tokens/transcripts.ts
|
|
1514
1583
|
import * as fs3 from "fs/promises";
|
|
1515
|
-
import * as
|
|
1584
|
+
import * as path5 from "path";
|
|
1516
1585
|
var MAX_PROJECT_DEPTH = 8;
|
|
1517
1586
|
function conversationId(file, root) {
|
|
1518
|
-
const rel =
|
|
1519
|
-
const [project, session] = rel.split(
|
|
1587
|
+
const rel = path5.relative(root, file);
|
|
1588
|
+
const [project, session] = rel.split(path5.sep);
|
|
1520
1589
|
if (project === void 0 || session === void 0) return rel.replace(/\.jsonl$/, "");
|
|
1521
1590
|
return `${project}/${session.replace(/\.jsonl$/, "")}`;
|
|
1522
1591
|
}
|
|
@@ -1548,7 +1617,7 @@ async function listJsonlFiles(root) {
|
|
|
1548
1617
|
const projects = await fs3.readdir(root);
|
|
1549
1618
|
const out = [];
|
|
1550
1619
|
for (const project of projects) {
|
|
1551
|
-
const projectDir =
|
|
1620
|
+
const projectDir = path5.join(root, project);
|
|
1552
1621
|
const stat3 = await fs3.stat(projectDir);
|
|
1553
1622
|
if (!stat3.isDirectory()) continue;
|
|
1554
1623
|
await collectJsonl(projectDir, MAX_PROJECT_DEPTH, out);
|
|
@@ -1560,9 +1629,9 @@ async function collectJsonl(dir, depth, out) {
|
|
|
1560
1629
|
const entries = await fs3.readdir(dir);
|
|
1561
1630
|
for (const entry of entries) {
|
|
1562
1631
|
if (entry.endsWith(".jsonl")) {
|
|
1563
|
-
out.push(
|
|
1632
|
+
out.push(path5.join(dir, entry));
|
|
1564
1633
|
} else if (depth > 1) {
|
|
1565
|
-
const child =
|
|
1634
|
+
const child = path5.join(dir, entry);
|
|
1566
1635
|
const st = await fs3.stat(child);
|
|
1567
1636
|
if (st.isDirectory()) await collectJsonl(child, depth - 1, out);
|
|
1568
1637
|
}
|
|
@@ -1593,7 +1662,7 @@ async function sumFile(file) {
|
|
|
1593
1662
|
|
|
1594
1663
|
// src/tokens/codex.ts
|
|
1595
1664
|
import * as fs4 from "fs/promises";
|
|
1596
|
-
import * as
|
|
1665
|
+
import * as path6 from "path";
|
|
1597
1666
|
function num(v) {
|
|
1598
1667
|
return typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
1599
1668
|
}
|
|
@@ -1601,8 +1670,8 @@ async function sumCodexByConversation() {
|
|
|
1601
1670
|
const root = codexSessionsDir();
|
|
1602
1671
|
await fs4.stat(root);
|
|
1603
1672
|
const files = [
|
|
1604
|
-
...await collectRollouts(
|
|
1605
|
-
...await collectRollouts(
|
|
1673
|
+
...await collectRollouts(path6.join(root, "sessions")),
|
|
1674
|
+
...await collectRollouts(path6.join(root, "archived_sessions"))
|
|
1606
1675
|
];
|
|
1607
1676
|
const byConv = /* @__PURE__ */ new Map();
|
|
1608
1677
|
for (const file of files) {
|
|
@@ -1630,7 +1699,7 @@ async function collectRollouts(dir) {
|
|
|
1630
1699
|
}
|
|
1631
1700
|
const out = [];
|
|
1632
1701
|
for (const entry of entries) {
|
|
1633
|
-
const full =
|
|
1702
|
+
const full = path6.join(dir, entry.name);
|
|
1634
1703
|
if (entry.isDirectory()) out.push(...await collectRollouts(full));
|
|
1635
1704
|
else if (entry.name.startsWith("rollout-") && entry.name.endsWith(".jsonl")) out.push(full);
|
|
1636
1705
|
}
|
|
@@ -1665,7 +1734,7 @@ async function lastTokenCount(file) {
|
|
|
1665
1734
|
|
|
1666
1735
|
// src/tokens/gemini.ts
|
|
1667
1736
|
import * as fs5 from "fs/promises";
|
|
1668
|
-
import * as
|
|
1737
|
+
import * as path7 from "path";
|
|
1669
1738
|
function num2(v) {
|
|
1670
1739
|
return typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
1671
1740
|
}
|
|
@@ -1691,7 +1760,7 @@ async function listChatFiles(root) {
|
|
|
1691
1760
|
const entries = await fs5.readdir(root);
|
|
1692
1761
|
const out = [];
|
|
1693
1762
|
for (const entry of entries) {
|
|
1694
|
-
const chatsDir =
|
|
1763
|
+
const chatsDir = path7.join(root, entry, "chats");
|
|
1695
1764
|
let files;
|
|
1696
1765
|
try {
|
|
1697
1766
|
files = await fs5.readdir(chatsDir);
|
|
@@ -1699,7 +1768,7 @@ async function listChatFiles(root) {
|
|
|
1699
1768
|
continue;
|
|
1700
1769
|
}
|
|
1701
1770
|
for (const f of files) {
|
|
1702
|
-
if (f.endsWith(".json") || f.endsWith(".jsonl")) out.push(
|
|
1771
|
+
if (f.endsWith(".json") || f.endsWith(".jsonl")) out.push(path7.join(chatsDir, f));
|
|
1703
1772
|
}
|
|
1704
1773
|
}
|
|
1705
1774
|
return out;
|
|
@@ -1925,8 +1994,6 @@ function RunRace({ active, initialState, pendingMode, ownUserName }) {
|
|
|
1925
1994
|
const ctrl = useRef(new AbortController());
|
|
1926
1995
|
const [stalled, setStalled] = useState5(false);
|
|
1927
1996
|
const [stallReason, setStallReason] = useState5(null);
|
|
1928
|
-
const baselineRef = useRef(initialState.acked);
|
|
1929
|
-
const [perSource, setPerSource] = useState5({ claude: 0, codex: 0, gemini: 0 });
|
|
1930
1997
|
useEffect2(() => {
|
|
1931
1998
|
const t = setInterval(() => setTickNow(/* @__PURE__ */ new Date()), 1e3);
|
|
1932
1999
|
return () => clearInterval(t);
|
|
@@ -1956,12 +2023,6 @@ function RunRace({ active, initialState, pendingMode, ownUserName }) {
|
|
|
1956
2023
|
if (pendingRef.current && !isStall(reading)) tracker.reprime();
|
|
1957
2024
|
setStalled(tracker.stalled);
|
|
1958
2025
|
setStallReason(tracker.stalled ? tracker.stallReason : null);
|
|
1959
|
-
const since = tracker.secondarySinceJoin(baselineRef.current);
|
|
1960
|
-
const ps = { claude: 0, codex: 0, gemini: 0 };
|
|
1961
|
-
for (const k of MODEL_KEYS) {
|
|
1962
|
-
ps[k] = k === active.primary_model ? tracker.primaryCounted() : since[k];
|
|
1963
|
-
}
|
|
1964
|
-
setPerSource(ps);
|
|
1965
2026
|
return tracker.nextBeat();
|
|
1966
2027
|
},
|
|
1967
2028
|
sendBeat: async (snapshot) => {
|
|
@@ -2029,9 +2090,7 @@ function RunRace({ active, initialState, pendingMode, ownUserName }) {
|
|
|
2029
2090
|
lastHeartbeatOk: lastHbOk,
|
|
2030
2091
|
stalled,
|
|
2031
2092
|
stallReason,
|
|
2032
|
-
primaryModel: active.primary_model
|
|
2033
|
-
perSource,
|
|
2034
|
-
primaryCapped: primaryConversationCap(active.primary_top5 ?? false) !== Infinity
|
|
2093
|
+
primaryModel: active.primary_model
|
|
2035
2094
|
}
|
|
2036
2095
|
),
|
|
2037
2096
|
achievements.length > 0 && /* @__PURE__ */ jsxs6(Box8, { flexDirection: "column", marginTop: 1, children: [
|
|
@@ -2910,6 +2969,36 @@ async function webCommand(deps = {}) {
|
|
|
2910
2969
|
return 0;
|
|
2911
2970
|
}
|
|
2912
2971
|
|
|
2972
|
+
// src/commands/env.ts
|
|
2973
|
+
function warnOverrides() {
|
|
2974
|
+
if (process.env.TOKEN_DERBY_HOME) {
|
|
2975
|
+
console.error("Warning: TOKEN_DERBY_HOME overrides the per-env data directory; `env` selection does not change where the identity is stored.");
|
|
2976
|
+
}
|
|
2977
|
+
if (process.env.TOKEN_DERBY_API_BASE) {
|
|
2978
|
+
console.error("Warning: TOKEN_DERBY_API_BASE overrides the API base; `env` selection does not change which API is used.");
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2981
|
+
function envCommand(arg) {
|
|
2982
|
+
if (!arg) {
|
|
2983
|
+
console.log(`Environment: ${selectedEnv()}`);
|
|
2984
|
+
console.log(`API base: ${apiBase()}`);
|
|
2985
|
+
console.log(`Data dir: ${homeDir()}`);
|
|
2986
|
+
warnOverrides();
|
|
2987
|
+
return 0;
|
|
2988
|
+
}
|
|
2989
|
+
if (!ENV_NAMES.includes(arg)) {
|
|
2990
|
+
console.error(`Unknown environment: ${arg}`);
|
|
2991
|
+
console.error(`Valid environments: ${ENV_NAMES.join(", ")}`);
|
|
2992
|
+
return 2;
|
|
2993
|
+
}
|
|
2994
|
+
setSelectedEnv(arg);
|
|
2995
|
+
console.log(`Switched to ${arg}.`);
|
|
2996
|
+
console.log(`API base: ${apiBase()}`);
|
|
2997
|
+
console.log(`Data dir: ${homeDir()}`);
|
|
2998
|
+
warnOverrides();
|
|
2999
|
+
return 0;
|
|
3000
|
+
}
|
|
3001
|
+
|
|
2913
3002
|
// src/bin.ts
|
|
2914
3003
|
var HELP = `token-derby v${CLI_VERSION}
|
|
2915
3004
|
|
|
@@ -2946,8 +3035,12 @@ Cosmetics:
|
|
|
2946
3035
|
Earn rolls by leveling up horses.
|
|
2947
3036
|
|
|
2948
3037
|
Environment:
|
|
2949
|
-
|
|
2950
|
-
|
|
3038
|
+
token-derby env Show the active environment (prod|staging)
|
|
3039
|
+
token-derby env <prod|staging> Switch environment. Each env has its own
|
|
3040
|
+
identity/stable dir, so switching never
|
|
3041
|
+
touches the other env's account.
|
|
3042
|
+
TOKEN_DERBY_API_BASE Hard-override API base URL (wins over env)
|
|
3043
|
+
TOKEN_DERBY_HOME Hard-override identity/stable directory
|
|
2951
3044
|
`;
|
|
2952
3045
|
async function main() {
|
|
2953
3046
|
const argv = process.argv.slice(2);
|
|
@@ -2965,6 +3058,7 @@ async function main() {
|
|
|
2965
3058
|
return initCommand(reset);
|
|
2966
3059
|
}
|
|
2967
3060
|
if (cmd === "update") return updateCommand();
|
|
3061
|
+
if (cmd === "env") return envCommand(argv[1]);
|
|
2968
3062
|
const identity = await loadIdentity();
|
|
2969
3063
|
if (!identity) {
|
|
2970
3064
|
console.error("Run `token-derby init` to set up your identity before using any other command.");
|