opencodespaces 1.1.5 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,14 +10,14 @@
10
10
  * opencodespaces sync stop [id] # Stop sync
11
11
  * opencodespaces sync status # Show sync status
12
12
  */
13
- import { execSync, spawn } from 'child_process';
13
+ import { execSync, execFileSync, spawn } from 'child_process';
14
14
  import fs from 'fs';
15
15
  import path from 'path';
16
16
  import os from 'os';
17
17
  import ora from 'ora';
18
18
  import inquirer from 'inquirer';
19
19
  import { isLoggedIn } from '../lib/auth.js';
20
- import { api } from '../lib/api.js';
20
+ import { api, ApiError } from '../lib/api.js';
21
21
  import { getIgnoreList, saveSessionKey, deleteSessionKey, } from '../lib/config.js';
22
22
  import { logger } from '../utils/logger.js';
23
23
  // SSH config directory
@@ -116,7 +116,38 @@ async function startSync(sessionId, localDir) {
116
116
  const spinner = ora('Initializing sync...').start();
117
117
  try {
118
118
  // Initialize sync on server (get SSH credentials)
119
- const syncInfo = await api.initSync(sessionId);
119
+ let syncInfo;
120
+ try {
121
+ syncInfo = await api.initSync(sessionId);
122
+ }
123
+ catch (initError) {
124
+ // Handle "Sync already active" error (409)
125
+ if (initError instanceof ApiError && initError.statusCode === 409) {
126
+ spinner.stop();
127
+ logger.warn('A previous sync connection exists on the server.');
128
+ const { cleanup } = await inquirer.prompt([
129
+ {
130
+ type: 'confirm',
131
+ name: 'cleanup',
132
+ message: 'Clean up stale connection and retry?',
133
+ default: true,
134
+ },
135
+ ]);
136
+ if (cleanup) {
137
+ spinner.start('Cleaning up stale connection...');
138
+ await api.stopSync(sessionId);
139
+ spinner.text = 'Initializing sync...';
140
+ syncInfo = await api.initSync(sessionId);
141
+ }
142
+ else {
143
+ logger.info('Run "opencodespaces sync stop" to manually clean up.');
144
+ process.exit(0);
145
+ }
146
+ }
147
+ else {
148
+ throw initError;
149
+ }
150
+ }
120
151
  // Save private key
121
152
  const keyPath = saveSessionKey(sessionId, syncInfo.privateKey);
122
153
  spinner.text = 'Configuring SSH...';
@@ -145,7 +176,7 @@ async function startSync(sessionId, localDir) {
145
176
  'two-way-resolved',
146
177
  ...ignoreArgs,
147
178
  ];
148
- execSync(`mutagen ${mutagenArgs.join(' ')}`, { stdio: 'pipe' });
179
+ execFileSync('mutagen', mutagenArgs, { stdio: 'pipe' });
149
180
  spinner.succeed(`Syncing ${localPath} ↔ ${hostAlias}:${remotePath}`);
150
181
  logger.log('');
151
182
  logger.warn('Note: node_modules and other large directories are excluded by default.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencodespaces",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "CLI for OpenCodeSpaces - Connect your local IDE to cloud sessions",
5
5
  "type": "module",
6
6
  "bin": {