@fastgpt-sdk/sandbox-adapter 0.0.35 → 0.0.37

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/index.js CHANGED
@@ -5,39 +5,60 @@ var __defProp = Object.defineProperty;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ function __accessProp(key) {
9
+ return this[key];
10
+ }
11
+ var __toESMCache_node;
12
+ var __toESMCache_esm;
8
13
  var __toESM = (mod, isNodeMode, target) => {
14
+ var canCache = mod != null && typeof mod === "object";
15
+ if (canCache) {
16
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
17
+ var cached = cache.get(mod);
18
+ if (cached)
19
+ return cached;
20
+ }
9
21
  target = mod != null ? __create(__getProtoOf(mod)) : {};
10
22
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
23
  for (let key of __getOwnPropNames(mod))
12
24
  if (!__hasOwnProp.call(to, key))
13
25
  __defProp(to, key, {
14
- get: () => mod[key],
26
+ get: __accessProp.bind(mod, key),
15
27
  enumerable: true
16
28
  });
29
+ if (canCache)
30
+ cache.set(mod, to);
17
31
  return to;
18
32
  };
19
- var __moduleCache = /* @__PURE__ */ new WeakMap;
20
33
  var __toCommonJS = (from) => {
21
- var entry = __moduleCache.get(from), desc;
34
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
22
35
  if (entry)
23
36
  return entry;
24
37
  entry = __defProp({}, "__esModule", { value: true });
25
- if (from && typeof from === "object" || typeof from === "function")
26
- __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
27
- get: () => from[key],
28
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
29
- }));
38
+ if (from && typeof from === "object" || typeof from === "function") {
39
+ for (var key of __getOwnPropNames(from))
40
+ if (!__hasOwnProp.call(entry, key))
41
+ __defProp(entry, key, {
42
+ get: __accessProp.bind(from, key),
43
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
44
+ });
45
+ }
30
46
  __moduleCache.set(from, entry);
31
47
  return entry;
32
48
  };
49
+ var __moduleCache;
33
50
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
51
+ var __returnValue = (v) => v;
52
+ function __exportSetter(name, newValue) {
53
+ this[name] = __returnValue.bind(null, newValue);
54
+ }
34
55
  var __export = (target, all) => {
35
56
  for (var name in all)
36
57
  __defProp(target, name, {
37
58
  get: all[name],
38
59
  enumerable: true,
39
60
  configurable: true,
40
- set: (newValue) => all[name] = () => newValue
61
+ set: __exportSetter.bind(all, name)
41
62
  });
42
63
  };
