@sealant/sdk 0.3.1 → 0.5.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/index.d.ts CHANGED
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * @sealant/sdk — the fluent public SDK for Sealant.
3
3
  *
4
- * Create a live sandbox around a real repository, run the harness you already use, stream progress
5
- * while it works, and keep the replayable execution record after the sandbox is gone:
4
+ * Create a live workspace around a real repository, run the harness you already use, stream progress
5
+ * while it works, and keep the replayable execution record after the workspace is gone:
6
6
  *
7
7
  * import { Sealant, opencode } from "@sealant/sdk"
8
8
  *
9
9
  * const sealant = new Sealant({ baseUrl: "http://localhost:8080" })
10
- * const sandbox = await sealant.sandboxes.create({
10
+ * const workspace = await sealant.workspaces.create({
11
11
  * repository: "github.com/acme/billing-service",
12
12
  * harness: opencode(),
13
13
  * })
14
- * const run = await sandbox.harness.run("Round invoice totals once, after applying the discount.")
14
+ * const run = await workspace.harness.run("Round invoice totals once, after applying the discount.")
15
15
  * await run.record.replay()
16
16
  */
17
17
  export { Sealant } from "./client.js";
package/dist/index.js CHANGED
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * @sealant/sdk — the fluent public SDK for Sealant.
3
3
  *
4
- * Create a live sandbox around a real repository, run the harness you already use, stream progress
5
- * while it works, and keep the replayable execution record after the sandbox is gone:
4
+ * Create a live workspace around a real repository, run the harness you already use, stream progress
5
+ * while it works, and keep the replayable execution record after the workspace is gone:
6
6
  *
7
7
  * import { Sealant, opencode } from "@sealant/sdk"
8
8
  *
9
9
  * const sealant = new Sealant({ baseUrl: "http://localhost:8080" })
10
- * const sandbox = await sealant.sandboxes.create({
10
+ * const workspace = await sealant.workspaces.create({
11
11
  * repository: "github.com/acme/billing-service",
12
12
  * harness: opencode(),
13
13
  * })
14
- * const run = await sandbox.harness.run("Round invoice totals once, after applying the discount.")
14
+ * const run = await workspace.harness.run("Round invoice totals once, after applying the discount.")
15
15
  * await run.record.replay()
16
16
  */
17
17
  export { Sealant } from "./client.js";
@@ -1,6 +1,6 @@
1
1
  import type { CreateOptions } from "../types.js";
2
2
  import type { SealantInternalConfig } from "./config.js";
3
- export declare const buildCreateSandboxRequest: (options: CreateOptions, config: SealantInternalConfig) => {
3
+ export declare const buildCreateWorkspaceRequest: (options: CreateOptions, config: SealantInternalConfig) => {
4
4
  readonly payload: {
5
5
  readonly ownerUserId: string;
6
6
  readonly registryId: string;
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * Lowers the fluent `create({ repository, harness })` options into the existing
3
- * `createSandboxRequestSchema` the control plane accepts — entirely client-side, so the slice needs
3
+ * `createWorkspaceRequestSchema` the control plane accepts — entirely client-side, so the slice needs
4
4
  * no contract change. The public `repository` is the SOURCE git repo (it becomes
5
- * `spec.sources.sandbox.url`); the contract's `repository`/`tag` are the OCI push coordinates, which
5
+ * `spec.sources.workspace.url`); the contract's `repository`/`tag` are the OCI push coordinates, which
6
6
  * we derive. `customization.enableSealantd` is forced on (it bakes + launches the daemon the run path
7
7
  * connects to), the runtime target is pinned to docker (the only bridgeable adapter today), and the
8
- * foreground is a keepalive so the sandbox idles with the daemon up and the harness is exec'd on
8
+ * foreground is a keepalive so the workspace idles with the daemon up and the harness is exec'd on
9
9
  * demand by `run()` rather than launched at boot. `options.credentials`, if present, is lowered via
10
- * `mapSandboxCredentials` (see `./credentials.js`) and folded into `spec.credentials`; the control
10
+ * `mapWorkspaceCredentials` (see `./credentials.js`) and folded into `spec.credentials`; the control
11
11
  * plane resolves those account references server-side (never secret material over this path).
12
12
  */
13
13
  import { randomUUID } from "node:crypto";
14
- import { mapSandboxCredentials } from "./credentials.js";
14
+ import { mapWorkspaceCredentials } from "./credentials.js";
15
15
  const sanitizeRepoSlug = (value) => {
16
16
  const slug = value
17
17
  .toLowerCase()
@@ -26,16 +26,16 @@ const toGitUrl = (repository) => {
26
26
  }
27
27
  return `https://${repository}.git`;
28
28
  };
29
- export const buildCreateSandboxRequest = (options, config) => {
29
+ export const buildCreateWorkspaceRequest = (options, config) => {
30
30
  const tail = options.repository
31
31
  .split("/")
32
32
  .filter((s) => s.length > 0)
33
33
  .pop() ?? options.repository;
34
- const credentials = mapSandboxCredentials(options.credentials);
34
+ const credentials = mapWorkspaceCredentials(options.credentials);
35
35
  const spec = {
36
36
  version: "1",
37
37
  sources: {
38
- sandbox: {
38
+ workspace: {
39
39
  kind: "git",
40
40
  provider: "generic",
41
41
  url: toGitUrl(options.repository),
@@ -9,9 +9,9 @@
9
9
  */
10
10
  import type { SealantConfig } from "../types.js";
11
11
  export interface SealantHostLocalConfig {
12
- /** Owner principal the control plane attributes sandboxes/runs to (pre-auth). */
12
+ /** Owner principal the control plane attributes workspaces/runs to (pre-auth). */
13
13
  readonly ownerUserId: string;
14
- /** Registry the sandbox image is published to and launched from. */
14
+ /** Registry the workspace image is published to and launched from. */
15
15
  readonly registryId: string;
16
16
  }
17
17
  export interface SealantInternalConfig {
@@ -1,22 +1,22 @@
1
1
  /**
2
- * Lowers the public `SandboxCredentialsOptions` onto the control-plane's sandbox-create payload
3
- * shape. Pure and side-effect free so it is unit-testable on its own; `buildCreateSandboxRequest`
2
+ * Lowers the public `WorkspaceCredentialsOptions` onto the control-plane's workspace-create payload
3
+ * shape. Pure and side-effect free so it is unit-testable on its own; `buildCreateWorkspaceRequest`
4
4
  * calls it and folds the result into the request it builds.
5
5
  *
6
6
  * SECURITY: this only ever moves account **references** (booleans/names/ids) — never token values or
7
7
  * other secret material. `true` resolves to the literal account name `"default"`; a string passes
8
8
  * through as the named account; `profile` becomes `profileId`.
9
9
  */
10
- import type { SandboxCredentialsOptions } from "../types.js";
11
- /** The control-plane's sandbox-create payload shape for connected-account credentials. */
12
- export interface SandboxCredentialsPayload {
10
+ import type { WorkspaceCredentialsOptions } from "../types.js";
11
+ /** The control-plane's workspace-create payload shape for connected-account credentials. */
12
+ export interface WorkspaceCredentialsPayload {
13
13
  readonly profileId?: string;
14
14
  readonly claude?: string;
15
15
  readonly codex?: string;
16
16
  readonly github?: string;
17
17
  }
18
18
  /**
19
- * Maps `SandboxCredentialsOptions` to the API payload shape, or `undefined` when no credentials were
19
+ * Maps `WorkspaceCredentialsOptions` to the API payload shape, or `undefined` when no credentials were
20
20
  * requested (omitted entirely, rather than serialized as an empty object).
21
21
  */
22
- export declare const mapSandboxCredentials: (options: SandboxCredentialsOptions | undefined) => SandboxCredentialsPayload | undefined;
22
+ export declare const mapWorkspaceCredentials: (options: WorkspaceCredentialsOptions | undefined) => WorkspaceCredentialsPayload | undefined;
@@ -6,10 +6,10 @@ const mapAccountRef = (value) => {
6
6
  return value === true ? DEFAULT_ACCOUNT_NAME : value;
7
7
  };
8
8
  /**
9
- * Maps `SandboxCredentialsOptions` to the API payload shape, or `undefined` when no credentials were
9
+ * Maps `WorkspaceCredentialsOptions` to the API payload shape, or `undefined` when no credentials were
10
10
  * requested (omitted entirely, rather than serialized as an empty object).
11
11
  */
12
- export const mapSandboxCredentials = (options) => {
12
+ export const mapWorkspaceCredentials = (options) => {
13
13
  if (options === undefined) {
14
14
  return undefined;
15
15
  }
@@ -0,0 +1,47 @@
1
+ import type { InferenceContinueOptions, InferenceRespondOptions, InferenceResponse } from "../types.js";
2
+ export declare const buildInferenceRespondRequest: (options: InferenceContinueOptions | InferenceRespondOptions, ownerUserId: string) => {
3
+ readonly ownerUserId: string;
4
+ readonly credentials?: {
5
+ readonly profileId?: string | undefined;
6
+ readonly claude?: string | undefined;
7
+ readonly codex?: string | undefined;
8
+ } | undefined;
9
+ readonly prompt?: string | undefined;
10
+ readonly system?: string | undefined;
11
+ readonly model?: string | undefined;
12
+ readonly maxTurns?: number | undefined;
13
+ readonly tools?: readonly {
14
+ readonly name: string;
15
+ readonly description?: string | undefined;
16
+ readonly inputSchema: unknown;
17
+ }[] | undefined;
18
+ readonly responseFormat?: {
19
+ readonly type: "json";
20
+ readonly schema?: unknown;
21
+ } | undefined;
22
+ readonly sessionId?: string | undefined;
23
+ readonly toolResults?: readonly {
24
+ readonly toolCallId: string;
25
+ readonly content: string;
26
+ readonly isError?: boolean | undefined;
27
+ }[] | undefined;
28
+ };
29
+ export declare const mapInferenceResponse: (wire: {
30
+ readonly sessionId: string;
31
+ readonly turn: {
32
+ readonly type: "text";
33
+ readonly text: string;
34
+ readonly json?: unknown;
35
+ } | {
36
+ readonly type: "toolCalls";
37
+ readonly calls: readonly {
38
+ readonly toolCallId: string;
39
+ readonly name: string;
40
+ readonly input: unknown;
41
+ }[];
42
+ };
43
+ readonly usage?: {
44
+ readonly inputTokens: number;
45
+ readonly outputTokens: number;
46
+ } | undefined;
47
+ }) => InferenceResponse;
@@ -0,0 +1,78 @@
1
+ const DEFAULT_ACCOUNT_NAME = "default";
2
+ const mapAccountRef = (value) => {
3
+ if (value === undefined || value === false) {
4
+ return undefined;
5
+ }
6
+ return value === true ? DEFAULT_ACCOUNT_NAME : value;
7
+ };
8
+ export const buildInferenceRespondRequest = (options, ownerUserId) => {
9
+ if ("sessionId" in options) {
10
+ return {
11
+ ownerUserId,
12
+ sessionId: options.sessionId,
13
+ toolResults: options.toolResults.map((result) => ({
14
+ toolCallId: result.toolCallId,
15
+ content: result.content,
16
+ ...(result.isError === undefined ? {} : { isError: result.isError }),
17
+ })),
18
+ };
19
+ }
20
+ const claude = mapAccountRef(options.credentials.claude);
21
+ const codex = mapAccountRef(options.credentials.codex);
22
+ return {
23
+ ownerUserId,
24
+ credentials: {
25
+ ...(options.credentials.profile === undefined
26
+ ? {}
27
+ : { profileId: options.credentials.profile }),
28
+ ...(claude === undefined ? {} : { claude }),
29
+ ...(codex === undefined ? {} : { codex }),
30
+ },
31
+ prompt: options.prompt,
32
+ ...(options.system === undefined ? {} : { system: options.system }),
33
+ ...(options.model === undefined ? {} : { model: options.model }),
34
+ ...(options.maxTurns === undefined ? {} : { maxTurns: options.maxTurns }),
35
+ ...(options.tools === undefined
36
+ ? {}
37
+ : {
38
+ tools: options.tools.map((tool) => ({
39
+ name: tool.name,
40
+ ...(tool.description === undefined ? {} : { description: tool.description }),
41
+ inputSchema: tool.inputSchema,
42
+ })),
43
+ }),
44
+ ...(options.responseFormat === undefined
45
+ ? {}
46
+ : {
47
+ responseFormat: {
48
+ type: options.responseFormat.type,
49
+ ...(options.responseFormat.schema === undefined
50
+ ? {}
51
+ : { schema: options.responseFormat.schema }),
52
+ },
53
+ }),
54
+ };
55
+ };
56
+ export const mapInferenceResponse = (wire) => {
57
+ const turn = wire.turn.type === "text"
58
+ ? {
59
+ type: "text",
60
+ text: wire.turn.text,
61
+ ...(wire.turn.json === undefined ? {} : { json: wire.turn.json }),
62
+ }
63
+ : {
64
+ type: "toolCalls",
65
+ calls: wire.turn.calls.map((call) => ({
66
+ toolCallId: call.toolCallId,
67
+ name: call.name,
68
+ input: call.input,
69
+ })),
70
+ };
71
+ return {
72
+ sessionId: wire.sessionId,
73
+ turn,
74
+ ...(wire.usage === undefined
75
+ ? {}
76
+ : { usage: { inputTokens: wire.usage.inputTokens, outputTokens: wire.usage.outputTokens } }),
77
+ };
78
+ };
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Maps any failure crossing the Effect boundary onto a plain public `SealantError`. The Effect core
3
- * fails with `@sealant/api-contracts` tagged errors (e.g. `SandboxNotFoundError`), Effect HTTP-client
3
+ * fails with `@sealant/api-contracts` tagged errors (e.g. `WorkspaceNotFoundError`), Effect HTTP-client
4
4
  * errors, or schema decode errors; the runtime squashes the `Cause` to its failure value and hands it
5
5
  * here. This is the single funnel that keeps Effect internals out of the public, Promise-based API.
6
6
  */
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Maps any failure crossing the Effect boundary onto a plain public `SealantError`. The Effect core
3
- * fails with `@sealant/api-contracts` tagged errors (e.g. `SandboxNotFoundError`), Effect HTTP-client
3
+ * fails with `@sealant/api-contracts` tagged errors (e.g. `WorkspaceNotFoundError`), Effect HTTP-client
4
4
  * errors, or schema decode errors; the runtime squashes the `Cause` to its failure value and hands it
5
5
  * here. This is the single funnel that keeps Effect internals out of the public, Promise-based API.
6
6
  */