@fastgpt-sdk/sandbox-adapter 0.0.31 → 0.0.33
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/dist/adapters/BaseSandboxAdapter.d.ts +15 -1
- package/dist/adapters/E2BAdapter/index.d.ts +1 -0
- package/dist/adapters/E2BAdapter/type.d.ts +1 -1
- package/dist/adapters/OpenSandboxAdapter/index.d.ts +10 -10
- package/dist/adapters/SealosDevboxAdapter/index.d.ts +1 -1
- package/dist/index.cjs +153 -65
- package/dist/index.d.ts +1 -0
- package/dist/index.js +153 -65
- package/dist/interfaces/ISandboxLifecycle.d.ts +2 -1
- package/package.json +1 -1
|
@@ -9,11 +9,24 @@ import type { ContentReplaceEntry, DirectoryEntry, ExecuteOptions, ExecuteResult
|
|
|
9
9
|
* Subclasses can override the polyfill service in their constructor.
|
|
10
10
|
*/
|
|
11
11
|
export declare abstract class BaseSandboxAdapter implements ISandbox {
|
|
12
|
-
abstract readonly id
|
|
12
|
+
abstract readonly id?: SandboxId;
|
|
13
13
|
abstract readonly provider: string;
|
|
14
14
|
protected _status: SandboxStatus;
|
|
15
15
|
protected polyfillService?: CommandPolyfillService;
|
|
16
16
|
constructor();
|
|
17
|
+
/**
|
|
18
|
+
* The root path of the sandbox filesystem.
|
|
19
|
+
* Subclasses should override this to return the provider-specific root path.
|
|
20
|
+
*/
|
|
21
|
+
get rootPath(): string;
|
|
22
|
+
/**
|
|
23
|
+
* Normalize a path relative to rootPath.
|
|
24
|
+
* - '.' or './' → rootPath
|
|
25
|
+
* - './foo' → rootPath/foo
|
|
26
|
+
* - 'foo' → rootPath/foo
|
|
27
|
+
* - '/absolute' → '/absolute' (pass through)
|
|
28
|
+
*/
|
|
29
|
+
protected normalizePath(path?: string): string;
|
|
17
30
|
get status(): SandboxStatus;
|
|
18
31
|
abstract ensureRunning(): Promise<void>;
|
|
19
32
|
abstract create(): Promise<void>;
|
|
@@ -22,6 +35,7 @@ export declare abstract class BaseSandboxAdapter implements ISandbox {
|
|
|
22
35
|
abstract delete(): Promise<void>;
|
|
23
36
|
abstract getInfo(): Promise<SandboxInfo | null>;
|
|
24
37
|
waitUntilReady(timeoutMs?: number): Promise<void>;
|
|
38
|
+
waitUntilDeleted(timeoutMs?: number): Promise<void>;
|
|
25
39
|
renewExpiration(_additionalSeconds: number): Promise<void>;
|
|
26
40
|
abstract execute(command: string, options?: ExecuteOptions): Promise<ExecuteResult>;
|
|
27
41
|
executeStream(command: string, handlers: StreamHandlers, options?: ExecuteOptions): Promise<void>;
|
|
@@ -12,8 +12,9 @@ export type SandboxRuntimeType = 'docker' | 'kubernetes';
|
|
|
12
12
|
* Connection configuration options for OpenSandboxAdapter.
|
|
13
13
|
*/
|
|
14
14
|
export interface OpenSandboxConnectionConfig {
|
|
15
|
+
sessionId: string;
|
|
15
16
|
/** Base URL for the OpenSandbox API */
|
|
16
|
-
baseUrl
|
|
17
|
+
baseUrl: string;
|
|
17
18
|
/** API key for authentication */
|
|
18
19
|
apiKey?: string;
|
|
19
20
|
/** SDK request timeout in seconds */
|
|
@@ -50,14 +51,16 @@ export interface OpenSandboxConnectionConfig {
|
|
|
50
51
|
*/
|
|
51
52
|
export declare class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
52
53
|
private connectionConfig;
|
|
53
|
-
private createConfig
|
|
54
|
+
private createConfig;
|
|
54
55
|
readonly provider: "opensandbox";
|
|
55
56
|
readonly runtime: SandboxRuntimeType;
|
|
56
57
|
private _sandbox?;
|
|
57
58
|
private _connection;
|
|
58
|
-
private _id
|
|
59
|
-
constructor(connectionConfig
|
|
60
|
-
get
|
|
59
|
+
private _id?;
|
|
60
|
+
constructor(connectionConfig: OpenSandboxConnectionConfig, createConfig: OpenSandboxConfigType);
|
|
61
|
+
get rootPath(): string;
|
|
62
|
+
get id(): SandboxId | undefined;
|
|
63
|
+
private set sandbox(value);
|
|
61
64
|
private get sandbox();
|
|
62
65
|
private createConnectionConfig;
|
|
63
66
|
private static readonly STATE_MAP;
|
|
@@ -67,9 +70,11 @@ export declare class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
67
70
|
private convertResourceLimits;
|
|
68
71
|
private parseResourceLimits;
|
|
69
72
|
private extractExitCode;
|
|
73
|
+
private getSandboxBySessionId;
|
|
70
74
|
ensureRunning(): Promise<void>;
|
|
71
75
|
create(): Promise<void>;
|
|
72
76
|
connect(sandboxId: string): Promise<void>;
|
|
77
|
+
private resume;
|
|
73
78
|
start(): Promise<void>;
|
|
74
79
|
stop(): Promise<void>;
|
|
75
80
|
delete(): Promise<void>;
|
|
@@ -85,11 +90,6 @@ export declare class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
85
90
|
* @returns Endpoint with host, port, protocol and url fields
|
|
86
91
|
*/
|
|
87
92
|
getEndpoint(port: number): Promise<Endpoint>;
|
|
88
|
-
/**
|
|
89
|
-
* Convert SDK Endpoint (no-scheme string) to our Endpoint type.
|
|
90
|
-
* SDK format: "localhost:44772" or "domain/route/.../44772"
|
|
91
|
-
*/
|
|
92
|
-
private convertSdkEndpoint;
|
|
93
93
|
getInfo(): Promise<SandboxInfo | null>;
|
|
94
94
|
renewExpiration(additionalSeconds: number): Promise<void>;
|
|
95
95
|
execute(command: string, options?: ExecuteOptions): Promise<ExecuteResult>;
|
|
@@ -13,12 +13,12 @@ export interface SealosDevboxConfig {
|
|
|
13
13
|
export declare class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
14
14
|
private config;
|
|
15
15
|
readonly provider: "sealosdevbox";
|
|
16
|
+
get rootPath(): string;
|
|
16
17
|
private api;
|
|
17
18
|
private _id;
|
|
18
19
|
constructor(config: SealosDevboxConfig);
|
|
19
20
|
get id(): SandboxId;
|
|
20
21
|
private StatusAdapt;
|
|
21
|
-
private waitUntilDeleted;
|
|
22
22
|
getInfo(): Promise<SandboxInfo | null>;
|
|
23
23
|
ensureRunning(): Promise<void>;
|
|
24
24
|
create(): Promise<void>;
|
package/dist/index.cjs
CHANGED
|
@@ -47506,6 +47506,19 @@ class BaseSandboxAdapter {
|
|
|
47506
47506
|
_status = { state: "Creating" };
|
|
47507
47507
|
polyfillService;
|
|
47508
47508
|
constructor() {}
|
|
47509
|
+
get rootPath() {
|
|
47510
|
+
return "/";
|
|
47511
|
+
}
|
|
47512
|
+
normalizePath(path = "") {
|
|
47513
|
+
if (path === "." || path === "./")
|
|
47514
|
+
return this.rootPath;
|
|
47515
|
+
const root = this.rootPath.replace(/\/+$/, "");
|
|
47516
|
+
if (path.startsWith("./"))
|
|
47517
|
+
return `${root}/${path.slice(2)}`;
|
|
47518
|
+
if (!path.startsWith("/"))
|
|
47519
|
+
return `${root}/${path}`;
|
|
47520
|
+
return path;
|
|
47521
|
+
}
|
|
47509
47522
|
get status() {
|
|
47510
47523
|
return this._status;
|
|
47511
47524
|
}
|
|
@@ -47519,7 +47532,19 @@ class BaseSandboxAdapter {
|
|
|
47519
47532
|
}
|
|
47520
47533
|
await this.sleep(checkInterval);
|
|
47521
47534
|
}
|
|
47522
|
-
throw new SandboxReadyTimeoutError(this.id, timeoutMs);
|
|
47535
|
+
throw new SandboxReadyTimeoutError(this.id ?? "Unknown", timeoutMs);
|
|
47536
|
+
}
|
|
47537
|
+
async waitUntilDeleted(timeoutMs = 120000) {
|
|
47538
|
+
const startTime = Date.now();
|
|
47539
|
+
const checkInterval = 1000;
|
|
47540
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
47541
|
+
const data = await this.getInfo().catch(() => true);
|
|
47542
|
+
if (!data) {
|
|
47543
|
+
return;
|
|
47544
|
+
}
|
|
47545
|
+
await this.sleep(checkInterval);
|
|
47546
|
+
}
|
|
47547
|
+
throw new SandboxReadyTimeoutError(this.id ?? "Unknown", timeoutMs);
|
|
47523
47548
|
}
|
|
47524
47549
|
async renewExpiration(_additionalSeconds) {
|
|
47525
47550
|
throw new FeatureNotSupportedError("Sandbox expiration renewal not supported by this provider", "renewExpiration", this.provider);
|
|
@@ -47545,7 +47570,7 @@ class BaseSandboxAdapter {
|
|
|
47545
47570
|
async readFiles(paths, options) {
|
|
47546
47571
|
const polyfillService = this.requirePolyfillService("readFiles", "File read not supported by this provider");
|
|
47547
47572
|
const results = [];
|
|
47548
|
-
for (const path of paths) {
|
|
47573
|
+
for (const path of paths.map((p) => this.normalizePath(p))) {
|
|
47549
47574
|
try {
|
|
47550
47575
|
let content;
|
|
47551
47576
|
if (options?.range) {
|
|
@@ -47573,7 +47598,7 @@ class BaseSandboxAdapter {
|
|
|
47573
47598
|
async writeFiles(entries) {
|
|
47574
47599
|
const polyfillService = this.requirePolyfillService("writeFiles", "File write not supported by this provider");
|
|
47575
47600
|
const results = [];
|
|
47576
|
-
for (const entry of entries) {
|
|
47601
|
+
for (const entry of entries.map((e) => ({ ...e, path: this.normalizePath(e.path) }))) {
|
|
47577
47602
|
try {
|
|
47578
47603
|
let bytesWritten;
|
|
47579
47604
|
if (typeof entry.data === "string") {
|
|
@@ -47617,7 +47642,7 @@ class BaseSandboxAdapter {
|
|
|
47617
47642
|
}
|
|
47618
47643
|
async deleteFiles(paths) {
|
|
47619
47644
|
const polyfillService = this.requirePolyfillService("deleteFiles", "File delete not supported by this provider");
|
|
47620
|
-
const polyfillResults = await polyfillService.deleteFiles(paths);
|
|
47645
|
+
const polyfillResults = await polyfillService.deleteFiles(paths.map((p) => this.normalizePath(p)));
|
|
47621
47646
|
return polyfillResults.map((r) => ({
|
|
47622
47647
|
path: r.path,
|
|
47623
47648
|
success: r.success,
|
|
@@ -47626,7 +47651,10 @@ class BaseSandboxAdapter {
|
|
|
47626
47651
|
}
|
|
47627
47652
|
async moveFiles(entries) {
|
|
47628
47653
|
const polyfillService = this.requirePolyfillService("moveFiles", "File move not supported by this provider");
|
|
47629
|
-
await polyfillService.moveFiles(entries.map((e) => ({
|
|
47654
|
+
await polyfillService.moveFiles(entries.map((e) => ({
|
|
47655
|
+
source: this.normalizePath(e.source),
|
|
47656
|
+
destination: this.normalizePath(e.destination)
|
|
47657
|
+
})));
|
|
47630
47658
|
}
|
|
47631
47659
|
async replaceContent(entries) {
|
|
47632
47660
|
const polyfillService = this.requirePolyfillService("replaceContent", "Content replace not supported by this provider");
|
|
@@ -47634,15 +47662,15 @@ class BaseSandboxAdapter {
|
|
|
47634
47662
|
}
|
|
47635
47663
|
async createDirectories(paths, options) {
|
|
47636
47664
|
const polyfillService = this.requirePolyfillService("createDirectories", "Directory creation not supported by this provider");
|
|
47637
|
-
await polyfillService.createDirectories(paths, options);
|
|
47665
|
+
await polyfillService.createDirectories(paths.map((p) => this.normalizePath(p)), options);
|
|
47638
47666
|
}
|
|
47639
47667
|
async deleteDirectories(paths, options) {
|
|
47640
47668
|
const polyfillService = this.requirePolyfillService("deleteDirectories", "Directory deletion not supported by this provider");
|
|
47641
|
-
await polyfillService.deleteDirectories(paths, options);
|
|
47669
|
+
await polyfillService.deleteDirectories(paths.map((p) => this.normalizePath(p)), options);
|
|
47642
47670
|
}
|
|
47643
47671
|
async listDirectory(path) {
|
|
47644
47672
|
const polyfillService = this.requirePolyfillService("listDirectory", "Directory listing not supported by this provider");
|
|
47645
|
-
return polyfillService.listDirectory(path);
|
|
47673
|
+
return polyfillService.listDirectory(this.normalizePath(path));
|
|
47646
47674
|
}
|
|
47647
47675
|
async* readFileStream(path) {
|
|
47648
47676
|
this.requirePolyfillService("readFileStream", "File stream read not supported by this provider");
|
|
@@ -47694,7 +47722,7 @@ class BaseSandboxAdapter {
|
|
|
47694
47722
|
}
|
|
47695
47723
|
async getFileInfo(paths) {
|
|
47696
47724
|
const polyfillService = this.requirePolyfillService("getFileInfo", "File info not supported by this provider");
|
|
47697
|
-
return polyfillService.getFileInfo(paths);
|
|
47725
|
+
return polyfillService.getFileInfo(paths.map((p) => this.normalizePath(p)));
|
|
47698
47726
|
}
|
|
47699
47727
|
async setPermissions(entries) {
|
|
47700
47728
|
const polyfillService = this.requirePolyfillService("setPermissions", "Permission setting not supported by this provider");
|
|
@@ -47702,7 +47730,7 @@ class BaseSandboxAdapter {
|
|
|
47702
47730
|
}
|
|
47703
47731
|
async search(pattern, path) {
|
|
47704
47732
|
const polyfillService = this.requirePolyfillService("search", "File search not supported by this provider");
|
|
47705
|
-
return polyfillService.search(pattern, path);
|
|
47733
|
+
return polyfillService.search(pattern, path !== undefined ? this.normalizePath(path) : path);
|
|
47706
47734
|
}
|
|
47707
47735
|
async ping() {
|
|
47708
47736
|
const polyfillService = this.requirePolyfillService("ping", "Health check not supported by this provider");
|
|
@@ -47825,6 +47853,9 @@ class DevboxApi {
|
|
|
47825
47853
|
class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
47826
47854
|
config;
|
|
47827
47855
|
provider = "sealosdevbox";
|
|
47856
|
+
get rootPath() {
|
|
47857
|
+
return "/home/devbox/workspace";
|
|
47858
|
+
}
|
|
47828
47859
|
api;
|
|
47829
47860
|
_id;
|
|
47830
47861
|
constructor(config) {
|
|
@@ -47854,18 +47885,6 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
|
47854
47885
|
return "Error";
|
|
47855
47886
|
}
|
|
47856
47887
|
}
|
|
47857
|
-
async waitUntilDeleted() {
|
|
47858
|
-
const startTime = Date.now();
|
|
47859
|
-
const checkInterval = 1000;
|
|
47860
|
-
while (Date.now() - startTime < 120000) {
|
|
47861
|
-
const data = await this.getInfo().catch(() => true);
|
|
47862
|
-
if (!data) {
|
|
47863
|
-
return;
|
|
47864
|
-
}
|
|
47865
|
-
await this.sleep(checkInterval);
|
|
47866
|
-
}
|
|
47867
|
-
throw new TimeoutError("Sandbox not deleted", 120000, "waitUntilDeleted");
|
|
47868
|
-
}
|
|
47869
47888
|
async getInfo() {
|
|
47870
47889
|
try {
|
|
47871
47890
|
const res = await this.api.info(this._id);
|
|
@@ -47956,7 +47975,7 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
|
47956
47975
|
}
|
|
47957
47976
|
}
|
|
47958
47977
|
async execute(command, options) {
|
|
47959
|
-
const cmd = this.buildCommand(command, options?.workingDirectory);
|
|
47978
|
+
const cmd = this.buildCommand(command, this.normalizePath(options?.workingDirectory));
|
|
47960
47979
|
try {
|
|
47961
47980
|
const res = await this.api.exec(this._id, {
|
|
47962
47981
|
command: cmd,
|
|
@@ -47995,8 +48014,8 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
47995
48014
|
runtime;
|
|
47996
48015
|
_sandbox;
|
|
47997
48016
|
_connection;
|
|
47998
|
-
_id
|
|
47999
|
-
constructor(connectionConfig
|
|
48017
|
+
_id;
|
|
48018
|
+
constructor(connectionConfig, createConfig) {
|
|
48000
48019
|
super();
|
|
48001
48020
|
this.connectionConfig = connectionConfig;
|
|
48002
48021
|
this.createConfig = createConfig;
|
|
@@ -48004,9 +48023,17 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48004
48023
|
this._connection = this.createConnectionConfig();
|
|
48005
48024
|
this.polyfillService = new CommandPolyfillService(this);
|
|
48006
48025
|
}
|
|
48026
|
+
get rootPath() {
|
|
48027
|
+
const mountPath = this.createConfig.volumes?.[0]?.mountPath;
|
|
48028
|
+
return mountPath ? mountPath.replace(/\/+$/, "") : "/home/sandbox";
|
|
48029
|
+
}
|
|
48007
48030
|
get id() {
|
|
48008
48031
|
return this._id;
|
|
48009
48032
|
}
|
|
48033
|
+
set sandbox(sandbox) {
|
|
48034
|
+
this._sandbox = sandbox;
|
|
48035
|
+
this._id = sandbox?.id;
|
|
48036
|
+
}
|
|
48010
48037
|
get sandbox() {
|
|
48011
48038
|
if (!this._sandbox) {
|
|
48012
48039
|
throw new SandboxStateError("Sandbox not initialized. Call create() or connect() first.", "UnExist", "Running");
|
|
@@ -48015,9 +48042,6 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48015
48042
|
}
|
|
48016
48043
|
createConnectionConfig() {
|
|
48017
48044
|
const { baseUrl, apiKey, requestTimeoutSeconds, debug, useServerProxy } = this.connectionConfig;
|
|
48018
|
-
if (!baseUrl) {
|
|
48019
|
-
return new import_opensandbox.ConnectionConfig({ apiKey, requestTimeoutSeconds, debug, useServerProxy });
|
|
48020
|
-
}
|
|
48021
48045
|
return new import_opensandbox.ConnectionConfig({
|
|
48022
48046
|
domain: baseUrl,
|
|
48023
48047
|
apiKey,
|
|
@@ -48128,32 +48152,74 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48128
48152
|
}
|
|
48129
48153
|
return 0;
|
|
48130
48154
|
}
|
|
48155
|
+
async getSandboxBySessionId() {
|
|
48156
|
+
const manager = import_opensandbox.SandboxManager.create({ connectionConfig: this._connection });
|
|
48157
|
+
const result = await manager.listSandboxInfos({
|
|
48158
|
+
metadata: { sessionId: this.connectionConfig.sessionId }
|
|
48159
|
+
});
|
|
48160
|
+
const val = result.items[0];
|
|
48161
|
+
if (val) {
|
|
48162
|
+
const status = this.mapStatus(val.status);
|
|
48163
|
+
return {
|
|
48164
|
+
id: val.id,
|
|
48165
|
+
status
|
|
48166
|
+
};
|
|
48167
|
+
}
|
|
48168
|
+
}
|
|
48131
48169
|
async ensureRunning() {
|
|
48132
|
-
|
|
48170
|
+
const sandbox = await this.getSandboxBySessionId();
|
|
48171
|
+
if (sandbox) {
|
|
48172
|
+
switch (sandbox.status.state) {
|
|
48173
|
+
case "UnExist":
|
|
48174
|
+
await this.create();
|
|
48175
|
+
break;
|
|
48176
|
+
case "Running":
|
|
48177
|
+
await this.connect(sandbox.id);
|
|
48178
|
+
break;
|
|
48179
|
+
case "Creating":
|
|
48180
|
+
case "Starting":
|
|
48181
|
+
await this.waitUntilReady();
|
|
48182
|
+
break;
|
|
48183
|
+
case "Stopping":
|
|
48184
|
+
case "Stopped":
|
|
48185
|
+
await this.resume(sandbox.id);
|
|
48186
|
+
break;
|
|
48187
|
+
case "Deleting":
|
|
48188
|
+
await this.waitUntilDeleted();
|
|
48189
|
+
await this.create();
|
|
48190
|
+
break;
|
|
48191
|
+
case "Error":
|
|
48192
|
+
throw new ConnectionError(`Sandbox error: ${sandbox.status.message}`);
|
|
48193
|
+
default:
|
|
48194
|
+
throw new ConnectionError(`Sandbox state ${sandbox.status.state} not supported`);
|
|
48195
|
+
}
|
|
48196
|
+
} else {
|
|
48197
|
+
await this.create();
|
|
48198
|
+
}
|
|
48133
48199
|
}
|
|
48134
48200
|
async create() {
|
|
48135
|
-
if (!this.createConfig) {
|
|
48136
|
-
throw new Error("createConfig is required to create a sandbox. Pass it as the third argument to createSandbox().");
|
|
48137
|
-
}
|
|
48138
48201
|
const cfg = this.createConfig;
|
|
48139
48202
|
try {
|
|
48140
48203
|
this._status = { state: "Creating" };
|
|
48141
48204
|
const image = this.convertImageSpec(cfg.image);
|
|
48142
48205
|
const resource = this.convertResourceLimits(cfg.resourceLimits);
|
|
48143
|
-
this.
|
|
48206
|
+
this.sandbox = await import_opensandbox.Sandbox.create({
|
|
48144
48207
|
connectionConfig: this._connection,
|
|
48145
48208
|
image,
|
|
48146
48209
|
entrypoint: cfg.entrypoint,
|
|
48147
48210
|
timeoutSeconds: cfg.timeoutSeconds ?? null,
|
|
48148
48211
|
resource,
|
|
48149
48212
|
env: cfg.env,
|
|
48150
|
-
metadata:
|
|
48213
|
+
metadata: {
|
|
48214
|
+
...cfg.metadata,
|
|
48215
|
+
sessionId: this.connectionConfig.sessionId
|
|
48216
|
+
},
|
|
48151
48217
|
volumes: cfg.volumes,
|
|
48152
48218
|
skipHealthCheck: cfg.skipHealthCheck,
|
|
48153
48219
|
readyTimeoutSeconds: cfg.readyTimeoutSeconds,
|
|
48154
48220
|
healthCheckPollingInterval: cfg.healthCheckPollingInterval
|
|
48155
48221
|
});
|
|
48156
|
-
|
|
48222
|
+
await this.waitUntilReady();
|
|
48157
48223
|
this._status = { state: "Running" };
|
|
48158
48224
|
} catch (error) {
|
|
48159
48225
|
this._status = { state: "Error", message: String(error) };
|
|
@@ -48163,31 +48229,51 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48163
48229
|
async connect(sandboxId) {
|
|
48164
48230
|
try {
|
|
48165
48231
|
this._status = { state: "Starting" };
|
|
48166
|
-
this.
|
|
48232
|
+
this.sandbox = await import_opensandbox.Sandbox.connect({
|
|
48167
48233
|
sandboxId,
|
|
48168
48234
|
connectionConfig: this._connection,
|
|
48169
48235
|
skipHealthCheck: this.createConfig?.skipHealthCheck,
|
|
48170
48236
|
readyTimeoutSeconds: this.createConfig?.readyTimeoutSeconds,
|
|
48171
48237
|
healthCheckPollingInterval: this.createConfig?.healthCheckPollingInterval
|
|
48172
48238
|
});
|
|
48173
|
-
this._id = this._sandbox.id;
|
|
48174
48239
|
this._status = { state: "Running" };
|
|
48175
48240
|
} catch (error) {
|
|
48176
48241
|
this._status = { state: "Error", message: String(error) };
|
|
48177
48242
|
throw new ConnectionError(`Failed to connect to sandbox ${sandboxId}`, this.connectionConfig.baseUrl, error);
|
|
48178
48243
|
}
|
|
48179
48244
|
}
|
|
48245
|
+
async resume(sandboxId) {
|
|
48246
|
+
try {
|
|
48247
|
+
this._status = { state: "Starting" };
|
|
48248
|
+
this.sandbox = await import_opensandbox.Sandbox.resume({
|
|
48249
|
+
sandboxId,
|
|
48250
|
+
connectionConfig: this._connection,
|
|
48251
|
+
skipHealthCheck: this.createConfig?.skipHealthCheck,
|
|
48252
|
+
readyTimeoutSeconds: this.createConfig?.readyTimeoutSeconds,
|
|
48253
|
+
healthCheckPollingInterval: this.createConfig?.healthCheckPollingInterval
|
|
48254
|
+
});
|
|
48255
|
+
this._status = { state: "Running" };
|
|
48256
|
+
} catch (error) {
|
|
48257
|
+
this._status = { state: "Error", message: String(error) };
|
|
48258
|
+
throw new ConnectionError(`Failed to resume sandbox ${sandboxId}`, this.connectionConfig.baseUrl, error);
|
|
48259
|
+
}
|
|
48260
|
+
}
|
|
48180
48261
|
async start() {
|
|
48181
48262
|
try {
|
|
48182
48263
|
this._status = { state: "Starting" };
|
|
48183
|
-
this.
|
|
48184
|
-
|
|
48264
|
+
this.sandbox = await this.sandbox.resume();
|
|
48265
|
+
await this.waitUntilReady();
|
|
48185
48266
|
this._status = { state: "Running" };
|
|
48186
48267
|
} catch (error) {
|
|
48187
|
-
|
|
48188
|
-
|
|
48268
|
+
const code = error instanceof import_opensandbox.SandboxException ? error.error.code : undefined;
|
|
48269
|
+
switch (code) {
|
|
48270
|
+
case "DOCKER::SANDBOX_NOT_PAUSED":
|
|
48271
|
+
return;
|
|
48272
|
+
case "SANDBOX::API_NOT_SUPPORTED":
|
|
48273
|
+
throw new FeatureNotSupportedError("Start/resume not supported by this runtime", "start", this.provider);
|
|
48274
|
+
default:
|
|
48275
|
+
throw new CommandExecutionError("Failed to start sandbox", "start", error instanceof Error ? error : undefined);
|
|
48189
48276
|
}
|
|
48190
|
-
throw new CommandExecutionError("Failed to start sandbox", "start", error instanceof Error ? error : undefined);
|
|
48191
48277
|
}
|
|
48192
48278
|
}
|
|
48193
48279
|
async stop() {
|
|
@@ -48196,6 +48282,10 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48196
48282
|
await this.sandbox.pause();
|
|
48197
48283
|
this._status = { state: "Stopped" };
|
|
48198
48284
|
} catch (error) {
|
|
48285
|
+
const message = error instanceof import_opensandbox.SandboxException ? error.error.message : undefined;
|
|
48286
|
+
if (message?.includes("already paused")) {
|
|
48287
|
+
return;
|
|
48288
|
+
}
|
|
48199
48289
|
if (error && typeof error === "object" && "code" in error && error.code === "SANDBOX::API_NOT_SUPPORTED") {
|
|
48200
48290
|
throw new FeatureNotSupportedError("Stop/pause not supported by this runtime", "stop", this.provider);
|
|
48201
48291
|
}
|
|
@@ -48206,43 +48296,38 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48206
48296
|
try {
|
|
48207
48297
|
this._status = { state: "Deleting" };
|
|
48208
48298
|
await this.sandbox.kill();
|
|
48209
|
-
this.
|
|
48210
|
-
this._id = "";
|
|
48299
|
+
this.sandbox = undefined;
|
|
48211
48300
|
this._status = { state: "UnExist" };
|
|
48212
48301
|
} catch (error) {
|
|
48213
48302
|
throw new CommandExecutionError("Failed to delete sandbox", "delete", error instanceof Error ? error : undefined);
|
|
48214
48303
|
}
|
|
48215
48304
|
}
|
|
48216
48305
|
async close() {
|
|
48217
|
-
|
|
48218
|
-
await this._sandbox.close();
|
|
48219
|
-
}
|
|
48306
|
+
await this.sandbox.close();
|
|
48220
48307
|
}
|
|
48221
48308
|
async getEndpoint(port) {
|
|
48222
48309
|
const sdkEndpoint = await this.sandbox.getEndpoint(port);
|
|
48223
|
-
return this.convertSdkEndpoint(sdkEndpoint, port);
|
|
48224
|
-
}
|
|
48225
|
-
convertSdkEndpoint(sdkEndpoint, requestedPort) {
|
|
48226
48310
|
const raw = sdkEndpoint.endpoint;
|
|
48227
48311
|
const colonIdx = raw.lastIndexOf(":");
|
|
48228
48312
|
const hasPathBeforeColon = colonIdx !== -1 && raw.slice(0, colonIdx).includes("/");
|
|
48229
48313
|
if (colonIdx !== -1 && !hasPathBeforeColon) {
|
|
48230
48314
|
const host = raw.slice(0, colonIdx);
|
|
48231
48315
|
const parsedPort = parseInt(raw.slice(colonIdx + 1), 10);
|
|
48232
|
-
const
|
|
48316
|
+
const portNumber = isNaN(parsedPort) ? port : parsedPort;
|
|
48233
48317
|
const protocol = port === 443 ? "https" : "http";
|
|
48234
|
-
return { host, port, protocol, url: `${protocol}://${raw}` };
|
|
48318
|
+
return { host, port: portNumber, protocol, url: `${protocol}://${raw}` };
|
|
48235
48319
|
}
|
|
48236
48320
|
return {
|
|
48237
48321
|
host: raw,
|
|
48238
|
-
port
|
|
48322
|
+
port,
|
|
48239
48323
|
protocol: "https",
|
|
48240
48324
|
url: `https://${raw}`
|
|
48241
48325
|
};
|
|
48242
48326
|
}
|
|
48243
48327
|
async getInfo() {
|
|
48244
|
-
if (!this._sandbox)
|
|
48328
|
+
if (!this._sandbox) {
|
|
48245
48329
|
return null;
|
|
48330
|
+
}
|
|
48246
48331
|
try {
|
|
48247
48332
|
const info = await this.sandbox.getInfo();
|
|
48248
48333
|
return {
|
|
@@ -48269,7 +48354,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48269
48354
|
async execute(command, options) {
|
|
48270
48355
|
try {
|
|
48271
48356
|
const execution = await this.sandbox.commands.run(command, {
|
|
48272
|
-
workingDirectory: options?.workingDirectory,
|
|
48357
|
+
workingDirectory: this.normalizePath(options?.workingDirectory),
|
|
48273
48358
|
background: options?.background
|
|
48274
48359
|
});
|
|
48275
48360
|
const stdout = execution.logs.stdout.map((msg) => msg.text).join(`
|
|
@@ -48306,7 +48391,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48306
48391
|
} : {}
|
|
48307
48392
|
};
|
|
48308
48393
|
const execution = await this.sandbox.commands.run(command, {
|
|
48309
|
-
workingDirectory: options?.workingDirectory,
|
|
48394
|
+
workingDirectory: this.normalizePath(options?.workingDirectory),
|
|
48310
48395
|
background: options?.background
|
|
48311
48396
|
}, sdkHandlers);
|
|
48312
48397
|
if (handlers.onComplete) {
|
|
@@ -48328,7 +48413,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48328
48413
|
async executeBackground(command, options) {
|
|
48329
48414
|
try {
|
|
48330
48415
|
const execution = await this.sandbox.commands.run(command, {
|
|
48331
|
-
workingDirectory: options?.workingDirectory,
|
|
48416
|
+
workingDirectory: this.normalizePath(options?.workingDirectory),
|
|
48332
48417
|
background: true
|
|
48333
48418
|
});
|
|
48334
48419
|
if (!execution.id) {
|
|
@@ -48376,6 +48461,9 @@ var import_code_interpreter = __toESM(require_dist4());
|
|
|
48376
48461
|
class E2BAdapter extends BaseSandboxAdapter {
|
|
48377
48462
|
config;
|
|
48378
48463
|
provider = "e2b";
|
|
48464
|
+
get rootPath() {
|
|
48465
|
+
return "/home/user";
|
|
48466
|
+
}
|
|
48379
48467
|
sandbox = null;
|
|
48380
48468
|
_id;
|
|
48381
48469
|
constructor(config) {
|
|
@@ -48505,7 +48593,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48505
48593
|
try {
|
|
48506
48594
|
const sandbox = await this.ensureSandbox();
|
|
48507
48595
|
const result = await sandbox.commands.run(command, {
|
|
48508
|
-
cwd: options?.workingDirectory,
|
|
48596
|
+
cwd: this.normalizePath(options?.workingDirectory),
|
|
48509
48597
|
timeoutMs: options?.timeoutMs
|
|
48510
48598
|
});
|
|
48511
48599
|
return {
|
|
@@ -48528,7 +48616,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48528
48616
|
const sandbox = await this.ensureSandbox();
|
|
48529
48617
|
try {
|
|
48530
48618
|
const results = [];
|
|
48531
|
-
for (const path of paths) {
|
|
48619
|
+
for (const path of paths.map((p) => this.normalizePath(p))) {
|
|
48532
48620
|
try {
|
|
48533
48621
|
const content = await sandbox.files.read(path);
|
|
48534
48622
|
results.push({
|
|
@@ -48565,7 +48653,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48565
48653
|
data = "";
|
|
48566
48654
|
}
|
|
48567
48655
|
return {
|
|
48568
|
-
path: f.path,
|
|
48656
|
+
path: this.normalizePath(f.path),
|
|
48569
48657
|
data
|
|
48570
48658
|
};
|
|
48571
48659
|
});
|
|
@@ -48604,7 +48692,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48604
48692
|
const sandbox = await this.ensureSandbox();
|
|
48605
48693
|
try {
|
|
48606
48694
|
const results = [];
|
|
48607
|
-
for (const path of paths) {
|
|
48695
|
+
for (const path of paths.map((p) => this.normalizePath(p))) {
|
|
48608
48696
|
try {
|
|
48609
48697
|
await sandbox.files.remove(path);
|
|
48610
48698
|
results.push({
|
|
@@ -48629,7 +48717,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48629
48717
|
const sandbox = await this.ensureSandbox();
|
|
48630
48718
|
try {
|
|
48631
48719
|
for (const { source, destination } of moves) {
|
|
48632
|
-
await sandbox.files.rename(source, destination);
|
|
48720
|
+
await sandbox.files.rename(this.normalizePath(source), this.normalizePath(destination));
|
|
48633
48721
|
}
|
|
48634
48722
|
} catch (error) {
|
|
48635
48723
|
throw new CommandExecutionError("Failed to move files", "moveFiles", error instanceof Error ? error : undefined);
|
|
@@ -48638,7 +48726,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48638
48726
|
async createDirectories(paths) {
|
|
48639
48727
|
const sandbox = await this.ensureSandbox();
|
|
48640
48728
|
try {
|
|
48641
|
-
for (const path of paths) {
|
|
48729
|
+
for (const path of paths.map((p) => this.normalizePath(p))) {
|
|
48642
48730
|
await sandbox.files.makeDir(path);
|
|
48643
48731
|
}
|
|
48644
48732
|
} catch (error) {
|
|
@@ -48648,7 +48736,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48648
48736
|
async deleteDirectories(paths) {
|
|
48649
48737
|
const sandbox = await this.ensureSandbox();
|
|
48650
48738
|
try {
|
|
48651
|
-
for (const path of paths) {
|
|
48739
|
+
for (const path of paths.map((p) => this.normalizePath(p))) {
|
|
48652
48740
|
await sandbox.files.remove(path);
|
|
48653
48741
|
}
|
|
48654
48742
|
} catch (error) {
|
|
@@ -48658,7 +48746,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48658
48746
|
async listDirectory(path) {
|
|
48659
48747
|
const sandbox = await this.ensureSandbox();
|
|
48660
48748
|
try {
|
|
48661
|
-
const entries = await sandbox.files.list(path);
|
|
48749
|
+
const entries = await sandbox.files.list(this.normalizePath(path));
|
|
48662
48750
|
return entries.map((entry) => {
|
|
48663
48751
|
const isDirectory = entry.type === import_code_interpreter.FileType.DIR;
|
|
48664
48752
|
return {
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -47490,6 +47490,19 @@ class BaseSandboxAdapter {
|
|
|
47490
47490
|
_status = { state: "Creating" };
|
|
47491
47491
|
polyfillService;
|
|
47492
47492
|
constructor() {}
|
|
47493
|
+
get rootPath() {
|
|
47494
|
+
return "/";
|
|
47495
|
+
}
|
|
47496
|
+
normalizePath(path = "") {
|
|
47497
|
+
if (path === "." || path === "./")
|
|
47498
|
+
return this.rootPath;
|
|
47499
|
+
const root = this.rootPath.replace(/\/+$/, "");
|
|
47500
|
+
if (path.startsWith("./"))
|
|
47501
|
+
return `${root}/${path.slice(2)}`;
|
|
47502
|
+
if (!path.startsWith("/"))
|
|
47503
|
+
return `${root}/${path}`;
|
|
47504
|
+
return path;
|
|
47505
|
+
}
|
|
47493
47506
|
get status() {
|
|
47494
47507
|
return this._status;
|
|
47495
47508
|
}
|
|
@@ -47503,7 +47516,19 @@ class BaseSandboxAdapter {
|
|
|
47503
47516
|
}
|
|
47504
47517
|
await this.sleep(checkInterval);
|
|
47505
47518
|
}
|
|
47506
|
-
throw new SandboxReadyTimeoutError(this.id, timeoutMs);
|
|
47519
|
+
throw new SandboxReadyTimeoutError(this.id ?? "Unknown", timeoutMs);
|
|
47520
|
+
}
|
|
47521
|
+
async waitUntilDeleted(timeoutMs = 120000) {
|
|
47522
|
+
const startTime = Date.now();
|
|
47523
|
+
const checkInterval = 1000;
|
|
47524
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
47525
|
+
const data = await this.getInfo().catch(() => true);
|
|
47526
|
+
if (!data) {
|
|
47527
|
+
return;
|
|
47528
|
+
}
|
|
47529
|
+
await this.sleep(checkInterval);
|
|
47530
|
+
}
|
|
47531
|
+
throw new SandboxReadyTimeoutError(this.id ?? "Unknown", timeoutMs);
|
|
47507
47532
|
}
|
|
47508
47533
|
async renewExpiration(_additionalSeconds) {
|
|
47509
47534
|
throw new FeatureNotSupportedError("Sandbox expiration renewal not supported by this provider", "renewExpiration", this.provider);
|
|
@@ -47529,7 +47554,7 @@ class BaseSandboxAdapter {
|
|
|
47529
47554
|
async readFiles(paths, options) {
|
|
47530
47555
|
const polyfillService = this.requirePolyfillService("readFiles", "File read not supported by this provider");
|
|
47531
47556
|
const results = [];
|
|
47532
|
-
for (const path of paths) {
|
|
47557
|
+
for (const path of paths.map((p) => this.normalizePath(p))) {
|
|
47533
47558
|
try {
|
|
47534
47559
|
let content;
|
|
47535
47560
|
if (options?.range) {
|
|
@@ -47557,7 +47582,7 @@ class BaseSandboxAdapter {
|
|
|
47557
47582
|
async writeFiles(entries) {
|
|
47558
47583
|
const polyfillService = this.requirePolyfillService("writeFiles", "File write not supported by this provider");
|
|
47559
47584
|
const results = [];
|
|
47560
|
-
for (const entry of entries) {
|
|
47585
|
+
for (const entry of entries.map((e) => ({ ...e, path: this.normalizePath(e.path) }))) {
|
|
47561
47586
|
try {
|
|
47562
47587
|
let bytesWritten;
|
|
47563
47588
|
if (typeof entry.data === "string") {
|
|
@@ -47601,7 +47626,7 @@ class BaseSandboxAdapter {
|
|
|
47601
47626
|
}
|
|
47602
47627
|
async deleteFiles(paths) {
|
|
47603
47628
|
const polyfillService = this.requirePolyfillService("deleteFiles", "File delete not supported by this provider");
|
|
47604
|
-
const polyfillResults = await polyfillService.deleteFiles(paths);
|
|
47629
|
+
const polyfillResults = await polyfillService.deleteFiles(paths.map((p) => this.normalizePath(p)));
|
|
47605
47630
|
return polyfillResults.map((r) => ({
|
|
47606
47631
|
path: r.path,
|
|
47607
47632
|
success: r.success,
|
|
@@ -47610,7 +47635,10 @@ class BaseSandboxAdapter {
|
|
|
47610
47635
|
}
|
|
47611
47636
|
async moveFiles(entries) {
|
|
47612
47637
|
const polyfillService = this.requirePolyfillService("moveFiles", "File move not supported by this provider");
|
|
47613
|
-
await polyfillService.moveFiles(entries.map((e) => ({
|
|
47638
|
+
await polyfillService.moveFiles(entries.map((e) => ({
|
|
47639
|
+
source: this.normalizePath(e.source),
|
|
47640
|
+
destination: this.normalizePath(e.destination)
|
|
47641
|
+
})));
|
|
47614
47642
|
}
|
|
47615
47643
|
async replaceContent(entries) {
|
|
47616
47644
|
const polyfillService = this.requirePolyfillService("replaceContent", "Content replace not supported by this provider");
|
|
@@ -47618,15 +47646,15 @@ class BaseSandboxAdapter {
|
|
|
47618
47646
|
}
|
|
47619
47647
|
async createDirectories(paths, options) {
|
|
47620
47648
|
const polyfillService = this.requirePolyfillService("createDirectories", "Directory creation not supported by this provider");
|
|
47621
|
-
await polyfillService.createDirectories(paths, options);
|
|
47649
|
+
await polyfillService.createDirectories(paths.map((p) => this.normalizePath(p)), options);
|
|
47622
47650
|
}
|
|
47623
47651
|
async deleteDirectories(paths, options) {
|
|
47624
47652
|
const polyfillService = this.requirePolyfillService("deleteDirectories", "Directory deletion not supported by this provider");
|
|
47625
|
-
await polyfillService.deleteDirectories(paths, options);
|
|
47653
|
+
await polyfillService.deleteDirectories(paths.map((p) => this.normalizePath(p)), options);
|
|
47626
47654
|
}
|
|
47627
47655
|
async listDirectory(path) {
|
|
47628
47656
|
const polyfillService = this.requirePolyfillService("listDirectory", "Directory listing not supported by this provider");
|
|
47629
|
-
return polyfillService.listDirectory(path);
|
|
47657
|
+
return polyfillService.listDirectory(this.normalizePath(path));
|
|
47630
47658
|
}
|
|
47631
47659
|
async* readFileStream(path) {
|
|
47632
47660
|
this.requirePolyfillService("readFileStream", "File stream read not supported by this provider");
|
|
@@ -47678,7 +47706,7 @@ class BaseSandboxAdapter {
|
|
|
47678
47706
|
}
|
|
47679
47707
|
async getFileInfo(paths) {
|
|
47680
47708
|
const polyfillService = this.requirePolyfillService("getFileInfo", "File info not supported by this provider");
|
|
47681
|
-
return polyfillService.getFileInfo(paths);
|
|
47709
|
+
return polyfillService.getFileInfo(paths.map((p) => this.normalizePath(p)));
|
|
47682
47710
|
}
|
|
47683
47711
|
async setPermissions(entries) {
|
|
47684
47712
|
const polyfillService = this.requirePolyfillService("setPermissions", "Permission setting not supported by this provider");
|
|
@@ -47686,7 +47714,7 @@ class BaseSandboxAdapter {
|
|
|
47686
47714
|
}
|
|
47687
47715
|
async search(pattern, path) {
|
|
47688
47716
|
const polyfillService = this.requirePolyfillService("search", "File search not supported by this provider");
|
|
47689
|
-
return polyfillService.search(pattern, path);
|
|
47717
|
+
return polyfillService.search(pattern, path !== undefined ? this.normalizePath(path) : path);
|
|
47690
47718
|
}
|
|
47691
47719
|
async ping() {
|
|
47692
47720
|
const polyfillService = this.requirePolyfillService("ping", "Health check not supported by this provider");
|
|
@@ -47809,6 +47837,9 @@ class DevboxApi {
|
|
|
47809
47837
|
class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
47810
47838
|
config;
|
|
47811
47839
|
provider = "sealosdevbox";
|
|
47840
|
+
get rootPath() {
|
|
47841
|
+
return "/home/devbox/workspace";
|
|
47842
|
+
}
|
|
47812
47843
|
api;
|
|
47813
47844
|
_id;
|
|
47814
47845
|
constructor(config) {
|
|
@@ -47838,18 +47869,6 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
|
47838
47869
|
return "Error";
|
|
47839
47870
|
}
|
|
47840
47871
|
}
|
|
47841
|
-
async waitUntilDeleted() {
|
|
47842
|
-
const startTime = Date.now();
|
|
47843
|
-
const checkInterval = 1000;
|
|
47844
|
-
while (Date.now() - startTime < 120000) {
|
|
47845
|
-
const data = await this.getInfo().catch(() => true);
|
|
47846
|
-
if (!data) {
|
|
47847
|
-
return;
|
|
47848
|
-
}
|
|
47849
|
-
await this.sleep(checkInterval);
|
|
47850
|
-
}
|
|
47851
|
-
throw new TimeoutError("Sandbox not deleted", 120000, "waitUntilDeleted");
|
|
47852
|
-
}
|
|
47853
47872
|
async getInfo() {
|
|
47854
47873
|
try {
|
|
47855
47874
|
const res = await this.api.info(this._id);
|
|
@@ -47940,7 +47959,7 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
|
47940
47959
|
}
|
|
47941
47960
|
}
|
|
47942
47961
|
async execute(command, options) {
|
|
47943
|
-
const cmd = this.buildCommand(command, options?.workingDirectory);
|
|
47962
|
+
const cmd = this.buildCommand(command, this.normalizePath(options?.workingDirectory));
|
|
47944
47963
|
try {
|
|
47945
47964
|
const res = await this.api.exec(this._id, {
|
|
47946
47965
|
command: cmd,
|
|
@@ -47979,8 +47998,8 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
47979
47998
|
runtime;
|
|
47980
47999
|
_sandbox;
|
|
47981
48000
|
_connection;
|
|
47982
|
-
_id
|
|
47983
|
-
constructor(connectionConfig
|
|
48001
|
+
_id;
|
|
48002
|
+
constructor(connectionConfig, createConfig) {
|
|
47984
48003
|
super();
|
|
47985
48004
|
this.connectionConfig = connectionConfig;
|
|
47986
48005
|
this.createConfig = createConfig;
|
|
@@ -47988,9 +48007,17 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
47988
48007
|
this._connection = this.createConnectionConfig();
|
|
47989
48008
|
this.polyfillService = new CommandPolyfillService(this);
|
|
47990
48009
|
}
|
|
48010
|
+
get rootPath() {
|
|
48011
|
+
const mountPath = this.createConfig.volumes?.[0]?.mountPath;
|
|
48012
|
+
return mountPath ? mountPath.replace(/\/+$/, "") : "/home/sandbox";
|
|
48013
|
+
}
|
|
47991
48014
|
get id() {
|
|
47992
48015
|
return this._id;
|
|
47993
48016
|
}
|
|
48017
|
+
set sandbox(sandbox) {
|
|
48018
|
+
this._sandbox = sandbox;
|
|
48019
|
+
this._id = sandbox?.id;
|
|
48020
|
+
}
|
|
47994
48021
|
get sandbox() {
|
|
47995
48022
|
if (!this._sandbox) {
|
|
47996
48023
|
throw new SandboxStateError("Sandbox not initialized. Call create() or connect() first.", "UnExist", "Running");
|
|
@@ -47999,9 +48026,6 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
47999
48026
|
}
|
|
48000
48027
|
createConnectionConfig() {
|
|
48001
48028
|
const { baseUrl, apiKey, requestTimeoutSeconds, debug, useServerProxy } = this.connectionConfig;
|
|
48002
|
-
if (!baseUrl) {
|
|
48003
|
-
return new import_opensandbox.ConnectionConfig({ apiKey, requestTimeoutSeconds, debug, useServerProxy });
|
|
48004
|
-
}
|
|
48005
48029
|
return new import_opensandbox.ConnectionConfig({
|
|
48006
48030
|
domain: baseUrl,
|
|
48007
48031
|
apiKey,
|
|
@@ -48112,32 +48136,74 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48112
48136
|
}
|
|
48113
48137
|
return 0;
|
|
48114
48138
|
}
|
|
48139
|
+
async getSandboxBySessionId() {
|
|
48140
|
+
const manager = import_opensandbox.SandboxManager.create({ connectionConfig: this._connection });
|
|
48141
|
+
const result = await manager.listSandboxInfos({
|
|
48142
|
+
metadata: { sessionId: this.connectionConfig.sessionId }
|
|
48143
|
+
});
|
|
48144
|
+
const val = result.items[0];
|
|
48145
|
+
if (val) {
|
|
48146
|
+
const status = this.mapStatus(val.status);
|
|
48147
|
+
return {
|
|
48148
|
+
id: val.id,
|
|
48149
|
+
status
|
|
48150
|
+
};
|
|
48151
|
+
}
|
|
48152
|
+
}
|
|
48115
48153
|
async ensureRunning() {
|
|
48116
|
-
|
|
48154
|
+
const sandbox = await this.getSandboxBySessionId();
|
|
48155
|
+
if (sandbox) {
|
|
48156
|
+
switch (sandbox.status.state) {
|
|
48157
|
+
case "UnExist":
|
|
48158
|
+
await this.create();
|
|
48159
|
+
break;
|
|
48160
|
+
case "Running":
|
|
48161
|
+
await this.connect(sandbox.id);
|
|
48162
|
+
break;
|
|
48163
|
+
case "Creating":
|
|
48164
|
+
case "Starting":
|
|
48165
|
+
await this.waitUntilReady();
|
|
48166
|
+
break;
|
|
48167
|
+
case "Stopping":
|
|
48168
|
+
case "Stopped":
|
|
48169
|
+
await this.resume(sandbox.id);
|
|
48170
|
+
break;
|
|
48171
|
+
case "Deleting":
|
|
48172
|
+
await this.waitUntilDeleted();
|
|
48173
|
+
await this.create();
|
|
48174
|
+
break;
|
|
48175
|
+
case "Error":
|
|
48176
|
+
throw new ConnectionError(`Sandbox error: ${sandbox.status.message}`);
|
|
48177
|
+
default:
|
|
48178
|
+
throw new ConnectionError(`Sandbox state ${sandbox.status.state} not supported`);
|
|
48179
|
+
}
|
|
48180
|
+
} else {
|
|
48181
|
+
await this.create();
|
|
48182
|
+
}
|
|
48117
48183
|
}
|
|
48118
48184
|
async create() {
|
|
48119
|
-
if (!this.createConfig) {
|
|
48120
|
-
throw new Error("createConfig is required to create a sandbox. Pass it as the third argument to createSandbox().");
|
|
48121
|
-
}
|
|
48122
48185
|
const cfg = this.createConfig;
|
|
48123
48186
|
try {
|
|
48124
48187
|
this._status = { state: "Creating" };
|
|
48125
48188
|
const image = this.convertImageSpec(cfg.image);
|
|
48126
48189
|
const resource = this.convertResourceLimits(cfg.resourceLimits);
|
|
48127
|
-
this.
|
|
48190
|
+
this.sandbox = await import_opensandbox.Sandbox.create({
|
|
48128
48191
|
connectionConfig: this._connection,
|
|
48129
48192
|
image,
|
|
48130
48193
|
entrypoint: cfg.entrypoint,
|
|
48131
48194
|
timeoutSeconds: cfg.timeoutSeconds ?? null,
|
|
48132
48195
|
resource,
|
|
48133
48196
|
env: cfg.env,
|
|
48134
|
-
metadata:
|
|
48197
|
+
metadata: {
|
|
48198
|
+
...cfg.metadata,
|
|
48199
|
+
sessionId: this.connectionConfig.sessionId
|
|
48200
|
+
},
|
|
48135
48201
|
volumes: cfg.volumes,
|
|
48136
48202
|
skipHealthCheck: cfg.skipHealthCheck,
|
|
48137
48203
|
readyTimeoutSeconds: cfg.readyTimeoutSeconds,
|
|
48138
48204
|
healthCheckPollingInterval: cfg.healthCheckPollingInterval
|
|
48139
48205
|
});
|
|
48140
|
-
|
|
48206
|
+
await this.waitUntilReady();
|
|
48141
48207
|
this._status = { state: "Running" };
|
|
48142
48208
|
} catch (error) {
|
|
48143
48209
|
this._status = { state: "Error", message: String(error) };
|
|
@@ -48147,31 +48213,51 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48147
48213
|
async connect(sandboxId) {
|
|
48148
48214
|
try {
|
|
48149
48215
|
this._status = { state: "Starting" };
|
|
48150
|
-
this.
|
|
48216
|
+
this.sandbox = await import_opensandbox.Sandbox.connect({
|
|
48151
48217
|
sandboxId,
|
|
48152
48218
|
connectionConfig: this._connection,
|
|
48153
48219
|
skipHealthCheck: this.createConfig?.skipHealthCheck,
|
|
48154
48220
|
readyTimeoutSeconds: this.createConfig?.readyTimeoutSeconds,
|
|
48155
48221
|
healthCheckPollingInterval: this.createConfig?.healthCheckPollingInterval
|
|
48156
48222
|
});
|
|
48157
|
-
this._id = this._sandbox.id;
|
|
48158
48223
|
this._status = { state: "Running" };
|
|
48159
48224
|
} catch (error) {
|
|
48160
48225
|
this._status = { state: "Error", message: String(error) };
|
|
48161
48226
|
throw new ConnectionError(`Failed to connect to sandbox ${sandboxId}`, this.connectionConfig.baseUrl, error);
|
|
48162
48227
|
}
|
|
48163
48228
|
}
|
|
48229
|
+
async resume(sandboxId) {
|
|
48230
|
+
try {
|
|
48231
|
+
this._status = { state: "Starting" };
|
|
48232
|
+
this.sandbox = await import_opensandbox.Sandbox.resume({
|
|
48233
|
+
sandboxId,
|
|
48234
|
+
connectionConfig: this._connection,
|
|
48235
|
+
skipHealthCheck: this.createConfig?.skipHealthCheck,
|
|
48236
|
+
readyTimeoutSeconds: this.createConfig?.readyTimeoutSeconds,
|
|
48237
|
+
healthCheckPollingInterval: this.createConfig?.healthCheckPollingInterval
|
|
48238
|
+
});
|
|
48239
|
+
this._status = { state: "Running" };
|
|
48240
|
+
} catch (error) {
|
|
48241
|
+
this._status = { state: "Error", message: String(error) };
|
|
48242
|
+
throw new ConnectionError(`Failed to resume sandbox ${sandboxId}`, this.connectionConfig.baseUrl, error);
|
|
48243
|
+
}
|
|
48244
|
+
}
|
|
48164
48245
|
async start() {
|
|
48165
48246
|
try {
|
|
48166
48247
|
this._status = { state: "Starting" };
|
|
48167
|
-
this.
|
|
48168
|
-
|
|
48248
|
+
this.sandbox = await this.sandbox.resume();
|
|
48249
|
+
await this.waitUntilReady();
|
|
48169
48250
|
this._status = { state: "Running" };
|
|
48170
48251
|
} catch (error) {
|
|
48171
|
-
|
|
48172
|
-
|
|
48252
|
+
const code = error instanceof import_opensandbox.SandboxException ? error.error.code : undefined;
|
|
48253
|
+
switch (code) {
|
|
48254
|
+
case "DOCKER::SANDBOX_NOT_PAUSED":
|
|
48255
|
+
return;
|
|
48256
|
+
case "SANDBOX::API_NOT_SUPPORTED":
|
|
48257
|
+
throw new FeatureNotSupportedError("Start/resume not supported by this runtime", "start", this.provider);
|
|
48258
|
+
default:
|
|
48259
|
+
throw new CommandExecutionError("Failed to start sandbox", "start", error instanceof Error ? error : undefined);
|
|
48173
48260
|
}
|
|
48174
|
-
throw new CommandExecutionError("Failed to start sandbox", "start", error instanceof Error ? error : undefined);
|
|
48175
48261
|
}
|
|
48176
48262
|
}
|
|
48177
48263
|
async stop() {
|
|
@@ -48180,6 +48266,10 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48180
48266
|
await this.sandbox.pause();
|
|
48181
48267
|
this._status = { state: "Stopped" };
|
|
48182
48268
|
} catch (error) {
|
|
48269
|
+
const message = error instanceof import_opensandbox.SandboxException ? error.error.message : undefined;
|
|
48270
|
+
if (message?.includes("already paused")) {
|
|
48271
|
+
return;
|
|
48272
|
+
}
|
|
48183
48273
|
if (error && typeof error === "object" && "code" in error && error.code === "SANDBOX::API_NOT_SUPPORTED") {
|
|
48184
48274
|
throw new FeatureNotSupportedError("Stop/pause not supported by this runtime", "stop", this.provider);
|
|
48185
48275
|
}
|
|
@@ -48190,43 +48280,38 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48190
48280
|
try {
|
|
48191
48281
|
this._status = { state: "Deleting" };
|
|
48192
48282
|
await this.sandbox.kill();
|
|
48193
|
-
this.
|
|
48194
|
-
this._id = "";
|
|
48283
|
+
this.sandbox = undefined;
|
|
48195
48284
|
this._status = { state: "UnExist" };
|
|
48196
48285
|
} catch (error) {
|
|
48197
48286
|
throw new CommandExecutionError("Failed to delete sandbox", "delete", error instanceof Error ? error : undefined);
|
|
48198
48287
|
}
|
|
48199
48288
|
}
|
|
48200
48289
|
async close() {
|
|
48201
|
-
|
|
48202
|
-
await this._sandbox.close();
|
|
48203
|
-
}
|
|
48290
|
+
await this.sandbox.close();
|
|
48204
48291
|
}
|
|
48205
48292
|
async getEndpoint(port) {
|
|
48206
48293
|
const sdkEndpoint = await this.sandbox.getEndpoint(port);
|
|
48207
|
-
return this.convertSdkEndpoint(sdkEndpoint, port);
|
|
48208
|
-
}
|
|
48209
|
-
convertSdkEndpoint(sdkEndpoint, requestedPort) {
|
|
48210
48294
|
const raw = sdkEndpoint.endpoint;
|
|
48211
48295
|
const colonIdx = raw.lastIndexOf(":");
|
|
48212
48296
|
const hasPathBeforeColon = colonIdx !== -1 && raw.slice(0, colonIdx).includes("/");
|
|
48213
48297
|
if (colonIdx !== -1 && !hasPathBeforeColon) {
|
|
48214
48298
|
const host = raw.slice(0, colonIdx);
|
|
48215
48299
|
const parsedPort = parseInt(raw.slice(colonIdx + 1), 10);
|
|
48216
|
-
const
|
|
48300
|
+
const portNumber = isNaN(parsedPort) ? port : parsedPort;
|
|
48217
48301
|
const protocol = port === 443 ? "https" : "http";
|
|
48218
|
-
return { host, port, protocol, url: `${protocol}://${raw}` };
|
|
48302
|
+
return { host, port: portNumber, protocol, url: `${protocol}://${raw}` };
|
|
48219
48303
|
}
|
|
48220
48304
|
return {
|
|
48221
48305
|
host: raw,
|
|
48222
|
-
port
|
|
48306
|
+
port,
|
|
48223
48307
|
protocol: "https",
|
|
48224
48308
|
url: `https://${raw}`
|
|
48225
48309
|
};
|
|
48226
48310
|
}
|
|
48227
48311
|
async getInfo() {
|
|
48228
|
-
if (!this._sandbox)
|
|
48312
|
+
if (!this._sandbox) {
|
|
48229
48313
|
return null;
|
|
48314
|
+
}
|
|
48230
48315
|
try {
|
|
48231
48316
|
const info = await this.sandbox.getInfo();
|
|
48232
48317
|
return {
|
|
@@ -48253,7 +48338,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48253
48338
|
async execute(command, options) {
|
|
48254
48339
|
try {
|
|
48255
48340
|
const execution = await this.sandbox.commands.run(command, {
|
|
48256
|
-
workingDirectory: options?.workingDirectory,
|
|
48341
|
+
workingDirectory: this.normalizePath(options?.workingDirectory),
|
|
48257
48342
|
background: options?.background
|
|
48258
48343
|
});
|
|
48259
48344
|
const stdout = execution.logs.stdout.map((msg) => msg.text).join(`
|
|
@@ -48290,7 +48375,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48290
48375
|
} : {}
|
|
48291
48376
|
};
|
|
48292
48377
|
const execution = await this.sandbox.commands.run(command, {
|
|
48293
|
-
workingDirectory: options?.workingDirectory,
|
|
48378
|
+
workingDirectory: this.normalizePath(options?.workingDirectory),
|
|
48294
48379
|
background: options?.background
|
|
48295
48380
|
}, sdkHandlers);
|
|
48296
48381
|
if (handlers.onComplete) {
|
|
@@ -48312,7 +48397,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48312
48397
|
async executeBackground(command, options) {
|
|
48313
48398
|
try {
|
|
48314
48399
|
const execution = await this.sandbox.commands.run(command, {
|
|
48315
|
-
workingDirectory: options?.workingDirectory,
|
|
48400
|
+
workingDirectory: this.normalizePath(options?.workingDirectory),
|
|
48316
48401
|
background: true
|
|
48317
48402
|
});
|
|
48318
48403
|
if (!execution.id) {
|
|
@@ -48360,6 +48445,9 @@ var import_code_interpreter = __toESM(require_dist4(), 1);
|
|
|
48360
48445
|
class E2BAdapter extends BaseSandboxAdapter {
|
|
48361
48446
|
config;
|
|
48362
48447
|
provider = "e2b";
|
|
48448
|
+
get rootPath() {
|
|
48449
|
+
return "/home/user";
|
|
48450
|
+
}
|
|
48363
48451
|
sandbox = null;
|
|
48364
48452
|
_id;
|
|
48365
48453
|
constructor(config) {
|
|
@@ -48489,7 +48577,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48489
48577
|
try {
|
|
48490
48578
|
const sandbox = await this.ensureSandbox();
|
|
48491
48579
|
const result = await sandbox.commands.run(command, {
|
|
48492
|
-
cwd: options?.workingDirectory,
|
|
48580
|
+
cwd: this.normalizePath(options?.workingDirectory),
|
|
48493
48581
|
timeoutMs: options?.timeoutMs
|
|
48494
48582
|
});
|
|
48495
48583
|
return {
|
|
@@ -48512,7 +48600,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48512
48600
|
const sandbox = await this.ensureSandbox();
|
|
48513
48601
|
try {
|
|
48514
48602
|
const results = [];
|
|
48515
|
-
for (const path of paths) {
|
|
48603
|
+
for (const path of paths.map((p) => this.normalizePath(p))) {
|
|
48516
48604
|
try {
|
|
48517
48605
|
const content = await sandbox.files.read(path);
|
|
48518
48606
|
results.push({
|
|
@@ -48549,7 +48637,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48549
48637
|
data = "";
|
|
48550
48638
|
}
|
|
48551
48639
|
return {
|
|
48552
|
-
path: f.path,
|
|
48640
|
+
path: this.normalizePath(f.path),
|
|
48553
48641
|
data
|
|
48554
48642
|
};
|
|
48555
48643
|
});
|
|
@@ -48588,7 +48676,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48588
48676
|
const sandbox = await this.ensureSandbox();
|
|
48589
48677
|
try {
|
|
48590
48678
|
const results = [];
|
|
48591
|
-
for (const path of paths) {
|
|
48679
|
+
for (const path of paths.map((p) => this.normalizePath(p))) {
|
|
48592
48680
|
try {
|
|
48593
48681
|
await sandbox.files.remove(path);
|
|
48594
48682
|
results.push({
|
|
@@ -48613,7 +48701,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48613
48701
|
const sandbox = await this.ensureSandbox();
|
|
48614
48702
|
try {
|
|
48615
48703
|
for (const { source, destination } of moves) {
|
|
48616
|
-
await sandbox.files.rename(source, destination);
|
|
48704
|
+
await sandbox.files.rename(this.normalizePath(source), this.normalizePath(destination));
|
|
48617
48705
|
}
|
|
48618
48706
|
} catch (error) {
|
|
48619
48707
|
throw new CommandExecutionError("Failed to move files", "moveFiles", error instanceof Error ? error : undefined);
|
|
@@ -48622,7 +48710,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48622
48710
|
async createDirectories(paths) {
|
|
48623
48711
|
const sandbox = await this.ensureSandbox();
|
|
48624
48712
|
try {
|
|
48625
|
-
for (const path of paths) {
|
|
48713
|
+
for (const path of paths.map((p) => this.normalizePath(p))) {
|
|
48626
48714
|
await sandbox.files.makeDir(path);
|
|
48627
48715
|
}
|
|
48628
48716
|
} catch (error) {
|
|
@@ -48632,7 +48720,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48632
48720
|
async deleteDirectories(paths) {
|
|
48633
48721
|
const sandbox = await this.ensureSandbox();
|
|
48634
48722
|
try {
|
|
48635
|
-
for (const path of paths) {
|
|
48723
|
+
for (const path of paths.map((p) => this.normalizePath(p))) {
|
|
48636
48724
|
await sandbox.files.remove(path);
|
|
48637
48725
|
}
|
|
48638
48726
|
} catch (error) {
|
|
@@ -48642,7 +48730,7 @@ class E2BAdapter extends BaseSandboxAdapter {
|
|
|
48642
48730
|
async listDirectory(path) {
|
|
48643
48731
|
const sandbox = await this.ensureSandbox();
|
|
48644
48732
|
try {
|
|
48645
|
-
const entries = await sandbox.files.list(path);
|
|
48733
|
+
const entries = await sandbox.files.list(this.normalizePath(path));
|
|
48646
48734
|
return entries.map((entry) => {
|
|
48647
48735
|
const isDirectory = entry.type === import_code_interpreter.FileType.DIR;
|
|
48648
48736
|
return {
|
|
@@ -5,7 +5,7 @@ import type { SandboxId, SandboxInfo, SandboxStatus } from '../types';
|
|
|
5
5
|
*/
|
|
6
6
|
export interface ISandboxLifecycle {
|
|
7
7
|
/** Unique identifier for this sandbox */
|
|
8
|
-
readonly id
|
|
8
|
+
readonly id?: SandboxId;
|
|
9
9
|
/** Current status of the sandbox */
|
|
10
10
|
readonly status: SandboxStatus;
|
|
11
11
|
/**
|
|
@@ -39,6 +39,7 @@ export interface ISandboxLifecycle {
|
|
|
39
39
|
* @throws {SandboxReadyTimeoutError} If timeout is exceeded
|
|
40
40
|
*/
|
|
41
41
|
waitUntilReady(timeoutMs?: number): Promise<void>;
|
|
42
|
+
waitUntilDeleted(timeoutMs?: number): Promise<void>;
|
|
42
43
|
/**
|
|
43
44
|
* Renew the sandbox expiration, extending its lifetime.
|
|
44
45
|
* Not all providers support this.
|
package/package.json
CHANGED