| 230 | } |
| 231 | |
| 232 | export async function listDirectory(sessionId: string, dirPath: string): Promise<FileEntry[]> { |
| 233 | const container = containerCache.get(sessionId); |
| 234 | if (!container) { |
| 235 | throw new Error(`No container found for session: ${sessionId}`); |
| 236 | } |
| 237 | |
| 238 | try { |
| 239 | // Use ls command to list directory contents |
| 240 | const result = await execCommand(sessionId, ['ls', '-la', '--color=never', dirPath]); |
| 241 | |
| 242 | if (result.exitCode !== 0) { |
| 243 | throw new Error(`Failed to list directory: ${result.stderr}`); |
| 244 | } |
| 245 | |
| 246 | const entries: FileEntry[] = []; |
| 247 | const lines = result.stdout.split('\n').filter(line => line.trim()); |
| 248 | |
| 249 | // Skip first line (total) and parse each entry |
| 250 | for (let i = 1; i < lines.length; i++) { |
| 251 | const line = lines[i]; |
| 252 | const parts = line.split(/\s+/); |
| 253 | |
| 254 | if (parts.length < 9) continue; |
| 255 | |
| 256 | const permissions = parts[0]; |
| 257 | const name = parts.slice(8).join(' '); |
| 258 | |
| 259 | // Skip . and .. |
| 260 | if (name === '.' || name === '..') continue; |
| 261 | |
| 262 | const isDirectory = permissions.startsWith('d'); |
| 263 | const size = parseInt(parts[4], 10) || 0; |
| 264 | const fullPath = `${dirPath}/${name}`.replace(/\/+/g, '/'); |
| 265 | |
| 266 | entries.push({ |
| 267 | name, |
| 268 | type: isDirectory ? 'directory' : 'file', |
| 269 | size, |
| 270 | path: fullPath, |
| 271 | }); |
| 272 | } |
| 273 | |
| 274 | logger.info('Directory listed', { sessionId, dirPath, entries: entries.length }); |
| 275 | return entries; |
| 276 | } catch (error) { |
| 277 | logger.error('Failed to list directory', { sessionId, dirPath, error }); |
| 278 | throw new Error(`Failed to list directory: ${error}`); |
| 279 | } |
| 280 | } |
| 281 | |
| 282 | /** |
| 283 | * Write a file to the container |