atris 3.74.7 → 3.74.9

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/commands/gm.js CHANGED
@@ -797,19 +797,20 @@ function tail(text, used, width) {
797
797
  return clip(text, Math.max(10, width - used));
798
798
  }
799
799
 
800
- // Last guard on width: a long line breaks after a comma onto an indented
801
- // line; anything still too long ends in "...".
800
+ // Last guard on width, in terminal columns: a long line breaks after a
801
+ // comma onto an indented line; anything still too long ends in "...".
802
802
  function fitLines(lines, width) {
803
+ const { displayWidth, sliceColumns } = require('../lib/text-table');
803
804
  const out = [];
804
805
  for (const line of lines) {
805
806
  let rest = line;
806
- while (rest.length > width) {
807
- const cut = rest.lastIndexOf(', ', width - 1);
807
+ while (displayWidth(rest) > width) {
808
+ const cut = rest.lastIndexOf(', ', sliceColumns(rest, width).length - 1);
808
809
  if (cut <= 0) break;
809
810
  out.push(rest.slice(0, cut + 1));
810
811
  rest = ` ${rest.slice(cut + 2)}`;
811
812
  }
812
- out.push(rest.length > width ? `${rest.slice(0, width - 3)}...` : rest);
813
+ out.push(displayWidth(rest) > width ? `${sliceColumns(rest, width - 3)}...` : rest);
813
814
  }
814
815
  return out;
815
816
  }
@@ -830,13 +831,30 @@ function boardWorkspaceRoot(args = []) {
830
831
  return taskDb.workspaceRoot(path.resolve(workspaceArg));
831
832
  }
832
833
 
834
+ // The team page's cells (role, ovr, engine) for each roster member, read
835
+ // only when the board draws its box in a terminal; null otherwise.
836
+ function boardCells(board, workspaceRoot, ratings) {
837
+ if (!process.stdout.isTTY || !workspaceRoot) return null;
838
+ return require('../lib/gm-bet').teamCells(workspaceRoot, board.roster.map(r => r.name), { ratings });
839
+ }
840
+
833
841
  function loadBoard(workspaceRoot, options = {}) {
842
+ return loadSeasonBoard(workspaceRoot, options).board;
843
+ }
844
+
845
+ // The board and every member's rating (gm-season memberRatings, the same
846
+ // numbers the orb's team page reads) from one read of the season.
847
+ function loadSeasonBoard(workspaceRoot, options = {}) {
834
848
  const season = require('../lib/gm-season');
835
- return season.seasonBoard(season.loadSeason(workspaceRoot, { lastSeen: options.lastSeen }), options);
849
+ const played = season.loadSeason(workspaceRoot, { lastSeen: options.lastSeen });
850
+ return { board: season.seasonBoard(played, options), ratings: season.memberRatings(played.outcomes || []) };
836
851
  }
837
852
 
838
853
  // One screen, about 40 rows at most. Pure: board in, lines out.
839
- function renderBoardLines(board, { interactive = false, width = termWidth() } = {}) {
854
+ // In a terminal, given the team page's cells, the roster is the orb's team
855
+ // table as a divided box (member, role, ovr, engine, status); piped, or when
856
+ // the box cannot fit the width, it keeps the plain columns.
857
+ function renderBoardLines(board, { interactive = false, width = termWidth(), bordered = Boolean(process.stdout.isTTY), cells = null } = {}) {
840
858
  const { clockLabel } = require('../lib/gm-season');
841
859
  const lines = [];
842
860
  const nameW = nameWidth([
@@ -856,7 +874,12 @@ function renderBoardLines(board, { interactive = false, width = termWidth() } =
856
874
  lines.push('');
857
875
 
858
876
  lines.push('roster, last 30 days');
859
- if (board.roster.length) {
877
+ const boxed = bordered && cells && board.roster.length
878
+ ? require('../lib/gm-bet').teamBox(board.roster.map(r => ({ member: r.name, status: r.status })), cells, { width: width - 2 })
879
+ : null;
880
+ if (boxed) {
881
+ lines.push(...boxed.split('\n').map(line => ` ${line}`));
882
+ } else if (board.roster.length) {
860
883
  lines.push(` ${pad('name', nameW)}${pad('ovr', 8)}${pad('form', 7)}${pad('record', 18)}status`);
861
884
  for (const row of board.roster) {
862
885
  const record = `landed ${row.landed} of ${row.jobs}`;
@@ -913,9 +936,10 @@ function renderBoardLines(board, { interactive = false, width = termWidth() } =
913
936
  }
914
937
  lines.push('');
915
938
 
916
- lines.push('key: ovr 60 to 99 = share of finished jobs landed, rookie under 3 finished,');
939
+ lines.push(`key: ovr 60 to 99 = share of finished jobs landed, ${boxed ? 'new' : 'rookie'} under 3 finished,`);
917
940
  lines.push(' stricter than the website rating on purpose (drops and abandons count)');
918
- lines.push(' form: last 5, newest right: k landed, d dropped, x sent back, a abandoned');
941
+ if (boxed) lines.push(' ·· = nothing to show yet: no finished job, no role, or no pinned model');
942
+ else lines.push(' form: last 5, newest right: k landed, d dropped, x sent back, a abandoned');
919
943
  lines.push(' hours: claim to result. on a job: moved in the last 6h. review: pending');
920
944
  if (interactive) for (const line of PLAY_KEYS) lines.push(line);
921
945
  else lines.push(' run atris gm in a terminal to play');
@@ -990,9 +1014,10 @@ function printLeague() {
990
1014
  }
991
1015
 
992
1016
  function printBoard(args = []) {
993
- const board = loadBoard(boardWorkspaceRoot(args));
1017
+ const root = boardWorkspaceRoot(args);
1018
+ const { board, ratings } = loadSeasonBoard(root);
994
1019
  if (board.error) return failRead(board.error);
995
- console.log(renderBoardLines(board).join('\n'));
1020
+ console.log(renderBoardLines(board, { cells: boardCells(board, root, ratings) }).join('\n'));
996
1021
  return undefined;
997
1022
  }
998
1023
 
@@ -1107,11 +1132,11 @@ async function gmPlay(args = []) {
1107
1132
  leagueRowsSeen = [...board.rows, ...(board.hidden_clubs || [])];
1108
1133
  write(renderLeagueLines(board, { interactive: true }).join('\n'));
1109
1134
  } else {
1110
- const board = loadBoard(workspaceRoot, { seen, lastSeen });
1135
+ const { board, ratings } = loadSeasonBoard(workspaceRoot, { seen, lastSeen });
1111
1136
  lastBoard = board;
1112
1137
  seen = new Set(board.last_plays.map(play => play.id));
1113
1138
  stuck = board.stuck || [];
1114
- write(renderBoardLines(board, { interactive: true }).join('\n'));
1139
+ write(renderBoardLines(board, { interactive: true, cells: boardCells(board, workspaceRoot, ratings) }).join('\n'));
1115
1140
  season.writeLastSeen(workspaceRoot, board.now);
1116
1141
  }
1117
1142
  } catch (err) {
@@ -1986,9 +2011,11 @@ async function gmCommand(...args) {
1986
2011
  }
1987
2012
 
1988
2013
  module.exports = {
2014
+ boardCells,
1989
2015
  displayCommand,
1990
2016
  ensureStarterMission,
1991
2017
  gmCommand,
2018
+ loadSeasonBoard,
1992
2019
  pickClub,
1993
2020
  playAction,
1994
2021
  renderBoardLines,
@@ -11664,6 +11664,44 @@ async function memberStandupWalk(room, args = []) {
11664
11664
  return payload;
11665
11665
  }
11666
11666
 
11667
+ // The team page's cells (role, ovr, engine) per standup member, read only
11668
+ // when the standup can draw its table (a terminal); --json never carries
11669
+ // them. ovr comes from gm-season memberRatings, as on the orb's team page.
11670
+ function standupTableData(standup, cwd = process.cwd()) {
11671
+ if (!process.stdout.isTTY) return { bordered: false };
11672
+ const season = require('../lib/gm-season');
11673
+ const root = require('../lib/task-db').workspaceRoot(path.resolve(cwd));
11674
+ let ratings = new Map();
11675
+ try {
11676
+ const played = season.loadSeason(root, { lastSeen: null });
11677
+ if (played && !played.error) ratings = season.memberRatings(played.outcomes || []);
11678
+ } catch { ratings = new Map(); }
11679
+ const cells = require('../lib/gm-bet').teamCells(root, standup.map((s) => s.member), { ratings });
11680
+ return { bordered: true, cells };
11681
+ }
11682
+
11683
+ // The standup: in a terminal the orb's team table as a divided box
11684
+ // (member, role, ovr, engine, status) with each member's found and push
11685
+ // lines under it; piped, or when the box cannot fit, the boxes it always had.
11686
+ function memberStandupLines(standup, { bordered = false, width = process.stdout.columns, cells = null } = {}) {
11687
+ if (bordered && cells && standup.length) {
11688
+ const table = require('../lib/gm-bet').teamBox(standup.map((s) => ({ member: s.member, status: s.status })), cells, { width: Number(width) - 2 });
11689
+ if (table) {
11690
+ return [
11691
+ ...table.split('\n').map((line) => ` ${line}`),
11692
+ ...standup.flatMap((s) => [` ${s.member}`, ` found: ${s.latest_update}`, ` push: ${s.next_push}`]),
11693
+ ];
11694
+ }
11695
+ }
11696
+ return standup.flatMap((s, idx) => [
11697
+ `+-----------------------------------------------------------------------+`,
11698
+ `| ${idx + 1}. ${s.member.toUpperCase()} (${s.role}) · ${s.status} · engine:${s.engine}`,
11699
+ `| Found: ${s.latest_update}`,
11700
+ `| Push: ${s.next_push}`,
11701
+ `+-----------------------------------------------------------------------+`,
11702
+ ]);
11703
+ }
11704
+
11667
11705
  async function memberRoom(...args) {
11668
11706
  if (hasFlag(args, '--help') || hasFlag(args, '-h')) {
11669
11707
  console.log('Usage: atris member [day|standup|room] [--walk] [--limit N] [--decisions "y|idea|n"] [--json]');
@@ -11680,13 +11718,7 @@ async function memberRoom(...args) {
11680
11718
  ? `Your team runs on ${teamEngines.length > 1 ? `${teamEngines.slice(0, -1).join(', ')} and ${teamEngines[teamEngines.length - 1]}` : teamEngines[0]}.`
11681
11719
  : 'Your team picks an engine for each job.';
11682
11720
 
11683
- const standupRows = room.standup.flatMap((s, idx) => [
11684
- `+-----------------------------------------------------------------------+`,
11685
- `| ${idx + 1}. ${s.member.toUpperCase()} (${s.role}) · ${s.status} · engine:${s.engine}`,
11686
- `| Found: ${s.latest_update}`,
11687
- `| Push: ${s.next_push}`,
11688
- `+-----------------------------------------------------------------------+`,
11689
- ]);
11721
+ const standupRows = memberStandupLines(room.standup, standupTableData(room.standup));
11690
11722
 
11691
11723
  const handoffRows = room.handoffs.length
11692
11724
  ? room.handoffs.map((h) => ` - ${h.from} -> ${h.to}: ${h.summary} (run: ${h.next_command})`)
@@ -12019,6 +12051,8 @@ async function memberCommand(subcommand, ...args) {
12019
12051
 
12020
12052
  module.exports = {
12021
12053
  logDateForScan,
12054
+ memberStandupLines,
12055
+ standupTableData,
12022
12056
  memberRunDefaultWallSeconds,
12023
12057
  memberRunWantsReferee,
12024
12058
  proposalPromptForGoal,