@agent-vm/openclaw-agent-vm-plugin 0.0.58 → 0.0.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +19 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +208 -27
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
//#region src/controller-lease-client.d.ts
|
|
2
2
|
interface GondolinLeaseResponse {
|
|
3
|
+
readonly idleTtlMs?: number;
|
|
3
4
|
readonly leaseId: string;
|
|
4
5
|
readonly ssh: {
|
|
5
6
|
readonly host: string;
|
|
@@ -25,9 +26,19 @@ interface LeasePeekResponse {
|
|
|
25
26
|
readonly tcpSlot: number;
|
|
26
27
|
readonly zoneId: string;
|
|
27
28
|
}
|
|
29
|
+
interface OpenClawRuntimeStatusReport {
|
|
30
|
+
readonly findings: readonly {
|
|
31
|
+
readonly hint: string;
|
|
32
|
+
readonly id: string;
|
|
33
|
+
readonly ok: boolean;
|
|
34
|
+
}[];
|
|
35
|
+
readonly pluginId: 'gondolin';
|
|
36
|
+
readonly zoneId: string;
|
|
37
|
+
}
|
|
28
38
|
interface LeaseClient {
|
|
29
39
|
keepLeaseAlive(leaseId: string): Promise<GondolinLeaseResponse>;
|
|
30
40
|
peekLease(leaseId: string): Promise<LeasePeekResponse>;
|
|
41
|
+
publishOpenClawRuntimeStatus?(report: OpenClawRuntimeStatusReport): Promise<void>;
|
|
31
42
|
releaseLease(leaseId: string): Promise<void>;
|
|
32
43
|
requestLease(request: {
|
|
33
44
|
readonly agentWorkspaceDir: string;
|
|
@@ -191,6 +202,7 @@ interface GondolinSandboxBackendHandle {
|
|
|
191
202
|
//#region src/sandbox-backend/sandbox-backend-handle-factory.d.ts
|
|
192
203
|
declare function createGondolinSandboxBackendFactory(options: {
|
|
193
204
|
readonly controllerUrl: string;
|
|
205
|
+
readonly openClawRuntimeStatusProvider?: () => OpenClawRuntimeStatusReport | undefined;
|
|
194
206
|
readonly profileId?: string;
|
|
195
207
|
readonly zoneId: string;
|
|
196
208
|
}, dependencies: CreateBackendDependencies): (params: {
|
|
@@ -329,14 +341,20 @@ declare const plugin: {
|
|
|
329
341
|
name: string;
|
|
330
342
|
description: string;
|
|
331
343
|
register(api: {
|
|
344
|
+
readonly config?: Record<string, unknown>;
|
|
332
345
|
readonly pluginConfig: Record<string, unknown>;
|
|
333
346
|
readonly registerTool?: OpenClawToolRegistrationApi["registerTool"];
|
|
334
347
|
readonly registrationMode: string;
|
|
348
|
+
readonly runtime?: {
|
|
349
|
+
readonly config?: {
|
|
350
|
+
readonly current?: () => Record<string, unknown>;
|
|
351
|
+
};
|
|
352
|
+
};
|
|
335
353
|
}): void;
|
|
336
354
|
};
|
|
337
355
|
//#endregion
|
|
338
356
|
//#region src/index.d.ts
|
|
339
357
|
declare const OPENCLAW_GONDOLIN_PLUGIN_PACKAGE_NAME = "@agent-vm/openclaw-agent-vm-plugin";
|
|
340
358
|
//#endregion
|
|
341
|
-
export { ControllerLeaseRequestError, ControllerLeaseRequestErrorKind, CreateBackendDependencies, FsBridgeLeaseContext, GondolinFsBridge, GondolinLeaseResponse, GondolinSandboxBackendHandle, LeaseClient, LeasePeekResponse, OPENCLAW_GONDOLIN_PLUGIN_PACKAGE_NAME, ResolvedGondolinPluginConfig, type SshHelpers, createBackendDeps, createGondolinSandboxBackendFactory, createGondolinSandboxBackendManager, createLeaseClient, plugin as default, resolveGondolinPluginConfig };
|
|
359
|
+
export { ControllerLeaseRequestError, ControllerLeaseRequestErrorKind, CreateBackendDependencies, FsBridgeLeaseContext, GondolinFsBridge, GondolinLeaseResponse, GondolinSandboxBackendHandle, LeaseClient, LeasePeekResponse, OPENCLAW_GONDOLIN_PLUGIN_PACKAGE_NAME, OpenClawRuntimeStatusReport, ResolvedGondolinPluginConfig, type SshHelpers, createBackendDeps, createGondolinSandboxBackendFactory, createGondolinSandboxBackendManager, createLeaseClient, plugin as default, resolveGondolinPluginConfig };
|
|
342
360
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +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"],"
|
|
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"],"mappings":";UAAiB,qBAAA;EAAA,SACP,SAAA;EAAA,SACA,OAAA;EAAA,SACA,GAAA;IAAA,SACC,IAAA;IAAA,SACA,WAAA;IAAA,SACA,cAAA;IAAA,SACA,IAAA;IAAA,SACA,IAAA;EAAA;EAAA,SAED,OAAA;EAAA,SACA,OAAA;AAAA;AAAA,UAGO,iBAAA;EAAA,SACP,SAAA;EAAA,SACA,UAAA;EAAA,SACA,OAAA;EAAA,SACA,SAAA;EAAA,SACA,QAAA;EAAA,SACA,GAAA;IAAA,SACC,IAAA;IAAA,SACA,IAAA;IAAA,SACA,IAAA;EAAA;EAAA,SAED,OAAA;EAAA,SACA,MAAA;AAAA;AAAA,UAGO,2BAAA;EAAA,SACP,QAAA;IAAA,SACC,IAAA;IAAA,SACA,EAAA;IAAA,SACA,EAAA;EAAA;EAAA,SAED,QAAA;EAAA,SACA,MAAA;AAAA;AAAA,UAGO,WAAA;EAEhB,cAAA,CAAe,OAAA,WAAkB,OAAA,CAAQ,qBAAA;EACzC,SAAA,CAAU,OAAA,WAAkB,OAAA,CAAQ,iBAAA;EACpC,4BAAA,EAA8B,MAAA,EAAQ,2BAAA,GAA8B,OAAA;EACpE,YAAA,CAAa,OAAA,WAAkB,OAAA;EAC/B,YAAA,CAAa,OAAA;IAAA,SACH,iBAAA;IAAA,SACA,SAAA;IAAA,SACA,QAAA;IAAA,SACA,YAAA;IAAA,SACA,MAAA;EAAA,IACN,OAAA,CAAQ,qBAAA;AAAA;AAAA,KAGD,+BAAA;AAAA,cAEC,2BAAA,SAAoC,KAAA;EAAA,SACvC,QAAA;EAAA,SACA,IAAA,EAAM,+BAAA;EAAA,SACN,YAAA;EAAA,SACA,MAAA;cAEG,OAAA;IAAA,SACF,QAAA;IAAA,SACA,OAAA;IAAA,SACA,YAAA;IAAA,SACA,MAAA;EAAA;AAAA;AAAA,iBAwHK,iBAAA,CAAkB,OAAA;EAAA,SACxB,aAAA;EAAA,SACA,SAAA,IAAa,KAAA,WAAgB,GAAA,GAAM,OAAA,EAAS,IAAA,GAAO,WAAA,KAAgB,OAAA,CAAQ,QAAA;AAAA,IACjF,WAAA;;;UC/Ka,oBAAA;EAAA,SACP,uBAAA;EAAA,SACA,kBAAA;EAAA,SACA,oBAAA,GAAuB,MAAA;IAAA,SACtB,YAAA;IAAA,SACA,IAAA;IAAA,SACA,MAAA;IAAA,SACA,MAAA,GAAS,WAAA;IAAA,SACT,KAAA,GAAQ,MAAA;EAAA,MACZ,OAAA;IAAA,SACI,IAAA;IAAA,SACA,MAAA,EAAQ,MAAA;IAAA,SACR,MAAA,EAAQ,MAAA;EAAA;AAAA;AAAA,UAIF,gBAAA;EAChB,MAAA,CAAO,MAAA;IAAA,SACG,GAAA;IAAA,SACA,QAAA;IAAA,SACA,MAAA,GAAS,WAAA;EAAA,IACf,OAAA;EACJ,QAAA,CAAS,MAAA;IAAA,SACC,GAAA;IAAA,SACA,QAAA;IAAA,SACA,MAAA,GAAS,WAAA;EAAA,IACf,OAAA,CAAQ,MAAA;EACZ,MAAA,CAAO,MAAA;IAAA,SACG,GAAA;IAAA,SACA,QAAA;IAAA,SACA,KAAA;IAAA,SACA,SAAA;IAAA,SACA,MAAA,GAAS,WAAA;EAAA,IACf,OAAA;EACJ,MAAA,CAAO,MAAA;IAAA,SACG,GAAA;IAAA,SACA,IAAA;IAAA,SACA,MAAA,GAAS,WAAA;IAAA,SACT,EAAA;EAAA,IACN,OAAA;EACJ,WAAA,CAAY,MAAA;IAAA,SAAmB,GAAA;IAAA,SAAuB,QAAA;EAAA;IAAA,SAC5C,aAAA;IAAA,SACA,YAAA;EAAA;EAEV,IAAA,CAAK,MAAA;IAAA,SACK,GAAA;IAAA,SACA,QAAA;IAAA,SACA,MAAA,GAAS,WAAA;EAAA,IACf,OAAA;IAAA,SACM,OAAA;IAAA,SACA,IAAA;IAAA,SACA,IAAA;EAAA;EAEV,SAAA,CAAU,MAAA;IAAA,SACA,GAAA;IAAA,SACA,IAAA,EAAM,MAAA;IAAA,SACN,QAAA,GAAW,cAAA;IAAA,SACX,QAAA;IAAA,SACA,KAAA;IAAA,SACA,MAAA,GAAS,WAAA;EAAA,IACf,OAAA;AAAA;AAAA,UAGY,yBAAA;EAAA,SACP,aAAA,GAAgB,MAAA;IAAA,SACf,OAAA;IAAA,SACA,GAAA,EAAK,MAAA;IAAA,SACL,GAAA,EAAK,qBAAA;IAAA,SACL,MAAA;IAAA,SACA,OAAA;EAAA,MACJ,OAAA;IAAA,SACI,IAAA;IAAA,SACA,GAAA,EAAK,MAAA;IAAA,SACL,aAAA;IAAA,SACA,SAAA;EAAA;EAAA,SAED,qBAAA,IACR,YAAA,EAAc,oBAAA,MACT,MAAA;IAAA,SAAmB,OAAA;EAAA,MAAuB,gBAAA;EAAA,SACvC,iBAAA,IAAqB,OAAA;IAAA,SAAoB,aAAA;EAAA,MAA4B,WAAA;EAAA,SACrE,oBAAA,GAAuB,MAAA;IAAA,SACtB,YAAA;IAAA,SACA,MAAA;IAAA,SACA,MAAA,GAAS,WAAA;IAAA,SACT,GAAA,EAAK,qBAAA;IAAA,SACL,KAAA,GAAQ,MAAA;EAAA,MACZ,OAAA;IAAA,SACI,IAAA;IAAA,SACA,MAAA,EAAQ,MAAA;IAAA,SACR,MAAA,EAAQ,MAAA;EAAA;AAAA;AAAA,UAIF,4BAAA;EAAA,SACP,WAAA;EAAA,SACA,eAAA;EACT,cAAA,IAAkB,MAAA;IAAA,SAAmB,OAAA;EAAA,MAAuB,gBAAA;EAC5D,GAAA,GAAM,MAAA;EAAA,SACG,EAAA;EAAA,SACA,SAAA;EAAA,SACA,YAAA;EAAA,SACA,OAAA;EACT,aAAA,CAAc,MAAA;IAAA,SACJ,OAAA;IAAA,SACA,GAAA,EAAK,MAAA;IAAA,SACL,MAAA;IAAA,SACA,OAAA;EAAA,IACN,OAAA;IAAA,SACM,IAAA;IAAA,SACA,GAAA,EAAK,MAAA;IAAA,SACL,aAAA;IAAA,SACA,SAAA;EAAA;EAEV,YAAA,IAAgB,MAAA;IAAA,SACN,QAAA;IAAA,SACA,MAAA;IAAA,SACA,QAAA;IAAA,SACA,KAAA;EAAA,MACJ,OAAA;EACN,eAAA,CAAgB,MAAA;IAAA,SAAmB,MAAA;EAAA,IAAmB,OAAA;IAAA,SAC5C,IAAA;IAAA,SACA,MAAA,EAAQ,MAAA;IAAA,SACR,MAAA,EAAQ,MAAA;EAAA;AAAA;;;iBCtEH,mCAAA,CACf,OAAA;EAAA,SACU,aAAA;EAAA,SACA,6BAAA,SAAsC,2BAAA;EAAA,SACtC,SAAA;EAAA,SACA,MAAA;AAAA,GAEV,YAAA,EAAc,yBAAA,IACX,MAAA;EAAA,SACM,iBAAA;EAAA,SACA,GAAA;IAAA,SACC,MAAA;MAAA,SACC,GAAA,GAAM,MAAA;IAAA;EAAA;EAAA,SAGR,QAAA;EAAA,SACA,UAAA;EAAA,SACA,YAAA;AAAA,MACJ,OAAA,CAAQ,4BAAA;;;iBCjFE,mCAAA,CACf,OAAA;EAAA,SACU,aAAA;EAAA,SACA,MAAA;AAAA,GAEV,YAAA,EAAc,yBAAA;EAEd,eAAA,GAAkB,MAAA;IAAA,SACR,KAAA;MAAA,SAAkB,aAAA;IAAA;EAAA,MACtB,OAAA;IAAA,SAAmB,gBAAA;IAAA,SAAoC,OAAA;EAAA;EAC7D,aAAA,GAAgB,MAAA;IAAA,SAAmB,KAAA;MAAA,SAAkB,aAAA;IAAA;EAAA,MAA8B,OAAA;AAAA;;;UCbnE,4BAAA;EAAA,SACP,aAAA;EAAA,SACA,SAAA;EAAA,SACA,YAAA;EAAA,SACA,eAAA;EAAA,SACA,MAAA;AAAA;AAAA,iBAGM,2BAAA,CACf,MAAA,EAAQ,MAAA,oBACN,4BAAA;;;UCVc,iBAAA;EAAA,SACP,OAAA;EAAA,SACA,UAAA;EAAA,SACA,IAAA;AAAA;AAAA,UAGO,UAAA;EAAA,SACP,sBAAA,GAAyB,MAAA;IAAA,SACxB,OAAA;IAAA,SACA,GAAA,EAAK,MAAA;IAAA,SACL,OAAA;EAAA;EAAA,SAED,kBAAA,GAAqB,IAAA;EAAA,SACrB,mBAAA,GAAsB,MAAA;IAAA,SACrB,aAAA;IAAA,SACA,OAAA,EAAS,iBAAA;IAAA,SACT,GAAA;EAAA;EAAA,SAED,gCAAA,GAAmC,MAAA;IAAA,SAClC,OAAA;MAAA,SACC,uBAAA;MAAA,SACA,kBAAA;MAAA,SACA,oBAAA,GAAuB,WAAA;QAAA,SACtB,YAAA;QAAA,SACA,IAAA;QAAA,SACA,MAAA;QAAA,SACA,MAAA,GAAS,WAAA;QAAA,SACT,KAAA,GAAQ,MAAA;MAAA,MACZ,OAAA;QAAA,SACI,IAAA;QAAA,SACA,MAAA,EAAQ,MAAA;QAAA,SACR,MAAA,EAAQ,MAAA;MAAA;IAAA;IAAA,SAGV,OAAA;EAAA,MANK,gBAAA;EAAA,SAQN,mCAAA,GAAsC,QAAA;IAAA,SACrC,OAAA;IAAA,SACA,YAAA;IAAA,SACA,qBAAA;IAAA,SACA,MAAA;IAAA,SACA,cAAA;IAAA,SACA,aAAA;EAAA,MACJ,OAAA,CAAQ,iBAAA;EAAA,SACL,wBAAA,IAA4B,OAAA,EAAS,iBAAA,KAAsB,OAAA;EAAA,SAC3D,oBAAA,GAAuB,MAAA;IAAA,SACtB,YAAA;IAAA,SACA,aAAA;IAAA,SACA,OAAA,EAAS,iBAAA;IAAA,SACT,MAAA,GAAS,WAAA;IAAA,SACT,KAAA,GAAQ,MAAA;EAAA,MACZ,OAAA;IAAA,SACI,IAAA;IAAA,SACA,MAAA,EAAQ,MAAA;IAAA,SACR,MAAA,EAAQ,MAAA;EAAA;EAAA,SAET,eAAA,GAAkB,GAAA,EAAK,MAAA,CAAO,UAAA;IAAA,SAC7B,OAAA,EAAS,MAAA;EAAA;AAAA;AAAA,UAIH,wBAAA;EAAA,SACP,WAAA;EAAA,SACA,OAAA,GAAU,UAAA,UAAoB,MAAA,cAAoB,OAAA,CAAQ,kBAAA;EAAA,SAC1D,IAAA;EAAA,SACA,UAAA,EAAY,MAAA;AAAA;AAAA,UAGL,+BAAA;EAAA,SACP,IAAA;EAAA,SACA,KAAA;EAAA,SACA,QAAA;AAAA;AAAA,UAGO,kBAAA;EAAA,SACP,OAAA;EAAA,SACA,OAAA;AAAA;AAAA,UAGO,2BAAA;EAAA,SACP,YAAA,IACR,IAAA,EAAM,wBAAA,EACN,OAAA,GAAU,+BAAA;AAAA;;;iBC3EI,iBAAA,CAAkB,GAAA,EAAK,UAAA;EAAA,SAC7B,aAAA,EAAe,yBAAA;EAAA,SACf,qBAAA,GACR,YAAA,EAAc,oBAAA,MACT,MAAA;IAAA,SAAmB,OAAA;EAAA,MAAuB,gBAAA;EAAA,SACvC,oBAAA,EAAsB,yBAAA;AAAA;;;cCI1B,MAAA;;;;;aAMK,MAAA,GAAS,MAAA;IAAA,SACT,YAAA,EAAc,MAAA;IAAA,SACd,YAAA,GAAe,2BAAA;IAAA,SACf,gBAAA;IAAA,SACA,OAAA;MAAA,SACC,MAAA;QAAA,SACC,OAAA,SAAgB,MAAA;MAAA;IAAA;EAAA;AAAA;;;cCtBhB,qCAAA"}
|
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@ function isLeasePeekSshResponse(value) {
|
|
|
26
26
|
}
|
|
27
27
|
function isGondolinLeaseResponse$1(value) {
|
|
28
28
|
const record = objectValue(value);
|
|
29
|
-
return record !== void 0 && typeof Reflect.get(record, "leaseId") === "string" && isSshResponse(Reflect.get(record, "ssh")) && typeof Reflect.get(record, "tcpSlot") === "number" && typeof Reflect.get(record, "workdir") === "string";
|
|
29
|
+
return record !== void 0 && (Reflect.get(record, "idleTtlMs") === void 0 || typeof Reflect.get(record, "idleTtlMs") === "number") && typeof Reflect.get(record, "leaseId") === "string" && isSshResponse(Reflect.get(record, "ssh")) && typeof Reflect.get(record, "tcpSlot") === "number" && typeof Reflect.get(record, "workdir") === "string";
|
|
30
30
|
}
|
|
31
31
|
function isLeasePeekResponse(value) {
|
|
32
32
|
const record = objectValue(value);
|
|
@@ -77,6 +77,22 @@ function createLeaseClient(options) {
|
|
|
77
77
|
peekLease: async (leaseId) => {
|
|
78
78
|
return await readJsonResponse(await fetchImpl(`${baseUrl}/lease/${leaseId}/peek`), "Controller lease peek API", isLeasePeekResponse);
|
|
79
79
|
},
|
|
80
|
+
publishOpenClawRuntimeStatus: async (report) => {
|
|
81
|
+
const response = await fetchImpl(`${baseUrl}/zones/${encodeURIComponent(report.zoneId)}/openclaw-runtime-status`, {
|
|
82
|
+
body: JSON.stringify(report),
|
|
83
|
+
headers: { "content-type": "application/json" },
|
|
84
|
+
method: "POST"
|
|
85
|
+
});
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
const errorBody = await readErrorBody(response, "Controller OpenClaw runtime status API");
|
|
88
|
+
throw new ControllerLeaseRequestError({
|
|
89
|
+
bodyText: errorBody.bodyText,
|
|
90
|
+
context: "Controller OpenClaw runtime status API",
|
|
91
|
+
responseBody: errorBody.responseBody,
|
|
92
|
+
status: response.status
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
},
|
|
80
96
|
releaseLease: async (leaseId) => {
|
|
81
97
|
const response = await fetchImpl(`${baseUrl}/lease/${leaseId}`, { method: "DELETE" });
|
|
82
98
|
if (!response.ok) {
|
|
@@ -104,20 +120,17 @@ function createLeaseClient(options) {
|
|
|
104
120
|
}
|
|
105
121
|
};
|
|
106
122
|
}
|
|
107
|
-
|
|
108
123
|
//#endregion
|
|
109
124
|
//#region src/sandbox-backend/sandbox-backend-contract.ts
|
|
110
125
|
function isGondolinLeaseResponse(value) {
|
|
111
126
|
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;
|
|
112
127
|
}
|
|
113
|
-
|
|
114
128
|
//#endregion
|
|
115
129
|
//#region src/sandbox-backend/sandbox-shell-script.ts
|
|
116
130
|
function buildShellScriptWithArgs(script, args) {
|
|
117
131
|
if (!args || args.length === 0) return script;
|
|
118
132
|
return `set -- ${args.map((arg) => `'${arg.replace(/'/g, "'\\''")}'`).join(" ")}; ${script}`;
|
|
119
133
|
}
|
|
120
|
-
|
|
121
134
|
//#endregion
|
|
122
135
|
//#region src/sandbox-backend/sandbox-backend-handle-factory.ts
|
|
123
136
|
function scopeCacheKey(params) {
|
|
@@ -138,6 +151,15 @@ function writeSandboxBackendLog(message) {
|
|
|
138
151
|
function shouldRefreshCachedLease(error) {
|
|
139
152
|
return error instanceof ControllerLeaseRequestError && error.status === 404;
|
|
140
153
|
}
|
|
154
|
+
function hasDisposeFunction(value) {
|
|
155
|
+
return typeof value === "object" && value !== null && "dispose" in value && typeof value.dispose === "function";
|
|
156
|
+
}
|
|
157
|
+
function renewalIntervalMsForLease(lease) {
|
|
158
|
+
const fallbackRenewalIntervalMs = 6e4;
|
|
159
|
+
const minimumRenewalIntervalMs = 1e3;
|
|
160
|
+
if (lease.idleTtlMs === void 0) return fallbackRenewalIntervalMs;
|
|
161
|
+
return Math.max(minimumRenewalIntervalMs, Math.min(fallbackRenewalIntervalMs, Math.floor(lease.idleTtlMs / 3)));
|
|
162
|
+
}
|
|
141
163
|
function createGondolinSandboxBackendFactory(options, dependencies) {
|
|
142
164
|
const scopeCache = /* @__PURE__ */ new Map();
|
|
143
165
|
return async (params) => {
|
|
@@ -159,6 +181,8 @@ function createGondolinSandboxBackendFactory(options, dependencies) {
|
|
|
159
181
|
if (!shouldRefreshCachedLease(error)) throw error;
|
|
160
182
|
scopeCache.delete(cacheKey);
|
|
161
183
|
}
|
|
184
|
+
const runtimeStatus = options.openClawRuntimeStatusProvider?.();
|
|
185
|
+
if (runtimeStatus && leaseClient.publishOpenClawRuntimeStatus) await leaseClient.publishOpenClawRuntimeStatus(runtimeStatus);
|
|
162
186
|
const leaseResponse = await leaseClient.requestLease({
|
|
163
187
|
agentWorkspaceDir: params.agentWorkspaceDir,
|
|
164
188
|
profileId,
|
|
@@ -172,6 +196,17 @@ function createGondolinSandboxBackendFactory(options, dependencies) {
|
|
|
172
196
|
cfg: params.cfg,
|
|
173
197
|
controllerUrl: options.controllerUrl,
|
|
174
198
|
createFsBridgeBuilder: dependencies.createFsBridgeBuilder,
|
|
199
|
+
keepLeaseAlive: async (operation) => {
|
|
200
|
+
try {
|
|
201
|
+
await leaseClient.keepLeaseAlive(lease.leaseId);
|
|
202
|
+
} catch (error) {
|
|
203
|
+
writeSandboxBackendLog(`lease command keepalive failed during ${operation} for zone '${options.zoneId}' scope '${params.scopeKey}' lease '${lease.leaseId}': ${formatUnknownError(error)}`);
|
|
204
|
+
if (shouldRefreshCachedLease(error)) {
|
|
205
|
+
if (scopeCache.get(cacheKey)?.lease.leaseId === lease.leaseId) scopeCache.delete(cacheKey);
|
|
206
|
+
}
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
},
|
|
175
210
|
lease,
|
|
176
211
|
runRemoteShellScript: dependencies.runRemoteShellScript,
|
|
177
212
|
buildExecSpec: dependencies.buildExecSpec,
|
|
@@ -186,13 +221,45 @@ function createGondolinSandboxBackendFactory(options, dependencies) {
|
|
|
186
221
|
};
|
|
187
222
|
}
|
|
188
223
|
function createSandboxBackendHandle(options) {
|
|
189
|
-
const
|
|
224
|
+
const renewalIntervalMs = renewalIntervalMsForLease(options.lease);
|
|
225
|
+
function beginLeaseRenewalTimer(operation) {
|
|
226
|
+
const interval = setInterval(() => {
|
|
227
|
+
options.keepLeaseAlive(`${operation} active`).catch((error) => {
|
|
228
|
+
writeSandboxBackendLog(`lease command keepalive failed while ${operation} was active for zone '${options.zoneId}' scope '${options.scopeKey}' lease '${options.lease.leaseId}': ${formatUnknownError(error)}`);
|
|
229
|
+
});
|
|
230
|
+
}, renewalIntervalMs);
|
|
231
|
+
if ("unref" in interval && typeof interval.unref === "function") interval.unref();
|
|
232
|
+
return { dispose: () => clearInterval(interval) };
|
|
233
|
+
}
|
|
234
|
+
async function renewLeaseAfterOperation(operation, optionsForRenewal) {
|
|
235
|
+
try {
|
|
236
|
+
await options.keepLeaseAlive(operation);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
if (!optionsForRenewal.hadPrimaryError) throw error;
|
|
239
|
+
writeSandboxBackendLog(`lease command keepalive failed after ${operation} for zone '${options.zoneId}' scope '${options.scopeKey}' lease '${options.lease.leaseId}': ${formatUnknownError(error)}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
async function runWithLeaseRenewal(operation, runOperation) {
|
|
243
|
+
await options.keepLeaseAlive(`${operation} start`);
|
|
244
|
+
const renewalTimer = beginLeaseRenewalTimer(operation);
|
|
245
|
+
try {
|
|
246
|
+
const result = await runOperation();
|
|
247
|
+
renewalTimer.dispose();
|
|
248
|
+
await renewLeaseAfterOperation(`${operation} end`, { hadPrimaryError: false });
|
|
249
|
+
return result;
|
|
250
|
+
} catch (error) {
|
|
251
|
+
renewalTimer.dispose();
|
|
252
|
+
await renewLeaseAfterOperation(`${operation} end`, { hadPrimaryError: true });
|
|
253
|
+
throw error;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const boundRunRemoteShellScript = async (shellParams) => await runWithLeaseRenewal("fs bridge shell command", async () => await options.runRemoteShellScript({
|
|
190
257
|
...shellParams.allowFailure !== void 0 ? { allowFailure: shellParams.allowFailure } : {},
|
|
191
258
|
script: buildShellScriptWithArgs(shellParams.script, shellParams.args),
|
|
192
259
|
...shellParams.signal !== void 0 ? { signal: shellParams.signal } : {},
|
|
193
260
|
ssh: options.lease.ssh,
|
|
194
261
|
...shellParams.stdin !== void 0 ? { stdin: shellParams.stdin } : {}
|
|
195
|
-
});
|
|
262
|
+
}));
|
|
196
263
|
const createFsBridge = options.createFsBridgeBuilder?.({
|
|
197
264
|
remoteAgentWorkspaceDir: options.lease.workdir,
|
|
198
265
|
remoteWorkspaceDir: options.lease.workdir,
|
|
@@ -207,23 +274,53 @@ function createSandboxBackendHandle(options) {
|
|
|
207
274
|
runtimeId: options.lease.leaseId,
|
|
208
275
|
runtimeLabel: options.lease.leaseId,
|
|
209
276
|
workdir: options.lease.workdir,
|
|
210
|
-
buildExecSpec: async (execParams) =>
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
277
|
+
buildExecSpec: async (execParams) => {
|
|
278
|
+
await options.keepLeaseAlive("exec spec build start");
|
|
279
|
+
const execRenewalTimer = beginLeaseRenewalTimer("exec command");
|
|
280
|
+
let execSpec;
|
|
281
|
+
try {
|
|
282
|
+
execSpec = await options.buildExecSpec({
|
|
283
|
+
command: execParams.command,
|
|
284
|
+
env: execParams.env,
|
|
285
|
+
ssh: options.lease.ssh,
|
|
286
|
+
usePty: execParams.usePty,
|
|
287
|
+
workdir: execParams.workdir ?? options.lease.workdir
|
|
288
|
+
});
|
|
289
|
+
} catch (error) {
|
|
290
|
+
execRenewalTimer.dispose();
|
|
291
|
+
throw error;
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
...execSpec,
|
|
295
|
+
finalizeToken: {
|
|
296
|
+
innerToken: execSpec.finalizeToken,
|
|
297
|
+
leaseRenewalTimer: execRenewalTimer
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
},
|
|
217
301
|
finalizeExec: async (finalizeParams) => {
|
|
218
|
-
|
|
302
|
+
const token = finalizeParams.token;
|
|
303
|
+
const leaseRenewalTimer = typeof token === "object" && token !== null && "leaseRenewalTimer" in token && hasDisposeFunction(token.leaseRenewalTimer) ? token.leaseRenewalTimer : void 0;
|
|
304
|
+
const innerToken = typeof token === "object" && token !== null && "innerToken" in token ? token.innerToken : token;
|
|
305
|
+
let hadPrimaryError = false;
|
|
306
|
+
let primaryError;
|
|
307
|
+
try {
|
|
308
|
+
if (hasDisposeFunction(innerToken)) await innerToken.dispose();
|
|
309
|
+
} catch (error) {
|
|
310
|
+
hadPrimaryError = true;
|
|
311
|
+
primaryError = error;
|
|
312
|
+
} finally {
|
|
313
|
+
await leaseRenewalTimer?.dispose();
|
|
314
|
+
}
|
|
315
|
+
await renewLeaseAfterOperation("exec finalize", { hadPrimaryError });
|
|
316
|
+
if (hadPrimaryError) throw primaryError;
|
|
219
317
|
},
|
|
220
|
-
runShellCommand: async (commandParams) => await options.runRemoteShellScript({
|
|
318
|
+
runShellCommand: async (commandParams) => await runWithLeaseRenewal("shell command", async () => await options.runRemoteShellScript({
|
|
221
319
|
script: commandParams.script,
|
|
222
320
|
ssh: options.lease.ssh
|
|
223
|
-
})
|
|
321
|
+
}))
|
|
224
322
|
};
|
|
225
323
|
}
|
|
226
|
-
|
|
227
324
|
//#endregion
|
|
228
325
|
//#region src/sandbox-backend/sandbox-backend-manager.ts
|
|
229
326
|
function createGondolinSandboxBackendManager(options, dependencies) {
|
|
@@ -247,7 +344,6 @@ function createGondolinSandboxBackendManager(options, dependencies) {
|
|
|
247
344
|
}
|
|
248
345
|
};
|
|
249
346
|
}
|
|
250
|
-
|
|
251
347
|
//#endregion
|
|
252
348
|
//#region src/gondolin-plugin-config.ts
|
|
253
349
|
function resolveGondolinPluginConfig(config) {
|
|
@@ -260,7 +356,6 @@ function resolveGondolinPluginConfig(config) {
|
|
|
260
356
|
zoneId: config.zoneId
|
|
261
357
|
};
|
|
262
358
|
}
|
|
263
|
-
|
|
264
359
|
//#endregion
|
|
265
360
|
//#region src/openclaw-backend-dependencies.ts
|
|
266
361
|
function createBackendDeps(ssh) {
|
|
@@ -327,7 +422,82 @@ function createBackendDeps(ssh) {
|
|
|
327
422
|
}
|
|
328
423
|
};
|
|
329
424
|
}
|
|
330
|
-
|
|
425
|
+
//#endregion
|
|
426
|
+
//#region src/openclaw-runtime-status.ts
|
|
427
|
+
function isObjectRecord(value) {
|
|
428
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
429
|
+
}
|
|
430
|
+
function readAgentConfigEntries(config) {
|
|
431
|
+
const defaultConfig = config.agents?.defaults ?? {};
|
|
432
|
+
const agentConfigs = (config.agents?.list ?? []).filter(isObjectRecord).map((agentConfig, agentIndex) => ({
|
|
433
|
+
config: agentConfig,
|
|
434
|
+
label: typeof agentConfig.id === "string" ? `agent-${agentConfig.id}` : `agent-${String(agentIndex)}`
|
|
435
|
+
}));
|
|
436
|
+
return [{
|
|
437
|
+
config: defaultConfig,
|
|
438
|
+
label: "defaults"
|
|
439
|
+
}, ...agentConfigs];
|
|
440
|
+
}
|
|
441
|
+
function effectiveSandboxValue(defaults, agentConfig, key) {
|
|
442
|
+
return agentConfig.sandbox?.[key] ?? defaults.sandbox?.[key];
|
|
443
|
+
}
|
|
444
|
+
function effectiveWorkspace(defaults, agentConfig) {
|
|
445
|
+
return agentConfig.workspace ?? defaults.workspace;
|
|
446
|
+
}
|
|
447
|
+
function requirementFinding(options) {
|
|
448
|
+
const ok = options.actualValue === options.expectedValue;
|
|
449
|
+
return {
|
|
450
|
+
id: `openclaw-tool-vm-${options.fieldPath.replace(/[.[\]]/gu, "-")}-${options.zoneId}-${options.label}`,
|
|
451
|
+
ok,
|
|
452
|
+
hint: ok ? `${options.fieldPath}=${options.expectedValue}` : `Set ${options.fieldPath} to "${options.expectedValue}" for OpenClaw Tool VM mediation.`
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
function buildOpenClawRuntimeStatusReport(options) {
|
|
456
|
+
const config = options.config;
|
|
457
|
+
const defaults = config.agents?.defaults ?? {};
|
|
458
|
+
return {
|
|
459
|
+
pluginId: "gondolin",
|
|
460
|
+
zoneId: options.zoneId,
|
|
461
|
+
findings: readAgentConfigEntries(config).flatMap(({ config: agentConfig, label }) => {
|
|
462
|
+
const workspace = effectiveWorkspace(defaults, agentConfig);
|
|
463
|
+
return [
|
|
464
|
+
requirementFinding({
|
|
465
|
+
actualValue: effectiveSandboxValue(defaults, agentConfig, "backend"),
|
|
466
|
+
expectedValue: "gondolin",
|
|
467
|
+
fieldPath: `agents.${label}.sandbox.backend`,
|
|
468
|
+
label,
|
|
469
|
+
zoneId: options.zoneId
|
|
470
|
+
}),
|
|
471
|
+
requirementFinding({
|
|
472
|
+
actualValue: effectiveSandboxValue(defaults, agentConfig, "mode"),
|
|
473
|
+
expectedValue: "all",
|
|
474
|
+
fieldPath: `agents.${label}.sandbox.mode`,
|
|
475
|
+
label,
|
|
476
|
+
zoneId: options.zoneId
|
|
477
|
+
}),
|
|
478
|
+
requirementFinding({
|
|
479
|
+
actualValue: effectiveSandboxValue(defaults, agentConfig, "scope"),
|
|
480
|
+
expectedValue: "agent",
|
|
481
|
+
fieldPath: `agents.${label}.sandbox.scope`,
|
|
482
|
+
label,
|
|
483
|
+
zoneId: options.zoneId
|
|
484
|
+
}),
|
|
485
|
+
requirementFinding({
|
|
486
|
+
actualValue: effectiveSandboxValue(defaults, agentConfig, "workspaceAccess"),
|
|
487
|
+
expectedValue: "rw",
|
|
488
|
+
fieldPath: `agents.${label}.sandbox.workspaceAccess`,
|
|
489
|
+
label,
|
|
490
|
+
zoneId: options.zoneId
|
|
491
|
+
}),
|
|
492
|
+
{
|
|
493
|
+
id: `openclaw-tool-vm-workspace-${options.zoneId}-${label}`,
|
|
494
|
+
ok: workspace !== "/zone",
|
|
495
|
+
hint: workspace === "/zone" ? "Use /zone/agents/default or per-agent workspaces; keep /zone for shared zone files." : typeof workspace === "string" ? workspace : "agents workspace is unset"
|
|
496
|
+
}
|
|
497
|
+
];
|
|
498
|
+
})
|
|
499
|
+
};
|
|
500
|
+
}
|
|
331
501
|
//#endregion
|
|
332
502
|
//#region src/openclaw-sandbox-sdk-contract.ts
|
|
333
503
|
function assertSdkShape(value) {
|
|
@@ -343,7 +513,6 @@ function assertSdkShape(value) {
|
|
|
343
513
|
"registerSandboxBackend"
|
|
344
514
|
]) if (typeof value[exportName] !== "function") throw new TypeError(`OpenClaw SDK missing required export: ${exportName}`);
|
|
345
515
|
}
|
|
346
|
-
|
|
347
516
|
//#endregion
|
|
348
517
|
//#region src/zone-git-tool.ts
|
|
349
518
|
const zoneGitCapabilityHeader = "x-agent-vm-zone-git-token";
|
|
@@ -403,7 +572,6 @@ function registerZoneGitTool(options) {
|
|
|
403
572
|
optional: true
|
|
404
573
|
});
|
|
405
574
|
}
|
|
406
|
-
|
|
407
575
|
//#endregion
|
|
408
576
|
//#region src/openclaw-plugin-registration.ts
|
|
409
577
|
const plugin = {
|
|
@@ -425,6 +593,18 @@ const plugin = {
|
|
|
425
593
|
zoneId: pluginConfig.zoneId
|
|
426
594
|
});
|
|
427
595
|
if (api.registrationMode !== "full") return;
|
|
596
|
+
const buildRuntimeStatus = () => {
|
|
597
|
+
const runtimeConfig = api.runtime?.config?.current?.() ?? api.config;
|
|
598
|
+
return runtimeConfig ? buildOpenClawRuntimeStatusReport({
|
|
599
|
+
config: runtimeConfig,
|
|
600
|
+
zoneId: pluginConfig.zoneId
|
|
601
|
+
}) : void 0;
|
|
602
|
+
};
|
|
603
|
+
const initialRuntimeStatus = buildRuntimeStatus();
|
|
604
|
+
if (initialRuntimeStatus) createLeaseClient({ controllerUrl: pluginConfig.controllerUrl }).publishOpenClawRuntimeStatus?.(initialRuntimeStatus)?.catch((error) => {
|
|
605
|
+
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
|
606
|
+
process.stderr.write(`[gondolin] failed to publish OpenClaw runtime status: ${message}\n`);
|
|
607
|
+
});
|
|
428
608
|
import("/opt/openclaw-sdk/sandbox.js").then((sdkRaw) => {
|
|
429
609
|
assertSdkShape(sdkRaw);
|
|
430
610
|
const backendDependencies = createBackendDeps({
|
|
@@ -438,7 +618,10 @@ const plugin = {
|
|
|
438
618
|
sanitizeEnvVars: sdkRaw.sanitizeEnvVars
|
|
439
619
|
});
|
|
440
620
|
sdkRaw.registerSandboxBackend("gondolin", {
|
|
441
|
-
factory: createGondolinSandboxBackendFactory(
|
|
621
|
+
factory: createGondolinSandboxBackendFactory({
|
|
622
|
+
...pluginConfig,
|
|
623
|
+
openClawRuntimeStatusProvider: buildRuntimeStatus
|
|
624
|
+
}, backendDependencies),
|
|
442
625
|
manager: createGondolinSandboxBackendManager(pluginConfig, backendDependencies)
|
|
443
626
|
});
|
|
444
627
|
}).catch((error) => {
|
|
@@ -447,12 +630,10 @@ const plugin = {
|
|
|
447
630
|
});
|
|
448
631
|
}
|
|
449
632
|
};
|
|
450
|
-
var openclaw_plugin_registration_default = plugin;
|
|
451
|
-
|
|
452
633
|
//#endregion
|
|
453
634
|
//#region src/index.ts
|
|
454
635
|
const OPENCLAW_GONDOLIN_PLUGIN_PACKAGE_NAME = "@agent-vm/openclaw-agent-vm-plugin";
|
|
455
|
-
|
|
456
636
|
//#endregion
|
|
457
|
-
export { ControllerLeaseRequestError, OPENCLAW_GONDOLIN_PLUGIN_PACKAGE_NAME, createBackendDeps, createGondolinSandboxBackendFactory, createGondolinSandboxBackendManager, createLeaseClient,
|
|
637
|
+
export { ControllerLeaseRequestError, OPENCLAW_GONDOLIN_PLUGIN_PACKAGE_NAME, createBackendDeps, createGondolinSandboxBackendFactory, createGondolinSandboxBackendManager, createLeaseClient, plugin as default, resolveGondolinPluginConfig };
|
|
638
|
+
|
|
458
639
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["kind: ControllerLeaseRequestErrorKind","isGondolinLeaseResponse","formatUnknownError","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/zone-git-tool.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 LeasePeekResponse {\n\treadonly createdAt: number;\n\treadonly lastUsedAt: number;\n\treadonly leaseId: string;\n\treadonly profileId: string;\n\treadonly scopeKey: string;\n\treadonly ssh: {\n\t\treadonly host: string;\n\t\treadonly port: number;\n\t\treadonly user: string;\n\t};\n\treadonly tcpSlot: number;\n\treadonly zoneId: string;\n}\n\nexport interface LeaseClient {\n\t// Cached handles use keepalive; read-only runtime probes use peekLease.\n\tkeepLeaseAlive(leaseId: string): Promise<GondolinLeaseResponse>;\n\tpeekLease(leaseId: string): Promise<LeasePeekResponse>;\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 workMountDir: string;\n\t\treadonly zoneId: string;\n\t}): Promise<GondolinLeaseResponse>;\n}\n\nexport type ControllerLeaseRequestErrorKind = 'client-error' | 'server-error';\n\nexport class ControllerLeaseRequestError extends Error {\n\treadonly bodyText: string;\n\treadonly kind: ControllerLeaseRequestErrorKind;\n\treadonly responseBody: unknown;\n\treadonly status: number;\n\n\tconstructor(options: {\n\t\treadonly bodyText: string;\n\t\treadonly context: string;\n\t\treadonly responseBody: unknown;\n\t\treadonly status: number;\n\t}) {\n\t\tconst kind: ControllerLeaseRequestErrorKind =\n\t\t\toptions.status >= 400 && options.status < 500 ? 'client-error' : 'server-error';\n\t\tsuper(`${options.context} returned HTTP ${String(options.status)} (${kind})`);\n\t\tthis.bodyText = options.bodyText;\n\t\tthis.kind = kind;\n\t\tthis.responseBody = options.responseBody;\n\t\tthis.status = options.status;\n\t}\n}\n\nfunction objectValue(value: unknown): object | undefined {\n\treturn typeof value === 'object' && value !== null ? value : undefined;\n}\n\nfunction isSshResponse(value: unknown): value is GondolinLeaseResponse['ssh'] {\n\tconst record = objectValue(value);\n\treturn (\n\t\trecord !== undefined &&\n\t\ttypeof Reflect.get(record, 'host') === 'string' &&\n\t\ttypeof Reflect.get(record, 'identityPem') === 'string' &&\n\t\ttypeof Reflect.get(record, 'knownHostsLine') === 'string' &&\n\t\ttypeof Reflect.get(record, 'port') === 'number' &&\n\t\ttypeof Reflect.get(record, 'user') === 'string'\n\t);\n}\n\nfunction isLeasePeekSshResponse(value: unknown): value is LeasePeekResponse['ssh'] {\n\tconst record = objectValue(value);\n\treturn (\n\t\trecord !== undefined &&\n\t\ttypeof Reflect.get(record, 'host') === 'string' &&\n\t\ttypeof Reflect.get(record, 'port') === 'number' &&\n\t\ttypeof Reflect.get(record, 'user') === 'string'\n\t);\n}\n\nfunction isGondolinLeaseResponse(value: unknown): value is GondolinLeaseResponse {\n\tconst record = objectValue(value);\n\treturn (\n\t\trecord !== undefined &&\n\t\ttypeof Reflect.get(record, 'leaseId') === 'string' &&\n\t\tisSshResponse(Reflect.get(record, 'ssh')) &&\n\t\ttypeof Reflect.get(record, 'tcpSlot') === 'number' &&\n\t\ttypeof Reflect.get(record, 'workdir') === 'string'\n\t);\n}\n\nfunction isLeasePeekResponse(value: unknown): value is LeasePeekResponse {\n\tconst record = objectValue(value);\n\treturn (\n\t\trecord !== undefined &&\n\t\ttypeof Reflect.get(record, 'createdAt') === 'number' &&\n\t\ttypeof Reflect.get(record, 'lastUsedAt') === 'number' &&\n\t\ttypeof Reflect.get(record, 'leaseId') === 'string' &&\n\t\ttypeof Reflect.get(record, 'profileId') === 'string' &&\n\t\ttypeof Reflect.get(record, 'scopeKey') === 'string' &&\n\t\tisLeasePeekSshResponse(Reflect.get(record, 'ssh')) &&\n\t\ttypeof Reflect.get(record, 'tcpSlot') === 'number' &&\n\t\ttypeof Reflect.get(record, 'zoneId') === 'string'\n\t);\n}\n\nfunction formatUnknownError(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction writeLeaseClientLog(message: string): void {\n\tprocess.stderr.write(`[openclaw-agent-vm-plugin] ${message}\\n`);\n}\n\nfunction parseJsonBody(bodyText: string, context: string): unknown {\n\ttry {\n\t\treturn JSON.parse(bodyText);\n\t} catch (error) {\n\t\twriteLeaseClientLog(`${context} returned a non-JSON error body: ${formatUnknownError(error)}`);\n\t\treturn undefined;\n\t}\n}\n\nasync function readErrorBody(\n\tresponse: Response,\n\tcontext: string,\n): Promise<{\n\treadonly bodyText: string;\n\treadonly responseBody: unknown;\n}> {\n\tconst bodyText = await response.text().catch(() => '(unreadable)');\n\treturn {\n\t\tbodyText,\n\t\tresponseBody: bodyText === '(unreadable)' ? undefined : parseJsonBody(bodyText, context),\n\t};\n}\n\nasync function readJsonResponse<TValue>(\n\tresponse: Response,\n\tcontext: string,\n\tisExpectedResponse: (value: unknown) => value is TValue,\n): Promise<TValue> {\n\tif (!response.ok) {\n\t\tconst errorBody = await readErrorBody(response, context);\n\t\tthrow new ControllerLeaseRequestError({\n\t\t\tbodyText: errorBody.bodyText,\n\t\t\tcontext,\n\t\t\tresponseBody: errorBody.responseBody,\n\t\t\tstatus: response.status,\n\t\t});\n\t}\n\tconst payload = await response.json();\n\tif (!isExpectedResponse(payload)) {\n\t\tthrow new TypeError(\n\t\t\t`${context} returned an invalid response: ${JSON.stringify(payload).slice(0, 200)}`,\n\t\t);\n\t}\n\treturn payload;\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\tkeepLeaseAlive: async (leaseId: string): Promise<GondolinLeaseResponse> => {\n\t\t\tconst response = await fetchImpl(`${baseUrl}/lease/${leaseId}`);\n\t\t\treturn await readJsonResponse(\n\t\t\t\tresponse,\n\t\t\t\t'Controller lease keepalive API',\n\t\t\t\tisGondolinLeaseResponse,\n\t\t\t);\n\t\t},\n\t\tpeekLease: async (leaseId: string): Promise<LeasePeekResponse> => {\n\t\t\tconst response = await fetchImpl(`${baseUrl}/lease/${leaseId}/peek`);\n\t\t\treturn await readJsonResponse(response, 'Controller lease peek API', isLeasePeekResponse);\n\t\t},\n\t\treleaseLease: async (leaseId: string): Promise<void> => {\n\t\t\tconst response = await fetchImpl(`${baseUrl}/lease/${leaseId}`, {\n\t\t\t\tmethod: 'DELETE',\n\t\t\t});\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errorBody = await readErrorBody(response, 'Controller lease release API');\n\t\t\t\tthrow new ControllerLeaseRequestError({\n\t\t\t\t\tbodyText: errorBody.bodyText,\n\t\t\t\t\tcontext: 'Controller lease release API',\n\t\t\t\t\tresponseBody: errorBody.responseBody,\n\t\t\t\t\tstatus: response.status,\n\t\t\t\t});\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({\n\t\t\t\t\tagentWorkspaceDir: request.agentWorkspaceDir,\n\t\t\t\t\tprofileId: request.profileId,\n\t\t\t\t\tscopeKey: request.scopeKey,\n\t\t\t\t\tworkMountDir: request.workMountDir,\n\t\t\t\t\tzoneId: request.zoneId,\n\t\t\t\t}),\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\treturn await readJsonResponse(response, 'Controller lease API', isGondolinLeaseResponse);\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 {\n\tControllerLeaseRequestError,\n\tcreateLeaseClient,\n\ttype GondolinLeaseResponse,\n} 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\nfunction scopeCacheKey(params: {\n\treadonly agentWorkspaceDir: string;\n\treadonly profileId: string;\n\treadonly scopeKey: string;\n\treadonly workspaceDir: string;\n\treadonly zoneId: string;\n}): string {\n\treturn [\n\t\tparams.zoneId,\n\t\tparams.scopeKey,\n\t\tparams.profileId,\n\t\tparams.agentWorkspaceDir,\n\t\tparams.workspaceDir,\n\t].join('\\0');\n}\n\nfunction formatUnknownError(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction writeSandboxBackendLog(message: string): void {\n\tprocess.stderr.write(`[openclaw-agent-vm-plugin] ${message}\\n`);\n}\n\nfunction shouldRefreshCachedLease(error: unknown): boolean {\n\treturn error instanceof ControllerLeaseRequestError && error.status === 404;\n}\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 profileId = options.profileId ?? 'standard';\n\t\tconst cacheKey = scopeCacheKey({\n\t\t\tagentWorkspaceDir: params.agentWorkspaceDir,\n\t\t\tprofileId,\n\t\t\tscopeKey: params.scopeKey,\n\t\t\tworkspaceDir: params.workspaceDir,\n\t\t\tzoneId: options.zoneId,\n\t\t});\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(cacheKey);\n\t\tif (cachedEntry) {\n\t\t\ttry {\n\t\t\t\tawait leaseClient.keepLeaseAlive(cachedEntry.lease.leaseId);\n\t\t\t\treturn cachedEntry.handle;\n\t\t\t} catch (error) {\n\t\t\t\twriteSandboxBackendLog(\n\t\t\t\t\t`lease keepalive failed for zone '${options.zoneId}' scope '${params.scopeKey}' lease '${cachedEntry.lease.leaseId}': ${formatUnknownError(error)}`,\n\t\t\t\t);\n\t\t\t\tif (!shouldRefreshCachedLease(error)) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tscopeCache.delete(cacheKey);\n\t\t\t}\n\t\t}\n\t\t// OpenClaw SDK still names the selected sandbox path `workspaceDir`.\n\t\t// agent-vm's controller calls the same value `workMountDir` because it\n\t\t// backs the Tool VM /work mount.\n\t\tconst leaseResponse = await leaseClient.requestLease({\n\t\t\tagentWorkspaceDir: params.agentWorkspaceDir,\n\t\t\tprofileId,\n\t\t\tscopeKey: params.scopeKey,\n\t\t\tworkMountDir: 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(cacheKey, { 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.peekLease(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 zoneGitToken?: string;\n\treadonly zoneGitTokenEnv?: 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\t...(typeof config.zoneGitToken === 'string' ? { zoneGitToken: config.zoneGitToken } : {}),\n\t\t...(typeof config.zoneGitTokenEnv === 'string'\n\t\t\t? { zoneGitTokenEnv: config.zoneGitTokenEnv }\n\t\t\t: {}),\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: '/work',\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 interface OpenClawToolRegistration {\n\treadonly description: string;\n\treadonly execute: (toolCallId: string, params: unknown) => Promise<OpenClawToolResult>;\n\treadonly name: string;\n\treadonly parameters: Record<string, unknown>;\n}\n\nexport interface OpenClawToolRegistrationOptions {\n\treadonly name?: string;\n\treadonly names?: readonly string[];\n\treadonly optional?: boolean;\n}\n\nexport interface OpenClawToolResult {\n\treadonly content: string;\n\treadonly details?: unknown;\n}\n\nexport interface OpenClawToolRegistrationApi {\n\treadonly registerTool?: (\n\t\ttool: OpenClawToolRegistration,\n\t\toptions?: OpenClawToolRegistrationOptions,\n\t) => void;\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 type { OpenClawToolRegistrationApi } from './openclaw-sandbox-sdk-contract.js';\n\ntype RequiredOpenClawToolRegistrationApi = OpenClawToolRegistrationApi & {\n\treadonly registerTool: NonNullable<OpenClawToolRegistrationApi['registerTool']>;\n};\n\nexport interface RegisterZoneGitToolOptions {\n\treadonly api: RequiredOpenClawToolRegistrationApi;\n\treadonly controllerUrl: string;\n\treadonly fetchImpl?: typeof fetch;\n\treadonly zoneGitToken?: string;\n\treadonly zoneId: string;\n}\n\nconst zoneGitCapabilityHeader = 'x-agent-vm-zone-git-token';\n\nfunction readExpectedHead(input: unknown): string {\n\tif (typeof input !== 'object' || input === null || !('expectedHead' in input)) {\n\t\tthrow new Error('zone_git_push requires expectedHead.');\n\t}\n\tconst expectedHead = input.expectedHead;\n\tif (typeof expectedHead !== 'string' || expectedHead.length === 0) {\n\t\tthrow new Error('zone_git_push requires expectedHead.');\n\t}\n\treturn expectedHead;\n}\n\nfunction buildControllerUrl(controllerUrl: string, zoneId: string): string {\n\treturn `${controllerUrl.replace(/\\/$/u, '')}/zones/${encodeURIComponent(zoneId)}/zone-git/push`;\n}\n\nasync function readResponseText(response: Response): Promise<string> {\n\ttry {\n\t\treturn await response.text();\n\t} catch (error) {\n\t\treturn error instanceof Error ? error.message : String(error);\n\t}\n}\n\nfunction parseJsonPayload(responseText: string): unknown {\n\ttry {\n\t\treturn JSON.parse(responseText);\n\t} catch (error) {\n\t\tthrow new Error(`zone_git_push returned non-JSON response: ${responseText.slice(0, 500)}`, {\n\t\t\tcause: error,\n\t\t});\n\t}\n}\n\nexport function registerZoneGitTool(options: RegisterZoneGitToolOptions): void {\n\toptions.api.registerTool(\n\t\t{\n\t\t\tname: 'zone_git_push',\n\t\t\tdescription:\n\t\t\t\t'Push committed OpenClaw zone workspace changes through the agent-vm controller. Use after git commit; do not run raw git push.',\n\t\t\tparameters: {\n\t\t\t\ttype: 'object',\n\t\t\t\tadditionalProperties: false,\n\t\t\t\tproperties: {\n\t\t\t\t\texpectedHead: { type: 'string' },\n\t\t\t\t},\n\t\t\t\trequired: ['expectedHead'],\n\t\t\t},\n\t\t\texecute: async (_toolCallId: string, input: unknown) => {\n\t\t\t\tconst expectedHead = readExpectedHead(input);\n\t\t\t\tconst response = await (options.fetchImpl ?? fetch)(\n\t\t\t\t\tbuildControllerUrl(options.controllerUrl, options.zoneId),\n\t\t\t\t\t{\n\t\t\t\t\t\tbody: JSON.stringify({ expectedHead }),\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t'content-type': 'application/json',\n\t\t\t\t\t\t\t...(options.zoneGitToken ? { [zoneGitCapabilityHeader]: options.zoneGitToken } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tconst responseText = await readResponseText(response);\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`zone_git_push failed: ${response.status} ${responseText.slice(0, 500)}`);\n\t\t\t\t}\n\t\t\t\tconst payload = parseJsonPayload(responseText);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: JSON.stringify(payload),\n\t\t\t\t\tdetails: payload,\n\t\t\t\t};\n\t\t\t},\n\t\t},\n\t\t{ name: 'zone_git_push', optional: true },\n\t);\n}\n","import { resolveGondolinPluginConfig } from './gondolin-plugin-config.js';\nimport { createBackendDeps } from './openclaw-backend-dependencies.js';\nimport {\n\tassertSdkShape,\n\ttype OpenClawToolRegistrationApi,\n\ttype SshHelpers,\n\ttype SshSandboxSession,\n} from './openclaw-sandbox-sdk-contract.js';\nimport {\n\tcreateGondolinSandboxBackendFactory,\n\tcreateGondolinSandboxBackendManager,\n} from './sandbox-backend-factory.js';\nimport { registerZoneGitTool } from './zone-git-tool.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 registerTool?: OpenClawToolRegistrationApi['registerTool'];\n\t\treadonly registrationMode: string;\n\t}): void {\n\t\tconst registerTool = api.registerTool;\n\t\tif (typeof registerTool !== 'function') {\n\t\t\tif (api.registrationMode === 'full') {\n\t\t\t\tthrow new Error('Gondolin full registration requires OpenClaw registerTool.');\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tconst pluginConfig = resolveGondolinPluginConfig(api.pluginConfig);\n\t\tconst zoneGitToken =\n\t\t\tpluginConfig.zoneGitToken ??\n\t\t\t(pluginConfig.zoneGitTokenEnv ? process.env[pluginConfig.zoneGitTokenEnv] : undefined);\n\t\tregisterZoneGitTool({\n\t\t\tapi: { registerTool },\n\t\t\tcontrollerUrl: pluginConfig.controllerUrl,\n\t\t\t...(zoneGitToken ? { zoneGitToken } : {}),\n\t\t\tzoneId: pluginConfig.zoneId,\n\t\t});\n\t\tif (api.registrationMode !== 'full') {\n\t\t\treturn;\n\t\t}\n\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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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["isGondolinLeaseResponse","formatUnknownError"],"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-runtime-status.ts","../src/openclaw-sandbox-sdk-contract.ts","../src/zone-git-tool.ts","../src/openclaw-plugin-registration.ts","../src/index.ts"],"sourcesContent":["export interface GondolinLeaseResponse {\n\treadonly idleTtlMs?: number;\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 LeasePeekResponse {\n\treadonly createdAt: number;\n\treadonly lastUsedAt: number;\n\treadonly leaseId: string;\n\treadonly profileId: string;\n\treadonly scopeKey: string;\n\treadonly ssh: {\n\t\treadonly host: string;\n\t\treadonly port: number;\n\t\treadonly user: string;\n\t};\n\treadonly tcpSlot: number;\n\treadonly zoneId: string;\n}\n\nexport interface OpenClawRuntimeStatusReport {\n\treadonly findings: readonly {\n\t\treadonly hint: string;\n\t\treadonly id: string;\n\t\treadonly ok: boolean;\n\t}[];\n\treadonly pluginId: 'gondolin';\n\treadonly zoneId: string;\n}\n\nexport interface LeaseClient {\n\t// Cached handles use keepalive; read-only runtime probes use peekLease.\n\tkeepLeaseAlive(leaseId: string): Promise<GondolinLeaseResponse>;\n\tpeekLease(leaseId: string): Promise<LeasePeekResponse>;\n\tpublishOpenClawRuntimeStatus?(report: OpenClawRuntimeStatusReport): Promise<void>;\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 workMountDir: string;\n\t\treadonly zoneId: string;\n\t}): Promise<GondolinLeaseResponse>;\n}\n\nexport type ControllerLeaseRequestErrorKind = 'client-error' | 'server-error';\n\nexport class ControllerLeaseRequestError extends Error {\n\treadonly bodyText: string;\n\treadonly kind: ControllerLeaseRequestErrorKind;\n\treadonly responseBody: unknown;\n\treadonly status: number;\n\n\tconstructor(options: {\n\t\treadonly bodyText: string;\n\t\treadonly context: string;\n\t\treadonly responseBody: unknown;\n\t\treadonly status: number;\n\t}) {\n\t\tconst kind: ControllerLeaseRequestErrorKind =\n\t\t\toptions.status >= 400 && options.status < 500 ? 'client-error' : 'server-error';\n\t\tsuper(`${options.context} returned HTTP ${String(options.status)} (${kind})`);\n\t\tthis.bodyText = options.bodyText;\n\t\tthis.kind = kind;\n\t\tthis.responseBody = options.responseBody;\n\t\tthis.status = options.status;\n\t}\n}\n\nfunction objectValue(value: unknown): object | undefined {\n\treturn typeof value === 'object' && value !== null ? value : undefined;\n}\n\nfunction isSshResponse(value: unknown): value is GondolinLeaseResponse['ssh'] {\n\tconst record = objectValue(value);\n\treturn (\n\t\trecord !== undefined &&\n\t\ttypeof Reflect.get(record, 'host') === 'string' &&\n\t\ttypeof Reflect.get(record, 'identityPem') === 'string' &&\n\t\ttypeof Reflect.get(record, 'knownHostsLine') === 'string' &&\n\t\ttypeof Reflect.get(record, 'port') === 'number' &&\n\t\ttypeof Reflect.get(record, 'user') === 'string'\n\t);\n}\n\nfunction isLeasePeekSshResponse(value: unknown): value is LeasePeekResponse['ssh'] {\n\tconst record = objectValue(value);\n\treturn (\n\t\trecord !== undefined &&\n\t\ttypeof Reflect.get(record, 'host') === 'string' &&\n\t\ttypeof Reflect.get(record, 'port') === 'number' &&\n\t\ttypeof Reflect.get(record, 'user') === 'string'\n\t);\n}\n\nfunction isGondolinLeaseResponse(value: unknown): value is GondolinLeaseResponse {\n\tconst record = objectValue(value);\n\treturn (\n\t\trecord !== undefined &&\n\t\t(Reflect.get(record, 'idleTtlMs') === undefined ||\n\t\t\ttypeof Reflect.get(record, 'idleTtlMs') === 'number') &&\n\t\ttypeof Reflect.get(record, 'leaseId') === 'string' &&\n\t\tisSshResponse(Reflect.get(record, 'ssh')) &&\n\t\ttypeof Reflect.get(record, 'tcpSlot') === 'number' &&\n\t\ttypeof Reflect.get(record, 'workdir') === 'string'\n\t);\n}\n\nfunction isLeasePeekResponse(value: unknown): value is LeasePeekResponse {\n\tconst record = objectValue(value);\n\treturn (\n\t\trecord !== undefined &&\n\t\ttypeof Reflect.get(record, 'createdAt') === 'number' &&\n\t\ttypeof Reflect.get(record, 'lastUsedAt') === 'number' &&\n\t\ttypeof Reflect.get(record, 'leaseId') === 'string' &&\n\t\ttypeof Reflect.get(record, 'profileId') === 'string' &&\n\t\ttypeof Reflect.get(record, 'scopeKey') === 'string' &&\n\t\tisLeasePeekSshResponse(Reflect.get(record, 'ssh')) &&\n\t\ttypeof Reflect.get(record, 'tcpSlot') === 'number' &&\n\t\ttypeof Reflect.get(record, 'zoneId') === 'string'\n\t);\n}\n\nfunction formatUnknownError(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction writeLeaseClientLog(message: string): void {\n\tprocess.stderr.write(`[openclaw-agent-vm-plugin] ${message}\\n`);\n}\n\nfunction parseJsonBody(bodyText: string, context: string): unknown {\n\ttry {\n\t\treturn JSON.parse(bodyText);\n\t} catch (error) {\n\t\twriteLeaseClientLog(`${context} returned a non-JSON error body: ${formatUnknownError(error)}`);\n\t\treturn undefined;\n\t}\n}\n\nasync function readErrorBody(\n\tresponse: Response,\n\tcontext: string,\n): Promise<{\n\treadonly bodyText: string;\n\treadonly responseBody: unknown;\n}> {\n\tconst bodyText = await response.text().catch(() => '(unreadable)');\n\treturn {\n\t\tbodyText,\n\t\tresponseBody: bodyText === '(unreadable)' ? undefined : parseJsonBody(bodyText, context),\n\t};\n}\n\nasync function readJsonResponse<TValue>(\n\tresponse: Response,\n\tcontext: string,\n\tisExpectedResponse: (value: unknown) => value is TValue,\n): Promise<TValue> {\n\tif (!response.ok) {\n\t\tconst errorBody = await readErrorBody(response, context);\n\t\tthrow new ControllerLeaseRequestError({\n\t\t\tbodyText: errorBody.bodyText,\n\t\t\tcontext,\n\t\t\tresponseBody: errorBody.responseBody,\n\t\t\tstatus: response.status,\n\t\t});\n\t}\n\tconst payload = await response.json();\n\tif (!isExpectedResponse(payload)) {\n\t\tthrow new TypeError(\n\t\t\t`${context} returned an invalid response: ${JSON.stringify(payload).slice(0, 200)}`,\n\t\t);\n\t}\n\treturn payload;\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\tkeepLeaseAlive: async (leaseId: string): Promise<GondolinLeaseResponse> => {\n\t\t\tconst response = await fetchImpl(`${baseUrl}/lease/${leaseId}`);\n\t\t\treturn await readJsonResponse(\n\t\t\t\tresponse,\n\t\t\t\t'Controller lease keepalive API',\n\t\t\t\tisGondolinLeaseResponse,\n\t\t\t);\n\t\t},\n\t\tpeekLease: async (leaseId: string): Promise<LeasePeekResponse> => {\n\t\t\tconst response = await fetchImpl(`${baseUrl}/lease/${leaseId}/peek`);\n\t\t\treturn await readJsonResponse(response, 'Controller lease peek API', isLeasePeekResponse);\n\t\t},\n\t\tpublishOpenClawRuntimeStatus: async (report): Promise<void> => {\n\t\t\tconst response = await fetchImpl(\n\t\t\t\t`${baseUrl}/zones/${encodeURIComponent(report.zoneId)}/openclaw-runtime-status`,\n\t\t\t\t{\n\t\t\t\t\tbody: JSON.stringify(report),\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t'content-type': 'application/json',\n\t\t\t\t\t},\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t},\n\t\t\t);\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errorBody = await readErrorBody(response, 'Controller OpenClaw runtime status API');\n\t\t\t\tthrow new ControllerLeaseRequestError({\n\t\t\t\t\tbodyText: errorBody.bodyText,\n\t\t\t\t\tcontext: 'Controller OpenClaw runtime status API',\n\t\t\t\t\tresponseBody: errorBody.responseBody,\n\t\t\t\t\tstatus: response.status,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\treleaseLease: async (leaseId: string): Promise<void> => {\n\t\t\tconst response = await fetchImpl(`${baseUrl}/lease/${leaseId}`, {\n\t\t\t\tmethod: 'DELETE',\n\t\t\t});\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errorBody = await readErrorBody(response, 'Controller lease release API');\n\t\t\t\tthrow new ControllerLeaseRequestError({\n\t\t\t\t\tbodyText: errorBody.bodyText,\n\t\t\t\t\tcontext: 'Controller lease release API',\n\t\t\t\t\tresponseBody: errorBody.responseBody,\n\t\t\t\t\tstatus: response.status,\n\t\t\t\t});\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({\n\t\t\t\t\tagentWorkspaceDir: request.agentWorkspaceDir,\n\t\t\t\t\tprofileId: request.profileId,\n\t\t\t\t\tscopeKey: request.scopeKey,\n\t\t\t\t\tworkMountDir: request.workMountDir,\n\t\t\t\t\tzoneId: request.zoneId,\n\t\t\t\t}),\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\treturn await readJsonResponse(response, 'Controller lease API', isGondolinLeaseResponse);\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 {\n\tControllerLeaseRequestError,\n\tcreateLeaseClient,\n\ttype GondolinLeaseResponse,\n\ttype OpenClawRuntimeStatusReport,\n} 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\nfunction scopeCacheKey(params: {\n\treadonly agentWorkspaceDir: string;\n\treadonly profileId: string;\n\treadonly scopeKey: string;\n\treadonly workspaceDir: string;\n\treadonly zoneId: string;\n}): string {\n\treturn [\n\t\tparams.zoneId,\n\t\tparams.scopeKey,\n\t\tparams.profileId,\n\t\tparams.agentWorkspaceDir,\n\t\tparams.workspaceDir,\n\t].join('\\0');\n}\n\nfunction formatUnknownError(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction writeSandboxBackendLog(message: string): void {\n\tprocess.stderr.write(`[openclaw-agent-vm-plugin] ${message}\\n`);\n}\n\nfunction shouldRefreshCachedLease(error: unknown): boolean {\n\treturn error instanceof ControllerLeaseRequestError && error.status === 404;\n}\n\nfunction hasDisposeFunction(\n\tvalue: unknown,\n): value is { readonly dispose: () => void | Promise<void> } {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t'dispose' in value &&\n\t\ttypeof value.dispose === 'function'\n\t);\n}\n\nfunction renewalIntervalMsForLease(lease: GondolinLeaseResponse): number {\n\tconst fallbackRenewalIntervalMs = 60_000;\n\tconst minimumRenewalIntervalMs = 1_000;\n\tif (lease.idleTtlMs === undefined) {\n\t\treturn fallbackRenewalIntervalMs;\n\t}\n\treturn Math.max(\n\t\tminimumRenewalIntervalMs,\n\t\tMath.min(fallbackRenewalIntervalMs, Math.floor(lease.idleTtlMs / 3)),\n\t);\n}\n\nexport function createGondolinSandboxBackendFactory(\n\toptions: {\n\t\treadonly controllerUrl: string;\n\t\treadonly openClawRuntimeStatusProvider?: () => OpenClawRuntimeStatusReport | undefined;\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 profileId = options.profileId ?? 'standard';\n\t\tconst cacheKey = scopeCacheKey({\n\t\t\tagentWorkspaceDir: params.agentWorkspaceDir,\n\t\t\tprofileId,\n\t\t\tscopeKey: params.scopeKey,\n\t\t\tworkspaceDir: params.workspaceDir,\n\t\t\tzoneId: options.zoneId,\n\t\t});\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(cacheKey);\n\t\tif (cachedEntry) {\n\t\t\ttry {\n\t\t\t\tawait leaseClient.keepLeaseAlive(cachedEntry.lease.leaseId);\n\t\t\t\treturn cachedEntry.handle;\n\t\t\t} catch (error) {\n\t\t\t\twriteSandboxBackendLog(\n\t\t\t\t\t`lease keepalive failed for zone '${options.zoneId}' scope '${params.scopeKey}' lease '${cachedEntry.lease.leaseId}': ${formatUnknownError(error)}`,\n\t\t\t\t);\n\t\t\t\tif (!shouldRefreshCachedLease(error)) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tscopeCache.delete(cacheKey);\n\t\t\t}\n\t\t}\n\t\t// OpenClaw SDK still names the selected sandbox path `workspaceDir`.\n\t\t// agent-vm's controller calls the same value `workMountDir` because it\n\t\t// backs the Tool VM /work mount.\n\t\tconst runtimeStatus = options.openClawRuntimeStatusProvider?.();\n\t\tif (runtimeStatus && leaseClient.publishOpenClawRuntimeStatus) {\n\t\t\tawait leaseClient.publishOpenClawRuntimeStatus(runtimeStatus);\n\t\t}\n\t\tconst leaseResponse = await leaseClient.requestLease({\n\t\t\tagentWorkspaceDir: params.agentWorkspaceDir,\n\t\t\tprofileId,\n\t\t\tscopeKey: params.scopeKey,\n\t\t\tworkMountDir: 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\tkeepLeaseAlive: async (operation) => {\n\t\t\t\ttry {\n\t\t\t\t\tawait leaseClient.keepLeaseAlive(lease.leaseId);\n\t\t\t\t} catch (error) {\n\t\t\t\t\twriteSandboxBackendLog(\n\t\t\t\t\t\t`lease command keepalive failed during ${operation} for zone '${options.zoneId}' scope '${params.scopeKey}' lease '${lease.leaseId}': ${formatUnknownError(error)}`,\n\t\t\t\t\t);\n\t\t\t\t\tif (shouldRefreshCachedLease(error)) {\n\t\t\t\t\t\tconst cachedEntryForLease = scopeCache.get(cacheKey);\n\t\t\t\t\t\tif (cachedEntryForLease?.lease.leaseId === lease.leaseId) {\n\t\t\t\t\t\t\tscopeCache.delete(cacheKey);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t},\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(cacheKey, { 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 keepLeaseAlive: (operation: string) => Promise<void>;\n\treadonly lease: GondolinLeaseResponse;\n\treadonly runRemoteShellScript: CreateBackendDependencies['runRemoteShellScript'];\n\treadonly scopeKey: string;\n\treadonly zoneId: string;\n}): GondolinSandboxBackendHandle {\n\tconst renewalIntervalMs = renewalIntervalMsForLease(options.lease);\n\n\tfunction beginLeaseRenewalTimer(operation: string): { readonly dispose: () => void } {\n\t\tconst interval = setInterval(() => {\n\t\t\tvoid options.keepLeaseAlive(`${operation} active`).catch((error: unknown) => {\n\t\t\t\twriteSandboxBackendLog(\n\t\t\t\t\t`lease command keepalive failed while ${operation} was active for zone '${options.zoneId}' scope '${options.scopeKey}' lease '${options.lease.leaseId}': ${formatUnknownError(error)}`,\n\t\t\t\t);\n\t\t\t});\n\t\t}, renewalIntervalMs);\n\t\tif ('unref' in interval && typeof interval.unref === 'function') {\n\t\t\tinterval.unref();\n\t\t}\n\t\treturn {\n\t\t\tdispose: () => clearInterval(interval),\n\t\t};\n\t}\n\n\tasync function renewLeaseAfterOperation(\n\t\toperation: string,\n\t\toptionsForRenewal: { readonly hadPrimaryError: boolean },\n\t): Promise<void> {\n\t\ttry {\n\t\t\tawait options.keepLeaseAlive(operation);\n\t\t} catch (error) {\n\t\t\tif (!optionsForRenewal.hadPrimaryError) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\twriteSandboxBackendLog(\n\t\t\t\t`lease command keepalive failed after ${operation} for zone '${options.zoneId}' scope '${options.scopeKey}' lease '${options.lease.leaseId}': ${formatUnknownError(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tasync function runWithLeaseRenewal<TValue>(\n\t\toperation: string,\n\t\trunOperation: () => Promise<TValue>,\n\t): Promise<TValue> {\n\t\tawait options.keepLeaseAlive(`${operation} start`);\n\t\tconst renewalTimer = beginLeaseRenewalTimer(operation);\n\t\ttry {\n\t\t\tconst result = await runOperation();\n\t\t\trenewalTimer.dispose();\n\t\t\tawait renewLeaseAfterOperation(`${operation} end`, { hadPrimaryError: false });\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\trenewalTimer.dispose();\n\t\t\tawait renewLeaseAfterOperation(`${operation} end`, { hadPrimaryError: true });\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tconst boundRunRemoteShellScript: FsBridgeLeaseContext['runRemoteShellScript'] = async (\n\t\tshellParams,\n\t) =>\n\t\tawait runWithLeaseRenewal(\n\t\t\t'fs bridge shell command',\n\t\t\tasync () =>\n\t\t\t\tawait options.runRemoteShellScript({\n\t\t\t\t\t...(shellParams.allowFailure !== undefined\n\t\t\t\t\t\t? { allowFailure: shellParams.allowFailure }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\tscript: buildShellScriptWithArgs(shellParams.script, shellParams.args),\n\t\t\t\t\t...(shellParams.signal !== undefined ? { signal: shellParams.signal } : {}),\n\t\t\t\t\tssh: options.lease.ssh,\n\t\t\t\t\t...(shellParams.stdin !== undefined ? { stdin: shellParams.stdin } : {}),\n\t\t\t\t}),\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.keepLeaseAlive('exec spec build start');\n\t\t\tconst execRenewalTimer = beginLeaseRenewalTimer('exec command');\n\t\t\tlet execSpec: Awaited<ReturnType<CreateBackendDependencies['buildExecSpec']>>;\n\t\t\ttry {\n\t\t\t\texecSpec = await options.buildExecSpec({\n\t\t\t\t\tcommand: execParams.command,\n\t\t\t\t\tenv: execParams.env,\n\t\t\t\t\tssh: options.lease.ssh,\n\t\t\t\t\tusePty: execParams.usePty,\n\t\t\t\t\tworkdir: execParams.workdir ?? options.lease.workdir,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\texecRenewalTimer.dispose();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\t...execSpec,\n\t\t\t\tfinalizeToken: {\n\t\t\t\t\tinnerToken: execSpec.finalizeToken,\n\t\t\t\t\tleaseRenewalTimer: execRenewalTimer,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\tfinalizeExec: async (finalizeParams) => {\n\t\t\tconst token = finalizeParams.token;\n\t\t\tconst leaseRenewalTimer =\n\t\t\t\ttypeof token === 'object' &&\n\t\t\t\ttoken !== null &&\n\t\t\t\t'leaseRenewalTimer' in token &&\n\t\t\t\thasDisposeFunction(token.leaseRenewalTimer)\n\t\t\t\t\t? token.leaseRenewalTimer\n\t\t\t\t\t: undefined;\n\t\t\tconst innerToken =\n\t\t\t\ttypeof token === 'object' && token !== null && 'innerToken' in token\n\t\t\t\t\t? token.innerToken\n\t\t\t\t\t: token;\n\t\t\tlet hadPrimaryError = false;\n\t\t\tlet primaryError: unknown;\n\t\t\ttry {\n\t\t\t\tif (hasDisposeFunction(innerToken)) {\n\t\t\t\t\tawait innerToken.dispose();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\thadPrimaryError = true;\n\t\t\t\tprimaryError = error;\n\t\t\t} finally {\n\t\t\t\tawait leaseRenewalTimer?.dispose();\n\t\t\t}\n\t\t\tawait renewLeaseAfterOperation('exec finalize', {\n\t\t\t\thadPrimaryError,\n\t\t\t});\n\t\t\tif (hadPrimaryError) {\n\t\t\t\tthrow primaryError;\n\t\t\t}\n\t\t},\n\t\trunShellCommand: async (commandParams) =>\n\t\t\tawait runWithLeaseRenewal(\n\t\t\t\t'shell command',\n\t\t\t\tasync () =>\n\t\t\t\t\tawait options.runRemoteShellScript({\n\t\t\t\t\t\tscript: commandParams.script,\n\t\t\t\t\t\tssh: options.lease.ssh,\n\t\t\t\t\t}),\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.peekLease(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 zoneGitToken?: string;\n\treadonly zoneGitTokenEnv?: 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\t...(typeof config.zoneGitToken === 'string' ? { zoneGitToken: config.zoneGitToken } : {}),\n\t\t...(typeof config.zoneGitTokenEnv === 'string'\n\t\t\t? { zoneGitTokenEnv: config.zoneGitTokenEnv }\n\t\t\t: {}),\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: '/work',\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","interface OpenClawAgentConfig {\n\treadonly [key: string]: unknown;\n\treadonly id?: unknown;\n\treadonly sandbox?: {\n\t\treadonly [key: string]: unknown;\n\t\treadonly backend?: unknown;\n\t\treadonly mode?: unknown;\n\t\treadonly scope?: unknown;\n\t\treadonly workspaceAccess?: unknown;\n\t};\n\treadonly workspace?: unknown;\n}\n\ninterface OpenClawRuntimeConfig {\n\treadonly [key: string]: unknown;\n\treadonly agents?: {\n\t\treadonly defaults?: OpenClawAgentConfig;\n\t\treadonly list?: readonly unknown[];\n\t};\n}\n\nexport interface OpenClawRuntimeRequirementFinding {\n\treadonly hint: string;\n\treadonly id: string;\n\treadonly ok: boolean;\n}\n\nexport interface OpenClawRuntimeStatusReport {\n\treadonly findings: readonly OpenClawRuntimeRequirementFinding[];\n\treadonly pluginId: 'gondolin';\n\treadonly zoneId: string;\n}\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction readAgentConfigEntries(config: OpenClawRuntimeConfig): readonly {\n\treadonly config: OpenClawAgentConfig;\n\treadonly label: string;\n}[] {\n\tconst defaultConfig = config.agents?.defaults ?? {};\n\tconst agentConfigs = (config.agents?.list ?? [])\n\t\t.filter(isObjectRecord)\n\t\t.map((agentConfig, agentIndex) => ({\n\t\t\tconfig: agentConfig,\n\t\t\tlabel:\n\t\t\t\ttypeof agentConfig.id === 'string'\n\t\t\t\t\t? `agent-${agentConfig.id}`\n\t\t\t\t\t: `agent-${String(agentIndex)}`,\n\t\t}));\n\treturn [{ config: defaultConfig, label: 'defaults' }, ...agentConfigs];\n}\n\nfunction effectiveSandboxValue(\n\tdefaults: OpenClawAgentConfig,\n\tagentConfig: OpenClawAgentConfig,\n\tkey: 'backend' | 'mode' | 'scope' | 'workspaceAccess',\n): unknown {\n\treturn agentConfig.sandbox?.[key] ?? defaults.sandbox?.[key];\n}\n\nfunction effectiveWorkspace(\n\tdefaults: OpenClawAgentConfig,\n\tagentConfig: OpenClawAgentConfig,\n): unknown {\n\treturn agentConfig.workspace ?? defaults.workspace;\n}\n\nfunction requirementFinding(options: {\n\treadonly actualValue: unknown;\n\treadonly expectedValue: string;\n\treadonly fieldPath: string;\n\treadonly label: string;\n\treadonly zoneId: string;\n}): OpenClawRuntimeRequirementFinding {\n\tconst ok = options.actualValue === options.expectedValue;\n\treturn {\n\t\tid: `openclaw-tool-vm-${options.fieldPath.replace(/[.[\\]]/gu, '-')}-${options.zoneId}-${options.label}`,\n\t\tok,\n\t\thint: ok\n\t\t\t? `${options.fieldPath}=${options.expectedValue}`\n\t\t\t: `Set ${options.fieldPath} to \"${options.expectedValue}\" for OpenClaw Tool VM mediation.`,\n\t};\n}\n\nexport function buildOpenClawRuntimeStatusReport(options: {\n\treadonly config: Record<string, unknown>;\n\treadonly zoneId: string;\n}): OpenClawRuntimeStatusReport {\n\tconst config: OpenClawRuntimeConfig = options.config;\n\tconst defaults = config.agents?.defaults ?? {};\n\treturn {\n\t\tpluginId: 'gondolin',\n\t\tzoneId: options.zoneId,\n\t\tfindings: readAgentConfigEntries(config).flatMap(({ config: agentConfig, label }) => {\n\t\t\tconst workspace = effectiveWorkspace(defaults, agentConfig);\n\t\t\treturn [\n\t\t\t\trequirementFinding({\n\t\t\t\t\tactualValue: effectiveSandboxValue(defaults, agentConfig, 'backend'),\n\t\t\t\t\texpectedValue: 'gondolin',\n\t\t\t\t\tfieldPath: `agents.${label}.sandbox.backend`,\n\t\t\t\t\tlabel,\n\t\t\t\t\tzoneId: options.zoneId,\n\t\t\t\t}),\n\t\t\t\trequirementFinding({\n\t\t\t\t\tactualValue: effectiveSandboxValue(defaults, agentConfig, 'mode'),\n\t\t\t\t\texpectedValue: 'all',\n\t\t\t\t\tfieldPath: `agents.${label}.sandbox.mode`,\n\t\t\t\t\tlabel,\n\t\t\t\t\tzoneId: options.zoneId,\n\t\t\t\t}),\n\t\t\t\trequirementFinding({\n\t\t\t\t\tactualValue: effectiveSandboxValue(defaults, agentConfig, 'scope'),\n\t\t\t\t\texpectedValue: 'agent',\n\t\t\t\t\tfieldPath: `agents.${label}.sandbox.scope`,\n\t\t\t\t\tlabel,\n\t\t\t\t\tzoneId: options.zoneId,\n\t\t\t\t}),\n\t\t\t\trequirementFinding({\n\t\t\t\t\tactualValue: effectiveSandboxValue(defaults, agentConfig, 'workspaceAccess'),\n\t\t\t\t\texpectedValue: 'rw',\n\t\t\t\t\tfieldPath: `agents.${label}.sandbox.workspaceAccess`,\n\t\t\t\t\tlabel,\n\t\t\t\t\tzoneId: options.zoneId,\n\t\t\t\t}),\n\t\t\t\t{\n\t\t\t\t\tid: `openclaw-tool-vm-workspace-${options.zoneId}-${label}`,\n\t\t\t\t\tok: workspace !== '/zone',\n\t\t\t\t\thint:\n\t\t\t\t\t\tworkspace === '/zone'\n\t\t\t\t\t\t\t? 'Use /zone/agents/default or per-agent workspaces; keep /zone for shared zone files.'\n\t\t\t\t\t\t\t: typeof workspace === 'string'\n\t\t\t\t\t\t\t\t? workspace\n\t\t\t\t\t\t\t\t: 'agents workspace is unset',\n\t\t\t\t},\n\t\t\t] as const satisfies readonly OpenClawRuntimeRequirementFinding[];\n\t\t}),\n\t};\n}\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 interface OpenClawToolRegistration {\n\treadonly description: string;\n\treadonly execute: (toolCallId: string, params: unknown) => Promise<OpenClawToolResult>;\n\treadonly name: string;\n\treadonly parameters: Record<string, unknown>;\n}\n\nexport interface OpenClawToolRegistrationOptions {\n\treadonly name?: string;\n\treadonly names?: readonly string[];\n\treadonly optional?: boolean;\n}\n\nexport interface OpenClawToolResult {\n\treadonly content: string;\n\treadonly details?: unknown;\n}\n\nexport interface OpenClawToolRegistrationApi {\n\treadonly registerTool?: (\n\t\ttool: OpenClawToolRegistration,\n\t\toptions?: OpenClawToolRegistrationOptions,\n\t) => void;\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 type { OpenClawToolRegistrationApi } from './openclaw-sandbox-sdk-contract.js';\n\ntype RequiredOpenClawToolRegistrationApi = OpenClawToolRegistrationApi & {\n\treadonly registerTool: NonNullable<OpenClawToolRegistrationApi['registerTool']>;\n};\n\nexport interface RegisterZoneGitToolOptions {\n\treadonly api: RequiredOpenClawToolRegistrationApi;\n\treadonly controllerUrl: string;\n\treadonly fetchImpl?: typeof fetch;\n\treadonly zoneGitToken?: string;\n\treadonly zoneId: string;\n}\n\nconst zoneGitCapabilityHeader = 'x-agent-vm-zone-git-token';\n\nfunction readExpectedHead(input: unknown): string {\n\tif (typeof input !== 'object' || input === null || !('expectedHead' in input)) {\n\t\tthrow new Error('zone_git_push requires expectedHead.');\n\t}\n\tconst expectedHead = input.expectedHead;\n\tif (typeof expectedHead !== 'string' || expectedHead.length === 0) {\n\t\tthrow new Error('zone_git_push requires expectedHead.');\n\t}\n\treturn expectedHead;\n}\n\nfunction buildControllerUrl(controllerUrl: string, zoneId: string): string {\n\treturn `${controllerUrl.replace(/\\/$/u, '')}/zones/${encodeURIComponent(zoneId)}/zone-git/push`;\n}\n\nasync function readResponseText(response: Response): Promise<string> {\n\ttry {\n\t\treturn await response.text();\n\t} catch (error) {\n\t\treturn error instanceof Error ? error.message : String(error);\n\t}\n}\n\nfunction parseJsonPayload(responseText: string): unknown {\n\ttry {\n\t\treturn JSON.parse(responseText);\n\t} catch (error) {\n\t\tthrow new Error(`zone_git_push returned non-JSON response: ${responseText.slice(0, 500)}`, {\n\t\t\tcause: error,\n\t\t});\n\t}\n}\n\nexport function registerZoneGitTool(options: RegisterZoneGitToolOptions): void {\n\toptions.api.registerTool(\n\t\t{\n\t\t\tname: 'zone_git_push',\n\t\t\tdescription:\n\t\t\t\t'Push committed OpenClaw zone workspace changes through the agent-vm controller. Use after git commit; do not run raw git push.',\n\t\t\tparameters: {\n\t\t\t\ttype: 'object',\n\t\t\t\tadditionalProperties: false,\n\t\t\t\tproperties: {\n\t\t\t\t\texpectedHead: { type: 'string' },\n\t\t\t\t},\n\t\t\t\trequired: ['expectedHead'],\n\t\t\t},\n\t\t\texecute: async (_toolCallId: string, input: unknown) => {\n\t\t\t\tconst expectedHead = readExpectedHead(input);\n\t\t\t\tconst response = await (options.fetchImpl ?? fetch)(\n\t\t\t\t\tbuildControllerUrl(options.controllerUrl, options.zoneId),\n\t\t\t\t\t{\n\t\t\t\t\t\tbody: JSON.stringify({ expectedHead }),\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t'content-type': 'application/json',\n\t\t\t\t\t\t\t...(options.zoneGitToken ? { [zoneGitCapabilityHeader]: options.zoneGitToken } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tconst responseText = await readResponseText(response);\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`zone_git_push failed: ${response.status} ${responseText.slice(0, 500)}`);\n\t\t\t\t}\n\t\t\t\tconst payload = parseJsonPayload(responseText);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: JSON.stringify(payload),\n\t\t\t\t\tdetails: payload,\n\t\t\t\t};\n\t\t\t},\n\t\t},\n\t\t{ name: 'zone_git_push', optional: true },\n\t);\n}\n","import { createLeaseClient } from './controller-lease-client.js';\nimport { resolveGondolinPluginConfig } from './gondolin-plugin-config.js';\nimport { createBackendDeps } from './openclaw-backend-dependencies.js';\nimport { buildOpenClawRuntimeStatusReport } from './openclaw-runtime-status.js';\nimport {\n\tassertSdkShape,\n\ttype OpenClawToolRegistrationApi,\n\ttype SshHelpers,\n\ttype SshSandboxSession,\n} from './openclaw-sandbox-sdk-contract.js';\nimport {\n\tcreateGondolinSandboxBackendFactory,\n\tcreateGondolinSandboxBackendManager,\n} from './sandbox-backend-factory.js';\nimport { registerZoneGitTool } from './zone-git-tool.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 config?: Record<string, unknown>;\n\t\treadonly pluginConfig: Record<string, unknown>;\n\t\treadonly registerTool?: OpenClawToolRegistrationApi['registerTool'];\n\t\treadonly registrationMode: string;\n\t\treadonly runtime?: {\n\t\t\treadonly config?: {\n\t\t\t\treadonly current?: () => Record<string, unknown>;\n\t\t\t};\n\t\t};\n\t}): void {\n\t\tconst registerTool = api.registerTool;\n\t\tif (typeof registerTool !== 'function') {\n\t\t\tif (api.registrationMode === 'full') {\n\t\t\t\tthrow new Error('Gondolin full registration requires OpenClaw registerTool.');\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tconst pluginConfig = resolveGondolinPluginConfig(api.pluginConfig);\n\t\tconst zoneGitToken =\n\t\t\tpluginConfig.zoneGitToken ??\n\t\t\t(pluginConfig.zoneGitTokenEnv ? process.env[pluginConfig.zoneGitTokenEnv] : undefined);\n\t\tregisterZoneGitTool({\n\t\t\tapi: { registerTool },\n\t\t\tcontrollerUrl: pluginConfig.controllerUrl,\n\t\t\t...(zoneGitToken ? { zoneGitToken } : {}),\n\t\t\tzoneId: pluginConfig.zoneId,\n\t\t});\n\t\tif (api.registrationMode !== 'full') {\n\t\t\treturn;\n\t\t}\n\t\tconst buildRuntimeStatus = ():\n\t\t\t| ReturnType<typeof buildOpenClawRuntimeStatusReport>\n\t\t\t| undefined => {\n\t\t\tconst runtimeConfig = api.runtime?.config?.current?.() ?? api.config;\n\t\t\treturn runtimeConfig\n\t\t\t\t? buildOpenClawRuntimeStatusReport({\n\t\t\t\t\t\tconfig: runtimeConfig,\n\t\t\t\t\t\tzoneId: pluginConfig.zoneId,\n\t\t\t\t\t})\n\t\t\t\t: undefined;\n\t\t};\n\t\tconst initialRuntimeStatus = buildRuntimeStatus();\n\t\tif (initialRuntimeStatus) {\n\t\t\tconst leaseClient = createLeaseClient({ controllerUrl: pluginConfig.controllerUrl });\n\t\t\tvoid leaseClient\n\t\t\t\t.publishOpenClawRuntimeStatus?.(initialRuntimeStatus)\n\t\t\t\t?.catch((error: unknown) => {\n\t\t\t\t\tconst message = error instanceof Error ? error.message : JSON.stringify(error);\n\t\t\t\t\tprocess.stderr.write(\n\t\t\t\t\t\t`[gondolin] failed to publish OpenClaw runtime status: ${message}\\n`,\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t}\n\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(\n\t\t\t\t\t{\n\t\t\t\t\t\t...pluginConfig,\n\t\t\t\t\t\topenClawRuntimeStatusProvider: buildRuntimeStatus,\n\t\t\t\t\t},\n\t\t\t\t\tbackendDependencies,\n\t\t\t\t),\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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-vm/openclaw-agent-vm-plugin",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.60",
|
|
4
4
|
"description": "OpenClaw sandbox-backend plugin that delegates execution to a Gondolin-managed VM.",
|
|
5
5
|
"homepage": "https://github.com/ShravanSunder/agent-vm#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@agent-vm/gondolin-adapter": "0.0.
|
|
32
|
+
"@agent-vm/gondolin-adapter": "0.0.60"
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
35
|
"build": "tsdown && cp openclaw.plugin.json sdk-validate.mjs dist/",
|