genbox 1.0.207 → 1.0.209
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/connect.js +15 -15
- package/dist/commands/provider-command.js +249 -26
- package/dist/commands/session/index.js +57 -484
- package/dist/utils/image-upload.js +248 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/interactive-prompt.js +419 -0
- package/dist/utils/ssh-proxy.js +394 -0
- package/package.json +1 -1
package/dist/commands/connect.js
CHANGED
|
@@ -42,6 +42,7 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
42
42
|
const api_1 = require("../api");
|
|
43
43
|
const genbox_selector_1 = require("../genbox-selector");
|
|
44
44
|
const ssh_config_1 = require("../ssh-config");
|
|
45
|
+
const ssh_proxy_1 = require("../utils/ssh-proxy");
|
|
45
46
|
const os = __importStar(require("os"));
|
|
46
47
|
const path = __importStar(require("path"));
|
|
47
48
|
const fs = __importStar(require("fs"));
|
|
@@ -85,14 +86,14 @@ exports.connectCommand = new commander_1.Command('connect')
|
|
|
85
86
|
(0, ssh_config_1.addSshConfigEntry)({ name: localSession.name, ipAddress: localSession.ipAddress });
|
|
86
87
|
}
|
|
87
88
|
console.log(chalk_1.default.dim(`Connecting to local VM ${chalk_1.default.bold(localSession.name)} (${localSession.ipAddress})...`));
|
|
89
|
+
console.log(chalk_1.default.dim(` Image auto-upload: ${chalk_1.default.green('enabled')} - Paste local image paths, they'll be uploaded automatically`));
|
|
88
90
|
console.log(chalk_1.default.dim(` You can also use: ssh genbox-${localSession.name}`));
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const ssh = (0, child_process_1.spawn)('ssh', sshArgs, { stdio: 'inherit' });
|
|
91
|
+
// Use SSH proxy with input interception for automatic image uploads
|
|
92
|
+
const ssh = (0, ssh_proxy_1.createSshProxy)({
|
|
93
|
+
ipAddress: localSession.ipAddress,
|
|
94
|
+
keyPath,
|
|
95
|
+
genboxName: localSession.name,
|
|
96
|
+
});
|
|
96
97
|
ssh.on('close', (code) => {
|
|
97
98
|
if (code !== 0) {
|
|
98
99
|
console.log(chalk_1.default.dim(`Connection closed with code ${code}`));
|
|
@@ -129,15 +130,14 @@ exports.connectCommand = new commander_1.Command('connect')
|
|
|
129
130
|
}
|
|
130
131
|
// 3. Get Key
|
|
131
132
|
const keyPath = getPrivateSshKey();
|
|
132
|
-
// 4. Connect
|
|
133
|
+
// 4. Connect via SSH proxy with input interception for automatic image uploads
|
|
133
134
|
console.log(chalk_1.default.dim(`Connecting to ${chalk_1.default.bold(target.name)} (${target.ipAddress})...`));
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const ssh = (0, child_process_1.spawn)('ssh', sshArgs, { stdio: 'inherit' });
|
|
135
|
+
console.log(chalk_1.default.dim(` Image auto-upload: ${chalk_1.default.green('enabled')} - Paste local image paths, they'll be uploaded automatically`));
|
|
136
|
+
const ssh = (0, ssh_proxy_1.createSshProxy)({
|
|
137
|
+
ipAddress: target.ipAddress,
|
|
138
|
+
keyPath,
|
|
139
|
+
genboxName: target.name,
|
|
140
|
+
});
|
|
141
141
|
ssh.on('close', (code) => {
|
|
142
142
|
if (code !== 0) {
|
|
143
143
|
console.log(chalk_1.default.dim(`Connection closed with code ${code}`));
|
|
@@ -58,9 +58,11 @@ const select_1 = __importDefault(require("@inquirer/select"));
|
|
|
58
58
|
const prompts_1 = require("@inquirer/prompts");
|
|
59
59
|
const api_1 = require("../api");
|
|
60
60
|
const ssh_keys_1 = require("../utils/ssh-keys");
|
|
61
|
+
const ssh_proxy_1 = require("../utils/ssh-proxy");
|
|
61
62
|
const unified_session_1 = require("../lib/unified-session");
|
|
62
63
|
const genbox_progress_1 = require("../lib/genbox-progress");
|
|
63
64
|
const genbox_wizard_1 = require("../lib/genbox-wizard");
|
|
65
|
+
const interactive_prompt_1 = require("../utils/interactive-prompt");
|
|
64
66
|
const child_process_1 = require("child_process");
|
|
65
67
|
const os = __importStar(require("os"));
|
|
66
68
|
const path = __importStar(require("path"));
|
|
@@ -441,7 +443,8 @@ async function startLocalMultipass(genbox) {
|
|
|
441
443
|
/**
|
|
442
444
|
* Create and attach to a session on a genbox
|
|
443
445
|
*/
|
|
444
|
-
async function startSessionOnGenbox(provider, genbox) {
|
|
446
|
+
async function startSessionOnGenbox(provider, genbox, options = {}) {
|
|
447
|
+
const { initialPrompt } = options;
|
|
445
448
|
let targetGenbox = genbox;
|
|
446
449
|
let sshTarget;
|
|
447
450
|
let sshPortArgs = [];
|
|
@@ -481,6 +484,8 @@ async function startSessionOnGenbox(provider, genbox) {
|
|
|
481
484
|
}
|
|
482
485
|
const keyPath = requireSshKey();
|
|
483
486
|
const sessionName = `${provider}-${Date.now().toString(36)}`;
|
|
487
|
+
// Always start CLI without prompt - we'll inject it after attaching
|
|
488
|
+
// This keeps the session interactive instead of one-shot mode
|
|
484
489
|
const cliCommand = provider === 'claude'
|
|
485
490
|
? 'claude --dangerously-skip-permissions'
|
|
486
491
|
: provider === 'gemini'
|
|
@@ -587,19 +592,23 @@ exec ${cliCommand}
|
|
|
587
592
|
// Wait for session to start
|
|
588
593
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
589
594
|
console.log(chalk_1.default.green(`Session created: ${sessionName}`));
|
|
595
|
+
console.log(chalk_1.default.dim(`Image auto-upload: ${chalk_1.default.green('enabled')} - Paste local image paths, they'll be uploaded automatically`));
|
|
590
596
|
console.log(chalk_1.default.dim('Tip: Detach with Ctrl+\\\n'));
|
|
591
|
-
// Attach to session
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
'
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
597
|
+
// Attach to session using SSH proxy with image path interception
|
|
598
|
+
// Extract IP address from sshTarget (format: dev@IP or dev@localhost)
|
|
599
|
+
const attachIpAddress = sshTarget.split('@')[1];
|
|
600
|
+
// Get port from sshPortArgs if it's a Docker container
|
|
601
|
+
const sshPort = sshPortArgs.length >= 2 ? parseInt(sshPortArgs[1], 10) : undefined;
|
|
602
|
+
const proc = (0, ssh_proxy_1.attachWithProxy)({
|
|
603
|
+
ipAddress: attachIpAddress === 'localhost' ? '127.0.0.1' : attachIpAddress,
|
|
604
|
+
keyPath,
|
|
605
|
+
genboxName: targetGenbox.name,
|
|
606
|
+
socketPath,
|
|
607
|
+
user: 'dev',
|
|
608
|
+
port: sshPort,
|
|
609
|
+
verbose: true,
|
|
610
|
+
initialPrompt, // Inject prompt after connection
|
|
611
|
+
});
|
|
603
612
|
await new Promise(resolve => proc.on('close', () => resolve()));
|
|
604
613
|
console.log(chalk_1.default.dim('\nDetached from session.'));
|
|
605
614
|
console.log(chalk_1.default.dim(`Reattach with: ${chalk_1.default.cyan(`gb ${provider} --attach ${sessionName}`)}`));
|
|
@@ -618,22 +627,20 @@ async function attachToSession(session) {
|
|
|
618
627
|
console.log(chalk_1.default.dim('\nDetached from session.'));
|
|
619
628
|
}
|
|
620
629
|
else {
|
|
621
|
-
// Cloud genbox session
|
|
630
|
+
// Cloud genbox session - use SSH proxy with image path interception
|
|
622
631
|
const keyPath = requireSshKey();
|
|
623
632
|
const remoteSocketDir = getRemoteDtachSocketDir();
|
|
624
633
|
const socketPath = `${remoteSocketDir}/${session.name}.sock`;
|
|
625
634
|
console.log(chalk_1.default.dim(`\nAttaching to ${session.name} on ${session.genboxName}...`));
|
|
635
|
+
console.log(chalk_1.default.dim(`Image auto-upload: ${chalk_1.default.green('enabled')} - Paste local image paths, they'll be uploaded automatically`));
|
|
626
636
|
console.log(chalk_1.default.dim('Tip: Detach with Ctrl+\\\n'));
|
|
627
|
-
const
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
`dtach -a ${socketPath}`,
|
|
635
|
-
];
|
|
636
|
-
const proc = (0, child_process_1.spawn)('ssh', sshArgs, { stdio: 'inherit' });
|
|
637
|
+
const proc = (0, ssh_proxy_1.attachWithProxy)({
|
|
638
|
+
ipAddress: session.ipAddress,
|
|
639
|
+
keyPath,
|
|
640
|
+
genboxName: session.genboxName,
|
|
641
|
+
socketPath,
|
|
642
|
+
user: 'dev',
|
|
643
|
+
});
|
|
637
644
|
await new Promise(resolve => proc.on('close', () => resolve()));
|
|
638
645
|
console.log(chalk_1.default.dim('\nDetached from session.'));
|
|
639
646
|
}
|
|
@@ -675,7 +682,8 @@ async function killSession(session) {
|
|
|
675
682
|
/**
|
|
676
683
|
* Start a direct (no isolation) session
|
|
677
684
|
*/
|
|
678
|
-
async function startDirectSession(provider) {
|
|
685
|
+
async function startDirectSession(provider, options = {}) {
|
|
686
|
+
const { initialPrompt } = options;
|
|
679
687
|
// Check for dtach
|
|
680
688
|
const dtachStatus = await ensureLocalDtach();
|
|
681
689
|
if (dtachStatus === 'cancel') {
|
|
@@ -693,6 +701,7 @@ async function startDirectSession(provider) {
|
|
|
693
701
|
syncEnabled: false, // Local-first: no API sync by default
|
|
694
702
|
});
|
|
695
703
|
const sessionName = session.name;
|
|
704
|
+
// Always start CLI without prompt - inject after connection
|
|
696
705
|
const cliCommand = provider === 'claude'
|
|
697
706
|
? 'claude --dangerously-skip-permissions'
|
|
698
707
|
: provider === 'gemini'
|
|
@@ -722,7 +731,39 @@ async function startDirectSession(provider) {
|
|
|
722
731
|
}
|
|
723
732
|
// Mark session as running
|
|
724
733
|
await sessionManager.markRunning(session.id);
|
|
725
|
-
|
|
734
|
+
// For direct mode, we need to pipe stdin to inject the prompt
|
|
735
|
+
const proc = (0, child_process_1.spawn)('bash', ['-c', cmd], {
|
|
736
|
+
stdio: initialPrompt ? ['pipe', 'inherit', 'inherit'] : 'inherit',
|
|
737
|
+
});
|
|
738
|
+
// Inject initial prompt after CLI is ready
|
|
739
|
+
if (initialPrompt && proc.stdin) {
|
|
740
|
+
setTimeout(() => {
|
|
741
|
+
if (proc.stdin && !proc.killed) {
|
|
742
|
+
// Send prompt character by character with slower typing
|
|
743
|
+
const chars = initialPrompt.split('');
|
|
744
|
+
let i = 0;
|
|
745
|
+
const typeChar = () => {
|
|
746
|
+
if (i < chars.length && proc.stdin && !proc.killed) {
|
|
747
|
+
proc.stdin.write(chars[i]);
|
|
748
|
+
i++;
|
|
749
|
+
setTimeout(typeChar, 15); // 15ms between chars (slower, more reliable)
|
|
750
|
+
}
|
|
751
|
+
else if (proc.stdin && !proc.killed) {
|
|
752
|
+
// All chars sent, press Enter, then pipe user input
|
|
753
|
+
setTimeout(() => {
|
|
754
|
+
proc.stdin?.write('\r');
|
|
755
|
+
// Continue piping user input after prompt is sent
|
|
756
|
+
setTimeout(() => {
|
|
757
|
+
process.stdin.pipe(proc.stdin);
|
|
758
|
+
process.stdin.resume();
|
|
759
|
+
}, 200);
|
|
760
|
+
}, 100);
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
typeChar();
|
|
764
|
+
}
|
|
765
|
+
}, 3000); // 3 second delay for local sessions
|
|
766
|
+
}
|
|
726
767
|
await new Promise((resolve) => {
|
|
727
768
|
proc.on('close', () => {
|
|
728
769
|
if (useDtach && fs.existsSync(socketPath)) {
|
|
@@ -892,6 +933,179 @@ async function runInteractiveFlow(provider) {
|
|
|
892
933
|
break;
|
|
893
934
|
}
|
|
894
935
|
}
|
|
936
|
+
/**
|
|
937
|
+
* Interactive prompt mode flow (-p flag)
|
|
938
|
+
*
|
|
939
|
+
* This flow:
|
|
940
|
+
* 1. Collects multiline prompt (inline or via $EDITOR with -e)
|
|
941
|
+
* 2. Collects image paths (optional)
|
|
942
|
+
* 3. Shows target selection (genbox vs direct)
|
|
943
|
+
* 4. Uploads images to genbox if needed (waits for genbox to be ready)
|
|
944
|
+
* 5. Starts session with the composed prompt
|
|
945
|
+
*/
|
|
946
|
+
async function runPromptModeFlow(provider, options = {}) {
|
|
947
|
+
const { useEditor = false } = options;
|
|
948
|
+
console.log(chalk_1.default.bold(`\n${provider.charAt(0).toUpperCase() + provider.slice(1)} - Interactive Prompt Mode`));
|
|
949
|
+
if (useEditor) {
|
|
950
|
+
console.log(chalk_1.default.dim('Compose your prompt in $EDITOR with optional images\n'));
|
|
951
|
+
}
|
|
952
|
+
else {
|
|
953
|
+
console.log(chalk_1.default.dim('Compose your prompt with optional images\n'));
|
|
954
|
+
}
|
|
955
|
+
// Step 1: Collect prompt and images
|
|
956
|
+
const collected = await (0, interactive_prompt_1.collectPromptWithImages)({ useEditor });
|
|
957
|
+
if (!collected) {
|
|
958
|
+
console.log(chalk_1.default.dim('\nCancelled.'));
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
const { text, images } = collected;
|
|
962
|
+
// Show what was collected
|
|
963
|
+
console.log(chalk_1.default.dim(`\nPrompt: ${text.substring(0, 50)}${text.length > 50 ? '...' : ''}`));
|
|
964
|
+
if (images.length > 0) {
|
|
965
|
+
console.log(chalk_1.default.dim(`Images: ${images.length} file(s)`));
|
|
966
|
+
}
|
|
967
|
+
// Step 2: Select target (simplified menu since we have a specific prompt)
|
|
968
|
+
console.log(chalk_1.default.dim('\nFetching genboxes...'));
|
|
969
|
+
const genboxes = await getGenboxes(true);
|
|
970
|
+
const targetChoices = [];
|
|
971
|
+
// Running genboxes first (can upload immediately)
|
|
972
|
+
const runningGenboxes = genboxes.filter(g => g.status === 'running' && g.ipAddress);
|
|
973
|
+
const stoppedGenboxes = genboxes.filter(g => g.status === 'stopped');
|
|
974
|
+
if (runningGenboxes.length > 0) {
|
|
975
|
+
for (const g of runningGenboxes) {
|
|
976
|
+
const localLabel = g._isLocal ? chalk_1.default.yellow(' (local)') : '';
|
|
977
|
+
targetChoices.push({
|
|
978
|
+
name: `${chalk_1.default.green('●')} ${g.name}${localLabel} ${chalk_1.default.dim('- ready, can upload immediately')}`,
|
|
979
|
+
value: { type: 'genbox', genbox: g },
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
if (stoppedGenboxes.length > 0) {
|
|
984
|
+
for (const g of stoppedGenboxes) {
|
|
985
|
+
const localLabel = g._isLocal ? chalk_1.default.yellow(' (local)') : '';
|
|
986
|
+
targetChoices.push({
|
|
987
|
+
name: `${chalk_1.default.yellow('○')} ${g.name}${localLabel} ${chalk_1.default.dim('- will start, then upload')}`,
|
|
988
|
+
value: { type: 'genbox', genbox: g },
|
|
989
|
+
});
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
// Create new option
|
|
993
|
+
targetChoices.push({
|
|
994
|
+
name: chalk_1.default.dim('─────────────────────────────────────'),
|
|
995
|
+
value: { type: 'cancel' },
|
|
996
|
+
disabled: true,
|
|
997
|
+
});
|
|
998
|
+
targetChoices.push({
|
|
999
|
+
name: chalk_1.default.green('+') + ' Create new Genbox ' + chalk_1.default.dim('(will upload after creation)'),
|
|
1000
|
+
value: { type: 'create-genbox' },
|
|
1001
|
+
});
|
|
1002
|
+
// Direct option (no upload needed)
|
|
1003
|
+
if (images.length > 0) {
|
|
1004
|
+
targetChoices.push({
|
|
1005
|
+
name: chalk_1.default.dim(' Run directly (images stay local)'),
|
|
1006
|
+
value: { type: 'direct' },
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
else {
|
|
1010
|
+
targetChoices.push({
|
|
1011
|
+
name: chalk_1.default.dim(' Run directly on this machine'),
|
|
1012
|
+
value: { type: 'direct' },
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
targetChoices.push({
|
|
1016
|
+
name: chalk_1.default.dim(' Cancel'),
|
|
1017
|
+
value: { type: 'cancel' },
|
|
1018
|
+
});
|
|
1019
|
+
let targetAction;
|
|
1020
|
+
try {
|
|
1021
|
+
targetAction = await (0, select_1.default)({
|
|
1022
|
+
message: 'Where should this run?',
|
|
1023
|
+
choices: targetChoices.filter(c => !c.disabled),
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
catch {
|
|
1027
|
+
console.log(chalk_1.default.dim('\nCancelled.'));
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
// Step 3: Handle based on target
|
|
1031
|
+
switch (targetAction.type) {
|
|
1032
|
+
case 'genbox': {
|
|
1033
|
+
const genbox = targetAction.genbox;
|
|
1034
|
+
let finalPrompt;
|
|
1035
|
+
if (images.length > 0) {
|
|
1036
|
+
// Upload images to genbox (waits for ready if needed)
|
|
1037
|
+
const uploadResult = await (0, interactive_prompt_1.uploadImagesToGenbox)(images, genbox, {
|
|
1038
|
+
showProgress: true,
|
|
1039
|
+
waitForReady: true,
|
|
1040
|
+
});
|
|
1041
|
+
if (uploadResult.errors.length > 0 && uploadResult.remotePaths.length === 0) {
|
|
1042
|
+
console.log(chalk_1.default.yellow('\nWarning: Could not upload images. Proceeding with prompt only.'));
|
|
1043
|
+
finalPrompt = text;
|
|
1044
|
+
}
|
|
1045
|
+
else {
|
|
1046
|
+
if (uploadResult.errors.length > 0) {
|
|
1047
|
+
console.log(chalk_1.default.yellow(`\nWarning: ${uploadResult.errors.length} image(s) failed to upload.`));
|
|
1048
|
+
}
|
|
1049
|
+
finalPrompt = (0, interactive_prompt_1.buildPromptWithImages)(text, uploadResult.remotePaths, { isRemote: true });
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
else {
|
|
1053
|
+
finalPrompt = text;
|
|
1054
|
+
}
|
|
1055
|
+
// Start session with prompt
|
|
1056
|
+
await startSessionOnGenbox(provider, genbox, { initialPrompt: finalPrompt });
|
|
1057
|
+
break;
|
|
1058
|
+
}
|
|
1059
|
+
case 'create-genbox': {
|
|
1060
|
+
// Use wizard to create genbox
|
|
1061
|
+
const result = await (0, genbox_wizard_1.runCreateWizard)({
|
|
1062
|
+
provider,
|
|
1063
|
+
includeDirect: false,
|
|
1064
|
+
});
|
|
1065
|
+
if (!result.success || !result.genbox) {
|
|
1066
|
+
console.log(chalk_1.default.dim('\nGenbox creation cancelled or failed.'));
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
const genbox = result.genbox;
|
|
1070
|
+
let finalPrompt;
|
|
1071
|
+
if (images.length > 0) {
|
|
1072
|
+
// Upload images to newly created genbox
|
|
1073
|
+
const uploadResult = await (0, interactive_prompt_1.uploadImagesToGenbox)(images, genbox, {
|
|
1074
|
+
showProgress: true,
|
|
1075
|
+
waitForReady: true, // Wizard already waits, but just in case
|
|
1076
|
+
});
|
|
1077
|
+
if (uploadResult.remotePaths.length > 0) {
|
|
1078
|
+
finalPrompt = (0, interactive_prompt_1.buildPromptWithImages)(text, uploadResult.remotePaths, { isRemote: true });
|
|
1079
|
+
}
|
|
1080
|
+
else {
|
|
1081
|
+
console.log(chalk_1.default.yellow('\nWarning: Could not upload images. Proceeding with prompt only.'));
|
|
1082
|
+
finalPrompt = text;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
else {
|
|
1086
|
+
finalPrompt = text;
|
|
1087
|
+
}
|
|
1088
|
+
await startSessionOnGenbox(provider, genbox, { initialPrompt: finalPrompt });
|
|
1089
|
+
break;
|
|
1090
|
+
}
|
|
1091
|
+
case 'direct': {
|
|
1092
|
+
const proceed = await showDirectModeWarning();
|
|
1093
|
+
if (!proceed) {
|
|
1094
|
+
console.log(chalk_1.default.dim('\nCancelled.'));
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
// Direct mode: use local paths
|
|
1098
|
+
const finalPrompt = images.length > 0
|
|
1099
|
+
? (0, interactive_prompt_1.buildPromptWithImages)(text, images, { isRemote: false })
|
|
1100
|
+
: text;
|
|
1101
|
+
await startDirectSession(provider, { initialPrompt: finalPrompt });
|
|
1102
|
+
break;
|
|
1103
|
+
}
|
|
1104
|
+
case 'cancel':
|
|
1105
|
+
console.log(chalk_1.default.dim('\nCancelled.'));
|
|
1106
|
+
break;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
895
1109
|
/**
|
|
896
1110
|
* Create list subcommand for a provider
|
|
897
1111
|
*/
|
|
@@ -1194,9 +1408,13 @@ function createProviderCommand(provider) {
|
|
|
1194
1408
|
.option('--on <genbox>', 'Use specific genbox')
|
|
1195
1409
|
.option('--direct', 'Run directly on this machine (no isolation)')
|
|
1196
1410
|
.option('-y, --yes', 'Skip confirmations')
|
|
1411
|
+
.option('-p, --prompt-mode', 'Interactive prompt mode: compose prompt with optional images')
|
|
1412
|
+
.option('-e, --editor', 'Use $EDITOR for prompt input (with -p)')
|
|
1197
1413
|
.addHelpText('after', `
|
|
1198
1414
|
Examples:
|
|
1199
1415
|
gb ${provider} Interactive mode
|
|
1416
|
+
gb ${provider} -p Prompt mode: inline multiline input
|
|
1417
|
+
gb ${provider} -p -e Prompt mode: open $EDITOR for input
|
|
1200
1418
|
gb ${provider} list List all ${provider} sessions
|
|
1201
1419
|
gb ${provider} attach [session] Attach to a session
|
|
1202
1420
|
gb ${provider} stop [session] Stop a session
|
|
@@ -1207,6 +1425,11 @@ Examples:
|
|
|
1207
1425
|
`)
|
|
1208
1426
|
.action(async (options) => {
|
|
1209
1427
|
try {
|
|
1428
|
+
// -p / --prompt-mode: Interactive prompt with optional images
|
|
1429
|
+
if (options.promptMode) {
|
|
1430
|
+
await runPromptModeFlow(provider, { useEditor: options.editor });
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1210
1433
|
// --on: Use specific genbox
|
|
1211
1434
|
if (options.on) {
|
|
1212
1435
|
const genboxes = await getGenboxes();
|