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

233 lines 10.3 kB
"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 }); exports.fromList = fromList; const p = __importStar(require("@clack/prompts")); const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const import_1 = require("../features/import"); const download_1 = require("../features/download"); const helpers_1 = require("../core/helpers"); const constants_1 = require("../config/constants"); async function fromList(options) { try { p.intro("📥 Download from Extension List"); // Get input file let filePath = options.file; if (!filePath) { filePath = (await p.text({ message: "Enter path to extensions list file:", validate: (input) => { if (!input.trim()) return "Please enter a file path"; if (!fs_1.default.existsSync(input.trim())) return "File does not exist"; return undefined; }, })); if (p.isCancel(filePath)) { p.cancel("Operation cancelled."); process.exit(0); } } // Validate file exists if (!fs_1.default.existsSync(filePath)) { p.log.error(`❌ File not found: ${filePath}`); process.exit(1); } // Read file content const content = fs_1.default.readFileSync(filePath, "utf-8"); // Determine format from file extension if not specified let format = options.format; if (!format) { const ext = path_1.default.extname(filePath).toLowerCase(); if (ext === ".json") { // Only accept VS Code extensions.json try { const parsed = JSON.parse(content); format = parsed.recommendations ? "extensions.json" : undefined; } catch { format = undefined; } } else { format = "txt"; } } if (format === "json") { p.log.error("❌ JSON arrays of IDs are no longer supported. Use txt (one ID per line) or VS Code extensions.json."); process.exit(1); } // Parse extensions list let extensionIds; try { extensionIds = (0, import_1.parseExtensionsList)(content, format, filePath); } catch (error) { p.log.error(`❌ Failed to parse file: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } if (extensionIds.length === 0) { p.log.warn("⚠️ No extensions found in the file"); return; } p.log.info(`📦 Found ${extensionIds.length} extension(s) to download`); // Convert extension IDs to bulk download format const bulkItems = extensionIds.map((id) => { // Parse publisher.name format const parts = id.split("."); if (parts.length < 2) { throw new Error(`Invalid extension ID format: ${id}. Expected format: publisher.name`); } const publisher = parts[0]; const name = parts.slice(1).join("."); // Construct marketplace URL const url = `https://marketplace.visualstudio.com/items?itemName=${id}`; return { name: `${publisher}.${name}`, url, version: "latest", // Use latest by default }; }); // Create temporary JSON file for bulk download const tempJsonPath = path_1.default.join(process.cwd(), `.temp-extensions-${Date.now()}.json`); try { // Write temporary JSON file fs_1.default.writeFileSync(tempJsonPath, JSON.stringify(bulkItems, null, 2)); // Prepare bulk download options const bulkOptions = (0, helpers_1.buildBulkOptionsFromCli)(options, { parallel: 3, retry: 3, retryDelay: 1000, }); // Determine output directory (cache-dir takes precedence, then output, then prompt) let outputDir; if (options.cacheDir) { outputDir = options.cacheDir; } else if (options.output) { outputDir = options.output; } else { const outputInput = await p.text({ message: "Enter output directory:", placeholder: "./downloads", initialValue: constants_1.DEFAULT_OUTPUT_DIR, }); if (p.isCancel(outputInput)) { p.cancel("Operation cancelled."); process.exit(0); } outputDir = outputInput.trim() || constants_1.DEFAULT_OUTPUT_DIR; } // Show preview in interactive mode if (!options.quiet && !options.json) { p.note(extensionIds.slice(0, 10).join("\n") + (extensionIds.length > 10 ? `\n... and ${extensionIds.length - 10} more` : ""), "Extensions to download"); const proceed = await p.confirm({ message: "Proceed with download?", }); if (p.isCancel(proceed) || !proceed) { p.cancel("Operation cancelled."); process.exit(0); } } // Perform bulk download using temporary file await (0, download_1.downloadBulkExtensions)(tempJsonPath, outputDir, bulkOptions); // Install after download if requested if (options.install && !options.downloadOnly) { if (!options.quiet) { p.log.info("🔧 Installing downloaded extensions..."); } const { getInstallFromListService } = await Promise.resolve().then(() => __importStar(require("../features/install"))); const installService = getInstallFromListService(); // Resolve editor for installation const { getEditorService } = await Promise.resolve().then(() => __importStar(require("../features/install"))); const editorService = getEditorService(); const availableEditors = await editorService.getAvailableEditors(); if (availableEditors.length === 0) { p.log.warn("⚠️ No editors found for installation. Extensions downloaded but not installed."); return; } // Auto-select editor (prefer Cursor) const editor = availableEditors.find((e) => e.name === "cursor") || availableEditors[0]; const binPath = editor.binaryPath; // Use the same list file for installation const installResult = await installService.installFromList(binPath, filePath, [outputDir], // Search in the download directory { downloadMissing: false, // Already downloaded installOptions: { dryRun: false, skipInstalled: true, // Skip already installed by default parallel: 1, // Conservative for post-download install retry: Number(options.retry) || 2, retryDelay: Number(options.retryDelay) || 1000, quiet: options.quiet, }, }, (message) => { if (!options.quiet) { p.log.info(`🔧 ${message}`); } }); if (!options.quiet) { p.note(`Downloaded: ${extensionIds.length}\nInstalled: ${installResult.installedExtensions}\nSkipped: ${installResult.skippedExtensions}\nFailed: ${installResult.failedExtensions}`, "Download & Install Summary"); } } } finally { // Clean up temporary file if (fs_1.default.existsSync(tempJsonPath)) { fs_1.default.unlinkSync(tempJsonPath); } } if (!options.quiet) { if (options.install && !options.downloadOnly) { p.outro("✨ Download and install completed!"); } else { p.outro("✨ Download completed!"); } } } catch (error) { p.log.error("❌ Error: " + (error instanceof Error ? error.message : String(error))); process.exit(1); } } //# sourceMappingURL=fromList.js.map