UNPKG

vsix-extension-manager

Version:

VSIX Extension Manager: A comprehensive CLI tool to download, export, import, and manage VS Code/Cursor extensions as VSIX files

252 lines 14 kB
#!/usr/bin/env node "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const commander_1 = require("commander"); const download_1 = require("./commands/download"); const constants_1 = require("./config/constants"); const errors_1 = require("./core/errors"); const package_json_1 = __importDefault(require("../package.json")); /** * Wrap command action with configuration loading and error handling */ async function withConfigAndErrorHandling(action, options) { try { // Get global config file path if set const globalOpts = program.opts(); const configFilePath = globalOpts.config; // Convert CLI options to config format const cliConfig = (0, constants_1.convertCliToConfig)(options); // Load full configuration (CLI > ENV > FILE > DEFAULTS) const config = await (0, constants_1.loadConfig)(cliConfig, configFilePath); // Update error handler with config settings (0, errors_1.initializeErrorHandler)(config.quiet, config.json); // Execute command with loaded config await action(config, options); } catch (error) { (0, errors_1.handleErrorAndExit)(error instanceof Error ? error : new Error(String(error))); } } const program = new commander_1.Command(); program .name("vsix-extension-manager") .description("VSIX Extension Manager: download, list versions, export, and manage VS Code/Cursor extensions") .version(package_json_1.default.version) .option("--config <path>", "Path to configuration file"); program .command("download") .alias("dl") .description("Download a VSIX file from marketplace URL") .option("-u, --url <url>", "Marketplace URL of the extension") .option("-v, --version <version>", "Version of the extension to download") .option("-o, --output <path>", "Output directory (default: ./downloads)") .option("-f, --file <path>", "Bulk JSON file path (non-interactive mode)") .option("--parallel <n>", "Number of parallel downloads (bulk mode)") .option("--retry <n>", "Number of retry attempts per item (bulk mode)") .option("--retry-delay <ms>", "Delay in ms between retries (bulk mode)") .option("--skip-existing", "Skip downloads if target file already exists", false) .option("--overwrite", "Overwrite existing files", false) .option("--quiet", "Reduce output (non-interactive)", false) .option("--json", "Machine-readable logs (where applicable)", false) .option("--summary <path>", "Write bulk summary JSON to the given path") .option("--pre-release", "Prefer pre-release when resolving 'latest'", false) .option("--source <source>", "Source registry: marketplace|open-vsx|auto (default: marketplace)") .option("--filename-template <template>", "Custom filename template (default: {name}-{version}.vsix)") .option("--cache-dir <path>", "Cache directory for downloads (overrides output)") .option("--checksum", "Generate SHA256 checksum for downloaded files", false) .option("--verify-checksum <hash>", "Verify downloaded file against provided SHA256 hash") .option("--install-after", "Install downloaded extensions after successful downloads", false) .action(async (opts) => { await withConfigAndErrorHandling(async (config, options) => { await (0, download_1.downloadVsix)({ ...options, ...config }); }, opts); }); program .command("quick-install") .alias("qi") .description("Quickly download an extension by URL to a temp dir, install it, then clean up") .option("-u, --url <url>", "Marketplace or OpenVSX URL of the extension") .option("-e, --editor <editor>", "Target editor: vscode|cursor|auto (default: auto)") .option("--code-bin <path>", "Explicit path to VS Code binary") .option("--cursor-bin <path>", "Explicit path to Cursor binary") .option("--allow-mismatched-binary", "Allow proceeding when resolved binary identity mismatches the requested editor", false) .option("--pre-release", "Prefer pre-release when resolving 'latest'", false) .option("--source <source>", "Source registry: marketplace|open-vsx|auto (default: auto)") .option("--dry-run", "Show what would be installed without making changes", false) .option("--quiet", "Reduce output", false) .option("--json", "Machine-readable output", false) .action(async (opts) => { await withConfigAndErrorHandling(async (config, options) => { const { quickInstall } = await Promise.resolve().then(() => __importStar(require("./commands/quickInstall"))); await quickInstall({ ...options, ...config }); }, opts); }); program .command("versions") .description("List available versions for an extension") .option("-u, --url <url>", "Marketplace URL of the extension") .option("--json", "Output JSON", false) .action(async (opts) => { await withConfigAndErrorHandling(async (config, options) => { const { listVersions } = await Promise.resolve().then(() => __importStar(require("./commands/versions"))); await listVersions({ ...options, ...config }); }, opts); }); program .command("export-installed") .alias("export") .description("Export currently installed extensions from VS Code or Cursor") .option("-o, --output <path>", "Output file path") .option("-f, --format <format>", "Output format: txt|extensions.json") .option("-e, --editor <editor>", "Editor to export from: vscode|cursor|auto (default: auto)") .option("-w, --workspace", "Export workspace extensions.json instead of installed", false) .option("--json", "Machine-readable output", false) .action(async (opts) => { await withConfigAndErrorHandling(async (config, options) => { const { exportInstalled } = await Promise.resolve().then(() => __importStar(require("./commands/exportInstalled"))); await exportInstalled({ ...options, ...config }); }, opts); }); program .command("from-list") .description("Download extensions from a list file") .option("-f, --file <path>", "Path to extensions list file") .option("-o, --output <path>", "Output directory (default: ./downloads)") .option("--format <format>", "Input file format: txt|extensions.json|auto") .option("--parallel <n>", "Number of parallel downloads") .option("--retry <n>", "Number of retry attempts per item") .option("--retry-delay <ms>", "Delay in ms between retries") .option("--skip-existing", "Skip downloads if target file already exists", false) .option("--overwrite", "Overwrite existing files", false) .option("--quiet", "Reduce output", false) .option("--json", "Machine-readable logs", false) .option("--summary <path>", "Write bulk summary JSON to the given path") .option("--pre-release", "Prefer pre-release when resolving 'latest'", false) .option("--source <source>", "Source registry: marketplace|open-vsx|auto (default: auto)") .option("--filename-template <template>", "Custom filename template") .option("--cache-dir <path>", "Cache directory for downloads") .option("--checksum", "Generate SHA256 checksum for downloaded files", false) .option("--install", "Install extensions after downloading (requires --download-missing behavior)", false) .option("--download-only", "Download only, do not install (default behavior)", false) .action(async (opts) => { await withConfigAndErrorHandling(async (config, options) => { const { fromList } = await Promise.resolve().then(() => __importStar(require("./commands/fromList"))); await fromList({ ...options, ...config }); }, opts); }); program .command("install") .description("Install VSIX files or extensions from lists into VS Code/Cursor") .option("--vsix <path>", "Single VSIX file to install") .option("--vsix-dir <paths...>", "Directories to scan for VSIX files (recursive)") .option("-f, --file <path>", "Extension list file (.txt or extensions.json) to install from") .option("--download-missing", "Download missing extensions when installing from list", false) .option("-e, --editor <editor>", "Target editor: vscode|cursor|auto (default: auto)") .option("--code-bin <path>", "Explicit path to VS Code binary") .option("--cursor-bin <path>", "Explicit path to Cursor binary") .option("--skip-installed", "Skip if same version already installed", false) .option("--force-reinstall", "Force reinstall even if same version", false) .option("--dry-run", "Show what would be installed without making changes", false) .option("--parallel <n>", "Number of parallel installs (default: 1)") .option("--retry <n>", "Number of retry attempts per install") .option("--retry-delay <ms>", "Delay in ms between retries") .option("--quiet", "Reduce output", false) .option("--json", "Machine-readable logs", false) .option("--summary <path>", "Write install summary JSON to the given path") .option("--allow-mismatched-binary", "Allow proceeding when resolved binary identity mismatches the requested editor", false) .action(async (opts) => { await withConfigAndErrorHandling(async (config, options) => { const { installExtensions } = await Promise.resolve().then(() => __importStar(require("./commands/install"))); await installExtensions({ ...options, ...config }); }, opts); }); program .command("update-installed") .alias("update") .description("Update installed extensions to latest available versions") .option("-e, --editor <editor>", "Target editor: vscode|cursor|auto (default: auto)") .option("--pre-release", "Prefer pre-release when resolving 'latest'", false) .option("--source <source>", "Source registry: marketplace|open-vsx|auto (default: auto)") .option("--parallel <n>", "Number of parallel updates (default: 1)") .option("--retry <n>", "Number of retry attempts per extension") .option("--retry-delay <ms>", "Delay in ms between retries") .option("--quiet", "Reduce output", false) .option("--json", "Machine-readable output", false) .option("--dry-run", "Preview updates without downloading/installing", false) .option("--summary <path>", "Write update summary JSON to the given path") .option("--code-bin <path>", "Explicit path to VS Code binary") .option("--cursor-bin <path>", "Explicit path to Cursor binary") .option("--allow-mismatched-binary", "Allow proceeding when resolved binary identity mismatches the requested editor", false) .option("--skip-backup", "Skip creating backups before updating", false) .option("--backup-dir <path>", "Custom backup directory (default: ~/.vsix-backups)") .action(async (opts) => { await withConfigAndErrorHandling(async (config, options) => { const { updateInstalled } = await Promise.resolve().then(() => __importStar(require("./commands/updateInstalled"))); await updateInstalled({ ...options, ...config }); }, opts); }); program .command("rollback") .description("Rollback extensions from backups") .option("--extension-id <id>", "Extension ID to rollback") .option("-e, --editor <editor>", "Filter by editor: vscode|cursor") .option("--backup-id <id>", "Specific backup ID to restore") .option("--latest", "Restore latest backup for the extension", false) .option("--list", "List available backups", false) .option("--force", "Force restore even if extension exists", false) .option("--cleanup", "Clean up old backups", false) .option("--keep-count <n>", "Number of backups to keep per extension (default: 3)") .option("--quiet", "Reduce output", false) .option("--json", "Machine-readable output", false) .option("--backup-dir <path>", "Custom backup directory (default: ~/.vsix-backups)") .action(async (opts) => { await withConfigAndErrorHandling(async (config, options) => { const { rollback } = await Promise.resolve().then(() => __importStar(require("./commands/rollback"))); // Don't merge config for rollback - it has different options await rollback(options); }, opts); }); program.action(async () => { await withConfigAndErrorHandling(async (config) => { const { runInteractive } = await Promise.resolve().then(() => __importStar(require("./commands/interactive"))); await runInteractive(config); }, {}); }); program.parse(); //# sourceMappingURL=index.js.map