super-dsh 0.3.1 → 0.3.2-e

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.
Files changed (48) hide show
  1. package/client/index.js +135 -14
  2. package/package.json +1 -1
  3. package/remote/helper-bin/MANIFEST.json +35 -0
  4. package/remote/helper-bin/aarch64-apple-darwin/BUILT-VER +1 -0
  5. package/remote/helper-bin/aarch64-apple-darwin/superd-run +0 -0
  6. package/remote/helper-bin/aarch64-unknown-linux-musl/BUILT-VER +1 -0
  7. package/remote/helper-bin/aarch64-unknown-linux-musl/superd-run +0 -0
  8. package/remote/helper-bin/x86_64-pc-windows-gnu/BUILT-VER +1 -0
  9. package/remote/helper-bin/x86_64-pc-windows-gnu/superd-run.exe +0 -0
  10. package/remote/helper-bin/x86_64-unknown-linux-musl/BUILT-VER +1 -0
  11. package/remote/helper-bin/x86_64-unknown-linux-musl/superd-run +0 -0
  12. package/remote/hub-pty-pump.mjs +97 -0
  13. package/remote/plugin.d.ts +523 -199
  14. package/remote/plugin.js +2530 -768
  15. package/remote/provenance.json +36 -21
  16. package/superd-hub/dist/a2a-host.d.ts +11 -3
  17. package/superd-hub/dist/a2a-host.js +7 -7
  18. package/superd-hub/dist/a2a-row.js +7 -1
  19. package/superd-hub/dist/carrier.d.ts +9 -7
  20. package/superd-hub/dist/carrier.js +3 -3
  21. package/superd-hub/dist/client/pill-geometry.d.ts +70 -0
  22. package/superd-hub/dist/client/pill-geometry.js +49 -0
  23. package/superd-hub/dist/client/switch.d.ts +15 -0
  24. package/superd-hub/dist/client/switch.js +54 -1
  25. package/superd-hub/dist/companions.js +8 -6
  26. package/superd-hub/dist/exec.d.ts +3 -2
  27. package/superd-hub/dist/exec.js +6 -5
  28. package/superd-hub/dist/fusion-transport.d.ts +18 -1
  29. package/superd-hub/dist/fusion-transport.js +44 -5
  30. package/superd-hub/dist/gateway.js +8 -1
  31. package/superd-hub/dist/hub-route.d.ts +5 -2
  32. package/superd-hub/dist/hub-route.js +6 -6
  33. package/superd-hub/dist/hub-tool.d.ts +1 -1
  34. package/superd-hub/dist/hub-tool.js +6 -6
  35. package/superd-hub/dist/remote-provider.js +70 -36
  36. package/superd-hub/dist/rpc.d.ts +5 -0
  37. package/superd-hub/dist/rpc.js +20 -1
  38. package/superd-hub/dist/switch-core.d.ts +41 -0
  39. package/superd-hub/dist/switch-core.js +40 -0
  40. package/superd-hub/dist/targets.d.ts +7 -0
  41. package/superd-hub/dist/world-lifecycle.js +1 -1
  42. package/superd-hub/lib/client/index.js +135 -14
  43. package/superd-hub/dist/exec-pty-channel.d.ts +0 -58
  44. package/superd-hub/dist/exec-pty-channel.js +0 -162
  45. package/superd-hub/dist/exec-pty-framing.d.ts +0 -34
  46. package/superd-hub/dist/exec-pty-framing.js +0 -89
  47. package/superd-hub/dist/exec-pty-session.d.ts +0 -78
  48. package/superd-hub/dist/exec-pty-session.js +0 -228
@@ -90,22 +90,403 @@ interface SshConnection {
90
90
  readonly key?: string;
91
91
  readonly proxyJump?: string;
92
92
  }
93
- /** One instance per Agent-owned driver; destroyed with its Agent/plugin owners. */
94
- declare class SshTargets {
95
- private readonly targets;
96
- register(label: string, connection: SshConnection): SshConnection;
97
- get(label: string): SshConnection | undefined;
98
- entries(): ReadonlyArray<readonly [string, SshConnection]>;
99
- clear(): void;
100
- }
101
93
  /** Shared by execution, probes and file/relay consumers. extraArgs is trusted
102
- * internal SSH argv (e.g. forwarding), never a model-provided shell string. */
94
+ * internal SSH argv (e.g. forwarding), never a model-provided shell string.
95
+ * Identity assembly lives in ssh-argv.ts (the ONE policy — 2026-10-17 ruling);
96
+ * this wrapper only picks the tty/batch dialect base. */
103
97
  declare function sshArgv(connection: SshConnection, options?: {
104
98
  tty?: boolean;
105
99
  extraArgs?: readonly string[];
106
100
  command?: string;
107
101
  }): string[];
108
102
  //#endregion
