@sealant/sdk 0.0.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.
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The control-plane wire client — DERIVED, never hand-written.
3
+ *
4
+ * `HttpApiClient.make(ControlPlaneAPI)` generates a fully-typed client directly from the
5
+ * `@sealant/api-contracts` Effect `HttpApi` definition (the single source of truth): requests are
6
+ * encoded and responses decoded by the SAME `Schema`s, and the typed error channel carries the same
7
+ * `TaggedError`s the server declares. No codegen step, no generated artifact, no drift — change the
8
+ * contract and these call sites move with it. (OpenAPI/`buf generate` is reserved for non-TypeScript
9
+ * clients, per SEALANT-PLAN §8.)
10
+ */
11
+ import { ControlPlaneAPI } from "@sealant/api-contracts";
12
+ import { Context, Effect, Layer } from "effect";
13
+ import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/unstable/http";
14
+ import { HttpApiClient } from "effect/unstable/httpapi";
15
+ /** Builds the contract-derived client. Requires an `HttpClient` in context (provided by the layer). */
16
+ const buildControlPlaneClient = (config) => {
17
+ const { apiKey } = config;
18
+ if (apiKey === undefined) {
19
+ return HttpApiClient.make(ControlPlaneAPI, { baseUrl: config.baseUrl });
20
+ }
21
+ return HttpApiClient.make(ControlPlaneAPI, {
22
+ baseUrl: config.baseUrl,
23
+ transformClient: (client) => HttpClient.mapRequest(client, HttpClientRequest.bearerToken(apiKey)),
24
+ });
25
+ };
26
+ export class SealantApiClient extends Context.Service()("@sealant/sdk/SealantApiClient") {
27
+ }
28
+ /** Live layer: derives the client over the global-fetch `HttpClient`, with an optional bearer token. */
29
+ export const sealantApiClientLayer = (config) => Layer.effect(SealantApiClient, buildControlPlaneClient(config)).pipe(Layer.provide(FetchHttpClient.layer));
@@ -0,0 +1,236 @@
1
+ import { Effect } from "effect";
2
+ import { SealantApiClient } from "./api-client.js";
3
+ export declare const createSandboxOp: (payload: {
4
+ readonly ownerUserId: string;
5
+ readonly registryId: string;
6
+ readonly repository: string;
7
+ readonly tag: string;
8
+ readonly name?: string | undefined;
9
+ readonly sourceSelection?: {
10
+ readonly provider: "github";
11
+ readonly installationId: string;
12
+ readonly installationRepositoryId: string;
13
+ readonly ref?: string | undefined;
14
+ } | undefined;
15
+ readonly dotfilesSelection?: {
16
+ readonly provider: "github";
17
+ readonly installationId: string;
18
+ readonly installationRepositoryId: string;
19
+ readonly ref?: string | undefined;
20
+ } | undefined;
21
+ readonly credentials?: {
22
+ readonly profileId?: string | undefined;
23
+ readonly claude?: string | undefined;
24
+ readonly codex?: string | undefined;
25
+ readonly github?: string | undefined;
26
+ } | undefined;
27
+ readonly spec: unknown;
28
+ }, idempotencyKey?: string | undefined) => Effect.Effect<{
29
+ readonly sandboxId: string;
30
+ readonly name: string;
31
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
32
+ readonly registryId: string;
33
+ readonly repository: string;
34
+ readonly tag: string;
35
+ }, import("effect/unstable/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").SandboxBadGatewayError | import("@sealant/api-contracts").SandboxBadRequestError | import("@sealant/api-contracts").SandboxConflictError | import("@sealant/api-contracts").SandboxForbiddenError | import("@sealant/api-contracts").SandboxInternalServerError | import("@sealant/api-contracts").SandboxNotFoundError | import("@sealant/api-contracts").SandboxServiceUnavailableError | import("effect/Schema").SchemaError, SealantApiClient>;
36
+ export declare const getSandboxOp: (sandboxId: string) => Effect.Effect<{
37
+ readonly sandboxId: string;
38
+ readonly name: string;
39
+ readonly ownerUserId: string;
40
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
41
+ readonly registryId?: string | undefined;
42
+ readonly repository?: string | undefined;
43
+ readonly tag?: string | undefined;
44
+ readonly runtime?: {
45
+ readonly adapter: "docker" | "k3s" | "k8s";
46
+ readonly resourceId: string;
47
+ readonly reference: string;
48
+ readonly status: "failed" | "pending" | "ready" | "running" | "stopped";
49
+ readonly endpoint?: string | undefined;
50
+ } | undefined;
51
+ readonly publishedImage?: {
52
+ readonly reference: string;
53
+ readonly digestReference: string;
54
+ readonly digest: string;
55
+ } | undefined;
56
+ readonly error?: {
57
+ readonly message: string;
58
+ readonly code?: string | undefined;
59
+ } | undefined;
60
+ readonly createdAt: string;
61
+ readonly updatedAt: string;
62
+ readonly startedAt?: string | undefined;
63
+ readonly finishedAt?: string | undefined;
64
+ readonly spec?: unknown;
65
+ }, unknown, SealantApiClient>;
66
+ export declare const listSandboxesOp: (query: {
67
+ readonly ownerUserId: string;
68
+ readonly status?: "cancelled" | "failed" | "queued" | "ready" | "running" | undefined;
69
+ readonly limit?: string | undefined;
70
+ }) => Effect.Effect<{
71
+ readonly items: readonly {
72
+ readonly sandboxId: string;
73
+ readonly name: string;
74
+ readonly ownerUserId: string;
75
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
76
+ readonly registryId?: string | undefined;
77
+ readonly repository?: string | undefined;
78
+ readonly tag?: string | undefined;
79
+ readonly runtime?: {
80
+ readonly adapter: "docker" | "k3s" | "k8s";
81
+ readonly resourceId: string;
82
+ readonly reference: string;
83
+ readonly status: "failed" | "pending" | "ready" | "running" | "stopped";
84
+ readonly endpoint?: string | undefined;
85
+ } | undefined;
86
+ readonly publishedImage?: {
87
+ readonly reference: string;
88
+ readonly digestReference: string;
89
+ readonly digest: string;
90
+ } | undefined;
91
+ readonly error?: {
92
+ readonly message: string;
93
+ readonly code?: string | undefined;
94
+ } | undefined;
95
+ readonly createdAt: string;
96
+ readonly updatedAt: string;
97
+ readonly startedAt?: string | undefined;
98
+ readonly finishedAt?: string | undefined;
99
+ }[];
100
+ }, import("effect/unstable/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").SandboxBadRequestError | import("@sealant/api-contracts").SandboxInternalServerError | import("effect/Schema").SchemaError, SealantApiClient>;
101
+ export declare const createRunOp: (payload: {
102
+ readonly sandboxId: string;
103
+ readonly harnessId: string;
104
+ readonly ownerUserId: string;
105
+ readonly mode?: "interactive" | "one-shot" | undefined;
106
+ readonly prompt?: string | undefined;
107
+ readonly attemptId?: string | undefined;
108
+ readonly command?: {
109
+ readonly executable: string;
110
+ readonly args: readonly string[];
111
+ readonly cwd?: string | undefined;
112
+ } | undefined;
113
+ }) => Effect.Effect<{
114
+ readonly runId: string;
115
+ readonly sandboxId: string;
116
+ readonly attemptId?: string | undefined;
117
+ readonly ownerUserId: string;
118
+ readonly harnessId: string;
119
+ readonly mode: "interactive" | "one-shot";
120
+ readonly status: "cancelled" | "completed" | "failed" | "queued" | "running";
121
+ readonly prompt?: string | undefined;
122
+ readonly exitCode?: number | undefined;
123
+ readonly errorMessage?: string | undefined;
124
+ readonly startedAt?: string | undefined;
125
+ readonly finishedAt?: string | undefined;
126
+ readonly createdAt: string;
127
+ readonly updatedAt: string;
128
+ }, unknown, SealantApiClient>;
129
+ export declare const getRunOp: (runId: string) => Effect.Effect<{
130
+ readonly runId: string;
131
+ readonly sandboxId: string;
132
+ readonly attemptId?: string | undefined;
133
+ readonly ownerUserId: string;
134
+ readonly harnessId: string;
135
+ readonly mode: "interactive" | "one-shot";
136
+ readonly status: "cancelled" | "completed" | "failed" | "queued" | "running";
137
+ readonly prompt?: string | undefined;
138
+ readonly exitCode?: number | undefined;
139
+ readonly errorMessage?: string | undefined;
140
+ readonly startedAt?: string | undefined;
141
+ readonly finishedAt?: string | undefined;
142
+ readonly createdAt: string;
143
+ readonly updatedAt: string;
144
+ }, unknown, SealantApiClient>;
145
+ export declare const listRunsOp: (query: {
146
+ readonly sandboxId?: string | undefined;
147
+ readonly ownerUserId?: string | undefined;
148
+ readonly status?: "cancelled" | "completed" | "failed" | "queued" | "running" | undefined;
149
+ readonly limit?: string | undefined;
150
+ }) => Effect.Effect<{
151
+ readonly items: readonly {
152
+ readonly runId: string;
153
+ readonly sandboxId: string;
154
+ readonly attemptId?: string | undefined;
155
+ readonly ownerUserId: string;
156
+ readonly harnessId: string;
157
+ readonly mode: "interactive" | "one-shot";
158
+ readonly status: "cancelled" | "completed" | "failed" | "queued" | "running";
159
+ readonly prompt?: string | undefined;
160
+ readonly exitCode?: number | undefined;
161
+ readonly errorMessage?: string | undefined;
162
+ readonly startedAt?: string | undefined;
163
+ readonly finishedAt?: string | undefined;
164
+ readonly createdAt: string;
165
+ readonly updatedAt: string;
166
+ }[];
167
+ }, import("effect/unstable/http/HttpClientError").HttpClientError | import("@sealant/api-contracts").RunBadRequestError | import("@sealant/api-contracts").RunInternalServerError | import("effect/Schema").SchemaError, SealantApiClient>;
168
+ export declare const updateRunOp: (runId: string, payload: {
169
+ readonly status?: "cancelled" | "completed" | "failed" | "queued" | "running" | undefined;
170
+ readonly exitCode?: number | undefined;
171
+ readonly errorMessage?: string | undefined;
172
+ }) => Effect.Effect<{
173
+ readonly runId: string;
174
+ readonly sandboxId: string;
175
+ readonly attemptId?: string | undefined;
176
+ readonly ownerUserId: string;
177
+ readonly harnessId: string;
178
+ readonly mode: "interactive" | "one-shot";
179
+ readonly status: "cancelled" | "completed" | "failed" | "queued" | "running";
180
+ readonly prompt?: string | undefined;
181
+ readonly exitCode?: number | undefined;
182
+ readonly errorMessage?: string | undefined;
183
+ readonly startedAt?: string | undefined;
184
+ readonly finishedAt?: string | undefined;
185
+ readonly createdAt: string;
186
+ readonly updatedAt: string;
187
+ }, unknown, SealantApiClient>;
188
+ export declare const getRunTimelineOp: (runId: string, query: {
189
+ readonly fromSequence?: string | undefined;
190
+ readonly toSequence?: string | undefined;
191
+ readonly limit?: string | undefined;
192
+ readonly kinds?: string | undefined;
193
+ }) => Effect.Effect<readonly {
194
+ readonly eventId: string;
195
+ readonly sequence: string;
196
+ readonly kind: string;
197
+ readonly occurredAt: string;
198
+ readonly summary: string;
199
+ readonly ref?: unknown;
200
+ readonly processId?: string | undefined;
201
+ readonly captureMethod: number;
202
+ readonly confidence: number;
203
+ }[], unknown, SealantApiClient>;
204
+ export declare const getRunScrollbackOp: (runId: string, query: {
205
+ readonly processId: string;
206
+ readonly stream: "stderr" | "stdout";
207
+ readonly atSequence?: string | undefined;
208
+ }) => Effect.Effect<{
209
+ readonly processId: string;
210
+ readonly stream: "stderr" | "stdout";
211
+ readonly byteCount: number;
212
+ readonly contentBase64: string;
213
+ }, unknown, SealantApiClient>;
214
+ export declare const getRunLossOp: (runId: string) => Effect.Effect<{
215
+ readonly runId: string;
216
+ readonly droppedEventCount: string;
217
+ readonly sequenceGapCount: number;
218
+ readonly watchOverflowCount: number;
219
+ readonly earlyClose: boolean;
220
+ readonly spans: readonly {
221
+ readonly kind: "dropped_event" | "early_close" | "sequence_gap" | "watch_overflow";
222
+ readonly fromSequence?: string | undefined;
223
+ readonly toSequence?: string | undefined;
224
+ readonly droppedCount?: string | undefined;
225
+ readonly detectedVia: "gap" | "marker";
226
+ readonly reason?: string | undefined;
227
+ }[];
228
+ }, unknown, SealantApiClient>;
229
+ export declare const getRunChangesOp: (runId: string) => Effect.Effect<{
230
+ readonly files: readonly {
231
+ readonly path: string;
232
+ readonly change: "added" | "deleted" | "modified" | "renamed";
233
+ readonly oldPath?: string | undefined;
234
+ }[];
235
+ readonly diff: string;
236
+ }, unknown, SealantApiClient>;
@@ -0,0 +1,18 @@
1
+ import { Effect } from "effect";
2
+ import { SealantApiClient } from "./api-client.js";
3
+ // ---- sandboxes ----
4
+ export const createSandboxOp = (payload, idempotencyKey) => Effect.flatMap(SealantApiClient, (client) => client.sandboxes.createSandbox({
5
+ payload,
6
+ headers: idempotencyKey === undefined ? {} : { "idempotency-key": idempotencyKey },
7
+ }));
8
+ export const getSandboxOp = (sandboxId) => Effect.flatMap(SealantApiClient, (client) => client.sandboxes.getSandbox({ params: { sandboxId } }));
9
+ export const listSandboxesOp = (query) => Effect.flatMap(SealantApiClient, (client) => client.sandboxes.listSandboxes({ query }));
10
+ // ---- runs ----
11
+ export const createRunOp = (payload) => Effect.flatMap(SealantApiClient, (client) => client.runs.createRun({ payload }));
12
+ export const getRunOp = (runId) => Effect.flatMap(SealantApiClient, (client) => client.runs.getRun({ params: { runId } }));
13
+ export const listRunsOp = (query) => Effect.flatMap(SealantApiClient, (client) => client.runs.listRuns({ query }));
14
+ export const updateRunOp = (runId, payload) => Effect.flatMap(SealantApiClient, (client) => client.runs.updateRun({ params: { runId }, payload }));
15
+ export const getRunTimelineOp = (runId, query) => Effect.flatMap(SealantApiClient, (client) => Effect.map(client.runs.getRunTimeline({ params: { runId }, query }), (r) => r.items));
16
+ export const getRunScrollbackOp = (runId, query) => Effect.flatMap(SealantApiClient, (client) => client.runs.getRunScrollback({ params: { runId }, query }));
17
+ export const getRunLossOp = (runId) => Effect.flatMap(SealantApiClient, (client) => client.runs.getRunLoss({ params: { runId } }));
18
+ export const getRunChangesOp = (runId) => Effect.flatMap(SealantApiClient, (client) => client.runs.getRunChanges({ params: { runId } }));
@@ -0,0 +1,9 @@
1
+ import type { RunHarnessFn } from "../facade/sandbox.js";
2
+ /** The BLOCKING `harness.run()` implementation, registered into the Sandbox facade by the client. */
3
+ export declare const runHarness: RunHarnessFn;
4
+ /**
5
+ * The NON-BLOCKING `harness.start()` implementation: register the run and return the live handle
6
+ * immediately. Callers stream progress via `run.record.stream()` and settle via `run.wait()` (which
7
+ * fetches the captured changes once terminal).
8
+ */
9
+ export declare const startHarness: RunHarnessFn;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * `harness.run()` / `harness.start()` — the one-shot execution paths, THIN HTTP CLIENTS.
3
+ *
4
+ * The SDK no longer execs the harness or writes telemetry itself (that moved server-side into the
5
+ * worker). Both paths register a run via the control plane WITH the harness command (so the control
6
+ * plane executes it). `run()` then polls until the run reaches a terminal status and reads the
7
+ * captured changes; `start()` returns the live handle immediately (stream via `run.record.stream()`,
8
+ * settle via `run.wait()`). No Postgres pool, no docker-exec, no telemetry sink: this is what makes
9
+ * @sealant/sdk a plain client that runs anywhere.
10
+ */
11
+ import { Effect } from "effect";
12
+ import { SealantError } from "../errors.js";
13
+ import { makeRun, toRunChangesData } from "../facade/run.js";
14
+ import { createRunOp, getRunChangesOp, getRunOp } from "./operations.js";
15
+ const TERMINAL_STATUSES = new Set(["completed", "failed", "cancelled"]);
16
+ const POLL_INTERVAL = "500 millis";
17
+ const RUN_TIMEOUT_MS = 30 * 60 * 1_000;
18
+ /**
19
+ * Registers the run WITH the harness command — the control plane executes it server-side (the worker
20
+ * docker-execs it and ingests telemetry). The cwd is the sandbox repo, which the worker defaults to.
21
+ */
22
+ const createHarnessRunEffect = (ctx, init, prompt) => Effect.gen(function* () {
23
+ const harness = init.harness;
24
+ if (harness === undefined) {
25
+ return yield* Effect.fail(new SealantError("This sandbox handle has no harness; use the handle returned by sandboxes.create().", { code: "harness_required" }));
26
+ }
27
+ const command = harness.buildRunCommand(prompt);
28
+ return yield* createRunOp({
29
+ sandboxId: init.id,
30
+ ownerUserId: ctx.config.hostLocal.ownerUserId,
31
+ harnessId: harness.id,
32
+ mode: "one-shot",
33
+ prompt,
34
+ command: { executable: command.executable, args: [...command.args] },
35
+ });
36
+ });
37
+ const runHarnessEffect = (ctx, init, prompt) => Effect.gen(function* () {
38
+ const created = yield* createHarnessRunEffect(ctx, init, prompt);
39
+ const runId = created.runId;
40
+ // Block until the run is terminal, polling the control plane.
41
+ const deadline = Date.now() + RUN_TIMEOUT_MS;
42
+ let wire = created;
43
+ while (!TERMINAL_STATUSES.has(wire.status)) {
44
+ if (Date.now() > deadline) {
45
+ return yield* Effect.fail(new SealantError(`Timed out waiting for run ${runId} to complete.`, {
46
+ code: "run_timeout",
47
+ }));
48
+ }
49
+ yield* Effect.sleep(POLL_INTERVAL);
50
+ wire = yield* getRunOp(runId);
51
+ }
52
+ // Read the changes the run produced (captured server-side).
53
+ const changes = toRunChangesData(yield* getRunChangesOp(runId));
54
+ return makeRun(ctx, { wire, changes });
55
+ });
56
+ /** The BLOCKING `harness.run()` implementation, registered into the Sandbox facade by the client. */
57
+ export const runHarness = (ctx, init, prompt) => ctx.runtime.run(runHarnessEffect(ctx, init, prompt));
58
+ /**
59
+ * The NON-BLOCKING `harness.start()` implementation: register the run and return the live handle
60
+ * immediately. Callers stream progress via `run.record.stream()` and settle via `run.wait()` (which
61
+ * fetches the captured changes once terminal).
62
+ */
63
+ export const startHarness = (ctx, init, prompt) => ctx.runtime.run(Effect.map(createHarnessRunEffect(ctx, init, prompt), (created) => makeRun(ctx, { wire: created })));
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The SDK runtime — the Effect-core boundary the Promise facade runs against.
3
+ *
4
+ * The app `Layer` is built ONCE into a process-lifetime `Scope`, lazily and memoized. It provides a
5
+ * single service — `SealantApiClient`, the contract-derived control-plane client — so the SDK is a
6
+ * THIN HTTP CLIENT: every operation (create/run/read) is an HTTP call to `baseUrl`. Run execution and
7
+ * telemetry ingest moved SERVER-SIDE (the worker), so the SDK no longer opens a Postgres pool, spawns
8
+ * docker, or writes telemetry. Every operation surfaces a plain `SealantError` (the typed Effect
9
+ * failure is squashed and mapped here). `dispose()` closes the scope (the HTTP client) and is idempotent.
10
+ */
11
+ import { Effect } from "effect";
12
+ import type { SealantInternalConfig } from "../internal/config.js";
13
+ import { SealantApiClient } from "./api-client.js";
14
+ /** Services the SDK runtime provides to operation effects. */
15
+ export type SdkServices = SealantApiClient;
16
+ export interface SdkRuntime {
17
+ /** Provide the app context and run an operation effect, surfacing plain `SealantError`s. */
18
+ readonly run: <A, E, R extends SdkServices>(effect: Effect.Effect<A, E, R>) => Promise<A>;
19
+ /** Dispose the runtime scope (the HTTP client). Idempotent. */
20
+ readonly dispose: () => Promise<void>;
21
+ }
22
+ export declare const makeSdkRuntime: (config: SealantInternalConfig) => SdkRuntime;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The SDK runtime — the Effect-core boundary the Promise facade runs against.
3
+ *
4
+ * The app `Layer` is built ONCE into a process-lifetime `Scope`, lazily and memoized. It provides a
5
+ * single service — `SealantApiClient`, the contract-derived control-plane client — so the SDK is a
6
+ * THIN HTTP CLIENT: every operation (create/run/read) is an HTTP call to `baseUrl`. Run execution and
7
+ * telemetry ingest moved SERVER-SIDE (the worker), so the SDK no longer opens a Postgres pool, spawns
8
+ * docker, or writes telemetry. Every operation surfaces a plain `SealantError` (the typed Effect
9
+ * failure is squashed and mapped here). `dispose()` closes the scope (the HTTP client) and is idempotent.
10
+ */
11
+ import { Cause, Context, Effect, Exit, Layer, Scope } from "effect";
12
+ import { toSealantError } from "../internal/map-error.js";
13
+ import { SealantApiClient, sealantApiClientLayer } from "./api-client.js";
14
+ // A single service: the contract-derived HTTP client. No DB pool, no docker-exec, no telemetry sink.
15
+ const makeAppLayer = (config) => sealantApiClientLayer(config);
16
+ export const makeSdkRuntime = (config) => {
17
+ const appLayer = makeAppLayer(config);
18
+ let built;
19
+ const build = () => {
20
+ if (built === undefined) {
21
+ built = Effect.runPromiseExit(Effect.gen(function* () {
22
+ const scope = yield* Scope.make();
23
+ const context = yield* Layer.buildWithScope(appLayer, scope);
24
+ // The layer provides a superset of SdkServices; narrow to the surfaced services.
25
+ return { context: context, scope };
26
+ })).then((exit) => {
27
+ if (Exit.isSuccess(exit)) {
28
+ return exit.value;
29
+ }
30
+ // The layer's error channel is non-`never` (e.g. SqlError: the DB pool can fail to construct),
31
+ // so route a build failure through the SAME funnel as operations instead of leaking a raw
32
+ // Effect/SQL error out of the public Promise API. Reset memoization so a transient first-build
33
+ // failure (DB momentarily down) can be retried instead of poisoning the runtime forever.
34
+ built = undefined;
35
+ throw toSealantError(Cause.squash(exit.cause));
36
+ });
37
+ }
38
+ return built;
39
+ };
40
+ return {
41
+ run: async (effect) => {
42
+ const { context } = await build();
43
+ // R extends SdkServices and the context provides SdkServices, so all requirements are met
44
+ // (TS can't reduce Exclude<R, SdkServices> to never for a generic R).
45
+ const provided = Effect.provide(effect, context);
46
+ const exit = await Effect.runPromiseExit(provided);
47
+ if (Exit.isSuccess(exit)) {
48
+ return exit.value;
49
+ }
50
+ // Squash the Cause to its underlying failure/defect value, then map to a plain error.
51
+ throw toSealantError(Cause.squash(exit.cause));
52
+ },
53
+ dispose: async () => {
54
+ if (built === undefined) {
55
+ return;
56
+ }
57
+ const current = built;
58
+ built = undefined;
59
+ const { scope } = await current;
60
+ await Effect.runPromise(Scope.close(scope, Exit.succeed(undefined)));
61
+ },
62
+ };
63
+ };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Public SDK errors. The Effect core fails on a typed `Schema.TaggedError` channel; the facade maps
3
+ * every tagged failure onto one of these PLAIN `Error` subclasses (a single `_tag` switch) so the
4
+ * public, Promise-based surface never leaks Effect internals. Consumers `catch` ordinary `Error`s.
5
+ */
6
+ /** Base class for every error the SDK throws. */
7
+ export declare class SealantError extends Error {
8
+ readonly name: string;
9
+ /** Stable, machine-readable code for branching on the failure. */
10
+ readonly code: string;
11
+ constructor(message: string, options?: {
12
+ readonly code?: string;
13
+ readonly cause?: unknown;
14
+ });
15
+ }
16
+ /** A typed control/transport failure from the sandbox runtime daemon. */
17
+ export declare class SealantRuntimeError extends SealantError {
18
+ readonly name = "SealantRuntimeError";
19
+ constructor(message: string, options?: {
20
+ readonly code?: string;
21
+ readonly cause?: unknown;
22
+ });
23
+ }
24
+ /** A control-plane API request failed (HTTP-level or typed API error). */
25
+ export declare class SealantApiError extends SealantError {
26
+ readonly name = "SealantApiError";
27
+ /** HTTP status, when the failure came from a response. */
28
+ readonly status?: number;
29
+ constructor(message: string, options?: {
30
+ readonly code?: string;
31
+ readonly status?: number;
32
+ readonly cause?: unknown;
33
+ });
34
+ }
35
+ /** The requested operation is part of the public surface but not yet implemented in this slice. */
36
+ export declare class SealantNotImplementedError extends SealantError {
37
+ readonly name = "SealantNotImplementedError";
38
+ constructor(operation: string);
39
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Public SDK errors. The Effect core fails on a typed `Schema.TaggedError` channel; the facade maps
3
+ * every tagged failure onto one of these PLAIN `Error` subclasses (a single `_tag` switch) so the
4
+ * public, Promise-based surface never leaks Effect internals. Consumers `catch` ordinary `Error`s.
5
+ */
6
+ /** Base class for every error the SDK throws. */
7
+ export class SealantError extends Error {
8
+ name = "SealantError";
9
+ /** Stable, machine-readable code for branching on the failure. */
10
+ code;
11
+ constructor(message, options) {
12
+ super(message, options?.cause === undefined ? undefined : { cause: options.cause });
13
+ this.code = options?.code ?? "sealant_error";
14
+ }
15
+ }
16
+ /** A typed control/transport failure from the sandbox runtime daemon. */
17
+ export class SealantRuntimeError extends SealantError {
18
+ name = "SealantRuntimeError";
19
+ constructor(message, options) {
20
+ super(message, {
21
+ code: options?.code ?? "runtime_error",
22
+ ...(options?.cause === undefined ? {} : { cause: options.cause }),
23
+ });
24
+ }
25
+ }
26
+ /** A control-plane API request failed (HTTP-level or typed API error). */
27
+ export class SealantApiError extends SealantError {
28
+ name = "SealantApiError";
29
+ /** HTTP status, when the failure came from a response. */
30
+ status;
31
+ constructor(message, options) {
32
+ super(message, {
33
+ code: options?.code ?? "api_error",
34
+ ...(options?.cause === undefined ? {} : { cause: options.cause }),
35
+ });
36
+ if (options?.status !== undefined) {
37
+ this.status = options.status;
38
+ }
39
+ }
40
+ }
41
+ /** The requested operation is part of the public surface but not yet implemented in this slice. */
42
+ export class SealantNotImplementedError extends SealantError {
43
+ name = "SealantNotImplementedError";
44
+ constructor(operation) {
45
+ super(`${operation} is part of the Sealant SDK surface but is not implemented in this build yet.`, { code: "not_implemented" });
46
+ }
47
+ }
@@ -0,0 +1,9 @@
1
+ import type { SdkRuntime } from "../effect/runtime.js";
2
+ import type { SealantInternalConfig } from "../internal/config.js";
3
+ /** What every facade object needs: the execution boundary and the resolved (host-local) config. */
4
+ export interface SdkContext {
5
+ readonly runtime: SdkRuntime;
6
+ readonly config: SealantInternalConfig;
7
+ }
8
+ /** An AsyncIterable whose iteration rejects — for surface that is typed now but not yet implemented. */
9
+ export declare const notImplementedAsyncIterable: <A>(operation: string, error: Error) => AsyncIterable<A>;
@@ -0,0 +1,9 @@
1
+ /** An AsyncIterable whose iteration rejects — for surface that is typed now but not yet implemented. */
2
+ export const notImplementedAsyncIterable = (operation, error) => ({
3
+ [Symbol.asyncIterator]() {
4
+ return {
5
+ next: () => Promise.reject(error),
6
+ return: () => Promise.resolve({ done: true, value: undefined }),
7
+ };
8
+ },
9
+ });
@@ -0,0 +1,20 @@
1
+ import type { RunCommand, RunRecord } from "../types.js";
2
+ import type { SdkContext } from "./context.js";
3
+ /**
4
+ * Folds the timeline into the ordered list of terminal commands. Process boundaries are
5
+ * `processStarted`/`processExited`; `ioChunk` byte counts accrue to the current command. Daemon noise
6
+ * (`runtimeStateChanged`, and the boot foreground we never `processStarted`) is skipped naturally.
7
+ */
8
+ export declare const reconstructCommands: (entries: readonly {
9
+ readonly eventId: string;
10
+ readonly sequence: string;
11
+ readonly kind: string;
12
+ readonly occurredAt: string;
13
+ readonly summary: string;
14
+ readonly ref?: unknown;
15
+ readonly processId?: string | undefined;
16
+ readonly captureMethod: number;
17
+ readonly confidence: number;
18
+ }[]) => RunCommand[];
19
+ export declare const renderTranscript: (commands: readonly RunCommand[]) => string;
20
+ export declare const makeRunRecord: (ctx: SdkContext, runId: string) => RunRecord;