fix(cli): ensure skills list outputs to stdout in non-interactive environments (#24566)

This commit is contained in:
Spencer
2026-04-06 22:40:23 -04:00
committed by GitHub
parent 53d0db7e2d
commit a773f3bb43
2 changed files with 33 additions and 35 deletions
+26 -27
View File
@@ -4,8 +4,16 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest'; import {
import { coreEvents, type Config } from '@google/gemini-cli-core'; vi,
describe,
it,
expect,
beforeEach,
afterEach,
type MockInstance,
} from 'vitest';
import { type Config } from '@google/gemini-cli-core';
import { handleList, listCommand } from './list.js'; import { handleList, listCommand } from './list.js';
import { loadSettings, type LoadedSettings } from '../../config/settings.js'; import { loadSettings, type LoadedSettings } from '../../config/settings.js';
import { loadCliConfig } from '../../config/config.js'; import { loadCliConfig } from '../../config/config.js';
@@ -32,12 +40,16 @@ vi.mock('../utils.js', () => ({
describe('skills list command', () => { describe('skills list command', () => {
const mockLoadSettings = vi.mocked(loadSettings); const mockLoadSettings = vi.mocked(loadSettings);
const mockLoadCliConfig = vi.mocked(loadCliConfig); const mockLoadCliConfig = vi.mocked(loadCliConfig);
let stdoutWriteSpy: MockInstance<typeof process.stdout.write>;
beforeEach(async () => { beforeEach(async () => {
vi.clearAllMocks(); vi.clearAllMocks();
mockLoadSettings.mockReturnValue({ mockLoadSettings.mockReturnValue({
merged: {}, merged: {},
} as unknown as LoadedSettings); } as unknown as LoadedSettings);
stdoutWriteSpy = vi
.spyOn(process.stdout, 'write')
.mockImplementation(() => true);
}); });
afterEach(() => { afterEach(() => {
@@ -56,10 +68,7 @@ describe('skills list command', () => {
await handleList({}); await handleList({});
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith( expect(stdoutWriteSpy).toHaveBeenCalledWith('No skills discovered.\n');
'log',
'No skills discovered.',
);
}); });
it('should list all discovered skills', async () => { it('should list all discovered skills', async () => {
@@ -87,24 +96,19 @@ describe('skills list command', () => {
await handleList({}); await handleList({});
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith( expect(stdoutWriteSpy).toHaveBeenCalledWith(
'log', chalk.bold('Discovered Agent Skills:') + '\n\n',
chalk.bold('Discovered Agent Skills:'),
); );
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith( expect(stdoutWriteSpy).toHaveBeenCalledWith(
'log',
expect.stringContaining('skill1'), expect.stringContaining('skill1'),
); );
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith( expect(stdoutWriteSpy).toHaveBeenCalledWith(
'log',
expect.stringContaining(chalk.green('[Enabled]')), expect.stringContaining(chalk.green('[Enabled]')),
); );
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith( expect(stdoutWriteSpy).toHaveBeenCalledWith(
'log',
expect.stringContaining('skill2'), expect.stringContaining('skill2'),
); );
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith( expect(stdoutWriteSpy).toHaveBeenCalledWith(
'log',
expect.stringContaining(chalk.red('[Disabled]')), expect.stringContaining(chalk.red('[Disabled]')),
); );
}); });
@@ -135,12 +139,10 @@ describe('skills list command', () => {
// Default // Default
await handleList({ all: false }); await handleList({ all: false });
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith( expect(stdoutWriteSpy).toHaveBeenCalledWith(
'log',
expect.stringContaining('regular'), expect.stringContaining('regular'),
); );
expect(coreEvents.emitConsoleLog).not.toHaveBeenCalledWith( expect(stdoutWriteSpy).not.toHaveBeenCalledWith(
'log',
expect.stringContaining('builtin'), expect.stringContaining('builtin'),
); );
@@ -148,16 +150,13 @@ describe('skills list command', () => {
// With all: true // With all: true
await handleList({ all: true }); await handleList({ all: true });
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith( expect(stdoutWriteSpy).toHaveBeenCalledWith(
'log',
expect.stringContaining('regular'), expect.stringContaining('regular'),
); );
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith( expect(stdoutWriteSpy).toHaveBeenCalledWith(
'log',
expect.stringContaining('builtin'), expect.stringContaining('builtin'),
); );
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith( expect(stdoutWriteSpy).toHaveBeenCalledWith(
'log',
expect.stringContaining(chalk.gray(' [Built-in]')), expect.stringContaining(chalk.gray(' [Built-in]')),
); );
}); });
+7 -8
View File
@@ -5,7 +5,6 @@
*/ */
import type { CommandModule } from 'yargs'; import type { CommandModule } from 'yargs';
import { debugLogger } from '@google/gemini-cli-core';
import { loadSettings } from '../../config/settings.js'; import { loadSettings } from '../../config/settings.js';
import { loadCliConfig, type CliArgs } from '../../config/config.js'; import { loadCliConfig, type CliArgs } from '../../config/config.js';
import { exitCli } from '../utils.js'; import { exitCli } from '../utils.js';
@@ -42,12 +41,11 @@ export async function handleList(args: { all?: boolean }) {
}); });
if (skills.length === 0) { if (skills.length === 0) {
debugLogger.log('No skills discovered.'); process.stdout.write('No skills discovered.\n');
return; return;
} }
debugLogger.log(chalk.bold('Discovered Agent Skills:')); process.stdout.write(chalk.bold('Discovered Agent Skills:') + '\n\n');
debugLogger.log('');
for (const skill of skills) { for (const skill of skills) {
const status = skill.disabled const status = skill.disabled
@@ -56,10 +54,11 @@ export async function handleList(args: { all?: boolean }) {
const builtinSuffix = skill.isBuiltin ? chalk.gray(' [Built-in]') : ''; const builtinSuffix = skill.isBuiltin ? chalk.gray(' [Built-in]') : '';
debugLogger.log(`${chalk.bold(skill.name)} ${status}${builtinSuffix}`); process.stdout.write(
debugLogger.log(` Description: ${skill.description}`); `${chalk.bold(skill.name)} ${status}${builtinSuffix}\n`,
debugLogger.log(` Location: ${skill.location}`); );
debugLogger.log(''); process.stdout.write(` Description: ${skill.description}\n`);
process.stdout.write(` Location: ${skill.location}\n\n`);
} }
} }