computesdk 1.11.0 → 1.12.0

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/README.md CHANGED
@@ -283,6 +283,209 @@ Remove a file or directory.
283
283
  await sandbox.filesystem.remove('/tmp/hello.py');
284
284
  ```
285
285
 
286
+ ### Terminal Operations
287
+
288
+ The sandbox provides terminal access in two modes: **PTY mode** (interactive shell) and **Exec mode** (command tracking).
289
+
290
+ #### `sandbox.terminal.create(options?)`
291
+
292
+ Create a new terminal session.
293
+
294
+ ```typescript
295
+ // PTY mode - Interactive shell
296
+ const pty = await sandbox.terminal.create({ pty: true, shell: '/bin/bash' });
297
+
298
+ // Exec mode - Command tracking (default)
299
+ const exec = await sandbox.terminal.create({ pty: false });
300
+ ```
301
+
302
+ **Options:**
303
+ - `pty?: boolean` - Terminal mode: `true` = PTY (interactive), `false` = exec (command tracking). Default: `false`
304
+ - `shell?: string` - Shell to use (e.g., '/bin/bash'). PTY mode only
305
+ - `encoding?: 'raw' | 'base64'` - Output encoding. Default: `'raw'`
306
+
307
+ **Returns:** `TerminalInstance`
308
+
309
+ #### `sandbox.terminal.list()`
310
+
311
+ List all active terminals.
312
+
313
+ ```typescript
314
+ const terminals = await sandbox.terminal.list();
315
+ console.log(terminals); // [{ id: 'term-1', pty: true, status: 'running', ... }]
316
+ ```
317
+
318
+ #### `sandbox.terminal.retrieve(id)`
319
+
320
+ Retrieve a specific terminal by ID.
321
+
322
+ ```typescript
323
+ const terminal = await sandbox.terminal.retrieve('term-123');
324
+ console.log(terminal.id, terminal.status);
325
+ ```
326
+
327
+ #### `sandbox.terminal.destroy(id)`
328
+
329
+ Destroy a terminal by ID.
330
+
331
+ ```typescript
332
+ await sandbox.terminal.destroy('term-123');
333
+ ```
334
+
335
+ ### PTY Mode (Interactive Shell)
336
+
337
+ PTY mode creates an interactive shell session with real-time input/output over WebSocket.
338
+
339
+ #### `terminal.write(input)`
340
+
341
+ Send input to the terminal shell.
342
+
343
+ ```typescript
344
+ const pty = await sandbox.terminal.create({ pty: true });
345
+ pty.on('output', (data) => console.log(data));
346
+ pty.write('ls -la\n');
347
+ pty.write('pwd\n');
348
+ await pty.destroy();
349
+ ```
350
+
351
+ #### `terminal.resize(cols, rows)`
352
+
353
+ Resize the terminal window.
354
+
355
+ ```typescript
356
+ pty.resize(120, 40);
357
+ ```
358
+
359
+ #### `terminal.on(event, handler)`
360
+
361
+ Register an event handler. Events: `'output'`, `'error'`, `'destroyed'`.
362
+
363
+ ```typescript
364
+ pty.on('output', (data) => console.log('Output:', data));
365
+ pty.on('error', (error) => console.error('Error:', error));
366
+ pty.on('destroyed', () => console.log('Terminal destroyed'));
367
+ ```
368
+
369
+ #### `terminal.off(event, handler)`
370
+
371
+ Unregister an event handler.
372
+
373
+ ```typescript
374
+ const handler = (data) => console.log(data);
375
+ pty.on('output', handler);
376
+ pty.off('output', handler);
377
+ ```
378
+
379
+ #### Terminal Properties
380
+
381
+ ```typescript
382
+ console.log(pty.id); // Terminal ID
383
+ console.log(pty.status); // 'running' | 'stopped' | 'active' | 'ready'
384
+ console.log(pty.channel); // WebSocket channel (PTY only)
385
+ console.log(pty.pty); // true for PTY mode
386
+ ```
387
+
388
+ ### Exec Mode (Command Tracking)
389
+
390
+ Exec mode executes commands with structured result tracking, suitable for automation.
391
+
392
+ #### `terminal.command.run(command, options?)`
393
+
394
+ Execute a command in the terminal.
395
+
396
+ ```typescript
397
+ const exec = await sandbox.terminal.create({ pty: false });
398
+
399
+ // Foreground execution (waits for completion)
400
+ const cmd = await exec.command.run('npm test');
401
+ console.log(cmd.stdout);
402
+ console.log(cmd.stderr);
403
+ console.log(cmd.exitCode);
404
+
405
+ // Background execution (returns immediately)
406
+ const bgCmd = await exec.command.run('npm install', { background: true });
407
+ console.log(bgCmd.status); // 'running'
408
+ await bgCmd.wait(); // Wait for completion
409
+ console.log(bgCmd.exitCode);
410
+ ```
411
+
412
+ **Parameters:**
413
+ - `command: string` - The command to execute
414
+ - `options?: { background?: boolean }` - Execution options
415
+
416
+ **Returns:** `Command` object
417
+
418
+ #### `terminal.command.list()`
419
+
420
+ List all commands executed in this terminal.
421
+
422
+ ```typescript
423
+ const commands = await exec.command.list();
424
+ commands.forEach(cmd => {
425
+ console.log(cmd.id, cmd.command, cmd.status, cmd.exitCode);
426
+ });
427
+ ```
428
+
429
+ #### `terminal.command.retrieve(cmdId)`
430
+
431
+ Retrieve a specific command by ID.
432
+
433
+ ```typescript
434
+ const cmd = await exec.command.retrieve('cmd-123');
435
+ console.log(cmd.stdout);
436
+ ```
437
+
438
+ ### Command Object
439
+
440
+ The `Command` object represents a command execution result.
441
+
442
+ #### Command Properties
443
+
444
+ ```typescript
445
+ console.log(cmd.id); // Command ID
446
+ console.log(cmd.terminalId); // Parent terminal ID
447
+ console.log(cmd.command); // Executed command
448
+ console.log(cmd.status); // 'running' | 'completed' | 'failed'
449
+ console.log(cmd.stdout); // Standard output
450
+ console.log(cmd.stderr); // Standard error
451
+ console.log(cmd.exitCode); // Exit code (undefined if running)
452
+ console.log(cmd.durationMs); // Execution time in milliseconds
453
+ console.log(cmd.startedAt); // Start timestamp
454
+ console.log(cmd.finishedAt); // Finish timestamp (undefined if running)
455
+ ```
456
+
457
+ #### `command.wait(timeout?)`
458
+
459
+ Wait for a background command to complete.
460
+
461
+ ```typescript
462
+ const cmd = await exec.command.run('sleep 5', { background: true });
463
+ await cmd.wait(); // Waits up to default timeout
464
+ console.log(cmd.exitCode);
465
+
466
+ // With custom timeout (in seconds, 0 = no timeout)
467
+ await cmd.wait(10);
468
+ ```
469
+
470
+ #### `command.refresh()`
471
+
472
+ Refresh the command status from the server.
473
+
474
+ ```typescript
475
+ const cmd = await exec.command.run('npm build', { background: true });
476
+ // ... later ...
477
+ await cmd.refresh();
478
+ console.log(cmd.status, cmd.exitCode);
479
+ ```
480
+
481
+ #### `terminal.destroy()`
482
+
483
+ Destroy the terminal and clean up resources.
484
+
485
+ ```typescript
486
+ await exec.destroy();
487
+ ```
488
+
286
489
  ## Examples
287
490
 
288
491
  ### Data Science Workflow
@@ -391,6 +594,82 @@ console.log(runResult.stdout);
391
594
  await sandbox.destroy();
392
595
  ```
