@electric-agent/studio 1.0.0
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/bridge/daytona.d.ts +35 -0
- package/dist/bridge/daytona.d.ts.map +1 -0
- package/dist/bridge/daytona.js +146 -0
- package/dist/bridge/daytona.js.map +1 -0
- package/dist/bridge/docker-stdio.d.ts +30 -0
- package/dist/bridge/docker-stdio.d.ts.map +1 -0
- package/dist/bridge/docker-stdio.js +141 -0
- package/dist/bridge/docker-stdio.js.map +1 -0
- package/dist/bridge/hosted.d.ts +28 -0
- package/dist/bridge/hosted.d.ts.map +1 -0
- package/dist/bridge/hosted.js +113 -0
- package/dist/bridge/hosted.js.map +1 -0
- package/dist/bridge/index.d.ts +6 -0
- package/dist/bridge/index.d.ts.map +1 -0
- package/dist/bridge/index.js +5 -0
- package/dist/bridge/index.js.map +1 -0
- package/dist/bridge/sprites.d.ts +32 -0
- package/dist/bridge/sprites.d.ts.map +1 -0
- package/dist/bridge/sprites.js +138 -0
- package/dist/bridge/sprites.js.map +1 -0
- package/dist/bridge/types.d.ts +97 -0
- package/dist/bridge/types.d.ts.map +1 -0
- package/dist/bridge/types.js +2 -0
- package/dist/bridge/types.js.map +1 -0
- package/dist/client/assets/OpenSauceOne-Bold-BeiFYFR5.woff2 +0 -0
- package/dist/client/assets/OpenSauceOne-ExtraBold-DO6BqiNe.woff2 +0 -0
- package/dist/client/assets/OpenSauceOne-Light-NEdTeQp-.woff2 +0 -0
- package/dist/client/assets/OpenSauceOne-Medium-Cu5cjAHY.woff2 +0 -0
- package/dist/client/assets/OpenSauceOne-Regular-BivIUdzJ.woff2 +0 -0
- package/dist/client/assets/SourceCodePro-Regular-CoIbWt_c.woff2 +0 -0
- package/dist/client/assets/index-CK__1-6e.css +1 -0
- package/dist/client/assets/index-DKL-jl7t.js +241 -0
- package/dist/client/favicon.ico +0 -0
- package/dist/client/img/brand/favicon.png +0 -0
- package/dist/client/img/brand/favicon.svg +4 -0
- package/dist/client/img/brand/icon.svg +4 -0
- package/dist/client/img/brand/logo.inverse.svg +13 -0
- package/dist/client/img/brand/logo.svg +13 -0
- package/dist/client/index.html +16 -0
- package/dist/electric-api.d.ts +14 -0
- package/dist/electric-api.d.ts.map +1 -0
- package/dist/electric-api.js +70 -0
- package/dist/electric-api.js.map +1 -0
- package/dist/gate.d.ts +28 -0
- package/dist/gate.d.ts.map +1 -0
- package/dist/gate.js +72 -0
- package/dist/gate.js.map +1 -0
- package/dist/git.d.ts +30 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +115 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/project-utils.d.ts +9 -0
- package/dist/project-utils.d.ts.map +1 -0
- package/dist/project-utils.js +17 -0
- package/dist/project-utils.js.map +1 -0
- package/dist/sandbox/daytona-push.d.ts +3 -0
- package/dist/sandbox/daytona-push.d.ts.map +1 -0
- package/dist/sandbox/daytona-push.js +56 -0
- package/dist/sandbox/daytona-push.js.map +1 -0
- package/dist/sandbox/daytona-registry.d.ts +41 -0
- package/dist/sandbox/daytona-registry.d.ts.map +1 -0
- package/dist/sandbox/daytona-registry.js +127 -0
- package/dist/sandbox/daytona-registry.js.map +1 -0
- package/dist/sandbox/daytona.d.ts +41 -0
- package/dist/sandbox/daytona.d.ts.map +1 -0
- package/dist/sandbox/daytona.js +282 -0
- package/dist/sandbox/daytona.js.map +1 -0
- package/dist/sandbox/docker.d.ts +29 -0
- package/dist/sandbox/docker.d.ts.map +1 -0
- package/dist/sandbox/docker.js +465 -0
- package/dist/sandbox/docker.js.map +1 -0
- package/dist/sandbox/index.d.ts +5 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +4 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/sprites-bootstrap.d.ts +26 -0
- package/dist/sandbox/sprites-bootstrap.d.ts.map +1 -0
- package/dist/sandbox/sprites-bootstrap.js +127 -0
- package/dist/sandbox/sprites-bootstrap.js.map +1 -0
- package/dist/sandbox/sprites.d.ts +55 -0
- package/dist/sandbox/sprites.d.ts.map +1 -0
- package/dist/sandbox/sprites.js +323 -0
- package/dist/sandbox/sprites.js.map +1 -0
- package/dist/sandbox/types.d.ts +73 -0
- package/dist/sandbox/types.d.ts.map +1 -0
- package/dist/sandbox/types.js +5 -0
- package/dist/sandbox/types.js.map +1 -0
- package/dist/server.d.ts +26 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +1266 -0
- package/dist/server.js.map +1 -0
- package/dist/sessions.d.ts +46 -0
- package/dist/sessions.d.ts.map +1 -0
- package/dist/sessions.js +66 -0
- package/dist/sessions.js.map +1 -0
- package/dist/streams.d.ts +34 -0
- package/dist/streams.d.ts.map +1 -0
- package/dist/streams.js +42 -0
- package/dist/streams.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { Configuration, DockerRegistryApi } from "@daytonaio/api-client";
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Daytona Transient Registry — push local images + create snapshots
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
const SANDBOX_IMAGE = process.env.SANDBOX_IMAGE || "electric-agent-sandbox";
|
|
10
|
+
function getPackageVersion() {
|
|
11
|
+
try {
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = dirname(__filename);
|
|
14
|
+
const pkgPath = resolve(__dirname, "../../../package.json");
|
|
15
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
16
|
+
return pkg.version || "0.1.0";
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return "0.1.0";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Push a local Docker image to Daytona's transient registry.
|
|
24
|
+
*
|
|
25
|
+
* 1. Gets temporary push credentials via `DockerRegistryApi.getTransientPushAccess()`
|
|
26
|
+
* 2. Tags the local image with the remote registry path
|
|
27
|
+
* 3. Logs in, pushes, and logs out
|
|
28
|
+
*/
|
|
29
|
+
export async function pushImageToDaytona(opts) {
|
|
30
|
+
const localImage = opts.localImage ?? SANDBOX_IMAGE;
|
|
31
|
+
const apiUrl = opts.apiUrl ?? "https://app.daytona.io/api";
|
|
32
|
+
const version = getPackageVersion();
|
|
33
|
+
// Get transient push access credentials
|
|
34
|
+
// DockerRegistryApi uses Bearer auth (accessToken), not apiKey header
|
|
35
|
+
const config = new Configuration({
|
|
36
|
+
accessToken: opts.apiKey,
|
|
37
|
+
basePath: apiUrl,
|
|
38
|
+
});
|
|
39
|
+
const registryApi = new DockerRegistryApi(config);
|
|
40
|
+
const response = await registryApi.getTransientPushAccess();
|
|
41
|
+
const access = response.data;
|
|
42
|
+
const remoteImage = `${access.registryUrl}/${access.project}/${localImage}:${version}`;
|
|
43
|
+
console.log(`[daytona-registry] Pushing ${localImage} → ${remoteImage}`);
|
|
44
|
+
console.log(`[daytona-registry] Registry: ${access.registryUrl} (expires: ${access.expiresAt})`);
|
|
45
|
+
try {
|
|
46
|
+
// Tag the local image
|
|
47
|
+
execSync(`docker tag ${localImage} ${remoteImage}`, { stdio: "pipe" });
|
|
48
|
+
// Login to the transient registry
|
|
49
|
+
execSync(`docker login ${access.registryUrl} -u ${access.username} --password-stdin`, {
|
|
50
|
+
input: access.secret,
|
|
51
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
52
|
+
});
|
|
53
|
+
// Push the image
|
|
54
|
+
console.log("[daytona-registry] Pushing image (this may take a while)...");
|
|
55
|
+
execSync(`docker push ${remoteImage}`, { stdio: "inherit", timeout: 600_000 });
|
|
56
|
+
console.log("[daytona-registry] Push complete");
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
try {
|
|
60
|
+
execSync(`docker logout ${access.registryUrl}`, { stdio: "pipe" });
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Ignore logout errors
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
remoteImage,
|
|
68
|
+
registryUrl: access.registryUrl,
|
|
69
|
+
project: access.project,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Ensure a Daytona snapshot exists for the sandbox image.
|
|
74
|
+
*
|
|
75
|
+
* - If a snapshot with the expected name already exists and is active, returns its name.
|
|
76
|
+
* - Otherwise, pushes the local image to the transient registry and creates a snapshot.
|
|
77
|
+
*/
|
|
78
|
+
export async function ensureSnapshot(daytona, opts) {
|
|
79
|
+
const localImage = opts.localImage ?? SANDBOX_IMAGE;
|
|
80
|
+
const snapshotName = localImage;
|
|
81
|
+
// Check if snapshot already exists
|
|
82
|
+
try {
|
|
83
|
+
const existing = await daytona.snapshot.get(snapshotName);
|
|
84
|
+
if (existing.state === "active") {
|
|
85
|
+
console.log(`[daytona-registry] Snapshot "${snapshotName}" already exists and is active`);
|
|
86
|
+
return snapshotName;
|
|
87
|
+
}
|
|
88
|
+
console.log(`[daytona-registry] Snapshot "${snapshotName}" exists but state=${existing.state}, deleting before recreate...`);
|
|
89
|
+
await daytona.snapshot.delete(existing);
|
|
90
|
+
console.log(`[daytona-registry] Old snapshot deleted`);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
console.log(`[daytona-registry] Snapshot "${snapshotName}" not found, creating...`);
|
|
94
|
+
}
|
|
95
|
+
// Push the local image to Daytona's transient registry
|
|
96
|
+
const { remoteImage } = await pushImageToDaytona({
|
|
97
|
+
apiKey: opts.apiKey,
|
|
98
|
+
apiUrl: opts.apiUrl,
|
|
99
|
+
localImage,
|
|
100
|
+
});
|
|
101
|
+
// Create the snapshot from the pushed image
|
|
102
|
+
console.log(`[daytona-registry] Creating snapshot "${snapshotName}" from ${remoteImage}...`);
|
|
103
|
+
await daytona.snapshot.create({
|
|
104
|
+
name: snapshotName,
|
|
105
|
+
image: remoteImage,
|
|
106
|
+
entrypoint: ["/bin/sh", "-c", "sleep infinity"],
|
|
107
|
+
}, {
|
|
108
|
+
onLogs: opts.onLogs ?? ((chunk) => process.stdout.write(chunk)),
|
|
109
|
+
timeout: 600,
|
|
110
|
+
});
|
|
111
|
+
console.log(`[daytona-registry] Snapshot "${snapshotName}" created successfully`);
|
|
112
|
+
return snapshotName;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Check if a snapshot exists and is active (non-throwing).
|
|
116
|
+
*/
|
|
117
|
+
export async function getSnapshotStatus(daytona, snapshotName) {
|
|
118
|
+
const name = snapshotName ?? SANDBOX_IMAGE;
|
|
119
|
+
try {
|
|
120
|
+
const snapshot = await daytona.snapshot.get(name);
|
|
121
|
+
return { exists: true, state: snapshot.state };
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return { exists: false };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=daytona-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daytona-registry.js","sourceRoot":"","sources":["../../src/sandbox/daytona-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAGxE,8EAA8E;AAC9E,oEAAoE;AACpE,8EAA8E;AAE9E,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,wBAAwB,CAAA;AAE3E,SAAS,iBAAiB;IACzB,IAAI,CAAC;QACJ,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACjD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;QACrC,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,uBAAuB,CAAC,CAAA;QAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAA;QACtD,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,OAAO,CAAA;IACf,CAAC;AACF,CAAC;AAcD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAmB;IAC3D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,aAAa,CAAA;IACnD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,4BAA4B,CAAA;IAC1D,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAA;IAEnC,wCAAwC;IACxC,sEAAsE;IACtE,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC;QAChC,WAAW,EAAE,IAAI,CAAC,MAAM;QACxB,QAAQ,EAAE,MAAM;KAChB,CAAC,CAAA;IACF,MAAM,WAAW,GAAG,IAAI,iBAAiB,CAAC,MAAM,CAAC,CAAA;IACjD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,sBAAsB,EAAE,CAAA;IAC3D,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAA;IAE5B,MAAM,WAAW,GAAG,GAAG,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,OAAO,IAAI,UAAU,IAAI,OAAO,EAAE,CAAA;IAEtF,OAAO,CAAC,GAAG,CAAC,8BAA8B,UAAU,MAAM,WAAW,EAAE,CAAC,CAAA;IACxE,OAAO,CAAC,GAAG,CAAC,gCAAgC,MAAM,CAAC,WAAW,cAAc,MAAM,CAAC,SAAS,GAAG,CAAC,CAAA;IAEhG,IAAI,CAAC;QACJ,sBAAsB;QACtB,QAAQ,CAAC,cAAc,UAAU,IAAI,WAAW,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QAEtE,kCAAkC;QAClC,QAAQ,CAAC,gBAAgB,MAAM,CAAC,WAAW,OAAO,MAAM,CAAC,QAAQ,mBAAmB,EAAE;YACrF,KAAK,EAAE,MAAM,CAAC,MAAM;YACpB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAC/B,CAAC,CAAA;QAEF,iBAAiB;QACjB,OAAO,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAA;QAC1E,QAAQ,CAAC,eAAe,WAAW,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;QAE9E,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAA;IAChD,CAAC;YAAS,CAAC;QACV,IAAI,CAAC;YACJ,QAAQ,CAAC,iBAAiB,MAAM,CAAC,WAAW,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QACnE,CAAC;QAAC,MAAM,CAAC;YACR,uBAAuB;QACxB,CAAC;IACF,CAAC;IAED,OAAO;QACN,WAAW;QACX,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,OAAO,EAAE,MAAM,CAAC,OAAO;KACvB,CAAA;AACF,CAAC;AAUD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAgB,EAAE,IAAwB;IAC9E,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,aAAa,CAAA;IACnD,MAAM,YAAY,GAAG,UAAU,CAAA;IAE/B,mCAAmC;IACnC,IAAI,CAAC;QACJ,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QACzD,IAAI,QAAQ,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,gCAAgC,YAAY,gCAAgC,CAAC,CAAA;YACzF,OAAO,YAAY,CAAA;QACpB,CAAC;QACD,OAAO,CAAC,GAAG,CACV,gCAAgC,YAAY,sBAAsB,QAAQ,CAAC,KAAK,+BAA+B,CAC/G,CAAA;QACD,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACvC,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAA;IACvD,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,CAAC,GAAG,CAAC,gCAAgC,YAAY,0BAA0B,CAAC,CAAA;IACpF,CAAC;IAED,uDAAuD;IACvD,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,kBAAkB,CAAC;QAChD,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,UAAU;KACV,CAAC,CAAA;IAEF,4CAA4C;IAC5C,OAAO,CAAC,GAAG,CAAC,yCAAyC,YAAY,UAAU,WAAW,KAAK,CAAC,CAAA;IAC5F,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAC5B;QACC,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,WAAW;QAClB,UAAU,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,gBAAgB,CAAC;KAC/C,EACD;QACC,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,KAAa,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO,EAAE,GAAG;KACZ,CACD,CAAA;IAED,OAAO,CAAC,GAAG,CAAC,gCAAgC,YAAY,wBAAwB,CAAC,CAAA;IACjF,OAAO,YAAY,CAAA;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACtC,OAAgB,EAChB,YAAqB;IAErB,MAAM,IAAI,GAAG,YAAY,IAAI,aAAa,CAAA;IAC1C,IAAI,CAAC;QACJ,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACjD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAA;IAC/C,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAA;IACzB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type Sandbox } from "@daytonaio/sdk";
|
|
2
|
+
import type { CreateSandboxOpts, GitStatus, SandboxHandle, SandboxProvider } from "./types.js";
|
|
3
|
+
export declare class DaytonaSandboxProvider implements SandboxProvider {
|
|
4
|
+
readonly runtime: "daytona";
|
|
5
|
+
private client;
|
|
6
|
+
private handles;
|
|
7
|
+
private sandboxes;
|
|
8
|
+
private apiKey;
|
|
9
|
+
private apiUrl?;
|
|
10
|
+
private cachedSnapshot;
|
|
11
|
+
constructor(opts?: {
|
|
12
|
+
apiKey?: string;
|
|
13
|
+
apiUrl?: string;
|
|
14
|
+
target?: string;
|
|
15
|
+
});
|
|
16
|
+
private getSandbox;
|
|
17
|
+
private resolveSnapshot;
|
|
18
|
+
create(sessionId: string, opts?: CreateSandboxOpts): Promise<SandboxHandle>;
|
|
19
|
+
destroy(handle: SandboxHandle): Promise<void>;
|
|
20
|
+
restartAgent(handle: SandboxHandle): Promise<SandboxHandle>;
|
|
21
|
+
/** Get the underlying Daytona SDK Sandbox object for bridge communication */
|
|
22
|
+
getSandboxObject(sessionId: string): Sandbox | undefined;
|
|
23
|
+
get(sessionId: string): SandboxHandle | undefined;
|
|
24
|
+
list(): SandboxHandle[];
|
|
25
|
+
isAlive(handle: SandboxHandle): boolean;
|
|
26
|
+
exec(handle: SandboxHandle, command: string): Promise<string>;
|
|
27
|
+
listFiles(handle: SandboxHandle, dir: string): Promise<string[]>;
|
|
28
|
+
readFile(handle: SandboxHandle, filePath: string): Promise<string | null>;
|
|
29
|
+
startApp(handle: SandboxHandle): Promise<boolean>;
|
|
30
|
+
stopApp(handle: SandboxHandle): Promise<boolean>;
|
|
31
|
+
isAppRunning(handle: SandboxHandle): Promise<boolean>;
|
|
32
|
+
gitStatus(handle: SandboxHandle, projectDir: string): Promise<GitStatus>;
|
|
33
|
+
getPreviewUrl(handle: SandboxHandle, port: number): Promise<string | null>;
|
|
34
|
+
createFromRepo(sessionId: string, repoUrl: string, opts?: {
|
|
35
|
+
branch?: string;
|
|
36
|
+
apiKey?: string;
|
|
37
|
+
oauthToken?: string;
|
|
38
|
+
ghToken?: string;
|
|
39
|
+
}): Promise<SandboxHandle>;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=daytona.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daytona.d.ts","sourceRoot":"","sources":["../../src/sandbox/daytona.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAEtD,OAAO,KAAK,EACX,iBAAiB,EACjB,SAAS,EAET,aAAa,EACb,eAAe,EACf,MAAM,YAAY,CAAA;AAQnB,qBAAa,sBAAuB,YAAW,eAAe;IAC7D,QAAQ,CAAC,OAAO,EAAG,SAAS,CAAS;IAErC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,MAAM,CAAC,CAAQ;IACvB,OAAO,CAAC,cAAc,CAAsB;gBAEhC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAUxE,OAAO,CAAC,UAAU;YAMJ,eAAe;IAavB,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC;IA2E3E,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAc7C,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAejE,6EAA6E;IAC7E,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAIxD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIjD,IAAI,IAAI,aAAa,EAAE;IAIvB,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO;IAMjC,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAM7D,SAAS,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAoBhE,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAYzE,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBjD,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBhD,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBrD,SAAS,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAiExE,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAY1E,cAAc,CACnB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAChF,OAAO,CAAC,aAAa,CAAC;CA8BzB"}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { Daytona } from "@daytonaio/sdk";
|
|
2
|
+
import { ensureSnapshot } from "./daytona-registry.js";
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// DaytonaSandboxProvider — cloud sandboxes via Daytona
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
const SANDBOX_IMAGE = process.env.SANDBOX_IMAGE || "electric-agent-sandbox";
|
|
7
|
+
export class DaytonaSandboxProvider {
|
|
8
|
+
runtime = "daytona";
|
|
9
|
+
client;
|
|
10
|
+
handles = new Map();
|
|
11
|
+
sandboxes = new Map();
|
|
12
|
+
apiKey;
|
|
13
|
+
apiUrl;
|
|
14
|
+
cachedSnapshot = null;
|
|
15
|
+
constructor(opts) {
|
|
16
|
+
this.apiKey = opts?.apiKey ?? process.env.DAYTONA_API_KEY ?? "";
|
|
17
|
+
this.apiUrl = opts?.apiUrl ?? process.env.DAYTONA_API_URL;
|
|
18
|
+
this.client = new Daytona({
|
|
19
|
+
apiKey: this.apiKey,
|
|
20
|
+
apiUrl: this.apiUrl,
|
|
21
|
+
target: opts?.target ?? process.env.DAYTONA_TARGET ?? "eu",
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
getSandbox(handle) {
|
|
25
|
+
const sb = this.sandboxes.get(handle.sessionId);
|
|
26
|
+
if (!sb)
|
|
27
|
+
throw new Error(`No Daytona sandbox for session ${handle.sessionId}`);
|
|
28
|
+
return sb;
|
|
29
|
+
}
|
|
30
|
+
async resolveSnapshot() {
|
|
31
|
+
if (this.cachedSnapshot)
|
|
32
|
+
return this.cachedSnapshot;
|
|
33
|
+
const snapshotName = await ensureSnapshot(this.client, {
|
|
34
|
+
apiKey: this.apiKey,
|
|
35
|
+
apiUrl: this.apiUrl,
|
|
36
|
+
localImage: SANDBOX_IMAGE,
|
|
37
|
+
});
|
|
38
|
+
this.cachedSnapshot = snapshotName;
|
|
39
|
+
return snapshotName;
|
|
40
|
+
}
|
|
41
|
+
async create(sessionId, opts) {
|
|
42
|
+
const infra = opts?.infra ?? { mode: "local" };
|
|
43
|
+
const isCloud = infra.mode === "cloud";
|
|
44
|
+
const projectName = opts?.projectName || sessionId.slice(0, 8);
|
|
45
|
+
console.log(`[daytona] Creating sandbox: session=${sessionId} project=${projectName} image=${SANDBOX_IMAGE} infra=${infra.mode}`);
|
|
46
|
+
const envVars = {
|
|
47
|
+
SANDBOX_MODE: "1",
|
|
48
|
+
VITE_PORT: "5173",
|
|
49
|
+
};
|
|
50
|
+
if (isCloud) {
|
|
51
|
+
envVars.DATABASE_URL = infra.databaseUrl;
|
|
52
|
+
envVars.ELECTRIC_URL = infra.electricUrl;
|
|
53
|
+
envVars.ELECTRIC_SOURCE_ID = infra.sourceId;
|
|
54
|
+
envVars.ELECTRIC_SECRET = infra.secret;
|
|
55
|
+
}
|
|
56
|
+
if (opts?.apiKey) {
|
|
57
|
+
envVars.ANTHROPIC_API_KEY = opts.apiKey;
|
|
58
|
+
}
|
|
59
|
+
else if (opts?.oauthToken) {
|
|
60
|
+
envVars.CLAUDE_CODE_OAUTH_TOKEN = opts.oauthToken;
|
|
61
|
+
}
|
|
62
|
+
if (opts?.ghToken) {
|
|
63
|
+
envVars.GH_TOKEN = opts.ghToken;
|
|
64
|
+
}
|
|
65
|
+
// Note: stream env vars are NOT passed to Daytona sandboxes.
|
|
66
|
+
// The DaytonaSessionBridge communicates via the session API (stdin/stdout),
|
|
67
|
+
// so the agent doesn't need direct access to Durable Streams.
|
|
68
|
+
// Ensure a Daytona snapshot exists (push image + create snapshot if needed)
|
|
69
|
+
const snapshotName = await this.resolveSnapshot();
|
|
70
|
+
console.log(`[daytona] Creating sandbox from snapshot "${snapshotName}" with ${Object.keys(envVars).length} env vars...`);
|
|
71
|
+
console.log("[daytona] Waiting for sandbox to be ready (this may take up to 2 minutes)...");
|
|
72
|
+
const sandbox = await this.client.create({
|
|
73
|
+
snapshot: snapshotName,
|
|
74
|
+
envVars,
|
|
75
|
+
labels: { sessionId, projectName },
|
|
76
|
+
}, { timeout: 120 });
|
|
77
|
+
console.log(`[daytona] Sandbox created, getting preview link...`);
|
|
78
|
+
const previewLink = await sandbox.getPreviewLink(5173);
|
|
79
|
+
const projectDir = `/home/agent/workspace/${projectName}`;
|
|
80
|
+
console.log(`[daytona] Preview URL: ${previewLink.url}`);
|
|
81
|
+
const handle = {
|
|
82
|
+
sessionId,
|
|
83
|
+
runtime: "daytona",
|
|
84
|
+
port: 5173,
|
|
85
|
+
projectDir,
|
|
86
|
+
previewUrl: previewLink.url,
|
|
87
|
+
};
|
|
88
|
+
this.handles.set(sessionId, handle);
|
|
89
|
+
this.sandboxes.set(sessionId, sandbox);
|
|
90
|
+
// Agent is NOT started here — the DaytonaSessionBridge starts it
|
|
91
|
+
// via the session API (createSession + executeSessionCommand)
|
|
92
|
+
console.log("[daytona] Sandbox ready (agent will be started by bridge)");
|
|
93
|
+
return handle;
|
|
94
|
+
}
|
|
95
|
+
async destroy(handle) {
|
|
96
|
+
const sandbox = this.sandboxes.get(handle.sessionId);
|
|
97
|
+
this.handles.delete(handle.sessionId);
|
|
98
|
+
this.sandboxes.delete(handle.sessionId);
|
|
99
|
+
if (sandbox) {
|
|
100
|
+
try {
|
|
101
|
+
await sandbox.delete(30);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Sandbox may already be deleted
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async restartAgent(handle) {
|
|
109
|
+
const sandbox = this.getSandbox(handle);
|
|
110
|
+
// Kill any running agent process — the bridge will restart it
|
|
111
|
+
try {
|
|
112
|
+
await sandbox.process.executeCommand("pkill -f 'electric-agent headless' || true");
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// Process may not be running
|
|
116
|
+
}
|
|
117
|
+
const newHandle = { ...handle };
|
|
118
|
+
this.handles.set(handle.sessionId, newHandle);
|
|
119
|
+
return newHandle;
|
|
120
|
+
}
|
|
121
|
+
/** Get the underlying Daytona SDK Sandbox object for bridge communication */
|
|
122
|
+
getSandboxObject(sessionId) {
|
|
123
|
+
return this.sandboxes.get(sessionId);
|
|
124
|
+
}
|
|
125
|
+
get(sessionId) {
|
|
126
|
+
return this.handles.get(sessionId);
|
|
127
|
+
}
|
|
128
|
+
list() {
|
|
129
|
+
return [...this.handles.values()];
|
|
130
|
+
}
|
|
131
|
+
isAlive(handle) {
|
|
132
|
+
const sandbox = this.sandboxes.get(handle.sessionId);
|
|
133
|
+
if (!sandbox)
|
|
134
|
+
return false;
|
|
135
|
+
return sandbox.state === "started";
|
|
136
|
+
}
|
|
137
|
+
async exec(handle, command) {
|
|
138
|
+
const sandbox = this.getSandbox(handle);
|
|
139
|
+
const result = await sandbox.process.executeCommand(command, undefined, undefined, 30);
|
|
140
|
+
return result.result?.trim() ?? "";
|
|
141
|
+
}
|
|
142
|
+
async listFiles(handle, dir) {
|
|
143
|
+
const sandbox = this.sandboxes.get(handle.sessionId);
|
|
144
|
+
if (!sandbox)
|
|
145
|
+
return [];
|
|
146
|
+
try {
|
|
147
|
+
const result = await sandbox.process.executeCommand(`find ${dir} -type f -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/dist/*' -not -path '*/.next/*' -not -path '*/.cache/*' -not -path '*/.electric/*' -not -name 'pnpm-lock.yaml' -not -name 'package-lock.json'`, undefined, undefined, 10);
|
|
148
|
+
return (result.result ?? "")
|
|
149
|
+
.split("\n")
|
|
150
|
+
.map((l) => l.trim())
|
|
151
|
+
.filter(Boolean);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async readFile(handle, filePath) {
|
|
158
|
+
const sandbox = this.sandboxes.get(handle.sessionId);
|
|
159
|
+
if (!sandbox)
|
|
160
|
+
return null;
|
|
161
|
+
try {
|
|
162
|
+
const buffer = await sandbox.fs.downloadFile(filePath, 5);
|
|
163
|
+
return buffer.toString("utf-8");
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async startApp(handle) {
|
|
170
|
+
const sandbox = this.sandboxes.get(handle.sessionId);
|
|
171
|
+
if (!sandbox)
|
|
172
|
+
return false;
|
|
173
|
+
try {
|
|
174
|
+
await sandbox.process.executeCommand("cd /home/agent/workspace/*/ && pnpm dev:start", undefined, undefined, 10);
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
async stopApp(handle) {
|
|
182
|
+
const sandbox = this.sandboxes.get(handle.sessionId);
|
|
183
|
+
if (!sandbox)
|
|
184
|
+
return false;
|
|
185
|
+
try {
|
|
186
|
+
await sandbox.process.executeCommand("cd /home/agent/workspace/*/ && pnpm dev:stop", undefined, undefined, 5);
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async isAppRunning(handle) {
|
|
194
|
+
const sandbox = this.sandboxes.get(handle.sessionId);
|
|
195
|
+
if (!sandbox)
|
|
196
|
+
return false;
|
|
197
|
+
try {
|
|
198
|
+
const result = await sandbox.process.executeCommand("kill -0 $(cat /tmp/dev-server.pid 2>/dev/null) 2>/dev/null && echo RUNNING || echo STOPPED", undefined, undefined, 5);
|
|
199
|
+
return (result.result ?? "").includes("RUNNING");
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
async gitStatus(handle, projectDir) {
|
|
206
|
+
const sandbox = this.sandboxes.get(handle.sessionId);
|
|
207
|
+
if (!sandbox) {
|
|
208
|
+
return {
|
|
209
|
+
initialized: false,
|
|
210
|
+
branch: null,
|
|
211
|
+
hasUncommitted: false,
|
|
212
|
+
lastCommitHash: null,
|
|
213
|
+
lastCommitMessage: null,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
try {
|
|
217
|
+
const initCheck = await sandbox.process.executeCommand(`cd ${projectDir} && test -d .git && echo "GIT_INIT=yes" || echo "GIT_INIT=no"`);
|
|
218
|
+
if (!(initCheck.result ?? "").includes("GIT_INIT=yes")) {
|
|
219
|
+
return {
|
|
220
|
+
initialized: false,
|
|
221
|
+
branch: null,
|
|
222
|
+
hasUncommitted: false,
|
|
223
|
+
lastCommitHash: null,
|
|
224
|
+
lastCommitMessage: null,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
const branch = (await sandbox.process.executeCommand(`cd ${projectDir} && git rev-parse --abbrev-ref HEAD 2>/dev/null || echo ""`)).result?.trim();
|
|
228
|
+
const hash = (await sandbox.process.executeCommand(`cd ${projectDir} && git rev-parse HEAD 2>/dev/null || echo ""`)).result?.trim();
|
|
229
|
+
const message = (await sandbox.process.executeCommand(`cd ${projectDir} && git log -1 --format=%s 2>/dev/null || echo ""`)).result?.trim();
|
|
230
|
+
const statusOutput = (await sandbox.process.executeCommand(`cd ${projectDir} && git status --porcelain 2>/dev/null || echo ""`)).result?.trim();
|
|
231
|
+
return {
|
|
232
|
+
initialized: true,
|
|
233
|
+
branch: branch || null,
|
|
234
|
+
hasUncommitted: (statusOutput ?? "").length > 0,
|
|
235
|
+
lastCommitHash: hash || null,
|
|
236
|
+
lastCommitMessage: message || null,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
return {
|
|
241
|
+
initialized: false,
|
|
242
|
+
branch: null,
|
|
243
|
+
hasUncommitted: false,
|
|
244
|
+
lastCommitHash: null,
|
|
245
|
+
lastCommitMessage: null,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
async getPreviewUrl(handle, port) {
|
|
250
|
+
const sandbox = this.sandboxes.get(handle.sessionId);
|
|
251
|
+
if (!sandbox)
|
|
252
|
+
return null;
|
|
253
|
+
try {
|
|
254
|
+
const preview = await sandbox.getPreviewLink(port);
|
|
255
|
+
return preview.url;
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async createFromRepo(sessionId, repoUrl, opts) {
|
|
262
|
+
const repoName = repoUrl
|
|
263
|
+
.split("/")
|
|
264
|
+
.pop()
|
|
265
|
+
?.replace(/\.git$/, "") || "resumed-project";
|
|
266
|
+
const handle = await this.create(sessionId, {
|
|
267
|
+
apiKey: opts?.apiKey,
|
|
268
|
+
oauthToken: opts?.oauthToken,
|
|
269
|
+
ghToken: opts?.ghToken,
|
|
270
|
+
projectName: repoName,
|
|
271
|
+
});
|
|
272
|
+
const sandbox = this.getSandbox(handle);
|
|
273
|
+
const targetDir = `/home/agent/workspace/${repoName}`;
|
|
274
|
+
await sandbox.process.executeCommand(`gh repo clone "${repoUrl}" "${targetDir}" 2>/dev/null || git clone "${repoUrl}" "${targetDir}"`, undefined, undefined, 60);
|
|
275
|
+
if (opts?.branch) {
|
|
276
|
+
await sandbox.process.executeCommand(`cd ${targetDir} && git checkout ${opts.branch}`);
|
|
277
|
+
}
|
|
278
|
+
handle.projectDir = targetDir;
|
|
279
|
+
return handle;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=daytona.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daytona.js","sourceRoot":"","sources":["../../src/sandbox/daytona.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAgB,MAAM,gBAAgB,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAStD,8EAA8E;AAC9E,uDAAuD;AACvD,8EAA8E;AAE9E,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,wBAAwB,CAAA;AAE3E,MAAM,OAAO,sBAAsB;IACzB,OAAO,GAAG,SAAkB,CAAA;IAE7B,MAAM,CAAS;IACf,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAA;IAC1C,SAAS,GAAG,IAAI,GAAG,EAAmB,CAAA;IACtC,MAAM,CAAQ;IACd,MAAM,CAAS;IACf,cAAc,GAAkB,IAAI,CAAA;IAE5C,YAAY,IAA4D;QACvE,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAA;QAC/D,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAA;QACzD,IAAI,CAAC,MAAM,GAAG,IAAI,OAAO,CAAC;YACzB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,IAAI,EAAE,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI;SAC1D,CAAC,CAAA;IACH,CAAC;IAEO,UAAU,CAAC,MAAqB;QACvC,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QAC/C,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAA;QAC9E,OAAO,EAAE,CAAA;IACV,CAAC;IAEO,KAAK,CAAC,eAAe;QAC5B,IAAI,IAAI,CAAC,cAAc;YAAE,OAAO,IAAI,CAAC,cAAc,CAAA;QAEnD,MAAM,YAAY,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE;YACtD,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,UAAU,EAAE,aAAa;SACzB,CAAC,CAAA;QAEF,IAAI,CAAC,cAAc,GAAG,YAAY,CAAA;QAClC,OAAO,YAAY,CAAA;IACpB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB,EAAE,IAAwB;QACvD,MAAM,KAAK,GAAgB,IAAI,EAAE,KAAK,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;QAC3D,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,KAAK,OAAO,CAAA;QACtC,MAAM,WAAW,GAAG,IAAI,EAAE,WAAW,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAE9D,OAAO,CAAC,GAAG,CACV,uCAAuC,SAAS,YAAY,WAAW,UAAU,aAAa,UAAU,KAAK,CAAC,IAAI,EAAE,CACpH,CAAA;QAED,MAAM,OAAO,GAA2B;YACvC,YAAY,EAAE,GAAG;YACjB,SAAS,EAAE,MAAM;SACjB,CAAA;QAED,IAAI,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,YAAY,GAAG,KAAK,CAAC,WAAW,CAAA;YACxC,OAAO,CAAC,YAAY,GAAG,KAAK,CAAC,WAAW,CAAA;YACxC,OAAO,CAAC,kBAAkB,GAAG,KAAK,CAAC,QAAQ,CAAA;YAC3C,OAAO,CAAC,eAAe,GAAG,KAAK,CAAC,MAAM,CAAA;QACvC,CAAC;QAED,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC;YAClB,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,MAAM,CAAA;QACxC,CAAC;aAAM,IAAI,IAAI,EAAE,UAAU,EAAE,CAAC;YAC7B,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,UAAU,CAAA;QAClD,CAAC;QAED,IAAI,IAAI,EAAE,OAAO,EAAE,CAAC;YACnB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAA;QAChC,CAAC;QAED,6DAA6D;QAC7D,4EAA4E;QAC5E,8DAA8D;QAE9D,4EAA4E;QAC5E,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,eAAe,EAAE,CAAA;QAEjD,OAAO,CAAC,GAAG,CACV,6CAA6C,YAAY,UAAU,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,cAAc,CAC5G,CAAA;QACD,OAAO,CAAC,GAAG,CAAC,8EAA8E,CAAC,CAAA;QAC3F,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CACvC;YACC,QAAQ,EAAE,YAAY;YACtB,OAAO;YACP,MAAM,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;SAClC,EACD,EAAE,OAAO,EAAE,GAAG,EAAE,CAChB,CAAA;QACD,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAA;QAEjE,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA;QACtD,MAAM,UAAU,GAAG,yBAAyB,WAAW,EAAE,CAAA;QAEzD,OAAO,CAAC,GAAG,CAAC,0BAA0B,WAAW,CAAC,GAAG,EAAE,CAAC,CAAA;QAExD,MAAM,MAAM,GAAkB;YAC7B,SAAS;YACT,OAAO,EAAE,SAAS;YAClB,IAAI,EAAE,IAAI;YACV,UAAU;YACV,UAAU,EAAE,WAAW,CAAC,GAAG;SAC3B,CAAA;QAED,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;QACnC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;QAEtC,iEAAiE;QACjE,8DAA8D;QAC9D,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAA;QAExE,OAAO,MAAM,CAAA;IACd,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAqB;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QACpD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QACrC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QAEvC,IAAI,OAAO,EAAE,CAAC;YACb,IAAI,CAAC;gBACJ,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YACzB,CAAC;YAAC,MAAM,CAAC;gBACR,iCAAiC;YAClC,CAAC;QACF,CAAC;IACF,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,MAAqB;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;QAEvC,8DAA8D;QAC9D,IAAI,CAAC;YACJ,MAAM,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,4CAA4C,CAAC,CAAA;QACnF,CAAC;QAAC,MAAM,CAAC;YACR,6BAA6B;QAC9B,CAAC;QAED,MAAM,SAAS,GAAkB,EAAE,GAAG,MAAM,EAAE,CAAA;QAC9C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;QAC7C,OAAO,SAAS,CAAA;IACjB,CAAC;IAED,6EAA6E;IAC7E,gBAAgB,CAAC,SAAiB;QACjC,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACrC,CAAC;IAED,GAAG,CAAC,SAAiB;QACpB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACnC,CAAC;IAED,IAAI;QACH,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAClC,CAAC;IAED,OAAO,CAAC,MAAqB;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QACpD,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAA;QAC1B,OAAO,OAAO,CAAC,KAAK,KAAK,SAAS,CAAA;IACnC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAqB,EAAE,OAAe;QAChD,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;QACvC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,CAAC,CAAA;QACtF,OAAO,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;IACnC,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,MAAqB,EAAE,GAAW;QACjD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QACpD,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,CAAA;QAEvB,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,cAAc,CAClD,QAAQ,GAAG,yNAAyN,EACpO,SAAS,EACT,SAAS,EACT,EAAE,CACF,CAAA;YACD,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;iBAC1B,KAAK,CAAC,IAAI,CAAC;iBACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBACpB,MAAM,CAAC,OAAO,CAAC,CAAA;QAClB,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,EAAE,CAAA;QACV,CAAC;IACF,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,MAAqB,EAAE,QAAgB;QACrD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QACpD,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAA;QAEzB,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;YACzD,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;QAChC,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,IAAI,CAAA;QACZ,CAAC;IACF,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,MAAqB;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QACpD,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAA;QAE1B,IAAI,CAAC;YACJ,MAAM,OAAO,CAAC,OAAO,CAAC,cAAc,CACnC,+CAA+C,EAC/C,SAAS,EACT,SAAS,EACT,EAAE,CACF,CAAA;YACD,OAAO,IAAI,CAAA;QACZ,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,KAAK,CAAA;QACb,CAAC;IACF,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAqB;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QACpD,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAA;QAE1B,IAAI,CAAC;YACJ,MAAM,OAAO,CAAC,OAAO,CAAC,cAAc,CACnC,8CAA8C,EAC9C,SAAS,EACT,SAAS,EACT,CAAC,CACD,CAAA;YACD,OAAO,IAAI,CAAA;QACZ,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,KAAK,CAAA;QACb,CAAC;IACF,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,MAAqB;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QACpD,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAA;QAE1B,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,cAAc,CAClD,4FAA4F,EAC5F,SAAS,EACT,SAAS,EACT,CAAC,CACD,CAAA;YACD,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;QACjD,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,KAAK,CAAA;QACb,CAAC;IACF,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,MAAqB,EAAE,UAAkB;QACxD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QACpD,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,OAAO;gBACN,WAAW,EAAE,KAAK;gBAClB,MAAM,EAAE,IAAI;gBACZ,cAAc,EAAE,KAAK;gBACrB,cAAc,EAAE,IAAI;gBACpB,iBAAiB,EAAE,IAAI;aACvB,CAAA;QACF,CAAC;QAED,IAAI,CAAC;YACJ,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,cAAc,CACrD,MAAM,UAAU,+DAA+D,CAC/E,CAAA;YACD,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;gBACxD,OAAO;oBACN,WAAW,EAAE,KAAK;oBAClB,MAAM,EAAE,IAAI;oBACZ,cAAc,EAAE,KAAK;oBACrB,cAAc,EAAE,IAAI;oBACpB,iBAAiB,EAAE,IAAI;iBACvB,CAAA;YACF,CAAC;YAED,MAAM,MAAM,GAAG,CACd,MAAM,OAAO,CAAC,OAAO,CAAC,cAAc,CACnC,MAAM,UAAU,4DAA4D,CAC5E,CACD,CAAC,MAAM,EAAE,IAAI,EAAE,CAAA;YAChB,MAAM,IAAI,GAAG,CACZ,MAAM,OAAO,CAAC,OAAO,CAAC,cAAc,CACnC,MAAM,UAAU,+CAA+C,CAC/D,CACD,CAAC,MAAM,EAAE,IAAI,EAAE,CAAA;YAChB,MAAM,OAAO,GAAG,CACf,MAAM,OAAO,CAAC,OAAO,CAAC,cAAc,CACnC,MAAM,UAAU,mDAAmD,CACnE,CACD,CAAC,MAAM,EAAE,IAAI,EAAE,CAAA;YAChB,MAAM,YAAY,GAAG,CACpB,MAAM,OAAO,CAAC,OAAO,CAAC,cAAc,CACnC,MAAM,UAAU,mDAAmD,CACnE,CACD,CAAC,MAAM,EAAE,IAAI,EAAE,CAAA;YAEhB,OAAO;gBACN,WAAW,EAAE,IAAI;gBACjB,MAAM,EAAE,MAAM,IAAI,IAAI;gBACtB,cAAc,EAAE,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;gBAC/C,cAAc,EAAE,IAAI,IAAI,IAAI;gBAC5B,iBAAiB,EAAE,OAAO,IAAI,IAAI;aAClC,CAAA;QACF,CAAC;QAAC,MAAM,CAAC;YACR,OAAO;gBACN,WAAW,EAAE,KAAK;gBAClB,MAAM,EAAE,IAAI;gBACZ,cAAc,EAAE,KAAK;gBACrB,cAAc,EAAE,IAAI;gBACpB,iBAAiB,EAAE,IAAI;aACvB,CAAA;QACF,CAAC;IACF,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,MAAqB,EAAE,IAAY;QACtD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QACpD,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAA;QAEzB,IAAI,CAAC;YACJ,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA;YAClD,OAAO,OAAO,CAAC,GAAG,CAAA;QACnB,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,IAAI,CAAA;QACZ,CAAC;IACF,CAAC;IAED,KAAK,CAAC,cAAc,CACnB,SAAiB,EACjB,OAAe,EACf,IAAkF;QAElF,MAAM,QAAQ,GACb,OAAO;aACL,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,EAAE;YACN,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,iBAAiB,CAAA;QAE9C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;YAC3C,MAAM,EAAE,IAAI,EAAE,MAAM;YACpB,UAAU,EAAE,IAAI,EAAE,UAAU;YAC5B,OAAO,EAAE,IAAI,EAAE,OAAO;YACtB,WAAW,EAAE,QAAQ;SACrB,CAAC,CAAA;QACF,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;QAEvC,MAAM,SAAS,GAAG,yBAAyB,QAAQ,EAAE,CAAA;QACrD,MAAM,OAAO,CAAC,OAAO,CAAC,cAAc,CACnC,kBAAkB,OAAO,MAAM,SAAS,+BAA+B,OAAO,MAAM,SAAS,GAAG,EAChG,SAAS,EACT,SAAS,EACT,EAAE,CACF,CAAA;QAED,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC;YAClB,MAAM,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,SAAS,oBAAoB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;QACvF,CAAC;QAED,MAAM,CAAC,UAAU,GAAG,SAAS,CAAA;QAC7B,OAAO,MAAM,CAAA;IACd,CAAC;CACD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { CreateSandboxOpts, GitStatus, SandboxHandle, SandboxProvider } from "./types.js";
|
|
2
|
+
export declare class DockerSandboxProvider implements SandboxProvider {
|
|
3
|
+
readonly runtime: "docker";
|
|
4
|
+
private activeContainers;
|
|
5
|
+
private internalState;
|
|
6
|
+
private getState;
|
|
7
|
+
create(sessionId: string, opts?: CreateSandboxOpts): Promise<SandboxHandle>;
|
|
8
|
+
destroy(handle: SandboxHandle): Promise<void>;
|
|
9
|
+
restartAgent(handle: SandboxHandle): Promise<SandboxHandle>;
|
|
10
|
+
/** Get the Docker container ID for a session's agent service */
|
|
11
|
+
getContainerId(sessionId: string): string | null;
|
|
12
|
+
get(sessionId: string): SandboxHandle | undefined;
|
|
13
|
+
list(): SandboxHandle[];
|
|
14
|
+
isAlive(handle: SandboxHandle): boolean;
|
|
15
|
+
exec(handle: SandboxHandle, command: string): Promise<string>;
|
|
16
|
+
listFiles(handle: SandboxHandle, dir: string): Promise<string[]>;
|
|
17
|
+
readFile(handle: SandboxHandle, filePath: string): Promise<string | null>;
|
|
18
|
+
startApp(handle: SandboxHandle): Promise<boolean>;
|
|
19
|
+
stopApp(handle: SandboxHandle): Promise<boolean>;
|
|
20
|
+
isAppRunning(handle: SandboxHandle): Promise<boolean>;
|
|
21
|
+
gitStatus(handle: SandboxHandle, projectDir: string): Promise<GitStatus>;
|
|
22
|
+
createFromRepo(sessionId: string, repoUrl: string, opts?: {
|
|
23
|
+
branch?: string;
|
|
24
|
+
apiKey?: string;
|
|
25
|
+
oauthToken?: string;
|
|
26
|
+
ghToken?: string;
|
|
27
|
+
}): Promise<SandboxHandle>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=docker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../../src/sandbox/docker.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACX,iBAAiB,EACjB,SAAS,EAET,aAAa,EACb,eAAe,EACf,MAAM,YAAY,CAAA;AAgMnB,qBAAa,qBAAsB,YAAW,eAAe;IAC5D,QAAQ,CAAC,OAAO,EAAG,QAAQ,CAAS;IAEpC,OAAO,CAAC,gBAAgB,CAAmC;IAC3D,OAAO,CAAC,aAAa,CAAyC;IAE9D,OAAO,CAAC,QAAQ;IAMV,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC;IAiE3E,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB7C,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAmCjE,gEAAgE;IAChE,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAMhD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIjD,IAAI,IAAI,aAAa,EAAE;IAIvB,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO;IAOjC,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK7D,SAAS,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAqDhE,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAkBzE,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IAmBjD,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IAmBhD,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IAyBrD,SAAS,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IA8DxE,cAAc,CACnB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAChF,OAAO,CAAC,aAAa,CAAC;CA6BzB"}
|