@sema-agent/server 7.140.0 → 7.141.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/MIGRATION.md +290 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +75 -13
- package/dist/approval-batch-census.d.ts +27 -0
- package/dist/approval-batch-census.js +27 -0
- package/dist/approval-card.d.ts +31 -16
- package/dist/approval-card.js +6 -3
- package/dist/approval.d.ts +15 -0
- package/dist/approval.js +10 -0
- package/dist/audit.d.ts +4 -2
- package/dist/audit.js +2 -2
- package/dist/boot/device-lane.d.ts +11 -0
- package/dist/boot/device-lane.js +16 -0
- package/dist/boot/engine-lease.d.ts +24 -3
- package/dist/boot/engine-lease.js +9 -2
- package/dist/boot/execution-env.js +8 -4
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/memory-consolidation.d.ts +1 -1
- package/dist/boot/memory-consolidation.js +1 -1
- package/dist/boot/reapers.d.ts +2 -2
- package/dist/boot/resolve-spec.js +7 -4
- package/dist/boot/session-faces.d.ts +1 -1
- package/dist/boot/session-faces.js +4 -3
- package/dist/boot/shutdown.js +5 -0
- package/dist/boot/stage-05-execution-env.js +3 -1
- package/dist/boot/stage-06-runners.d.ts +0 -2
- package/dist/boot/stage-06-runners.js +1 -1
- package/dist/boot/stage-07-capability-layer.d.ts +0 -1
- package/dist/boot/stage-07-capability-layer.js +8 -10
- package/dist/boot/stage-08-reapers.d.ts +0 -1
- package/dist/boot/stage-09-leader.d.ts +0 -1
- package/dist/boot/stage-10-http-server.d.ts +0 -1
- package/dist/boot/stage-10-http-server.js +1 -0
- package/dist/boot/stores.js +10 -4
- package/dist/boot/web-admin.js +1 -0
- package/dist/capabilities/scenarios.d.ts +1 -1
- package/dist/capability-facts.d.ts +9 -0
- package/dist/capability-facts.js +9 -0
- package/dist/card-void.d.ts +38 -0
- package/dist/card-void.js +23 -0
- package/dist/config-catalog.js +11 -8
- package/dist/config-provider.d.ts +13 -13
- package/dist/config-provider.js +19 -33
- package/dist/config-types.d.ts +26 -8
- package/dist/config.js +55 -46
- package/dist/delegated-session-owner.d.ts +21 -19
- package/dist/delegated-session-owner.js +1 -1
- package/dist/device-store.d.ts +7 -0
- package/dist/device-store.js +3 -0
- package/dist/execution-config-root.d.ts +22 -0
- package/dist/execution-config-root.js +35 -0
- package/dist/execution-lane-caps.d.ts +49 -2
- package/dist/execution-lane-caps.js +90 -13
- package/dist/execution-placement.d.ts +3 -0
- package/dist/execution-placement.js +7 -0
- package/dist/fleet/drain-entry.d.ts +3 -0
- package/dist/hosted-posture.d.ts +8 -0
- package/dist/hosted-posture.js +4 -0
- package/dist/http/admission.js +3 -3
- package/dist/http/caller-trust.d.ts +3 -2
- package/dist/http/caller-trust.js +2 -1
- package/dist/http/dispatch.js +4 -0
- package/dist/http/live-frame.d.ts +24 -0
- package/dist/http/live-frame.js +16 -0
- package/dist/http/resume-legs.js +37 -20
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/approvals-assistant.js +1 -0
- package/dist/http/routes/capabilities.js +5 -4
- package/dist/http/routes/diagnostics.d.ts +0 -19
- package/dist/http/routes/diagnostics.js +16 -2
- package/dist/http/routes/memory-bundle.d.ts +2 -2
- package/dist/http/routes/memory-bundle.js +1 -1
- package/dist/http/routes/memory-compliance.js +1 -1
- package/dist/http/routes/memory-policy.js +2 -2
- package/dist/http/routes/run-permission-mode.d.ts +75 -0
- package/dist/http/routes/run-permission-mode.js +170 -0
- package/dist/http/routes/session-sync.d.ts +3 -6
- package/dist/http/routes/session-sync.js +7 -2
- package/dist/http/routes/sessions.js +5 -4
- package/dist/http/routes/tasks.js +63 -66
- package/dist/http/run-read-face.js +3 -3
- package/dist/http/send.d.ts +1 -1
- package/dist/http/send.js +2 -2
- package/dist/http/server.d.ts +9 -2
- package/dist/http/sse-log.d.ts +3 -8
- package/dist/http/stored-body-replay.d.ts +3 -3
- package/dist/http/stored-body-replay.js +3 -1
- package/dist/instruction-source-notice.d.ts +7 -0
- package/dist/instruction-source-notice.js +6 -6
- package/dist/mcp-assertion-header.d.ts +4 -0
- package/dist/mcp-assertion-header.js +5 -0
- package/dist/memory-posture.d.ts +1 -1
- package/dist/memory-scope.d.ts +4 -4
- package/dist/memory-scope.js +1 -1
- package/dist/memory-sync-client.d.ts +14 -2
- package/dist/memory-sync-client.js +80 -18
- package/dist/observability/fail-open.d.ts +30 -2
- package/dist/observability/fail-open.js +30 -2
- package/dist/observability/metrics.js +0 -1
- package/dist/observability/run-terminal.d.ts +6 -2
- package/dist/observability/run-terminal.js +25 -26
- package/dist/observability/secret-env-scrub.d.ts +20 -1
- package/dist/observability/secret-env-scrub.js +14 -0
- package/dist/orchestration/workflow-completion-inbox.d.ts +5 -2
- package/dist/orchestration/workflow-completion-inbox.js +13 -5
- package/dist/orchestration/workflow-notify-journal.d.ts +5 -3
- package/dist/orchestration/workflow-notify-journal.js +2 -1
- package/dist/permission-mode-admission.d.ts +68 -0
- package/dist/permission-mode-admission.js +23 -0
- package/dist/permission-rule-list.d.ts +55 -6
- package/dist/permission-rule-list.js +52 -5
- package/dist/plugins/caching-session-store.d.ts +6 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +65 -17
- package/dist/plugins/checkpoint-store-sql.js +74 -3
- package/dist/plugins/device-store-sql.d.ts +5 -2
- package/dist/plugins/device-store-sql.js +4 -1
- package/dist/plugins/execution-placement-sql.d.ts +11 -1
- package/dist/plugins/execution-placement-sql.js +12 -1
- package/dist/plugins/file-run-store.d.ts +2 -2
- package/dist/plugins/file-run-store.js +1 -1
- package/dist/plugins/fork-routing-session-store.d.ts +10 -32
- package/dist/plugins/fork-routing-session-store.js +2 -61
- package/dist/plugins/k8s-exec-protocol.d.ts +4 -1
- package/dist/plugins/k8s-exec-protocol.js +6 -1
- package/dist/plugins/local-checkpoint-store.d.ts +10 -1
- package/dist/plugins/local-checkpoint-store.js +22 -0
- package/dist/plugins/local-session-store.d.ts +227 -35
- package/dist/plugins/local-session-store.js +518 -37
- package/dist/plugins/local-session-window.d.ts +17 -3
- package/dist/plugins/local-session-window.js +7 -13
- package/dist/plugins/memory-run-store.d.ts +2 -2
- package/dist/plugins/memory-run-store.js +1 -1
- package/dist/plugins/one-time-migrations.d.ts +42 -2
- package/dist/plugins/one-time-migrations.js +65 -3
- package/dist/plugins/pg-pool.js +3 -2
- package/dist/plugins/pg-session-storage.d.ts +2 -0
- package/dist/plugins/pg-session-storage.js +3 -2
- package/dist/plugins/remote-env-e2b.d.ts +24 -3
- package/dist/plugins/remote-env-e2b.js +131 -18
- package/dist/plugins/remote-env-k8s.d.ts +20 -1
- package/dist/plugins/remote-env-k8s.js +148 -25
- package/dist/plugins/remote-env-local-docker.d.ts +25 -11
- package/dist/plugins/remote-env-local-docker.js +87 -21
- package/dist/plugins/run-store-sql.d.ts +3 -3
- package/dist/plugins/run-store-sql.js +4 -3
- package/dist/plugins/sandbox-read-floor.d.ts +273 -0
- package/dist/plugins/sandbox-read-floor.js +608 -0
- package/dist/plugins/session-ownership.d.ts +2 -1
- package/dist/plugins/session-placement.d.ts +17 -4
- package/dist/plugins/session-placement.js +2 -1
- package/dist/plugins/session-store.d.ts +18 -20
- package/dist/plugins/session-store.js +4 -12
- package/dist/plugins/store-backend.d.ts +31 -0
- package/dist/plugins/store-backend.js +21 -4
- package/dist/plugins/store-contracts.d.ts +9 -2
- package/dist/plugins/tidb-pool.js +2 -1
- package/dist/plugins/tidb-session-store.d.ts +4 -1
- package/dist/plugins/tidb-session-store.js +3 -2
- package/dist/run-cancel-context.d.ts +34 -0
- package/dist/run-cancel-context.js +7 -0
- package/dist/runs.d.ts +39 -12
- package/dist/runs.js +68 -53
- package/dist/security.d.ts +2 -2
- package/dist/server-secret-env.d.ts +2 -1
- package/dist/server-secret-env.js +2 -4
- package/dist/session-error-wire.d.ts +22 -4
- package/dist/session-error-wire.js +16 -0
- package/dist/session-incarnation.d.ts +9 -3
- package/dist/session-sync-kernel.d.ts +42 -1
- package/dist/session-sync-kernel.js +17 -0
- package/dist/session-sync.js +16 -4
- package/dist/sql-engine-coordinates.d.ts +49 -0
- package/dist/sql-engine-coordinates.js +27 -0
- package/dist/standing-answer-grant.d.ts +31 -2
- package/dist/standing-answer-grant.js +14 -2
- package/dist/store-posture.d.ts +1 -1
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-mcp.d.ts +1 -1
- package/dist/task-settings.d.ts +52 -25
- package/dist/task-settings.js +91 -28
- package/dist/terminal.d.ts +77 -20
- package/dist/terminal.js +66 -20
- package/dist/trace/core-keyset-guard.d.ts +79 -2
- package/dist/trace/exit-seat.d.ts +7 -0
- package/dist/trace/exit-seat.js +1 -0
- package/dist/trace/model-segment.d.ts +2 -2
- package/dist/trace/redact.js +323 -90
- package/dist/trace/self-minted-wire.d.ts +168 -2
- package/dist/trace/self-minted-wire.js +63 -0
- package/dist/verifier-pause-card.d.ts +8 -0
- package/dist/verifier-pause-card.js +19 -0
- package/dist/web-admin-client/apply-effective.d.ts +5 -7
- package/dist/web-admin-client/apply-effective.js +2 -2
- package/dist/web-admin-client/candidate-gate.d.ts +1 -1
- package/dist/web-admin-client/read-warnings.d.ts +2 -2
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -2
- package/package.json +2 -2
- package/wire-changes/server@7.141.0.json +367 -0
|
@@ -2,6 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import { Sandbox, CommandExitError, FileType } from "e2b";
|
|
3
3
|
import { FileError, ExecutionError, RemoteExecutionError, RollingTailBuffer, markTruncated, } from "@sema-agent/core";
|
|
4
4
|
import { capabilitiesFor } from "../execution-lane-caps.js";
|
|
5
|
+
import { ADAPTER_START, BOOTSTRAP_START, createSandboxReadFloor, e2bFloorCommand, engineStart, } from "./sandbox-read-floor.js";
|
|
5
6
|
import { LANE_HOME_PROBE_COMMAND, LaneHomeSeat } from "../lane-home-probe.js";
|
|
6
7
|
import { fileErrorFromExec } from "./remote-env-file-error.js";
|
|
7
8
|
import { appendFileStaged, rewriteAppend, numEnvOr, runSymlinkChain, shellQuote, writeFileStaged } from "./remote-shell.js";
|
|
@@ -52,8 +53,90 @@ export class RemoteContainerExecutionEnv {
|
|
|
52
53
|
this.cwd = this.cfg.mountPath;
|
|
53
54
|
this.homeSeat = new LaneHomeSeat(PROVIDER, config);
|
|
54
55
|
this.sandboxApi = deps.sandboxApi ?? Sandbox;
|
|
56
|
+
this.floor = deps.readFloor ?? createSandboxReadFloor({ lane: PROVIDER, knob: config.sandboxReadFloor, ...(config.logger !== undefined ? { logger: config.logger } : {}) });
|
|
57
|
+
this.capabilities = capabilitiesFor({ remoteExec: { provider: PROVIDER }, sandboxReadFloor: config.sandboxReadFloor });
|
|
58
|
+
}
|
|
59
|
+
capabilities;
|
|
60
|
+
floor;
|
|
61
|
+
startIn(start, command, envs) {
|
|
62
|
+
const launch = this.floor.wrap(start);
|
|
63
|
+
return launch.ok ? ok(e2bFloorCommand(launch.value, command, envs)) : launch;
|
|
64
|
+
}
|
|
65
|
+
runIn(sbx, s, opts = {}) {
|
|
66
|
+
const { background, ...rest } = opts;
|
|
67
|
+
const o = { ...rest, ...(s.user !== undefined ? { user: s.user } : {}), ...(s.envs !== undefined ? { envs: s.envs } : {}) };
|
|
68
|
+
return background ? sbx.commands.run(s.cmd, { ...o, background: true }) : sbx.commands.run(s.cmd, o);
|
|
69
|
+
}
|
|
70
|
+
floorTransport(sbx) {
|
|
71
|
+
const bootstrap = async (command) => {
|
|
72
|
+
const s = this.startIn(BOOTSTRAP_START, command, undefined);
|
|
73
|
+
if (!s.ok)
|
|
74
|
+
return { ok: false, error: s.error.message };
|
|
75
|
+
try {
|
|
76
|
+
const r = await this.rpc("floor.bootstrap", (signal) => this.runIn(sbx, s.value, { signal, timeoutMs: this.cfg.rpcTimeoutMs }));
|
|
77
|
+
return { ok: true, exitCode: r.exitCode, stdout: r.stdout, stderr: r.stderr };
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
if (e instanceof CommandExitError)
|
|
81
|
+
return { ok: true, exitCode: e.exitCode, stdout: e.stdout, stderr: e.stderr };
|
|
82
|
+
return { ok: false, error: errMsg(e) };
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
bootstrap,
|
|
87
|
+
place: async (dest, bytes) => {
|
|
88
|
+
const dir = path.posix.dirname(dest);
|
|
89
|
+
const tmp = `${dest}.${Math.random().toString(16).slice(2, 10)}`;
|
|
90
|
+
const mk = await bootstrap(`umask 022 && mkdir -p ${shellQuote(dir)}`);
|
|
91
|
+
if (!mk.ok || mk.exitCode !== 0)
|
|
92
|
+
return { ok: false, error: mk.ok ? mk.stderr.trim() || `exit ${mk.exitCode}` : mk.error };
|
|
93
|
+
try {
|
|
94
|
+
const ab = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
95
|
+
await this.rpc("files.write", (signal) => sbx.files.write(tmp, ab, { user: "root", signal }), undefined, this.cfg.dataTimeoutMs);
|
|
96
|
+
}
|
|
97
|
+
catch (e) {
|
|
98
|
+
return { ok: false, error: errMsg(e) };
|
|
99
|
+
}
|
|
100
|
+
const mv = await bootstrap(`chmod 0755 ${shellQuote(tmp)} && mv -f ${shellQuote(tmp)} ${shellQuote(dest)}`);
|
|
101
|
+
return mv.ok && mv.exitCode === 0 ? { ok: true } : { ok: false, error: mv.ok ? mv.stderr.trim() || `exit ${mv.exitCode}` : mv.error };
|
|
102
|
+
},
|
|
103
|
+
openRelay: (identity, command, events) => {
|
|
104
|
+
let handle;
|
|
105
|
+
let closed = false;
|
|
106
|
+
const pending = [];
|
|
107
|
+
const user = (() => {
|
|
108
|
+
switch (identity) {
|
|
109
|
+
case "root":
|
|
110
|
+
return { user: "root" };
|
|
111
|
+
case "exec-user":
|
|
112
|
+
return {};
|
|
113
|
+
}
|
|
114
|
+
})();
|
|
115
|
+
sbx.commands
|
|
116
|
+
.run(command, { background: true, stdin: true, timeoutMs: 0, ...user, onStdout: (d) => events.data(d) })
|
|
117
|
+
.then((h) => {
|
|
118
|
+
handle = h;
|
|
119
|
+
if (closed)
|
|
120
|
+
return void h.kill().catch(() => { });
|
|
121
|
+
for (const line of pending.splice(0))
|
|
122
|
+
void h.sendStdin(line).catch(() => { });
|
|
123
|
+
h.wait().then(() => events.closed("relay exited"), (e) => events.closed(`relay exited: ${errMsg(e)}`));
|
|
124
|
+
}, (e) => events.closed(`relay start failed: ${errMsg(e)}`));
|
|
125
|
+
return {
|
|
126
|
+
send: (line) => {
|
|
127
|
+
if (handle !== undefined)
|
|
128
|
+
void handle.sendStdin(line).catch(() => { });
|
|
129
|
+
else
|
|
130
|
+
pending.push(line);
|
|
131
|
+
},
|
|
132
|
+
close: () => {
|
|
133
|
+
closed = true;
|
|
134
|
+
void handle?.kill().catch(() => { });
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
},
|
|
138
|
+
};
|
|
55
139
|
}
|
|
56
|
-
capabilities = capabilitiesFor({ remoteExec: { provider: "e2b" } });
|
|
57
140
|
workspaceHandle() {
|
|
58
141
|
if (!this.handle) {
|
|
59
142
|
throw new RemoteExecutionError("connect_failed", "workspaceHandle() called before connect()");
|
|
@@ -66,8 +149,12 @@ export class RemoteContainerExecutionEnv {
|
|
|
66
149
|
}
|
|
67
150
|
async startBackground(command) {
|
|
68
151
|
const conn = await this.ensureConnected();
|
|
69
|
-
if (conn.ok)
|
|
70
|
-
|
|
152
|
+
if (!conn.ok)
|
|
153
|
+
return;
|
|
154
|
+
const s = this.startIn(engineStart(undefined), command, undefined);
|
|
155
|
+
if (!s.ok)
|
|
156
|
+
return void this.cfg.logger?.warn?.("remote_env_background_refused", { error: s.error.message });
|
|
157
|
+
await this.runIn(conn.value, s.value, { background: true });
|
|
71
158
|
}
|
|
72
159
|
async connect(config) {
|
|
73
160
|
if (config?.snapshotId) {
|
|
@@ -109,6 +196,11 @@ export class RemoteContainerExecutionEnv {
|
|
|
109
196
|
this.cfg.metrics?.inc("remote_env_connect_total", { provider: PROVIDER, result: "error" });
|
|
110
197
|
return { ok: false, error: home ?? new RemoteExecutionError("connect_failed", "execution env destroyed during connect") };
|
|
111
198
|
}
|
|
199
|
+
await this.floor.attach(this.floorTransport(sbx), { origin: "created", workspaceRoot: this.cfg.mountPath });
|
|
200
|
+
if (this.destroyed) {
|
|
201
|
+
await sbx.kill().catch(() => { });
|
|
202
|
+
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during connect") };
|
|
203
|
+
}
|
|
112
204
|
this.sbx = sbx;
|
|
113
205
|
this.paused = false;
|
|
114
206
|
this.startKeepAlive();
|
|
@@ -180,6 +272,12 @@ export class RemoteContainerExecutionEnv {
|
|
|
180
272
|
await sbx.kill().catch(() => { });
|
|
181
273
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during resume") };
|
|
182
274
|
}
|
|
275
|
+
const restoredRoot = options?.priorHandle?.mountPath ?? this.cfg.mountPath;
|
|
276
|
+
await this.floor.attach(this.floorTransport(sbx), { origin: "resumed", workspaceRoot: restoredRoot });
|
|
277
|
+
if (this.destroyed) {
|
|
278
|
+
await sbx.kill().catch(() => { });
|
|
279
|
+
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during resume") };
|
|
280
|
+
}
|
|
183
281
|
const home = await this.homeVerdict(sbx, options?.abortSignal);
|
|
184
282
|
if (this.destroyed) {
|
|
185
283
|
await sbx.kill().catch(() => { });
|
|
@@ -194,7 +292,6 @@ export class RemoteContainerExecutionEnv {
|
|
|
194
292
|
this.paused = false;
|
|
195
293
|
this.startKeepAlive();
|
|
196
294
|
this.cfg.logger?.info?.("remote_env_resume", { requested: snapshotId, connected: sbx.sandboxId });
|
|
197
|
-
const restoredRoot = options?.priorHandle?.mountPath ?? this.cfg.mountPath;
|
|
198
295
|
this.cwd = restoredRoot;
|
|
199
296
|
this.handle = { sandboxId: sbx.sandboxId, provider: PROVIDER, mountPath: restoredRoot, snapshotId, sessionToken: sbx.sandboxId };
|
|
200
297
|
this.cfg.metrics?.inc("remote_env_resume_total", { provider: PROVIDER, result: "ok" });
|
|
@@ -227,7 +324,10 @@ export class RemoteContainerExecutionEnv {
|
|
|
227
324
|
return undefined;
|
|
228
325
|
let probe;
|
|
229
326
|
try {
|
|
230
|
-
const
|
|
327
|
+
const start = this.startIn(ADAPTER_START, LANE_HOME_PROBE_COMMAND, undefined);
|
|
328
|
+
if (!start.ok)
|
|
329
|
+
throw start.error;
|
|
330
|
+
const r = await this.rpc("sandbox.home", (s) => this.runIn(sbx, start.value, { signal: s }), signal);
|
|
231
331
|
probe = r.exitCode === 0 ? { ok: true, stdout: r.stdout } : { ok: false, reason: `exit ${r.exitCode}` };
|
|
232
332
|
}
|
|
233
333
|
catch (e) {
|
|
@@ -265,6 +365,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
265
365
|
this.destroyed = true;
|
|
266
366
|
this.connecting = undefined;
|
|
267
367
|
this.stopKeepAlive();
|
|
368
|
+
this.floor.dispose();
|
|
268
369
|
await this.disposeBackgroundShells();
|
|
269
370
|
const sbx = this.sbx;
|
|
270
371
|
this.sbx = undefined;
|
|
@@ -285,12 +386,21 @@ export class RemoteContainerExecutionEnv {
|
|
|
285
386
|
await this.destroy();
|
|
286
387
|
}
|
|
287
388
|
async exec(command, options) {
|
|
389
|
+
return this.execAs(engineStart(options?.readFloor), command, options);
|
|
390
|
+
}
|
|
391
|
+
execInternal(command, options) {
|
|
392
|
+
return this.execAs(ADAPTER_START, command, options);
|
|
393
|
+
}
|
|
394
|
+
async execAs(start, command, options) {
|
|
288
395
|
if (options?.abortSignal?.aborted)
|
|
289
396
|
return { ok: false, error: new ExecutionError("aborted", "exec aborted before start") };
|
|
290
397
|
const conn = await this.ensureConnected();
|
|
291
398
|
if (!conn.ok)
|
|
292
399
|
return { ok: false, error: new ExecutionError("shell_unavailable", `remote connect failed: ${conn.error.message}`, conn.error) };
|
|
293
400
|
const sbx = conn.value;
|
|
401
|
+
const launch = this.startIn(start, command, options?.env);
|
|
402
|
+
if (!launch.ok)
|
|
403
|
+
return launch;
|
|
294
404
|
this.activeCommands++;
|
|
295
405
|
const detachSignal = options?.detachSignal;
|
|
296
406
|
const tee = detachSignal
|
|
@@ -315,10 +425,9 @@ export class RemoteContainerExecutionEnv {
|
|
|
315
425
|
let starting;
|
|
316
426
|
let startCut = false;
|
|
317
427
|
try {
|
|
318
|
-
handle = await this.rpc("commands.run", () => (starting =
|
|
428
|
+
handle = await this.rpc("commands.run", () => (starting = this.runIn(sbx, launch.value, {
|
|
319
429
|
background: true,
|
|
320
430
|
cwd: this.resolve(options?.cwd ?? this.cwd),
|
|
321
|
-
...(options?.env ? { envs: options.env } : {}),
|
|
322
431
|
timeoutMs: tee
|
|
323
432
|
? Math.max(this.commandTimeoutMs(options?.timeout), (E2B_BG_MAX_TIMEOUT_SEC + E2B_BG_PROVIDER_BACKSTOP_PAD_SEC) * 1000)
|
|
324
433
|
: this.commandTimeoutMs(options?.timeout),
|
|
@@ -442,6 +551,9 @@ export class RemoteContainerExecutionEnv {
|
|
|
442
551
|
if (!conn.ok)
|
|
443
552
|
throw conn.error;
|
|
444
553
|
const sbx = conn.value;
|
|
554
|
+
const launch = this.startIn(engineStart(undefined), command, options?.env);
|
|
555
|
+
if (!launch.ok)
|
|
556
|
+
throw new RemoteExecutionError("unsupported", launch.error.message, launch.error);
|
|
445
557
|
const queue = [];
|
|
446
558
|
let finished = false;
|
|
447
559
|
let failure;
|
|
@@ -468,10 +580,9 @@ export class RemoteContainerExecutionEnv {
|
|
|
468
580
|
let handle;
|
|
469
581
|
let starting;
|
|
470
582
|
try {
|
|
471
|
-
handle = await this.rpc("commands.run", () => (starting =
|
|
583
|
+
handle = await this.rpc("commands.run", () => (starting = this.runIn(sbx, launch.value, {
|
|
472
584
|
background: true,
|
|
473
585
|
cwd: this.resolve(options?.cwd ?? this.cwd),
|
|
474
|
-
...(options?.env ? { envs: options.env } : {}),
|
|
475
586
|
timeoutMs: this.commandTimeoutMs(options?.timeout),
|
|
476
587
|
onStdout: (d) => push("stdout", d),
|
|
477
588
|
onStderr: (d) => push("stderr", d),
|
|
@@ -599,12 +710,14 @@ export class RemoteContainerExecutionEnv {
|
|
|
599
710
|
if (!conn.ok)
|
|
600
711
|
throw new Error(`remote connect failed: ${conn.error.message}`);
|
|
601
712
|
const sbx = conn.value;
|
|
713
|
+
const launch = self.startIn(engineStart(options?.readFloor), command, options?.env);
|
|
714
|
+
if (!launch.ok)
|
|
715
|
+
throw launch.error;
|
|
602
716
|
const stdout = { tail: new RollingTailBuffer(), total: 0, cursor: 0 };
|
|
603
717
|
const stderr = { tail: new RollingTailBuffer(), total: 0, cursor: 0 };
|
|
604
|
-
const handle = await self.rpc("commands.run.bg", () =>
|
|
718
|
+
const handle = await self.rpc("commands.run.bg", () => self.runIn(sbx, launch.value, {
|
|
605
719
|
background: true,
|
|
606
720
|
cwd: self.resolve(options?.cwd ?? self.cwd),
|
|
607
|
-
...(options?.env ? { envs: options.env } : {}),
|
|
608
721
|
timeoutMs: (ctx.bgTimeoutSec + E2B_BG_PROVIDER_BACKSTOP_PAD_SEC) * 1000,
|
|
609
722
|
onStdout: (d) => {
|
|
610
723
|
const b = Buffer.from(d, "utf8");
|
|
@@ -722,7 +835,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
722
835
|
return { ok: false, error: this.fileError(e, dest, signal) };
|
|
723
836
|
}
|
|
724
837
|
},
|
|
725
|
-
run: (cmd, signal) => this.
|
|
838
|
+
run: (cmd, signal) => this.execInternal(cmd, { cwd: "/", ...(signal !== undefined ? { abortSignal: signal } : {}) }),
|
|
726
839
|
};
|
|
727
840
|
}
|
|
728
841
|
async writeFile(p, content, abortSignal) {
|
|
@@ -764,7 +877,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
764
877
|
}
|
|
765
878
|
async readLink(p, abortSignal) {
|
|
766
879
|
const abs = this.resolve(p);
|
|
767
|
-
const r = await this.
|
|
880
|
+
const r = await this.execInternal(`readlink -- ${shellQuote(abs)}`, { abortSignal });
|
|
768
881
|
if (!r.ok)
|
|
769
882
|
return { ok: false, error: fileErrorFromExec(r.error, abs) };
|
|
770
883
|
if (r.value.exitCode !== 0)
|
|
@@ -772,11 +885,11 @@ export class RemoteContainerExecutionEnv {
|
|
|
772
885
|
return ok(r.value.stdout.trim());
|
|
773
886
|
}
|
|
774
887
|
async canonicalChain(p, abortSignal) {
|
|
775
|
-
return runSymlinkChain(this.resolve(p), (cmd) => this.
|
|
888
|
+
return runSymlinkChain(this.resolve(p), (cmd) => this.execInternal(cmd, { abortSignal }));
|
|
776
889
|
}
|
|
777
890
|
async canonicalPath(p, abortSignal) {
|
|
778
891
|
const abs = this.resolve(p);
|
|
779
|
-
const r = await this.
|
|
892
|
+
const r = await this.execInternal(`realpath -- ${shellQuote(abs)}`, { abortSignal });
|
|
780
893
|
if (!r.ok)
|
|
781
894
|
return { ok: false, error: fileErrorFromExec(r.error, abs) };
|
|
782
895
|
if (r.value.exitCode !== 0) {
|
|
@@ -823,7 +936,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
823
936
|
const abs = this.resolve(p);
|
|
824
937
|
if (options?.recursive) {
|
|
825
938
|
const flags = options.force ? "-rf" : "-r";
|
|
826
|
-
const r = await this.
|
|
939
|
+
const r = await this.execInternal(`rm ${flags} -- ${shellQuote(abs)}`, { abortSignal: options.abortSignal });
|
|
827
940
|
if (!r.ok)
|
|
828
941
|
return { ok: false, error: fileErrorFromExec(r.error, abs) };
|
|
829
942
|
if (r.value.exitCode !== 0)
|
|
@@ -842,14 +955,14 @@ export class RemoteContainerExecutionEnv {
|
|
|
842
955
|
}
|
|
843
956
|
}
|
|
844
957
|
async createTempDir(prefix = "tmp-", abortSignal) {
|
|
845
|
-
const r = await this.
|
|
958
|
+
const r = await this.execInternal(`mktemp -d -t ${shellQuote(`${prefix}XXXXXX`)}`, { abortSignal });
|
|
846
959
|
return this.tempResult(r, "mktemp -d");
|
|
847
960
|
}
|
|
848
961
|
async createTempFile(options) {
|
|
849
962
|
const prefix = options?.prefix ?? "";
|
|
850
963
|
const suffix = options?.suffix ?? "";
|
|
851
964
|
const suffixArg = suffix ? `--suffix=${shellQuote(suffix)} -t` : "-t";
|
|
852
|
-
const r = await this.
|
|
965
|
+
const r = await this.execInternal(`mktemp ${suffixArg} ${shellQuote(`${prefix}XXXXXX`)}`, { abortSignal: options?.abortSignal });
|
|
853
966
|
return this.tempResult(r, "mktemp");
|
|
854
967
|
}
|
|
855
968
|
resolve(p) {
|
|
@@ -3,6 +3,8 @@ import { type SpaceCommitFence } from "../workspace-space-commit.js";
|
|
|
3
3
|
import { type CacheMissMemory, type WorkspaceCacheCapability } from "../workspace-cache.js";
|
|
4
4
|
import { type SandboxEgressGap, type SandboxIpv6 } from "../sandbox-egress-policy.js";
|
|
5
5
|
import { FileError, ExecutionError, RemoteExecutionError, type ExecutionEnv, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type SymlinkChain, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type VmLifecycleOptions, type ExecutionEnvFactory, type BackgroundShellCapability, type BackgroundShellId, type BackgroundShellError, type BackgroundSpawnOptions, type BackgroundPoll, type ExecutionEnvCapabilities } from "@sema-agent/core";
|
|
6
|
+
import { type SandboxReadFloorKnob } from "../execution-lane-caps.js";
|
|
7
|
+
import { type SandboxReadFloor } from "./sandbox-read-floor.js";
|
|
6
8
|
import type { PodSpecPatch } from "./k8s-exec-protocol.js";
|
|
7
9
|
import { type LaneHomeConfig } from "../lane-home-probe.js";
|
|
8
10
|
type ExecOpts = Parameters<ExecutionEnv["exec"]>[1];
|
|
@@ -162,6 +164,8 @@ export interface K8sEnvConfig extends LaneHomeConfig {
|
|
|
162
164
|
readonly image: string;
|
|
163
165
|
readonly origins: readonly string[];
|
|
164
166
|
};
|
|
167
|
+
/** `SANDBOX_READ_FLOOR`(keep | off;缺席 ⇒ keep):本 pod 守不守读拒表的字节地板 = 读地板模块服务本车道 ∧ 本键不是 off(`sandbox-read-floor.ts`)。 */
|
|
168
|
+
sandboxReadFloor?: SandboxReadFloorKnob;
|
|
165
169
|
}
|
|
166
170
|
import { type SandboxSecretSeatKind, type SandboxSecretVerb } from "./k8s-exec-protocol.js";
|
|
167
171
|
export { type PodSpecPatch, applyPodSpecPatch } from "./k8s-exec-protocol.js";
|
|
@@ -179,6 +183,8 @@ export interface ExecSocket {
|
|
|
179
183
|
on(event: "open" | "message" | "close" | "error", listener: (...args: unknown[]) => void): void;
|
|
180
184
|
close(): void;
|
|
181
185
|
terminate?(): void;
|
|
186
|
+
/** 写一帧(读地板中继的 stdin:首字节 = 通道 0)。只读的 exec 不用;没有它的套接字起不了中继(附着按 `relay_silent` 拒)。 */
|
|
187
|
+
send?(data: Buffer): void;
|
|
182
188
|
}
|
|
183
189
|
/**
|
|
184
190
|
* Test seam ([ref] §9.3 fault-injection): inject the REST `request` and/or the exec-socket factory, so pod
|
|
@@ -199,6 +205,8 @@ export interface K8sEnvDeps {
|
|
|
199
205
|
connectOnce?: (signal?: AbortSignal) => Promise<ConnectResult>;
|
|
200
206
|
/** Worker-side object-store requests (the space pointer, listing, deletes). Default: global `fetch`. */
|
|
201
207
|
fetch?: typeof fetch;
|
|
208
|
+
/** 这只环境手里的读地板模块(缺席 ⇒ `createSandboxReadFloor` 按旋钮选;钉注入守地板的模块)。能力块的 `keepsReadFloor` 读它的状态。 */
|
|
209
|
+
readFloor?: SandboxReadFloor;
|
|
202
210
|
}
|
|
203
211
|
/**
|
|
204
212
|
* One run's space occupant — the space key of both lanes keyed by it (the space lane, the cache volume) — a closed set of three
|
|
@@ -290,8 +298,10 @@ export type SandboxLeaseWrite = {
|
|
|
290
298
|
readonly message: string;
|
|
291
299
|
};
|
|
292
300
|
export declare class RemoteK8sExecutionEnv implements RemoteExecutionEnv, BackgroundShellCapability {
|
|
293
|
-
/** 能力块的唯一作者 = `capabilitiesFor`(`execution-lane-caps.ts`;逐键表态与理由在那里,本类零能力字面量)
|
|
301
|
+
/** 能力块的唯一作者 = `capabilitiesFor`(`execution-lane-caps.ts`;逐键表态与理由在那里,本类零能力字面量)。快照店与读地板旋钮是它的输入(构造期铸,见下);{@link floor} 由同一只判据、同一个旋钮值选出。 */
|
|
294
302
|
readonly capabilities: ExecutionEnvCapabilities;
|
|
303
|
+
/** 读拒表字节地板模块:pod 里每一次 exec 起动都先经它的 `wrap`({@link runExec},唯一接缝)。 */
|
|
304
|
+
private readonly floor;
|
|
295
305
|
cwd: string;
|
|
296
306
|
private podName?;
|
|
297
307
|
/** Cluster-internal pod address, captured when the pod reaches Running — the LSP `getHost` surface.
|
|
@@ -731,6 +741,15 @@ export declare class RemoteK8sExecutionEnv implements RemoteExecutionEnv, Backgr
|
|
|
731
741
|
* being claimed) uploads nothing, and is that same upload failure.
|
|
732
742
|
*/
|
|
733
743
|
private persistWorkspace;
|
|
744
|
+
/**
|
|
745
|
+
* 守地板的 pod 的二进制座:本包带的每个架构一只 ConfigMap(名 = 架构 + 摘要前 16 位,不可变;201 = 新建,409 = 同名同内容已在)。建不成
|
|
746
|
+
* ⇒ 告诉地板模块(附着按 `binary_digest` 拒,pod 照起、不带这只卷);不守地板 ⇒ `undefined`(pod 与改前逐字同)。部署前提:命名空间里 configmaps 的 create。
|
|
747
|
+
*/
|
|
748
|
+
private ensureFloorSeat;
|
|
749
|
+
/** 地板模块的三件原语。引导命令经 {@link runExec}(起动形 `bootstrap`:只在附着中合法);放置由 pod 的只读卷完成(自检 `--digest` 证字节);
|
|
750
|
+
* 中继 = 一只开着 stdin 的长连 exec(与命令同一身份 —— k8s 的 exec 没有换身份的口),stdout 帧是中继的问,stdin 帧(首字节 0)是判官的答。 */
|
|
751
|
+
private floorTransport;
|
|
752
|
+
/** exec 的 URL:`argv` 原样作 `command` 参数(唯一来源 = {@link runExec} 里模块答案的编码,或地板模块自己的中继);`stdin` ⇒ 开 stdin 通道。 */
|
|
734
753
|
private execUrl;
|
|
735
754
|
/**
|
|
736
755
|
* Run a command over the exec WebSocket. Frames: byte0=channel (1 stdout / 2 stderr / 3 status JSON with the
|