@sealant/sdk 0.17.0 → 0.18.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.
- package/README.md +25 -0
- package/dist/internal/blueprint.js +57 -1
- package/dist/types.d.ts +55 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -124,6 +124,31 @@ const workspace = await sealant.workspaces.create({
|
|
|
124
124
|
rootless daemon at launch. The workspace receives `DOCKER_HOST`; Sealant never mounts the host
|
|
125
125
|
Docker socket. GitHub credentials provide both `GH_TOKEN` and `GITHUB_TOKEN` to the workspace.
|
|
126
126
|
|
|
127
|
+
## Dotfiles and shell
|
|
128
|
+
|
|
129
|
+
Bring your own environment: a login shell and dotfiles applied before the workspace accepts work.
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
const workspace = await sealant.workspaces.create({
|
|
133
|
+
repository: "github.com/acme/billing-service",
|
|
134
|
+
harness: codex(),
|
|
135
|
+
shell: "zsh",
|
|
136
|
+
dotfiles: {
|
|
137
|
+
// A repo the platform clones and applies (chezmoi/stow layouts detected, else copied):
|
|
138
|
+
repository: { url: "github.com/acme/dotfiles" },
|
|
139
|
+
// And/or caller-resolved archives — a checkout cloned host-side with your own ssh identity,
|
|
140
|
+
// or a scanned selection of home files, sent as gzipped tars (max 4, ~4MB decoded each):
|
|
141
|
+
archives: [{ data: tarGzBase64, manager: "copy", bootstrap: false }],
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`shell` installs the shell package and switches the login shell, so `.zshrc`/`.fishrc` actually take
|
|
147
|
+
effect. The `repository` applies first, then each archive in order, so local selections override
|
|
148
|
+
repo files. A failing apply fails the launch loudly rather than handing the agent a half-prepared
|
|
149
|
+
home. Managed OS families only — with `baseImage`, `dotfiles` and non-bash `shell` are rejected
|
|
150
|
+
client-side with the platform's reasoning.
|
|
151
|
+
|
|
127
152
|
## Custom base images
|
|
128
153
|
|
|
129
154
|
Instead of a managed OS family, a workspace image can be built from any image reference you already
|
|
@@ -41,6 +41,17 @@ export const buildCreateWorkspaceRequest = (options, config) => {
|
|
|
41
41
|
if (options.os !== undefined && options.baseImage !== undefined) {
|
|
42
42
|
throw new SealantError("workspaces.create accepts either `os` (a managed OS family) or `baseImage` (a custom base image reference), not both.", { code: "invalid_create_options" });
|
|
43
43
|
}
|
|
44
|
+
if (options.baseImage !== undefined && options.dotfiles !== undefined) {
|
|
45
|
+
throw new SealantError("`dotfiles` is not supported with `baseImage`: custom bases guarantee only a POSIX shell, so the dotfiles managers are not provisioned.", { code: "invalid_create_options" });
|
|
46
|
+
}
|
|
47
|
+
if (options.baseImage !== undefined && options.shell !== undefined && options.shell !== "bash") {
|
|
48
|
+
throw new SealantError("`shell` is not supported with `baseImage`: custom bases run /bin/sh and the login shell cannot be switched.", { code: "invalid_create_options" });
|
|
49
|
+
}
|
|
50
|
+
if (options.dotfiles !== undefined &&
|
|
51
|
+
options.dotfiles.repository === undefined &&
|
|
52
|
+
(options.dotfiles.archives === undefined || options.dotfiles.archives.length === 0)) {
|
|
53
|
+
throw new SealantError("`dotfiles` requires a `repository`, at least one entry in `archives`, or both.", { code: "invalid_create_options" });
|
|
54
|
+
}
|
|
44
55
|
const sourceName = options.repository ?? options.source?.path ?? "workspace";
|
|
45
56
|
const tail = sourceName
|
|
46
57
|
.split("/")
|
|
@@ -72,6 +83,8 @@ export const buildCreateWorkspaceRequest = (options, config) => {
|
|
|
72
83
|
...(toolingPackages.length === 0 ? {} : { packages: toolingPackages }),
|
|
73
84
|
...(dockerService ? { services: { docker: { enabled: true } } } : {}),
|
|
74
85
|
};
|
|
86
|
+
const dotfilesRepository = options.dotfiles?.repository;
|
|
87
|
+
const dotfilesArchives = options.dotfiles?.archives ?? [];
|
|
75
88
|
const spec = {
|
|
76
89
|
version: "1",
|
|
77
90
|
sources: {
|
|
@@ -84,6 +97,21 @@ export const buildCreateWorkspaceRequest = (options, config) => {
|
|
|
84
97
|
...(options.ref === undefined ? {} : { ref: options.ref }),
|
|
85
98
|
}
|
|
86
99
|
: { kind: "mount", hostPath: options.source?.path },
|
|
100
|
+
...(dotfilesRepository === undefined
|
|
101
|
+
? {}
|
|
102
|
+
: {
|
|
103
|
+
inputs: [
|
|
104
|
+
{
|
|
105
|
+
id: "dotfiles",
|
|
106
|
+
kind: "git",
|
|
107
|
+
purpose: "dotfiles",
|
|
108
|
+
provider: "generic",
|
|
109
|
+
url: toGitUrl(dotfilesRepository.url),
|
|
110
|
+
// Omitted ref = the remote's default branch — never assumed to be `main`.
|
|
111
|
+
...(dotfilesRepository.ref === undefined ? {} : { ref: dotfilesRepository.ref }),
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
}),
|
|
87
115
|
...(mounts.length === 0
|
|
88
116
|
? {}
|
|
89
117
|
: {
|
|
@@ -96,7 +124,35 @@ export const buildCreateWorkspaceRequest = (options, config) => {
|
|
|
96
124
|
}),
|
|
97
125
|
},
|
|
98
126
|
harness: { id: options.harness.id },
|
|
99
|
-
customization: {
|
|
127
|
+
customization: {
|
|
128
|
+
enableSealantd: true,
|
|
129
|
+
...(options.shell === undefined ? {} : { defaultShell: options.shell }),
|
|
130
|
+
// The repository path's knobs live at customization level; archives carry their own.
|
|
131
|
+
...(dotfilesRepository?.manager === undefined
|
|
132
|
+
? {}
|
|
133
|
+
: { dotfilesManager: dotfilesRepository.manager }),
|
|
134
|
+
...(dotfilesRepository?.bootstrap === undefined
|
|
135
|
+
? {}
|
|
136
|
+
: { dotfilesBootstrap: dotfilesRepository.bootstrap }),
|
|
137
|
+
...(dotfilesRepository?.bootstrapCommand === undefined
|
|
138
|
+
? {}
|
|
139
|
+
: { dotfilesBootstrapCommand: dotfilesRepository.bootstrapCommand }),
|
|
140
|
+
},
|
|
141
|
+
...(dotfilesArchives.length === 0
|
|
142
|
+
? {}
|
|
143
|
+
: {
|
|
144
|
+
runtime: {
|
|
145
|
+
dotfilesArchives: dotfilesArchives.map((archive) => ({
|
|
146
|
+
data: archive.data,
|
|
147
|
+
...(archive.manager === undefined ? {} : { manager: archive.manager }),
|
|
148
|
+
...(archive.target === undefined ? {} : { target: archive.target }),
|
|
149
|
+
...(archive.bootstrap === undefined ? {} : { bootstrap: archive.bootstrap }),
|
|
150
|
+
...(archive.bootstrapCommand === undefined
|
|
151
|
+
? {}
|
|
152
|
+
: { bootstrapCommand: archive.bootstrapCommand }),
|
|
153
|
+
})),
|
|
154
|
+
},
|
|
155
|
+
}),
|
|
100
156
|
target: {
|
|
101
157
|
os: options.baseImage !== undefined
|
|
102
158
|
? { family: "custom", mode: "require", baseImage: options.baseImage }
|
package/dist/types.d.ts
CHANGED
|
@@ -123,6 +123,53 @@ export interface WorkspaceExtraMount {
|
|
|
123
123
|
/** Defaults to `true`. Pass `false` deliberately — writes to extra mounts are unrecorded. */
|
|
124
124
|
readonly readOnly?: boolean;
|
|
125
125
|
}
|
|
126
|
+
/** How a dotfiles tree is applied inside the workspace. */
|
|
127
|
+
export type WorkspaceDotfilesManager = "auto" | "chezmoi" | "stow" | "copy";
|
|
128
|
+
/**
|
|
129
|
+
* A dotfiles repository the platform clones and applies before the workspace accepts work. Public
|
|
130
|
+
* or GitHub-App-reachable repos work as-is; for a repo only the caller's own ssh identity can
|
|
131
|
+
* reach, resolve it host-side and send the checkout as an archive instead (see
|
|
132
|
+
* `WorkspaceDotfilesArchive`).
|
|
133
|
+
*/
|
|
134
|
+
export interface WorkspaceDotfilesRepository {
|
|
135
|
+
/** Clone URL (or `"github.com/acme/dotfiles"` shorthand). */
|
|
136
|
+
readonly url: string;
|
|
137
|
+
/** Git ref. Omitted = the remote's default branch — never assumed to be `main`. */
|
|
138
|
+
readonly ref?: string;
|
|
139
|
+
/** Defaults to `"auto"`: chezmoi/stow layouts are detected, everything else is copied. */
|
|
140
|
+
readonly manager?: WorkspaceDotfilesManager;
|
|
141
|
+
/** Run the repo's bootstrap command after applying (skipped when absent). Defaults to true. */
|
|
142
|
+
readonly bootstrap?: boolean;
|
|
143
|
+
/** Bootstrap command, relative to the checkout. Defaults to `./install.sh`. */
|
|
144
|
+
readonly bootstrapCommand?: string;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* A caller-resolved dotfiles tree: a gzipped tar the daemon extracts and applies at boot through
|
|
148
|
+
* the same manager dispatch as a cloned repo. This is the shape for dotfiles resolved host-side —
|
|
149
|
+
* a checkout cloned with the caller's own ssh identity, or a scanned selection of home files —
|
|
150
|
+
* so no URL or credential ever has to reach the workspace. Max 4 archives, ~4MB decoded each.
|
|
151
|
+
*/
|
|
152
|
+
export interface WorkspaceDotfilesArchive {
|
|
153
|
+
/** base64 of a `.tar.gz` whose contents apply relative to the target. */
|
|
154
|
+
readonly data: string;
|
|
155
|
+
/** Defaults to `"auto"`. Scanned home files usually want `"copy"`. */
|
|
156
|
+
readonly manager?: WorkspaceDotfilesManager;
|
|
157
|
+
/** Where the tree lands: `"home"` (default) or `"config"` (`$HOME/.config`, copy manager only). */
|
|
158
|
+
readonly target?: "home" | "config";
|
|
159
|
+
/** Run `./install.sh` (or `bootstrapCommand`) after applying when present. Defaults to true. */
|
|
160
|
+
readonly bootstrap?: boolean;
|
|
161
|
+
readonly bootstrapCommand?: string;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Dotfiles for the workspace: a repository the platform clones, caller-resolved archives, or both
|
|
165
|
+
* (the repository applies first, archives after — in order — so local selections override repo
|
|
166
|
+
* files). Applied before the workspace reports ready; a failing apply fails the launch loudly.
|
|
167
|
+
* Not supported with `baseImage` (custom bases guarantee only a POSIX shell).
|
|
168
|
+
*/
|
|
169
|
+
export interface WorkspaceDotfilesOptions {
|
|
170
|
+
readonly repository?: WorkspaceDotfilesRepository;
|
|
171
|
+
readonly archives?: readonly WorkspaceDotfilesArchive[];
|
|
172
|
+
}
|
|
126
173
|
/** Runtime-managed services attached only to this workspace. */
|
|
127
174
|
export interface WorkspaceServicesOptions {
|
|
128
175
|
/**
|
|
@@ -160,6 +207,14 @@ export interface CreateOptions {
|
|
|
160
207
|
readonly baseImage?: string;
|
|
161
208
|
/** Extra OS packages to install in the workspace. */
|
|
162
209
|
readonly packages?: readonly string[];
|
|
210
|
+
/**
|
|
211
|
+
* Login shell for the workspace user (`"bash"` default). The shell package is installed and the
|
|
212
|
+
* login shell switched, so dotfiles like `.zshrc` actually take effect. Managed OS families
|
|
213
|
+
* only — custom bases guarantee just a POSIX shell.
|
|
214
|
+
*/
|
|
215
|
+
readonly shell?: "bash" | "zsh" | "fish";
|
|
216
|
+
/** Dotfiles applied before the workspace accepts work (see `WorkspaceDotfilesOptions`). */
|
|
217
|
+
readonly dotfiles?: WorkspaceDotfilesOptions;
|
|
163
218
|
/** Runtime-managed services that need more than installing an OS package. */
|
|
164
219
|
readonly services?: WorkspaceServicesOptions;
|
|
165
220
|
/** When true (default), resolve only once the workspace runtime is live. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sealant/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.1",
|
|
4
4
|
"description": "The fluent public SDK for Sealant — create a workspace, run a harness, replay the record.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"access": "public"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@sealant/api-contracts": "^0.
|
|
29
|
+
"@sealant/api-contracts": "^0.18.1"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@effect/vitest": "4.0.0-beta.85",
|