genbox 1.0.141 → 1.0.142

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.
@@ -45,6 +45,7 @@ const child_process_1 = require("child_process");
45
45
  const os = __importStar(require("os"));
46
46
  const path = __importStar(require("path"));
47
47
  const fs = __importStar(require("fs"));
48
+ const inquirer_1 = __importDefault(require("inquirer"));
48
49
  function getPrivateSshKey() {
49
50
  const home = os.homedir();
50
51
  const potentialKeys = [
@@ -85,13 +86,40 @@ set -g window-status-format ' #W '
85
86
  `.trim();
86
87
  async function listTmuxSessions(ipAddress, keyPath) {
87
88
  try {
88
- const result = (0, child_process_1.execSync)(`ssh -i "${keyPath}" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dev@${ipAddress} "tmux list-sessions -F '#{session_name}'" 2>/dev/null`, { encoding: 'utf-8' });
89
- return result.trim().split('\n').filter(s => s.length > 0);
89
+ const result = (0, child_process_1.execSync)(`ssh -i "${keyPath}" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dev@${ipAddress} "tmux list-sessions -F '#{session_name}|#{session_windows}|#{session_created}|#{session_attached}'" 2>/dev/null`, { encoding: 'utf-8' });
90
+ return result.trim().split('\n').filter(s => s.length > 0).map(line => {
91
+ const [name, windows, created, attached] = line.split('|');
92
+ return {
93
+ name,
94
+ windows: parseInt(windows) || 1,
95
+ created: new Date(parseInt(created) * 1000).toLocaleTimeString(),
96
+ attached: attached === '1',
97
+ };
98
+ });
90
99
  }
91
100
  catch {
92
101
  return [];
93
102
  }
94
103
  }
104
+ async function selectSession(sessions) {
105
+ const choices = sessions.map(s => ({
106
+ name: `${s.name}${s.attached ? chalk_1.default.green(' (attached)') : ''} ${chalk_1.default.dim(`- ${s.windows} window(s), started ${s.created}`)}`,
107
+ value: s.name,
108
+ }));
109
+ choices.push({
110
+ name: chalk_1.default.dim('Cancel'),
111
+ value: '__cancel__',
112
+ });
113
+ const { session } = await inquirer_1.default.prompt([
114
+ {
115
+ type: 'list',
116
+ name: 'session',
117
+ message: 'Select a session to attach:',
118
+ choices,
119
+ },
120
+ ]);
121
+ return session === '__cancel__' ? null : session;
122
+ }
95
123
  async function ensureTmuxConfig(ipAddress, keyPath) {
96
124
  const configPath = '/home/dev/.tmux.conf';
97
125
  const marker = '# GENBOX_BRANDED_CONFIG';
@@ -116,12 +144,11 @@ GENBOX_TMUX_EOF`, { encoding: 'utf-8' });
116
144
  exports.attachCommand = new commander_1.Command('attach')
117
145
  .description('Attach to an active Claude/AI session in a Genbox')
118
146
  .argument('[name]', 'Name of the Genbox (optional - will prompt if not provided)')
119
- .option('-s, --session <session>', 'Tmux session name to attach to')
147
+ .option('-s, --session <session>', 'Tmux session name to attach to directly')
120
148
  .option('-a, --all', 'Select from all genboxes (not just current project)')
121
- .option('-l, --list', 'List available sessions without attaching')
122
149
  .action(async (name, options) => {
123
150
  try {
124
- // 1. Select Genbox
151
+ // 1. Select Genbox (interactive if no name provided)
125
152
  const { genbox: target, cancelled } = await (0, genbox_selector_1.selectGenbox)(name, {
126
153
  all: options.all,
127
154
  selectMessage: 'Select a genbox to attach to:',
@@ -140,45 +167,48 @@ exports.attachCommand = new commander_1.Command('attach')
140
167
  // 2. Get SSH key
141
168
  const keyPath = getPrivateSshKey();
142
169
  // 3. List available tmux sessions
170
+ console.log(chalk_1.default.dim(`Checking sessions on ${target.name}...`));
143
171
  const sessions = await listTmuxSessions(target.ipAddress, keyPath);
144
172
  if (sessions.length === 0) {
145
- console.log(chalk_1.default.yellow('No active sessions found.'));
146
- console.log(chalk_1.default.dim('Start a new Claude session with: gb run-prompt <genbox>'));
147
- return;
148
- }
149
- if (options.list) {
150
- console.log(chalk_1.default.bold(`\nActive sessions in ${target.name}:\n`));
151
- for (const session of sessions) {
152
- console.log(` ${chalk_1.default.cyan('•')} ${session}`);
153
- }
154
- console.log('');
155
- console.log(chalk_1.default.dim(`Attach with: gb attach ${target.name} -s <session>`));
173
+ console.log(chalk_1.default.yellow('\nNo active sessions found.'));
174
+ console.log(chalk_1.default.dim('Start a new Claude session with: gb run-prompt ' + target.name));
156
175
  return;
157
176
  }
158
177
  // 4. Determine which session to attach to
159
178
  let sessionName = options.session;
160
179
  if (!sessionName) {
161
- // Default to claude-session if it exists, otherwise first session
162
- if (sessions.includes('claude-session')) {
163
- sessionName = 'claude-session';
180
+ if (sessions.length === 1) {
181
+ // Only one session - attach directly
182
+ sessionName = sessions[0].name;
183
+ console.log(chalk_1.default.dim(`Found session: ${sessionName}`));
164
184
  }
165
185
  else {
166
- sessionName = sessions[0];
186
+ // Multiple sessions - show interactive picker
187
+ console.log('');
188
+ sessionName = await selectSession(sessions);
189
+ if (!sessionName) {
190
+ console.log(chalk_1.default.dim('Cancelled.'));
191
+ return;
192
+ }
167
193
  }
168
194
  }
169
- if (!sessions.includes(sessionName)) {
170
- console.error(chalk_1.default.red(`Session '${sessionName}' not found.`));
171
- console.log(chalk_1.default.dim('Available sessions:'));
172
- for (const s of sessions) {
173
- console.log(` ${chalk_1.default.cyan('•')} ${s}`);
195
+ else {
196
+ // Validate the provided session name
197
+ const sessionNames = sessions.map(s => s.name);
198
+ if (!sessionNames.includes(sessionName)) {
199
+ console.error(chalk_1.default.red(`\nSession '${sessionName}' not found.`));
200
+ console.log(chalk_1.default.dim('Available sessions:'));
201
+ for (const s of sessions) {
202
+ console.log(` ${chalk_1.default.cyan('•')} ${s.name}`);
203
+ }
204
+ return;
174
205
  }
175
- return;
176
206
  }
177
207
  // 5. Ensure tmux is configured with branding
178
208
  console.log(chalk_1.default.dim(`Setting up terminal...`));
179
209
  await ensureTmuxConfig(target.ipAddress, keyPath);
180
210
  // 6. Attach to session
181
- console.log(chalk_1.default.dim(`Attaching to ${chalk_1.default.bold(sessionName)} on ${chalk_1.default.bold(target.name)}...`));
211
+ console.log(chalk_1.default.dim(`\nAttaching to ${chalk_1.default.bold(sessionName)} on ${chalk_1.default.bold(target.name)}...`));
182
212
  console.log(chalk_1.default.dim('Tip: Scroll with mouse wheel, detach with Ctrl+b d\n'));
183
213
  const sshArgs = [
184
214
  '-t', // Force pseudo-terminal allocation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genbox",
3
- "version": "1.0.141",
3
+ "version": "1.0.142",
4
4
  "description": "Genbox CLI - AI-Powered Development Environments",
5
5
  "main": "dist/index.js",
6
6
  "bin": {