briefOutput

tcmts.cli.mcp.briefOutput · #tbmqrihg · term · runs anywhere

A command's output as a tool says it, briefly: a test run's passing tests as a list of names rather than a line each (hundreds of them), so what failed, what ran, and the counts, are what an agent reads. The tests that ran are named; the cached ones too when tests were named or something failed (else the summary counts them). A merge's or revert's changes by name and count (mergeSummary: tcm diff has the code). Waiting for the machine's suite slots, a section's last line of it, above its summary, unless the summary says how long it waited. Other commands' as they are.

import { SLOT_WAIT_LINE } from "#codebase/tcmts/cli/budget";
import { liveArgv, mergeSummary } from "#codebase/tcmts/cli/mcp";

export function briefOutput(argv: string[], out: string): string {
  // (the command, as the codebase's own tcm runs it, `live`, or run in another directory)
  const own = liveArgv([]);
  if (own.every((a, i) => argv[i] === a)) return briefOutput(argv.slice(own.length), out);
  if (argv[0] === "-C") return briefOutput(argv.slice(2), out);
  if (argv[0] === "merge" || argv[0] === "revert") return mergeSummary(out);
  if (argv[0] !== "test") return out;
  // tests named on the command line (not a flag's value)
  const named = argv.slice(1).some((a, i, xs) => !a.startsWith("-") && xs[i - 1] !== "--bin");
  // names under the namespace they share, so a list of end-to-end tests isn't mostly `tcmts.cli.test.e2e.`
  const listed = (label: string, paths: string[]) => {
    const shown = paths.slice(0, 40).map((p) => p.split("."));
    let n = 0;
    while (shown.length > 1 && shown.every((s) => s.length > n + 1 && s[n] === shown[0][n])) n++;
    const more = paths.length > shown.length ? `, and ${paths.length - shown.length} more` : "";
    const under = n ? ` under ${shown[0].slice(0, n).join(".")}` : "";
    return `${label}${under}: ${shown.map((s) => s.slice(n).join(".")).join(", ")}${more}`;
  };
  const lines: string[] = [];
  let ran: string[] = [];
  let cached: string[] = [];
  let failed = false;
  let wait: string | undefined;
  for (const l of out.split("\n")) {
    if (SLOT_WAIT_LINE.test(l)) {
      wait = l.trim();
      continue;
    }
    const pass = /^\s*✓ (\S+)\s*(\(cached\))?/.exec(l);
    if (pass) {
      (pass[2] ? cached : ran).push(pass[1]);
      continue;
    }
    if (/^\s*✗ /.test(l)) failed = true;
    // a section's summary: its passing tests by name, above it
    if (/^(suites: )?\d+ passed, \d+ failed/.test(l)) {
      if (ran.length) lines.push(listed("ran", ran));
      if (cached.length && (named || failed)) lines.push(listed("cached", cached));
      if (wait && !/waiting for slots/.test(l)) lines.push(wait);
      wait = undefined;
      ran = [];
      cached = [];
      failed = false;
    }
    lines.push(l);
  }
  if (wait) lines.push(wait);
  return lines
    .join("\n")
    .replace(/\n{3,}/g, "\n\n")
    .trim();
}

uses

used by