43
64
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -19141,7 +19162,7 @@ var require_frame = __commonJS((exports, module) => {
19141
19162
  var BUFFER_SIZE = 8 * 1024;
19142
19163
  var buffer = null;
19143
19164
  var bufIdx = BUFFER_SIZE;
19144
- var randomFillSync = runtimeFeatures.has("crypto") ? __require("node:crypto").randomFillSync : function randomFillSync(buffer2, _offset, _size) {
19165
+ var randomFillSync = runtimeFeatures.has("crypto") ? __require("node:crypto").randomFillSync : function randomFillSync2(buffer2, _offset, _size) {
19145
19166
  for (let i = 0;i < buffer2.length; ++i) {
19146
19167
  buffer2[i] = Math.random() * 255 | 0;
19147
19168
  }
@@ -21085,7 +21106,7 @@ var require_eventsource = __commonJS((exports, module) => {
21085
21106
 
21086
21107
  // node_modules/undici/index.js
21087
21108
  var require_undici = __commonJS((exports, module) => {
21088
- var __filename = "/Volumes/code/dev/agent-sandbox-adaptor/node_modules/undici/index.js";
21109
+ var __filename = "/Users/sealos/Documents/GitHub/agent-sandbox-adaptor/node_modules/undici/index.js";
21089
21110
  var Client = require_client();
21090
21111
  var Dispatcher = require_dispatcher();
21091
21112
  var Pool = require_pool();
@@ -21208,7 +21229,7 @@ var require_undici = __commonJS((exports, module) => {
21208
21229
  err.stack = stack ? `${stack}
21209
21230
  ${captureLines}` : capture.stack;
21210
21231
  }
21211
- exports.fetch = function fetch(init, options = undefined) {
21232
+ exports.fetch = function fetch2(init, options = undefined) {
21212
21233
  return fetchImpl(init, options).catch((err) => {
21213
21234
  appendFetchStackTrace(err, __filename);
21214
21235
  throw err;
@@ -45007,13 +45028,34 @@ class CommandPolyfillService {
45007
45028
  constructor(executor) {
45008
45029
  this.executor = executor;
45009
45030
  }
45031
+ static READ_CHUNK_SIZE = 256 * 1024;
45010
45032
  async readFile(path) {
45011
45033
  try {
45012
- const result = await this.executor.execute(`cat "${this.escapePath(path)}" | base64 -w 0`);
45013
- if (result.exitCode !== 0) {
45014
- throw this.createFileError(path, result.stderr);
45034
+ const size = await this.statSize(path);
45035
+ if (size === undefined) {
45036
+ const result = await this.executor.execute(`cat "${this.escapePath(path)}" | base64 -w 0`);
45037
+ if (result.exitCode !== 0) {
45038
+ throw this.createFileError(path, result.stderr);
45039
+ }
45040
+ return base64ToBytes(result.stdout);
45041
+ }
45042
+ if (size === 0)
45043
+ return new Uint8Array;
45044
+ const chunks = [];
45045
+ let totalLength = 0;
45046
+ for (let offset = 0;offset < size; offset += CommandPolyfillService.READ_CHUNK_SIZE) {
45047
+ const end = Math.min(offset + CommandPolyfillService.READ_CHUNK_SIZE, size);
45048
+ const chunk = await this.readFileRange(path, offset, end);
45049
+ chunks.push(chunk);
45050
+ totalLength += chunk.length;
45015
45051
  }
45016
- return base64ToBytes(result.stdout);
45052
+ const combined = new Uint8Array(totalLength);
45053
+ let writeOffset = 0;
45054
+ for (const chunk of chunks) {
45055
+ combined.set(chunk, writeOffset);
45056
+ writeOffset += chunk.length;
45057
+ }
45058
+ return combined;
45017
45059
  } catch (error) {
45018
45060
  if (error instanceof FileOperationError) {
45019
45061
  throw error;
@@ -45024,9 +45066,18 @@ class CommandPolyfillService {
45024
45066
  throw error;
45025
45067
  }
45026
45068
  }
45069
+ async statSize(path) {
45070
+ const result = await this.executor.execute(`stat -c '%s' "${this.escapePath(path)}" 2>/dev/null || stat -f '%z' "${this.escapePath(path)}" 2>/dev/null || echo STAT_FAILED`);
45071
+ const stdout = result.stdout.trim();
45072
+ if (!stdout || stdout.includes("STAT_FAILED"))
45073
+ return;
45074
+ const parsed = Number.parseInt(stdout, 10);
45075
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : undefined;
45076
+ }
45027
45077
  async readFileRange(path, start, end) {
45028
- const length = end ? end - start : "";
45029
- const cmd = `dd if="${this.escapePath(path)}" bs=1 skip=${start} count=${length} 2>/dev/null | base64 -w 0`;
45078
+ const escaped = this.escapePath(path);
45079
+ const tailPos = start + 1;
45080
+ const cmd = end !== undefined ? `tail -c +${tailPos} "${escaped}" | head -c ${end - start} | base64 -w 0` : `tail -c +${tailPos} "${escaped}" | base64 -w 0`;
45030
45081
  const result = await this.executor.execute(cmd);
45031
45082
  if (result.exitCode !== 0) {
45032
45083
  throw this.createFileError(path, result.stderr);
@@ -45034,10 +45085,25 @@ class CommandPolyfillService {
45034
45085
  return base64ToBytes(result.stdout);
45035
45086
  }
45036
45087
  async writeFile(path, data) {
45088
+ await this.appendBytes(path, data, { truncate: true });
45089
+ return data.length;
45090
+ }
45091
+ async appendBytes(path, data, options) {
45092
+ if (options?.truncate) {
45093
+ await this.createParentDirectory(path);
45094
+ }
45095
+ if (data.length === 0) {
45096
+ if (options?.truncate) {
45097
+ const result = await this.executor.execute(`: > "${this.escapePath(path)}"`);
45098
+ if (result.exitCode !== 0) {
45099
+ throw this.createFileError(path, result.stderr);
45100
+ }
45101
+ }
45102
+ return;
45103
+ }
45037
45104
  const base64 = bytesToBase64(data);
45038
45105
  const chunkSize = 1024;
45039
- await this.createParentDirectory(path);
45040
- let first = true;
45106
+ let first = Boolean(options?.truncate);
45041
45107
  for (let i = 0;i < base64.length; i += chunkSize) {
45042
45108
  const chunk = base64.slice(i, i + chunkSize);
45043
45109
  const redirect = first ? ">" : ">>";
@@ -45047,7 +45113,6 @@ class CommandPolyfillService {
45047
45113
  }
45048
45114
  first = false;
45049
45115
  }
45050
- return data.length;
45051
45116
  }
45052
45117
  async writeTextFile(path, content) {
45053
45118
  await this.createParentDirectory(path);
@@ -45328,6 +45393,12 @@ class BaseSandboxAdapter {
45328
45393
  async renewExpiration(_additionalSeconds) {
45329
45394
  throw new FeatureNotSupportedError("Sandbox expiration renewal not supported by this provider", "renewExpiration", this.provider);
45330
45395
  }
45396
+ async getEndpoint(_selector) {
45397
+ throw new FeatureNotSupportedError("Endpoint resolution not supported by this provider", "getEndpoint", this.provider);
45398
+ }
45399
+ async getProxyTarget(_service = "code-server") {
45400
+ throw new FeatureNotSupportedError("Proxy target resolution not supported by this provider", "getProxyTarget", this.provider);
45401
+ }
45331
45402
  async executeStream(command, handlers, options) {
45332
45403
  const result = await this.execute(command, options);
45333
45404
  if (handlers.onStdout && result.stdout) {
@@ -45390,23 +45461,7 @@ class BaseSandboxAdapter {
45390
45461
  const arrayBuffer = await entry.data.arrayBuffer();
45391
45462
  bytesWritten = await polyfillService.writeFile(entry.path, new Uint8Array(arrayBuffer));
45392
45463
  } else {
45393
- const chunks = [];
45394
- const reader = entry.data.getReader();
45395
- while (true) {
45396
- const { done, value } = await reader.read();
45397
- if (done) {
45398
- break;
45399
- }
45400
- chunks.push(value);
45401
- }
45402
- const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);
45403
- const combined = new Uint8Array(totalLength);
45404
- let offset = 0;
45405
- for (const chunk of chunks) {
45406
- combined.set(chunk, offset);
45407
- offset += chunk.length;
45408
- }
45409
- bytesWritten = await polyfillService.writeFile(entry.path, combined);
45464
+ bytesWritten = await this.writeStreamToFile(polyfillService, entry.path, entry.data);
45410
45465
  }
45411
45466
  results.push({ path: entry.path, bytesWritten, error: null });
45412
45467
  } catch (error) {
@@ -45481,23 +45536,36 @@ class BaseSandboxAdapter {
45481
45536
  }
45482
45537
  }
45483
45538
  async writeFileStream(path, stream) {
45539
+ const polyfillService = this.requirePolyfillService("writeFileStream", "File stream write not supported by this provider");
45540
+ await this.writeStreamToFile(polyfillService, this.normalizePath(path), stream);
45541
+ }
45542
+ async writeStreamToFile(polyfillService, path, stream) {
45543
+ const tmpPath = `${path}.tmp.${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
45484
45544
  const reader = stream.getReader();
45485
- const chunks = [];
45486
- while (true) {
45487
- const { done, value } = await reader.read();
45488
- if (done) {
45489
- break;
45545
+ let totalBytes = 0;
45546
+ let first = true;
45547
+ try {
45548
+ while (true) {
45549
+ const { done, value } = await reader.read();
45550
+ if (done)
45551
+ break;
45552
+ if (!value || value.length === 0)
45553
+ continue;
45554
+ await polyfillService.appendBytes(tmpPath, value, first ? { truncate: true } : undefined);
45555
+ totalBytes += value.length;
45556
+ first = false;
45490
45557
  }
45491
- chunks.push(value);
45492
- }
45493
- const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);
45494
- const combined = new Uint8Array(totalLength);
45495
- let offset = 0;
45496
- for (const chunk of chunks) {
45497
- combined.set(chunk, offset);
45498
- offset += chunk.length;
45558
+ if (first) {
45559
+ await polyfillService.appendBytes(tmpPath, new Uint8Array, { truncate: true });
45560
+ }
45561
+ await polyfillService.moveFiles([{ source: tmpPath, destination: path }]);
45562
+ } catch (error) {
45563
+ await polyfillService.deleteFiles([tmpPath]).catch(() => {});
45564
+ throw error;
45565
+ } finally {
45566
+ reader.releaseLock();
45499
45567
  }
45500
- await this.writeFiles([{ path, data: combined }]);
45568
+ return totalBytes;
45501
45569
  }
45502
45570
  async getFileInfo(paths) {
45503
45571
  const polyfillService = this.requirePolyfillService("getFileInfo", "File info not supported by this provider");
@@ -45567,10 +45635,10 @@ class DevboxApi {
45567
45635
  const result = await res.json();
45568
45636
  return result;
45569
45637
  }
45570
- async create(name) {
45638
+ async create(req) {
45571
45639
  return this.request(this.url("/api/v1/devbox"), {
45572
45640
  method: "POST",
45573
- body: JSON.stringify({ name })
45641
+ body: JSON.stringify(req)
45574
45642
  });
45575
45643
  }
45576
45644
  async info(name) {
@@ -45628,18 +45696,60 @@ class DevboxApi {
45628
45696
  }
45629
45697
  }
45630
45698
 
45699
+ // src/adapters/ports.ts
45700
+ var OPEN_SANDBOX_EXECD_PORT = 44772;
45701
+ var OPEN_SANDBOX_CODE_SERVER_PORT = 8080;
45702
+ var SEALOS_DEVBOX_CODE_SERVER_PORT = 1318;
45703
+
45704
+ // src/utils/image.ts
45705
+ function formatImageSpec(image) {
45706
+ const parts = [image.repository];
45707
+ if (image.tag)
45708
+ parts.push(":", image.tag);
45709
+ if (image.digest)
45710
+ parts.push("@", image.digest);
45711
+ return parts.join("");
45712
+ }
45713
+ function parseImageSpec(image) {
45714
+ if (!image)
45715
+ return { repository: "" };
45716
+ const atIndex = image.indexOf("@");
45717
+ if (atIndex > -1) {
45718
+ return { repository: image.slice(0, atIndex), digest: image.slice(atIndex + 1) };
45719
+ }
45720
+ const colonIndex = image.indexOf(":");
45721
+ if (colonIndex > -1) {
45722
+ return { repository: image.slice(0, colonIndex), tag: image.slice(colonIndex + 1) };
45723
+ }
45724
+ return { repository: image };
45725
+ }
45726
+
45727
+ // src/utils/url.ts
45728
+ function normalizePathPrefix(path) {
45729
+ if (!path)
45730
+ return "";
45731
+ const normalized = path.startsWith("/") ? path : `/${path}`;
45732
+ return normalized.length > 1 ? normalized.replace(/\/+$/, "") : "";
45733
+ }
45734
+ function joinUrlPath(url, path) {
45735
+ const normalizedPath = normalizePathPrefix(path);
45736
+ return normalizedPath ? `${url.replace(/\/+$/, "")}${normalizedPath}` : url.replace(/\/+$/, "");
45737
+ }
45738
+
45631
45739
  // src/adapters/SealosDevboxAdapter/index.ts
45632
45740
  class SealosDevboxAdapter extends BaseSandboxAdapter {
45633
45741
  config;
45742
+ createConfig;
45634
45743
  provider = "sealosdevbox";
45635
45744
  get rootPath() {
45636
45745
  return "/home/devbox/workspace";
45637
45746
  }
45638
45747
  api;
45639
45748
  _id;
45640
- constructor(config) {
45749
+ constructor(config, createConfig) {
45641
45750
  super();
45642
45751
  this.config = config;
45752
+ this.createConfig = createConfig;
45643
45753
  this.api = new DevboxApi({ baseUrl: config.baseUrl, token: config.token });
45644
45754
  this._id = config.sandboxId;
45645
45755
  this.polyfillService = new CommandPolyfillService(this);
@@ -45664,6 +45774,26 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45664
45774
  return "Error";
45665
45775
  }
45666
45776
  }
45777
+ buildCreateRequest() {
45778
+ const spec = this.createConfig ?? {};
45779
+ const env = { ...spec.env ?? {} };
45780
+ if (spec.workingDir && !env.CODEX_GATEWAY_CWD) {
45781
+ env.CODEX_GATEWAY_CWD = spec.workingDir;
45782
+ }
45783
+ return this.removeUndefined({
45784
+ name: this._id,
45785
+ image: spec.image ? formatImageSpec(spec.image) : undefined,
45786
+ env: Object.keys(env).length > 0 ? env : undefined,
45787
+ labels: spec.labels,
45788
+ upstreamID: spec.upstreamID,
45789
+ kubeAccess: spec.kubeAccess,
45790
+ pauseAt: spec.lifecycle?.pauseAt,
45791
+ archiveAfterPauseTime: spec.lifecycle?.archiveAfterPauseTime
45792
+ });
45793
+ }
45794
+ removeUndefined(obj) {
45795
+ return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined));
45796
+ }
45667
45797
  async getInfo() {
45668
45798
  try {
45669
45799
  const res = await this.api.info(this._id);
@@ -45675,10 +45805,10 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45675
45805
  this._status = { state: this.StatusAdapt(data), message: res.message };
45676
45806
  return {
45677
45807
  id: data.name,
45678
- image: { repository: "" },
45808
+ image: parseImageSpec(data.image),
45679
45809
  entrypoint: [],
45680
45810
  status: this._status,
45681
- createdAt: new Date
45811
+ createdAt: data.creationTimestamp ? new Date(data.creationTimestamp) : new Date
45682
45812
  };
45683
45813
  } catch (error) {
45684
45814
  throw new CommandExecutionError(`Failed to get sandbox info`, "getInfo", error instanceof Error ? error : undefined);
@@ -45716,7 +45846,10 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45716
45846
  async create() {
45717
45847
  try {
45718
45848
  this._status = { state: "Creating" };
45719
- await this.api.create(this._id);
45849
+ const res = await this.api.create(this.buildCreateRequest());
45850
+ if (res.code !== 200 && res.code !== 201) {
45851
+ throw new Error(res.message || `Devbox create failed with code ${res.code}`);
45852
+ }
45720
45853
  await this.waitUntilReady();
45721
45854
  await new Promise((resolve) => setTimeout(resolve, 1000));
45722
45855
  this._status = { state: "Running" };
@@ -45772,11 +45905,98 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45772
45905
  throw new CommandExecutionError(`Command execution failed: ${error?.message || error?.code}`, command, error instanceof Error ? error : undefined);
45773
45906
  }
45774
45907
  }
45908
+ async getEndpoint(selector) {
45909
+ const port = typeof selector === "number" ? selector : SEALOS_DEVBOX_CODE_SERVER_PORT;
45910
+ const target = await this.getHttpgateTarget(port);
45911
+ const url = new URL(target.origin);
45912
+ return {
45913
+ host: url.host,
45914
+ port: target.port,
45915
+ protocol: url.protocol === "https:" ? "https" : "http",
45916
+ url: joinUrlPath(target.origin, target.basePath)
45917
+ };
45918
+ }
45919
+ async getProxyTarget(service = "code-server") {
45920
+ if (service !== "code-server") {
45921
+ throw new FeatureNotSupportedError(`Proxy service "${service}" is not supported by this provider`, "getProxyTarget", this.provider);
45922
+ }
45923
+ const target = await this.getHttpgateTarget(SEALOS_DEVBOX_CODE_SERVER_PORT);
45924
+ return {
45925
+ service,
45926
+ origin: target.origin,
45927
+ basePath: target.basePath,
45928
+ auth: "code-server",
45929
+ ...target.password ? { password: target.password } : {}
45930
+ };
45931
+ }
45932
+ async getHttpgateTarget(port) {
45933
+ const res = await this.api.info(this._id);
45934
+ if (res.code !== 200 || !res.data) {
45935
+ throw new ConnectionError(`Failed to get devbox info: ${res.message}`, this.config.baseUrl);
45936
+ }
45937
+ if (port === SEALOS_DEVBOX_CODE_SERVER_PORT) {
45938
+ const gateway2 = res.data.codeServerGateway;
45939
+ if (!gateway2?.url) {
45940
+ throw new ConnectionError("Devbox info does not include codeServerGateway.url; cannot resolve code-server endpoint", this.config.baseUrl);
45941
+ }
45942
+ const codeServerUrl = new URL(gateway2.url);
45943
+ return {
45944
+ origin: codeServerUrl.origin,
45945
+ basePath: normalizePathPrefix(codeServerUrl.pathname),
45946
+ port: gateway2.port ?? port,
45947
+ password: gateway2.password
45948
+ };
45949
+ }
45950
+ const gatewayUrl = res.data.gateway?.url;
45951
+ if (!gatewayUrl) {
45952
+ throw new ConnectionError("Devbox info does not include gateway.url; cannot derive httpgate endpoint", this.config.baseUrl);
45953
+ }
45954
+ const gateway = new URL(gatewayUrl);
45955
+ const uniqueID = this.getGatewayUniqueID(res.data, gateway);
45956
+ const domain = this.getHttpgateDomain(gateway);
45957
+ return {
45958
+ origin: `${gateway.protocol}//devbox-${uniqueID}-${port}.${domain}`,
45959
+ basePath: "",
45960
+ port
45961
+ };
45962
+ }
45963
+ getGatewayUniqueID(data, gateway) {
45964
+ if (data.gateway?.uniqueID)
45965
+ return data.gateway.uniqueID;
45966
+ const parts = gateway.pathname.split("/").filter(Boolean);
45967
+ const uniqueID = parts[parts.length - 1];
45968
+ if (!uniqueID) {
45969
+ throw new ConnectionError("Devbox gateway.url does not include uniqueID; cannot derive httpgate endpoint", this.config.baseUrl);
45970
+ }
45971
+ return uniqueID;
45972
+ }
45973
+ getHttpgateDomain(gateway) {
45974
+ if (this.config.httpgateDomain) {
45975
+ return this.normalizeHttpgateDomain(this.config.httpgateDomain);
45976
+ }
45977
+ const prefix = "devbox-gateway.";
45978
+ if (!gateway.host.startsWith(prefix)) {
45979
+ throw new ConnectionError(`Cannot derive httpgate domain from gateway host "${gateway.host}"`, this.config.baseUrl);
45980
+ }
45981
+ return gateway.host.slice(prefix.length);
45982
+ }
45983
+ normalizeHttpgateDomain(domain) {
45984
+ const trimmed = domain.trim().replace(/^\.+|\.+$/g, "");
45985
+ if (!trimmed) {
45986
+ throw new ConnectionError("httpgateDomain is empty", this.config.baseUrl);
45987
+ }
45988
+ if (trimmed.includes("://")) {
45989
+ return new URL(trimmed).host;
45990
+ }
45991
+ return trimmed;
45992
+ }
45775
45993
  async ping() {
45776
45994
  try {
45777
45995
  const res = await this.api.info(this._id);
45778
45996
  if (res.code !== 200)
45779
45997
  return false;
45998
+ if (!res.data)
45999
+ return false;
45780
46000
  return res.data.state.phase === "Running" /* Running */;
45781
46001
  } catch {
45782
46002
  return false;
@@ -47893,7 +48113,79 @@ var Sandbox = class _Sandbox {
47893
48113
  }
47894
48114
  };
47895
48115
 
48116
+ // src/utils/outputBuffer.ts
48117
+ class BoundedOutputBuffer {
48118
+ maxBytes;
48119
+ chunks = [];
48120
+ currentBytes = 0;
48121
+ _totalBytes = 0;
48122
+ _truncated = false;
48123
+ separatorBuf;
48124
+ constructor(maxBytes, separator) {
48125
+ this.maxBytes = maxBytes;
48126
+ if (!(maxBytes > 0)) {
48127
+ throw new Error(`BoundedOutputBuffer: maxBytes must be > 0 (got ${maxBytes})`);
48128
+ }
48129
+ if (separator) {
48130
+ this.separatorBuf = Buffer.from(separator, "utf8");
48131
+ }
48132
+ }
48133
+ append(text) {
48134
+ if (!text)
48135
+ return;
48136
+ const needsSep = this.separatorBuf && this.chunks.length > 0;
48137
+ const textBuf = Buffer.from(text, "utf8");
48138
+ const sepLen = needsSep ? this.separatorBuf.length : 0;
48139
+ this._totalBytes += textBuf.length + sepLen;
48140
+ if (textBuf.length + sepLen > this.maxBytes) {
48141
+ this._truncated = true;
48142
+ const keep = Math.min(textBuf.length, this.maxBytes);
48143
+ this.chunks = [
48144
+ keep < textBuf.length ? Buffer.from(textBuf.subarray(textBuf.length - keep)) : textBuf
48145
+ ];
48146
+ this.currentBytes = keep;
48147
+ return;
48148
+ }
48149
+ const chunk = needsSep ? Buffer.concat([this.separatorBuf, textBuf]) : textBuf;
48150
+ this.chunks.push(chunk);
48151
+ this.currentBytes += chunk.length;
48152
+ if (this.currentBytes <= this.maxBytes)
48153
+ return;
48154
+ this._truncated = true;
48155
+ while (this.chunks.length > 1 && this.currentBytes - this.chunks[0].length >= this.maxBytes) {
48156
+ this.currentBytes -= this.chunks[0].length;
48157
+ this.chunks.shift();
48158
+ }
48159
+ if (this.currentBytes > this.maxBytes && this.chunks.length > 0) {
48160
+ const overflow = this.currentBytes - this.maxBytes;
48161
+ this.chunks[0] = this.chunks[0].subarray(overflow);
48162
+ this.currentBytes -= overflow;
48163
+ }
48164
+ if (this.separatorBuf && this.chunks.length > 0) {
48165
+ const first = this.chunks[0];
48166
+ const sep = this.separatorBuf;
48167
+ if (first.subarray(0, sep.length).equals(sep)) {
48168
+ this.chunks[0] = first.subarray(sep.length);
48169
+ this.currentBytes -= sep.length;
48170
+ }
48171
+ }
48172
+ }
48173
+ get totalBytes() {
48174
+ return this._totalBytes;
48175
+ }
48176
+ get truncated() {
48177
+ return this._truncated;
48178
+ }
48179
+ toString() {
48180
+ if (this.chunks.length === 0)
48181
+ return "";
48182
+ return Buffer.concat(this.chunks, this.currentBytes).toString("utf8");
48183
+ }
48184
+ }
48185
+
47896
48186
  // src/adapters/OpenSandboxAdapter/index.ts
48187
+ var DEFAULT_MAX_OUTPUT_BYTES = 1024 * 1024;
48188
+
47897
48189
  class OpenSandboxAdapter extends BaseSandboxAdapter {
47898
48190
  connectionConfig;
47899
48191
  createConfig;
@@ -47956,27 +48248,6 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
47956
48248
  message: sdkStatus.message
47957
48249
  };
47958
48250
  }
47959
- convertImageSpec(image) {
47960
- const parts = [image.repository];
47961
- if (image.tag) {
47962
- parts.push(":", image.tag);
47963
- }
47964
- if (image.digest) {
47965
- parts.push("@", image.digest);
47966
- }
47967
- return parts.join("");
47968
- }
47969
- parseImageSpec(image) {
47970
- const atIndex = image.indexOf("@");
47971
- if (atIndex > -1) {
47972
- return { repository: image.slice(0, atIndex), digest: image.slice(atIndex + 1) };
47973
- }
47974
- const colonIndex = image.indexOf(":");
47975
- if (colonIndex > -1) {
47976
- return { repository: image.slice(0, colonIndex), tag: image.slice(colonIndex + 1) };
47977
- }
47978
- return { repository: image };
47979
- }
47980
48251
  convertResourceLimits(resourceLimits) {
47981
48252
  if (!resourceLimits)
47982
48253
  return;
@@ -48091,7 +48362,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48091
48362
  }
48092
48363
  try {
48093
48364
  this._status = { state: "Creating" };
48094
- const image = this.convertImageSpec(cfg.image);
48365
+ const image = formatImageSpec(cfg.image);
48095
48366
  const resource = this.convertResourceLimits(cfg.resourceLimits);
48096
48367
  this.sandbox = await Sandbox.create({
48097
48368
  connectionConfig: this._connection,
@@ -48195,7 +48466,18 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48195
48466
  async close() {
48196
48467
  await this.sandbox.close();
48197
48468
  }
48198
- async getEndpoint(port) {
48469
+ async getEndpoint(selector) {
48470
+ const port = typeof selector === "number" ? selector : OPEN_SANDBOX_EXECD_PORT;
48471
+ const endpoint = await this.getOpenSandboxEndpoint(port);
48472
+ if (selector === "code-server") {
48473
+ return {
48474
+ ...endpoint,
48475
+ url: joinUrlPath(endpoint.url, `/proxy/${OPEN_SANDBOX_CODE_SERVER_PORT}`)
48476
+ };
48477
+ }
48478
+ return endpoint;
48479
+ }
48480
+ async getOpenSandboxEndpoint(port) {
48199
48481
  const sdkEndpoint = await this.sandbox.getEndpoint(port);
48200
48482
  const raw = sdkEndpoint.endpoint;
48201
48483
  const colonIdx = raw.lastIndexOf(":");
@@ -48214,6 +48496,40 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48214
48496
  url: `https://${raw}`
48215
48497
  };
48216
48498
  }
48499
+ async getProxyTarget(service = "code-server") {
48500
+ if (service !== "code-server") {
48501
+ throw new FeatureNotSupportedError(`Proxy service "${service}" is not supported by this provider`, "getProxyTarget", this.provider);
48502
+ }
48503
+ return {
48504
+ service,
48505
+ origin: await this.getDirectEndpointOrigin(OPEN_SANDBOX_EXECD_PORT),
48506
+ basePath: `/proxy/${OPEN_SANDBOX_CODE_SERVER_PORT}`,
48507
+ auth: "code-server"
48508
+ };
48509
+ }
48510
+ async getDirectEndpointOrigin(port) {
48511
+ if (!this.id) {
48512
+ throw new SandboxStateError("Sandbox not initialized. Call create() or connect() first.", "UnExist", "Running");
48513
+ }
48514
+ const headers = {
48515
+ ...this._connection.headers,
48516
+ Accept: "application/json"
48517
+ };
48518
+ const response = await this._connection.fetch(`${this._connection.getBaseUrl()}/sandboxes/${this.id}/endpoints/${port}?use_server_proxy=false`, { method: "GET", headers });
48519
+ if (!response.ok) {
48520
+ throw new ConnectionError(`OpenSandbox endpoint lookup failed: HTTP ${response.status}`, this.connectionConfig.baseUrl);
48521
+ }
48522
+ const data = await response.json();
48523
+ if (!data.endpoint) {
48524
+ throw new ConnectionError("OpenSandbox returned no endpoint", this.connectionConfig.baseUrl);
48525
+ }
48526
+ let hostPort = data.endpoint.replace(/\/proxy\/\d+\/?$/, "");
48527
+ if (this.connectionConfig.replaceDockerInternalWithLocalhost) {
48528
+ hostPort = hostPort.replace(/^host\.docker\.internal\b/, "localhost");
48529
+ }
48530
+ const url = new URL(/^https?:\/\//.test(hostPort) ? hostPort : `http://${hostPort}`);
48531
+ return url.origin;
48532
+ }
48217
48533
  async getInfo() {
48218
48534
  if (!this._sandbox) {
48219
48535
  return null;
@@ -48222,7 +48538,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48222
48538
  const info = await this.sandbox.getInfo();
48223
48539
  return {
48224
48540
  id: info.id,
48225
- image: typeof info.image === "string" ? this.parseImageSpec(info.image) : ("uri" in info.image) ? this.parseImageSpec(info.image.uri) : info.image,
48541
+ image: typeof info.image === "string" ? parseImageSpec(info.image) : ("uri" in info.image) ? parseImageSpec(info.image.uri) : info.image,
48226
48542
  entrypoint: info.entrypoint,
48227
48543
  metadata: info.metadata,
48228
48544
  status: this.mapStatus(info.status),
@@ -48277,21 +48593,30 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48277
48593
  return results;
48278
48594
  }
48279
48595
  async execute(command, options) {
48596
+ const maxBytes = options?.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
48597
+ const stdoutBuf = new BoundedOutputBuffer(maxBytes, `
48598
+ `);
48599
+ const stderrBuf = new BoundedOutputBuffer(maxBytes, `
48600
+ `);
48280
48601
  try {
48281
48602
  const execution = await this.sandbox.commands.run(command, {
48282
48603
  workingDirectory: this.normalizePath(options?.workingDirectory),
48283
48604
  background: options?.background
48605
+ }, {
48606
+ onStdout: (msg) => {
48607
+ stdoutBuf.append(msg.text);
48608
+ },
48609
+ onStderr: (msg) => {
48610
+ stderrBuf.append(msg.text);
48611
+ }
48284
48612
  });
48285
- const stdout = execution.logs.stdout.map((msg) => msg.text).join(`
48286
- `);
48287
- const stderr = execution.logs.stderr.map((msg) => msg.text).join(`
48288
- `);
48289
48613
  const exitCode = this.extractExitCode(execution);
48290
- const stdoutLength = execution.logs.stdout.reduce((sum, msg) => sum + msg.text.length, 0);
48291
- const stderrLength = execution.logs.stderr.reduce((sum, msg) => sum + msg.text.length, 0);
48292
- const MaxOutputSize = 1024 * 1024;
48293
- const truncated = stdoutLength >= MaxOutputSize || stderrLength >= MaxOutputSize;
48294
- return { stdout, stderr, exitCode, truncated };
48614
+ return {
48615
+ stdout: stdoutBuf.toString(),
48616
+ stderr: stderrBuf.toString(),
48617
+ exitCode,
48618
+ truncated: stdoutBuf.truncated || stderrBuf.truncated
48619
+ };
48295
48620
  } catch (error) {
48296
48621
  if (error instanceof SandboxStateError)
48297
48622
  throw error;
@@ -48299,10 +48624,26 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48299
48624
  }
48300
48625
  }
48301
48626
  async executeStream(command, handlers, options) {
48627
+ const wantsComplete = Boolean(handlers.onComplete);
48628
+ const maxBytes = options?.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
48629
+ const stdoutBuf = wantsComplete ? new BoundedOutputBuffer(maxBytes, `
48630
+ `) : undefined;
48631
+ const stderrBuf = wantsComplete ? new BoundedOutputBuffer(maxBytes, `
48632
+ `) : undefined;
48302
48633
  try {
48303
48634
  const sdkHandlers = {
48304
- ...handlers.onStderr ? { onStderr: handlers.onStderr } : {},
48305
- ...handlers.onStdout ? { onStdout: handlers.onStdout } : {},
48635
+ ...handlers.onStdout || wantsComplete ? {
48636
+ onStdout: async (msg) => {
48637
+ stdoutBuf?.append(msg.text);
48638
+ await handlers.onStdout?.(msg);
48639
+ }
48640
+ } : {},
48641
+ ...handlers.onStderr || wantsComplete ? {
48642
+ onStderr: async (msg) => {
48643
+ stderrBuf?.append(msg.text);
48644
+ await handlers.onStderr?.(msg);
48645
+ }
48646
+ } : {},
48306
48647
  ...handlers.onError ? {
48307
48648
  onError: async (err) => {
48308
48649
  const error = new Error(err.value || err.name || "Execution error");
@@ -48319,17 +48660,14 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48319
48660
  workingDirectory: this.normalizePath(options?.workingDirectory),
48320
48661
  background: options?.background
48321
48662
  }, sdkHandlers);
48322
- if (handlers.onComplete) {
48323
- const stdout = execution.logs.stdout.map((msg) => msg.text).join(`
48324
- `);
48325
- const stderr = execution.logs.stderr.map((msg) => msg.text).join(`
48326
- `);
48663
+ if (wantsComplete) {
48327
48664
  const exitCode = this.extractExitCode(execution);
48328
- const stdoutLength = execution.logs.stdout.reduce((sum, msg) => sum + msg.text.length, 0);
48329
- const stderrLength = execution.logs.stderr.reduce((sum, msg) => sum + msg.text.length, 0);
48330
- const MaxOutputSize = 1024 * 1024;
48331
- const truncated = stdoutLength >= MaxOutputSize || stderrLength >= MaxOutputSize;
48332
- await handlers.onComplete({ stdout, stderr, exitCode, truncated });
48665
+ await handlers.onComplete({
48666
+ stdout: stdoutBuf.toString(),
48667
+ stderr: stderrBuf.toString(),
48668
+ exitCode,
48669
+ truncated: stdoutBuf.truncated || stderrBuf.truncated
48670
+ });
48333
48671
  }
48334
48672
  } catch (error) {
48335
48673
  throw new CommandExecutionError(`Streaming command execution failed: ${command}`, command, error instanceof Error ? error : undefined);
@@ -48702,7 +49040,7 @@ function createSandbox(provider, config, createConfig) {
48702
49040
  case "opensandbox":
48703
49041
  return new OpenSandboxAdapter(config, createConfig);
48704
49042
  case "sealosdevbox":
48705
- return new SealosDevboxAdapter(config);
49043
+ return new SealosDevboxAdapter(config, createConfig);
48706
49044
  case "e2b":
48707
49045
  return new E2BAdapter(config);
48708
49046
  default: