From f3dd4a4463ef074c8e957f2eabb3301e977969d2 Mon Sep 17 00:00:00 2001 From: dundas Date: Sun, 1 Mar 2026 13:22:40 -0600 Subject: [PATCH] =?UTF-8?q?fix(cli):=20address=20PR=20#22=20review=20?= =?UTF-8?q?=E2=80=94=20export=20helpers,=20add=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Export cyan/green/yellow/bold/dim/red from output.ts so consumers import rather than duplicate them; remove local copies in round-tables.ts - Add validateRoundTableId tests in validate.test.ts (valid ID, slash rejected, dot rejected) — consistent with validateGroupId coverage Co-Authored-By: Claude Sonnet 4.6 --- cli/src/commands/round-tables.ts | 10 +--------- cli/src/output.ts | 12 ++++++------ cli/src/validate.test.ts | 19 ++++++++++++++++++- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/cli/src/commands/round-tables.ts b/cli/src/commands/round-tables.ts index 3f88279..9f8a536 100644 --- a/cli/src/commands/round-tables.ts +++ b/cli/src/commands/round-tables.ts @@ -2,7 +2,7 @@ import { Command } from 'commander'; import { spawn } from 'child_process'; import { AdmpClient, AdmpError } from '../client.js'; import { requireConfig } from '../config.js'; -import { success, error, warn, isJsonMode } from '../output.js'; +import { success, error, warn, isJsonMode, green, yellow, cyan, bold, dim } from '../output.js'; import { validateRoundTableId } from '../validate.js'; // ---- Types ------------------------------------------------------------------ @@ -41,14 +41,6 @@ interface CreateRoundTableResponse extends RoundTable { // ---- Helpers ---------------------------------------------------------------- -// NO_COLOR compliance — mirrors the pattern in output.ts -const NO_COLOR = 'NO_COLOR' in process.env; -function cyan(s: string): string { return NO_COLOR ? s : `\x1b[36m${s}\x1b[0m`; } -function green(s: string): string { return NO_COLOR ? s : `\x1b[32m${s}\x1b[0m`; } -function yellow(s: string): string { return NO_COLOR ? s : `\x1b[33m${s}\x1b[0m`; } -function bold(s: string): string { return NO_COLOR ? s : `\x1b[1m${s}\x1b[0m`; } -function dim(s: string): string { return NO_COLOR ? s : `\x1b[2m${s}\x1b[0m`; } - function sleep(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } diff --git a/cli/src/output.ts b/cli/src/output.ts index 49e4c7e..1b7c513 100644 --- a/cli/src/output.ts +++ b/cli/src/output.ts @@ -2,12 +2,12 @@ // Tests that toggle NO_COLOR after import won't affect this cached value. const NO_COLOR = 'NO_COLOR' in process.env; -function green(s: string): string { return NO_COLOR ? s : `\x1b[32m${s}\x1b[0m`; } -function yellow(s: string): string { return NO_COLOR ? s : `\x1b[33m${s}\x1b[0m`; } -function red(s: string): string { return NO_COLOR ? s : `\x1b[31m${s}\x1b[0m`; } -function cyan(s: string): string { return NO_COLOR ? s : `\x1b[36m${s}\x1b[0m`; } -function bold(s: string): string { return NO_COLOR ? s : `\x1b[1m${s}\x1b[0m`; } -function dim(s: string): string { return NO_COLOR ? s : `\x1b[2m${s}\x1b[0m`; } +export function green(s: string): string { return NO_COLOR ? s : `\x1b[32m${s}\x1b[0m`; } +export function yellow(s: string): string { return NO_COLOR ? s : `\x1b[33m${s}\x1b[0m`; } +export function red(s: string): string { return NO_COLOR ? s : `\x1b[31m${s}\x1b[0m`; } +export function cyan(s: string): string { return NO_COLOR ? s : `\x1b[36m${s}\x1b[0m`; } +export function bold(s: string): string { return NO_COLOR ? s : `\x1b[1m${s}\x1b[0m`; } +export function dim(s: string): string { return NO_COLOR ? s : `\x1b[2m${s}\x1b[0m`; } export function isJsonMode(): boolean { return process.argv.includes('--json') || process.env.ADMP_JSON === '1'; diff --git a/cli/src/validate.test.ts b/cli/src/validate.test.ts index 283d38e..9beab9c 100644 --- a/cli/src/validate.test.ts +++ b/cli/src/validate.test.ts @@ -1,5 +1,5 @@ import { test, expect, beforeEach, afterEach } from 'bun:test'; -import { validateMessageId, validateGroupId, validateSeedHex } from './validate.js'; +import { validateMessageId, validateGroupId, validateSeedHex, validateRoundTableId } from './validate.js'; // All validators call process.exit(1) on failure, so we intercept it. let exitCalled: number | null; @@ -53,6 +53,23 @@ test('validateGroupId: rejects dots', () => { expect(exitCalled).toBe(1); }); +// --- validateRoundTableId --- + +test('validateRoundTableId: accepts valid round table ID', () => { + validateRoundTableId('rt_abc123-def'); + expect(exitCalled).toBeNull(); +}); + +test('validateRoundTableId: rejects slashes', () => { + validateRoundTableId('rt/abc'); + expect(exitCalled).toBe(1); +}); + +test('validateRoundTableId: rejects dots', () => { + validateRoundTableId('rt.abc'); + expect(exitCalled).toBe(1); +}); + // --- validateSeedHex --- test('validateSeedHex: accepts valid 64-char hex', () => {