@shardflux/sdk 0.15.0 → 0.16.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +42 -22
  2. package/README.md +99 -1
  3. package/dist/account.d.ts +2 -0
  4. package/dist/account.js +6 -0
  5. package/dist/cell.d.ts +2 -0
  6. package/dist/cell.js +2 -0
  7. package/dist/client.d.ts +25 -1
  8. package/dist/client.js +44 -3
  9. package/dist/computer.d.ts +11 -1
  10. package/dist/computer.js +89 -6
  11. package/dist/errors.d.ts +5 -1
  12. package/dist/errors.js +9 -0
  13. package/dist/executions.d.ts +2 -6
  14. package/dist/executions.js +9 -0
  15. package/dist/exit-code.d.ts +7 -0
  16. package/dist/exit-code.js +12 -0
  17. package/dist/generated/app-api.d.ts +565 -13
  18. package/dist/generated/cell-api.d.ts +2 -0
  19. package/dist/http.d.ts +7 -1
  20. package/dist/http.js +34 -13
  21. package/dist/index.d.ts +8 -5
  22. package/dist/index.js +4 -2
  23. package/dist/ports.d.ts +7 -0
  24. package/dist/ports.js +1 -1
  25. package/dist/progress.d.ts +2 -2
  26. package/dist/progress.js +1 -1
  27. package/dist/testing/index.d.ts +62 -0
  28. package/dist/testing/index.js +585 -0
  29. package/dist/testing/seed.d.ts +433 -0
  30. package/dist/testing/seed.js +449 -0
  31. package/dist/tools.d.ts +5 -0
  32. package/dist/tools.js +4 -2
  33. package/dist/tunnel-assets/linux-amd64.gz +0 -0
  34. package/dist/tunnel-assets/linux-arm64.gz +0 -0
  35. package/dist/tunnel-assets.d.ts +10 -0
  36. package/dist/tunnel-assets.js +11 -0
  37. package/dist/tunnel-packet.d.ts +3 -0
  38. package/dist/tunnel-packet.js +43 -0
  39. package/dist/tunnel-pty.d.ts +86 -0
  40. package/dist/tunnel-pty.js +243 -0
  41. package/dist/tunnels.d.ts +47 -0
  42. package/dist/tunnels.js +454 -0
  43. package/dist/workspace-ref.d.ts +4 -0
  44. package/dist/workspace-ref.js +24 -0
  45. package/dist/workspace.d.ts +18 -1
  46. package/dist/workspace.js +76 -3
  47. package/package.json +7 -2
