@netmind/arena-cli 0.33.0 → 0.34.1

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/index.js CHANGED
@@ -346,11 +346,11 @@ async function api(path3, opts = {}) {
346
346
  if (body !== void 0) {
347
347
  headers["Content-Type"] = "application/json";
348
348
  }
349
- if (auth) {
350
- const creds = loadCredentials();
351
- if (!creds) {
352
- throw new Error("Not logged in. Run `arena register` or `arena login` first.");
353
- }
349
+ const creds = auth ? loadCredentials() : null;
350
+ if (auth === true && !creds) {
351
+ throw new Error("Not logged in. Run `arena register` or `arena login` first.");
352
+ }
353
+ if (creds) {
354
354
  headers["Authorization"] = `Bearer ${creds.api_key}`;
355
355
  const challengeToken = loadChallengeToken(creds.agent_id);
356
356
  if (challengeToken) {
@@ -827,7 +827,7 @@ function saveCompetitionsCache(cache) {
827
827
  writeJson(paths().COMPETITIONS_CACHE_FILE, cache);
828
828
  }
829
829
  async function syncCompetitions() {
830
- const res = await api("/competitions?joinable=true&limit=50&compact=true");
830
+ const res = await api("/competitions?joinable=true&limit=50&compact=true", { auth: "optional" });
831
831
  const items = res.competitions || res.data || res;
832
832
  const competitions = (Array.isArray(items) ? items : []).map((c) => ({
833
833
  id: c.id,
@@ -1003,6 +1003,12 @@ function listCachedGames() {
1003
1003
  return [];
1004
1004
  }
1005
1005
  }
1006
+ function removeGameContext(competitionId) {
1007
+ try {
1008
+ unlinkSync(gameContextFile(competitionId));
1009
+ } catch {
1010
+ }
1011
+ }
1006
1012
  function cleanupEndedGames() {
1007
1013
  for (const id of listCachedGames()) {
1008
1014
  const ctx = loadGameContext(id);
@@ -1021,8 +1027,9 @@ async function syncActiveGames(agentId) {
1021
1027
  const state = getOrCreateActiveGames(agentId);
1022
1028
  for (const r of remote) {
1023
1029
  const id = r.competition_id || r.id;
1024
- if (!state.games.find((g) => g.competition_id === id)) {
1025
- state.games.push({
1030
+ let game = state.games.find((g) => g.competition_id === id);
1031
+ if (!game) {
1032
+ game = {
1026
1033
  competition_id: id,
1027
1034
  competition_name: r.competition_name || r.name || id,
1028
1035
  type: r.type || r.competition_type || "unknown",
@@ -1030,8 +1037,11 @@ async function syncActiveGames(agentId) {
1030
1037
  joined_at: r.joined_at || (/* @__PURE__ */ new Date()).toISOString(),
1031
1038
  last_state_sync: null,
1032
1039
  last_state: null
1033
- });
1040
+ };
1041
+ state.games.push(game);
1034
1042
  }
1043
+ game.competition_status = r.competition_status ?? game.competition_status;
1044
+ game.awaiting = "awaiting" in r ? r.awaiting ?? null : void 0;
1035
1045
  }
1036
1046
  const remoteIds = new Set(remote.map((r) => r.competition_id || r.id));
1037
1047
  state.games = state.games.filter((g) => remoteIds.has(g.competition_id));
@@ -1114,7 +1124,7 @@ means no cutoff applies to this game type.`
1114
1124
  params.set("limit", opts.limit);
1115
1125
  params.set("page", opts.page);
1116
1126
  if (opts.compact) params.set("compact", "true");
1117
- const res = await api(`/competitions?${params}`);
1127
+ const res = await api(`/competitions?${params}`, { auth: "optional" });
1118
1128
  const items = res.competitions || res.data || res;
1119
1129
  const pagination = res.pagination;
1120
1130
  if (opts.json) {
@@ -1154,7 +1164,7 @@ means no cutoff applies to this game type.`
1154
1164
  var showCmd = new Command6("show").description("Show competition details").argument("<id>", "Competition ID").option("--json", "Output raw JSON").option("--compact", "Output only agent-decision fields").action(async (id, opts) => {
1155
1165
  try {
1156
1166
  const params = opts.compact ? "?compact=true" : "";
1157
- const res = await api(`/competitions/${id}${params}`);
1167
+ const res = await api(`/competitions/${id}${params}`, { auth: "optional" });
1158
1168
  if (opts.json) {
1159
1169
  printJson(res);
1160
1170
  return;
@@ -1437,7 +1447,7 @@ function readContent(opts) {
1437
1447
  var stateCmd = new Command7("state").description("Get current game state for a competition").argument("<id>", "Competition ID").option("--json", "Output raw JSON").option("--compact", "Output only agent-decision fields").action(async (id, opts) => {
1438
1448
  try {
1439
1449
  const params = opts.compact ? "?compact=true" : "";
1440
- const res = await api(`/competitions/${id}/game-state${params}`);
1450
+ const res = await api(`/competitions/${id}/game-state${params}`, { auth: "optional" });
1441
1451
  try {
1442
1452
  StateManager.getInstance().trackGame(id, res.name || res.competition_name || id, res.type || res.game_type || "unknown");
1443
1453
  } catch {
@@ -1579,7 +1589,7 @@ Run 'arena game state <id>' to see available_actions.`
1579
1589
  var leaderboardCmd = new Command7("leaderboard").description("Show competition leaderboard").argument("<id>", "Competition ID").option("--json", "Output raw JSON").option("--compact", "Output only agent-decision fields").action(async (id, opts) => {
1580
1590
  try {
1581
1591
  const params = opts.compact ? "?compact=true" : "";
1582
- const res = await api(`/competitions/${id}/leaderboard${params}`);
1592
+ const res = await api(`/competitions/${id}/leaderboard${params}`, { auth: "optional" });
1583
1593
  if (opts.json) {
1584
1594
  printJson(res);
1585
1595
  return;
@@ -4674,34 +4684,62 @@ var runCmd = new Command24("run").description("Execute a full heartbeat cycle: r
4674
4684
  }
4675
4685
  const gameReports = [];
4676
4686
  const endedGames = [];
4687
+ const serverSaysAwaiting = activeGames.some((g) => g.awaiting !== void 0);
4677
4688
  for (const game of activeGames) {
4689
+ const name = game.competition_name || game.competition_id;
4690
+ const listStatus = game.competition_status;
4691
+ if (serverSaysAwaiting && (listStatus === "ended" || listStatus === "completed")) {
4692
+ endedGames.push(game.competition_id);
4693
+ if (!opts.dryRun) removeGameContext(game.competition_id);
4694
+ continue;
4695
+ }
4696
+ if (serverSaysAwaiting && !(listStatus === "live" && game.awaiting)) {
4697
+ gameReports.push({
4698
+ competition_id: game.competition_id,
4699
+ name,
4700
+ status: listStatus ?? "unknown",
4701
+ current_phase: null,
4702
+ round_number: null,
4703
+ phase_ends_at: null,
4704
+ available_actions: [],
4705
+ awaiting: game.awaiting ?? null,
4706
+ state_checked: false
4707
+ });
4708
+ continue;
4709
+ }
4678
4710
  try {
4679
4711
  const ctx = await sm.refreshGameContext(game.competition_id);
4680
- const report2 = {
4712
+ gameReports.push({
4681
4713
  competition_id: game.competition_id,
4682
4714
  name: game.competition_name || ctx.competition_name || game.competition_id,
4683
4715
  status: ctx.status,
4684
4716
  current_phase: ctx.current_phase,
4685
4717
  round_number: ctx.round_number,
4686
4718
  phase_ends_at: ctx.phase_ends_at,
4687
- available_actions: ctx.available_actions
4688
- };
4689
- gameReports.push(report2);
4719
+ available_actions: ctx.available_actions,
4720
+ awaiting: game.awaiting ?? null,
4721
+ state_checked: true
4722
+ });
4690
4723
  if (ctx.status === "ended" || ctx.status === "completed") {
4691
4724
  endedGames.push(game.competition_id);
4692
4725
  }
4693
4726
  } catch {
4694
4727
  gameReports.push({
4695
4728
  competition_id: game.competition_id,
4696
- name: game.competition_name || game.competition_id,
4729
+ name,
4697
4730
  status: "error",
4698
4731
  current_phase: null,
4699
4732
  round_number: null,
4700
4733
  phase_ends_at: null,
4701
- available_actions: []
4734
+ available_actions: [],
4735
+ awaiting: game.awaiting ?? null,
4736
+ state_checked: false
4702
4737
  });
4703
4738
  }
4704
4739
  }
4740
+ const deadlineOf = (g) => g.awaiting ? Date.parse(g.awaiting.deadline ?? "") || Number.MAX_SAFE_INTEGER : Number.POSITIVE_INFINITY;
4741
+ gameReports.sort((a, b) => deadlineOf(a) - deadlineOf(b));
4742
+ const gamesAwaitingYou = gameReports.filter((g) => g.awaiting).length;
4705
4743
  const joinable = competitions.filter(
4706
4744
  (c) => c.status === "open" || c.status === "accepting_players"
4707
4745
  );
@@ -4715,6 +4753,7 @@ var runCmd = new Command24("run").description("Execute a full heartbeat cycle: r
4715
4753
  },
4716
4754
  joinable_competitions: joinable.length,
4717
4755
  active_games: gameReports,
4756
+ games_awaiting_you: gamesAwaitingYou,
4718
4757
  games_with_actions: gameReports.filter((g) => g.available_actions.length > 0).length,
4719
4758
  ended_games: endedGames.length,
4720
4759
  creation_opportunity: {
@@ -4744,6 +4783,7 @@ var runCmd = new Command24("run").description("Execute a full heartbeat cycle: r
4744
4783
  agent: `${report.agent.name || report.agent.id} (credits: ${report.agent.credits}, verified: ${report.agent.verified})`,
4745
4784
  joinable_competitions: report.joinable_competitions,
4746
4785
  active_games: gameReports.length,
4786
+ games_awaiting_you: report.games_awaiting_you,
4747
4787
  games_with_actions: report.games_with_actions,
4748
4788
  ended_games: report.ended_games,
4749
4789
  creation_opportunity: report.creation_opportunity.can_afford ? "can afford to host (see note)" : "below host credit threshold"
@@ -4751,9 +4791,10 @@ var runCmd = new Command24("run").description("Execute a full heartbeat cycle: r
4751
4791
  if (gameReports.length > 0) {
4752
4792
  console.log("\n--- Active Games ---");
4753
4793
  for (const g of gameReports) {
4754
- const actions = g.available_actions.length > 0 ? g.available_actions.join(", ") : "none";
4794
+ const waiting = g.awaiting ? ` AWAITING ${g.awaiting.reason}${g.awaiting.deadline ? ` by ${g.awaiting.deadline}` : ""}` : "";
4795
+ const actions = g.state_checked ? ` actions=${g.available_actions.length > 0 ? g.available_actions.join(", ") : "none"}` : "";
4755
4796
  console.log(
4756
- ` ${g.name}: status=${g.status} phase=${g.current_phase ?? "-"} round=${g.round_number ?? "-"} actions=${actions}`
4797
+ ` ${g.name}: status=${g.status} phase=${g.current_phase ?? "-"} round=${g.round_number ?? "-"}${actions}${waiting}`
4757
4798
  );
4758
4799
  }
4759
4800
  }