@agentuity/core 2.0.0-beta.0 → 2.0.0-beta.1

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.
Files changed (68) hide show
  1. package/dist/deprecation.d.ts +20 -0
  2. package/dist/deprecation.d.ts.map +1 -0
  3. package/dist/deprecation.js +102 -0
  4. package/dist/deprecation.js.map +1 -0
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +2 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/services/api.d.ts.map +1 -1
  10. package/dist/services/api.js +13 -5
  11. package/dist/services/api.js.map +1 -1
  12. package/dist/services/oauth/flow.d.ts +51 -0
  13. package/dist/services/oauth/flow.d.ts.map +1 -0
  14. package/dist/services/oauth/flow.js +183 -0
  15. package/dist/services/oauth/flow.js.map +1 -0
  16. package/dist/services/oauth/index.d.ts +1 -0
  17. package/dist/services/oauth/index.d.ts.map +1 -1
  18. package/dist/services/oauth/index.js +1 -0
  19. package/dist/services/oauth/index.js.map +1 -1
  20. package/dist/services/oauth/types.d.ts +42 -0
  21. package/dist/services/oauth/types.d.ts.map +1 -1
  22. package/dist/services/oauth/types.js +53 -0
  23. package/dist/services/oauth/types.js.map +1 -1
  24. package/dist/services/sandbox/client.d.ts +201 -1
  25. package/dist/services/sandbox/client.d.ts.map +1 -1
  26. package/dist/services/sandbox/client.js +276 -15
  27. package/dist/services/sandbox/client.js.map +1 -1
  28. package/dist/services/sandbox/create.d.ts +2 -0
  29. package/dist/services/sandbox/create.d.ts.map +1 -1
  30. package/dist/services/sandbox/create.js +4 -0
  31. package/dist/services/sandbox/create.js.map +1 -1
  32. package/dist/services/sandbox/execution.d.ts +1 -0
  33. package/dist/services/sandbox/execution.d.ts.map +1 -1
  34. package/dist/services/sandbox/execution.js +4 -2
  35. package/dist/services/sandbox/execution.js.map +1 -1
  36. package/dist/services/sandbox/files.js +1 -1
  37. package/dist/services/sandbox/files.js.map +1 -1
  38. package/dist/services/sandbox/index.d.ts +3 -1
  39. package/dist/services/sandbox/index.d.ts.map +1 -1
  40. package/dist/services/sandbox/index.js +1 -0
  41. package/dist/services/sandbox/index.js.map +1 -1
  42. package/dist/services/sandbox/job.d.ts +227 -0
  43. package/dist/services/sandbox/job.d.ts.map +1 -0
  44. package/dist/services/sandbox/job.js +109 -0
  45. package/dist/services/sandbox/job.js.map +1 -0
  46. package/dist/services/sandbox/types.d.ts +35 -0
  47. package/dist/services/sandbox/types.d.ts.map +1 -1
  48. package/dist/services/sandbox/types.js +23 -0
  49. package/dist/services/sandbox/types.js.map +1 -1
  50. package/dist/services/sandbox/util.d.ts +1 -0
  51. package/dist/services/sandbox/util.d.ts.map +1 -1
  52. package/dist/services/sandbox/util.js +1 -0
  53. package/dist/services/sandbox/util.js.map +1 -1
  54. package/package.json +2 -2
  55. package/src/deprecation.ts +120 -0
  56. package/src/index.ts +3 -0
  57. package/src/services/api.ts +15 -5
  58. package/src/services/oauth/flow.ts +215 -0
  59. package/src/services/oauth/index.ts +1 -0
  60. package/src/services/oauth/types.ts +67 -0
  61. package/src/services/sandbox/client.ts +446 -16
  62. package/src/services/sandbox/create.ts +4 -0
  63. package/src/services/sandbox/execution.ts +5 -2
  64. package/src/services/sandbox/files.ts +1 -1
  65. package/src/services/sandbox/index.ts +20 -0
  66. package/src/services/sandbox/job.ts +161 -0
  67. package/src/services/sandbox/types.ts +29 -0
  68. package/src/services/sandbox/util.ts +1 -0
@@ -19,6 +19,7 @@ export const OAuthClientSchema = z.object({
19
19
  refresh_token_lifetime_seconds: z.number().optional(),
20
20
  id_token_lifetime_seconds: z.number().optional(),
21
21
  allowed_user_ids: z.array(z.string()),
22
+ internal: z.boolean().optional().default(false),
22
23
  created_at: z.string(),
23
24
  updated_at: z.string(),
24
25
  });