393
596
 
597
+ ### Terminal Command Execution
598
+
599
+ ```typescript
600
+ import { compute } from 'computesdk';
601
+
602
+ const sandbox = await compute.sandbox.create({ runtime: 'node' });
603
+
604
+ // Create exec mode terminal for command tracking
605
+ const terminal = await sandbox.terminal.create({ pty: false });
606
+
607
+ // Run build commands with tracking
608
+ const install = await terminal.command.run('npm install');
609
+ console.log('Install exit code:', install.exitCode);
610
+
611
+ const build = await terminal.command.run('npm run build');
612
+ console.log('Build output:', build.stdout);
613
+
614
+ // Run tests in background
615
+ const tests = await terminal.command.run('npm test', { background: true });
616
+ console.log('Tests started:', tests.status);
617
+
618
+ // Wait for tests to complete
619
+ await tests.wait(60); // 60 second timeout
620
+ console.log('Tests completed:', tests.exitCode === 0 ? 'PASSED' : 'FAILED');
621
+ console.log('Test output:', tests.stdout);
622
+
623
+ // List all commands
624
+ const commands = await terminal.command.list();
625
+ console.log(`Executed ${commands.length} commands`);
626
+
627
+ await terminal.destroy();
628
+ await sandbox.destroy();
629
+ ```
630
+
631
+ ### Interactive Terminal Session
632
+
633
+ ```typescript
634
+ import { compute } from 'computesdk';
635
+
636
+ const sandbox = await compute.sandbox.create({ runtime: 'node' });
637
+
638
+ // Create PTY terminal for interactive shell
639
+ const pty = await sandbox.terminal.create({
640
+ pty: true,
641
+ shell: '/bin/bash'
642
+ });
643
+
644
+ // Collect all output
645
+ let output = '';
646
+ pty.on('output', (data) => {
647
+ output += data;
648
+ console.log(data);
649
+ });
650
+
651
+ pty.on('error', (error) => {
652
+ console.error('Terminal error:', error);
653
+ });
654
+
655
+ // Execute interactive commands
656
+ pty.write('echo "Starting project setup"\n');
657
+ pty.write('mkdir -p /workspace/myproject\n');
658
+ pty.write('cd /workspace/myproject\n');
659
+ pty.write('npm init -y\n');
660
+ pty.write('npm install express\n');
661
+ pty.write('echo "Setup complete"\n');
662
+
663
+ // Wait for operations to complete
664
+ await new Promise(resolve => setTimeout(resolve, 5000));
665
+
666
+ // Clean up
667
+ await pty.destroy();
668
+ await sandbox.destroy();
669
+
670
+ console.log('Complete output:', output);
671
+ ```
672
+
394
673
  ### Using Different Providers
