@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.
@@ -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: SandboxId;
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>;
@@ -9,6 +9,7 @@ import type { E2BConfig } from './type';
9
9
  export declare class E2BAdapter extends BaseSandboxAdapter {
10
10
  private config;
11
11
  readonly provider: "e2b";
12
+ get rootPath(): string;
12
13
  private sandbox;
13
14
  private _id;
14
15
  constructor(config: E2BConfig);
@@ -4,7 +4,7 @@
4
4
  export interface E2BConfig {
5
5
  /** E2B API Key */
6
6
  apiKey: string;
7
- /** 可选的沙盒 ID,用于连接到已存在的沙盒 */
7
+ /** 的沙盒 ID,用于连接到已存在的沙盒 */
8
8
  sandboxId: string;
9
9
  /** 可选的模板 ID,用于创建新沙盒 */
10
10
  template?: string;
@@ -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?: string;
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?: OpenSandboxConnectionConfig, createConfig?: OpenSandboxConfigType | undefined);
60
- get id(): SandboxId;
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) => ({ source: e.source, destination: e.destination })));
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 = {}, createConfig) {
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
- return this.create();
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._sandbox = await import_opensandbox.Sandbox.create({
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: cfg.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
- this._id = this._sandbox.id;
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._sandbox = await import_opensandbox.Sandbox.connect({
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._sandbox = await this.sandbox.resume();
48184
- this._id = this.sandbox.id;
48264
+ this.sandbox = await this.sandbox.resume();
48265
+ await this.waitUntilReady();
48185
48266
  this._status = { state: "Running" };
48186
48267
  } catch (error) {
48187
- if (error && typeof error === "object" && "code" in error && error.code === "SANDBOX::API_NOT_SUPPORTED") {
48188
- throw new FeatureNotSupportedError("Start/resume not supported by this runtime", "start", this.provider);
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._sandbox = undefined;
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
- if (this._sandbox) {
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 port = isNaN(parsedPort) ? requestedPort : parsedPort;
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: requestedPort,
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
@@ -2,3 +2,4 @@ export * from './adapters';
2
2
  export * from './errors';
3
3
  export * from './interfaces';
4
4
  export * from './types';
5
+ export type { Volume as SandboxVolume } from '../opensandbox';
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) => ({ source: e.source, destination: e.destination })));
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 = {}, createConfig) {
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
- return this.create();
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._sandbox = await import_opensandbox.Sandbox.create({
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: cfg.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
- this._id = this._sandbox.id;
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._sandbox = await import_opensandbox.Sandbox.connect({
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._sandbox = await this.sandbox.resume();
48168
- this._id = this.sandbox.id;
48248
+ this.sandbox = await this.sandbox.resume();
48249
+ await this.waitUntilReady();
48169
48250
  this._status = { state: "Running" };
48170
48251
  } catch (error) {
48171
- if (error && typeof error === "object" && "code" in error && error.code === "SANDBOX::API_NOT_SUPPORTED") {
48172
- throw new FeatureNotSupportedError("Start/resume not supported by this runtime", "start", this.provider);
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._sandbox = undefined;
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
- if (this._sandbox) {
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 port = isNaN(parsedPort) ? requestedPort : parsedPort;
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: requestedPort,
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: SandboxId;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastgpt-sdk/sandbox-adapter",
3
- "version": "0.0.31",
3
+ "version": "0.0.33",
4
4
  "description": "Unified abstraction layer for cloud sandbox providers with adapter pattern and feature polyfilling",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",