Skip to content

Commit 0a8da98

Browse files
authored
fix(cli): ensure skills list outputs to stdout in non-interactive environments (google-gemini#24566)
1 parent 984f02c commit 0a8da98

2 files changed

Lines changed: 33 additions & 35 deletions

File tree

packages/cli/src/commands/skills/list.test.ts

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,16 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7-
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
8-
import { coreEvents, type Config } from '@google/gemini-cli-core';
7+
import {
8+
vi,
9+
describe,
10+
it,
11+
expect,
12+
beforeEach,
13+
afterEach,
14+
type MockInstance,
15+
} from 'vitest';
16+
import { type Config } from '@google/gemini-cli-core';
917
import { handleList, listCommand } from './list.js';
1018
import { loadSettings, type LoadedSettings } from '../../config/settings.js';
1119
import { loadCliConfig } from '../../config/config.js';
@@ -32,12 +40,16 @@ vi.mock('../utils.js', () => ({
3240
describe('skills list command', () => {
3341
const mockLoadSettings = vi.mocked(loadSettings);
3442
const mockLoadCliConfig = vi.mocked(loadCliConfig);
43+
let stdoutWriteSpy: MockInstance<typeof process.stdout.write>;
3544

3645
beforeEach(async () => {
3746
vi.clearAllMocks();
3847
mockLoadSettings.mockReturnValue({
3948
merged: {},
4049
} as unknown as LoadedSettings);
50+
stdoutWriteSpy = vi
51+
.spyOn(process.stdout, 'write')
52+
.mockImplementation(() => true);
4153
});
4254

4355
afterEach(() => {
@@ -56,10 +68,7 @@ describe('skills list command', () => {
5668

5769
await handleList({});
5870

59-
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
60-
'log',
61-
'No skills discovered.',
62-
);
71+
expect(stdoutWriteSpy).toHaveBeenCalledWith('No skills discovered.\n');
6372
});
6473

6574
it('should list all discovered skills', async () => {
@@ -87,24 +96,19 @@ describe('skills list command', () => {
8796

8897
await handleList({});
8998

90-
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
91-
'log',
92-
chalk.bold('Discovered Agent Skills:'),
99+
expect(stdoutWriteSpy).toHaveBeenCalledWith(
100+
chalk.bold('Discovered Agent Skills:') + '\n\n',
93101
);
94-
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
95-
'log',
102+
expect(stdoutWriteSpy).toHaveBeenCalledWith(
96103
expect.stringContaining('skill1'),
97104
);
98-
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
99-
'log',
105+
expect(stdoutWriteSpy).toHaveBeenCalledWith(
100106
expect.stringContaining(chalk.green('[Enabled]')),
101107
);
102-
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
103-
'log',
108+
expect(stdoutWriteSpy).toHaveBeenCalledWith(
104109
expect.stringContaining('skill2'),
105110
);
106-
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
107-
'log',
111+
expect(stdoutWriteSpy).toHaveBeenCalledWith(
108112
expect.stringContaining(chalk.red('[Disabled]')),
109113
);
110114
});
@@ -135,29 +139,24 @@ describe('skills list command', () => {
135139

136140
// Default
137141
await handleList({ all: false });
138-
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
139-
'log',
142+
expect(stdoutWriteSpy).toHaveBeenCalledWith(
140143
expect.stringContaining('regular'),
141144
);
142-
expect(coreEvents.emitConsoleLog).not.toHaveBeenCalledWith(
143-
'log',
145+
expect(stdoutWriteSpy).not.toHaveBeenCalledWith(
144146
expect.stringContaining('builtin'),
145147
);
146148

147149
vi.clearAllMocks();
148150

149151
// With all: true
150152
await handleList({ all: true });
151-
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
152-
'log',
153+
expect(stdoutWriteSpy).toHaveBeenCalledWith(
153154
expect.stringContaining('regular'),
154155
);
155-
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
156-
'log',
156+
expect(stdoutWriteSpy).toHaveBeenCalledWith(
157157
expect.stringContaining('builtin'),
158158
);
159-
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
160-
'log',
159+
expect(stdoutWriteSpy).toHaveBeenCalledWith(
161160
expect.stringContaining(chalk.gray(' [Built-in]')),
162161
);
163162
});

packages/cli/src/commands/skills/list.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
*/
66

77
import type { CommandModule } from 'yargs';
8-
import { debugLogger } from '@google/gemini-cli-core';
98
import { loadSettings } from '../../config/settings.js';
109
import { loadCliConfig, type CliArgs } from '../../config/config.js';
1110
import { exitCli } from '../utils.js';
@@ -42,12 +41,11 @@ export async function handleList(args: { all?: boolean }) {
4241
});
4342

4443
if (skills.length === 0) {
45-
debugLogger.log('No skills discovered.');
44+
process.stdout.write('No skills discovered.\n');
4645
return;
4746
}
4847

49-
debugLogger.log(chalk.bold('Discovered Agent Skills:'));
50-
debugLogger.log('');
48+
process.stdout.write(chalk.bold('Discovered Agent Skills:') + '\n\n');
5149

5250
for (const skill of skills) {
5351
const status = skill.disabled
@@ -56,10 +54,11 @@ export async function handleList(args: { all?: boolean }) {
5654

5755
const builtinSuffix = skill.isBuiltin ? chalk.gray(' [Built-in]') : '';
5856

59-
debugLogger.log(`${chalk.bold(skill.name)} ${status}${builtinSuffix}`);
60-
debugLogger.log(` Description: ${skill.description}`);
61-
debugLogger.log(` Location: ${skill.location}`);
62-
debugLogger.log('');
57+
process.stdout.write(
58+
`${chalk.bold(skill.name)} ${status}${builtinSuffix}\n`,
59+
);
60+
process.stdout.write(` Description: ${skill.description}\n`);
61+
process.stdout.write(` Location: ${skill.location}\n\n`);
6362
}
6463
}
6564

0 commit comments

Comments
 (0)