@@ -0,0 +1,449 @@
1
+ // Captured response shapes; regenerate with node packages/sdk/scripts/generate-testing-fixtures.mjs.
2
+ export const seed = {
3
+ "_captured": "Production session workspaces, 2026-10-04T22:06:24.279Z; credentials omitted, IDs and cell hostname replaced. Canonical capture: packages/sdk/test/fixtures/testing-api-capture.json. Supplemental captures carry their original provenance.",
4
+ "defaultWorkspace": {
5
+ "id": "00000000-0000-7000-8000-00000000001e",
6
+ "organization_id": "00000000-0000-7000-8000-000000000018",
7
+ "project_id": "00000000-0000-7000-8000-000000000019",
8
+ "workspace_key": "qmfx/testing/default-1791151583295",
9
+ "labels": {},
10
+ "template_version_id": "00000000-0000-7000-8000-00000000001a",
11
+ "template": {
12
+ "version_id": "00000000-0000-7000-8000-00000000001a",
13
+ "template_id": "00000000-0000-7000-8000-00000000001b",
14
+ "slug": "python-node-browser",
15
+ "version": 15,
16
+ "immutable_version": null
17
+ },
18
+ "desired_state": "running",
19
+ "observed_state": "running",
20
+ "cell_id": "c1",
21
+ "cell_endpoint": "https://cell.fake.invalid",
22
+ "ownership_epoch": 1,
23
+ "caps": {
24
+ "cpu_millis": null,
25
+ "memory_mib": null,
26
+ "disk_gib": null,
27
+ "allocation_mode": "elastic",
28
+ "memory_mib_held": 1024
29
+ },
30
+ "memory": {
31
+ "allocation_mode": "elastic",
32
+ "promised_mib": 8192,
33
+ "held_mib": 1024,
34
+ "plugged_mib": 0
35
+ },
36
+ "ceilings": {
37
+ "cpu_millis": 4000,
38
+ "memory_mib": 8192,
39
+ "disk_gib": 20,
40
+ "sources": {
41
+ "cpu_millis": "plan",
42
+ "memory_mib": "plan",
43
+ "disk_gib": "plan"
44
+ },
45
+ "resolved_at": "2026-10-04T22:06:23.533Z"
46
+ },
47
+ "grants": {
48
+ "disk_gib": 20,
49
+ "cpu_millis": 4000,
50
+ "memory_mib": 1024,
51
+ "memory_layout": 2,
52
+ "memory_mib_max": 8192,
53
+ "allocation_mode": "elastic",
54
+ "memory_mib_base": 1024,
55
+ "memory_mib_held": 1024,
56
+ "memory_mib_ceiling": 32768
57
+ },
58
+ "active_operation": null,
59
+ "pending_reason": null,
60
+ "forked_from_workspace_id": null,
61
+ "disk_layout": "layered",
62
+ "lifetime": "session",
63
+ "purpose": "standard",
64
+ "idle_timeout_seconds": 600,
65
+ "idle": null,
66
+ "origin": null,
67
+ "ended_reason": null,
68
+ "dev_template_id": null,
69
+ "startup": null,
70
+ "mode": "processful",
71
+ "tree_revision": 0,
72
+ "computer_use": {
73
+ "enabled": false,
74
+ "workspace": null,
75
+ "template": false,
76
+ "available": true
77
+ },
78
+ "created_at": "2026-10-04T22:06:23.533Z",
79
+ "updated_at": "2026-10-04T22:06:23.706Z",
80
+ "deleted_at": null
81
+ },
82
+ "workspace": {
83
+ "id": "00000000-0000-7000-8000-000000000001",
84
+ "organization_id": "00000000-0000-7000-8000-000000000002",
85
+ "project_id": "00000000-0000-7000-8000-000000000003",
86
+ "workspace_key": "qmfx/testing/seed",
87
+ "labels": {},
88
+ "template_version_id": "00000000-0000-7000-8000-000000000004",
89
+ "template": {
90
+ "version_id": "00000000-0000-7000-8000-000000000004",
91
+ "template_id": "00000000-0000-7000-8000-000000000005",
92
+ "slug": "python-node-browser",
93
+ "version": 15,
94
+ "immutable_version": null
95
+ },
96
+ "desired_state": "running",
97
+ "observed_state": "running",
98
+ "cell_id": "c1",
99
+ "cell_endpoint": "https://cell.fake.invalid",
100
+ "ownership_epoch": 1,
101
+ "caps": {
102
+ "cpu_millis": null,
103
+ "memory_mib": 2048,
104
+ "disk_gib": null,
105
+ "allocation_mode": "fixed"
106
+ },
107
+ "memory": {
108
+ "allocation_mode": "fixed",
109
+ "promised_mib": 2048,
110
+ "held_mib": 2048,
111
+ "plugged_mib": null
112
+ },
113
+ "ceilings": {
114
+ "cpu_millis": 4000,
115
+ "memory_mib": 2048,
116
+ "disk_gib": 20,
117
+ "sources": {
118
+ "cpu_millis": "plan",
119
+ "memory_mib": "user",
120
+ "disk_gib": "plan"
121
+ },
122
+ "resolved_at": "2026-10-04T21:43:52.608Z"
123
+ },
124
+ "grants": {
125
+ "disk_gib": 20,
126
+ "cpu_millis": 4000,
127
+ "memory_mib": 2048,
128
+ "memory_layout": 2,
129
+ "allocation_mode": "fixed",
130
+ "memory_mib_base": 1024,
131
+ "memory_mib_ceiling": 32768
132
+ },
133
+ "active_operation": null,
134
+ "pending_reason": null,
135
+ "forked_from_workspace_id": null,
136
+ "disk_layout": "layered",
137
+ "lifetime": "session",
138
+ "purpose": "standard",
139
+ "idle_timeout_seconds": 600,
140
+ "idle": null,
141
+ "origin": null,
142
+ "ended_reason": null,
143
+ "dev_template_id": null,
144
+ "startup": null,
145
+ "mode": "processful",
146
+ "tree_revision": 0,
147
+ "computer_use": {
148
+ "enabled": false,
149
+ "workspace": null,
150
+ "template": false,
151
+ "available": true
152
+ },
153
+ "created_at": "2026-10-04T21:43:52.608Z",
154
+ "updated_at": "2026-10-04T21:43:52.731Z",
155
+ "deleted_at": null
156
+ },
157
+ "idle": {
158
+ "auto_suspend": {
159
+ "backoff_until": null,
160
+ "disabled_reason": null,
161
+ "enabled": true,
162
+ "failures": 0,
163
+ "last_error": null,
164
+ "last_operation_id": null
165
+ },
166
+ "idle_since": "2026-10-04T21:43:52.731942Z",
167
+ "keepalive_until": null,
168
+ "last_attach_at": null,
169
+ "last_tool_at": null,
170
+ "observed_state": "running",
171
+ "policy": {
172
+ "idle_minutes": null,
173
+ "mode": "adaptive",
174
+ "source": "default"
175
+ },
176
+ "running_since": "2026-10-04T21:43:52.731942Z",
177
+ "suspend_at": null,
178
+ "suspend_request": null
179
+ },
180
+ "busyIdle": {
181
+ "auto_suspend": {
182
+ "backoff_until": null,
183
+ "disabled_reason": null,
184
+ "enabled": true,
185
+ "failures": 0,
186
+ "last_error": null,
187
+ "last_operation_id": null
188
+ },
189
+ "idle_since": "2026-10-04T21:45:01.862826Z",
190
+ "keepalive_until": null,
191
+ "last_attach_at": null,
192
+ "last_tool_at": "2026-10-04T21:44:21.839643Z",
193
+ "observed_state": "running",
194
+ "policy": {
195
+ "idle_minutes": null,
196
+ "mode": "adaptive",
197
+ "source": "default"
198
+ },
199
+ "running_since": "2026-10-04T21:44:21.620863Z",
200
+ "suspend_at": null,
201
+ "suspend_request": null
202
+ },
203
+ "resize": {
204
+ "workspace_id": "00000000-0000-7000-8000-000000000001",
205
+ "operation_id": "00000000-0000-7000-8000-000000000009",
206
+ "state": "running",
207
+ "caps": {
208
+ "cpu_millis": null,
209
+ "memory_mib": 3072,
210
+ "disk_gib": null,
211
+ "allocation_mode": "fixed"
212
+ },
213
+ "memory": {
214
+ "applies_at": "now",
215
+ "allocation_mode": "fixed",
216
+ "requested_mib": 3072,
217
+ "target_mib": 3072,
218
+ "previous_mib": 2048,
219
+ "applied_mib": 3072,
220
+ "held_mib": null,
221
+ "converged": true,
222
+ "limit_reason": null,
223
+ "reason": null
224
+ }
225
+ },
226
+ "missing": {
227
+ "error": {
228
+ "code": "not_found",
229
+ "message": "open /home/user/qmfx-missing: no such file or directory",
230
+ "request_id": "00000000-0000-7000-8000-000000000008",
231
+ "retryable": false,
232
+ "details": {
233
+ "reason": "path_not_found"
234
+ }
235
+ }
236
+ },
237
+ "sessionLifetime": {
238
+ "error": {
239
+ "code": "conflict",
240
+ "message": "A session workspace cannot be suspended; close it, or fork it to keep its state.",
241
+ "request_id": "req-d294f3f70dde403a8423a3f2",
242
+ "retryable": false,
243
+ "details": {
244
+ "reason": "session_lifetime"
245
+ }
246
+ }
247
+ },
248
+ "gone": {
249
+ "error": {
250
+ "code": "conflict",
251
+ "message": "The workspace was deleted.",
252
+ "request_id": "req-f98733e54db546848e558390",
253
+ "retryable": false,
254
+ "details": {
255
+ "reason": "workspace_deleted"
256
+ }
257
+ }
258
+ },
259
+ "computerUnavailable": {
260
+ "error": {
261
+ "code": "conflict",
262
+ "message": "This workspace’s template version cannot run a desktop; open a workspace of a version whose guest agent has desktop.v1.",
263
+ "request_id": "req-ea53380457d24c63ac8313f8",
264
+ "retryable": false,
265
+ "details": {
266
+ "reason": "computer_use_unavailable"
267
+ }
268
+ }
269
+ },
270
+ "templateViews": {
271
+ "python-node-browser": {
272
+ "version_id": "00000000-0000-7000-8000-00000000001a",
273
+ "template_id": "00000000-0000-7000-8000-00000000001b",
274
+ "slug": "python-node-browser",
275
+ "version": 15,
276
+ "immutable_version": null
277
+ },
278
+ "ubuntu-24.04": {
279
+ "version_id": "00000000-0000-7000-8000-00000000000e",
280
+ "template_id": "00000000-0000-7000-8000-00000000000f",
281
+ "slug": "ubuntu-24.04",
282
+ "version": 5,
283
+ "immutable_version": null
284
+ }
285
+ },
286
+ "_supplemental": {
287
+ "token": "Captured 2026-09-26 from the Shardflux API (local build, same code as the service); hostnames replaced.",
288
+ "computerStopped": "Captured 2026-10-04 from the Shardflux cell gateway (local build, same code as the service) by services/cell/internal/gateway/computer_test.go.",
289
+ "me": "Captured 2026-10-04 from the Shardflux API (local build, same code as the service) by apps/api/test/clients-workspace-by-key.test.ts."
290
+ },
291
+ "token": {
292
+ "token": "fake-tool-token",
293
+ "token_type": "Bearer",
294
+ "expires_at": "9999-12-31T00:00:00.000Z",
295
+ "issued_at": "2026-09-26T19:36:04.000Z",
296
+ "kid": "local-dev.z4kHk7UK",
297
+ "audience": "cell-1.example",
298
+ "workspace_id": "01a0df37-b3a1-7303-aba8-8953543f16f2",
299
+ "agent_session_id": "01a0df37-b41e-7f39-a9f6-d38b2963083d",
300
+ "ownership_epoch": 1,
301
+ "tools": [
302
+ "exec",
303
+ "files"
304
+ ],
305
+ "cell_endpoint": "https://cell.example.test"
306
+ },
307
+ "computerStopped": {
308
+ "running": false,
309
+ "streams": {
310
+ "interactive": false,
311
+ "view": false
312
+ }
313
+ },
314
+ "me": {
315
+ "type": "api_key",
316
+ "user": null,
317
+ "memberships": [],
318
+ "api_key": {
319
+ "id": "01a10572-208c-7593-9cf6-6c8053d7db7a",
320
+ "key_id": "tbxqkfu5dn7wpycd",
321
+ "organization_id": "01a10572-2083-7c10-bdc7-fab17b3fe4c0",
322
+ "project_id": "01a10572-2088-7d5c-acf5-6a1d9fe016b7",
323
+ "tool_permissions": [
324
+ "exec",
325
+ "files",
326
+ "processes",
327
+ "computer"
328
+ ]
329
+ }
330
+ },
331
+ "fileInfo": {
332
+ "gid": 1000,
333
+ "mode": "0644",
334
+ "modified_at": "2026-10-04T21:56:05.210721792Z",
335
+ "name": "a.txt",
336
+ "path": "/home/user/qmfx/a.txt",
337
+ "revision": "fe9c2dadb34bee2ae03fc8fe25e26c64ce2f572a53a127db5d6e73899b64fc11",
338
+ "size": 12,
339
+ "type": "file",
340
+ "uid": 1000
341
+ },
342
+ "fileWrite": {
343
+ "bytes_written": 12,
344
+ "durable": true,
345
+ "file": {
346
+ "gid": 1000,
347
+ "mode": "0644",
348
+ "modified_at": "2026-10-04T21:56:05.210721792Z",
349
+ "name": "a.txt",
350
+ "path": "/home/user/qmfx/a.txt",
351
+ "revision": "fe9c2dadb34bee2ae03fc8fe25e26c64ce2f572a53a127db5d6e73899b64fc11",
352
+ "size": 12,
353
+ "type": "file",
354
+ "uid": 1000
355
+ },
356
+ "path": "/home/user/qmfx/a.txt",
357
+ "revision": "fe9c2dadb34bee2ae03fc8fe25e26c64ce2f572a53a127db5d6e73899b64fc11",
358
+ "sha256": "fe9c2dadb34bee2ae03fc8fe25e26c64ce2f572a53a127db5d6e73899b64fc11"
359
+ },
360
+ "fileList": {
361
+ "entries": [
362
+ {
363
+ "gid": 1000,
364
+ "mode": "0644",
365
+ "modified_at": "2026-10-04T21:56:05.210721792Z",
366
+ "name": "a.txt",
367
+ "path": "/home/user/qmfx/a.txt",
368
+ "size": 12,
369
+ "type": "file",
370
+ "uid": 1000
371
+ }
372
+ ],
373
+ "truncated": false
374
+ },
375
+ "filePatch": {
376
+ "bytes_written": 13,
377
+ "durable": true,
378
+ "file": {
379
+ "gid": 1000,
380
+ "mode": "0644",
381
+ "modified_at": "2026-10-04T21:56:05.3747218Z",
382
+ "name": "a.txt",
383
+ "path": "/home/user/qmfx/a.txt",
384
+ "revision": "0d7a3fcb331d2c4ef08fb4f733f5f1435b31cd77d73c4cc0fb64a7364ad50e51",
385
+ "size": 13,
386
+ "type": "file",
387
+ "uid": 1000
388
+ },
389
+ "path": "/home/user/qmfx/a.txt",
390
+ "previous_revision": "fe9c2dadb34bee2ae03fc8fe25e26c64ce2f572a53a127db5d6e73899b64fc11",
391
+ "replacements": 1,
392
+ "revision": "0d7a3fcb331d2c4ef08fb4f733f5f1435b31cd77d73c4cc0fb64a7364ad50e51"
393
+ },
394
+ "fileSearch": {
395
+ "files_scanned": 1,
396
+ "matches": [
397
+ {
398
+ "column": 1,
399
+ "line": 1,
400
+ "path": "/home/user/qmfx/a.txt",
401
+ "text": "a = 10"
402
+ }
403
+ ],
404
+ "truncated": false
405
+ },
406
+ "computerStatus": {
407
+ "display": ":1",
408
+ "height": 800,
409
+ "running": true,
410
+ "session": "/etc/shardflux/desktop/session",
411
+ "started_at": "2026-10-04T21:56:05.601Z",
412
+ "streams": {
413
+ "interactive": false,
414
+ "view": false
415
+ },
416
+ "width": 1280
417
+ },
418
+ "computerActions": {
419
+ "results": [],
420
+ "screenshot": {
421
+ "format": "png",
422
+ "width": 1280,
423
+ "height": 800,
424
+ "data": "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"
425
+ },
426
+ "cursor": [
427
+ 640,
428
+ 400
429
+ ],
430
+ "display": {
431
+ "width": 1280,
432
+ "height": 800
433
+ }
434
+ },
435
+ "execSession": {
436
+ "canceled": false,
437
+ "created": false,
438
+ "created_at": "2026-10-04T21:43:53.15828654Z",
439
+ "ended_at": "2026-10-04T21:43:53.192347995Z",
440
+ "exit_code": 7,
441
+ "pid": 699,
442
+ "session_id": "run-943621b9fdd74017a300920c",
443
+ "started_at": "2026-10-04T21:43:53.182710241Z",
444
+ "state": "exited",
445
+ "stderr_size": 0,
446
+ "stdout_size": 7,
447
+ "timed_out": false
448
+ }
449
+ };
package/dist/tools.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { BeforeComputerAction } from './computer.js';
1
2
  import type { CellClient, CellClientOptions } from './cell.js';
