genbox 1.0.164 → 1.0.165
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.
- package/dist/commands/attach.js +55 -33
- package/package.json +1 -1
package/dist/commands/attach.js
CHANGED
|
@@ -153,18 +153,48 @@ function extractLocalImagePath(text) {
|
|
|
153
153
|
}
|
|
154
154
|
return { path: null };
|
|
155
155
|
}
|
|
156
|
+
// SSH ControlMaster for faster subsequent connections
|
|
157
|
+
function getControlPath(ipAddress) {
|
|
158
|
+
return `/tmp/genbox-ssh-${ipAddress}`;
|
|
159
|
+
}
|
|
160
|
+
function setupSshMultiplexing(ipAddress, keyPath) {
|
|
161
|
+
const controlPath = getControlPath(ipAddress);
|
|
162
|
+
// Check if master connection already exists
|
|
163
|
+
const checkResult = (0, child_process_1.spawnSync)('ssh', [
|
|
164
|
+
'-O', 'check',
|
|
165
|
+
'-o', `ControlPath=${controlPath}`,
|
|
166
|
+
`dev@${ipAddress}`
|
|
167
|
+
], { stdio: 'ignore' });
|
|
168
|
+
if (checkResult.status === 0) {
|
|
169
|
+
return; // Already connected
|
|
170
|
+
}
|
|
171
|
+
// Start master connection in background
|
|
172
|
+
(0, child_process_1.spawn)('ssh', [
|
|
173
|
+
'-i', keyPath,
|
|
174
|
+
'-o', 'StrictHostKeyChecking=no',
|
|
175
|
+
'-o', 'UserKnownHostsFile=/dev/null',
|
|
176
|
+
'-o', 'ControlMaster=yes',
|
|
177
|
+
'-o', `ControlPath=${controlPath}`,
|
|
178
|
+
'-o', 'ControlPersist=10m',
|
|
179
|
+
'-fN', // Background, no command
|
|
180
|
+
`dev@${ipAddress}`
|
|
181
|
+
], { stdio: 'ignore', detached: true });
|
|
182
|
+
}
|
|
156
183
|
function uploadFileSync(localPath, ipAddress, keyPath) {
|
|
157
184
|
const fileName = path.basename(localPath);
|
|
158
185
|
const timestamp = Date.now();
|
|
159
186
|
const remotePath = `/home/dev/uploads/${timestamp}-${fileName}`;
|
|
187
|
+
const controlPath = getControlPath(ipAddress);
|
|
160
188
|
try {
|
|
161
|
-
// Ensure uploads directory exists
|
|
162
|
-
(0, child_process_1.execSync)(`ssh -i "${keyPath}" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dev@${ipAddress} "mkdir -p /home/dev/uploads" 2>/dev/null`, { encoding: 'utf-8', timeout: 10000 });
|
|
163
|
-
// Upload file
|
|
189
|
+
// Ensure uploads directory exists (uses multiplexed connection if available)
|
|
190
|
+
(0, child_process_1.execSync)(`ssh -i "${keyPath}" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ControlPath=${controlPath} dev@${ipAddress} "mkdir -p /home/dev/uploads" 2>/dev/null`, { encoding: 'utf-8', timeout: 10000 });
|
|
191
|
+
// Upload file with compression and multiplexing
|
|
164
192
|
const result = (0, child_process_1.spawnSync)('scp', [
|
|
165
193
|
'-i', keyPath,
|
|
166
194
|
'-o', 'StrictHostKeyChecking=no',
|
|
167
195
|
'-o', 'UserKnownHostsFile=/dev/null',
|
|
196
|
+
'-o', `ControlPath=${controlPath}`,
|
|
197
|
+
'-C', // Enable compression
|
|
168
198
|
localPath,
|
|
169
199
|
`dev@${ipAddress}:${remotePath}`
|
|
170
200
|
], { timeout: 60000 });
|
|
@@ -177,6 +207,17 @@ function uploadFileSync(localPath, ipAddress, keyPath) {
|
|
|
177
207
|
return { success: false, remotePath: '', error: error.message };
|
|
178
208
|
}
|
|
179
209
|
}
|
|
210
|
+
// Show message in tmux status bar
|
|
211
|
+
function showTmuxMessage(ipAddress, keyPath, sessionName, message) {
|
|
212
|
+
const controlPath = getControlPath(ipAddress);
|
|
213
|
+
try {
|
|
214
|
+
// Send message to tmux session's status bar
|
|
215
|
+
(0, child_process_1.execSync)(`ssh -i "${keyPath}" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ControlPath=${controlPath} dev@${ipAddress} "tmux display-message -t ${sessionName} -d 3000 '${message.replace(/'/g, "\\'")}'" 2>/dev/null`, { encoding: 'utf-8', timeout: 5000 });
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
// Fallback to macOS notification if tmux message fails
|
|
219
|
+
}
|
|
220
|
+
}
|
|
180
221
|
function getPrivateSshKey() {
|
|
181
222
|
const home = os.homedir();
|
|
182
223
|
const potentialKeys = [
|
|
@@ -450,8 +491,10 @@ async function attachToSession(ipAddress, keyPath, sessionName, genboxName) {
|
|
|
450
491
|
console.log(chalk_1.default.dim(`\nAttaching to ${chalk_1.default.bold(sessionName)} on ${chalk_1.default.bold(genboxName)}...`));
|
|
451
492
|
console.log(chalk_1.default.dim('Detach: Ctrl+b d'));
|
|
452
493
|
console.log('');
|
|
453
|
-
console.log(chalk_1.default.yellow('📋 Image Upload Active') + chalk_1.default.dim(' -
|
|
454
|
-
console.log(chalk_1.default.dim('
|
|
494
|
+
console.log(chalk_1.default.yellow('📋 Image Upload Active') + chalk_1.default.dim(' - Cmd+C image file → wait for tmux message → Cmd+V'));
|
|
495
|
+
console.log(chalk_1.default.dim(' Setting up fast upload connection...\n'));
|
|
496
|
+
// Set up SSH multiplexing for faster uploads
|
|
497
|
+
setupSshMultiplexing(ipAddress, keyPath);
|
|
455
498
|
const sshArgs = [
|
|
456
499
|
'-t',
|
|
457
500
|
'-i', keyPath,
|
|
@@ -480,13 +523,7 @@ async function attachToSession(ipAddress, keyPath, sessionName, genboxName) {
|
|
|
480
523
|
// If file path was detected but file doesn't exist (e.g., macOS temp file was cleaned up)
|
|
481
524
|
if (extractResult.notFound) {
|
|
482
525
|
const fileName = path.basename(extractResult.notFound);
|
|
483
|
-
|
|
484
|
-
if (os.platform() === 'darwin') {
|
|
485
|
-
try {
|
|
486
|
-
(0, child_process_1.execSync)(`osascript -e 'display notification "File not found: ${fileName.replace(/'/g, "\\'")}" with title "Genbox" sound name "Basso"'`, { stdio: 'ignore' });
|
|
487
|
-
}
|
|
488
|
-
catch { }
|
|
489
|
-
}
|
|
526
|
+
showTmuxMessage(ipAddress, keyPath, sessionName, '⚠ File not found: ' + fileName.substring(0, 30));
|
|
490
527
|
return;
|
|
491
528
|
}
|
|
492
529
|
if (!extractResult.path) {
|
|
@@ -497,13 +534,8 @@ async function attachToSession(ipAddress, keyPath, sessionName, genboxName) {
|
|
|
497
534
|
if (uploadedPaths.has(localPath)) {
|
|
498
535
|
return;
|
|
499
536
|
}
|
|
500
|
-
// Show uploading
|
|
501
|
-
|
|
502
|
-
try {
|
|
503
|
-
(0, child_process_1.execSync)(`osascript -e 'display notification "Uploading to genbox..." with title "📤 Image Detected"'`, { stdio: 'ignore' });
|
|
504
|
-
}
|
|
505
|
-
catch { }
|
|
506
|
-
}
|
|
537
|
+
// Show uploading message in tmux
|
|
538
|
+
showTmuxMessage(ipAddress, keyPath, sessionName, '📤 Uploading image... please wait');
|
|
507
539
|
// Upload the file (this happens in background, might cause brief pause)
|
|
508
540
|
const result = uploadFileSync(localPath, ipAddress, keyPath);
|
|
509
541
|
if (result.success) {
|
|
@@ -511,22 +543,12 @@ async function attachToSession(ipAddress, keyPath, sessionName, genboxName) {
|
|
|
511
543
|
uploadedPaths.add(result.remotePath); // Also track remote path to avoid re-detection
|
|
512
544
|
// Replace clipboard with remote path
|
|
513
545
|
setClipboard(result.remotePath);
|
|
514
|
-
//
|
|
515
|
-
|
|
516
|
-
try {
|
|
517
|
-
(0, child_process_1.execSync)(`osascript -e 'display notification "Copied to clipboard! Cmd+V to paste." with title "✓ Uploaded" sound name "Glass"'`, { stdio: 'ignore' });
|
|
518
|
-
}
|
|
519
|
-
catch { }
|
|
520
|
-
}
|
|
546
|
+
// Show success in tmux
|
|
547
|
+
showTmuxMessage(ipAddress, keyPath, sessionName, '✓ Image ready! Press Cmd+V to paste');
|
|
521
548
|
}
|
|
522
549
|
else {
|
|
523
|
-
//
|
|
524
|
-
|
|
525
|
-
try {
|
|
526
|
-
(0, child_process_1.execSync)(`osascript -e 'display notification "Upload failed: ${(result.error || 'unknown').replace(/'/g, "\\'")}" with title "Genbox" sound name "Basso"'`, { stdio: 'ignore' });
|
|
527
|
-
}
|
|
528
|
-
catch { }
|
|
529
|
-
}
|
|
550
|
+
// Show failure in tmux
|
|
551
|
+
showTmuxMessage(ipAddress, keyPath, sessionName, '✗ Upload failed: ' + (result.error || 'unknown'));
|
|
530
552
|
}
|
|
531
553
|
}
|
|
532
554
|
catch {
|