Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/__tests__/output.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {describe, it, expect, vi, afterEach} from 'vitest';
import {set_quiet, info, success, warn} from '../utils/output';

describe('output quiet mode', ()=>{
afterEach(()=>{
set_quiet(false);
vi.restoreAllMocks();
});

it('suppresses info and success on stderr when quiet', ()=>{
const spy = vi.spyOn(console, 'error').mockImplementation(()=>{});
set_quiet(true);
info('resolving profile');
success('logged in');
expect(spy).not.toHaveBeenCalled();
});

it('still emits warnings when quiet (they are not progress noise)', ()=>{
const spy = vi.spyOn(console, 'error').mockImplementation(()=>{});
set_quiet(true);
warn('token expires soon');
expect(spy).toHaveBeenCalledOnce();
});

it('emits info and success normally when not quiet', ()=>{
const spy = vi.spyOn(console, 'error').mockImplementation(()=>{});
set_quiet(false);
info('resolving profile');
success('logged in');
expect(spy).toHaveBeenCalledTimes(2);
});
});
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {profile_command} from './commands/profile';
import {team_command} from './commands/team';
import {api_command} from './commands/api';
import {CliError} from './utils/errors';
import {set_quiet} from './utils/output';

// Route every command through commander's throwing mode so usage errors reach
// our handler and map to exit code 2 (vs 1 for runtime/API failures).
Expand All @@ -32,8 +33,13 @@ const build_program = (): Command=>{
.option('--json', 'Output compact JSON to stdout')
.option('--pretty', 'Output indented JSON to stdout')
.option('--verbose', 'Print the full request/response to stderr, credentials redacted (api)')
.option('-q, --quiet', 'Suppress progress messages on stderr (warnings and errors still shown)')
.showHelpAfterError();

// Apply --quiet before any command action runs, so progress output is
// silenced for the whole invocation.
program.hook('preAction', ()=>{set_quiet(program.opts().quiet === true);});

program.addCommand(auth_command);
program.addCommand(profile_command);
program.addCommand(team_command);
Expand Down
11 changes: 8 additions & 3 deletions src/utils/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,14 @@ const safe_record = (record: Credential_record): Record<string, unknown>=>{

const is_tty = process.stdout.isTTY === true;

const success = (msg: string): void=>console.error(pc.green(`✓ ${msg}`));
// --quiet silences routine progress on stderr (info/success). Warnings and
// errors are never suppressed — they carry information the user still needs.
let quiet_mode = false;
const set_quiet = (on: boolean): void=>{quiet_mode = on;};

const success = (msg: string): void=>{if (!quiet_mode) console.error(pc.green(`✓ ${msg}`));};
const warn = (msg: string): void=>console.error(pc.yellow(`⚠ ${msg}`));
const info = (msg: string): void=>console.error(pc.dim(msg));
const info = (msg: string): void=>{if (!quiet_mode) console.error(pc.dim(msg));};

type Print_opts = {
json?: boolean;
Expand All @@ -55,5 +60,5 @@ const print = (data: unknown, opts: Print_opts = {}): void=>{
process.stdout.write(serialize(data, opts) + '\n');
};

export {is_tty, pc, REDACTED, redact, safe_record, success, warn, info, print};
export {is_tty, pc, REDACTED, redact, safe_record, set_quiet, success, warn, info, print};
export type {Print_opts};
Loading