mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-30 04:30:48 +00:00
i18n add extension commands
This commit is contained in:
parent
ba14e9e531
commit
e87376e06c
12 changed files with 440 additions and 67 deletions
|
|
@ -8,6 +8,7 @@ import { type CommandModule } from 'yargs';
|
|||
import { SettingScope } from '../../config/settings.js';
|
||||
import { getErrorMessage } from '../../utils/errors.js';
|
||||
import { getExtensionManager } from './utils.js';
|
||||
import { t } from '../../i18n/index.js';
|
||||
|
||||
interface DisableArgs {
|
||||
name: string;
|
||||
|
|
@ -23,7 +24,10 @@ export async function handleDisable(args: DisableArgs) {
|
|||
extensionManager.disableExtension(args.name, SettingScope.User);
|
||||
}
|
||||
console.log(
|
||||
`Extension "${args.name}" successfully disabled for scope "${args.scope}".`,
|
||||
t('Extension "{{name}}" successfully disabled for scope "{{scope}}".', {
|
||||
name: args.name,
|
||||
scope: args.scope || SettingScope.User,
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(getErrorMessage(error));
|
||||
|
|
@ -33,15 +37,15 @@ export async function handleDisable(args: DisableArgs) {
|
|||
|
||||
export const disableCommand: CommandModule = {
|
||||
command: 'disable [--scope] <name>',
|
||||
describe: 'Disables an extension.',
|
||||
describe: t('Disables an extension.'),
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.positional('name', {
|
||||
describe: 'The name of the extension to disable.',
|
||||
describe: t('The name of the extension to disable.'),
|
||||
type: 'string',
|
||||
})
|
||||
.option('scope', {
|
||||
describe: 'The scope to disable the extenison in.',
|
||||
describe: t('The scope to disable the extenison in.'),
|
||||
type: 'string',
|
||||
default: SettingScope.User,
|
||||
})
|
||||
|
|
@ -53,11 +57,12 @@ export const disableCommand: CommandModule = {
|
|||
.includes((argv.scope as string).toLowerCase())
|
||||
) {
|
||||
throw new Error(
|
||||
`Invalid scope: ${argv.scope}. Please use one of ${Object.values(
|
||||
SettingScope,
|
||||
)
|
||||
.map((s) => s.toLowerCase())
|
||||
.join(', ')}.`,
|
||||
t('Invalid scope: {{scope}}. Please use one of {{scopes}}.', {
|
||||
scope: argv.scope as string,
|
||||
scopes: Object.values(SettingScope)
|
||||
.map((s) => s.toLowerCase())
|
||||
.join(', '),
|
||||
}),
|
||||
);
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { type CommandModule } from 'yargs';
|
|||
import { FatalConfigError, getErrorMessage } from '@qwen-code/qwen-code-core';
|
||||
import { SettingScope } from '../../config/settings.js';
|
||||
import { getExtensionManager } from './utils.js';
|
||||
import { t } from '../../i18n/index.js';
|
||||
|
||||
interface EnableArgs {
|
||||
name: string;
|
||||
|
|
@ -25,11 +26,16 @@ export async function handleEnable(args: EnableArgs) {
|
|||
}
|
||||
if (args.scope) {
|
||||
console.log(
|
||||
`Extension "${args.name}" successfully enabled for scope "${args.scope}".`,
|
||||
t('Extension "{{name}}" successfully enabled for scope "{{scope}}".', {
|
||||
name: args.name,
|
||||
scope: args.scope,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
console.log(
|
||||
`Extension "${args.name}" successfully enabled in all scopes.`,
|
||||
t('Extension "{{name}}" successfully enabled in all scopes.', {
|
||||
name: args.name,
|
||||
}),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
@ -39,16 +45,17 @@ export async function handleEnable(args: EnableArgs) {
|
|||
|
||||
export const enableCommand: CommandModule = {
|
||||
command: 'enable [--scope] <name>',
|
||||
describe: 'Enables an extension.',
|
||||
describe: t('Enables an extension.'),
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.positional('name', {
|
||||
describe: 'The name of the extension to enable.',
|
||||
describe: t('The name of the extension to enable.'),
|
||||
type: 'string',
|
||||
})
|
||||
.option('scope', {
|
||||
describe:
|
||||
describe: t(
|
||||
'The scope to enable the extenison in. If not set, will be enabled in all scopes.',
|
||||
),
|
||||
type: 'string',
|
||||
})
|
||||
.check((argv) => {
|
||||
|
|
@ -59,11 +66,12 @@ export const enableCommand: CommandModule = {
|
|||
.includes((argv.scope as string).toLowerCase())
|
||||
) {
|
||||
throw new Error(
|
||||
`Invalid scope: ${argv.scope}. Please use one of ${Object.values(
|
||||
SettingScope,
|
||||
)
|
||||
.map((s) => s.toLowerCase())
|
||||
.join(', ')}.`,
|
||||
t('Invalid scope: {{scope}}. Please use one of {{scopes}}.', {
|
||||
scope: argv.scope as string,
|
||||
scopes: Object.values(SettingScope)
|
||||
.map((s) => s.toLowerCase())
|
||||
.join(', '),
|
||||
}),
|
||||
);
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import {
|
|||
requestConsentOrFail,
|
||||
requestConsentNonInteractive,
|
||||
} from './consent.js';
|
||||
import { t } from '../../i18n/index.js';
|
||||
|
||||
interface InstallArgs {
|
||||
source: string;
|
||||
|
|
@ -36,7 +37,9 @@ export async function handleInstall(args: InstallArgs) {
|
|||
) {
|
||||
if (args.ref || args.autoUpdate) {
|
||||
throw new Error(
|
||||
'--ref and --auto-update are not applicable for marketplace extensions.',
|
||||
t(
|
||||
'--ref and --auto-update are not applicable for marketplace extensions.',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -64,7 +67,9 @@ export async function handleInstall(args: InstallArgs) {
|
|||
requestConsent,
|
||||
);
|
||||
console.log(
|
||||
`Extension "${extension.name}" installed successfully and enabled.`,
|
||||
t('Extension "{{name}}" installed successfully and enabled.', {
|
||||
name: extension.name,
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(getErrorMessage(error));
|
||||
|
|
@ -74,37 +79,40 @@ export async function handleInstall(args: InstallArgs) {
|
|||
|
||||
export const installCommand: CommandModule = {
|
||||
command: 'install <source>',
|
||||
describe:
|
||||
describe: t(
|
||||
'Installs an extension from a git repository URL, local path, or claude marketplace (marketplace-url:plugin-name).',
|
||||
),
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.positional('source', {
|
||||
describe:
|
||||
describe: t(
|
||||
'The github URL, local path, or marketplace source (marketplace-url:plugin-name) of the extension to install.',
|
||||
),
|
||||
type: 'string',
|
||||
demandOption: true,
|
||||
})
|
||||
.option('ref', {
|
||||
describe: 'The git ref to install from.',
|
||||
describe: t('The git ref to install from.'),
|
||||
type: 'string',
|
||||
})
|
||||
.option('auto-update', {
|
||||
describe: 'Enable auto-update for this extension.',
|
||||
describe: t('Enable auto-update for this extension.'),
|
||||
type: 'boolean',
|
||||
})
|
||||
.option('pre-release', {
|
||||
describe: 'Enable pre-release versions for this extension.',
|
||||
describe: t('Enable pre-release versions for this extension.'),
|
||||
type: 'boolean',
|
||||
})
|
||||
.option('consent', {
|
||||
describe:
|
||||
describe: t(
|
||||
'Acknowledge the security risks of installing an extension and skip the confirmation prompt.',
|
||||
),
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
})
|
||||
.check((argv) => {
|
||||
if (!argv.source) {
|
||||
throw new Error('The source argument must be provided.');
|
||||
throw new Error(t('The source argument must be provided.'));
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
requestConsentOrFail,
|
||||
} from './consent.js';
|
||||
import { getExtensionManager } from './utils.js';
|
||||
import { t } from '../../i18n/index.js';
|
||||
|
||||
interface InstallArgs {
|
||||
path: string;
|
||||
|
|
@ -30,11 +31,13 @@ export async function handleLink(args: InstallArgs) {
|
|||
requestConsentOrFail.bind(null, requestConsentNonInteractive),
|
||||
);
|
||||
if (!extension) {
|
||||
console.log('Link extension failed to install.');
|
||||
console.log(t('Link extension failed to install.'));
|
||||
return;
|
||||
}
|
||||
console.log(
|
||||
`Extension "${extension.name}" linked successfully and enabled.`,
|
||||
t('Extension "{{name}}" linked successfully and enabled.', {
|
||||
name: extension.name,
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(getErrorMessage(error));
|
||||
|
|
@ -44,12 +47,13 @@ export async function handleLink(args: InstallArgs) {
|
|||
|
||||
export const linkCommand: CommandModule = {
|
||||
command: 'link <path>',
|
||||
describe:
|
||||
describe: t(
|
||||
'Links an extension from a local path. Updates made to the local path will always be reflected.',
|
||||
),
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.positional('path', {
|
||||
describe: 'The name of the extension to link.',
|
||||
describe: t('The name of the extension to link.'),
|
||||
type: 'string',
|
||||
})
|
||||
.check((_) => true),
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
import type { CommandModule } from 'yargs';
|
||||
import { getErrorMessage } from '../../utils/errors.js';
|
||||
import { getExtensionManager } from './utils.js';
|
||||
import { t } from '../../i18n/index.js';
|
||||
|
||||
export async function handleList() {
|
||||
try {
|
||||
|
|
@ -14,7 +15,7 @@ export async function handleList() {
|
|||
const extensions = extensionManager.getLoadedExtensions();
|
||||
|
||||
if (!extensions || extensions.length === 0) {
|
||||
console.log('No extensions installed.');
|
||||
console.log(t('No extensions installed.'));
|
||||
return;
|
||||
}
|
||||
console.log(
|
||||
|
|
@ -32,7 +33,7 @@ export async function handleList() {
|
|||
|
||||
export const listCommand: CommandModule = {
|
||||
command: 'list',
|
||||
describe: 'Lists installed extensions.',
|
||||
describe: t('Lists installed extensions.'),
|
||||
builder: (yargs) => yargs,
|
||||
handler: async () => {
|
||||
await handleList();
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
promptForSetting,
|
||||
updateSetting,
|
||||
} from '@qwen-code/qwen-code-core';
|
||||
import { t } from '../../i18n/index.js';
|
||||
|
||||
// --- SET COMMAND ---
|
||||
interface SetArgs {
|
||||
|
|
@ -22,21 +23,21 @@ interface SetArgs {
|
|||
|
||||
const setCommand: CommandModule<object, SetArgs> = {
|
||||
command: 'set [--scope] <name> <setting>',
|
||||
describe: 'Set a specific setting for an extension.',
|
||||
describe: t('Set a specific setting for an extension.'),
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.positional('name', {
|
||||
describe: 'Name of the extension to configure.',
|
||||
describe: t('Name of the extension to configure.'),
|
||||
type: 'string',
|
||||
demandOption: true,
|
||||
})
|
||||
.positional('setting', {
|
||||
describe: 'The setting to configure (name or env var).',
|
||||
describe: t('The setting to configure (name or env var).'),
|
||||
type: 'string',
|
||||
demandOption: true,
|
||||
})
|
||||
.option('scope', {
|
||||
describe: 'The scope to set the setting in.',
|
||||
describe: t('The scope to set the setting in.'),
|
||||
type: 'string',
|
||||
choices: ['user', 'workspace'],
|
||||
default: 'user',
|
||||
|
|
@ -49,7 +50,7 @@ const setCommand: CommandModule<object, SetArgs> = {
|
|||
if (!extensions || extensions.length === 0) return;
|
||||
const extension = extensions.find((e) => e.name === name);
|
||||
if (!extension) {
|
||||
console.log(`Extension "${name}" not found.`);
|
||||
console.log(t('Extension "{{name}}" not found.', { name }));
|
||||
return;
|
||||
}
|
||||
await updateSetting(
|
||||
|
|
@ -69,10 +70,10 @@ interface ListArgs {
|
|||
|
||||
const listCommand: CommandModule<object, ListArgs> = {
|
||||
command: 'list <name>',
|
||||
describe: 'List all settings for an extension.',
|
||||
describe: t('List all settings for an extension.'),
|
||||
builder: (yargs) =>
|
||||
yargs.positional('name', {
|
||||
describe: 'Name of the extension.',
|
||||
describe: t('Name of the extension.'),
|
||||
type: 'string',
|
||||
demandOption: true,
|
||||
}),
|
||||
|
|
@ -84,11 +85,13 @@ const listCommand: CommandModule<object, ListArgs> = {
|
|||
if (!extensions || extensions.length === 0) return;
|
||||
const extension = extensions.find((e) => e.name === name);
|
||||
if (!extension) {
|
||||
console.log(`Extension "${name}" not found.`);
|
||||
console.log(t('Extension "{{name}}" not found.', { name }));
|
||||
return;
|
||||
}
|
||||
if (!extension || !extension.settings || extension.settings.length === 0) {
|
||||
console.log(`Extension "${name}" has no settings to configure.`);
|
||||
console.log(
|
||||
t('Extension "{{name}}" has no settings to configure.', { name }),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -104,29 +107,29 @@ const listCommand: CommandModule<object, ListArgs> = {
|
|||
);
|
||||
const mergedSettings = { ...userSettings, ...workspaceSettings };
|
||||
|
||||
console.log(`Settings for "${name}":`);
|
||||
console.log(t('Settings for "{{name}}":', { name }));
|
||||
for (const setting of extension.settings) {
|
||||
const value = mergedSettings[setting.envVar];
|
||||
let displayValue: string;
|
||||
let scopeInfo = '';
|
||||
|
||||
if (workspaceSettings[setting.envVar] !== undefined) {
|
||||
scopeInfo = ' (workspace)';
|
||||
scopeInfo = ' ' + t('(workspace)');
|
||||
} else if (userSettings[setting.envVar] !== undefined) {
|
||||
scopeInfo = ' (user)';
|
||||
scopeInfo = ' ' + t('(user)');
|
||||
}
|
||||
|
||||
if (value === undefined) {
|
||||
displayValue = '[not set]';
|
||||
displayValue = t('[not set]');
|
||||
} else if (setting.sensitive) {
|
||||
displayValue = '[value stored in keychain]';
|
||||
displayValue = t('[value stored in keychain]');
|
||||
} else {
|
||||
displayValue = value;
|
||||
}
|
||||
console.log(`
|
||||
- ${setting.name} (${setting.envVar})`);
|
||||
console.log(` Description: ${setting.description}`);
|
||||
console.log(` Value: ${displayValue}${scopeInfo}`);
|
||||
console.log(` ${t('Description:')} ${setting.description}`);
|
||||
console.log(` ${t('Value:')} ${displayValue}${scopeInfo}`);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
@ -134,12 +137,12 @@ const listCommand: CommandModule<object, ListArgs> = {
|
|||
// --- SETTINGS COMMAND ---
|
||||
export const settingsCommand: CommandModule = {
|
||||
command: 'settings <command>',
|
||||
describe: 'Manage extension settings.',
|
||||
describe: t('Manage extension settings.'),
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.command(setCommand)
|
||||
.command(listCommand)
|
||||
.demandCommand(1, 'You need to specify a command (set or list).')
|
||||
.demandCommand(1, t('You need to specify a command (set or list).'))
|
||||
.version(false),
|
||||
handler: () => {
|
||||
// This handler is not called when a subcommand is provided.
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
} from './consent.js';
|
||||
import { isWorkspaceTrusted } from '../../config/trustedFolders.js';
|
||||
import { loadSettings } from '../../config/settings.js';
|
||||
import { t } from '../../i18n/index.js';
|
||||
|
||||
interface UninstallArgs {
|
||||
name: string; // can be extension name or source URL.
|
||||
|
|
@ -33,7 +34,9 @@ export async function handleUninstall(args: UninstallArgs) {
|
|||
});
|
||||
await extensionManager.refreshCache();
|
||||
await extensionManager.uninstallExtension(args.name, false);
|
||||
console.log(`Extension "${args.name}" successfully uninstalled.`);
|
||||
console.log(
|
||||
t('Extension "{{name}}" successfully uninstalled.', { name: args.name }),
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(getErrorMessage(error));
|
||||
process.exit(1);
|
||||
|
|
@ -42,17 +45,19 @@ export async function handleUninstall(args: UninstallArgs) {
|
|||
|
||||
export const uninstallCommand: CommandModule = {
|
||||
command: 'uninstall <name>',
|
||||
describe: 'Uninstalls an extension.',
|
||||
describe: t('Uninstalls an extension.'),
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.positional('name', {
|
||||
describe: 'The name or source path of the extension to uninstall.',
|
||||
describe: t('The name or source path of the extension to uninstall.'),
|
||||
type: 'string',
|
||||
})
|
||||
.check((argv) => {
|
||||
if (!argv.name) {
|
||||
throw new Error(
|
||||
'Please include the name of the extension to uninstall as a positional argument.',
|
||||
t(
|
||||
'Please include the name of the extension to uninstall as a positional argument.',
|
||||
),
|
||||
);
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
type ExtensionUpdateInfo,
|
||||
} from '@qwen-code/qwen-code-core';
|
||||
import { getExtensionManager } from './utils.js';
|
||||
import { t } from '../../i18n/index.js';
|
||||
|
||||
interface UpdateArgs {
|
||||
name?: string;
|
||||
|
|
@ -19,7 +20,14 @@ interface UpdateArgs {
|
|||
}
|
||||
|
||||
const updateOutput = (info: ExtensionUpdateInfo) =>
|
||||
`Extension "${info.name}" successfully updated: ${info.originalVersion} → ${info.updatedVersion}.`;
|
||||
t(
|
||||
'Extension "{{name}}" successfully updated: {{oldVersion}} → {{newVersion}}.',
|
||||
{
|
||||
name: info.name,
|
||||
oldVersion: info.originalVersion,
|
||||
newVersion: info.updatedVersion,
|
||||
},
|
||||
);
|
||||
|
||||
export async function handleUpdate(args: UpdateArgs) {
|
||||
const extensionManager = await getExtensionManager();
|
||||
|
|
@ -31,12 +39,15 @@ export async function handleUpdate(args: UpdateArgs) {
|
|||
(extension) => extension.name === args.name,
|
||||
);
|
||||
if (!extension) {
|
||||
console.log(`Extension "${args.name}" not found.`);
|
||||
console.log(t('Extension "{{name}}" not found.', { name: args.name }));
|
||||
return;
|
||||
}
|
||||
if (!extension.installMetadata) {
|
||||
console.log(
|
||||
`Unable to install extension "${args.name}" due to missing install metadata`,
|
||||
t(
|
||||
'Unable to install extension "{{name}}" due to missing install metadata',
|
||||
{ name: args.name },
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -45,7 +56,9 @@ export async function handleUpdate(args: UpdateArgs) {
|
|||
extensionManager,
|
||||
);
|
||||
if (updateState !== ExtensionUpdateState.UPDATE_AVAILABLE) {
|
||||
console.log(`Extension "${args.name}" is already up to date.`);
|
||||
console.log(
|
||||
t('Extension "{{name}}" is already up to date.', { name: args.name }),
|
||||
);
|
||||
return;
|
||||
}
|
||||
// TODO(chrstnb): we should list extensions if the requested extension is not installed.
|
||||
|
|
@ -59,10 +72,19 @@ export async function handleUpdate(args: UpdateArgs) {
|
|||
updatedExtensionInfo.updatedVersion
|
||||
) {
|
||||
console.log(
|
||||
`Extension "${args.name}" successfully updated: ${updatedExtensionInfo.originalVersion} → ${updatedExtensionInfo.updatedVersion}.`,
|
||||
t(
|
||||
'Extension "{{name}}" successfully updated: {{oldVersion}} → {{newVersion}}.',
|
||||
{
|
||||
name: args.name,
|
||||
oldVersion: updatedExtensionInfo.originalVersion,
|
||||
newVersion: updatedExtensionInfo.updatedVersion,
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
console.log(`Extension "${args.name}" is already up to date.`);
|
||||
console.log(
|
||||
t('Extension "{{name}}" is already up to date.', { name: args.name }),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(getErrorMessage(error));
|
||||
|
|
@ -87,7 +109,7 @@ export async function handleUpdate(args: UpdateArgs) {
|
|||
(info) => info.originalVersion !== info.updatedVersion,
|
||||
);
|
||||
if (updateInfos.length === 0) {
|
||||
console.log('No extensions to update.');
|
||||
console.log(t('No extensions to update.'));
|
||||
return;
|
||||
}
|
||||
console.log(updateInfos.map((info) => updateOutput(info)).join('\n'));
|
||||
|
|
@ -99,22 +121,25 @@ export async function handleUpdate(args: UpdateArgs) {
|
|||
|
||||
export const updateCommand: CommandModule = {
|
||||
command: 'update [<name>] [--all]',
|
||||
describe:
|
||||
describe: t(
|
||||
'Updates all extensions or a named extension to the latest version.',
|
||||
),
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.positional('name', {
|
||||
describe: 'The name of the extension to update.',
|
||||
describe: t('The name of the extension to update.'),
|
||||
type: 'string',
|
||||
})
|
||||
.option('all', {
|
||||
describe: 'Update all extensions.',
|
||||
describe: t('Update all extensions.'),
|
||||
type: 'boolean',
|
||||
})
|
||||
.conflicts('name', 'all')
|
||||
.check((argv) => {
|
||||
if (!argv.all && !argv.name) {
|
||||
throw new Error('Either an extension name or --all must be provided');
|
||||
throw new Error(
|
||||
t('Either an extension name or --all must be provided'),
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue