From bc6f8622cd7fe46369ae4b6599f5360a35a282f4 Mon Sep 17 00:00:00 2001 From: Rob von Behren Date: Tue, 7 Apr 2026 16:33:35 -0700 Subject: [PATCH 1/3] fix: improve column width formatting for agent listing --- src/commands/agent/list.ts | 129 +++++++++++++++++++++++++++---------- 1 file changed, 94 insertions(+), 35 deletions(-) diff --git a/src/commands/agent/list.ts b/src/commands/agent/list.ts index 935d972..2aa95ae 100644 --- a/src/commands/agent/list.ts +++ b/src/commands/agent/list.ts @@ -16,16 +16,93 @@ interface ListOptions { output?: string; } -// Column widths (NAME is dynamic, takes remaining space) -const COL_VERSION = 18; -const COL_VISIBILITY = 10; -const COL_ID = 30; -const COL_CREATED = 10; -const FIXED_WIDTH = COL_VERSION + COL_VISIBILITY + COL_ID + COL_CREATED + 4; // 4 for spacing - -function truncate(str: string, maxLen: number): string { - if (str.length <= maxLen) return str; - return str.slice(0, maxLen - 1) + "…"; +interface ColumnDef { + header: string; + raw: (agent: Agent) => string; + styled: (agent: Agent) => string; +} + +const columns: ColumnDef[] = [ + { + header: "NAME", + raw: (a) => (a.is_public ? "➰ " : "") + a.name, + styled(a) { + return this.raw(a); + }, + }, + { + header: "SOURCE", + raw: (a) => (a as any).source?.type || "-", + styled(a) { + return this.raw(a); + }, + }, + { + header: "VERSION", + raw: (a) => { + const pkg = + (a as any).source?.npm?.package_name || + (a as any).source?.pip?.package_name; + return pkg ? `${pkg}@${a.version}` : a.version; + }, + styled(a) { + const pkg = + (a as any).source?.npm?.package_name || + (a as any).source?.pip?.package_name; + return pkg ? chalk.dim(pkg + "@") + a.version : a.version; + }, + }, + { + header: "VISIBILITY", + raw: (a) => (a.is_public ? "public" : "private"), + styled(a) { + return a.is_public + ? chalk.green(this.raw(a)) + : chalk.dim(this.raw(a)); + }, + }, + { + header: "ID", + raw: (a) => a.id, + styled(a) { + return chalk.dim(a.id); + }, + }, + { + header: "CREATED", + raw: (a) => formatTimeAgo(a.create_time_ms), + styled(a) { + return chalk.dim(this.raw(a)); + }, + }, +]; + +function computeColumnWidths(agents: Agent[]): number[] { + const minPad = 2; + const maxPad = 4; + const termWidth = process.stdout.columns || 120; + + // Min width per column: max of header and all row values, plus minimum padding + const minWidths = columns.map((col) => { + const maxContent = agents.reduce( + (w, a) => Math.max(w, col.raw(a).length), + col.header.length, + ); + return maxContent + minPad; + }); + + const totalMin = minWidths.reduce((s, w) => s + w, 0); + const slack = termWidth - totalMin; + const extraPerCol = Math.min( + maxPad - minPad, + Math.max(0, Math.floor(slack / columns.length)), + ); + + return minWidths.map((w) => w + extraPerCol); +} + +function padStyled(raw: string, styled: string, width: number): string { + return styled + " ".repeat(Math.max(0, width - raw.length)); } function printTable(agents: Agent[]): void { @@ -34,38 +111,20 @@ function printTable(agents: Agent[]): void { return; } + const widths = computeColumnWidths(agents); const termWidth = process.stdout.columns || 120; - const nameWidth = Math.max(10, termWidth - FIXED_WIDTH); // Header - const header = - "NAME".padEnd(nameWidth) + - " " + - "VERSION".padEnd(COL_VERSION) + - " " + - "VISIBILITY".padEnd(COL_VISIBILITY) + - " " + - "ID".padEnd(COL_ID) + - " " + - "CREATED".padEnd(COL_CREATED); + const header = columns.map((col, i) => col.header.padEnd(widths[i])).join(""); console.log(chalk.bold(header)); console.log(chalk.dim("─".repeat(Math.min(header.length, termWidth)))); + // Rows for (const agent of agents) { - const name = truncate(agent.name, nameWidth).padEnd(nameWidth); - const version = truncate(agent.version, COL_VERSION).padEnd(COL_VERSION); - const visibility = (agent.is_public ? "public" : "private").padEnd( - COL_VISIBILITY, - ); - const visibilityColored = agent.is_public - ? chalk.green(visibility) - : chalk.dim(visibility); - const id = truncate(agent.id, COL_ID).padEnd(COL_ID); - const created = formatTimeAgo(agent.create_time_ms).padEnd(COL_CREATED); - - console.log( - `${name} ${version} ${visibilityColored} ${chalk.dim(id)} ${chalk.dim(created)}`, - ); + const line = columns + .map((col, i) => padStyled(col.raw(agent), col.styled(agent), widths[i])) + .join(""); + console.log(line); } console.log(); From eae322fba5dca7272752f61872d0d0ca3e767455 Mon Sep 17 00:00:00 2001 From: Rob von Behren Date: Tue, 7 Apr 2026 16:38:53 -0700 Subject: [PATCH 2/3] fmt --- src/commands/agent/list.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/commands/agent/list.ts b/src/commands/agent/list.ts index 2aa95ae..9abcbb0 100644 --- a/src/commands/agent/list.ts +++ b/src/commands/agent/list.ts @@ -56,9 +56,7 @@ const columns: ColumnDef[] = [ header: "VISIBILITY", raw: (a) => (a.is_public ? "public" : "private"), styled(a) { - return a.is_public - ? chalk.green(this.raw(a)) - : chalk.dim(this.raw(a)); + return a.is_public ? chalk.green(this.raw(a)) : chalk.dim(this.raw(a)); }, }, { From a36f087e08031a4f7ec19eaae7d0f8a21ad7706c Mon Sep 17 00:00:00 2001 From: Rob von Behren Date: Tue, 7 Apr 2026 18:33:47 -0700 Subject: [PATCH 3/3] slim down visibility info --- src/commands/agent/list.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/commands/agent/list.ts b/src/commands/agent/list.ts index 9abcbb0..e0617bd 100644 --- a/src/commands/agent/list.ts +++ b/src/commands/agent/list.ts @@ -25,7 +25,7 @@ interface ColumnDef { const columns: ColumnDef[] = [ { header: "NAME", - raw: (a) => (a.is_public ? "➰ " : "") + a.name, + raw: (a) => a.name, styled(a) { return this.raw(a); }, @@ -52,13 +52,6 @@ const columns: ColumnDef[] = [ return pkg ? chalk.dim(pkg + "@") + a.version : a.version; }, }, - { - header: "VISIBILITY", - raw: (a) => (a.is_public ? "public" : "private"), - styled(a) { - return a.is_public ? chalk.green(this.raw(a)) : chalk.dim(this.raw(a)); - }, - }, { header: "ID", raw: (a) => a.id, @@ -103,7 +96,18 @@ function padStyled(raw: string, styled: string, width: number): string { return styled + " ".repeat(Math.max(0, width - raw.length)); } -function printTable(agents: Agent[]): void { +function printTable(agents: Agent[], isPublic: boolean): void { + if (isPublic) { + console.log( + chalk.dim("Showing PUBLIC agents. Use --private to see private agents"), + ); + } else { + console.log( + chalk.dim("Showing PRIVATE agents. Use --public to see public agents"), + ); + } + console.log(); + if (agents.length === 0) { console.log(chalk.dim("No agents found")); return; @@ -162,7 +166,7 @@ export async function listAgentsCommand(options: ListOptions): Promise { if (format !== "text") { output(agents, { format, defaultFormat: "json" }); } else { - printTable(agents); + printTable(agents, !!options.public); } } catch (error) { outputError("Failed to list agents", error);