@@ -238,3 +239,69 @@ export type OAuthUserConsentRevokeResponse = z.infer<typeof OAuthUserConsentRevo
238
239
  export type OAuthScopesResponse = z.infer<typeof OAuthScopesResponseSchema>;
239
240
  export type OAuthOrgMembersResponse = z.infer<typeof OAuthOrgMembersResponseSchema>;
240
241
  export type OAuthKeysRotateResponse = z.infer<typeof OAuthKeysRotateResponseSchema>;
242
+
243
+ // ============================================================================
244
+ // OAuth 2.0 Authorization Code Flow Types
245
+ // ============================================================================
246
+
247
+ export const OAuthFlowConfigSchema = z.object({
248
+ clientId: z.string().optional().describe('OAuth client ID. Defaults to OAUTH_CLIENT_ID env var'),
249
+ clientSecret: z
250
+ .string()
251
+ .optional()
252
+ .describe('OAuth client secret. Defaults to OAUTH_CLIENT_SECRET env var'),
253
+ issuer: z
254
+ .string()
255
+ .optional()
256
+ .describe(
257
+ 'OIDC issuer base URL. Defaults to OAUTH_ISSUER env var. Used to derive authorize/token/userinfo URLs'
258
+ ),
259
+ authorizeUrl: z
260
+ .string()
261
+ .optional()
262
+ .describe('Authorization endpoint. Defaults to OAUTH_AUTHORIZE_URL or {issuer}/authorize'),
263
+ tokenUrl: z
264
+ .string()
265
+ .optional()
266
+ .describe('Token endpoint. Defaults to OAUTH_TOKEN_URL or {issuer}/oauth/token'),
267
+ userinfoUrl: z
268
+ .string()
269
+ .optional()
270
+ .describe('UserInfo endpoint. Defaults to OAUTH_USERINFO_URL or {issuer}/userinfo'),
271
+ scopes: z
272
+ .string()
273
+ .optional()
274
+ .describe('Space-separated scopes. Defaults to OAUTH_SCOPES or "openid profile email"'),
275
+ prompt: z
276
+ .enum(['none', 'login', 'consent', 'select_account'])
277
+ .optional()
278
+ .describe(
279
+ 'OIDC prompt parameter. Controls authentication UX: "login" forces re-auth, "consent" forces consent screen, "none" fails if not authenticated, "select_account" lets user pick an account'
280
+ ),
281
+ });
282
+
283
+ export type OAuthFlowConfig = z.infer<typeof OAuthFlowConfigSchema>;
284
+
285
+ export const OAuthTokenResponseSchema = z.object({
286
+ access_token: z.string(),
287
+ token_type: z.string().optional(),
288
+ expires_in: z.number().optional(),
289
+ refresh_token: z.string().optional(),
290
+ scope: z.string().optional(),
291
+ id_token: z.string().optional(),
292
+ });
293
+
294
+ export type OAuthTokenResponse = z.infer<typeof OAuthTokenResponseSchema>;
295
+
296
+ export const OAuthUserInfoSchema = z
297
+ .object({
298
+ sub: z.string(),
299
+ name: z.string().optional(),
300
+ given_name: z.string().optional(),
301
+ family_name: z.string().optional(),
302
+ email: z.string().optional(),
303
+ email_verified: z.boolean().optional(),
304
+ })
305
+ .catchall(z.unknown());
306
+
307
+ export type OAuthUserInfo = z.infer<typeof OAuthUserInfoSchema>;
@@ -5,9 +5,16 @@ import {
5
5
  type SandboxInfo,
6
6
  type SandboxStatus,
7
7
  type Execution,
8
+ type ExecutionStatus,
8
9
  type FileToWrite,
9
10
  type SandboxRunOptions,
10
11
  type SandboxRunResult,
12
+ type ListSandboxesParams,
13
+ type ListSandboxesResponse,
14
+ type ListRuntimesParams,
15
+ type ListRuntimesResponse,
16
+ type Job,
17
+ type CreateJobOptions,
11
18
  } from './types.ts';
12
19
  import type { Logger } from '../../logger.ts';
13
20
  import type { Readable, Writable } from 'node:stream';
