@computesdk/archil 0.4.28 → 0.4.29

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 CHANGED
@@ -2,21 +2,22 @@
2
2
 
3
3
  [Archil](https://archil.com) provider for [ComputeSDK](https://www.computesdk.com).
4
4
 
5
- The provider supports Archil's two compute surfaces, selected by the
6
- `execution` config option:
7
-
8
- - **`exec`** (default): `create` resolves a handle to an existing Archil disk
9
- id, and `runCommand` executes shell commands in a managed ephemeral
10
- container with that disk attached via the control-plane `exec` endpoint.
11
- `destroy` is a no-op because disk lifecycle is managed by Archil.
12
- `getById` requires a disk id.
13
- - **`persistent`**: `create` provisions a persistent Archil sandbox — a
14
- long-running Linux VM with a dedicated disk — and waits until it is
15
- `running`. `runCommand` uses the sandbox's interactive process API over a
16
- short-lived WebSocket connection (a fresh connection URL is fetched per
17
- command, so expiry is handled automatically). `destroy` deletes the
18
- sandbox, `getById` fetches the sandbox and resumes it if paused, and
19
- `getUrl` resolves the sandbox's published endpoints.
5
+ Archil sandboxes are persistent Linux VMs, and that is what this provider
6
+ creates by default:
7
+
8
+ - `create()` provisions a VM and waits until it is `running`. `getById`
9
+ fetches a VM (resuming it if paused or stopped), `list` returns the
10
+ account's VMs, and `destroy` stops and deletes one.
11
+ - `runCommand`, streaming (`onStdout`/`onStderr`) and `startProcess` run on
12
+ Archil's native process API over a short-lived WebSocket (a fresh connection
13
+ URL per process). Files move through Archil's native file transfer API.
14
+ - Snapshots are paused forks of a VM; `create({ snapshotId })` restores one
15
+ into a new VM. `sandbox.pause()`/`resume()` pause the VM natively (also on
16
+ `sandbox.getInstance()`).
17
+
18
+ The older disk exec surface (a fresh container per command with an existing
19
+ disk mounted at `/mnt/archil`) is still available as an explicit opt-in; see
20
+ [Exec mode](#exec-mode-opt-in).
20
21
 
21
22
  ## Installation
22
23
 
@@ -26,12 +27,12 @@ npm install @computesdk/archil
26
27
 
27
28
  ## Configuration
28
29
 
29
- | Option | Env var | Required | Description |
30
- | ----------- | ------------------ | -------- | ----------------------------------------------- |
31
- | `apiKey` | `ARCHIL_API_KEY` | yes | Archil control-plane API key |
32
- | `region` | `ARCHIL_REGION` | yes | Archil region (e.g. `aws-us-east-1`) |
33
- | `baseUrl` | — | no | Override control-plane URL (for testing) |
34
- | `execution` | — | no | `"exec"` (default) or `"persistent"` |
30
+ | Option | Env var | Required | Description |
31
+ | ----------- | ------------------ | -------- | ---------------------------------------------------- |
32
+ | `apiKey` | `ARCHIL_API_KEY` | yes | Archil control-plane API key |
33
+ | `region` | `ARCHIL_REGION` | yes | Archil region (e.g. `aws-us-east-1`) |
34
+ | `baseUrl` | — | no | Override control-plane URL (for testing) |
35
+ | `execution` | `ARCHIL_EXECUTION` | no | `"persistent"` (default) or `"exec"` (disk exec) |
35
36
 
36
37
  ## Usage
37
38
 
@@ -40,105 +41,117 @@ import { archil } from '@computesdk/archil';
40
41
 
41
42
  const provider = archil();
42
43
 
43
- // Attach to an existing disk by id.
44
- const { sandbox } = await provider.sandbox.create({
45
- diskId: 'disk_abc123',
44
+ const sandbox = await provider.sandbox.create({
45
+ name: 'ci-job',
46
+ baseImage: 'node:24-bookworm', // OCI image; `image` / `templateId` work too
47
+ vcpus: 4, // or `cpu` / `cpus`, or `sizeClass: 'lg'`
48
+ memoryMiB: 8192, // or `memory`
49
+ env: { CI: '1' }, // or `envs`
50
+ maxTtlSeconds: 3600, // or `timeout` in ms; per powered-on session
51
+ sandbox: { /* extra Archil create fields */ },
46
52
  });
47
53
 
48
- const result = await provider.sandbox.runCommand(sandbox, 'echo hello > /mnt/note && cat /mnt/note');
49
- console.log(result.stdout); // "hello"
54
+ // Filesystem state, installs and background processes persist between calls.
55
+ // `cwd` and `env` apply to every part of a compound command.
56
+ await sandbox.runCommand('npm ci && npm test', { cwd: '/repo', env: { CI: '1' } });
57
+
58
+ // Native streaming and processes.
59
+ await sandbox.runCommand('npm run build', { onStdout: (c) => process.stdout.write(c) });
60
+ const proc = await sandbox.startProcess('cat', { stdin: true });
61
+ await proc.write('hello\n');
62
+ await proc.closeStdin();
63
+ await proc.wait();
50
64
 
51
- // Look up later by disk id:
52
- const byId = await provider.sandbox.getById(sandbox.instanceId);
65
+ // Pause/resume the same VM (memory, processes and disk preserved).
66
+ await sandbox.pause!();
67
+ await sandbox.resume!();
53
68
 
54
- await provider.sandbox.destroy(sandbox.instanceId);
69
+ await provider.sandbox.destroy(sandbox.sandboxId);
55
70
  ```
56
71
 
57
- `create()` requires top-level `diskId` as the target disk id.
72
+ The shared `ephemeral` create option overrides the configured mode per sandbox:
73
+ `ephemeral: true` resolves an exec-mode disk handle (requires `diskId`),
74
+ `ephemeral: false` provisions a VM.
58
75
 
59
- ### Persistent mode
76
+ ### Snapshots
60
77
 
61
78
  ```ts
62
- const provider = archil({ execution: 'persistent' });
79
+ const snapshot = await provider.snapshot.create(sandbox.sandboxId, { name: 'golden' });
80
+ const restored = await provider.sandbox.create({ snapshotId: snapshot.id });
81
+ const snapshots = await provider.snapshot.list();
82
+
83
+ // Archil deletes forks before their parent (it returns 409 otherwise):
84
+ await provider.sandbox.destroy(restored.sandboxId);
85
+ await provider.snapshot.delete(snapshot.id);
86
+ await provider.sandbox.destroy(sandbox.sandboxId);
87
+ ```
63
88
 
64
- const sandbox = await provider.sandbox.create({
65
- name: 'ci-job',
66
- baseImage: 'node:24-bookworm', // OCI image; `templateId` works too
67
- vcpus: 4, // or `cpu` / `cpus`
68
- memoryMiB: 8192, // or `memory`
69
- env: { CI: '1' },
70
- maxTtlSeconds: 3600, // per powered-on session
71
- sandbox: { /* extra Archil fields, e.g. network policy */ },
72
- });
89
+ A snapshot is a fork of the source VM's memory and disk, paused so it holds
90
+ state without running, and named `csdk-snap-<name>-<suffix>`. `snapshot.list()`
91
+ returns VMs with that prefix and `sandbox.list()` leaves them out. Restoring
92
+ forks the snapshot again into an independent VM. Snapshot ids are ordinary
93
+ Archil sandbox ids, so any VM id can be passed as `snapshotId`.
73
94
 
74
- // cwd/env/installs and background processes persist between calls.
75
- await sandbox.runCommand('npm ci', { cwd: '/repo' });
76
- await sandbox.runCommand('npm test', { cwd: '/repo' });
95
+ Declared capabilities, observed live: `provider.sandbox.pause` is
96
+ `{ memory: true, createOptions: { ephemeral: false } }` and
97
+ `provider.snapshot.capabilities` is `{ scope: 'rootfs', memory: true,
98
+ destroysSource: false, createOptions: { ephemeral: false } }` — the whole disk
99
+ (`/tmp`, `/root`, `/opt`, …) and running processes survive both, and the source
100
+ keeps running after a snapshot. A process must outlive the command that started
101
+ it to survive: use `startProcess` or `setsid`, since Archil reaps a command's
102
+ process group (including `nohup … &` children) when the command exits.
77
103
 
78
- // Paused sandboxes are resumed automatically on getById/runCommand.
79
- const resumed = await provider.sandbox.getById(sandbox.instanceId);
104
+ ## Exec mode (opt-in)
80
105
 
81
- await provider.sandbox.destroy(sandbox.instanceId); // deletes the sandbox
82
- ```
106
+ ```ts
107
+ const provider = archil({ execution: 'exec' }); // or ARCHIL_EXECUTION=exec
83
108
 
84
- Sandbox `create` accepts generic `CreateInstanceOptions` fields (`vcpus`/`cpu`/`cpus`,
85
- `memory`/`memoryMiB`, `image`/`templateId`, `envs`, `timeout` (ms → `maxTtlSeconds`))
86
- plus the Archil-specific keys shown above.
109
+ const sandbox = await provider.sandbox.create({ diskId: 'dsk-0000000000000000' });
110
+ await sandbox.runCommand('echo hello > /mnt/archil/note && cat /mnt/archil/note');
111
+ ```
87
112
 
88
- The shared `ephemeral` create option overrides the configured mode per sandbox:
89
- `ephemeral: true` resolves an exec-mode disk handle (requires `diskId`),
90
- `ephemeral: false` provisions a persistent sandbox — matching the same flag on
91
- other dual-mode providers like Upstash. `getById`/`list`/`destroy` follow the
92
- configured `execution` mode.
93
-
94
- ### Choosing a mode
95
-
96
- | | `exec` | `persistent` |
97
- | --------------------- | ------------------------------- | ------------------------------------------- |
98
- | Compute | Ephemeral container per command | Persistent VM |
99
- | `cwd`/`env`/installs | Lost between commands | Persist while running |
100
- | Filesystem writes | Only under `/mnt/archil` | Anywhere on the VM |
101
- | Background processes | Die with the container | Keep running |
102
- | `create` input | Existing `diskId` | Sandbox spec (image, vcpus, memory, …) |
103
- | Billing | Per `executeMs` | Per running wall-clock time |
104
- | `getUrl` | ❌ | ✅ (published endpoints) |
113
+ Each command runs in a fresh Archil-managed container with the disk mounted at
114
+ `/mnt/archil`. `create()` requires `diskId`; passing `diskId` without opting in
115
+ throws. `getById`/`list` operate on disks, `destroy` is a no-op (disk lifecycle
116
+ is managed by Archil), and ids starting with `dsk-` are always treated as disk
117
+ handles. `cwd`, `env` and installs do not persist between commands.
105
118
 
106
119
  ## Supported operations
107
120
 
108
- | Method | exec mode | persistent mode |
109
- | ------------- | --------- | ------------ |
110
- | `create` | ✅ Resolves an existing disk from top-level `diskId`. | ✅ Provisions a sandbox, waits for `running`. |
111
- | `getById` | ✅ Requires the disk id. | ✅ Fetches the sandbox; resumes if paused/stopped. |
112
- | `list` | ✅ Lists all disks visible to the API key. | ✅ Lists sandboxes. |
113
- | `destroy` | no-op — disk lifecycle is managed by Archil. | ✅ Deletes the sandbox and its backing disk. |
114
- | `runCommand` | ✅ Executes via the HTTP `exec` endpoint. | ✅ Executes via the process API (fresh connection URL per command). |
115
- | `getInfo` | ✅ | ✅ |
116
- | `getUrl` | ❌ Ephemeral containers have no port to expose. | ✅ Resolves the sandbox's endpoint for the port. |
117
- | `filesystem` | ✅ Maps paths into `/mnt/archil`; manages shared-mode checkout/checkin. | ✅ Uses the sandbox file transfer API; paths are the VM's real paths. |
121
+ | Method | Persistent VM (default) | Exec mode (opt-in) |
122
+ | ----------------- | ----------------------- | ------------------ |
123
+ | `create` | ✅ Provisions a VM, waits for `running`. | ✅ Resolves an existing disk from `diskId`. |
124
+ | `getById` | ✅ Fetches the VM; resumes if paused/stopped. | ✅ Fetches the disk. |
125
+ | `list` | ✅ All VMs on the account, minus snapshots. | ✅ All disks visible to the API key. |
126
+ | `destroy` | ✅ Stops and deletes the VM. | no-op |
127
+ | `runCommand` | ✅ Native process API. | ✅ HTTP `exec` endpoint. |
128
+ | Streaming | ✅ Native, live over the process WebSocket. | Output delivered when the command exits. |
129
+ | `startProcess` | ✅ Native (stdin, kill, wait). | ❌ |
130
+ | `filesystem` | ✅ Native file transfer for read/write; `mkdir`/`readdir`/`exists`/`remove` run shell commands. | ✅ Maps paths into `/mnt/archil`. |
131
+ | Snapshots | ✅ create / list / delete / restore. | ❌ |
132
+ | `pause`/`resume` | ✅ Native; memory and processes survive. | ❌ |
133
+ | `getUrl` | Only for ports already published as sandbox endpoints (not proven live). | ❌ |
118
134
 
119
135
  ## Limitations
120
136
 
121
- - **exec mode**: each `exec` call provisions a fresh container — there is no
122
- persistent state between calls beyond what is written to the disk.
123
- - **exec mode**: responses are truncated to ~5 MB by the Archil control plane.
124
- - **exec mode**: `getUrl` is not supported — each exec runs in a fresh
125
- ephemeral container, so there is no long-lived process to expose a port on.
126
- - **exec mode**: filesystem operations accept normal absolute paths and map
127
- them into the `/mnt/archil` disk mount internally. Each mutating operation
128
- checks out and checks in the disk automatically. Raw `runCommand` strings
129
- are not rewritten — commands that access the disk must use `/mnt/archil`
130
- themselves.
131
- - **persistent mode**: `pause`/`resume`/`fork` are available on the underlying
132
- `disk`-SDK sandbox via `getInstance()` — the generic provider interface has
133
- no `pause`/`resume` methods, so only `getById`/`runCommand` auto-resume.
137
+ - `list()` is one Archil API call: Archil's sandbox list endpoint returns every
138
+ sandbox in a single response (there is no cursor to page through).
139
+ - `kill(signal)` on a native process cancels it through Archil's process
140
+ control; Archil does not accept a signal name, so the result reports the
141
+ requested signal (`SIGKILL` by default) with exit code 137. Timed-out
142
+ commands report exit code 124.
143
+ - A VM with live forks (snapshots or VMs restored from it) cannot be deleted
144
+ until those forks are deleted.
145
+ - Exec mode: responses are truncated to ~5 MB by the Archil control plane, and
146
+ raw `runCommand` strings are not rewritten — commands that access the disk
147
+ must use `/mnt/archil` themselves.
134
148
 
135
149
  ## Standard sizes (persistent VMs only)
136
150
 
137
- `archil({ execution: 'persistent' }).sizes.list()` / `resolve('sm')` declares exact
138
- `sm`, `md`, `lg`, and `xl` requests. `create({ sizeClass: 'sm' })` maps to adapter
139
- `vcpus: 1`, `memoryMiB: 2048`, then native `vcpuCount` / `memSizeMiB`. Explicit
140
- `ephemeral: false` can select persistent mode; the default exec mode remains
141
- unchanged and reports `unavailable` for VM sizing. Attach (`sandboxId`/`instanceId`)
151
+ `archil().sizes.list()` / `resolve('sm')` declares exact `sm`, `md`, `lg`, and
152
+ `xl` requests. `create({ sizeClass: 'sm' })` maps to adapter `vcpus: 1`,
153
+ `memoryMiB: 2048`, then native `vcpuCount` / `memSizeMiB`. Exec mode
154
+ (`execution: 'exec'` or `ephemeral: true`) reports `unavailable` for VM sizing. Attach (`sandboxId`/`instanceId`)
142
155
  and fork (`snapshotId`) standard requests reject as `unsupported` before API calls;
143
156
  those paths cannot apply a new VM size. Conflicting native controls reject too.
144
157
  `xs`/`2xl` remain `unknown` in this initial adapter catalog.
package/dist/index.d.mts CHANGED
@@ -4,8 +4,8 @@ import { Archil, Sandbox } from 'disk';
4
4
 
5
5
  /**
6
6
  * Archil execution mode:
7
- * - "exec": serverless per-command containers on a disk (default).
8
- * - "persistent": a persistent sandbox VM run through the process API.
7
+ * - "persistent" (default): a persistent sandbox VM run through the process API.
8
+ * - "exec": serverless per-command containers on an existing disk (opt-in).
9
9
  */
10
10
  type ArchilExecutionMode = 'exec' | 'persistent';
11
11
  interface ArchilConfig {
@@ -16,10 +16,11 @@ interface ArchilConfig {
16
16
  /** Override the control-plane base URL (useful for testing). */
17
17
  baseUrl?: string;
18
18
  /**
19
- * Which Archil compute surface to use. Defaults to "exec". In
20
- * "persistent" mode create() provisions a persistent sandbox VM instead of
21
- * resolving a disk handle. Per-sandbox override: `ephemeral` on
22
- * create() options (true -> exec handle, false -> persistent VM).
19
+ * Which Archil compute surface to use. Falls back to ARCHIL_EXECUTION, then
20
+ * "persistent": create() provisions a persistent sandbox VM. "exec"
21
+ * resolves create({ diskId }) to a disk exec handle instead. Per-sandbox
22
+ * override: `ephemeral` on create() options (true -> exec handle, false ->
23
+ * persistent VM).
23
24
  */
24
25
  execution?: ArchilExecutionMode;
25
26
  }
@@ -45,6 +46,10 @@ interface ArchilSandbox {
45
46
  vm?: Sandbox;
46
47
  resolved: ResolvedConfig;
47
48
  createdAt: Date;
49
+ /** persistent mode: pause the VM, preserving CPU and memory state. */
50
+ pause?: () => Promise<void>;
51
+ /** persistent mode: resume the paused VM under the same sandbox id. */
52
+ resume?: () => Promise<void>;
48
53
  }
49
54
  declare const archil: (config?: ArchilConfig) => _computesdk_provider.Provider<ArchilSandbox, any, any, computesdk.Volume> & {
50
55
  readonly sizes: computesdk.InstanceSizeManager;
package/dist/index.d.ts CHANGED
@@ -4,8 +4,8 @@ import { Archil, Sandbox } from 'disk';
4
4
 
5
5
  /**
6
6
  * Archil execution mode:
7
- * - "exec": serverless per-command containers on a disk (default).
8
- * - "persistent": a persistent sandbox VM run through the process API.
7
+ * - "persistent" (default): a persistent sandbox VM run through the process API.
8
+ * - "exec": serverless per-command containers on an existing disk (opt-in).
9
9
  */
10
10
  type ArchilExecutionMode = 'exec' | 'persistent';
11
11
  interface ArchilConfig {
@@ -16,10 +16,11 @@ interface ArchilConfig {
16
16
  /** Override the control-plane base URL (useful for testing). */
17
17
  baseUrl?: string;
18
18
  /**
19
- * Which Archil compute surface to use. Defaults to "exec". In
20
- * "persistent" mode create() provisions a persistent sandbox VM instead of
21
- * resolving a disk handle. Per-sandbox override: `ephemeral` on
22
- * create() options (true -> exec handle, false -> persistent VM).
19
+ * Which Archil compute surface to use. Falls back to ARCHIL_EXECUTION, then
20
+ * "persistent": create() provisions a persistent sandbox VM. "exec"
21
+ * resolves create({ diskId }) to a disk exec handle instead. Per-sandbox
22
+ * override: `ephemeral` on create() options (true -> exec handle, false ->
23
+ * persistent VM).
23
24
  */
24
25
  execution?: ArchilExecutionMode;
25
26
  }
@@ -45,6 +46,10 @@ interface ArchilSandbox {
45
46
  vm?: Sandbox;
46
47
  resolved: ResolvedConfig;
47
48
  createdAt: Date;
49
+ /** persistent mode: pause the VM, preserving CPU and memory state. */
50
+ pause?: () => Promise<void>;
51
+ /** persistent mode: resume the paused VM under the same sandbox id. */
52
+ resume?: () => Promise<void>;
48
53
  }
49
54
  declare const archil: (config?: ArchilConfig) => _computesdk_provider.Provider<ArchilSandbox, any, any, computesdk.Volume> & {
50
55
  readonly sizes: computesdk.InstanceSizeManager;