@nimbus-sh/sdk 0.1.4 → 0.2.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/README.md CHANGED
@@ -72,6 +72,15 @@ export default createNimbusHandler({
72
72
  });
73
73
  ```
74
74
 
75
+ The bundled session UI includes an Agent surface in the editor workspace.
76
+ Configure it with Worker vars
77
+ `NIMBUS_CF_OAUTH_CLIENT_ID`, `NIMBUS_CF_OAUTH_SCOPES`,
78
+ `NIMBUS_AGENT_MODEL`, `NIMBUS_AGENT_GATEWAY_ID`, and the secrets
79
+ `NIMBUS_AGENT_COOKIE_SECRET` or `NIMBUS_CLOUDFLARE_API_TOKEN` when you want
80
+ Cloudflare OAuth or owner-token Workers AI access. User OAuth uses
81
+ Authorization Code + PKCE and encrypted browser cookies; Nimbus does not store
82
+ user OAuth tokens in Durable Object storage.
83
+
75
84
  ## Programmatic sandbox quickstart
76
85
 
77
86
  The same sandbox handle API works in two modes:
@@ -152,6 +161,32 @@ Worker verifies the JWT, enforces `sid` pins and `sandbox:use` scope, applies
152
161
  the configured runtime policy, and delegates to the same `NimbusSession` RPC
153
162
  methods used by `Nimbus.fromEnv()`.
154
163
 
164
+ Sandbox destruction is a separate lifecycle operation. Tokens that call
165
+ `box.destroy()` must include `session:destroy` or `session:admin` in addition
166
+ to the normal sandbox scope.
167
+
168
+ ## Flue connector
169
+
170
+ Use `@nimbus-sh/sdk/flue` when an agent runtime expects Flue's sandbox
171
+ provider contract:
172
+
173
+ ```ts
174
+ import { Nimbus } from '@nimbus-sh/sdk/sandbox';
175
+ import { nimbusFlue } from '@nimbus-sh/sdk/flue';
176
+
177
+ const box = Nimbus.fromEnv(env, nimbusConfig).sandbox('job-123');
178
+ await box.ready();
179
+
180
+ const factory = nimbusFlue(box);
181
+ const sessionEnv = await factory.createSessionEnv({
182
+ id: 'job-123',
183
+ cwd: '/home/user',
184
+ });
185
+
186
+ await sessionEnv.writeFile('/home/user/main.py', 'print(2 + 2)\n');
187
+ const result = await sessionEnv.exec('python /home/user/main.py');
188
+ ```
189
+
155
190
  ## Sandbox handle API
156
191
 
157
192
  ```ts
