Terminal: stop shrinking CLI tables by one column

This commit is contained in:
Vincent Koc
2026-03-11 01:40:01 -04:00
parent c58fffdab6
commit 209decf25c
16 changed files with 38 additions and 37 deletions

View File

@@ -9,7 +9,7 @@ import {
} from "../infra/device-pairing.js";
import { formatTimeAgo } from "../infra/format-time/format-relative.ts";
import { defaultRuntime } from "../runtime.js";
import { renderTable } from "../terminal/table.js";
import { getTerminalTableWidth, renderTable } from "../terminal/table.js";
import { theme } from "../terminal/theme.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
import { withProgress } from "./progress.js";
@@ -224,7 +224,7 @@ export function registerDevicesCli(program: Command) {
return;
}
if (list.pending?.length) {
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
defaultRuntime.log(
`${theme.heading("Pending")} ${theme.muted(`(${list.pending.length})`)}`,
);
@@ -251,7 +251,7 @@ export function registerDevicesCli(program: Command) {
);
}
if (list.paired?.length) {
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
defaultRuntime.log(
`${theme.heading("Paired")} ${theme.muted(`(${list.paired.length})`)}`,
);

View File

@@ -6,7 +6,7 @@ import { danger } from "../globals.js";
import { resolveMessageChannelSelection } from "../infra/outbound/channel-selection.js";
import { defaultRuntime } from "../runtime.js";
import { formatDocsLink } from "../terminal/links.js";
import { renderTable } from "../terminal/table.js";
import { getTerminalTableWidth, renderTable } from "../terminal/table.js";
import { theme } from "../terminal/theme.js";
import { formatHelpExamples } from "./help-format.js";
@@ -48,7 +48,7 @@ function printDirectoryList(params: {
return;
}
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
defaultRuntime.log(`${theme.heading(params.title)} ${theme.muted(`(${params.entries.length})`)}`);
defaultRuntime.log(
renderTable({
@@ -166,7 +166,7 @@ export function registerDirectoryCli(program: Command) {
defaultRuntime.log(theme.muted("Not available."));
return;
}
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
defaultRuntime.log(theme.heading("Self"));
defaultRuntime.log(
renderTable({

View File

@@ -7,7 +7,7 @@ import { pickPrimaryTailnetIPv4, pickPrimaryTailnetIPv6 } from "../infra/tailnet
import { getWideAreaZonePath, resolveWideAreaDiscoveryDomain } from "../infra/widearea-dns.js";
import { defaultRuntime } from "../runtime.js";
import { formatDocsLink } from "../terminal/links.js";
import { renderTable } from "../terminal/table.js";
import { getTerminalTableWidth, renderTable } from "../terminal/table.js";
import { theme } from "../terminal/theme.js";
type RunOpts = { allowFailure?: boolean; inherit?: boolean };
@@ -133,7 +133,7 @@ export function registerDnsCli(program: Command) {
}
const zonePath = getWideAreaZonePath(wideAreaDomain);
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
defaultRuntime.log(theme.heading("DNS setup"));
defaultRuntime.log(
renderTable({

View File

@@ -10,7 +10,7 @@ import {
import { formatTimeAgo } from "../infra/format-time/format-relative.ts";
import { defaultRuntime } from "../runtime.js";
import { formatDocsLink } from "../terminal/links.js";
import { renderTable } from "../terminal/table.js";
import { getTerminalTableWidth, renderTable } from "../terminal/table.js";
import { isRich, theme } from "../terminal/theme.js";
import { describeUnknownError } from "./gateway-cli/shared.js";
import { callGatewayFromCli } from "./gateway-rpc.js";
@@ -151,7 +151,7 @@ function renderApprovalsSnapshot(snapshot: ExecApprovalsSnapshot, targetLabel: s
const rich = isRich();
const heading = (text: string) => (rich ? theme.heading(text) : text);
const muted = (text: string) => (rich ? theme.muted(text) : text);
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
const file = snapshot.file ?? { version: 1 };
const defaults = file.defaults ?? {};

View File

@@ -22,7 +22,7 @@ import { resolveArchiveKind } from "../infra/archive.js";
import { buildPluginStatusReport } from "../plugins/status.js";
import { defaultRuntime } from "../runtime.js";
import { formatDocsLink } from "../terminal/links.js";
import { renderTable } from "../terminal/table.js";
import { getTerminalTableWidth, renderTable } from "../terminal/table.js";
import { theme } from "../terminal/theme.js";
import { resolveUserPath, shortenHomePath } from "../utils.js";
import { formatCliCommand } from "./command-format.js";
@@ -273,7 +273,7 @@ export function formatHooksList(report: HookStatusReport, opts: HooksListOptions
}
const eligible = hooks.filter((h) => h.eligible);
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
const rows = hooks.map((hook) => {
const missing = formatHookMissingSummary(hook);
return {

View File

@@ -1,6 +1,6 @@
import type { Command } from "commander";
import { defaultRuntime } from "../../runtime.js";
import { renderTable } from "../../terminal/table.js";
import { getTerminalTableWidth, renderTable } from "../../terminal/table.js";
import { shortenHomePath } from "../../utils.js";
import {
type CameraFacing,
@@ -71,7 +71,7 @@ export function registerNodesCameraCommands(nodes: Command) {
}
const { heading, muted } = getNodesTheme();
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
const rows = devices.map((device) => ({
Name: typeof device.name === "string" ? device.name : "Unknown Camera",
Position: typeof device.position === "string" ? device.position : muted("unspecified"),

View File

@@ -1,5 +1,6 @@
import type { Command } from "commander";
import { defaultRuntime } from "../../runtime.js";
import { getTerminalTableWidth } from "../../terminal/table.js";
import { getNodesTheme, runNodesCommand } from "./cli-utils.js";
import { parsePairingList } from "./format.js";
import { renderPendingPairingRequestsTable } from "./pairing-render.js";
@@ -25,7 +26,7 @@ export function registerNodesPairingCommands(nodes: Command) {
return;
}
const { heading, warn, muted } = getNodesTheme();
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
const now = Date.now();
const rendered = renderPendingPairingRequestsTable({
pending,

View File

@@ -1,7 +1,7 @@
import type { Command } from "commander";
import { formatTimeAgo } from "../../infra/format-time/format-relative.ts";
import { defaultRuntime } from "../../runtime.js";
import { renderTable } from "../../terminal/table.js";
import { getTerminalTableWidth, renderTable } from "../../terminal/table.js";
import { shortenHomeInString } from "../../utils.js";
import { parseDurationMs } from "../parse-duration.js";
import { getNodesTheme, runNodesCommand } from "./cli-utils.js";
@@ -112,7 +112,7 @@ export function registerNodesStatusCommands(nodes: Command) {
const obj: Record<string, unknown> =
typeof result === "object" && result !== null ? result : {};
const { ok, warn, muted } = getNodesTheme();
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
const now = Date.now();
const nodes = parseNodeList(result);
const lastConnectedById =
@@ -256,7 +256,7 @@ export function registerNodesStatusCommands(nodes: Command) {
const status = `${paired ? ok("paired") : warn("unpaired")} · ${
connected ? ok("connected") : muted("disconnected")
}`;
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
const rows = [
{ Field: "ID", Value: nodeId },
displayName ? { Field: "Name", Value: displayName } : null,
@@ -307,7 +307,7 @@ export function registerNodesStatusCommands(nodes: Command) {
const result = await callGatewayCli("node.pair.list", opts, {});
const { pending, paired } = parsePairingList(result);
const { heading, muted, warn } = getNodesTheme();
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
const now = Date.now();
const hasFilters = connectedOnly || sinceMs !== undefined;
const pendingRows = hasFilters ? [] : pending;

View File

@@ -10,7 +10,7 @@ import {
} from "../pairing/pairing-store.js";
import { defaultRuntime } from "../runtime.js";
import { formatDocsLink } from "../terminal/links.js";
import { renderTable } from "../terminal/table.js";
import { getTerminalTableWidth, renderTable } from "../terminal/table.js";
import { theme } from "../terminal/theme.js";
import { formatCliCommand } from "./command-format.js";
@@ -88,7 +88,7 @@ export function registerPairingCli(program: Command) {
return;
}
const idLabel = resolvePairingIdLabel(channel);
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
defaultRuntime.log(
`${theme.heading("Pairing requests")} ${theme.muted(`(${requests.length})`)}`,
);

View File

@@ -19,7 +19,7 @@ import { resolveUninstallDirectoryTarget, uninstallPlugin } from "../plugins/uni
import { updateNpmInstalledPlugins } from "../plugins/update.js";
import { defaultRuntime } from "../runtime.js";
import { formatDocsLink } from "../terminal/links.js";
import { renderTable } from "../terminal/table.js";
import { getTerminalTableWidth, renderTable } from "../terminal/table.js";
import { theme } from "../terminal/theme.js";
import { resolveUserPath, shortenHomeInString, shortenHomePath } from "../utils.js";
import { looksLikeLocalInstallSpec } from "./install-spec.js";
@@ -404,7 +404,7 @@ export function registerPluginsCli(program: Command) {
);
if (!opts.verbose) {
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
const sourceRoots = resolvePluginSourceRoots({
workspaceDir: report.workspaceDir,
});

View File

@@ -1,5 +1,5 @@
import type { SkillStatusEntry, SkillStatusReport } from "../agents/skills-status.js";
import { renderTable } from "../terminal/table.js";
import { getTerminalTableWidth, renderTable } from "../terminal/table.js";
import { theme } from "../terminal/theme.js";
import { shortenHomePath } from "../utils.js";
import { formatCliCommand } from "./command-format.js";
@@ -39,7 +39,7 @@ function formatSkillStatus(skill: SkillStatusEntry): string {
}
function formatSkillName(skill: SkillStatusEntry): string {
const emoji = skill.emoji ?? "📦";
const emoji = (skill.emoji ?? "📦").replaceAll("\uFE0E", "\uFE0F");
return `${emoji} ${theme.command(skill.name)}`;
}
@@ -95,7 +95,7 @@ export function formatSkillsList(report: SkillStatusReport, opts: SkillsListOpti
}
const eligible = skills.filter((s) => s.eligible);
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
const rows = skills.map((skill) => {
const missing = formatSkillMissingSummary(skill);
return {
@@ -109,7 +109,7 @@ export function formatSkillsList(report: SkillStatusReport, opts: SkillsListOpti
const columns = [
{ key: "Status", header: "Status", minWidth: 10 },
{ key: "Skill", header: "Skill", minWidth: 18, flex: true },
{ key: "Skill", header: "Skill", minWidth: 22 },
{ key: "Description", header: "Description", minWidth: 24, flex: true },
{ key: "Source", header: "Source", minWidth: 10 },
];

View File

@@ -10,7 +10,7 @@ import {
} from "../../infra/update-channels.js";
import { checkUpdateStatus } from "../../infra/update-check.js";
import { defaultRuntime } from "../../runtime.js";
import { renderTable } from "../../terminal/table.js";
import { getTerminalTableWidth, renderTable } from "../../terminal/table.js";
import { theme } from "../../terminal/theme.js";
import { parseTimeoutMsOrExit, resolveUpdateRoot, type UpdateStatusOptions } from "./shared.js";
@@ -89,7 +89,7 @@ export async function updateStatusCommand(opts: UpdateStatusOptions): Promise<vo
return;
}
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
const installLabel =
update.installKind === "git"
? `git (${update.root ?? "unknown"})`

View File

@@ -4,7 +4,7 @@ import type { OutboundDeliveryResult } from "../infra/outbound/deliver.js";
import { formatGatewaySummary, formatOutboundDeliverySummary } from "../infra/outbound/format.js";
import type { MessageActionRunResult } from "../infra/outbound/message-action-runner.js";
import { formatTargetDisplay } from "../infra/outbound/target-resolver.js";
import { renderTable } from "../terminal/table.js";
import { getTerminalTableWidth, renderTable } from "../terminal/table.js";
import { isRich, theme } from "../terminal/theme.js";
import { shortenText } from "./text-format.js";
@@ -257,7 +257,7 @@ export function formatMessageCliText(result: MessageActionRunResult): string[] {
const muted = (text: string) => (rich ? theme.muted(text) : text);
const heading = (text: string) => (rich ? theme.heading(text) : text);
const width = Math.max(60, (process.stdout.columns ?? 120) - 1);
const width = getTerminalTableWidth();
const opts: FormatOpts = { width };
if (result.handledBy === "dry-run") {

View File

@@ -38,7 +38,7 @@ import {
} from "../../infra/provider-usage.js";
import { getShellEnvAppliedKeys, shouldEnableShellEnvFallback } from "../../infra/shell-env.js";
import type { RuntimeEnv } from "../../runtime.js";
import { renderTable } from "../../terminal/table.js";
import { getTerminalTableWidth, renderTable } from "../../terminal/table.js";
import { colorize, theme } from "../../terminal/theme.js";
import { shortenHomePath } from "../../utils.js";
import { resolveProviderAuthOverview } from "./list.auth-overview.js";
@@ -631,7 +631,7 @@ export async function modelsStatusCommand(
if (probeSummary.results.length === 0) {
runtime.log(colorize(rich, theme.muted, "- none"));
} else {
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
const sorted = sortProbeResults(probeSummary.results);
const statusColor = (status: string) => {
if (status === "ok") {

View File

@@ -1,5 +1,5 @@
import type { ProgressReporter } from "../../cli/progress.js";
import { renderTable } from "../../terminal/table.js";
import { getTerminalTableWidth, renderTable } from "../../terminal/table.js";
import { isRich, theme } from "../../terminal/theme.js";
import { groupChannelIssuesByChannel } from "./channel-issues.js";
import { appendStatusAllDiagnosis } from "./diagnosis.js";
@@ -57,7 +57,7 @@ export async function buildStatusAllReportLines(params: {
const fail = (text: string) => (rich ? theme.error(text) : text);
const muted = (text: string) => (rich ? theme.muted(text) : text);
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
const overview = renderTable({
width: tableWidth,

View File

@@ -16,7 +16,7 @@ import {
} from "../memory/status-format.js";
import type { RuntimeEnv } from "../runtime.js";
import { runSecurityAudit } from "../security/audit.js";
import { renderTable } from "../terminal/table.js";
import { getTerminalTableWidth, renderTable } from "../terminal/table.js";
import { theme } from "../terminal/theme.js";
import { formatHealthChannelLines, type HealthSummary } from "./health.js";
import { resolveControlUiLinks } from "./onboard-helpers.js";
@@ -229,7 +229,7 @@ export async function statusCommand(
runtime.log("");
}
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
const tableWidth = getTerminalTableWidth();
if (secretDiagnostics.length > 0) {
runtime.log(theme.warn("Secret diagnostics:"));