395
674
 
396
675
  ```typescript
package/dist/index.d.mts CHANGED
@@ -1103,25 +1103,64 @@ declare class Terminal {
1103
1103
  * Server - Resource namespace for managed server operations
1104
1104
  */
1105
1105
 
1106
+ /**
1107
+ * Options for starting a managed server
1108
+ */
1109
+ interface ServerStartOptions {
1110
+ /** Unique server identifier (URL-safe) */
1111
+ slug: string;
1112
+ /** Command to start the server */
1113
+ command: string;
1114
+ /** Working directory (optional) */
1115
+ path?: string;
1116
+ /** Path to .env file relative to path (optional) */
1117
+ env_file?: string;
1118
+ /** Inline environment variables (merged with env_file if both provided) */
1119
+ environment?: Record<string, string>;
1120
+ /**
1121
+ * When to automatically restart the server:
1122
+ * - `never`: No automatic restart (default)
1123
+ * - `on-failure`: Restart only on non-zero exit code
1124
+ * - `always`: Always restart on exit (including exit code 0)
1125
+ */
1126
+ restart_policy?: RestartPolicy;
1127
+ /** Maximum restart attempts (0 = unlimited, default: 0) */
1128
+ max_restarts?: number;
1129
+ /** Delay between restart attempts in milliseconds (default: 1000) */
1130
+ restart_delay_ms?: number;
1131
+ /** Graceful shutdown timeout in milliseconds - SIGTERM → wait → SIGKILL (default: 10000) */
1132
+ stop_timeout_ms?: number;
1133
+ }
1106
1134
  /**
1107
1135
  * Server resource namespace
1108
1136
  *
1109
1137
  * @example
1110
1138
  * ```typescript
1111
- * // Start a new server
1139
+ * // Start a basic server
1112
1140
  * const server = await sandbox.server.start({
1113
1141
  * slug: 'api',
1114
1142
  * command: 'npm start',
1115
1143
  * path: '/app',
1116
1144
  * });
1117
1145
  *
1146
+ * // Start with supervisor settings (auto-restart on failure)
1147
+ * const server = await sandbox.server.start({
1148
+ * slug: 'web',
1149
+ * command: 'node server.js',
1150
+ * path: '/app',
1151
+ * environment: { NODE_ENV: 'production', PORT: '3000' },
1152
+ * restart_policy: 'on-failure',
1153
+ * max_restarts: 5,
1154
+ * restart_delay_ms: 2000,
1155
+ * });
1156
+ *
1118
1157
  * // List all servers
