UNPKG

@jalasem/dss

Version:

Dev Spaces Switcher (DSS) - Seamlessly manage isolated development environments with separate SSH keys and Git configurations. Enhanced UI with beautiful tables and improved documentation.

328 lines (327 loc) 16.1 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.bulkUpdateSpaces = exports.importSpaceConfiguration = exports.exportSpaceConfiguration = exports.batchSwitchSpaces = void 0; const fs_extra_1 = __importDefault(require("fs-extra")); const path_1 = __importDefault(require("path")); const os_1 = __importDefault(require("os")); const prompts_1 = require("@inquirer/prompts"); const ui_1 = require("./ui"); const SpaceManager_1 = require("./SpaceManager"); const sshKeyGen_1 = require("./sshKeyGen"); const configPath = path_1.default.join(os_1.default.homedir(), '.dss', 'spaces', 'config.json'); function batchSwitchSpaces() { return __awaiter(this, void 0, void 0, function* () { const config = yield fs_extra_1.default.readJson(configPath); if (config.spaces.length === 0) { ui_1.UIHelper.warning('No spaces available for batch operations.'); return; } ui_1.UIHelper.printHeader('Batch Switch Spaces'); ui_1.UIHelper.info('Select multiple spaces to switch between them quickly.'); const selectedSpaces = yield (0, prompts_1.checkbox)({ message: 'Select spaces to switch between:', choices: config.spaces.map(space => ({ name: space.name === config.activeSpace ? ui_1.UIHelper.activeSpace(space.name) : space.name, value: space.name, description: `${space.email} (${space.userName})` })) }); if (selectedSpaces.length === 0) { ui_1.UIHelper.info('No spaces selected.'); return; } ui_1.UIHelper.info(`Selected ${selectedSpaces.length} spaces for batch switching.`); for (const spaceName of selectedSpaces) { try { ui_1.UIHelper.info(`Switching to: ${ui_1.UIHelper.highlight(spaceName)}`); yield (0, SpaceManager_1.switchSpace)(spaceName); const continueNext = yield (0, prompts_1.confirm)({ message: 'Continue to next space?', default: true }); if (!continueNext) break; } catch (error) { ui_1.UIHelper.error(`Failed to switch to ${spaceName}: ${error.message}`); const continueOnError = yield (0, prompts_1.confirm)({ message: 'Continue with remaining spaces?', default: true }); if (!continueOnError) break; } } ui_1.UIHelper.success('Batch operation completed!'); }); } exports.batchSwitchSpaces = batchSwitchSpaces; function exportSpaceConfiguration() { return __awaiter(this, void 0, void 0, function* () { const config = yield fs_extra_1.default.readJson(configPath); if (config.spaces.length === 0) { ui_1.UIHelper.warning('No spaces to export.'); return; } ui_1.UIHelper.printHeader('Export Space Configuration'); const selectedSpaces = yield (0, prompts_1.checkbox)({ message: 'Select spaces to export:', choices: config.spaces.map(space => ({ name: space.name, value: space.name, description: `${space.email} (${space.userName})` })) }); if (selectedSpaces.length === 0) { ui_1.UIHelper.info('No spaces selected for export.'); return; } const exportData = { version: '1.0.0', exportDate: new Date().toISOString(), spaces: config.spaces.filter(space => selectedSpaces.includes(space.name)) .map(space => ({ name: space.name, email: space.email, userName: space.userName, // Don't export SSH key paths for security hasSSHKey: !!space.sshKeyPath })) }; const exportPath = path_1.default.join(os_1.default.homedir(), 'dss-export.json'); yield fs_extra_1.default.writeJson(exportPath, exportData, { spaces: 2 }); ui_1.UIHelper.printSuccessBox('Configuration Exported', [ `✓ ${selectedSpaces.length} spaces exported`, `✓ Saved to: ${exportPath}`, '', 'Note: SSH keys not included for security' ]); }); } exports.exportSpaceConfiguration = exportSpaceConfiguration; function importSpaceConfiguration() { return __awaiter(this, void 0, void 0, function* () { ui_1.UIHelper.printHeader('Import Space Configuration'); const importPath = path_1.default.join(os_1.default.homedir(), 'dss-export.json'); if (!(yield fs_extra_1.default.pathExists(importPath))) { ui_1.UIHelper.error(`Import file not found: ${importPath}`); ui_1.UIHelper.info('Please ensure the export file exists in your home directory.'); return; } try { const importData = yield fs_extra_1.default.readJson(importPath); if (!importData.spaces || !Array.isArray(importData.spaces)) { ui_1.UIHelper.error('Invalid import file format.'); return; } ui_1.UIHelper.info(`Found ${importData.spaces.length} spaces in import file.`); const config = yield fs_extra_1.default.readJson(configPath).catch(() => ({ spaces: [] })); const spacesToImport = importData.spaces.filter((importSpace) => { const exists = config.spaces.some(existing => existing.name === importSpace.name); if (exists) { ui_1.UIHelper.warning(`Space '${importSpace.name}' already exists - skipping.`); } return !exists; }); if (spacesToImport.length === 0) { ui_1.UIHelper.info('No new spaces to import.'); return; } const confirmImport = yield (0, prompts_1.confirm)({ message: `Import ${spacesToImport.length} new spaces?`, default: true }); if (!confirmImport) { ui_1.UIHelper.info('Import cancelled.'); return; } // Convert import format to internal format const newSpaces = spacesToImport.map((importSpace) => ({ name: importSpace.name, email: importSpace.email, userName: importSpace.userName, sshKeyPath: '' // Will need to be set up manually })); config.spaces.push(...newSpaces); yield fs_extra_1.default.writeJson(configPath, config); ui_1.UIHelper.printSuccessBox('Import Completed', [ `✓ ${spacesToImport.length} spaces imported`, '', 'Note: SSH keys need to be set up manually', 'Use `dss edit <space>` to configure SSH keys' ]); } catch (error) { ui_1.UIHelper.error(`Failed to import configuration: ${error.message}`); } }); } exports.importSpaceConfiguration = importSpaceConfiguration; function bulkUpdateSpaces() { return __awaiter(this, void 0, void 0, function* () { const config = yield fs_extra_1.default.readJson(configPath); if (config.spaces.length === 0) { ui_1.UIHelper.warning('No spaces available for bulk update.'); return; } ui_1.UIHelper.printHeader('Bulk Update Spaces'); const updateType = yield (0, prompts_1.select)({ message: 'What would you like to update?', choices: [ { name: 'Email domain', value: 'email-domain' }, { name: 'User name prefix/suffix', value: 'username-pattern' }, { name: 'Regenerate SSH keys', value: 'regenerate-keys' } ] }); const selectedSpaces = yield (0, prompts_1.checkbox)({ message: 'Select spaces to update:', choices: config.spaces.map(space => ({ name: space.name, value: space.name, description: `${space.email} (${space.userName})` })) }); if (selectedSpaces.length === 0) { ui_1.UIHelper.info('No spaces selected.'); return; } ui_1.UIHelper.info(`Selected ${selectedSpaces.length} spaces for update.`); let updatedCount = 0; try { switch (updateType) { case 'email-domain': { const oldDomain = yield (0, prompts_1.input)({ message: 'Enter the old domain to replace (e.g., oldcompany.com):', validate: (input) => input.trim().length > 0 || 'Domain is required' }); const newDomain = yield (0, prompts_1.input)({ message: 'Enter the new domain (e.g., newcompany.com):', validate: (input) => input.trim().length > 0 || 'Domain is required' }); ui_1.UIHelper.printProgress(`Updating email domains from ${oldDomain} to ${newDomain}`); for (const spaceName of selectedSpaces) { const space = config.spaces.find(s => s.name === spaceName); if (space && space.email.includes(oldDomain)) { space.email = space.email.replace(oldDomain, newDomain); updatedCount++; } } break; } case 'username-pattern': { const operation = yield (0, prompts_1.select)({ message: 'What would you like to do with usernames?', choices: [ { name: 'Add prefix', value: 'add-prefix' }, { name: 'Add suffix', value: 'add-suffix' }, { name: 'Replace text', value: 'replace' } ] }); if (operation === 'add-prefix') { const prefix = yield (0, prompts_1.input)({ message: 'Enter prefix to add:', validate: (input) => input.trim().length > 0 || 'Prefix is required' }); ui_1.UIHelper.printProgress(`Adding prefix "${prefix}" to usernames`); for (const spaceName of selectedSpaces) { const space = config.spaces.find(s => s.name === spaceName); if (space && !space.userName.startsWith(prefix)) { space.userName = prefix + space.userName; updatedCount++; } } } else if (operation === 'add-suffix') { const suffix = yield (0, prompts_1.input)({ message: 'Enter suffix to add:', validate: (input) => input.trim().length > 0 || 'Suffix is required' }); ui_1.UIHelper.printProgress(`Adding suffix "${suffix}" to usernames`); for (const spaceName of selectedSpaces) { const space = config.spaces.find(s => s.name === spaceName); if (space && !space.userName.endsWith(suffix)) { space.userName = space.userName + suffix; updatedCount++; } } } else if (operation === 'replace') { const oldText = yield (0, prompts_1.input)({ message: 'Enter text to replace:', validate: (input) => input.trim().length > 0 || 'Text is required' }); const newText = yield (0, prompts_1.input)({ message: 'Enter replacement text:', validate: (input) => input.trim().length > 0 || 'Replacement text is required' }); ui_1.UIHelper.printProgress(`Replacing "${oldText}" with "${newText}" in usernames`); for (const spaceName of selectedSpaces) { const space = config.spaces.find(s => s.name === spaceName); if (space && space.userName.includes(oldText)) { space.userName = space.userName.replace(new RegExp(oldText, 'g'), newText); updatedCount++; } } } break; } case 'regenerate-keys': { const confirmRegenerate = yield (0, prompts_1.confirm)({ message: 'Are you sure you want to regenerate SSH keys? This will replace existing keys.', default: false }); if (!confirmRegenerate) { ui_1.UIHelper.info('SSH key regeneration cancelled.'); return; } ui_1.UIHelper.printProgress('Regenerating SSH keys'); for (const spaceName of selectedSpaces) { const space = config.spaces.find(s => s.name === spaceName); if (space) { try { ui_1.UIHelper.updateProgress(`Regenerating SSH key for ${space.name}`); const newKeyPath = yield (0, sshKeyGen_1.generateSSHKey)(space.name, space.email); space.sshKeyPath = newKeyPath; updatedCount++; } catch (error) { ui_1.UIHelper.error(`Failed to regenerate SSH key for ${space.name}: ${error.message}`); } } } break; } } ui_1.UIHelper.clearProgress(); if (updatedCount > 0) { yield fs_extra_1.default.writeJson(configPath, config); ui_1.UIHelper.printSuccessBox('Bulk Update Complete', [ `✓ ${updatedCount} spaces updated successfully`, `✓ Operation: ${updateType}`, '', 'Use `dss list` to view updated spaces' ]); } else { ui_1.UIHelper.info('No spaces were updated.'); } } catch (error) { ui_1.UIHelper.clearProgress(); ui_1.UIHelper.error(`Bulk update failed: ${error.message}`); } }); } exports.bulkUpdateSpaces = bulkUpdateSpaces;