@sema-agent/server 7.49.0 → 7.51.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/USAGE.md +39 -0
- package/dist/boot/device-lane.d.ts +79 -0
- package/dist/boot/device-lane.js +63 -0
- package/dist/boot/engine-lease.d.ts +95 -0
- package/dist/boot/engine-lease.js +56 -0
- package/dist/boot/execution-env.d.ts +48 -2
- package/dist/boot/execution-env.js +57 -5
- package/dist/boot/resolve-spec.d.ts +3 -0
- package/dist/boot/resolve-spec.js +12 -9
- package/dist/boot/session-faces.d.ts +5 -0
- package/dist/boot/session-faces.js +4 -1
- package/dist/boot/shutdown.d.ts +10 -0
- package/dist/boot/shutdown.js +19 -1
- package/dist/boot/stores.js +9 -0
- package/dist/config-center/types.d.ts +10 -3
- package/dist/config-invariants.d.ts +2 -2
- package/dist/config-invariants.js +18 -0
- package/dist/config-types.d.ts +32 -1
- package/dist/config.js +69 -10
- package/dist/device-enrollment.d.ts +125 -0
- package/dist/device-enrollment.js +156 -0
- package/dist/device-store.d.ts +385 -0
- package/dist/device-store.js +407 -0
- package/dist/device-ws-hub.d.ts +182 -0
- package/dist/device-ws-hub.js +1012 -0
- package/dist/device-ws-protocol.d.ts +429 -0
- package/dist/device-ws-protocol.js +464 -0
- package/dist/env-facts.d.ts +4 -1
- package/dist/env-facts.js +1 -0
- package/dist/execution-lane-caps.d.ts +152 -0
- package/dist/execution-lane-caps.js +166 -0
- package/dist/fleet/subagent-tail-bus.d.ts +1 -1
- package/dist/fleet/subagent-tail-bus.js +10 -0
- package/dist/http/routes/approvals-assistant.js +1 -1
- package/dist/http/routes/capabilities.js +7 -2
- package/dist/http/routes/sessions.js +1 -1
- package/dist/http/routes/tasks.js +12 -6
- package/dist/http/send.d.ts +14 -0
- package/dist/http/send.js +5 -0
- package/dist/http/server.d.ts +19 -0
- package/dist/http/server.js +21 -2
- package/dist/http/wire-types.d.ts +1 -1
- package/dist/leader/wire.js +4 -2
- package/dist/main.js +10 -3
- package/dist/orchestration/hardened-vm-runner.d.ts +7 -0
- package/dist/orchestration/hardened-vm-runner.js +11 -1
- package/dist/orchestration/hardened-vm-worker-runner.js +2 -2
- package/dist/plugins/device-store-sql.d.ts +130 -0
- package/dist/plugins/device-store-sql.js +574 -0
- package/dist/plugins/remote-env-device.d.ts +271 -0
- package/dist/plugins/remote-env-device.js +727 -0
- package/dist/plugins/remote-scratchpad.js +1 -1
- package/dist/plugins/store-backend.d.ts +9 -0
- package/dist/plugins/store-backend.js +3 -0
- package/dist/plugins/usage-window-store-sql.d.ts +2 -2
- package/dist/plugins/usage-window-store-sql.js +17 -6
- package/dist/task-cwd.d.ts +25 -0
- package/dist/task-cwd.js +3 -0
- package/dist/task-settings.js +3 -1
- package/dist/trace/core-keyset-guard.d.ts +3 -3
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { ExecutionError, FileError, RemoteExecutionError, type ExecutionEnv, type ExecutionEnvFactory, type ExecStreamOptions, type FileInfo, type OutputChunk, type RemoteConnectConfig, type RemoteExecutionEnv, type Result, type SessionToken, type SnapshotId, type VmLifecycleOptions, type WorkspaceHandle, type WriteExpectation, type WriteReceipt } from "@sema-agent/core";
|
|
2
|
+
import { DEVICE_RATE_LIMIT_CODE, type DeviceErrorCode, type DeviceOwner, type DeviceRow, type DeviceStore } from "../device-store.js";
|
|
3
|
+
import type { DeviceEnrollment } from "../device-enrollment.js";
|
|
4
|
+
import type { DeviceWsHub } from "../device-ws-hub.js";
|
|
5
|
+
import type { DeviceInstructionKind, DeviceOutcomeErrorCode } from "../device-ws-protocol.js";
|
|
6
|
+
/** `WorkspaceHandle.provider` 与 `REMOTE_EXEC` 词表的那一个词,单点。 */
|
|
7
|
+
export declare const DEVICE_PROVIDER: "device";
|
|
8
|
+
/** core 没从包根导出 `ExecutionEnvExecOptions` —— 从接口上取,与六条兄弟腿逐字同姿势
|
|
9
|
+
* (`remote-env-host.ts` 的 `type ExecOpts = Parameters<ExecutionEnv["exec"]>[1]`)。 */
|
|
10
|
+
type ExecOpts = Parameters<ExecutionEnv["exec"]>[1];
|
|
11
|
+
/**
|
|
12
|
+
* 设备**结局帧**的错误码 → core `FileErrorCode`。
|
|
13
|
+
*
|
|
14
|
+
* `Record<DeviceOutcomeErrorCode, …>` 是**穷举**的:协议的结局码闭集加词而此处不加行 = 编译红
|
|
15
|
+
* (#157 词表纪律;不是运行时 switch 的默认臂)。
|
|
16
|
+
*
|
|
17
|
+
* 🔴 三条不许折错的线:
|
|
18
|
+
* ① `outcome_unknown` **原样过境**——core 把它排除在 `RETRYABLE_REMOTE_ERROR_CODES` 之外正是为了
|
|
19
|
+
* 「可能已经执行过」这一格;折成 `timeout`/`transport_lost` 会让上层按可重试处理,重驱已提交副作用。
|
|
20
|
+
* ② `target_unavailable`(never-started 的诚实词)在 `FileErrorCode` 上**没有对位词** —— 落
|
|
21
|
+
* `transport_lost`:它的契约是「连接故事已知、重连后可重试」,而 never-started 的重试确实是安全的。
|
|
22
|
+
* 诚实残余:file 面因此**分不出**「从未开始」与「传输中断」,两者都落在同一个可重试桶里(方向对、
|
|
23
|
+
* 粒度粗)。要分得开需要 core 在 `FileErrorCode` 上补 never-started 词 —— 已作 O12 的后续请托登记。
|
|
24
|
+
* ③ exec 专属词(`shell_unavailable`/`spawn_error`/`callback_error`/`suspended`/`auth_failed`)出现在
|
|
25
|
+
* file 面上是**设备端协议违约**(它把一个 exec 结局贴到一次文件操作上)⇒ 落 `unknown`,不猜。
|
|
26
|
+
*/
|
|
27
|
+
export declare const DEVICE_OUTCOME_TO_FILE_ERROR: Readonly<Record<DeviceOutcomeErrorCode, FileError["code"]>>;
|
|
28
|
+
/**
|
|
29
|
+
* 设备**结局帧**的错误码 → core `ExecutionErrorCode`。穷举同上。
|
|
30
|
+
*
|
|
31
|
+
* 🔴 file 专属词(`already_exists`/`is_directory`/`not_directory`/`not_found`/`permission_denied`/
|
|
32
|
+
* `precondition_failed`/`invalid`)出现在 exec 面同样是协议违约 ⇒ `unknown`,不猜。
|
|
33
|
+
* `not_supported` 在 `ExecutionErrorCode` 上无对位词 —— 落 `shell_unavailable`(它的契约就是「命令
|
|
34
|
+
* **从未启动**,因为可执行面解析不了」,与「设备没有这条指令面」同侧;never-started 语义保住)。
|
|
35
|
+
*/
|
|
36
|
+
export declare const DEVICE_OUTCOME_TO_EXEC_ERROR: Readonly<Record<DeviceOutcomeErrorCode, ExecutionError["code"]>>;
|
|
37
|
+
type RejectCode = DeviceErrorCode | typeof DEVICE_RATE_LIMIT_CODE;
|
|
38
|
+
/**
|
|
39
|
+
* 汇聚端的 **typed 拒**(投递门**之前**,§5.3 投递边界:设备从未可能见过这条指令)→ core 错误码。
|
|
40
|
+
*
|
|
41
|
+
* 🔴 全部落在**可安全重试**的那一侧,这是投递边界给的硬事实,不是乐观估计。exec 面用 O12 的
|
|
42
|
+
* `target_unavailable`(「目标在 commit 前拒了,命令从未启动」的诚实词);file 面无对位词,同上落
|
|
43
|
+
* `transport_lost`。
|
|
44
|
+
* 例外 `identity_mismatch` / `revoked` / `not_found`:那是**永久**拒(换设备/吊销/不是你的),重试
|
|
45
|
+
* 只会同样失败 —— exec 面落 `auth_failed`(NEVER retry 的那一格),file 面无对位词落 `permission_denied`
|
|
46
|
+
* (「这条路你走不通,而且不是暂时的」是它最近的语义)。
|
|
47
|
+
*/
|
|
48
|
+
export declare const DEVICE_REJECT_TO_EXEC_ERROR: Readonly<Record<RejectCode, ExecutionError["code"]>>;
|
|
49
|
+
export declare const DEVICE_REJECT_TO_FILE_ERROR: Readonly<Record<RejectCode, FileError["code"]>>;
|
|
50
|
+
export interface DeviceEnvLogger {
|
|
51
|
+
warn(msg: string, fields?: Record<string, unknown>): void;
|
|
52
|
+
info?(msg: string, fields?: Record<string, unknown>): void;
|
|
53
|
+
}
|
|
54
|
+
export interface DeviceEnvFactoryDeps {
|
|
55
|
+
hub: DeviceWsHub;
|
|
56
|
+
store: DeviceStore;
|
|
57
|
+
enrollment: DeviceEnrollment;
|
|
58
|
+
/** 指令级默认超时(ms;`DEVICE_EXEC_TIMEOUT_MS`,§4.7)。core 的 per-command `timeout` 可收紧它。 */
|
|
59
|
+
execTimeoutMs?: number;
|
|
60
|
+
/** §4.3.3 蜂道:`deviceCwdHonored` 闸下由 resolve-spec 注册的 per-session cwd(**单写者**)。 */
|
|
61
|
+
perSessionCwd?: ReadonlyMap<string, string>;
|
|
62
|
+
perSessionShellEnv?: ReadonlyMap<string, Record<string, string>>;
|
|
63
|
+
logger?: DeviceEnvLogger;
|
|
64
|
+
}
|
|
65
|
+
interface DeviceEnvConfig {
|
|
66
|
+
hub: DeviceWsHub;
|
|
67
|
+
enrollment: DeviceEnrollment;
|
|
68
|
+
rootSessionId: string;
|
|
69
|
+
deviceId: string;
|
|
70
|
+
owner: DeviceOwner;
|
|
71
|
+
cwd: string;
|
|
72
|
+
shellEnv?: Record<string, string>;
|
|
73
|
+
execTimeoutMs: number;
|
|
74
|
+
/** 设备当前连接声明的指令面(`undefined` = 铸 env 时设备不在线 ⇒ 可选面一律缺席)。 */
|
|
75
|
+
supports: ReadonlySet<DeviceInstructionKind> | undefined;
|
|
76
|
+
logger?: DeviceEnvLogger;
|
|
77
|
+
}
|
|
78
|
+
export declare class RemoteDeviceExecutionEnv implements RemoteExecutionEnv {
|
|
79
|
+
private readonly cfg;
|
|
80
|
+
/**
|
|
81
|
+
* 🔴 `suspendable: false` 在 core 契约里**同时断言**「工作区在目标上外部持久」(remote-env.ts 的
|
|
82
|
+
* load-bearing 不变量)—— 设备工作区 = 员工机磁盘,真持久 ✅,park-only 降级腿因此合法可用。
|
|
83
|
+
* 谁要把 executor 的工作区改成临时目录,先来改这一行:那一刻这个 `false` 就变成谎话,park 赎回会
|
|
84
|
+
* 落到一个空工作区上而链路上没有任何一层会报错。
|
|
85
|
+
*/
|
|
86
|
+
readonly capabilities: {
|
|
87
|
+
isolation: boolean;
|
|
88
|
+
suspendable: boolean;
|
|
89
|
+
};
|
|
90
|
+
readonly externalContentTarget = true;
|
|
91
|
+
/** #211:设备路径不在 worker 宿主文件系统上 —— host-path 回执消费方据此拒绝把它当宿主路径呈现。 */
|
|
92
|
+
readonly hostLocalPaths = false;
|
|
93
|
+
cwd: string;
|
|
94
|
+
/** 可选面(presence-typed,见文件头「铁律」段):构造期按设备声明装配,缺席就是缺席。 */
|
|
95
|
+
readLink?: (path: string, abortSignal?: AbortSignal) => Promise<Result<string, FileError>>;
|
|
96
|
+
writeFileExclusive?: (path: string, content: string | Uint8Array, abortSignal?: AbortSignal) => Promise<Result<void, FileError>>;
|
|
97
|
+
writeFileGuarded?: (path: string, content: string | Uint8Array, expect: WriteExpectation, abortSignal?: AbortSignal) => Promise<Result<WriteReceipt, FileError>>;
|
|
98
|
+
private connected;
|
|
99
|
+
/** 拆除是**终态**(六条兄弟腿同纪律:destroy 之后 connect/exec/读面一律 fail-closed,不复活)。 */
|
|
100
|
+
private destroyed;
|
|
101
|
+
constructor(cfg: DeviceEnvConfig);
|
|
102
|
+
/**
|
|
103
|
+
* 铸造时装配的**保护型**可选面(guarded / exclusive 写)。`connect()` 拿它与设备**此刻**的声明对拍。
|
|
104
|
+
*
|
|
105
|
+
* 🔴 为什么只对拍这两条而不是全部 supports(codex R1-F2 的修法边界):这两条是 core 契约里
|
|
106
|
+
* 「缺席 ⇒ 调用方按 advisory 降级并自担 TOCTOU」的那一类 —— 它们的缺席是**放宽**方向。其余面
|
|
107
|
+
* (exec/read/…)缺席时调用会得到一条响亮的 `not_supported`,不构成静默降级。
|
|
108
|
+
*/
|
|
109
|
+
private guardFaceSnapshot;
|
|
110
|
+
/**
|
|
111
|
+
* 设备**此刻**多出来的保护面(相对本 env 铸造时的快照)。非空 = 漂移。
|
|
112
|
+
*
|
|
113
|
+
* 🔴 **为什么这条判据不能只守 `connect()`**(codex R2-F3,判真):`connect()` 一辈子只跑一两次,而
|
|
114
|
+
* 设备的 WS 可以**透明重连** —— 断开、以同一 deviceId 连回来,`this.connected` 全程不变,后续
|
|
115
|
+
* `dispatch` 直接用汇聚端的**当前**连接。于是「弱能力连接上铸的 env + 设备连回时带上了 guarded 面」
|
|
116
|
+
* 这一形绕过了 connect 期的闸:core 仍看不到 guarded 方法、仍走非原子写降级,而没有任何一层再问一次。
|
|
117
|
+
* 所以判据要落在**每一次非原子写之前**(那正是被降级的那条路),connect 期的检查是它的早期快门。
|
|
118
|
+
*/
|
|
119
|
+
private guardFaceDrift;
|
|
120
|
+
/**
|
|
121
|
+
* 铸造时**缺席**的保护面 —— 交给 hub 在投递门上原子复核(codex R3-F1)。
|
|
122
|
+
*
|
|
123
|
+
* adapter 侧的 {@link guardFaceDrift} 是**早期快门**:它与真正的下发之间隔着 `admitSession` 的一次
|
|
124
|
+
* SQL 往返,设备可以在那个窗口里以更强的能力连回来。投递门是本进程里唯一同时持有「最终选中的连接」
|
|
125
|
+
* 与「不可回退的 commit」的地方,所以权威判据在那儿;这里只负责把「我是在没有它们的前提下铸的」这句
|
|
126
|
+
* 话原样送过去。
|
|
127
|
+
*/
|
|
128
|
+
private absentGuardFaces;
|
|
129
|
+
private driftError;
|
|
130
|
+
private resolve;
|
|
131
|
+
absolutePath(p: string): Promise<Result<string, FileError>>;
|
|
132
|
+
joinPath(parts: string[]): Promise<Result<string, FileError>>;
|
|
133
|
+
workspaceHandle(): WorkspaceHandle;
|
|
134
|
+
/**
|
|
135
|
+
* 不建连接:做**准入 + 取活连接**(文件头「唯一范式差」)。
|
|
136
|
+
*
|
|
137
|
+
* 🔴 **绝不换设备**:准入解出的 deviceId 与本 env 铸造时钉住的那一台不符 ⇒ typed
|
|
138
|
+
* `device.identity_mismatch`(lane 是身份不是偏好,§4.5 步 2)。这一格正是 park 赎回期换绑/吊销的
|
|
139
|
+
* 落点:静默改投等于把一次会话的全部工作区假设搬到另一台机器上。
|
|
140
|
+
*/
|
|
141
|
+
connect(config?: RemoteConnectConfig): Promise<{
|
|
142
|
+
ok: true;
|
|
143
|
+
value: WorkspaceHandle;
|
|
144
|
+
} | {
|
|
145
|
+
ok: false;
|
|
146
|
+
error: RemoteExecutionError;
|
|
147
|
+
}>;
|
|
148
|
+
/** 控制面重连(core 在 transport 重挂时调)——语义与 connect 逐字同一条:重新准入 + 身份等值。 */
|
|
149
|
+
reconnect(_sessionToken: SessionToken): Promise<{
|
|
150
|
+
ok: true;
|
|
151
|
+
value: WorkspaceHandle;
|
|
152
|
+
} | {
|
|
153
|
+
ok: false;
|
|
154
|
+
error: RemoteExecutionError;
|
|
155
|
+
}>;
|
|
156
|
+
suspendVM(_options?: VmLifecycleOptions): Promise<{
|
|
157
|
+
ok: true;
|
|
158
|
+
value: SnapshotId;
|
|
159
|
+
} | {
|
|
160
|
+
ok: false;
|
|
161
|
+
error: RemoteExecutionError;
|
|
162
|
+
}>;
|
|
163
|
+
resumeVM(_snapshotId: SnapshotId, _options?: VmLifecycleOptions): Promise<{
|
|
164
|
+
ok: true;
|
|
165
|
+
value: WorkspaceHandle;
|
|
166
|
+
} | {
|
|
167
|
+
ok: false;
|
|
168
|
+
error: RemoteExecutionError;
|
|
169
|
+
}>;
|
|
170
|
+
postResumeInit(): Promise<{
|
|
171
|
+
ok: true;
|
|
172
|
+
value: void;
|
|
173
|
+
} | {
|
|
174
|
+
ok: false;
|
|
175
|
+
error: RemoteExecutionError;
|
|
176
|
+
}>;
|
|
177
|
+
private unsupported;
|
|
178
|
+
/**
|
|
179
|
+
* 解除本 env 与设备的关联。**不动设备上的工作区文件**(与 adb 腿「destroy 只断开不重置手机」同纪律
|
|
180
|
+
* —— 那是员工自己的盘,§11-O6 才是「要不要清理」这个问题的属主)。幂等,永不抛。
|
|
181
|
+
*/
|
|
182
|
+
destroy(): Promise<void>;
|
|
183
|
+
cleanup(): Promise<void>;
|
|
184
|
+
/** 终态/未连接的 fail-closed 门(exec 面)。 */
|
|
185
|
+
private shellGate;
|
|
186
|
+
/** 终态/未连接的 fail-closed 门(文件面)。 */
|
|
187
|
+
private fsGate;
|
|
188
|
+
private timeoutMsFor;
|
|
189
|
+
private dispatch;
|
|
190
|
+
/**
|
|
191
|
+
* 三态结果 → 文件面的 `Result`。
|
|
192
|
+
*
|
|
193
|
+
* **穷举 switch,无 default 臂**:`DeviceDispatchResult` 加臂而此处不加 = 编译红。三态各自的
|
|
194
|
+
* 「重试安全性」在 hub 的类型注里逐字定义,本函数只做翻译,不重新判断。
|
|
195
|
+
*/
|
|
196
|
+
private fileOutcome;
|
|
197
|
+
/** 结局 kind 与请求面不符 = 设备协议违约:响亮拒,**不猜**(否则一个没发生的操作会被读成成功)。 */
|
|
198
|
+
private wrongOutcome;
|
|
199
|
+
exec(command: string, options?: ExecOpts): Promise<Result<{
|
|
200
|
+
stdout: string;
|
|
201
|
+
stderr: string;
|
|
202
|
+
exitCode: number;
|
|
203
|
+
}, ExecutionError>>;
|
|
204
|
+
/**
|
|
205
|
+
* 流式 exec。契约:按序 yield `stdout`/`stderr`,末尾**恰好一个** `exit` 片;失败在 exit 之前 throw
|
|
206
|
+
* `RemoteExecutionError`(core `OutputChunk` 契约)。
|
|
207
|
+
*
|
|
208
|
+
* 🔴 「恰好一个 exit」不是本层的信任,是**汇聚端已判过**的事实(hub 的 `expectsStreamTerminator`
|
|
209
|
+
* 对声明了流的调用强制唯一终止片,缺了就把整条指令判失败而不是静默尾截断)。本层只负责不把它弄丢。
|
|
210
|
+
*/
|
|
211
|
+
execStream(command: string, options?: ExecStreamOptions): AsyncIterable<OutputChunk>;
|
|
212
|
+
exists(p: string, abortSignal?: AbortSignal): Promise<Result<boolean, FileError>>;
|
|
213
|
+
canonicalPath(p: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
|
|
214
|
+
fileInfo(p: string, abortSignal?: AbortSignal): Promise<Result<FileInfo, FileError>>;
|
|
215
|
+
private doReadLink;
|
|
216
|
+
readBinaryFile(p: string, abortSignal?: AbortSignal): Promise<Result<Uint8Array, FileError>>;
|
|
217
|
+
readTextFile(p: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
|
|
218
|
+
readTextLines(p: string, options?: {
|
|
219
|
+
maxLines?: number;
|
|
220
|
+
abortSignal?: AbortSignal;
|
|
221
|
+
}): Promise<Result<string[], FileError>>;
|
|
222
|
+
listDir(p: string, abortSignal?: AbortSignal): Promise<Result<FileInfo[], FileError>>;
|
|
223
|
+
writeFile(p: string, content: string | Uint8Array, abortSignal?: AbortSignal): Promise<Result<void, FileError>>;
|
|
224
|
+
appendFile(p: string, content: string | Uint8Array, abortSignal?: AbortSignal): Promise<Result<void, FileError>>;
|
|
225
|
+
private doWrite;
|
|
226
|
+
/**
|
|
227
|
+
* O13 守卫写:前置条件与写入在设备上的**同一原子步**里发生,回一份落盘对象收据。
|
|
228
|
+
*
|
|
229
|
+
* 🔴 这是 §4.3.1「把裁决绑定到真实落盘对象」的**唯一**承载。它成立的边界要说清:关掉的是「调用方
|
|
230
|
+
* 铸前置条件」与「写入」之间那个窗;更早的策略裁决(例如等过人类审批的写门判决)不在这条收据里 ——
|
|
231
|
+
* core 的方法注对此已逐字声明,本腿不越界宣称。
|
|
232
|
+
*/
|
|
233
|
+
private doGuardedWrite;
|
|
234
|
+
private warnMissingCreated;
|
|
235
|
+
createDir(p: string, options?: {
|
|
236
|
+
recursive?: boolean;
|
|
237
|
+
abortSignal?: AbortSignal;
|
|
238
|
+
}): Promise<Result<void, FileError>>;
|
|
239
|
+
remove(p: string, options?: {
|
|
240
|
+
recursive?: boolean;
|
|
241
|
+
force?: boolean;
|
|
242
|
+
abortSignal?: AbortSignal;
|
|
243
|
+
}): Promise<Result<void, FileError>>;
|
|
244
|
+
createTempDir(prefix?: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
|
|
245
|
+
createTempFile(options?: {
|
|
246
|
+
prefix?: string;
|
|
247
|
+
suffix?: string;
|
|
248
|
+
abortSignal?: AbortSignal;
|
|
249
|
+
}): Promise<Result<string, FileError>>;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* device lane 的 `ExecutionEnvFactory`(`boot/execution-env.ts` 的第七臂)。
|
|
253
|
+
*
|
|
254
|
+
* 🔴 **异步工厂,且在铸 env 之前就把绑定读出来** —— 三个理由,每个都不能省:
|
|
255
|
+
* ① `cwd` 是 `FileSystem` 的**同步属性**:缺省值 = 设备 hello 声明的 `workspaceRoot`,那在库里;
|
|
256
|
+
* ② 可选面的 presence(`writeFileGuarded`…)必须在构造期定(core 降级律,见文件头);
|
|
257
|
+
* ③ 「这个 placement 根本没绑设备」是**装配/准入错误**,不是一次运行期业务拒绝 —— 响亮抛,让 spawn
|
|
258
|
+
* 失败(core 对 `isolation:"worktree"` 的同款姿势:宁可 throw,绝不静默给一个不对的 env)。
|
|
259
|
+
* 对比:「绑了但现在不在线」是运行期事实 ⇒ 构造成功,`connect()` 回 typed `device.offline`。
|
|
260
|
+
*/
|
|
261
|
+
export declare function deviceExecutionEnvFactory(deps: DeviceEnvFactoryDeps): ExecutionEnvFactory;
|
|
262
|
+
/**
|
|
263
|
+
* §4.3.3 的 cwd 优先序 —— 与 host 腿的 `effectiveHostWorkspace` **同源**:
|
|
264
|
+
* ① 本 session 显式注册的 cwd(`deviceCwdHonored` 闸下由 resolve-spec 写);
|
|
265
|
+
* ② `ctx.parentCwd`(委派子代:自己没注册过 cwd,继承父的工作目录 —— 少了它子代会丢工作目录);
|
|
266
|
+
* ③ 设备 hello 声明并落库的 `workspaceRoot`(缺 cwd 时的解析基准,有明确 wire 契约,不是「executor
|
|
267
|
+
* 默认根」这种空话)。
|
|
268
|
+
*/
|
|
269
|
+
export declare function effectiveDeviceCwd(sessionCwd: string | undefined, parentCwd: string | undefined, row: Pick<DeviceRow, "workspaceRoot">): string;
|
|
270
|
+
export {};
|
|
271
|
+
//# sourceMappingURL=remote-env-device.d.ts.map
|