feat(cli): integrate profile support into subcommands and fix MCP loading

This commit is contained in:
Rahul Kamat
2026-03-10 16:12:57 -07:00
parent 949392b384
commit a15ea53ff8
8 changed files with 222 additions and 82 deletions

View File

@@ -9,7 +9,9 @@ import { coreEvents } from '@google/gemini-cli-core';
import { handleList, listCommand } from './list.js';
import { ExtensionManager } from '../../config/extension-manager.js';
import { loadSettings, type LoadedSettings } from '../../config/settings.js';
import { loadCliConfig, type CliArgs } from '../../config/config.js';
import { getErrorMessage } from '../../utils/errors.js';
import type { Config } from '@google/gemini-cli-core';
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
const { mockCoreDebugLogger } = await import(
@@ -25,6 +27,7 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
vi.mock('../../config/extension-manager.js');
vi.mock('../../config/settings.js');
vi.mock('../../config/config.js');
vi.mock('../../utils/errors.js');
vi.mock('../../config/extensions/consent.js', () => ({
requestConsentNonInteractive: vi.fn(),
@@ -40,6 +43,7 @@ describe('extensions list command', () => {
const mockLoadSettings = vi.mocked(loadSettings);
const mockGetErrorMessage = vi.mocked(getErrorMessage);
const mockExtensionManager = vi.mocked(ExtensionManager);
const mockLoadCliConfig = vi.mocked(loadCliConfig);
beforeEach(async () => {
vi.clearAllMocks();
@@ -55,10 +59,17 @@ describe('extensions list command', () => {
describe('handleList', () => {
it('should log a message if no extensions are installed', async () => {
const mockCwd = vi.spyOn(process, 'cwd').mockReturnValue('/test/dir');
const mockConfig = {
initialize: vi.fn().mockResolvedValue(undefined),
getExtensionLoader: vi
.fn()
.mockReturnValue(mockExtensionManager.prototype),
};
mockLoadCliConfig.mockResolvedValue(mockConfig as unknown as Config);
mockExtensionManager.prototype.loadExtensions = vi
.fn()
.mockResolvedValue([]);
await handleList();
await handleList({} as unknown as CliArgs);
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
'log',
@@ -69,10 +80,17 @@ describe('extensions list command', () => {
it('should output empty JSON array if no extensions are installed and output-format is json', async () => {
const mockCwd = vi.spyOn(process, 'cwd').mockReturnValue('/test/dir');
const mockConfig = {
initialize: vi.fn().mockResolvedValue(undefined),
getExtensionLoader: vi
.fn()
.mockReturnValue(mockExtensionManager.prototype),
};
mockLoadCliConfig.mockResolvedValue(mockConfig as unknown as Config);
mockExtensionManager.prototype.loadExtensions = vi
.fn()
.mockResolvedValue([]);
await handleList({ outputFormat: 'json' });
await handleList({} as unknown as CliArgs, { outputFormat: 'json' });
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith('log', '[]');
mockCwd.mockRestore();
@@ -80,6 +98,14 @@ describe('extensions list command', () => {
it('should list all installed extensions', async () => {
const mockCwd = vi.spyOn(process, 'cwd').mockReturnValue('/test/dir');
const mockConfig = {
initialize: vi.fn().mockResolvedValue(undefined),
getExtensionLoader: vi
.fn()
.mockReturnValue(mockExtensionManager.prototype),
};
mockLoadCliConfig.mockResolvedValue(mockConfig as unknown as Config);
const extensions = [
{ name: 'ext1', version: '1.0.0' },
{ name: 'ext2', version: '2.0.0' },
@@ -90,7 +116,7 @@ describe('extensions list command', () => {
mockExtensionManager.prototype.toOutputString = vi.fn(
(ext) => `${ext.name}@${ext.version}`,
);
await handleList();
await handleList({} as unknown as CliArgs);
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
'log',
@@ -101,6 +127,14 @@ describe('extensions list command', () => {
it('should list all installed extensions in JSON format', async () => {
const mockCwd = vi.spyOn(process, 'cwd').mockReturnValue('/test/dir');
const mockConfig = {
initialize: vi.fn().mockResolvedValue(undefined),
getExtensionLoader: vi
.fn()
.mockReturnValue(mockExtensionManager.prototype),
};
mockLoadCliConfig.mockResolvedValue(mockConfig as unknown as Config);
const extensions = [
{ name: 'ext1', version: '1.0.0' },
{ name: 'ext2', version: '2.0.0' },
@@ -108,7 +142,7 @@ describe('extensions list command', () => {
mockExtensionManager.prototype.loadExtensions = vi
.fn()
.mockResolvedValue(extensions);
await handleList({ outputFormat: 'json' });
await handleList({} as unknown as CliArgs, { outputFormat: 'json' });
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
'log',
@@ -124,12 +158,11 @@ describe('extensions list command', () => {
code?: string | number | null | undefined,
) => never);
const error = new Error('List failed');
mockExtensionManager.prototype.loadExtensions = vi
.fn()
.mockRejectedValue(error);
mockLoadCliConfig.mockRejectedValue(error);
mockGetErrorMessage.mockReturnValue('List failed message');
await handleList();
await handleList({} as unknown as CliArgs);
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
'error',
@@ -167,6 +200,13 @@ describe('extensions list command', () => {
});
it('handler should call handleList with parsed arguments', async () => {
const mockConfig = {
initialize: vi.fn().mockResolvedValue(undefined),
getExtensionLoader: vi
.fn()
.mockReturnValue(mockExtensionManager.prototype),
};
mockLoadCliConfig.mockResolvedValue(mockConfig as unknown as Config);
mockExtensionManager.prototype.loadExtensions = vi
.fn()
.mockResolvedValue([]);
@@ -177,7 +217,7 @@ describe('extensions list command', () => {
)({
'output-format': 'json',
});
expect(mockExtensionManager.prototype.loadExtensions).toHaveBeenCalled();
expect(mockLoadCliConfig).toHaveBeenCalled();
});
});
});

View File

@@ -7,21 +7,29 @@
import type { CommandModule } from 'yargs';
import { getErrorMessage } from '../../utils/errors.js';
import { debugLogger } from '@google/gemini-cli-core';
import { ExtensionManager } from '../../config/extension-manager.js';
import { requestConsentNonInteractive } from '../../config/extensions/consent.js';
import { loadCliConfig, type CliArgs } from '../../config/config.js';
import { loadSettings } from '../../config/settings.js';
import { promptForSetting } from '../../config/extensions/extensionSettings.js';
import type { ExtensionManager } from '../../config/extension-manager.js';
import { exitCli } from '../utils.js';
export async function handleList(options?: { outputFormat?: 'text' | 'json' }) {
export async function handleList(
argv: CliArgs,
options?: { outputFormat?: 'text' | 'json' },
) {
try {
const workspaceDir = process.cwd();
const extensionManager = new ExtensionManager({
workspaceDir,
requestConsent: requestConsentNonInteractive,
requestSetting: promptForSetting,
settings: loadSettings(workspaceDir).merged,
});
const settings = loadSettings(workspaceDir);
const config = await loadCliConfig(
settings.merged,
'extensions-list-session',
argv,
{ cwd: workspaceDir },
);
// Initialize to trigger extension loading (and profile filtering)
await config.initialize();
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const extensionManager = config.getExtensionLoader() as ExtensionManager;
const extensions = await extensionManager.loadExtensions();
if (extensions.length === 0) {
if (options?.outputFormat === 'json') {
@@ -61,7 +69,8 @@ export const listCommand: CommandModule = {
default: 'text',
}),
handler: async (argv) => {
await handleList({
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
await handleList(argv as unknown as CliArgs, {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
outputFormat: argv['output-format'] as 'text' | 'json',
});

View File

@@ -14,30 +14,42 @@ import {
import { loadSettings } from '../../config/settings.js';
import { exitCli } from '../utils.js';
import { getMcpServersFromConfig } from './list.js';
import { loadCliConfig, type CliArgs } from '../../config/config.js';
import type { ExtensionManager } from '../../config/extension-manager.js';
const GREEN = '\x1b[32m';
const YELLOW = '\x1b[33m';
const RED = '\x1b[31m';
const RESET = '\x1b[0m';
interface Args {
interface Args extends CliArgs {
name: string;
session?: boolean;
}
async function handleEnable(args: Args): Promise<void> {
async function handleEnable(argv: Args): Promise<void> {
const manager = McpServerEnablementManager.getInstance();
const name = normalizeServerId(args.name);
const name = normalizeServerId(argv.name);
// Check settings blocks
const settings = loadSettings();
const config = await loadCliConfig(settings.merged, 'mcp-enable', argv, {
cwd: process.cwd(),
});
await config.initialize();
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const extensionManager = config.getExtensionLoader() as ExtensionManager;
// Get all servers including extensions
const servers = await getMcpServersFromConfig();
const { mcpServers: servers } = await getMcpServersFromConfig(
settings.merged,
extensionManager,
);
const normalizedServerNames = Object.keys(servers).map(normalizeServerId);
if (!normalizedServerNames.includes(name)) {
debugLogger.log(
`${RED}Error:${RESET} Server '${args.name}' not found. Use 'gemini mcp' to see available servers.`,
`${RED}Error:${RESET} Server '${argv.name}' not found. Use 'gemini mcp' to see available servers.`,
);
return;
}
@@ -56,7 +68,7 @@ async function handleEnable(args: Args): Promise<void> {
return;
}
if (args.session) {
if (argv.session) {
manager.clearSessionDisable(name);
debugLogger.log(`${GREEN}${RESET} Session disable cleared for '${name}'.`);
} else {
@@ -71,21 +83,34 @@ async function handleEnable(args: Args): Promise<void> {
}
}
async function handleDisable(args: Args): Promise<void> {
async function handleDisable(argv: Args): Promise<void> {
const manager = McpServerEnablementManager.getInstance();
const name = normalizeServerId(args.name);
const name = normalizeServerId(argv.name);
// Check settings blocks
const settings = loadSettings();
const config = await loadCliConfig(settings.merged, 'mcp-disable', argv, {
cwd: process.cwd(),
});
await config.initialize();
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const extensionManager = config.getExtensionLoader() as ExtensionManager;
// Get all servers including extensions
const servers = await getMcpServersFromConfig();
const { mcpServers: servers } = await getMcpServersFromConfig(
settings.merged,
extensionManager,
);
const normalizedServerNames = Object.keys(servers).map(normalizeServerId);
if (!normalizedServerNames.includes(name)) {
debugLogger.log(
`${RED}Error:${RESET} Server '${args.name}' not found. Use 'gemini mcp' to see available servers.`,
`${RED}Error:${RESET} Server '${argv.name}' not found. Use 'gemini mcp' to see available servers.`,
);
return;
}
if (args.session) {
if (argv.session) {
manager.disableForSession(name);
debugLogger.log(
`${GREEN}${RESET} MCP server '${name}' disabled for this session.`,
@@ -100,6 +125,7 @@ export const enableCommand: CommandModule<object, Args> = {
command: 'enable <name>',
describe: 'Enable an MCP server',
builder: (yargs) =>
/* eslint-disable @typescript-eslint/no-unsafe-type-assertion, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */
yargs
.positional('name', {
describe: 'MCP server name to enable',
@@ -110,7 +136,8 @@ export const enableCommand: CommandModule<object, Args> = {
describe: 'Clear session-only disable',
type: 'boolean',
default: false,
}),
}) as any,
/* eslint-enable @typescript-eslint/no-unsafe-type-assertion, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */
handler: async (argv) => {
await handleEnable(argv as Args);
await exitCli();
@@ -121,6 +148,7 @@ export const disableCommand: CommandModule<object, Args> = {
command: 'disable <name>',
describe: 'Disable an MCP server',
builder: (yargs) =>
/* eslint-disable @typescript-eslint/no-unsafe-type-assertion, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */
yargs
.positional('name', {
describe: 'MCP server name to disable',
@@ -131,7 +159,8 @@ export const disableCommand: CommandModule<object, Args> = {
describe: 'Disable for current session only',
type: 'boolean',
default: false,
}),
}) as any,
/* eslint-enable @typescript-eslint/no-unsafe-type-assertion, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */
handler: async (argv) => {
await handleDisable(argv as Args);
await exitCli();

View File

@@ -24,6 +24,8 @@ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { ExtensionStorage } from '../../config/extensions/storage.js';
import { ExtensionManager } from '../../config/extension-manager.js';
import { McpServerEnablementManager } from '../../config/mcp/index.js';
import { loadCliConfig, type CliArgs } from '../../config/config.js';
import type { Config } from '@google/gemini-cli-core';
vi.mock('../../config/settings.js', async (importOriginal) => {
const actual =
@@ -33,6 +35,7 @@ vi.mock('../../config/settings.js', async (importOriginal) => {
loadSettings: vi.fn(),
};
});
vi.mock('../../config/config.js');
vi.mock('../../config/extensions/storage.js', () => ({
ExtensionStorage: {
getUserExtensionsDir: vi.fn(),
@@ -62,6 +65,7 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
{
getGlobalSettingsPath: () => '/tmp/gemini/settings.json',
getGlobalGeminiDir: () => '/tmp/gemini',
getGlobalTempDir: () => '/tmp/gemini/tmp',
},
),
GEMINI_DIR: '.gemini',
@@ -138,7 +142,13 @@ describe('mcp list command', () => {
merged: { ...defaultMergedSettings, mcpServers: {} },
});
await listMcpServers();
const mockConfig = {
initialize: vi.fn().mockResolvedValue(undefined),
getExtensionLoader: vi.fn().mockReturnValue(mockExtensionManager),
};
(loadCliConfig as Mock).mockResolvedValue(mockConfig as unknown as Config);
await listMcpServers({} as unknown as CliArgs);
expect(debugLogger.log).toHaveBeenCalledWith('No MCP servers configured.');
});
@@ -162,10 +172,16 @@ describe('mcp list command', () => {
isTrusted: true,
});
const mockConfig = {
initialize: vi.fn().mockResolvedValue(undefined),
getExtensionLoader: vi.fn().mockReturnValue(mockExtensionManager),
};
(loadCliConfig as Mock).mockResolvedValue(mockConfig as unknown as Config);
mockClient.connect.mockResolvedValue(undefined);
mockClient.ping.mockResolvedValue(undefined);
await listMcpServers();
await listMcpServers({} as unknown as CliArgs);
expect(debugLogger.log).toHaveBeenCalledWith('Configured MCP servers:\n');
expect(debugLogger.log).toHaveBeenCalledWith(
@@ -206,9 +222,15 @@ describe('mcp list command', () => {
},
});
const mockConfig = {
initialize: vi.fn().mockResolvedValue(undefined),
getExtensionLoader: vi.fn().mockReturnValue(mockExtensionManager),
};
(loadCliConfig as Mock).mockResolvedValue(mockConfig as unknown as Config);
mockClient.connect.mockRejectedValue(new Error('Connection failed'));
await listMcpServers();
await listMcpServers({} as unknown as CliArgs);
expect(debugLogger.log).toHaveBeenCalledWith(
expect.stringContaining(
@@ -236,10 +258,16 @@ describe('mcp list command', () => {
},
]);
const mockConfig = {
initialize: vi.fn().mockResolvedValue(undefined),
getExtensionLoader: vi.fn().mockReturnValue(mockExtensionManager),
};
(loadCliConfig as Mock).mockResolvedValue(mockConfig as unknown as Config);
mockClient.connect.mockResolvedValue(undefined);
mockClient.ping.mockResolvedValue(undefined);
await listMcpServers();
await listMcpServers({} as unknown as CliArgs);
expect(debugLogger.log).toHaveBeenCalledWith(
expect.stringContaining(
@@ -276,13 +304,22 @@ describe('mcp list command', () => {
merged: settingsWithAllowlist,
});
const mockConfig = {
initialize: vi.fn().mockResolvedValue(undefined),
getExtensionLoader: vi.fn().mockReturnValue(mockExtensionManager),
};
(loadCliConfig as Mock).mockResolvedValue(mockConfig as unknown as Config);
mockClient.connect.mockResolvedValue(undefined);
mockClient.ping.mockResolvedValue(undefined);
await listMcpServers({
merged: settingsWithAllowlist,
isTrusted: true,
} as unknown as LoadedSettings);
await listMcpServers(
{} as unknown as CliArgs,
{
merged: settingsWithAllowlist,
isTrusted: true,
} as unknown as LoadedSettings,
);
expect(debugLogger.log).toHaveBeenCalledWith(
expect.stringContaining('allowed-server'),
@@ -310,10 +347,16 @@ describe('mcp list command', () => {
isTrusted: false,
});
const mockConfig = {
initialize: vi.fn().mockResolvedValue(undefined),
getExtensionLoader: vi.fn().mockReturnValue(mockExtensionManager),
};
(loadCliConfig as Mock).mockResolvedValue(mockConfig as unknown as Config);
// createTransport will throw in core if not trusted
mockedCreateTransport.mockRejectedValue(new Error('Folder not trusted'));
await listMcpServers();
await listMcpServers({} as unknown as CliArgs);
expect(debugLogger.log).toHaveBeenCalledWith(
expect.stringContaining(
@@ -337,7 +380,13 @@ describe('mcp list command', () => {
isTrusted: true,
});
await listMcpServers();
const mockConfig = {
initialize: vi.fn().mockResolvedValue(undefined),
getExtensionLoader: vi.fn().mockReturnValue(mockExtensionManager),
};
(loadCliConfig as Mock).mockResolvedValue(mockConfig as unknown as Config);
await listMcpServers({} as unknown as CliArgs);
expect(debugLogger.log).toHaveBeenCalledWith(
expect.stringContaining(
@@ -359,12 +408,18 @@ describe('mcp list command', () => {
isTrusted: true,
});
const mockConfig = {
initialize: vi.fn().mockResolvedValue(undefined),
getExtensionLoader: vi.fn().mockReturnValue(mockExtensionManager),
};
(loadCliConfig as Mock).mockResolvedValue(mockConfig as unknown as Config);
vi.spyOn(
McpServerEnablementManager.prototype,
'isFileEnabled',
).mockResolvedValue(false);
await listMcpServers();
await listMcpServers({} as unknown as CliArgs);
expect(debugLogger.log).toHaveBeenCalledWith(
expect.stringContaining(

View File

@@ -17,36 +17,32 @@ import {
debugLogger,
applyAdminAllowlist,
getAdminBlockedMcpServersMessage,
type GeminiCLIExtension,
type MCPServerConfig,
} from '@google/gemini-cli-core';
import type { MCPServerConfig } from '@google/gemini-cli-core';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { ExtensionManager } from '../../config/extension-manager.js';
import type { ExtensionManager } from '../../config/extension-manager.js';
import {
canLoadServer,
McpServerEnablementManager,
} from '../../config/mcp/index.js';
import { requestConsentNonInteractive } from '../../config/extensions/consent.js';
import { promptForSetting } from '../../config/extensions/extensionSettings.js';
import { loadCliConfig, type CliArgs } from '../../config/config.js';
import { exitCli } from '../utils.js';
import chalk from 'chalk';
export async function getMcpServersFromConfig(
settings?: MergedSettings,
settings: MergedSettings,
extensionManager: ExtensionManager,
): Promise<{
mcpServers: Record<string, MCPServerConfig>;
blockedServerNames: string[];
}> {
if (!settings) {
settings = loadSettings().merged;
let extensions: GeminiCLIExtension[];
try {
extensions = extensionManager.getExtensions();
} catch {
extensions = await extensionManager.loadExtensions();
}
const extensionManager = new ExtensionManager({
settings,
workspaceDir: process.cwd(),
requestConsent: requestConsentNonInteractive,
requestSetting: promptForSetting,
});
const extensions = await extensionManager.loadExtensions();
const mcpServers = { ...settings.mcpServers };
for (const extension of extensions) {
Object.entries(extension.mcpServers || {}).forEach(([key, server]) => {
@@ -170,13 +166,23 @@ async function getServerStatus(
}
export async function listMcpServers(
argv: CliArgs,
loadedSettingsArg?: LoadedSettings,
): Promise<void> {
const loadedSettings = loadedSettingsArg ?? loadSettings();
const activeSettings = loadedSettings.merged;
const { mcpServers, blockedServerNames } =
await getMcpServersFromConfig(activeSettings);
const config = await loadCliConfig(activeSettings, 'mcp-list-session', argv, {
cwd: process.cwd(),
});
await config.initialize();
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const extensionManager = config.getExtensionLoader() as ExtensionManager;
const { mcpServers, blockedServerNames } = await getMcpServersFromConfig(
activeSettings,
extensionManager,
);
const serverNames = Object.keys(mcpServers);
if (blockedServerNames.length > 0) {
@@ -257,7 +263,8 @@ export const listCommand: CommandModule<object, ListArgs> = {
command: 'list',
describe: 'List all configured MCP servers',
handler: async (argv) => {
await listMcpServers(argv.loadedSettings);
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
await listMcpServers(argv as unknown as CliArgs, argv.loadedSettings);
await exitCli();
},
};

View File

@@ -8,7 +8,7 @@ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
import { coreEvents } from '@google/gemini-cli-core';
import { handleList, listCommand } from './list.js';
import { loadSettings, type LoadedSettings } from '../../config/settings.js';
import { loadCliConfig } from '../../config/config.js';
import { loadCliConfig, type CliArgs } from '../../config/config.js';
import type { Config } from '@google/gemini-cli-core';
import chalk from 'chalk';
@@ -55,7 +55,7 @@ describe('skills list command', () => {
};
mockLoadCliConfig.mockResolvedValue(mockConfig as unknown as Config);
await handleList({});
await handleList({} as unknown as CliArgs, {});
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
'log',
@@ -86,7 +86,7 @@ describe('skills list command', () => {
};
mockLoadCliConfig.mockResolvedValue(mockConfig as unknown as Config);
await handleList({});
await handleList({} as unknown as CliArgs, {});
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
'log',
@@ -135,7 +135,7 @@ describe('skills list command', () => {
mockLoadCliConfig.mockResolvedValue(mockConfig as unknown as Config);
// Default
await handleList({ all: false });
await handleList({} as unknown as CliArgs, { all: false });
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
'log',
expect.stringContaining('regular'),
@@ -148,7 +148,7 @@ describe('skills list command', () => {
vi.clearAllMocks();
// With all: true
await handleList({ all: true });
await handleList({} as unknown as CliArgs, { all: true });
expect(coreEvents.emitConsoleLog).toHaveBeenCalledWith(
'log',
expect.stringContaining('regular'),
@@ -166,7 +166,9 @@ describe('skills list command', () => {
it('should throw an error when listing fails', async () => {
mockLoadCliConfig.mockRejectedValue(new Error('List failed'));
await expect(handleList({})).rejects.toThrow('List failed');
await expect(handleList({} as unknown as CliArgs, {})).rejects.toThrow(
'List failed',
);
});
});

View File

@@ -11,17 +11,14 @@ import { loadCliConfig, type CliArgs } from '../../config/config.js';
import { exitCli } from '../utils.js';
import chalk from 'chalk';
export async function handleList(args: { all?: boolean }) {
export async function handleList(argv: CliArgs, args: { all?: boolean }) {
const workspaceDir = process.cwd();
const settings = loadSettings(workspaceDir);
const config = await loadCliConfig(
settings.merged,
'skills-list-session',
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
{
debug: false,
} as Partial<CliArgs> as CliArgs,
argv,
{ cwd: workspaceDir },
);
@@ -73,8 +70,9 @@ export const listCommand: CommandModule = {
default: false,
}),
handler: async (argv) => {
const args = { all: Boolean(argv['all']) };
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
await handleList({ all: argv['all'] as boolean });
await handleList(argv as unknown as CliArgs, args);
await exitCli();
},
};

View File

@@ -109,6 +109,13 @@ export async function parseArguments(
.usage(
'Usage: gemini [options] [command]\n\nGemini CLI - Defaults to interactive mode. Use -p/--prompt for non-interactive (headless) mode.',
)
.option('profile', {
alias: ['profiles', 'P'],
type: 'string',
nargs: 1,
global: true,
description: 'The name of the profile to use for this session.',
})
.option('debug', {
alias: 'd',
type: 'boolean',
@@ -146,13 +153,6 @@ export async function parseArguments(
type: 'boolean',
description: 'Run in sandbox?',
})
.option('profile', {
alias: ['profiles', 'P'],
type: 'string',
nargs: 1,
description: 'The name of the profile to use for this session.',
})
.option('yolo', {
alias: 'y',
type: 'boolean',