@kosa8/sdk 0.0.0-stage → 0.3.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,1343 @@
1
+ import * as http from 'node:http';
2
+
3
+ /**
4
+ * Shapes of the kosa8 native API (/kosa8/v1), taken from the daemon's Go
5
+ * source (pkg/apid/native, pkg/sandbox, pkg/engine, pkg/vnet). Field names
6
+ * are the daemon's JSON names, unchanged.
7
+ */
8
+ /** GET /kosa8/v1/health */
9
+ interface Health {
10
+ status: string;
11
+ version: string;
12
+ commit: string;
13
+ go: string;
14
+ uptime_seconds: number;
15
+ phase: string;
16
+ }
17
+ /** A host directory exposed inside a sandbox (pkg/sandbox Mount). */
18
+ interface Mount {
19
+ host_path: string;
20
+ guest_path: string;
21
+ read_only: boolean;
22
+ }
23
+ /**
24
+ * Egress policy string the daemon accepts (pkg/vnet ParsePolicy):
25
+ * `any`, `deny`, `fakenet`, or `allow:HOST[,HOST...]` where each entry is a
26
+ * hostname, a `*.domain` wildcard, an IPv4 address or an IPv4 CIDR.
27
+ */
28
+ type EgressPolicyString = 'any' | 'deny' | 'fakenet' | `allow:${string}`;
29
+ /**
30
+ * Egress policy as this SDK takes it: one of the daemon's strings, or
31
+ * `{ allow: [...] }` for an allow-list (everything else is refused on the host).
32
+ */
33
+ type EgressPolicy = EgressPolicyString | {
34
+ allow: readonly string[];
35
+ };
36
+ /** A host the sandbox may reach through an egress broker (pkg/broker HostRule). */
37
+ interface BrokerHostRule {
38
+ /** Exact DNS name, a `*.domain` wildcard, or a literal IPv4 address. */
39
+ host: string;
40
+ /** Ports the host may be reached on. Empty means 443 and 80. */
41
+ ports?: number[];
42
+ /** Methods allowed for plain-HTTP requests. Empty means any. */
43
+ methods?: string[];
44
+ }
45
+ /** A credentialed upstream behind the broker (pkg/sandbox BrokerRoute). */
46
+ interface BrokerRoute {
47
+ name: string;
48
+ upstream: string;
49
+ methods?: string[];
50
+ paths?: string[];
51
+ /** Header the broker sets on the way out, e.g. `Authorization` or `x-api-key`. */
52
+ header: string;
53
+ scheme?: string;
54
+ /** The real credential. Held by the broker on the host, never by the sandbox. */
55
+ secret: string;
56
+ }
57
+ /** Puts a sandbox behind an egress broker (pkg/sandbox BrokerSpec). */
58
+ interface BrokerSpec {
59
+ allow?: BrokerHostRule[];
60
+ routes?: BrokerRoute[];
61
+ }
62
+ /** The broker as a running sandbox reports it (pkg/sandbox BrokerInfo). */
63
+ interface BrokerInfo {
64
+ url: string;
65
+ hosts?: string[];
66
+ routes?: string[];
67
+ }
68
+ /** Packet capture to a pcapng file on the host (pkg/sandbox CaptureSpec). */
69
+ interface CaptureSpec {
70
+ /** Absolute path on the host. */
71
+ path: string;
72
+ max_bytes?: number;
73
+ max_files?: number;
74
+ }
75
+ /** A sandbox (pkg/sandbox Sandbox). */
76
+ interface Sandbox {
77
+ id: string;
78
+ name: string;
79
+ created: string;
80
+ /** running | paused | stopped */
81
+ state: string;
82
+ parent?: string;
83
+ cpus: number;
84
+ mem_mb: number;
85
+ disk_gb?: number;
86
+ mounts?: Mount[];
87
+ egress?: string;
88
+ capture?: string;
89
+ ip?: string;
90
+ labels?: Record<string, string>;
91
+ broker?: BrokerInfo;
92
+ /** When it stops or is deleted by itself (pkg/sandbox Lifecycle). */
93
+ lifecycle?: Lifecycle;
94
+ /** When it last stopped (RFC 3339). */
95
+ stopped_at?: string;
96
+ }
97
+ /**
98
+ * When a sandbox stops or goes away by itself (pkg/sandbox Lifecycle).
99
+ * A field left out (or 0) is off.
100
+ */
101
+ interface Lifecycle {
102
+ /** Stop after this many minutes without use. */
103
+ auto_stop_min?: number;
104
+ /** Delete once it has been stopped this many minutes. */
105
+ auto_delete_min?: number;
106
+ /** Stop this many minutes after it was created, in use or not. */
107
+ ttl_min?: number;
108
+ /** Delete instead of stopping, disk and all. */
109
+ ephemeral?: boolean;
110
+ }
111
+ /** A saved sandbox state (pkg/sandbox Snapshot). */
112
+ interface Snapshot {
113
+ id: string;
114
+ sandbox: string;
115
+ created: string;
116
+ machine_id?: string;
117
+ mac?: string;
118
+ cpus: number;
119
+ mem_mb: number;
120
+ cmdline: string;
121
+ size_bytes: number;
122
+ state_path: string;
123
+ disk_path?: string;
124
+ data_path?: string;
125
+ disk_gb?: number;
126
+ ephemeral?: boolean;
127
+ mounts?: Mount[];
128
+ egress?: string;
129
+ received?: boolean;
130
+ received_mounts?: string[];
131
+ sealed?: boolean;
132
+ labels?: Record<string, string>;
133
+ encryption?: Record<string, unknown>;
134
+ [key: string]: unknown;
135
+ }
136
+ /** A container inside an engine (pkg/engine Container). */
137
+ interface Container {
138
+ id: string;
139
+ image: string;
140
+ status: string;
141
+ exit?: number;
142
+ ip?: string;
143
+ }
144
+ /** POST /kosa8/v1/sandboxes answer. */
145
+ interface CreateSandboxResult {
146
+ sandbox: Sandbox;
147
+ boot_ms: number;
148
+ /** Present when the sandbox was created behind a broker: the stand-ins the sandbox holds. */
149
+ broker?: {
150
+ url: string;
151
+ placeholders: Record<string, string>;
152
+ };
153
+ }
154
+ /** POST /kosa8/v1/sandboxes/{id}/up answer. */
155
+ interface StartSandboxResult {
156
+ sandbox: Sandbox;
157
+ boot_ms: number;
158
+ warning?: string;
159
+ }
160
+ /** POST /kosa8/v1/sandboxes/{id}/down answer. */
161
+ interface StopSandboxResult {
162
+ ok: boolean;
163
+ sandbox?: Sandbox;
164
+ warning?: string;
165
+ already_stopped?: boolean;
166
+ }
167
+ /** DELETE /kosa8/v1/sandboxes/{id} answer. */
168
+ interface DeleteSandboxResult {
169
+ ok: boolean;
170
+ wipe?: unknown;
171
+ files?: unknown;
172
+ }
173
+ /** POST /kosa8/v1/sandboxes/{id}/snapshot answer. */
174
+ interface SnapshotSandboxResult {
175
+ snapshot: Snapshot;
176
+ snapshot_ms: number;
177
+ encrypted_by_policy?: string;
178
+ encrypt_ms?: number;
179
+ encryption?: unknown;
180
+ }
181
+ /** POST /kosa8/v1/sandboxes/{id}/fork answer. */
182
+ interface ForkResult {
183
+ forks: Sandbox[];
184
+ /** The (ephemeral) snapshot the forks were restored from. */
185
+ snapshot: string;
186
+ fork_ms: number;
187
+ count: number;
188
+ encrypted_by_policy?: string;
189
+ encrypt_ms?: number;
190
+ }
191
+ /** POST /kosa8/v1/snapshots/{id}/restore answer. */
192
+ interface RestoreResult {
193
+ sandbox: Sandbox;
194
+ restore_ms: number;
195
+ seal?: unknown;
196
+ }
197
+ /** DELETE /kosa8/v1/snapshots/{id} answer. */
198
+ interface DeleteSnapshotResult {
199
+ ok: boolean;
200
+ removed: string;
201
+ encrypted: boolean;
202
+ shred?: unknown;
203
+ wipe?: unknown;
204
+ files?: unknown;
205
+ }
206
+ /** GET /kosa8/v1/sandboxes/{id}/egress answer (pkg/sandbox EgressStatus). */
207
+ interface EgressStatus {
208
+ policy: string;
209
+ stats: {
210
+ passed: number;
211
+ denied: number;
212
+ dropped: number;
213
+ dns_answered: number;
214
+ dns_refused: number;
215
+ fakenet?: number;
216
+ };
217
+ capture?: string;
218
+ wildcards?: {
219
+ wildcard: string;
220
+ names?: string[];
221
+ more?: number;
222
+ }[];
223
+ fakenet?: {
224
+ interactions: number;
225
+ dropped?: number;
226
+ ca?: string;
227
+ log?: string;
228
+ };
229
+ }
230
+ /** One frame of a streamed answer (pkg/engine Frame), with `data` decoded. */
231
+ interface Frame {
232
+ /** stdout | stderr | status */
233
+ stream?: string;
234
+ data?: Buffer;
235
+ done?: boolean;
236
+ ok?: boolean;
237
+ error?: string;
238
+ exit?: number;
239
+ id?: string;
240
+ image?: string;
241
+ [key: string]: unknown;
242
+ }
243
+ /** The collected result of a streamed run or exec. */
244
+ interface ExecResult {
245
+ exitCode: number;
246
+ stdout: string;
247
+ stderr: string;
248
+ stdoutBytes: Buffer;
249
+ stderrBytes: Buffer;
250
+ }
251
+ /** A client-side restore point (same record as `kosa8 checkpoint`, pkg/checkpoint). */
252
+ interface Checkpoint {
253
+ /** The underlying snapshot id, e.g. `web-ckpt-3`. */
254
+ id: string;
255
+ sandbox: string;
256
+ label: string;
257
+ auto?: boolean;
258
+ /** RFC 3339 time it was taken. */
259
+ created: string;
260
+ }
261
+ /** One branch of an explore. */
262
+ interface ExploreBranch {
263
+ /** The forked sandbox's id. */
264
+ name: string;
265
+ variant: string;
266
+ exit: number;
267
+ output: string;
268
+ duration_ms: number;
269
+ error?: string;
270
+ }
271
+ interface ExploreResult {
272
+ parent: string;
273
+ branches: ExploreBranch[];
274
+ /** The fastest successful branch, or "" when every branch failed. */
275
+ winner: string;
276
+ removed: number;
277
+ }
278
+ /** A file a code run produced: today, a chart as a PNG. */
279
+ interface CodeArtifact {
280
+ /** Media type, e.g. `image/png`. */
281
+ type: string;
282
+ name: string;
283
+ data: Buffer;
284
+ }
285
+ /** The outcome of `runCode`. A non-zero `exitCode` is a result, not an error. */
286
+ interface CodeResult {
287
+ /** `exitCode === 0` and not timed out. */
288
+ ok: boolean;
289
+ exitCode: number;
290
+ stdout: string;
291
+ stderr: string;
292
+ language: string;
293
+ image: string;
294
+ artifacts: CodeArtifact[];
295
+ durationMs: number;
296
+ timedOut: boolean;
297
+ /** Output was cut at the daemon's limit. */
298
+ truncated: boolean;
299
+ }
300
+ /** The outcome of one command in a shell session. `cwd` is where the shell is now. */
301
+ interface ShellResult {
302
+ ok: boolean;
303
+ exitCode: number;
304
+ stdout: string;
305
+ stderr: string;
306
+ cwd: string;
307
+ durationMs: number;
308
+ timedOut: boolean;
309
+ truncated: boolean;
310
+ }
311
+ /** A file or folder in the sandbox workspace (pkg/engine FileInfo). */
312
+ interface FileInfo {
313
+ name: string;
314
+ path: string;
315
+ /** file | dir | symlink | other */
316
+ type: string;
317
+ size: number;
318
+ /** Permission bits. */
319
+ mode: number;
320
+ mod_time: string;
321
+ /** A symlink's target. */
322
+ link?: string;
323
+ }
324
+ /** One changed path in `git status`. */
325
+ interface GitFileStatus {
326
+ path: string;
327
+ /** A rename's old path. */
328
+ from?: string;
329
+ index: string;
330
+ worktree: string;
331
+ }
332
+ interface GitStatus {
333
+ branch: string;
334
+ upstream?: string;
335
+ ahead: number;
336
+ behind: number;
337
+ clean: boolean;
338
+ files: GitFileStatus[];
339
+ }
340
+ interface GitCommit {
341
+ hash: string;
342
+ author_name: string;
343
+ author_email: string;
344
+ date: string;
345
+ subject: string;
346
+ }
347
+ interface GitBranch {
348
+ name: string;
349
+ current: boolean;
350
+ }
351
+ /** The git operations the daemon runs (POST …/git). */
352
+ type GitOp = 'clone' | 'status' | 'add' | 'commit' | 'push' | 'pull' | 'checkout' | 'branches' | 'log' | 'diff';
353
+ /**
354
+ * The outcome of a git operation. A git failure is `ok: false`, not an error;
355
+ * `status`, `log` or `branches` are filled for those ops.
356
+ */
357
+ interface GitResult {
358
+ op: string;
359
+ ok: boolean;
360
+ exitCode: number;
361
+ stdout: string;
362
+ stderr: string;
363
+ /** The repository, in the workspace. */
364
+ path: string;
365
+ status?: GitStatus;
366
+ log?: GitCommit[];
367
+ branches?: GitBranch[];
368
+ }
369
+ /** A shell session (POST/GET …/sessions). */
370
+ interface SessionInfo {
371
+ name: string;
372
+ /** The session's container id. */
373
+ id: string;
374
+ image: string;
375
+ status: string;
376
+ }
377
+ /** POST …/previews answer: a signed link to a port in the sandbox. */
378
+ interface Preview {
379
+ url: string;
380
+ token: string;
381
+ /** RFC 3339. */
382
+ expires_at: string;
383
+ container: string;
384
+ port: number;
385
+ /** Where the daemon's preview listener is. */
386
+ listen: string;
387
+ }
388
+ /** A sandbox template (GET /kosa8/v1/templates). */
389
+ interface Template {
390
+ name: string;
391
+ image: string;
392
+ size_bytes: number;
393
+ created: string;
394
+ dockerfile?: string;
395
+ }
396
+
397
+ /**
398
+ * Checkpoints are client-side bookkeeping over daemon snapshots, exactly as
399
+ * in the kosa8 CLI and MCP server (pkg/checkpoint): a checkpoint is a
400
+ * snapshot with the id `<sandbox>-ckpt-<n>`, and an ordered stack of them per
401
+ * sandbox records labels and order. The daemon itself has no checkpoint
402
+ * endpoint.
403
+ */
404
+ /** How many checkpoints are kept per sandbox; the oldest is evicted (pkg/checkpoint MaxPerSandbox). */
405
+ declare const MAX_CHECKPOINTS_PER_SANDBOX = 10;
406
+ type StoreData = Record<string, Checkpoint[]>;
407
+ /** Where checkpoint stacks are kept. */
408
+ interface CheckpointStore {
409
+ /** Read every stack. */
410
+ load(): Promise<StoreData>;
411
+ /** Run `fn` on the stacks and save what it leaves, serialised against other updates. */
412
+ update<T>(fn: (data: StoreData) => T | Promise<T>): Promise<T>;
413
+ }
414
+ /** Reject a name that could escape the store (pkg/checkpoint validSandbox). */
415
+ declare function validateSandboxName(name: string): void;
416
+ /** Keeps stacks in memory only; nothing is shared with the kosa8 CLI. */
417
+ declare class MemoryCheckpointStore implements CheckpointStore {
418
+ private data;
419
+ private queue;
420
+ load(): Promise<StoreData>;
421
+ update<T>(fn: (data: StoreData) => T | Promise<T>): Promise<T>;
422
+ }
423
+ /**
424
+ * The store the kosa8 CLI, MCP server and desk use: `~/.kosa8/checkpoints.json`
425
+ * (mode 0600, rewritten atomically). Checkpoints taken through the SDK are
426
+ * therefore visible to `kosa8 rewind` and the other way round.
427
+ *
428
+ * Updates are serialised within this process and between Node processes
429
+ * using this store (an exclusive lock file beside it). The Go tools lock the
430
+ * same file with flock(2), which Node cannot take, so an SDK update that
431
+ * lands in the same instant as a CLI update could lose one record; the
432
+ * snapshots themselves are unaffected.
433
+ */
434
+ declare class FileCheckpointStore implements CheckpointStore {
435
+ readonly path: string;
436
+ private queue;
437
+ constructor(filePath?: string);
438
+ load(): Promise<StoreData>;
439
+ update<T>(fn: (data: StoreData) => T | Promise<T>): Promise<T>;
440
+ private locked;
441
+ }
442
+ /** The stack logic of pkg/checkpoint, over any store. */
443
+ declare class CheckpointBook {
444
+ readonly store: CheckpointStore;
445
+ constructor(store: CheckpointStore);
446
+ /** The snapshot id the next checkpoint should use, and ids to evict to stay under the cap. */
447
+ nextId(sandbox: string): Promise<{
448
+ id: string;
449
+ evict: string[];
450
+ }>;
451
+ record(c: Omit<Checkpoint, 'created'> & {
452
+ created?: string;
453
+ }, evicted?: string[]): Promise<Checkpoint>;
454
+ list(sandbox: string): Promise<Checkpoint[]>;
455
+ latest(sandbox: string): Promise<Checkpoint>;
456
+ /** Find by id or (case-insensitive) label, newest match first. */
457
+ resolve(sandbox: string, ref: string): Promise<Checkpoint>;
458
+ /** Keep `id` as the top of the stack; return the ids taken after it (now meaningless). */
459
+ pop(sandbox: string, id: string): Promise<string[]>;
460
+ /** Drop every checkpoint of a sandbox; return the snapshot ids to delete. */
461
+ forget(sandbox: string): Promise<string[]>;
462
+ }
463
+
464
+ /** Who the audit log should file a request under (pkg/policyd Actor). */
465
+ type Actor = 'human' | 'agent' | 'tool';
466
+ interface TransportOptions {
467
+ /**
468
+ * Unix socket of the daemon. Default: `$HOME/.kosa8/run/kosa8.sock`.
469
+ * Ignored when `host` (or KOSA8_HOST) is set.
470
+ */
471
+ socketPath?: string;
472
+ /**
473
+ * A remote kosa8 worker: `https://host`, `http://host:port`, `tcp://host:port`
474
+ * or a bare `host:port`, the same spellings the kosa8 CLI accepts in
475
+ * KOSA8_HOST. `unix:///path/to.sock` selects a socket. Defaults to the
476
+ * KOSA8_HOST environment variable.
477
+ */
478
+ host?: string;
479
+ /** Bearer token for a remote worker. Defaults to KOSA8_TOKEN when KOSA8_HOST is in use. */
480
+ token?: string;
481
+ /**
482
+ * Allow plain http to a non-loopback host. Off by default, as in the CLI,
483
+ * because the token and every request would cross the network unencrypted.
484
+ * KOSA8_INSECURE=1 also allows it.
485
+ */
486
+ insecure?: boolean;
487
+ /** Sent as X-Kosa8-Actor so the audit log files requests correctly. Default `tool`. */
488
+ actor?: Actor;
489
+ /** Agent identity token (X-Kosa8-Agent-Token). Defaults to KOSA8_AGENT_TOKEN. */
490
+ agentToken?: string;
491
+ /** Extra headers on every request. */
492
+ headers?: Record<string, string>;
493
+ /** Environment to read KOSA8_* variables from. Default `process.env`. */
494
+ env?: Record<string, string | undefined>;
495
+ /**
496
+ * The CLI's saved worker connection, used when neither `host` nor KOSA8_HOST
497
+ * is set (and no `socketPath` is given): what `kosa8 wsl setup` writes on
498
+ * Windows, and `kosa8 worker join` anywhere. Default
499
+ * `$HOME/.kosa8/worker.json`; `null` reads none.
500
+ */
501
+ workerFile?: string | null;
502
+ }
503
+ interface RequestOptions {
504
+ query?: Record<string, string | number | boolean | undefined>;
505
+ body?: unknown;
506
+ /** A raw (non-JSON) request body, sent as-is; an async iterable is streamed chunked. */
507
+ rawBody?: Uint8Array | string | AsyncIterable<Uint8Array | string>;
508
+ /** Signed-approval id, sent as X-Kosa8-Approval. */
509
+ approval?: string;
510
+ signal?: AbortSignal;
511
+ headers?: Record<string, string>;
512
+ }
513
+ type Endpoint = {
514
+ kind: 'unix';
515
+ socketPath: string;
516
+ } | {
517
+ kind: 'tcp';
518
+ url: URL;
519
+ token?: string;
520
+ };
521
+ declare const APPROVAL_HEADER = "X-Kosa8-Approval";
522
+ declare const ACTOR_HEADER = "X-Kosa8-Actor";
523
+ declare const AGENT_TOKEN_HEADER = "X-Kosa8-Agent-Token";
524
+ /** The daemon's default socket: $HOME/.kosa8/run/kosa8.sock (pkg/paths). */
525
+ declare function defaultSocketPath(): string;
526
+ /** The CLI's saved worker connection: $HOME/.kosa8/worker.json (internal/cli/worker.go). */
527
+ declare function defaultWorkerFile(): string;
528
+ /** Resolve where to connect, following the CLI's KOSA8_HOST rules. */
529
+ declare function resolveEndpoint(opts: TransportOptions): Endpoint;
530
+ interface RawResponse {
531
+ status: number;
532
+ headers: http.IncomingHttpHeaders;
533
+ stream: http.IncomingMessage;
534
+ }
535
+ /** HTTP over the daemon's unix socket (or a remote worker). No dependencies. */
536
+ declare class Transport {
537
+ private readonly endpoint;
538
+ private readonly actor;
539
+ private readonly agentToken?;
540
+ private readonly extraHeaders;
541
+ constructor(opts?: TransportOptions);
542
+ /** Human-readable description of where requests go. */
543
+ get target(): string;
544
+ private buildPath;
545
+ /** Send a request and return the raw response once headers arrive. */
546
+ raw(method: string, p: string, opts?: RequestOptions): Promise<RawResponse>;
547
+ /** Send a request and decode a JSON answer; HTTP errors become typed errors. */
548
+ json<T>(method: string, p: string, opts?: RequestOptions): Promise<T>;
549
+ /**
550
+ * Send a request whose answer is a stream of NDJSON frames (run, exec,
551
+ * attach). HTTP errors (a refusal before streaming began) become typed
552
+ * errors; each frame's base64 `data` is decoded to a Buffer.
553
+ */
554
+ frames(method: string, p: string, opts?: RequestOptions): AsyncGenerator<Frame>;
555
+ }
556
+
557
+ /** Options every call accepts. */
558
+ interface CallOptions {
559
+ /**
560
+ * Id of a recorded signed approval for this exact action, sent as
561
+ * X-Kosa8-Approval. Needed only when the org policy requires one; a
562
+ * refusal (Kosa8ApprovalRequiredError) says how a human gets it.
563
+ */
564
+ approval?: string;
565
+ signal?: AbortSignal;
566
+ }
567
+ interface Kosa8ClientOptions extends TransportOptions {
568
+ /**
569
+ * Where checkpoint stacks are kept. Default: the kosa8 CLI's own store,
570
+ * `~/.kosa8/checkpoints.json`, so `kosa8 rewind` sees SDK checkpoints.
571
+ */
572
+ checkpointStore?: CheckpointStore;
573
+ }
574
+ interface CreateSandboxOptions extends CallOptions {
575
+ /** Sandbox name; the daemon generates one when omitted. */
576
+ name?: string;
577
+ cpus?: number;
578
+ memMb?: number;
579
+ /** Data disk in GB (holds images and everything written inside). 0 = daemon default. */
580
+ diskGb?: number;
581
+ mounts?: Mount[];
582
+ /**
583
+ * Network policy: `'deny'`, `'any'`, `'fakenet'`, `'allow:a.com,b.com'` or
584
+ * `{ allow: ['a.com', '*.b.com', '10.0.0.0/8'] }`. When omitted the daemon
585
+ * applies the org policy's default egress, else `any`.
586
+ */
587
+ egress?: EgressPolicy;
588
+ /** Shorthand for `egress: { allow: [...] }`. */
589
+ egressAllow?: readonly string[];
590
+ /** Start a packet capture from the first frame. */
591
+ capture?: CaptureSpec;
592
+ labels?: Record<string, string>;
593
+ /** Put the sandbox behind an egress broker that adds credentials it never holds. */
594
+ broker?: BrokerSpec;
595
+ /** Stop it after this many idle minutes. */
596
+ autoStopMin?: number;
597
+ /** Stop it this many minutes after creation, in use or not. */
598
+ ttlMin?: number;
599
+ /** Delete it once it has been stopped this many minutes. */
600
+ autoDeleteMin?: number;
601
+ /** Delete it (disk and all) whenever it stops. */
602
+ ephemeral?: boolean;
603
+ /** Start it with a template's image (see `buildTemplate`). */
604
+ template?: string;
605
+ }
606
+ interface RunCodeOptions extends CallOptions {
607
+ /** `python` (default), `javascript` or `typescript`. */
608
+ language?: string;
609
+ /** Image to run in; the daemon picks one per language (or the sandbox template's). */
610
+ image?: string;
611
+ env?: Record<string, string>;
612
+ /** Time limit in seconds; past it the run is killed and `timedOut` set. */
613
+ timeoutS?: number;
614
+ }
615
+ interface WriteFileOptions extends CallOptions {
616
+ /** Permission bits as octal text, e.g. `0755`. */
617
+ mode?: string;
618
+ }
619
+ /** The fields of a git op; which ones matter depends on the op. */
620
+ interface GitOptions extends CallOptions {
621
+ /** The repository, in the workspace. */
622
+ path?: string;
623
+ /** clone */
624
+ url?: string;
625
+ branch?: string;
626
+ /** clone --depth */
627
+ depth?: number;
628
+ /** push | pull; default origin */
629
+ remote?: string;
630
+ /** checkout -b */
631
+ create?: boolean;
632
+ /** add: these paths (default everything) */
633
+ files?: string[];
634
+ /** commit */
635
+ message?: string;
636
+ authorName?: string;
637
+ authorEmail?: string;
638
+ /** log: how many (default 20) */
639
+ n?: number;
640
+ /** diff --cached */
641
+ staged?: boolean;
642
+ /** For an https remote that needs credentials. */
643
+ username?: string;
644
+ token?: string;
645
+ /** Image git runs in. */
646
+ image?: string;
647
+ }
648
+ interface GitCommitOptions extends Omit<GitOptions, 'path' | 'message'> {
649
+ /** Stage everything first (default true). */
650
+ addAll?: boolean;
651
+ }
652
+ interface CreateSessionOptions extends CallOptions {
653
+ image?: string;
654
+ env?: Record<string, string>;
655
+ }
656
+ interface SessionExecOptions extends CallOptions {
657
+ /** Time limit in seconds for this command. */
658
+ timeoutS?: number;
659
+ }
660
+ interface ShellOptions extends SessionExecOptions {
661
+ /** Session to run in; made on first use. Default `main`. */
662
+ session?: string;
663
+ }
664
+ interface StartPtyOptions extends CallOptions {
665
+ image?: string;
666
+ command?: string[];
667
+ cols?: number;
668
+ rows?: number;
669
+ env?: Record<string, string>;
670
+ }
671
+ interface CreatePreviewOptions extends CallOptions {
672
+ /** Which session's container serves the port. */
673
+ session?: string;
674
+ /** Or which container. */
675
+ container?: string;
676
+ /** How long the link lives, in seconds. */
677
+ expiresInS?: number;
678
+ }
679
+ interface SetLifecycleOptions extends CallOptions {
680
+ autoStopMin?: number;
681
+ autoDeleteMin?: number;
682
+ ttlMin?: number;
683
+ ephemeral?: boolean;
684
+ }
685
+ interface BuildTemplateOptions extends CallOptions {
686
+ /** Dockerfile name inside the context (default `Dockerfile`). */
687
+ dockerfile?: string;
688
+ buildArgs?: Record<string, string>;
689
+ /** Network the build sandbox gets (daemon default `any`). */
690
+ egress?: EgressPolicy;
691
+ /** Build again over an existing template of the same name. */
692
+ replace?: boolean;
693
+ /** Build output as it arrives. */
694
+ onOutput?: (chunk: Buffer, stream: string) => void;
695
+ }
696
+ interface RunOptions extends CallOptions {
697
+ env?: Record<string, string> | string[];
698
+ onStdout?: (chunk: Buffer) => void;
699
+ onStderr?: (chunk: Buffer) => void;
700
+ /** Progress lines the daemon emits (e.g. "pulling alpine"). */
701
+ onStatus?: (chunk: Buffer) => void;
702
+ }
703
+ interface ExecOptions extends CallOptions {
704
+ onStdout?: (chunk: Buffer) => void;
705
+ onStderr?: (chunk: Buffer) => void;
706
+ }
707
+ interface ForkOptions extends CallOptions {
708
+ /** Number of copies (default 1). */
709
+ n?: number;
710
+ /** Name prefix; copies are named `<prefix>1`, `<prefix>2`, ... (default `<sandbox>-fork`). */
711
+ prefix?: string;
712
+ /** Raise the copies' classification label above the parent's. */
713
+ label?: string;
714
+ }
715
+ interface ExploreOptions extends CallOptions {
716
+ /** Shell commands, one per branch (at least two). */
717
+ variants: string[];
718
+ /** Image the variants run in (default `alpine:latest`). */
719
+ image?: string;
720
+ /** Keep every branch instead of only the winner. */
721
+ keepAll?: boolean;
722
+ /** Keep this branch (by id) instead of the winner. */
723
+ keep?: string;
724
+ /** Per-branch time limit in ms (default 120000). */
725
+ timeoutMs?: number;
726
+ /** Branch name prefix (default `<sandbox>-explore-<n>`). */
727
+ prefix?: string;
728
+ /**
729
+ * Pull `image` into the parent sandbox before forking so every branch has
730
+ * it (a sandbox's engine does not pull on run). Default true.
731
+ */
732
+ pull?: boolean;
733
+ }
734
+ interface CheckpointOptions extends CallOptions {
735
+ /** Why it is being taken, e.g. "before the migration". */
736
+ label?: string;
737
+ }
738
+ interface CheckpointResult {
739
+ checkpoint: Checkpoint;
740
+ /** Older checkpoints dropped to stay under the cap of 10. */
741
+ evicted: string[];
742
+ snapshot: SnapshotSandboxResult;
743
+ }
744
+ interface RewindOptions extends CallOptions {
745
+ /** Checkpoint id or label (default: the most recent). */
746
+ to?: string;
747
+ }
748
+ interface RewindResult {
749
+ sandbox: Sandbox;
750
+ checkpoint: Checkpoint;
751
+ /** Checkpoints taken after the one returned to, now deleted. */
752
+ dropped: string[];
753
+ restore_ms: number;
754
+ }
755
+ interface RestoreOptions extends CallOptions {
756
+ /** Name for the restored sandbox. */
757
+ name?: string;
758
+ /** Raise the restored sandbox's classification label. */
759
+ label?: string;
760
+ /** Restore a sealed snapshot whose seal does not verify (recorded in the audit log). */
761
+ allowTampered?: boolean;
762
+ }
763
+ /**
764
+ * Typed client for the kosa8 native API over the daemon's unix socket.
765
+ *
766
+ * ```ts
767
+ * const kosa8 = new Kosa8Client();
768
+ * const { sandbox } = await kosa8.createSandbox({ name: 'demo', egress: 'deny' });
769
+ * ```
770
+ */
771
+ declare class Kosa8Client {
772
+ readonly transport: Transport;
773
+ readonly checkpoints: CheckpointBook;
774
+ constructor(options?: Kosa8ClientOptions);
775
+ /** GET /kosa8/v1/health: daemon status and version. */
776
+ health(opts?: CallOptions): Promise<Health>;
777
+ /** The daemon's version string. */
778
+ version(opts?: CallOptions): Promise<string>;
779
+ /** POST /kosa8/v1/pull: pull an image into the host engine (checked against the registry allow-list). */
780
+ pull(ref: string, opts?: CallOptions): Promise<{
781
+ ok: boolean;
782
+ image: string;
783
+ }>;
784
+ /** GET /kosa8/v1/sandboxes */
785
+ listSandboxes(opts?: CallOptions): Promise<Sandbox[]>;
786
+ /** Find one sandbox by id or name (from the list; there is no single-sandbox GET). */
787
+ getSandbox(idOrName: string, opts?: CallOptions): Promise<Sandbox | undefined>;
788
+ /** POST /kosa8/v1/sandboxes: boot a microVM sandbox. */
789
+ createSandbox(options?: CreateSandboxOptions): Promise<CreateSandboxResult>;
790
+ /** POST /kosa8/v1/sandboxes/{id}/up: boot a stopped sandbox from its own disk. */
791
+ startSandbox(id: string, opts?: CallOptions): Promise<StartSandboxResult>;
792
+ /** POST /kosa8/v1/sandboxes/{id}/down: stop without deleting (disk kept). */
793
+ stopSandbox(id: string, opts?: CallOptions): Promise<StopSandboxResult>;
794
+ /**
795
+ * DELETE /kosa8/v1/sandboxes/{id}. Like `kosa8 sandbox rm`, the sandbox's
796
+ * checkpoints and their snapshots are dropped too unless
797
+ * `keepCheckpoints` is set.
798
+ */
799
+ deleteSandbox(id: string, opts?: CallOptions & {
800
+ wipe?: boolean;
801
+ keepCheckpoints?: boolean;
802
+ }): Promise<DeleteSandboxResult & {
803
+ checkpoints_dropped: number;
804
+ }>;
805
+ /** POST /kosa8/v1/sandboxes/{id}/pull: pull an image into the sandbox's private engine (fetched on the host). */
806
+ pullIntoSandbox(id: string, ref: string, opts?: CallOptions): Promise<{
807
+ ok: boolean;
808
+ image: string;
809
+ }>;
810
+ /** GET /kosa8/v1/sandboxes/{id}/images */
811
+ sandboxImages(id: string, opts?: CallOptions): Promise<string[]>;
812
+ /** GET /kosa8/v1/sandboxes/{id}/containers */
813
+ sandboxContainers(id: string, opts?: CallOptions): Promise<Container[]>;
814
+ /** GET /kosa8/v1/sandboxes/{id}/egress: the policy the host enforces and what it decided. */
815
+ sandboxEgress(id: string, opts?: CallOptions): Promise<EgressStatus>;
816
+ /**
817
+ * POST /kosa8/v1/sandboxes/{id}/run: run a container to completion inside
818
+ * the sandbox's engine. The image must already be in the sandbox
819
+ * (`pullIntoSandbox`). Resolves with the exit code; a non-zero exit is not
820
+ * an error.
821
+ */
822
+ run(id: string, image: string, args?: string[], opts?: RunOptions): Promise<ExecResult>;
823
+ /** POST /kosa8/v1/sandboxes/{id}/start: start a detached container; resolves with its id. */
824
+ startContainer(id: string, image: string, args?: string[], opts?: CallOptions): Promise<string>;
825
+ /** POST /kosa8/v1/sandboxes/{id}/exec: run a command in a running container of the sandbox. */
826
+ exec(id: string, container: string, args: string[], opts?: ExecOptions): Promise<ExecResult>;
827
+ /** The raw frame stream of an exec, for callers that want to process output as it arrives. */
828
+ execFrames(id: string, container: string, args: string[], opts?: CallOptions): AsyncGenerator<Frame>;
829
+ /** POST /kosa8/v1/sandboxes/{id}/start-interactive: start a container with stdin held open. */
830
+ startInteractive(id: string, image: string, args?: string[], opts?: CallOptions & {
831
+ env?: Record<string, string> | string[];
832
+ tty?: boolean;
833
+ }): Promise<string>;
834
+ /** POST /kosa8/v1/sandboxes/{id}/containers/{cid}/stdin: stream bytes into an interactive container's stdin. */
835
+ writeStdin(id: string, container: string, data: Uint8Array | string | AsyncIterable<Uint8Array | string>, opts?: CallOptions): Promise<{
836
+ ok: boolean;
837
+ }>;
838
+ /** POST /kosa8/v1/sandboxes/{id}/containers/{cid}/attach: follow a container's output until it exits. */
839
+ attach(id: string, container: string, opts?: ExecOptions): Promise<ExecResult>;
840
+ /** POST /kosa8/v1/sandboxes/{id}/snapshot: capture memory, processes and disks. */
841
+ snapshot(id: string, opts?: CallOptions & {
842
+ id?: string;
843
+ encrypt?: boolean;
844
+ }): Promise<SnapshotSandboxResult>;
845
+ /** GET /kosa8/v1/snapshots */
846
+ listSnapshots(opts?: CallOptions): Promise<Snapshot[]>;
847
+ /** POST /kosa8/v1/snapshots/{id}/restore: boot a sandbox from a snapshot, processes resumed. */
848
+ restoreSnapshot(snapshotId: string, opts?: RestoreOptions): Promise<RestoreResult>;
849
+ /** DELETE /kosa8/v1/snapshots/{id} */
850
+ deleteSnapshot(snapshotId: string, opts?: CallOptions & {
851
+ wipe?: boolean;
852
+ force?: boolean;
853
+ }): Promise<DeleteSnapshotResult>;
854
+ /** POST /kosa8/v1/sandboxes/{id}/fork: N live copies of a running sandbox. */
855
+ fork(id: string, opts?: ForkOptions): Promise<ForkResult>;
856
+ /**
857
+ * Best-of-N, as `kosa8 explore`: fork the sandbox once per variant, run
858
+ * each variant (`sh -c VARIANT` in `image`) in its own branch
859
+ * concurrently, keep the fastest successful branch and delete the rest.
860
+ */
861
+ explore(id: string, opts: ExploreOptions): Promise<ExploreResult>;
862
+ private runBranch;
863
+ /**
864
+ * Save a restore point: a snapshot with id `<sandbox>-ckpt-<n>`, recorded on
865
+ * the sandbox's checkpoint stack (the same store `kosa8 checkpoint` uses).
866
+ * The oldest is evicted past 10.
867
+ */
868
+ checkpoint(sandbox: string, opts?: CheckpointOptions): Promise<CheckpointResult>;
869
+ /** A sandbox's restore points, oldest first. */
870
+ listCheckpoints(sandbox: string): Promise<Checkpoint[]>;
871
+ /**
872
+ * Undo: put the sandbox back to a checkpoint under the same name, processes
873
+ * resumed. Deletes the sandbox, then restores the snapshot with its name;
874
+ * checkpoints taken after the target are discarded. Current state is lost.
875
+ */
876
+ rewind(sandbox: string, opts?: RewindOptions): Promise<RewindResult>;
877
+ /**
878
+ * POST /kosa8/v1/sandboxes/{id}/code: run a Python, JavaScript or
879
+ * TypeScript snippet. It starts in `/workspace`. Charts a Python snippet
880
+ * draws with matplotlib come back in `artifacts` as PNG bytes.
881
+ */
882
+ runCode(id: string, code: string, opts?: RunCodeOptions): Promise<CodeResult>;
883
+ /** GET …/files: a folder in the workspace (default `/workspace`), or one entry. */
884
+ listFiles(id: string, path?: string, opts?: CallOptions): Promise<FileInfo[]>;
885
+ /** GET …/files/stat: one entry, not following a symlink. */
886
+ statFile(id: string, path: string, opts?: CallOptions): Promise<FileInfo>;
887
+ /** GET …/files/content: a file's bytes. A body cut short is a Kosa8StreamError. */
888
+ readFile(id: string, path: string, opts?: CallOptions): Promise<Buffer>;
889
+ /** A file's contents as text (UTF-8 by default). */
890
+ readText(id: string, path: string, opts?: CallOptions & {
891
+ encoding?: BufferEncoding;
892
+ }): Promise<string>;
893
+ /** PUT …/files/content: replace a file, making its folders. Answers the new entry. */
894
+ writeFile(id: string, path: string, data: Uint8Array | string | AsyncIterable<Uint8Array | string>, opts?: WriteFileOptions): Promise<FileInfo>;
895
+ /** DELETE …/files: a file, or with `recursive` a folder and everything in it. */
896
+ deleteFile(id: string, path: string, opts?: CallOptions & {
897
+ recursive?: boolean;
898
+ }): Promise<{
899
+ removed: string;
900
+ }>;
901
+ /** POST …/files/mkdir: a folder, with its parents. */
902
+ makeDir(id: string, path: string, opts?: CallOptions): Promise<FileInfo>;
903
+ /** POST …/files/move: rename or move a file or folder. Answers the entry at `to`. */
904
+ moveFile(id: string, from: string, to: string, opts?: CallOptions): Promise<FileInfo>;
905
+ /**
906
+ * POST …/git: one git operation in the workspace. A git failure resolves
907
+ * with `ok: false`; only a refusal (bad op, no sandbox, policy) throws.
908
+ */
909
+ git(id: string, op: GitOp | (string & {}), opts?: GitOptions): Promise<GitResult>;
910
+ /** Clone `url` into the workspace (into `path`, else a folder named after the repo). */
911
+ gitClone(id: string, url: string, opts?: GitOptions): Promise<GitResult>;
912
+ /** `git status` of the repository at `path`, parsed into `status`. */
913
+ gitStatus(id: string, path: string, opts?: GitOptions): Promise<GitResult>;
914
+ /** Stage everything (unless `addAll: false`) and commit. A failed add is returned as is. */
915
+ gitCommit(id: string, path: string, message: string, opts?: GitCommitOptions): Promise<GitResult>;
916
+ /** POST …/sessions: a shell that keeps `cd` and `export` between commands. */
917
+ createSession(id: string, name?: string, opts?: CreateSessionOptions): Promise<SessionInfo>;
918
+ /** GET …/sessions */
919
+ listSessions(id: string, opts?: CallOptions): Promise<SessionInfo[]>;
920
+ /** POST …/sessions/{name}/exec: run one command line in the session. */
921
+ sessionExec(id: string, session: string, command: string, opts?: SessionExecOptions): Promise<ShellResult>;
922
+ /** Run a command in a session (default `main`), making the session on first use. */
923
+ shell(id: string, command: string, opts?: ShellOptions): Promise<ShellResult>;
924
+ /** DELETE …/sessions/{name} */
925
+ deleteSession(id: string, session: string, opts?: CallOptions): Promise<{
926
+ deleted: string;
927
+ }>;
928
+ /**
929
+ * POST …/pty: a container with a terminal; resolves with its id. Connect
930
+ * to `/kosa8/v1/sandboxes/{id}/containers/{cid}/tty` with any WebSocket
931
+ * client: binary messages are the terminal, text messages JSON control.
932
+ */
933
+ startPty(id: string, opts?: StartPtyOptions): Promise<string>;
934
+ /** POST …/containers/{cid}/resize: set a terminal's size. */
935
+ resizePty(id: string, container: string, cols: number, rows: number, opts?: CallOptions): Promise<{
936
+ ok: boolean;
937
+ }>;
938
+ /** POST …/previews: a signed link, which expires, to a web server in the sandbox. */
939
+ createPreview(id: string, port: number, opts?: CreatePreviewOptions): Promise<Preview>;
940
+ /** POST /kosa8/v1/previews/rotate: end every preview link at once. */
941
+ revokePreviews(opts?: CallOptions): Promise<{
942
+ ok: boolean;
943
+ revoked: string;
944
+ }>;
945
+ /**
946
+ * POST …/lifecycle: change auto-stop, auto-delete, TTL or ephemeral.
947
+ * Options left out keep their value; 0 (or `false`) turns one off.
948
+ */
949
+ setLifecycle(id: string, opts?: SetLifecycleOptions): Promise<Sandbox>;
950
+ /** GET /kosa8/v1/templates */
951
+ listTemplates(opts?: CallOptions): Promise<Template[]>;
952
+ /** DELETE /kosa8/v1/templates/{name}. Sandboxes made from it keep their copy. */
953
+ deleteTemplate(name: string, opts?: CallOptions): Promise<{
954
+ deleted: string;
955
+ }>;
956
+ /**
957
+ * POST /kosa8/v1/templates: build `contextDir`'s Dockerfile in a throwaway
958
+ * sandbox and keep the image as a template, for `createSandbox({ template })`.
959
+ * The context is packed honouring `.dockerignore`. Resolves with the final
960
+ * frame (`{ done, ok, image }`); a failed build throws Kosa8StreamError.
961
+ */
962
+ buildTemplate(name: string, contextDir?: string, opts?: BuildTemplateOptions): Promise<Frame>;
963
+ /** A handle bound to one sandbox. */
964
+ sandbox(id: string): SandboxHandle;
965
+ private collect;
966
+ }
967
+ /** Convenience wrapper: the client's sandbox methods bound to one sandbox id. */
968
+ declare class SandboxHandle {
969
+ readonly client: Kosa8Client;
970
+ readonly id: string;
971
+ constructor(client: Kosa8Client, id: string);
972
+ info(opts?: CallOptions): Promise<Sandbox | undefined>;
973
+ start(opts?: CallOptions): Promise<StartSandboxResult>;
974
+ stop(opts?: CallOptions): Promise<StopSandboxResult>;
975
+ delete(opts?: CallOptions & {
976
+ wipe?: boolean;
977
+ keepCheckpoints?: boolean;
978
+ }): Promise<DeleteSandboxResult & {
979
+ checkpoints_dropped: number;
980
+ }>;
981
+ pull(ref: string, opts?: CallOptions): Promise<{
982
+ ok: boolean;
983
+ image: string;
984
+ }>;
985
+ run(image: string, args?: string[], opts?: RunOptions): Promise<ExecResult>;
986
+ startContainer(image: string, args?: string[], opts?: CallOptions): Promise<string>;
987
+ exec(container: string, args: string[], opts?: ExecOptions): Promise<ExecResult>;
988
+ containers(opts?: CallOptions): Promise<Container[]>;
989
+ images(opts?: CallOptions): Promise<string[]>;
990
+ egress(opts?: CallOptions): Promise<EgressStatus>;
991
+ snapshot(opts?: CallOptions & {
992
+ id?: string;
993
+ encrypt?: boolean;
994
+ }): Promise<SnapshotSandboxResult>;
995
+ fork(opts?: ForkOptions): Promise<ForkResult>;
996
+ explore(opts: ExploreOptions): Promise<ExploreResult>;
997
+ checkpoint(opts?: CheckpointOptions): Promise<CheckpointResult>;
998
+ checkpoints(): Promise<Checkpoint[]>;
999
+ rewind(opts?: RewindOptions): Promise<RewindResult>;
1000
+ runCode(code: string, opts?: RunCodeOptions): Promise<CodeResult>;
1001
+ listFiles(path?: string, opts?: CallOptions): Promise<FileInfo[]>;
1002
+ statFile(path: string, opts?: CallOptions): Promise<FileInfo>;
1003
+ readFile(path: string, opts?: CallOptions): Promise<Buffer<ArrayBufferLike>>;
1004
+ readText(path: string, opts?: CallOptions & {
1005
+ encoding?: BufferEncoding;
1006
+ }): Promise<string>;
1007
+ writeFile(path: string, data: Uint8Array | string | AsyncIterable<Uint8Array | string>, opts?: WriteFileOptions): Promise<FileInfo>;
1008
+ deleteFile(path: string, opts?: CallOptions & {
1009
+ recursive?: boolean;
1010
+ }): Promise<{
1011
+ removed: string;
1012
+ }>;
1013
+ makeDir(path: string, opts?: CallOptions): Promise<FileInfo>;
1014
+ moveFile(from: string, to: string, opts?: CallOptions): Promise<FileInfo>;
1015
+ git(op: GitOp | (string & {}), opts?: GitOptions): Promise<GitResult>;
1016
+ gitClone(url: string, opts?: GitOptions): Promise<GitResult>;
1017
+ gitStatus(path: string, opts?: GitOptions): Promise<GitResult>;
1018
+ gitCommit(path: string, message: string, opts?: GitCommitOptions): Promise<GitResult>;
1019
+ createSession(name?: string, opts?: CreateSessionOptions): Promise<SessionInfo>;
1020
+ sessions(opts?: CallOptions): Promise<SessionInfo[]>;
1021
+ sessionExec(session: string, command: string, opts?: SessionExecOptions): Promise<ShellResult>;
1022
+ shell(command: string, opts?: ShellOptions): Promise<ShellResult>;
1023
+ deleteSession(session: string, opts?: CallOptions): Promise<{
1024
+ deleted: string;
1025
+ }>;
1026
+ startPty(opts?: StartPtyOptions): Promise<string>;
1027
+ resizePty(container: string, cols: number, rows: number, opts?: CallOptions): Promise<{
1028
+ ok: boolean;
1029
+ }>;
1030
+ createPreview(port: number, opts?: CreatePreviewOptions): Promise<Preview>;
1031
+ setLifecycle(opts: SetLifecycleOptions): Promise<Sandbox>;
1032
+ }
1033
+
1034
+ /**
1035
+ * Pack `dir` as a tar archive for POST /kosa8/v1/templates. Throws when the
1036
+ * Dockerfile is missing, so a bad path fails before anything is sent.
1037
+ */
1038
+ declare function tarContext(dir: string, dockerfile?: string): Promise<Buffer>;
1039
+
1040
+ /**
1041
+ * Typed errors. Every error the daemon answers with carries its own words:
1042
+ * `daemonMessage` is the daemon's `error` field verbatim, and `remediation`
1043
+ * is its `remediation` field (what to do about it). A refusal because the
1044
+ * org policy wants signed approvals also carries the refusal itself, under
1045
+ * `approval`, exactly as the daemon sent it.
1046
+ */
1047
+ /** An approval rule from the org policy, as the daemon reports it. */
1048
+ interface ApprovalRule {
1049
+ [key: string]: unknown;
1050
+ }
1051
+ /** What the policy requires before an action may run. */
1052
+ interface ApprovalRequirement {
1053
+ policy: string;
1054
+ rules: ApprovalRule[];
1055
+ }
1056
+ /** The action a refusal is about. */
1057
+ interface ApprovalAction {
1058
+ kind: string;
1059
+ target?: string;
1060
+ command?: string[];
1061
+ sandbox?: string;
1062
+ [key: string]: unknown;
1063
+ }
1064
+ /**
1065
+ * The daemon's answer to a call the org policy wants signed approvals for
1066
+ * and that did not bring a usable one (pkg/approve Refusal).
1067
+ */
1068
+ interface ApprovalRefusal {
1069
+ route: string;
1070
+ action: ApprovalAction;
1071
+ description: string;
1072
+ /** read-only | contained | destructive | escalating */
1073
+ class: string;
1074
+ policy: string;
1075
+ policy_digest: string;
1076
+ requirement: ApprovalRequirement;
1077
+ /** The approval id the call presented, if any. */
1078
+ request_id?: string;
1079
+ /** What was wrong: nothing presented, not recorded, used, expired, ... */
1080
+ why: string;
1081
+ /** People the policy lets approve this action. */
1082
+ signers?: string[];
1083
+ /** The CLI command that opens a request for exactly this action. */
1084
+ request_command: string;
1085
+ }
1086
+ interface Kosa8ErrorOptions {
1087
+ status?: number;
1088
+ daemonMessage?: string;
1089
+ remediation?: string;
1090
+ method?: string;
1091
+ path?: string;
1092
+ body?: unknown;
1093
+ cause?: unknown;
1094
+ /** kosa8 Cloud's stable error code, such as payment_required. */
1095
+ code?: string;
1096
+ }
1097
+ /** Base class of every error this SDK throws. */
1098
+ declare class Kosa8Error extends Error {
1099
+ /** HTTP status the daemon answered with, when there was an answer. */
1100
+ readonly status?: number;
1101
+ /** The daemon's `error` text, verbatim. */
1102
+ readonly daemonMessage?: string;
1103
+ /** The daemon's `remediation` text: what to do about it. */
1104
+ readonly remediation?: string;
1105
+ readonly method?: string;
1106
+ readonly path?: string;
1107
+ /** The decoded response body, when there was one. */
1108
+ readonly body?: unknown;
1109
+ /** kosa8 Cloud's stable error code (payment_required, quota_exceeded, ...). */
1110
+ readonly code?: string;
1111
+ constructor(message: string, options?: Kosa8ErrorOptions);
1112
+ }
1113
+ /** The daemon could not be reached (no socket, connection refused, ...). */
1114
+ declare class Kosa8ConnectionError extends Kosa8Error {
1115
+ }
1116
+ /**
1117
+ * A call took longer than its timeout. A connection error too, so code that
1118
+ * catches Kosa8ConnectionError keeps catching it.
1119
+ */
1120
+ declare class Kosa8TimeoutError extends Kosa8ConnectionError {
1121
+ }
1122
+ /** The daemon answered with an HTTP error. */
1123
+ declare class Kosa8ApiError extends Kosa8Error {
1124
+ }
1125
+ /** 400: the request was malformed or a value was refused (an egress policy, say). */
1126
+ declare class Kosa8BadRequestError extends Kosa8ApiError {
1127
+ }
1128
+ /** 401: a bearer token (remote worker) or agent token was missing or refused. */
1129
+ declare class Kosa8AuthError extends Kosa8ApiError {
1130
+ }
1131
+ /** 403: refused by policy (org policy, registry allow-list, labels, ...). */
1132
+ declare class Kosa8PolicyError extends Kosa8ApiError {
1133
+ }
1134
+ /**
1135
+ * 403 with a signed-approval refusal: the org policy wants people other than
1136
+ * the caller to approve this exact action. Get the approval id from a human
1137
+ * and repeat the call with `{ approval: id }`.
1138
+ */
1139
+ declare class Kosa8ApprovalRequiredError extends Kosa8PolicyError {
1140
+ readonly approval: ApprovalRefusal;
1141
+ constructor(message: string, approval: ApprovalRefusal, options?: Kosa8ErrorOptions);
1142
+ }
1143
+ /** 404: no such sandbox, snapshot, container, ... */
1144
+ declare class Kosa8NotFoundError extends Kosa8ApiError {
1145
+ }
1146
+ /** 409: a conflict, e.g. the sandbox exists but is not running, or a snapshot id is taken. */
1147
+ declare class Kosa8ConflictError extends Kosa8ApiError {
1148
+ }
1149
+ /** 501: the platform cannot do this (sandboxes need macOS on Apple silicon or Linux with KVM). */
1150
+ declare class Kosa8UnsupportedError extends Kosa8ApiError {
1151
+ }
1152
+ /**
1153
+ * A streamed operation (run, exec, attach) ended with an error frame rather
1154
+ * than an exit code. Output produced before the error is kept.
1155
+ */
1156
+ declare class Kosa8StreamError extends Kosa8Error {
1157
+ readonly stdout: string;
1158
+ readonly stderr: string;
1159
+ constructor(message: string, out: {
1160
+ stdout: string;
1161
+ stderr: string;
1162
+ }, options?: Kosa8ErrorOptions);
1163
+ }
1164
+ /** kosa8 Cloud refused new work until a payment method is on file (402). */
1165
+ declare class Kosa8PaymentRequiredError extends Kosa8ApiError {
1166
+ }
1167
+ /** Too many requests or a quota reached (429). */
1168
+ declare class Kosa8RateLimitError extends Kosa8ApiError {
1169
+ }
1170
+ /** A client-side checkpoint operation failed (no checkpoint, bad name, ...). */
1171
+ declare class Kosa8CheckpointError extends Kosa8Error {
1172
+ }
1173
+ /**
1174
+ * Build the typed error for an HTTP error answer. The message is the daemon's
1175
+ * own, with its remediation in parentheses, the way the kosa8 CLI and MCP
1176
+ * server print it.
1177
+ */
1178
+ declare function errorFromResponse(status: number, body: unknown, ctx?: {
1179
+ method?: string;
1180
+ path?: string;
1181
+ code?: string;
1182
+ }): Kosa8ApiError;
1183
+
1184
+ declare const DEFAULT_CLOUD_URL = "https://api.kosa8.cloud";
1185
+ declare const CLOUD_KEY_PREFIX = "k8c_live_";
1186
+ interface Kosa8CloudOptions {
1187
+ /** API key. Defaults to the KOSA8_API_KEY environment variable. */
1188
+ apiKey?: string;
1189
+ /** Control-plane address. Defaults to KOSA8_CLOUD_URL, then https://api.kosa8.cloud. */
1190
+ baseUrl?: string;
1191
+ /** Where to read KOSA8_API_KEY and KOSA8_CLOUD_URL from. Defaults to process.env. */
1192
+ env?: Record<string, string | undefined>;
1193
+ /** A fetch to use instead of the global one (tests, proxies). */
1194
+ fetch?: typeof fetch;
1195
+ /** Per-request timeout. Default 120 s. */
1196
+ timeoutMs?: number;
1197
+ }
1198
+ interface CloudSandboxInfo {
1199
+ id: string;
1200
+ state: 'creating' | 'running' | 'sleeping' | 'stopped' | 'deleted' | 'error' | string;
1201
+ template: string;
1202
+ cpus: number;
1203
+ mem_mb: number;
1204
+ source: 'pool' | 'restore' | 'cold' | null;
1205
+ region: string | null;
1206
+ own_host: boolean;
1207
+ created_at: number;
1208
+ started_at: number | null;
1209
+ stopped_at: number | null;
1210
+ deleted_at: number | null;
1211
+ last_error: string | null;
1212
+ running_s: number;
1213
+ asleep_s: number;
1214
+ sleep_bytes: number;
1215
+ cost_usd: number;
1216
+ }
1217
+ interface CloudCreateOptions {
1218
+ /** Template key, such as base, python or node. Defaults to the org's setting. */
1219
+ template?: string;
1220
+ /** Region id, such as eu-hel1. Defaults to the org's setting (any region). */
1221
+ region?: string;
1222
+ /** Idle seconds before the sandbox sleeps; 0 never. Defaults to the org's setting. */
1223
+ sleepAfterS?: number;
1224
+ }
1225
+ interface CloudExecOptions {
1226
+ /** Image to run the command in. Defaults to the template's own image. */
1227
+ image?: string;
1228
+ /** Environment variables for the command. */
1229
+ env?: Record<string, string>;
1230
+ }
1231
+ interface CloudExecResult {
1232
+ exitCode: number | null;
1233
+ stdout: string;
1234
+ stderr: string;
1235
+ /** Set when the sandbox was asleep and woke for this command. */
1236
+ wokeMs?: number;
1237
+ }
1238
+ interface CloudInvocation {
1239
+ id: string;
1240
+ function: string;
1241
+ function_id: string;
1242
+ version: number;
1243
+ trigger: 'api' | 'web' | 'map' | 'cron' | string;
1244
+ }
1245
+ interface CloudInvokeResult<T = unknown> {
1246
+ invocation: CloudInvocation | null;
1247
+ /** False when the handler raised; `error` then says what. */
1248
+ ok: boolean;
1249
+ result?: T;
1250
+ error?: {
1251
+ type: string;
1252
+ message: string;
1253
+ };
1254
+ logs?: string;
1255
+ source?: 'pool' | 'restore' | null;
1256
+ timings_ms?: {
1257
+ start: number | null;
1258
+ run: number | null;
1259
+ host_total: number | null;
1260
+ total: number;
1261
+ };
1262
+ }
1263
+ interface CloudFunctionSpec {
1264
+ runtime: 'python3.12' | 'node22' | string;
1265
+ code: string;
1266
+ env?: Record<string, string>;
1267
+ timeout_s?: number;
1268
+ web?: 'off' | 'public' | 'key' | string;
1269
+ schedule?: string | null;
1270
+ [k: string]: unknown;
1271
+ }
1272
+ type Json = Record<string, unknown>;
1273
+ /** A client for the kosa8 Cloud control plane. */
1274
+ declare class Kosa8Cloud {
1275
+ readonly baseUrl: string;
1276
+ readonly sandboxes: CloudSandboxes;
1277
+ readonly functions: CloudFunctions;
1278
+ private readonly apiKey;
1279
+ private readonly fetchImpl;
1280
+ private readonly timeoutMs;
1281
+ constructor(options?: Kosa8CloudOptions);
1282
+ /** The org, the key in use and, for a member's key, the member. */
1283
+ me(): Promise<Json>;
1284
+ /** This month's usage, bill estimate and whether work is paused for payment. */
1285
+ usage(): Promise<Json>;
1286
+ /** @internal */
1287
+ request<T = Json>(method: string, path: string, body?: unknown): Promise<T>;
1288
+ }
1289
+ declare class CloudSandboxes {
1290
+ private readonly cloud;
1291
+ constructor(cloud: Kosa8Cloud);
1292
+ /** Start a sandbox; resolves once it is running. */
1293
+ create(opts?: CloudCreateOptions): Promise<CloudSandbox>;
1294
+ /** The org's sandboxes; with all, deleted ones too. */
1295
+ list(opts?: {
1296
+ all?: boolean;
1297
+ }): Promise<CloudSandbox[]>;
1298
+ get(id: string): Promise<CloudSandbox>;
1299
+ }
1300
+ /** One cloud sandbox. `info` is its state as of the last call. */
1301
+ declare class CloudSandbox {
1302
+ private readonly cloud;
1303
+ info: CloudSandboxInfo;
1304
+ constructor(cloud: Kosa8Cloud, info: CloudSandboxInfo);
1305
+ get id(): string;
1306
+ private path;
1307
+ /**
1308
+ * Run a command and wait for it. A string runs through `sh -c`. A
1309
+ * sleeping sandbox wakes for it.
1310
+ */
1311
+ exec(cmd: string | string[], opts?: CloudExecOptions): Promise<CloudExecResult>;
1312
+ /** Snapshot it and free its VM; it then costs only snapshot storage. */
1313
+ sleep(): Promise<this>;
1314
+ /** Restore a sleeping sandbox, files and all. */
1315
+ wake(): Promise<this>;
1316
+ refresh(): Promise<this>;
1317
+ delete(): Promise<void>;
1318
+ }
1319
+ declare class CloudFunctions {
1320
+ private readonly cloud;
1321
+ constructor(cloud: Kosa8Cloud);
1322
+ /** Deploy (create or replace) a function; every deploy bumps its version. */
1323
+ deploy(name: string, spec: CloudFunctionSpec): Promise<Json>;
1324
+ list(): Promise<Json[]>;
1325
+ get(name: string): Promise<Json>;
1326
+ delete(name: string): Promise<void>;
1327
+ /** Call it once. A handler that raises resolves with ok: false, not a throw. */
1328
+ invoke<T = unknown>(name: string, event?: unknown): Promise<CloudInvokeResult<T>>;
1329
+ /** One call per event, results in input order. */
1330
+ map<T = unknown>(name: string, events: unknown[], opts?: {
1331
+ concurrency?: number;
1332
+ }): Promise<{
1333
+ function: string;
1334
+ version: number;
1335
+ count: number;
1336
+ succeeded: number;
1337
+ failed: number;
1338
+ total_ms: number;
1339
+ results: CloudInvokeResult<T>[];
1340
+ }>;
1341
+ }
1342
+
1343
+ export { ACTOR_HEADER, AGENT_TOKEN_HEADER, APPROVAL_HEADER, type Actor, type ApprovalAction, type ApprovalRefusal, type ApprovalRequirement, type ApprovalRule, type BrokerHostRule, type BrokerInfo, type BrokerRoute, type BrokerSpec, type BuildTemplateOptions, CLOUD_KEY_PREFIX, type CallOptions, type CaptureSpec, type Checkpoint, CheckpointBook, type CheckpointOptions, type CheckpointResult, type CheckpointStore, type CloudCreateOptions, type CloudExecOptions, type CloudExecResult, type CloudFunctionSpec, CloudFunctions, type CloudInvocation, type CloudInvokeResult, CloudSandbox, type CloudSandboxInfo, CloudSandboxes, type CodeArtifact, type CodeResult, type Container, type CreatePreviewOptions, type CreateSandboxOptions, type CreateSandboxResult, type CreateSessionOptions, DEFAULT_CLOUD_URL, type DeleteSandboxResult, type DeleteSnapshotResult, type EgressPolicy, type EgressPolicyString, type EgressStatus, type ExecOptions, type ExecResult, type ExploreBranch, type ExploreOptions, type ExploreResult, FileCheckpointStore, type FileInfo, type ForkOptions, type ForkResult, type Frame, type GitBranch, type GitCommit, type GitCommitOptions, type GitFileStatus, type GitOp, type GitOptions, type GitResult, type GitStatus, type Health, Kosa8ApiError, Kosa8ApprovalRequiredError, Kosa8AuthError, Kosa8BadRequestError, Kosa8CheckpointError, Kosa8Client, type Kosa8ClientOptions, Kosa8Cloud, type Kosa8CloudOptions, Kosa8ConflictError, Kosa8ConnectionError, Kosa8Error, Kosa8NotFoundError, Kosa8PaymentRequiredError, Kosa8PolicyError, Kosa8RateLimitError, Kosa8StreamError, Kosa8TimeoutError, Kosa8UnsupportedError, type Lifecycle, MAX_CHECKPOINTS_PER_SANDBOX, MemoryCheckpointStore, type Mount, type Preview, type RequestOptions, type RestoreOptions, type RestoreResult, type RewindOptions, type RewindResult, type RunCodeOptions, type RunOptions, type Sandbox, SandboxHandle, type SessionExecOptions, type SessionInfo, type SetLifecycleOptions, type ShellOptions, type ShellResult, type Snapshot, type SnapshotSandboxResult, type StartPtyOptions, type StartSandboxResult, type StopSandboxResult, type Template, Transport, type TransportOptions, type WriteFileOptions, defaultSocketPath, defaultWorkerFile, errorFromResponse, resolveEndpoint, tarContext, validateSandboxName };