103
+ //#region src/remote/hub-contract.d.ts
104
+ /** Owned structural boundary. Better never imports or depends on Super. */
105
+ interface RemoteInput {
106
+ target?: string;
107
+ spawn?: string;
108
+ ssh?: SshConnection;
109
+ cmd?: string;
110
+ scriptPath?: string;
111
+ stdin?: string;
112
+ mode?: 'oneshot' | 'pty';
113
+ timeout?: number;
114
+ }
115
+ interface PreparedRemoteInput {
116
+ target?: string;
117
+ spawn?: string;
118
+ ssh?: SshConnection;
119
+ cmd: string;
120
+ stdin?: string;
121
+ mode?: 'oneshot' | 'pty';
122
+ timeout?: number;
123
+ }
124
+ /** Counters exclude diagnostic banners. dropped is ring eviction; total-returned is all omitted output. */
125
+ type OutputStats = {
126
+ unit: 'utf16' | 'bytes';
127
+ total: number;
128
+ retained: number;
129
+ dropped: number;
130
+ returned: number;
131
+ retentionLimit: number;
132
+ };
133
+ type StreamOutputStats = {
134
+ stdout: OutputStats;
135
+ stderr?: OutputStats;
136
+ };
137
+ interface RemoteProcess {
138
+ cancel(reason?: string): void;
139
+ done: Promise<{
140
+ exit: number | null;
141
+ timedOut: boolean;
142
+ durationMs: number;
143
+ cancelled?: boolean;
144
+ }>;
145
+ /** diagnostic is executor-generated text, not process output; excluded from byte cursor and counters. */
146
+ read(channel: 'stdout' | 'stderr', fromByte: number): {
147
+ text: string;
148
+ nextOffset: number;
149
+ lossy: boolean;
150
+ stats?: OutputStats;
151
+ diagnostic?: string;
152
+ };
153
+ }
154
+ interface BinaryFileEndpoint {
155
+ exportTree(path: string, signal: AbortSignal): Promise<NodeJS.ReadableStream>;
156
+ importTree(path: string, source: NodeJS.ReadableStream, options: {
157
+ mkdir: boolean;
158
+ signal: AbortSignal;
159
+ }): Promise<void>;
160
+ digest(path: string, signal: AbortSignal, selection?: readonly string[]): Promise<{
161
+ sha256: string;
162
+ bytes: number;
163
+ entries: number;
164
+ }>;
165
+ }
166
+ interface HubTarget {
167
+ id: string;
168
+ label: string;
169
+ execEnabled: boolean;
170
+ }
171
+ interface HubRemoteTransport {
172
+ protocol: 1;
173
+ listTargets(): readonly HubTarget[];
174
+ start(machine: string, input: PreparedRemoteInput, owner: string): Promise<RemoteProcess>;
175
+ /** Hub PTY 端点(0.3.2-c):url = ws(s)://<origin>/api/superd/exec/pty;cookie = pairing 凭据;
176
+ * wsPath = transport 侧(superd-hub 上下文,分叉的 proven 解析链)解析好的 ws 模块绝对路径。 */
177
+ ptyEndpoint(machine: string): {
178
+ url: string;
179
+ cookie: string;
180
+ wsPath: string;
181
+ };
182
+ fileEndpoint(machine: string): BinaryFileEndpoint;
183
+ releaseOwner(owner: string): Promise<void>;
184
+ }
185
+ //#endregion
186
+ //#region src/remote/output-ring.d.ts
187
+ /** Byte-addressed decoded output: mid-codepoint cursors skip forward and explicitly report loss. */
188
+ declare function readUtf8Tail(bytes: Buffer, totalBytes: number, fromByte: number): {
189
+ text: string;
190
+ nextOffset: number;
191
+ lossy: boolean;
192
+ };
193
+ /** Native/PTY retention is UTF16 units; cursor offsets remain real UTF8 bytes. Input is decoded text. */
194
+ declare class Utf16TailRing {
195
+ readonly capacity: number;
196
+ text: string;
197
+ total: number;
198
+ private totalBytes;
199
+ constructor(capacity?: number);
200
+ push(text: string): void;
201
+ stats(returned?: number): OutputStats;
202
+ read(fromByte: number): ReturnType<typeof readUtf8Tail>;
203
+ }
204
+ /** Raw byte retention for Hub oneshot. Tail/read starts skip partial UTF8 prefixes, never invent replacement characters. */
205
+ declare class ByteTailRing {
206
+ readonly capacity: number;
207
+ total: number;
208
+ private chunks;
209
+ private retained;
210
+ constructor(capacity?: number);
211
+ push(chunk: Buffer): void;
212
+ tail(maxBytes?: number): Buffer;
213
+ stats(returned?: number): OutputStats;
214
+ read(fromByte: number): ReturnType<typeof readUtf8Tail>;
215
+ }
216
+ //#endregion
217
+ //#region src/remote/process.d.ts
218
+ declare const PROCESS_CLEANUP_BOUND_MS: number;
219
+ interface ProcessOptions {
220
+ stdin?: string;
221
+ timeoutSec?: number;
222
+ cwd?: string;
223
+ /** Hub retains raw bytes; native transports retain decoded UTF16 units. */
224
+ unit?: 'bytes' | 'utf16';
225
+ onOutput?: () => void;
226
+ /** Overlay on process.env (tool-built values only, e.g. RSYNC_RSH). */
227
+ env?: NodeJS.ProcessEnv;
228
+ }
229
+ /** Real detached process. Completion includes group cleanup, even after its leader closes. */
230
+ declare function startBinaryProcess(argv: string[], options?: Pick<ProcessOptions, 'cwd' | 'timeoutSec' | 'env'>): {
231
+ stdout: Readable;
232
+ stderr: Readable;
233
+ stdin: Writable;
234
+ cancel(): void;
235
+ done: RemoteProcess['done'];
236
+ diagnostic(): string | undefined;
237
+ };
238
+ /** Text adapter over the same owned process-group lifecycle as binary pipelines. */
239
+ declare function startOneShot(argv: string[], options?: ProcessOptions): RemoteProcess;
240
+ //#endregion
241
+ //#region src/remote/nonce-framing.d.ts
242
+ /** 0.3.2-e:自有 30K 返回窗口已删(原生 agent runtime 的 spill/输出保护接管模型上下文
243
+ * 尺寸)。本 helper 只做 retention 披露:ring 留存(4M UTF-16 / 4MiB bytes)未驱逐时
244
+ * 全量透传(returned=retained,无 banner);驱逐(dropped>0,仅 >4M 输出发生)时打一行
245
+ * banner 且 truncated=原始总量。text 已是 ring 尾部,不再二次裁剪。 */
246
+ declare function disclose(text: string, stats?: OutputStats): {
247
+ text: string;
248
+ truncated?: number;
249
+ stats?: OutputStats;
250
+ };
251
+ interface EnvDelta {
252
+ added: string[];
253
+ changed: string[];
254
+ removed: string[];
255
+ }
256
+ //#endregion
257
+ //#region src/remote/pty-session.d.ts
258
+ interface PtySessionOptions {
259
+ key: string;
260
+ argv: string[];
261
+ /** Workbench 身份(§3):自动 id(p-xxxx)+ 可选 label + connection 展示名(ssh:dev4 / docker:c / BYOP)。 */
262
+ id: string;
263
+ label?: string;
264
+ connection: string;
265
+ byo?: boolean;
266
+ /** connection 来自 BYO ssh 身份(card 面标 `(built on)`,与 roster 同词)。 */
267
+ builtOn?: boolean;
268
+ /** spawn 原文(BYO 会话存档;v2 无 spec 对比——不再参与复用判定,仅供回执/账本溯源)。 */
269
+ origin?: string;
270
+ idleTtlSec: number;
271
+ initTimeoutSec?: number;
272
+ /** 池回调:会话彻底出池(dispose)时触发;进程意外死亡不出池(Ruling 7)。 */
273
+ onDead?: () => void;
274
+ }
275
+ interface PtyDispatchOptions {
276
+ stdin?: string;
277
+ timeoutSec?: number; /** 账本键:driver 分配(background 通道预传入 registry jobId;同步命令同格式本地生成)——一个命令永远只有一个 id。 */
278
+ commandId: string; /** P5:立即回执 running job,不等帧(run_in_background 与超时 handoff 共用同一条 job 通道)。 */
279
+ background?: boolean; /** background 通道预传入的 registry jobId(此时与 commandId 字面相等):账本与 input 回执如实携带,免 driver 侧二次回填。 */
280
+ jobId?: string;
281
+ }
282
+ /** §3.3(2026-10-25)interactive-stdin:input 动作的选项与回执(写入成功才回执)。 */
283
+ interface PtyInputOptions {
284
+ stdin: string;
285
+ commandId?: string;
286
+ }
287
+ interface PtyInputReceipt {
288
+ /** 模型面会话名(pty:<id>)。 */
289
+ session: string;
290
+ commandId: string;
291
+ /** 存在官方 job 时才有(background 预传 / timeout handoff 收养回填)。 */
292
+ jobId?: string;
293
+ /** 实际写入的 UTF-8 字节数。 */
294
+ writtenBytes: number;
295
+ }
296
+ /** detached job 的完成结果(frame 或会话死亡时结算;与 dispatch 回执同构)。 */
297
+ interface PtyJobResult {
298
+ output: string;
299
+ outputStats?: StreamOutputStats;
300
+ exit: number | null;
301
+ cwd: string | null;
302
+ timedOut: boolean;
303
+ commandId: string;
304
+ envDelta?: EnvDelta;
305
+ }
306
+ /** P4/P5(2026-10-19)running job 句柄:byte-cursor 增量读 + P8 显式中断 + 完成时帧结算。 */
307
+ interface PtyRunningJob {
308
+ /** 账本键:与 jobId 同构(background 通道预传入 registry id;同步完成命令用同格式生成 id)。 */
309
+ commandId: string;
310
+ /** Byte-cursor incremental read over the command's merged output (tail-ring retention; lossy reports eviction). */
311
+ read: (fromByte: number) => {
312
+ text: string;
313
+ nextOffset: number;
314
+ lossy: boolean;
315
+ };
316
+ stats: () => OutputStats;
317
+ /** P8 两段式 ^C 中断(会话存活;trap-INT 走宽限 group-kill 兜底)。 */
318
+ interrupt: () => void;
319
+ /** Settles on the exit frame, or with exit null when the session dies. */
320
+ done: Promise<PtyJobResult>;
321
+ }
322
+ interface PtyDispatchResult {
323
+ output: string;
324
+ outputStats?: StreamOutputStats;
325
+ exit: number | null;
326
+ cwd: string | null;
327
+ timedOut: boolean;
328
+ reconnected: boolean;
329
+ durationMs: number;
330
+ commandId: string;
331
+ /** env delta(E 帧侧信道):只回名字 + 变动标记,值不回传;init 侧信道失败时省略。 */
332
+ envDelta?: EnvDelta;
333
+ /** P4/P5:true = 命令仍在前台运行,本回执是 handoff(job 句柄随行)。 */
334
+ running?: boolean;
335
+ job?: PtyRunningJob;
336
+ }
337
+ /** 账本条目(§5):commandId / 摘要 / exit / 耗时;保留最近 20 条(user 定案)。 */
338
+ interface LedgerEntry {
339
+ commandId: string;
340
+ jobId?: string;
341
+ summary: string;
342
+ exit: number | null;
343
+ durationMs: number;
344
+ running: boolean;
345
+ }
346
+ type PtyState = 'cold' | 'starting' | 'ready' | 'dead' | 'disposed';
347
+ /** 会话运行时快照(status 面消费,Ruling 16 词汇源)。 */
348
+ interface SessionSnapshot {
349
+ state: PtyState;
350
+ busy: boolean;
351
+ idleMs: number | null;
352
+ pid: number | null;
353
+ }
354
+ declare class PtySession {
355
+ private readonly opts;
356
+ private proc;
357
+ private state;
358
+ private startPromise;
359
+ private idleTimer;
360
+ private onChunk;
361
+ private deathWaiters;
362
+ private diag;
363
+ private inFlight;
364
+ /** P4/P5:当前占用前台的 detached job(background/超时 handoff)。非 null 时新命令拒绝(Q6)。 */
365
+ private detachedJob;
366
+ /** §3.2(2026-10-25):当前占用会话的命令——dispatch 同步占位,settle/cleanup 释放;input 的唯一写入对象。 */
367
+ private activeCommand;
368
+ /** 账本(§5):本会话最近 20 条命令(FIFO,超出丢最旧)。 */
369
+ private ledger;
370
+ /** env 侧信道基线(init E 帧);undefined = 侧信道不可用(不报假 delta)。 */
371
+ private envBaseline;
372
+ /** idle 起点(ready / settle 时重置);null = 尚无 idle 时钟(cold 或已 dispose)。 */
373
+ private idleSince;
374
+ /** 意外死亡后的回收定时器(R2):ready 过的会话先留池供 reconnect,超时仍无人寻址则出池。 */
375
+ private deathTimer;
376
+ private lastCwdSeen;
377
+ /** 是否曾成功初始化(ready 过)。决定死亡语义:ready 过 → reconnect(留池);从未 ready → 出池(见 start())。 */
378
+ private everReady;
379
+ private disposal;
380
+ private procClose;
381
+ private groupCleanup;
382
+ constructor(opts: PtySessionOptions);
383
+ get sessionState(): PtyState;
384
+ /** 池键(driver 的 ttl/inspect 用)。 */
385
+ get key(): string;
386
+ /** 最近帧 cwd(card 面);从未执行过 = null。 */
387
+ get lastCwd(): string | null;
388
+ /** 占用前台的 detached job 的 commandId(无 = null;close 拒绝与 busy 文案共用)。 */
389
+ get detachedCommandId(): string | null;
390
+ /** job 通道收养后回填 jobId(timeout handoff 时 registry id ≠ commandId,账本如实记录两者);运行中的命令同步携带(input 回执用)。 */
391
+ attachJob(commandId: string, jobId: string): void;
392
+ /** Workbench 身份(§3):id + 可选 label + connection + byo 标记。 */
393
+ get identity(): {
394
+ id: string;
395
+ label?: string;
396
+ connection: string;
397
+ byo: boolean;
398
+ builtOn: boolean;
399
+ };
400
+ /** 账本快照(session card 面,只读)。 */
401
+ ledgerSnapshot(): readonly LedgerEntry[];
402
+ /** spawn 创建原文(仅 BYO 会话;v2 起仅存档,不参与复用判定)。 */
403
+ get origin(): string | undefined;
404
+ /** status 面快照:state + busy(有命令在跑)+ idleMs(上次 settle 至今)+ pid(进程组头,kill 兜底可观测)。 */
405
+ get snapshot(): SessionSnapshot;
406
+ /** 预热创建(创建形无 cmd):真正拨号到 init 帧——「会话已就绪」必须是真的,
407
+ * 而且只有 ready 过才挂 idle 回收(cold 会话没有 timer,会永远占配额)。 */
408
+ warm(): Promise<void>;
409
+ /** 同一会话命令占位制(2026-10-25 interactive-stdin 轮):dispatch 入口**同步**建立
410
+ * 命令占位(activeCommand + inFlight + 账本条目)——上一条命令仍在运行(同步等待 /
411
+ * 等输入 / detached job)时新 cmd 立即 E_SESSION_BUSY;原「纯同步并发排 FIFO」语义
412
+ * 废除(排队会让等输入的命令与补输入动作互相卡死,也给 busy 留下绕行窗口)。
413
+ * P4/P5:超时不杀命令而是 handoff 成 running job;background 立即回执;P8 显式
414
+ * interrupt 保留在 job.interrupt;死亡/冷态先重启(reconnect 语义不变)。 */
415
+ dispatch(cmd: string, dOpts: PtyDispatchOptions): Promise<PtyDispatchResult>;
416
+ /** §3.1(2026-10-25)interactive-stdin:向当前运行中的命令追加 stdin——只写既有通道
417
+ * 与身份,不新建命令、账本条目或输出游标;不重连、不重放(dead/disposed 明确拒绝)。
418
+ * 校验与写入全同步:多次 input 按调用顺序整段写入不交错;写入失败如实抛错(私有
419
+ * write() 的静默忽略不适用于回执语义)。stdin:"" 是零字节写入,不是 EOF。 */
420
+ input(options: PtyInputOptions): Promise<PtyInputReceipt>;
421
+ /** TTL / row teardown:尽力 exit,1s 后杀组,出池。 */
422
+ dispose(): Promise<void>;
423
+ private write;
424
+ private start;
425
+ private doStart;
426
+ private markDead;
427
+ private resetIdleTimer;
428
+ private clearIdleTimer;
429
+ /** 意外死亡后的回收:留池只换取一次 reconnect 机会,不得超过一段 idle TTL(R2 复核 P0)。
430
+ * 否则死会话永久占 label + 永久计入 10 配额,Agent 再也开不出新会话。 */
431
+ private armDeathReaper;
432
+ private clearDeathTimer;
433
+ private killTree;
434
+ /** A direct child's close is not proof that its detached process group is gone. */
435
+ private reapGroup;
436
+ }
437
+ //#endregion
438
+ //#region src/remote/target.d.ts
439
+ /** 解析后的传输计划:三种 CLI 传输之一。 */
440
+ type TargetPlan = {
441
+ kind: 'ssh';
442
+ host: string;
443
+ connection?: SshConnection;
444
+ } | {
445
+ kind: 'docker';
446
+ container: string;
447
+ } | {
448
+ kind: 'incus';
449
+ container: string;
450
+ };
451
+ //#endregion
452
+ //#region src/remote/helper.d.ts
453
+ interface HelperManifest {
454
+ format: 1;
455
+ name: string;
456
+ ver: string;
457
+ protocol: number;
458
+ targets: Record<string, {
459
+ file: string;
460
+ bytes: number;
461
+ sha256: string;
462
+ }>;
463
+ }
464
+ interface HelperAssets {
465
+ dir: string;
466
+ manifest: HelperManifest;
467
+ }
468
+ //#endregion
469
+ //#region src/remote/transports.d.ts
470
+ /** Hub PTY 端点事实(ptyEndpoint 的返回形;结构类型,不引 superd-hub)。wsPath 由 transport
471
+ * 侧解析成绝对路径(superd-hub 上下文 = 分叉验证过的解析链;闭包/泵内绝不做按名解析赌注)。 */
472
+ interface HubPtyEndpoint {
473
+ url: string;
474
+ cookie: string;
475
+ wsPath: string;
476
+ }
477
+ /** Hub PTY(0.3.2-c;0.3.2-d F4 修正):会话子进程 = 本地 `script` PTY 托管的 WS 字节泵
478
+ * (hub-pty-pump.mjs)。与 docker exec 的嵌套 PTY 同形,但泵是哑 node 子进程、不像
479
+ * `ssh -tt` / `docker exec -it` 那样作为前台子进程自己把本地 tty 置 raw——所以本地包装必须
480
+ * `stty raw`:canonical+ISIG 下 0x03 在本地变 SIGINT 杀泵、0x04 变 EOF 结束泵 stdin
481
+ * (F4:input ^C/^D 与 job_kill 会打死整条会话)。raw 只作用于本地半段;对端 script PTY
482
+ * 保持 canonical,^C/^D 在对端产生 SIGINT/EOF 正是我们要的语义(字节原样过线,解释权在
483
+ * 对端)。kill 链 session 组杀 → 泵死 → WS 关 → 对端组杀,双向自然闭合。连接事实走 wrapper
484
+ * 内 env 赋值(cookie 不进 argv、不落 ps)。 */
485
+ declare function buildHubPtyArgv(endpoint: HubPtyEndpoint, assets: {
486
+ pumpPath: string;
487
+ nodePath?: string;
488
+ }): string[];
489
+ //#endregion
109
490
  //#region src/remote/copy.d.ts
