@sema-agent/server 7.138.0 → 7.140.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 +457 -7
- package/README.md +7 -4
- package/README.zh-CN.md +6 -4
- package/USAGE.md +91 -41
- package/deploy/sema-up/README.md +1 -1
- package/deploy/sema-up/lib/lanes.json +3 -2
- package/dist/adoption/runner.js +1 -1
- package/dist/adoption/sql.js +1 -1
- package/dist/adoption/wire.d.ts +3 -3
- package/dist/approval-card.d.ts +26 -26
- package/dist/bench/s1/arms.d.ts +1 -1
- package/dist/bench/s1/arms.js +1 -3
- 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/bench/s1/run-firm.js +2 -2
- package/dist/boot/adoption.js +1 -1
- package/dist/boot/device-lane.d.ts +8 -3
- package/dist/boot/device-lane.js +7 -2
- package/dist/boot/execution-env.d.ts +4 -2
- package/dist/boot/execution-env.js +28 -34
- package/dist/boot/execution-lane.d.ts +9 -1
- package/dist/boot/execution-lane.js +6 -1
- package/dist/boot/governance-seams.d.ts +3 -2
- package/dist/boot/governance-seams.js +9 -11
- package/dist/boot/memory-boundary.d.ts +14 -51
- package/dist/boot/memory-boundary.js +10 -20
- package/dist/boot/memory-consolidation.d.ts +15 -11
- package/dist/boot/memory-consolidation.js +25 -14
- package/dist/boot/resolve-spec.d.ts +4 -6
- package/dist/boot/resolve-spec.js +10 -13
- package/dist/boot/retention-lane.d.ts +5 -5
- package/dist/boot/retention-lane.js +0 -6
- package/dist/boot/runner-deps.d.ts +6 -4
- package/dist/boot/runner-deps.js +3 -1
- package/dist/boot/session-faces.d.ts +0 -3
- package/dist/boot/session-faces.js +15 -8
- package/dist/boot/stage-02-web-admin-pull.js +2 -2
- 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 +2 -2
- package/dist/boot/stage-06-runners.d.ts +2 -6
- package/dist/boot/stage-06-runners.js +2 -3
- package/dist/boot/stage-07-capability-layer.d.ts +2 -6
- package/dist/boot/stage-08-reapers.d.ts +2 -6
- package/dist/boot/stage-09-leader.d.ts +2 -6
- package/dist/boot/stage-09-leader.js +1 -2
- package/dist/boot/stage-10-http-server.d.ts +2 -6
- package/dist/boot/stage-10-http-server.js +7 -6
- package/dist/boot/stores.d.ts +3 -6
- package/dist/boot/stores.js +27 -40
- 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 +37 -11
- package/dist/capabilities/execution-lane.d.ts +2 -2
- package/dist/capabilities/mcp-probe.js +1 -1
- package/dist/capabilities/scenarios.d.ts +1 -1
- package/dist/capability-facts.d.ts +15 -7
- package/dist/capability-facts.js +8 -3
- package/dist/config-catalog.js +9 -8
- package/dist/config-invariants.d.ts +23 -3
- package/dist/config-invariants.js +42 -0
- package/dist/config-provider.d.ts +33 -37
- package/dist/config-provider.js +51 -30
- package/dist/config-types.d.ts +21 -7
- package/dist/config.d.ts +33 -0
- package/dist/config.js +46 -16
- package/dist/delegated-session-owner.d.ts +4 -3
- package/dist/delegated-session-owner.js +1 -1
- package/dist/deployment-shape.d.ts +10 -9
- package/dist/deployment-shape.js +4 -4
- package/dist/device-enrollment.d.ts +41 -2
- package/dist/device-enrollment.js +27 -12
- package/dist/device-store.d.ts +58 -85
- package/dist/device-store.js +19 -49
- package/dist/device-ws-hub.js +2 -1
- package/dist/env-name-allowlist-knobs.d.ts +5 -4
- package/dist/exec-cut.d.ts +60 -0
- package/dist/exec-cut.js +36 -0
- package/dist/execution-lane-caps.d.ts +115 -105
- package/dist/execution-lane-caps.js +76 -82
- package/dist/execution-placement.d.ts +259 -0
- package/dist/execution-placement.js +199 -0
- package/dist/field-conflict.d.ts +3 -2
- package/dist/field-conflict.js +1 -0
- package/dist/hosted-posture.d.ts +2 -2
- package/dist/http/admission.js +8 -19
- package/dist/http/checkpoint-ctx.d.ts +21 -12
- package/dist/http/checkpoint-ctx.js +4 -2
- package/dist/http/claimed-run.d.ts +1 -1
- package/dist/http/durable-run-leg.js +9 -5
- package/dist/http/execution-context.d.ts +218 -0
- package/dist/http/execution-context.js +330 -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 +63 -36
- package/dist/http/retired-service-deps.d.ts +1 -1
- package/dist/http/retired-service-deps.js +1 -1
- package/dist/http/route-ctx.d.ts +14 -8
- package/dist/http/routes/adoption.js +1 -1
- package/dist/http/routes/background.d.ts +29 -1
- package/dist/http/routes/background.js +29 -2
- package/dist/http/routes/devices.d.ts +13 -19
- package/dist/http/routes/devices.js +21 -26
- package/dist/http/routes/memory-bundle.js +3 -0
- package/dist/http/routes/memory-compliance.js +8 -1
- 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 +5 -0
- package/dist/http/routes/session-sync.js +110 -15
- package/dist/http/routes/sessions.d.ts +6 -0
- package/dist/http/routes/sessions.js +143 -22
- package/dist/http/routes/side-query.d.ts +12 -4
- package/dist/http/routes/side-query.js +4 -5
- package/dist/http/routes/tasks.js +41 -33
- package/dist/http/server.d.ts +40 -44
- package/dist/http/server.js +13 -2
- package/dist/http/session-inherit-env.d.ts +3 -4
- package/dist/http/session-inherit-env.js +1 -1
- package/dist/http/wire-types.d.ts +8 -12
- package/dist/identity-source.d.ts +1 -1
- package/dist/identity-source.js +1 -1
- package/dist/index.d.ts +1 -0
- 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/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-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 +29 -5
- package/dist/memory-scope.js +16 -4
- package/dist/memory-sync-client.d.ts +70 -18
- package/dist/memory-sync-client.js +215 -117
- package/dist/memory-sync.d.ts +1 -1
- package/dist/memory-sync.js +3 -2
- package/dist/observability/cost-taxonomy.d.ts +2 -2
- package/dist/observability/fail-open.d.ts +12 -0
- package/dist/observability/fail-open.js +12 -0
- package/dist/observability/run-terminal.js +0 -1
- package/dist/orchestration/workflow-notify-journal.js +4 -4
- package/dist/org-memory-admission.d.ts +4 -3
- package/dist/org-memory-admission.js +6 -6
- package/dist/parked-decide.d.ts +34 -9
- package/dist/parked-decide.js +12 -19
- package/dist/parked-revive-surface.d.ts +12 -15
- package/dist/parked-revive-surface.js +3 -6
- package/dist/peer-seat.d.ts +13 -7
- package/dist/peer-seat.js +37 -3
- package/dist/plugins/adoption-log-sql.js +4 -4
- package/dist/plugins/approval-ask-store-file.d.ts +7 -0
- package/dist/plugins/approval-ask-store-file.js +11 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +6 -0
- package/dist/plugins/approval-ask-store-memory.js +12 -0
- package/dist/plugins/approval-ask-store-sql.d.ts +22 -5
- package/dist/plugins/approval-ask-store-sql.js +44 -26
- 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 -2
- package/dist/plugins/caching-session-store.js +9 -3
- package/dist/plugins/checkpoint-index-columns.js +2 -2
- package/dist/plugins/checkpoint-store-sql.d.ts +6 -5
- package/dist/plugins/checkpoint-store-sql.js +21 -23
- package/dist/plugins/device-store-sql.d.ts +25 -51
- package/dist/plugins/device-store-sql.js +68 -122
- package/dist/plugins/ensure-index.d.ts +1 -2
- package/dist/plugins/execution-placement-sql.d.ts +151 -0
- package/dist/plugins/execution-placement-sql.js +223 -0
- package/dist/plugins/file-history-store-sql.d.ts +9 -8
- package/dist/plugins/file-history-store-sql.js +9 -9
- package/dist/plugins/file-run-store.d.ts +6 -1
- package/dist/plugins/file-run-store.js +4 -0
- package/dist/plugins/fork-routing-session-store.d.ts +6 -0
- package/dist/plugins/fork-routing-session-store.js +16 -0
- package/dist/plugins/image-bake-store-sql.js +9 -9
- package/dist/plugins/image-index-sql.js +11 -11
- package/dist/plugins/leader-run-store-sql.js +4 -4
- package/dist/plugins/local-session-store.d.ts +149 -50
- package/dist/plugins/local-session-store.js +382 -107
- 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-key-guards.d.ts +4 -0
- package/dist/plugins/memory-key-guards.js +1 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +1 -1
- package/dist/plugins/memory-run-store.d.ts +1 -1
- package/dist/plugins/memory-sync-store-tidb.js +3 -3
- package/dist/plugins/one-time-migrations.d.ts +117 -8
- package/dist/plugins/one-time-migrations.js +408 -38
- package/dist/plugins/org-delivery-quota-store.js +2 -2
- package/dist/plugins/outcome-ledger-sql.d.ts +2 -2
- package/dist/plugins/outcome-ledger-sql.js +2 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +17 -19
- package/dist/plugins/permission-rule-store-sql.js +29 -32
- package/dist/plugins/pg-pool.d.ts +7 -3
- package/dist/plugins/pg-session-storage.d.ts +31 -20
- package/dist/plugins/pg-session-storage.js +120 -52
- package/dist/plugins/remote-env-adb.d.ts +18 -19
- package/dist/plugins/remote-env-adb.js +91 -66
- package/dist/plugins/remote-env-device.d.ts +23 -31
- package/dist/plugins/remote-env-device.js +19 -17
- package/dist/plugins/remote-env-e2b.d.ts +27 -21
- package/dist/plugins/remote-env-e2b.js +91 -45
- package/dist/plugins/remote-env-file-error.d.ts +3 -1
- package/dist/plugins/remote-env-file-error.js +9 -3
- package/dist/plugins/remote-env-host.d.ts +31 -34
- package/dist/plugins/remote-env-host.js +91 -72
- package/dist/plugins/remote-env-k8s.d.ts +13 -29
- package/dist/plugins/remote-env-k8s.js +63 -55
- package/dist/plugins/remote-env-local-docker.d.ts +24 -12
- package/dist/plugins/remote-env-local-docker.js +49 -61
- package/dist/plugins/remote-env-ssh.d.ts +11 -19
- package/dist/plugins/remote-env-ssh.js +74 -57
- package/dist/plugins/remote-shell.d.ts +100 -3
- package/dist/plugins/remote-shell.js +166 -2
- 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 +10 -7
- package/dist/plugins/retention-store-sql.js +13 -7
- package/dist/plugins/run-store-sql.d.ts +13 -3
- package/dist/plugins/run-store-sql.js +20 -15
- package/dist/plugins/schema-consistency.d.ts +21 -11
- package/dist/plugins/schema-consistency.js +15 -9
- package/dist/plugins/schema-drift-sentence.d.ts +27 -0
- package/dist/plugins/schema-drift-sentence.js +38 -0
- 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-fork.d.ts +54 -0
- package/dist/plugins/session-fork.js +38 -1
- package/dist/plugins/session-row-sql.d.ts +22 -0
- package/dist/plugins/session-row-sql.js +81 -0
- 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 +1 -1
- 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 +5 -7
- package/dist/plugins/store-backend.js +23 -11
- package/dist/plugins/store-contracts.d.ts +25 -5
- package/dist/plugins/task-list-store-sql.js +11 -11
- package/dist/plugins/tidb-pool.d.ts +12 -7
- package/dist/plugins/tidb-pool.js +13 -7
- package/dist/plugins/tidb-session-storage.js +4 -4
- package/dist/plugins/tidb-session-store.d.ts +57 -26
- package/dist/plugins/tidb-session-store.js +127 -59
- package/dist/plugins/tool-result-store-sql.d.ts +5 -4
- package/dist/plugins/tool-result-store-sql.js +21 -13
- 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/project-memory.d.ts +9 -15
- package/dist/project-memory.js +5 -4
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +6 -7
- package/dist/request-value-closure.js +1 -3
- 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-local.d.ts +6 -0
- package/dist/run-local.js +34 -35
- package/dist/runs.d.ts +10 -5
- package/dist/runs.js +52 -66
- package/dist/security.d.ts +38 -12
- package/dist/security.js +8 -2
- package/dist/server-secret-env.d.ts +9 -5
- package/dist/session-children-retire.d.ts +27 -9
- package/dist/session-children-retire.js +9 -5
- package/dist/session-incarnation.d.ts +20 -10
- package/dist/session-incarnation.js +5 -3
- package/dist/session-policy-wire.d.ts +1 -1
- package/dist/session-row.d.ts +114 -5
- package/dist/session-row.js +55 -5
- package/dist/session-titler.d.ts +2 -2
- package/dist/sql-engine-posture.d.ts +1 -1
- package/dist/sql-engine-posture.js +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-cwd.d.ts +6 -1
- package/dist/task-mcp.d.ts +22 -9
- package/dist/task-mcp.js +17 -9
- package/dist/terminal.d.ts +27 -0
- package/dist/terminal.js +6 -0
- package/dist/tool-approval.d.ts +6 -0
- package/dist/tool-approval.js +8 -1
- package/dist/trace/project.d.ts +1 -0
- package/dist/trace/project.js +1 -0
- package/dist/trace/redact.d.ts +3 -1
- package/dist/trace/redact.js +80 -28
- package/dist/trace/self-minted-wire.d.ts +169 -2
- package/dist/trace/self-minted-wire.js +54 -1
- package/dist/url-refusal.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.d.ts +17 -3
- package/dist/web-admin-client/apply-effective.js +20 -10
- 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/dist/web-admin-client/skills-mcp.js +3 -2
- package/dist/web-admin-client/types.d.ts +6 -0
- package/package.json +3 -3
- package/wire-changes/server@7.139.0.json +348 -0
- package/wire-changes/server@7.140.0.json +184 -0
- package/dist/http/device-placement.d.ts +0 -175
- package/dist/http/device-placement.js +0 -145
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { Sandbox, CommandExitError, FileType } from "e2b";
|
|
3
3
|
import { FileError, ExecutionError, RemoteExecutionError, RollingTailBuffer, markTruncated, } from "@sema-agent/core";
|
|
4
|
+
import { capabilitiesFor } from "../execution-lane-caps.js";
|
|
5
|
+
import { LANE_HOME_PROBE_COMMAND, LaneHomeSeat } from "../lane-home-probe.js";
|
|
4
6
|
import { fileErrorFromExec } from "./remote-env-file-error.js";
|
|
5
|
-
import { numEnvOr, runSymlinkChain, shellQuote } from "./remote-shell.js";
|
|
7
|
+
import { appendFileStaged, rewriteAppend, numEnvOr, runSymlinkChain, shellQuote, writeFileStaged } from "./remote-shell.js";
|
|
6
8
|
import { buildLivenessCut, commandBoundsOf, firstBoundOf, laneLivenessOf, LIVENESS_MS_DEFAULT } from "../exec-bounds.js";
|
|
9
|
+
import { createCutError } from "../exec-cut.js";
|
|
7
10
|
import { BackgroundShellManager } from "./background-shell-support.js";
|
|
8
11
|
const PROVIDER = "e2b";
|
|
9
12
|
const DEFAULT_MOUNT_PATH = "/home/user";
|
|
@@ -18,7 +21,9 @@ const E2B_BG_PROVIDER_BACKSTOP_PAD_SEC = 30;
|
|
|
18
21
|
const ok = (value) => ({ ok: true, value });
|
|
19
22
|
export class RemoteContainerExecutionEnv {
|
|
20
23
|
cwd;
|
|
21
|
-
homeDir
|
|
24
|
+
get homeDir() {
|
|
25
|
+
return this.homeSeat.home;
|
|
26
|
+
}
|
|
22
27
|
cdPath = "unknown";
|
|
23
28
|
withheldEnv = [];
|
|
24
29
|
cfg;
|
|
@@ -28,6 +33,8 @@ export class RemoteContainerExecutionEnv {
|
|
|
28
33
|
keepAlive;
|
|
29
34
|
handle;
|
|
30
35
|
destroyed = false;
|
|
36
|
+
homeSeat;
|
|
37
|
+
homeRefusal;
|
|
31
38
|
connecting;
|
|
32
39
|
activeCommands = 0;
|
|
33
40
|
paused = false;
|
|
@@ -43,10 +50,10 @@ export class RemoteContainerExecutionEnv {
|
|
|
43
50
|
};
|
|
44
51
|
this.laneLiveness = laneLivenessOf(this.cfg.livenessMs, "E2B_LIVENESS_MS");
|
|
45
52
|
this.cwd = this.cfg.mountPath;
|
|
46
|
-
this.
|
|
53
|
+
this.homeSeat = new LaneHomeSeat(PROVIDER, config);
|
|
47
54
|
this.sandboxApi = deps.sandboxApi ?? Sandbox;
|
|
48
55
|
}
|
|
49
|
-
capabilities = {
|
|
56
|
+
capabilities = capabilitiesFor({ remoteExec: { provider: "e2b" } });
|
|
50
57
|
workspaceHandle() {
|
|
51
58
|
if (!this.handle) {
|
|
52
59
|
throw new RemoteExecutionError("connect_failed", "workspaceHandle() called before connect()");
|
|
@@ -68,6 +75,8 @@ export class RemoteContainerExecutionEnv {
|
|
|
68
75
|
}
|
|
69
76
|
if (this.destroyed)
|
|
70
77
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env already destroyed") };
|
|
78
|
+
if (this.homeRefusal)
|
|
79
|
+
return { ok: false, error: this.homeRefusal };
|
|
71
80
|
if (this.paused)
|
|
72
81
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env is suspended (paused) — resumeVM(snapshotId) before use") };
|
|
73
82
|
if (this.sbx)
|
|
@@ -94,6 +103,12 @@ export class RemoteContainerExecutionEnv {
|
|
|
94
103
|
await sbx.kill().catch(() => { });
|
|
95
104
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during connect") };
|
|
96
105
|
}
|
|
106
|
+
const home = await this.homeVerdict(sbx, config?.abortSignal);
|
|
107
|
+
if (home !== undefined || this.destroyed) {
|
|
108
|
+
await sbx.kill().catch(() => { });
|
|
109
|
+
this.cfg.metrics?.inc("remote_env_connect_total", { provider: PROVIDER, result: "error" });
|
|
110
|
+
return { ok: false, error: home ?? new RemoteExecutionError("connect_failed", "execution env destroyed during connect") };
|
|
111
|
+
}
|
|
97
112
|
this.sbx = sbx;
|
|
98
113
|
this.paused = false;
|
|
99
114
|
this.startKeepAlive();
|
|
@@ -146,6 +161,8 @@ export class RemoteContainerExecutionEnv {
|
|
|
146
161
|
async resumeVM(snapshotId, options) {
|
|
147
162
|
if (this.destroyed)
|
|
148
163
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "env already destroyed") };
|
|
164
|
+
if (this.homeRefusal)
|
|
165
|
+
return { ok: false, error: this.homeRefusal };
|
|
149
166
|
if (this.sbx && !this.paused && this.sbx.sandboxId === snapshotId)
|
|
150
167
|
return ok(this.workspaceHandle());
|
|
151
168
|
if (this.connecting)
|
|
@@ -163,6 +180,16 @@ export class RemoteContainerExecutionEnv {
|
|
|
163
180
|
await sbx.kill().catch(() => { });
|
|
164
181
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during resume") };
|
|
165
182
|
}
|
|
183
|
+
const home = await this.homeVerdict(sbx, options?.abortSignal);
|
|
184
|
+
if (this.destroyed) {
|
|
185
|
+
await sbx.kill().catch(() => { });
|
|
186
|
+
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during resume") };
|
|
187
|
+
}
|
|
188
|
+
if (home !== undefined) {
|
|
189
|
+
await this.rpc("sandbox.pause", (signal) => sbx.pause({ signal }), undefined, this.cfg.dataTimeoutMs).catch((e) => this.cfg.logger?.warn?.("remote_env_home_refused_repause_failed", { sandboxId: sbx.sandboxId, error: errMsg(e) }));
|
|
190
|
+
this.cfg.metrics?.inc("remote_env_resume_total", { provider: PROVIDER, result: "error" });
|
|
191
|
+
return { ok: false, error: home };
|
|
192
|
+
}
|
|
166
193
|
this.sbx = sbx;
|
|
167
194
|
this.paused = false;
|
|
168
195
|
this.startKeepAlive();
|
|
@@ -195,6 +222,27 @@ export class RemoteContainerExecutionEnv {
|
|
|
195
222
|
return { ok: false, error: this.remoteError(e, "post_resume_failed") };
|
|
196
223
|
}
|
|
197
224
|
}
|
|
225
|
+
async homeVerdict(sbx, signal) {
|
|
226
|
+
if (!this.homeSeat.asks)
|
|
227
|
+
return undefined;
|
|
228
|
+
let probe;
|
|
229
|
+
try {
|
|
230
|
+
const r = await this.rpc("sandbox.home", (s) => sbx.commands.run(LANE_HOME_PROBE_COMMAND, { signal: s }), signal);
|
|
231
|
+
probe = r.exitCode === 0 ? { ok: true, stdout: r.stdout } : { ok: false, reason: `exit ${r.exitCode}` };
|
|
232
|
+
}
|
|
233
|
+
catch (e) {
|
|
234
|
+
probe = { ok: false, reason: e instanceof CommandExitError ? `exit ${e.exitCode}` : errMsg(e) };
|
|
235
|
+
}
|
|
236
|
+
if (signal?.aborted)
|
|
237
|
+
return new RemoteExecutionError("aborted", "connect aborted while reading the sandbox's home");
|
|
238
|
+
const verdict = this.homeSeat.settle(probe);
|
|
239
|
+
if (verdict === undefined)
|
|
240
|
+
return undefined;
|
|
241
|
+
const error = new RemoteExecutionError("connect_failed", verdict.refusal);
|
|
242
|
+
if (verdict.answered)
|
|
243
|
+
this.homeRefusal = error;
|
|
244
|
+
return error;
|
|
245
|
+
}
|
|
198
246
|
startKeepAlive() {
|
|
199
247
|
this.stopKeepAlive();
|
|
200
248
|
const everyMs = Math.max(30_000, Math.floor(this.cfg.timeoutMs * 0.8));
|
|
@@ -251,6 +299,8 @@ export class RemoteContainerExecutionEnv {
|
|
|
251
299
|
stderr: { tail: new RollingTailBuffer(), total: 0, cursor: 0 },
|
|
252
300
|
}
|
|
253
301
|
: undefined;
|
|
302
|
+
let started;
|
|
303
|
+
const captured = () => ({ stdout: started?.stdout ?? "", stderr: started?.stderr ?? "" });
|
|
254
304
|
let detached = false;
|
|
255
305
|
const teePush = (s, d) => {
|
|
256
306
|
const b = Buffer.from(d, "utf8");
|
|
@@ -299,10 +349,10 @@ export class RemoteContainerExecutionEnv {
|
|
|
299
349
|
this.settleAbandonedStart(starting);
|
|
300
350
|
const cut = e instanceof RemoteExecutionError && e.code === "timeout" && !options?.abortSignal?.aborted;
|
|
301
351
|
if (!cut)
|
|
302
|
-
return { ok: false, error: this.execError(e, options?.abortSignal) };
|
|
303
|
-
|
|
304
|
-
return { ok: false, error: new ExecutionError(bc.code, bc.message, undefined, undefined, bc.noOutputSec) };
|
|
352
|
+
return { ok: false, error: this.execError(e, options?.abortSignal, captured()) };
|
|
353
|
+
return { ok: false, error: createCutError(boundCut(first), captured()) };
|
|
305
354
|
}
|
|
355
|
+
started = handle;
|
|
306
356
|
const onAbort = () => { if (!detached)
|
|
307
357
|
void handle.kill().catch(() => { }); };
|
|
308
358
|
if (options?.abortSignal) {
|
|
@@ -352,6 +402,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
352
402
|
disarmed: () => detached,
|
|
353
403
|
...(tee ? { wall: { totalMs: this.commandTimeoutMs(options?.timeout), leftMs: Math.max(0, this.commandTimeoutMs(options?.timeout) - (Date.now() - startedAt)) } } : {}),
|
|
354
404
|
liveness: bounds.liveness,
|
|
405
|
+
captured,
|
|
355
406
|
});
|
|
356
407
|
const winner = await (detachedP ? Promise.race([fg, detachedP]) : fg);
|
|
357
408
|
if (winner === "detached") {
|
|
@@ -365,18 +416,18 @@ export class RemoteContainerExecutionEnv {
|
|
|
365
416
|
});
|
|
366
417
|
}
|
|
367
418
|
if (options?.abortSignal?.aborted && !detached) {
|
|
368
|
-
return { ok: false, error:
|
|
419
|
+
return { ok: false, error: createCutError({ code: "aborted", message: "exec aborted (remote process killed)" }, captured()) };
|
|
369
420
|
}
|
|
370
421
|
return ok({ stdout: winner.stdout, stderr: winner.stderr, exitCode: winner.exitCode });
|
|
371
422
|
}
|
|
372
423
|
catch (e) {
|
|
373
424
|
if (options?.abortSignal?.aborted && !detached) {
|
|
374
|
-
return { ok: false, error: this.execError(e, options.abortSignal) };
|
|
425
|
+
return { ok: false, error: this.execError(e, options.abortSignal, captured()) };
|
|
375
426
|
}
|
|
376
427
|
if (e instanceof CommandExitError) {
|
|
377
428
|
return ok({ stdout: e.stdout, stderr: e.stderr, exitCode: e.exitCode });
|
|
378
429
|
}
|
|
379
|
-
return { ok: false, error: this.execError(e, options?.abortSignal) };
|
|
430
|
+
return { ok: false, error: this.execError(e, options?.abortSignal, captured()) };
|
|
380
431
|
}
|
|
381
432
|
finally {
|
|
382
433
|
fgSettled = true;
|
|
@@ -659,37 +710,33 @@ export class RemoteContainerExecutionEnv {
|
|
|
659
710
|
return { ok: false, error: this.fileError(e, this.resolve(p), abortSignal) };
|
|
660
711
|
}
|
|
661
712
|
}
|
|
713
|
+
stagedLane(sbx, content) {
|
|
714
|
+
const data = typeof content === "string" ? content : toArrayBuffer(content);
|
|
715
|
+
return {
|
|
716
|
+
upload: async (dest, signal) => {
|
|
717
|
+
try {
|
|
718
|
+
await this.rpc("files.write", (s) => sbx.files.write(dest, data, { signal: s }), signal, this.cfg.dataTimeoutMs);
|
|
719
|
+
return ok(undefined);
|
|
720
|
+
}
|
|
721
|
+
catch (e) {
|
|
722
|
+
return { ok: false, error: this.fileError(e, dest, signal) };
|
|
723
|
+
}
|
|
724
|
+
},
|
|
725
|
+
run: (cmd, signal) => this.exec(cmd, { cwd: "/", ...(signal !== undefined ? { abortSignal: signal } : {}) }),
|
|
726
|
+
};
|
|
727
|
+
}
|
|
662
728
|
async writeFile(p, content, abortSignal) {
|
|
663
729
|
const sbx = await this.fsReady(p);
|
|
664
730
|
if (!sbx.ok)
|
|
665
731
|
return sbx;
|
|
666
|
-
|
|
667
|
-
const data = typeof content === "string" ? content : toArrayBuffer(content);
|
|
668
|
-
await this.rpc("files.write", (signal) => sbx.value.files.write(this.resolve(p), data, { signal }), abortSignal, this.cfg.dataTimeoutMs);
|
|
669
|
-
return ok(undefined);
|
|
670
|
-
}
|
|
671
|
-
catch (e) {
|
|
672
|
-
return { ok: false, error: this.fileError(e, this.resolve(p), abortSignal) };
|
|
673
|
-
}
|
|
732
|
+
return writeFileStaged(this.stagedLane(sbx.value, content), this.resolve(p), abortSignal);
|
|
674
733
|
}
|
|
675
734
|
async appendFile(p, content, abortSignal) {
|
|
735
|
+
const sbx = await this.fsReady(p);
|
|
736
|
+
if (!sbx.ok)
|
|
737
|
+
return sbx;
|
|
676
738
|
const abs = this.resolve(p);
|
|
677
|
-
|
|
678
|
-
let base;
|
|
679
|
-
if (existing.ok) {
|
|
680
|
-
base = existing.value;
|
|
681
|
-
}
|
|
682
|
-
else if (existing.error.code === "not_found") {
|
|
683
|
-
base = new Uint8Array(0);
|
|
684
|
-
}
|
|
685
|
-
else {
|
|
686
|
-
return existing;
|
|
687
|
-
}
|
|
688
|
-
const add = typeof content === "string" ? new TextEncoder().encode(content) : content;
|
|
689
|
-
const merged = new Uint8Array(base.length + add.length);
|
|
690
|
-
merged.set(base, 0);
|
|
691
|
-
merged.set(add, base.length);
|
|
692
|
-
return this.writeFile(abs, merged, abortSignal);
|
|
739
|
+
return appendFileStaged(this.stagedLane(sbx.value, content), abs, abortSignal, (ctx) => rewriteAppend((signal) => this.readBinaryFile(abs, signal), (bytes, signal) => this.stagedLane(sbx.value, bytes).upload(abs, signal), content, ctx));
|
|
693
740
|
}
|
|
694
741
|
async fileInfo(p, abortSignal) {
|
|
695
742
|
const sbx = await this.fsReady(p);
|
|
@@ -851,16 +898,15 @@ export class RemoteContainerExecutionEnv {
|
|
|
851
898
|
async waitWithLiveness(handle, lastProgress, opts) {
|
|
852
899
|
let timer;
|
|
853
900
|
let wallTimer;
|
|
854
|
-
const liveness = opts
|
|
901
|
+
const liveness = opts.liveness;
|
|
855
902
|
const idle = new Promise((_, reject) => {
|
|
856
903
|
const arm = (bound) => {
|
|
857
904
|
timer = setTimeout(() => {
|
|
858
|
-
if (opts
|
|
905
|
+
if (opts.disarmed?.())
|
|
859
906
|
return;
|
|
860
907
|
const idleFor = Date.now() - lastProgress();
|
|
861
908
|
if (idleFor >= bound.ms) {
|
|
862
|
-
|
|
863
|
-
reject(new ExecutionError(cut.code, cut.message, undefined, undefined, cut.noOutputSec));
|
|
909
|
+
reject(createCutError(buildLivenessCut(bound), opts.captured()));
|
|
864
910
|
void handle.kill().catch(() => { });
|
|
865
911
|
this.cfg.metrics?.inc("remote_env_exec_idle_timeout_total", { provider: PROVIDER });
|
|
866
912
|
}
|
|
@@ -871,18 +917,18 @@ export class RemoteContainerExecutionEnv {
|
|
|
871
917
|
};
|
|
872
918
|
if (liveness !== undefined)
|
|
873
919
|
arm(liveness);
|
|
874
|
-
if (opts
|
|
920
|
+
if (opts.wall !== undefined) {
|
|
875
921
|
const wall = opts.wall;
|
|
876
922
|
wallTimer = setTimeout(() => {
|
|
877
923
|
if (opts.disarmed?.())
|
|
878
924
|
return;
|
|
879
|
-
reject(
|
|
925
|
+
reject(createCutError({ code: "timeout", message: wallCutMessage(wall.totalMs) }, opts.captured()));
|
|
880
926
|
void handle.kill().catch(() => { });
|
|
881
927
|
}, wall.leftMs);
|
|
882
928
|
}
|
|
883
929
|
});
|
|
884
930
|
try {
|
|
885
|
-
return await Promise.race([opts
|
|
931
|
+
return await Promise.race([opts.waitP ?? handle.wait(), idle]);
|
|
886
932
|
}
|
|
887
933
|
finally {
|
|
888
934
|
if (timer)
|
|
@@ -906,7 +952,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
906
952
|
async fsReady(p) {
|
|
907
953
|
const conn = await this.ensureConnected();
|
|
908
954
|
if (!conn.ok)
|
|
909
|
-
return { ok: false, error:
|
|
955
|
+
return { ok: false, error: fileErrorFromExec(conn.error, this.resolve(p)) };
|
|
910
956
|
return ok(conn.value);
|
|
911
957
|
}
|
|
912
958
|
tempResult(r, op) {
|
|
@@ -953,15 +999,15 @@ export class RemoteContainerExecutionEnv {
|
|
|
953
999
|
return new FileError("is_directory", msg, p);
|
|
954
1000
|
return new FileError("unknown", msg, p);
|
|
955
1001
|
}
|
|
956
|
-
execError(e, abortSignal) {
|
|
1002
|
+
execError(e, abortSignal, captured) {
|
|
957
1003
|
if (e instanceof ExecutionError)
|
|
958
1004
|
return e;
|
|
959
1005
|
const msg = errMsg(e);
|
|
960
1006
|
const name = e?.name;
|
|
961
1007
|
if (abortSignal?.aborted || name === "AbortError")
|
|
962
|
-
return
|
|
1008
|
+
return createCutError({ code: "aborted", message: msg }, captured);
|
|
963
1009
|
if (providerTimedOut(e))
|
|
964
|
-
return
|
|
1010
|
+
return createCutError({ code: "timeout", message: msg }, captured);
|
|
965
1011
|
return new ExecutionError("unknown", msg, e instanceof Error ? e : undefined);
|
|
966
1012
|
}
|
|
967
1013
|
remoteError(e, code = "unknown") {
|
|
@@ -15,9 +15,11 @@
|
|
|
15
15
|
* 那条教训:宣布"类修完成"而三个实现只落了一个)。收成一处之后,判据只有一条 ——
|
|
16
16
|
* **文件面的 exec 包装必须走这里**,而这条能被机器检查(见 `test/env-adapter-file-error-parity.test.ts`)。
|
|
17
17
|
*/
|
|
18
|
-
import { FileError,
|
|
18
|
+
import { FileError, RemoteExecutionError, type ExecutionError } from "@sema-agent/core";
|
|
19
19
|
/** exec 层的错误码 → 文件层的码。只映射**有对应语义**的那些,其余落 `unknown`(诚实降级)。 */
|
|
20
20
|
export declare function fileErrorFromExec(e: ExecutionError | RemoteExecutionError, path?: string): FileError;
|
|
21
|
+
/** POSIX 的一个名字段上限(NAME_MAX,字节;Linux / macOS / 常见文件系统同值)。也是远端写的私有暂存目录名的上限(`remote-shell.ts` `buildStagingPaths`)。 */
|
|
22
|
+
export declare const NAME_MAX_BYTES = 255;
|
|
21
23
|
/**
|
|
22
24
|
* core 7.56.0 [ref]:`ENAMETOOLONG` 的**一只读法**(本文件的 stderr 分类器与 host 车道的 errno 映射同调)—— 路径有一段超过 NAME_MAX(按 UTF-8 字节量)⇒
|
|
23
25
|
* `name_too_long`:没有目录装得下这个名字,引擎读站把它读作缺席(与 `not_found` 同读);段都短、只是整条超 PATH_MAX ⇒ `unknown`(那种文件可能存在,从下层目录够得着)。
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
import { FileError } from "@sema-agent/core";
|
|
1
|
+
import { FileError, RemoteExecutionError } from "@sema-agent/core";
|
|
2
|
+
function neverOpened(e) {
|
|
3
|
+
if (e.code === "connect_failed")
|
|
4
|
+
return true;
|
|
5
|
+
const cause = e.cause;
|
|
6
|
+
return cause instanceof RemoteExecutionError && cause.code === "connect_failed";
|
|
7
|
+
}
|
|
2
8
|
export function fileErrorFromExec(e, path) {
|
|
3
|
-
const code = e.code === "aborted" ? "aborted" : "unknown";
|
|
9
|
+
const code = e.code === "aborted" ? "aborted" : neverOpened(e) ? "target_unavailable" : "unknown";
|
|
4
10
|
return new FileError(code, e.message, path, e);
|
|
5
11
|
}
|
|
6
|
-
const NAME_MAX_BYTES = 255;
|
|
12
|
+
export const NAME_MAX_BYTES = 255;
|
|
7
13
|
export function nameTooLongCode(p) {
|
|
8
14
|
return p !== undefined && p.split(/[\\/]/).some((part) => Buffer.byteLength(part, "utf8") > NAME_MAX_BYTES) ? "name_too_long" : "unknown";
|
|
9
15
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
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
|
+
import { type LaneHomeConfig } from "../lane-home-probe.js";
|
|
2
3
|
/** Options accepted by `ExecutionEnv.exec` (core does not re-export the type; derive it from the seam). */
|
|
3
4
|
type ExecOpts = Parameters<ExecutionEnv["exec"]>[1];
|
|
4
5
|
/** SIGTERM → grace → SIGKILL (no host isolation). 🔴 宽限的**唯一属主**:本 driver 的 `kill` 梯子用它排升级定时器;会话级收敛
|
|
@@ -6,7 +7,7 @@ type ExecOpts = Parameters<ExecutionEnv["exec"]>[1];
|
|
|
6
7
|
* 这把梯子的用户面宽限取消),不另抄数。启动期读一次;`0` 被 `numEnvOr` 读作缺席(回落 1000),要几乎不等写 `1`。 */
|
|
7
8
|
export declare const HOST_BG_KILL_GRACE_MS: number;
|
|
8
9
|
/** Construction config for {@link RemoteHostExecutionEnv}. */
|
|
9
|
-
export interface HostEnvConfig {
|
|
10
|
+
export interface HostEnvConfig extends LaneHomeConfig {
|
|
10
11
|
/**
|
|
11
12
|
* Base directory under which this adapter creates its per-task working directory. Default {@link os.tmpdir}.
|
|
12
13
|
* The actual workspace is `<workspaceBase>/sema-host-<id>` and is `rm -rf`'d on {@link destroy}.
|
|
@@ -24,15 +25,6 @@ export interface HostEnvConfig {
|
|
|
24
25
|
* own `process.env` is the default base (a local coding agent inherits the user's environment).
|
|
25
26
|
*/
|
|
26
27
|
env?: Record<string, string>;
|
|
27
|
-
/**
|
|
28
|
-
* [ref]④ / core [ref] —— 本执行环境的 **home 目录**(`ExecutionEnv.homeDir` 座,绝对路径,本环境自己的
|
|
29
|
-
* 命名空间里)。`~/…` 形权限规则(`Edit(~/.ssh/**)`)对**跑在本 env 里的调用**就以它为基。
|
|
30
|
-
* 缺席 ⇒ 本 env 声明「我没有 home」,core 对 `~/` 规则判 `unreadable`(fail-closed 的 ask),
|
|
31
|
-
* 绝不回落引擎进程自己的 home(那在远端腿上是另一个用户的另一个目录 —— 静默守错目录正是 [ref] 的病)。
|
|
32
|
-
* 值由 `boot/execution-env.ts` 从**唯一属主** `execution-lane-caps.ts` 的 `executionLaneHomeDir` 递进来;
|
|
33
|
-
* adapter 不自算(两处各算一份 = 422 门与引擎对同一条规则给相反答案)。
|
|
34
|
-
*/
|
|
35
|
-
homeDir?: string;
|
|
36
28
|
/** Per-command wall-clock bound (ms) when the caller gives none. Default {@link DEFAULT_COMMAND_TIMEOUT_MS}. */
|
|
37
29
|
commandTimeoutMs?: number;
|
|
38
30
|
/** Shell-child env policy — core's `InheritEnvPolicy`, read by core's `inheritedHostEnv` (the three words are judged
|
|
@@ -64,24 +56,8 @@ export interface HostEnvConfig {
|
|
|
64
56
|
backgroundShell?: boolean;
|
|
65
57
|
}
|
|
66
58
|
export declare class RemoteHostExecutionEnv implements RemoteExecutionEnv, SchedulerCapability, BackgroundShellCapability {
|
|
67
|
-
/**
|
|
68
|
-
|
|
69
|
-
* 🔴 **[ref] / core 7.20.0([ref])`canonicalPathAuthoritative: true`** —— 本适配器的 `canonicalPath`
|
|
70
|
-
* 就是**命令真正跑的那块文件系统**的权威答案(worker 本机的 `fs.realpath`)。声明它 = 告诉引擎:整链答不出来是**解析器出了事**
|
|
71
|
-
* (RPC 断、传输掉),不是「一个它看不见的命名空间」⇒ 读边界的执行期复核**拒**,而不是让词法判决站着。
|
|
72
|
-
* 缺席是今天每个适配器的读法(整链沉默 ⇒ 词法判决成立、命令照跑),所以这一声明是**收紧**方向。
|
|
73
|
-
* 严格读法 `=== true`(core `canonicalPathIsAuthoritative`);`isSuspendable` 一族同样严格,对本仓的
|
|
74
|
-
* 布尔字面量零影响(四键都写死字面 `true`/`false`,不存在「非布尔值被读成缺席」那一形 —— 那一形由
|
|
75
|
-
* core 的 `config.execution_env_capability_invalid` 普查响亮播报,本仓的受众表已登记)。
|
|
76
|
-
* 谁该声明由闭集门看着(`test/execution-lane-caps.test.ts` 的逐 lane 对账:新 lane 不表态 = 编译红)。
|
|
77
|
-
*/
|
|
78
|
-
/** `sharesProcessTable`(core 7.57.0,必填):命令是本进程 spawn 的子进程(同一张进程表),引擎的模式杀守卫对它照 NodeExecutionEnv 一样问 `pgrep`。 */
|
|
79
|
-
readonly capabilities: {
|
|
80
|
-
isolation: boolean;
|
|
81
|
-
suspendable: boolean;
|
|
82
|
-
canonicalPathAuthoritative: boolean;
|
|
83
|
-
sharesProcessTable: boolean;
|
|
84
|
-
};
|
|
59
|
+
/** 能力块的唯一作者 = `capabilitiesFor`(`execution-lane-caps.ts`;逐键表态与理由在那里,本类零能力字面量)。 */
|
|
60
|
+
readonly capabilities: import("@sema-agent/core").ExecutionEnvCapabilities;
|
|
85
61
|
/** R7 自唤醒: structural delegation to the injected scheduler backend. `hasScheduler(env)` checks BOTH the method
|
|
86
62
|
* presence (always, since we implement the interface) AND `schedulerCapabilities.supported===true` — which is only
|
|
87
63
|
* true when a backend was injected, so a host env without one stays INERT (the four scheduler tools don't mount). */
|
|
@@ -93,8 +69,13 @@ export declare class RemoteHostExecutionEnv implements RemoteExecutionEnv, Sched
|
|
|
93
69
|
list(ctx: SchedulerContext): Promise<Result<ScheduledTaskSummary[], SchedulerError>>;
|
|
94
70
|
/** Working directory; relative paths resolve against it (ExecutionEnv contract). Starts at the workspace root. */
|
|
95
71
|
cwd: string;
|
|
96
|
-
/** core `ExecutionEnv.homeDir`([ref])
|
|
97
|
-
|
|
72
|
+
/** core `ExecutionEnv.homeDir`([ref]):本机执行用户的 home —— 主张在场 ⇒ 主张(构造时与子进程拿到的 `HOME` 对证过),否则构造时读到的那个 `HOME`,见 {@link LaneHomeSeat}。 */
|
|
73
|
+
get homeDir(): string | undefined;
|
|
74
|
+
/** 家目录的座(主张在场 ⇒ 构造时对证 · 否则构造时实测)。读数 = {@link childHome}:本类自己组合给子进程的那份 env,不 spawn。 */
|
|
75
|
+
private readonly homeSeat;
|
|
76
|
+
/** 家目录:主张与子进程拿到的 `HOME` 对不上 ⇒ 这只环境的拒句;`shellReady` / `fsReady` / `connect` 三道门原样回它,一条命令、一次文件动作都不做。
|
|
77
|
+
* 读数是本类自己组合的 env(纯函数,同一份输入同一个答案)⇒ 构造时判一次、记一辈子。 */
|
|
78
|
+
private readonly homeRefusal;
|
|
98
79
|
/**
|
|
99
80
|
* core 7.49.0 [ref]:shell 子进程**真拿到的** `CDPATH` 条目(`[]` = 没有)—— 删除守卫按它解裸 `cd <dir>`。本车道的命令就是本机子进程,
|
|
100
81
|
* env 是本类自己组合的(继承姿态 + `cfg.env`),所以说得出:读同一只组合({@link childEnv} 的**读面**,不披露、不钉 shell),切法与 core
|
|
@@ -299,8 +280,9 @@ export declare class RemoteHostExecutionEnv implements RemoteExecutionEnv, Sched
|
|
|
299
280
|
maxLines?: number;
|
|
300
281
|
abortSignal?: AbortSignal;
|
|
301
282
|
}): Promise<Result<string[], FileError>>;
|
|
302
|
-
/** core `NodeExecutionEnv`
|
|
303
|
-
|
|
283
|
+
/** core `NodeExecutionEnv` 的一只实例 —— 本车道把**落盘那一步**委托给它的两只面({@link openBound} 的持有读、{@link writeFile} 的整文件替换);
|
|
284
|
+
* 首次用时建(构造无副作用,只记 cwd)。门(`fsReady`)、在飞登记(`withInflightFs`)与工作区相对解析留在本适配器。 */
|
|
285
|
+
private coreFs;
|
|
304
286
|
/**
|
|
305
287
|
* core 7.50.0 `FileSystem.openBound`:开着并**持有**一只对象(叶链接不跟,开后身份对拍),调用方判的与读的是同一只对象 ——
|
|
306
288
|
* LSP 会话的读口与路径附件只经它读,不实现 ⇒ 两者在本车道一律拒。
|
|
@@ -310,8 +292,15 @@ export declare class RemoteHostExecutionEnv implements RemoteExecutionEnv, Sched
|
|
|
310
292
|
*/
|
|
311
293
|
openBound(p: string, abortSignal?: AbortSignal): Promise<Result<BoundFileObject, FileError>>;
|
|
312
294
|
readBinaryFile(p: string, abortSignal?: AbortSignal): Promise<Result<Uint8Array, FileError>>;
|
|
313
|
-
/**
|
|
314
|
-
*
|
|
295
|
+
/**
|
|
296
|
+
* 整文件替换:**整旧或整新;`aborted` ⇒ 目标未碰**。
|
|
297
|
+
* 🔴 **不重写**:落盘那一步委托 core `NodeExecutionEnv.writeFile`(同目录暂存 + fsync + rename;父目录自建;单跳链接改写它指的
|
|
298
|
+
* 常规文件、链接链 / 非常规文件 / rename 不可用的文件系统回落就地写;已有文件的权限位带过去)—— 该原语的唯一属主在 core。
|
|
299
|
+
* 本适配器只给它与其余写面同一的入口纪律:[ref] 在飞登记(整只方法体**含** `fsReady` 那道门走 `withInflightFs` —— 登记必须与
|
|
300
|
+
* 调用方同一同步段,否则 destroy 的快照可能刚好在 `await this.fsReady(...)` 的让出点上取完;见那处头注)、销毁后拒、工作区相对解析。
|
|
301
|
+
* 修前这里是裸 `fs.writeFile(abs, data, { signal })`:open 即 O_TRUNC,中途取消 / 出错 ⇒ 目标 = 新内容的前缀,原件不可恢复。
|
|
302
|
+
* 已知语义变化(与 core / CC 同形):rename 断开硬链接 —— 另一条链接留旧内容。
|
|
303
|
+
*/
|
|
315
304
|
writeFile(p: string, content: string | Uint8Array, abortSignal?: AbortSignal): Promise<Result<void, FileError>>;
|
|
316
305
|
/** [ref](写面一律 `withInflightFs`,见那处头注)。本面是唯一能在 `destroyed` **之后**过门的写面
|
|
317
306
|
* (`lingeringBgWrite`):那一族登记在 destroy 的快照**之后**,所以 destroy 不会去等它们 —— 正确,
|
|
@@ -441,6 +430,14 @@ export declare class RemoteHostExecutionEnv implements RemoteExecutionEnv, Sched
|
|
|
441
430
|
* 引擎对点到自有凭据名的白名单在这里**抛**(spawn 时的拒;构造器已先问过同一只判)—— 子进程不起,拒句带名。
|
|
442
431
|
*/
|
|
443
432
|
private childEnv;
|
|
433
|
+
/**
|
|
434
|
+
* 家目录的读数:本类组合给子进程的那份 env 里的 `HOME`(组合层,不 spawn、不记剥除 —— 与 {@link cdPath} 同一只读面)。env 里没有 `HOME` ⇒ 读
|
|
435
|
+
* 账户的家目录(`os.userInfo().homedir`):那正是子进程的 shell 对缺席 `HOME` 的 `~` 展开(POSIX 取账户 passwd 行;win32 是账户的配置目录)。
|
|
436
|
+
* 不读 `os.homedir()`:它先读**服务进程自己的** `HOME` —— 子进程没继承到的那个值(对抗轮 r1 [high] 实测:服务 `HOME` 指别处 + `inheritEnv: []` 时两者分叉)。
|
|
437
|
+
* 账户查不到(无 passwd 行)⇒ 读不出(有主张 ⇒ 不开;没主张 ⇒ 座缺席 + warn)。
|
|
438
|
+
* 残余(引擎 `NodeExecutionEnv.homeDir` 注同一句):POSIX 上 `HOME` 缺席时 shell 里的 `$HOME` 字面量展开为空,与 `~` 不是一个值 —— 本读数按 `~` 记。
|
|
439
|
+
*/
|
|
440
|
+
private childHome;
|
|
444
441
|
private fileError;
|
|
445
442
|
}
|
|
446
443
|
/**
|