@@ -30,18 +37,59 @@ import {
30
37
  import { sandboxPause } from './pause.ts';
31
38
  import { sandboxResume } from './resume.ts';
32
39
  import { sandboxRun } from './run.ts';
33
- import { executionGet, type ExecutionInfo } from './execution.ts';
40
+ import {
41
+ executionGet,
42
+ executionList,
43
+ type ExecutionInfo,
44
+ type ExecutionListResponse,
45
+ } from './execution.ts';
34
46
  import { createMinimalLogger } from '../logger.ts';
35
47
  import { getServiceUrls } from '../config.ts';
36
48
  import { writeAndDrain } from './util.ts';
37
-
38
- // Server-side long-poll wait duration (max 5 minutes supported by server)
49
+ import { sandboxList } from './list.ts';
50
+ import { runtimeList } from './runtime.ts';
51
+ import { jobCreate, jobGet, jobList, jobStop, type JobListResponse } from './job.ts';
52
+ import {
53
+ diskCheckpointCreate,
54
+ diskCheckpointList,
55
+ diskCheckpointRestore,
56
+ diskCheckpointDelete,
57
+ type DiskCheckpointInfo,
58
+ } from './disk-checkpoint.ts';
59
+ import {
60
+ snapshotCreate,
61
+ snapshotGet,
62
+ snapshotList,
63
+ snapshotDelete,
64
+ snapshotTag,
65
+ snapshotLineage,
66
+ type SnapshotInfo,
67
+ type SnapshotListResponse,
68
+ type SnapshotLineageResponse,
69
+ type SnapshotListParams,
70
+ type SnapshotLineageParams,
71
+ } from './snapshot.ts';
72
+ import { sandboxEventList, type SandboxEventListResponse } from './events.ts';
73
+
74
+ // Server-side long-poll wait duration per iteration (max 5 minutes supported by server)
39
75
  const EXECUTION_WAIT_DURATION = '5m';
40
76
 
77
+ /** Terminal execution statuses that indicate the command has finished. */
78
+ const TERMINAL_STATUSES: Set<ExecutionStatus> = new Set([
79
+ 'completed',
80
+ 'failed',
81
+ 'timeout',
82
+ 'cancelled',
83
+ ]);
84
+
41
85
  /**
42
- * Wait for execution completion using server-side long-polling.
43
- * This is more efficient than client-side polling and provides immediate
44
- * error detection if the sandbox is terminated.
86
+ * Wait for execution completion using server-side long-polling with automatic retry.
87
+ *
88
+ * Each iteration asks the server to hold the connection for up to
89
+ * EXECUTION_WAIT_DURATION. If the execution is still running when the
90
+ * server-side wait expires, we loop and issue another long-poll request.
91
+ * This continues until the execution reaches a terminal state or the
92
+ * caller's AbortSignal fires.
45
93
  */
46
94
  async function waitForExecution(
47
95
  client: APIClient,
@@ -49,17 +97,30 @@ async function waitForExecution(
49
97
  orgId?: string,
50
98
  signal?: AbortSignal
51
99
  ): Promise<ExecutionInfo> {
52
- if (signal?.aborted) {
53
- throw new DOMException('The operation was aborted.', 'AbortError');
54
- }
100
+ while (true) {
101
+ if (signal?.aborted) {
102
+ throw new DOMException('The operation was aborted.', 'AbortError');
103
+ }
104
+
105
+ // Use server-side long-polling - the server will hold the connection
106
+ // until the execution reaches a terminal state or the wait duration expires.
107
+ // The signal is forwarded so the in-flight fetch is cancelled immediately
108
+ // when the caller aborts, rather than waiting the full poll duration.
109
+ const result = await executionGet(client, {
110
+ executionId,
111
+ orgId,
112
+ wait: EXECUTION_WAIT_DURATION,
113
+ signal,
114
+ });
115
+
116
+ // If the execution reached a terminal state, return immediately
117
+ if (TERMINAL_STATUSES.has(result.status as ExecutionStatus)) {
118
+ return result;
119
+ }
55
120
 
56
- // Use server-side long-polling - the server will hold the connection
57
- // until the execution reaches a terminal state or the wait duration expires
58
- return executionGet(client, {
59
- executionId,
60
- orgId,
61
- wait: EXECUTION_WAIT_DURATION,
62
- });
121
+ // Non-terminal status (e.g., 'running', 'queued') the server-side
122
+ // long-poll expired before the command finished. Loop to poll again.
123
+ }
63
124
  }
64
125
 
65
126
  /**
@@ -350,6 +411,117 @@ function createSandboxInstanceMethods(
350
411
  };
351
412
  }
352
413
 
414
+ /**
415
+ * A job instance returned by SandboxClient.createJob() or SandboxClient.getJob()
416
+ */
417
+ export interface JobInstance {
418
+ /**
419
+ * Unique job identifier
420
+ */
421
+ readonly id: string;
422
+
423
+ /**
424
+ * ID of the sandbox this job belongs to
425
+ */
426
+ readonly sandboxId: string;
427
+
428
+ /**
429
+ * Current job status
430
+ */
431
+ readonly status: string;
432
+
433
+ /**
434
+ * Get the current job status and details
435
+ */
436
+ get(): Promise<Job>;
437
+
438
+ /**
439
+ * Stop the job
440
+ * @param force - Force termination with SIGKILL
441
+ */
442
+ stop(force?: boolean): Promise<Job>;
443
+ }
444
+
445
+ /**
446
+ * Creates the method implementations for JobInstance
447
+ */
448
+ function createJobInstanceMethods(
449
+ client: APIClient,
450
+ sandboxId: string,
451
+ jobId: string,
452
+ orgId?: string
453
+ ): Omit<JobInstance, 'id' | 'sandboxId' | 'status'> {
454
+ return {
455
+ async get(): Promise<Job> {
456
+ return jobGet(client, { sandboxId, jobId, orgId });
457
+ },
458
+
459
+ async stop(force?: boolean): Promise<Job> {
460
+ return jobStop(client, { sandboxId, jobId, force, orgId });
461
+ },
462
+ };
463
+ }
464
+
465
+ /**
466
+ * A disk checkpoint instance returned by SandboxClient.createDiskCheckpoint() or SandboxClient.getDiskCheckpoint()
467
+ */
468
+ export interface DiskCheckpointInstance {
469
+ /**
470
+ * Unique checkpoint identifier
471
+ */
472
+ readonly id: string;
473
+
474
+ /**
475
+ * User-provided checkpoint name
476
+ */
477
+ readonly name: string;
478
+
479
+ /**
480
+ * ID of the sandbox this checkpoint belongs to
481
+ */
482
+ readonly sandboxId: string;
483
+
484
+ /**
485
+ * ISO timestamp of creation
486
+ */
487
+ readonly createdAt: string;
488
+
489
+ /**
490
+ * Parent checkpoint name
491
+ */
492
+ readonly parent: string;
493
+
494
+ /**
495
+ * Restore the sandbox to this checkpoint
496
+ */
497
+ restore(): Promise<void>;
498
+
499
+ /**
500
+ * Delete this checkpoint
501
+ */
502
+ delete(): Promise<void>;
503
+ }
504
+
505
+ /**
506
+ * Creates the method implementations for DiskCheckpointInstance
507
+ */
508
+ function createDiskCheckpointInstanceMethods(
509
+ client: APIClient,
510
+ sandboxId: string,
511
+ checkpointId: string,
512
+ orgId?: string
513
+ ): Omit<DiskCheckpointInstance, 'id' | 'name' | 'sandboxId' | 'createdAt' | 'parent'> {
514
+ return {
515
+ async restore(): Promise<void> {
516
+ return diskCheckpointRestore(client, { sandboxId, checkpointId, orgId });
517
+ },
518
+
519
+ async delete(): Promise<void> {
520
+ return diskCheckpointDelete(client, { sandboxId, checkpointId, orgId });
521
+ },
522
+ };
523
+ }
524
+
353
525
  /**
354
526
  * Convenience client for sandbox operations.
355
527
  *
@@ -563,4 +735,262 @@ export class SandboxClient {
563
735
  async resume(sandboxId: string): Promise<void> {
564
736
  return sandboxResume(this.#client, { sandboxId, orgId: this.#orgId });
565
737
  }
738
+
739
+ // ===== List Operations =====
740
+
741
+ /**
742
+ * List all sandboxes with optional filtering and pagination
743
+ *
744
+ * @param params - Optional parameters for filtering by project, status, and pagination
745
+ * @returns Paginated list of sandboxes with total count
746
+ */
747
+ async list(params?: ListSandboxesParams): Promise<ListSandboxesResponse> {
748
+ return sandboxList(this.#client, { ...params, orgId: this.#orgId });
749
+ }
750
+
751
+ /**
752
+ * List available sandbox runtimes
753
+ *
754
+ * @param params - Optional parameters for pagination
755
+ * @returns List of runtimes with total count
756
+ */
757
+ async listRuntimes(params?: ListRuntimesParams): Promise<ListRuntimesResponse> {
758
+ return runtimeList(this.#client, { ...params, orgId: this.#orgId });
759
+ }
760
+
761
+ // ===== Job Operations =====
762
+
763
+ /**
764
+ * Create a new job in a sandbox
765
+ *
766
+ * @param sandboxId - The sandbox ID where the job should run
767
+ * @param options - Job creation options including command
768
+ * @returns A job instance with get() and stop() methods
769
+ */
770
+ async createJob(sandboxId: string, options: CreateJobOptions): Promise<JobInstance> {
771
+ const job = await jobCreate(this.#client, { sandboxId, options, orgId: this.#orgId });
772
+
773
+ return {
774
+ id: job.jobId,
775
+ sandboxId,
776
+ status: job.status,
777
+ ...createJobInstanceMethods(this.#client, sandboxId, job.jobId, this.#orgId),
778
+ };
779
+ }
780
+
781
+ /**
782
+ * Get a job instance by ID
783
+ *
784
+ * @param sandboxId - The sandbox ID
785
+ * @param jobId - The job ID
786
+ * @returns A job instance with get() and stop() methods
787
+ */
788
+ async getJob(sandboxId: string, jobId: string): Promise<JobInstance> {
789
+ const job = await jobGet(this.#client, { sandboxId, jobId, orgId: this.#orgId });
790
+
791
+ return {
792
+ id: job.jobId,
793
+ sandboxId,
794
+ status: job.status,
795
+ ...createJobInstanceMethods(this.#client, sandboxId, job.jobId, this.#orgId),
796
+ };
797
+ }
798
+
799
+ /**
800
+ * List all jobs in a sandbox
801
+ *
802
+ * @param sandboxId - The sandbox ID
803
+ * @param limit - Maximum number of results
804
+ * @returns List of jobs
805
+ */
806
+ async listJobs(sandboxId: string, limit?: number): Promise<JobListResponse> {
807
+ return jobList(this.#client, { sandboxId, limit, orgId: this.#orgId });
808
+ }
809
+
810
+ // ===== Disk Checkpoint Operations =====
811
+
812
+ /**
813
+ * Create a disk checkpoint of a sandbox
814
+ *
815
+ * @param sandboxId - The sandbox ID
816
+ * @param name - Name for the checkpoint
817
+ * @returns A checkpoint instance with restore() and delete() methods
818
+ */
819
+ async createDiskCheckpoint(sandboxId: string, name: string): Promise<DiskCheckpointInstance> {
820
+ const checkpoint = await diskCheckpointCreate(this.#client, {
821
+ sandboxId,
822
+ name,
823
+ orgId: this.#orgId,
824
+ });
825
+
826
+ return {
827
+ id: checkpoint.id,
828
+ name: checkpoint.name,
829
+ sandboxId,
830
+ createdAt: checkpoint.createdAt,
831
+ parent: checkpoint.parent,
832
+ ...createDiskCheckpointInstanceMethods(
833
+ this.#client,
834
+ sandboxId,
835
+ checkpoint.id,
836
+ this.#orgId
837
+ ),
838
+ };
839
+ }
840
+
841
+ /**
842
+ * List all disk checkpoints for a sandbox
843
+ *
844
+ * @param sandboxId - The sandbox ID
845
+ * @returns List of checkpoint info objects
846
+ */
847
+ async listDiskCheckpoints(sandboxId: string): Promise<DiskCheckpointInfo[]> {
848
+ return diskCheckpointList(this.#client, { sandboxId, orgId: this.#orgId });
849
+ }
850
+
851
+ /**
852
+ * Get a disk checkpoint instance by ID
853
+ *
854
+ * @param sandboxId - The sandbox ID
855
+ * @param checkpointId - The checkpoint ID
856
+ * @returns A checkpoint instance with restore() and delete() methods
857
+ */
858
+ async getDiskCheckpoint(
859
+ sandboxId: string,
860
+ checkpointId: string
861
+ ): Promise<DiskCheckpointInstance> {
862
+ const checkpoints = await diskCheckpointList(this.#client, {
863
+ sandboxId,
864
+ orgId: this.#orgId,
865
+ });
866
+ const checkpoint = checkpoints.find((c) => c.id === checkpointId);
867
+ if (!checkpoint) {
868
+ throw new Error(`Checkpoint ${checkpointId} not found in sandbox ${sandboxId}`);
869
+ }
870
+
871
+ return {
872
+ id: checkpoint.id,
873
+ name: checkpoint.name,
874
+ sandboxId,
875
+ createdAt: checkpoint.createdAt,
876
+ parent: checkpoint.parent,
877
+ ...createDiskCheckpointInstanceMethods(
878
+ this.#client,
879
+ sandboxId,
880
+ checkpoint.id,
881
+ this.#orgId
882
+ ),
883
+ };
884
+ }
885
+
886
+ // ===== Snapshot Operations =====
887
+
888
+ /**
889
+ * Create a snapshot of a sandbox
890
+ *
891
+ * @param sandboxId - The sandbox ID to snapshot
892
+ * @param params - Optional snapshot parameters (name, tag, public, etc.)
893
+ * @returns The created snapshot information
894
+ */
895
+ async createSnapshot(
896
+ sandboxId: string,
897
+ params?: {
898
+ name?: string;
899
+ description?: string;
900
+ tag?: string;
901
+ public?: boolean;
902
+ }
903
+ ): Promise<SnapshotInfo> {
904
+ return snapshotCreate(this.#client, { sandboxId, ...params, orgId: this.#orgId });
905
+ }
906
+
907
+ /**
908
+ * Get snapshot information by ID
909
+ *
910
+ * @param snapshotId - The snapshot ID
911
+ * @returns Snapshot information
912
+ */
913
+ async getSnapshot(snapshotId: string): Promise<SnapshotInfo> {
914
+ return snapshotGet(this.#client, { snapshotId, orgId: this.#orgId });
915
+ }
916
+
917
+ /**
918
+ * List snapshots with optional filtering and pagination
919
+ *
920
+ * @param params - Optional parameters for filtering and pagination
921
+ * @returns Paginated list of snapshots
922
+ */
923
+ async listSnapshots(params?: SnapshotListParams): Promise<SnapshotListResponse> {
924
+ return snapshotList(this.#client, { ...params, orgId: this.#orgId });
925
+ }
926
+
927
+ /**
928
+ * Delete a snapshot
929
+ *
930
+ * @param snapshotId - The snapshot ID to delete
931
+ */
932
+ async deleteSnapshot(snapshotId: string): Promise<void> {
933
+ return snapshotDelete(this.#client, { snapshotId, orgId: this.#orgId });
934
+ }
935
+
936
+ /**
937
+ * Update the tag on a snapshot
938
+ *
939
+ * @param snapshotId - The snapshot ID
940
+ * @param tag - New tag (or null to remove)
941
+ * @returns Updated snapshot information
942
+ */
943
+ async tagSnapshot(snapshotId: string, tag: string | null): Promise<SnapshotInfo> {
944
+ return snapshotTag(this.#client, { snapshotId, tag, orgId: this.#orgId });
945
+ }
946
+
947
+ /**
948
+ * Get the lineage (ancestry chain) of a snapshot
949
+ *
950
+ * @param params - Parameters specifying which snapshot to get lineage for
951
+ * @returns Ordered list of snapshots in the lineage
952
+ */
953
+ async getSnapshotLineage(params?: SnapshotLineageParams): Promise<SnapshotLineageResponse> {
954
+ return snapshotLineage(this.#client, { ...params, orgId: this.#orgId });
955
+ }
956
+
957
+ // ===== Execution Operations =====
958
+
959
+ /**
960
+ * Get execution information by ID
961
+ *
962
+ * @param executionId - The execution ID
963
+ * @param wait - Optional wait duration for long-polling (e.g., "5m")
964
+ * @returns Execution information
965
+ */
966
+ async getExecution(executionId: string, wait?: string): Promise<ExecutionInfo> {
967
+ return executionGet(this.#client, { executionId, wait, orgId: this.#orgId });
968
+ }
969
+
970
+ /**
971
+ * List executions for a sandbox
972
+ *
973
+ * @param sandboxId - The sandbox ID
974
+ * @param limit - Maximum number of results
975
+ * @returns List of executions
976
+ */
977
+ async listExecutions(sandboxId: string, limit?: number): Promise<ExecutionListResponse> {
978
+ return executionList(this.#client, { sandboxId, limit, orgId: this.#orgId });
979
+ }
980
+
981
+ // ===== Event Operations =====
982
+
983
+ /**
984
+ * List events for a sandbox
985
+ *
986
+ * @param sandboxId - The sandbox ID
987
+ * @param params - Optional parameters for limit and sort direction
988
+ * @returns List of sandbox events
989
+ */
990
+ async listEvents(
991
+ sandboxId: string,
992
+ params?: { limit?: number; direction?: 'asc' | 'desc' }
993
+ ): Promise<SandboxEventListResponse> {
994
+ return sandboxEventList(this.#client, { sandboxId, ...params, orgId: this.#orgId });
995
+ }
566
996
  }
@@ -133,6 +133,10 @@ export const SandboxCreateDataSchema = z
133
133
  'failed',
134
134
  ])
135
135
  .describe('Current status of the sandbox'),
136
+ url: z
137
+ .string()
138
+ .optional()
139
+ .describe('Public URL for the sandbox (only set when a network port is configured)'),
136
140
  stdoutStreamId: z.string().optional().describe('Stream ID for reading stdout'),
137
141
  stdoutStreamUrl: z.string().optional().describe('URL for streaming stdout output'),
138
142
  stderrStreamId: z.string().optional().describe('Stream ID for reading stderr'),
@@ -44,6 +44,8 @@ export const ExecutionGetParamsSchema = z.object({
44
44
  orgId: z.string().optional().describe('organization id'),
45
45
  /** Optional wait duration for long-polling. */
46
46
  wait: z.string().optional().describe('wait duration for long-polling'),
47
+ /** Optional AbortSignal to cancel the in-flight request. */
48
+ signal: z.custom<AbortSignal>().optional().describe('abort signal for cancellation'),
47
49
  });
48
50
  export type ExecutionGetParams = z.infer<typeof ExecutionGetParamsSchema>;
49
51
 
@@ -67,7 +69,7 @@ export async function executionGet(
67
69
  client: APIClient,
68
70
  params: ExecutionGetParams
69
71
  ): Promise<ExecutionInfo> {
70
- const { executionId, orgId, wait } = params;
72
+ const { executionId, orgId, wait, signal } = params;
71
73
  const queryParams = new URLSearchParams();
72
74
  if (orgId) {
73
75
  queryParams.set('orgId', orgId);
@@ -80,7 +82,8 @@ export async function executionGet(
80
82
 
81
83
  const resp = await client.get<z.infer<typeof ExecutionGetResponseSchema>>(
82
84
  url,
83
- ExecutionGetResponseSchema
85
+ ExecutionGetResponseSchema,
86
+ signal
84
87
  );
85
88
 
86
89
  if (resp.success) {
@@ -124,7 +124,7 @@ export async function sandboxReadFile(
124
124
  if (!response.ok) {
125
125
  const text = await response.text().catch(() => 'Unknown error');
126
126
  throw new SandboxResponseError({
127
- message: `Failed to read file: ${response.status} ${text}`,
127
+ message: `Failed to read file "${path}": ${response.status} ${text}`,
128
128
  sandboxId,
129
129
  sessionId,
130
130
  });
@@ -11,6 +11,8 @@ export type {
11
11
  SandboxClientOptions,
12
12
  SandboxClientRunIO,
13
13
  SandboxInstance,
14
+ JobInstance,
15
+ DiskCheckpointInstance,
14
16
  } from './client.ts';
15
17
  export {
16
18
  ExecuteOptionsSchema as SandboxClientExecuteOptionsSchema,
@@ -78,6 +80,24 @@ export {
78
80
  executionGet,
79
81
  executionList,
80
82
  } from './execution.ts';
83
+ export type {
84
+ JobCreateParams,
85
+ JobGetParams,
86
+ JobListParams,
87
+ JobListResponse,
88
+ JobStopParams,
89
+ } from './job.ts';
90
+ export {
91
+ JobCreateParamsSchema,
92
+ JobGetParamsSchema,
93
+ JobListParamsSchema,
94
+ JobListResponseSchema,
95
+ JobStopParamsSchema,
96
+ jobCreate,
97
+ jobGet,
98
+ jobList,
99
+ jobStop,
100
+ } from './job.ts';
81
101
  export type {
82
102
  SandboxEventInfo,
83
103
  SandboxEventListParams,