@@ -168,13 +203,20 @@ const box = nimbus.sandbox('session-or-job-id', {
168
203
 
169
204
  await box.ready();
170
205
  await box.exec('node -e "console.log(2 + 2)"');
171
- await box.startProcess('node --watch /home/user/app/server.js');
206
+ const proc = await box.startProcess('node --watch /home/user/app/server.js');
207
+ // returns immediately with proc.pid; poll box.processes.logs(proc.pid) for
208
+ // output and the exit record, or box.processes.kill(proc.pid) to stop it
172
209
  await box.runCode('print(2 + 2)', { language: 'python', install: 'ifMissing' });
173
210
 
174
211
  await box.files.write('/home/user/app/a.txt', 'hello');
175
212
  await box.files.read('/home/user/app/a.txt');
176
213
  await box.files.list('/home/user/app');
177
- await box.files.delete('/home/user/app/a.txt');
214
+ await box.files.stat('/home/user/app/a.txt');
215
+ await box.files.lstat('/home/user/app/link');
216
+ await box.files.rename('/home/user/app/a.txt', '/home/user/app/b.txt');
217
+ await box.files.chmod('/home/user/app/b.txt', 0o755);
218
+ await box.files.readRange('/home/user/app/b.txt', 0, 64);
219
+ await box.files.delete('/home/user/app/b.txt');
178
220
 
179
221
  await box.runtimes.available();
180
222
  await box.runtimes.installed();
@@ -208,7 +250,7 @@ object with `tools.exec.execute`, `runCode`, `readFile`, `writeFile`,
208
250
  `provider.capabilities` is intentionally honest: Nimbus claims shell,
209
251
  JavaScript/TypeScript, npm, git, owned filesystem, outbound fetch, inbound
210
252
  HTTP-like port routing, process spawn/long-running processes, Python/Ruby
211
- when allowed, and clang as WASI-native. It does not claim Docker, apt, GPU,
253
+ when allowed, and clang-backed WASI/WebAssembly execution. It does not claim Docker, apt, GPU,
212
254
  custom Linux images, native Linux ELF execution, or raw TCP listeners.
213
255
 
214
256
  ## Quickstart — mint a session token
package/dist/flue.d.ts ADDED
@@ -0,0 +1,93 @@
1
+ /**
2
+ * @nimbus-sh/sdk/flue - Flue sandbox connector for Nimbus sandboxes.
3
+ *
4
+ * Flue owns the agent harness. Nimbus owns the sandbox. This adapter maps a
5
+ * `NimbusSandbox` handle to Flue's `SandboxFactory`/`SandboxApi` contract
6
+ * without making `@flue/runtime` a hard dependency of the core SDK.
7
+ */
8
+ import type { NimbusSandbox } from './sandbox.js';
9
+ export interface NimbusFlueFileStat {
10
+ isFile: boolean;
11
+ isDirectory: boolean;
12
+ isSymbolicLink: boolean;
13
+ size: number;
14
+ mtime: Date;
15
+ }
16
+ export interface NimbusFlueSessionEnv {
17
+ exec(command: string, options?: NimbusFlueExecOptions): Promise<NimbusFlueShellResult>;
18
+ readFile(path: string): Promise<string>;
19
+ readFileBuffer(path: string): Promise<Uint8Array>;
20
+ writeFile(path: string, content: string | Uint8Array): Promise<void>;
21
+ stat(path: string): Promise<NimbusFlueFileStat>;
22
+ readdir(path: string): Promise<string[]>;
23
+ exists(path: string): Promise<boolean>;
24
+ mkdir(path: string, options?: {
25
+ recursive?: boolean;
26
+ }): Promise<void>;
27
+ rm(path: string, options?: {
28
+ recursive?: boolean;
29
+ force?: boolean;
30
+ }): Promise<void>;
31
+ cwd: string;
32
+ resolvePath(path: string): string;
33
+ }
34
+ export interface NimbusFlueShellResult {
35
+ stdout: string;
36
+ stderr: string;
37
+ exitCode: number;
38
+ }
39
+ export interface NimbusFlueExecOptions {
40
+ cwd?: string;
41
+ env?: Record<string, string>;
42
+ timeout?: number;
43
+ signal?: AbortSignal;
44
+ }
45
+ export interface NimbusFlueSandboxApi {
46
+ readFile(path: string): Promise<string>;
47
+ readFileBuffer(path: string): Promise<Uint8Array>;
48
+ writeFile(path: string, content: string | Uint8Array): Promise<void>;
49
+ stat(path: string): Promise<NimbusFlueFileStat>;
50
+ readdir(path: string): Promise<string[]>;
51
+ exists(path: string): Promise<boolean>;
52
+ mkdir(path: string, options?: {
53
+ recursive?: boolean;
54
+ }): Promise<void>;
55
+ rm(path: string, options?: {
56
+ recursive?: boolean;
57
+ force?: boolean;
58
+ }): Promise<void>;
59
+ exec(command: string, options?: NimbusFlueExecOptions): Promise<NimbusFlueShellResult>;
60
+ }
61
+ export interface NimbusFlueRuntime<SessionEnv = NimbusFlueSessionEnv> {
62
+ createSandboxSessionEnv(api: NimbusFlueSandboxApi, cwd: string): SessionEnv;
63
+ }
64
+ export interface NimbusFlueFactory<SessionEnv = NimbusFlueSessionEnv> {
65
+ createSessionEnv(options: {
66
+ id: string;
67
+ cwd?: string;
68
+ }): Promise<SessionEnv>;
69
+ }
70
+ export interface NimbusFlueOptions<SessionEnv = NimbusFlueSessionEnv> {
71
+ cwd?: string;
72
+ runtime?: NimbusFlueRuntime<SessionEnv>;
73
+ }
74
+ export declare function nimbusFlue<SessionEnv = NimbusFlueSessionEnv>(sandbox: NimbusSandbox, options?: NimbusFlueOptions<SessionEnv>): NimbusFlueFactory<SessionEnv>;
75
+ export declare class NimbusFlueApi implements NimbusFlueSandboxApi {
76
+ private readonly sandbox;
77
+ constructor(sandbox: NimbusSandbox);
78
+ readFile(path: string): Promise<string>;
79
+ readFileBuffer(path: string): Promise<Uint8Array>;
80
+ writeFile(path: string, content: string | Uint8Array): Promise<void>;
81
+ stat(path: string): Promise<NimbusFlueFileStat>;
82
+ readdir(path: string): Promise<string[]>;
83
+ exists(path: string): Promise<boolean>;
84
+ mkdir(path: string, _options?: {
85
+ recursive?: boolean;
86
+ }): Promise<void>;
87
+ rm(path: string, options?: {
88
+ recursive?: boolean;
89
+ force?: boolean;
90
+ }): Promise<void>;
91
+ exec(command: string, options?: NimbusFlueExecOptions): Promise<NimbusFlueShellResult>;
92
+ }
93
+ //# sourceMappingURL=flue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flue.d.ts","sourceRoot":"","sources":["../src/flue.ts"],"names":[],"mappings":"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"}
package/dist/flue.js ADDED
@@ -0,0 +1,112 @@
1
+ /**
2
+ * @nimbus-sh/sdk/flue - Flue sandbox connector for Nimbus sandboxes.
3
+ *
4
+ * Flue owns the agent harness. Nimbus owns the sandbox. This adapter maps a
5
+ * `NimbusSandbox` handle to Flue's `SandboxFactory`/`SandboxApi` contract
6
+ * without making `@flue/runtime` a hard dependency of the core SDK.
7
+ */
8
+ export function nimbusFlue(sandbox, options = {}) {
9
+ return {
10
+ async createSessionEnv({ cwd }) {
11
+ const runtime = options.runtime ?? await loadFlueRuntime();
12
+ return runtime.createSandboxSessionEnv(new NimbusFlueApi(sandbox), cwd ?? options.cwd ?? '/home/user');
13
+ },
14
+ };
15
+ }
16
+ export class NimbusFlueApi {
17
+ sandbox;
18
+ constructor(sandbox) {
19
+ this.sandbox = sandbox;
20
+ }
21
+ async readFile(path) {
22
+ const content = await this.sandbox.files.read(path);
23
+ if (content == null)
24
+ throw enoent(path);
25
+ return content;
26
+ }
27
+ async readFileBuffer(path) {
28
+ const content = await this.sandbox.files.readBytes(path);
29
+ if (content == null)
30
+ throw enoent(path);
31
+ return content;
32
+ }
33
+ async writeFile(path, content) {
34
+ await this.sandbox.files.write(path, content);
35
+ }
36
+ async stat(path) {
37
+ const stat = await this.sandbox.files.stat(path);
38
+ if (!stat)
39
+ throw enoent(path);
40
+ return toFlueStat(stat);
41
+ }
42
+ async readdir(path) {
43
+ const entries = await this.sandbox.files.list(path);
44
+ return entries.map((entry) => entry.name);
45
+ }
46
+ async exists(path) {
47
+ return this.sandbox.files.exists(path);
48
+ }
49
+ async mkdir(path, _options = {}) {
50
+ await this.sandbox.files.mkdir(path);
51
+ }
52
+ async rm(path, options = {}) {
53
+ if (options.force && !(await this.sandbox.files.exists(path)))
54
+ return;
55
+ await this.sandbox.files.delete(path, { recursive: options.recursive });
56
+ }
57
+ async exec(command, options = {}) {
58
+ const result = await this.sandbox.exec(command, {
59
+ cwd: options.cwd,
60
+ env: options.env,
61
+ timeoutMs: secondsToMilliseconds(options.timeout),
62
+ });
63
+ if (options.signal?.aborted)
64
+ throw abortError(options.signal);
65
+ return toShellResult(result);
66
+ }
67
+ }
68
+ async function loadFlueRuntime() {
69
+ try {
70
+ const specifier = '@flue/runtime';
71
+ const runtime = await import(specifier);
72
+ if (typeof runtime.createSandboxSessionEnv === 'function') {
73
+ return runtime;
74
+ }
75
+ }
76
+ catch {
77
+ // Error below gives callers the exact integration action.
78
+ }
79
+ throw new Error('nimbusFlue requires @flue/runtime. Install Flue or pass { runtime: { createSandboxSessionEnv } }.');
80
+ }
81
+ function toFlueStat(stat) {
82
+ const type = String(stat.type);
83
+ return {
84
+ isFile: type === 'file',
85
+ isDirectory: type === 'directory',
86
+ isSymbolicLink: false,
87
+ size: Number(stat.size) || 0,
88
+ mtime: new Date(Number(stat.mtime) || Date.now()),
89
+ };
90
+ }
91
+ function toShellResult(result) {
92
+ return {
93
+ stdout: result.stdout,
94
+ stderr: result.stderr,
95
+ exitCode: result.exitCode,
96
+ };
97
+ }
98
+ function secondsToMilliseconds(timeout) {
99
+ if (typeof timeout !== 'number' || !Number.isFinite(timeout) || timeout <= 0)
100
+ return undefined;
101
+ return Math.max(1, Math.round(timeout * 1000));
102
+ }
103
+ function enoent(path) {
104
+ const error = new Error(`ENOENT: no such file or directory, '${path}'`);
105
+ error.code = 'ENOENT';
106
+ return error;
107
+ }
108
+ function abortError(signal) {
109
+ return signal.reason instanceof Error
110
+ ? signal.reason
111
+ : new DOMException('The operation was aborted', 'AbortError');
112
+ }
package/dist/index.d.ts CHANGED
@@ -26,4 +26,5 @@ export * from './token.js';
26
26
  export * from './errors.js';
27
27
  export * from './session.js';
28
28
  export * from './sandbox.js';
29
+ export * from './flue.js';
29
30
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC"}
package/dist/index.js CHANGED
@@ -26,3 +26,4 @@ export * from './token.js';
26
26
  export * from './errors.js';
27
27
  export * from './session.js';
28
28
  export * from './sandbox.js';
29
+ export * from './flue.js';
package/dist/sandbox.d.ts CHANGED
@@ -22,6 +22,14 @@ export interface NimbusSandboxProfile {
22
22
  }
23
23
  export interface NimbusConfig {
24
24
  endpoint?: string;
25
+ /**
26
+ * The deployment's `NIMBUS_PREVIEW_HOST_SUFFIX`, enabling the
27
+ * `<port>--<sid>.<suffix>` preview origin. `Nimbus.fromEnv` reads it off
28
+ * the bindings, so in-Worker callers never restate it; remote clients
29
+ * (`Nimbus.connect`) have no bindings and must supply it to get host-form
30
+ * preview URLs.
31
+ */
32
+ previewHostSuffix?: string;
25
33
  sandboxes?: Record<string, NimbusSandboxProfile>;
26
34
  }
27
35
  export interface NimbusFromEnvOptions {
@@ -64,10 +72,31 @@ export interface NimbusExecResult {
64
72
  duration: number;
65
73
  timestamp: number;
66
74
  }
67
- export interface NimbusStartResult extends NimbusExecResult {
68
- pid: number | null;
69
- process: NimbusProcess | null;
75
+ export interface NimbusTerminalSize {
76
+ columns: number;
77
+ rows: number;
78
+ }
79
+ export interface NimbusDestroyOptions {
80
+ reason?: string;
81
+ }
82
+ export interface NimbusDestroyResult {
83
+ ok: true;
84
+ killed: number;
85
+ destroyedAt: number;
86
+ reason: string | null;
87
+ }
88
+ /**
89
+ * A started background process. It is still running when `startProcess`
90
+ * returns, so there is no exit code or captured output here — poll
91
+ * `processes.logs(pid)` (which carries the exit record once it lands),
92
+ * `processes.list()`, or `processes.attach(pid)`.
93
+ */
94
+ export interface NimbusStartResult {
95
+ command: string;
96
+ pid: number;
97
+ process: NimbusProcess;
70
98
  ports: NimbusPort[];
99
+ startedAt: number;
71
100
  }
72
101
  export interface NimbusProcess {
73
102
  pid: number;
@@ -79,22 +108,63 @@ export interface NimbusProcess {
79
108
  startTime: number;
80
109
  endTime: number | null;
81
110
  longRunning: boolean;
111
+ attachedTty: boolean;
112
+ }
113
+ export interface NimbusProcessLogChunk {
114
+ seq: number;
115
+ ts: number;
116
+ stream: 'stdout' | 'stderr';
117
+ data: string;
118
+ binary?: boolean;
119
+ }
120
+ export interface NimbusProcessExitInfo {
121
+ code: number;
122
+ at: number;
123
+ reason?: string;
124
+ }
125
+ export interface NimbusProcessLogsOptions {
126
+ cursor?: number;
127
+ lines?: number;
128
+ bytes?: number;
129
+ }
130
+ export interface NimbusProcessLogsResult {
131
+ pid: number;
132
+ chunks: NimbusProcessLogChunk[];
133
+ text: string;
134
+ cursor: number;
135
+ truncated: boolean;
136
+ exit: NimbusProcessExitInfo | null;
137
+ }
138
+ export interface NimbusProcessAttachOptions {
139
+ pollIntervalMs?: number;
140
+ lines?: number;
141
+ bytes?: number;
142
+ signal?: AbortSignal;
82
143
  }
83
144
  export interface NimbusPort {
84
145
  port: number;
85
146
  pid: number;
86
147
  registeredAt: number;
87
148
  }
149
+ export interface NimbusFileStat {
150
+ type: 'file' | 'directory' | string;
151
+ size: number;
152
+ ctime?: number;
153
+ mtime: number;
154
+ mode: number;
155
+ }
88
156
  export interface NimbusRuntimeSummary {
89
157
  name: string;
90
158
  version: string;
91
159
  root: string;
160
+ abi: string;
92
161
  bins: string[];
93
162
  sizeBytes: number;
94
163
  license: string;
95
164
  }
96
165
  export interface NimbusAvailableRuntime {
97
166
  name: string;
167
+ abi: string;
98
168
  defaultVersion: string;
99
169
  versions: Array<{
100
170
  version: string;
@@ -102,7 +172,82 @@ export interface NimbusAvailableRuntime {
102
172
  license: string;
103
173
  }>;
104
174
  }
105
- type NimbusSessionNamespace = DurableObjectNamespace<any>;
175
+ interface NimbusSessionStub {
176
+ _rpcReady(options?: {
177
+ preinstall?: string[];
178
+ }): Promise<{
179
+ ok: true;
180
+ preinstalled: string[];
181
+ }>;
182
+ _rpcExec(command: string, options?: Record<string, unknown>): Promise<NimbusExecResult>;
183
+ _rpcStartProcess(command: string, options?: Record<string, unknown>): Promise<NimbusStartResult>;
184
+ _rpcRunCode(code: string, options?: Record<string, unknown>): Promise<NimbusExecResult>;
185
+ _rpcReadFile(path: string): Promise<string | null>;
186
+ _rpcReadFileBytes(path: string): Promise<Uint8Array | null>;
187
+ _rpcWriteFile(path: string, content: string | Uint8Array): Promise<void>;
188
+ _rpcStat(path: string): Promise<NimbusFileStat | null>;
189
+ _rpcLstat(path: string): Promise<NimbusFileStat | null>;
190
+ _rpcReaddir(path: string): Promise<{
191
+ name: string;
192
+ type: string;
193
+ }[]>;
194
+ _rpcRename(from: string, to: string): Promise<void>;
195
+ _rpcChmod(path: string, mode: number): Promise<void>;
196
+ _rpcFsReadRange(path: string, offset: number, length: number): Promise<Uint8Array | null>;
197
+ _rpcExists(path: string): Promise<boolean>;
198
+ _rpcMkdir(path: string): Promise<void>;
199
+ _rpcDeleteFile(path: string, options?: {
200
+ recursive?: boolean;
201
+ }): Promise<void>;
202
+ _rpcInstallRuntime(spec: string, options?: {
203
+ force?: boolean;
204
+ }): Promise<unknown>;
205
+ _rpcEnsureRuntimes(specs: string[], options?: {
206
+ force?: boolean;
207
+ }): Promise<unknown>;
208
+ _rpcListRuntimes(): Promise<{
209
+ installed: NimbusRuntimeSummary[];
210
+ available: NimbusAvailableRuntime[];
211
+ }>;
212
+ _rpcListProcesses(): Promise<NimbusProcess[]>;
213
+ _rpcKillProcess(pid: number): Promise<{
214
+ ok: boolean;
215
+ pid: number;
216
+ }>;
217
+ _rpcWriteProcessInput(pid: number, data: string): Promise<{
218
+ ok: boolean;
219
+ pid: number;
220
+ }>;
221
+ _rpcEndProcessInput(pid: number): Promise<{
222
+ ok: boolean;
223
+ pid: number;
224
+ }>;
225
+ _rpcResizeProcess(pid: number, size: NimbusTerminalSize): Promise<{
226
+ ok: boolean;
227
+ pid: number;
228
+ }>;
229
+ _rpcSignalProcess(pid: number, signal: string): Promise<{
230
+ ok: boolean;
231
+ pid: number;
232
+ }>;
233
+ _rpcProcessLogs(pid: number, options?: NimbusProcessLogsOptions): Promise<NimbusProcessLogsResult>;
234
+ _rpcListPorts(): Promise<NimbusPort[]>;
235
+ _rpcExposePort(port: number): Promise<{
236
+ port: number;
237
+ listening: boolean;
238
+ pid: number | null;
239
+ registeredAt: number | null;
240
+ }>;
241
+ _rpcUnexposePort(port: number): Promise<{
242
+ port: number;
243
+ ok: boolean;
244
+ }>;
245
+ _rpcDestroy(options?: NimbusDestroyOptions): Promise<NimbusDestroyResult>;
246
+ }
247
+ interface NimbusSessionNamespace {
248
+ idFromName(name: string): DurableObjectId;
249
+ get(id: DurableObjectId): NimbusSessionStub;
250
+ }
106
251
  type NimbusTarget = {
107
252
  kind: 'binding';
108
253
  namespace: NimbusSessionNamespace;
@@ -149,15 +294,27 @@ export declare class NimbusSandbox {
149
294
  private remoteRpc;
150
295
  ready(): Promise<void>;
151
296
  exec(command: string, options?: NimbusExecOptions): Promise<NimbusExecResult>;
297
+ /**
298
+ * Start a command in the background. Returns as soon as the process has a
299
+ * pid — it does not wait for the command to finish.
300
+ */
152
301
  startProcess(command: string, options?: NimbusExecOptions): Promise<NimbusStartResult>;
153
302
  runCode(code: string, options?: NimbusExecOptions & {
154
303
  language?: 'javascript' | 'typescript' | 'python' | 'ruby' | 'shell';
155
304
  install?: 'never' | 'ifMissing';
156
305
  }): Promise<NimbusExecResult>;
306
+ destroy(options?: NimbusDestroyOptions): Promise<NimbusDestroyResult>;
157
307
  files: {
158
308
  read: (path: string) => Promise<string | null>;
159
309
  readBytes: (path: string) => Promise<Uint8Array | null>;
160
310
  write: (path: string, content: string | Uint8Array) => Promise<void>;
311
+ stat: (path: string) => Promise<NimbusFileStat | null>;
312
+ /** stat without following a symlink leaf. */
313
+ lstat: (path: string) => Promise<NimbusFileStat | null>;
314
+ rename: (from: string, to: string) => Promise<void>;
315
+ chmod: (path: string, mode: number) => Promise<void>;
316
+ /** Read `length` bytes at `offset` without materializing the whole file. */
317
+ readRange: (path: string, offset: number, length: number) => Promise<Uint8Array | null>;
161
318
  list: (path?: string) => Promise<{
162
319
  name: string;
163
320
  type: string;
@@ -188,10 +345,24 @@ export declare class NimbusSandbox {
188
345
  ok: boolean;
189
346
  pid: number;
190
347
  }>;
191
- logs: (pid: number, options?: {
192
- lines?: number;
193
- bytes?: number;
194
- }) => Promise<unknown>;
348
+ write: (pid: number, data: string) => Promise<{
349
+ ok: boolean;
350
+ pid: number;
351
+ }>;
352
+ endInput: (pid: number) => Promise<{
353
+ ok: boolean;
354
+ pid: number;
355
+ }>;
356
+ resize: (pid: number, size: NimbusTerminalSize) => Promise<{
357
+ ok: boolean;
358
+ pid: number;
359
+ }>;
360
+ signal: (pid: number, signal: string) => Promise<{
361
+ ok: boolean;
362
+ pid: number;
363
+ }>;
364
+ logs: (pid: number, options?: NimbusProcessLogsOptions) => Promise<NimbusProcessLogsResult>;
365
+ attach: (pid: number, options?: NimbusProcessAttachOptions) => NimbusProcessAttachment;
195
366
  };
196
367
  ports: {
197
368
  list: () => Promise<NimbusPort[]>;
@@ -230,7 +401,7 @@ export declare class NimbusSandbox {
230
401
  execute: (input: unknown) => Promise<string | null>;
231
402
  };
232
403
  writeFile: {
233
- execute: (input: any) => Promise<void>;
404
+ execute: (input: unknown) => Promise<void>;
234
405
  };
235
406
  listFiles: {
236
407
  execute: (input?: unknown) => Promise<{
@@ -245,7 +416,7 @@ export declare class NimbusSandbox {
245
416
  }[]>;
246
417
  };
247
418
  deleteFile: {
248
- execute: (input: any) => Promise<void>;
419
+ execute: (input: unknown) => Promise<void>;
249
420
  };
250
421
  exists: {
251
422
  execute: (input: unknown) => Promise<boolean>;
@@ -261,12 +432,48 @@ export declare class NimbusSandbox {
261
432
  pid: number;
262
433
  }>;
263
434
  };
435
+ writeProcessInput: {
436
+ execute: (input: {
437
+ pid: number;
438
+ data: string;
439
+ }) => Promise<{
440
+ ok: boolean;
441
+ pid: number;
442
+ }>;
443
+ };
444
+ endProcessInput: {
445
+ execute: (input: number | {
446
+ pid: number;
447
+ }) => Promise<{
448
+ ok: boolean;
449
+ pid: number;
450
+ }>;
451
+ };
452
+ resizeProcess: {
453
+ execute: (input: {
454
+ pid: number;
455
+ columns: number;
456
+ rows: number;
457
+ }) => Promise<{
458
+ ok: boolean;
459
+ pid: number;
460
+ }>;
461
+ };
462
+ signalProcess: {
463
+ execute: (input: {
464
+ pid: number;
465
+ signal: string;
466
+ }) => Promise<{
467
+ ok: boolean;
468
+ pid: number;
469
+ }>;
470
+ };
264
471
  logs: {
265
472
  execute: (input: number | {
266
473
  pid: number;
267
474
  lines?: number;
268
475
  bytes?: number;
269
- }) => Promise<unknown>;
476
+ }) => Promise<NimbusProcessLogsResult>;
270
477
  };
271
478
  exposePort: {
272
479
  execute: (input: number | {
@@ -304,7 +511,47 @@ export declare class NimbusSandbox {
304
511
  capabilities(): string[];
305
512
  private execOptions;
306
513
  private assertRuntimeAllowed;
514
+ /**
515
+ * Browser-facing URL for an exposed port, or undefined when the deployment
516
+ * is not addressable (no `endpoint`, no configured preview base).
517
+ *
518
+ * The URL carries NO credential. On a deployment with auth enforced it is
519
+ * the destination, not the ticket: the session mints a single-use attach
520
+ * token for it at `GET /s/<id>/api/preview-url?port=<n>`, which is what the
521
+ * session shell opens and what an embedder should hand to a browser.
522
+ */
307
523
  private portUrl;
524
+ private rpc;
525
+ }
526
+ export declare class NimbusProcessAttachment implements AsyncIterable<NimbusProcessLogChunk> {
527
+ private readonly sandbox;
528
+ readonly pid: number;
529
+ private readonly options;
530
+ private cursor;
531
+ constructor(sandbox: NimbusSandbox, pid: number, options?: NimbusProcessAttachOptions);
532
+ write(data: string): Promise<{
533
+ ok: boolean;
534
+ pid: number;
535
+ }>;
536
+ endInput(): Promise<{
537
+ ok: boolean;
538
+ pid: number;
539
+ }>;
540
+ resize(size: NimbusTerminalSize): Promise<{
541
+ ok: boolean;
542
+ pid: number;
543
+ }>;
544
+ signal(signal: string): Promise<{
545
+ ok: boolean;
546
+ pid: number;
547
+ }>;
548
+ kill(): Promise<{
549
+ ok: boolean;
550
+ pid: number;
551
+ }>;
552
+ logs(options?: NimbusProcessLogsOptions): Promise<NimbusProcessLogsResult>;
553
+ stream(options?: NimbusProcessAttachOptions): AsyncIterable<NimbusProcessLogChunk>;
554
+ [Symbol.asyncIterator](): AsyncIterator<NimbusProcessLogChunk>;
308
555
  }
309
556
  export {};
310
557
  //# sourceMappingURL=sandbox.d.ts.map