@agent-vm/openclaw-agent-vm-plugin 0.0.20
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/LICENSE +21 -0
- package/dist/index.d.ts +293 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +285 -0
- package/dist/index.js.map +1 -0
- package/dist/openclaw.plugin.json +20 -0
- package/dist/sdk-validate.mjs +42 -0
- package/package.json +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Shravan Sunder
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
//#region src/controller-lease-client.d.ts
|
|
2
|
+
interface GondolinLeaseResponse {
|
|
3
|
+
readonly leaseId: string;
|
|
4
|
+
readonly ssh: {
|
|
5
|
+
readonly host: string;
|
|
6
|
+
readonly identityPem: string;
|
|
7
|
+
readonly knownHostsLine: string;
|
|
8
|
+
readonly port: number;
|
|
9
|
+
readonly user: string;
|
|
10
|
+
};
|
|
11
|
+
readonly tcpSlot: number;
|
|
12
|
+
readonly workdir: string;
|
|
13
|
+
}
|
|
14
|
+
interface LeaseClient {
|
|
15
|
+
getLeaseStatus(leaseId: string): Promise<unknown>;
|
|
16
|
+
releaseLease(leaseId: string): Promise<void>;
|
|
17
|
+
requestLease(request: {
|
|
18
|
+
readonly agentWorkspaceDir: string;
|
|
19
|
+
readonly profileId: string;
|
|
20
|
+
readonly scopeKey: string;
|
|
21
|
+
readonly workspaceDir: string;
|
|
22
|
+
readonly zoneId: string;
|
|
23
|
+
}): Promise<GondolinLeaseResponse>;
|
|
24
|
+
}
|
|
25
|
+
declare function createLeaseClient(options: {
|
|
26
|
+
readonly controllerUrl: string;
|
|
27
|
+
readonly fetchImpl?: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
28
|
+
}): LeaseClient;
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/sandbox-backend/sandbox-backend-contract.d.ts
|
|
31
|
+
interface FsBridgeLeaseContext {
|
|
32
|
+
readonly remoteAgentWorkspaceDir: string;
|
|
33
|
+
readonly remoteWorkspaceDir: string;
|
|
34
|
+
readonly runRemoteShellScript: (params: {
|
|
35
|
+
readonly allowFailure?: boolean;
|
|
36
|
+
readonly args?: string[];
|
|
37
|
+
readonly script: string;
|
|
38
|
+
readonly signal?: AbortSignal;
|
|
39
|
+
readonly stdin?: Buffer | string;
|
|
40
|
+
}) => Promise<{
|
|
41
|
+
readonly code: number;
|
|
42
|
+
readonly stderr: Buffer;
|
|
43
|
+
readonly stdout: Buffer;
|
|
44
|
+
}>;
|
|
45
|
+
}
|
|
46
|
+
interface GondolinFsBridge {
|
|
47
|
+
mkdirp(params: {
|
|
48
|
+
readonly cwd?: string;
|
|
49
|
+
readonly filePath: string;
|
|
50
|
+
readonly signal?: AbortSignal;
|
|
51
|
+
}): Promise<void>;
|
|
52
|
+
readFile(params: {
|
|
53
|
+
readonly cwd?: string;
|
|
54
|
+
readonly filePath: string;
|
|
55
|
+
readonly signal?: AbortSignal;
|
|
56
|
+
}): Promise<Buffer>;
|
|
57
|
+
remove(params: {
|
|
58
|
+
readonly cwd?: string;
|
|
59
|
+
readonly filePath: string;
|
|
60
|
+
readonly force?: boolean;
|
|
61
|
+
readonly recursive?: boolean;
|
|
62
|
+
readonly signal?: AbortSignal;
|
|
63
|
+
}): Promise<void>;
|
|
64
|
+
rename(params: {
|
|
65
|
+
readonly cwd?: string;
|
|
66
|
+
readonly from: string;
|
|
67
|
+
readonly signal?: AbortSignal;
|
|
68
|
+
readonly to: string;
|
|
69
|
+
}): Promise<void>;
|
|
70
|
+
resolvePath(params: {
|
|
71
|
+
readonly cwd?: string;
|
|
72
|
+
readonly filePath: string;
|
|
73
|
+
}): {
|
|
74
|
+
readonly containerPath: string;
|
|
75
|
+
readonly relativePath: string;
|
|
76
|
+
};
|
|
77
|
+
stat(params: {
|
|
78
|
+
readonly cwd?: string;
|
|
79
|
+
readonly filePath: string;
|
|
80
|
+
readonly signal?: AbortSignal;
|
|
81
|
+
}): Promise<{
|
|
82
|
+
readonly mtimeMs: number;
|
|
83
|
+
readonly size: number;
|
|
84
|
+
readonly type: 'directory' | 'file' | 'other';
|
|
85
|
+
} | null>;
|
|
86
|
+
writeFile(params: {
|
|
87
|
+
readonly cwd?: string;
|
|
88
|
+
readonly data: Buffer | string;
|
|
89
|
+
readonly encoding?: BufferEncoding;
|
|
90
|
+
readonly filePath: string;
|
|
91
|
+
readonly mkdir?: boolean;
|
|
92
|
+
readonly signal?: AbortSignal;
|
|
93
|
+
}): Promise<void>;
|
|
94
|
+
}
|
|
95
|
+
interface CreateBackendDependencies {
|
|
96
|
+
readonly buildExecSpec: (params: {
|
|
97
|
+
readonly command: string;
|
|
98
|
+
readonly env: Record<string, string>;
|
|
99
|
+
readonly ssh: GondolinLeaseResponse['ssh'];
|
|
100
|
+
readonly usePty: boolean;
|
|
101
|
+
readonly workdir: string;
|
|
102
|
+
}) => Promise<{
|
|
103
|
+
readonly argv: string[];
|
|
104
|
+
readonly env: Record<string, string>;
|
|
105
|
+
readonly finalizeToken?: unknown;
|
|
106
|
+
readonly stdinMode: 'pipe-open' | 'pipe-closed';
|
|
107
|
+
}>;
|
|
108
|
+
readonly createFsBridgeBuilder?: (leaseContext: FsBridgeLeaseContext) => (params: {
|
|
109
|
+
readonly sandbox: unknown;
|
|
110
|
+
}) => GondolinFsBridge;
|
|
111
|
+
readonly createLeaseClient?: (options: {
|
|
112
|
+
readonly controllerUrl: string;
|
|
113
|
+
}) => LeaseClient;
|
|
114
|
+
readonly runRemoteShellScript: (params: {
|
|
115
|
+
readonly allowFailure?: boolean;
|
|
116
|
+
readonly script: string;
|
|
117
|
+
readonly signal?: AbortSignal;
|
|
118
|
+
readonly ssh: GondolinLeaseResponse['ssh'];
|
|
119
|
+
readonly stdin?: Buffer | string;
|
|
120
|
+
}) => Promise<{
|
|
121
|
+
readonly code: number;
|
|
122
|
+
readonly stderr: Buffer;
|
|
123
|
+
readonly stdout: Buffer;
|
|
124
|
+
}>;
|
|
125
|
+
}
|
|
126
|
+
interface GondolinSandboxBackendHandle {
|
|
127
|
+
readonly configLabel?: string;
|
|
128
|
+
readonly configLabelKind?: string;
|
|
129
|
+
createFsBridge?: (params: {
|
|
130
|
+
readonly sandbox: unknown;
|
|
131
|
+
}) => GondolinFsBridge;
|
|
132
|
+
env?: Record<string, string>;
|
|
133
|
+
readonly id: string;
|
|
134
|
+
readonly runtimeId: string;
|
|
135
|
+
readonly runtimeLabel: string;
|
|
136
|
+
readonly workdir: string;
|
|
137
|
+
buildExecSpec(params: {
|
|
138
|
+
readonly command: string;
|
|
139
|
+
readonly env: Record<string, string>;
|
|
140
|
+
readonly usePty: boolean;
|
|
141
|
+
readonly workdir?: string;
|
|
142
|
+
}): Promise<{
|
|
143
|
+
readonly argv: string[];
|
|
144
|
+
readonly env: Record<string, string>;
|
|
145
|
+
readonly finalizeToken?: unknown;
|
|
146
|
+
readonly stdinMode: 'pipe-open' | 'pipe-closed';
|
|
147
|
+
}>;
|
|
148
|
+
finalizeExec?: (params: {
|
|
149
|
+
readonly exitCode: number | null;
|
|
150
|
+
readonly status: 'completed' | 'failed';
|
|
151
|
+
readonly timedOut: boolean;
|
|
152
|
+
readonly token?: unknown;
|
|
153
|
+
}) => Promise<void>;
|
|
154
|
+
runShellCommand(params: {
|
|
155
|
+
readonly script: string;
|
|
156
|
+
}): Promise<{
|
|
157
|
+
readonly code: number;
|
|
158
|
+
readonly stderr: Buffer;
|
|
159
|
+
readonly stdout: Buffer;
|
|
160
|
+
}>;
|
|
161
|
+
}
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region src/sandbox-backend/sandbox-backend-handle-factory.d.ts
|
|
164
|
+
declare function createGondolinSandboxBackendFactory(options: {
|
|
165
|
+
readonly controllerUrl: string;
|
|
166
|
+
readonly profileId?: string;
|
|
167
|
+
readonly zoneId: string;
|
|
168
|
+
}, dependencies: CreateBackendDependencies): (params: {
|
|
169
|
+
readonly agentWorkspaceDir: string;
|
|
170
|
+
readonly cfg: {
|
|
171
|
+
readonly docker?: {
|
|
172
|
+
readonly env?: Record<string, string>;
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
readonly scopeKey: string;
|
|
176
|
+
readonly sessionKey: string;
|
|
177
|
+
readonly workspaceDir: string;
|
|
178
|
+
}) => Promise<GondolinSandboxBackendHandle>;
|
|
179
|
+
//#endregion
|
|
180
|
+
//#region src/sandbox-backend/sandbox-backend-manager.d.ts
|
|
181
|
+
declare function createGondolinSandboxBackendManager(options: {
|
|
182
|
+
readonly controllerUrl: string;
|
|
183
|
+
readonly zoneId: string;
|
|
184
|
+
}, dependencies: CreateBackendDependencies): {
|
|
185
|
+
describeRuntime: (params: {
|
|
186
|
+
readonly entry: {
|
|
187
|
+
readonly containerName: string;
|
|
188
|
+
};
|
|
189
|
+
}) => Promise<{
|
|
190
|
+
readonly configLabelMatch: boolean;
|
|
191
|
+
readonly running: boolean;
|
|
192
|
+
}>;
|
|
193
|
+
removeRuntime: (params: {
|
|
194
|
+
readonly entry: {
|
|
195
|
+
readonly containerName: string;
|
|
196
|
+
};
|
|
197
|
+
}) => Promise<void>;
|
|
198
|
+
};
|
|
199
|
+
//#endregion
|
|
200
|
+
//#region src/gondolin-plugin-config.d.ts
|
|
201
|
+
interface ResolvedGondolinPluginConfig {
|
|
202
|
+
readonly controllerUrl: string;
|
|
203
|
+
readonly profileId?: string;
|
|
204
|
+
readonly zoneId: string;
|
|
205
|
+
}
|
|
206
|
+
declare function resolveGondolinPluginConfig(config: Record<string, unknown>): ResolvedGondolinPluginConfig;
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/openclaw-sandbox-sdk-contract.d.ts
|
|
209
|
+
interface SshSandboxSession {
|
|
210
|
+
readonly command: string;
|
|
211
|
+
readonly configPath: string;
|
|
212
|
+
readonly host: string;
|
|
213
|
+
}
|
|
214
|
+
interface SshHelpers {
|
|
215
|
+
readonly buildExecRemoteCommand: (params: {
|
|
216
|
+
readonly command: string;
|
|
217
|
+
readonly env: Record<string, string>;
|
|
218
|
+
readonly workdir?: string;
|
|
219
|
+
}) => string;
|
|
220
|
+
readonly buildRemoteCommand: (argv: readonly string[]) => string;
|
|
221
|
+
readonly buildSshSandboxArgv: (params: {
|
|
222
|
+
readonly remoteCommand: string;
|
|
223
|
+
readonly session: SshSandboxSession;
|
|
224
|
+
readonly tty?: boolean;
|
|
225
|
+
}) => string[];
|
|
226
|
+
readonly createRemoteShellSandboxFsBridge: (params: {
|
|
227
|
+
readonly runtime: {
|
|
228
|
+
readonly remoteAgentWorkspaceDir: string;
|
|
229
|
+
readonly remoteWorkspaceDir: string;
|
|
230
|
+
readonly runRemoteShellScript: (shellParams: {
|
|
231
|
+
readonly allowFailure?: boolean;
|
|
232
|
+
readonly args?: string[];
|
|
233
|
+
readonly script: string;
|
|
234
|
+
readonly signal?: AbortSignal;
|
|
235
|
+
readonly stdin?: Buffer | string;
|
|
236
|
+
}) => Promise<{
|
|
237
|
+
readonly code: number;
|
|
238
|
+
readonly stderr: Buffer;
|
|
239
|
+
readonly stdout: Buffer;
|
|
240
|
+
}>;
|
|
241
|
+
};
|
|
242
|
+
readonly sandbox: unknown;
|
|
243
|
+
}) => GondolinFsBridge;
|
|
244
|
+
readonly createSshSandboxSessionFromSettings: (settings: {
|
|
245
|
+
readonly command: string;
|
|
246
|
+
readonly identityData?: string;
|
|
247
|
+
readonly strictHostKeyChecking: boolean;
|
|
248
|
+
readonly target: string;
|
|
249
|
+
readonly updateHostKeys: boolean;
|
|
250
|
+
readonly workspaceRoot: string;
|
|
251
|
+
}) => Promise<SshSandboxSession>;
|
|
252
|
+
readonly disposeSshSandboxSession?: (session: SshSandboxSession) => Promise<void>;
|
|
253
|
+
readonly runSshSandboxCommand: (params: {
|
|
254
|
+
readonly allowFailure?: boolean;
|
|
255
|
+
readonly remoteCommand: string;
|
|
256
|
+
readonly session: SshSandboxSession;
|
|
257
|
+
readonly signal?: AbortSignal;
|
|
258
|
+
readonly stdin?: Buffer | string;
|
|
259
|
+
}) => Promise<{
|
|
260
|
+
readonly code: number;
|
|
261
|
+
readonly stderr: Buffer;
|
|
262
|
+
readonly stdout: Buffer;
|
|
263
|
+
}>;
|
|
264
|
+
readonly sanitizeEnvVars: (env: NodeJS.ProcessEnv) => {
|
|
265
|
+
readonly allowed: Record<string, string>;
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
//#endregion
|
|
269
|
+
//#region src/openclaw-backend-dependencies.d.ts
|
|
270
|
+
declare function createBackendDeps(ssh: SshHelpers): {
|
|
271
|
+
readonly buildExecSpec: CreateBackendDependencies['buildExecSpec'];
|
|
272
|
+
readonly createFsBridgeBuilder: (leaseContext: FsBridgeLeaseContext) => (params: {
|
|
273
|
+
readonly sandbox: unknown;
|
|
274
|
+
}) => GondolinFsBridge;
|
|
275
|
+
readonly runRemoteShellScript: CreateBackendDependencies['runRemoteShellScript'];
|
|
276
|
+
};
|
|
277
|
+
//#endregion
|
|
278
|
+
//#region src/openclaw-plugin-registration.d.ts
|
|
279
|
+
declare const plugin: {
|
|
280
|
+
id: string;
|
|
281
|
+
name: string;
|
|
282
|
+
description: string;
|
|
283
|
+
register(api: {
|
|
284
|
+
readonly pluginConfig: Record<string, unknown>;
|
|
285
|
+
readonly registrationMode: string;
|
|
286
|
+
}): void;
|
|
287
|
+
};
|
|
288
|
+
//#endregion
|
|
289
|
+
//#region src/index.d.ts
|
|
290
|
+
declare const OPENCLAW_GONDOLIN_PLUGIN_PACKAGE_NAME = "@agent-vm/openclaw-agent-vm-plugin";
|
|
291
|
+
//#endregion
|
|
292
|
+
export { CreateBackendDependencies, FsBridgeLeaseContext, GondolinFsBridge, GondolinLeaseResponse, GondolinSandboxBackendHandle, LeaseClient, OPENCLAW_GONDOLIN_PLUGIN_PACKAGE_NAME, ResolvedGondolinPluginConfig, type SshHelpers, createBackendDeps, createGondolinSandboxBackendFactory, createGondolinSandboxBackendManager, createLeaseClient, plugin as default, resolveGondolinPluginConfig };
|
|
293
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/controller-lease-client.ts","../src/sandbox-backend/sandbox-backend-contract.ts","../src/sandbox-backend/sandbox-backend-handle-factory.ts","../src/sandbox-backend/sandbox-backend-manager.ts","../src/gondolin-plugin-config.ts","../src/openclaw-sandbox-sdk-contract.ts","../src/openclaw-backend-dependencies.ts","../src/openclaw-plugin-registration.ts","../src/index.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
//#region src/controller-lease-client.ts
|
|
2
|
+
function isGondolinLeaseResponse$1(value) {
|
|
3
|
+
return typeof value === "object" && value !== null && typeof value.leaseId === "string" && typeof value.tcpSlot === "number" && typeof value.workdir === "string";
|
|
4
|
+
}
|
|
5
|
+
function createLeaseClient(options) {
|
|
6
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
7
|
+
const baseUrl = options.controllerUrl.replace(/\/$/u, "");
|
|
8
|
+
return {
|
|
9
|
+
getLeaseStatus: async (leaseId) => {
|
|
10
|
+
const response = await fetchImpl(`${baseUrl}/lease/${leaseId}`);
|
|
11
|
+
if (!response.ok) {
|
|
12
|
+
const errorBody = await response.text().catch(() => "(unreadable)");
|
|
13
|
+
throw new TypeError(`Controller lease status API returned HTTP ${response.status}: ${errorBody}`);
|
|
14
|
+
}
|
|
15
|
+
return await response.json();
|
|
16
|
+
},
|
|
17
|
+
releaseLease: async (leaseId) => {
|
|
18
|
+
await fetchImpl(`${baseUrl}/lease/${leaseId}`, { method: "DELETE" });
|
|
19
|
+
},
|
|
20
|
+
requestLease: async (request) => {
|
|
21
|
+
const response = await fetchImpl(`${baseUrl}/lease`, {
|
|
22
|
+
body: JSON.stringify(request),
|
|
23
|
+
headers: { "content-type": "application/json" },
|
|
24
|
+
method: "POST"
|
|
25
|
+
});
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
const errorBody = await response.text().catch(() => "(unreadable)");
|
|
28
|
+
throw new TypeError(`Controller lease API returned HTTP ${response.status}: ${errorBody}`);
|
|
29
|
+
}
|
|
30
|
+
const payload = await response.json();
|
|
31
|
+
if (!isGondolinLeaseResponse$1(payload)) throw new TypeError(`Controller returned an invalid lease response: ${JSON.stringify(payload).slice(0, 200)}`);
|
|
32
|
+
return payload;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/sandbox-backend/sandbox-backend-contract.ts
|
|
39
|
+
function isGondolinLeaseResponse(value) {
|
|
40
|
+
return typeof value === "object" && value !== null && typeof value.leaseId === "string" && typeof value.tcpSlot === "number" && typeof value.workdir === "string" && typeof value.ssh === "object" && value.ssh !== null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/sandbox-backend/sandbox-shell-script.ts
|
|
45
|
+
function buildShellScriptWithArgs(script, args) {
|
|
46
|
+
if (!args || args.length === 0) return script;
|
|
47
|
+
return `set -- ${args.map((arg) => `'${arg.replace(/'/g, "'\\''")}'`).join(" ")}; ${script}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/sandbox-backend/sandbox-backend-handle-factory.ts
|
|
52
|
+
function createGondolinSandboxBackendFactory(options, dependencies) {
|
|
53
|
+
const scopeCache = /* @__PURE__ */ new Map();
|
|
54
|
+
return async (params) => {
|
|
55
|
+
const leaseClient = dependencies.createLeaseClient?.({ controllerUrl: options.controllerUrl }) ?? createLeaseClient({ controllerUrl: options.controllerUrl });
|
|
56
|
+
const cachedEntry = scopeCache.get(params.scopeKey);
|
|
57
|
+
if (cachedEntry) try {
|
|
58
|
+
await leaseClient.getLeaseStatus(cachedEntry.lease.leaseId);
|
|
59
|
+
return cachedEntry.handle;
|
|
60
|
+
} catch {
|
|
61
|
+
scopeCache.delete(params.scopeKey);
|
|
62
|
+
}
|
|
63
|
+
const leaseResponse = await leaseClient.requestLease({
|
|
64
|
+
agentWorkspaceDir: params.agentWorkspaceDir,
|
|
65
|
+
profileId: options.profileId ?? "standard",
|
|
66
|
+
scopeKey: params.scopeKey,
|
|
67
|
+
workspaceDir: params.workspaceDir,
|
|
68
|
+
zoneId: options.zoneId
|
|
69
|
+
});
|
|
70
|
+
if (!isGondolinLeaseResponse(leaseResponse)) throw new TypeError("Controller lease API returned an unexpected response.");
|
|
71
|
+
const lease = leaseResponse;
|
|
72
|
+
const handle = createSandboxBackendHandle({
|
|
73
|
+
cfg: params.cfg,
|
|
74
|
+
controllerUrl: options.controllerUrl,
|
|
75
|
+
createFsBridgeBuilder: dependencies.createFsBridgeBuilder,
|
|
76
|
+
lease,
|
|
77
|
+
runRemoteShellScript: dependencies.runRemoteShellScript,
|
|
78
|
+
buildExecSpec: dependencies.buildExecSpec,
|
|
79
|
+
scopeKey: params.scopeKey,
|
|
80
|
+
zoneId: options.zoneId
|
|
81
|
+
});
|
|
82
|
+
scopeCache.set(params.scopeKey, {
|
|
83
|
+
handle,
|
|
84
|
+
lease
|
|
85
|
+
});
|
|
86
|
+
return handle;
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function createSandboxBackendHandle(options) {
|
|
90
|
+
const boundRunRemoteShellScript = async (shellParams) => await options.runRemoteShellScript({
|
|
91
|
+
...shellParams.allowFailure !== void 0 ? { allowFailure: shellParams.allowFailure } : {},
|
|
92
|
+
script: buildShellScriptWithArgs(shellParams.script, shellParams.args),
|
|
93
|
+
...shellParams.signal !== void 0 ? { signal: shellParams.signal } : {},
|
|
94
|
+
ssh: options.lease.ssh,
|
|
95
|
+
...shellParams.stdin !== void 0 ? { stdin: shellParams.stdin } : {}
|
|
96
|
+
});
|
|
97
|
+
const createFsBridge = options.createFsBridgeBuilder?.({
|
|
98
|
+
remoteAgentWorkspaceDir: options.lease.workdir,
|
|
99
|
+
remoteWorkspaceDir: options.lease.workdir,
|
|
100
|
+
runRemoteShellScript: boundRunRemoteShellScript
|
|
101
|
+
});
|
|
102
|
+
return {
|
|
103
|
+
...createFsBridge ? { createFsBridge } : {},
|
|
104
|
+
...options.cfg.docker?.env ? { env: options.cfg.docker.env } : {},
|
|
105
|
+
configLabel: `${options.controllerUrl} (${options.zoneId})`,
|
|
106
|
+
configLabelKind: "VM",
|
|
107
|
+
id: "gondolin",
|
|
108
|
+
runtimeId: options.lease.leaseId,
|
|
109
|
+
runtimeLabel: options.lease.leaseId,
|
|
110
|
+
workdir: options.lease.workdir,
|
|
111
|
+
buildExecSpec: async (execParams) => await options.buildExecSpec({
|
|
112
|
+
command: execParams.command,
|
|
113
|
+
env: execParams.env,
|
|
114
|
+
ssh: options.lease.ssh,
|
|
115
|
+
usePty: execParams.usePty,
|
|
116
|
+
workdir: execParams.workdir ?? options.lease.workdir
|
|
117
|
+
}),
|
|
118
|
+
finalizeExec: async (finalizeParams) => {
|
|
119
|
+
if (finalizeParams.token && typeof finalizeParams.token === "object" && "dispose" in finalizeParams.token) await finalizeParams.token.dispose();
|
|
120
|
+
},
|
|
121
|
+
runShellCommand: async (commandParams) => await options.runRemoteShellScript({
|
|
122
|
+
script: commandParams.script,
|
|
123
|
+
ssh: options.lease.ssh
|
|
124
|
+
})
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
//#endregion
|
|
129
|
+
//#region src/sandbox-backend/sandbox-backend-manager.ts
|
|
130
|
+
function createGondolinSandboxBackendManager(options, dependencies) {
|
|
131
|
+
return {
|
|
132
|
+
describeRuntime: async (params) => {
|
|
133
|
+
const leaseClient = dependencies.createLeaseClient?.({ controllerUrl: options.controllerUrl }) ?? createLeaseClient({ controllerUrl: options.controllerUrl });
|
|
134
|
+
try {
|
|
135
|
+
return {
|
|
136
|
+
configLabelMatch: true,
|
|
137
|
+
running: await leaseClient.getLeaseStatus(params.entry.containerName) !== null
|
|
138
|
+
};
|
|
139
|
+
} catch {
|
|
140
|
+
return {
|
|
141
|
+
configLabelMatch: false,
|
|
142
|
+
running: false
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
removeRuntime: async (params) => {
|
|
147
|
+
await (dependencies.createLeaseClient?.({ controllerUrl: options.controllerUrl }) ?? createLeaseClient({ controllerUrl: options.controllerUrl })).releaseLease(params.entry.containerName);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region src/gondolin-plugin-config.ts
|
|
154
|
+
function resolveGondolinPluginConfig(config) {
|
|
155
|
+
if (typeof config.controllerUrl !== "string" || typeof config.zoneId !== "string") throw new Error("Gondolin plugin config requires controllerUrl and zoneId.");
|
|
156
|
+
return {
|
|
157
|
+
controllerUrl: config.controllerUrl,
|
|
158
|
+
...typeof config.profileId === "string" ? { profileId: config.profileId } : {},
|
|
159
|
+
zoneId: config.zoneId
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
//#endregion
|
|
164
|
+
//#region src/openclaw-backend-dependencies.ts
|
|
165
|
+
function createBackendDeps(ssh) {
|
|
166
|
+
return {
|
|
167
|
+
buildExecSpec: async ({ command, env, ssh: sshCreds, usePty, workdir }) => {
|
|
168
|
+
const session = await ssh.createSshSandboxSessionFromSettings({
|
|
169
|
+
command: "ssh",
|
|
170
|
+
identityData: sshCreds.identityPem,
|
|
171
|
+
strictHostKeyChecking: false,
|
|
172
|
+
target: `${sshCreds.user}@${sshCreds.host}:${sshCreds.port}`,
|
|
173
|
+
updateHostKeys: false,
|
|
174
|
+
workspaceRoot: workdir
|
|
175
|
+
});
|
|
176
|
+
const disposeSshSandboxSession = ssh.disposeSshSandboxSession;
|
|
177
|
+
return {
|
|
178
|
+
argv: ssh.buildSshSandboxArgv({
|
|
179
|
+
remoteCommand: ssh.buildExecRemoteCommand({
|
|
180
|
+
command,
|
|
181
|
+
env,
|
|
182
|
+
workdir
|
|
183
|
+
}),
|
|
184
|
+
session,
|
|
185
|
+
tty: usePty
|
|
186
|
+
}),
|
|
187
|
+
env: ssh.sanitizeEnvVars(process.env).allowed,
|
|
188
|
+
finalizeToken: {
|
|
189
|
+
dispose: async () => {
|
|
190
|
+
if (disposeSshSandboxSession) await disposeSshSandboxSession(session);
|
|
191
|
+
},
|
|
192
|
+
session
|
|
193
|
+
},
|
|
194
|
+
stdinMode: "pipe-open"
|
|
195
|
+
};
|
|
196
|
+
},
|
|
197
|
+
createFsBridgeBuilder: (leaseContext) => (params) => ssh.createRemoteShellSandboxFsBridge({
|
|
198
|
+
sandbox: params.sandbox,
|
|
199
|
+
runtime: {
|
|
200
|
+
remoteAgentWorkspaceDir: leaseContext.remoteAgentWorkspaceDir,
|
|
201
|
+
remoteWorkspaceDir: leaseContext.remoteWorkspaceDir,
|
|
202
|
+
runRemoteShellScript: leaseContext.runRemoteShellScript
|
|
203
|
+
}
|
|
204
|
+
}),
|
|
205
|
+
runRemoteShellScript: async ({ allowFailure, script, signal, ssh: sshCreds, stdin }) => {
|
|
206
|
+
const session = await ssh.createSshSandboxSessionFromSettings({
|
|
207
|
+
command: "ssh",
|
|
208
|
+
identityData: sshCreds.identityPem,
|
|
209
|
+
strictHostKeyChecking: false,
|
|
210
|
+
target: `${sshCreds.user}@${sshCreds.host}:${sshCreds.port}`,
|
|
211
|
+
updateHostKeys: false,
|
|
212
|
+
workspaceRoot: "/workspace"
|
|
213
|
+
});
|
|
214
|
+
return await ssh.runSshSandboxCommand({
|
|
215
|
+
...allowFailure !== void 0 ? { allowFailure } : {},
|
|
216
|
+
remoteCommand: ssh.buildRemoteCommand([
|
|
217
|
+
"/bin/sh",
|
|
218
|
+
"-c",
|
|
219
|
+
script,
|
|
220
|
+
"gondolin-sandbox-fs"
|
|
221
|
+
]),
|
|
222
|
+
session,
|
|
223
|
+
...signal !== void 0 ? { signal } : {},
|
|
224
|
+
...stdin !== void 0 ? { stdin } : {}
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
//#endregion
|
|
231
|
+
//#region src/openclaw-sandbox-sdk-contract.ts
|
|
232
|
+
function assertSdkShape(value) {
|
|
233
|
+
if (typeof value !== "object" || value === null) throw new TypeError("OpenClaw SDK module is not an object");
|
|
234
|
+
for (const exportName of [
|
|
235
|
+
"buildExecRemoteCommand",
|
|
236
|
+
"buildRemoteCommand",
|
|
237
|
+
"buildSshSandboxArgv",
|
|
238
|
+
"createRemoteShellSandboxFsBridge",
|
|
239
|
+
"createSshSandboxSessionFromSettings",
|
|
240
|
+
"runSshSandboxCommand",
|
|
241
|
+
"sanitizeEnvVars",
|
|
242
|
+
"registerSandboxBackend"
|
|
243
|
+
]) if (typeof value[exportName] !== "function") throw new TypeError(`OpenClaw SDK missing required export: ${exportName}`);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
//#endregion
|
|
247
|
+
//#region src/openclaw-plugin-registration.ts
|
|
248
|
+
const plugin = {
|
|
249
|
+
id: "gondolin",
|
|
250
|
+
name: "Gondolin VM Sandbox",
|
|
251
|
+
description: "Sandbox backend powered by Gondolin micro-VMs.",
|
|
252
|
+
register(api) {
|
|
253
|
+
if (api.registrationMode !== "full") return;
|
|
254
|
+
const pluginConfig = resolveGondolinPluginConfig(api.pluginConfig);
|
|
255
|
+
import("/opt/openclaw-sdk/sandbox.js").then((sdkRaw) => {
|
|
256
|
+
assertSdkShape(sdkRaw);
|
|
257
|
+
const backendDependencies = createBackendDeps({
|
|
258
|
+
buildExecRemoteCommand: sdkRaw.buildExecRemoteCommand,
|
|
259
|
+
buildRemoteCommand: sdkRaw.buildRemoteCommand,
|
|
260
|
+
buildSshSandboxArgv: sdkRaw.buildSshSandboxArgv,
|
|
261
|
+
createRemoteShellSandboxFsBridge: sdkRaw.createRemoteShellSandboxFsBridge,
|
|
262
|
+
createSshSandboxSessionFromSettings: sdkRaw.createSshSandboxSessionFromSettings,
|
|
263
|
+
...typeof sdkRaw.disposeSshSandboxSession === "function" ? { disposeSshSandboxSession: sdkRaw.disposeSshSandboxSession } : {},
|
|
264
|
+
runSshSandboxCommand: sdkRaw.runSshSandboxCommand,
|
|
265
|
+
sanitizeEnvVars: sdkRaw.sanitizeEnvVars
|
|
266
|
+
});
|
|
267
|
+
sdkRaw.registerSandboxBackend("gondolin", {
|
|
268
|
+
factory: createGondolinSandboxBackendFactory(pluginConfig, backendDependencies),
|
|
269
|
+
manager: createGondolinSandboxBackendManager(pluginConfig, backendDependencies)
|
|
270
|
+
});
|
|
271
|
+
}).catch((error) => {
|
|
272
|
+
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
|
273
|
+
process.stderr.write(`[gondolin] failed to load OpenClaw SDK: ${message}\n`);
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
var openclaw_plugin_registration_default = plugin;
|
|
278
|
+
|
|
279
|
+
//#endregion
|
|
280
|
+
//#region src/index.ts
|
|
281
|
+
const OPENCLAW_GONDOLIN_PLUGIN_PACKAGE_NAME = "@agent-vm/openclaw-agent-vm-plugin";
|
|
282
|
+
|
|
283
|
+
//#endregion
|
|
284
|
+
export { OPENCLAW_GONDOLIN_PLUGIN_PACKAGE_NAME, createBackendDeps, createGondolinSandboxBackendFactory, createGondolinSandboxBackendManager, createLeaseClient, openclaw_plugin_registration_default as default, resolveGondolinPluginConfig };
|
|
285
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["isGondolinLeaseResponse","boundRunRemoteShellScript: FsBridgeLeaseContext['runRemoteShellScript']"],"sources":["../src/controller-lease-client.ts","../src/sandbox-backend/sandbox-backend-contract.ts","../src/sandbox-backend/sandbox-shell-script.ts","../src/sandbox-backend/sandbox-backend-handle-factory.ts","../src/sandbox-backend/sandbox-backend-manager.ts","../src/gondolin-plugin-config.ts","../src/openclaw-backend-dependencies.ts","../src/openclaw-sandbox-sdk-contract.ts","../src/openclaw-plugin-registration.ts","../src/index.ts"],"sourcesContent":["export interface GondolinLeaseResponse {\n\treadonly leaseId: string;\n\treadonly ssh: {\n\t\treadonly host: string;\n\t\treadonly identityPem: string;\n\t\treadonly knownHostsLine: string;\n\t\treadonly port: number;\n\t\treadonly user: string;\n\t};\n\treadonly tcpSlot: number;\n\treadonly workdir: string;\n}\n\nexport interface LeaseClient {\n\tgetLeaseStatus(leaseId: string): Promise<unknown>;\n\treleaseLease(leaseId: string): Promise<void>;\n\trequestLease(request: {\n\t\treadonly agentWorkspaceDir: string;\n\t\treadonly profileId: string;\n\t\treadonly scopeKey: string;\n\t\treadonly workspaceDir: string;\n\t\treadonly zoneId: string;\n\t}): Promise<GondolinLeaseResponse>;\n}\n\nfunction isGondolinLeaseResponse(value: unknown): value is GondolinLeaseResponse {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\ttypeof (value as { leaseId?: unknown }).leaseId === 'string' &&\n\t\ttypeof (value as { tcpSlot?: unknown }).tcpSlot === 'number' &&\n\t\ttypeof (value as { workdir?: unknown }).workdir === 'string'\n\t);\n}\n\nexport function createLeaseClient(options: {\n\treadonly controllerUrl: string;\n\treadonly fetchImpl?: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;\n}): LeaseClient {\n\tconst fetchImpl = options.fetchImpl ?? fetch;\n\tconst baseUrl = options.controllerUrl.replace(/\\/$/u, '');\n\n\treturn {\n\t\tgetLeaseStatus: async (leaseId: string): Promise<unknown> => {\n\t\t\tconst response = await fetchImpl(`${baseUrl}/lease/${leaseId}`);\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errorBody = await response.text().catch(() => '(unreadable)');\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t`Controller lease status API returned HTTP ${response.status}: ${errorBody}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn await response.json();\n\t\t},\n\t\treleaseLease: async (leaseId: string): Promise<void> => {\n\t\t\tawait fetchImpl(`${baseUrl}/lease/${leaseId}`, {\n\t\t\t\tmethod: 'DELETE',\n\t\t\t});\n\t\t},\n\t\trequestLease: async (request): Promise<GondolinLeaseResponse> => {\n\t\t\tconst response = await fetchImpl(`${baseUrl}/lease`, {\n\t\t\t\tbody: JSON.stringify(request),\n\t\t\t\theaders: {\n\t\t\t\t\t'content-type': 'application/json',\n\t\t\t\t},\n\t\t\t\tmethod: 'POST',\n\t\t\t});\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errorBody = await response.text().catch(() => '(unreadable)');\n\t\t\t\tthrow new TypeError(`Controller lease API returned HTTP ${response.status}: ${errorBody}`);\n\t\t\t}\n\t\t\tconst payload = await response.json();\n\t\t\tif (!isGondolinLeaseResponse(payload)) {\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t`Controller returned an invalid lease response: ${JSON.stringify(payload).slice(0, 200)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn payload;\n\t\t},\n\t};\n}\n","import type { GondolinLeaseResponse, LeaseClient } from '../controller-lease-client.js';\n\nexport function isGondolinLeaseResponse(value: unknown): value is GondolinLeaseResponse {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\ttypeof (value as { leaseId?: unknown }).leaseId === 'string' &&\n\t\ttypeof (value as { tcpSlot?: unknown }).tcpSlot === 'number' &&\n\t\ttypeof (value as { workdir?: unknown }).workdir === 'string' &&\n\t\ttypeof (value as { ssh?: unknown }).ssh === 'object' &&\n\t\t(value as { ssh?: unknown }).ssh !== null\n\t);\n}\n\nexport interface FsBridgeLeaseContext {\n\treadonly remoteAgentWorkspaceDir: string;\n\treadonly remoteWorkspaceDir: string;\n\treadonly runRemoteShellScript: (params: {\n\t\treadonly allowFailure?: boolean;\n\t\treadonly args?: string[];\n\t\treadonly script: string;\n\t\treadonly signal?: AbortSignal;\n\t\treadonly stdin?: Buffer | string;\n\t}) => Promise<{\n\t\treadonly code: number;\n\t\treadonly stderr: Buffer;\n\t\treadonly stdout: Buffer;\n\t}>;\n}\n\nexport interface GondolinFsBridge {\n\tmkdirp(params: {\n\t\treadonly cwd?: string;\n\t\treadonly filePath: string;\n\t\treadonly signal?: AbortSignal;\n\t}): Promise<void>;\n\treadFile(params: {\n\t\treadonly cwd?: string;\n\t\treadonly filePath: string;\n\t\treadonly signal?: AbortSignal;\n\t}): Promise<Buffer>;\n\tremove(params: {\n\t\treadonly cwd?: string;\n\t\treadonly filePath: string;\n\t\treadonly force?: boolean;\n\t\treadonly recursive?: boolean;\n\t\treadonly signal?: AbortSignal;\n\t}): Promise<void>;\n\trename(params: {\n\t\treadonly cwd?: string;\n\t\treadonly from: string;\n\t\treadonly signal?: AbortSignal;\n\t\treadonly to: string;\n\t}): Promise<void>;\n\tresolvePath(params: { readonly cwd?: string; readonly filePath: string }): {\n\t\treadonly containerPath: string;\n\t\treadonly relativePath: string;\n\t};\n\tstat(params: {\n\t\treadonly cwd?: string;\n\t\treadonly filePath: string;\n\t\treadonly signal?: AbortSignal;\n\t}): Promise<{\n\t\treadonly mtimeMs: number;\n\t\treadonly size: number;\n\t\treadonly type: 'directory' | 'file' | 'other';\n\t} | null>;\n\twriteFile(params: {\n\t\treadonly cwd?: string;\n\t\treadonly data: Buffer | string;\n\t\treadonly encoding?: BufferEncoding;\n\t\treadonly filePath: string;\n\t\treadonly mkdir?: boolean;\n\t\treadonly signal?: AbortSignal;\n\t}): Promise<void>;\n}\n\nexport interface CreateBackendDependencies {\n\treadonly buildExecSpec: (params: {\n\t\treadonly command: string;\n\t\treadonly env: Record<string, string>;\n\t\treadonly ssh: GondolinLeaseResponse['ssh'];\n\t\treadonly usePty: boolean;\n\t\treadonly workdir: string;\n\t}) => Promise<{\n\t\treadonly argv: string[];\n\t\treadonly env: Record<string, string>;\n\t\treadonly finalizeToken?: unknown;\n\t\treadonly stdinMode: 'pipe-open' | 'pipe-closed';\n\t}>;\n\treadonly createFsBridgeBuilder?: (\n\t\tleaseContext: FsBridgeLeaseContext,\n\t) => (params: { readonly sandbox: unknown }) => GondolinFsBridge;\n\treadonly createLeaseClient?: (options: { readonly controllerUrl: string }) => LeaseClient;\n\treadonly runRemoteShellScript: (params: {\n\t\treadonly allowFailure?: boolean;\n\t\treadonly script: string;\n\t\treadonly signal?: AbortSignal;\n\t\treadonly ssh: GondolinLeaseResponse['ssh'];\n\t\treadonly stdin?: Buffer | string;\n\t}) => Promise<{\n\t\treadonly code: number;\n\t\treadonly stderr: Buffer;\n\t\treadonly stdout: Buffer;\n\t}>;\n}\n\nexport interface GondolinSandboxBackendHandle {\n\treadonly configLabel?: string;\n\treadonly configLabelKind?: string;\n\tcreateFsBridge?: (params: { readonly sandbox: unknown }) => GondolinFsBridge;\n\tenv?: Record<string, string>;\n\treadonly id: string;\n\treadonly runtimeId: string;\n\treadonly runtimeLabel: string;\n\treadonly workdir: string;\n\tbuildExecSpec(params: {\n\t\treadonly command: string;\n\t\treadonly env: Record<string, string>;\n\t\treadonly usePty: boolean;\n\t\treadonly workdir?: string;\n\t}): Promise<{\n\t\treadonly argv: string[];\n\t\treadonly env: Record<string, string>;\n\t\treadonly finalizeToken?: unknown;\n\t\treadonly stdinMode: 'pipe-open' | 'pipe-closed';\n\t}>;\n\tfinalizeExec?: (params: {\n\t\treadonly exitCode: number | null;\n\t\treadonly status: 'completed' | 'failed';\n\t\treadonly timedOut: boolean;\n\t\treadonly token?: unknown;\n\t}) => Promise<void>;\n\trunShellCommand(params: { readonly script: string }): Promise<{\n\t\treadonly code: number;\n\t\treadonly stderr: Buffer;\n\t\treadonly stdout: Buffer;\n\t}>;\n}\n\nexport interface CachedScopeEntry {\n\treadonly handle: GondolinSandboxBackendHandle;\n\treadonly lease: GondolinLeaseResponse;\n}\n","export function buildShellScriptWithArgs(script: string, args?: readonly string[]): string {\n\tif (!args || args.length === 0) {\n\t\treturn script;\n\t}\n\n\tconst escapedArgs = args.map((arg) => `'${arg.replace(/'/g, \"'\\\\''\")}'`).join(' ');\n\treturn `set -- ${escapedArgs}; ${script}`;\n}\n","import { createLeaseClient, type GondolinLeaseResponse } from '../controller-lease-client.js';\nimport {\n\ttype CachedScopeEntry,\n\ttype CreateBackendDependencies,\n\ttype FsBridgeLeaseContext,\n\ttype GondolinSandboxBackendHandle,\n\tisGondolinLeaseResponse,\n} from './sandbox-backend-contract.js';\nimport { buildShellScriptWithArgs } from './sandbox-shell-script.js';\n\nexport function createGondolinSandboxBackendFactory(\n\toptions: {\n\t\treadonly controllerUrl: string;\n\t\treadonly profileId?: string;\n\t\treadonly zoneId: string;\n\t},\n\tdependencies: CreateBackendDependencies,\n): (params: {\n\treadonly agentWorkspaceDir: string;\n\treadonly cfg: {\n\t\treadonly docker?: {\n\t\t\treadonly env?: Record<string, string>;\n\t\t};\n\t};\n\treadonly scopeKey: string;\n\treadonly sessionKey: string;\n\treadonly workspaceDir: string;\n}) => Promise<GondolinSandboxBackendHandle> {\n\tconst scopeCache = new Map<string, CachedScopeEntry>();\n\n\treturn async (params) => {\n\t\tconst leaseClient =\n\t\t\tdependencies.createLeaseClient?.({\n\t\t\t\tcontrollerUrl: options.controllerUrl,\n\t\t\t}) ?? createLeaseClient({ controllerUrl: options.controllerUrl });\n\t\tconst cachedEntry = scopeCache.get(params.scopeKey);\n\t\tif (cachedEntry) {\n\t\t\ttry {\n\t\t\t\tawait leaseClient.getLeaseStatus(cachedEntry.lease.leaseId);\n\t\t\t\treturn cachedEntry.handle;\n\t\t\t} catch {\n\t\t\t\tscopeCache.delete(params.scopeKey);\n\t\t\t}\n\t\t}\n\t\tconst leaseResponse = await leaseClient.requestLease({\n\t\t\tagentWorkspaceDir: params.agentWorkspaceDir,\n\t\t\tprofileId: options.profileId ?? 'standard',\n\t\t\tscopeKey: params.scopeKey,\n\t\t\tworkspaceDir: params.workspaceDir,\n\t\t\tzoneId: options.zoneId,\n\t\t});\n\t\tif (!isGondolinLeaseResponse(leaseResponse)) {\n\t\t\tthrow new TypeError('Controller lease API returned an unexpected response.');\n\t\t}\n\n\t\tconst lease = leaseResponse;\n\t\tconst handle = createSandboxBackendHandle({\n\t\t\tcfg: params.cfg,\n\t\t\tcontrollerUrl: options.controllerUrl,\n\t\t\tcreateFsBridgeBuilder: dependencies.createFsBridgeBuilder,\n\t\t\tlease,\n\t\t\trunRemoteShellScript: dependencies.runRemoteShellScript,\n\t\t\tbuildExecSpec: dependencies.buildExecSpec,\n\t\t\tscopeKey: params.scopeKey,\n\t\t\tzoneId: options.zoneId,\n\t\t});\n\t\tscopeCache.set(params.scopeKey, { handle, lease });\n\t\treturn handle;\n\t};\n}\n\nfunction createSandboxBackendHandle(options: {\n\treadonly buildExecSpec: CreateBackendDependencies['buildExecSpec'];\n\treadonly cfg: {\n\t\treadonly docker?: {\n\t\t\treadonly env?: Record<string, string>;\n\t\t};\n\t};\n\treadonly controllerUrl: string;\n\treadonly createFsBridgeBuilder?: CreateBackendDependencies['createFsBridgeBuilder'];\n\treadonly lease: GondolinLeaseResponse;\n\treadonly runRemoteShellScript: CreateBackendDependencies['runRemoteShellScript'];\n\treadonly scopeKey: string;\n\treadonly zoneId: string;\n}): GondolinSandboxBackendHandle {\n\tconst boundRunRemoteShellScript: FsBridgeLeaseContext['runRemoteShellScript'] = async (\n\t\tshellParams,\n\t) =>\n\t\tawait options.runRemoteShellScript({\n\t\t\t...(shellParams.allowFailure !== undefined ? { allowFailure: shellParams.allowFailure } : {}),\n\t\t\tscript: buildShellScriptWithArgs(shellParams.script, shellParams.args),\n\t\t\t...(shellParams.signal !== undefined ? { signal: shellParams.signal } : {}),\n\t\t\tssh: options.lease.ssh,\n\t\t\t...(shellParams.stdin !== undefined ? { stdin: shellParams.stdin } : {}),\n\t\t});\n\n\tconst createFsBridge = options.createFsBridgeBuilder?.({\n\t\tremoteAgentWorkspaceDir: options.lease.workdir,\n\t\tremoteWorkspaceDir: options.lease.workdir,\n\t\trunRemoteShellScript: boundRunRemoteShellScript,\n\t});\n\n\treturn {\n\t\t...(createFsBridge ? { createFsBridge } : {}),\n\t\t...(options.cfg.docker?.env ? { env: options.cfg.docker.env } : {}),\n\t\tconfigLabel: `${options.controllerUrl} (${options.zoneId})`,\n\t\tconfigLabelKind: 'VM',\n\t\tid: 'gondolin',\n\t\truntimeId: options.lease.leaseId,\n\t\truntimeLabel: options.lease.leaseId,\n\t\tworkdir: options.lease.workdir,\n\t\tbuildExecSpec: async (execParams) =>\n\t\t\tawait options.buildExecSpec({\n\t\t\t\tcommand: execParams.command,\n\t\t\t\tenv: execParams.env,\n\t\t\t\tssh: options.lease.ssh,\n\t\t\t\tusePty: execParams.usePty,\n\t\t\t\tworkdir: execParams.workdir ?? options.lease.workdir,\n\t\t\t}),\n\t\tfinalizeExec: async (finalizeParams) => {\n\t\t\tif (\n\t\t\t\tfinalizeParams.token &&\n\t\t\t\ttypeof finalizeParams.token === 'object' &&\n\t\t\t\t'dispose' in finalizeParams.token\n\t\t\t) {\n\t\t\t\tawait (finalizeParams.token as { dispose: () => Promise<void> }).dispose();\n\t\t\t}\n\t\t},\n\t\trunShellCommand: async (commandParams) =>\n\t\t\tawait options.runRemoteShellScript({\n\t\t\t\tscript: commandParams.script,\n\t\t\t\tssh: options.lease.ssh,\n\t\t\t}),\n\t} satisfies GondolinSandboxBackendHandle;\n}\n","import { createLeaseClient } from '../controller-lease-client.js';\nimport type { CreateBackendDependencies } from './sandbox-backend-contract.js';\n\nexport function createGondolinSandboxBackendManager(\n\toptions: {\n\t\treadonly controllerUrl: string;\n\t\treadonly zoneId: string;\n\t},\n\tdependencies: CreateBackendDependencies,\n): {\n\tdescribeRuntime: (params: {\n\t\treadonly entry: { readonly containerName: string };\n\t}) => Promise<{ readonly configLabelMatch: boolean; readonly running: boolean }>;\n\tremoveRuntime: (params: { readonly entry: { readonly containerName: string } }) => Promise<void>;\n} {\n\treturn {\n\t\tdescribeRuntime: async (params) => {\n\t\t\tconst leaseClient =\n\t\t\t\tdependencies.createLeaseClient?.({\n\t\t\t\t\tcontrollerUrl: options.controllerUrl,\n\t\t\t\t}) ?? createLeaseClient({ controllerUrl: options.controllerUrl });\n\t\t\ttry {\n\t\t\t\tconst leaseStatus = await leaseClient.getLeaseStatus(params.entry.containerName);\n\t\t\t\treturn { configLabelMatch: true, running: leaseStatus !== null };\n\t\t\t} catch {\n\t\t\t\treturn { configLabelMatch: false, running: false };\n\t\t\t}\n\t\t},\n\t\tremoveRuntime: async (params) => {\n\t\t\tconst leaseClient =\n\t\t\t\tdependencies.createLeaseClient?.({\n\t\t\t\t\tcontrollerUrl: options.controllerUrl,\n\t\t\t\t}) ?? createLeaseClient({ controllerUrl: options.controllerUrl });\n\t\t\tawait leaseClient.releaseLease(params.entry.containerName);\n\t\t},\n\t};\n}\n","export interface ResolvedGondolinPluginConfig {\n\treadonly controllerUrl: string;\n\treadonly profileId?: string;\n\treadonly zoneId: string;\n}\n\nexport function resolveGondolinPluginConfig(\n\tconfig: Record<string, unknown>,\n): ResolvedGondolinPluginConfig {\n\tif (typeof config.controllerUrl !== 'string' || typeof config.zoneId !== 'string') {\n\t\tthrow new Error('Gondolin plugin config requires controllerUrl and zoneId.');\n\t}\n\n\treturn {\n\t\tcontrollerUrl: config.controllerUrl,\n\t\t...(typeof config.profileId === 'string' ? { profileId: config.profileId } : {}),\n\t\tzoneId: config.zoneId,\n\t};\n}\n","import type { SshHelpers, SshSandboxSession } from './openclaw-sandbox-sdk-contract.js';\nimport type {\n\tCreateBackendDependencies,\n\tFsBridgeLeaseContext,\n\tGondolinFsBridge,\n} from './sandbox-backend-factory.js';\n\nexport function createBackendDeps(ssh: SshHelpers): {\n\treadonly buildExecSpec: CreateBackendDependencies['buildExecSpec'];\n\treadonly createFsBridgeBuilder: (\n\t\tleaseContext: FsBridgeLeaseContext,\n\t) => (params: { readonly sandbox: unknown }) => GondolinFsBridge;\n\treadonly runRemoteShellScript: CreateBackendDependencies['runRemoteShellScript'];\n} {\n\treturn {\n\t\tbuildExecSpec: async ({ command, env, ssh: sshCreds, usePty, workdir }) => {\n\t\t\tconst session = await ssh.createSshSandboxSessionFromSettings({\n\t\t\t\tcommand: 'ssh',\n\t\t\t\tidentityData: sshCreds.identityPem,\n\t\t\t\tstrictHostKeyChecking: false,\n\t\t\t\ttarget: `${sshCreds.user}@${sshCreds.host}:${sshCreds.port}`,\n\t\t\t\tupdateHostKeys: false,\n\t\t\t\tworkspaceRoot: workdir,\n\t\t\t});\n\t\t\tconst disposeSshSandboxSession = ssh.disposeSshSandboxSession;\n\t\t\treturn {\n\t\t\t\targv: ssh.buildSshSandboxArgv({\n\t\t\t\t\tremoteCommand: ssh.buildExecRemoteCommand({\n\t\t\t\t\t\tcommand,\n\t\t\t\t\t\tenv,\n\t\t\t\t\t\tworkdir,\n\t\t\t\t\t}),\n\t\t\t\t\tsession,\n\t\t\t\t\ttty: usePty,\n\t\t\t\t}),\n\t\t\t\tenv: ssh.sanitizeEnvVars(process.env).allowed,\n\t\t\t\tfinalizeToken: {\n\t\t\t\t\tdispose: async (): Promise<void> => {\n\t\t\t\t\t\tif (disposeSshSandboxSession) {\n\t\t\t\t\t\t\tawait disposeSshSandboxSession(session);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tsession,\n\t\t\t\t},\n\t\t\t\tstdinMode: 'pipe-open' as const,\n\t\t\t};\n\t\t},\n\t\tcreateFsBridgeBuilder:\n\t\t\t(leaseContext: FsBridgeLeaseContext) =>\n\t\t\t(params: { readonly sandbox: unknown }): GondolinFsBridge =>\n\t\t\t\tssh.createRemoteShellSandboxFsBridge({\n\t\t\t\t\tsandbox: params.sandbox,\n\t\t\t\t\truntime: {\n\t\t\t\t\t\tremoteAgentWorkspaceDir: leaseContext.remoteAgentWorkspaceDir,\n\t\t\t\t\t\tremoteWorkspaceDir: leaseContext.remoteWorkspaceDir,\n\t\t\t\t\t\trunRemoteShellScript: leaseContext.runRemoteShellScript,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\trunRemoteShellScript: async ({ allowFailure, script, signal, ssh: sshCreds, stdin }) => {\n\t\t\tconst session = await ssh.createSshSandboxSessionFromSettings({\n\t\t\t\tcommand: 'ssh',\n\t\t\t\tidentityData: sshCreds.identityPem,\n\t\t\t\tstrictHostKeyChecking: false,\n\t\t\t\ttarget: `${sshCreds.user}@${sshCreds.host}:${sshCreds.port}`,\n\t\t\t\tupdateHostKeys: false,\n\t\t\t\tworkspaceRoot: '/workspace',\n\t\t\t});\n\t\t\treturn await ssh.runSshSandboxCommand({\n\t\t\t\t...(allowFailure !== undefined ? { allowFailure } : {}),\n\t\t\t\tremoteCommand: ssh.buildRemoteCommand(['/bin/sh', '-c', script, 'gondolin-sandbox-fs']),\n\t\t\t\tsession,\n\t\t\t\t...(signal !== undefined ? { signal } : {}),\n\t\t\t\t...(stdin !== undefined ? { stdin } : {}),\n\t\t\t});\n\t\t},\n\t};\n}\n\nexport type { SshHelpers, SshSandboxSession };\n","export interface SshSandboxSession {\n\treadonly command: string;\n\treadonly configPath: string;\n\treadonly host: string;\n}\n\nexport interface SshHelpers {\n\treadonly buildExecRemoteCommand: (params: {\n\t\treadonly command: string;\n\t\treadonly env: Record<string, string>;\n\t\treadonly workdir?: string;\n\t}) => string;\n\treadonly buildRemoteCommand: (argv: readonly string[]) => string;\n\treadonly buildSshSandboxArgv: (params: {\n\t\treadonly remoteCommand: string;\n\t\treadonly session: SshSandboxSession;\n\t\treadonly tty?: boolean;\n\t}) => string[];\n\treadonly createRemoteShellSandboxFsBridge: (params: {\n\t\treadonly runtime: {\n\t\t\treadonly remoteAgentWorkspaceDir: string;\n\t\t\treadonly remoteWorkspaceDir: string;\n\t\t\treadonly runRemoteShellScript: (shellParams: {\n\t\t\t\treadonly allowFailure?: boolean;\n\t\t\t\treadonly args?: string[];\n\t\t\t\treadonly script: string;\n\t\t\t\treadonly signal?: AbortSignal;\n\t\t\t\treadonly stdin?: Buffer | string;\n\t\t\t}) => Promise<{\n\t\t\t\treadonly code: number;\n\t\t\t\treadonly stderr: Buffer;\n\t\t\t\treadonly stdout: Buffer;\n\t\t\t}>;\n\t\t};\n\t\treadonly sandbox: unknown;\n\t}) => import('./sandbox-backend-factory.js').GondolinFsBridge;\n\treadonly createSshSandboxSessionFromSettings: (settings: {\n\t\treadonly command: string;\n\t\treadonly identityData?: string;\n\t\treadonly strictHostKeyChecking: boolean;\n\t\treadonly target: string;\n\t\treadonly updateHostKeys: boolean;\n\t\treadonly workspaceRoot: string;\n\t}) => Promise<SshSandboxSession>;\n\treadonly disposeSshSandboxSession?: (session: SshSandboxSession) => Promise<void>;\n\treadonly runSshSandboxCommand: (params: {\n\t\treadonly allowFailure?: boolean;\n\t\treadonly remoteCommand: string;\n\t\treadonly session: SshSandboxSession;\n\t\treadonly signal?: AbortSignal;\n\t\treadonly stdin?: Buffer | string;\n\t}) => Promise<{\n\t\treadonly code: number;\n\t\treadonly stderr: Buffer;\n\t\treadonly stdout: Buffer;\n\t}>;\n\treadonly sanitizeEnvVars: (env: NodeJS.ProcessEnv) => {\n\t\treadonly allowed: Record<string, string>;\n\t};\n}\n\nexport function assertSdkShape(value: unknown): asserts value is SshHelpers & {\n\tregisterSandboxBackend: (\n\t\tid: string,\n\t\tregistration: {\n\t\t\tfactory: ReturnType<\n\t\t\t\ttypeof import('./sandbox-backend-factory.js').createGondolinSandboxBackendFactory\n\t\t\t>;\n\t\t\tmanager?: ReturnType<\n\t\t\t\ttypeof import('./sandbox-backend-factory.js').createGondolinSandboxBackendManager\n\t\t\t>;\n\t\t},\n\t) => void;\n} {\n\tif (typeof value !== 'object' || value === null) {\n\t\tthrow new TypeError('OpenClaw SDK module is not an object');\n\t}\n\n\tfor (const exportName of [\n\t\t'buildExecRemoteCommand',\n\t\t'buildRemoteCommand',\n\t\t'buildSshSandboxArgv',\n\t\t'createRemoteShellSandboxFsBridge',\n\t\t'createSshSandboxSessionFromSettings',\n\t\t'runSshSandboxCommand',\n\t\t'sanitizeEnvVars',\n\t\t'registerSandboxBackend',\n\t] as const) {\n\t\tif (typeof (value as Record<string, unknown>)[exportName] !== 'function') {\n\t\t\tthrow new TypeError(`OpenClaw SDK missing required export: ${exportName}`);\n\t\t}\n\t}\n}\n","import { resolveGondolinPluginConfig } from './gondolin-plugin-config.js';\nimport { createBackendDeps } from './openclaw-backend-dependencies.js';\nimport {\n\tassertSdkShape,\n\ttype SshHelpers,\n\ttype SshSandboxSession,\n} from './openclaw-sandbox-sdk-contract.js';\nimport {\n\tcreateGondolinSandboxBackendFactory,\n\tcreateGondolinSandboxBackendManager,\n} from './sandbox-backend-factory.js';\n\nconst plugin = {\n\tid: 'gondolin',\n\tname: 'Gondolin VM Sandbox',\n\tdescription: 'Sandbox backend powered by Gondolin micro-VMs.',\n\n\tregister(api: {\n\t\treadonly pluginConfig: Record<string, unknown>;\n\t\treadonly registrationMode: string;\n\t}): void {\n\t\tif (api.registrationMode !== 'full') {\n\t\t\treturn;\n\t\t}\n\n\t\tconst pluginConfig = resolveGondolinPluginConfig(api.pluginConfig);\n\t\tconst sdkPath = '/opt/openclaw-sdk/sandbox.js';\n\t\tconst sdkPromise = import(sdkPath).then((sdkRaw: Record<string, unknown>) => {\n\t\t\tassertSdkShape(sdkRaw);\n\n\t\t\tconst sshHelpers: SshHelpers = {\n\t\t\t\tbuildExecRemoteCommand: sdkRaw.buildExecRemoteCommand,\n\t\t\t\tbuildRemoteCommand: sdkRaw.buildRemoteCommand,\n\t\t\t\tbuildSshSandboxArgv: sdkRaw.buildSshSandboxArgv,\n\t\t\t\tcreateRemoteShellSandboxFsBridge: sdkRaw.createRemoteShellSandboxFsBridge,\n\t\t\t\tcreateSshSandboxSessionFromSettings: sdkRaw.createSshSandboxSessionFromSettings,\n\t\t\t\t...(typeof sdkRaw.disposeSshSandboxSession === 'function'\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tdisposeSshSandboxSession: sdkRaw.disposeSshSandboxSession as (\n\t\t\t\t\t\t\t\tsession: SshSandboxSession,\n\t\t\t\t\t\t\t) => Promise<void>,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t\trunSshSandboxCommand: sdkRaw.runSshSandboxCommand,\n\t\t\t\tsanitizeEnvVars: sdkRaw.sanitizeEnvVars,\n\t\t\t};\n\n\t\t\tconst backendDependencies = createBackendDeps(sshHelpers);\n\t\t\tsdkRaw.registerSandboxBackend('gondolin', {\n\t\t\t\tfactory: createGondolinSandboxBackendFactory(pluginConfig, backendDependencies),\n\t\t\t\tmanager: createGondolinSandboxBackendManager(pluginConfig, backendDependencies),\n\t\t\t});\n\t\t});\n\n\t\tsdkPromise.catch((error: unknown) => {\n\t\t\tconst message = error instanceof Error ? error.message : JSON.stringify(error);\n\t\t\tprocess.stderr.write(`[gondolin] failed to load OpenClaw SDK: ${message}\\n`);\n\t\t});\n\t},\n};\n\nexport default plugin;\n\nexport { createBackendDeps };\nexport type { SshHelpers };\n","export * from './sandbox-backend-factory.js';\nexport * from './gondolin-plugin-config.js';\nexport * from './controller-lease-client.js';\nexport * from './openclaw-plugin-registration.js';\nexport { default } from './openclaw-plugin-registration.js';\n\nexport const OPENCLAW_GONDOLIN_PLUGIN_PACKAGE_NAME = '@agent-vm/openclaw-agent-vm-plugin';\n"],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "gondolin",
|
|
3
|
+
"name": "Gondolin VM Sandbox",
|
|
4
|
+
"description": "Sandbox backend powered by Gondolin micro-VMs with SSH-based command execution via controller lease API.",
|
|
5
|
+
"configSchema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"controllerUrl": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"minLength": 1
|
|
12
|
+
},
|
|
13
|
+
"zoneId": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"minLength": 1
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"required": ["controllerUrl", "zoneId"]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Runtime SDK validation — run this INSIDE a gateway VM to verify
|
|
4
|
+
* our plugin's type guard matches the actual OpenClaw SDK exports.
|
|
5
|
+
*
|
|
6
|
+
* Usage (inside VM):
|
|
7
|
+
* node /opt/extensions/gondolin/sdk-validate.mjs
|
|
8
|
+
*
|
|
9
|
+
* Exit 0 = compatible, Exit 1 = mismatch (lists missing exports)
|
|
10
|
+
*/
|
|
11
|
+
const SDK_PATH = '/opt/openclaw-sdk/sandbox.js';
|
|
12
|
+
|
|
13
|
+
const REQUIRED_EXPORTS = [
|
|
14
|
+
'buildExecRemoteCommand',
|
|
15
|
+
'buildRemoteCommand',
|
|
16
|
+
'buildSshSandboxArgv',
|
|
17
|
+
'createSshSandboxSessionFromSettings',
|
|
18
|
+
'runSshSandboxCommand',
|
|
19
|
+
'sanitizeEnvVars',
|
|
20
|
+
'registerSandboxBackend',
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const sdk = await import(SDK_PATH);
|
|
25
|
+
const missing = REQUIRED_EXPORTS.filter((name) => typeof sdk[name] !== 'function');
|
|
26
|
+
|
|
27
|
+
if (missing.length > 0) {
|
|
28
|
+
process.stderr.write(`SDK MISMATCH - missing exports: ${missing.join(', ')}\n`);
|
|
29
|
+
process.stderr.write('Update assertSdkShape() and SshHelpers interface in plugin.ts\n');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
process.stdout.write(
|
|
34
|
+
`SDK COMPATIBLE - all ${String(REQUIRED_EXPORTS.length)} required exports found\n`,
|
|
35
|
+
);
|
|
36
|
+
process.exit(0);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
|
39
|
+
process.stderr.write(`SDK LOAD FAILED: ${message}\n`);
|
|
40
|
+
process.stderr.write(`Is OpenClaw installed? Expected at: ${SDK_PATH}\n`);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agent-vm/openclaw-agent-vm-plugin",
|
|
3
|
+
"version": "0.0.20",
|
|
4
|
+
"description": "OpenClaw sandbox-backend plugin that delegates execution to a Gondolin-managed VM.",
|
|
5
|
+
"homepage": "https://github.com/ShravanSunder/agent-vm#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/ShravanSunder/agent-vm/issues"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"author": "Shravan Sunder <ShravanSunder@users.noreply.github.com>",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/ShravanSunder/agent-vm.git",
|
|
14
|
+
"directory": "packages/openclaw-agent-vm-plugin"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"import": "./dist/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@agent-vm/gondolin-adapter": "0.0.20"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsdown && cp openclaw.plugin.json sdk-validate.mjs dist/",
|
|
36
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
37
|
+
}
|
|
38
|
+
}
|