@sellable/install 0.1.358 → 0.1.359-phase111.20260720052618
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/bin/sellable-install.mjs +0 -2
- package/package.json +2 -11
- package/skill-templates/refill-sends-evergreen.md +5 -0
- package/skill-templates/refill-sends-v2.md +23 -1
- package/skill-templates/refill-sends.md +14 -1
- package/bin/sellable-agent-egress-proxy.mjs +0 -31
- package/bin/sellable-agent-host-bootstrap.mjs +0 -26
- package/bin/sellable-agent-host-worker.mjs +0 -9
- package/bin/sellable-agent-runtime-helper.mjs +0 -37
- package/bin/sellable-agent-runtime-launcher.mjs +0 -151
- package/bin/sellable-agent-runtime-probe.mjs +0 -163
- package/bin/sellable-agent-sandbox-init.mjs +0 -93
- package/container/Dockerfile +0 -37
- package/container/README.md +0 -15
- package/container/compose.yaml +0 -22
- package/container/entrypoint.sh +0 -13
- package/lib/sellable-agent/containment-contract.mjs +0 -472
- package/lib/sellable-agent/external-runtime-builder.mjs +0 -272
- package/lib/sellable-agent/hermes-bridge.mjs +0 -497
- package/lib/sellable-agent/host-bootstrap.mjs +0 -458
- package/lib/sellable-agent/host-worker.mjs +0 -2067
- package/lib/sellable-agent/profile-materializer.mjs +0 -1410
- package/lib/sellable-agent/provisioning-adapter.mjs +0 -992
- package/lib/sellable-agent/runtime-boundary.mjs +0 -635
- package/lib/sellable-agent/runtime-egress-proxy.mjs +0 -241
- package/lib/sellable-agent/runtime-helper.mjs +0 -1428
- package/lib/sellable-agent/runtime-reconciler.mjs +0 -683
- package/lib/sellable-agent/service-installer.mjs +0 -441
- package/services/s6/sellable-agent-egress-proxy/run +0 -15
- package/services/s6/sellable-agent-host-worker/run +0 -4
- package/services/s6/sellable-agent-runtime/run +0 -19
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
chmodSync,
|
|
4
|
-
chownSync,
|
|
5
|
-
existsSync,
|
|
6
|
-
lstatSync,
|
|
7
|
-
mkdirSync,
|
|
8
|
-
readFileSync,
|
|
9
|
-
readdirSync,
|
|
10
|
-
realpathSync,
|
|
11
|
-
renameSync,
|
|
12
|
-
rmSync,
|
|
13
|
-
writeFileSync,
|
|
14
|
-
} from "node:fs";
|
|
15
|
-
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
16
|
-
import {
|
|
17
|
-
HERMES_AGENT_BRIDGE_CONTRACT,
|
|
18
|
-
installHermesAgentBridge,
|
|
19
|
-
verifyHermesAgentBridge,
|
|
20
|
-
} from "./hermes-bridge.mjs";
|
|
21
|
-
import {
|
|
22
|
-
EXTERNAL_HERMES_ENTRYPOINT,
|
|
23
|
-
EXTERNAL_MCP_ENTRYPOINT,
|
|
24
|
-
EXTERNAL_RUNTIME_CLOSURE_ROOT,
|
|
25
|
-
EXTERNAL_RUNTIME_MANIFEST_PATH,
|
|
26
|
-
observeExternalRuntimeClosure,
|
|
27
|
-
} from "./runtime-helper.mjs";
|
|
28
|
-
|
|
29
|
-
const MANIFEST_VERSION = "sellable-agent-external-runtime-closure/v1";
|
|
30
|
-
const MCP_PACKAGE = "@sellable/mcp";
|
|
31
|
-
const MCP_VERSION = "0.1.619";
|
|
32
|
-
const SAFE_COMPONENT = /^[A-Za-z0-9@._+-]+$/;
|
|
33
|
-
const HERMES_EXCLUDES = new Set([".git", ".playwright", "node_modules"]);
|
|
34
|
-
|
|
35
|
-
const sha256 = (value) => createHash("sha256").update(value).digest("hex");
|
|
36
|
-
|
|
37
|
-
function mapped(pathRoot, absolutePath) {
|
|
38
|
-
const root = realpathSync(resolve(pathRoot));
|
|
39
|
-
const target = root === "/"
|
|
40
|
-
? resolve(absolutePath)
|
|
41
|
-
: join(root, absolutePath.replace(/^\/+/, ""));
|
|
42
|
-
const confined = relative(root, target);
|
|
43
|
-
if (!isAbsolute(absolutePath) || confined.startsWith("..") || isAbsolute(confined)) {
|
|
44
|
-
throw new Error("external runtime build target rejected");
|
|
45
|
-
}
|
|
46
|
-
return target;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function trustedDirectory(pathValue) {
|
|
50
|
-
const resolved = realpathSync(resolve(pathValue));
|
|
51
|
-
const link = lstatSync(resolved);
|
|
52
|
-
if (
|
|
53
|
-
link.isSymbolicLink() || !link.isDirectory() || (link.mode & 0o022) !== 0
|
|
54
|
-
) throw new Error("external runtime source rejected");
|
|
55
|
-
return resolved;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function copyFile(source, target, transform = (bytes) => bytes) {
|
|
59
|
-
const link = lstatSync(source);
|
|
60
|
-
if (!link.isFile() || link.isSymbolicLink()) throw new Error("external runtime source file rejected");
|
|
61
|
-
const bytes = transform(readFileSync(source));
|
|
62
|
-
const mode = (link.mode & 0o111) === 0 ? 0o644 : 0o755;
|
|
63
|
-
writeFileSync(target, bytes, { flag: "wx", mode });
|
|
64
|
-
chmodSync(target, mode);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function hermesScript(bytes) {
|
|
68
|
-
const source = bytes.toString("utf8");
|
|
69
|
-
const newline = source.indexOf("\n");
|
|
70
|
-
const first = newline < 0 ? source : source.slice(0, newline);
|
|
71
|
-
if (!first.startsWith("#!/opt/hermes/.venv/bin/python")) return bytes;
|
|
72
|
-
const rest = newline < 0 ? "" : source.slice(newline);
|
|
73
|
-
return Buffer.from(`#!${EXTERNAL_RUNTIME_CLOSURE_ROOT}/hermes/venv/bin/python3${rest}`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function copyTree({ sourceRoot, targetRoot, kind, logicalRoot = "" }) {
|
|
77
|
-
for (const name of readdirSync(sourceRoot).sort()) {
|
|
78
|
-
if (!SAFE_COMPONENT.test(name)) throw new Error("external runtime source name rejected");
|
|
79
|
-
if (kind === "hermes" && HERMES_EXCLUDES.has(name)) continue;
|
|
80
|
-
if (kind === "mcp-dependencies" && [".bin", ".package-lock.json"].includes(name)) continue;
|
|
81
|
-
if (kind === "mcp-dependencies" && logicalRoot === "" && name === "@sellable") {
|
|
82
|
-
const scopedSource = join(sourceRoot, name);
|
|
83
|
-
const scopedTarget = join(targetRoot, name);
|
|
84
|
-
mkdirSync(scopedTarget, { mode: 0o755 });
|
|
85
|
-
for (const scopedName of readdirSync(scopedSource).sort()) {
|
|
86
|
-
if (scopedName === "mcp" || scopedName === "install") continue;
|
|
87
|
-
if (!SAFE_COMPONENT.test(scopedName)) throw new Error("external runtime source name rejected");
|
|
88
|
-
const nestedSource = join(scopedSource, scopedName);
|
|
89
|
-
const nestedTarget = join(scopedTarget, scopedName);
|
|
90
|
-
const nested = lstatSync(nestedSource);
|
|
91
|
-
if (!nested.isDirectory() || nested.isSymbolicLink()) {
|
|
92
|
-
throw new Error("external runtime dependency rejected");
|
|
93
|
-
}
|
|
94
|
-
mkdirSync(nestedTarget, { mode: 0o755 });
|
|
95
|
-
copyTree({
|
|
96
|
-
sourceRoot: nestedSource,
|
|
97
|
-
targetRoot: nestedTarget,
|
|
98
|
-
kind,
|
|
99
|
-
logicalRoot: `${name}/${scopedName}`,
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
if (readdirSync(scopedTarget).length === 0) rmSync(scopedTarget, { recursive: true });
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
const outputName = kind === "hermes" && logicalRoot === "" && name === ".venv"
|
|
106
|
-
? "venv"
|
|
107
|
-
: name;
|
|
108
|
-
const source = join(sourceRoot, name);
|
|
109
|
-
const target = join(targetRoot, outputName);
|
|
110
|
-
const logicalPath = logicalRoot ? `${logicalRoot}/${outputName}` : outputName;
|
|
111
|
-
const link = lstatSync(source);
|
|
112
|
-
if (link.isSymbolicLink()) {
|
|
113
|
-
if (kind !== "hermes") throw new Error("external runtime dependency symlink rejected");
|
|
114
|
-
if (logicalPath === "venv/lib64") continue;
|
|
115
|
-
if (!["venv/bin/python", "venv/bin/python3", "venv/bin/python3.13"].includes(logicalPath)) {
|
|
116
|
-
throw new Error("external Hermes symlink rejected");
|
|
117
|
-
}
|
|
118
|
-
copyFile(realpathSync(source), target);
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
if (link.isDirectory()) {
|
|
122
|
-
mkdirSync(target, { mode: 0o755 });
|
|
123
|
-
copyTree({ sourceRoot: source, targetRoot: target, kind, logicalRoot: logicalPath });
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
if (!link.isFile()) throw new Error("external runtime special source rejected");
|
|
127
|
-
copyFile(source, target, kind === "hermes" && logicalPath.startsWith("venv/bin/")
|
|
128
|
-
? hermesScript
|
|
129
|
-
: undefined);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function normalizeTree(root, ownerUid, ownerGid) {
|
|
134
|
-
const directories = [];
|
|
135
|
-
const files = [];
|
|
136
|
-
const visit = (directory, logicalDirectory) => {
|
|
137
|
-
for (const name of readdirSync(directory).sort()) {
|
|
138
|
-
const pathValue = join(directory, name);
|
|
139
|
-
const logicalPath = logicalDirectory ? `${logicalDirectory}/${name}` : name;
|
|
140
|
-
const link = lstatSync(pathValue);
|
|
141
|
-
if (link.isSymbolicLink()) throw new Error("external runtime output symlink rejected");
|
|
142
|
-
if (link.isDirectory()) {
|
|
143
|
-
visit(pathValue, logicalPath);
|
|
144
|
-
chmodSync(pathValue, 0o555);
|
|
145
|
-
chownSync(pathValue, ownerUid, ownerGid);
|
|
146
|
-
directories.push({ path: logicalPath, mode: 0o555 });
|
|
147
|
-
} else if (link.isFile()) {
|
|
148
|
-
const mode = (link.mode & 0o111) === 0 ? 0o444 : 0o555;
|
|
149
|
-
chmodSync(pathValue, mode);
|
|
150
|
-
chownSync(pathValue, ownerUid, ownerGid);
|
|
151
|
-
files.push({ path: logicalPath, mode, digest: sha256(readFileSync(pathValue)) });
|
|
152
|
-
} else {
|
|
153
|
-
throw new Error("external runtime output special file rejected");
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
visit(root, "");
|
|
158
|
-
chmodSync(root, 0o555);
|
|
159
|
-
chownSync(root, ownerUid, ownerGid);
|
|
160
|
-
return {
|
|
161
|
-
directories: directories.sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0),
|
|
162
|
-
files: files.sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0),
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function packageIdentity(root) {
|
|
167
|
-
const parsed = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
168
|
-
if (parsed?.name !== MCP_PACKAGE || parsed.version !== MCP_VERSION) {
|
|
169
|
-
throw new Error("external MCP package identity rejected");
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function bridgeContract(input) {
|
|
174
|
-
return input.disposableFixture === true && input.hermesBridgeContract
|
|
175
|
-
? input.hermesBridgeContract
|
|
176
|
-
: HERMES_AGENT_BRIDGE_CONTRACT;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function currentClosure(input, pathRoot, ownerUid, ownerGid) {
|
|
180
|
-
const observed = observeExternalRuntimeClosure({
|
|
181
|
-
pathRoot,
|
|
182
|
-
manifestPath: EXTERNAL_RUNTIME_MANIFEST_PATH,
|
|
183
|
-
expectedClosureRoot: EXTERNAL_RUNTIME_CLOSURE_ROOT,
|
|
184
|
-
trustRoot: dirname(EXTERNAL_RUNTIME_CLOSURE_ROOT),
|
|
185
|
-
ownerUid,
|
|
186
|
-
ownerGid,
|
|
187
|
-
expectedEntrypoints: { mcp: EXTERNAL_MCP_ENTRYPOINT, hermes: EXTERNAL_HERMES_ENTRYPOINT },
|
|
188
|
-
});
|
|
189
|
-
const root = mapped(pathRoot, EXTERNAL_RUNTIME_CLOSURE_ROOT);
|
|
190
|
-
packageIdentity(join(root, "mcp"));
|
|
191
|
-
verifyHermesAgentBridge({
|
|
192
|
-
sourceRoot: join(root, "hermes"),
|
|
193
|
-
contract: bridgeContract(input),
|
|
194
|
-
});
|
|
195
|
-
return { ...observed, reused: true };
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export function buildExternalRuntimeClosure(input = {}) {
|
|
199
|
-
const pathRoot = resolve(input.pathRoot ?? "/");
|
|
200
|
-
if (!isAbsolute(pathRoot) || !existsSync(pathRoot)) throw new Error("external runtime path root rejected");
|
|
201
|
-
if (pathRoot !== "/" && input.disposableFixture !== true) {
|
|
202
|
-
throw new Error("external runtime live root rejected");
|
|
203
|
-
}
|
|
204
|
-
const ownerUid = input.ownerUid ?? process.getuid?.() ?? 0;
|
|
205
|
-
const ownerGid = input.ownerGid ?? process.getgid?.() ?? 0;
|
|
206
|
-
if (!Number.isSafeInteger(ownerUid) || ownerUid < 0 || !Number.isSafeInteger(ownerGid) || ownerGid < 0) {
|
|
207
|
-
throw new Error("external runtime owner rejected");
|
|
208
|
-
}
|
|
209
|
-
const mcpPackageRoot = trustedDirectory(input.mcpPackageRoot);
|
|
210
|
-
const mcpNodeModulesRoot = trustedDirectory(input.mcpNodeModulesRoot);
|
|
211
|
-
const hermesSourceRoot = trustedDirectory(input.hermesSourceRoot);
|
|
212
|
-
packageIdentity(mcpPackageRoot);
|
|
213
|
-
const target = mapped(pathRoot, EXTERNAL_RUNTIME_CLOSURE_ROOT);
|
|
214
|
-
if (existsSync(target)) return currentClosure(input, pathRoot, ownerUid, ownerGid);
|
|
215
|
-
|
|
216
|
-
const trustRoot = dirname(target);
|
|
217
|
-
if (!existsSync(trustRoot)) mkdirSync(trustRoot, { recursive: true, mode: 0o755 });
|
|
218
|
-
const staging = join(trustRoot, `.external-runtime-${randomUUID()}`);
|
|
219
|
-
mkdirSync(staging, { mode: 0o755 });
|
|
220
|
-
try {
|
|
221
|
-
const mcpRoot = join(staging, "mcp");
|
|
222
|
-
const dependencyRoot = join(mcpRoot, "node_modules");
|
|
223
|
-
const hermesRoot = join(staging, "hermes");
|
|
224
|
-
mkdirSync(mcpRoot, { mode: 0o755 });
|
|
225
|
-
mkdirSync(dependencyRoot, { mode: 0o755 });
|
|
226
|
-
mkdirSync(hermesRoot, { mode: 0o755 });
|
|
227
|
-
copyTree({ sourceRoot: mcpPackageRoot, targetRoot: mcpRoot, kind: "mcp" });
|
|
228
|
-
copyTree({ sourceRoot: mcpNodeModulesRoot, targetRoot: dependencyRoot, kind: "mcp-dependencies" });
|
|
229
|
-
mkdirSync(join(mcpRoot, "bin"), { mode: 0o755 });
|
|
230
|
-
writeFileSync(
|
|
231
|
-
join(mcpRoot, "bin", "sellable-mcp"),
|
|
232
|
-
`#!/bin/sh\nexec /usr/bin/node '${EXTERNAL_RUNTIME_CLOSURE_ROOT}/mcp/dist/index.js' "$@"\n`,
|
|
233
|
-
{ mode: 0o755, flag: "wx" },
|
|
234
|
-
);
|
|
235
|
-
copyTree({ sourceRoot: hermesSourceRoot, targetRoot: hermesRoot, kind: "hermes" });
|
|
236
|
-
installHermesAgentBridge({ sourceRoot: hermesRoot, contract: bridgeContract(input) });
|
|
237
|
-
|
|
238
|
-
const mcp = normalizeTree(mcpRoot, ownerUid, ownerGid);
|
|
239
|
-
const hermes = normalizeTree(hermesRoot, ownerUid, ownerGid);
|
|
240
|
-
const manifest = {
|
|
241
|
-
version: MANIFEST_VERSION,
|
|
242
|
-
closureRoot: EXTERNAL_RUNTIME_CLOSURE_ROOT,
|
|
243
|
-
roots: [
|
|
244
|
-
{ kind: "mcp", entrypoint: "bin/sellable-mcp", rootMode: 0o555, ...mcp },
|
|
245
|
-
{ kind: "hermes", entrypoint: "venv/bin/hermes", rootMode: 0o555, ...hermes },
|
|
246
|
-
],
|
|
247
|
-
};
|
|
248
|
-
writeFileSync(join(staging, "manifest.json"), `${JSON.stringify(manifest, null, 2)}\n`, {
|
|
249
|
-
mode: 0o444,
|
|
250
|
-
flag: "wx",
|
|
251
|
-
});
|
|
252
|
-
chmodSync(join(staging, "manifest.json"), 0o444);
|
|
253
|
-
chownSync(join(staging, "manifest.json"), ownerUid, ownerGid);
|
|
254
|
-
chownSync(staging, ownerUid, ownerGid);
|
|
255
|
-
renameSync(staging, target);
|
|
256
|
-
chmodSync(target, 0o555);
|
|
257
|
-
return { ...currentClosure(input, pathRoot, ownerUid, ownerGid), reused: false };
|
|
258
|
-
} catch (error) {
|
|
259
|
-
if (existsSync(staging)) {
|
|
260
|
-
const makeWritable = (pathValue) => {
|
|
261
|
-
const link = lstatSync(pathValue);
|
|
262
|
-
if (link.isDirectory()) {
|
|
263
|
-
chmodSync(pathValue, 0o755);
|
|
264
|
-
for (const name of readdirSync(pathValue)) makeWritable(join(pathValue, name));
|
|
265
|
-
} else if (link.isFile()) chmodSync(pathValue, 0o644);
|
|
266
|
-
};
|
|
267
|
-
makeWritable(staging);
|
|
268
|
-
rmSync(staging, { recursive: true });
|
|
269
|
-
}
|
|
270
|
-
throw error;
|
|
271
|
-
}
|
|
272
|
-
}
|