diff --git a/packages/coding-agent/README.md b/packages/coding-agent/README.md index 0c9e97a7..79d78c43 100644 --- a/packages/coding-agent/README.md +++ b/packages/coding-agent/README.md @@ -1245,6 +1245,7 @@ pi [options] [@files...] [messages...] | `install [-l]` | Install extension source and add to settings (`-l` for project) | | `remove [-l]` | Remove extension source from settings | | `update [source]` | Update installed extensions (skips pinned sources) | +| `list` | List installed extensions from settings | ### Options diff --git a/packages/coding-agent/src/cli/args.ts b/packages/coding-agent/src/cli/args.ts index 8fb80dec..ddab572c 100644 --- a/packages/coding-agent/src/cli/args.ts +++ b/packages/coding-agent/src/cli/args.ts @@ -180,6 +180,7 @@ ${chalk.bold("Commands:")} ${APP_NAME} install [-l] Install extension source and add to settings ${APP_NAME} remove [-l] Remove extension source from settings ${APP_NAME} update [source] Update installed extensions (skips pinned sources) + ${APP_NAME} list List installed extensions from settings ${chalk.bold("Options:")} --provider Provider name (default: google) diff --git a/packages/coding-agent/src/core/package-manager.ts b/packages/coding-agent/src/core/package-manager.ts index 10072d02..82b2f1d7 100644 --- a/packages/coding-agent/src/core/package-manager.ts +++ b/packages/coding-agent/src/core/package-manager.ts @@ -161,7 +161,7 @@ export class DefaultPackageManager implements PackageManager { return; } if (parsed.type === "git") { - await this.installGit(parsed, scope, false); + await this.installGit(parsed, scope); this.emitProgress({ type: "complete", action: "install", source }); return; } @@ -184,7 +184,7 @@ export class DefaultPackageManager implements PackageManager { return; } if (parsed.type === "git") { - await this.removeGit(parsed, scope, false); + await this.removeGit(parsed, scope); this.emitProgress({ type: "complete", action: "remove", source }); return; } @@ -232,7 +232,7 @@ export class DefaultPackageManager implements PackageManager { if (parsed.pinned) return; this.emitProgress({ type: "start", action: "update", source, message: `Updating ${source}...` }); try { - await this.updateGit(parsed, scope, false); + await this.updateGit(parsed, scope); this.emitProgress({ type: "complete", action: "update", source }); } catch (error) { const message = error instanceof Error ? error.message : String(error); @@ -317,7 +317,7 @@ export class DefaultPackageManager implements PackageManager { return; } if (parsed.type === "git") { - await this.installGit(parsed, scope, scope === "temporary"); + await this.installGit(parsed, scope); return; } } @@ -394,8 +394,8 @@ export class DefaultPackageManager implements PackageManager { await this.runCommand("npm", ["uninstall", source.name, "--prefix", installRoot]); } - private async installGit(source: GitSource, scope: SourceScope, temporary: boolean): Promise { - const targetDir = this.getGitInstallPath(source, scope, temporary); + private async installGit(source: GitSource, scope: SourceScope): Promise { + const targetDir = this.getGitInstallPath(source, scope); if (existsSync(targetDir)) { return; } @@ -407,17 +407,17 @@ export class DefaultPackageManager implements PackageManager { } } - private async updateGit(source: GitSource, scope: SourceScope, temporary: boolean): Promise { - const targetDir = this.getGitInstallPath(source, scope, temporary); + private async updateGit(source: GitSource, scope: SourceScope): Promise { + const targetDir = this.getGitInstallPath(source, scope); if (!existsSync(targetDir)) { - await this.installGit(source, scope, temporary); + await this.installGit(source, scope); return; } await this.runCommand("git", ["pull"], { cwd: targetDir }); } - private async removeGit(source: GitSource, scope: SourceScope, temporary: boolean): Promise { - const targetDir = this.getGitInstallPath(source, scope, temporary); + private async removeGit(source: GitSource, scope: SourceScope): Promise { + const targetDir = this.getGitInstallPath(source, scope); if (!existsSync(targetDir)) return; rmSync(targetDir, { recursive: true, force: true }); } @@ -462,8 +462,8 @@ export class DefaultPackageManager implements PackageManager { return join(this.getGlobalNpmRoot(), source.name); } - private getGitInstallPath(source: GitSource, scope: SourceScope, temporary?: boolean): string { - if (temporary) { + private getGitInstallPath(source: GitSource, scope: SourceScope): string { + if (scope === "temporary") { return this.getTemporaryDir(`git-${source.host}`, source.path); } if (scope === "project") { diff --git a/packages/coding-agent/src/main.ts b/packages/coding-agent/src/main.ts index 4d8b4770..7182d92b 100644 --- a/packages/coding-agent/src/main.ts +++ b/packages/coding-agent/src/main.ts @@ -53,7 +53,7 @@ async function readPipedStdin(): Promise { }); } -type PackageCommand = "install" | "remove" | "update"; +type PackageCommand = "install" | "remove" | "update" | "list"; interface PackageCommandOptions { command: PackageCommand; @@ -63,7 +63,7 @@ interface PackageCommandOptions { function parsePackageCommand(args: string[]): PackageCommandOptions | undefined { const [command, ...rest] = args; - if (command !== "install" && command !== "remove" && command !== "update") { + if (command !== "install" && command !== "remove" && command !== "update" && command !== "list") { return undefined; } @@ -165,6 +165,35 @@ async function handlePackageCommand(args: string[]): Promise { return true; } + if (options.command === "list") { + const globalSettings = settingsManager.getGlobalSettings(); + const projectSettings = settingsManager.getProjectSettings(); + const globalExtensions = globalSettings.extensions ?? []; + const projectExtensions = projectSettings.extensions ?? []; + + if (globalExtensions.length === 0 && projectExtensions.length === 0) { + console.log(chalk.dim("No extensions installed.")); + return true; + } + + if (globalExtensions.length > 0) { + console.log(chalk.bold("Global extensions:")); + for (const ext of globalExtensions) { + console.log(` ${ext}`); + } + } + + if (projectExtensions.length > 0) { + if (globalExtensions.length > 0) console.log(); + console.log(chalk.bold("Project extensions:")); + for (const ext of projectExtensions) { + console.log(` ${ext}`); + } + } + + return true; + } + await packageManager.update(options.source); if (options.source) { console.log(chalk.green(`Updated ${options.source}`));