@fastgpt-sdk/sandbox-adapter 0.0.36 → 0.0.38
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 +3 -1
- package/dist/adapters/OpenSandboxAdapter/index.d.ts +11 -7
- package/dist/adapters/OpenSandboxAdapter/type.d.ts +1 -1
- package/dist/adapters/SealosDevboxAdapter/api.d.ts +2 -2
- package/dist/adapters/SealosDevboxAdapter/index.d.ts +26 -2
- package/dist/adapters/SealosDevboxAdapter/type.d.ts +30 -0
- package/dist/adapters/index.d.ts +3 -3
- package/dist/adapters/ports.d.ts +7 -0
- package/dist/index.cjs +275 -45
- package/dist/index.js +273 -43
- package/dist/interfaces/ISandbox.d.ts +5 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/sandbox.d.ts +45 -0
- package/dist/utils/image.d.ts +3 -0
- package/dist/utils/url.d.ts +2 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ISandbox } from '../interfaces/ISandbox';
|
|
2
2
|
import { CommandPolyfillService } from '../polyfill/CommandPolyfillService';
|
|
3
|
-
import type { ContentReplaceEntry, DirectoryEntry, ExecuteOptions, ExecuteResult, FileDeleteResult, FileInfo, FileReadResult, FileWriteEntry, FileWriteResult, MoveEntry, PermissionEntry, ReadFileOptions, SandboxId, SandboxInfo, SandboxMetrics, SandboxStatus, SearchResult, StreamHandlers } from '../types';
|
|
3
|
+
import type { ContentReplaceEntry, DirectoryEntry, Endpoint, ExecuteOptions, ExecuteResult, FileDeleteResult, FileInfo, FileReadResult, FileWriteEntry, FileWriteResult, MoveEntry, PermissionEntry, ReadFileOptions, SandboxEndpointSelector, SandboxId, SandboxInfo, SandboxMetrics, SandboxProxyService, SandboxProxyTarget, SandboxStatus, SearchResult, StreamHandlers } from '../types';
|
|
4
4
|
/**
|
|
5
5
|
* Abstract base class for all sandbox adapters.
|
|
6
6
|
*
|
|
@@ -37,6 +37,8 @@ export declare abstract class BaseSandboxAdapter implements ISandbox {
|
|
|
37
37
|
waitUntilReady(timeoutMs?: number): Promise<void>;
|
|
38
38
|
waitUntilDeleted(timeoutMs?: number): Promise<void>;
|
|
39
39
|
renewExpiration(_additionalSeconds: number): Promise<void>;
|
|
40
|
+
getEndpoint(_selector: SandboxEndpointSelector): Promise<Endpoint>;
|
|
41
|
+
getProxyTarget(_service?: SandboxProxyService): Promise<SandboxProxyTarget>;
|
|
40
42
|
abstract execute(command: string, options?: ExecuteOptions): Promise<ExecuteResult>;
|
|
41
43
|
executeStream(command: string, handlers: StreamHandlers, options?: ExecuteOptions): Promise<void>;
|
|
42
44
|
executeBackground(_command: string, _options?: ExecuteOptions): Promise<{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Endpoint, ExecuteOptions, ExecuteResult, FileWriteEntry, FileWriteResult, SandboxId, SandboxInfo, SandboxMetrics, StreamHandlers } from '@/types';
|
|
1
|
+
import type { Endpoint, ExecuteOptions, ExecuteResult, FileWriteEntry, FileWriteResult, SandboxEndpointSelector, SandboxId, SandboxInfo, SandboxMetrics, SandboxProxyService, SandboxProxyTarget, StreamHandlers } from '@/types';
|
|
2
2
|
import { BaseSandboxAdapter } from '../BaseSandboxAdapter';
|
|
3
3
|
import type { OpenSandboxConfigType } from './type';
|
|
4
4
|
export type { OpenSandboxConfigType } from './type';
|
|
@@ -23,6 +23,11 @@ export interface OpenSandboxConnectionConfig {
|
|
|
23
23
|
debug?: boolean;
|
|
24
24
|
/** Route execd traffic through the OpenSandbox server proxy */
|
|
25
25
|
useServerProxy?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Rewrite OpenSandbox local endpoint host when sandbox-proxy runs on the host
|
|
28
|
+
* instead of inside Docker/Kubernetes.
|
|
29
|
+
*/
|
|
30
|
+
replaceDockerInternalWithLocalhost?: boolean;
|
|
26
31
|
/**
|
|
27
32
|
* Sandbox runtime type.
|
|
28
33
|
* @default 'docker'
|
|
@@ -65,8 +70,6 @@ export declare class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
65
70
|
private createConnectionConfig;
|
|
66
71
|
private static readonly STATE_MAP;
|
|
67
72
|
private mapStatus;
|
|
68
|
-
private convertImageSpec;
|
|
69
|
-
private parseImageSpec;
|
|
70
73
|
private convertResourceLimits;
|
|
71
74
|
private parseResourceLimits;
|
|
72
75
|
private extractExitCode;
|
|
@@ -85,11 +88,12 @@ export declare class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
85
88
|
*/
|
|
86
89
|
close(): Promise<void>;
|
|
87
90
|
/**
|
|
88
|
-
* Get endpoint information for a
|
|
89
|
-
* @param port The port number to get endpoint for
|
|
90
|
-
* @returns Endpoint with host, port, protocol and url fields
|
|
91
|
+
* Get endpoint information for a provider endpoint or well-known service.
|
|
91
92
|
*/
|
|
92
|
-
getEndpoint(
|
|
93
|
+
getEndpoint(selector: SandboxEndpointSelector): Promise<Endpoint>;
|
|
94
|
+
private getOpenSandboxEndpoint;
|
|
95
|
+
getProxyTarget(service?: SandboxProxyService): Promise<SandboxProxyTarget>;
|
|
96
|
+
private getDirectEndpointOrigin;
|
|
93
97
|
getInfo(): Promise<SandboxInfo | null>;
|
|
94
98
|
renewExpiration(additionalSeconds: number): Promise<void>;
|
|
95
99
|
writeFiles(entries: FileWriteEntry[]): Promise<FileWriteResult[]>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type DevboxApiConfig, type DevboxApiResponse, type DevboxInfoData, type DevboxMutationData, type DownloadFileParams, type ExecRequest, type ExecResponseData, type UploadFileParams, type UploadResponseData } from './type';
|
|
1
|
+
import { type DevboxApiConfig, type DevboxApiResponse, type DevboxCreateRequest, type DevboxInfoData, type DevboxMutationData, type DownloadFileParams, type ExecRequest, type ExecResponseData, type UploadFileParams, type UploadResponseData } from './type';
|
|
2
2
|
/**
|
|
3
3
|
* HTTP client for the Sealos Devbox REST API.
|
|
4
4
|
*
|
|
@@ -11,7 +11,7 @@ export declare class DevboxApi {
|
|
|
11
11
|
private url;
|
|
12
12
|
private request;
|
|
13
13
|
/** POST /api/v1/devbox — create a devbox */
|
|
14
|
-
create(
|
|
14
|
+
create(req: DevboxCreateRequest): Promise<DevboxApiResponse<DevboxMutationData>>;
|
|
15
15
|
/** GET /api/v1/devbox/{name} — query devbox info (state + SSH) */
|
|
16
16
|
info(name: string): Promise<DevboxApiResponse<DevboxInfoData>>;
|
|
17
17
|
/** POST /api/v1/devbox/{name}/pause */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExecuteOptions, ExecuteResult, SandboxId, SandboxInfo } from '../../types';
|
|
1
|
+
import type { Endpoint, ExecuteOptions, ExecuteResult, ImageSpec, KubeAccessPolicy, LabelSpec, LifecyclePolicy, SandboxEndpointSelector, SandboxId, SandboxInfo, SandboxProxyService, SandboxProxyTarget } from '../../types';
|
|
2
2
|
import { BaseSandboxAdapter } from '../BaseSandboxAdapter';
|
|
3
3
|
/**
|
|
4
4
|
* Configuration for Sealos Devbox Adapter.
|
|
@@ -9,16 +9,33 @@ export interface SealosDevboxConfig {
|
|
|
9
9
|
/** JWT authentication token */
|
|
10
10
|
token: string;
|
|
11
11
|
sandboxId: string;
|
|
12
|
+
/**
|
|
13
|
+
* Optional override for the Sealos httpgate wildcard domain. When omitted,
|
|
14
|
+
* it is derived from gateway.url returned by Devbox Server.
|
|
15
|
+
*/
|
|
16
|
+
httpgateDomain?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface SealosDevboxCreateConfig {
|
|
19
|
+
image?: ImageSpec;
|
|
20
|
+
env?: Record<string, string>;
|
|
21
|
+
labels?: LabelSpec[];
|
|
22
|
+
upstreamID?: string;
|
|
23
|
+
kubeAccess?: KubeAccessPolicy;
|
|
24
|
+
lifecycle?: LifecyclePolicy;
|
|
25
|
+
workingDir?: string;
|
|
12
26
|
}
|
|
13
27
|
export declare class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
14
28
|
private config;
|
|
29
|
+
private createConfig?;
|
|
15
30
|
readonly provider: "sealosdevbox";
|
|
16
31
|
get rootPath(): string;
|
|
17
32
|
private api;
|
|
18
33
|
private _id;
|
|
19
|
-
constructor(config: SealosDevboxConfig);
|
|
34
|
+
constructor(config: SealosDevboxConfig, createConfig?: SealosDevboxCreateConfig | undefined);
|
|
20
35
|
get id(): SandboxId;
|
|
21
36
|
private StatusAdapt;
|
|
37
|
+
private buildCreateRequest;
|
|
38
|
+
private removeUndefined;
|
|
22
39
|
getInfo(): Promise<SandboxInfo | null>;
|
|
23
40
|
ensureRunning(): Promise<void>;
|
|
24
41
|
create(): Promise<void>;
|
|
@@ -26,6 +43,13 @@ export declare class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
|
26
43
|
start(): Promise<void>;
|
|
27
44
|
delete(): Promise<void>;
|
|
28
45
|
execute(command: string, options?: ExecuteOptions): Promise<ExecuteResult>;
|
|
46
|
+
getEndpoint(selector: SandboxEndpointSelector): Promise<Endpoint>;
|
|
47
|
+
getProxyTarget(service?: SandboxProxyService): Promise<SandboxProxyTarget>;
|
|
48
|
+
private waitForCodeServerHealthz;
|
|
49
|
+
private getHttpgateTarget;
|
|
50
|
+
private getGatewayUniqueID;
|
|
51
|
+
private getHttpgateDomain;
|
|
52
|
+
private normalizeHttpgateDomain;
|
|
29
53
|
/**
|
|
30
54
|
* Check if the devbox is ready by querying info endpoint.
|
|
31
55
|
* Ready when spec, status, and phase are all "Running".
|
|
@@ -52,6 +52,23 @@ export interface DevboxMutationData {
|
|
|
52
52
|
state?: string;
|
|
53
53
|
status?: string;
|
|
54
54
|
}
|
|
55
|
+
/** Request body for the create endpoint. */
|
|
56
|
+
export interface DevboxCreateRequest {
|
|
57
|
+
name: string;
|
|
58
|
+
image?: string;
|
|
59
|
+
env?: Record<string, string>;
|
|
60
|
+
labels?: Array<{
|
|
61
|
+
key: string;
|
|
62
|
+
value: string;
|
|
63
|
+
}>;
|
|
64
|
+
upstreamID?: string;
|
|
65
|
+
kubeAccess?: {
|
|
66
|
+
enabled?: boolean;
|
|
67
|
+
roleTemplate?: 'view' | 'edit' | 'admin';
|
|
68
|
+
};
|
|
69
|
+
pauseAt?: string;
|
|
70
|
+
archiveAfterPauseTime?: string;
|
|
71
|
+
}
|
|
55
72
|
/** SSH connection info returned by the info endpoint. */
|
|
56
73
|
export interface DevboxSshInfo {
|
|
57
74
|
user: string;
|
|
@@ -63,14 +80,27 @@ export interface DevboxSshInfo {
|
|
|
63
80
|
privateKeyEncoding: string;
|
|
64
81
|
privateKeyBase64: string;
|
|
65
82
|
}
|
|
83
|
+
/** HTTP gateway info returned by the info endpoint. */
|
|
84
|
+
export interface DevboxGatewayInfo {
|
|
85
|
+
url: string;
|
|
86
|
+
token?: string;
|
|
87
|
+
port?: number;
|
|
88
|
+
uniqueID?: string;
|
|
89
|
+
}
|
|
66
90
|
/** Response data from the GET info endpoint. */
|
|
67
91
|
export interface DevboxInfoData {
|
|
68
92
|
name: string;
|
|
93
|
+
image?: string;
|
|
94
|
+
creationTimestamp?: string;
|
|
69
95
|
deletionTimestamp?: string | null;
|
|
70
96
|
state: {
|
|
71
97
|
phase: `${DevboxPhaseEnum}`;
|
|
72
98
|
};
|
|
73
99
|
ssh: DevboxSshInfo;
|
|
100
|
+
gateway?: DevboxGatewayInfo;
|
|
101
|
+
codeServerGateway?: DevboxGatewayInfo & {
|
|
102
|
+
password?: string;
|
|
103
|
+
};
|
|
74
104
|
}
|
|
75
105
|
/** Response data from the upload endpoint. */
|
|
76
106
|
export interface UploadResponseData {
|
package/dist/adapters/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { type SealosDevboxConfig } from './SealosDevboxAdapter';
|
|
1
|
+
import { type SealosDevboxConfig, type SealosDevboxCreateConfig } from './SealosDevboxAdapter';
|
|
2
2
|
import { type OpenSandboxConnectionConfig, type OpenSandboxConfigType } from './OpenSandboxAdapter';
|
|
3
3
|
import { type E2BConfig } from './E2BAdapter';
|
|
4
4
|
import { ISandbox } from '@/interfaces';
|
|
5
5
|
export { SealosDevboxAdapter } from './SealosDevboxAdapter';
|
|
6
|
-
export type { SealosDevboxConfig } from './SealosDevboxAdapter';
|
|
6
|
+
export type { SealosDevboxConfig, SealosDevboxCreateConfig } from './SealosDevboxAdapter';
|
|
7
7
|
export { OpenSandboxAdapter } from './OpenSandboxAdapter';
|
|
8
8
|
export type { OpenSandboxConfigType, OpenSandboxConnectionConfig } from './OpenSandboxAdapter';
|
|
9
9
|
export type { Volume as OpenSandboxVolume } from '@alibaba-group/opensandbox';
|
|
@@ -13,7 +13,7 @@ export type SandboxProviderType = 'opensandbox' | 'sealosdevbox' | 'e2b';
|
|
|
13
13
|
/** Maps each provider name to the ISandbox config type it exposes. */
|
|
14
14
|
interface SandboxConfigMap {
|
|
15
15
|
opensandbox: OpenSandboxConfigType;
|
|
16
|
-
sealosdevbox:
|
|
16
|
+
sealosdevbox: SealosDevboxCreateConfig;
|
|
17
17
|
e2b: undefined;
|
|
18
18
|
}
|
|
19
19
|
/** Resolves the concrete ISandbox type for a given provider. */
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenSandbox exposes execd through this direct endpoint. code-server itself is
|
|
3
|
+
* still reached via execd path proxying at /proxy/8080.
|
|
4
|
+
*/
|
|
5
|
+
export declare const OPEN_SANDBOX_EXECD_PORT = 44772;
|
|
6
|
+
export declare const OPEN_SANDBOX_CODE_SERVER_PORT = 8080;
|
|
7
|
+
export declare const SEALOS_DEVBOX_CODE_SERVER_PORT = 1318;
|
package/dist/index.cjs
CHANGED
|
@@ -4,39 +4,60 @@ var __defProp = Object.defineProperty;
|
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
function __accessProp(key) {
|
|
8
|
+
return this[key];
|
|
9
|
+
}
|
|
10
|
+
var __toESMCache_node;
|
|
11
|
+
var __toESMCache_esm;
|
|
7
12
|
var __toESM = (mod, isNodeMode, target) => {
|
|
13
|
+
var canCache = mod != null && typeof mod === "object";
|
|
14
|
+
if (canCache) {
|
|
15
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
16
|
+
var cached = cache.get(mod);
|
|
17
|
+
if (cached)
|
|
18
|
+
return cached;
|
|
19
|
+
}
|
|
8
20
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
21
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
22
|
for (let key of __getOwnPropNames(mod))
|
|
11
23
|
if (!__hasOwnProp.call(to, key))
|
|
12
24
|
__defProp(to, key, {
|
|
13
|
-
get: (
|
|
25
|
+
get: __accessProp.bind(mod, key),
|
|
14
26
|
enumerable: true
|
|
15
27
|
});
|
|
28
|
+
if (canCache)
|
|
29
|
+
cache.set(mod, to);
|
|
16
30
|
return to;
|
|
17
31
|
};
|
|
18
|
-
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
19
32
|
var __toCommonJS = (from) => {
|
|
20
|
-
var entry = __moduleCache.get(from), desc;
|
|
33
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
21
34
|
if (entry)
|
|
22
35
|
return entry;
|
|
23
36
|
entry = __defProp({}, "__esModule", { value: true });
|
|
24
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
38
|
+
for (var key of __getOwnPropNames(from))
|
|
39
|
+
if (!__hasOwnProp.call(entry, key))
|
|
40
|
+
__defProp(entry, key, {
|
|
41
|
+
get: __accessProp.bind(from, key),
|
|
42
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
43
|
+
});
|
|
44
|
+
}
|
|
29
45
|
__moduleCache.set(from, entry);
|
|
30
46
|
return entry;
|
|
31
47
|
};
|
|
48
|
+
var __moduleCache;
|
|
32
49
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
50
|
+
var __returnValue = (v) => v;
|
|
51
|
+
function __exportSetter(name, newValue) {
|
|
52
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
53
|
+
}
|
|
33
54
|
var __export = (target, all) => {
|
|
34
55
|
for (var name in all)
|
|
35
56
|
__defProp(target, name, {
|
|
36
57
|
get: all[name],
|
|
37
58
|
enumerable: true,
|
|
38
59
|
configurable: true,
|
|
39
|
-
set: (
|
|
60
|
+
set: __exportSetter.bind(all, name)
|
|
40
61
|
});
|
|
41
62
|
};
|
|
42
63
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -19139,7 +19160,7 @@ var require_frame = __commonJS((exports2, module2) => {
|
|
|
19139
19160
|
var BUFFER_SIZE = 8 * 1024;
|
|
19140
19161
|
var buffer = null;
|
|
19141
19162
|
var bufIdx = BUFFER_SIZE;
|
|
19142
|
-
var randomFillSync = runtimeFeatures.has("crypto") ? require("node:crypto").randomFillSync : function
|
|
19163
|
+
var randomFillSync = runtimeFeatures.has("crypto") ? require("node:crypto").randomFillSync : function randomFillSync2(buffer2, _offset, _size) {
|
|
19143
19164
|
for (let i = 0;i < buffer2.length; ++i) {
|
|
19144
19165
|
buffer2[i] = Math.random() * 255 | 0;
|
|
19145
19166
|
}
|
|
@@ -21083,7 +21104,7 @@ var require_eventsource = __commonJS((exports2, module2) => {
|
|
|
21083
21104
|
|
|
21084
21105
|
// node_modules/undici/index.js
|
|
21085
21106
|
var require_undici = __commonJS((exports2, module2) => {
|
|
21086
|
-
var __filename = "/
|
|
21107
|
+
var __filename = "/Users/sealos/Documents/GitHub/agent-sandbox-adaptor/node_modules/undici/index.js";
|
|
21087
21108
|
var Client = require_client();
|
|
21088
21109
|
var Dispatcher = require_dispatcher();
|
|
21089
21110
|
var Pool = require_pool();
|
|
@@ -21206,7 +21227,7 @@ var require_undici = __commonJS((exports2, module2) => {
|
|
|
21206
21227
|
err.stack = stack ? `${stack}
|
|
21207
21228
|
${captureLines}` : capture.stack;
|
|
21208
21229
|
}
|
|
21209
|
-
module2.exports.fetch = function
|
|
21230
|
+
module2.exports.fetch = function fetch2(init, options = undefined) {
|
|
21210
21231
|
return fetchImpl(init, options).catch((err) => {
|
|
21211
21232
|
appendFetchStackTrace(err, __filename);
|
|
21212
21233
|
throw err;
|
|
@@ -45388,6 +45409,12 @@ class BaseSandboxAdapter {
|
|
|
45388
45409
|
async renewExpiration(_additionalSeconds) {
|
|
45389
45410
|
throw new FeatureNotSupportedError("Sandbox expiration renewal not supported by this provider", "renewExpiration", this.provider);
|
|
45390
45411
|
}
|
|
45412
|
+
async getEndpoint(_selector) {
|
|
45413
|
+
throw new FeatureNotSupportedError("Endpoint resolution not supported by this provider", "getEndpoint", this.provider);
|
|
45414
|
+
}
|
|
45415
|
+
async getProxyTarget(_service = "code-server") {
|
|
45416
|
+
throw new FeatureNotSupportedError("Proxy target resolution not supported by this provider", "getProxyTarget", this.provider);
|
|
45417
|
+
}
|
|
45391
45418
|
async executeStream(command, handlers, options) {
|
|
45392
45419
|
const result = await this.execute(command, options);
|
|
45393
45420
|
if (handlers.onStdout && result.stdout) {
|
|
@@ -45624,10 +45651,10 @@ class DevboxApi {
|
|
|
45624
45651
|
const result = await res.json();
|
|
45625
45652
|
return result;
|
|
45626
45653
|
}
|
|
45627
|
-
async create(
|
|
45654
|
+
async create(req) {
|
|
45628
45655
|
return this.request(this.url("/api/v1/devbox"), {
|
|
45629
45656
|
method: "POST",
|
|
45630
|
-
body: JSON.stringify(
|
|
45657
|
+
body: JSON.stringify(req)
|
|
45631
45658
|
});
|
|
45632
45659
|
}
|
|
45633
45660
|
async info(name) {
|
|
@@ -45685,18 +45712,60 @@ class DevboxApi {
|
|
|
45685
45712
|
}
|
|
45686
45713
|
}
|
|
45687
45714
|
|
|
45715
|
+
// src/adapters/ports.ts
|
|
45716
|
+
var OPEN_SANDBOX_EXECD_PORT = 44772;
|
|
45717
|
+
var OPEN_SANDBOX_CODE_SERVER_PORT = 8080;
|
|
45718
|
+
var SEALOS_DEVBOX_CODE_SERVER_PORT = 1318;
|
|
45719
|
+
|
|
45720
|
+
// src/utils/image.ts
|
|
45721
|
+
function formatImageSpec(image) {
|
|
45722
|
+
const parts = [image.repository];
|
|
45723
|
+
if (image.tag)
|
|
45724
|
+
parts.push(":", image.tag);
|
|
45725
|
+
if (image.digest)
|
|
45726
|
+
parts.push("@", image.digest);
|
|
45727
|
+
return parts.join("");
|
|
45728
|
+
}
|
|
45729
|
+
function parseImageSpec(image) {
|
|
45730
|
+
if (!image)
|
|
45731
|
+
return { repository: "" };
|
|
45732
|
+
const atIndex = image.indexOf("@");
|
|
45733
|
+
if (atIndex > -1) {
|
|
45734
|
+
return { repository: image.slice(0, atIndex), digest: image.slice(atIndex + 1) };
|
|
45735
|
+
}
|
|
45736
|
+
const colonIndex = image.indexOf(":");
|
|
45737
|
+
if (colonIndex > -1) {
|
|
45738
|
+
return { repository: image.slice(0, colonIndex), tag: image.slice(colonIndex + 1) };
|
|
45739
|
+
}
|
|
45740
|
+
return { repository: image };
|
|
45741
|
+
}
|
|
45742
|
+
|
|
45743
|
+
// src/utils/url.ts
|
|
45744
|
+
function normalizePathPrefix(path) {
|
|
45745
|
+
if (!path)
|
|
45746
|
+
return "";
|
|
45747
|
+
const normalized = path.startsWith("/") ? path : `/${path}`;
|
|
45748
|
+
return normalized.length > 1 ? normalized.replace(/\/+$/, "") : "";
|
|
45749
|
+
}
|
|
45750
|
+
function joinUrlPath(url, path) {
|
|
45751
|
+
const normalizedPath = normalizePathPrefix(path);
|
|
45752
|
+
return normalizedPath ? `${url.replace(/\/+$/, "")}${normalizedPath}` : url.replace(/\/+$/, "");
|
|
45753
|
+
}
|
|
45754
|
+
|
|
45688
45755
|
// src/adapters/SealosDevboxAdapter/index.ts
|
|
45689
45756
|
class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
45690
45757
|
config;
|
|
45758
|
+
createConfig;
|
|
45691
45759
|
provider = "sealosdevbox";
|
|
45692
45760
|
get rootPath() {
|
|
45693
45761
|
return "/home/devbox/workspace";
|
|
45694
45762
|
}
|
|
45695
45763
|
api;
|
|
45696
45764
|
_id;
|
|
45697
|
-
constructor(config) {
|
|
45765
|
+
constructor(config, createConfig) {
|
|
45698
45766
|
super();
|
|
45699
45767
|
this.config = config;
|
|
45768
|
+
this.createConfig = createConfig;
|
|
45700
45769
|
this.api = new DevboxApi({ baseUrl: config.baseUrl, token: config.token });
|
|
45701
45770
|
this._id = config.sandboxId;
|
|
45702
45771
|
this.polyfillService = new CommandPolyfillService(this);
|
|
@@ -45721,6 +45790,26 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
|
45721
45790
|
return "Error";
|
|
45722
45791
|
}
|
|
45723
45792
|
}
|
|
45793
|
+
buildCreateRequest() {
|
|
45794
|
+
const spec = this.createConfig ?? {};
|
|
45795
|
+
const env = { ...spec.env ?? {} };
|
|
45796
|
+
if (spec.workingDir && !env.CODEX_GATEWAY_CWD) {
|
|
45797
|
+
env.CODEX_GATEWAY_CWD = spec.workingDir;
|
|
45798
|
+
}
|
|
45799
|
+
return this.removeUndefined({
|
|
45800
|
+
name: this._id,
|
|
45801
|
+
image: spec.image ? formatImageSpec(spec.image) : undefined,
|
|
45802
|
+
env: Object.keys(env).length > 0 ? env : undefined,
|
|
45803
|
+
labels: spec.labels,
|
|
45804
|
+
upstreamID: spec.upstreamID,
|
|
45805
|
+
kubeAccess: spec.kubeAccess,
|
|
45806
|
+
pauseAt: spec.lifecycle?.pauseAt,
|
|
45807
|
+
archiveAfterPauseTime: spec.lifecycle?.archiveAfterPauseTime
|
|
45808
|
+
});
|
|
45809
|
+
}
|
|
45810
|
+
removeUndefined(obj) {
|
|
45811
|
+
return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined));
|
|
45812
|
+
}
|
|
45724
45813
|
async getInfo() {
|
|
45725
45814
|
try {
|
|
45726
45815
|
const res = await this.api.info(this._id);
|
|
@@ -45732,10 +45821,10 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
|
45732
45821
|
this._status = { state: this.StatusAdapt(data), message: res.message };
|
|
45733
45822
|
return {
|
|
45734
45823
|
id: data.name,
|
|
45735
|
-
image:
|
|
45824
|
+
image: parseImageSpec(data.image),
|
|
45736
45825
|
entrypoint: [],
|
|
45737
45826
|
status: this._status,
|
|
45738
|
-
createdAt: new Date
|
|
45827
|
+
createdAt: data.creationTimestamp ? new Date(data.creationTimestamp) : new Date
|
|
45739
45828
|
};
|
|
45740
45829
|
} catch (error) {
|
|
45741
45830
|
throw new CommandExecutionError(`Failed to get sandbox info`, "getInfo", error instanceof Error ? error : undefined);
|
|
@@ -45773,7 +45862,10 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
|
45773
45862
|
async create() {
|
|
45774
45863
|
try {
|
|
45775
45864
|
this._status = { state: "Creating" };
|
|
45776
|
-
await this.api.create(this.
|
|
45865
|
+
const res = await this.api.create(this.buildCreateRequest());
|
|
45866
|
+
if (res.code !== 200 && res.code !== 201) {
|
|
45867
|
+
throw new Error(res.message || `Devbox create failed with code ${res.code}`);
|
|
45868
|
+
}
|
|
45777
45869
|
await this.waitUntilReady();
|
|
45778
45870
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
45779
45871
|
this._status = { state: "Running" };
|
|
@@ -45829,11 +45921,125 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
|
45829
45921
|
throw new CommandExecutionError(`Command execution failed: ${error?.message || error?.code}`, command, error instanceof Error ? error : undefined);
|
|
45830
45922
|
}
|
|
45831
45923
|
}
|
|
45924
|
+
async getEndpoint(selector) {
|
|
45925
|
+
const port = typeof selector === "number" ? selector : SEALOS_DEVBOX_CODE_SERVER_PORT;
|
|
45926
|
+
const target = await this.getHttpgateTarget(port);
|
|
45927
|
+
if (selector === "code-server") {
|
|
45928
|
+
await this.waitForCodeServerHealthz(target);
|
|
45929
|
+
}
|
|
45930
|
+
const url = new URL(target.origin);
|
|
45931
|
+
return {
|
|
45932
|
+
host: url.host,
|
|
45933
|
+
port: target.port,
|
|
45934
|
+
protocol: url.protocol === "https:" ? "https" : "http",
|
|
45935
|
+
url: joinUrlPath(target.origin, target.basePath)
|
|
45936
|
+
};
|
|
45937
|
+
}
|
|
45938
|
+
async getProxyTarget(service = "code-server") {
|
|
45939
|
+
if (service !== "code-server") {
|
|
45940
|
+
throw new FeatureNotSupportedError(`Proxy service "${service}" is not supported by this provider`, "getProxyTarget", this.provider);
|
|
45941
|
+
}
|
|
45942
|
+
const target = await this.getHttpgateTarget(SEALOS_DEVBOX_CODE_SERVER_PORT);
|
|
45943
|
+
return {
|
|
45944
|
+
service,
|
|
45945
|
+
origin: target.origin,
|
|
45946
|
+
basePath: target.basePath,
|
|
45947
|
+
auth: "code-server",
|
|
45948
|
+
...target.password ? { password: target.password } : {}
|
|
45949
|
+
};
|
|
45950
|
+
}
|
|
45951
|
+
async waitForCodeServerHealthz(target) {
|
|
45952
|
+
const healthUrl = joinUrlPath(joinUrlPath(target.origin, target.basePath), "/healthz");
|
|
45953
|
+
const timeoutMs = 60000;
|
|
45954
|
+
const intervalMs = 500;
|
|
45955
|
+
const requestTimeoutMs = 3000;
|
|
45956
|
+
const deadline = Date.now() + timeoutMs;
|
|
45957
|
+
let lastResult = "not checked";
|
|
45958
|
+
while (Date.now() < deadline) {
|
|
45959
|
+
try {
|
|
45960
|
+
const res = await fetch(healthUrl, {
|
|
45961
|
+
method: "GET",
|
|
45962
|
+
signal: AbortSignal.timeout(requestTimeoutMs)
|
|
45963
|
+
});
|
|
45964
|
+
if (res.status >= 200 && res.status < 400) {
|
|
45965
|
+
return;
|
|
45966
|
+
}
|
|
45967
|
+
lastResult = `status ${res.status}`;
|
|
45968
|
+
} catch (error) {
|
|
45969
|
+
lastResult = error instanceof Error ? error.message : String(error);
|
|
45970
|
+
}
|
|
45971
|
+
await this.sleep(intervalMs);
|
|
45972
|
+
}
|
|
45973
|
+
throw new ConnectionError(`Devbox code-server health check ${healthUrl} did not become ready within ${timeoutMs}ms. Last result: ${lastResult}`, this.config.baseUrl);
|
|
45974
|
+
}
|
|
45975
|
+
async getHttpgateTarget(port) {
|
|
45976
|
+
const res = await this.api.info(this._id);
|
|
45977
|
+
if (res.code !== 200 || !res.data) {
|
|
45978
|
+
throw new ConnectionError(`Failed to get devbox info: ${res.message}`, this.config.baseUrl);
|
|
45979
|
+
}
|
|
45980
|
+
if (port === SEALOS_DEVBOX_CODE_SERVER_PORT) {
|
|
45981
|
+
const gateway2 = res.data.codeServerGateway;
|
|
45982
|
+
if (!gateway2?.url) {
|
|
45983
|
+
throw new ConnectionError("Devbox info does not include codeServerGateway.url; cannot resolve code-server endpoint", this.config.baseUrl);
|
|
45984
|
+
}
|
|
45985
|
+
const codeServerUrl = new URL(gateway2.url);
|
|
45986
|
+
return {
|
|
45987
|
+
origin: codeServerUrl.origin,
|
|
45988
|
+
basePath: normalizePathPrefix(codeServerUrl.pathname),
|
|
45989
|
+
port: gateway2.port ?? port,
|
|
45990
|
+
password: gateway2.password
|
|
45991
|
+
};
|
|
45992
|
+
}
|
|
45993
|
+
const gatewayUrl = res.data.gateway?.url;
|
|
45994
|
+
if (!gatewayUrl) {
|
|
45995
|
+
throw new ConnectionError("Devbox info does not include gateway.url; cannot derive httpgate endpoint", this.config.baseUrl);
|
|
45996
|
+
}
|
|
45997
|
+
const gateway = new URL(gatewayUrl);
|
|
45998
|
+
const uniqueID = this.getGatewayUniqueID(res.data, gateway);
|
|
45999
|
+
const domain = this.getHttpgateDomain(gateway);
|
|
46000
|
+
return {
|
|
46001
|
+
origin: `${gateway.protocol}//devbox-${uniqueID}-${port}.${domain}`,
|
|
46002
|
+
basePath: "",
|
|
46003
|
+
port
|
|
46004
|
+
};
|
|
46005
|
+
}
|
|
46006
|
+
getGatewayUniqueID(data, gateway) {
|
|
46007
|
+
if (data.gateway?.uniqueID)
|
|
46008
|
+
return data.gateway.uniqueID;
|
|
46009
|
+
const parts = gateway.pathname.split("/").filter(Boolean);
|
|
46010
|
+
const uniqueID = parts[parts.length - 1];
|
|
46011
|
+
if (!uniqueID) {
|
|
46012
|
+
throw new ConnectionError("Devbox gateway.url does not include uniqueID; cannot derive httpgate endpoint", this.config.baseUrl);
|
|
46013
|
+
}
|
|
46014
|
+
return uniqueID;
|
|
46015
|
+
}
|
|
46016
|
+
getHttpgateDomain(gateway) {
|
|
46017
|
+
if (this.config.httpgateDomain) {
|
|
46018
|
+
return this.normalizeHttpgateDomain(this.config.httpgateDomain);
|
|
46019
|
+
}
|
|
46020
|
+
const prefix = "devbox-gateway.";
|
|
46021
|
+
if (!gateway.host.startsWith(prefix)) {
|
|
46022
|
+
throw new ConnectionError(`Cannot derive httpgate domain from gateway host "${gateway.host}"`, this.config.baseUrl);
|
|
46023
|
+
}
|
|
46024
|
+
return gateway.host.slice(prefix.length);
|
|
46025
|
+
}
|
|
46026
|
+
normalizeHttpgateDomain(domain) {
|
|
46027
|
+
const trimmed = domain.trim().replace(/^\.+|\.+$/g, "");
|
|
46028
|
+
if (!trimmed) {
|
|
46029
|
+
throw new ConnectionError("httpgateDomain is empty", this.config.baseUrl);
|
|
46030
|
+
}
|
|
46031
|
+
if (trimmed.includes("://")) {
|
|
46032
|
+
return new URL(trimmed).host;
|
|
46033
|
+
}
|
|
46034
|
+
return trimmed;
|
|
46035
|
+
}
|
|
45832
46036
|
async ping() {
|
|
45833
46037
|
try {
|
|
45834
46038
|
const res = await this.api.info(this._id);
|
|
45835
46039
|
if (res.code !== 200)
|
|
45836
46040
|
return false;
|
|
46041
|
+
if (!res.data)
|
|
46042
|
+
return false;
|
|
45837
46043
|
return res.data.state.phase === "Running" /* Running */;
|
|
45838
46044
|
} catch {
|
|
45839
46045
|
return false;
|
|
@@ -47425,7 +47631,7 @@ function createNodeFetch() {
|
|
|
47425
47631
|
const nodeFetch = async (input, init) => {
|
|
47426
47632
|
dispatcherPromise ??= (async () => {
|
|
47427
47633
|
try {
|
|
47428
|
-
const mod = await Promise.resolve().then(() => __toESM(require_undici()));
|
|
47634
|
+
const mod = await Promise.resolve().then(() => __toESM(require_undici(), 1));
|
|
47429
47635
|
const Agent = mod.Agent;
|
|
47430
47636
|
if (!Agent) {
|
|
47431
47637
|
return;
|
|
@@ -48085,27 +48291,6 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48085
48291
|
message: sdkStatus.message
|
|
48086
48292
|
};
|
|
48087
48293
|
}
|
|
48088
|
-
convertImageSpec(image) {
|
|
48089
|
-
const parts = [image.repository];
|
|
48090
|
-
if (image.tag) {
|
|
48091
|
-
parts.push(":", image.tag);
|
|
48092
|
-
}
|
|
48093
|
-
if (image.digest) {
|
|
48094
|
-
parts.push("@", image.digest);
|
|
48095
|
-
}
|
|
48096
|
-
return parts.join("");
|
|
48097
|
-
}
|
|
48098
|
-
parseImageSpec(image) {
|
|
48099
|
-
const atIndex = image.indexOf("@");
|
|
48100
|
-
if (atIndex > -1) {
|
|
48101
|
-
return { repository: image.slice(0, atIndex), digest: image.slice(atIndex + 1) };
|
|
48102
|
-
}
|
|
48103
|
-
const colonIndex = image.indexOf(":");
|
|
48104
|
-
if (colonIndex > -1) {
|
|
48105
|
-
return { repository: image.slice(0, colonIndex), tag: image.slice(colonIndex + 1) };
|
|
48106
|
-
}
|
|
48107
|
-
return { repository: image };
|
|
48108
|
-
}
|
|
48109
48294
|
convertResourceLimits(resourceLimits) {
|
|
48110
48295
|
if (!resourceLimits)
|
|
48111
48296
|
return;
|
|
@@ -48220,7 +48405,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48220
48405
|
}
|
|
48221
48406
|
try {
|
|
48222
48407
|
this._status = { state: "Creating" };
|
|
48223
|
-
const image =
|
|
48408
|
+
const image = formatImageSpec(cfg.image);
|
|
48224
48409
|
const resource = this.convertResourceLimits(cfg.resourceLimits);
|
|
48225
48410
|
this.sandbox = await Sandbox.create({
|
|
48226
48411
|
connectionConfig: this._connection,
|
|
@@ -48324,7 +48509,18 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48324
48509
|
async close() {
|
|
48325
48510
|
await this.sandbox.close();
|
|
48326
48511
|
}
|
|
48327
|
-
async getEndpoint(
|
|
48512
|
+
async getEndpoint(selector) {
|
|
48513
|
+
const port = typeof selector === "number" ? selector : OPEN_SANDBOX_EXECD_PORT;
|
|
48514
|
+
const endpoint = await this.getOpenSandboxEndpoint(port);
|
|
48515
|
+
if (selector === "code-server") {
|
|
48516
|
+
return {
|
|
48517
|
+
...endpoint,
|
|
48518
|
+
url: joinUrlPath(endpoint.url, `/proxy/${OPEN_SANDBOX_CODE_SERVER_PORT}`)
|
|
48519
|
+
};
|
|
48520
|
+
}
|
|
48521
|
+
return endpoint;
|
|
48522
|
+
}
|
|
48523
|
+
async getOpenSandboxEndpoint(port) {
|
|
48328
48524
|
const sdkEndpoint = await this.sandbox.getEndpoint(port);
|
|
48329
48525
|
const raw = sdkEndpoint.endpoint;
|
|
48330
48526
|
const colonIdx = raw.lastIndexOf(":");
|
|
@@ -48343,6 +48539,40 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48343
48539
|
url: `https://${raw}`
|
|
48344
48540
|
};
|
|
48345
48541
|
}
|
|
48542
|
+
async getProxyTarget(service = "code-server") {
|
|
48543
|
+
if (service !== "code-server") {
|
|
48544
|
+
throw new FeatureNotSupportedError(`Proxy service "${service}" is not supported by this provider`, "getProxyTarget", this.provider);
|
|
48545
|
+
}
|
|
48546
|
+
return {
|
|
48547
|
+
service,
|
|
48548
|
+
origin: await this.getDirectEndpointOrigin(OPEN_SANDBOX_EXECD_PORT),
|
|
48549
|
+
basePath: `/proxy/${OPEN_SANDBOX_CODE_SERVER_PORT}`,
|
|
48550
|
+
auth: "code-server"
|
|
48551
|
+
};
|
|
48552
|
+
}
|
|
48553
|
+
async getDirectEndpointOrigin(port) {
|
|
48554
|
+
if (!this.id) {
|
|
48555
|
+
throw new SandboxStateError("Sandbox not initialized. Call create() or connect() first.", "UnExist", "Running");
|
|
48556
|
+
}
|
|
48557
|
+
const headers = {
|
|
48558
|
+
...this._connection.headers,
|
|
48559
|
+
Accept: "application/json"
|
|
48560
|
+
};
|
|
48561
|
+
const response = await this._connection.fetch(`${this._connection.getBaseUrl()}/sandboxes/${this.id}/endpoints/${port}?use_server_proxy=false`, { method: "GET", headers });
|
|
48562
|
+
if (!response.ok) {
|
|
48563
|
+
throw new ConnectionError(`OpenSandbox endpoint lookup failed: HTTP ${response.status}`, this.connectionConfig.baseUrl);
|
|
48564
|
+
}
|
|
48565
|
+
const data = await response.json();
|
|
48566
|
+
if (!data.endpoint) {
|
|
48567
|
+
throw new ConnectionError("OpenSandbox returned no endpoint", this.connectionConfig.baseUrl);
|
|
48568
|
+
}
|
|
48569
|
+
let hostPort = data.endpoint.replace(/\/proxy\/\d+\/?$/, "");
|
|
48570
|
+
if (this.connectionConfig.replaceDockerInternalWithLocalhost) {
|
|
48571
|
+
hostPort = hostPort.replace(/^host\.docker\.internal\b/, "localhost");
|
|
48572
|
+
}
|
|
48573
|
+
const url = new URL(/^https?:\/\//.test(hostPort) ? hostPort : `http://${hostPort}`);
|
|
48574
|
+
return url.origin;
|
|
48575
|
+
}
|
|
48346
48576
|
async getInfo() {
|
|
48347
48577
|
if (!this._sandbox) {
|
|
48348
48578
|
return null;
|
|
@@ -48351,7 +48581,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48351
48581
|
const info = await this.sandbox.getInfo();
|
|
48352
48582
|
return {
|
|
48353
48583
|
id: info.id,
|
|
48354
|
-
image: typeof info.image === "string" ?
|
|
48584
|
+
image: typeof info.image === "string" ? parseImageSpec(info.image) : ("uri" in info.image) ? parseImageSpec(info.image.uri) : info.image,
|
|
48355
48585
|
entrypoint: info.entrypoint,
|
|
48356
48586
|
metadata: info.metadata,
|
|
48357
48587
|
status: this.mapStatus(info.status),
|
|
@@ -48533,7 +48763,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48533
48763
|
}
|
|
48534
48764
|
|
|
48535
48765
|
// src/adapters/E2BAdapter/index.ts
|
|
48536
|
-
var import_code_interpreter = __toESM(require_dist3());
|
|
48766
|
+
var import_code_interpreter = __toESM(require_dist3(), 1);
|
|
48537
48767
|
class E2BAdapter extends BaseSandboxAdapter {
|
|
48538
48768
|
config;
|
|
48539
48769
|
provider = "e2b";
|
|
@@ -48853,7 +49083,7 @@ function createSandbox(provider, config, createConfig) {
|
|
|
48853
49083
|
case "opensandbox":
|
|
48854
49084
|
return new OpenSandboxAdapter(config, createConfig);
|
|
48855
49085
|
case "sealosdevbox":
|
|
48856
|
-
return new SealosDevboxAdapter(config);
|
|
49086
|
+
return new SealosDevboxAdapter(config, createConfig);
|
|
48857
49087
|
case "e2b":
|
|
48858
49088
|
return new E2BAdapter(config);
|
|
48859
49089
|
default:
|
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: (
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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: (
|
|
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
|
|
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 = "/
|
|
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
|
|
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;
|
|
@@ -45372,6 +45393,12 @@ class BaseSandboxAdapter {
|
|
|
45372
45393
|
async renewExpiration(_additionalSeconds) {
|
|
45373
45394
|
throw new FeatureNotSupportedError("Sandbox expiration renewal not supported by this provider", "renewExpiration", this.provider);
|
|
45374
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
|
+
}
|
|
45375
45402
|
async executeStream(command, handlers, options) {
|
|
45376
45403
|
const result = await this.execute(command, options);
|
|
45377
45404
|
if (handlers.onStdout && result.stdout) {
|
|
@@ -45608,10 +45635,10 @@ class DevboxApi {
|
|
|
45608
45635
|
const result = await res.json();
|
|
45609
45636
|
return result;
|
|
45610
45637
|
}
|
|
45611
|
-
async create(
|
|
45638
|
+
async create(req) {
|
|
45612
45639
|
return this.request(this.url("/api/v1/devbox"), {
|
|
45613
45640
|
method: "POST",
|
|
45614
|
-
body: JSON.stringify(
|
|
45641
|
+
body: JSON.stringify(req)
|
|
45615
45642
|
});
|
|
45616
45643
|
}
|
|
45617
45644
|
async info(name) {
|
|
@@ -45669,18 +45696,60 @@ class DevboxApi {
|
|
|
45669
45696
|
}
|
|
45670
45697
|
}
|
|
45671
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
|
+
|
|
45672
45739
|
// src/adapters/SealosDevboxAdapter/index.ts
|
|
45673
45740
|
class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
45674
45741
|
config;
|
|
45742
|
+
createConfig;
|
|
45675
45743
|
provider = "sealosdevbox";
|
|
45676
45744
|
get rootPath() {
|
|
45677
45745
|
return "/home/devbox/workspace";
|
|
45678
45746
|
}
|
|
45679
45747
|
api;
|
|
45680
45748
|
_id;
|
|
45681
|
-
constructor(config) {
|
|
45749
|
+
constructor(config, createConfig) {
|
|
45682
45750
|
super();
|
|
45683
45751
|
this.config = config;
|
|
45752
|
+
this.createConfig = createConfig;
|
|
45684
45753
|
this.api = new DevboxApi({ baseUrl: config.baseUrl, token: config.token });
|
|
45685
45754
|
this._id = config.sandboxId;
|
|
45686
45755
|
this.polyfillService = new CommandPolyfillService(this);
|
|
@@ -45705,6 +45774,26 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
|
45705
45774
|
return "Error";
|
|
45706
45775
|
}
|
|
45707
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
|
+
}
|
|
45708
45797
|
async getInfo() {
|
|
45709
45798
|
try {
|
|
45710
45799
|
const res = await this.api.info(this._id);
|
|
@@ -45716,10 +45805,10 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
|
45716
45805
|
this._status = { state: this.StatusAdapt(data), message: res.message };
|
|
45717
45806
|
return {
|
|
45718
45807
|
id: data.name,
|
|
45719
|
-
image:
|
|
45808
|
+
image: parseImageSpec(data.image),
|
|
45720
45809
|
entrypoint: [],
|
|
45721
45810
|
status: this._status,
|
|
45722
|
-
createdAt: new Date
|
|
45811
|
+
createdAt: data.creationTimestamp ? new Date(data.creationTimestamp) : new Date
|
|
45723
45812
|
};
|
|
45724
45813
|
} catch (error) {
|
|
45725
45814
|
throw new CommandExecutionError(`Failed to get sandbox info`, "getInfo", error instanceof Error ? error : undefined);
|
|
@@ -45757,7 +45846,10 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
|
45757
45846
|
async create() {
|
|
45758
45847
|
try {
|
|
45759
45848
|
this._status = { state: "Creating" };
|
|
45760
|
-
await this.api.create(this.
|
|
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
|
+
}
|
|
45761
45853
|
await this.waitUntilReady();
|
|
45762
45854
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
45763
45855
|
this._status = { state: "Running" };
|
|
@@ -45813,11 +45905,125 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
|
|
|
45813
45905
|
throw new CommandExecutionError(`Command execution failed: ${error?.message || error?.code}`, command, error instanceof Error ? error : undefined);
|
|
45814
45906
|
}
|
|
45815
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
|
+
if (selector === "code-server") {
|
|
45912
|
+
await this.waitForCodeServerHealthz(target);
|
|
45913
|
+
}
|
|
45914
|
+
const url = new URL(target.origin);
|
|
45915
|
+
return {
|
|
45916
|
+
host: url.host,
|
|
45917
|
+
port: target.port,
|
|
45918
|
+
protocol: url.protocol === "https:" ? "https" : "http",
|
|
45919
|
+
url: joinUrlPath(target.origin, target.basePath)
|
|
45920
|
+
};
|
|
45921
|
+
}
|
|
45922
|
+
async getProxyTarget(service = "code-server") {
|
|
45923
|
+
if (service !== "code-server") {
|
|
45924
|
+
throw new FeatureNotSupportedError(`Proxy service "${service}" is not supported by this provider`, "getProxyTarget", this.provider);
|
|
45925
|
+
}
|
|
45926
|
+
const target = await this.getHttpgateTarget(SEALOS_DEVBOX_CODE_SERVER_PORT);
|
|
45927
|
+
return {
|
|
45928
|
+
service,
|
|
45929
|
+
origin: target.origin,
|
|
45930
|
+
basePath: target.basePath,
|
|
45931
|
+
auth: "code-server",
|
|
45932
|
+
...target.password ? { password: target.password } : {}
|
|
45933
|
+
};
|
|
45934
|
+
}
|
|
45935
|
+
async waitForCodeServerHealthz(target) {
|
|
45936
|
+
const healthUrl = joinUrlPath(joinUrlPath(target.origin, target.basePath), "/healthz");
|
|
45937
|
+
const timeoutMs = 60000;
|
|
45938
|
+
const intervalMs = 500;
|
|
45939
|
+
const requestTimeoutMs = 3000;
|
|
45940
|
+
const deadline = Date.now() + timeoutMs;
|
|
45941
|
+
let lastResult = "not checked";
|
|
45942
|
+
while (Date.now() < deadline) {
|
|
45943
|
+
try {
|
|
45944
|
+
const res = await fetch(healthUrl, {
|
|
45945
|
+
method: "GET",
|
|
45946
|
+
signal: AbortSignal.timeout(requestTimeoutMs)
|
|
45947
|
+
});
|
|
45948
|
+
if (res.status >= 200 && res.status < 400) {
|
|
45949
|
+
return;
|
|
45950
|
+
}
|
|
45951
|
+
lastResult = `status ${res.status}`;
|
|
45952
|
+
} catch (error) {
|
|
45953
|
+
lastResult = error instanceof Error ? error.message : String(error);
|
|
45954
|
+
}
|
|
45955
|
+
await this.sleep(intervalMs);
|
|
45956
|
+
}
|
|
45957
|
+
throw new ConnectionError(`Devbox code-server health check ${healthUrl} did not become ready within ${timeoutMs}ms. Last result: ${lastResult}`, this.config.baseUrl);
|
|
45958
|
+
}
|
|
45959
|
+
async getHttpgateTarget(port) {
|
|
45960
|
+
const res = await this.api.info(this._id);
|
|
45961
|
+
if (res.code !== 200 || !res.data) {
|
|
45962
|
+
throw new ConnectionError(`Failed to get devbox info: ${res.message}`, this.config.baseUrl);
|
|
45963
|
+
}
|
|
45964
|
+
if (port === SEALOS_DEVBOX_CODE_SERVER_PORT) {
|
|
45965
|
+
const gateway2 = res.data.codeServerGateway;
|
|
45966
|
+
if (!gateway2?.url) {
|
|
45967
|
+
throw new ConnectionError("Devbox info does not include codeServerGateway.url; cannot resolve code-server endpoint", this.config.baseUrl);
|
|
45968
|
+
}
|
|
45969
|
+
const codeServerUrl = new URL(gateway2.url);
|
|
45970
|
+
return {
|
|
45971
|
+
origin: codeServerUrl.origin,
|
|
45972
|
+
basePath: normalizePathPrefix(codeServerUrl.pathname),
|
|
45973
|
+
port: gateway2.port ?? port,
|
|
45974
|
+
password: gateway2.password
|
|
45975
|
+
};
|
|
45976
|
+
}
|
|
45977
|
+
const gatewayUrl = res.data.gateway?.url;
|
|
45978
|
+
if (!gatewayUrl) {
|
|
45979
|
+
throw new ConnectionError("Devbox info does not include gateway.url; cannot derive httpgate endpoint", this.config.baseUrl);
|
|
45980
|
+
}
|
|
45981
|
+
const gateway = new URL(gatewayUrl);
|
|
45982
|
+
const uniqueID = this.getGatewayUniqueID(res.data, gateway);
|
|
45983
|
+
const domain = this.getHttpgateDomain(gateway);
|
|
45984
|
+
return {
|
|
45985
|
+
origin: `${gateway.protocol}//devbox-${uniqueID}-${port}.${domain}`,
|
|
45986
|
+
basePath: "",
|
|
45987
|
+
port
|
|
45988
|
+
};
|
|
45989
|
+
}
|
|
45990
|
+
getGatewayUniqueID(data, gateway) {
|
|
45991
|
+
if (data.gateway?.uniqueID)
|
|
45992
|
+
return data.gateway.uniqueID;
|
|
45993
|
+
const parts = gateway.pathname.split("/").filter(Boolean);
|
|
45994
|
+
const uniqueID = parts[parts.length - 1];
|
|
45995
|
+
if (!uniqueID) {
|
|
45996
|
+
throw new ConnectionError("Devbox gateway.url does not include uniqueID; cannot derive httpgate endpoint", this.config.baseUrl);
|
|
45997
|
+
}
|
|
45998
|
+
return uniqueID;
|
|
45999
|
+
}
|
|
46000
|
+
getHttpgateDomain(gateway) {
|
|
46001
|
+
if (this.config.httpgateDomain) {
|
|
46002
|
+
return this.normalizeHttpgateDomain(this.config.httpgateDomain);
|
|
46003
|
+
}
|
|
46004
|
+
const prefix = "devbox-gateway.";
|
|
46005
|
+
if (!gateway.host.startsWith(prefix)) {
|
|
46006
|
+
throw new ConnectionError(`Cannot derive httpgate domain from gateway host "${gateway.host}"`, this.config.baseUrl);
|
|
46007
|
+
}
|
|
46008
|
+
return gateway.host.slice(prefix.length);
|
|
46009
|
+
}
|
|
46010
|
+
normalizeHttpgateDomain(domain) {
|
|
46011
|
+
const trimmed = domain.trim().replace(/^\.+|\.+$/g, "");
|
|
46012
|
+
if (!trimmed) {
|
|
46013
|
+
throw new ConnectionError("httpgateDomain is empty", this.config.baseUrl);
|
|
46014
|
+
}
|
|
46015
|
+
if (trimmed.includes("://")) {
|
|
46016
|
+
return new URL(trimmed).host;
|
|
46017
|
+
}
|
|
46018
|
+
return trimmed;
|
|
46019
|
+
}
|
|
45816
46020
|
async ping() {
|
|
45817
46021
|
try {
|
|
45818
46022
|
const res = await this.api.info(this._id);
|
|
45819
46023
|
if (res.code !== 200)
|
|
45820
46024
|
return false;
|
|
46025
|
+
if (!res.data)
|
|
46026
|
+
return false;
|
|
45821
46027
|
return res.data.state.phase === "Running" /* Running */;
|
|
45822
46028
|
} catch {
|
|
45823
46029
|
return false;
|
|
@@ -48069,27 +48275,6 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48069
48275
|
message: sdkStatus.message
|
|
48070
48276
|
};
|
|
48071
48277
|
}
|
|
48072
|
-
convertImageSpec(image) {
|
|
48073
|
-
const parts = [image.repository];
|
|
48074
|
-
if (image.tag) {
|
|
48075
|
-
parts.push(":", image.tag);
|
|
48076
|
-
}
|
|
48077
|
-
if (image.digest) {
|
|
48078
|
-
parts.push("@", image.digest);
|
|
48079
|
-
}
|
|
48080
|
-
return parts.join("");
|
|
48081
|
-
}
|
|
48082
|
-
parseImageSpec(image) {
|
|
48083
|
-
const atIndex = image.indexOf("@");
|
|
48084
|
-
if (atIndex > -1) {
|
|
48085
|
-
return { repository: image.slice(0, atIndex), digest: image.slice(atIndex + 1) };
|
|
48086
|
-
}
|
|
48087
|
-
const colonIndex = image.indexOf(":");
|
|
48088
|
-
if (colonIndex > -1) {
|
|
48089
|
-
return { repository: image.slice(0, colonIndex), tag: image.slice(colonIndex + 1) };
|
|
48090
|
-
}
|
|
48091
|
-
return { repository: image };
|
|
48092
|
-
}
|
|
48093
48278
|
convertResourceLimits(resourceLimits) {
|
|
48094
48279
|
if (!resourceLimits)
|
|
48095
48280
|
return;
|
|
@@ -48204,7 +48389,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48204
48389
|
}
|
|
48205
48390
|
try {
|
|
48206
48391
|
this._status = { state: "Creating" };
|
|
48207
|
-
const image =
|
|
48392
|
+
const image = formatImageSpec(cfg.image);
|
|
48208
48393
|
const resource = this.convertResourceLimits(cfg.resourceLimits);
|
|
48209
48394
|
this.sandbox = await Sandbox.create({
|
|
48210
48395
|
connectionConfig: this._connection,
|
|
@@ -48308,7 +48493,18 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48308
48493
|
async close() {
|
|
48309
48494
|
await this.sandbox.close();
|
|
48310
48495
|
}
|
|
48311
|
-
async getEndpoint(
|
|
48496
|
+
async getEndpoint(selector) {
|
|
48497
|
+
const port = typeof selector === "number" ? selector : OPEN_SANDBOX_EXECD_PORT;
|
|
48498
|
+
const endpoint = await this.getOpenSandboxEndpoint(port);
|
|
48499
|
+
if (selector === "code-server") {
|
|
48500
|
+
return {
|
|
48501
|
+
...endpoint,
|
|
48502
|
+
url: joinUrlPath(endpoint.url, `/proxy/${OPEN_SANDBOX_CODE_SERVER_PORT}`)
|
|
48503
|
+
};
|
|
48504
|
+
}
|
|
48505
|
+
return endpoint;
|
|
48506
|
+
}
|
|
48507
|
+
async getOpenSandboxEndpoint(port) {
|
|
48312
48508
|
const sdkEndpoint = await this.sandbox.getEndpoint(port);
|
|
48313
48509
|
const raw = sdkEndpoint.endpoint;
|
|
48314
48510
|
const colonIdx = raw.lastIndexOf(":");
|
|
@@ -48327,6 +48523,40 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48327
48523
|
url: `https://${raw}`
|
|
48328
48524
|
};
|
|
48329
48525
|
}
|
|
48526
|
+
async getProxyTarget(service = "code-server") {
|
|
48527
|
+
if (service !== "code-server") {
|
|
48528
|
+
throw new FeatureNotSupportedError(`Proxy service "${service}" is not supported by this provider`, "getProxyTarget", this.provider);
|
|
48529
|
+
}
|
|
48530
|
+
return {
|
|
48531
|
+
service,
|
|
48532
|
+
origin: await this.getDirectEndpointOrigin(OPEN_SANDBOX_EXECD_PORT),
|
|
48533
|
+
basePath: `/proxy/${OPEN_SANDBOX_CODE_SERVER_PORT}`,
|
|
48534
|
+
auth: "code-server"
|
|
48535
|
+
};
|
|
48536
|
+
}
|
|
48537
|
+
async getDirectEndpointOrigin(port) {
|
|
48538
|
+
if (!this.id) {
|
|
48539
|
+
throw new SandboxStateError("Sandbox not initialized. Call create() or connect() first.", "UnExist", "Running");
|
|
48540
|
+
}
|
|
48541
|
+
const headers = {
|
|
48542
|
+
...this._connection.headers,
|
|
48543
|
+
Accept: "application/json"
|
|
48544
|
+
};
|
|
48545
|
+
const response = await this._connection.fetch(`${this._connection.getBaseUrl()}/sandboxes/${this.id}/endpoints/${port}?use_server_proxy=false`, { method: "GET", headers });
|
|
48546
|
+
if (!response.ok) {
|
|
48547
|
+
throw new ConnectionError(`OpenSandbox endpoint lookup failed: HTTP ${response.status}`, this.connectionConfig.baseUrl);
|
|
48548
|
+
}
|
|
48549
|
+
const data = await response.json();
|
|
48550
|
+
if (!data.endpoint) {
|
|
48551
|
+
throw new ConnectionError("OpenSandbox returned no endpoint", this.connectionConfig.baseUrl);
|
|
48552
|
+
}
|
|
48553
|
+
let hostPort = data.endpoint.replace(/\/proxy\/\d+\/?$/, "");
|
|
48554
|
+
if (this.connectionConfig.replaceDockerInternalWithLocalhost) {
|
|
48555
|
+
hostPort = hostPort.replace(/^host\.docker\.internal\b/, "localhost");
|
|
48556
|
+
}
|
|
48557
|
+
const url = new URL(/^https?:\/\//.test(hostPort) ? hostPort : `http://${hostPort}`);
|
|
48558
|
+
return url.origin;
|
|
48559
|
+
}
|
|
48330
48560
|
async getInfo() {
|
|
48331
48561
|
if (!this._sandbox) {
|
|
48332
48562
|
return null;
|
|
@@ -48335,7 +48565,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
|
48335
48565
|
const info = await this.sandbox.getInfo();
|
|
48336
48566
|
return {
|
|
48337
48567
|
id: info.id,
|
|
48338
|
-
image: typeof info.image === "string" ?
|
|
48568
|
+
image: typeof info.image === "string" ? parseImageSpec(info.image) : ("uri" in info.image) ? parseImageSpec(info.image.uri) : info.image,
|
|
48339
48569
|
entrypoint: info.entrypoint,
|
|
48340
48570
|
metadata: info.metadata,
|
|
48341
48571
|
status: this.mapStatus(info.status),
|
|
@@ -48837,7 +49067,7 @@ function createSandbox(provider, config, createConfig) {
|
|
|
48837
49067
|
case "opensandbox":
|
|
48838
49068
|
return new OpenSandboxAdapter(config, createConfig);
|
|
48839
49069
|
case "sealosdevbox":
|
|
48840
|
-
return new SealosDevboxAdapter(config);
|
|
49070
|
+
return new SealosDevboxAdapter(config, createConfig);
|
|
48841
49071
|
case "e2b":
|
|
48842
49072
|
return new E2BAdapter(config);
|
|
48843
49073
|
default:
|
|
@@ -2,6 +2,7 @@ import type { ICommandExecution } from './ICommandExecution';
|
|
|
2
2
|
import type { IFileSystem } from './IFileSystem';
|
|
3
3
|
import type { IHealthCheck } from './IHealthCheck';
|
|
4
4
|
import type { ISandboxLifecycle } from './ISandboxLifecycle';
|
|
5
|
+
import type { Endpoint, SandboxEndpointSelector, SandboxProxyService, SandboxProxyTarget } from '../types';
|
|
5
6
|
/**
|
|
6
7
|
* Unified sandbox interface.
|
|
7
8
|
* Composes all sandbox behaviors into a single interface.
|
|
@@ -15,4 +16,8 @@ import type { ISandboxLifecycle } from './ISandboxLifecycle';
|
|
|
15
16
|
export interface ISandbox extends ISandboxLifecycle, ICommandExecution, IFileSystem, IHealthCheck {
|
|
16
17
|
/** Provider name (e.g., 'opensandbox') */
|
|
17
18
|
readonly provider: string;
|
|
19
|
+
/** Resolve an endpoint exposed by the sandbox provider. */
|
|
20
|
+
getEndpoint(selector: SandboxEndpointSelector): Promise<Endpoint>;
|
|
21
|
+
/** Resolve the upstream target used by FastGPT sandbox-proxy. */
|
|
22
|
+
getProxyTarget(service?: SandboxProxyService): Promise<SandboxProxyTarget>;
|
|
18
23
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export type { BackgroundExecution, ExecuteOptions, ExecuteResult, OutputMessage, StreamHandlers } from './execution';
|
|
2
2
|
export type { ContentReplaceEntry, DirectoryEntry, FileDeleteResult, FileInfo, FileReadResult, FileWriteEntry, FileWriteResult, MoveEntry, PermissionEntry, ReadFileOptions, SearchResult } from './filesystem';
|
|
3
|
-
export type { Endpoint, ImageSpec, NetworkPolicy, ResourceLimits, SandboxId, SandboxInfo, SandboxMetrics, SandboxState, SandboxStatus } from './sandbox';
|
|
3
|
+
export type { Endpoint, ImageSpec, KubeAccessPolicy, LabelSpec, LifecyclePolicy, NetworkPolicy, ResourceLimits, SandboxCreateSpec, SandboxEndpointSelector, SandboxId, SandboxInfo, SandboxMetrics, SandboxProxyService, SandboxProxyTarget, SandboxState, SandboxStatus } from './sandbox';
|
package/dist/types/sandbox.d.ts
CHANGED
|
@@ -37,6 +37,18 @@ export interface NetworkPolicy {
|
|
|
37
37
|
allowEgress?: boolean;
|
|
38
38
|
allowedHosts?: string[];
|
|
39
39
|
}
|
|
40
|
+
export interface LabelSpec {
|
|
41
|
+
key: string;
|
|
42
|
+
value: string;
|
|
43
|
+
}
|
|
44
|
+
export interface LifecyclePolicy {
|
|
45
|
+
pauseAt?: string;
|
|
46
|
+
archiveAfterPauseTime?: string;
|
|
47
|
+
}
|
|
48
|
+
export interface KubeAccessPolicy {
|
|
49
|
+
enabled?: boolean;
|
|
50
|
+
roleTemplate?: 'view' | 'edit' | 'admin';
|
|
51
|
+
}
|
|
40
52
|
/**
|
|
41
53
|
* Information about a sandbox.
|
|
42
54
|
*/
|
|
@@ -69,3 +81,36 @@ export interface Endpoint {
|
|
|
69
81
|
protocol: 'http' | 'https';
|
|
70
82
|
url: string;
|
|
71
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* App-facing create spec shared by callers that choose a provider at runtime.
|
|
86
|
+
* Individual adapters should map only the fields their backend actually supports.
|
|
87
|
+
*/
|
|
88
|
+
export interface SandboxCreateSpec {
|
|
89
|
+
image?: ImageSpec;
|
|
90
|
+
entrypoint?: string[];
|
|
91
|
+
timeout?: number;
|
|
92
|
+
timeoutSeconds?: number | null;
|
|
93
|
+
resourceLimits?: ResourceLimits;
|
|
94
|
+
env?: Record<string, string>;
|
|
95
|
+
metadata?: Record<string, unknown>;
|
|
96
|
+
labels?: LabelSpec[];
|
|
97
|
+
lifecycle?: LifecyclePolicy;
|
|
98
|
+
kubeAccess?: KubeAccessPolicy;
|
|
99
|
+
networkPolicy?: NetworkPolicy;
|
|
100
|
+
volumes?: unknown[];
|
|
101
|
+
workingDir?: string;
|
|
102
|
+
upstreamID?: string;
|
|
103
|
+
extensions?: Record<string, unknown>;
|
|
104
|
+
skipHealthCheck?: boolean;
|
|
105
|
+
readyTimeoutSeconds?: number;
|
|
106
|
+
healthCheckPollingInterval?: number;
|
|
107
|
+
}
|
|
108
|
+
export type SandboxProxyService = 'code-server';
|
|
109
|
+
export type SandboxEndpointSelector = number | SandboxProxyService;
|
|
110
|
+
export interface SandboxProxyTarget {
|
|
111
|
+
service: SandboxProxyService;
|
|
112
|
+
origin: string;
|
|
113
|
+
basePath: string;
|
|
114
|
+
auth: 'code-server';
|
|
115
|
+
password?: string;
|
|
116
|
+
}
|
package/package.json
CHANGED