@sema-agent/server 7.139.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 +471 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +94 -26
- package/dist/adoption/runner.js +1 -1
- package/dist/adoption/sql.js +1 -1
- package/dist/approval-batch-census.d.ts +27 -0
- package/dist/approval-batch-census.js +27 -0
- package/dist/approval-card.d.ts +37 -22
- 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/bench/s1/live-deps.js +3 -2
- package/dist/bench/s1/row.d.ts +5 -2
- package/dist/bench/s1/row.js +2 -22
- package/dist/boot/adoption.js +1 -1
- 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 +18 -12
- package/dist/boot/execution-lane.d.ts +8 -0
- package/dist/boot/execution-lane.js +6 -1
- package/dist/boot/memory-boundary.d.ts +16 -53
- package/dist/boot/memory-boundary.js +10 -20
- package/dist/boot/memory-consolidation.d.ts +16 -12
- package/dist/boot/memory-consolidation.js +24 -13
- package/dist/boot/reapers.d.ts +2 -2
- package/dist/boot/resolve-spec.d.ts +3 -5
- package/dist/boot/resolve-spec.js +9 -8
- package/dist/boot/runner-deps.d.ts +3 -3
- package/dist/boot/runner-deps.js +1 -0
- 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-03-store-backend.d.ts +2 -6
- package/dist/boot/stage-03-store-backend.js +2 -3
- package/dist/boot/stage-04-stores.d.ts +2 -6
- package/dist/boot/stage-04-stores.js +5 -5
- package/dist/boot/stage-05-execution-env.d.ts +2 -6
- package/dist/boot/stage-05-execution-env.js +3 -1
- package/dist/boot/stage-06-runners.d.ts +2 -8
- package/dist/boot/stage-06-runners.js +3 -3
- package/dist/boot/stage-07-capability-layer.d.ts +2 -7
- package/dist/boot/stage-07-capability-layer.js +8 -10
- package/dist/boot/stage-08-reapers.d.ts +2 -7
- package/dist/boot/stage-09-leader.d.ts +2 -7
- package/dist/boot/stage-10-http-server.d.ts +2 -7
- package/dist/boot/stage-10-http-server.js +6 -4
- package/dist/boot/stores.d.ts +3 -6
- package/dist/boot/stores.js +37 -44
- package/dist/boot/task-list-lane.d.ts +1 -1
- package/dist/boot/task-list-lane.js +1 -1
- package/dist/boot/web-admin.js +36 -9
- package/dist/capabilities/execution-lane.d.ts +2 -2
- 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 +12 -8
- package/dist/config-provider.d.ts +18 -17
- package/dist/config-provider.js +28 -36
- package/dist/config-types.d.ts +36 -9
- package/dist/config.js +56 -46
- package/dist/delegated-session-owner.d.ts +23 -20
- package/dist/delegated-session-owner.js +2 -2
- package/dist/deployment-shape.d.ts +9 -8
- package/dist/deployment-shape.js +4 -4
- 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 +145 -107
- package/dist/execution-lane-caps.js +144 -83
- 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/memory-compliance-failure-reply.d.ts +3 -1
- package/dist/http/memory-compliance-failure-reply.js +5 -0
- package/dist/http/memory-layer-reply.d.ts +30 -0
- package/dist/http/memory-layer-reply.js +24 -0
- package/dist/http/resume-legs.js +49 -35
- package/dist/http/retired-service-deps.d.ts +1 -1
- package/dist/http/retired-service-deps.js +1 -1
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/adoption.js +1 -1
- 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 +4 -1
- package/dist/http/routes/memory-compliance.js +9 -2
- package/dist/http/routes/memory-consolidation.js +12 -1
- package/dist/http/routes/memory-origin.js +14 -2
- package/dist/http/routes/memory-policy.js +7 -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 +33 -15
- package/dist/http/routes/tasks.js +67 -68
- 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 +14 -27
- package/dist/http/server.js +2 -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/identity-source.d.ts +1 -1
- package/dist/identity-source.js +1 -1
- package/dist/instruction-source-notice.d.ts +7 -0
- package/dist/instruction-source-notice.js +6 -6
- package/dist/lane-home-probe.d.ts +68 -42
- package/dist/lane-home-probe.js +53 -30
- package/dist/leader/wire.js +5 -4
- package/dist/mcp-assertion-header.d.ts +4 -0
- package/dist/mcp-assertion-header.js +5 -0
- package/dist/memory-bundle-engine.d.ts +16 -9
- package/dist/memory-bundle-engine.js +29 -6
- package/dist/memory-operator-faces.d.ts +85 -30
- package/dist/memory-operator-faces.js +136 -30
- package/dist/memory-posture.d.ts +1 -1
- package/dist/memory-project-layer.d.ts +3 -21
- package/dist/memory-project-layer.js +11 -8
- package/dist/memory-scope-stores.d.ts +73 -0
- package/dist/memory-scope-stores.js +86 -0
- package/dist/memory-scope.d.ts +33 -9
- package/dist/memory-scope.js +17 -5
- package/dist/memory-sync-client.d.ts +34 -9
- package/dist/memory-sync-client.js +108 -28
- 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/adoption-log-sql.js +4 -4
- package/dist/plugins/approval-ask-store-sql.js +14 -14
- package/dist/plugins/approval-nonce-store.js +4 -4
- package/dist/plugins/blob-backend.d.ts +4 -4
- package/dist/plugins/blob-backend.js +7 -7
- package/dist/plugins/breaker-state-sql.js +2 -2
- package/dist/plugins/caching-session-store.d.ts +6 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-index-columns.js +2 -2
- package/dist/plugins/checkpoint-store-sql.d.ts +65 -17
- package/dist/plugins/checkpoint-store-sql.js +90 -19
- package/dist/plugins/device-store-sql.d.ts +5 -2
- package/dist/plugins/device-store-sql.js +23 -20
- package/dist/plugins/ensure-index.d.ts +1 -2
- package/dist/plugins/execution-placement-sql.d.ts +19 -9
- package/dist/plugins/execution-placement-sql.js +20 -9
- package/dist/plugins/file-history-store-sql.d.ts +2 -2
- package/dist/plugins/file-history-store-sql.js +4 -4
- 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/image-bake-store-sql.js +9 -9
- package/dist/plugins/image-index-sql.js +11 -11
- package/dist/plugins/k8s-exec-protocol.d.ts +4 -1
- package/dist/plugins/k8s-exec-protocol.js +6 -1
- package/dist/plugins/leader-run-store-sql.js +4 -4
- 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/mailbox-store-sql.d.ts +2 -1
- package/dist/plugins/mailbox-store-sql.js +4 -4
- package/dist/plugins/memory-engine-tidb.js +5 -5
- package/dist/plugins/memory-optout-grant-store-sql.js +1 -1
- package/dist/plugins/memory-run-store.d.ts +2 -2
- package/dist/plugins/memory-run-store.js +1 -1
- package/dist/plugins/memory-sync-store-tidb.js +3 -3
- package/dist/plugins/one-time-migrations.d.ts +52 -11
- package/dist/plugins/one-time-migrations.js +101 -39
- package/dist/plugins/org-delivery-quota-store.js +2 -2
- package/dist/plugins/outcome-ledger-sql.js +2 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +4 -4
- package/dist/plugins/permission-rule-store-sql.js +16 -16
- 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-adb.d.ts +7 -24
- package/dist/plugins/remote-env-adb.js +22 -5
- package/dist/plugins/remote-env-device.d.ts +2 -28
- package/dist/plugins/remote-env-device.js +2 -1
- package/dist/plugins/remote-env-e2b.d.ts +40 -27
- package/dist/plugins/remote-env-e2b.js +180 -20
- package/dist/plugins/remote-env-file-error.d.ts +1 -1
- package/dist/plugins/remote-env-file-error.js +8 -2
- package/dist/plugins/remote-env-host.d.ts +19 -35
- package/dist/plugins/remote-env-host.js +26 -3
- package/dist/plugins/remote-env-k8s.d.ts +22 -14
- package/dist/plugins/remote-env-k8s.js +150 -26
- package/dist/plugins/remote-env-local-docker.d.ts +27 -24
- package/dist/plugins/remote-env-local-docker.js +91 -24
- package/dist/plugins/remote-env-ssh.d.ts +4 -24
- package/dist/plugins/remote-env-ssh.js +4 -3
- package/dist/plugins/resume-anchor-store-sql.js +2 -2
- package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
- package/dist/plugins/retention-lane-store-sql.js +2 -2
- package/dist/plugins/retention-store-sql.d.ts +1 -1
- package/dist/plugins/retention-store-sql.js +6 -6
- package/dist/plugins/run-store-sql.d.ts +3 -3
- package/dist/plugins/run-store-sql.js +19 -18
- package/dist/plugins/sandbox-read-floor.d.ts +273 -0
- package/dist/plugins/sandbox-read-floor.js +608 -0
- package/dist/plugins/schema-consistency.d.ts +6 -6
- package/dist/plugins/schema-consistency.js +1 -1
- package/dist/plugins/schema-ensure-legs.d.ts +2 -3
- package/dist/plugins/schema-ensure-legs.js +2 -2
- package/dist/plugins/schema-live-columns.d.ts +1 -1
- package/dist/plugins/session-capture-record-store-sql.js +1 -1
- 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-rules-column.d.ts +1 -1
- package/dist/plugins/session-rules-column.js +1 -1
- package/dist/plugins/session-store.d.ts +18 -20
- package/dist/plugins/session-store.js +4 -12
- package/dist/plugins/session-workspace-cell.d.ts +1 -1
- package/dist/plugins/session-workspace-cell.js +1 -1
- package/dist/plugins/shared-memory-store-sql.js +2 -2
- package/dist/plugins/sql-driver.d.ts +10 -5
- package/dist/plugins/sql-driver.js +6 -6
- package/dist/plugins/sql-errors.js +1 -1
- package/dist/plugins/store-backend.d.ts +35 -6
- package/dist/plugins/store-backend.js +27 -10
- package/dist/plugins/store-contracts.d.ts +9 -2
- package/dist/plugins/task-list-store-sql.js +11 -11
- package/dist/plugins/tidb-pool.js +7 -6
- package/dist/plugins/tidb-session-storage.js +4 -4
- package/dist/plugins/tidb-session-store.d.ts +4 -1
- package/dist/plugins/tidb-session-store.js +16 -15
- package/dist/plugins/tool-result-store-sql.d.ts +2 -2
- package/dist/plugins/tool-result-store-sql.js +3 -3
- package/dist/plugins/user-input-ledger-sql.js +2 -2
- package/dist/plugins/workflow-journal-store-sql.js +5 -5
- package/dist/plugins/workflow-run-store-sql.js +19 -19
- package/dist/plugins/write-behind-counter.d.ts +2 -3
- package/dist/plugins/write-behind-counter.js +5 -5
- package/dist/resource-suspend.d.ts +14 -12
- package/dist/resource-suspend.js +1 -1
- package/dist/resource-window.d.ts +4 -3
- package/dist/run-cancel-context.d.ts +34 -0
- package/dist/run-cancel-context.js +7 -0
- package/dist/run-local.js +14 -19
- package/dist/runs.d.ts +47 -16
- package/dist/runs.js +112 -113
- 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 +10 -4
- package/dist/session-incarnation.js +1 -1
- package/dist/session-policy-wire.d.ts +1 -1
- 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/sql-engine-posture.d.ts +1 -1
- package/dist/sql-engine-posture.js +1 -1
- 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/{plugins → stores-sql}/background-agent-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/background-agent-store-sql.js +8 -8
- package/dist/{plugins → stores-sql}/session-policy-store-sql.d.ts +7 -5
- package/dist/{plugins → stores-sql}/session-policy-store-sql.js +12 -12
- package/dist/{plugins → stores-sql}/usage-window-store-sql.d.ts +1 -1
- package/dist/{plugins → stores-sql}/usage-window-store-sql.js +3 -3
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-a2a.js +5 -6
- package/dist/task-mcp.d.ts +21 -8
- package/dist/task-mcp.js +17 -9
- package/dist/task-settings.d.ts +52 -25
- package/dist/task-settings.js +91 -28
- package/dist/terminal.d.ts +103 -19
- package/dist/terminal.js +72 -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.d.ts +3 -1
- package/dist/trace/redact.js +395 -110
- package/dist/trace/self-minted-wire.d.ts +226 -2
- package/dist/trace/self-minted-wire.js +79 -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 +11 -7
- package/dist/web-admin-client/candidate-gate.js +1 -1
- package/dist/web-admin-client/http-client.d.ts +5 -4
- package/dist/web-admin-client/http-client.js +2 -2
- package/dist/web-admin-client/read-warnings.d.ts +7 -17
- package/dist/web-admin-client/read-warnings.js +5 -9
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -2
- package/package.json +2 -2
- package/wire-changes/server@7.140.0.json +184 -0
- package/wire-changes/server@7.141.0.json +367 -0
|
@@ -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,19 +298,10 @@ export type SandboxLeaseWrite = {
|
|
|
290
298
|
readonly message: string;
|
|
291
299
|
};
|
|
292
300
|
export declare class RemoteK8sExecutionEnv implements RemoteExecutionEnv, BackgroundShellCapability {
|
|
293
|
-
/**
|
|
294
|
-
* 🔴 **[ref] / core 7.20.0([ref])`canonicalPathAuthoritative: true`** —— 本适配器的 `canonicalPath`
|
|
295
|
-
* 就是**命令真正跑的那块文件系统**的权威答案(`posix-shell-fs` 的 `canonicalPath` 原语,经 pod exec 解到落点)。声明它 = 告诉引擎:整链答不出来是**解析器出了事**
|
|
296
|
-
* (RPC 断、传输掉),不是「一个它看不见的命名空间」⇒ 读边界的执行期复核**拒**,而不是让词法判决站着。
|
|
297
|
-
* 缺席是今天每个适配器的读法(整链沉默 ⇒ 词法判决成立、命令照跑),所以这一声明是**收紧**方向。
|
|
298
|
-
* 严格读法 `=== true`(core `canonicalPathIsAuthoritative`);`isSuspendable` 一族同样严格,对本仓的
|
|
299
|
-
* 布尔字面量零影响(四键都写死字面 `true`/`false`,不存在「非布尔值被读成缺席」那一形 —— 那一形由
|
|
300
|
-
* core 的 `config.execution_env_capability_invalid` 普查响亮播报,本仓的受众表已登记)。
|
|
301
|
-
* 谁该声明由闭集门看着(`test/execution-lane-caps.test.ts` 的逐 lane 对账:新 lane 不表态 = 编译红)。
|
|
302
|
-
*/
|
|
303
|
-
/** `sharesProcessTable`(core 7.57.0,必填):命令跑在沙箱 pod 自己的 PID 命名空间里(不开 hostPID),不在本进程所在的进程表。 */
|
|
304
|
-
/** 能力块(引擎 [ref],八键必填、各键只经引擎读器读):`hostLocalPaths` = 这条车道答出的路径是不是本进程所在机器上的文件;`externalContentTarget` = 产出是否来自部署信任边界之外;`io` = 文件与 shell 两面真到达目标;`keepsReadFloor` = 是否守住读拒表的字节地板(本车道不守 ⇒ 读拒表非空的 run 被告知,部署要求地板时准备期拒)。 */
|
|
301
|
+
/** 能力块的唯一作者 = `capabilitiesFor`(`execution-lane-caps.ts`;逐键表态与理由在那里,本类零能力字面量)。快照店与读地板旋钮是它的输入(构造期铸,见下);{@link floor} 由同一只判据、同一个旋钮值选出。 */
|
|
305
302
|
readonly capabilities: ExecutionEnvCapabilities;
|
|
303
|
+
/** 读拒表字节地板模块:pod 里每一次 exec 起动都先经它的 `wrap`({@link runExec},唯一接缝)。 */
|
|
304
|
+
private readonly floor;
|
|
306
305
|
cwd: string;
|
|
307
306
|
private podName?;
|
|
308
307
|
/** Cluster-internal pod address, captured when the pod reaches Running — the LSP `getHost` surface.
|
|
@@ -327,9 +326,9 @@ export declare class RemoteK8sExecutionEnv implements RemoteExecutionEnv, Backgr
|
|
|
327
326
|
* the space restore (`latest` names an archive that is there and did not come back — {@link restoreSnapshot}) and the pod's admission (the cluster created
|
|
328
327
|
* the pod and it ended `Failed` before it ran — {@link createPod}). Neither goes away by asking again: the same request answers the same. */
|
|
329
328
|
private connectRefusal?;
|
|
330
|
-
/** core `ExecutionEnv.homeDir`([ref]):pod 里执行用户的 home ——
|
|
329
|
+
/** core `ExecutionEnv.homeDir`([ref]):pod 里执行用户的 home —— 声明在场 ⇒ 声明(开环境那一拍与 `$HOME` 对证过),否则 pod 就绪那一拍实测的 `$HOME`,见 {@link LaneHomeSeat}。读时才取(没声明时 pod 起来之前缺席)。 */
|
|
331
330
|
get homeDir(): string | undefined;
|
|
332
|
-
/** 家目录的座(
|
|
331
|
+
/** 家目录的座(声明在场 ⇒ 开环境那一拍对证 · 否则 pod 就绪那一拍实测 · 实测缺席 ⇒ 缺席 + 一行 warn)。与其余读得出家目录的车道同一只判官、同一句拒。 */
|
|
333
332
|
private readonly homeSeat;
|
|
334
333
|
/** core 7.49.0 [ref]:shell 子进程真拿到的 `CDPATH` 条目 —— 本车道的命令跑在 pod 里(镜像与 pod spec 的 env),本类不读那份 env ⇒ `"unknown"`(core 契约:说不出就说 unknown,
|
|
335
334
|
* 不许报一张没读过的空表;删除守卫因此对裸 `cd <相对名>` 之后的删除问人,而不是按「没有 CDPATH」放行)。 */
|
|
@@ -742,6 +741,15 @@ export declare class RemoteK8sExecutionEnv implements RemoteExecutionEnv, Backgr
|
|
|
742
741
|
* being claimed) uploads nothing, and is that same upload failure.
|
|
743
742
|
*/
|
|
744
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 通道。 */
|
|
745
753
|
private execUrl;
|
|
746
754
|
/**
|
|
747
755
|
* Run a command over the exec WebSocket. Frames: byte0=channel (1 stdout / 2 stderr / 3 status JSON with the
|
|
@@ -18,6 +18,8 @@ import { buildLivenessCut, commandBoundsOf, laneLivenessOf, LIVENESS_MS_DEFAULT
|
|
|
18
18
|
import { buildCapturedOutput, createCutError } from "../exec-cut.js";
|
|
19
19
|
import { SANDBOX_IPV6_DEFAULT, sandboxEgressGaps, sandboxPodSysctls } from "../sandbox-egress-policy.js";
|
|
20
20
|
import { FileError, ExecutionError, RemoteExecutionError, withRetry, RollingTailBuffer, markTruncated, } from "@sema-agent/core";
|
|
21
|
+
import { capabilitiesFor } from "../execution-lane-caps.js";
|
|
22
|
+
import { ADAPTER_START, BOOTSTRAP_START, buildFloorPodSeat, createSandboxReadFloor, FLOOR_K8S_CONFIGMAP_KEY, engineStart, floorArgv, } from "./sandbox-read-floor.js";
|
|
21
23
|
import { fileErrorFromExec, classifyFsStderr } from "./remote-env-file-error.js";
|
|
22
24
|
import { createPosixShellFs } from "./posix-shell-fs.js";
|
|
23
25
|
import { randomUUID } from "node:crypto";
|
|
@@ -201,6 +203,7 @@ function brokerContainer(image) {
|
|
|
201
203
|
}
|
|
202
204
|
export class RemoteK8sExecutionEnv {
|
|
203
205
|
capabilities;
|
|
206
|
+
floor;
|
|
204
207
|
cwd;
|
|
205
208
|
podName;
|
|
206
209
|
podIP;
|
|
@@ -258,7 +261,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
258
261
|
...(config.snapshotExclude && config.snapshotExclude.length > 0 ? { snapshotExclude: config.snapshotExclude } : {}),
|
|
259
262
|
};
|
|
260
263
|
this.cwd = this.cfg.mountPath;
|
|
261
|
-
this.homeSeat = new LaneHomeSeat(
|
|
264
|
+
this.homeSeat = new LaneHomeSeat(PROVIDER, config);
|
|
262
265
|
this.deps = deps ?? {};
|
|
263
266
|
this.laneLiveness = laneLivenessOf(this.cfg.livenessMs, "K8S_LIVENESS_MS");
|
|
264
267
|
const occupant = occupantKeyOf(config.spaceOccupant);
|
|
@@ -268,7 +271,8 @@ export class RemoteK8sExecutionEnv {
|
|
|
268
271
|
this.logger = config.logger;
|
|
269
272
|
this.onWorkspaceSnapshot = config.onWorkspaceSnapshot;
|
|
270
273
|
this.cacheMisses = config.cacheMisses;
|
|
271
|
-
this.
|
|
274
|
+
this.floor = this.deps.readFloor ?? createSandboxReadFloor({ lane: PROVIDER, knob: config.sandboxReadFloor, ...(config.logger !== undefined ? { logger: config.logger } : {}) });
|
|
275
|
+
this.capabilities = capabilitiesFor({ remoteExec: { provider: PROVIDER, s3Snapshot: this.cfg.s3Snapshot }, sandboxReadFloor: config.sandboxReadFloor });
|
|
272
276
|
const bgMax = Math.max(1, Math.min(K8S_BG_MAX_TIMEOUT_SEC, Math.floor(this.cfg.timeoutMs / 1000)));
|
|
273
277
|
this.backgroundCapabilities = {
|
|
274
278
|
supported: true,
|
|
@@ -666,6 +670,8 @@ export class RemoteK8sExecutionEnv {
|
|
|
666
670
|
];
|
|
667
671
|
const pkgSourceMarked = Boolean(this.cfg.podEnv?.SEMA_PKG_SOURCE || secretEnv.SEMA_PKG_SOURCE);
|
|
668
672
|
const sysctls = sandboxPodSysctls(this.cfg.ipv6);
|
|
673
|
+
const floorSeat = await this.ensureFloorSeat(signal);
|
|
674
|
+
const mounts = [...(cache ? [{ name: CACHE_VOLUME, mountPath: cache.mount }] : []), ...(floorSeat?.mounts ?? [])];
|
|
669
675
|
const pod = {
|
|
670
676
|
apiVersion: "v1",
|
|
671
677
|
kind: "Pod",
|
|
@@ -690,7 +696,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
690
696
|
? ["sh", "-c", "[ -f /opt/sema/pkg-source.sh ] && sh /opt/sema/pkg-source.sh || true; sleep infinity"]
|
|
691
697
|
: ["sh", "-c", "sleep infinity"],
|
|
692
698
|
...(envEntries.length > 0 ? { env: envEntries } : {}),
|
|
693
|
-
...(
|
|
699
|
+
...(mounts.length > 0 ? { volumeMounts: mounts } : {}),
|
|
694
700
|
resources: { limits: { cpu: this.cfg.cpu, memory: this.cfg.memory } },
|
|
695
701
|
},
|
|
696
702
|
...(broker !== undefined ? [brokerContainer(broker.image)] : []),
|
|
@@ -698,6 +704,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
698
704
|
...((volumes) => (volumes.length > 0 ? { volumes } : {}))([
|
|
699
705
|
...(cache ? [{ name: CACHE_VOLUME, persistentVolumeClaim: { claimName: cache.claim.name } }] : []),
|
|
700
706
|
...(leaseName !== undefined ? [{ name: BROKER_VOLUME_NAME, secret: { secretName: leaseName, items: [{ key: BROKER_LEASE_KEY, path: BROKER_LEASE_KEY }], defaultMode: 0o400 } }] : []),
|
|
707
|
+
...(floorSeat?.volumes ?? []),
|
|
701
708
|
]),
|
|
702
709
|
},
|
|
703
710
|
};
|
|
@@ -805,7 +812,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
805
812
|
this.podIP = podIP;
|
|
806
813
|
this.leaseRef = leaseName !== undefined && broker !== undefined ? { namespace: ns, podName: name, leaseSecretName: leaseName, origins: [...broker.origins] } : undefined;
|
|
807
814
|
const askHome = this.homeSeat.asks;
|
|
808
|
-
const mk = await this.runExec(`mkdir -p ${shellQuote(this.cfg.mountPath)}${askHome ? ` && { ${LANE_HOME_PROBE_COMMAND} || true; }` : ""}`);
|
|
815
|
+
const mk = await this.runExec(ADAPTER_START, `mkdir -p ${shellQuote(this.cfg.mountPath)}${askHome ? ` && { ${LANE_HOME_PROBE_COMMAND} || true; }` : ""}`);
|
|
809
816
|
if (!mk.ok || mk.value.exitCode !== 0) {
|
|
810
817
|
await this.deletePod(name).catch(() => { });
|
|
811
818
|
this.podName = undefined;
|
|
@@ -824,6 +831,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
824
831
|
}
|
|
825
832
|
if (cache?.fresh)
|
|
826
833
|
this.logger?.warn("workspace_cache_fresh", { space: incarnationLogPrefix(cache.spaceKey), claim: cache.claim.name, size: cache.size });
|
|
834
|
+
await this.floor.attach(this.floorTransport(), { origin: "created", workspaceRoot: this.cfg.mountPath });
|
|
827
835
|
return ok(this.workspaceHandle());
|
|
828
836
|
}
|
|
829
837
|
async createPodSecret(secretName, podName, podUid, values, signal) {
|
|
@@ -1183,7 +1191,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
1183
1191
|
const excludes = (this.cfg.snapshotExclude ?? []).map((item) => ` --exclude=${shellQuote(`./${item}`)}`).join("");
|
|
1184
1192
|
const cmd = `tar czf ${tmp}${excludes} -C ${shellQuote(this.cfg.mountPath)} . && curl -fsS -X PUT -T ${tmp} ${shellQuote(url)}; ` +
|
|
1185
1193
|
`rc=$?; rm -f ${tmp}; exit $rc`;
|
|
1186
|
-
const r = await this.runExec(cmd, { timeoutMs: boundMs });
|
|
1194
|
+
const r = await this.runExec(ADAPTER_START, cmd, { timeoutMs: boundMs });
|
|
1187
1195
|
if (!r.ok)
|
|
1188
1196
|
return { ok: false, error: new RemoteExecutionError("connect_failed", `workspace snapshot upload failed: ${this.redactUrl(r.error.message, url)}`, r.error) };
|
|
1189
1197
|
if (r.value.exitCode !== 0)
|
|
@@ -1219,7 +1227,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
1219
1227
|
const c = await this.provision(abortSignal);
|
|
1220
1228
|
if (!c.ok)
|
|
1221
1229
|
return c;
|
|
1222
|
-
const r = await this.runExec(cmd, { timeoutMs: this.cfg.dataTimeoutMs });
|
|
1230
|
+
const r = await this.runExec(ADAPTER_START, cmd, { timeoutMs: this.cfg.dataTimeoutMs });
|
|
1223
1231
|
const failure = !r.ok
|
|
1224
1232
|
? { cls: r.error.code === "timeout" ? "timeout" : "transport", detail: `workspace snapshot restore failed: ${this.redactUrl(r.error.message, url)}`, cause: r.error }
|
|
1225
1233
|
: r.value.exitCode !== 0
|
|
@@ -1325,6 +1333,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
1325
1333
|
}
|
|
1326
1334
|
async destroy() {
|
|
1327
1335
|
await this.disposeBackgroundShells().catch(() => { });
|
|
1336
|
+
this.floor.dispose();
|
|
1328
1337
|
this.destroyed = true;
|
|
1329
1338
|
const lane = this.spaceLane;
|
|
1330
1339
|
switch (lane.state) {
|
|
@@ -1409,7 +1418,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
1409
1418
|
async killPodProcesses() {
|
|
1410
1419
|
if (!this.podName)
|
|
1411
1420
|
return false;
|
|
1412
|
-
const r = await this.runExec(buildKillAllScript(), { timeoutMs: this.cfg.rpcTimeoutMs + KILL_ALL_RECHECK_MS });
|
|
1421
|
+
const r = await this.runExec(ADAPTER_START, buildKillAllScript(), { timeoutMs: this.cfg.rpcTimeoutMs + KILL_ALL_RECHECK_MS });
|
|
1413
1422
|
return r.ok && r.value.exitCode === 0;
|
|
1414
1423
|
}
|
|
1415
1424
|
async persistWorkspace(space) {
|
|
@@ -1462,23 +1471,124 @@ export class RemoteK8sExecutionEnv {
|
|
|
1462
1471
|
await this.endSpace(space);
|
|
1463
1472
|
}
|
|
1464
1473
|
}
|
|
1465
|
-
|
|
1474
|
+
async ensureFloorSeat(signal) {
|
|
1475
|
+
const seat = buildFloorPodSeat(this.floor);
|
|
1476
|
+
if (seat === undefined)
|
|
1477
|
+
return undefined;
|
|
1478
|
+
if (seat.configMaps.length === 0) {
|
|
1479
|
+
this.floor.refusePlacement("this server carries no pinned supervisor build");
|
|
1480
|
+
return undefined;
|
|
1481
|
+
}
|
|
1482
|
+
for (const cm of seat.configMaps) {
|
|
1483
|
+
const body = { apiVersion: "v1", kind: "ConfigMap", metadata: { name: cm.name }, immutable: true, binaryData: { [FLOOR_K8S_CONFIGMAP_KEY]: cm.binaryDataB64 } };
|
|
1484
|
+
let r;
|
|
1485
|
+
try {
|
|
1486
|
+
r = await this.request("POST", `/api/v1/namespaces/${this.cfg.namespace}/configmaps`, body, { signal });
|
|
1487
|
+
}
|
|
1488
|
+
catch (e) {
|
|
1489
|
+
this.floor.refusePlacement(`creating the supervisor ConfigMap ${cm.name} failed: ${errorMessageOf(e)}`);
|
|
1490
|
+
return undefined;
|
|
1491
|
+
}
|
|
1492
|
+
if (r.status !== 409 && (r.status < 200 || r.status >= 300)) {
|
|
1493
|
+
this.floor.refusePlacement(`creating the supervisor ConfigMap ${cm.name} was answered ${r.status}${r.status === 401 || r.status === 403 ? " (the server's service account needs create on configmaps in this namespace)" : ""}`);
|
|
1494
|
+
return undefined;
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
return seat;
|
|
1498
|
+
}
|
|
1499
|
+
floorTransport() {
|
|
1500
|
+
return {
|
|
1501
|
+
bootstrap: async (command) => {
|
|
1502
|
+
const r = await this.runExec(BOOTSTRAP_START, command, { timeoutMs: this.cfg.rpcTimeoutMs });
|
|
1503
|
+
return r.ok ? { ok: true, exitCode: r.value.exitCode, stdout: r.value.stdout, stderr: r.value.stderr } : { ok: false, error: r.error.message };
|
|
1504
|
+
},
|
|
1505
|
+
place: async () => ({ ok: true }),
|
|
1506
|
+
openRelay: (identity, command, events) => {
|
|
1507
|
+
let closed = false;
|
|
1508
|
+
const close = (why) => {
|
|
1509
|
+
if (closed)
|
|
1510
|
+
return;
|
|
1511
|
+
closed = true;
|
|
1512
|
+
events.closed(why);
|
|
1513
|
+
};
|
|
1514
|
+
switch (identity) {
|
|
1515
|
+
case "root":
|
|
1516
|
+
queueMicrotask(() => close("a k8s exec cannot start the relay as root"));
|
|
1517
|
+
return { send: () => { }, close: () => { } };
|
|
1518
|
+
case "exec-user":
|
|
1519
|
+
break;
|
|
1520
|
+
}
|
|
1521
|
+
let sock;
|
|
1522
|
+
try {
|
|
1523
|
+
const { url, headers } = this.execUrl(["sh", "-c", command], true);
|
|
1524
|
+
sock = this.openExec(url, headers);
|
|
1525
|
+
}
|
|
1526
|
+
catch (e) {
|
|
1527
|
+
queueMicrotask(() => close(`the relay exec could not be opened: ${errorMessageOf(e)}`));
|
|
1528
|
+
return { send: () => { }, close: () => { } };
|
|
1529
|
+
}
|
|
1530
|
+
const decoder = new StringDecoder("utf8");
|
|
1531
|
+
let open = false;
|
|
1532
|
+
const pending = [];
|
|
1533
|
+
const write = (frame) => {
|
|
1534
|
+
if (sock.send === undefined)
|
|
1535
|
+
return close("the exec socket cannot write (no stdin channel)");
|
|
1536
|
+
try {
|
|
1537
|
+
sock.send(frame);
|
|
1538
|
+
}
|
|
1539
|
+
catch (e) {
|
|
1540
|
+
close(`writing to the relay failed: ${errorMessageOf(e)}`);
|
|
1541
|
+
}
|
|
1542
|
+
};
|
|
1543
|
+
sock.on("open", () => {
|
|
1544
|
+
open = true;
|
|
1545
|
+
for (const f of pending.splice(0))
|
|
1546
|
+
write(f);
|
|
1547
|
+
});
|
|
1548
|
+
sock.on("message", (...args) => {
|
|
1549
|
+
const data = args[0];
|
|
1550
|
+
const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
1551
|
+
if (buf.length > 1 && buf[0] === 1)
|
|
1552
|
+
events.data(decoder.write(buf.subarray(1)));
|
|
1553
|
+
});
|
|
1554
|
+
sock.on("close", () => close("the relay exec closed"));
|
|
1555
|
+
sock.on("error", (e) => close(`the relay exec failed: ${errorMessageOf(e)}`));
|
|
1556
|
+
return {
|
|
1557
|
+
send: (line) => {
|
|
1558
|
+
const frame = Buffer.concat([Buffer.from([0]), Buffer.from(line, "utf8")]);
|
|
1559
|
+
if (open)
|
|
1560
|
+
write(frame);
|
|
1561
|
+
else
|
|
1562
|
+
pending.push(frame);
|
|
1563
|
+
},
|
|
1564
|
+
close: () => (sock.terminate ?? sock.close).call(sock),
|
|
1565
|
+
};
|
|
1566
|
+
},
|
|
1567
|
+
};
|
|
1568
|
+
}
|
|
1569
|
+
execUrl(argv, stdin = false) {
|
|
1466
1570
|
const { apiUrl, token } = this.creds();
|
|
1467
1571
|
const base = apiUrl.replace(/^http/, "ws");
|
|
1468
1572
|
const q = new URLSearchParams();
|
|
1469
1573
|
q.append("container", "sandbox");
|
|
1574
|
+
if (stdin)
|
|
1575
|
+
q.append("stdin", "true");
|
|
1470
1576
|
q.append("stdout", "true");
|
|
1471
1577
|
q.append("stderr", "true");
|
|
1472
|
-
for (const part of
|
|
1578
|
+
for (const part of argv)
|
|
1473
1579
|
q.append("command", part);
|
|
1474
1580
|
return { url: `${base}/api/v1/namespaces/${this.cfg.namespace}/pods/${this.podName}/exec?${q.toString()}`, headers: { authorization: `Bearer ${token}` } };
|
|
1475
1581
|
}
|
|
1476
|
-
runExec(command, opts) {
|
|
1582
|
+
runExec(start, command, opts) {
|
|
1583
|
+
const launch = this.floor.wrap(start);
|
|
1584
|
+
if (!launch.ok)
|
|
1585
|
+
return Promise.resolve(launch);
|
|
1586
|
+
opts?.onLaunch?.(launch.value);
|
|
1477
1587
|
let sock;
|
|
1478
1588
|
let headers;
|
|
1479
1589
|
let url;
|
|
1480
1590
|
try {
|
|
1481
|
-
({ url, headers } = this.execUrl(command));
|
|
1591
|
+
({ url, headers } = this.execUrl(floorArgv(launch.value, ["sh", "-c", command])));
|
|
1482
1592
|
sock = this.openExec(url, headers);
|
|
1483
1593
|
}
|
|
1484
1594
|
catch (e) {
|
|
@@ -1672,12 +1782,12 @@ export class RemoteK8sExecutionEnv {
|
|
|
1672
1782
|
});
|
|
1673
1783
|
}
|
|
1674
1784
|
async exec(command, options) {
|
|
1675
|
-
return this.execCall(createCwdGuardedCall("k8s", command, this.workingDirOf(options?.cwd), options?.env), options);
|
|
1785
|
+
return this.execCall(engineStart(options?.readFloor), createCwdGuardedCall("k8s", command, this.workingDirOf(options?.cwd), options?.env), options);
|
|
1676
1786
|
}
|
|
1677
1787
|
fsExec(command, abortSignal) {
|
|
1678
|
-
return this.execCall(createCwdGuardedCall("k8s", command, undefined, undefined), { abortSignal });
|
|
1788
|
+
return this.execCall(ADAPTER_START, createCwdGuardedCall("k8s", command, undefined, undefined), { abortSignal });
|
|
1679
1789
|
}
|
|
1680
|
-
async execCall(call, options) {
|
|
1790
|
+
async execCall(start, call, options) {
|
|
1681
1791
|
const c = await this.ensureConnected();
|
|
1682
1792
|
if (!c.ok)
|
|
1683
1793
|
return c;
|
|
@@ -1686,7 +1796,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
1686
1796
|
const abortSignal = options?.abortSignal ? AbortSignal.any([options.abortSignal, inflight.signal]) : inflight.signal;
|
|
1687
1797
|
try {
|
|
1688
1798
|
if (!detachSignal) {
|
|
1689
|
-
return call.settle(await this.runExec(call.command, {
|
|
1799
|
+
return call.settle(await this.runExec(start, call.command, {
|
|
1690
1800
|
signal: abortSignal,
|
|
1691
1801
|
timeoutMs: options?.timeout != null ? options.timeout * 1000 : undefined,
|
|
1692
1802
|
boundOutput: true,
|
|
@@ -1698,7 +1808,10 @@ export class RemoteK8sExecutionEnv {
|
|
|
1698
1808
|
const adoptId = randomUUID();
|
|
1699
1809
|
const dir = `${K8S_BG_DIR_ROOT}/exec-${adoptId}`;
|
|
1700
1810
|
const tee = { out: seedMemStream(""), err: seedMemStream("") };
|
|
1701
|
-
|
|
1811
|
+
let startId;
|
|
1812
|
+
let adoptedHere = false;
|
|
1813
|
+
const settled = call.settle(await this.runExec(start.kind === "engine" ? engineStart(start.readFloor, true) : start, buildDetachCapableExec(dir, call.command), {
|
|
1814
|
+
onLaunch: (l) => void (startId = l.mode === "run" ? l.startId : undefined),
|
|
1702
1815
|
signal: abortSignal,
|
|
1703
1816
|
timeoutMs: options?.timeout != null ? options.timeout * 1000 : undefined,
|
|
1704
1817
|
boundOutput: true,
|
|
@@ -1715,12 +1828,17 @@ export class RemoteK8sExecutionEnv {
|
|
|
1715
1828
|
data: (channel, payload) => feedMemStream(channel === 1 ? mem.out : mem.err, payload, K8S_BG_MEM_CAP),
|
|
1716
1829
|
closed: (terminal) => ctx.onTerminal(terminal.failed, terminal.exitCode),
|
|
1717
1830
|
});
|
|
1718
|
-
return { jobId: adoptId, dir, stdoutCursor: 0, stderrCursor: 0, adopt: { mem, sock: io.sock } };
|
|
1831
|
+
return { jobId: adoptId, dir, stdoutCursor: 0, stderrCursor: 0, adopt: { mem, sock: io.sock }, ...(startId !== undefined ? { startId } : {}) };
|
|
1719
1832
|
});
|
|
1833
|
+
if (adopted !== undefined)
|
|
1834
|
+
adoptedHere = true;
|
|
1720
1835
|
return adopted?.shellId;
|
|
1721
1836
|
},
|
|
1722
1837
|
},
|
|
1723
1838
|
}));
|
|
1839
|
+
if (!adoptedHere)
|
|
1840
|
+
this.floor.release(startId);
|
|
1841
|
+
return settled;
|
|
1724
1842
|
}
|
|
1725
1843
|
finally {
|
|
1726
1844
|
this.endExec(inflight);
|
|
@@ -1758,7 +1876,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
1758
1876
|
const cap = options?.maxOutputBytes;
|
|
1759
1877
|
let bytes = 0;
|
|
1760
1878
|
const signal = options?.signal ? AbortSignal.any([options.signal, ac.signal]) : ac.signal;
|
|
1761
|
-
const done = this.runExec(buildCwdEnvCommand(command, this.workingDirOf(options?.cwd), options?.env, "raw").command, {
|
|
1879
|
+
const done = this.runExec(engineStart(undefined), buildCwdEnvCommand(command, this.workingDirOf(options?.cwd), options?.env, "raw").command, {
|
|
1762
1880
|
signal,
|
|
1763
1881
|
timeoutMs: options?.timeout != null ? options.timeout * 1000 : undefined,
|
|
1764
1882
|
readTimeoutMs: options?.readTimeoutMs,
|
|
@@ -1827,7 +1945,8 @@ export class RemoteK8sExecutionEnv {
|
|
|
1827
1945
|
}
|
|
1828
1946
|
makeBgDriver() {
|
|
1829
1947
|
const self = this;
|
|
1830
|
-
const bgExec = (script, boundOutput) => self.runExec(script, { timeoutMs: self.cfg.rpcTimeoutMs, boundOutput });
|
|
1948
|
+
const bgExec = (start, script, boundOutput, onLaunch) => self.runExec(start, script, { timeoutMs: self.cfg.rpcTimeoutMs, boundOutput, ...(onLaunch !== undefined ? { onLaunch } : {}) });
|
|
1949
|
+
const under = (state) => ({ kind: "under", startId: state.startId });
|
|
1831
1950
|
return {
|
|
1832
1951
|
async launch(command, options, ctx) {
|
|
1833
1952
|
const conn = await self.ensureConnected();
|
|
@@ -1838,14 +1957,17 @@ export class RemoteK8sExecutionEnv {
|
|
|
1838
1957
|
const inner = buildCwdEnvCommand(command, self.workingDirOf(options?.cwd), options?.env, "raw").command;
|
|
1839
1958
|
const cmdB64 = Buffer.from(inner, "utf8").toString("base64");
|
|
1840
1959
|
const runnerB64 = Buffer.from(buildBgRunnerScript(dir), "utf8").toString("base64");
|
|
1841
|
-
|
|
1960
|
+
let startId;
|
|
1961
|
+
const r = await bgExec(engineStart(options?.readFloor, true), buildBgLauncherScript(dir, cmdB64, runnerB64), true, (l) => void (startId = l.mode === "run" ? l.startId : undefined));
|
|
1962
|
+
if (!r.ok || r.value.exitCode !== 0 || !r.value.stdout.includes("SEMABG_LAUNCHED"))
|
|
1963
|
+
self.floor.release(startId);
|
|
1842
1964
|
if (!r.ok)
|
|
1843
1965
|
throw new Error(`background launch failed: ${r.error.message}`);
|
|
1844
1966
|
if (r.value.exitCode !== 0 || !r.value.stdout.includes("SEMABG_LAUNCHED")) {
|
|
1845
1967
|
throw new Error(`background launch exited ${r.value.exitCode}: ${r.value.stderr.slice(0, 200)}`);
|
|
1846
1968
|
}
|
|
1847
1969
|
void ctx;
|
|
1848
|
-
return { jobId, dir, stdoutCursor: 0, stderrCursor: 0 };
|
|
1970
|
+
return { jobId, dir, stdoutCursor: 0, stderrCursor: 0, ...(startId !== undefined ? { startId } : {}) };
|
|
1849
1971
|
},
|
|
1850
1972
|
async read(state) {
|
|
1851
1973
|
if (state.adopt) {
|
|
@@ -1858,7 +1980,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
1858
1980
|
bytesDroppedBeforeCursor: o.dropped + e.dropped,
|
|
1859
1981
|
};
|
|
1860
1982
|
}
|
|
1861
|
-
const r = await bgExec(buildBgPollScript(state.dir, state.stdoutCursor, state.stderrCursor, K8S_BG_READ_CAP), false);
|
|
1983
|
+
const r = await bgExec(under(state), buildBgPollScript(state.dir, state.stdoutCursor, state.stderrCursor, K8S_BG_READ_CAP), false);
|
|
1862
1984
|
if (!r.ok)
|
|
1863
1985
|
throw new Error(`background poll failed: ${r.error.message}`);
|
|
1864
1986
|
const p = parseBgPollOutput(r.value.stdout);
|
|
@@ -1873,7 +1995,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
1873
1995
|
state.stderrCursor = p.errTotal;
|
|
1874
1996
|
let terminal = p.exitCode !== undefined ? { failed: false, exitCode: p.exitCode } : !p.alive ? { failed: true } : undefined;
|
|
1875
1997
|
if (!terminal && (p.outTotal > K8S_BG_FILE_CAP || p.errTotal > K8S_BG_FILE_CAP)) {
|
|
1876
|
-
void bgExec(buildBgKillScript(state.dir), true).catch(() => { });
|
|
1998
|
+
void bgExec(under(state), buildBgKillScript(state.dir), true).catch(() => { });
|
|
1877
1999
|
terminal = { failed: true };
|
|
1878
2000
|
}
|
|
1879
2001
|
return {
|
|
@@ -1885,7 +2007,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
1885
2007
|
};
|
|
1886
2008
|
},
|
|
1887
2009
|
async kill(state) {
|
|
1888
|
-
await bgExec(buildBgKillScript(state.dir), true).catch(() => { });
|
|
2010
|
+
await bgExec(under(state), buildBgKillScript(state.dir), true).catch(() => { });
|
|
1889
2011
|
},
|
|
1890
2012
|
async disposeOne(state) {
|
|
1891
2013
|
const closeAdopted = () => {
|
|
@@ -1898,10 +2020,12 @@ export class RemoteK8sExecutionEnv {
|
|
|
1898
2020
|
};
|
|
1899
2021
|
if (self.destroyed) {
|
|
1900
2022
|
closeAdopted();
|
|
2023
|
+
self.floor.release(state.startId);
|
|
1901
2024
|
return;
|
|
1902
2025
|
}
|
|
1903
|
-
await bgExec(buildBgDisposeScript(state.dir), true).catch(() => { });
|
|
2026
|
+
await bgExec(under(state), buildBgDisposeScript(state.dir), true).catch(() => { });
|
|
1904
2027
|
closeAdopted();
|
|
2028
|
+
self.floor.release(state.startId);
|
|
1905
2029
|
},
|
|
1906
2030
|
};
|
|
1907
2031
|
}
|
|
@@ -2012,7 +2136,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
2012
2136
|
const c = await this.ensureConnected();
|
|
2013
2137
|
if (!c.ok)
|
|
2014
2138
|
return c;
|
|
2015
|
-
return this.runExec(command, { signal: abortSignal, capMs: this.cfg.dataTimeoutMs });
|
|
2139
|
+
return this.runExec(ADAPTER_START, command, { signal: abortSignal, capMs: this.cfg.dataTimeoutMs });
|
|
2016
2140
|
}
|
|
2017
2141
|
workingDirOf(cwd) {
|
|
2018
2142
|
const dir = cwd ?? this.cwd;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { type LaneHomeConfig } from "../lane-home-probe.js";
|
|
3
|
-
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 } from "@sema-agent/core";
|
|
3
|
+
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 ExecutionEnvCapabilities } from "@sema-agent/core";
|
|
4
|
+
import { type SandboxReadFloorKnob } from "../execution-lane-caps.js";
|
|
5
|
+
import { type SandboxReadFloor } from "./sandbox-read-floor.js";
|
|
4
6
|
/** Options accepted by `ExecutionEnv.exec` (core does not re-export the type; derive it from the seam). */
|
|
5
7
|
type ExecOpts = Parameters<ExecutionEnv["exec"]>[1];
|
|
6
8
|
/** Construction config for {@link RemoteLocalDockerExecutionEnv}. */
|
|
@@ -55,28 +57,23 @@ export interface LocalDockerEnvConfig extends LaneHomeConfig {
|
|
|
55
57
|
/** Stable id mixed into the container NAME (e.g. the sessionId). A random suffix is always appended so two
|
|
56
58
|
* envs sharing an id never collide. Default = a random id. */
|
|
57
59
|
id?: string;
|
|
60
|
+
/** `SANDBOX_READ_FLOOR`(keep | off;缺席 ⇒ keep):本容器守不守读拒表的字节地板 = 读地板模块服务本车道 ∧ 本键不是 off(`sandbox-read-floor.ts`)。 */
|
|
61
|
+
sandboxReadFloor?: SandboxReadFloorKnob;
|
|
58
62
|
}
|
|
59
63
|
/** Inject `spawn` for tests (a fake docker CLI). Defaults to node's child_process spawn. */
|
|
60
64
|
export interface LocalDockerEnvDeps {
|
|
61
65
|
spawn?: typeof spawn;
|
|
66
|
+
/** 这只环境手里的读地板模块(缺席 ⇒ `createSandboxReadFloor` 按旋钮选;钉注入守地板的模块)。能力块的 `keepsReadFloor` 读它的状态。 */
|
|
67
|
+
readFloor?: SandboxReadFloor;
|
|
62
68
|
}
|
|
63
69
|
export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv {
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
readonly
|
|
68
|
-
isolation: true;
|
|
69
|
-
suspendable: false;
|
|
70
|
-
canonicalPathAuthoritative: true;
|
|
71
|
-
sharesProcessTable: false;
|
|
72
|
-
hostLocalPaths: false;
|
|
73
|
-
externalContentTarget: false;
|
|
74
|
-
io: true;
|
|
75
|
-
keepsReadFloor: false;
|
|
76
|
-
};
|
|
70
|
+
/** 能力块的唯一作者 = `capabilitiesFor`(`execution-lane-caps.ts`;逐键表态与理由在那里,本类零能力字面量)。读地板旋钮是它的输入,{@link floor} 由同一只判据、同一个旋钮值选出。 */
|
|
71
|
+
readonly capabilities: ExecutionEnvCapabilities;
|
|
72
|
+
/** 读拒表字节地板模块:容器里每一次 `docker exec` 起动都先经它的 `wrap`({@link startArgv},唯一接缝)。 */
|
|
73
|
+
private readonly floor;
|
|
77
74
|
/** Working directory inside the container; relative paths resolve against it (ExecutionEnv contract). */
|
|
78
75
|
cwd: string;
|
|
79
|
-
/** core `ExecutionEnv.homeDir`([ref]):本容器里执行用户的 home ——
|
|
76
|
+
/** core `ExecutionEnv.homeDir`([ref]):本容器里执行用户的 home —— 声明在场 ⇒ 声明(开环境那一拍与 `$HOME` 对证过),否则开容器那一拍实测的 `$HOME`,见 {@link LaneHomeSeat}。读时才取(没声明时连上之前缺席)。 */
|
|
80
77
|
get homeDir(): string | undefined;
|
|
81
78
|
/** core 7.49.0 [ref]:shell 子进程真拿到的 `CDPATH` 条目 —— 本车道的命令跑在容器里(镜像的 env),本类不读那份 env ⇒ `"unknown"`(core 契约:说不出就说 unknown,
|
|
82
79
|
* 不许报一张没读过的空表;删除守卫因此对裸 `cd <相对名>` 之后的删除问人,而不是按「没有 CDPATH」放行)。 */
|
|
@@ -97,7 +94,7 @@ export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv
|
|
|
97
94
|
private connecting?;
|
|
98
95
|
/** 家目录:环境答了而与声明不一致 ⇒ 这只环境的拒,记一次、此后每次连接原样回它(同一镜像同一答案:不再起容器、不再问)。 */
|
|
99
96
|
private homeRefusal?;
|
|
100
|
-
/** 家目录的座(
|
|
97
|
+
/** 家目录的座(声明在场 ⇒ 开环境那一拍对证 · 否则开容器那一拍实测 · 实测缺席 ⇒ 缺席 + 一行 warn)。与其余读得出家目录的车道同一只判官、同一句拒。 */
|
|
101
98
|
private readonly homeSeat;
|
|
102
99
|
constructor(config: LocalDockerEnvConfig, deps?: LocalDockerEnvDeps);
|
|
103
100
|
private resolve;
|
|
@@ -170,7 +167,7 @@ export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv
|
|
|
170
167
|
}): Promise<Result<string[], FileError>>;
|
|
171
168
|
/** 暂存写的两只面(规则与提交脚本的唯一属主 = `remote-shell.ts` `writeFileStaged` / `appendFileStaged`;父目录与私有暂存目录由编排的准备那一步建):
|
|
172
169
|
* 上传 = 容器内 `cat` 从 stdin 收整份字节落到私有目录里的暂存件({@link pipeIn});提交 = 容器内一次 shell 往返。两者同一身份 ——
|
|
173
|
-
* 同一只 argv 构造({@link
|
|
170
|
+
* 同一只 argv 构造({@link startArgv}),都是镜像的用户。不用 `docker cp`:它由守护进程以 root 落盘,镜像用户 ≠ root 时暂存件属 root、
|
|
174
171
|
* 提交方拿不走也清不掉,「目录不收新名字」也探不出来(root 哪里都写得进)。 */
|
|
175
172
|
private stagedLane;
|
|
176
173
|
/** 整旧或整新(暂存 → 一次 `mv -f`)。修前 `docker cp` 直落目标(以守护进程的 root 身份):传输中途断 / 取消时目标剩什么取决于守护进程的解包实现,本适配器不依赖它。 */
|
|
@@ -216,17 +213,23 @@ export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv
|
|
|
216
213
|
/**
|
|
217
214
|
* 交给宿主 `docker` CLI 的 env —— 宿主子进程 env 的唯一组合(`server-secret-env.ts` `hostSubprocessEnv`),继承词 `"all"`:本服务自有凭据(起服声明的名与值)
|
|
218
215
|
* 任何词都不交,CLI 与它拉起的凭据助手 / CLI 插件要读的变量(`DOCKER_*` / `AWS_*` …)照交 —— 形状剥会剥 `AWS_SECRET_ACCESS_KEY` 一类,ECR / GCR 凭据助手因此断。
|
|
219
|
-
* 命令本身跑在容器里,容器的 env 只由 `
|
|
216
|
+
* 命令本身跑在容器里,容器的 env 只由 `startArgv` 的 `-e K=V` 显式给,本 env 到不了容器。每次起进程现算一次(与 host shell 同)。
|
|
220
217
|
*/
|
|
221
218
|
private cliEnv;
|
|
222
219
|
/** Prepend `-H <dockerHost>` to a docker argv when configured (per-invocation, not the process env). */
|
|
223
220
|
private withHostFlag;
|
|
224
|
-
/**
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
221
|
+
/**
|
|
222
|
+
* **唯一起动接缝**:容器里的每一次 `docker exec` 起动(引擎的命令、文件面助手、探针、地板的引导命令)都从这里拿 argv —— 先问地板模块
|
|
223
|
+
* `wrap(起动形)`,再按答案编码(身份旗标 + 监督者命令行头;不守地板 ⇒ 与改前逐字同)。本适配器对地板零判断;模块拒 ⇒ `spawn_error`,命令从未起。
|
|
224
|
+
* argv elements are SEPARATE (no host-side shell join) — the command runs in the CONTAINER's shell (`-c`). `stdin` ⇒ `-i` (the payload of
|
|
225
|
+
* {@link pipeIn}); nothing else differs, so a piped upload runs as the same user as every other exec. cwd (`-w`) and per-command env (`-e K=V`;
|
|
226
|
+
* adapter base env under, per-command wins) — except `containerDefaults`: the command asks about the container's OWN defaults (the shell probe),
|
|
227
|
+
* so it carries neither (the bare argv is then `exec <name> <shell> -c <cmd>`, byte-identical to the pre-floor probe).
|
|
228
|
+
*/
|
|
229
|
+
private startArgv;
|
|
230
|
+
/** 地板模块的三件原语(引导命令 / 放置 / 中继)。引导与放置经 {@link startArgv}(起动形 `bootstrap`:只在附着中合法);中继以模块给的身份起一只
|
|
231
|
+
* 长连的 `docker exec -i`(stdin / stdout 作双工),随本环境 `destroy` 由模块关。 */
|
|
232
|
+
private floorTransport;
|
|
230
233
|
/** Spawn the docker binary with argv; collect stdout/stderr (+ raw bytes when binary), bound by timeout/abort. */
|
|
231
234
|
private docker;
|
|
232
235
|
/** Lazy connect for an exec path → ExecutionError on failure (fail closed, never throws). */
|