1119
1158
  * const servers = await sandbox.server.list();
1120
1159
  *
1121
1160
  * // Retrieve a specific server
1122
1161
  * const server = await sandbox.server.retrieve('api');
1123
1162
  *
1124
- * // Stop a server
1163
+ * // Stop a server (graceful shutdown with SIGTERM → SIGKILL)
1125
1164
  * await sandbox.server.stop('api');
1126
1165
  *
1127
1166
  * // Restart a server
@@ -1136,12 +1175,7 @@ declare class Server {
1136
1175
  private restartHandler;
1137
1176
  private updateStatusHandler;
1138
1177
  constructor(handlers: {
1139
- start: (options: {
1140
- slug: string;
1141
- command: string;
1142
- path?: string;
1143
- env_file?: string;
1144
- }) => Promise<ServerResponse>;
1178
+ start: (options: ServerStartOptions) => Promise<ServerResponse>;
1145
1179
  list: () => Promise<ServersListResponse>;
1146
1180
  retrieve: (slug: string) => Promise<ServerResponse>;
1147
1181
  stop: (slug: string) => Promise<ServerStopResponse | void>;
@@ -1149,20 +1183,40 @@ declare class Server {
1149
1183
  updateStatus: (slug: string, status: ServerStatus) => Promise<void>;
1150
1184
  });
1151
1185
  /**
1152
- * Start a new managed server
1186
+ * Start a new managed server with optional supervisor settings
1187
+ *
1188
+ * **Restart Policies:**
1189
+ * - `never` (default): No automatic restart on exit
1190
+ * - `on-failure`: Restart only on non-zero exit code
1191
+ * - `always`: Always restart on exit (including exit code 0)
1192
+ *
1193
+ * **Graceful Shutdown:**
1194
+ * When stopping a server, it first sends SIGTERM and waits for `stop_timeout_ms`
1195
+ * before sending SIGKILL if the process hasn't exited.
1196
+ *
1153
1197
  * @param options - Server configuration
1154
- * @param options.slug - Unique server slug (URL-safe identifier)
1155
- * @param options.command - Command to start the server
1156
- * @param options.path - Working directory (optional)
1157
- * @param options.env_file - Path to env file (optional)
1158
1198
  * @returns Server info
1199
+ *
1200
+ * @example
1201
+ * ```typescript
1202
+ * // Basic server
1203
+ * const server = await sandbox.server.start({
1204
+ * slug: 'web',
1205
+ * command: 'npm run dev',
1206
+ * path: '/app',
1207
+ * });
1208
+ *
1209
+ * // With supervisor settings
1210
+ * const server = await sandbox.server.start({
1211
+ * slug: 'api',
1212
+ * command: 'node server.js',
1213
+ * environment: { NODE_ENV: 'production' },
1214
+ * restart_policy: 'always',
1215
+ * max_restarts: 0, // unlimited
1216
+ * });
1217
+ * ```
1159
1218
  */
1160
- start(options: {
1161
- slug: string;
1162
- command: string;
1163
- path?: string;
1164
- env_file?: string;
1165
- }): Promise<ServerInfo>;
1219
+ start(options: ServerStartOptions): Promise<ServerInfo>;
1166
1220
  /**
1167
1221
  * List all managed servers
1168
1222
  * @returns Array of server info
@@ -2301,23 +2355,61 @@ interface TerminalResponse {
2301
2355
  }
2302
2356
  /**
2303
2357
  * Server status types
2358
+ *
2359
+ * - `starting`: Initial startup of the server process
2360
+ * - `running`: Server process is running
2361
+ * - `ready`: Server is running and ready to accept traffic
2362
+ * - `failed`: Server failed to start or encountered a fatal error
2363
+ * - `stopped`: Server was intentionally stopped
2364
+ * - `restarting`: Server is being automatically restarted by the supervisor
2365
+ */
2366
+ type ServerStatus = 'starting' | 'running' | 'ready' | 'failed' | 'stopped' | 'restarting';
2367
+ /**
2368
+ * Server restart policy
2369
+ * - `never`: No automatic restart (default)
2370
+ * - `on-failure`: Restart only on non-zero exit code
2371
+ * - `always`: Always restart on exit (including exit code 0)
2304
2372
  */
2305
- type ServerStatus = 'starting' | 'running' | 'ready' | 'failed' | 'stopped';
2373
+ type RestartPolicy = 'never' | 'on-failure' | 'always';
2306
2374
  /**
2307
2375
  * Server information
2308
2376
  */
2309
2377
  interface ServerInfo {
2378
+ /** Unique server identifier */
2310
2379
  slug: string;
2380
+ /** Command used to start the server */
2311
2381
  command: string;
2382
+ /** Working directory path */
2312
2383
  path: string;
2384
+ /** Original path before resolution */
2313
2385
  original_path?: string;
2386
+ /** Path to .env file */
2314
2387
  env_file?: string;
2388
+ /** Inline environment variables */
2389
+ environment?: Record<string, string>;
2390
+ /** Auto-detected port number (populated when port monitor detects listening port) */
2315
2391
  port?: number;
2392
+ /** Generated URL from subdomain + port (populated when port is detected) */
2316
2393
  url?: string;
2394
+ /** Server lifecycle status */
2317
2395
  status: ServerStatus;
2396
+ /** Process ID (direct process, not shell wrapper) */
2318
2397
  pid?: number;
2319
- terminal_id?: string;
2398
+ /** Configured restart policy */
2399
+ restart_policy?: RestartPolicy;
2400
+ /** Maximum restart attempts (0 = unlimited) */
2401
+ max_restarts?: number;
2402
+ /** Delay between restarts in nanoseconds (input uses milliseconds via restart_delay_ms) */
2403
+ restart_delay?: number;
2404
+ /** Graceful shutdown timeout in nanoseconds (input uses milliseconds via stop_timeout_ms) */
2405
+ stop_timeout?: number;
2406
+ /** Number of times the server has been automatically restarted */
2407
+ restart_count?: number;
2408
+ /** Last exit code (null if process is still running) */
2409
+ exit_code?: number | null;
2410
+ /** When the server was created */
2320
2411
  created_at: string;
2412
+ /** When the server was last updated */
2321
2413
  updated_at: string;
2322
2414
  }
2323
2415
  /**
@@ -2882,14 +2974,51 @@ declare class Sandbox {
2882
2974
  */
2883
2975
  listServers(): Promise<ServersListResponse>;
2884
2976
  /**
2885
- * Start a new managed server
2977
+ * Start a new managed server with optional supervisor settings
2978
+ *
2886
2979
  * @param options - Server configuration
2980
+ * @param options.slug - Unique server identifier
2981
+ * @param options.command - Command to start the server
2982
+ * @param options.path - Working directory (optional)
2983
+ * @param options.env_file - Path to .env file relative to path (optional)
2984
+ * @param options.environment - Inline environment variables (merged with env_file if both provided)
2985
+ * @param options.restart_policy - When to automatically restart: 'never' (default), 'on-failure', 'always'
2986
+ * @param options.max_restarts - Maximum restart attempts, 0 = unlimited (default: 0)
2987
+ * @param options.restart_delay_ms - Delay between restart attempts in milliseconds (default: 1000)
2988
+ * @param options.stop_timeout_ms - Graceful shutdown timeout in milliseconds (default: 10000)
2989
+ *
2990
+ * @example
2991
+ * ```typescript
2992
+ * // Basic server
2993
+ * await sandbox.startServer({
2994
+ * slug: 'web',
2995
+ * command: 'npm run dev',
2996
+ * path: '/app',
2997
+ * });
2998
+ *
2999
+ * // With supervisor settings
3000
+ * await sandbox.startServer({
3001
+ * slug: 'api',
3002
+ * command: 'node server.js',
3003
+ * path: '/app',
3004
+ * environment: { NODE_ENV: 'production', PORT: '3000' },
3005
+ * restart_policy: 'on-failure',
3006
+ * max_restarts: 5,
3007
+ * restart_delay_ms: 2000,
3008
+ * stop_timeout_ms: 5000,
3009
+ * });
3010
+ * ```
2887
3011
  */
2888
3012
  startServer(options: {
2889
3013
  slug: string;
2890
3014
  command: string;
2891
3015
  path?: string;
2892
3016
  env_file?: string;
3017
+ environment?: Record<string, string>;
3018
+ restart_policy?: RestartPolicy;
3019
+ max_restarts?: number;
3020
+ restart_delay_ms?: number;
3021
+ stop_timeout_ms?: number;
2893
3022
  }): Promise<ServerResponse>;
2894
3023
  /**
2895
3024
  * Get information about a specific server