@sealant/sdk 0.5.1 → 0.7.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/dist/client.d.ts +8 -1
- package/dist/client.js +26 -1
- package/dist/effect/api-client.d.ts +710 -14
- package/dist/effect/operations.d.ts +226 -6
- package/dist/effect/operations.js +18 -0
- package/dist/effect/run-harness.js +32 -13
- package/dist/facade/session.d.ts +22 -0
- package/dist/facade/session.js +171 -0
- package/dist/facade/workspace.js +109 -6
- package/dist/internal/blueprint.d.ts +1 -0
- package/dist/internal/blueprint.js +23 -8
- package/dist/internal/duration.d.ts +6 -0
- package/dist/internal/duration.js +34 -0
- package/dist/types.d.ts +136 -14
- package/package.json +2 -2
|
@@ -25,10 +25,11 @@ export declare const createWorkspaceOp: (payload: {
|
|
|
25
25
|
readonly github?: string | undefined;
|
|
26
26
|
} | undefined;
|
|
27
27
|
readonly spec: unknown;
|
|
28
|
+
readonly ttlSeconds?: number | undefined;
|
|
28
29
|
}, idempotencyKey?: string | undefined) => Effect.Effect<{
|
|
29
30
|
readonly workspaceId: string;
|
|
30
31
|
readonly name: string;
|
|
31
|
-
readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
|
|
32
|
+
readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
|
|
32
33
|
readonly registryId: string;
|
|
33
34
|
readonly repository: string;
|
|
34
35
|
readonly tag: string;
|
|
@@ -37,7 +38,7 @@ export declare const getWorkspaceOp: (workspaceId: string) => Effect.Effect<{
|
|
|
37
38
|
readonly workspaceId: string;
|
|
38
39
|
readonly name: string;
|
|
39
40
|
readonly ownerUserId: string;
|
|
40
|
-
readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
|
|
41
|
+
readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
|
|
41
42
|
readonly registryId?: string | undefined;
|
|
42
43
|
readonly repository?: string | undefined;
|
|
43
44
|
readonly tag?: string | undefined;
|
|
@@ -61,18 +62,19 @@ export declare const getWorkspaceOp: (workspaceId: string) => Effect.Effect<{
|
|
|
61
62
|
readonly updatedAt: string;
|
|
62
63
|
readonly startedAt?: string | undefined;
|
|
63
64
|
readonly finishedAt?: string | undefined;
|
|
65
|
+
readonly expiresAt?: string | undefined;
|
|
64
66
|
readonly spec?: unknown;
|
|
65
67
|
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError, SealantApiClient>;
|
|
66
68
|
export declare const listWorkspacesOp: (query: {
|
|
67
69
|
readonly ownerUserId: string;
|
|
68
|
-
readonly status?: "cancelled" | "failed" | "queued" | "ready" | "running" | undefined;
|
|
70
|
+
readonly status?: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped" | undefined;
|
|
69
71
|
readonly limit?: string | undefined;
|
|
70
72
|
}) => Effect.Effect<{
|
|
71
73
|
readonly items: readonly {
|
|
72
74
|
readonly workspaceId: string;
|
|
73
75
|
readonly name: string;
|
|
74
76
|
readonly ownerUserId: string;
|
|
75
|
-
readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
|
|
77
|
+
readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
|
|
76
78
|
readonly registryId?: string | undefined;
|
|
77
79
|
readonly repository?: string | undefined;
|
|
78
80
|
readonly tag?: string | undefined;
|
|
@@ -96,6 +98,7 @@ export declare const listWorkspacesOp: (query: {
|
|
|
96
98
|
readonly updatedAt: string;
|
|
97
99
|
readonly startedAt?: string | undefined;
|
|
98
100
|
readonly finishedAt?: string | undefined;
|
|
101
|
+
readonly expiresAt?: string | undefined;
|
|
99
102
|
}[];
|
|
100
103
|
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceInternalServerError, SealantApiClient>;
|
|
101
104
|
export declare const execWorkspaceOp: (workspaceId: string, payload: {
|
|
@@ -114,6 +117,14 @@ export declare const execWorkspaceOp: (workspaceId: string, payload: {
|
|
|
114
117
|
readonly mode: "interactive" | "one-shot";
|
|
115
118
|
readonly status: "cancelled" | "completed" | "failed" | "queued" | "running";
|
|
116
119
|
readonly prompt?: string | undefined;
|
|
120
|
+
readonly command?: {
|
|
121
|
+
readonly executable: string;
|
|
122
|
+
readonly args: readonly string[];
|
|
123
|
+
readonly cwd?: string | undefined;
|
|
124
|
+
} | undefined;
|
|
125
|
+
readonly metadata?: {
|
|
126
|
+
readonly [x: string]: unknown;
|
|
127
|
+
} | undefined;
|
|
117
128
|
readonly exitCode?: number | undefined;
|
|
118
129
|
readonly errorMessage?: string | undefined;
|
|
119
130
|
readonly startedAt?: string | undefined;
|
|
@@ -121,6 +132,26 @@ export declare const execWorkspaceOp: (workspaceId: string, payload: {
|
|
|
121
132
|
readonly createdAt: string;
|
|
122
133
|
readonly updatedAt: string;
|
|
123
134
|
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError, SealantApiClient>;
|
|
135
|
+
export declare const stopWorkspaceOp: (workspaceId: string, payload: {
|
|
136
|
+
readonly ownerUserId: string;
|
|
137
|
+
}) => Effect.Effect<{
|
|
138
|
+
readonly workspaceId: string;
|
|
139
|
+
readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
|
|
140
|
+
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadGatewayError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError, SealantApiClient>;
|
|
141
|
+
export declare const restartWorkspaceOp: (workspaceId: string, payload: {
|
|
142
|
+
readonly ownerUserId: string;
|
|
143
|
+
}) => Effect.Effect<{
|
|
144
|
+
readonly workspaceId: string;
|
|
145
|
+
readonly runId: string;
|
|
146
|
+
readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
|
|
147
|
+
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadGatewayError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError, SealantApiClient>;
|
|
148
|
+
export declare const expireWorkspaceOp: (workspaceId: string, payload: {
|
|
149
|
+
readonly ownerUserId: string;
|
|
150
|
+
readonly ttlSeconds?: number | null | undefined;
|
|
151
|
+
}) => Effect.Effect<{
|
|
152
|
+
readonly workspaceId: string;
|
|
153
|
+
readonly expiresAt: string | null;
|
|
154
|
+
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError, SealantApiClient>;
|
|
124
155
|
export declare const createRunOp: (payload: {
|
|
125
156
|
readonly workspaceId: string;
|
|
126
157
|
readonly harnessId: string;
|
|
@@ -133,6 +164,9 @@ export declare const createRunOp: (payload: {
|
|
|
133
164
|
readonly args: readonly string[];
|
|
134
165
|
readonly cwd?: string | undefined;
|
|
135
166
|
} | undefined;
|
|
167
|
+
readonly metadata?: {
|
|
168
|
+
readonly [x: string]: unknown;
|
|
169
|
+
} | undefined;
|
|
136
170
|
}) => Effect.Effect<{
|
|
137
171
|
readonly runId: string;
|
|
138
172
|
readonly workspaceId: string;
|
|
@@ -142,6 +176,14 @@ export declare const createRunOp: (payload: {
|
|
|
142
176
|
readonly mode: "interactive" | "one-shot";
|
|
143
177
|
readonly status: "cancelled" | "completed" | "failed" | "queued" | "running";
|
|
144
178
|
readonly prompt?: string | undefined;
|
|
179
|
+
readonly command?: {
|
|
180
|
+
readonly executable: string;
|
|
181
|
+
readonly args: readonly string[];
|
|
182
|
+
readonly cwd?: string | undefined;
|
|
183
|
+
} | undefined;
|
|
184
|
+
readonly metadata?: {
|
|
185
|
+
readonly [x: string]: unknown;
|
|
186
|
+
} | undefined;
|
|
145
187
|
readonly exitCode?: number | undefined;
|
|
146
188
|
readonly errorMessage?: string | undefined;
|
|
147
189
|
readonly startedAt?: string | undefined;
|
|
@@ -158,6 +200,14 @@ export declare const getRunOp: (runId: string) => Effect.Effect<{
|
|
|
158
200
|
readonly mode: "interactive" | "one-shot";
|
|
159
201
|
readonly status: "cancelled" | "completed" | "failed" | "queued" | "running";
|
|
160
202
|
readonly prompt?: string | undefined;
|
|
203
|
+
readonly command?: {
|
|
204
|
+
readonly executable: string;
|
|
205
|
+
readonly args: readonly string[];
|
|
206
|
+
readonly cwd?: string | undefined;
|
|
207
|
+
} | undefined;
|
|
208
|
+
readonly metadata?: {
|
|
209
|
+
readonly [x: string]: unknown;
|
|
210
|
+
} | undefined;
|
|
161
211
|
readonly exitCode?: number | undefined;
|
|
162
212
|
readonly errorMessage?: string | undefined;
|
|
163
213
|
readonly startedAt?: string | undefined;
|
|
@@ -180,6 +230,14 @@ export declare const listRunsOp: (query: {
|
|
|
180
230
|
readonly mode: "interactive" | "one-shot";
|
|
181
231
|
readonly status: "cancelled" | "completed" | "failed" | "queued" | "running";
|
|
182
232
|
readonly prompt?: string | undefined;
|
|
233
|
+
readonly command?: {
|
|
234
|
+
readonly executable: string;
|
|
235
|
+
readonly args: readonly string[];
|
|
236
|
+
readonly cwd?: string | undefined;
|
|
237
|
+
} | undefined;
|
|
238
|
+
readonly metadata?: {
|
|
239
|
+
readonly [x: string]: unknown;
|
|
240
|
+
} | undefined;
|
|
183
241
|
readonly exitCode?: number | undefined;
|
|
184
242
|
readonly errorMessage?: string | undefined;
|
|
185
243
|
readonly startedAt?: string | undefined;
|
|
@@ -207,6 +265,14 @@ export declare const updateRunOp: (runId: string, payload: {
|
|
|
207
265
|
readonly mode: "interactive" | "one-shot";
|
|
208
266
|
readonly status: "cancelled" | "completed" | "failed" | "queued" | "running";
|
|
209
267
|
readonly prompt?: string | undefined;
|
|
268
|
+
readonly command?: {
|
|
269
|
+
readonly executable: string;
|
|
270
|
+
readonly args: readonly string[];
|
|
271
|
+
readonly cwd?: string | undefined;
|
|
272
|
+
} | undefined;
|
|
273
|
+
readonly metadata?: {
|
|
274
|
+
readonly [x: string]: unknown;
|
|
275
|
+
} | undefined;
|
|
210
276
|
readonly exitCode?: number | undefined;
|
|
211
277
|
readonly errorMessage?: string | undefined;
|
|
212
278
|
readonly startedAt?: string | undefined;
|
|
@@ -232,11 +298,13 @@ export declare const getRunTimelineOp: (runId: string, query: {
|
|
|
232
298
|
}[], import("effect/unstable/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").RunBadRequestError | import("@sealant/api-contracts").RunInternalServerError | import("@sealant/api-contracts").RunNotFoundError | import("effect/Schema").SchemaError, SealantApiClient>;
|
|
233
299
|
export declare const getRunScrollbackOp: (runId: string, query: {
|
|
234
300
|
readonly processId: string;
|
|
235
|
-
readonly stream: "stderr" | "stdout";
|
|
301
|
+
readonly stream: "pty" | "stderr" | "stdout";
|
|
236
302
|
readonly atSequence?: string | undefined;
|
|
303
|
+
readonly fromSequence?: string | undefined;
|
|
304
|
+
readonly limit?: string | undefined;
|
|
237
305
|
}) => Effect.Effect<{
|
|
238
306
|
readonly processId: string;
|
|
239
|
-
readonly stream: "stderr" | "stdout";
|
|
307
|
+
readonly stream: "pty" | "stderr" | "stdout";
|
|
240
308
|
readonly byteCount: number;
|
|
241
309
|
readonly contentBase64: string;
|
|
242
310
|
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").RunBadRequestError | import("@sealant/api-contracts").RunInternalServerError | import("@sealant/api-contracts").RunNotFoundError | import("effect/Schema").SchemaError, SealantApiClient>;
|
|
@@ -263,6 +331,158 @@ export declare const getRunChangesOp: (runId: string) => Effect.Effect<{
|
|
|
263
331
|
}[];
|
|
264
332
|
readonly diff: string;
|
|
265
333
|
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").RunInternalServerError | import("@sealant/api-contracts").RunNotFoundError | import("effect/Schema").SchemaError, SealantApiClient>;
|
|
334
|
+
export declare const createSessionOp: (payload: {
|
|
335
|
+
readonly workspaceId: string;
|
|
336
|
+
readonly ownerUserId: string;
|
|
337
|
+
readonly argv: readonly string[];
|
|
338
|
+
readonly cwd?: string | undefined;
|
|
339
|
+
readonly env?: {
|
|
340
|
+
readonly [x: string]: string;
|
|
341
|
+
} | undefined;
|
|
342
|
+
readonly cols?: number | undefined;
|
|
343
|
+
readonly rows?: number | undefined;
|
|
344
|
+
readonly term?: string | undefined;
|
|
345
|
+
readonly metadata?: {
|
|
346
|
+
readonly [x: string]: unknown;
|
|
347
|
+
} | undefined;
|
|
348
|
+
}) => Effect.Effect<{
|
|
349
|
+
readonly sessionId: string;
|
|
350
|
+
readonly workspaceId: string;
|
|
351
|
+
readonly runId: string;
|
|
352
|
+
readonly ownerUserId: string;
|
|
353
|
+
readonly status: "exited" | "failed" | "running" | "starting";
|
|
354
|
+
readonly argv: readonly string[];
|
|
355
|
+
readonly cwd?: string | undefined;
|
|
356
|
+
readonly cols: number;
|
|
357
|
+
readonly rows: number;
|
|
358
|
+
readonly exitCode?: number | undefined;
|
|
359
|
+
readonly exitSignal?: number | undefined;
|
|
360
|
+
readonly errorMessage?: string | undefined;
|
|
361
|
+
readonly metadata?: {
|
|
362
|
+
readonly [x: string]: unknown;
|
|
363
|
+
} | undefined;
|
|
364
|
+
readonly outputHighWater: string;
|
|
365
|
+
readonly createdAt: string;
|
|
366
|
+
readonly endedAt?: string | undefined;
|
|
367
|
+
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").SessionBadGatewayError | import("@sealant/api-contracts").SessionBadRequestError | import("@sealant/api-contracts").SessionConflictError | import("@sealant/api-contracts").SessionForbiddenError | import("@sealant/api-contracts").SessionInternalServerError | import("@sealant/api-contracts").SessionNotFoundError | import("@sealant/api-contracts").SessionUnauthorizedError, SealantApiClient>;
|
|
368
|
+
export declare const getSessionOp: (sessionId: string, ownerUserId?: string | undefined) => Effect.Effect<{
|
|
369
|
+
readonly sessionId: string;
|
|
370
|
+
readonly workspaceId: string;
|
|
371
|
+
readonly runId: string;
|
|
372
|
+
readonly ownerUserId: string;
|
|
373
|
+
readonly status: "exited" | "failed" | "running" | "starting";
|
|
374
|
+
readonly argv: readonly string[];
|
|
375
|
+
readonly cwd?: string | undefined;
|
|
376
|
+
readonly cols: number;
|
|
377
|
+
readonly rows: number;
|
|
378
|
+
readonly exitCode?: number | undefined;
|
|
379
|
+
readonly exitSignal?: number | undefined;
|
|
380
|
+
readonly errorMessage?: string | undefined;
|
|
381
|
+
readonly metadata?: {
|
|
382
|
+
readonly [x: string]: unknown;
|
|
383
|
+
} | undefined;
|
|
384
|
+
readonly outputHighWater: string;
|
|
385
|
+
readonly createdAt: string;
|
|
386
|
+
readonly endedAt?: string | undefined;
|
|
387
|
+
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").SessionBadRequestError | import("@sealant/api-contracts").SessionForbiddenError | import("@sealant/api-contracts").SessionInternalServerError | import("@sealant/api-contracts").SessionNotFoundError | import("@sealant/api-contracts").SessionUnauthorizedError, SealantApiClient>;
|
|
388
|
+
export declare const listSessionsOp: (query: {
|
|
389
|
+
readonly ownerUserId: string;
|
|
390
|
+
readonly workspaceId?: string | undefined;
|
|
391
|
+
readonly status?: "exited" | "failed" | "running" | "starting" | undefined;
|
|
392
|
+
readonly limit?: string | undefined;
|
|
393
|
+
}) => Effect.Effect<{
|
|
394
|
+
readonly items: readonly {
|
|
395
|
+
readonly sessionId: string;
|
|
396
|
+
readonly workspaceId: string;
|
|
397
|
+
readonly runId: string;
|
|
398
|
+
readonly ownerUserId: string;
|
|
399
|
+
readonly status: "exited" | "failed" | "running" | "starting";
|
|
400
|
+
readonly argv: readonly string[];
|
|
401
|
+
readonly cwd?: string | undefined;
|
|
402
|
+
readonly cols: number;
|
|
403
|
+
readonly rows: number;
|
|
404
|
+
readonly exitCode?: number | undefined;
|
|
405
|
+
readonly exitSignal?: number | undefined;
|
|
406
|
+
readonly errorMessage?: string | undefined;
|
|
407
|
+
readonly metadata?: {
|
|
408
|
+
readonly [x: string]: unknown;
|
|
409
|
+
} | undefined;
|
|
410
|
+
readonly outputHighWater: string;
|
|
411
|
+
readonly createdAt: string;
|
|
412
|
+
readonly endedAt?: string | undefined;
|
|
413
|
+
}[];
|
|
414
|
+
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").SessionBadRequestError | import("@sealant/api-contracts").SessionForbiddenError | import("@sealant/api-contracts").SessionInternalServerError | import("@sealant/api-contracts").SessionUnauthorizedError, SealantApiClient>;
|
|
415
|
+
export declare const getSessionOutputOp: (sessionId: string, query: {
|
|
416
|
+
readonly ownerUserId?: string | undefined;
|
|
417
|
+
readonly from?: string | undefined;
|
|
418
|
+
readonly limit?: string | undefined;
|
|
419
|
+
}) => Effect.Effect<{
|
|
420
|
+
readonly sessionId: string;
|
|
421
|
+
readonly chunks: readonly {
|
|
422
|
+
readonly sequence: string;
|
|
423
|
+
readonly dataBase64: string;
|
|
424
|
+
}[];
|
|
425
|
+
readonly nextFrom: string;
|
|
426
|
+
readonly status: "exited" | "failed" | "running" | "starting";
|
|
427
|
+
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").SessionBadRequestError | import("@sealant/api-contracts").SessionForbiddenError | import("@sealant/api-contracts").SessionInternalServerError | import("@sealant/api-contracts").SessionNotFoundError | import("@sealant/api-contracts").SessionUnauthorizedError, SealantApiClient>;
|
|
428
|
+
export declare const sendSessionInputOp: (sessionId: string, payload: {
|
|
429
|
+
readonly ownerUserId?: string | undefined;
|
|
430
|
+
readonly dataBase64: string;
|
|
431
|
+
}) => Effect.Effect<{
|
|
432
|
+
readonly ok: boolean;
|
|
433
|
+
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").SessionBadGatewayError | import("@sealant/api-contracts").SessionBadRequestError | import("@sealant/api-contracts").SessionConflictError | import("@sealant/api-contracts").SessionForbiddenError | import("@sealant/api-contracts").SessionInternalServerError | import("@sealant/api-contracts").SessionNotFoundError | import("@sealant/api-contracts").SessionUnauthorizedError, SealantApiClient>;
|
|
434
|
+
export declare const resizeSessionOp: (sessionId: string, payload: {
|
|
435
|
+
readonly ownerUserId?: string | undefined;
|
|
436
|
+
readonly cols: number;
|
|
437
|
+
readonly rows: number;
|
|
438
|
+
}) => Effect.Effect<{
|
|
439
|
+
readonly ok: boolean;
|
|
440
|
+
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").SessionBadGatewayError | import("@sealant/api-contracts").SessionBadRequestError | import("@sealant/api-contracts").SessionConflictError | import("@sealant/api-contracts").SessionForbiddenError | import("@sealant/api-contracts").SessionInternalServerError | import("@sealant/api-contracts").SessionNotFoundError | import("@sealant/api-contracts").SessionUnauthorizedError, SealantApiClient>;
|
|
441
|
+
export declare const signalSessionOp: (sessionId: string, payload: {
|
|
442
|
+
readonly ownerUserId?: string | undefined;
|
|
443
|
+
readonly signal: number;
|
|
444
|
+
}) => Effect.Effect<{
|
|
445
|
+
readonly ok: boolean;
|
|
446
|
+
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").SessionBadGatewayError | import("@sealant/api-contracts").SessionBadRequestError | import("@sealant/api-contracts").SessionConflictError | import("@sealant/api-contracts").SessionForbiddenError | import("@sealant/api-contracts").SessionInternalServerError | import("@sealant/api-contracts").SessionNotFoundError | import("@sealant/api-contracts").SessionUnauthorizedError, SealantApiClient>;
|
|
447
|
+
export declare const closeSessionOp: (sessionId: string, payload: {
|
|
448
|
+
readonly ownerUserId?: string | undefined;
|
|
449
|
+
}) => Effect.Effect<{
|
|
450
|
+
readonly sessionId: string;
|
|
451
|
+
readonly workspaceId: string;
|
|
452
|
+
readonly runId: string;
|
|
453
|
+
readonly ownerUserId: string;
|
|
454
|
+
readonly status: "exited" | "failed" | "running" | "starting";
|
|
455
|
+
readonly argv: readonly string[];
|
|
456
|
+
readonly cwd?: string | undefined;
|
|
457
|
+
readonly cols: number;
|
|
458
|
+
readonly rows: number;
|
|
459
|
+
readonly exitCode?: number | undefined;
|
|
460
|
+
readonly exitSignal?: number | undefined;
|
|
461
|
+
readonly errorMessage?: string | undefined;
|
|
462
|
+
readonly metadata?: {
|
|
463
|
+
readonly [x: string]: unknown;
|
|
464
|
+
} | undefined;
|
|
465
|
+
readonly outputHighWater: string;
|
|
466
|
+
readonly createdAt: string;
|
|
467
|
+
readonly endedAt?: string | undefined;
|
|
468
|
+
}, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").SessionBadGatewayError | import("@sealant/api-contracts").SessionBadRequestError | import("@sealant/api-contracts").SessionForbiddenError | import("@sealant/api-contracts").SessionInternalServerError | import("@sealant/api-contracts").SessionNotFoundError | import("@sealant/api-contracts").SessionUnauthorizedError, SealantApiClient>;
|
|
469
|
+
export declare const createAccessTokenOp: (payload: {
|
|
470
|
+
readonly ownerUserId: string;
|
|
471
|
+
readonly scopes: readonly ("session:input" | "session:read" | "workspace:exec")[];
|
|
472
|
+
readonly name?: string | undefined;
|
|
473
|
+
readonly workspaceId?: string | undefined;
|
|
474
|
+
readonly ttlSeconds?: number | undefined;
|
|
475
|
+
}) => Effect.Effect<{
|
|
476
|
+
readonly tokenId: string;
|
|
477
|
+
readonly ownerUserId: string;
|
|
478
|
+
readonly name?: string | undefined;
|
|
479
|
+
readonly scopes: readonly ("session:input" | "session:read" | "workspace:exec")[];
|
|
480
|
+
readonly workspaceId?: string | undefined;
|
|
481
|
+
readonly expiresAt?: string | undefined;
|
|
482
|
+
readonly revokedAt?: string | undefined;
|
|
483
|
+
readonly createdAt: string;
|
|
484
|
+
readonly token: string;
|
|
485
|
+
}, import("@sealant/api-contracts").AccessTokenBadRequestError | import("@sealant/api-contracts").AccessTokenInternalServerError | import("@sealant/api-contracts").AccessTokenNotFoundError | import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError, SealantApiClient>;
|
|
266
486
|
export declare const inferenceRespondOp: (payload: {
|
|
267
487
|
readonly ownerUserId: string;
|
|
268
488
|
readonly credentials?: {
|
|
@@ -8,6 +8,9 @@ export const createWorkspaceOp = (payload, idempotencyKey) => Effect.flatMap(Sea
|
|
|
8
8
|
export const getWorkspaceOp = (workspaceId) => Effect.flatMap(SealantApiClient, (client) => client.workspaces.getWorkspace({ params: { workspaceId } }));
|
|
9
9
|
export const listWorkspacesOp = (query) => Effect.flatMap(SealantApiClient, (client) => client.workspaces.listWorkspaces({ query }));
|
|
10
10
|
export const execWorkspaceOp = (workspaceId, payload) => Effect.flatMap(SealantApiClient, (client) => client.workspaces.execWorkspace({ params: { workspaceId }, payload }));
|
|
11
|
+
export const stopWorkspaceOp = (workspaceId, payload) => Effect.flatMap(SealantApiClient, (client) => client.workspaces.stopWorkspace({ params: { workspaceId }, payload }));
|
|
12
|
+
export const restartWorkspaceOp = (workspaceId, payload) => Effect.flatMap(SealantApiClient, (client) => client.workspaces.restartWorkspace({ params: { workspaceId }, payload }));
|
|
13
|
+
export const expireWorkspaceOp = (workspaceId, payload) => Effect.flatMap(SealantApiClient, (client) => client.workspaces.expireWorkspace({ params: { workspaceId }, payload }));
|
|
11
14
|
// ---- runs ----
|
|
12
15
|
export const createRunOp = (payload) => Effect.flatMap(SealantApiClient, (client) => client.runs.createRun({ payload }));
|
|
13
16
|
export const getRunOp = (runId) => Effect.flatMap(SealantApiClient, (client) => client.runs.getRun({ params: { runId } }));
|
|
@@ -17,5 +20,20 @@ export const getRunTimelineOp = (runId, query) => Effect.flatMap(SealantApiClien
|
|
|
17
20
|
export const getRunScrollbackOp = (runId, query) => Effect.flatMap(SealantApiClient, (client) => client.runs.getRunScrollback({ params: { runId }, query }));
|
|
18
21
|
export const getRunLossOp = (runId) => Effect.flatMap(SealantApiClient, (client) => client.runs.getRunLoss({ params: { runId } }));
|
|
19
22
|
export const getRunChangesOp = (runId) => Effect.flatMap(SealantApiClient, (client) => client.runs.getRunChanges({ params: { runId } }));
|
|
23
|
+
// ---- sessions ----
|
|
24
|
+
export const createSessionOp = (payload) => Effect.flatMap(SealantApiClient, (client) => client.sessions.createSession({ payload, headers: {} }));
|
|
25
|
+
export const getSessionOp = (sessionId, ownerUserId) => Effect.flatMap(SealantApiClient, (client) => client.sessions.getSession({
|
|
26
|
+
params: { sessionId },
|
|
27
|
+
headers: {},
|
|
28
|
+
query: ownerUserId === undefined ? {} : { ownerUserId },
|
|
29
|
+
}));
|
|
30
|
+
export const listSessionsOp = (query) => Effect.flatMap(SealantApiClient, (client) => client.sessions.listSessions({ query, headers: {} }));
|
|
31
|
+
export const getSessionOutputOp = (sessionId, query) => Effect.flatMap(SealantApiClient, (client) => client.sessions.getSessionOutput({ params: { sessionId }, headers: {}, query }));
|
|
32
|
+
export const sendSessionInputOp = (sessionId, payload) => Effect.flatMap(SealantApiClient, (client) => client.sessions.sendSessionInput({ params: { sessionId }, headers: {}, payload }));
|
|
33
|
+
export const resizeSessionOp = (sessionId, payload) => Effect.flatMap(SealantApiClient, (client) => client.sessions.resizeSession({ params: { sessionId }, headers: {}, payload }));
|
|
34
|
+
export const signalSessionOp = (sessionId, payload) => Effect.flatMap(SealantApiClient, (client) => client.sessions.signalSession({ params: { sessionId }, headers: {}, payload }));
|
|
35
|
+
export const closeSessionOp = (sessionId, payload) => Effect.flatMap(SealantApiClient, (client) => client.sessions.closeSession({ params: { sessionId }, headers: {}, payload }));
|
|
36
|
+
// ---- access tokens ----
|
|
37
|
+
export const createAccessTokenOp = (payload) => Effect.flatMap(SealantApiClient, (client) => client.accessTokens.createAccessToken({ payload }));
|
|
20
38
|
// ---- inference ----
|
|
21
39
|
export const inferenceRespondOp = (payload) => Effect.flatMap(SealantApiClient, (client) => client.inference.respond({ payload }));
|
|
@@ -11,31 +11,50 @@
|
|
|
11
11
|
import { Effect } from "effect";
|
|
12
12
|
import { SealantError } from "../errors.js";
|
|
13
13
|
import { makeRun, toRunChangesData } from "../facade/run.js";
|
|
14
|
-
import { createRunOp, getRunChangesOp, getRunOp } from "./operations.js";
|
|
14
|
+
import { createRunOp, getRunChangesOp, getRunOp, getWorkspaceOp } from "./operations.js";
|
|
15
15
|
const TERMINAL_STATUSES = new Set(["completed", "failed", "cancelled"]);
|
|
16
16
|
const POLL_INTERVAL = "500 millis";
|
|
17
17
|
const RUN_TIMEOUT_MS = 30 * 60 * 1_000;
|
|
18
18
|
/**
|
|
19
|
-
* Registers the run
|
|
20
|
-
*
|
|
19
|
+
* Registers the run — the control plane executes it server-side (the worker docker-execs it and
|
|
20
|
+
* ingests telemetry). With a client harness value (the creating handle), the client-built command
|
|
21
|
+
* rides along — the escape hatch that keeps `customHarness()` working. WITHOUT one (a handle from
|
|
22
|
+
* `workspaces.get(id)`), the harness id is read from the workspace's own spec and NO command is
|
|
23
|
+
* sent: the control plane constructs the invocation server-side, so re-fetched handles are fully
|
|
24
|
+
* capable.
|
|
21
25
|
*/
|
|
22
|
-
const createHarnessRunEffect = (ctx, init, prompt) => Effect.gen(function* () {
|
|
26
|
+
const createHarnessRunEffect = (ctx, init, prompt, options) => Effect.gen(function* () {
|
|
27
|
+
const metadata = options?.metadata === undefined ? {} : { metadata: { ...options.metadata } };
|
|
23
28
|
const harness = init.harness;
|
|
24
|
-
if (harness
|
|
25
|
-
|
|
29
|
+
if (harness !== undefined) {
|
|
30
|
+
const command = harness.buildRunCommand(prompt);
|
|
31
|
+
return yield* createRunOp({
|
|
32
|
+
workspaceId: init.id,
|
|
33
|
+
ownerUserId: ctx.config.hostLocal.ownerUserId,
|
|
34
|
+
harnessId: harness.id,
|
|
35
|
+
mode: "one-shot",
|
|
36
|
+
prompt,
|
|
37
|
+
command: { executable: command.executable, args: [...command.args] },
|
|
38
|
+
...metadata,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
const details = yield* getWorkspaceOp(init.id);
|
|
42
|
+
const spec = details.spec;
|
|
43
|
+
const harnessId = spec?.harness?.id;
|
|
44
|
+
if (harnessId === undefined) {
|
|
45
|
+
return yield* Effect.fail(new SealantError(`Workspace ${init.id} has no harness in its spec; pass a harness at workspaces.create() or use workspace.exec().`, { code: "harness_required" }));
|
|
26
46
|
}
|
|
27
|
-
const command = harness.buildRunCommand(prompt);
|
|
28
47
|
return yield* createRunOp({
|
|
29
48
|
workspaceId: init.id,
|
|
30
49
|
ownerUserId: ctx.config.hostLocal.ownerUserId,
|
|
31
|
-
harnessId
|
|
50
|
+
harnessId,
|
|
32
51
|
mode: "one-shot",
|
|
33
52
|
prompt,
|
|
34
|
-
|
|
53
|
+
...metadata,
|
|
35
54
|
});
|
|
36
55
|
});
|
|
37
|
-
const runHarnessEffect = (ctx, init, prompt) => Effect.gen(function* () {
|
|
38
|
-
const created = yield* createHarnessRunEffect(ctx, init, prompt);
|
|
56
|
+
const runHarnessEffect = (ctx, init, prompt, options) => Effect.gen(function* () {
|
|
57
|
+
const created = yield* createHarnessRunEffect(ctx, init, prompt, options);
|
|
39
58
|
const runId = created.runId;
|
|
40
59
|
// Block until the run is terminal, polling the control plane.
|
|
41
60
|
const deadline = Date.now() + RUN_TIMEOUT_MS;
|
|
@@ -54,10 +73,10 @@ const runHarnessEffect = (ctx, init, prompt) => Effect.gen(function* () {
|
|
|
54
73
|
return makeRun(ctx, { wire, changes });
|
|
55
74
|
});
|
|
56
75
|
/** The BLOCKING `harness.run()` implementation, registered into the Workspace facade by the client. */
|
|
57
|
-
export const runHarness = (ctx, init, prompt) => ctx.runtime.run(runHarnessEffect(ctx, init, prompt));
|
|
76
|
+
export const runHarness = (ctx, init, prompt, options) => ctx.runtime.run(runHarnessEffect(ctx, init, prompt, options));
|
|
58
77
|
/**
|
|
59
78
|
* The NON-BLOCKING `harness.start()` implementation: register the run and return the live handle
|
|
60
79
|
* immediately. Callers stream progress via `run.record.stream()` and settle via `run.wait()` (which
|
|
61
80
|
* fetches the captured changes once terminal).
|
|
62
81
|
*/
|
|
63
|
-
export const startHarness = (ctx, init, prompt) => ctx.runtime.run(Effect.map(createHarnessRunEffect(ctx, init, prompt), (created) => makeRun(ctx, { wire: created })));
|
|
82
|
+
export const startHarness = (ctx, init, prompt, options) => ctx.runtime.run(Effect.map(createHarnessRunEffect(ctx, init, prompt, options), (created) => makeRun(ctx, { wire: created })));
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { InteractiveSession } from "../types.js";
|
|
2
|
+
import type { SdkContext } from "./context.js";
|
|
3
|
+
export declare const makeInteractiveSession: (ctx: SdkContext, wire: {
|
|
4
|
+
readonly sessionId: string;
|
|
5
|
+
readonly workspaceId: string;
|
|
6
|
+
readonly runId: string;
|
|
7
|
+
readonly ownerUserId: string;
|
|
8
|
+
readonly status: "exited" | "failed" | "running" | "starting";
|
|
9
|
+
readonly argv: readonly string[];
|
|
10
|
+
readonly cwd?: string | undefined;
|
|
11
|
+
readonly cols: number;
|
|
12
|
+
readonly rows: number;
|
|
13
|
+
readonly exitCode?: number | undefined;
|
|
14
|
+
readonly exitSignal?: number | undefined;
|
|
15
|
+
readonly errorMessage?: string | undefined;
|
|
16
|
+
readonly metadata?: {
|
|
17
|
+
readonly [x: string]: unknown;
|
|
18
|
+
} | undefined;
|
|
19
|
+
readonly outputHighWater: string;
|
|
20
|
+
readonly createdAt: string;
|
|
21
|
+
readonly endedAt?: string | undefined;
|
|
22
|
+
}) => InteractiveSession;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { closeSessionOp, getSessionOp, getSessionOutputOp, resizeSessionOp, sendSessionInputOp, signalSessionOp, } from "../effect/operations.js";
|
|
2
|
+
const OUTPUT_POLL_INTERVAL_MS = 250;
|
|
3
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
4
|
+
const decodeBase64 = (value) => {
|
|
5
|
+
const buffer = Buffer.from(value, "base64");
|
|
6
|
+
return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
7
|
+
};
|
|
8
|
+
/** Parse one SSE frame block ("event: ...\nid: ...\ndata: ...") into its fields. */
|
|
9
|
+
const parseSseFrame = (block) => {
|
|
10
|
+
let event = "message";
|
|
11
|
+
let id;
|
|
12
|
+
const dataLines = [];
|
|
13
|
+
for (const line of block.split("\n")) {
|
|
14
|
+
if (line.startsWith(":")) {
|
|
15
|
+
continue; // comment / keep-alive
|
|
16
|
+
}
|
|
17
|
+
if (line.startsWith("event:")) {
|
|
18
|
+
event = line.slice(6).trim();
|
|
19
|
+
}
|
|
20
|
+
else if (line.startsWith("id:")) {
|
|
21
|
+
id = line.slice(3).trim();
|
|
22
|
+
}
|
|
23
|
+
else if (line.startsWith("data:")) {
|
|
24
|
+
dataLines.push(line.slice(5).trimStart());
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (dataLines.length === 0 && id === undefined) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
return { event, id, data: dataLines.join("\n") };
|
|
31
|
+
};
|
|
32
|
+
/** Stream the session's output over SSE. Throws on transport failure (caller falls back). */
|
|
33
|
+
async function* streamOverSse(ctx, sessionId, from, signal) {
|
|
34
|
+
const config = ctx.config;
|
|
35
|
+
const fetchImpl = config.fetch ?? fetch;
|
|
36
|
+
const url = new URL(`/v1/sessions/${sessionId}/output/stream`, config.baseUrl);
|
|
37
|
+
url.searchParams.set("from", from.toString());
|
|
38
|
+
if (config.apiKey === undefined) {
|
|
39
|
+
url.searchParams.set("ownerUserId", config.hostLocal.ownerUserId);
|
|
40
|
+
}
|
|
41
|
+
const response = await fetchImpl(url, {
|
|
42
|
+
headers: {
|
|
43
|
+
accept: "text/event-stream",
|
|
44
|
+
...(config.apiKey === undefined ? {} : { authorization: `Bearer ${config.apiKey}` }),
|
|
45
|
+
},
|
|
46
|
+
...(signal === undefined ? {} : { signal }),
|
|
47
|
+
});
|
|
48
|
+
if (!response.ok || response.body === null) {
|
|
49
|
+
throw new Error(`session output stream failed: HTTP ${response.status}`);
|
|
50
|
+
}
|
|
51
|
+
const reader = response.body.getReader();
|
|
52
|
+
const decoder = new TextDecoder();
|
|
53
|
+
let buffered = "";
|
|
54
|
+
try {
|
|
55
|
+
for (;;) {
|
|
56
|
+
const { done, value } = await reader.read();
|
|
57
|
+
if (done) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
buffered += decoder.decode(value, { stream: true });
|
|
61
|
+
for (;;) {
|
|
62
|
+
const boundary = buffered.indexOf("\n\n");
|
|
63
|
+
if (boundary === -1) {
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
const block = buffered.slice(0, boundary);
|
|
67
|
+
buffered = buffered.slice(boundary + 2);
|
|
68
|
+
const frame = parseSseFrame(block);
|
|
69
|
+
if (frame === undefined) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (frame.event === "end") {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (frame.event === "output" && frame.id !== undefined) {
|
|
76
|
+
yield { sequence: BigInt(frame.id), data: decodeBase64(frame.data) };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
await reader.cancel().catch(() => undefined);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** Poll-backed fallback: page the range endpoint until the session settles. */
|
|
86
|
+
async function* streamByPolling(ctx, sessionId, from, signal) {
|
|
87
|
+
let cursor = from;
|
|
88
|
+
for (;;) {
|
|
89
|
+
if (signal?.aborted === true) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const page = await ctx.runtime.run(getSessionOutputOp(sessionId, {
|
|
93
|
+
ownerUserId: ctx.config.hostLocal.ownerUserId,
|
|
94
|
+
from: cursor.toString(),
|
|
95
|
+
}));
|
|
96
|
+
for (const chunk of page.chunks) {
|
|
97
|
+
yield { sequence: BigInt(chunk.sequence), data: decodeBase64(chunk.dataBase64) };
|
|
98
|
+
}
|
|
99
|
+
cursor = BigInt(page.nextFrom);
|
|
100
|
+
if (page.chunks.length === 0) {
|
|
101
|
+
if (page.status === "exited" || page.status === "failed") {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
await delay(OUTPUT_POLL_INTERVAL_MS);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export const makeInteractiveSession = (ctx, wire) => {
|
|
109
|
+
const sessionId = wire.sessionId;
|
|
110
|
+
return {
|
|
111
|
+
id: sessionId,
|
|
112
|
+
workspaceId: wire.workspaceId,
|
|
113
|
+
runId: wire.runId,
|
|
114
|
+
send: async (input) => {
|
|
115
|
+
const bytes = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
116
|
+
await ctx.runtime.run(sendSessionInputOp(sessionId, {
|
|
117
|
+
ownerUserId: ctx.config.hostLocal.ownerUserId,
|
|
118
|
+
dataBase64: Buffer.from(bytes).toString("base64"),
|
|
119
|
+
}));
|
|
120
|
+
},
|
|
121
|
+
output: (options) => {
|
|
122
|
+
const from = options?.from ?? 0n;
|
|
123
|
+
const signal = options?.signal;
|
|
124
|
+
async function* iterate() {
|
|
125
|
+
let cursor = from;
|
|
126
|
+
try {
|
|
127
|
+
for await (const chunk of streamOverSse(ctx, sessionId, cursor, signal)) {
|
|
128
|
+
yield chunk;
|
|
129
|
+
cursor = chunk.sequence + 1n;
|
|
130
|
+
}
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
if (signal?.aborted === true) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// SSE transport unavailable (proxy, fetch impl, older server) — fall back to polling
|
|
138
|
+
// from the cursor; the sequence keying makes the switch seamless.
|
|
139
|
+
void error;
|
|
140
|
+
}
|
|
141
|
+
yield* streamByPolling(ctx, sessionId, cursor, signal);
|
|
142
|
+
}
|
|
143
|
+
return iterate();
|
|
144
|
+
},
|
|
145
|
+
resize: async (cols, rows) => {
|
|
146
|
+
await ctx.runtime.run(resizeSessionOp(sessionId, {
|
|
147
|
+
ownerUserId: ctx.config.hostLocal.ownerUserId,
|
|
148
|
+
cols,
|
|
149
|
+
rows,
|
|
150
|
+
}));
|
|
151
|
+
},
|
|
152
|
+
signal: async (signalNumber) => {
|
|
153
|
+
await ctx.runtime.run(signalSessionOp(sessionId, {
|
|
154
|
+
ownerUserId: ctx.config.hostLocal.ownerUserId,
|
|
155
|
+
signal: signalNumber,
|
|
156
|
+
}));
|
|
157
|
+
},
|
|
158
|
+
status: async () => {
|
|
159
|
+
const current = await ctx.runtime.run(getSessionOp(sessionId, ctx.config.hostLocal.ownerUserId));
|
|
160
|
+
return {
|
|
161
|
+
status: current.status,
|
|
162
|
+
...(current.exitCode === undefined ? {} : { exitCode: current.exitCode }),
|
|
163
|
+
...(current.exitSignal === undefined ? {} : { exitSignal: current.exitSignal }),
|
|
164
|
+
outputHighWater: BigInt(current.outputHighWater),
|
|
165
|
+
};
|
|
166
|
+
},
|
|
167
|
+
close: async () => {
|
|
168
|
+
await ctx.runtime.run(closeSessionOp(sessionId, { ownerUserId: ctx.config.hostLocal.ownerUserId }));
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
};
|