110
491
  interface CopyRequest {
111
492
  src: string;
@@ -117,7 +498,12 @@ interface TransferReceipt {
117
498
  action: 'copy';
118
499
  src: string;
119
500
  dst: string;
120
- verified: boolean;
501
+ route: 'hub-staged';
502
+ /** S4: tier actually performed — sha256 digests ran and matched, or explicitly skipped. */
503
+ verification: 'sha256' | 'not-applicable';
504
+ /** S3 unified failure envelope. */
505
+ ok: boolean;
506
+ reason?: 'digest-mismatch' | 'staging-error' | 'aborted';
121
507
  sourceDigest?: string;
122
508
  destinationDigest?: string;
123
509
  bytes: number;
@@ -127,20 +513,6 @@ interface TransferReceipt {
127
513
  error?: string;
128
514
  }
129
515
  //#endregion
130
- //#region src/remote/target.d.ts
131
- /** 解析后的传输计划:三种 CLI 传输之一。 */
132
- type TargetPlan = {
133
- kind: 'ssh';
134
- host: string;
135
- connection?: SshConnection;
136
- } | {
137
- kind: 'docker';
138
- container: string;
139
- } | {
140
- kind: 'incus';
141
- container: string;
142
- };
143
- //#endregion
144
516
  //#region src/remote/native-copy.d.ts
145
517
  interface NativeCopyReceipt {
146
518
  action: 'copy';
@@ -154,8 +526,16 @@ interface NativeCopyReceipt {
154
526
  stdout: string[];
155
527
  stderr: string[];
156
528
  outputTruncated: boolean;
157
- /** Native CLI success only — no independent digest was computed for this path. */
158
- verified: false;
529
+ /** S3/S4 (spec §3.3): verification names the tier actually performed — native routes are exit-code-only (D1=A). */
530
+ verification: 'native-exit-only';
531
+ /** S3 unified failure envelope: all native exits zero. */
532
+ ok: boolean;
533
+ /** Failure class when ok is false. */
534
+ reason?: 'non-zero-exit' | 'aborted';
535
+ /** Human context, e.g. two-segment 'push not started: pull failed' (prose moved out of route, S8). */
536
+ note?: string;
537
+ /** D3 mkdir pre-hop outcome: true = created this call, false = already existed, 'n-a' = skipped or unavailable (detail in note). */
538
+ created?: true | false | 'n-a';
159
539
  /** Tool-owned staging/config release: released on normal/observed exit, unknown when a channel was lost. */
160
540
  cleanup: 'released' | 'unknown' | 'none-required';
161
541
  }
@@ -203,6 +583,10 @@ interface RsyncReceipt extends RunResult {
203
583
  transferredBytes?: number;
204
584
  /** Two-SSH route actually used, when applicable. */
205
585
  route?: 'local-ssh' | 'ssh-ssh-forward' | 'ssh-ssh-stdio';
586
+ /** S3/S4: exit-code-only tier (D1=A) + unified failure envelope. */
587
+ verification: 'native-exit-only';
588
+ ok: boolean;
589
+ reason?: 'non-zero-exit' | 'aborted';
206
590
  }
207
591
  /**
208
592
  * Native rsync with ordered caller options. Local↔SSH runs rsync directly with
@@ -213,30 +597,6 @@ interface RsyncReceipt extends RunResult {
213
597
  */
214
598
  declare function runRsync(request: RsyncRequest, source: RsyncEndpoint, destination: RsyncEndpoint, signal: AbortSignal, options?: RelayRsyncOptions): Promise<RsyncReceipt>;
215
599
  //#endregion
216
- //#region src/remote/process.d.ts
217
- declare const PROCESS_CLEANUP_BOUND_MS: number;
218
- interface ProcessOptions {
219
- stdin?: string;
220
- timeoutSec?: number;
221
- cwd?: string;
222
- /** Hub retains raw bytes; native transports retain decoded UTF16 units. */
223
- unit?: 'bytes' | 'utf16';
224
- onOutput?: () => void;
225
- /** Overlay on process.env (tool-built values only, e.g. RSYNC_RSH). */
226
- env?: NodeJS.ProcessEnv;
227
- }
228
- /** Real detached process. Completion includes group cleanup, even after its leader closes. */
229
- declare function startBinaryProcess(argv: string[], options?: Pick<ProcessOptions, 'cwd' | 'timeoutSec' | 'env'>): {
230
- stdout: Readable;
231
- stderr: Readable;
232
- stdin: Writable;
233
- cancel(): void;
234
- done: RemoteProcess['done'];
235
- diagnostic(): string | undefined;
236
- };
237
- /** Text adapter over the same owned process-group lifecycle as binary pipelines. */
238
- declare function startOneShot(argv: string[], options?: ProcessOptions): RemoteProcess;
239
- //#endregion
240
600
  //#region src/remote/oneshot.d.ts
241
601
  interface OneShotOptions {
242
602
  stdin?: string;
@@ -260,7 +620,6 @@ interface ProbeOptions {
260
620
  //#endregion
261
621
  //#region src/remote/roster.d.ts
262
622
  interface RosterOptions {
263
- byosshLabels?: readonly string[];
264
623
  /** 测试缝:替代 runOneShot 的容器扫描执行器。 */
265
624
  runner?: (argv: string[], opts?: OneShotOptions) => Promise<OneShotResult>;
266
625
  /** 测试缝:替代 ~/.ssh/config 读取。 */
@@ -283,10 +642,25 @@ interface RemoteCallResult {
283
642
  truncated?: number;
284
643
  outputStats?: StreamOutputStats;
285
644
  outputStatsUnavailable?: boolean;
286
- /** `byop:<label>` 调用面:本会话的 label(模型自选、即复用入口)。transport target 会话不带。 */
645
+ /** §5.2 回执字段序:session(+label)→ connection → commandId → state 字段(cwd/envDelta/ttlSec/exit)。 */
287
646
  session?: string;
288
- /** 引导/教学行(同 label 重复给 spawn 时的「可省略 spawn」提示等);无则省略。 */
647
+ label?: string;
648
+ connection?: string;
649
+ /** (byo-pty)/(byo-ssh) 来源标注(创建回执与 roster/card;native 回执省略)。 */
650
+ byoTag?: 'byo-pty' | 'byo-ssh';
651
+ commandId?: string;
652
+ envDelta?: EnvDelta;
653
+ /** 引导/教学行;无则省略。 */
289
654
  notice?: string;
655
+ /** oneshot 监督路径的如实标注:`superd-run <ver> (<triple>)` 或 `posix-shim`(spec remote-rescope §5)。 */
656
+ runner?: string;
657
+ /** P4/P5(2026-10-19):true = pty 命令仍在前台运行(回执 = handoff),ptyJob 随行供 job 通道接管。 */
658
+ running?: boolean;
659
+ ptyJob?: PtyRunningJob;
660
+ /** 本会话 idle TTL 剩余(秒);回执即状态快照(P2/P3:状态留在上下文里)。 */
661
+ ttlSec?: number;
662
+ /** 预热(创建形无 cmd)回执 = true。 */
663
+ created?: boolean;
290
664
  }
291
665
  interface RemoteAuditRecord {
292
666
  target: string;
@@ -303,39 +677,54 @@ interface RemoteDriverOptions {
303
677
  getHub?: () => HubRemoteTransport | undefined;
304
678
  execTimeoutSec?: number;
305
679
  idleTtlSec?: number;
306
- maxOutputChars?: number;
307
680
  onAudit?: (r: RemoteAuditRecord) => void;
308
681
  oneshotArgvFor?: (plan: TargetPlan, cmd: string, options: {
309
682
  cleanupTag?: string;
310
683
  }) => string[];
311
684
  ptyArgvFor?: (plan: TargetPlan) => string[];
312
685
  spawnArgvFor?: (spawnCommand: string) => string[];
686
+ /** 测试/验收缝:hub PTY 泵 argv(默认 buildHubPtyArgv + 宿主树 ws 解析)。 */
687
+ hubPtyArgvFor?: (endpoint: HubPtyEndpoint) => string[];
313
688
  probeRunner?: ProbeOptions['runner'];
314
- /** 测试缝:roster 扫描执行器(bare-name 解析复用)。 */
689
+ /** 测试/验收缝:helper 资产来源(默认 lib 旁挂 helper-bin);显式 null 强制 shim 路径。 */
690
+ helperAssetsFor?: () => HelperAssets | null;
691
+ /** 测试缝:roster 扫描执行器(裸名解析复用)。 */
315
692
  rosterRunner?: RosterOptions['runner'];
316
- /** 测试缝:ssh config 读取(bare-name 解析复用)。 */
693
+ /** 测试缝:ssh config 读取(裸名解析复用)。 */
317
694
  sshConfigReader?: () => Promise<string>;
318
695
  }
319
- /** 双轨调度器(spec §七 Phase 2):参数校验 → 路由 → oneshot 子进程 / pty 会话池。 */
696
+ /** hub PTY 泵资产:pump 与本模块同目录(npm 包与 Super 闭包同构,helper.ts 同款纪律)。
697
+ * ws 模块路径由 transport 侧(superd-hub 上下文,分叉的 proven 解析链)解析后经
698
+ * ptyEndpoint 传入——闭包自身子树无可解析的 ws,按名解析不在闭包里做(0.3.2-c 定稿)。 */
699
+ declare function hubPtyAssets(): {
700
+ pumpPath: string;
701
+ };
702
+ /** 双轨调度器:参数校验 → 目标语法(parseTargetForm)→ 统一 label 池 → oneshot 子进程 / pty 会话池。 */
320
703
  declare class RemoteDriver {
321
704
  private readonly opts;
322
- private readonly sshTargets;
323
705
  private readonly pool;
706
+ private readonly labels;
324
707
  private readonly hubOwner;
325
708
  private readonly hubProviders;
326
709
  private readonly processes;
327
710
  private readonly starting;
328
711
  private readonly fileAbort;
329
712
  private disposed;
713
+ /** undefined = 未尝试;null = 资产缺失(shim-only);registry = 每 target sticky 状态机。 */
714
+ private helpers;
715
+ private readonly runnerOf;
330
716
  private disposal;
717
+ private readonly ptyIdleTtlSec;
331
718
  constructor(opts?: RemoteDriverOptions);
332
719
  call(params: RemoteCallParams, callCtx?: {
333
720
  sessionKey?: string;
721
+ ptyBackground?: boolean;
722
+ commandId?: string;
334
723
  }): Promise<RemoteCallResult>;
335
- /** Native-first copy routing (spec: remote-native-shortcut): CLI peers run
336
- * their native CLI verbatim; only Hub↔local↔local stays on the staged tree
337
- * lane with verify/mkdir. Mixed pairs (Hub↔CLI peer) are refused: Hub has no
338
- * native CLI and the tree lane has no CLI options. */
724
+ /** 参数互斥矩阵(§2):spawn/ssh 是 BYO 入口(参数在场即 BYO),只与对应形态的 target 配对。 */
725
+ private validate;
726
+ private execute;
727
+ /** Native-first copy routing (spec: remote-native-shortcut) — unchanged by the workbench round. */
339
728
  copy(request: CopyRequest & {
340
729
  argv?: unknown;
341
730
  pullArgv?: unknown;
@@ -347,160 +736,96 @@ declare class RemoteDriver {
347
736
  sessionKey?: string;
348
737
  }): Promise<RsyncReceipt>;
349
738
  /** Only called from JobSpec.run: admission precedes local file reads and discovery. */
350
- start(input: RemoteInput, signal: AbortSignal): Promise<RemoteProcess>;
739
+ start(input: RemoteInput, signal: AbortSignal, callCtx?: {
740
+ sessionKey?: string;
741
+ }): Promise<RemoteProcess>;
351
742
  private startPrepared;
352
743
  private nativeProcess;
744
+ /** Helper bootstrap is best-effort and sticky: any failure parks null for this driver
745
+ * lifetime and the shim stays the path. First call to a target pays probe (+ upload). */
746
+ private ensureHelper;
747
+ private helperExec;
353
748
  private own;
354
- /** Ruling 16/17:on-demand 探测 + 会话层,两行如实陈述。 */
355
- /**
356
- * Ruling P20 + PTY 候选表末位:裸名按名匹配——ssh config 字面 host → docker → incus(本地廉价扫描,
357
- * 撞名 ssh 优先),三段全不中再看池内活 PTY label,最后才是默认 ssh(交原生错误)。
358
- * 位置即优先级:现有三段一位不挪。选择器前缀的 target 不经此路径。
359
- */
360
- private resolveBareName;
361
- /** Ruling P19:roster = 注意力入口——本地廉价扫描(ssh config/docker ps/incus list + 池内活会话),零拨号。
362
- * 活的 pty 会话按调用方 agent session 过滤(2026-10-03 裁决):ssh/docker/incus 是**公共静态配置**,
363
- * 而活会话是**操作环境**——复用别的 agent 留下的 shell 等于继承未知状态,且两个 agent 各开一条线
364
- * 的代价可忽略。BYO-PTY 天然是活的,于是自然落进这个 scope,无需另立规则。 */
749
+ /** 现场采集机器面并 merge 进本 session 注册表(ssh → docker → incus → hub,迟到者加前缀)。错误逐段吞掉(roster 另行如实呈现)。 */
750
+ private refreshMachines;
751
+ /** 池寻址:命中即回;miss 现场采集一次再寻址(docker 容器名不经 roster 也可达)。 */
752
+ private resolvePoolEntry;
753
+ private planOf;
754
+ /** ssh:<name> 的池感知解析:BYO 身份 → 其 connection;否则按 config 别名/主机名。 */
755
+ private sshPlanFor;
756
+ /** BYO ssh 注册(v2:无 spec 对比——label 占用即拒;注册成功才认领)。返回实际名(label 或 s-id)。 */
757
+ private registerByoSsh;
758
+ /** PTY 会话创建(native/spawn 同一形状):上限 → label 认领 → 惰性会话(失败由 onDead 释放 label)。 */
759
+ private createSession;
760
+ private ttlMinutes;
761
+ /** connection 由 BYO ssh 身份建立 → card 面标 `(built on)`(与 roster 同词,R2 复核 P2-10)。 */
762
+ private isBuiltOn;
763
+ /** PTY 创建形唯一实现(execute 与 background 预建共用):spawn BYO / ssh BYO / native `<transport>:pty`。 */
764
+ private createPtyLane;
765
+ /** background PTY lane:会话先占位(不拨号)再进官方 jobs registry——首回执必须能寻址;
766
+ * registry 拒绝时把新建的会话拆掉(复用形的会话绝不拆)。返回 undefined = 走普通 oneshot job。 */
767
+ preparePtyLane(params: RemoteCallParams, callCtx?: {
768
+ sessionKey?: string;
769
+ }): Promise<{
770
+ input: RemoteInput;
771
+ session: string;
772
+ connection: string;
773
+ label?: string;
774
+ cleanup: () => void;
775
+ } | undefined>;
776
+ /** `pty:<id|label>` 寻址:先 id 后 label;miss 给重建形式。 */
777
+ private resolvePty;
778
+ /** §6 close:默认撞 detached job 报错(列杀法);force = 杀组+关闭(披露 killed)。幂等 not-found。 */
779
+ closePty(selector: string, sessionKey: string, force?: boolean): {
780
+ session: string;
781
+ connection: string;
782
+ closed: boolean;
783
+ reason?: string;
784
+ killed: string[];
785
+ message?: string;
786
+ };
787
+ /** job 通道收养回填(timeout handoff 时 registry id ≠ commandId,账本记录两者)。 */
788
+ attachPtyJob(commandId: string, jobId: string, sessionKey: string): void;
789
+ /** §3.1(2026-10-25)interactive-stdin:input 动作——向已有 live PTY 的当前运行命令
790
+ * 追加 stdin。只解析池内已存在的会话(pty:<id|label> / 裸 label 命中 pty 项),
791
+ * 不触发发现、拨号、创建或重连;machine target 与创建形(:pty 后缀,含 hub:<m4>:pty)
792
+ * 一律明确拒绝并给出可恢复指引。回执附 connection/label 供工具层渲染。 */
793
+ input(target: string, options: PtyInputOptions, callCtx?: {
794
+ sessionKey?: string;
795
+ }): Promise<PtyInputReceipt & {
796
+ connection: string;
797
+ label?: string;
798
+ }>;
799
+ private dispatchPty;
800
+ /** 预热(创建形无 cmd)回执:§3——无 commandId/envDelta;timeout 忽略。 */
801
+ private warmReceipt;
802
+ /** session card 回执(`pty:<id|label>` 无 cmd):connection/state/cwd + 最近 20 条账本(不带输出尾,§9 Q7)。 */
803
+ private cardReceipt;
804
+ private oneshot;
805
+ private hubOneshot;
806
+ private hubOneshotProcess;
807
+ /** Ruling P19 + §2.5:roster = 注意力入口——本地扫描刷新统一池,零拨号;机器面公共,会话面 caller-scoped。 */
365
808
  roster(callCtx?: {
366
809
  sessionKey?: string;
367
810
  }): Promise<string>;
811
+ /** status probe(target 无 cmd):机器面 = probe + 该 connection 上的会话;pty selector = session card。 */
368
812
  status(target: string, callCtx?: {
369
813
  sessionKey?: string;
370
814
  }): Promise<string>;
371
- /** PTY 状态行:纯池内读取,零拨号(label 从来不是可拨目标)。 */
372
- private ptyStatus;
373
- /** Ruling 13:审计 best-effort——钩子抛错不得影响命令路径(成功被毒化成失败+双重审计)。 */
815
+ /** Ruling 13:审计 best-effort——钩子抛错不得影响命令路径。 */
374
816
  private audit;
375
- /** Registration never dials; response reveals labels only, not credentials. */
376
- registerSsh(target: string, connection: SshConnection): string;
377
- private byosshPlan;
378
- /** Single target resolver for later copy/rsync; BYO identities cannot be
379
- * independently re-resolved through the origin's alias table. */
817
+ /** Single target resolver for later copy/rsync; PTY sessions are not filesystem connections. */
380
818
  resolveConnectionTarget(target: string, callCtx?: {
381
819
  sessionKey?: string;
382
820
  }): Promise<TargetPlan>;
383
- private route;
384
- private execute;
385
- /** BYO-PTY 通道:label 即池键(agent 前缀之外),spawn 只在 label 尚不存在时被接受。
386
- * 三分支 —— 建(无会话)/ 复用(无 spawn,或有 spawn 且与创建来源相同)/ **冲突(有 spawn 且来源不同:不执行任何命令)**。 */
387
- private ptyCall;
821
+ /** P2/P3:回执即状态快照——idle TTL 剩余随每次 pty 回执带回。 */
822
+ private ptyTtl;
388
823
  hasHub(): boolean;
389
824
  private requireHub;
390
825
  private assertOpen;
391
826
  dispose(): Promise<void>;
392
827
  }
393
828
  //#endregion
394
- //#region src/remote/hub-contract.d.ts
395
- interface RemoteInput {
396
- target?: string;
397
- spawn?: string;
398
- ssh?: SshConnection;
399
- cmd?: string;
400
- script?: string;
401
- stdin?: string;
402
- mode?: 'oneshot' | 'pty';
403
- timeout?: number;
404
- }
405
- interface PreparedRemoteInput {
406
- target: string;
407
- spawn?: string;
408
- ssh?: SshConnection;
409
- cmd: string;
410
- stdin?: string;
411
- mode?: 'oneshot' | 'pty';
412
- timeout?: number;
413
- }
414
- /** Counters exclude diagnostic banners. dropped is ring eviction; total-returned is all omitted output. */
415
- type OutputStats = {
416
- unit: 'utf16' | 'bytes';
417
- total: number;
418
- retained: number;
419
- dropped: number;
420
- returned: number;
421
- retentionLimit: number;
422
- };
423
- type StreamOutputStats = {
424
- stdout: OutputStats;
425
- stderr?: OutputStats;
426
- };
427
- interface RemoteProcess {
428
- cancel(reason?: string): void;
429
- done: Promise<{
430
- exit: number | null;
431
- timedOut: boolean;
432
- durationMs: number;
433
- cancelled?: boolean;
434
- }>;
435
- /** diagnostic is executor-generated text, not process output; excluded from byte cursor and counters. */
436
- read(channel: 'stdout' | 'stderr', fromByte: number): {
437
- text: string;
438
- nextOffset: number;
439
- lossy: boolean;
440
- stats?: OutputStats;
441
- diagnostic?: string;
442
- };
443
- }
444
- interface BinaryFileEndpoint {
445
- exportTree(path: string, signal: AbortSignal): Promise<NodeJS.ReadableStream>;
446
- importTree(path: string, source: NodeJS.ReadableStream, options: {
447
- mkdir: boolean;
448
- signal: AbortSignal;
449
- }): Promise<void>;
450
- digest(path: string, signal: AbortSignal, selection?: readonly string[]): Promise<{
451
- sha256: string;
452
- bytes: number;
453
- entries: number;
454
- }>;
455
- }
456
- interface HubTarget {
457
- id: string;
458
- label: string;
459
- execEnabled: boolean;
460
- }
461
- interface HubRemoteTransport {
462
- protocol: 1;
463
- listTargets(): readonly HubTarget[];
464
- start(machine: string, input: PreparedRemoteInput, owner: string): Promise<RemoteProcess>;
465
- pty(machine: string, cmd: string, owner: string, options: {
466
- stdin?: string;
467
- timeout?: number;
468
- }): Promise<RemoteCallResult>;
469
- fileEndpoint(machine: string): BinaryFileEndpoint;
470
- releaseOwner(owner: string): Promise<void>;
471
- }
472
- //#endregion
473
- //#region src/remote/output-ring.d.ts
474
- /** Byte-addressed decoded output: mid-codepoint cursors skip forward and explicitly report loss. */
475
- declare function readUtf8Tail(bytes: Buffer, totalBytes: number, fromByte: number): {
476
- text: string;
477
- nextOffset: number;
478
- lossy: boolean;
479
- };
480
- /** Native/PTY retention is UTF16 units; cursor offsets remain real UTF8 bytes. Input is decoded text. */
481
- declare class Utf16TailRing {
482
- readonly capacity: number;
483
- text: string;
484
- total: number;
485
- private totalBytes;
486
- constructor(capacity?: number);
487
- push(text: string): void;
488
- stats(returned?: number): OutputStats;
489
- read(fromByte: number): ReturnType<typeof readUtf8Tail>;
490
- }
491
- /** Raw byte retention for Hub oneshot. Tail/read starts skip partial UTF8 prefixes, never invent replacement characters. */
492
- declare class ByteTailRing {
493
- readonly capacity: number;
494
- total: number;
495
- private chunks;
496
- private retained;
497
- constructor(capacity?: number);
498
- push(chunk: Buffer): void;
499
- tail(maxBytes?: number): Buffer;
500
- stats(returned?: number): OutputStats;
501
- read(fromByte: number): ReturnType<typeof readUtf8Tail>;
502
- }
503
- //#endregion
504
829
  //#region src/remote/jobs.d.ts
505
830
  declare module '@deepseek-ai/dsh-jobs' {
506
831
  interface JobKindMap {
@@ -539,7 +864,6 @@ declare const inject: string[];
539
864
  interface RemoteRowConfig {
540
865
  execTimeoutSec: number;
541
866
  idleTtlSec: number;
542
- maxOutputChars: number;
543
867
  }
544
868
  type RemoteConfigValidator = ((value?: unknown) => RemoteRowConfig) & StandardSchemaV1<unknown, RemoteRowConfig> & NativeConfigSchema;
545
869
  declare const Config: RemoteConfigValidator;
@@ -552,4 +876,4 @@ declare const _default: {
552
876
  apply: (ctx: Context, config: RemoteRowConfig) => (() => void);
553
877
  };
554
878
  //#endregion
555
- export { type BinaryFileEndpoint, ByteTailRing, Config, FILE_FRAME_BYTES, FILE_MAX_ENTRIES, FILE_MAX_METADATA, type HubRemoteTransport, type HubTarget, type OutputStats, PROCESS_CLEANUP_BOUND_MS, type PreparedRemoteInput, RemoteConfigValidator, type RemoteInput, type RemoteProcess, RemoteRowConfig, type RsyncEndpoint, type RsyncReceipt, type RsyncRequest, type SshConnection, SshTargets, type StreamOutputStats, Utf16TailRing, apply, checkAbsolute, checkSelection, _default as default, inject, localFileEndpoint, name, readUtf8Tail, runFileWorker, runRsync, sshArgv, startBinaryProcess, startOneShot, startRemoteJob };
879
+ export { type BinaryFileEndpoint, ByteTailRing, Config, FILE_FRAME_BYTES, FILE_MAX_ENTRIES, FILE_MAX_METADATA, type HubPtyEndpoint, type HubRemoteTransport, type HubTarget, type OutputStats, PROCESS_CLEANUP_BOUND_MS, type PreparedRemoteInput, type PtyDispatchResult, PtySession, RemoteConfigValidator, type RemoteInput, type RemoteProcess, RemoteRowConfig, type RsyncEndpoint, type RsyncReceipt, type RsyncRequest, type SshConnection, type StreamOutputStats, Utf16TailRing, apply, buildHubPtyArgv, checkAbsolute, checkSelection, _default as default, disclose, hubPtyAssets, inject, localFileEndpoint, name, readUtf8Tail, runFileWorker, runRsync, sshArgv, startBinaryProcess, startOneShot, startRemoteJob };