basant307/AI_Governance_Project
048
1/**2 * @license3 * Copyright 2025 Qwen4 * SPDX-License-Identifier: Apache-2.05 */6 7import type { CommandModule } from 'yargs';8import { redactUrlCredentials } from '@qwen-code/qwen-code-core';9import { getErrorMessage } from '../../utils/errors.js';10import { writeStdoutLine, writeStderrLine } from '../../utils/stdioHelpers.js';11import { getExtensionManager } from './utils.js';12import { t } from '../../i18n/index.js';13 14export async function handleSourcesAdd(args: { source: string }) {15 try {16 const extensionManager = await getExtensionManager();17 const entry = await extensionManager.addSource(args.source);18 writeStdoutLine(t('Added marketplace "{{name}}".', { name: entry.name }));19 } catch (error) {20 writeStderrLine(getErrorMessage(error));21 process.exit(1);22 }23}24 25export async function handleSourcesRemove(args: { name: string }) {26 try {27 const extensionManager = await getExtensionManager();28 if (!extensionManager.removeSource(args.name)) {29 writeStderrLine(30 t('Marketplace "{{name}}" not found.', { name: args.name }),31 );32 process.exit(1);33 return;34 }35 writeStdoutLine(t('Removed marketplace "{{name}}".', { name: args.name }));36 } catch (error) {37 writeStderrLine(getErrorMessage(error));38 process.exit(1);39 }40}41 42export async function handleSourcesList() {43 try {44 const extensionManager = await getExtensionManager();45 const sources = extensionManager.getSources();46 if (sources.length === 0) {47 writeStdoutLine(t('No marketplace sources added yet.'));48 return;49 }50 writeStdoutLine(51 sources52 .map((entry) => {53 let output = `${entry.name}`;54 output += `\n ${t('Source:')} ${redactUrlCredentials(entry.source)} (${t('Type:')} ${entry.type})`;55 const updated = entry.lastUpdatedAt ?? entry.addedAt;56 if (updated) {57 output += `\n ${t('Last updated: {{date}}', { date: updated })}`;58 }59 return output;60 })61 .join('\n\n'),62 );63 } catch (error) {64 writeStderrLine(getErrorMessage(error));65 process.exit(1);66 }67}68 69export async function handleSourcesUpdate(args: { name: string }) {70 try {71 const extensionManager = await getExtensionManager();72 const entry = extensionManager73 .getSources()74 .find((source) => source.name === args.name);75 if (!entry) {76 writeStderrLine(77 t('Marketplace "{{name}}" not found.', { name: args.name }),78 );79 process.exit(1);80 return;81 }82 const config = await extensionManager.loadSource(entry.source);83 if (!config) {84 writeStderrLine(t('Could not load this marketplace.'));85 process.exit(1);86 return;87 }88 extensionManager.markSourceUpdated(entry.name);89 writeStdoutLine(t('Updated marketplace "{{name}}".', { name: entry.name }));90 writeStdoutLine(91 t('{{count}} available extensions', {92 count: String(config.plugins?.length ?? 0),93 }),94 );95 } catch (error) {96 writeStderrLine(getErrorMessage(error));97 process.exit(1);98 }99}100 101const addCommand: CommandModule = {102 command: 'add <source>',103 describe: t('Adds a marketplace source (Claude format).'),104 builder: (yargs) =>105 yargs.positional('source', {106 describe: t(107 'The marketplace source to add: owner/repo (GitHub), a git or https URL, or a local path.',108 ),109 type: 'string',110 demandOption: true,111 }),112 handler: async (argv) => {113 await handleSourcesAdd({ source: argv['source'] as string });114 },115};116 117const removeCommand: CommandModule = {118 command: 'remove <name>',119 describe: t('Removes a marketplace source.'),120 builder: (yargs) =>121 yargs.positional('name', {122 describe: t('The name of the marketplace to remove.'),123 type: 'string',124 demandOption: true,125 }),126 handler: async (argv) => {127 await handleSourcesRemove({ name: argv['name'] as string });128 },129};130 131const listCommand: CommandModule = {132 command: 'list',133 describe: t('Lists configured marketplace sources.'),134 builder: (yargs) => yargs,135 handler: async () => {136 await handleSourcesList();137 },138};139 140const updateCommand: CommandModule = {141 command: 'update <name>',142 describe: t('Re-fetches a marketplace source and its plugin listing.'),143 builder: (yargs) =>144 yargs.positional('name', {145 describe: t('The name of the marketplace to update.'),146 type: 'string',147 demandOption: true,148 }),149 handler: async (argv) => {150 await handleSourcesUpdate({ name: argv['name'] as string });151 },152};153 154export const sourcesCommand: CommandModule = {155 command: 'sources <command>',156 describe: t('Manage marketplace sources for discovering extensions.'),157 builder: (yargs) =>158 yargs159 .command(addCommand)160 .command(removeCommand)161 .command(listCommand)162 .command(updateCommand)163 .demandCommand(1, t('You need at least one command before continuing.'))164 .version(false),165 handler: () => {166 // Yargs shows the help menu when no subcommand is provided.167 },168};169 