@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.
- package/CHANGELOG.md +42 -22
- package/README.md +99 -1
- package/dist/account.d.ts +2 -0
- package/dist/account.js +6 -0
- package/dist/cell.d.ts +2 -0
- package/dist/cell.js +2 -0
- package/dist/client.d.ts +25 -1
- package/dist/client.js +44 -3
- package/dist/computer.d.ts +11 -1
- package/dist/computer.js +89 -6
- package/dist/errors.d.ts +5 -1
- package/dist/errors.js +9 -0
- package/dist/executions.d.ts +2 -6
- package/dist/executions.js +9 -0
- package/dist/exit-code.d.ts +7 -0
- package/dist/exit-code.js +12 -0
- package/dist/generated/app-api.d.ts +565 -13
- package/dist/generated/cell-api.d.ts +2 -0
- package/dist/http.d.ts +7 -1
- package/dist/http.js +34 -13
- package/dist/index.d.ts +8 -5
- package/dist/index.js +4 -2
- package/dist/ports.d.ts +7 -0
- package/dist/ports.js +1 -1
- package/dist/progress.d.ts +2 -2
- package/dist/progress.js +1 -1
- package/dist/testing/index.d.ts +62 -0
- package/dist/testing/index.js +585 -0
- package/dist/testing/seed.d.ts +433 -0
- package/dist/testing/seed.js +449 -0
- package/dist/tools.d.ts +5 -0
- package/dist/tools.js +4 -2
- package/dist/tunnel-assets/linux-amd64.gz +0 -0
- package/dist/tunnel-assets/linux-arm64.gz +0 -0
- package/dist/tunnel-assets.d.ts +10 -0
- package/dist/tunnel-assets.js +11 -0
- package/dist/tunnel-packet.d.ts +3 -0
- package/dist/tunnel-packet.js +43 -0
- package/dist/tunnel-pty.d.ts +86 -0
- package/dist/tunnel-pty.js +243 -0
- package/dist/tunnels.d.ts +47 -0
- package/dist/tunnels.js +454 -0
- package/dist/workspace-ref.d.ts +4 -0
- package/dist/workspace-ref.js +24 -0
- package/dist/workspace.d.ts +18 -1
- package/dist/workspace.js +76 -3
- package/package.json +7 -2
package/dist/workspace.js
CHANGED
|
@@ -6,6 +6,7 @@ import { AFTER_WAIT, HELD_RESUME, TRACE } from "./lifecycle.js";
|
|
|
6
6
|
import { Trace, combineListeners, traced } from "./progress.js";
|
|
7
7
|
import { WorkspaceComputer } from "./computer.js";
|
|
8
8
|
import { WorkspacePorts } from "./ports.js";
|
|
9
|
+
import { WorkspaceTunnels } from "./tunnels.js";
|
|
9
10
|
import { WorkspaceSecrets } from "./secrets.js";
|
|
10
11
|
import { ToolTokenManager } from "./tokens.js";
|
|
11
12
|
const notRunning = (e) => e instanceof ShardfluxApiError && (e.code === 'workspace_not_running' || (e.code === 'conflict' && e.reason === 'workspace_not_running'));
|
|
@@ -16,12 +17,14 @@ export class Workspace {
|
|
|
16
17
|
#ctx;
|
|
17
18
|
#defaults;
|
|
18
19
|
#managers = new Map();
|
|
20
|
+
#computer;
|
|
19
21
|
#cells = new Map();
|
|
20
22
|
/** The open() that produced this handle; its timing is final once open() has returned. */
|
|
21
23
|
#openTrace;
|
|
22
24
|
#lastTiming;
|
|
23
25
|
/** The newest tree revision seen (file-first): the view's, or any cell response's since. */
|
|
24
26
|
#treeRevision;
|
|
27
|
+
#tunnels;
|
|
25
28
|
/**
|
|
26
29
|
* Whether the open() that returned this handle created the workspace (0.15.0+, contracts §46.2): true for a new key
|
|
27
30
|
* (or a key whose session ended), false when it reconnected to or resumed an existing workspace. Null for handles
|
|
@@ -101,6 +104,10 @@ export class Workspace {
|
|
|
101
104
|
get grants() {
|
|
102
105
|
return this.#view.grants;
|
|
103
106
|
}
|
|
107
|
+
/** Stored caps every later start uses, as of the latest workspace view. */
|
|
108
|
+
get caps() {
|
|
109
|
+
return this.#view.caps;
|
|
110
|
+
}
|
|
104
111
|
get ceilings() {
|
|
105
112
|
return this.#view.ceilings;
|
|
106
113
|
}
|
|
@@ -220,13 +227,17 @@ export class Workspace {
|
|
|
220
227
|
get ports() {
|
|
221
228
|
return new WorkspacePorts(this.#ctx, this.id);
|
|
222
229
|
}
|
|
230
|
+
/** Forward a guest TCP port to this machine. Close the returned handle in finally. */
|
|
231
|
+
get tunnels() {
|
|
232
|
+
return this.#tunnels ??= new WorkspaceTunnels(() => this.cell({ transitionTimeoutMs: 30_000 }), () => this.grantedTools);
|
|
233
|
+
}
|
|
223
234
|
/**
|
|
224
235
|
* The workspace desktop (0.15.0+, contracts §45): `act(actions)`, `screenshot()`, `stream()` (a private link to watch
|
|
225
236
|
* it), `status()`, `start()`, `stop()`. Needs computer use on (`setComputerUse(true)`, or the template's switch); the
|
|
226
237
|
* platform starts the desktop on the first call that needs it.
|
|
227
238
|
*/
|
|
228
239
|
get computer() {
|
|
229
|
-
return new WorkspaceComputer({
|
|
240
|
+
return this.#computer ??= new WorkspaceComputer({
|
|
230
241
|
cell: () => this.cell(),
|
|
231
242
|
ports: () => this.ports,
|
|
232
243
|
setEnabled: (enabled) => this.setComputerUse(enabled).then(() => this.computerUse),
|
|
@@ -257,6 +268,11 @@ export class Workspace {
|
|
|
257
268
|
this.#view = (await this.#ctx.workspaces.setLabels(this.id, labels)).data;
|
|
258
269
|
return this;
|
|
259
270
|
}
|
|
271
|
+
get retention() { return this.#view.retention ?? null; }
|
|
272
|
+
async setRetention(policy) {
|
|
273
|
+
this.#view = (await this.#ctx.workspaces.setRetention(this.id, policy)).data;
|
|
274
|
+
return this;
|
|
275
|
+
}
|
|
260
276
|
async setIdlePolicy(policy) {
|
|
261
277
|
this.#view = (await this.#ctx.workspaces.setIdlePolicy(this.id, policy)).data;
|
|
262
278
|
return this;
|
|
@@ -342,7 +358,10 @@ export class Workspace {
|
|
|
342
358
|
throw refusal;
|
|
343
359
|
const out = await this.#ctx.workspaces.resize(this.id, this.#tracked(params));
|
|
344
360
|
// The resize has happened: a failed view read leaves the old view (the next refresh() reads it again).
|
|
345
|
-
|
|
361
|
+
if (params.wait !== false)
|
|
362
|
+
await this.refresh().catch(() => undefined);
|
|
363
|
+
else if (out.caps)
|
|
364
|
+
this.#view = { ...this.#view, caps: out.caps };
|
|
346
365
|
return out;
|
|
347
366
|
}
|
|
348
367
|
resume(opts = {}) {
|
|
@@ -378,19 +397,49 @@ export class Workspace {
|
|
|
378
397
|
return this.#ctx.workspaces.fork(this.id, target, this.#tracked(opts));
|
|
379
398
|
}
|
|
380
399
|
async close(opts = {}) {
|
|
400
|
+
let tunnelError;
|
|
401
|
+
try {
|
|
402
|
+
await this.#tunnels?.close();
|
|
403
|
+
}
|
|
404
|
+
catch (e) {
|
|
405
|
+
tunnelError = e instanceof Error ? e : new Error(String(e));
|
|
406
|
+
}
|
|
381
407
|
// Closing aborts in-flight cell requests: tool-call capture writes recorded before it are flushed first (bounded).
|
|
382
408
|
await this.#ctx.captures.settle(this.id);
|
|
383
409
|
for (const c of this.#cells.values())
|
|
384
410
|
c.close();
|
|
385
411
|
this.#cells.clear();
|
|
386
|
-
if (this.lifetime !== 'session')
|
|
412
|
+
if (this.lifetime !== 'session') {
|
|
413
|
+
if (tunnelError)
|
|
414
|
+
throw tunnelError;
|
|
387
415
|
return null;
|
|
416
|
+
}
|
|
388
417
|
const out = await this.#ctx.workspaces.closeWithView(this.id, this.#tracked(opts));
|
|
389
418
|
this.#view = out.workspace;
|
|
390
419
|
for (const m of this.#managers.values())
|
|
391
420
|
m.invalidate();
|
|
421
|
+
if (tunnelError)
|
|
422
|
+
throw tunnelError;
|
|
392
423
|
return out.operation;
|
|
393
424
|
}
|
|
425
|
+
/**
|
|
426
|
+
* Wipes every change in this layered workspace and restarts it on its template (sends
|
|
427
|
+
* confirm_destructive). Returns the `reset` operation: requested, or with `{ wait: true }` finished. Tool tokens of
|
|
428
|
+
* the old epoch are dropped.
|
|
429
|
+
*/
|
|
430
|
+
/** Upgrade in place: keep files/packages/home; cold start drops memory and processes. */
|
|
431
|
+
async upgrade(opts = {}) {
|
|
432
|
+
const refusal = this.#needsVm('upgrade');
|
|
433
|
+
if (refusal)
|
|
434
|
+
throw refusal;
|
|
435
|
+
const op = await this.#ctx.workspaces.upgrade(this.id, { ...this.#tracked(opts), [AFTER_WAIT]: this.#refreshAfterWait() });
|
|
436
|
+
if (opts.at !== 'next_resume')
|
|
437
|
+
for (const m of this.#managers.values())
|
|
438
|
+
m.invalidate();
|
|
439
|
+
return op;
|
|
440
|
+
}
|
|
441
|
+
get upgradeAvailable() { return this.#view.upgrade_available ?? null; }
|
|
442
|
+
get upgradePending() { return this.#view.upgrade_pending ?? null; }
|
|
394
443
|
async reset(opts = {}) {
|
|
395
444
|
const refusal = this.#needsVm('reset');
|
|
396
445
|
if (refusal)
|
|
@@ -590,6 +639,30 @@ export class Workspace {
|
|
|
590
639
|
}
|
|
591
640
|
throw new Error(`workspace ${this.id} did not become runnable after repeated lifecycle conflicts`);
|
|
592
641
|
}
|
|
642
|
+
/** Hints without waiting, runs the turn, and requests idle suspension even if the body throws. */
|
|
643
|
+
async turn(fn, { afterSeconds = 0 } = {}) {
|
|
644
|
+
void this.hint().catch(() => undefined);
|
|
645
|
+
let result;
|
|
646
|
+
let failure;
|
|
647
|
+
let failed = false;
|
|
648
|
+
try {
|
|
649
|
+
result = await fn(this);
|
|
650
|
+
}
|
|
651
|
+
catch (err) {
|
|
652
|
+
failed = true;
|
|
653
|
+
failure = err;
|
|
654
|
+
}
|
|
655
|
+
try {
|
|
656
|
+
await this.suspendWhenIdle({ afterSeconds });
|
|
657
|
+
}
|
|
658
|
+
catch (err) {
|
|
659
|
+
if (!failed)
|
|
660
|
+
throw err;
|
|
661
|
+
}
|
|
662
|
+
if (failed)
|
|
663
|
+
throw failure;
|
|
664
|
+
return result;
|
|
665
|
+
}
|
|
593
666
|
/**
|
|
594
667
|
* Announces an imminent tool call (cell `POST /wake-hint`; 0.9.0+) so a parked workspace is restored
|
|
595
668
|
* ahead of it: call it when the model starts emitting a tool call, before its arguments are complete. The agent tools
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shardflux/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Shardflux TypeScript SDK:
|
|
5
|
+
"description": "Shardflux TypeScript SDK: serverless VMs for AI agents. Open a workspace by key and give your agent workspace tools (exec, files, processes, PTY, git, browser).",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"homepage": "https://shardflux.dev",
|
|
8
8
|
"bugs": {
|
|
@@ -29,6 +29,11 @@
|
|
|
29
29
|
"types": "./dist/index.d.ts",
|
|
30
30
|
"import": "./dist/index.js",
|
|
31
31
|
"default": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./testing": {
|
|
34
|
+
"types": "./dist/testing/index.d.ts",
|
|
35
|
+
"import": "./dist/testing/index.js",
|
|
36
|
+
"default": "./dist/testing/index.js"
|
|
32
37
|
}
|
|
33
38
|
},
|
|
34
39
|
"files": [
|