replicas-cli
Version:
CLI for managing Replicas workspaces - SSH into cloud dev environments with automatic port forwarding
128 lines • 6.45 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.prepareWorkspaceConnection = prepareWorkspaceConnection;
const chalk_1 = __importDefault(require("chalk"));
const prompts_1 = __importDefault(require("prompts"));
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const config_1 = require("./config");
const api_1 = require("./api");
const ssh_1 = require("./ssh");
const git_1 = require("./git");
const replicas_config_1 = require("./replicas-config");
const ports_1 = require("./ports");
async function prepareWorkspaceConnection(workspaceName, options) {
const orgId = (0, config_1.getOrganizationId)();
if (!orgId) {
throw new Error('No organization selected. Please run "replicas org switch" first.');
}
// Step 1: Query workspaces by name
console.log(chalk_1.default.blue(`\nSearching for workspace: ${workspaceName}...`));
const response = await (0, api_1.orgAuthenticatedFetch)(`/v1/workspaces?name=${encodeURIComponent(workspaceName)}`);
if (response.workspaces.length === 0) {
throw new Error(`No workspaces found with name matching "${workspaceName}".`);
}
// Step 2: If multiple workspaces, prompt user to select one
let selectedWorkspace;
if (response.workspaces.length === 1) {
selectedWorkspace = response.workspaces[0];
}
else {
console.log(chalk_1.default.yellow(`\nFound ${response.workspaces.length} workspaces matching "${workspaceName}":`));
const selectResponse = await (0, prompts_1.default)({
type: 'select',
name: 'workspaceId',
message: 'Select a workspace:',
choices: response.workspaces.map(ws => ({
title: `${ws.name} (${ws.status || 'unknown'})`,
value: ws.id,
description: `IP: ${ws.ipv4_address || 'N/A'} | Instance: ${ws.instance_type || 'N/A'}`,
})),
});
if (!selectResponse.workspaceId) {
throw new Error('Workspace selection cancelled.');
}
selectedWorkspace = response.workspaces.find(ws => ws.id === selectResponse.workspaceId);
}
console.log(chalk_1.default.green(`\n✓ Selected workspace: ${selectedWorkspace.name}`));
console.log(chalk_1.default.gray(` IP: ${selectedWorkspace.ipv4_address}`));
console.log(chalk_1.default.gray(` Status: ${selectedWorkspace.status || 'unknown'}`));
if (!selectedWorkspace.ipv4_address) {
throw new Error('Workspace does not have an IP address. It may not be running yet.');
}
// Step 3: Get SSH key
console.log(chalk_1.default.blue('\nRetrieving SSH key...'));
const privateKey = await (0, ssh_1.getSSHKey)(selectedWorkspace.ssh_key_id);
// Write key to a temporary file for SSH
const keyPath = path_1.default.join(config_1.CONFIG_DIR, 'keys', `${selectedWorkspace.ssh_key_id}.pem`);
fs_1.default.writeFileSync(keyPath, privateKey, { mode: 0o600 });
console.log(chalk_1.default.green('✓ SSH key ready'));
// Step 4: Handle --copy flag
let repoName = null;
if (options.copy) {
if (!(0, git_1.isInsideGitRepo)()) {
console.log(chalk_1.default.yellow('\nWarning: Not inside a git repository. Skipping file copy.'));
}
else {
repoName = (0, git_1.getGitRepoName)();
const replicasConfig = (0, replicas_config_1.readReplicasConfig)();
if (!replicasConfig || !replicasConfig.copy || replicasConfig.copy.length === 0) {
console.log(chalk_1.default.yellow('\nNo files to copy (replicas.json not found or empty).'));
}
else {
console.log(chalk_1.default.blue(`\nCopying files to workspace (repo: ${repoName})...`));
const { valid, invalid } = (0, replicas_config_1.validateCopyFiles)(replicasConfig.copy);
if (invalid.length > 0) {
console.log(chalk_1.default.yellow(`\nWarning: ${invalid.length} file(s) not found locally:`));
invalid.forEach(file => console.log(chalk_1.default.gray(` - ${file}`)));
}
for (const file of valid) {
const localPath = (0, replicas_config_1.getAbsoluteCopyPath)(file);
const remotePath = `/home/ubuntu/workspaces/${repoName}/${file}`;
console.log(chalk_1.default.gray(` Copying ${file}...`));
try {
await (0, ssh_1.scpCopyFile)(keyPath, localPath, remotePath, selectedWorkspace.ipv4_address);
console.log(chalk_1.default.green(` ✓ ${file}`));
}
catch (error) {
console.log(chalk_1.default.red(` ✗ Failed to copy ${file}: ${error instanceof Error ? error.message : 'Unknown error'}`));
}
}
console.log(chalk_1.default.green(`\n✓ File copy complete (${valid.length} files)`));
}
}
}
if (!repoName && (0, git_1.isInsideGitRepo)()) {
try {
repoName = (0, git_1.getGitRepoName)();
}
catch {
// Ignore errors, repo name is optional
}
}
// Step 6: Handle port forwarding
const portMappings = new Map();
// Add ports from replicas.json if inside a git repo
console.log(chalk_1.default.blue('\nSetting up port forwarding...'));
if ((0, git_1.isInsideGitRepo)()) {
const replicasConfig = (0, replicas_config_1.readReplicasConfig)();
if (replicasConfig && replicasConfig.ports && replicasConfig.ports.length > 0) {
const mappings = await (0, ports_1.mapPortsToLocal)(replicasConfig.ports);
for (const [remotePort, localPort] of mappings) {
portMappings.set(remotePort, localPort);
console.log(chalk_1.default.gray(` Forwarding localhost:${localPort} -> workspace:${remotePort}`));
}
}
}
console.log(chalk_1.default.green('✓ Port forwarding configured'));
return {
workspace: selectedWorkspace,
sshKeyPath: keyPath,
portMappings,
repoName,
};
}
//# sourceMappingURL=workspace-connection.js.map