2
3
  import type { WorkspaceMode } from './errors.js';
3
4
  import type { ToolName } from './tokens.js';
@@ -62,6 +63,10 @@ export interface ToolTarget {
62
63
  hint(opts?: HintOptions): Promise<HintResult>;
63
64
  }
64
65
  export interface WorkspaceToolsOptions {
66
+ /** Per-action desktop policy; refusal stops the remaining actions. */
67
+ computer?: {
68
+ beforeAction?: BeforeComputerAction;
69
+ };
65
70
  /**
66
71
  * Tool permissions to expose (default: the tools of the workspace's last token, else all). A file-first workspace
67
72
  * (`workspace.mode`) gets only the `exec` and `files` tools: `exec` runs each command as an execution
package/dist/tools.js CHANGED
@@ -10,6 +10,7 @@
10
10
  * application; toOpenAITools/toAnthropicTools export the definitions in those
11
11
  * providers' formats and executeToolCall dispatches a model's tool call.
12
12
  */
13
+ import { runComputerActions } from "./computer.js";
13
14
  import { CAPTURE_BARRIER, burstFailure } from "./cell.js";
14
15
  import { ExecStartError, ShardfluxApiError } from "./errors.js";
15
16
  import { newExecutionId } from "./executions.js";
@@ -724,7 +725,7 @@ export function workspaceTools(workspace, opts = {}) {
724
725
  parameters: obj({ ...COMPUTER_ACTION, ...COMPUTER_LOOK }, ['action']),
725
726
  run: async (a, o) => {
726
727
  const look = a.action === 'screenshot' || a.action === 'zoom' || a.action === 'cursor_position';
727
- const r = await (await cell()).computer.act({ actions: [computerAction(a)], screenshot: !look && a.screenshot !== false, ...computerImage(a) }, o.signal);
728
+ const r = await runComputerActions(async (actions, options) => (await cell()).computer.act({ actions, screenshot: options.screenshot, ...computerImage(a) }, o.signal), [computerAction(a)], { screenshot: !look && a.screenshot !== false }, opts.computer?.beforeAction);
728
729
  const res = r.results[0];
729
730
  const img = res?.image ?? r.screenshot;
730
731
  return {
@@ -747,7 +748,8 @@ export function workspaceTools(workspace, opts = {}) {
747
748
  }, ['actions']),
748
749
  run: async (a, o) => {
749
750
  const actions = a.actions.map(computerAction);
750
- const r = await (await cell()).computer.act({ actions, screenshot: a.screenshot !== false, ...computerImage(a) }, o.signal);
751
+ const lastLooks = ['screenshot', 'zoom'].includes(actions.at(-1)?.action ?? '');
752
+ const r = await runComputerActions(async (batch, options) => (await cell()).computer.act({ actions: batch, screenshot: options.screenshot, ...computerImage(a) }, o.signal), actions, { screenshot: !lastLooks && a.screenshot !== false }, opts.computer?.beforeAction);
751
753
  return {
752
754
  ok: r.results.every((x) => x.ok),
753
755
  results: r.results.map((x) => ({
@@ -0,0 +1,10 @@
1
+ export declare const TUNNEL_ASSETS: {
2
+ readonly x86_64: {
3
+ readonly file: "linux-amd64.gz";
4
+ readonly sha256: "e7b8a88b27c36b2605ee9e8182dae7700f816d9058d92bd87d6ae66781303650";
5
+ };
6
+ readonly aarch64: {
7
+ readonly file: "linux-arm64.gz";
8
+ readonly sha256: "740ce49febb1ab0e614a520d8daff68fa7b4ac32adf18dc93d5ff16b2dc57735";
9
+ };
10
+ };
@@ -0,0 +1,11 @@
1
+ // Generated by scripts/build-tunnel-helper.py.
2
+ export const TUNNEL_ASSETS = {
3
+ "x86_64": {
4
+ "file": "linux-amd64.gz",
5
+ "sha256": "e7b8a88b27c36b2605ee9e8182dae7700f816d9058d92bd87d6ae66781303650"
6
+ },
7
+ "aarch64": {
8
+ "file": "linux-arm64.gz",
9
+ "sha256": "740ce49febb1ab0e614a520d8daff68fa7b4ac32adf18dc93d5ff16b2dc57735"
10
+ }
11
+ };
@@ -0,0 +1,3 @@
1
+ export declare function packetCrc(bytes: Uint8Array): number;
2
+ /** Delimit both ends so a replay discards any truncated preceding packet before decoding. */
3
+ export declare function tunnelPacket(offset: number, bytes: Uint8Array): Buffer;
@@ -0,0 +1,43 @@
1
+ const table = Uint32Array.from({ length: 256 }, (_, value) => {
2
+ let crc = value;
3
+ for (let n = 0; n < 8; n++)
4
+ crc = (crc >>> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
5
+ return crc >>> 0;
6
+ });
7
+ export function packetCrc(bytes) {
8
+ let crc = 0xffffffff;
9
+ for (const b of bytes)
10
+ crc = (crc >>> 8) ^ table[(crc ^ b) & 255];
11
+ return (crc ^ 0xffffffff) >>> 0;
12
+ }
13
+ /** Delimit both ends so a replay discards any truncated preceding packet before decoding. */
14
+ export function tunnelPacket(offset, bytes) {
15
+ if (!Number.isSafeInteger(offset) || offset < 0 || bytes.length > 65536)
16
+ throw new Error('invalid tunnel packet');
17
+ const data = Buffer.alloc(bytes.length + 16);
18
+ data.write('SFRT');
19
+ data.writeBigUInt64BE(BigInt(offset), 4);
20
+ data.set(bytes, 12);
21
+ data.writeUInt32BE(packetCrc(data.subarray(0, -4)), data.length - 4);
22
+ const result = Buffer.alloc(data.length + Math.ceil(data.length / 254) + 3);
23
+ let write = 2, codeAt = 1, code = 1;
24
+ for (const b of data) {
25
+ if (b === 0) {
26
+ result[codeAt] = code;
27
+ codeAt = write++;
28
+ code = 1;
29
+ }
30
+ else {
31
+ result[write++] = b;
32
+ code++;
33
+ if (code === 255) {
34
+ result[codeAt] = code;
35
+ codeAt = write++;
36
+ code = 1;
37
+ }
38
+ }
39
+ }
40
+ result[codeAt] = code;
41
+ result[write++] = 0;
42
+ return result.subarray(0, write);
43
+ }
@@ -0,0 +1,86 @@
1
+ import { WebSocket } from 'undici';
2
+ import type { CellClient, ExecSession, OutputEvent } from './cell.js';
3
+ import type { TunnelTransport } from './tunnels.js';
4
+ /** Native PTY owns the channel; helper acknowledgements own bytes, independently of an HTTP request outcome. */
5
+ export declare class PtyTunnelTransport implements TunnelTransport {
6
+ #private;
7
+ readonly maxInputConcurrency = 64;
8
+ readonly kind: "pty";
9
+ constructor(cell: CellClient, open?: (url: string, opts: NonNullable<ConstructorParameters<typeof WebSocket>[1]>) => WebSocket);
10
+ readonly files: {
11
+ remove: (path: string, opts?: {
12
+ recursive?: boolean;
13
+ }) => Promise<void>;
14
+ };
15
+ readonly exec: {
16
+ start: (req: {
17
+ session_id?: import("./index.js").CellComponents["schemas"]["SessionIdValue"];
18
+ argv: string[];
19
+ env?: {
20
+ [key: string]: string;
21
+ };
22
+ cwd?: string;
23
+ user?: string;
24
+ stdin_open?: boolean;
25
+ stdin?: string;
26
+ timeout_ms?: number;
27
+ kill_grace_ms?: number;
28
+ secret_refs?: import("./index.js").CellComponents["schemas"]["SecretRefs"];
29
+ execution_id?: import("./index.js").CellComponents["schemas"]["ExecutionIdValue"];
30
+ output_limit_bytes?: number;
31
+ burst?: "never" | "always";
32
+ burst_vcpus?: number;
33
+ burst_memory_mib?: number;
34
+ resource_hint?: "auto" | "light" | "heavy";
35
+ }, signal?: AbortSignal | undefined) => Promise<{
36
+ session_id: string;
37
+ state: import("./index.js").CellComponents["schemas"]["SessionState"];
38
+ created: boolean;
39
+ pid?: number;
40
+ exit_code?: number | null;
41
+ term_signal?: number | null;
42
+ timed_out?: boolean;
43
+ canceled?: boolean;
44
+ stdout_size: number;
45
+ stderr_size: number;
46
+ created_at?: string;
47
+ started_at?: string | null;
48
+ ended_at?: string | null;
49
+ error?: string;
50
+ memory_grow?: import("./index.js").CellComponents["schemas"]["MemoryGrow"];
51
+ burst?: import("./index.js").CellComponents["schemas"]["BurstSummary"];
52
+ }>;
53
+ input: (id: string, bytes: string | Uint8Array, opts: {
54
+ offset: number;
55
+ close?: boolean;
56
+ signal?: AbortSignal;
57
+ }) => Promise<{
58
+ offset: number;
59
+ closed: false;
60
+ }>;
61
+ output: (id: string, opts?: {
62
+ stdoutOffset?: number;
63
+ stderrOffset?: number;
64
+ follow?: boolean;
65
+ signal?: AbortSignal;
66
+ }) => Promise<AsyncGenerator<{
67
+ type: "output" | "exit" | "heartbeat" | "error";
68
+ stream?: "stdout" | "stderr";
69
+ offset?: number;
70
+ data?: string;
71
+ session?: import("./index.js").CellComponents["schemas"]["ExecSession"];
72
+ error?: import("./index.js").CellComponents["schemas"]["ErrorBody"];
73
+ }, any, any>>;
74
+ cancel: (id: string) => Promise<ExecSession>;
75
+ };
76
+ input(id: string, value: string | Uint8Array, opts: {
77
+ offset: number;
78
+ signal?: AbortSignal;
79
+ }): Promise<{
80
+ offset: number;
81
+ closed: false;
82
+ }>;
83
+ output(id: string, opts?: {
84
+ signal?: AbortSignal;
85
+ }): Promise<AsyncGenerator<OutputEvent>>;
86
+ }