diff --git a/package-lock.json b/package-lock.json index ca35a950c..1523ac279 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17987,6 +17987,7 @@ "dependencies": { "@anthropic-ai/sdk": "^0.36.1", "@google/genai": "1.30.0", + "@iarna/toml": "^2.2.5", "@modelcontextprotocol/sdk": "^1.25.1", "@opentelemetry/api": "^1.9.0", "@opentelemetry/exporter-logs-otlp-grpc": "^0.203.0", diff --git a/packages/cli/src/commands/extensions/list.test.ts b/packages/cli/src/commands/extensions/list.test.ts index 01e41941c..8c7a24951 100644 --- a/packages/cli/src/commands/extensions/list.test.ts +++ b/packages/cli/src/commands/extensions/list.test.ts @@ -23,6 +23,7 @@ vi.mock('./utils.js', () => ({ getLoadedExtensions: mockGetLoadedExtensions, toOutputString: mockToOutputString, }), + extensionToOutputString: mockToOutputString, })); vi.mock('../../utils/errors.js', () => ({ diff --git a/packages/cli/src/commands/extensions/list.ts b/packages/cli/src/commands/extensions/list.ts index 9f8a3a7f6..6f5653be3 100644 --- a/packages/cli/src/commands/extensions/list.ts +++ b/packages/cli/src/commands/extensions/list.ts @@ -6,7 +6,7 @@ import type { CommandModule } from 'yargs'; import { getErrorMessage } from '../../utils/errors.js'; -import { getExtensionManager } from './utils.js'; +import { extensionToOutputString, getExtensionManager } from './utils.js'; import { t } from '../../i18n/index.js'; export async function handleList() { @@ -21,7 +21,7 @@ export async function handleList() { console.log( extensions .map((extension, _): string => - extensionManager.toOutputString(extension, process.cwd()), + extensionToOutputString(extension, extensionManager, process.cwd()), ) .join('\n\n'), ); diff --git a/packages/cli/src/commands/extensions/utils.ts b/packages/cli/src/commands/extensions/utils.ts index 49e5f15e5..b7605f32c 100644 --- a/packages/cli/src/commands/extensions/utils.ts +++ b/packages/cli/src/commands/extensions/utils.ts @@ -4,13 +4,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { ExtensionManager } from '@qwen-code/qwen-code-core'; +import { ExtensionManager, type Extension } from '@qwen-code/qwen-code-core'; import { loadSettings } from '../../config/settings.js'; import { requestConsentOrFail, requestConsentNonInteractive, } from './consent.js'; import { isWorkspaceTrusted } from '../../config/trustedFolders.js'; +import * as os from 'node:os'; +import chalk from 'chalk'; export async function getExtensionManager(): Promise { const workspaceDir = process.cwd(); @@ -25,3 +27,53 @@ export async function getExtensionManager(): Promise { await extensionManager.refreshCache(); return extensionManager; } + +export function extensionToOutputString( + extension: Extension, + extensionManager: ExtensionManager, + workspaceDir: string, +): string { + const cwd = workspaceDir; + const userEnabled = extensionManager.isEnabled( + extension.config.name, + os.homedir(), + ); + const workspaceEnabled = extensionManager.isEnabled( + extension.config.name, + cwd, + ); + + const status = workspaceEnabled ? chalk.green('✓') : chalk.red('✗'); + let output = `${status} ${extension.config.name} (${extension.config.version})`; + output += `\n Path: ${extension.path}`; + if (extension.installMetadata) { + output += `\n Source: ${extension.installMetadata.source} (Type: ${extension.installMetadata.type})`; + if (extension.installMetadata.ref) { + output += `\n Ref: ${extension.installMetadata.ref}`; + } + if (extension.installMetadata.releaseTag) { + output += `\n Release tag: ${extension.installMetadata.releaseTag}`; + } + } + output += `\n Enabled (User): ${userEnabled}`; + output += `\n Enabled (Workspace): ${workspaceEnabled}`; + if (extension.contextFiles.length > 0) { + output += `\n Context files:`; + extension.contextFiles.forEach((contextFile) => { + output += `\n ${contextFile}`; + }); + } + if (extension.commands && extension.commands.length > 0) { + output += `\n Commands:`; + extension.commands.forEach((command) => { + output += `\n /${command}`; + }); + } + if (extension.config.mcpServers) { + output += `\n MCP servers:`; + Object.keys(extension.config.mcpServers).forEach((key) => { + output += `\n ${key}`; + }); + } + return output; +} diff --git a/packages/core/package.json b/packages/core/package.json index 1b13743ae..d05f3258c 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -37,6 +37,7 @@ "@opentelemetry/sdk-node": "^0.203.0", "@types/html-to-text": "^9.0.4", "@xterm/headless": "5.5.0", + "@iarna/toml": "^2.2.5", "ajv": "^8.17.1", "ajv-formats": "^3.0.0", "async-mutex": "^0.5.0", diff --git a/packages/core/src/extension/extensionManager.ts b/packages/core/src/extension/extensionManager.ts index d41207ae2..07522f300 100644 --- a/packages/core/src/extension/extensionManager.ts +++ b/packages/core/src/extension/extensionManager.ts @@ -36,7 +36,6 @@ import { } from './github.js'; import type { LoadExtensionContext } from './variableSchema.js'; import { Override, type AllExtensionsEnablementConfig } from './override.js'; -import chalk from 'chalk'; import { parseMarketplaceSource } from './marketplace.js'; import { isGeminiExtensionConfig, @@ -1056,49 +1055,6 @@ export class ExtensionManager { ); } - /** - * Converts an extension to output string. - */ - toOutputString(extension: Extension, workspaceDir?: string): string { - const cwd = workspaceDir ?? this.workspaceDir; - const userEnabled = this.isEnabled(extension.config.name, os.homedir()); - const workspaceEnabled = this.isEnabled(extension.config.name, cwd); - - const status = workspaceEnabled ? chalk.green('✓') : chalk.red('✗'); - let output = `${status} ${extension.config.name} (${extension.config.version})`; - output += `\n Path: ${extension.path}`; - if (extension.installMetadata) { - output += `\n Source: ${extension.installMetadata.source} (Type: ${extension.installMetadata.type})`; - if (extension.installMetadata.ref) { - output += `\n Ref: ${extension.installMetadata.ref}`; - } - if (extension.installMetadata.releaseTag) { - output += `\n Release tag: ${extension.installMetadata.releaseTag}`; - } - } - output += `\n Enabled (User): ${userEnabled}`; - output += `\n Enabled (Workspace): ${workspaceEnabled}`; - if (extension.contextFiles.length > 0) { - output += `\n Context files:`; - extension.contextFiles.forEach((contextFile) => { - output += `\n ${contextFile}`; - }); - } - if (extension.commands && extension.commands.length > 0) { - output += `\n Commands:`; - extension.commands.forEach((command) => { - output += `\n /${command}`; - }); - } - if (extension.config.mcpServers) { - output += `\n MCP servers:`; - Object.keys(extension.config.mcpServers).forEach((key) => { - output += `\n ${key}`; - }); - } - return output; - } - async performWorkspaceExtensionMigration( extensions: Extension[], requestConsent: (options?: ExtensionRequestOptions) => Promise,