genbox 1.0.213 → 1.0.215

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.
@@ -97,6 +97,61 @@ async function fetchLiveState(sessionId) {
97
97
  return null;
98
98
  }
99
99
  }
100
+ /**
101
+ * Fetch sessions for a specific genbox from API
102
+ * Queries both ClaudeSession (monitoring) and Session (sync) collections
103
+ */
104
+ async function fetchGenboxSessions(genboxId) {
105
+ const allSessions = [];
106
+ try {
107
+ // Try ClaudeSession (monitoring) first
108
+ const claudeSessions = await (0, api_1.fetchApi)(`/claude/sessions/genbox/${genboxId}`);
109
+ if (Array.isArray(claudeSessions)) {
110
+ allSessions.push(...claudeSessions);
111
+ }
112
+ }
113
+ catch {
114
+ // Ignore errors
115
+ }
116
+ try {
117
+ // Also query Session (sync) collection
118
+ const sessions = await (0, api_1.fetchApi)(`/sessions/v2?limit=50`);
119
+ if (sessions && Array.isArray(sessions.sessions)) {
120
+ // Filter to cloud type sessions that might belong to this genbox
121
+ const cloudSessions = sessions.sessions.filter((s) => s.type === 'cloud');
122
+ allSessions.push(...cloudSessions);
123
+ }
124
+ }
125
+ catch {
126
+ // Ignore errors
127
+ }
128
+ return allSessions;
129
+ }
130
+ /**
131
+ * Match a remote session name to an API session
132
+ * Remote session names are like "claude-abc123" (from socket file)
133
+ * API sessions have dtachSocket paths like "/home/dev/.genbox/sockets/claude-abc123.sock"
134
+ */
135
+ function matchRemoteSessionToApiSession(remoteName, apiSessions) {
136
+ for (const apiSession of apiSessions) {
137
+ // Match by socket path
138
+ if (apiSession.dtachSocket) {
139
+ const socketName = apiSession.dtachSocket.split('/').pop()?.replace('.sock', '');
140
+ if (socketName === remoteName) {
141
+ return apiSession;
142
+ }
143
+ }
144
+ // Match by tmux session name (legacy)
145
+ if (apiSession.tmuxSession === remoteName) {
146
+ return apiSession;
147
+ }
148
+ // Match by session ID prefix
149
+ if (apiSession.sessionId?.startsWith(remoteName) || remoteName.includes(apiSession.sessionId?.substring(0, 8))) {
150
+ return apiSession;
151
+ }
152
+ }
153
+ return null;
154
+ }
100
155
  /**
101
156
  * Collect session states from all sources
102
157
  */
@@ -158,6 +213,21 @@ async function collectSessionStates(options) {
158
213
  });
159
214
  }
160
215
  // Process remote sessions from cloud genboxes
216
+ // Group remote sessions by genbox to batch API calls
217
+ const remoteByGenbox = new Map();
218
+ for (const remote of result.remoteSessions) {
219
+ const key = remote.genboxId;
220
+ if (!remoteByGenbox.has(key)) {
221
+ remoteByGenbox.set(key, []);
222
+ }
223
+ remoteByGenbox.get(key).push(remote);
224
+ }
225
+ // Fetch API sessions for each genbox in parallel
226
+ const genboxSessionsMap = new Map();
227
+ await Promise.all(Array.from(remoteByGenbox.keys()).map(async (genboxId) => {
228
+ const apiSessions = await fetchGenboxSessions(genboxId);
229
+ genboxSessionsMap.set(genboxId, apiSessions);
230
+ }));
161
231
  for (const remote of result.remoteSessions) {
162
232
  // Filter by genbox if specified
163
233
  if (options.genbox && !remote.genboxName.toLowerCase().includes(options.genbox.toLowerCase()))
@@ -168,14 +238,58 @@ async function collectSessionStates(options) {
168
238
  // Remote sessions are running by definition (we found their socket)
169
239
  if (options.status === 'stopped')
170
240
  continue;
241
+ // Try to match this remote session to an API session (ClaudeSession)
242
+ const apiSessions = genboxSessionsMap.get(remote.genboxId) || [];
243
+ const matchedApiSession = matchRemoteSessionToApiSession(remote.name, apiSessions);
244
+ // ClaudeSession has status: 'active', 'idle', 'waiting_input', 'error', 'ended'
245
+ // Map to our display states
246
+ const apiStatus = matchedApiSession?.status;
247
+ let displayStatus = 'running';
248
+ let displayState;
249
+ if (matchedApiSession) {
250
+ // We have API data - use it
251
+ switch (apiStatus) {
252
+ case 'active':
253
+ displayStatus = 'running';
254
+ displayState = 'thinking';
255
+ break;
256
+ case 'waiting_input':
257
+ displayStatus = 'idle';
258
+ displayState = 'waiting_for_input';
259
+ break;
260
+ case 'idle':
261
+ displayStatus = 'idle';
262
+ displayState = 'waiting_for_input';
263
+ break;
264
+ case 'error':
265
+ displayStatus = 'error';
266
+ break;
267
+ case 'ended':
268
+ displayStatus = 'stopped';
269
+ break;
270
+ default:
271
+ displayStatus = 'running';
272
+ }
273
+ }
274
+ else {
275
+ // No API data - session is running (we found socket) but state is unknown
276
+ displayStatus = 'running';
277
+ displayState = undefined; // Will show as "idle" indicator but no state text
278
+ }
171
279
  states.push({
172
- id: remote.name.substring(0, 8),
280
+ id: matchedApiSession?.sessionId?.substring(0, 8) || remote.name.substring(0, 8),
173
281
  name: remote.name,
174
282
  provider: remote.provider,
175
283
  type: 'cloud',
176
284
  genbox: remote.genboxName,
177
- status: 'running',
178
- duration: '?',
285
+ status: displayStatus,
286
+ state: displayState,
287
+ currentTool: undefined, // ClaudeSession doesn't track current tool
288
+ lastMessage: matchedApiSession?.lastPrompt?.substring(0, 50),
289
+ duration: matchedApiSession?.createdAt ? formatDuration(matchedApiSession.createdAt) : '?',
290
+ createdAt: matchedApiSession?.createdAt,
291
+ toolCalls: matchedApiSession?.toolUseCount,
292
+ messagesCount: matchedApiSession?.promptCount,
179
293
  });
180
294
  }
181
295
  // Also add cloud genboxes that might have sessions we didn't scan
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genbox",
3
- "version": "1.0.213",
3
+ "version": "1.0.215",
4
4
  "description": "Genbox CLI - AI-Powered Development Environments",
5
5
  "main": "dist/index.js",
6
6
  "bin": {