@sema-agent/server 7.136.0 → 7.138.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 +501 -139
- package/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/USAGE.md +149 -34
- package/deploy/sema-up/README.md +14 -0
- package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +7 -1
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +7 -1
- package/dist/approval-card.d.ts +21 -14
- package/dist/approval-card.js +1 -0
- package/dist/approval-content-kind.d.ts +6 -0
- package/dist/approval-content-kind.js +7 -0
- package/dist/approval-gate-currency.d.ts +48 -6
- package/dist/approval-gate-currency.js +16 -9
- package/dist/approval-hmac.d.ts +13 -1
- package/dist/approval-hmac.js +1 -1
- package/dist/approval.js +3 -3
- package/dist/audit.js +1 -0
- package/dist/auth-bridge.js +2 -2
- package/dist/background-agent-name.d.ts +5 -0
- package/dist/background-agent-name.js +5 -0
- package/dist/boot/budget-tracing.d.ts +1 -12
- package/dist/boot/deployment-mods.d.ts +46 -16
- package/dist/boot/deployment-mods.js +82 -6
- package/dist/boot/execution-env.d.ts +24 -1
- package/dist/boot/execution-env.js +69 -6
- package/dist/boot/governance-seams.d.ts +10 -17
- package/dist/boot/governance-seams.js +5 -17
- package/dist/boot/leader.d.ts +3 -0
- package/dist/boot/leader.js +1 -0
- package/dist/boot/org-delivery.js +15 -2
- package/dist/boot/reapers.d.ts +3 -0
- package/dist/boot/reapers.js +15 -1
- package/dist/boot/resolve-spec.d.ts +7 -0
- package/dist/boot/resolve-spec.js +36 -26
- package/dist/boot/retention-lane.d.ts +11 -5
- package/dist/boot/retention-lane.js +2 -2
- package/dist/boot/runner-deps.d.ts +7 -3
- package/dist/boot/runner-deps.js +1 -0
- package/dist/boot/stage-03-store-backend.d.ts +1 -1
- package/dist/boot/stage-04-stores.d.ts +2 -13
- package/dist/boot/stage-05-execution-env.d.ts +6 -13
- package/dist/boot/stage-05-execution-env.js +17 -5
- package/dist/boot/stage-06-runners.d.ts +6 -13
- package/dist/boot/stage-06-runners.js +10 -3
- package/dist/boot/stage-07-capability-layer.d.ts +7 -13
- package/dist/boot/stage-07-capability-layer.js +3 -3
- package/dist/boot/stage-08-reapers.d.ts +7 -13
- package/dist/boot/stage-08-reapers.js +2 -1
- package/dist/boot/stage-09-leader.d.ts +7 -13
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +7 -13
- package/dist/boot/stage-10-http-server.js +6 -3
- package/dist/boot/stores.d.ts +1 -1
- package/dist/boot/web-admin.d.ts +5 -2
- package/dist/boot/web-admin.js +3 -3
- package/dist/brain.js +5 -5
- package/dist/broker/broker.d.ts +89 -0
- package/dist/broker/broker.js +287 -0
- package/dist/broker/constants.d.ts +39 -0
- package/dist/broker/constants.js +15 -0
- package/dist/broker/http1.d.ts +111 -0
- package/dist/broker/http1.js +256 -0
- package/dist/broker/lease-book.d.ts +87 -0
- package/dist/broker/lease-book.js +142 -0
- package/dist/broker/lease-file.d.ts +60 -0
- package/dist/broker/lease-file.js +127 -0
- package/dist/broker/main.d.ts +2 -0
- package/dist/broker/main.js +20 -0
- package/dist/budget.d.ts +17 -15
- package/dist/budget.js +2 -2
- package/dist/capabilities/composite-members.d.ts +2 -1
- package/dist/capabilities/composite-members.js +2 -1
- package/dist/capabilities/engine-capabilities.js +1 -0
- package/dist/capabilities/mcp-probe.d.ts +36 -11
- package/dist/capabilities/mcp-probe.js +44 -5
- package/dist/capabilities/scenarios.d.ts +23 -8
- package/dist/capabilities/scenarios.js +13 -8
- package/dist/capabilities/skills.d.ts +28 -5
- package/dist/capabilities/skills.js +8 -0
- package/dist/capability-facts.d.ts +6 -0
- package/dist/capability-facts.js +5 -0
- package/dist/center-credential-renewer.js +5 -1
- package/dist/checkpoint-ctx-seal-m28.d.ts +3 -10
- package/dist/checkpoint-ctx-seal-m28.js +1 -1
- package/dist/checkpoint-identity.d.ts +13 -6
- package/dist/config-catalog.js +16 -7
- package/dist/config-types.d.ts +24 -7
- package/dist/config.d.ts +1 -1
- package/dist/config.js +42 -13
- package/dist/deployment-governance.d.ts +2 -2
- package/dist/deployment-governance.js +7 -9
- package/dist/deployment-shape.d.ts +6 -6
- package/dist/device-ws-protocol.d.ts +1 -0
- package/dist/device-ws-protocol.js +2 -1
- package/dist/file-history-disclosure.d.ts +4 -2
- package/dist/file-history-disclosure.js +2 -0
- package/dist/gate-settlement.d.ts +71 -0
- package/dist/gate-settlement.js +40 -0
- package/dist/hooks/classic-stations.d.ts +12 -54
- package/dist/hooks/classic-stations.js +1 -0
- package/dist/hooks/command-spawn.d.ts +2 -2
- package/dist/hooks/hook-runner.js +14 -14
- package/dist/http/admission.js +14 -9
- package/dist/http/approval-sweeps.js +4 -3
- package/dist/http/caller-trust.d.ts +2 -1
- package/dist/http/caller-trust.js +1 -3
- package/dist/http/checkpoint-ctx.d.ts +48 -7
- package/dist/http/checkpoint-ctx.js +40 -0
- package/dist/http/dispatch.d.ts +4 -0
- package/dist/http/dispatch.js +18 -10
- package/dist/http/durable-run-leg.d.ts +5 -1
- package/dist/http/durable-run-leg.js +5 -3
- package/dist/http/health-self-report.d.ts +2 -2
- package/dist/http/memory-compliance-failure-reply.js +3 -0
- package/dist/http/principal-gate.d.ts +15 -10
- package/dist/http/principal-gate.js +48 -9
- package/dist/http/resume-legs.d.ts +7 -31
- package/dist/http/resume-legs.js +185 -126
- package/dist/http/route-ctx.d.ts +38 -53
- package/dist/http/route-ctx.js +2 -5
- package/dist/http/routes/a2a-serve.js +10 -4
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/agents-roster.js +5 -1
- package/dist/http/routes/approvals-assistant.js +24 -10
- package/dist/http/routes/capabilities.js +23 -11
- package/dist/http/routes/mcp-reconnect.d.ts +3 -2
- package/dist/http/routes/mcp-reconnect.js +7 -7
- package/dist/http/routes/memory-consolidation.d.ts +1 -1
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/rules.js +3 -3
- package/dist/http/routes/runs.js +13 -8
- package/dist/http/routes/session-sync.js +42 -6
- package/dist/http/routes/sessions.js +6 -3
- package/dist/http/routes/side-query.js +2 -3
- package/dist/http/routes/tasks.js +794 -780
- package/dist/http/server.d.ts +35 -25
- package/dist/http/stored-body-replay.d.ts +3 -3
- package/dist/http/stored-body-replay.js +6 -1
- package/dist/http/wire-types.d.ts +66 -33
- package/dist/identity-source.d.ts +65 -0
- package/dist/identity-source.js +45 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/leader/wire.d.ts +7 -0
- package/dist/leader/wire.js +5 -4
- package/dist/mcp-assertion-header.d.ts +51 -40
- package/dist/mcp-assertion-header.js +10 -11
- package/dist/mcp-authorization-face.d.ts +27 -0
- package/dist/mcp-authorization-face.js +15 -0
- package/dist/memory-operator-faces.d.ts +13 -4
- package/dist/memory-operator-faces.js +1 -17
- package/dist/memory-store-refusal.d.ts +3 -3
- package/dist/memory-sync-client.js +72 -57
- package/dist/memory-sync.d.ts +1 -1
- package/dist/model-entry-refusal.d.ts +2 -0
- package/dist/model-entry-refusal.js +11 -0
- package/dist/model-route-gap.d.ts +6 -22
- package/dist/model-route-gap.js +7 -5
- package/dist/model-select.d.ts +6 -17
- package/dist/model-select.js +0 -3
- package/dist/mods-declaration.d.ts +110 -0
- package/dist/mods-declaration.js +109 -0
- package/dist/namespaced-rule-name.d.ts +1 -1
- package/dist/observability/err-text.d.ts +5 -0
- package/dist/observability/err-text.js +9 -0
- package/dist/observability/fail-open.d.ts +17 -1
- package/dist/observability/fail-open.js +17 -1
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/run-terminal.js +1 -0
- package/dist/observability/secret-env-scrub.d.ts +1 -1
- package/dist/observability/secret-env-scrub.js +1 -1
- package/dist/operator-ask.d.ts +2 -2
- package/dist/org-delivery-gate.js +1 -1
- package/dist/org-memory-admission.d.ts +2 -2
- package/dist/org-memory-admission.js +39 -2
- package/dist/parked-decide.d.ts +15 -2
- package/dist/parked-decide.js +17 -10
- package/dist/peer-directory.js +2 -0
- package/dist/peer-seat.d.ts +150 -0
- package/dist/peer-seat.js +239 -0
- package/dist/permission-rule-list.d.ts +2 -2
- package/dist/permission-rule-vocab.d.ts +7 -7
- package/dist/permission-rule-vocab.js +3 -3
- package/dist/plain-string-record.d.ts +38 -0
- package/dist/plain-string-record.js +38 -0
- package/dist/plugins/background-agent-store-sql.js +6 -3
- package/dist/plugins/caching-session-store.d.ts +5 -0
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +34 -29
- package/dist/plugins/checkpoint-store-sql.js +14 -14
- package/dist/plugins/file-history-store-sql.js +10 -16
- package/dist/plugins/file-run-store.js +8 -2
- package/dist/plugins/k8s-exec-protocol.d.ts +69 -13
- package/dist/plugins/k8s-exec-protocol.js +116 -28
- package/dist/plugins/k8s-pod-delete-failure.d.ts +25 -0
- package/dist/plugins/k8s-pod-delete-failure.js +17 -0
- package/dist/plugins/k8s-pod-reaper.d.ts +106 -0
- package/dist/plugins/k8s-pod-reaper.js +122 -0
- package/dist/plugins/local-checkpoint-store.d.ts +4 -17
- package/dist/plugins/local-checkpoint-store.js +3 -4
- package/dist/plugins/local-session-store.d.ts +66 -27
- package/dist/plugins/local-session-store.js +60 -28
- package/dist/plugins/mailbox-store-sql.d.ts +11 -3
- package/dist/plugins/mailbox-store-sql.js +103 -15
- package/dist/plugins/memory-run-store.js +2 -0
- package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
- package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
- package/dist/plugins/one-time-migrations.d.ts +34 -12
- package/dist/plugins/one-time-migrations.js +51 -9
- package/dist/plugins/permission-rule-store-file.js +2 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +17 -17
- package/dist/plugins/permission-rule-store-sql.js +37 -30
- package/dist/plugins/pg-pool.js +4 -0
- package/dist/plugins/pg-session-storage.d.ts +10 -2
- package/dist/plugins/pg-session-storage.js +20 -7
- package/dist/plugins/remote-env-adb.d.ts +6 -1
- package/dist/plugins/remote-env-adb.js +2 -1
- package/dist/plugins/remote-env-device.d.ts +6 -1
- package/dist/plugins/remote-env-device.js +5 -1
- package/dist/plugins/remote-env-e2b.d.ts +5 -0
- package/dist/plugins/remote-env-e2b.js +2 -1
- package/dist/plugins/remote-env-file-error.d.ts +8 -1
- package/dist/plugins/remote-env-file-error.js +7 -1
- package/dist/plugins/remote-env-host.d.ts +10 -2
- package/dist/plugins/remote-env-host.js +8 -2
- package/dist/plugins/remote-env-k8s.d.ts +140 -11
- package/dist/plugins/remote-env-k8s.js +277 -15
- package/dist/plugins/remote-env-local-docker.d.ts +5 -0
- package/dist/plugins/remote-env-local-docker.js +2 -1
- package/dist/plugins/remote-env-ssh.d.ts +6 -1
- package/dist/plugins/remote-env-ssh.js +2 -1
- package/dist/plugins/retention-store-sql.d.ts +14 -2
- package/dist/plugins/retention-store-sql.js +6 -0
- package/dist/plugins/run-store-sql.js +10 -4
- package/dist/plugins/session-fork.d.ts +10 -13
- package/dist/plugins/session-fork.js +5 -25
- package/dist/plugins/session-ownership.d.ts +24 -3
- package/dist/plugins/session-ownership.js +24 -5
- package/dist/plugins/session-workspace-cell.d.ts +17 -0
- package/dist/plugins/session-workspace-cell.js +38 -0
- package/dist/plugins/sql-errors.d.ts +23 -2
- package/dist/plugins/sql-errors.js +15 -0
- package/dist/plugins/store-backend.js +7 -7
- package/dist/plugins/store-contracts.d.ts +10 -1
- package/dist/plugins/store-fault.d.ts +2 -2
- package/dist/plugins/store-fault.js +4 -2
- package/dist/plugins/tidb-pool.js +13 -0
- package/dist/plugins/tidb-session-store.d.ts +17 -2
- package/dist/plugins/tidb-session-store.js +18 -7
- package/dist/plugins/tool-result-store-sql.d.ts +13 -6
- package/dist/plugins/tool-result-store-sql.js +8 -7
- package/dist/plugins/worktree-isolation.d.ts +3 -2
- package/dist/plugins/worktree-isolation.js +1 -7
- package/dist/project-identity.d.ts +1 -14
- package/dist/project-identity.js +0 -4
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +31 -2
- package/dist/request-value-closure.js +7 -1
- package/dist/rule-entry-list.d.ts +3 -2
- package/dist/rule-entry-list.js +2 -2
- package/dist/rules-consent.js +12 -7
- package/dist/run-local.d.ts +2 -2
- package/dist/run-local.js +12 -6
- package/dist/runs.d.ts +7 -1
- package/dist/runs.js +8 -2
- package/dist/runtime-governance.d.ts +5 -5
- package/dist/sandbox-git-lease.d.ts +49 -0
- package/dist/sandbox-git-lease.js +60 -0
- package/dist/sandbox-git-plane.d.ts +84 -0
- package/dist/sandbox-git-plane.js +105 -0
- package/dist/security.d.ts +16 -4
- package/dist/security.js +8 -3
- package/dist/server-secret-env.d.ts +12 -3
- package/dist/server-secret-env.js +18 -2
- package/dist/session-error-wire.d.ts +14 -6
- package/dist/session-error-wire.js +2 -1
- package/dist/session-incarnation.d.ts +4 -5
- package/dist/session-incarnation.js +2 -2
- package/dist/session-policy-wire.d.ts +1 -1
- package/dist/session-policy-wire.js +2 -2
- package/dist/session-sync.d.ts +1 -1
- package/dist/session-workspace.d.ts +130 -0
- package/dist/session-workspace.js +83 -0
- package/dist/spec-fields.d.ts +44 -14
- package/dist/spec-fields.js +33 -12
- package/dist/standing-answer-grant.d.ts +2 -13
- package/dist/standing-answer-grant.js +0 -7
- package/dist/stored-request-prompt-profile-m30.d.ts +49 -0
- package/dist/stored-request-prompt-profile-m30.js +25 -0
- package/dist/task-a2a.d.ts +44 -14
- package/dist/task-a2a.js +46 -20
- package/dist/task-mcp.d.ts +34 -21
- package/dist/task-mcp.js +46 -22
- package/dist/task-settings.d.ts +2 -2
- package/dist/tool-approval.d.ts +43 -9
- package/dist/tool-approval.js +57 -15
- package/dist/tool-rule-names.d.ts +5 -0
- package/dist/trace/core-keyset-guard.d.ts +34 -19
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +4 -0
- package/dist/trace/exit-seat.d.ts +20 -1
- package/dist/trace/exit-seat.js +5 -2
- package/dist/trace/extension-call-face.d.ts +33 -0
- package/dist/trace/extension-call-face.js +39 -0
- package/dist/trace/ledger-sink.d.ts +4 -5
- package/dist/trace/ledger-sink.js +3 -7
- package/dist/trace/project.d.ts +62 -10
- package/dist/trace/project.js +49 -9
- package/dist/trace/redact.d.ts +18 -6
- package/dist/trace/redact.js +154 -60
- package/dist/trace/self-minted-wire.d.ts +500 -7
- package/dist/trace/self-minted-wire.js +182 -1
- package/dist/trace/wire-projection-faces.d.ts +7 -5
- package/dist/trace/wire-projection-faces.js +9 -4
- package/dist/user-authored-text.d.ts +2 -2
- package/dist/user-authored-text.js +16 -1
- package/dist/web-admin-client/apply-effective.js +0 -1
- package/dist/web-admin-client/center-request.d.ts +23 -4
- package/dist/web-admin-client/center-request.js +42 -8
- package/dist/web-admin-client/http-client.js +6 -6
- package/dist/web-admin-client/skills-mcp.d.ts +8 -4
- package/dist/web-admin-client/skills-mcp.js +31 -18
- package/dist/web-admin-client/types.d.ts +10 -5
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +11 -5
- package/package.json +3 -3
- package/wire-changes/server@7.137.0.json +825 -0
- package/wire-changes/server@7.138.0.json +446 -0
|
@@ -14,11 +14,13 @@ import { createLogger } from "../observability/logger.js";
|
|
|
14
14
|
import { classifySyncRelationshipByIds, SyncConflictError, StagedCommitOwnerChangedError, stagingIdFor, STAGING_ID_MARKER, STAGING_GC_GRACE_MS, } from "../session-sync-kernel.js";
|
|
15
15
|
import { isPgUniqueViolation } from "./sql-errors.js";
|
|
16
16
|
import { BASELINE_IO_DEADLINE_MS, decodeInstructionSource, encodeInstructionSource } from "../instruction-source-notice.js";
|
|
17
|
-
import {
|
|
17
|
+
import { SESSION_META_WORKSPACE_COLUMN, decodeSessionWorkspaceCell, encodeSessionWorkspaceCell } from "./session-workspace-cell.js";
|
|
18
|
+
import { MANAGED_RETENTION, UNMANAGED_RETENTION } from "./retention-store-sql.js";
|
|
18
19
|
import { SESSION_META_INCARNATION_COLUMN, carriedIncarnation, headFromRow, incarnationFromCell, mintSessionIncarnation, sessionFaceFromRow } from "../session-incarnation.js";
|
|
19
20
|
import { ensureIndexes } from "./ensure-index.js";
|
|
20
|
-
import { assertFirstOwnerWritable, forkOwnerOf } from "./session-ownership.js";
|
|
21
|
-
import {
|
|
21
|
+
import { assertFirstOwnerWritable, forkOwnerOf, isSessionOwnerValue } from "./session-ownership.js";
|
|
22
|
+
import { selectForkRows } from "@sema-agent/core";
|
|
23
|
+
import { FORK_LOG_ROW_SHAPE, forkPointOf } from "./session-fork.js";
|
|
22
24
|
const isDupKey = isPgUniqueViolation;
|
|
23
25
|
function baselineQuery(text, values) {
|
|
24
26
|
return { text, values, query_timeout: BASELINE_IO_DEADLINE_MS };
|
|
@@ -39,6 +41,8 @@ export const PG_SESSION_SCHEMA = [
|
|
|
39
41
|
pinned BOOLEAN NOT NULL DEFAULT FALSE,
|
|
40
42
|
-- instruction_source(S-690):换源通告的基线 —— TiDB 孪生同名同宽,三态读法(NULL / '' / 链成员相对路径)见那里的列注。
|
|
41
43
|
instruction_source VARCHAR(64) COLLATE "C",
|
|
44
|
+
-- workspace:本会话上一条腿自己的最后一帧 workspace_changed —— TiDB 孪生同名同义(列注与唯一属主见那里:src/plugins/session-workspace-cell.ts)。
|
|
45
|
+
${SESSION_META_WORKSPACE_COLUMN.pg},
|
|
42
46
|
-- #292 C18(core 5.48.0 design/323)subagent 转录持久化 —— placement 元组(TiDB 孪生同名同宽,
|
|
43
47
|
-- 语义与六条义务见 src/plugins/session-placement.ts 顶注):创建时一次落行、first-write 不可变;
|
|
44
48
|
-- placement_kind 在场 ⇒ 住在 placement 分区(不上宿主枚举 / claim 形 acquire 恒拒 / release=真删除 /
|
|
@@ -176,13 +180,14 @@ export class PgSessionStorage extends BaseSessionStorage {
|
|
|
176
180
|
}
|
|
177
181
|
export class PgSessionStore {
|
|
178
182
|
pool;
|
|
179
|
-
retention
|
|
183
|
+
retention;
|
|
180
184
|
placements = SQL_SESSION_PLACEMENTS;
|
|
181
185
|
pending = new Map();
|
|
182
186
|
log;
|
|
183
187
|
constructor(pool, opts = {}) {
|
|
184
188
|
this.pool = pool;
|
|
185
189
|
this.log = opts.log ?? createLogger();
|
|
190
|
+
this.retention = opts.retention ?? UNMANAGED_RETENTION;
|
|
186
191
|
}
|
|
187
192
|
async acquire(sessionId, opts) {
|
|
188
193
|
if (!sessionId) {
|
|
@@ -219,7 +224,7 @@ export class PgSessionStore {
|
|
|
219
224
|
return { session: new StoredSession(storage), sessionId };
|
|
220
225
|
}
|
|
221
226
|
async register(sessionId, owner) {
|
|
222
|
-
if (
|
|
227
|
+
if (!isSessionOwnerValue(owner)) {
|
|
223
228
|
if ((await this.headOf(sessionId)) !== undefined)
|
|
224
229
|
return;
|
|
225
230
|
assertFirstOwnerWritable(sessionId, owner);
|
|
@@ -417,6 +422,14 @@ export class PgSessionStore {
|
|
|
417
422
|
await this.pool.query(baselineQuery("UPDATE session_meta SET instruction_source = $1 WHERE session_id = $2 AND instruction_source IS NULL", [next, sessionId]));
|
|
418
423
|
}
|
|
419
424
|
}
|
|
425
|
+
async readSessionWorkspace(sessionId) {
|
|
426
|
+
const res = await this.pool.query(`SELECT ${jsonColumnText("pg", "workspace")} FROM session_meta WHERE session_id = $1`, [sessionId]);
|
|
427
|
+
const row = res.rows[0];
|
|
428
|
+
return row === undefined ? undefined : decodeSessionWorkspaceCell(row.workspace, sessionId);
|
|
429
|
+
}
|
|
430
|
+
async recordSessionWorkspace(sessionId, incarnation, workspace) {
|
|
431
|
+
await this.pool.query("UPDATE session_meta SET workspace = $1::jsonb WHERE session_id = $2 AND incarnation = $3", [encodeSessionWorkspaceCell(workspace, pgSafeJsonStringify, sessionId), sessionId, incarnation]);
|
|
432
|
+
}
|
|
420
433
|
async fork(sourceId, owner) {
|
|
421
434
|
const metaRes = await this.pool.query("SELECT leaf_id, owner FROM session_meta WHERE session_id = $1", [sourceId]);
|
|
422
435
|
if (!metaRes.rows[0])
|
|
@@ -428,7 +441,7 @@ export class PgSessionStore {
|
|
|
428
441
|
return null;
|
|
429
442
|
const point = await forkPointOf(storage);
|
|
430
443
|
const eventRes = await this.pool.query(`SELECT entry_id, parent_id, type, ${jsonColumnText("pg", "payload")}, ts FROM session_event WHERE session_id = $1 ORDER BY seq ASC`, [sourceId]);
|
|
431
|
-
const { rows, leafId: forkLeafId } =
|
|
444
|
+
const { rows, leafId: forkLeafId } = selectForkRows(eventRes.rows, leafId, point, FORK_LOG_ROW_SHAPE);
|
|
432
445
|
const newId = uuidv7();
|
|
433
446
|
const now = new Date();
|
|
434
447
|
const conn = await this.pool.connect();
|
|
@@ -523,7 +536,7 @@ export class PgSessionStore {
|
|
|
523
536
|
}
|
|
524
537
|
await conn.query("DELETE FROM session_event WHERE session_id = $1", [sessionId]);
|
|
525
538
|
await conn.query("DELETE FROM session_meta WHERE session_id = $1 AND owner IS NOT DISTINCT FROM $2 AND placement_kind IS NULL", [sessionId, owner]);
|
|
526
|
-
await this.insertValidatedLog(conn, sessionId, owner, validated, carriedIncarnation(sessionId, placedRes.rows[0]
|
|
539
|
+
await this.insertValidatedLog(conn, sessionId, owner, validated, carriedIncarnation(sessionId, placedRes.rows[0]));
|
|
527
540
|
await conn.query("COMMIT");
|
|
528
541
|
}
|
|
529
542
|
catch (err) {
|
|
@@ -58,14 +58,16 @@ export declare class RemoteAdbExecutionEnv implements RemoteExecutionEnv {
|
|
|
58
58
|
* (RPC 断、传输掉),不是「一个它看不见的命名空间」⇒ 读边界的执行期复核**拒**,而不是让词法判决站着。
|
|
59
59
|
* 缺席是今天每个适配器的读法(整链沉默 ⇒ 词法判决成立、命令照跑),所以这一声明是**收紧**方向。
|
|
60
60
|
* 严格读法 `=== true`(core `canonicalPathIsAuthoritative`);`isSuspendable` 一族同样严格,对本仓的
|
|
61
|
-
* 布尔字面量零影响(
|
|
61
|
+
* 布尔字面量零影响(四键都写死字面 `true`/`false`,不存在「非布尔值被读成缺席」那一形 —— 那一形由
|
|
62
62
|
* core 的 `config.execution_env_capability_invalid` 普查响亮播报,本仓的受众表已登记)。
|
|
63
63
|
* 谁该声明由闭集门看着(`test/execution-lane-caps.test.ts` 的逐 lane 对账:新 lane 不表态 = 编译红)。
|
|
64
64
|
*/
|
|
65
|
+
/** `sharesProcessTable`(core 7.57.0,必填):命令跑在设备上(adb shell),不在本进程所在的进程表。 */
|
|
65
66
|
readonly capabilities: {
|
|
66
67
|
isolation: boolean;
|
|
67
68
|
suspendable: boolean;
|
|
68
69
|
canonicalPathAuthoritative: boolean;
|
|
70
|
+
sharesProcessTable: boolean;
|
|
69
71
|
};
|
|
70
72
|
cwd: string;
|
|
71
73
|
private connected;
|
|
@@ -85,6 +87,9 @@ export declare class RemoteAdbExecutionEnv implements RemoteExecutionEnv {
|
|
|
85
87
|
/** core 7.49.0 [ref]:shell 子进程真拿到的 `CDPATH` 条目 —— 本车道的命令跑在 Android 设备的 shell 里(设备自己的 env),本类不读那份 env ⇒ `"unknown"`(core 契约:说不出就说 unknown,
|
|
86
88
|
* 不许报一张没读过的空表;删除守卫因此对裸 `cd <相对名>` 之后的删除问人,而不是按「没有 CDPATH」放行)。 */
|
|
87
89
|
readonly cdPath: "unknown";
|
|
90
|
+
/** core 7.56.0 [ref]:shell 子进程继承的环境里收不到的条目 —— 本车道 shell 的环境在 Android 设备上**构建**(本进程的 env 从不注入,只有引擎逐次交的 `env`
|
|
91
|
+
* 这条显式授予),没有一条是从本进程继承的 ⇒ `[]`(core 契约:「`[]` when its shell environment is built rather than inherited」)。 */
|
|
92
|
+
readonly withheldEnv: readonly [];
|
|
88
93
|
private readonly cfg;
|
|
89
94
|
private readonly spawnFn;
|
|
90
95
|
private readonly injectedConnectOnce?;
|
|
@@ -27,7 +27,7 @@ export function isAdbTransportLost(stderr) {
|
|
|
27
27
|
return /device offline|device '.*' not found|no devices\/emulators found|connection reset|protocol fault|device disconnected/i.test(stderr);
|
|
28
28
|
}
|
|
29
29
|
export class RemoteAdbExecutionEnv {
|
|
30
|
-
capabilities = { isolation: false, suspendable: false, canonicalPathAuthoritative: true };
|
|
30
|
+
capabilities = { isolation: false, suspendable: false, canonicalPathAuthoritative: true, sharesProcessTable: false };
|
|
31
31
|
cwd;
|
|
32
32
|
connected = false;
|
|
33
33
|
destroyed = false;
|
|
@@ -37,6 +37,7 @@ export class RemoteAdbExecutionEnv {
|
|
|
37
37
|
}
|
|
38
38
|
homeSeat;
|
|
39
39
|
cdPath = "unknown";
|
|
40
|
+
withheldEnv = [];
|
|
40
41
|
cfg;
|
|
41
42
|
spawnFn;
|
|
42
43
|
injectedConnectOnce;
|
|
@@ -89,6 +89,9 @@ export declare class RemoteDeviceExecutionEnv implements RemoteExecutionEnv {
|
|
|
89
89
|
/** core 7.49.0 [ref]:shell 子进程真拿到的 `CDPATH` 条目 —— 本车道的命令跑在设备上(设备自己的 env),本类不读那份 env ⇒ `"unknown"`(core 契约:说不出就说 unknown,
|
|
90
90
|
* 不许报一张没读过的空表;删除守卫因此对裸 `cd <相对名>` 之后的删除问人,而不是按「没有 CDPATH」放行)。 */
|
|
91
91
|
readonly cdPath: "unknown";
|
|
92
|
+
/** core 7.56.0 [ref]:shell 子进程继承的环境里收不到的条目 —— 本车道 shell 的环境在设备上**构建**(本进程的 env 从不注入,只有引擎逐次交的 `env`
|
|
93
|
+
* 这条显式授予),没有一条是从本进程继承的 ⇒ `[]`(core 契约:「`[]` when its shell environment is built rather than inherited」)。 */
|
|
94
|
+
readonly withheldEnv: readonly [];
|
|
92
95
|
/**
|
|
93
96
|
* 🔴 `suspendable: false` 在 core 契约里**同时断言**「工作区在目标上外部持久」(remote-env.ts 的
|
|
94
97
|
* load-bearing 不变量)—— 设备工作区 = 员工机磁盘,真持久 ✅,park-only 降级腿因此合法可用。
|
|
@@ -101,14 +104,16 @@ export declare class RemoteDeviceExecutionEnv implements RemoteExecutionEnv {
|
|
|
101
104
|
* (RPC 断、传输掉),不是「一个它看不见的命名空间」⇒ 读边界的执行期复核**拒**,而不是让词法判决站着。
|
|
102
105
|
* 缺席是今天每个适配器的读法(整链沉默 ⇒ 词法判决成立、命令照跑),所以这一声明是**收紧**方向。
|
|
103
106
|
* 严格读法 `=== true`(core `canonicalPathIsAuthoritative`);`isSuspendable` 一族同样严格,对本仓的
|
|
104
|
-
* 布尔字面量零影响(
|
|
107
|
+
* 布尔字面量零影响(四键都写死字面 `true`/`false`,不存在「非布尔值被读成缺席」那一形 —— 那一形由
|
|
105
108
|
* core 的 `config.execution_env_capability_invalid` 普查响亮播报,本仓的受众表已登记)。
|
|
106
109
|
* 谁该声明由闭集门看着(`test/execution-lane-caps.test.ts` 的逐 lane 对账:新 lane 不表态 = 编译红)。
|
|
107
110
|
*/
|
|
111
|
+
/** `sharesProcessTable`(core 7.57.0,必填):命令跑在注册设备上(设备执行器),不在本进程所在的进程表。 */
|
|
108
112
|
readonly capabilities: {
|
|
109
113
|
isolation: boolean;
|
|
110
114
|
suspendable: boolean;
|
|
111
115
|
canonicalPathAuthoritative: boolean;
|
|
116
|
+
sharesProcessTable: boolean;
|
|
112
117
|
};
|
|
113
118
|
readonly externalContentTarget = true;
|
|
114
119
|
/** [ref]:设备路径不在 worker 宿主文件系统上 —— host-path 回执消费方据此拒绝把它当宿主路径呈现。 */
|
|
@@ -13,6 +13,7 @@ export const DEVICE_OUTCOME_TO_FILE_ERROR = {
|
|
|
13
13
|
invalid: "invalid",
|
|
14
14
|
is_directory: "is_directory",
|
|
15
15
|
liveness_no_output: "unknown",
|
|
16
|
+
name_too_long: "name_too_long",
|
|
16
17
|
not_directory: "not_directory",
|
|
17
18
|
not_found: "not_found",
|
|
18
19
|
not_supported: "not_supported",
|
|
@@ -35,6 +36,7 @@ export const DEVICE_OUTCOME_TO_EXEC_ERROR = {
|
|
|
35
36
|
invalid: "unknown",
|
|
36
37
|
is_directory: "unknown",
|
|
37
38
|
liveness_no_output: "liveness_no_output",
|
|
39
|
+
name_too_long: "unknown",
|
|
38
40
|
not_directory: "unknown",
|
|
39
41
|
not_found: "unknown",
|
|
40
42
|
not_supported: "shell_unavailable",
|
|
@@ -123,7 +125,8 @@ export class RemoteDeviceExecutionEnv {
|
|
|
123
125
|
cfg;
|
|
124
126
|
homeDir;
|
|
125
127
|
cdPath = "unknown";
|
|
126
|
-
|
|
128
|
+
withheldEnv = [];
|
|
129
|
+
capabilities = { isolation: false, suspendable: false, canonicalPathAuthoritative: true, sharesProcessTable: false };
|
|
127
130
|
externalContentTarget = true;
|
|
128
131
|
hostLocalPaths = false;
|
|
129
132
|
cwd;
|
|
@@ -766,6 +769,7 @@ const OUTCOME_TO_REMOTE_ERROR = {
|
|
|
766
769
|
invalid: "unknown",
|
|
767
770
|
is_directory: "unknown",
|
|
768
771
|
liveness_no_output: "liveness_no_output",
|
|
772
|
+
name_too_long: "unknown",
|
|
769
773
|
not_directory: "unknown",
|
|
770
774
|
not_found: "unknown",
|
|
771
775
|
not_supported: "unsupported",
|
|
@@ -104,6 +104,9 @@ export declare class RemoteContainerExecutionEnv implements RemoteExecutionEnv,
|
|
|
104
104
|
/** core 7.49.0 [ref]:shell 子进程真拿到的 `CDPATH` 条目 —— 本车道的命令跑在 e2b 沙箱里(模板镜像的 env),本类不读那份 env ⇒ `"unknown"`(core 契约:说不出就说 unknown,
|
|
105
105
|
* 不许报一张没读过的空表;删除守卫因此对裸 `cd <相对名>` 之后的删除问人,而不是按「没有 CDPATH」放行)。 */
|
|
106
106
|
readonly cdPath: "unknown";
|
|
107
|
+
/** core 7.56.0 [ref]:shell 子进程继承的环境里收不到的条目 —— 本车道 shell 的环境在沙箱里**构建**(本进程的 env 从不注入,只有引擎逐次交的 `env`
|
|
108
|
+
* 这条显式授予),没有一条是从本进程继承的 ⇒ `[]`(core 契约:「`[]` when its shell environment is built rather than inherited」)。 */
|
|
109
|
+
readonly withheldEnv: readonly [];
|
|
107
110
|
private readonly cfg;
|
|
108
111
|
private readonly sandboxApi;
|
|
109
112
|
/** This lane's own liveness bound — what {@link commandBoundsOf} falls back to when a command's caller stated no bound. */
|
|
@@ -132,10 +135,12 @@ export declare class RemoteContainerExecutionEnv implements RemoteExecutionEnv,
|
|
|
132
135
|
constructor(config: RemoteContainerEnvConfig, deps?: RemoteContainerEnvDeps);
|
|
133
136
|
/** [ref] §9: E2B is a FULL RemoteExecutionEnv — an isolated, snapshot-suspendable microVM. (SSH/ADB
|
|
134
137
|
* adapters declare {isolation:false, suspendable:false} — real machines/devices, not snapshotable.) */
|
|
138
|
+
/** `sharesProcessTable`(core 7.57.0,必填):命令跑在云沙箱里,不在本进程所在的进程表。 */
|
|
135
139
|
readonly capabilities: {
|
|
136
140
|
isolation: boolean;
|
|
137
141
|
suspendable: boolean;
|
|
138
142
|
canonicalPathAuthoritative: boolean;
|
|
143
|
+
sharesProcessTable: boolean;
|
|
139
144
|
};
|
|
140
145
|
workspaceHandle(): WorkspaceHandle;
|
|
141
146
|
/**
|
|
@@ -20,6 +20,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
20
20
|
cwd;
|
|
21
21
|
homeDir;
|
|
22
22
|
cdPath = "unknown";
|
|
23
|
+
withheldEnv = [];
|
|
23
24
|
cfg;
|
|
24
25
|
sandboxApi;
|
|
25
26
|
laneLiveness;
|
|
@@ -45,7 +46,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
45
46
|
this.homeDir = config.homeDir;
|
|
46
47
|
this.sandboxApi = deps.sandboxApi ?? Sandbox;
|
|
47
48
|
}
|
|
48
|
-
capabilities = { isolation: true, suspendable: true, canonicalPathAuthoritative: true };
|
|
49
|
+
capabilities = { isolation: true, suspendable: true, canonicalPathAuthoritative: true, sharesProcessTable: false };
|
|
49
50
|
workspaceHandle() {
|
|
50
51
|
if (!this.handle) {
|
|
51
52
|
throw new RemoteExecutionError("connect_failed", "workspaceHandle() called before connect()");
|
|
@@ -18,6 +18,12 @@
|
|
|
18
18
|
import { FileError, type ExecutionError, type RemoteExecutionError } from "@sema-agent/core";
|
|
19
19
|
/** exec 层的错误码 → 文件层的码。只映射**有对应语义**的那些,其余落 `unknown`(诚实降级)。 */
|
|
20
20
|
export declare function fileErrorFromExec(e: ExecutionError | RemoteExecutionError, path?: string): FileError;
|
|
21
|
+
/**
|
|
22
|
+
* core 7.56.0 [ref]:`ENAMETOOLONG` 的**一只读法**(本文件的 stderr 分类器与 host 车道的 errno 映射同调)—— 路径有一段超过 NAME_MAX(按 UTF-8 字节量)⇒
|
|
23
|
+
* `name_too_long`:没有目录装得下这个名字,引擎读站把它读作缺席(与 `not_found` 同读);段都短、只是整条超 PATH_MAX ⇒ `unknown`(那种文件可能存在,从下层目录够得着)。
|
|
24
|
+
* 没有路径可判 ⇒ `unknown`。与 core `NodeExecutionEnv` 同判(按 `/` 与 `\` 切段)。
|
|
25
|
+
*/
|
|
26
|
+
export declare function nameTooLongCode(p: string | undefined): "name_too_long" | "unknown";
|
|
21
27
|
/**
|
|
22
28
|
* shell 命令 exit≠0 时把 **stderr** 分类成 `FileError` 的共享分类器([ref] B6 R2 裁决:k8s 形=正形)。
|
|
23
29
|
*
|
|
@@ -29,7 +35,8 @@ export declare function fileErrorFromExec(e: ExecutionError | RemoteExecutionErr
|
|
|
29
35
|
* 1. 命令缺失形(`command not found` / `applet not found` / `: not found`)→ `unknown` —— 工具不存在
|
|
30
36
|
* 不是文件不存在;probe 族的 not_found fallback 绝不能吞它。
|
|
31
37
|
* 2. 完整硬失败(EIO/ELOOP/ENAMETOOLONG/ENOSPC)→ `unknown` —— 同 k8s 原注:真错不被 read-op 的
|
|
32
|
-
* not_found fallback
|
|
38
|
+
* not_found fallback 吞掉。**例外**(core 7.56.0 [ref]):`ENAMETOOLONG` 且路径有一段超过 NAME_MAX ⇒ `name_too_long`
|
|
39
|
+
* ({@link nameTooLongCode},一只读法,host 车道的 errno 映射同调)—— 那个名字没有目录装得下,是一种「不存在」,不是硬失败。
|
|
33
40
|
*
|
|
34
41
|
* `fallback` 由站点显式给:probe 族(readlink/realpath/stat——"它在吗"类问题)传 `not_found`
|
|
35
42
|
* (空 stderr + exit≠0 的主导原因就是缺文件);mutate 族(mkdir/rm/mktemp)传 `unknown`(诚实降级)。
|
|
@@ -3,11 +3,17 @@ export function fileErrorFromExec(e, path) {
|
|
|
3
3
|
const code = e.code === "aborted" ? "aborted" : "unknown";
|
|
4
4
|
return new FileError(code, e.message, path, e);
|
|
5
5
|
}
|
|
6
|
+
const NAME_MAX_BYTES = 255;
|
|
7
|
+
export function nameTooLongCode(p) {
|
|
8
|
+
return p !== undefined && p.split(/[\\/]/).some((part) => Buffer.byteLength(part, "utf8") > NAME_MAX_BYTES) ? "name_too_long" : "unknown";
|
|
9
|
+
}
|
|
6
10
|
export function classifyFsStderr(stderr, p, fallback = "unknown") {
|
|
7
11
|
const msg = stderr.trim();
|
|
8
12
|
if (/command not found|applet not found|:\s+not found\s*$/im.test(msg))
|
|
9
13
|
return new FileError("unknown", msg, p);
|
|
10
|
-
if (/
|
|
14
|
+
if (/file name too long/i.test(msg))
|
|
15
|
+
return new FileError(nameTooLongCode(p), msg, p);
|
|
16
|
+
if (/input\/output error|too many levels|no space left/i.test(msg))
|
|
11
17
|
return new FileError("unknown", msg, p);
|
|
12
18
|
if (/no such file/i.test(msg))
|
|
13
19
|
return new FileError("not_found", msg, p);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FileError, type InheritEnvPolicy, ExecutionError, RemoteExecutionError, SchedulerError, type SchedulerCapability, type ScheduledIntent, type SchedulerContext, type ScheduledTaskId, type ScheduledTaskSummary, type ExecutionEnv, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type SymlinkChain, type BoundFileObject, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type VmLifecycleOptions, type ExecutionEnvFactory, BackgroundShellError, type BackgroundShellCapability, type BackgroundShellId, type BackgroundHardKillOutcome, type BackgroundPoll, type BackgroundSpawnOptions } from "@sema-agent/core";
|
|
1
|
+
import { FileError, type InheritEnvPolicy, ExecutionError, RemoteExecutionError, SchedulerError, type SchedulerCapability, type ScheduledIntent, type SchedulerContext, type ScheduledTaskId, type ScheduledTaskSummary, type ExecutionEnv, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type SymlinkChain, type BoundFileObject, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type VmLifecycleOptions, type ExecutionEnvFactory, BackgroundShellError, type BackgroundShellCapability, type BackgroundShellId, type BackgroundHardKillOutcome, type BackgroundPoll, type BackgroundSpawnOptions, type SecretEnvFinding } from "@sema-agent/core";
|
|
2
2
|
/** Options accepted by `ExecutionEnv.exec` (core does not re-export the type; derive it from the seam). */
|
|
3
3
|
type ExecOpts = Parameters<ExecutionEnv["exec"]>[1];
|
|
4
4
|
/** SIGTERM → grace → SIGKILL (no host isolation). 🔴 宽限的**唯一属主**:本 driver 的 `kill` 梯子用它排升级定时器;会话级收敛
|
|
@@ -71,14 +71,16 @@ export declare class RemoteHostExecutionEnv implements RemoteExecutionEnv, Sched
|
|
|
71
71
|
* (RPC 断、传输掉),不是「一个它看不见的命名空间」⇒ 读边界的执行期复核**拒**,而不是让词法判决站着。
|
|
72
72
|
* 缺席是今天每个适配器的读法(整链沉默 ⇒ 词法判决成立、命令照跑),所以这一声明是**收紧**方向。
|
|
73
73
|
* 严格读法 `=== true`(core `canonicalPathIsAuthoritative`);`isSuspendable` 一族同样严格,对本仓的
|
|
74
|
-
* 布尔字面量零影响(
|
|
74
|
+
* 布尔字面量零影响(四键都写死字面 `true`/`false`,不存在「非布尔值被读成缺席」那一形 —— 那一形由
|
|
75
75
|
* core 的 `config.execution_env_capability_invalid` 普查响亮播报,本仓的受众表已登记)。
|
|
76
76
|
* 谁该声明由闭集门看着(`test/execution-lane-caps.test.ts` 的逐 lane 对账:新 lane 不表态 = 编译红)。
|
|
77
77
|
*/
|
|
78
|
+
/** `sharesProcessTable`(core 7.57.0,必填):命令是本进程 spawn 的子进程(同一张进程表),引擎的模式杀守卫对它照 NodeExecutionEnv 一样问 `pgrep`。 */
|
|
78
79
|
readonly capabilities: {
|
|
79
80
|
isolation: boolean;
|
|
80
81
|
suspendable: boolean;
|
|
81
82
|
canonicalPathAuthoritative: boolean;
|
|
83
|
+
sharesProcessTable: boolean;
|
|
82
84
|
};
|
|
83
85
|
/** R7 自唤醒: structural delegation to the injected scheduler backend. `hasScheduler(env)` checks BOTH the method
|
|
84
86
|
* presence (always, since we implement the interface) AND `schedulerCapabilities.supported===true` — which is only
|
|
@@ -101,6 +103,12 @@ export declare class RemoteHostExecutionEnv implements RemoteExecutionEnv, Sched
|
|
|
101
103
|
* {@link hostShell}(win32 上未落定同步抛 —— 修前每条 Bash 的策略链都因此被拒)。
|
|
102
104
|
*/
|
|
103
105
|
get cdPath(): readonly string[];
|
|
106
|
+
/**
|
|
107
|
+
* core 7.56.0 [ref]:shell 子进程继承的环境里**收不到**的条目(名 + 规则,从不带值)—— 与 {@link cdPath} 同一只组合的读面
|
|
108
|
+
* (`server-secret-env.ts` 的 `withheldFromHostSubprocess`:继承组合扣下的发现,减去 `cfg.env` 这条显式授予重供的键)。逐命令的 `options.env`
|
|
109
|
+
* 是引擎自己交的显式授予,它知道(core KL-1963-b 同一残余)。只读:不披露、不计数、不碰 shell。
|
|
110
|
+
*/
|
|
111
|
+
get withheldEnv(): readonly SecretEnvFinding[];
|
|
104
112
|
private readonly workspaceDir;
|
|
105
113
|
private readonly cfg;
|
|
106
114
|
/** Workspace created on disk (lazily, on first use). */
|
|
@@ -11,7 +11,8 @@ import { hostBackgroundShellEnabled, hostExecSpoolEnabled } from "../config.js";
|
|
|
11
11
|
import { IS_WIN32, resolveHostShell, hostShell, pinHostShell, spawnGroupOptions, killTreeHard, killTreeSoft, hardKillGroupNow, collapseWin32EnvKeys, adoptHostForegroundChild } from "./host-platform.js";
|
|
12
12
|
import { BackgroundShellManager, seedMemStream, feedMemStream, drainMemStream } from "./background-shell-support.js";
|
|
13
13
|
import { FileError, NodeExecutionEnv, inheritEnvPolicyProblem, ExecutionError, RemoteExecutionError, RollingTailBuffer, walkSymlinkChain, markTruncated, SchedulerError, BackgroundShellError, } from "@sema-agent/core";
|
|
14
|
-
import { composeHostSubprocessEnv, hostSubprocessEnv } from "../server-secret-env.js";
|
|
14
|
+
import { composeHostSubprocessEnv, hostSubprocessEnv, withheldFromHostSubprocess } from "../server-secret-env.js";
|
|
15
|
+
import { nameTooLongCode } from "./remote-env-file-error.js";
|
|
15
16
|
import { trackEphemeralHostWorkspace, untrackEphemeralHostWorkspace } from "./host-workspace-registry.js";
|
|
16
17
|
const PROVIDER = "host";
|
|
17
18
|
const DEFAULT_COMMAND_TIMEOUT_MS = 30 * 60_000;
|
|
@@ -36,7 +37,7 @@ const UNSUPPORTED_SCHEDULER_CAPS = {
|
|
|
36
37
|
maxScheduledHorizonSec: 0,
|
|
37
38
|
};
|
|
38
39
|
export class RemoteHostExecutionEnv {
|
|
39
|
-
capabilities = { isolation: false, suspendable: false, canonicalPathAuthoritative: true };
|
|
40
|
+
capabilities = { isolation: false, suspendable: false, canonicalPathAuthoritative: true, sharesProcessTable: true };
|
|
40
41
|
get schedulerCapabilities() {
|
|
41
42
|
return this.cfg.scheduler?.schedulerCapabilities ?? UNSUPPORTED_SCHEDULER_CAPS;
|
|
42
43
|
}
|
|
@@ -61,6 +62,9 @@ export class RemoteHostExecutionEnv {
|
|
|
61
62
|
const value = this.childEnv(undefined, undefined).CDPATH;
|
|
62
63
|
return value === undefined || value === "" ? [] : value.split(":");
|
|
63
64
|
}
|
|
65
|
+
get withheldEnv() {
|
|
66
|
+
return withheldFromHostSubprocess({ policy: this.cfg.inheritEnv, allow: [] }, this.cfg.env);
|
|
67
|
+
}
|
|
64
68
|
workspaceDir;
|
|
65
69
|
cfg;
|
|
66
70
|
prepared = false;
|
|
@@ -1331,6 +1335,8 @@ export class RemoteHostExecutionEnv {
|
|
|
1331
1335
|
return new FileError("not_directory", msg, p);
|
|
1332
1336
|
if (code === "EINVAL")
|
|
1333
1337
|
return new FileError("invalid", msg, p);
|
|
1338
|
+
if (code === "ENAMETOOLONG")
|
|
1339
|
+
return new FileError(nameTooLongCode(p), msg, p);
|
|
1334
1340
|
return new FileError("unknown", msg, p);
|
|
1335
1341
|
}
|
|
1336
1342
|
}
|
|
@@ -110,9 +110,11 @@ export interface K8sEnvConfig extends LaneHomeConfig {
|
|
|
110
110
|
cacheMisses?: CacheMissMemory;
|
|
111
111
|
/** Operator log seat (the e2b adapter's shape): `workspace_snapshot_failed` / `workspace_snapshot_prune_failed` /
|
|
112
112
|
* `workspace_space_unavailable` / `workspace_space_unreadable_occupant` / `workspace_commit_abandoned` / `workspace_latest_dangling` /
|
|
113
|
-
* `workspace_restore_failed` / `workspace_snapshot_bucket_missing` / `workspace_cache_fresh` / `workspace_cache_unavailable
|
|
113
|
+
* `workspace_restore_failed` / `workspace_snapshot_bucket_missing` / `workspace_cache_fresh` / `workspace_cache_unavailable`, and — at `error` level, on a seat
|
|
114
|
+
* that has one (the deployment's logger does; the seat itself is optional, and the counter behind the line does not depend on it) — `sandbox_pod_delete_failed`. */
|
|
114
115
|
logger?: {
|
|
115
116
|
warn(event: string, fields?: Record<string, unknown>): void;
|
|
117
|
+
error?(event: string, fields?: Record<string, unknown>): void;
|
|
116
118
|
};
|
|
117
119
|
/** Run-end outcome seat — called once per `destroy()` that attempted a space snapshot (the factory's caller binds it
|
|
118
120
|
* to the run, so the run's terminal frame can carry `workspaceSnapshot: "failed"`). */
|
|
@@ -130,13 +132,39 @@ export interface K8sEnvConfig extends LaneHomeConfig {
|
|
|
130
132
|
podSpecPatch?: PodSpecPatch;
|
|
131
133
|
/** RFC B5 (sema-internal server/docs/design/ENV-SELECT-AND-REGION-SOURCE.md 抽象点②): operator-trusted env injected into the
|
|
132
134
|
* sandbox container (e.g. `SEMA_PKG_SOURCE=cn|global` — the runtime package-source selector the image's
|
|
133
|
-
* pkg-source.sh hook materializes at start). Deployment config, NEVER task-controlled.
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* never a command string, the workspace or a snapshot. Absent = the pod is byte-identical to today. */
|
|
135
|
+
* pkg-source.sh hook materializes at start). Deployment config, NEVER task-controlled. The pod's NON-SECRET env seat: the region
|
|
136
|
+
* package-source set (and the cache env layered under it) — values that are no secret go into `containers[0].env[]` as `{ name, value }`.
|
|
137
|
+
* Never a command string, the workspace or a snapshot. Absent = no such entries. */
|
|
137
138
|
podEnv?: Record<string, string>;
|
|
139
|
+
/** The pod's SECRET env seat: the deployer-named forwarding (`K8S_SANDBOX_ENV` keys, original values; disjoint from {@link podEnv} — the boot
|
|
140
|
+
* assembly drops a collided name from the non-secret seat, explicit wins; a name in both is read here). The values reach the agent container
|
|
141
|
+
* ONLY through this pod's own Secret: the pod spec carries `valueFrom.secretKeyRef` and no value; the Secret is created after the pod, owned by
|
|
142
|
+
* it (`ownerReferences`, `immutable`) — a Secret that cannot be created ⇒ the pod is deleted and the connect refused, never a plaintext fallback.
|
|
143
|
+
* Absent / empty ⇒ no Secret, the pod as without it. */
|
|
144
|
+
podSecretEnv?: Record<string, string>;
|
|
145
|
+
/** The server run that owns this env — the TOP-LEVEL run's id (its task id), handed in by the per-run binding (`boot/execution-env.ts`), which
|
|
146
|
+
* hands none to a delegated child, a run the service starts for itself, or a run without a task id. Carried as the pod label `sema.io/run`
|
|
147
|
+
* (the reaper's key: a pod whose run is over is removed); a value that is no label value is not carried. Absent ⇒ the pod names no run. */
|
|
148
|
+
runId?: string;
|
|
149
|
+
/**
|
|
150
|
+
* The member git-credential broker seat — present ⇔ the per-run binding found the plane on and this run a member's (`sso`) run
|
|
151
|
+
* (`sandbox-git-plane.ts` `sandboxBrokerSeatOf`). The pod then carries the broker container (`containers[1]`: the fixed program of
|
|
152
|
+
* `broker/constants.ts`, image = `image`, the securityContext written key by key, an exec readiness probe), its lease volume (a SECOND
|
|
153
|
+
* per-pod Secret, `sema.io/sandbox-lease` — mutable, owned by the pod, only `broker.json`; created after the pod holding a placeholder lease
|
|
154
|
+
* in which every entry is withdrawn), `shareProcessNamespace: false`, and on the agent container one `GIT_CONFIG_*` insteadOf route per
|
|
155
|
+
* origin (`origins` = the pod's origin table, in order — the same table every lease write is stamped from). The connect waits for the
|
|
156
|
+
* broker container to be ready; any failure on that path deletes the pod and refuses the connect. A deployment patch that could reach
|
|
157
|
+
* the broker refuses the connect before any pod is created. Absent ⇒ the pod as without it (byte-identical).
|
|
158
|
+
*/
|
|
159
|
+
sandboxBroker?: {
|
|
160
|
+
readonly image: string;
|
|
161
|
+
readonly origins: readonly string[];
|
|
162
|
+
};
|
|
138
163
|
}
|
|
164
|
+
import { type SandboxSecretSeatKind, type SandboxSecretVerb } from "./k8s-exec-protocol.js";
|
|
139
165
|
export { type PodSpecPatch, applyPodSpecPatch } from "./k8s-exec-protocol.js";
|
|
166
|
+
import { type SandboxPodApi, type SandboxPodListing } from "./k8s-pod-reaper.js";
|
|
167
|
+
import { type SandboxLeaseEntryInput } from "../sandbox-git-lease.js";
|
|
140
168
|
type ConnectResult = {
|
|
141
169
|
ok: true;
|
|
142
170
|
value: WorkspaceHandle;
|
|
@@ -154,11 +182,14 @@ export interface ExecSocket {
|
|
|
154
182
|
* Test seam ([ref] §9.3 fault-injection): inject the REST `request` and/or the exec-socket factory, so pod
|
|
155
183
|
* lifecycle, retry policy, channel framing and liveness are deterministically testable without a cluster.
|
|
156
184
|
*/
|
|
185
|
+
/** One control-plane request's options: its wall-clock, its abort, and the body's media type (default `application/json`; a merge-patch says so). */
|
|
186
|
+
export interface K8sRequestOptions {
|
|
187
|
+
timeoutMs?: number;
|
|
188
|
+
signal?: AbortSignal;
|
|
189
|
+
contentType?: string;
|
|
190
|
+
}
|
|
157
191
|
export interface K8sEnvDeps {
|
|
158
|
-
request?: (method: string, apiPath: string, body?: unknown, opts?: {
|
|
159
|
-
timeoutMs?: number;
|
|
160
|
-
signal?: AbortSignal;
|
|
161
|
-
}) => Promise<{
|
|
192
|
+
request?: (method: string, apiPath: string, body?: unknown, opts?: K8sRequestOptions) => Promise<{
|
|
162
193
|
status: number;
|
|
163
194
|
json: unknown;
|
|
164
195
|
}>;
|
|
@@ -229,6 +260,35 @@ export declare function errorMessageOf(e: unknown): string;
|
|
|
229
260
|
export { exitCodeFromStatus } from "./k8s-exec-protocol.js";
|
|
230
261
|
/** The sandbox namespace when `K8S_NAMESPACE` is unset (the one spelling: the adapter and the boot's egress line read it). */
|
|
231
262
|
export declare const K8S_SANDBOX_NAMESPACE_DEFAULT = "sandboxes";
|
|
263
|
+
/**
|
|
264
|
+
* The boot reading of the sandbox Secret seat, a closed set: `granted` — every verb allowed · `denied` — the API answered "not allowed" for these
|
|
265
|
+
* verbs (a definite answer; it wins over a verb that could not be asked) · `unverified` — some verb could not be asked (the request failed, the
|
|
266
|
+
* review itself was refused, the answer had no `status.allowed`) and none was denied.
|
|
267
|
+
*/
|
|
268
|
+
export type SandboxSecretSeat = {
|
|
269
|
+
readonly state: "granted";
|
|
270
|
+
} | {
|
|
271
|
+
readonly state: "denied";
|
|
272
|
+
readonly verbs: SandboxSecretVerb[];
|
|
273
|
+
} | {
|
|
274
|
+
readonly state: "unverified";
|
|
275
|
+
readonly detail: string;
|
|
276
|
+
};
|
|
277
|
+
/** Where a pod's lease lives and which origin table it was built with — what {@link writeSandboxLease} needs (read it from {@link RemoteK8sExecutionEnv.sandboxLeaseRef}). */
|
|
278
|
+
export interface SandboxLeaseRef {
|
|
279
|
+
readonly namespace: string;
|
|
280
|
+
readonly podName: string;
|
|
281
|
+
readonly leaseSecretName: string;
|
|
282
|
+
readonly origins: readonly string[];
|
|
283
|
+
}
|
|
284
|
+
/** One lease write's outcome (closed set): written · refused before sending (the broker would refuse it) · refused by the API · the Secret is gone (so is its pod) · any other failure. */
|
|
285
|
+
export type SandboxLeaseWrite = {
|
|
286
|
+
readonly ok: true;
|
|
287
|
+
} | {
|
|
288
|
+
readonly ok: false;
|
|
289
|
+
readonly code: "lease_invalid" | "auth_failed" | "gone" | "write_failed";
|
|
290
|
+
readonly message: string;
|
|
291
|
+
};
|
|
232
292
|
export declare class RemoteK8sExecutionEnv implements RemoteExecutionEnv, BackgroundShellCapability {
|
|
233
293
|
/**
|
|
234
294
|
* 🔴 **[ref] / core 7.20.0([ref])`canonicalPathAuthoritative: true`** —— 本适配器的 `canonicalPath`
|
|
@@ -236,20 +296,24 @@ export declare class RemoteK8sExecutionEnv implements RemoteExecutionEnv, Backgr
|
|
|
236
296
|
* (RPC 断、传输掉),不是「一个它看不见的命名空间」⇒ 读边界的执行期复核**拒**,而不是让词法判决站着。
|
|
237
297
|
* 缺席是今天每个适配器的读法(整链沉默 ⇒ 词法判决成立、命令照跑),所以这一声明是**收紧**方向。
|
|
238
298
|
* 严格读法 `=== true`(core `canonicalPathIsAuthoritative`);`isSuspendable` 一族同样严格,对本仓的
|
|
239
|
-
* 布尔字面量零影响(
|
|
299
|
+
* 布尔字面量零影响(四键都写死字面 `true`/`false`,不存在「非布尔值被读成缺席」那一形 —— 那一形由
|
|
240
300
|
* core 的 `config.execution_env_capability_invalid` 普查响亮播报,本仓的受众表已登记)。
|
|
241
301
|
* 谁该声明由闭集门看着(`test/execution-lane-caps.test.ts` 的逐 lane 对账:新 lane 不表态 = 编译红)。
|
|
242
302
|
*/
|
|
303
|
+
/** `sharesProcessTable`(core 7.57.0,必填):命令跑在沙箱 pod 自己的 PID 命名空间里(不开 hostPID),不在本进程所在的进程表。 */
|
|
243
304
|
readonly capabilities: {
|
|
244
305
|
isolation: boolean;
|
|
245
306
|
suspendable: boolean;
|
|
246
307
|
canonicalPathAuthoritative: true;
|
|
308
|
+
sharesProcessTable: false;
|
|
247
309
|
};
|
|
248
310
|
cwd: string;
|
|
249
311
|
private podName?;
|
|
250
312
|
/** Cluster-internal pod address, captured when the pod reaches Running — the LSP `getHost` surface.
|
|
251
313
|
* Lifecycle mirrors podName exactly (set on connect, cleared on suspend/destroy/dead-reconnect). */
|
|
252
314
|
private podIP?;
|
|
315
|
+
/** The broker lease seat of the pod this env holds (set with {@link podName}; read through {@link sandboxLeaseRef}). */
|
|
316
|
+
private leaseRef?;
|
|
253
317
|
private destroyed;
|
|
254
318
|
/** Set after a successful resumeVM so workspaceHandle() carries the snapshot it was restored from. */
|
|
255
319
|
private handleSnapshotId?;
|
|
@@ -274,6 +338,9 @@ export declare class RemoteK8sExecutionEnv implements RemoteExecutionEnv, Backgr
|
|
|
274
338
|
/** core 7.49.0 [ref]:shell 子进程真拿到的 `CDPATH` 条目 —— 本车道的命令跑在 pod 里(镜像与 pod spec 的 env),本类不读那份 env ⇒ `"unknown"`(core 契约:说不出就说 unknown,
|
|
275
339
|
* 不许报一张没读过的空表;删除守卫因此对裸 `cd <相对名>` 之后的删除问人,而不是按「没有 CDPATH」放行)。 */
|
|
276
340
|
readonly cdPath: "unknown";
|
|
341
|
+
/** core 7.56.0 [ref]:shell 子进程继承的环境里收不到的条目 —— 本车道 shell 的环境在 pod 里**构建**(本进程的 env 从不注入,只有引擎逐次交的 `env`
|
|
342
|
+
* 这条显式授予),没有一条是从本进程继承的 ⇒ `[]`(core 契约:「`[]` when its shell environment is built rather than inherited」)。 */
|
|
343
|
+
readonly withheldEnv: readonly [];
|
|
277
344
|
private readonly cfg;
|
|
278
345
|
private readonly deps;
|
|
279
346
|
/** The known occupant's incarnation (`undefined` = this run has no known occupant: a delegated child, an unread session, a direct construction) — the
|
|
@@ -295,6 +362,8 @@ export declare class RemoteK8sExecutionEnv implements RemoteExecutionEnv, Backgr
|
|
|
295
362
|
private readonly onWorkspaceSnapshot?;
|
|
296
363
|
private readonly cacheMisses?;
|
|
297
364
|
constructor(config: K8sEnvConfig, deps?: K8sEnvDeps);
|
|
365
|
+
/** The lease seat of the pod this env holds now — `undefined` without a broker seat or without a pod (the server's lease writes follow it: a resumed env holds a new pod and a new seat). */
|
|
366
|
+
get sandboxLeaseRef(): SandboxLeaseRef | undefined;
|
|
298
367
|
/** 166-T2 — ExecutionEnv 寿命声明:pod `activeDeadlineSeconds = ceil(timeoutMs/1000)` 是平台真硬死线
|
|
299
368
|
* (k8s 到点杀 pod,无 keepalive 续期机制)⇒ 恒声明,core 在死线−60s 处 suspend(基建合格)或响亮
|
|
300
369
|
* 终局(env.lifetime_expired)。`lifetimeStartedAt` 有意不声明:core 只在 prepare 期读一次,lazy-connect
|
|
@@ -410,6 +479,15 @@ export declare class RemoteK8sExecutionEnv implements RemoteExecutionEnv, Backgr
|
|
|
410
479
|
* same merge `createPod` applies). A read that is refused / fails / times out is a `unreadable` gap, never a guess. Never throws.
|
|
411
480
|
*/
|
|
412
481
|
egressPolicyGaps(): Promise<SandboxEgressGap[]>;
|
|
482
|
+
/**
|
|
483
|
+
* The boot reading of one sandbox Secret seat ({@link SandboxSecretSeat}): one SelfSubjectAccessReview per verb of that seat's row in {@link SANDBOX_SECRET_SEAT_VERBS}
|
|
484
|
+
* on `secrets` in this env's namespace. An answer with `status.allowed: false` is a denial (RBAC never answers `denied: true` — "no rule allows
|
|
485
|
+
* it" IS its refusal); a failed request, a refused review or an answer without a boolean `status.allowed` is a verb not asked. The verbs are
|
|
486
|
+
* asked at once (the boot waits one control-plane bound, not four). Never throws.
|
|
487
|
+
*/
|
|
488
|
+
secretSeatReading(seat: SandboxSecretSeatKind): Promise<SandboxSecretSeat>;
|
|
489
|
+
/** The sandbox pods of this env's namespace (selected by the identity labels), read for the reaper ({@link createSandboxPodApi}). Throws on a failed / refused listing. */
|
|
490
|
+
listSandboxPods(): Promise<SandboxPodListing[]>;
|
|
413
491
|
/** The one spelling of "the reclaim call's deadline passed" — both halves of the reclaim (volume and objects) say it with this. */
|
|
414
492
|
private reclaimDeadlinePassed;
|
|
415
493
|
/** The cache volume could not be had: counted (`recordFailOpen`) and one operator line — once per env. */
|
|
@@ -417,6 +495,34 @@ export declare class RemoteK8sExecutionEnv implements RemoteExecutionEnv, Backgr
|
|
|
417
495
|
/** Create one pod (with the cache volume when given) and wait for it to run. A {@link CacheMiss} = a pod carrying the
|
|
418
496
|
* volume did not become ready (its claim unbound past the bind deadline, or bound and still not ready) — already deleted. */
|
|
419
497
|
private createPod;
|
|
498
|
+
/**
|
|
499
|
+
* This pod's own Secret — the secret env seat ({@link K8sEnvConfig.podSecretEnv}): created AFTER the pod, owned by it (`ownerReferences` → the
|
|
500
|
+
* pod's uid, `blockOwnerDeletion: false` — the cluster's garbage collector removes it with the pod), `immutable`, `data["env.<NAME>"]` = the
|
|
501
|
+
* value (base64). The caller deletes the pod on any refusal: no uid to bind (`connect_failed`), refused (401 / 403 ⇒ `auth_failed`, not
|
|
502
|
+
* retried), any other answer or a failed request (`connect_failed`). A refusal never carries a value: the API's text is scrubbed of every value
|
|
503
|
+
* (raw and base64) before it enters the sentence.
|
|
504
|
+
*/
|
|
505
|
+
private createPodSecret;
|
|
506
|
+
/**
|
|
507
|
+
* This pod's lease Secret — the member-credential broker's seat ({@link K8sEnvConfig.sandboxBroker}): created after the pod, owned by it
|
|
508
|
+
* (the same `ownerReferences` as the env Secret), NOT immutable (the server rewrites the lease: {@link writeSandboxLease}), one data key
|
|
509
|
+
* `broker.json` = the placeholder lease. Refusals as for the env Secret; the caller deletes the pod on any of them.
|
|
510
|
+
*/
|
|
511
|
+
private createLeaseSecret;
|
|
512
|
+
/**
|
|
513
|
+
* One Secret owned by this pod (`ownerReferences` → its uid, `blockOwnerDeletion: false`; the cluster's garbage collector removes it with
|
|
514
|
+
* the pod). No uid to bind ⇒ `connect_failed`; refused (401 / 403) ⇒ `auth_failed`; any other answer or a failed request ⇒ `connect_failed`.
|
|
515
|
+
* A refusal never carries a value: the API's text is scrubbed of every `hidden` string before it enters the sentence.
|
|
516
|
+
*/
|
|
517
|
+
private createOwnedSecret;
|
|
518
|
+
/**
|
|
519
|
+
* Rewrite one pod's lease (the server's ONLY lease write — {@link writeSandboxLease}): the file is built by the one lease builder from the
|
|
520
|
+
* pod's origin table (fresh `leaseId` per ready entry, the broker's own parser judges it — a file the broker would refuse is never sent) and
|
|
521
|
+
* lands as a merge-patch of `broker.json` on the pod's lease Secret. Every failure is typed, says one operator line
|
|
522
|
+
* (`sandbox_lease_write_failed`), carries no credential (the API's text is scrubbed of every secret and of the encoded file), and falls
|
|
523
|
+
* back to nothing: the broker keeps the lease it has, which lapses on its own clock.
|
|
524
|
+
*/
|
|
525
|
+
writeLease(ref: SandboxLeaseRef, entries: readonly SandboxLeaseEntryInput[]): Promise<SandboxLeaseWrite>;
|
|
420
526
|
/**
|
|
421
527
|
* Build a validated, presigned URL for a snapshot object of either lane (see {@link SnapshotTarget}) — the ONE place a
|
|
422
528
|
* snapshot object key is spelled, and the one place each lane's partition is chosen (park = the session id, space = the
|
|
@@ -584,7 +690,20 @@ export declare class RemoteK8sExecutionEnv implements RemoteExecutionEnv, Backgr
|
|
|
584
690
|
error: RemoteExecutionError;
|
|
585
691
|
}>;
|
|
586
692
|
reconnect(_sessionToken: SessionToken): Promise<ConnectResult>;
|
|
587
|
-
|
|
693
|
+
/**
|
|
694
|
+
* Delete one pod — the ONE request path of "delete a sandbox pod" (the run-end delete, every refusal / reconnect clean-up, and the reaper's face: no grace).
|
|
695
|
+
* Resolves `"deleted"` (2xx) or `"gone"` (404: the pod never was / is already gone); throws {@link PodDeleteRefused} on any other answer and the request's own error on a transport failure.
|
|
696
|
+
*/
|
|
697
|
+
deletePod(name: string): Promise<"deleted" | "gone">;
|
|
698
|
+
/**
|
|
699
|
+
* Give up the pod a refused connect had already created. The refusal is the caller's answer; the delete is the clean-up behind it — and a clean-up that FAILS leaves
|
|
700
|
+
* the pod, and the Secret(s) it owns (the deployer-named env values / the lease placeholder: data at rest that no connection carries), in the sandbox namespace until
|
|
701
|
+
* the pod reaper's backstop reaches them. That is said, not swallowed — through the ONE reporter the reaper's own delete step shares
|
|
702
|
+
* ({@link reportPodDeleteFailed}: the F-class counter `server.sandbox-pod.delete-failed` and one error line naming the pod, the namespace, why the pod was being
|
|
703
|
+
* given up and how the delete failed (`http_<status>` / `request_failed`) — never a value, never the API's own text).
|
|
704
|
+
* Never throws: the refusal the caller goes on to return stays the original one.
|
|
705
|
+
*/
|
|
706
|
+
private discardRefusedPod;
|
|
588
707
|
/**
|
|
589
708
|
* Delete the sandbox pod. Idempotent, never throws. Space lane open and a pod exists ⇒ FIRST the run-end space
|
|
590
709
|
* snapshot ({@link persistWorkspace}) — after the pod's processes are confirmed stopped, the commands still in flight having ended or been cut first ({@link quiesce}); from the
|
|
@@ -766,6 +885,16 @@ export declare function createSpaceReclaimer(config: K8sEnvConfig, deps?: K8sEnv
|
|
|
766
885
|
* nodes that join after boot are read at the next boot. Never throws (a read failure is an `unreadable` gap).
|
|
767
886
|
*/
|
|
768
887
|
export declare function checkSandboxEgressPolicy(config: K8sEnvConfig, deps?: K8sEnvDeps): Promise<SandboxEgressGap[]>;
|
|
888
|
+
/** The boot reading of one sandbox Secret seat for this k8s config ({@link RemoteK8sExecutionEnv.secretSeatReading}; a control-plane env, no pod). Never throws. */
|
|
889
|
+
export declare function readSandboxSecretSeat(config: K8sEnvConfig, seat: SandboxSecretSeatKind, deps?: K8sEnvDeps): Promise<SandboxSecretSeat>;
|
|
890
|
+
/**
|
|
891
|
+
* The server's one lease writer for a pod that carries the member-credential broker ({@link RemoteK8sExecutionEnv.writeLease}): `ref` is the
|
|
892
|
+
* pod's lease seat ({@link RemoteK8sExecutionEnv.sandboxLeaseRef}), `entries` one per origin of its table. A control-plane env, no pod.
|
|
893
|
+
*/
|
|
894
|
+
export declare function writeSandboxLease(config: K8sEnvConfig, ref: SandboxLeaseRef, entries: readonly SandboxLeaseEntryInput[], deps?: K8sEnvDeps): Promise<SandboxLeaseWrite>;
|
|
895
|
+
/** The reaper's narrow face onto the sandbox namespace (list by identity labels, delete one) — a control-plane env, no pod, built at first use
|
|
896
|
+
* (as the space reclaimer builds its envs per call: the boot never constructs an env just to hold this face). */
|
|
897
|
+
export declare function createSandboxPodApi(config: K8sEnvConfig, deps?: K8sEnvDeps): SandboxPodApi;
|
|
769
898
|
/**
|
|
770
899
|
* `ExecutionEnvFactory` for the k8s pod-sandbox backend — one fresh (unconnected) env per task; the pod is
|
|
771
900
|
* created lazily on connect and deleted by `destroy()` (Runner-owned lifetime; `activeDeadlineSeconds` is the
|