@tickernelz/paperclip-pro-plugin-exe-dev 2026.925.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/LICENSE +22 -0
- package/README.md +58 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.d.ts +4 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +171 -0
- package/dist/manifest.js.map +1 -0
- package/dist/plugin.d.ts +4 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +744 -0
- package/dist/plugin.js.map +1 -0
- package/dist/worker.d.ts +3 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +5 -0
- package/dist/worker.js.map +1 -0
- package/package.json +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Paperclip AI
|
|
4
|
+
Copyright (c) 2026 Zhafron Adani Kautsar (paperclip-pro fork modifications)
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# `@tickernelz/paperclip-pro-plugin-exe-dev`
|
|
2
|
+
|
|
3
|
+
Published exe.dev sandbox provider plugin for Paperclip.
|
|
4
|
+
|
|
5
|
+
This package lives in the Paperclip monorepo, but it is intentionally excluded from the root `pnpm` workspace and shaped to publish and install like a standalone npm package. That lets operators install it from the Plugins page by package name without introducing root lockfile churn.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
From a Paperclip instance, install:
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
@tickernelz/paperclip-pro-plugin-exe-dev
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Configuration
|
|
16
|
+
|
|
17
|
+
Configure exe.dev from `Instance Settings -> Environments`, not from the plugin's plugin page.
|
|
18
|
+
|
|
19
|
+
- Put the exe.dev API token on the sandbox environment itself.
|
|
20
|
+
- When you save an environment, Paperclip stores pasted API keys and pasted SSH private keys as company secrets.
|
|
21
|
+
- `EXE_API_KEY` remains an optional host-level fallback when an environment omits the API token.
|
|
22
|
+
- The current implementation provisions VMs through exe.dev's HTTPS API and runs commands through direct SSH to the created VM.
|
|
23
|
+
|
|
24
|
+
To use the provider successfully, the environment/host needs all of the following:
|
|
25
|
+
|
|
26
|
+
- An exe.dev API token that allows the lifecycle commands the provider uses: `new`, `ls`, and `rm`. `whoami` and `help` are recommended for manual debugging. `restart` is only needed if you extend the provider to restart retained VMs.
|
|
27
|
+
- SSH access from the Paperclip host to the resulting `*.exe.xyz` VMs.
|
|
28
|
+
- An SSH private key that exe.dev already recognizes. You can either:
|
|
29
|
+
- paste the private key into the environment config via `sshPrivateKey`
|
|
30
|
+
- point `sshIdentityFile` at an absolute host path
|
|
31
|
+
- or leave both blank and rely on the host's default SSH agent/keychain
|
|
32
|
+
- The matching public key must already be registered with exe.dev before the provider can execute commands inside the VM.
|
|
33
|
+
|
|
34
|
+
Operational notes:
|
|
35
|
+
|
|
36
|
+
- If exe.dev replies `Please complete registration by running: ssh exe.dev`, the host key has not finished exe.dev onboarding yet.
|
|
37
|
+
- Reusable leases keep the VM alive between runs. exe.dev does not expose a documented "stop and later resume" command in the public CLI docs, so `reuseLease: true` means "retain the VM" rather than "suspend it."
|
|
38
|
+
- The provisioning path uses `https://exe.dev/exec`, which exe.dev documents as a command-style HTTPS API with a 30-second request timeout. Typical `new` calls are expected to fit inside that limit; command execution itself does not use `/exec`.
|
|
39
|
+
- Probes still create and delete a real exe.dev VM through `/exec`, and so do the `new`/`rm` calls inside the normal acquire/release lifecycle. Treat all of those as real provisioning cost, not just probes.
|
|
40
|
+
- exe.dev runs `--setup-script` as the unprivileged `exedev` user, not as root. That user has passwordless `sudo`, so any system-level steps in a custom `setupScript` must invoke `sudo` explicitly (for example `sudo apt-get install -y …`). When you omit `setupScript`, the plugin supplies a default that installs Node 24 via the official nodesource script — Paperclip's sandbox callback bridge is a Node program, so the VM needs `node` on `PATH` before the bridge can launch.
|
|
41
|
+
|
|
42
|
+
## Local development
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
cd packages/plugins/sandbox-providers/exe-dev
|
|
46
|
+
pnpm install --ignore-workspace --no-lockfile
|
|
47
|
+
pnpm build
|
|
48
|
+
pnpm test
|
|
49
|
+
pnpm typecheck
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
These commands assume the repo root has already been installed once so the local `@tickernelz/paperclip-pro-plugin-sdk` workspace package is available to the compiler during development.
|
|
53
|
+
|
|
54
|
+
## Package layout
|
|
55
|
+
|
|
56
|
+
- `src/manifest.ts` declares the sandbox-provider driver metadata
|
|
57
|
+
- `src/plugin.ts` implements the environment lifecycle hooks
|
|
58
|
+
- `paperclipPlugin.manifest` and `paperclipPlugin.worker` point the host at the built plugin entrypoints in `dist/`
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAKtF,QAAA,MAAM,QAAQ,EAAE,yBA+Kf,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
const PLUGIN_ID = "paperclip.exe-dev-sandbox-provider";
|
|
2
|
+
const PLUGIN_VERSION = "0.1.2";
|
|
3
|
+
const manifest = {
|
|
4
|
+
id: PLUGIN_ID,
|
|
5
|
+
apiVersion: 1,
|
|
6
|
+
version: PLUGIN_VERSION,
|
|
7
|
+
displayName: "exe.dev Sandbox Provider",
|
|
8
|
+
description: "Sandbox provider plugin that provisions exe.dev VMs as Paperclip execution environments.",
|
|
9
|
+
author: "Paperclip",
|
|
10
|
+
categories: ["automation"],
|
|
11
|
+
capabilities: ["environment.drivers.register"],
|
|
12
|
+
entrypoints: {
|
|
13
|
+
worker: "./dist/worker.js",
|
|
14
|
+
},
|
|
15
|
+
environmentDrivers: [
|
|
16
|
+
{
|
|
17
|
+
driverKey: "exe-dev",
|
|
18
|
+
kind: "sandbox_provider",
|
|
19
|
+
displayName: "exe.dev VM",
|
|
20
|
+
description: "Provisions exe.dev VMs through the HTTPS API, then runs commands over direct SSH for long-lived Paperclip workloads.",
|
|
21
|
+
configSchema: {
|
|
22
|
+
type: "object",
|
|
23
|
+
properties: {
|
|
24
|
+
// ---- Essentials (always visible, in this order) ----
|
|
25
|
+
apiKey: {
|
|
26
|
+
type: "string",
|
|
27
|
+
format: "secret-ref",
|
|
28
|
+
description: "Paste your exe.dev API token, or pick a saved Paperclip secret. Create one at exe.dev → Settings → API tokens with `/exec` scope (`new`, `ls`, `rm`).",
|
|
29
|
+
},
|
|
30
|
+
sshPrivateKey: {
|
|
31
|
+
type: "string",
|
|
32
|
+
format: "secret-ref",
|
|
33
|
+
maxLength: 8192,
|
|
34
|
+
description: "Paste the SSH private key you registered with exe.dev, or pick a saved secret. Leave blank to fall back to an on-host key (see Advanced → SSH access).",
|
|
35
|
+
},
|
|
36
|
+
// ---- Advanced: SSH access ----
|
|
37
|
+
sshUser: {
|
|
38
|
+
type: "string",
|
|
39
|
+
description: "Login user on the VM. Leave blank to use the image default, usually `root`.",
|
|
40
|
+
"x-paperclip-advanced": true,
|
|
41
|
+
"x-paperclip-group": "SSH access",
|
|
42
|
+
},
|
|
43
|
+
sshIdentityFile: {
|
|
44
|
+
type: "string",
|
|
45
|
+
description: "Absolute path to a private key on the Paperclip host. Used only when SSH Private Key is empty.",
|
|
46
|
+
"x-paperclip-advanced": true,
|
|
47
|
+
"x-paperclip-group": "SSH access",
|
|
48
|
+
},
|
|
49
|
+
sshPort: {
|
|
50
|
+
type: "number",
|
|
51
|
+
description: "SSH port for direct VM access.",
|
|
52
|
+
default: 22,
|
|
53
|
+
"x-paperclip-advanced": true,
|
|
54
|
+
"x-paperclip-group": "SSH access",
|
|
55
|
+
},
|
|
56
|
+
strictHostKeyChecking: {
|
|
57
|
+
type: "string",
|
|
58
|
+
description: "Host key policy passed to ssh via StrictHostKeyChecking. Typical values are `accept-new`, `yes`, or `no`.",
|
|
59
|
+
default: "accept-new",
|
|
60
|
+
"x-paperclip-advanced": true,
|
|
61
|
+
"x-paperclip-group": "SSH access",
|
|
62
|
+
},
|
|
63
|
+
// ---- Advanced: VM resources ----
|
|
64
|
+
image: {
|
|
65
|
+
type: "string",
|
|
66
|
+
description: "Optional container image to use when creating the VM.",
|
|
67
|
+
"x-paperclip-advanced": true,
|
|
68
|
+
"x-paperclip-group": "VM resources",
|
|
69
|
+
},
|
|
70
|
+
cpu: {
|
|
71
|
+
type: "number",
|
|
72
|
+
description: "Optional CPU count passed to `exe.dev new --cpu`.",
|
|
73
|
+
default: 4,
|
|
74
|
+
"x-paperclip-advanced": true,
|
|
75
|
+
"x-paperclip-group": "VM resources",
|
|
76
|
+
},
|
|
77
|
+
memory: {
|
|
78
|
+
type: "string",
|
|
79
|
+
description: "Optional memory size such as `4GB`.",
|
|
80
|
+
default: "4GB",
|
|
81
|
+
"x-paperclip-advanced": true,
|
|
82
|
+
"x-paperclip-group": "VM resources",
|
|
83
|
+
},
|
|
84
|
+
disk: {
|
|
85
|
+
type: "string",
|
|
86
|
+
description: "Optional disk size such as `20GB`.",
|
|
87
|
+
default: "20GB",
|
|
88
|
+
"x-paperclip-advanced": true,
|
|
89
|
+
"x-paperclip-group": "VM resources",
|
|
90
|
+
},
|
|
91
|
+
// ---- Advanced: VM creation ----
|
|
92
|
+
command: {
|
|
93
|
+
type: "string",
|
|
94
|
+
description: "Optional container command passed to `exe.dev new --command`.",
|
|
95
|
+
"x-paperclip-advanced": true,
|
|
96
|
+
"x-paperclip-group": "VM creation",
|
|
97
|
+
},
|
|
98
|
+
env: {
|
|
99
|
+
type: "object",
|
|
100
|
+
description: "Optional environment variables applied at VM creation time.",
|
|
101
|
+
additionalProperties: { type: "string" },
|
|
102
|
+
"x-paperclip-advanced": true,
|
|
103
|
+
"x-paperclip-group": "VM creation",
|
|
104
|
+
},
|
|
105
|
+
integrations: {
|
|
106
|
+
type: "array",
|
|
107
|
+
description: "Optional exe.dev integrations to attach during VM creation.",
|
|
108
|
+
items: { type: "string" },
|
|
109
|
+
"x-paperclip-advanced": true,
|
|
110
|
+
"x-paperclip-group": "VM creation",
|
|
111
|
+
},
|
|
112
|
+
tags: {
|
|
113
|
+
type: "array",
|
|
114
|
+
description: "Optional tags to apply during VM creation.",
|
|
115
|
+
items: { type: "string" },
|
|
116
|
+
"x-paperclip-advanced": true,
|
|
117
|
+
"x-paperclip-group": "VM creation",
|
|
118
|
+
},
|
|
119
|
+
setupScript: {
|
|
120
|
+
type: "string",
|
|
121
|
+
description: "Optional first-boot setup script passed to `exe.dev new --setup-script`.",
|
|
122
|
+
"x-paperclip-advanced": true,
|
|
123
|
+
"x-paperclip-group": "VM creation",
|
|
124
|
+
},
|
|
125
|
+
prompt: {
|
|
126
|
+
type: "string",
|
|
127
|
+
description: "Optional Shelley prompt passed to `exe.dev new --prompt`.",
|
|
128
|
+
"x-paperclip-advanced": true,
|
|
129
|
+
"x-paperclip-group": "VM creation",
|
|
130
|
+
},
|
|
131
|
+
comment: {
|
|
132
|
+
type: "string",
|
|
133
|
+
description: "Optional short note attached to created VMs.",
|
|
134
|
+
"x-paperclip-advanced": true,
|
|
135
|
+
"x-paperclip-group": "VM creation",
|
|
136
|
+
},
|
|
137
|
+
namePrefix: {
|
|
138
|
+
type: "string",
|
|
139
|
+
description: "Optional prefix used when generating VM names.",
|
|
140
|
+
default: "paperclip",
|
|
141
|
+
"x-paperclip-advanced": true,
|
|
142
|
+
"x-paperclip-group": "VM creation",
|
|
143
|
+
},
|
|
144
|
+
// ---- Advanced: API + runtime ----
|
|
145
|
+
apiUrl: {
|
|
146
|
+
type: "string",
|
|
147
|
+
description: "Optional exe.dev HTTPS API base URL or /exec endpoint. Defaults to https://exe.dev/exec.",
|
|
148
|
+
"x-paperclip-advanced": true,
|
|
149
|
+
"x-paperclip-group": "API + runtime",
|
|
150
|
+
},
|
|
151
|
+
timeoutMs: {
|
|
152
|
+
type: "number",
|
|
153
|
+
description: "Timeout for VM lifecycle and SSH operations in milliseconds.",
|
|
154
|
+
default: 300000,
|
|
155
|
+
"x-paperclip-advanced": true,
|
|
156
|
+
"x-paperclip-group": "API + runtime",
|
|
157
|
+
},
|
|
158
|
+
reuseLease: {
|
|
159
|
+
type: "boolean",
|
|
160
|
+
description: "Whether to keep the VM alive between runs instead of deleting it on release.",
|
|
161
|
+
default: false,
|
|
162
|
+
"x-paperclip-advanced": true,
|
|
163
|
+
"x-paperclip-group": "API + runtime",
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
};
|
|
170
|
+
export default manifest;
|
|
171
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAyJA,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0DnE;AAmgBD,QAAA,MAAM,MAAM,gEA6OV,CAAC;AAEH,eAAe,MAAM,CAAC"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,744 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { chmod, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { definePlugin } from "@tickernelz/paperclip-pro-plugin-sdk";
|
|
7
|
+
const DEFAULT_API_URL = "https://exe.dev/exec";
|
|
8
|
+
const DEFAULT_TIMEOUT_MS = 300_000;
|
|
9
|
+
const EXE_DEV_API_MAX_TIMEOUT_MS = 29_000;
|
|
10
|
+
const SSH_SIGKILL_GRACE_MS = 250;
|
|
11
|
+
const MAX_VM_RECORD_DEPTH = 4;
|
|
12
|
+
const EXE_DEV_SSH_ONBOARDING_MARKER = "Please complete registration by running: ssh exe.dev";
|
|
13
|
+
const EXE_DEV_SSH_EMAIL_PROMPT = "Please enter your email address:";
|
|
14
|
+
const EXE_DEV_SSH_INVALID_KEY_FORMAT = /Load key [^\n]*invalid format/i;
|
|
15
|
+
const UUID_SECRET_REF_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
16
|
+
// exe.dev's `--setup-script` runs at VM init as the unprivileged `exedev` user, which
|
|
17
|
+
// has passwordless sudo. The Paperclip sandbox callback bridge is a Node script, so
|
|
18
|
+
// every Paperclip workload on this provider needs node on PATH before the bridge can
|
|
19
|
+
// start. When the operator hasn't supplied their own setup script, install Node 24 via
|
|
20
|
+
// nodesource so the VM comes up ready for Paperclip out of the box.
|
|
21
|
+
const DEFAULT_SETUP_SCRIPT = "(command -v node >/dev/null 2>&1 && " +
|
|
22
|
+
"node -e 'const v=process.versions.node.split(\".\").map(Number);" +
|
|
23
|
+
"process.exit(v[0]>24||(v[0]===24&&v[1]>=11)?0:1)' >/dev/null 2>&1) || " +
|
|
24
|
+
"(curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash - && " +
|
|
25
|
+
"sudo apt-get install -y nodejs)";
|
|
26
|
+
class ExeDevApiError extends Error {
|
|
27
|
+
status;
|
|
28
|
+
body;
|
|
29
|
+
constructor(message, status, body) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = "ExeDevApiError";
|
|
32
|
+
this.status = status;
|
|
33
|
+
this.body = body;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function parseOptionalString(value) {
|
|
37
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
38
|
+
return String(value);
|
|
39
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
40
|
+
}
|
|
41
|
+
function parseOptionalInteger(value) {
|
|
42
|
+
if (value == null || value === "")
|
|
43
|
+
return null;
|
|
44
|
+
const parsed = Number(value);
|
|
45
|
+
return Number.isFinite(parsed) ? Math.trunc(parsed) : null;
|
|
46
|
+
}
|
|
47
|
+
function parseStringArray(value) {
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
return value
|
|
50
|
+
.map((entry) => parseOptionalString(entry))
|
|
51
|
+
.filter((entry) => entry != null);
|
|
52
|
+
}
|
|
53
|
+
if (typeof value === "string") {
|
|
54
|
+
return value
|
|
55
|
+
.split(",")
|
|
56
|
+
.map((entry) => entry.trim())
|
|
57
|
+
.filter((entry) => entry.length > 0);
|
|
58
|
+
}
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
function parseEnvMap(value) {
|
|
62
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
63
|
+
return {};
|
|
64
|
+
const env = {};
|
|
65
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
66
|
+
const normalizedKey = key.trim();
|
|
67
|
+
const normalizedValue = parseOptionalString(raw);
|
|
68
|
+
if (normalizedKey.length > 0 && normalizedValue != null) {
|
|
69
|
+
env[normalizedKey] = normalizedValue;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return env;
|
|
73
|
+
}
|
|
74
|
+
function isValidUrl(value) {
|
|
75
|
+
try {
|
|
76
|
+
new URL(value);
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function isSecretRef(value) {
|
|
84
|
+
return UUID_SECRET_REF_RE.test(value);
|
|
85
|
+
}
|
|
86
|
+
// Catch the SSH-key paste failure modes we've seen in the wild (wrong file,
|
|
87
|
+
// PPK export, truncated paste) before the user pays the cost of provisioning a
|
|
88
|
+
// VM and getting a cryptic SSH error. Inline parse — no `ssh-keygen` dependency
|
|
89
|
+
// — so this also works on hosts where openssh-client isn't installed.
|
|
90
|
+
export function validateSshPrivateKey(rawKey) {
|
|
91
|
+
const trimmed = rawKey.trim();
|
|
92
|
+
if (!trimmed)
|
|
93
|
+
return null;
|
|
94
|
+
if (/^PuTTY-User-Key-File-\d/m.test(trimmed)) {
|
|
95
|
+
return "sshPrivateKey looks like a PuTTY .ppk file. Convert it to OpenSSH format (PuTTYgen → Conversions → Export OpenSSH key) and paste the resulting PEM.";
|
|
96
|
+
}
|
|
97
|
+
if (/^(?:ssh-(?:rsa|dss|ed25519)|ecdsa-sha2-[a-z0-9-]+|sk-(?:ssh-ed25519|ecdsa-sha2-[a-z0-9-]+)@openssh\.com)\s+\S/.test(trimmed)) {
|
|
98
|
+
return "sshPrivateKey looks like a PUBLIC key. Paste the matching private key (the file without the .pub extension).";
|
|
99
|
+
}
|
|
100
|
+
const headerMatch = trimmed.match(/^-----BEGIN ([A-Z0-9 ]*)PRIVATE KEY-----/m);
|
|
101
|
+
if (!headerMatch) {
|
|
102
|
+
return "sshPrivateKey must be a PEM-encoded private key starting with a line like '-----BEGIN OPENSSH PRIVATE KEY-----'.";
|
|
103
|
+
}
|
|
104
|
+
const footerMatch = trimmed.match(/^-----END ([A-Z0-9 ]*)PRIVATE KEY-----\s*$/m);
|
|
105
|
+
if (!footerMatch) {
|
|
106
|
+
return "sshPrivateKey is missing its '-----END … PRIVATE KEY-----' footer. Make sure you copied the whole file, including the final line.";
|
|
107
|
+
}
|
|
108
|
+
const headerLabel = headerMatch[1].trim();
|
|
109
|
+
const footerLabel = footerMatch[1].trim();
|
|
110
|
+
if (headerLabel !== footerLabel) {
|
|
111
|
+
return `sshPrivateKey header/footer mismatch (BEGIN ${headerLabel || "(none)"} vs END ${footerLabel || "(none)"}). The file is likely truncated or two keys are concatenated.`;
|
|
112
|
+
}
|
|
113
|
+
const headerLineEnd = trimmed.indexOf("\n", headerMatch.index ?? 0);
|
|
114
|
+
const footerStart = trimmed.lastIndexOf(footerMatch[0]);
|
|
115
|
+
if (headerLineEnd < 0 || footerStart <= headerLineEnd) {
|
|
116
|
+
return "sshPrivateKey appears to be empty between its BEGIN and END markers.";
|
|
117
|
+
}
|
|
118
|
+
const bodyLines = trimmed
|
|
119
|
+
.slice(headerLineEnd + 1, footerStart)
|
|
120
|
+
.split(/\r?\n/)
|
|
121
|
+
.map((line) => line.trim())
|
|
122
|
+
.filter((line) => line.length > 0);
|
|
123
|
+
if (bodyLines.length === 0) {
|
|
124
|
+
return "sshPrivateKey appears to be empty between its BEGIN and END markers.";
|
|
125
|
+
}
|
|
126
|
+
// PEM bodies are base64 lines, optionally preceded by `Header: value` lines
|
|
127
|
+
// on encrypted PKCS#1 keys (`Proc-Type:`, `DEK-Info:`).
|
|
128
|
+
const base64Line = /^[A-Za-z0-9+/=]+$/;
|
|
129
|
+
const pemHeaderLine = /^[A-Za-z][A-Za-z0-9-]*:\s.+$/;
|
|
130
|
+
for (const line of bodyLines) {
|
|
131
|
+
if (!base64Line.test(line) && !pemHeaderLine.test(line)) {
|
|
132
|
+
return "sshPrivateKey body contains non-base64 characters. The key may have been corrupted by line-wrapping or copy-paste.";
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
function normalizeApiUrl(value) {
|
|
138
|
+
if (!value)
|
|
139
|
+
return DEFAULT_API_URL;
|
|
140
|
+
const trimmed = value.trim();
|
|
141
|
+
if (!trimmed)
|
|
142
|
+
return DEFAULT_API_URL;
|
|
143
|
+
try {
|
|
144
|
+
const parsed = new URL(trimmed);
|
|
145
|
+
const normalizedPath = parsed.pathname.replace(/\/+$/, "") || "/";
|
|
146
|
+
if (normalizedPath === "/exec") {
|
|
147
|
+
parsed.pathname = "/exec";
|
|
148
|
+
return parsed.toString();
|
|
149
|
+
}
|
|
150
|
+
parsed.pathname = `${normalizedPath === "/" ? "" : normalizedPath}/exec`.replace(/\/{2,}/g, "/");
|
|
151
|
+
return parsed.toString();
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return trimmed;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function normalizeNamePrefix(value) {
|
|
158
|
+
const normalized = (value ?? "paperclip")
|
|
159
|
+
.toLowerCase()
|
|
160
|
+
.replace(/[^a-z0-9-]+/g, "-")
|
|
161
|
+
.replace(/^-+|-+$/g, "")
|
|
162
|
+
.replace(/-{2,}/g, "-");
|
|
163
|
+
return normalized.length > 0 ? normalized.slice(0, 24) : "paperclip";
|
|
164
|
+
}
|
|
165
|
+
function parseDriverConfig(raw) {
|
|
166
|
+
const timeoutMs = Number(raw.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
167
|
+
const sshPort = Number(raw.sshPort ?? 22);
|
|
168
|
+
return {
|
|
169
|
+
apiKey: parseOptionalString(raw.apiKey),
|
|
170
|
+
apiUrl: normalizeApiUrl(parseOptionalString(raw.apiUrl)),
|
|
171
|
+
namePrefix: normalizeNamePrefix(parseOptionalString(raw.namePrefix)),
|
|
172
|
+
image: parseOptionalString(raw.image),
|
|
173
|
+
command: parseOptionalString(raw.command),
|
|
174
|
+
cpu: parseOptionalInteger(raw.cpu),
|
|
175
|
+
memory: parseOptionalString(raw.memory),
|
|
176
|
+
disk: parseOptionalString(raw.disk),
|
|
177
|
+
comment: parseOptionalString(raw.comment),
|
|
178
|
+
env: parseEnvMap(raw.env),
|
|
179
|
+
integrations: parseStringArray(raw.integrations),
|
|
180
|
+
tags: parseStringArray(raw.tags),
|
|
181
|
+
setupScript: parseOptionalString(raw.setupScript),
|
|
182
|
+
prompt: parseOptionalString(raw.prompt),
|
|
183
|
+
timeoutMs: Number.isFinite(timeoutMs) ? Math.trunc(timeoutMs) : DEFAULT_TIMEOUT_MS,
|
|
184
|
+
reuseLease: raw.reuseLease === true,
|
|
185
|
+
sshUser: parseOptionalString(raw.sshUser),
|
|
186
|
+
sshPrivateKey: parseOptionalString(raw.sshPrivateKey),
|
|
187
|
+
sshIdentityFile: parseOptionalString(raw.sshIdentityFile),
|
|
188
|
+
sshPort: Number.isFinite(sshPort) ? Math.trunc(sshPort) : 22,
|
|
189
|
+
strictHostKeyChecking: parseOptionalString(raw.strictHostKeyChecking) ?? "accept-new",
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function resolveApiKey(config) {
|
|
193
|
+
if (config.apiKey)
|
|
194
|
+
return config.apiKey;
|
|
195
|
+
const envApiKey = process.env.EXE_API_KEY?.trim() ?? "";
|
|
196
|
+
if (!envApiKey) {
|
|
197
|
+
throw new Error("exe.dev environments require an API key in config or EXE_API_KEY.");
|
|
198
|
+
}
|
|
199
|
+
return envApiKey;
|
|
200
|
+
}
|
|
201
|
+
function isValidShellEnvKey(value) {
|
|
202
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(value);
|
|
203
|
+
}
|
|
204
|
+
function shellQuote(value) {
|
|
205
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
206
|
+
}
|
|
207
|
+
function formatErrorMessage(error) {
|
|
208
|
+
return error instanceof Error ? error.message : String(error);
|
|
209
|
+
}
|
|
210
|
+
function buildVmName(config, params) {
|
|
211
|
+
const envPart = params.environmentId.replace(/[^a-z0-9]+/gi, "").slice(0, 8).toLowerCase() || "env";
|
|
212
|
+
const runPart = params.runId.replace(/[^a-z0-9]+/gi, "").slice(0, 8).toLowerCase() || randomUUID().slice(0, 8);
|
|
213
|
+
return `${config.namePrefix}-${envPart}-${runPart}`.slice(0, 63);
|
|
214
|
+
}
|
|
215
|
+
function buildFlag(name, value) {
|
|
216
|
+
if (value == null)
|
|
217
|
+
return [];
|
|
218
|
+
return [`--${name}=${shellQuote(String(value))}`];
|
|
219
|
+
}
|
|
220
|
+
function buildRepeatedFlag(name, values) {
|
|
221
|
+
return values.flatMap((value) => buildFlag(name, value));
|
|
222
|
+
}
|
|
223
|
+
function buildEnvFlags(env) {
|
|
224
|
+
return Object.entries(env).flatMap(([key, value]) => buildFlag("env", `${key}=${value}`));
|
|
225
|
+
}
|
|
226
|
+
function resolveSetupScript(config) {
|
|
227
|
+
if (config.setupScript === null)
|
|
228
|
+
return DEFAULT_SETUP_SCRIPT;
|
|
229
|
+
const trimmed = config.setupScript.trim();
|
|
230
|
+
return trimmed.length > 0 ? config.setupScript : null;
|
|
231
|
+
}
|
|
232
|
+
function buildCreateCommand(config, vmName) {
|
|
233
|
+
return [
|
|
234
|
+
"new",
|
|
235
|
+
"--json",
|
|
236
|
+
"--no-email",
|
|
237
|
+
...buildFlag("name", vmName),
|
|
238
|
+
...buildFlag("image", config.image),
|
|
239
|
+
...buildFlag("command", config.command),
|
|
240
|
+
...buildFlag("cpu", config.cpu),
|
|
241
|
+
...buildFlag("memory", config.memory),
|
|
242
|
+
...buildFlag("disk", config.disk),
|
|
243
|
+
...buildFlag("comment", config.comment),
|
|
244
|
+
...buildEnvFlags(config.env),
|
|
245
|
+
...buildRepeatedFlag("integration", config.integrations),
|
|
246
|
+
...buildRepeatedFlag("tag", config.tags),
|
|
247
|
+
...buildFlag("setup-script", resolveSetupScript(config)),
|
|
248
|
+
...buildFlag("prompt", config.prompt),
|
|
249
|
+
].join(" ");
|
|
250
|
+
}
|
|
251
|
+
function replaceLiteralAll(input, search, replacement) {
|
|
252
|
+
return search.length === 0 ? input : input.split(search).join(replacement);
|
|
253
|
+
}
|
|
254
|
+
function redactCreateCommand(command, config) {
|
|
255
|
+
let redacted = command;
|
|
256
|
+
for (const [key, value] of Object.entries(config.env)) {
|
|
257
|
+
redacted = replaceLiteralAll(redacted, `--env=${shellQuote(`${key}=${value}`)}`, `--env=${shellQuote(`${key}=[REDACTED]`)}`);
|
|
258
|
+
}
|
|
259
|
+
if (config.prompt) {
|
|
260
|
+
redacted = replaceLiteralAll(redacted, `--prompt=${shellQuote(config.prompt)}`, `--prompt=${shellQuote("[REDACTED]")}`);
|
|
261
|
+
}
|
|
262
|
+
const resolvedSetupScript = resolveSetupScript(config);
|
|
263
|
+
if (resolvedSetupScript && resolvedSetupScript !== DEFAULT_SETUP_SCRIPT) {
|
|
264
|
+
redacted = replaceLiteralAll(redacted, `--setup-script=${shellQuote(resolvedSetupScript)}`, `--setup-script=${shellQuote("[REDACTED]")}`);
|
|
265
|
+
}
|
|
266
|
+
return redacted;
|
|
267
|
+
}
|
|
268
|
+
async function runLifecycleCommand(config, command, logCommand = command) {
|
|
269
|
+
const response = await fetch(config.apiUrl, {
|
|
270
|
+
method: "POST",
|
|
271
|
+
headers: {
|
|
272
|
+
Authorization: `Bearer ${resolveApiKey(config)}`,
|
|
273
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
274
|
+
},
|
|
275
|
+
body: command,
|
|
276
|
+
signal: AbortSignal.timeout(Math.min(config.timeoutMs, EXE_DEV_API_MAX_TIMEOUT_MS)),
|
|
277
|
+
});
|
|
278
|
+
const body = await response.text();
|
|
279
|
+
if (!response.ok) {
|
|
280
|
+
throw new ExeDevApiError(`exe.dev API command failed (${response.status}) for: ${logCommand}`, response.status, body);
|
|
281
|
+
}
|
|
282
|
+
const trimmed = body.trim();
|
|
283
|
+
if (!trimmed)
|
|
284
|
+
return null;
|
|
285
|
+
try {
|
|
286
|
+
return JSON.parse(trimmed);
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
return body;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function parseVmRecord(value, depth = 0) {
|
|
293
|
+
if (depth > MAX_VM_RECORD_DEPTH)
|
|
294
|
+
return null;
|
|
295
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
296
|
+
return null;
|
|
297
|
+
const record = value;
|
|
298
|
+
const nested = parseVmRecord(record.vm, depth + 1) ?? parseVmRecord(record.data, depth + 1);
|
|
299
|
+
if (nested)
|
|
300
|
+
return nested;
|
|
301
|
+
const name = parseOptionalString(record.vm_name ?? record.name ?? record.vmName);
|
|
302
|
+
const sshDest = parseOptionalString(record.ssh_dest ?? record.sshDest)
|
|
303
|
+
?? (name ? `${name}.exe.xyz` : null);
|
|
304
|
+
if (!name || !sshDest)
|
|
305
|
+
return null;
|
|
306
|
+
return {
|
|
307
|
+
name,
|
|
308
|
+
sshDest,
|
|
309
|
+
httpsUrl: parseOptionalString(record.https_url ?? record.httpsUrl),
|
|
310
|
+
status: parseOptionalString(record.status),
|
|
311
|
+
region: parseOptionalString(record.region),
|
|
312
|
+
regionDisplay: parseOptionalString(record.region_display ?? record.regionDisplay),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
async function lookupVm(config, vmName) {
|
|
316
|
+
const response = await runLifecycleCommand(config, `ls --json ${shellQuote(vmName)}`);
|
|
317
|
+
const list = Array.isArray(response?.vms)
|
|
318
|
+
? response.vms
|
|
319
|
+
: Array.isArray(response)
|
|
320
|
+
? response
|
|
321
|
+
: response
|
|
322
|
+
? [response]
|
|
323
|
+
: [];
|
|
324
|
+
for (const candidate of list) {
|
|
325
|
+
const parsed = parseVmRecord(candidate);
|
|
326
|
+
if (parsed?.name === vmName || parsed?.sshDest === vmName) {
|
|
327
|
+
return parsed;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
async function createVm(config, params) {
|
|
333
|
+
const vmName = "runId" in params
|
|
334
|
+
? buildVmName(config, params)
|
|
335
|
+
: `${config.namePrefix}-probe-${randomUUID().slice(0, 8)}`.slice(0, 63);
|
|
336
|
+
const command = buildCreateCommand(config, vmName);
|
|
337
|
+
const response = await runLifecycleCommand(config, command, redactCreateCommand(command, config));
|
|
338
|
+
const created = parseVmRecord(response) ?? await lookupVm(config, vmName);
|
|
339
|
+
if (!created) {
|
|
340
|
+
throw new Error(`exe.dev did not return VM metadata for ${vmName}.`);
|
|
341
|
+
}
|
|
342
|
+
return created;
|
|
343
|
+
}
|
|
344
|
+
async function deleteVm(config, vmName) {
|
|
345
|
+
await runLifecycleCommand(config, `rm --json ${shellQuote(vmName)}`);
|
|
346
|
+
}
|
|
347
|
+
function buildSshDestination(config, vm) {
|
|
348
|
+
return config.sshUser ? `${config.sshUser}@${vm.sshDest}` : vm.sshDest;
|
|
349
|
+
}
|
|
350
|
+
function buildSshArgs(config, vm, remoteCommand, sshIdentityFile) {
|
|
351
|
+
const args = [
|
|
352
|
+
"-T",
|
|
353
|
+
"-o",
|
|
354
|
+
"BatchMode=yes",
|
|
355
|
+
"-o",
|
|
356
|
+
`StrictHostKeyChecking=${config.strictHostKeyChecking}`,
|
|
357
|
+
"-o",
|
|
358
|
+
"ConnectTimeout=15",
|
|
359
|
+
"-p",
|
|
360
|
+
String(config.sshPort),
|
|
361
|
+
];
|
|
362
|
+
if (sshIdentityFile) {
|
|
363
|
+
args.push("-i", sshIdentityFile, "-o", "IdentitiesOnly=yes");
|
|
364
|
+
}
|
|
365
|
+
args.push(buildSshDestination(config, vm), remoteCommand);
|
|
366
|
+
return args;
|
|
367
|
+
}
|
|
368
|
+
async function prepareSshIdentity(config) {
|
|
369
|
+
if (!config.sshPrivateKey) {
|
|
370
|
+
return {
|
|
371
|
+
sshIdentityFile: config.sshIdentityFile,
|
|
372
|
+
cleanup: async () => { },
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
const tempDir = await mkdtemp(path.join(tmpdir(), "paperclip-exe-dev-ssh-"));
|
|
376
|
+
const sshIdentityFile = path.join(tempDir, "id_ed25519");
|
|
377
|
+
const privateKey = config.sshPrivateKey.endsWith("\n")
|
|
378
|
+
? config.sshPrivateKey
|
|
379
|
+
: `${config.sshPrivateKey}\n`;
|
|
380
|
+
await writeFile(sshIdentityFile, privateKey, { mode: 0o600 });
|
|
381
|
+
await chmod(sshIdentityFile, 0o600);
|
|
382
|
+
return {
|
|
383
|
+
sshIdentityFile,
|
|
384
|
+
cleanup: async () => {
|
|
385
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
386
|
+
},
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
function buildLoginShellScript(input) {
|
|
390
|
+
const env = input.env ?? {};
|
|
391
|
+
for (const key of Object.keys(env)) {
|
|
392
|
+
if (!isValidShellEnvKey(key)) {
|
|
393
|
+
throw new Error(`Invalid exe.dev environment variable key: ${key}`);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
const envArgs = Object.entries(env)
|
|
397
|
+
.filter((entry) => typeof entry[1] === "string")
|
|
398
|
+
.map(([key, value]) => `${key}=${shellQuote(value)}`);
|
|
399
|
+
const commandParts = [shellQuote(input.command), ...input.args.map(shellQuote)].join(" ");
|
|
400
|
+
const finalLine = envArgs.length > 0
|
|
401
|
+
? `exec env ${envArgs.join(" ")} ${commandParts}`
|
|
402
|
+
: `exec ${commandParts}`;
|
|
403
|
+
// Source the common login profiles before exec so the command runs with the
|
|
404
|
+
// interactive-shell PATH. The wrapper sources no `nvm.sh`; the sandbox image
|
|
405
|
+
// supplies node on the PATH.
|
|
406
|
+
const lines = [
|
|
407
|
+
'if [ -f /etc/profile ]; then . /etc/profile >/dev/null 2>&1 || true; fi',
|
|
408
|
+
'if [ -f "$HOME/.profile" ]; then . "$HOME/.profile" >/dev/null 2>&1 || true; fi',
|
|
409
|
+
'if [ -f "$HOME/.bash_profile" ]; then . "$HOME/.bash_profile" >/dev/null 2>&1 || true; elif [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc" >/dev/null 2>&1 || true; fi',
|
|
410
|
+
'if [ -f "$HOME/.zprofile" ]; then . "$HOME/.zprofile" >/dev/null 2>&1 || true; fi',
|
|
411
|
+
];
|
|
412
|
+
if (input.cwd) {
|
|
413
|
+
lines.push(`cd ${shellQuote(input.cwd)}`);
|
|
414
|
+
}
|
|
415
|
+
lines.push(finalLine);
|
|
416
|
+
return lines.join(" && ");
|
|
417
|
+
}
|
|
418
|
+
function formatSshFailure(action, vmName, result) {
|
|
419
|
+
const combinedOutput = `${result.stderr}\n${result.stdout}`;
|
|
420
|
+
if (combinedOutput.includes(EXE_DEV_SSH_ONBOARDING_MARKER)
|
|
421
|
+
|| combinedOutput.includes(EXE_DEV_SSH_EMAIL_PROMPT)) {
|
|
422
|
+
return [
|
|
423
|
+
`Failed to ${action} exe.dev VM ${vmName}: the Paperclip host SSH key is not registered with exe.dev.`,
|
|
424
|
+
"Complete exe.dev's one-time SSH onboarding on this host by running `ssh exe.dev` and following the email verification prompt, then retry.",
|
|
425
|
+
].join(" ");
|
|
426
|
+
}
|
|
427
|
+
if (EXE_DEV_SSH_INVALID_KEY_FORMAT.test(combinedOutput)) {
|
|
428
|
+
return [
|
|
429
|
+
`Failed to ${action} exe.dev VM ${vmName}: the configured SSH private key isn't an OpenSSH-format private key.`,
|
|
430
|
+
"Confirm the secret starts with `-----BEGIN … PRIVATE KEY-----` and isn't the `.pub` file or a PuTTY `.ppk` export.",
|
|
431
|
+
].join(" ");
|
|
432
|
+
}
|
|
433
|
+
return `Failed to ${action} exe.dev VM ${vmName}: ${result.stderr.trim() || result.stdout.trim() || "unknown error"}`;
|
|
434
|
+
}
|
|
435
|
+
async function runSshCommand(config, vm, remoteCommand, options = {}) {
|
|
436
|
+
const timeoutMs = options.timeoutMs ?? config.timeoutMs;
|
|
437
|
+
const identity = await prepareSshIdentity(config);
|
|
438
|
+
try {
|
|
439
|
+
return await new Promise((resolve, reject) => {
|
|
440
|
+
const child = spawn("ssh", buildSshArgs(config, vm, remoteCommand, identity.sshIdentityFile), {
|
|
441
|
+
stdio: [options.stdin != null ? "pipe" : "ignore", "pipe", "pipe"],
|
|
442
|
+
});
|
|
443
|
+
let stdout = "";
|
|
444
|
+
let stderr = "";
|
|
445
|
+
let timedOut = false;
|
|
446
|
+
let killTimer = null;
|
|
447
|
+
const timer = timeoutMs > 0
|
|
448
|
+
? setTimeout(() => {
|
|
449
|
+
timedOut = true;
|
|
450
|
+
child.kill("SIGTERM");
|
|
451
|
+
killTimer = setTimeout(() => {
|
|
452
|
+
child.kill("SIGKILL");
|
|
453
|
+
}, SSH_SIGKILL_GRACE_MS);
|
|
454
|
+
}, timeoutMs)
|
|
455
|
+
: null;
|
|
456
|
+
child.stdout?.on("data", (chunk) => {
|
|
457
|
+
stdout += String(chunk);
|
|
458
|
+
});
|
|
459
|
+
child.stderr?.on("data", (chunk) => {
|
|
460
|
+
stderr += String(chunk);
|
|
461
|
+
});
|
|
462
|
+
child.on("error", (error) => {
|
|
463
|
+
if (timer)
|
|
464
|
+
clearTimeout(timer);
|
|
465
|
+
if (killTimer)
|
|
466
|
+
clearTimeout(killTimer);
|
|
467
|
+
reject(error);
|
|
468
|
+
});
|
|
469
|
+
child.on("close", (code, signal) => {
|
|
470
|
+
if (timer)
|
|
471
|
+
clearTimeout(timer);
|
|
472
|
+
if (killTimer)
|
|
473
|
+
clearTimeout(killTimer);
|
|
474
|
+
resolve({
|
|
475
|
+
exitCode: timedOut ? null : code,
|
|
476
|
+
signal,
|
|
477
|
+
timedOut,
|
|
478
|
+
stdout,
|
|
479
|
+
stderr,
|
|
480
|
+
});
|
|
481
|
+
});
|
|
482
|
+
if (options.stdin != null && child.stdin) {
|
|
483
|
+
child.stdin.write(options.stdin);
|
|
484
|
+
child.stdin.end();
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
finally {
|
|
489
|
+
await identity.cleanup();
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
async function detectRemoteContext(config, vm) {
|
|
493
|
+
const result = await runSshCommand(config, vm, `sh -lc ${shellQuote('home="${HOME:-}"; if [ -z "$home" ]; then home="$(pwd)"; fi; if command -v bash >/dev/null 2>&1; then shell=bash; else shell=sh; fi; printf "%s\\n%s\\n" "$home" "$shell"')}`);
|
|
494
|
+
if (result.timedOut || result.exitCode !== 0) {
|
|
495
|
+
throw new Error(formatSshFailure("inspect", vm.name, result));
|
|
496
|
+
}
|
|
497
|
+
const [homeDirRaw, shellRaw] = result.stdout.split(/\r?\n/);
|
|
498
|
+
const homeDir = homeDirRaw?.trim() || "/tmp";
|
|
499
|
+
return {
|
|
500
|
+
homeDir,
|
|
501
|
+
shellCommand: shellRaw?.trim() === "bash" ? "bash" : "sh",
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
async function ensureRemoteWorkspace(config, vm, remoteCwd) {
|
|
505
|
+
const result = await runSshCommand(config, vm, `sh -lc ${shellQuote(`mkdir -p ${shellQuote(remoteCwd)}`)}`);
|
|
506
|
+
if (result.timedOut || result.exitCode !== 0) {
|
|
507
|
+
throw new Error(formatSshFailure("create workspace for", vm.name, result));
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
async function buildLease(config, vm, requestedCwd, resumedLease) {
|
|
511
|
+
const remote = await detectRemoteContext(config, vm);
|
|
512
|
+
const remoteCwd = requestedCwd?.trim() || path.posix.join(remote.homeDir, "paperclip-workspace");
|
|
513
|
+
await ensureRemoteWorkspace(config, vm, remoteCwd);
|
|
514
|
+
return {
|
|
515
|
+
providerLeaseId: vm.name,
|
|
516
|
+
metadata: {
|
|
517
|
+
provider: "exe-dev",
|
|
518
|
+
vmName: vm.name,
|
|
519
|
+
sshDest: vm.sshDest,
|
|
520
|
+
httpsUrl: vm.httpsUrl,
|
|
521
|
+
region: vm.region,
|
|
522
|
+
regionDisplay: vm.regionDisplay,
|
|
523
|
+
shellCommand: remote.shellCommand,
|
|
524
|
+
remoteCwd,
|
|
525
|
+
timeoutMs: config.timeoutMs,
|
|
526
|
+
reuseLease: config.reuseLease,
|
|
527
|
+
resumedLease,
|
|
528
|
+
},
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
function metadataVmRecord(params) {
|
|
532
|
+
if (!params.providerLeaseId)
|
|
533
|
+
return null;
|
|
534
|
+
const sshDest = parseOptionalString(params.leaseMetadata?.sshDest) ?? `${params.providerLeaseId}.exe.xyz`;
|
|
535
|
+
return {
|
|
536
|
+
name: params.providerLeaseId,
|
|
537
|
+
sshDest,
|
|
538
|
+
httpsUrl: parseOptionalString(params.leaseMetadata?.httpsUrl),
|
|
539
|
+
status: parseOptionalString(params.leaseMetadata?.status),
|
|
540
|
+
region: parseOptionalString(params.leaseMetadata?.region),
|
|
541
|
+
regionDisplay: parseOptionalString(params.leaseMetadata?.regionDisplay),
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
const plugin = definePlugin({
|
|
545
|
+
async setup(ctx) {
|
|
546
|
+
ctx.logger.info("exe.dev sandbox provider plugin ready");
|
|
547
|
+
},
|
|
548
|
+
async onHealth() {
|
|
549
|
+
return { status: "ok", message: "exe.dev sandbox provider plugin healthy" };
|
|
550
|
+
},
|
|
551
|
+
async onEnvironmentValidateConfig(params) {
|
|
552
|
+
const config = parseDriverConfig(params.config);
|
|
553
|
+
const errors = [];
|
|
554
|
+
const warnings = [];
|
|
555
|
+
if (config.apiUrl && !isValidUrl(config.apiUrl)) {
|
|
556
|
+
errors.push("apiUrl must be a valid URL.");
|
|
557
|
+
}
|
|
558
|
+
if (config.timeoutMs < 1 || config.timeoutMs > 86_400_000) {
|
|
559
|
+
errors.push("timeoutMs must be between 1 and 86400000.");
|
|
560
|
+
}
|
|
561
|
+
if (config.cpu != null && config.cpu <= 0) {
|
|
562
|
+
errors.push("cpu must be greater than 0 when provided.");
|
|
563
|
+
}
|
|
564
|
+
if (config.sshPort < 1 || config.sshPort > 65_535) {
|
|
565
|
+
errors.push("sshPort must be between 1 and 65535.");
|
|
566
|
+
}
|
|
567
|
+
if (!config.apiKey && !(process.env.EXE_API_KEY?.trim())) {
|
|
568
|
+
errors.push("exe.dev environments require an API key in config or EXE_API_KEY.");
|
|
569
|
+
}
|
|
570
|
+
for (const key of Object.keys(config.env)) {
|
|
571
|
+
if (!isValidShellEnvKey(key)) {
|
|
572
|
+
errors.push(`env contains an invalid key: ${key}`);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (typeof params.config.strictHostKeyChecking === "string" &&
|
|
576
|
+
params.config.strictHostKeyChecking.trim().length === 0) {
|
|
577
|
+
errors.push("strictHostKeyChecking cannot be empty.");
|
|
578
|
+
}
|
|
579
|
+
if (config.sshPrivateKey && !isSecretRef(config.sshPrivateKey)) {
|
|
580
|
+
const sshKeyError = validateSshPrivateKey(config.sshPrivateKey);
|
|
581
|
+
if (sshKeyError)
|
|
582
|
+
errors.push(sshKeyError);
|
|
583
|
+
}
|
|
584
|
+
warnings.push("The Paperclip host must have SSH access to the created exe.dev VM, and its SSH key must be registered with exe.dev. The API token only covers provisioning.");
|
|
585
|
+
if (config.reuseLease) {
|
|
586
|
+
warnings.push("reuseLease keeps the VM alive between runs; this provider does not suspend retained VMs.");
|
|
587
|
+
}
|
|
588
|
+
if (errors.length > 0) {
|
|
589
|
+
return { ok: false, errors, warnings };
|
|
590
|
+
}
|
|
591
|
+
return {
|
|
592
|
+
ok: true,
|
|
593
|
+
warnings,
|
|
594
|
+
normalizedConfig: { ...config },
|
|
595
|
+
};
|
|
596
|
+
},
|
|
597
|
+
async onEnvironmentProbe(params) {
|
|
598
|
+
const config = parseDriverConfig(params.config);
|
|
599
|
+
let vm = null;
|
|
600
|
+
try {
|
|
601
|
+
vm = await createVm(config, params);
|
|
602
|
+
const lease = await buildLease(config, vm, undefined, false);
|
|
603
|
+
return {
|
|
604
|
+
ok: true,
|
|
605
|
+
summary: `Connected to exe.dev VM ${vm.name}.`,
|
|
606
|
+
metadata: {
|
|
607
|
+
provider: "exe-dev",
|
|
608
|
+
vmName: vm.name,
|
|
609
|
+
sshDest: vm.sshDest,
|
|
610
|
+
timeoutMs: config.timeoutMs,
|
|
611
|
+
reuseLease: config.reuseLease,
|
|
612
|
+
remoteCwd: lease.metadata?.remoteCwd,
|
|
613
|
+
shellCommand: lease.metadata?.shellCommand,
|
|
614
|
+
},
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
catch (error) {
|
|
618
|
+
return {
|
|
619
|
+
ok: false,
|
|
620
|
+
summary: "exe.dev environment probe failed.",
|
|
621
|
+
metadata: {
|
|
622
|
+
provider: "exe-dev",
|
|
623
|
+
timeoutMs: config.timeoutMs,
|
|
624
|
+
reuseLease: config.reuseLease,
|
|
625
|
+
error: formatErrorMessage(error),
|
|
626
|
+
},
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
finally {
|
|
630
|
+
if (vm) {
|
|
631
|
+
await deleteVm(config, vm.name).catch(() => undefined);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
},
|
|
635
|
+
async onEnvironmentAcquireLease(params) {
|
|
636
|
+
const config = parseDriverConfig(params.config);
|
|
637
|
+
const vm = await createVm(config, params);
|
|
638
|
+
try {
|
|
639
|
+
return await buildLease(config, vm, params.requestedCwd, false);
|
|
640
|
+
}
|
|
641
|
+
catch (error) {
|
|
642
|
+
await deleteVm(config, vm.name).catch(() => undefined);
|
|
643
|
+
throw error;
|
|
644
|
+
}
|
|
645
|
+
},
|
|
646
|
+
async onEnvironmentResumeLease(params) {
|
|
647
|
+
const config = parseDriverConfig(params.config);
|
|
648
|
+
const vm = await lookupVm(config, params.providerLeaseId);
|
|
649
|
+
if (!vm) {
|
|
650
|
+
return { providerLeaseId: null, metadata: { expired: true } };
|
|
651
|
+
}
|
|
652
|
+
const requestedCwd = parseOptionalString(params.leaseMetadata?.remoteCwd);
|
|
653
|
+
return await buildLease(config, vm, requestedCwd ?? undefined, true);
|
|
654
|
+
},
|
|
655
|
+
async onEnvironmentReleaseLease(params) {
|
|
656
|
+
if (!params.providerLeaseId)
|
|
657
|
+
return;
|
|
658
|
+
const config = parseDriverConfig(params.config);
|
|
659
|
+
if (config.reuseLease)
|
|
660
|
+
return;
|
|
661
|
+
await deleteVm(config, params.providerLeaseId);
|
|
662
|
+
},
|
|
663
|
+
async onEnvironmentDestroyLease(params) {
|
|
664
|
+
if (!params.providerLeaseId)
|
|
665
|
+
return;
|
|
666
|
+
const config = parseDriverConfig(params.config);
|
|
667
|
+
await deleteVm(config, params.providerLeaseId);
|
|
668
|
+
},
|
|
669
|
+
async onEnvironmentRealizeWorkspace(params) {
|
|
670
|
+
const config = parseDriverConfig(params.config);
|
|
671
|
+
const remoteCwd = parseOptionalString(params.lease.metadata?.remoteCwd)
|
|
672
|
+
?? params.workspace.remotePath
|
|
673
|
+
?? params.workspace.localPath
|
|
674
|
+
?? "/tmp/paperclip-workspace";
|
|
675
|
+
const vm = metadataVmRecord({
|
|
676
|
+
providerLeaseId: params.lease.providerLeaseId,
|
|
677
|
+
leaseMetadata: params.lease.metadata,
|
|
678
|
+
});
|
|
679
|
+
if (vm) {
|
|
680
|
+
await ensureRemoteWorkspace(config, vm, remoteCwd);
|
|
681
|
+
}
|
|
682
|
+
return {
|
|
683
|
+
cwd: remoteCwd,
|
|
684
|
+
metadata: {
|
|
685
|
+
provider: "exe-dev",
|
|
686
|
+
remoteCwd,
|
|
687
|
+
},
|
|
688
|
+
};
|
|
689
|
+
},
|
|
690
|
+
async onEnvironmentExecute(params) {
|
|
691
|
+
if (!params.lease.providerLeaseId) {
|
|
692
|
+
return {
|
|
693
|
+
exitCode: 1,
|
|
694
|
+
signal: null,
|
|
695
|
+
timedOut: false,
|
|
696
|
+
stdout: "",
|
|
697
|
+
stderr: "No provider lease ID available for execution.",
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
const config = parseDriverConfig(params.config);
|
|
701
|
+
const vm = metadataVmRecord({
|
|
702
|
+
providerLeaseId: params.lease.providerLeaseId,
|
|
703
|
+
leaseMetadata: params.lease.metadata,
|
|
704
|
+
});
|
|
705
|
+
if (!vm) {
|
|
706
|
+
return {
|
|
707
|
+
exitCode: 1,
|
|
708
|
+
signal: null,
|
|
709
|
+
timedOut: false,
|
|
710
|
+
stdout: "",
|
|
711
|
+
stderr: "No exe.dev VM metadata available for execution.",
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
const command = buildLoginShellScript({
|
|
715
|
+
command: params.command,
|
|
716
|
+
args: params.args ?? [],
|
|
717
|
+
cwd: params.cwd ?? parseOptionalString(params.lease.metadata?.remoteCwd) ?? undefined,
|
|
718
|
+
env: params.env,
|
|
719
|
+
});
|
|
720
|
+
// `buildLoginShellScript` already explicitly sources `/etc/profile`,
|
|
721
|
+
// `~/.profile`, `~/.bash_profile`/`~/.bashrc`, and `~/.zprofile`. Wrapping
|
|
722
|
+
// the result in `sh -lc` (login shell) would source the same files a
|
|
723
|
+
// second time, which can cause `PATH` duplication or unexpected behavior
|
|
724
|
+
// on VMs whose profile init isn't idempotent. Use `sh -c` here so the
|
|
725
|
+
// explicit sourcing inside the script is the single source of truth.
|
|
726
|
+
const result = await runSshCommand(config, vm, `sh -c ${shellQuote(command)}`, { stdin: params.stdin, timeoutMs: params.timeoutMs ?? config.timeoutMs });
|
|
727
|
+
return {
|
|
728
|
+
exitCode: result.exitCode,
|
|
729
|
+
signal: result.signal,
|
|
730
|
+
timedOut: result.timedOut,
|
|
731
|
+
stdout: result.stdout,
|
|
732
|
+
stderr: !result.timedOut && result.exitCode !== 0
|
|
733
|
+
? formatSshFailure("execute commands on", vm.name, result)
|
|
734
|
+
: result.stderr,
|
|
735
|
+
metadata: {
|
|
736
|
+
provider: "exe-dev",
|
|
737
|
+
vmName: vm.name,
|
|
738
|
+
sshDest: vm.sshDest,
|
|
739
|
+
},
|
|
740
|
+
};
|
|
741
|
+
},
|
|
742
|
+
});
|
|
743
|
+
export default plugin;
|
|
744
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AA0DpE,MAAM,eAAe,GAAG,sBAAsB,CAAC;AAC/C,MAAM,kBAAkB,GAAG,OAAO,CAAC;AACnC,MAAM,0BAA0B,GAAG,MAAM,CAAC;AAC1C,MAAM,oBAAoB,GAAG,GAAG,CAAC;AACjC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAC9B,MAAM,6BAA6B,GAAG,sDAAsD,CAAC;AAC7F,MAAM,wBAAwB,GAAG,kCAAkC,CAAC;AACpE,MAAM,8BAA8B,GAAG,gCAAgC,CAAC;AACxE,MAAM,kBAAkB,GAAG,iEAAiE,CAAC;AAE7F,sFAAsF;AACtF,oFAAoF;AACpF,qFAAqF;AACrF,uFAAuF;AACvF,oEAAoE;AACpE,MAAM,oBAAoB,GACxB,sCAAsC;IACtC,kEAAkE;IAClE,wEAAwE;IACxE,wEAAwE;IACxE,iCAAiC,CAAC;AAEpC,MAAM,cAAe,SAAQ,KAAK;IACvB,MAAM,CAAS;IACf,IAAI,CAAS;IAEtB,YAAY,OAAe,EAAE,MAAc,EAAE,IAAY;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,SAAS,mBAAmB,CAAC,KAAc;IACzC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9E,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACpF,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAc;IAC1C,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAC/C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7D,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK;aACT,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;aAC1C,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK;aACT,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;aAC5B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3E,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,MAAM,aAAa,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACjC,MAAM,eAAe,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC;QACjD,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,IAAI,eAAe,IAAI,IAAI,EAAE,CAAC;YACxD,GAAG,CAAC,aAAa,CAAC,GAAG,eAAe,CAAC;QACvC,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACxC,CAAC;AAED,4EAA4E;AAC5E,+EAA+E;AAC/E,gFAAgF;AAChF,sEAAsE;AACtE,MAAM,UAAU,qBAAqB,CAAC,MAAc;IAClD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,IAAI,0BAA0B,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7C,OAAO,qJAAqJ,CAAC;IAC/J,CAAC;IAED,IACE,+GAA+G,CAAC,IAAI,CAClH,OAAO,CACR,EACD,CAAC;QACD,OAAO,8GAA8G,CAAC;IACxH,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/E,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,kHAAkH,CAAC;IAC5H,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjF,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,mIAAmI,CAAC;IAC7I,CAAC;IAED,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1C,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1C,IAAI,WAAW,KAAK,WAAW,EAAE,CAAC;QAChC,OAAO,+CAA+C,WAAW,IAAI,QAAQ,WAAW,WAAW,IAAI,QAAQ,+DAA+D,CAAC;IACjL,CAAC;IAED,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;IACpE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,IAAI,aAAa,GAAG,CAAC,IAAI,WAAW,IAAI,aAAa,EAAE,CAAC;QACtD,OAAO,sEAAsE,CAAC;IAChF,CAAC;IAED,MAAM,SAAS,GAAG,OAAO;SACtB,KAAK,CAAC,aAAa,GAAG,CAAC,EAAE,WAAW,CAAC;SACrC,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,sEAAsE,CAAC;IAChF,CAAC;IAED,4EAA4E;IAC5E,wDAAwD;IACxD,MAAM,UAAU,GAAG,mBAAmB,CAAC;IACvC,MAAM,aAAa,GAAG,8BAA8B,CAAC;IACrD,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACxD,OAAO,oHAAoH,CAAC;QAC9H,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,eAAe,CAAC,KAAoB;IAC3C,IAAI,CAAC,KAAK;QAAE,OAAO,eAAe,CAAC;IACnC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO;QAAE,OAAO,eAAe,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QAChC,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;QAClE,IAAI,cAAc,KAAK,OAAO,EAAE,CAAC;YAC/B,MAAM,CAAC,QAAQ,GAAG,OAAO,CAAC;YAC1B,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;QAC3B,CAAC;QACD,MAAM,CAAC,QAAQ,GAAG,GAAG,cAAc,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACjG,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAoB;IAC/C,MAAM,UAAU,GAAG,CAAC,KAAK,IAAI,WAAW,CAAC;SACtC,WAAW,EAAE;SACb,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC;SAC5B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC1B,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;AACvE,CAAC;AAED,SAAS,iBAAiB,CAAC,GAA4B;IACrD,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,IAAI,kBAAkB,CAAC,CAAC;IAC9D,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IAE1C,OAAO;QACL,MAAM,EAAE,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC;QACvC,MAAM,EAAE,eAAe,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACxD,UAAU,EAAE,mBAAmB,CAAC,mBAAmB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACpE,KAAK,EAAE,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC;QACrC,OAAO,EAAE,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC;QACzC,GAAG,EAAE,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC;QAClC,MAAM,EAAE,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC;QACvC,IAAI,EAAE,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC;QACnC,OAAO,EAAE,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC;QACzC,GAAG,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;QACzB,YAAY,EAAE,gBAAgB,CAAC,GAAG,CAAC,YAAY,CAAC;QAChD,IAAI,EAAE,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;QAChC,WAAW,EAAE,mBAAmB,CAAC,GAAG,CAAC,WAAW,CAAC;QACjD,MAAM,EAAE,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC;QACvC,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,kBAAkB;QAClF,UAAU,EAAE,GAAG,CAAC,UAAU,KAAK,IAAI;QACnC,OAAO,EAAE,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC;QACzC,aAAa,EAAE,mBAAmB,CAAC,GAAG,CAAC,aAAa,CAAC;QACrD,eAAe,EAAE,mBAAmB,CAAC,GAAG,CAAC,eAAe,CAAC;QACzD,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;QAC5D,qBAAqB,EAAE,mBAAmB,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,YAAY;KACtF,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,MAA0B;IAC/C,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC;IACxC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAa;IACvC,OAAO,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC7C,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc;IACxC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,WAAW,CAAC,MAA0B,EAAE,MAA2C;IAC1F,MAAM,OAAO,GAAG,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,KAAK,CAAC;IACpG,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/G,OAAO,GAAG,MAAM,CAAC,UAAU,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,SAAS,CAAC,IAAY,EAAE,KAAyC;IACxE,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,EAAE,CAAC;IAC7B,OAAO,CAAC,KAAK,IAAI,IAAI,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY,EAAE,MAAgB;IACvD,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,aAAa,CAAC,GAA2B;IAChD,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED,SAAS,kBAAkB,CAAC,MAA0B;IACpD,IAAI,MAAM,CAAC,WAAW,KAAK,IAAI;QAAE,OAAO,oBAAoB,CAAC;IAC7D,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;IAC1C,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;AACxD,CAAC;AAED,SAAS,kBAAkB,CACzB,MAA0B,EAC1B,MAAc;IAEd,OAAO;QACL,KAAK;QACL,QAAQ;QACR,YAAY;QACZ,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;QAC5B,GAAG,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC;QACnC,GAAG,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC;QACvC,GAAG,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;QAC/B,GAAG,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC;QACrC,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC;QACjC,GAAG,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC;QACvC,GAAG,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC;QAC5B,GAAG,iBAAiB,CAAC,aAAa,EAAE,MAAM,CAAC,YAAY,CAAC;QACxD,GAAG,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC;QACxC,GAAG,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACxD,GAAG,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC;KACtC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAa,EAAE,MAAc,EAAE,WAAmB;IAC3E,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAe,EAAE,MAA0B;IACtE,IAAI,QAAQ,GAAG,OAAO,CAAC;IAEvB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACtD,QAAQ,GAAG,iBAAiB,CAC1B,QAAQ,EACR,SAAS,UAAU,CAAC,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC,EAAE,EACxC,SAAS,UAAU,CAAC,GAAG,GAAG,aAAa,CAAC,EAAE,CAC3C,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,QAAQ,GAAG,iBAAiB,CAC1B,QAAQ,EACR,YAAY,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EACvC,YAAY,UAAU,CAAC,YAAY,CAAC,EAAE,CACvC,CAAC;IACJ,CAAC;IAED,MAAM,mBAAmB,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACvD,IAAI,mBAAmB,IAAI,mBAAmB,KAAK,oBAAoB,EAAE,CAAC;QACxE,QAAQ,GAAG,iBAAiB,CAC1B,QAAQ,EACR,kBAAkB,UAAU,CAAC,mBAAmB,CAAC,EAAE,EACnD,kBAAkB,UAAU,CAAC,YAAY,CAAC,EAAE,CAC7C,CAAC;IACJ,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,MAA0B,EAC1B,OAAe,EACf,UAAU,GAAG,OAAO;IAEpB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE;QAC1C,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,aAAa,CAAC,MAAM,CAAC,EAAE;YAChD,cAAc,EAAE,2BAA2B;SAC5C;QACD,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,0BAA0B,CAAC,CAAC;KACpF,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,cAAc,CACtB,+BAA+B,QAAQ,CAAC,MAAM,UAAU,UAAU,EAAE,EACpE,QAAQ,CAAC,MAAM,EACf,IAAI,CACL,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAc,EAAE,KAAK,GAAG,CAAC;IAC9C,IAAI,KAAK,GAAG,mBAAmB;QAAE,OAAO,IAAI,CAAC;IAC7C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7E,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,GAAG,CAAC,CAAC,IAAI,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;IAC5F,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,IAAI,GAAG,mBAAmB,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IACjF,MAAM,OAAO,GAAG,mBAAmB,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC;WACjE,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAEvC,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAEnC,OAAO;QACL,IAAI;QACJ,OAAO;QACP,QAAQ,EAAE,mBAAmB,CAAC,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC;QAClE,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC;QAC1C,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC;QAC1C,aAAa,EAAE,mBAAmB,CAAC,MAAM,CAAC,cAAc,IAAI,MAAM,CAAC,aAAa,CAAC;KAClF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,MAA0B,EAAE,MAAc;IAChE,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,MAAM,EAAE,aAAa,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACtF,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAE,QAAuC,EAAE,GAAG,CAAC;QACvE,CAAC,CAAE,QAA+B,CAAC,GAAG;QACtC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;YACvB,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,QAAQ;gBACR,CAAC,CAAC,CAAC,QAAQ,CAAC;gBACZ,CAAC,CAAC,EAAE,CAAC;IACX,KAAK,MAAM,SAAS,IAAI,IAAI,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;QACxC,IAAI,MAAM,EAAE,IAAI,KAAK,MAAM,IAAI,MAAM,EAAE,OAAO,KAAK,MAAM,EAAE,CAAC;YAC1D,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,QAAQ,CACrB,MAA0B,EAC1B,MAA0E;IAE1E,MAAM,MAAM,GAAG,OAAO,IAAI,MAAM;QAC9B,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;QAC7B,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,UAAU,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,MAAM,EAAE,OAAO,EAAE,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAClG,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,IAAI,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1E,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,0CAA0C,MAAM,GAAG,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,MAA0B,EAAE,MAAc;IAChE,MAAM,mBAAmB,CAAC,MAAM,EAAE,aAAa,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,mBAAmB,CAAC,MAA0B,EAAE,EAAkB;IACzE,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC;AACzE,CAAC;AAED,SAAS,YAAY,CACnB,MAA0B,EAC1B,EAAkB,EAClB,aAAqB,EACrB,eAA8B;IAE9B,MAAM,IAAI,GAAG;QACX,IAAI;QACJ,IAAI;QACJ,eAAe;QACf,IAAI;QACJ,yBAAyB,MAAM,CAAC,qBAAqB,EAAE;QACvD,IAAI;QACJ,mBAAmB;QACnB,IAAI;QACJ,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;KACvB,CAAC;IACF,IAAI,eAAe,EAAE,CAAC;QACpB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,oBAAoB,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,aAAa,CAAC,CAAC;IAC1D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,MAA0B;IAI1D,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;QAC1B,OAAO;YACL,eAAe,EAAE,MAAM,CAAC,eAAe;YACvC,OAAO,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;SACxB,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,wBAAwB,CAAC,CAAC,CAAC;IAC7E,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACzD,MAAM,UAAU,GAAG,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC;QACpD,CAAC,CAAC,MAAM,CAAC,aAAa;QACtB,CAAC,CAAC,GAAG,MAAM,CAAC,aAAa,IAAI,CAAC;IAEhC,MAAM,SAAS,CAAC,eAAe,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9D,MAAM,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IAEpC,OAAO;QACL,eAAe;QACf,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAAC,KAK9B;IACC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC;IAC5B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,6CAA6C,GAAG,EAAE,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;SAChC,MAAM,CAAC,CAAC,KAAK,EAA6B,EAAE,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC;SAC1E,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACxD,MAAM,YAAY,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1F,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC;QAClC,CAAC,CAAC,YAAY,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,YAAY,EAAE;QACjD,CAAC,CAAC,QAAQ,YAAY,EAAE,CAAC;IAC3B,4EAA4E;IAC5E,6EAA6E;IAC7E,6BAA6B;IAC7B,MAAM,KAAK,GAAG;QACZ,yEAAyE;QACzE,iFAAiF;QACjF,wKAAwK;QACxK,mFAAmF;KACpF,CAAC;IACF,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,MAAM,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtB,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,gBAAgB,CACvB,MAAc,EACd,MAAc,EACd,MAAqD;IAErD,MAAM,cAAc,GAAG,GAAG,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;IAC5D,IACE,cAAc,CAAC,QAAQ,CAAC,6BAA6B,CAAC;WACnD,cAAc,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EACpD,CAAC;QACD,OAAO;YACL,aAAa,MAAM,eAAe,MAAM,8DAA8D;YACtG,2IAA2I;SAC5I,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACd,CAAC;IAED,IAAI,8BAA8B,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;QACxD,OAAO;YACL,aAAa,MAAM,eAAe,MAAM,uEAAuE;YAC/G,oHAAoH;SACrH,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACd,CAAC;IAED,OAAO,aAAa,MAAM,eAAe,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,eAAe,EAAE,CAAC;AACxH,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,MAA0B,EAC1B,EAAkB,EAClB,aAAqB,EACrB,UAAkD,EAAE;IAEpD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,CAAC;IACxD,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAElD,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,YAAY,CAAC,MAAM,EAAE,EAAE,EAAE,aAAa,EAAE,QAAQ,CAAC,eAAe,CAAC,EAAE;gBAC5F,KAAK,EAAE,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;aACnE,CAAC,CAAC;YACH,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,IAAI,QAAQ,GAAG,KAAK,CAAC;YACrB,IAAI,SAAS,GAA0B,IAAI,CAAC;YAC5C,MAAM,KAAK,GAAG,SAAS,GAAG,CAAC;gBACzB,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE;oBACd,QAAQ,GAAG,IAAI,CAAC;oBAChB,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBACtB,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;wBAC1B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBACxB,CAAC,EAAE,oBAAoB,CAAC,CAAC;gBAC3B,CAAC,EAAE,SAAS,CAAC;gBACf,CAAC,CAAC,IAAI,CAAC;YAET,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjC,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1B,CAAC,CAAC,CAAC;YACH,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjC,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1B,CAAC,CAAC,CAAC;YACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC1B,IAAI,KAAK;oBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;gBAC/B,IAAI,SAAS;oBAAE,YAAY,CAAC,SAAS,CAAC,CAAC;gBACvC,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;YACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;gBACjC,IAAI,KAAK;oBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;gBAC/B,IAAI,SAAS;oBAAE,YAAY,CAAC,SAAS,CAAC,CAAC;gBACvC,OAAO,CAAC;oBACN,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;oBAChC,MAAM;oBACN,QAAQ;oBACR,MAAM;oBACN,MAAM;iBACP,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,IAAI,OAAO,CAAC,KAAK,IAAI,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;gBACzC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBACjC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;YACpB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,MAA0B,EAC1B,EAAkB;IAElB,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,MAAM,EACN,EAAE,EACF,UAAU,UAAU,CAClB,2KAA2K,CAC5K,EAAE,CACJ,CAAC;IACF,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,UAAU,EAAE,IAAI,EAAE,IAAI,MAAM,CAAC;IAC7C,OAAO;QACL,OAAO;QACP,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;KAC1D,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,qBAAqB,CAClC,MAA0B,EAC1B,EAAkB,EAClB,SAAiB;IAEjB,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,MAAM,EACN,EAAE,EACF,UAAU,UAAU,CAAC,YAAY,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAC5D,CAAC;IACF,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,sBAAsB,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7E,CAAC;AACH,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,MAA0B,EAC1B,EAAkB,EAClB,YAAgC,EAChC,YAAqB;IAErB,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,YAAY,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;IACjG,MAAM,qBAAqB,CAAC,MAAM,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC;IAEnD,OAAO;QACL,eAAe,EAAE,EAAE,CAAC,IAAI;QACxB,QAAQ,EAAE;YACR,QAAQ,EAAE,SAAS;YACnB,MAAM,EAAE,EAAE,CAAC,IAAI;YACf,OAAO,EAAE,EAAE,CAAC,OAAO;YACnB,QAAQ,EAAE,EAAE,CAAC,QAAQ;YACrB,MAAM,EAAE,EAAE,CAAC,MAAM;YACjB,aAAa,EAAE,EAAE,CAAC,aAAa;YAC/B,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,SAAS;YACT,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,YAAY;SACb;KACF,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,MAGzB;IACC,IAAI,CAAC,MAAM,CAAC,eAAe;QAAE,OAAO,IAAI,CAAC;IACzC,MAAM,OAAO,GAAG,mBAAmB,CAAC,MAAM,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,eAAe,UAAU,CAAC;IAC1G,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,eAAe;QAC5B,OAAO;QACP,QAAQ,EAAE,mBAAmB,CAAC,MAAM,CAAC,aAAa,EAAE,QAAQ,CAAC;QAC7D,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC;QACzD,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC;QACzD,aAAa,EAAE,mBAAmB,CAAC,MAAM,CAAC,aAAa,EAAE,aAAa,CAAC;KACxE,CAAC;AACJ,CAAC;AAED,MAAM,MAAM,GAAG,YAAY,CAAC;IAC1B,KAAK,CAAC,KAAK,CAAC,GAAG;QACb,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,yCAAyC,EAAE,CAAC;IAC9E,CAAC;IAED,KAAK,CAAC,2BAA2B,CAC/B,MAA6C;QAE7C,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YAChD,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,MAAM,CAAC,SAAS,GAAG,CAAC,IAAI,MAAM,CAAC,SAAS,GAAG,UAAU,EAAE,CAAC;YAC1D,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,MAAM,CAAC,GAAG,IAAI,IAAI,IAAI,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;YAC1C,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,GAAG,MAAM,EAAE,CAAC;YAClD,MAAM,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACzD,MAAM,CAAC,IAAI,CAAC,mEAAmE,CAAC,CAAC;QACnF,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1C,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAC;YACrD,CAAC;QACH,CAAC;QACD,IACE,OAAO,MAAM,CAAC,MAAM,CAAC,qBAAqB,KAAK,QAAQ;YACvD,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EACvD,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,MAAM,CAAC,aAAa,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;YAC/D,MAAM,WAAW,GAAG,qBAAqB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YAChE,IAAI,WAAW;gBAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC5C,CAAC;QAED,QAAQ,CAAC,IAAI,CACX,6JAA6J,CAC9J,CAAC;QACF,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACtB,QAAQ,CAAC,IAAI,CAAC,0FAA0F,CAAC,CAAC;QAC5G,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QACzC,CAAC;QAED,OAAO;YACL,EAAE,EAAE,IAAI;YACR,QAAQ;YACR,gBAAgB,EAAE,EAAE,GAAG,MAAM,EAAE;SAChC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,kBAAkB,CACtB,MAAoC;QAEpC,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,EAAE,GAA0B,IAAI,CAAC;QAErC,IAAI,CAAC;YACH,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACpC,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;YAC7D,OAAO;gBACL,EAAE,EAAE,IAAI;gBACR,OAAO,EAAE,2BAA2B,EAAE,CAAC,IAAI,GAAG;gBAC9C,QAAQ,EAAE;oBACR,QAAQ,EAAE,SAAS;oBACnB,MAAM,EAAE,EAAE,CAAC,IAAI;oBACf,OAAO,EAAE,EAAE,CAAC,OAAO;oBACnB,SAAS,EAAE,MAAM,CAAC,SAAS;oBAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;oBAC7B,SAAS,EAAE,KAAK,CAAC,QAAQ,EAAE,SAAS;oBACpC,YAAY,EAAE,KAAK,CAAC,QAAQ,EAAE,YAAY;iBAC3C;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,OAAO,EAAE,mCAAmC;gBAC5C,QAAQ,EAAE;oBACR,QAAQ,EAAE,SAAS;oBACnB,SAAS,EAAE,MAAM,CAAC,SAAS;oBAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;oBAC7B,KAAK,EAAE,kBAAkB,CAAC,KAAK,CAAC;iBACjC;aACF,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,IAAI,EAAE,EAAE,CAAC;gBACP,MAAM,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,yBAAyB,CAC7B,MAA2C;QAE3C,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC;YACH,OAAO,MAAM,UAAU,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;QAClE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YACvD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,wBAAwB,CAC5B,MAA0C;QAE1C,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;QAC1D,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;QAChE,CAAC;QACD,MAAM,YAAY,GAAG,mBAAmB,CAAC,MAAM,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;QAC1E,OAAO,MAAM,UAAU,CAAC,MAAM,EAAE,EAAE,EAAE,YAAY,IAAI,SAAS,EAAE,IAAI,CAAC,CAAC;IACvE,CAAC;IAED,KAAK,CAAC,yBAAyB,CAC7B,MAA2C;QAE3C,IAAI,CAAC,MAAM,CAAC,eAAe;YAAE,OAAO;QACpC,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,MAAM,CAAC,UAAU;YAAE,OAAO;QAC9B,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,yBAAyB,CAC7B,MAA2C;QAE3C,IAAI,CAAC,MAAM,CAAC,eAAe;YAAE,OAAO;QACpC,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,6BAA6B,CACjC,MAA+C;QAE/C,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,SAAS,GACb,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC;eAClD,MAAM,CAAC,SAAS,CAAC,UAAU;eAC3B,MAAM,CAAC,SAAS,CAAC,SAAS;eAC1B,0BAA0B,CAAC;QAEhC,MAAM,EAAE,GAAG,gBAAgB,CAAC;YAC1B,eAAe,EAAE,MAAM,CAAC,KAAK,CAAC,eAAe;YAC7C,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ;SACrC,CAAC,CAAC;QACH,IAAI,EAAE,EAAE,CAAC;YACP,MAAM,qBAAqB,CAAC,MAAM,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC;QACrD,CAAC;QAED,OAAO;YACL,GAAG,EAAE,SAAS;YACd,QAAQ,EAAE;gBACR,QAAQ,EAAE,SAAS;gBACnB,SAAS;aACV;SACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,oBAAoB,CACxB,MAAsC;QAEtC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC;YAClC,OAAO;gBACL,QAAQ,EAAE,CAAC;gBACX,MAAM,EAAE,IAAI;gBACZ,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAE,EAAE;gBACV,MAAM,EAAE,+CAA+C;aACxD,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,EAAE,GAAG,gBAAgB,CAAC;YAC1B,eAAe,EAAE,MAAM,CAAC,KAAK,CAAC,eAAe;YAC7C,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ;SACrC,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,OAAO;gBACL,QAAQ,EAAE,CAAC;gBACX,MAAM,EAAE,IAAI;gBACZ,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAE,EAAE;gBACV,MAAM,EAAE,iDAAiD;aAC1D,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,qBAAqB,CAAC;YACpC,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE;YACvB,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,SAAS;YACrF,GAAG,EAAE,MAAM,CAAC,GAAG;SAChB,CAAC,CAAC;QACH,qEAAqE;QACrE,2EAA2E;QAC3E,qEAAqE;QACrE,yEAAyE;QACzE,sEAAsE;QACtE,qEAAqE;QACrE,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,MAAM,EACN,EAAE,EACF,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,EAC9B,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,EAAE,CACzE,CAAC;QAEF,OAAO;YACL,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EACJ,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC;gBACvC,CAAC,CAAC,gBAAgB,CAAC,qBAAqB,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC;gBAC1D,CAAC,CAAC,MAAM,CAAC,MAAM;YACnB,QAAQ,EAAE;gBACR,QAAQ,EAAE,SAAS;gBACnB,MAAM,EAAE,EAAE,CAAC,IAAI;gBACf,OAAO,EAAE,EAAE,CAAC,OAAO;aACpB;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
|
package/dist/worker.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,eAAe,MAAM,CAAC"}
|
package/dist/worker.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AACjE,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,eAAe,MAAM,CAAC;AACtB,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tickernelz/paperclip-pro-plugin-exe-dev",
|
|
3
|
+
"version": "2026.925.0",
|
|
4
|
+
"description": "exe.dev sandbox provider plugin for Paperclip environments",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://github.com/tickernelz/paperclip-pro",
|
|
7
|
+
"bugs": {
|
|
8
|
+
"url": "https://github.com/tickernelz/paperclip-pro/issues"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/tickernelz/paperclip-pro",
|
|
13
|
+
"directory": "packages/plugins/sandbox-providers/exe-dev"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"main": "./dist/index.js",
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"paperclipPlugin": {
|
|
31
|
+
"manifest": "./dist/manifest.js",
|
|
32
|
+
"worker": "./dist/worker.js"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"paperclip",
|
|
36
|
+
"plugin",
|
|
37
|
+
"sandbox",
|
|
38
|
+
"exe.dev"
|
|
39
|
+
],
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@tickernelz/paperclip-pro-plugin-sdk": "2026.925.0"
|
|
42
|
+
}
|
|
43
|
+
}
|